需求开发

This commit is contained in:
FengHui
2026-05-20 20:50:51 +08:00
parent c74cdf13c2
commit 2175210ea0
8 changed files with 461 additions and 35 deletions

View File

@@ -329,6 +329,7 @@ export default {
// })
},
popupSearch(data) {
console.log(data[0].data[1]);
// 获取此次提交前,旧的政策类型值
const oldTypeL = this.queryParams.policyTypeL || "";
@@ -339,6 +340,15 @@ export default {
selections[item.type] = active.dictLabel === "全部" ? "" : active.dictValue;
});
// 政策类型选中 '0' 时传 tag 并清空 policyTypeL
if (selections.policyTypeL === '0') {
const tag = uni.getStorageSync('userInfo')?.userTagName || {};
this.queryParams.tag = tag
selections.policyTypeL = ""
} else {
delete this.queryParams.tag
}
// 核心判定逻辑:
// 如果发现“政策类型(policyTypeL)”发生了变化
if (selections.policyTypeL !== oldTypeL) {

View File

@@ -27,6 +27,12 @@
"navigationBarTitleText": "消息"
}
},
{
"path": "pages/msglog/messageDetail",
"style": {
"navigationBarTitleText": "消息详情"
}
},
{
"path": "pages/careerfair/careerfair",
"style": {

View File

@@ -101,6 +101,7 @@
<view class="row-left">
<image class="left-img" src="@/static/tabbar/chat4.png"></image>
<text class="left-text">消息</text>
<text v-if="unreadNoticeCount > 0" class="unread-badge">{{ unreadNoticeCount > 99 ? '99+' : unreadNoticeCount }}</text>
</view>
<view class="row-right">
<uni-icons color="#909090" type="right" size="14"></uni-icons>
@@ -192,6 +193,9 @@ const feedbackPopup = ref(null);
const { userInfo, Completion } = storeToRefs(useUserStore());
const counts = ref({});
// 计算未读消息数量
const unreadNoticeCount = computed(() => counts.value.unreadNoticeCount || 0);
// 提醒设置
const reminderEnabled = ref(true);
const reminderFrequency = ref('realtime');
@@ -442,6 +446,23 @@ function submitFeedback() {
font-size: 28rpx;
color: #333333;
}
.unread-badge{
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 32rpx;
height: 32rpx;
padding: 0 10rpx;
margin-left: 12rpx;
background: linear-gradient(135deg, #FF4757, #FF6B81);
border-radius: 16rpx;
font-size: 20rpx;
font-weight: 500;
color: #FFFFFF;
line-height: 32rpx;
text-align: center;
box-shadow: 0 2rpx 8rpx rgba(255, 71, 87, 0.4);
}
}
.row-right{
color: #6E6E6E;

View File

@@ -0,0 +1,343 @@
<template>
<AppLayout>
<view class="detail-content">
<scroll-view scroll-y class="detail-scroll">
<view class="scroll-body" v-if="message">
<view class="msg-card" :class="{ unread: message.isRead === '0' }">
<view class="card-row">
<view class="card-icon">
<image class="card-icon-img" v-if="message.title === '招聘会预约提醒'" src="/static/icon/msgtype.png"></image>
<image class="card-icon-img" v-else-if="message.title === '职位上新'" src="/static/icon/msgtype2.png"></image>
<image class="card-icon-img" v-else-if="message.title === '系统通知'" src="/static/icon/msgtype3.png"></image>
<image class="card-icon-img card-icon-default" v-else src="/static/icon/bell.png"></image>
</view>
<view class="card-info">
<view class="info-title-row">
<view class="unread-dot" v-if="message.isRead === '0'"></view>
<text class="info-title" :class="{ 'title-bold': message.isRead === '0' }">{{ message.title }}</text>
</view>
<view class="info-meta">
<text class="info-time">{{ message.createTime || message.date }}</text>
</view>
</view>
</view>
<view class="card-divider"></view>
<view class="card-subtitle" v-if="message.subTitle">
<text class="subtitle-label">摘要</text>
<text class="subtitle-text">{{ message.subTitle }}</text>
</view>
<view class="card-content" v-if="message.noticeContent">
<text class="content-label">详情</text>
<text class="content-text">{{ message.noticeContent }}</text>
</view>
<view class="card-footer" v-if="message.noticeType === '4'">
<text class="footer-hint" @click="handleMsgClick">点击查看详情</text>
<uni-icons color="#909090" type="right" size="14"></uni-icons>
</view>
</view>
<!-- <view class="info-card">
<view class="info-item">
<text class="info-item-label">消息类型</text>
<text class="info-item-value">{{ message.noticeType === '4' ? '职位相关' : message.title }}</text>
</view>
<view class="info-item">
<text class="info-item-label">接收时间</text>
<text class="info-item-value">{{ message.createTime || message.date }}</text>
</view>
<view class="info-item">
<text class="info-item-label">阅读状态</text>
<text class="info-item-value status-text" :class="{ unread: message.isRead === '0' }">{{ message.isRead === '0' ? '未读' : '已读' }}</text>
</view>
</view> -->
</view>
<view class="empty-state" v-else-if="!loading">
<image class="empty-icon" src="/static/icon/empty.png" mode="aspectFit"></image>
<text class="empty-text">消息不存在</text>
<text class="empty-desc">该消息可能已被删除</text>
</view>
<view class="loading-state" v-if="loading">
<text class="loading-text">加载中...</text>
</view>
</scroll-view>
</view>
</AppLayout>
</template>
<script setup>
import { inject, ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
const { $api, navTo } = inject('globalFunction');
import { useReadMsg } from '@/stores/useReadMsg';
const message = ref(null);
const loading = ref(false);
const hasMarkedRead = ref(false);
onLoad(() => {
const item = uni.getStorageSync('currentMessageDetail');
if (item) {
message.value = item;
if (item.isRead === '0') {
markAsRead(item);
}
}
loading.value = false;
});
function goBack() {
uni.navigateBack();
}
function markAsRead(item) {
if (!item.noticeId || hasMarkedRead.value) return;
hasMarkedRead.value = true;
$api.createRequest('/app/notice/read/noticeRead', { id: item.noticeId }, 'POST').then(() => {
message.value.isRead = '1';
useReadMsg().fetchMessages();
}).catch(err => {
console.error('标记已读失败:', err);
});
}
function handleMsgClick() {
const item = message.value;
if (!item) return;
if (item.noticeType === '4') {
if (item.bussinessIdEncrypt) {
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(item.bussinessId)}&encryptJobId=${encodeURIComponent(item.bussinessIdEncrypt)}`);
}
return;
}
// switch (item.title) {
// case '职位上新':
// navTo('/packageA/pages/newJobPosition/newJobPosition');
// break;
// case '招聘会预约提醒':
// navTo('/packageA/pages/reservation/reservation');
// break;
// case '系统通知':
// navTo('/packageA/pages/systemNotification/systemNotification');
// break;
// }
}
</script>
<style lang="stylus" scoped>
.detail-content
height: 100vh
display: flex
flex-direction: column
background: #F5F6FA
.detail-header
display: flex
align-items: center
justify-content: space-between
padding: 20rpx 28rpx
background: #FFFFFF
position: relative
.header-back
width: 60rpx
height: 60rpx
display: flex
align-items: center
justify-content: center
.header-title
font-size: 36rpx
font-weight: 600
color: #1A1A1A
position: absolute
left: 50%
transform: translateX(-50%)
.header-right
width: 60rpx
.detail-scroll
flex: 1
overflow: hidden
.scroll-body
padding: 28rpx
padding-bottom: 40rpx
.msg-card
background: #FFFFFF
border-radius: 20rpx
padding: 32rpx
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06)
transition: all 0.2s ease
&:active
transform: scale(0.99)
&.unread
border-left: 6rpx solid #FF4757
.card-row
display: flex
align-items: center
.card-icon
width: 88rpx
height: 88rpx
border-radius: 50%
display: flex
align-items: center
justify-content: center
margin-right: 24rpx
flex-shrink: 0
.card-icon-img
width: 100%
height: 100%
border-radius: 50%
.card-icon-default
width: 60%
height: 60%
.card-info
flex: 1
min-width: 0
.info-title-row
display: flex
align-items: center
margin-bottom: 12rpx
.unread-dot
width: 14rpx
height: 14rpx
background: #FF4757
border-radius: 50%
margin-right: 10rpx
flex-shrink: 0
.info-title
font-size: 34rpx
color: #1A1A1A
font-weight: 500
line-height: 1.3
&.title-bold
font-weight: 700
.info-meta
display: flex
align-items: center
.info-status
font-size: 24rpx
color: #FF4757
display: flex
align-items: center
margin-right: 20rpx
&.read
color: #BBBBBB
.status-dot
width: 10rpx
height: 10rpx
background: #FF4757
border-radius: 50%
margin-right: 6rpx
.info-time
font-size: 24rpx
color: #AAAAAA
.card-divider
height: 1rpx
background: #F0F0F0
margin: 28rpx 0
.card-subtitle
margin-bottom: 24rpx
.subtitle-label
display: inline-block
font-size: 22rpx
color: #FFFFFF
background: #256BFA
border-radius: 6rpx
padding: 2rpx 12rpx
margin-bottom: 12rpx
.subtitle-text
display: block
font-size: 28rpx
color: #333333
line-height: 1.5
.card-content
.content-label
display: inline-block
font-size: 22rpx
color: #FFFFFF
background: #9E74FD
border-radius: 6rpx
padding: 2rpx 12rpx
margin-bottom: 12rpx
.content-text
display: block
font-size: 28rpx
color: #555555
line-height: 1.7
.card-footer
margin-top: 32rpx
padding-top: 24rpx
border-top: 1rpx dashed #E8E8E8
display: flex
align-items: center
justify-content: center
.footer-hint
font-size: 26rpx
color: #256BFA
margin-right: 4rpx
.info-card
background: #FFFFFF
border-radius: 20rpx
padding: 24rpx 32rpx
margin-top: 24rpx
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06)
.info-item
display: flex
justify-content: space-between
align-items: center
padding: 20rpx 0
border-bottom: 1rpx solid #F5F5F5
&:last-child
border-bottom: none
.info-item-label
font-size: 26rpx
color: #999999
.info-item-value
font-size: 26rpx
color: #333333
font-weight: 500
&.status-text.unread
color: #FF4757
.empty-state
display: flex
flex-direction: column
align-items: center
justify-content: center
padding: 200rpx 40rpx
.empty-icon
width: 200rpx
height: 200rpx
margin-bottom: 32rpx
opacity: 0.5
.empty-text
font-size: 30rpx
color: #999999
font-weight: 500
margin-bottom: 12rpx
.empty-desc
font-size: 26rpx
color: #CCCCCC
.loading-state
display: flex
justify-content: center
padding: 200rpx 0
.loading-text
font-size: 28rpx
color: #BBBBBB
</style>

View File

@@ -4,6 +4,7 @@
<!-- 消息列表 -->
<view
class="list-card press-button"
:class="{ unread: item.isRead === '0' }"
v-for="(item, index) in msgList"
:key="index"
@click="seeDetail(item, index)"
@@ -16,21 +17,29 @@
></image>
<image
class="card-img-flame"
v-if="item.title === '职位上新'"
v-else-if="item.title === '职位上新'"
src="/static/icon/msgtype2.png"
></image>
<image
class="card-img-flame"
v-if="item.title === '系统通知'"
v-else-if="item.title === '系统通知'"
src="/static/icon/msgtype3.png"
></image>
<image
class="card-img-flame card-img-default"
v-else
src="/static/icon/bell.png"
></image>
<view class="subscript" v-if="item.notReadCount || !item.isRead">
{{ item.notReadCount || '' }}
</view>
</view>
<view class="card-info">
<view class="info-title">
<text>{{ item.title }}</text>
<view class="title-left">
<view class="unread-dot" v-if="item.isRead === '0'"></view>
<text :class="{ 'unread-text': item.isRead === '0' }">{{ item.title }}</text>
</view>
<view class="card-time">{{ item.date }}</view>
</view>
<view class="info-text line_2">{{ item.subTitle || '消息' }}</view>
@@ -66,26 +75,8 @@ async function loadData() {
}
function seeDetail(item, index) {
if (item.noticeType === '4') {
useReadMsg().markAsRead(item, index);
if (item.bussinessId) {
navTo(`/packageA/pages/post/post?jobId=${encodeURIComponent(item.bussinessId)}&encryptJobId=${encodeURIComponent(item.bussinessId)}`);
}
return;
}
switch (item.title) {
case '职位上新':
useReadMsg().markAsRead(item, index);
navTo('/packageA/pages/newJobPosition/newJobPosition');
break;
case '招聘会预约提醒':
useReadMsg().markAsRead(item, index);
navTo('/packageA/pages/reservation/reservation');
break;
case '系统通知':
navTo('/packageA/pages/systemNotification/systemNotification');
break;
}
uni.setStorageSync('currentMessageDetail', item);
navTo('/pages/msglog/messageDetail');
}
defineExpose({ loadData });
@@ -110,6 +101,8 @@ defineExpose({ loadData });
align-items: center;
padding: 26rpx 36rpx;
margin: 0 0 28rpx 0
&.unread
background: linear-gradient(135deg, #FFFAFA 0%, #FFFFFF 100%)
.card-img
width: 96rpx;
height: 96rpx;
@@ -121,6 +114,9 @@ defineExpose({ loadData });
.card-img-flame
width: 100%;
height: 100%
.card-img-default
width: 60%
height: 60%
.subscript
position: absolute;
right: 0;
@@ -147,15 +143,31 @@ defineExpose({ loadData });
color: #333333;
display: flex;
justify-content: space-between;
align-items: center;
width: 100%
text
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
.title-left
display: flex
align-items: center
min-width: 0
flex: 1
.unread-dot
width: 14rpx
height: 14rpx
background: #F73636
border-radius: 50%
margin-right: 12rpx
flex-shrink: 0
.unread-text
font-weight: 600
text
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
.card-time
font-weight: 400;
font-size: 28rpx;
color: #AAAAAA;
height: 100%
margin: 4rpx;
flex-shrink: 0
.info-text
font-weight: 400;
font-size: 28rpx;

View File

@@ -4,6 +4,7 @@
<!-- 未读消息列表 -->
<view
class="list-card press-button"
:class="{ unread: item.isRead === '0' }"
v-for="(item, index) in unreadMsgList"
:key="index"
@click="seeDetail(item)"
@@ -16,19 +17,27 @@
></image>
<image
class="card-img-flame"
v-if="item.title === '职位上新'"
v-else-if="item.title === '职位上新'"
src="/static/icon/msgtype2.png"
></image>
<image
class="card-img-flame"
v-if="item.title === '系统通知'"
v-else-if="item.title === '系统通知'"
src="/static/icon/msgtype3.png"
></image>
<image
class="card-img-flame card-img-default"
v-else
src="/static/icon/bell.png"
></image>
<view class="subscript" v-if="item.notReadCount">{{ item.notReadCount }}</view>
</view>
<view class="card-info">
<view class="info-title">
<text>{{ item.title }}</text>
<view class="title-left">
<view class="unread-dot" v-if="item.isRead === '0'"></view>
<text :class="{ 'unread-text': item.isRead === '0' }">{{ item.title }}</text>
</view>
<view class="card-time">{{ item.date }}</view>
</view>
<view class="info-text line_2">{{ item.subTitle || '消息' }}</view>
@@ -64,7 +73,8 @@ async function loadData() {
}
function seeDetail(item) {
console.log(item);
uni.setStorageSync('currentMessageDetail', item);
navTo('/pages/msglog/messageDetail');
}
defineExpose({ loadData });
@@ -89,6 +99,8 @@ defineExpose({ loadData });
align-items: center;
padding: 26rpx 36rpx;
margin: 0 0 28rpx 0
&.unread
background: linear-gradient(135deg, #FFFAFA 0%, #FFFFFF 100%)
.card-img
width: 96rpx;
height: 96rpx;
@@ -100,6 +112,9 @@ defineExpose({ loadData });
.card-img-flame
width: 100%;
height: 100%
.card-img-default
width: 60%
height: 60%
.subscript
position: absolute;
right: 0;
@@ -126,15 +141,31 @@ defineExpose({ loadData });
color: #333333;
display: flex;
justify-content: space-between;
align-items: center;
width: 100%
text
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
.title-left
display: flex
align-items: center
min-width: 0
flex: 1
.unread-dot
width: 14rpx
height: 14rpx
background: #F73636
border-radius: 50%
margin-right: 12rpx
flex-shrink: 0
.unread-text
font-weight: 600
text
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
.card-time
font-weight: 400;
font-size: 28rpx;
color: #AAAAAA;
height: 100%
margin: 4rpx;
flex-shrink: 0
.info-text
font-weight: 400;
font-size: 28rpx;

View File

@@ -39,7 +39,7 @@ export const useReadMsg = defineStore('readMsg', () => {
// 未读消息列表
const unreadMsgList = computed(() =>
msgList.value.filter(msg => msg.notReadCount > 0)
msgList.value.filter(msg => msg.isRead == 0)
)

View File

@@ -198,11 +198,14 @@ export function createRequest(url, data = {}, method = 'GET', loading = false, h
data: requestData,
header,
success: resData => {
const responseData = handleResponseData(resData.data)
console.log('[请求] 接口地址:', config.baseUrl + url)
console.log('[请求] 解密后数据:', JSON.stringify(responseData))
// 响应拦截
if (resData.statusCode === 200) {
const responseData = handleResponseData(resData.data)
console.log('[请求] 接口地址:', config.baseUrl + url)
console.log('[请求] 解密后数据:', JSON.stringify(responseData))
// const responseData = handleResponseData(resData.data)
// console.log('[请求] 接口地址:', config.baseUrl + url)
// console.log('[请求] 解密后数据:', JSON.stringify(responseData))
const {
code,
msg