diff --git a/TUICallKit-Vue3/TUIKit/components/CallView/CallView.vue b/TUICallKit-Vue3/TUIKit/components/CallView/CallView.vue index 5776f590..92f9616b 100644 --- a/TUICallKit-Vue3/TUIKit/components/CallView/CallView.vue +++ b/TUICallKit-Vue3/TUIKit/components/CallView/CallView.vue @@ -164,7 +164,7 @@ diff --git a/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue b/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue index 8fc56392..3ae7a849 100644 --- a/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue +++ b/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue @@ -277,6 +277,8 @@ const { proxy } = getCurrentInstance() let unsubscribeWxAppShow = null; let allowChatForegroundRelogin = false; let foregroundReloginTimer = null; + /** 避免 onUnload 重复上报离开 */ + let patientLeaveNotified = false; const CONFIRMATION_MESSAGE = `我已确认以下信息: 1、本人确认已在线下确诊; @@ -611,6 +613,7 @@ const { proxy } = getCurrentInstance() } onLoad(async (options) => { try { + patientLeaveNotified = false; console.log('进入onMounted:', options); const app = getApp(); const userID = options.userID|| app.globalData.userID; @@ -790,6 +793,11 @@ const { proxy } = getCurrentInstance() }); onUnload(() => { + // 患者退出聊天页:通知后端(与 notifyOpen 对称,供管理端轮询) + if (!patientLeaveNotified && targetUserID && String(targetUserID).startsWith('doctor_')) { + patientLeaveNotified = true; + void notifyDoctorOnChatClose(); + } allowChatForegroundRelogin = false; // #ifdef MP-WEIXIN if (typeof unsubscribeWxAppShow === 'function') { @@ -855,6 +863,47 @@ const { proxy } = getCurrentInstance() console.warn('后端通知失败:', e); } } + + /** 离开会话页时通知医生:IM 自定义消息 + 后端全局事件 */ + async function notifyDoctorOnChatClose() { + if (!targetUserID || !targetUserID.startsWith('doctor_')) return; + const doctorId = targetUserID.replace('doctor_', ''); + const userData = uni.getStorageSync('userData') || {}; + const patientName = userData.name || patient_data.value?.patient_name || '患者'; + const patientId = (currentUserID || '').replace('patient_', '') || ''; + try { + if (chat) { + const customPayload = { + businessID: 'patient_closed_chat', + patientId, + patientName, + doctorId, + time: Date.now() + }; + const imMsg = chat.createCustomMessage({ + to: targetUserID, + conversationType: TencentCloudChat.TYPES.CONV_C2C, + payload: { data: JSON.stringify(customPayload) } + }); + await chat.sendMessage(imMsg); + } + } catch (e) { + console.warn('IM 离开通知发送失败:', e); + } + try { + await proxy.apiUrl({ + url: '/api/chat/notifyClose', + method: 'POST', + data: { + doctor_id: doctorId, + patient_id: patientId, + patient_name: patientName + } + }, false); + } catch (e) { + console.warn('后端离开通知失败:', e); + } + } function applyDoctorEnteredSignalFromRawMessage(msg) { if (!msg || msg.type !== TencentCloudChat.TYPES.MSG_CUSTOM) return; @@ -956,6 +1005,9 @@ const { proxy } = getCurrentInstance() if (customData.businessID === 'patient_opened_chat') { return null; // 返回null表示不显示此消息 } + if (customData.businessID === 'patient_closed_chat') { + return null; + } // 医生进入诊室信令(admin 发送):仅更新顶部卡片,不在聊天列表展示 if (customData.businessID === 'doctor_entered_consult_room') { return null; diff --git a/admin/src/components/chat-notify-toast/index.vue b/admin/src/components/chat-notify-toast/index.vue index 9d4b69b5..ee840b71 100644 --- a/admin/src/components/chat-notify-toast/index.vue +++ b/admin/src/components/chat-notify-toast/index.vue @@ -9,17 +9,35 @@ v-for="item in notifications" :key="item.id" class="chat-notify-card" - :class="{ 'chat-notify-card-complete': item.type === 'consultation_complete' }" + :class="{ + 'chat-notify-card-complete': item.type === 'consultation_complete', + 'chat-notify-card-left': item.type === 'patient_left_chat' + }" @click="handleClick(item)" > -