diff --git a/miniprogram/api/repair/repair.js b/miniprogram/api/repair/repair.js index 70e694c..0012b5b 100644 --- a/miniprogram/api/repair/repair.js +++ b/miniprogram/api/repair/repair.js @@ -136,6 +136,15 @@ export function repairRemindListRq(data) { }); } +// 根据会议ID获取消息提醒列表 +export function repairRemindListByRepairIdRq(data) { + return request({ + url: `/app/repairRemind/listByRepairId`, + method: "get", + data + }); +} + // 消息提醒已读 export function repairRemindReadRq(data) { return request({ diff --git a/miniprogram/pages/meeting/meetingRoom/meetingStaff/meetingStaff.js b/miniprogram/pages/meeting/meetingRoom/meetingStaff/meetingStaff.js index 5855d97..b60feb6 100644 --- a/miniprogram/pages/meeting/meetingRoom/meetingStaff/meetingStaff.js +++ b/miniprogram/pages/meeting/meetingRoom/meetingStaff/meetingStaff.js @@ -40,6 +40,31 @@ Page({ let _this = this let rId = options.rId + // 从本地缓存获取会务人员总数信息 + let staffCountInfo = wx.getStorageSync('meeting_staff_count_' + rId); + if (staffCountInfo && staffCountInfo.totalStaffCount > 0) { + console.log('从本地缓存获取会务人员总数:', staffCountInfo.totalStaffCount); + } + + // 从本地缓存获取选择状态 + let staffStatus = wx.getStorageSync('staffStatus_' + rId); + if (staffStatus) { + // 计算已选人员总数 + const musicCount = staffStatus.musicIds ? staffStatus.musicIds.length : 0; + const serviceCount = staffStatus.serviceIds ? staffStatus.serviceIds.length : 0; + const totalCount = musicCount + serviceCount; + + if (totalCount > 0) { + console.log('从本地缓存状态获取会务人员总数:', totalCount); + + // 更新缓存中的会务人员总数 + wx.setStorageSync('meeting_staff_count_' + rId, { + totalStaffCount: totalCount, + timestamp: new Date().getTime() + }); + } + } + // console.log(ser) _this.setData({ rId: rId @@ -292,164 +317,123 @@ Page({ } }, - // 确定 + // 提交 submit() { - let _this = this; + let _this = this + let rId = _this.data.rId - console.log('提交全选状态:', { - musicCheckAll: _this.data.musicCheckAll, - serviceCheckAll: _this.data.serviceCheckAll - }); + // 收集已选择的人员 + let checkUser = [] + let musicList = _this.data.staffMusicList + let serveList = _this.data.staffServeList - // 收集音控组选择的ID - let staffMusicList = _this.data.staffMusicList; - let musicIds = []; - let hasMusicStaff = false; - - // 获取所有选中的音控组成员ID - staffMusicList.forEach(item => { - if (item.isSelect) { - hasMusicStaff = true; - musicIds.push(item.id); + // 音控组选择的人员 + let musicSelectedCount = 0 + let musicStaffIds = [] + for (let i = 0; i < musicList.length; i++) { + if (musicList[i].isSelect) { + musicSelectedCount++ + musicStaffIds.push(musicList[i].id) + checkUser.push({ + userId: musicList[i].id, + type: 1 + }) } - }); + } - // 收集会务服务组选择的ID - let staffServeList = _this.data.staffServeList; - let serveIds = []; - let hasServiceStaff = false; - - // 获取所有选中的会务服务组成员ID - staffServeList.forEach(item => { - if (item.isSelect) { - hasServiceStaff = true; - serveIds.push(item.id); + // 会务服务组选择的人员 + let serviceSelectedCount = 0 + let serviceStaffIds = [] + for (let i = 0; i < serveList.length; i++) { + if (serveList[i].isSelect) { + serviceSelectedCount++ + serviceStaffIds.push(serveList[i].id) + checkUser.push({ + userId: serveList[i].id, + type: 3 + }) } + } + + // 判断是否有选择,至少需要选择一个音控组人员和一个会务服务组人员 + if (musicSelectedCount < 1) { + return Notify({ + type: 'danger', + message: '请至少选择一个音控组人员' + }); + } + + if (serviceSelectedCount < 1) { + return Notify({ + type: 'danger', + message: '请至少选择一个会务服务组人员' + }); + } + + // 处理提交数据为字符串格式 + const musicIdsStr = musicStaffIds.join(','); + const serviceIdsStr = serviceStaffIds.join(','); + + console.log('提交选择的会务人员:', { + 音控组: musicIdsStr, + 会务服务组: serviceIdsStr }); - // 将数组转换为以逗号分隔的字符串 - let musicId = musicIds.join(','); - let serveId = serveIds.join(','); - - console.log('提交选择状态:', { - hasMusicStaff, - hasServiceStaff, - 音控组IDs: musicIds, - 会务服务组IDs: serveIds - }); - - // 保存选择状态到本地存储,添加更多信息和时间戳 - wx.setStorageSync('staffStatus_' + _this.data.rId, { - hasMusicStaff, - hasServiceStaff, - musicIds: musicIds, - serviceIds: serveIds, - timestamp: new Date().getTime() - }); - - // 显示加载中 + // 显示加载提示 wx.showLoading({ - title: '保存中...', + title: '提交中...', mask: true }); - // 调用接口保存到服务器 + // 保存当前会务负责人状态到本地存储,包含详细信息 + const hasMusicStaff = musicSelectedCount > 0; + const hasServiceStaff = serviceSelectedCount > 0; + wx.setStorageSync('staffStatus_' + _this.data.rId, { + hasMusicStaff, + hasServiceStaff, + musicIds: musicStaffIds, + serviceIds: serviceStaffIds, + timestamp: new Date().getTime() + }); + + // 保存实际选择的总人数到本地缓存 + const totalStaffCount = musicSelectedCount + serviceSelectedCount; + wx.setStorageSync('meeting_staff_count_' + _this.data.rId, { + totalStaffCount: totalStaffCount, + timestamp: new Date().getTime() + }); + + // 提交到服务器 - 使用正确的参数格式 addStaff({ - id: _this.data.rId, - voiceWaiter: musicId, // 音控组 type=1 - serveWaiter: serveId // 会务服务组 type=3 + id: rId, + voiceWaiter: musicIdsStr, // 音控组 - 使用逗号分隔的字符串 + serveWaiter: serviceIdsStr // 会务服务组 - 使用逗号分隔的字符串 }).then(res => { wx.hideLoading(); + console.log('提交会务负责人成功:', res); - if (res.code == 0) { - Notify({ - type: 'success', - message: '分配成功!' - }); - - // 再次确认状态已正确保存 - console.log('会务人员设置成功,最终状态:', { - 音控组: hasMusicStaff, - 会务服务组: hasServiceStaff, - 音控组人员: musicIds, - 会务服务组人员: serveIds - }); - - // 获取页面栈 - let pages = getCurrentPages(); - // 获取上一页实例 - let prevPage = pages[pages.length - 2]; - - // 判断上一页是否是approve页面 - if (prevPage && prevPage.route && prevPage.route.includes('approve')) { - // 设置上一页的dataChange为true,触发刷新 - prevPage.setData({ - dataChange: true - }); - - // 尝试直接更新上一页的记录数据 - try { - // 查找对应的预约记录并更新其状态 - const reservationList = prevPage.data.reservationDataList || []; - const currentRecord = reservationList.find(item => item.id === _this.data.rId); - - if (currentRecord) { - // 构造一个模拟的waiters数组 - const waiters = []; - - // 添加音控组人员 - musicIds.forEach(id => { - waiters.push({ - userId: id, - type: '1' - }); - }); - - // 添加会务服务组人员 - serveIds.forEach(id => { - waiters.push({ - userId: id, - type: '3' - }); - }); - - // 更新记录的waiters属性 - currentRecord.waiters = waiters; - - // 重新处理会务负责人状态 - if (typeof prevPage.processStaffStatus === 'function') { - prevPage.processStaffStatus(currentRecord); - - // 通知页面更新 - prevPage.setData({ - reservationDataList: reservationList - }); - - console.log('直接更新上一页预约记录状态成功'); - } - } - } catch (err) { - console.error('更新上一页数据失败:', err); - } - } - - // 返回上一页 - setTimeout(() => { + // 设置标记,表示会务负责人页面有更新,approve页面需要刷新通知状态 + wx.setStorageSync('staffPage_updated', { + meetingId: rId, + totalCount: totalStaffCount, + hasMusicStaff, + hasServiceStaff, + timestamp: new Date().getTime() + }); + + Notify({ + type: 'success', + message: '设置成功', + onClose: () => { wx.navigateBack(); - }, 500); - } else { - // 提交失败 - Notify({ - type: 'danger', - message: res.msg || '分配失败,请重试' - }); - } + } + }); }).catch(err => { wx.hideLoading(); - console.error('分配会务人员失败:', err); + console.error('提交会务负责人失败:', err); Notify({ type: 'danger', - message: '网络错误,请重试' + message: '设置失败' }); }); }, diff --git a/miniprogram/pages/meeting/reservationRecord/approve/approve.js b/miniprogram/pages/meeting/reservationRecord/approve/approve.js index 938de38..8378f8c 100644 --- a/miniprogram/pages/meeting/reservationRecord/approve/approve.js +++ b/miniprogram/pages/meeting/reservationRecord/approve/approve.js @@ -20,6 +20,13 @@ import { getStaff } from "../../../../api/meeting/meetingRoom.js" +// 引入消息通知相关API +import { + repairRemindListRq, + repairRemindListByRepairIdRq, + repairRemindReadRq +} from "../../../../api/repair/repair.js" + Page({ /** @@ -35,6 +42,8 @@ Page({ reservationPageSize: 10, reservationDataList: [], reservationIsDataAll: false, + // 会务人员通知状态 + staffNotifications: {}, search: { title: { text: '会议名称', @@ -241,8 +250,30 @@ Page({ maxDate: newDate.getTime() }) + // 注册全局通知状态更新监听器 + const app = getApp(); + if (app && app.registerNotificationStatusChange) { + this.notificationStatusChangeCallback = (data) => { + console.log('approve页面收到全局通知状态更新:', data); + + // 如果是会务人员(音控或服务人员)的通知,则更新状态 + if (data && data.meetingId && data.isStaffUser) { + _this.updateNotificationStatus(data); + } + }; + + app.registerNotificationStatusChange(this.notificationStatusChangeCallback); + console.log('已注册全局通知状态更新监听器'); + } + // 获取数据 _this.getDataList() + + // 页面加载完成后获取通知状态 + wx.nextTick(() => { + console.log('页面加载完成,获取通知状态'); + _this.getStaffNotificationStatus(); + }); }, // 获取数据 @@ -281,6 +312,203 @@ Page({ _this.getReservationData(param) }, + // 获取会务人员通知状态 + getStaffNotificationStatus() { + let _this = this; + + console.log('开始获取会务人员通知状态...'); + + // 初始化staffNotifications对象 + let staffNotifications = {}; + + // 获取所有待审核和待开始状态的会议ID列表 + const pendingMeetingIds = _this.data.reservationDataList + .filter(meeting => meeting.status == 5 || meeting.status == 7) + .map(meeting => meeting.id); + + console.log('需要获取通知状态的会议数量:', pendingMeetingIds.length); + + if (pendingMeetingIds.length === 0) { + _this.setData({ staffNotifications: {} }); + return; + } + + // 使用Promise.all处理所有会议的通知状态请求 + const notificationRequests = pendingMeetingIds.map(meetingId => { + // 使用新的API按会议ID查询通知 + return repairRemindListByRepairIdRq({ + repairId: meetingId, + pageNum: 1, + pageSize: 100 + }).then(res => { + console.log(`获取会议ID ${meetingId} 的通知状态:`, res); + + if (res && res.rows && res.rows.length > 0) { + // 获取该会议的所有通知 + const notifications = res.rows; + + // 找到当前会议对应的会议项 + const meetingItem = _this.data.reservationDataList.find(item => item.id === meetingId); + if (!meetingItem) { + console.error('未找到会议项:', meetingId); + return null; + } + + // 处理会务人员状态,获取会务人员ID列表 + const staffUserIds = _this.processStaffStatus(meetingItem) || []; + + // 统计已读人数和总人数 + let readCount = 0; + const readUserIds = []; + + // 此会议的总会务人员数量 - 使用确定的会务人员数量 + const totalStaffCount = staffUserIds.length; + + // 如果没有选择会务负责人,则不显示已读/未读信息 + if (totalStaffCount === 0) { + staffNotifications[meetingId + '_readCount'] = 0; + staffNotifications[meetingId + '_totalCount'] = 0; + staffNotifications[meetingId + '_readUserIds'] = []; + staffNotifications[meetingId] = false; + return null; + } + + // 确保meetingItem.totalStaffCount和计算的totalStaffCount一致 + meetingItem.totalStaffCount = totalStaffCount; + + notifications.forEach(notification => { + // 只处理会务负责人的通知 + if (staffUserIds.includes(notification.userId)) { + // 记录通知ID,方便后续标记已读 + staffNotifications[meetingId + '_notificationId_' + notification.userId] = notification.id; + + // 根据read字段判断是否已读,read === 1表示已读 + if (notification.read === 1) { + // 添加到已读用户列表 + if (!readUserIds.includes(notification.userId)) { + readUserIds.push(notification.userId); + readCount++; + } + } + } + }); + + // 确保已读数不超过总数 + readCount = Math.min(readCount, totalStaffCount); + + // 存储通知状态数据 + staffNotifications[meetingId + '_readCount'] = readCount; + staffNotifications[meetingId + '_totalCount'] = totalStaffCount; + staffNotifications[meetingId + '_readUserIds'] = readUserIds; + staffNotifications[meetingId] = readCount > 0; // 任一会务人员已读则标记为已读 + + console.log('会议ID:', meetingId, + '已读会务人员数:', readCount, + '总会务人员数:', totalStaffCount, + '最终已读状态:', readCount > 0); + + return { + meetingId, + readCount, + totalCount: totalStaffCount, + hasUnread: readCount < totalStaffCount + }; + } + + return null; + }).catch(err => { + console.error(`获取会议ID ${meetingId} 的通知状态失败:`, err); + return null; + }); + }); + + // 处理所有通知请求 + Promise.all(notificationRequests).then(() => { + // 更新通知状态 + _this.setData({ + staffNotifications: staffNotifications + }); + + // 更新会议列表中的通知状态 + _this.updateMeetingListNotificationStatus(); + }); + }, + + // 判断是否为会议相关通知 + isMeetingNotification(content) { + if (!content) return false; + + return content.includes('会议预约') || + content.includes('会务负责人') || + (content.includes('您收到会议预约') && content.includes('待审核')) || + (content.includes('会议预约') && content.includes('已取消')) || + (content.includes('您的会议预约') && ( + content.includes('被驳回') || + content.includes('已被管理员修改') || + content.includes('已审核通过') || + content.includes('即将开始') + )); + }, + + // 更新会议列表中的通知状态 + updateMeetingListNotificationStatus() { + let _this = this; + let reservationDataList = _this.data.reservationDataList; + let staffNotifications = _this.data.staffNotifications; + + console.log('开始更新会议列表通知状态,会议列表数量:', reservationDataList.length); + + // 计数器 + let updatedCount = 0; + + // 遍历会议列表,更新通知状态 + reservationDataList.forEach((meeting, index) => { + // 为所有待审核和待开始的会议添加通知标记 + if (meeting.status == 5 || meeting.status == 7) { + // 获取当前会议的通知状态 + let readCount = parseInt(staffNotifications[meeting.id + '_readCount'] || 0); + let totalCount = parseInt(staffNotifications[meeting.id + '_totalCount'] || 0); + const readUserIds = staffNotifications[meeting.id + '_readUserIds'] || []; + + // 确保计数逻辑正确 + readCount = Math.min(readCount, totalCount); + + // 只有在有选择会务负责人的情况下才显示通知状态 + const showNotification = totalCount > 0; + + // 标记会议是否有未读通知 + const isStaffNotificationRead = readCount > 0; + const hasUnreadNotification = totalCount > readCount; + + // 更新会议项的通知状态 + meeting.hasUnreadNotification = showNotification ? hasUnreadNotification : false; + meeting.isStaffNotificationRead = showNotification ? isStaffNotificationRead : false; + meeting.readCount = readCount; + meeting.totalStaffCount = totalCount; + meeting.readUserIds = readUserIds; + meeting.showNotification = showNotification; + + console.log('更新会议通知状态:', meeting.id, { + showNotification: showNotification, + hasUnreadNotification: hasUnreadNotification, + isStaffNotificationRead: isStaffNotificationRead, + readCount: readCount, + totalStaffCount: totalCount + }); + + updatedCount++; + } + }); + + // 只有存在更新时才重新渲染列表 + if (updatedCount > 0) { + console.log('已更新', updatedCount, '条会议通知状态'); + _this.setData({ + reservationDataList: reservationDataList + }); + } + }, + // 获取预约数据 getReservationData(param) { let _this = this; @@ -329,6 +557,9 @@ Page({ reservationDataList, }); + // 获取会务人员通知状态 + _this.getStaffNotificationStatus(); + // 超过总大小,则加载完成 if (_this.data.reservationDataList.length >= res.total) { _this.setData({ @@ -508,6 +739,20 @@ Page({ console.log(`JSON error : ${error}`); } } + + // 初始化会务通知状态 + item.isStaffNotificationRead = false; // 默认未读 + + // 初始化已读计数 + item.readCount = 0; // 默认0人已读 + item.totalStaffCount = 0; // 默认总会务人员数量为0,后续从通知接口获取 + + // 未读通知显示逻辑: + // 1. 会务负责人按钮上的红点 - 只在status为7且showStaff为true时显示 + // 2. 左侧的红条 - 在status为5(待审核)时显示 + // 3. 状态文字 - 在status为5或7时显示 + item.hasUnreadNotification = (item.status == 5 || item.status == 7); // 如果是待审核或待开始状态,默认显示未读标记 + for (let key in item) { // null设置为空 if (item[key] == null) { @@ -540,90 +785,169 @@ Page({ }).then(res => { console.log('获取预约详情(ID:' + item.id + '):', res); - // 更新waiters数据 - if (res && res.waiters) { + // 1. 检查waiters数组格式 + if (res && res.waiters && Array.isArray(res.waiters)) { item.waiters = res.waiters; + console.log('使用waiters数组格式数据'); + } + // 2. 检查voiceWaiter和serveWaiter字段 + else if (res) { + // 创建一个模拟的waiters数组 + item.waiters = []; - // 重新处理会务负责人状态 - this.processStaffStatus(item); + // 处理音控组数据 - voiceWaiter + if (res.voiceWaiter) { + const voiceIds = typeof res.voiceWaiter === 'string' + ? res.voiceWaiter.split(',').filter(id => id) + : (Array.isArray(res.voiceWaiter) ? res.voiceWaiter : []); + + voiceIds.forEach(id => { + item.waiters.push({ + userId: id, + type: '1' // 音控组类型为1 + }); + }); + + // 同步数据到会议项中 + item.voiceWaiter = res.voiceWaiter; + } - // 触发视图更新 - this.setData({ - reservationDataList: this.data.reservationDataList - }); + // 处理会务服务组数据 - serveWaiter + if (res.serveWaiter) { + const serveIds = typeof res.serveWaiter === 'string' + ? res.serveWaiter.split(',').filter(id => id) + : (Array.isArray(res.serveWaiter) ? res.serveWaiter : []); + + serveIds.forEach(id => { + item.waiters.push({ + userId: id, + type: '3' // 会务服务组类型为3 + }); + }); + + // 同步数据到会议项中 + item.serveWaiter = res.serveWaiter; + } + + console.log('从voiceWaiter和serveWaiter字段构建waiters数组:', item.waiters); } + + // 重新处理会务负责人状态 + this.processStaffStatus(item); + + // 触发视图更新 + this.setData({ + reservationDataList: this.data.reservationDataList + }); }).catch(err => { console.error('获取预约详情失败(ID:' + item.id + '):', err); }); }); }, - // 处理会务负责人状态 - 抽取为独立方法以便重用 + // 处理会务人员状态 processStaffStatus(item) { try { - // 从服务器数据中判断是否有选择(优先使用) + console.log('处理会务负责人状态:', item.id, item.title); + + // 初始化音控组和会务服务组状态 let hasMusicStaffFromServer = false; let hasServiceStaffFromServer = false; let musicIdsFromServer = []; let serviceIdsFromServer = []; + let staffIds = []; // 存储所有会务负责人的ID - if (item.waiters && item.waiters.length > 0) { - // 分别检查服务器返回的数据中是否有音控组和会务服务组的人员 - for (let i = 0; i < item.waiters.length; i++) { - // 音控组 - if (item.waiters[i].type === '1' || item.waiters[i].type === 1) { - hasMusicStaffFromServer = true; - musicIdsFromServer.push(item.waiters[i].userId); - } - // 会务服务组 - else if (item.waiters[i].type === '3' || item.waiters[i].type === 3) { + // 处理从服务器获取的会务负责人数据 + if (item.waiters) { + // 如果waiters是数组形式 + if (Array.isArray(item.waiters)) { + console.log('处理数组形式的waiters数据'); + // 分别检查服务器返回的数据中是否有音控组和会务服务组的人员 + for (let i = 0; i < item.waiters.length; i++) { + // 音控组 + if (item.waiters[i].type === '1' || item.waiters[i].type === 1) { + hasMusicStaffFromServer = true; + const userId = item.waiters[i].userId; + musicIdsFromServer.push(userId); + staffIds.push(userId); + } + // 会务服务组 + else if (item.waiters[i].type === '3' || item.waiters[i].type === 3) { + hasServiceStaffFromServer = true; + const userId = item.waiters[i].userId; + serviceIdsFromServer.push(userId); + staffIds.push(userId); + } + } + } + // 如果waiters是字符串形式(后台可能直接返回字符串ID) + else if (typeof item.waiters === 'string') { + console.log('处理字符串形式的waiters数据'); + const waiterIds = item.waiters.split(',').filter(id => id); + if (waiterIds.length > 0) { hasServiceStaffFromServer = true; - serviceIdsFromServer.push(item.waiters[i].userId); + waiterIds.forEach(id => { + serviceIdsFromServer.push(id); + staffIds.push(id); + }); } } } + // 处理单独的音控组和会务服务组字段 + if (item.voiceWaiter) { + console.log('处理voiceWaiter字段'); + const voiceIds = typeof item.voiceWaiter === 'string' + ? item.voiceWaiter.split(',').filter(id => id) + : (Array.isArray(item.voiceWaiter) ? item.voiceWaiter : []); + + if (voiceIds.length > 0) { + hasMusicStaffFromServer = true; + voiceIds.forEach(id => { + if (!musicIdsFromServer.includes(id)) { + musicIdsFromServer.push(id); + staffIds.push(id); + } + }); + } + } + + if (item.serveWaiter) { + console.log('处理serveWaiter字段'); + const serveIds = typeof item.serveWaiter === 'string' + ? item.serveWaiter.split(',').filter(id => id) + : (Array.isArray(item.serveWaiter) ? item.serveWaiter : []); + + if (serveIds.length > 0) { + hasServiceStaffFromServer = true; + serveIds.forEach(id => { + if (!serviceIdsFromServer.includes(id)) { + serviceIdsFromServer.push(id); + staffIds.push(id); + } + }); + } + } + + // 去重获取实际会务人员ID列表 + const uniqueStaffIds = [...new Set(staffIds)]; + + // 更新会务人员总数计数 - 使用实际选择的负责人数量,而不是默认值或来自其他地方的计数 + item.totalStaffCount = uniqueStaffIds.length; + console.log('服务器返回的会务负责人状态(ID:' + item.id + '):', { 音控组: hasMusicStaffFromServer, 会务服务组: hasServiceStaffFromServer, 音控组IDs: musicIdsFromServer, - 会务服务组IDs: serviceIdsFromServer + 会务服务组IDs: serviceIdsFromServer, + 音控组人数: musicIdsFromServer.length, + 会务服务组人数: serviceIdsFromServer.length, + 会务人员总数: item.totalStaffCount, + 实际负责人IDs: uniqueStaffIds }); - // 从本地存储获取会务负责人选择状态(作为备用) - let staffStatus = wx.getStorageSync('staffStatus_' + item.id); - - // 如果本地存储有详细信息,使用这些信息 - if (staffStatus) { - console.log('本地存储的会务负责人状态(ID:' + item.id + '):', { - 音控组: staffStatus.hasMusicStaff, - 会务服务组: staffStatus.hasServiceStaff, - 音控组IDs: staffStatus.musicIds || [], - 会务服务组IDs: staffStatus.serviceIds || [], - 时间戳: staffStatus.timestamp ? new Date(staffStatus.timestamp).toLocaleString() : '未知' - }); - } else { - console.log('本地存储中没有找到会务负责人状态(ID:' + item.id + ')'); - } - - // 优先使用服务器数据,如果服务器数据为空则使用本地存储 - // 如果本地存储时间戳比较新(10分钟内),则优先使用本地存储 - const useLocalFirst = staffStatus && staffStatus.timestamp && - (new Date().getTime() - staffStatus.timestamp < 10 * 60 * 1000); - - let hasMusicStaff, hasServiceStaff; - - if (useLocalFirst) { - // 优先使用本地存储(因为时间戳较新) - hasMusicStaff = staffStatus.hasMusicStaff; - hasServiceStaff = staffStatus.hasServiceStaff; - console.log('使用本地存储的状态(更新时间较新)'); - } else { - // 否则优先使用服务器数据 - hasMusicStaff = hasMusicStaffFromServer || (staffStatus && staffStatus.hasMusicStaff); - hasServiceStaff = hasServiceStaffFromServer || (staffStatus && staffStatus.hasServiceStaff); - console.log('优先使用服务器状态,并结合本地存储'); - } + let hasMusicStaff = hasMusicStaffFromServer; + let hasServiceStaff = hasServiceStaffFromServer; console.log('最终判断的会务负责人状态(ID:' + item.id + '):', {hasMusicStaff, hasServiceStaff}); @@ -631,7 +955,6 @@ Page({ // 音控组和会务服务组都有选择 item.staffBtnType = ''; // 绿色(无类型) item.staffTip = ''; - // 绿色样式标记 item.isStaffComplete = true; } else if (!hasMusicStaff && !hasServiceStaff) { // 音控组和会务服务组都没有选择 @@ -649,32 +972,209 @@ Page({ item.staffTip = '请选择音控组'; item.isStaffComplete = false; } + + // 存储会务人员ID列表 + item.staffUserIds = uniqueStaffIds; + + return uniqueStaffIds; // 返回会务人员ID列表 } catch (error) { - console.error('处理会务负责人状态失败', error); - // 出错时默认为未选择 - item.staffBtnType = 'danger'; - item.staffTip = '请选择音控组和会务服务组'; - item.isStaffComplete = false; + console.error('处理会务负责人状态异常(ID:' + item.id + '):', error); + return []; // 出错时返回空数组 + } + }, + + // 标记通知为已读 + markNotificationAsRead(id, userId) { + let _this = this; + let staffNotifications = _this.data.staffNotifications || {}; + + // 获取该用户对应的通知ID + const notificationId = staffNotifications[id + '_notificationId_' + userId]; + + if (notificationId) { + console.log('准备标记通知为已读 - 通知ID:', notificationId, '用户ID:', userId, '会议ID:', id); + + // 调用后端接口标记为已读 + return repairRemindReadRq({ + id: notificationId + }).then(res => { + console.log('通知标记已读成功:', res); + + // 更新本地通知状态 + let readUserIds = staffNotifications[id + '_readUserIds'] || []; + if (!readUserIds.includes(userId)) { + readUserIds.push(userId); + + // 更新已读人数 + const readCount = readUserIds.length; + const totalCount = parseInt(staffNotifications[id + '_totalCount'] || 1); + + staffNotifications[id + '_readCount'] = readCount; + staffNotifications[id + '_readUserIds'] = readUserIds; + staffNotifications[id] = readCount > 0; + + // 更新状态 + _this.setData({ + staffNotifications: staffNotifications + }); + + // 刷新会议列表通知状态 + _this.updateMeetingListNotificationStatus(); + } + + return Promise.resolve(res); + }).catch(err => { + console.error('标记通知已读失败:', err); + return Promise.reject(err); + }); + } else { + console.log('未找到对应的通知ID - 用户ID:', userId, '会议ID:', id); + return Promise.resolve(null); } }, // 跳转-预约详情 jumpMeetingDetail(e) { - console.log('jumpMeetingDetail', e); - let id = e.currentTarget.dataset.id - wx.navigateTo({ - url: "/pages/meeting/reservationRecord/meetingRecord/meetingDetail/meetingDetail?act=approve&id=" + id, - }) + let _this = this; + let id = e.currentTarget.dataset.id; + console.log('跳转会议详情,ID:', id); + + // 获取当前用户信息 + let userId = _this.data.userData ? _this.data.userData.id : ''; + + if (!userId) { + console.error('未获取到当前用户ID'); + wx.navigateTo({ + url: `/pages/meeting/reservationRecord/meetingRecord/meetingDetail/meetingDetail?act=approve&id=${id}`, + }); + return; + } + + // 先标记该用户的通知为已读 + _this.markNotificationAsRead(id, userId).then(() => { + // 无论是否成功标记已读,都跳转到详情页 + wx.navigateTo({ + url: `/pages/meeting/reservationRecord/meetingRecord/meetingDetail/meetingDetail?act=approve&id=${id}`, + }); + }).catch(err => { + console.error('标记通知已读失败:', err); + // 出错时仍然跳转 + wx.navigateTo({ + url: `/pages/meeting/reservationRecord/meetingRecord/meetingDetail/meetingDetail?act=approve&id=${id}`, + }); + }); }, + /** - * 跳转会务负责人页面,选择会务负责人 - * @param {}} e + * 跳转-会务负责人 */ goStaff(e) { - let id = e.currentTarget.dataset.id - wx.navigateTo({ - url: "/pages/meeting/meetingRoom/meetingStaff/meetingStaff?rId=" + id, - }) + let _this = this; + let id = e.currentTarget.dataset.id; + console.log('跳转会务负责人页面,ID:', id); + + // 获取当前用户信息 + let userId = _this.data.userData ? _this.data.userData.id : ''; + + if (!userId) { + console.error('未获取到当前用户ID'); + wx.navigateTo({ + url: `/pages/meeting/meetingRoom/meetingStaff/meetingStaff?rId=${id}`, + }); + return; + } + + // 标记该用户的通知为已读 + _this.markNotificationAsRead(id, userId).then(() => { + // 跳转到会务负责人页面 + wx.navigateTo({ + url: `/pages/meeting/meetingRoom/meetingStaff/meetingStaff?rId=${id}`, + }); + }).catch(err => { + console.error('标记通知已读失败:', err); + // 出错时仍然跳转 + wx.navigateTo({ + url: `/pages/meeting/meetingRoom/meetingStaff/meetingStaff?rId=${id}`, + }); + }); + }, + + /** + * 更新通知状态 - 当用户阅读通知后调用 + */ + updateNotificationStatus(data) { + let _this = this; + + if (!data || !data.meetingId) { + console.error('更新通知状态失败:缺少必要参数'); + return; + } + + console.log('收到通知状态更新请求:', data); + + const meetingId = data.meetingId; + const userId = data.userId; + + // 获取会议项 + const meetingItem = _this.data.reservationDataList.find(item => item.id === meetingId); + if (!meetingItem) { + console.error('未找到相关会议:', meetingId); + return; + } + + // 获取当前通知状态 + let staffNotifications = _this.data.staffNotifications || {}; + + // 获取已读用户ID列表 + let readUserIds = staffNotifications[meetingId + '_readUserIds'] || []; + + // 如果用户ID不在已读列表中,添加到已读列表 + if (userId && !readUserIds.includes(userId)) { + readUserIds.push(userId); + staffNotifications[meetingId + '_readUserIds'] = readUserIds; + + // 更新已读计数 + const totalCount = Math.max( + meetingItem.totalStaffCount || 0, + meetingItem.staffUserIds ? meetingItem.staffUserIds.length : 0, + 1 + ); + const readCount = Math.min(readUserIds.length, totalCount); + + // 更新通知状态 + staffNotifications[meetingId] = readCount > 0; + staffNotifications[meetingId + '_readCount'] = readCount; + + // 更新会议项的通知状态 + meetingItem.readCount = readCount; + meetingItem.isStaffNotificationRead = readCount > 0; + meetingItem.hasUnreadNotification = readCount < totalCount; + + // 更新数据 + _this.setData({ + staffNotifications: staffNotifications + }); + + console.log('已更新会议通知状态 - 会议ID:', meetingId, + '用户ID:', userId, + '已读人数:', readCount, + '总人数:', totalCount); + + // 调用后端API标记通知为已读 + if (data.notificationId) { + repairRemindReadRq({ + id: data.notificationId + }).then(res => { + console.log('标记通知已读成功:', res); + // 在成功后重新获取通知状态,确保UI更新 + setTimeout(() => { + _this.getStaffNotificationStatus(); + }, 500); + }).catch(err => { + console.error('标记通知已读失败:', err); + }); + } + } }, /** @@ -683,11 +1183,11 @@ Page({ */ onShow() { let _this = this; - + // 每次页面显示时检查用户角色是否有变化 let currentUserData = wx.getStorageSync('user'); let userRoleChanged = false; - + // 检查用户角色是否发生变化 if(_this.data.userData && currentUserData && _this.data.userData.roomRole !== currentUserData.roomRole) { userRoleChanged = true; @@ -697,18 +1197,68 @@ Page({ }); console.log('用户角色已变更,重新加载数据'); } - + // 数据是否变化或用户角色变化 if (_this.data.dataChange || userRoleChanged) { - // 刷新数据 + // 重置数据变化标志 _this.setData({ - dataChange: false, - // 预约记录参数 - reservationPageNum: 1, - reservationDataList: [], - reservationIsDataAll: false, - }) - _this.getDataList() + dataChange: false + }); + + // 检查是否从会务负责人页面返回 + const staffPageUpdated = wx.getStorageSync('staffPage_updated'); + if (staffPageUpdated) { + console.log('检测到会务负责人页面有更新:', staffPageUpdated); + + // 清除标记,避免重复处理 + wx.removeStorageSync('staffPage_updated'); + + // 如果会务人员选择页面提供了会议ID,优先处理特定会议的通知状态 + if (staffPageUpdated.meetingId) { + // 获取会议项数据 + const meetingItem = _this.data.reservationDataList.find( + item => item.id === staffPageUpdated.meetingId + ); + + if (meetingItem) { + console.log('找到需要更新的会议项:', meetingItem.id, meetingItem.title); + + // 重新获取该会议的会务人员ID列表 + const staffUserIds = _this.processStaffStatus(meetingItem); + + // 需要重新获取通知状态 + _this.getStaffNotificationStatus(); + return; + } + } + + // 仅刷新通知状态,不需要重新获取整个列表 + _this.getStaffNotificationStatus(); + } else { + // 检查是否有全局通知状态更新 + const notificationUpdated = wx.getStorageSync('meeting_notification_updated'); + if (notificationUpdated) { + console.log('检测到通知状态有更新:', notificationUpdated); + + // 清除标记,避免重复处理 + wx.removeStorageSync('meeting_notification_updated'); + + // 更新通知状态 + _this.updateNotificationStatus(notificationUpdated); + } + } + } else { + // 检查是否有全局通知状态更新 + const notificationUpdated = wx.getStorageSync('meeting_notification_updated'); + if (notificationUpdated) { + console.log('检测到通知状态有更新:', notificationUpdated); + + // 清除标记,避免重复处理 + wx.removeStorageSync('meeting_notification_updated'); + + // 更新通知状态 + _this.updateNotificationStatus(notificationUpdated); + } } }, // 取消预约一系列方法 @@ -1016,7 +1566,12 @@ Page({ * 生命周期函数--监听页面卸载 */ onUnload() { - + // 取消注册通知状态更新监听器 + const app = getApp(); + if (app && app.unregisterNotificationStatusChange && this.notificationStatusChangeCallback) { + app.unregisterNotificationStatusChange(this.notificationStatusChangeCallback); + console.log('已取消注册全局通知状态更新监听器'); + } }, /** diff --git a/miniprogram/pages/meeting/reservationRecord/approve/approve.wxml b/miniprogram/pages/meeting/reservationRecord/approve/approve.wxml index 453c26e..7fae146 100644 --- a/miniprogram/pages/meeting/reservationRecord/approve/approve.wxml +++ b/miniprogram/pages/meeting/reservationRecord/approve/approve.wxml @@ -13,7 +13,7 @@ - + {{item.timeSlot}} {{item.statusName}} @@ -30,18 +30,25 @@ 取消原因:{{item.operate[item.operate.length - 1].content}} 驳回原因:{{item.operate[item.operate.length - 1].content}} {{item.staffTip}} + + + {{item.readCount > 0 ? '已读' : '未读'}} + ({{item.readCount}}/{{item.totalStaffCount}}) + + - - 取消预约 - 修改信息 - 会务负责人 - 通过 - 驳回 - - + + 取消预约 + 修改信息 + + + 会务负责人 + + + 通过 + 驳回 + diff --git a/miniprogram/pages/meeting/reservationRecord/approve/approve.wxss b/miniprogram/pages/meeting/reservationRecord/approve/approve.wxss index 530b321..14586aa 100644 --- a/miniprogram/pages/meeting/reservationRecord/approve/approve.wxss +++ b/miniprogram/pages/meeting/reservationRecord/approve/approve.wxss @@ -7,7 +7,16 @@ background: white; margin: 30rpx 20rpx; padding: 30rpx 20rpx; - /* box-shadow: rgba(210,210,210,0.5) 0px 3.752px 3.752px 0px; */ + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08); + position: relative; + overflow: visible; + border-radius: 12rpx; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.itemView:active { + transform: translateY(2rpx); + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); } .itemView .headView { @@ -87,17 +96,19 @@ .itemView .priceView { display: flex; + flex-direction: column; justify-content: flex-end; - align-items: center; - margin: 30rpx 0; + align-items: flex-end; + margin: 20rpx 0; } .itemView .priceView .cancelContent { flex: 1; + width: 100%; margin-right: 40rpx; + margin-bottom: 10rpx; font-size: 32rpx; color: #7F7F7F; - text-overflow: ellipsis; overflow: hidden; word-break: break-all; @@ -123,9 +134,10 @@ .itemView .btnView { display: flex; - justify-content: flex-end; - align-items: center; - + flex-direction: column; + align-items: flex-end; + padding-top: 10rpx; + border-top: 1rpx solid rgba(0, 0, 0, 0.05); } .itemView .btnView .btn { @@ -164,4 +176,125 @@ .approve-btn-success { color: #000000 !important; border-color: #000000 !important; +} + +/* 会务负责人按钮容器 */ +.staff-btn-container { + position: relative; + display: flex; + flex-direction: column; + align-items: flex-end; + margin-right: 10rpx; +} + +/* 未读通知红点 */ +.unread-dot { + position: absolute; + top: -6rpx; + right: 2rpx; + width: 16rpx; + height: 16rpx; + background-color: #ee0a24; + border-radius: 50%; + box-shadow: 0 0 4rpx rgba(0,0,0,0.3); +} + +/* 左侧未读通知标记 */ +.notification-indicator { + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 8rpx; + height: 70%; + background-color: #ee0a24; + border-radius: 0 4rpx 4rpx 0; + z-index: 10; +} + +/* 操作按钮样式 */ +.action-btn { + margin-left: 16rpx !important; + margin-bottom: 12rpx !important; +} + +/* 按钮组样式 */ +.action-buttons { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 16rpx; + width: 100%; +} + +/* 会务服务人员阅读状态容器 */ +.staff-read-status-container { + display: flex; + margin-top: 10rpx; + margin-bottom: 0; + justify-content: flex-end; + align-self: flex-end; +} + +/* 会务服务人员阅读状态 */ +.staff-read-status { + display: inline-block; + padding: 4rpx 12rpx; + border-radius: 8rpx; + font-size: 24rpx; + margin-right: 0; + min-height: 32rpx; + line-height: 32rpx; + vertical-align: middle; + text-align: center; + box-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.1); + position: relative; + overflow: visible; +} + +/* 已读状态 */ +.staff-read { + color: #07c160; + background-color: rgba(7, 193, 96, 0.1); + border: 1rpx solid rgba(7, 193, 96, 0.2); +} + +/* 未读状态 */ +.staff-unread { + color: #ee0a24; + background-color: rgba(238, 10, 36, 0.1); + border: 1rpx solid rgba(238, 10, 36, 0.2); +} + +/* 数字样式 */ +.staff-read-status text { + font-weight: bold; + padding: 0 2rpx; +} + +/* 已读/未读状态标签样式 */ +.read-status-tag { + display: inline-block; + padding: 2rpx 12rpx; + border-radius: 10rpx; + font-size: 24rpx; + margin-bottom: 8rpx; + min-height: 32rpx; + line-height: 32rpx; + text-align: center; + font-weight: 600; +} + +/* 已读标签 - 绿色 */ +.read-tag { + color: #07c160; + background-color: rgba(7, 193, 96, 0.1); + border: 1rpx solid rgba(7, 193, 96, 0.2); +} + +/* 未读标签 - 红色 */ +.unread-tag { + color: #ee0a24; + background-color: rgba(238, 10, 36, 0.1); + border: 1rpx solid rgba(238, 10, 36, 0.2); } \ No newline at end of file diff --git a/miniprogram/pages/my/info/info.js b/miniprogram/pages/my/info/info.js index f50d78c..a58077d 100644 --- a/miniprogram/pages/my/info/info.js +++ b/miniprogram/pages/my/info/info.js @@ -79,6 +79,7 @@ Page({ repairRemindListRq(param).then(res => { console.log('repairRemindListRq', res); let dataList = res.rows + console.log("列表"+dataList); let isDataAll = false if (pageNum * pageSize >= res.total) { isDataAll = true @@ -128,13 +129,113 @@ Page({ // 此处为管理员收到的会议审核 url = "/pages/meeting/reservationRecord/meetingRecord/meetingDetail/meetingDetail?act=serve&id=" + repairId } + + // 处理会议预约相关的消息通知 + let isMeetingNotification = title.includes('会议预约') || title.includes('会务负责人'); + let userId = wx.getStorageSync('user') ? wx.getStorageSync('user').id : ''; + + // 判断用户角色:音控人员或会务服务人员 + let userRole = wx.getStorageSync('user') ? wx.getStorageSync('user').roomRole : ''; + let isStaffUser = userRole === '2' || userRole === '3'; // 2表示音控人员,3表示会务服务人员 + + console.log('处理消息通知:', { + id: id, + repairId: repairId, + isMeetingNotification: isMeetingNotification, + userId: userId, + userRole: userRole, + isStaffUser: isStaffUser, + title: title + }); + + // 调用API标记通知为已读 repairRemindReadRq({ id }).then(res => { + console.log('标记通知已读成功:', res); + + // 如果是会议相关通知,更新本地通知状态缓存 + if (isMeetingNotification && repairId) { + // 更新本地已读通知缓存 + let notificationKey = 'notification_' + repairId; + let notificationInfo = wx.getStorageSync(notificationKey) || {}; + + // 更新已读状态 + notificationInfo.isRead = true; + + // 如果有用户ID,记录已读用户 + if (userId) { + notificationInfo.readUsers = notificationInfo.readUsers || []; + if (!notificationInfo.readUsers.includes(userId)) { + notificationInfo.readUsers.push(userId); + } + } + + // 记录用户角色 + if (isStaffUser) { + notificationInfo.staffReadUsers = notificationInfo.staffReadUsers || []; + if (!notificationInfo.staffReadUsers.includes(userId)) { + notificationInfo.staffReadUsers.push(userId); + } + + // 记录具体角色类型 + notificationInfo.userRoles = notificationInfo.userRoles || {}; + notificationInfo.userRoles[userId] = userRole; + } + + // 更新已读时间 + notificationInfo.readTime = new Date().getTime(); + + // 保存到本地缓存 + wx.setStorageSync(notificationKey, notificationInfo); + console.log('更新本地通知缓存:', notificationKey, notificationInfo); + + // 广播通知状态更新事件,使approve页面能够更新通知状态 + const notificationData = { + meetingId: repairId, + notificationId: id, + isRead: true, + userId: userId, + userRole: userRole, + isStaffUser: isStaffUser, + timestamp: new Date().getTime() + }; + + // 保存到本地存储 + wx.setStorageSync('meeting_notification_updated', notificationData); + + // 尝试通过全局事件触发通知更新 + const app = getApp(); + if (app && app.triggerNotificationStatusChange) { + app.triggerNotificationStatusChange(notificationData); + console.log('已触发全局通知状态更新事件'); + } + + // 发布页面全局事件,确保所有打开的页面都能收到通知 + if (wx.canIUse('eventChannel')) { + const eventChannel = this.getOpenerEventChannel(); + if (eventChannel) { + try { + eventChannel.emit('notificationStatusUpdated', notificationData); + console.log('发送页面事件通知成功'); + } catch (err) { + console.error('发送页面事件通知失败:', err); + } + } + } + } + + // 跳转到相应页面 wx.navigateTo({ url: url, - }) - }) + }); + }).catch(err => { + console.error('标记通知已读失败:', err); + // 出错时仍然跳转 + wx.navigateTo({ + url: url, + }); + }); }, changeCheck(e) { console.log(e)