diff --git a/TUICallKit-Vue3/App.vue b/TUICallKit-Vue3/App.vue index 73f8e7e9..c58b9fcc 100644 --- a/TUICallKit-Vue3/App.vue +++ b/TUICallKit-Vue3/App.vue @@ -15,7 +15,6 @@ const globalData = { let avatarUrl = ref(""); // 声明为响应式变量 uni.CallManager = new CallManager(); onLaunch(() => { - uni.login({ provider: 'weixin', success: function (loginRes) { diff --git a/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue b/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue index f94a6da7..5d510e11 100644 --- a/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue +++ b/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue @@ -241,6 +241,8 @@ import groupPlugin from '@tencentcloud/lite-chat/plugins/group'; import * as GenerateTestUserSig from "@/debug/GenerateTestUserSig-es.js"; import { TUICallKitAPI } from '@/TUICallKit/src/TUICallService/index'; +import { TUIStore } from '@/TUICallKit/src/TUICallService/CallService/index'; +import { StoreName, NAME, CallStatus } from '@/TUICallKit/src/TUICallService/const/index'; // CallManager 在 App.vue 已挂载到 uni.CallManager,勿在此重复 new,否则会丢失通话状态 const { proxy } = getCurrentInstance() const messages = ref([]); @@ -271,6 +273,10 @@ const { proxy } = getCurrentInstance() let targetUserID = ''; let currentUserID = ''; // 当前登录用户ID let scrollTimer = null; // 滚动定时器 + /** 微信小程序:从系统后台回前台时刷新 IM/TUICall,避免无法接通视频 */ + let unsubscribeWxAppShow = null; + let allowChatForegroundRelogin = false; + let foregroundReloginTimer = null; const CONFIRMATION_MESSAGE = `我已确认以下信息: 1、本人确认已在线下确诊; @@ -730,6 +736,22 @@ const { proxy } = getCurrentInstance() uni.$on('TUICall:callEnd', onVideoCallEnd); //uni.showToast({ title: '聊天已就绪', icon: 'success' }); + // #ifdef MP-WEIXIN + // 系统级前后台切换时页面 onShow 不一定等价于「回前台」,用 wx.onAppShow 刷新音视频信令链路 + if (typeof wx !== 'undefined' && wx.onAppShow) { + unsubscribeWxAppShow = wx.onAppShow(() => { + if (!allowChatForegroundRelogin) return; + const pages = getCurrentPages(); + const top = pages[pages.length - 1]; + if (!(top?.route || '').includes('pages/chat/chat')) return; + reloginAfterMiniProgramForeground(); + }); + } + setTimeout(() => { + allowChatForegroundRelogin = true; + }, 800); + // #endif + // 监听键盘高度变化 uni.onKeyboardHeightChange((res) => { keyboardHeight.value = res.height; @@ -765,6 +787,17 @@ const { proxy } = getCurrentInstance() }); onUnload(() => { + allowChatForegroundRelogin = false; + // #ifdef MP-WEIXIN + if (typeof unsubscribeWxAppShow === 'function') { + unsubscribeWxAppShow(); + unsubscribeWxAppShow = null; + } + // #endif + if (foregroundReloginTimer) { + clearTimeout(foregroundReloginTimer); + foregroundReloginTimer = null; + } uni.$off('TUICall:callStart', onVideoCallStart); uni.$off('TUICall:callEnd', onVideoCallEnd); stopDoctorWaitTimer(); @@ -1039,6 +1072,26 @@ const { proxy } = getCurrentInstance() chat.on(TencentCloudChat.EVENT.MESSAGE_RECEIVED, onMessageReceived); await initTUICallKitWithTim(chat); } + + /** 小程序切后台再回前台:拉取新 UserSig 并重登 IM、重绑 TUICallEngine(与发消息失败时的 relogin 一致) */ + async function reloginAfterMiniProgramForeground() { + if (!chat || !currentUserID) return; + if (foregroundReloginTimer) clearTimeout(foregroundReloginTimer); + foregroundReloginTimer = setTimeout(async () => { + foregroundReloginTimer = null; + // reloginIMChat 会先 IM logout 再 initTUICallKit;若非 IDLE,destroyed 会失败且 IM 已断开,故仅 IDLE 时刷新 + try { + const status = TUIStore?.getData?.(StoreName.CALL, NAME.CALL_STATUS); + if (status != null && status !== CallStatus.IDLE) { + console.warn('前台恢复: 通话未结束,跳过 IM/TUICall 重绑'); + return; + } + await reloginIMChat(); + } catch (e) { + console.warn('前台恢复后 IM/TUICall 刷新失败:', e); + } + }, 400); + } async function sendTextMessage() { if (!inputText.value.trim()) return; @@ -1353,7 +1406,7 @@ const { proxy } = getCurrentInstance() hideDoctorCardByCall(); } - function onVideoCallEnd() { + async function onVideoCallEnd() { hideDoctorCardByCall(); uni.showToast({ title: '视频通话已结束', icon: 'success' }); } diff --git a/admin/src/api/tcm.ts b/admin/src/api/tcm.ts index 9e6de6e7..bdd7d088 100644 --- a/admin/src/api/tcm.ts +++ b/admin/src/api/tcm.ts @@ -50,6 +50,10 @@ export function tcmDiagnosisAssign(params: any) { return request.post({ url: '/tcm.diagnosis/assign', params }) } +export function tcmDiagnosisAssignLogList(params: { id: number }) { + return request.get({ url: '/tcm.diagnosis/assignLogList', params }) +} + // 获取医助列表 export function getAssistants() { return request.get({ url: '/tcm.diagnosis/getAssistants' }) @@ -224,6 +228,11 @@ export function prescriptionVoid(params: { id: number }) { return request.post({ url: '/tcm.prescription/void', params }) } +/** 处方审核:action approve | reject(驳回同时作废处方) */ +export function prescriptionAudit(params: { id: number; action: 'approve' | 'reject'; remark?: string }) { + return request.post({ url: '/tcm.prescription/audit', params }) +} + // ========== 处方库 ========== // 处方库列表 diff --git a/admin/src/components/chat-dialog/ChatMessageItem.vue b/admin/src/components/chat-dialog/ChatMessageItem.vue new file mode 100644 index 00000000..ac44d342 --- /dev/null +++ b/admin/src/components/chat-dialog/ChatMessageItem.vue @@ -0,0 +1,109 @@ + + + + + diff --git a/admin/src/components/chat-dialog/index.vue b/admin/src/components/chat-dialog/index.vue index 2b0ba0fe..0ee0a4dd 100644 --- a/admin/src/components/chat-dialog/index.vue +++ b/admin/src/components/chat-dialog/index.vue @@ -4,18 +4,34 @@ v-show="visible" ref="chatWindowRef" class="chat-floating-window" + :class="{ 'chat-floating-window--minimized': isMinimized }" :style="windowStyle" >
- 与 {{ patientName }} 聊天 - - - + 与 {{ patientName }} 聊天 +
+ + + + + + + 缩小 + + + + + + 展开 + + + +
-
+
{{ loadingText }} @@ -28,7 +44,7 @@
- + + + + + + + + + + + + +