diff --git a/App.vue b/App.vue index 0ea7c2d..9fedd72 100644 --- a/App.vue +++ b/App.vue @@ -29,13 +29,36 @@ export default { diff --git a/pages/message/article-list.vue b/pages/message/article-list.vue new file mode 100644 index 0000000..3c54a8f --- /dev/null +++ b/pages/message/article-list.vue @@ -0,0 +1,588 @@ + + + + + diff --git a/pages/message/chat.scss b/pages/message/chat.scss index a885920..d35fe0c 100644 --- a/pages/message/chat.scss +++ b/pages/message/chat.scss @@ -136,7 +136,7 @@ $primary-color: #0877F1; .message-list { padding: 0 16rpx; - padding-bottom: 20rpx; + padding-bottom: 60rpx; /* 增加底部内边距,防止被小程序底部横线遮挡 */ } .message-item { @@ -350,10 +350,10 @@ $primary-color: #0877F1; flex: 1; padding: 0 46rpx; background-color: #f3f5fa; - border-radius: 50rpx; + border-radius: 20rpx; margin: 0 16rpx; font-size: 28rpx; - height: 96rpx; + height: 80rpx; border: none; outline: none; box-sizing: border-box; @@ -372,8 +372,8 @@ $primary-color: #0877F1; justify-content: flex-start; background: #fff; border-top: 1rpx solid #eee; - padding: 20rpx 0 8rpx 60rpx; - gap: 40rpx; + padding: 20rpx 0 40rpx 60rpx; + gap: 40rpx 50rpx; flex-wrap: wrap; background-color: #f5f5f5; } @@ -1248,4 +1248,113 @@ $primary-color: #0877F1; @keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10rpx); } -} \ No newline at end of file +} + +/* 文章卡片样式 */ +.article-card { + display: flex; + align-items: center; + background-color: transparent; + border-radius: 12rpx; + padding: 24rpx; + max-width: 500rpx; + box-shadow: none; + background-color: #fff; +} + +.article-content { + flex: 1; + display: flex; + flex-direction: column; + margin-right: 20rpx; + min-width: 0; +} + +.article-title { + font-size: 28rpx; + color: #333; + font-weight: 500; + line-height: 1.4; + margin-bottom: 8rpx; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.article-desc { + font-size: 24rpx; + color: #999; + line-height: 1.3; +} + +.article-image { + width: 120rpx; + height: 120rpx; + border-radius: 8rpx; + flex-shrink: 0; +} + +/* 文章卡片在不同消息流中的样式 */ +.message-right .article-card { + background-color: transparent; +} + +.message-left .article-card { + background-color: transparent; +} + +/* 问卷卡片样式 */ +.survey-card { + display: flex; + align-items: center; + background-color: #fff; + border-radius: 12rpx; + padding: 24rpx; + max-width: 500rpx; + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08); +} + +.survey-content { + flex: 1; + display: flex; + flex-direction: column; + margin-right: 20rpx; + min-width: 0; +} + +.survey-title { + font-size: 28rpx; + color: #333; + font-weight: 500; + line-height: 1.4; + margin-bottom: 8rpx; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.survey-desc { + font-size: 24rpx; + color: #999; + line-height: 1.3; +} + +.survey-image { + width: 120rpx; + height: 120rpx; + border-radius: 8rpx; + flex-shrink: 0; +} + +/* 问卷卡片在不同消息流中的样式 */ +.message-right .survey-card { + background-color: #e8f4ff; +} + +.message-left .survey-card { + background-color: #fff; +} diff --git a/pages/message/common-phrases.vue b/pages/message/common-phrases.vue index f917d00..3f5bde1 100644 --- a/pages/message/common-phrases.vue +++ b/pages/message/common-phrases.vue @@ -5,11 +5,11 @@ @@ -23,26 +23,16 @@ - - - + - + + + + 新增分类 + - - - - + - 添加快捷回复 - - - {{ isEditMode ? "完成" : "编辑" }} - - - 暂无常用语 - 点击上方按钮添加常用语 + 点击下方按钮添加常用语 + + + + + + + 添加快捷回复 + + + {{ isEditMode ? "完成" : "编辑" }} + + @@ -108,7 +109,9 @@ > - 新建分类 + {{ + editingCategory ? "编辑分类" : "新建分类" + }} × @@ -117,11 +120,12 @@ v-model="categoryForm.name" class="category-input" placeholder="请输入分类名,最多6个字" - maxlength="6" /> - + @@ -130,7 +134,12 @@ + + diff --git a/pages/message/components/message-types.vue b/pages/message/components/message-types.vue index 4d358fe..4c19114 100644 --- a/pages/message/components/message-types.vue +++ b/pages/message/components/message-types.vue @@ -63,8 +63,46 @@ - + + {{ getArticleData(message).title }} + {{ getArticleData(message).desc }} + + + + + + + + {{ getSurveyData(message).title }} + {{ getSurveyData(message).desc }} + + + + + + + --> + diff --git a/pages/message/components/system-message.vue b/pages/message/components/system-message.vue index 0d28603..de4a907 100644 --- a/pages/message/components/system-message.vue +++ b/pages/message/components/system-message.vue @@ -1,9 +1,9 @@ @@ -143,13 +165,20 @@ import { handleViewDetail, checkIMConnectionStatus, } from "@/utils/chat-utils.js"; +import { sendConsultRejectedMessage, endConsultation, sendArticleMessage } from "@/utils/api.js"; import useGroupChat from "./hooks/use-group-chat"; import MessageTypes from "./components/message-types.vue"; import ChatInput from "./components/chat-input.vue"; import SystemMessage from "./components/system-message.vue"; +import ConsultAccept from "./components/consult-accept.vue"; +import RejectReasonModal from "./components/reject-reason-modal.vue"; const timChatManager = globalTimChatManager; +// 获取环境变量 +const env = __VITE_ENV__; +const corpId = env.MP_CORP_ID || ''; + // 获取登录状态 const { account, openid, isIMInitialized } = storeToRefs(useAccountStore()); const { initIMAfterLogin } = useAccountStore(); @@ -158,15 +187,12 @@ const { initIMAfterLogin } = useAccountStore(); const chatInputRef = ref(null); const groupId = ref(""); -const { - chatMember, - getGroupInfo -} = useGroupChat(groupId); +const { chatMember, getGroupInfo } = useGroupChat(groupId); // 动态设置导航栏标题 const updateNavigationTitle = () => { uni.setNavigationBarTitle({ - title: "群聊" + title: "群聊", }); }; @@ -180,6 +206,12 @@ const chatInfo = ref({ // 评价弹窗状态 const isEvaluationPopupOpen = ref(false); +// 接受问诊状态 +const showConsultAccept = ref(false); + +// 拒绝原因对话框状态 +const showRejectReasonModal = ref(false); + // 消息列表相关状态 const messageList = ref([]); const isLoading = ref(false); @@ -192,10 +224,80 @@ const lastFirstMessageId = ref(""); // 判断是否为系统消息 function isSystemMessage(message) { - const description = message.payload?.description; - return ( - message.type === "TIMCustomElem" && description === "SYSTEM_NOTIFICATION" - ); + if (message.type !== "TIMCustomElem") { + return false; + } + + try { + // 检查 payload.data 是否包含系统消息标记 + if (message.payload?.data) { + const data = + typeof message.payload.data === "string" + ? JSON.parse(message.payload.data) + : message.payload.data; + + // 检查是否为系统消息类型 + if (data.type === "system_message") { + return true; + } + } + + // 检查 description 是否为系统消息标记 + if (message.payload?.description === "系统消息标记") { + return true; + } + + // 兼容旧的系统消息格式 + if (message.payload?.description === "SYSTEM_NOTIFICATION") { + return true; + } + } catch (error) { + console.error("判断系统消息失败:", error); + } + + return false; +} + +// 检查是否有待接诊的系统消息 +function checkConsultPendingStatus() { + // 查找最新的系统消息 + for (let i = messageList.value.length - 1; i >= 0; i--) { + const message = messageList.value[i]; + + if (message.type === "TIMCustomElem" && message.payload?.data) { + try { + const data = + typeof message.payload.data === "string" + ? JSON.parse(message.payload.data) + : message.payload.data; + + // 如果是 consult_pending 类型的系统消息,显示接受组件 + if ( + data.type === "system_message" && + data.messageType === "consult_pending" + ) { + showConsultAccept.value = true; + return; + } + + // 如果是其他系统消息类型(如已接诊、已结束、已拒绝等),隐藏接受组件 + if ( + data.type === "system_message" && + (data.messageType === "consult_accepted" || + data.messageType === "consult_ended" || + data.messageType === "consult_rejected") + ) { + showConsultAccept.value = false; + return; + } + } catch (error) { + console.error("解析系统消息失败:", error); + } + } + } + + // 如果没有找到相关系统消息,隐藏接受组件 + showConsultAccept.value = false; } // 获取消息气泡样式类 @@ -204,9 +306,8 @@ function getBubbleClass(message) { if (message.type === "TIMImageElem") { return "image-bubble"; } - if (message.type === "TIMCustomElem") { - return message.flow === "out" ? "user-bubble" : "doctor-bubble-blue"; + return message.flow === "out" ? "" : ""; } return message.flow === "out" ? "user-bubble" : "doctor-bubble"; } @@ -224,6 +325,7 @@ onLoad((options) => { if (options.userID) { chatInfo.value.userID = options.userID; } + checkLoginAndInitTIM(); updateNavigationTitle(); }); @@ -288,6 +390,10 @@ const initTIMCallbacks = async () => { if (!existingMessage) { messageList.value.push(message); console.log("✓ 添加消息到列表,当前消息数量:", messageList.value.length); + + // 检查是否有待接诊的系统消息 + checkConsultPendingStatus(); + // 立即滚动到底部,不使用延迟 nextTick(() => { scrollToBottom(true); @@ -346,6 +452,9 @@ const initTIMCallbacks = async () => { isCompleted.value = data.isCompleted || false; isLoadingMore.value = false; + // 检查是否有待接诊的系统消息 + checkConsultPendingStatus(); + nextTick(() => { if (data.isRefresh) { console.log("后台刷新完成,保持当前滚动位置"); @@ -485,16 +594,16 @@ const scrollToBottom = (immediate = false) => { if (messageList.value.length > 0) { const lastMessage = messageList.value[messageList.value.length - 1]; const targetId = `msg-${lastMessage.ID}`; - + if (immediate) { // 立即滚动:先清空再设置,触发滚动 - scrollIntoView.value = ''; + scrollIntoView.value = ""; nextTick(() => { scrollIntoView.value = targetId; }); } else { // 正常滚动,使用短延迟确保DOM更新 - scrollIntoView.value = ''; + scrollIntoView.value = ""; setTimeout(() => { scrollIntoView.value = targetId; }, 50); @@ -594,18 +703,152 @@ onHide(() => { stopIMMonitoring(); }); -// 发送常用语(从常用语页面返回时调用) + const sendCommonPhrase = (content) => { if (chatInputRef.value) { chatInputRef.value.sendTextMessageFromPhrase(content); } }; - // 暴露方法给常用语页面调用 defineExpose({ - sendCommonPhrase + sendCommonPhrase, }); +// 处理接受问诊 +const handleAcceptConsult = async () => { + try { + uni.showLoading({ + title: "处理中...", + }); + + // 发送接受问诊的系统消息 + const customMessage = { + data: JSON.stringify({ + type: "system_message", + messageType: "consult_accepted", + content: "医生已接诊", + timestamp: Date.now(), + }), + description: "系统消息标记", + extension: "", + }; + + const message = timChatManager.tim.createCustomMessage({ + to: chatInfo.value.conversationID.replace("GROUP", ""), + conversationType: timChatManager.TIM.TYPES.CONV_GROUP, + payload: customMessage, + }); + + const sendResult = await timChatManager.tim.sendMessage(message); + + if (sendResult.code === 0) { + showConsultAccept.value = false; + uni.hideLoading(); + uni.showToast({ + title: "已接受问诊", + icon: "success", + }); + } else { + throw new Error(sendResult.message || "发送失败"); + } + } catch (error) { + console.error("接受问诊失败:", error); + uni.hideLoading(); + uni.showToast({ + title: error.message || "操作失败", + icon: "none", + }); + } +}; + +// 处理拒绝问诊 +const handleRejectConsult = () => { + // 显示拒绝原因选择对话框 + showRejectReasonModal.value = true; +}; + +// 处理拒绝原因确认 +const handleRejectReasonConfirm = async (reason) => { + try { + showRejectReasonModal.value = false; + + uni.showLoading({ + title: "处理中...", + }); + + // 获取医生信息 + const memberName = account.value?.name || "医生"; + + // 获取群组ID + const groupId = chatInfo.value.conversationID.replace("GROUP", ""); + + // 调用后端接口发送拒绝消息 + const result = await sendConsultRejectedMessage({ + groupId, + memberName, + reason, + }); + + uni.hideLoading(); + + if (result.success) { + showConsultAccept.value = false; + uni.showToast({ + title: "已拒绝问诊", + icon: "success", + }); + } else { + throw new Error(result.message || "发送失败"); + } + } catch (error) { + console.error("拒绝问诊失败:", error); + uni.hideLoading(); + uni.showToast({ + title: error.message || "操作失败", + icon: "none", + }); + } +}; + +// 处理拒绝原因取消 +const handleRejectReasonCancel = () => { + showRejectReasonModal.value = false; +}; +// 处理结束问诊 +const handleEndConsult = async () => { + try { + uni.showLoading({ + title: "处理中...", + }); + // 调用结束问诊接口,直接传入 groupId + const result = await endConsultation({ + groupId: groupId.value, + adminAccount: account.value?.userId || "", + extraData: { + endBy: account.value?.userId || "", + endByName: account.value?.name || "医生", + endReason: "问诊完成", + }, + }); + uni.hideLoading(); + if (result.success) { + uni.showToast({ + title: "问诊已结束", + icon: "success", + }); + } else { + throw new Error(result.message || "操作失败"); + } + } catch (error) { + console.error("结束问诊失败:", error); + uni.hideLoading(); + uni.showToast({ + title: error.message || "操作失败", + icon: "none", + }); + } +}; + // 页面卸载 onUnmounted(() => { clearMessageCache(); @@ -615,6 +858,101 @@ onUnmounted(() => { timChatManager.setCallback("onMessageReceived", null); timChatManager.setCallback("onMessageListLoaded", null); timChatManager.setCallback("onError", null); + // 移除问卷发送监听 + uni.$off("sendSurvey"); +}); + + +// 监听问卷发送事件 +uni.$on("sendSurvey", async (data) => { + const { survey, corpId, userId, sendSurveyId } = data; + + if (!survey || !survey._id) { + uni.showToast({ + title: "问卷信息不完整", + icon: "none", + }); + return; + } + try { + // 获取环境变量 + const env = __VITE_ENV__; + const baseUrl = env.VITE_PATIENT_PAGE_BASE_URL || ""; + const surveyUrl = env.VITE_SURVEY_URL || ""; + + // 获取客户信息 + const customerId = chatInfo.value.userID || ""; + const customerName = chatInfo.value.customerName || ""; + + // 创建问卷记录 + const { createSurveyRecord } = await import("@/utils/api.js"); + const recordRes = await createSurveyRecord({ + corpId, + userId, + surveryId: survey._id, + memberId: customerId, + customer: customerName, + sendSurveyId, + }); + + if (!recordRes.success) { + throw new Error(recordRes.message || "创建问卷记录失败"); + } + + const answerId = recordRes.data?.id || ""; + + // 构建问卷链接 + let surveyLink = ""; + if (survey.createBy === "system") { + // 系统问卷 + surveyLink = `${surveyUrl}?corpId=${corpId}&surveyId=${survey.surveyId}&memberId=${customerId}&sendSurveyId=${sendSurveyId}&userId=${userId}`; + } else { + // 自定义问卷 + surveyLink = `${baseUrl}pages/survery/fill?corpId=${corpId}&surveryId=${ + survey._id + }&memberId=${customerId}&answerId=${answerId}&name=${encodeURIComponent( + customerName + )}`; + } + + // 创建自定义消息 + const customMessage = { + data: JSON.stringify({ + type: "survey", + title: survey.name || "填写问卷", + desc: "请填写问卷", + url: surveyLink, + imgUrl: + "https://796f-youcan-clouddev-1-8ewcqf31dbb2b5-1317294507.tcb.qcloud.la/other/19-%E9%97%AE%E5%8D%B7.png?sign=55a4cd77c418b2c548b65792a2cf6bce&t=1701328694", + }), + description: "SURVEY", + extension: "", + }; + + // 发送自定义消息 + const message = timChatManager.tim.createCustomMessage({ + to: chatInfo.value.conversationID.replace("GROUP", ""), + conversationType: timChatManager.TIM.TYPES.CONV_GROUP, + payload: customMessage, + }); + + const sendResult = await timChatManager.tim.sendMessage(message); + + if (sendResult.code === 0) { + uni.showToast({ + title: "发送成功", + icon: "success", + }); + } else { + throw new Error(sendResult.message || "发送失败"); + } + } catch (error) { + console.error("发送问卷失败:", error); + uni.showToast({ + title: error.message || "发送失败", + icon: "none", + }); + } }); diff --git a/pages/message/survey-list.vue b/pages/message/survey-list.vue new file mode 100644 index 0000000..53a5261 --- /dev/null +++ b/pages/message/survey-list.vue @@ -0,0 +1,446 @@ + + + + + diff --git a/pages/webview/webview.vue b/pages/webview/webview.vue new file mode 100644 index 0000000..d4d603f --- /dev/null +++ b/pages/webview/webview.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/styles/theme.scss b/styles/theme.scss new file mode 100644 index 0000000..c147f45 --- /dev/null +++ b/styles/theme.scss @@ -0,0 +1,58 @@ +/** + * 项目主题色配置 + * 统一管理项目中使用的主题色 + */ + +// 主题色 +$primary-color: #0877F1; +$primary-light: #e8f3ff; +$primary-dark: #0660c9; +$primary-gradient-start: #1b5cc8; +$primary-gradient-end: #0877F1; + +// 辅助色 +$success-color: #4cd964; +$warning-color: #f0ad4e; +$error-color: #dd524d; +$info-color: #909399; + +// 文字颜色 +$text-color-primary: #333; +$text-color-regular: #666; +$text-color-secondary: #999; +$text-color-placeholder: #c0c4cc; +$text-color-white: #fff; + +// 背景颜色 +$bg-color-white: #ffffff; +$bg-color-page: #f5f5f5; +$bg-color-hover: #f1f1f1; +$bg-color-mask: rgba(0, 0, 0, 0.4); + +// 边框颜色 +$border-color-base: #e4e7ed; +$border-color-light: #ebeef5; +$border-color-lighter: #f2f6fc; + +// 圆角 +$border-radius-small: 4rpx; +$border-radius-base: 8rpx; +$border-radius-large: 16rpx; +$border-radius-round: 999rpx; + +// 间距 +$spacing-small: 16rpx; +$spacing-base: 24rpx; +$spacing-large: 32rpx; + +// 字体大小 +$font-size-small: 24rpx; +$font-size-base: 28rpx; +$font-size-medium: 32rpx; +$font-size-large: 36rpx; +$font-size-xlarge: 40rpx; + +// 阴影 +$box-shadow-light: 0 2rpx 12rpx rgba(0, 0, 0, 0.04); +$box-shadow-base: 0 4rpx 16rpx rgba(0, 0, 0, 0.08); +$box-shadow-dark: 0 8rpx 24rpx rgba(0, 0, 0, 0.12); diff --git a/uni.scss b/uni.scss index b9249e9..ac62a44 100644 --- a/uni.scss +++ b/uni.scss @@ -15,7 +15,7 @@ /* 颜色变量 */ /* 行为相关颜色 */ -$uni-color-primary: #007aff; +$uni-color-primary: #0877F1; $uni-color-success: #4cd964; $uni-color-warning: #f0ad4e; $uni-color-error: #dd524d; diff --git a/utils/api.js b/utils/api.js index d89509b..ef19d80 100644 --- a/utils/api.js +++ b/utils/api.js @@ -26,7 +26,26 @@ const urlsConfig = { saveCommonPhrase: 'saveCommonPhrase', deleteCommonPhrase: 'deleteCommonPhrase', getCommonPhraseCategories: 'getCommonPhraseCategories', - saveCommonPhraseCategory: 'saveCommonPhraseCategory' + saveCommonPhraseCategory: 'saveCommonPhraseCategory', + // 个人常用语接口 + getPersonalPhrases: 'getPersonalPhrases', + savePersonalPhrase: 'savePersonalPhrase', + deletePersonalPhrase: 'deletePersonalPhrase', + getPersonalPhraseCategories: 'getPersonalPhraseCategories', + savePersonalPhraseCategory: 'savePersonalPhraseCategory', + deletePersonalPhraseCategory: 'deletePersonalPhraseCategory', + // 宣教文章接口 + getArticleCateList: 'getArticleCateList', + getArticleList: 'getArticleList', + getArticle: 'getArticle', + addArticleSendRecord: 'addArticleSendRecord' + }, + + survery: { + getSurveyCateList: 'getSurveryCateList', + getSurveyList: 'getList', + createSurveyRecord: 'createRecord', + getSurveyDetail: 'getDetail' }, member: { addCustomer: 'add', @@ -43,7 +62,10 @@ const urlsConfig = { im: { getUserSig: 'getUserSig', sendSystemMessage: "sendSystemMessage", - getChatRecordsByGroupId: "getChatRecordsByGroupId" + getChatRecordsByGroupId: "getChatRecordsByGroupId", + sendConsultRejectedMessage: "sendConsultRejectedMessage", + endConsultation: "endConsultation", + getGroupListByGroupId: "getGroupListByGroupId" } } @@ -77,3 +99,76 @@ export default async function api(urlId, data) { }) } +// 宣教文章相关 API +export async function getArticleCateList(data) { + return api('getArticleCateList', data); +} + +export async function getArticleList(data) { + return api('getArticleList', data); +} + +export async function getArticle(data) { + return api('getArticle', data); +} + +export async function addArticleSendRecord(data) { + return api('addArticleSendRecord', data); +} + +// 问卷相关 API +export async function getSurveyCateList(data) { + return api('getSurveyCateList', data); +} + +export async function getSurveyList(data) { + return api('getSurveyList', data); +} + +export async function createSurveyRecord(data) { + return api('createSurveyRecord', data); +} + +export async function getSurveyDetail(data) { + return api('getSurveyDetail', data); +} + + + +// IM 系统消息相关 API +export async function sendConsultRejectedMessage(data) { + return request({ + url: '/getYoucanData/im', + data: { + type: 'sendConsultRejectedMessage', + ...data + } + }); +} + +// 发送宣教文章消息 +export async function sendArticleMessage(data) { + return request({ + url: '/getYoucanData/im', + data: { + type: 'sendArticleMessage', + ...data + } + }); +} + +// 结束问诊接口 +export async function endConsultation(data) { + return request({ + url: '/getYoucanData/im', + data: { + type: 'endConsultation', + ...data + } + }); +} + +// 根据群组ID获取群组记录 +export async function getGroupListByGroupId(data) { + return api('getGroupListByGroupId', data); +} diff --git a/utils/tim-chat.js b/utils/tim-chat.js index cbd6fb7..4ed5d28 100644 --- a/utils/tim-chat.js +++ b/utils/tim-chat.js @@ -363,7 +363,6 @@ class TimChatManager { } } - // 获取用户信息并登录 async getUserInfoAndLogin(userID) { try { if (userID) { @@ -376,7 +375,6 @@ class TimChatManager { } this.currentUserID = userInfo.userID } - this.currentUserSig = await this.getUserSig(this.currentUserID) await this.loginTIM() } catch (error) { @@ -711,26 +709,37 @@ class TimChatManager { // 获取消息所属的会话ID const messageConversationID = convertedMessage.conversationID + // 检查是否为系统消息 + const isSystemMsg = this.isSystemMessage(convertedMessage) + console.log('收到新消息:', { messageID: convertedMessage.ID, messageConversationID: messageConversationID, currentConversationID: this.currentConversationID, messageType: convertedMessage.type, - from: convertedMessage.from + from: convertedMessage.from, + isSystemMessage: isSystemMsg }) - // 判断是否为当前会话的消息(必须有currentConversationID且匹配才显示) - const isCurrentConversation = this.currentConversationID && - messageConversationID === this.currentConversationID + + // 判断是否为当前会话的消息 + // 系统消息:只要会话ID匹配就显示(不要求必须有currentConversationID) + // 普通消息:必须有currentConversationID且匹配才显示 + const isCurrentConversation = isSystemMsg + ? messageConversationID === this.currentConversationID + : (this.currentConversationID && messageConversationID === this.currentConversationID) + console.log('消息会话匹配检查:', { isCurrentConversation, + isSystemMessage: isSystemMsg, hasCurrentConversationID: !!this.currentConversationID, conversationIDMatch: messageConversationID === this.currentConversationID }) + if (isCurrentConversation) { // 当前会话的消息,触发回调 console.log('✓ 消息属于当前会话,触发显示') this.triggerCallback('onMessageReceived', convertedMessage) - // 处理已读状态 + // 处理已读状态(系统消息也标记为已读) if (this.currentConversationID) { this.markConversationAsRead(this.currentConversationID) } @@ -1093,7 +1102,52 @@ class TimChatManager { } else if (lastMessage.type === 'TIMSoundElem') { lastMessageText = '[语音]' } else if (lastMessage.type === 'TIMCustomElem') { - lastMessageText = lastMessage.payload.data || '[自定义消息]' + // 解析自定义消息 + try { + const customData = JSON.parse(lastMessage.payload.data) + const messageType = customData.messageType + // 根据消息类型返回不同的预览文本 + switch (messageType) { + case 'system_message': + lastMessageText = '[系统消息]' + break + case 'symptom': + lastMessageText = '[病情描述]' + break + case 'prescription': + lastMessageText = '[处方单]' + break + case 'refill': + lastMessageText = '[续方申请]' + break + case 'survey': + lastMessageText = '[问卷调查]' + break + case 'article': + lastMessageText = '[文章]' + break + case "consult_pending": + lastMessageText = '患者向团队发起咨询,请在1小时内接诊,超时将自动关闭会话' + break + case "consult_rejected": + lastMessageText = '患者向团队发起咨询,由于有紧急事务要处理暂时无法接受咨询.本次会话丿关闭' + break + case "consult_timeout": + lastMessageText = '患者向团队发起咨询,团队成员均未接受咨询,本次会话已自动关闭' + break + case "consult_accepted": + lastMessageText = '已接诊,会话已开始' + break + case "consult_ended": + lastMessageText = '已结束当前会话' + break + default: + lastMessageText = '[自定义消息]' + } + } catch (error) { + console.error('解析自定义消息失败:', error) + lastMessageText = '[自定义消息]' + } } else { lastMessageText = '[未知消息类型]' } @@ -2362,6 +2416,41 @@ class TimChatManager { } // 工具方法 + // 判断是否为系统消息 + isSystemMessage(message) { + if (message.type !== 'TIMCustomElem') { + return false + } + + // 检查 payload.data 是否包含系统消息标记 + try { + if (message.payload && message.payload.data) { + const data = typeof message.payload.data === 'string' + ? JSON.parse(message.payload.data) + : message.payload.data + + // 检查是否为系统消息类型 + if (data.type === 'system_message') { + return true + } + } + + // 检查 description 是否为系统消息标记 + if (message.payload && message.payload.description === '系统消息标记') { + return true + } + + // 兼容旧的系统消息格式 + if (message.payload && message.payload.description === 'SYSTEM_NOTIFICATION') { + return true + } + } catch (error) { + console.error('判断系统消息失败:', error) + } + + return false + } + filterMessage(message) { if (message.type === 'TIMCustomElem' && message.payload && message.payload.data) { if (message.payload.data === 'group_create' || message.payload.data === 'purchased') {