From 823341183172c1be5cdd3db8a3d791fd8ced455f Mon Sep 17 00:00:00 2001
From: wangdongbo <949818794@qq.com>
Date: Thu, 29 Jan 2026 11:42:56 +0800
Subject: [PATCH] no message
---
App.vue | 260 +++++++++++++++++++---------------
pages/login/redirect-page.vue | 52 +++----
pages/message/message.vue | 211 +++++++++++++++++++--------
static/icon/zhaopian.png | Bin 0 -> 1350 bytes
store/account.js | 32 ++++-
utils/api.js | 3 +-
utils/conversation-merger.js | 199 ++++++++++++++++++++++++++
utils/tim-chat.js | 27 ++++
8 files changed, 588 insertions(+), 196 deletions(-)
create mode 100644 static/icon/zhaopian.png
create mode 100644 utils/conversation-merger.js
diff --git a/App.vue b/App.vue
index 690d70b..250a8af 100644
--- a/App.vue
+++ b/App.vue
@@ -1,356 +1,392 @@
diff --git a/pages/login/redirect-page.vue b/pages/login/redirect-page.vue
index 6a0da11..98d2a73 100644
--- a/pages/login/redirect-page.vue
+++ b/pages/login/redirect-page.vue
@@ -4,53 +4,55 @@
diff --git a/static/icon/zhaopian.png b/static/icon/zhaopian.png
new file mode 100644
index 0000000000000000000000000000000000000000..6f55dffa75afce2d9a8be931282cf5b509a96344
GIT binary patch
literal 1350
zcmeAS@N?(olHy`uVBq!ia0vp^86eET1|(%=wk`xxoCO|{#S9E$svykh8Km+7D9BhG
zks&&vP#|?7qa}y`b##
zCXKrx$%=VV!RZT1f(3SI=-&O3{B&Jf;EQu9!Cb9U;c21ATbq8kvN--ZaB+n+v)f{B
z!BUYPjVw12pF2m2@9nYnJNC0e`0<_pDgW$uRO-K1Zux%N^820YbhSpEiLI@zQ}V85
z-xkT={n*Xr)2*Vy-D`BESscTrIb1k#RO=|qpM|-r1Kbur*^;`ocg32ROS6SIyN>2e
zZj$))Ek$MFid{`1eXeIV7$i-bJx4?(H7hnGc*3chdOfqsv&2T2;1b(E^L5ve%{w
zUE*1`Woc;0zCSLej??RVe2Y1RDlr|;a^v*5$eq^8@q8
z&g)+lCV#%ajyWL7>*cGO__n(L2Un}C*UbC#q%y+tSohEAfhE6>tX`09Uet8%OtbqV
z;rF!xn*aZ8brtyWdH%*n`&=jbM;vW*c6{KlbcdIZkKgGdN3{cwZeLcul_xJkojKcn
zav5XPg(qK1Ef-Clm+W@jD=hTv+4HB5HI`oDb6CD(v-ompt9?R^VkQ3{z7{G!eSUWL
z?`iLDv1T|fRsOMYuY1?;>?-?7AR`{MZRM4X?{pC7Y>wh6DJ{zqHDAkmXtBm3AHTI)
z=eW8*28%DM+_L`btuTGH2d8r;Pu#L*Ugd`!7UgNhHILQxPfY$(Ja_89ps1;$#sOOo
zDHgxDA$?q3ZT*S+*59|}Br?i7y6xSP%3r@+Oz^78j?ee=WHNR->eaB!oRd+oO7pbb
zmZfWjpR0+-PPVLAlh?AN_28%Ki;ZGWo=ho@k^dASV`z3c!I;N$WA*m``}d~?$*ozC
zRU~8n{+!F|jb`E3HPo&I-P8Rm`NDx~mHP3IW~(=@i+A#`ENGf^DpF79>07@G?LV2k
z0yaOjSoi8u^;)e9>H$qP`y38GxlzHX`?Sz?YtLg57pX?{c;3VHD(b4{60_W
zE^IU}`U#Ax`TM+`-7jkWz56D%%M&{T+Mz{{HN-2-M1{F
z%c~w~NC`fgEvSAx!bE(zx?AhYbL!St9G87@2zaUGTmG$)Ra5b7ir3Scz`6~$a=v{(
z#F%4zGRr&MDll-uSNDy+%XXLdFWp)a!@S4w>{o@onXB{aCOf4%P7@b460v{0ie(bR
z+sRIMd9r`Io+wI~nYknC%9KeS6BfH%QOjL8!L492<6_Sv7E(eXU8lS}7hZZjy-6oq
q=84#e<7c^aqt9*R($)5UAo^+ZwpOLH=QV-F9)qW=pUXO@geCy|2xP|q
literal 0
HcmV?d00001
diff --git a/store/account.js b/store/account.js
index b58b09a..55b4326 100644
--- a/store/account.js
+++ b/store/account.js
@@ -32,6 +32,11 @@ export default defineStore("accountStore", () => {
if (res.success && res.data && res.data.mobile) {
account.value = res.data;
openid.value = res.data.openid;
+
+ // 保存账户信息和 openId 到本地存储
+ uni.setStorageSync('account', res.data);
+ uni.setStorageSync('openid', res.data.openid);
+
initIMAfterLogin(openid.value)
return res.data
}
@@ -48,8 +53,29 @@ export default defineStore("accountStore", () => {
return true;
}
try {
- await initGlobalTIM();
+ // 使用 openid 作为 userID 初始化 IM
+ const userID = openid.value || uni.getStorageSync('openid');
+ if (!userID) {
+ console.error('无法获取 openid,IM 初始化失败');
+ return false;
+ }
+
+ console.log('开始初始化 IM,userID:', userID);
+ const success = await initGlobalTIM(userID);
+
+ if (!success) {
+ console.error('initGlobalTIM 返回失败');
+ return false;
+ }
+
+ // 验证 TIM 实例是否真正创建成功
+ if (!globalTimChatManager || !globalTimChatManager.tim) {
+ console.error('IM 初始化后 TIM 实例不存在');
+ return false;
+ }
+
isIMInitialized.value = true;
+ console.log('IM 初始化成功');
return true;
} catch (error) {
console.error('IM初始化失败:', error);
@@ -73,6 +99,10 @@ export default defineStore("accountStore", () => {
account.value = null;
openid.value = "";
isIMInitialized.value = false;
+
+ // 清除本地存储
+ uni.removeStorageSync('account');
+ uni.removeStorageSync('openid');
}
return { account, login, initIMAfterLogin, logout, openid, isIMInitialized }
diff --git a/utils/api.js b/utils/api.js
index 332109c..c1d3c99 100644
--- a/utils/api.js
+++ b/utils/api.js
@@ -57,7 +57,8 @@ const urlsConfig = {
endConsultation: "endConsultation",
getGroupListByGroupId: "getGroupListByGroupId",
createConsultGroup: "createConsultGroup",
- cancelConsultApplication: "cancelConsultApplication"
+ cancelConsultApplication: "cancelConsultApplication",
+ getGroupList: "getGroupList"
}
}
const urls = Object.keys(urlsConfig).reduce((acc, path) => {
diff --git a/utils/conversation-merger.js b/utils/conversation-merger.js
new file mode 100644
index 0000000..ed3cb8f
--- /dev/null
+++ b/utils/conversation-merger.js
@@ -0,0 +1,199 @@
+/**
+ * 会话列表与群组详细信息合并工具
+ *
+ * 功能:
+ * 1. 从 conversationList 中提取所有 groupID
+ * 2. 调用后端 getGroupList 接口获取群组详细信息
+ * 3. 合并会话数据和患者信息
+ * 4. 过滤掉后端不存在的会话
+ */
+
+import api from "@/utils/api.js"
+
+/**
+ * 合并会话列表和群组详细信息
+ *
+ * @param {Array} conversationList - 前端会话列表
+ * @param {Object} options - 可选参数
+ * @param {string} options.corpId - 企业ID(可选)
+ * @param {string} options.teamId - 团队ID(可选)
+ * @param {string} options.keyword - 搜索关键词(可选)
+ * @returns {Promise} 合并后的会话列表
+ */
+export async function mergeConversationWithGroupDetails(conversationList, options = {}) {
+ try {
+ // 1. 参数校验
+ if (!Array.isArray(conversationList) || conversationList.length === 0) {
+ console.log('会话列表为空,无需合并')
+ return []
+ }
+
+ // 2. 提取所有 groupID
+ const groupIds = conversationList
+ .map(conv => conv.groupID)
+ .filter(id => id) // 过滤掉空值
+
+ if (groupIds.length === 0) {
+ console.log('没有有效的 groupID,无需合并')
+ return []
+ }
+
+ console.log('提取到的 groupID 列表:', groupIds)
+
+ // 3. 调用后端接口获取群组详细信息
+ const requestData = {
+ groupIds,
+ ...options // 支持传入额外的查询参数(corpId, teamId, keyword等)
+ }
+
+ const response = await api('getGroupList', requestData)
+
+ // 4. 检查响应
+ if (!response || !response.success) {
+ console.error('获取群组详细信息失败:', response?.message || '未知错误')
+ return []
+ }
+
+ const groupDetailsMap = createGroupDetailsMap(response.data?.list || [])
+ console.log('获取到的群组详细信息数量:', Object.keys(groupDetailsMap).size)
+
+ // 5. 合并数据并过滤
+ const mergedList = conversationList
+ .map(conversation => mergeConversationData(conversation, groupDetailsMap))
+ .filter(item => item !== null) // 过滤掉后端不存在的会话
+
+ console.log('合并后的会话列表数量:', mergedList.length)
+ console.log('过滤掉的会话数量:', conversationList.length - mergedList.length)
+
+ // 6. 格式化并排序会话列表
+ const formattedList = mergedList.sort((a, b) => b.lastMessageTime - a.lastMessageTime)
+
+ return formattedList
+
+ } catch (error) {
+ console.error('合并会话列表失败:', error)
+ // 发生错误时返回空数组,避免影响页面渲染
+ return []
+ }
+}
+
+/**
+ * 创建群组详细信息映射表
+ *
+ * @param {Array} groupDetailsList - 后端返回的群组详细信息列表
+ * @returns {Map} groupID -> 群组详细信息的映射
+ */
+function createGroupDetailsMap(groupDetailsList) {
+ const map = new Map()
+
+ groupDetailsList.forEach(groupDetail => {
+ if (groupDetail.groupId) {
+ map.set(groupDetail.groupId, groupDetail)
+ }
+ })
+
+ return map
+}
+
+/**
+ * 合并单个会话数据
+ *
+ * @param {Object} conversation - 前端会话数据
+ * @param {Map} groupDetailsMap - 群组详细信息映射表
+ * @returns {Object|null} 合并后的会话数据,如果后端不存在则返回 null
+ */
+function mergeConversationData(conversation, groupDetailsMap) {
+ const groupDetail = groupDetailsMap.get(conversation.groupID)
+ // 如果后端没有该群组信息,返回 null(会被过滤掉)
+ if (!groupDetail) {
+ console.log(`会话 ${conversation.groupID} 在后端不存在,已过滤`)
+ return null
+ }
+
+ // 合并数据
+ return {
+ // 保留原有的会话信息
+ ...conversation,
+
+ // 合并后端的群组信息
+ _id: groupDetail._id,
+ corpId: groupDetail.corpId,
+ teamId: groupDetail.teamId,
+ customerId: groupDetail.customerId,
+ doctorId: groupDetail.doctorId,
+ patientId: groupDetail.patientId,
+ orderStatus: groupDetail.orderStatus,
+
+ // 合并患者信息(优先使用后端数据)
+ patientName: groupDetail.patientName || conversation.patientName,
+ patientSex: groupDetail.patient?.sex,
+ patientAge: groupDetail.patient?.age,
+ patientMobile: groupDetail.patient?.mobile,
+ patientAvatar: groupDetail.patient?.avatar || conversation.avatar,
+
+ // 合并团队信息
+ teamName: groupDetail.team?.name,
+ teamMemberList: groupDetail.team?.memberList,
+ teamDescription: groupDetail.team?.description,
+
+ // 时间信息
+ createdAt: groupDetail.createdAt,
+ updatedAt: groupDetail.updatedAt,
+
+ // 更新显示名称(使用后端的患者信息)
+ name: formatConversationName(groupDetail),
+
+ // 更新头像
+ avatar: groupDetail.patient?.avatar || conversation.avatar || '/static/default-avatar.png'
+ }
+}
+
+/**
+ * 格式化会话显示名称
+ *
+ * @param {Object} groupDetail - 群组详细信息
+ * @returns {string} 格式化后的名称
+ */
+function formatConversationName(groupDetail) {
+ const patientName = groupDetail.patientName || '患者'
+ const sex = groupDetail.patient?.sex === 1 ? '男' : groupDetail.patient?.sex === 2 ? '女' : ''
+ const age = groupDetail.patient?.age ? `${groupDetail.patient.age}岁` : ''
+
+ // 拼接名称:患者名 性别 年龄
+ const nameParts = [patientName, sex, age].filter(part => part)
+ const displayName = nameParts.join(' ')
+
+ return `${displayName}的问诊`
+}
+
+/**
+ * 批量合并会话列表(支持分页)
+ *
+ * @param {Array} conversationList - 前端会话列表
+ * @param {Object} options - 可选参数
+ * @param {number} options.batchSize - 每批处理的数量(默认50)
+ * @returns {Promise} 合并后的会话列表
+ */
+export async function mergeConversationWithGroupDetailsBatch(conversationList, options = {}) {
+ const { batchSize = 50, ...otherOptions } = options
+
+ if (!Array.isArray(conversationList) || conversationList.length === 0) {
+ return []
+ }
+
+ // 分批处理
+ const batches = []
+ for (let i = 0; i < conversationList.length; i += batchSize) {
+ batches.push(conversationList.slice(i, i + batchSize))
+ }
+
+ console.log(`会话列表分为 ${batches.length} 批处理,每批 ${batchSize} 条`)
+
+ // 并发处理所有批次
+ const results = await Promise.all(
+ batches.map(batch => mergeConversationWithGroupDetails(batch, otherOptions))
+ )
+
+ // 合并所有结果
+ return results.flat()
+}
diff --git a/utils/tim-chat.js b/utils/tim-chat.js
index dd60bd9..c741ed8 100644
--- a/utils/tim-chat.js
+++ b/utils/tim-chat.js
@@ -149,6 +149,7 @@ class TimChatManager {
this.isInitializing = true
console.log('=== 开始初始化IM ===')
+ console.log('传入的 userID:', userID)
try {
// 重置重连次数,允许重新登录
@@ -170,9 +171,12 @@ class TimChatManager {
console.log('创建TIM实例,SDKAppID:', TIM_CONFIG.SDKAppID)
this.tim = TIM.create({ SDKAppID: TIM_CONFIG.SDKAppID })
+ console.log('TIM实例创建成功:', !!this.tim)
// 等待TIM实例初始化完成
+ console.log('等待TIM实例就绪...')
await this.waitForTIMInstanceReady()
+ console.log('TIM实例已就绪')
// 注册上传插件
this.tim.registerPlugin({ "tim-upload-plugin": TIMUploadPlugin })
@@ -180,6 +184,7 @@ class TimChatManager {
// 注册事件监听器
this.registerEventListeners()
+ console.log('事件监听器已注册')
// 设置日志级别
if (typeof this.tim.setLogLevel === 'function') {
@@ -187,21 +192,29 @@ class TimChatManager {
}
// 获取用户信息并登录
+ console.log('开始获取用户信息并登录...')
await this.getUserInfoAndLogin(userID)
+ console.log('用户信息获取并登录成功')
// 等待SDK Ready
console.log('等待SDK Ready...')
await this.waitForSDKReady(IM_CONNECTION_CONFIG.SDK_READY_TIMEOUT)
console.log('=== IM初始化完成 ===')
+ console.log('最终状态 - this.tim 存在:', !!this.tim)
+ console.log('最终状态 - this.isLoggedIn:', this.isLoggedIn)
return true
} catch (error) {
console.error('=== IM初始化失败 ===', error)
+ console.error('错误详情:', error.message || error)
+ console.error('错误堆栈:', error.stack)
this.triggerCallback('onError', `初始化失败: ${error.message || error}`)
// 初始化失败时清理资源
+ console.log('初始化失败,开始清理资源...')
await this.cleanupOldInstance()
+ console.log('资源清理完成,this.tim 已设为 null')
return false
} finally {
this.isInitializing = false
@@ -365,20 +378,34 @@ class TimChatManager {
async getUserInfoAndLogin(userID) {
try {
+ console.log('getUserInfoAndLogin 开始,传入 userID:', userID)
+
if (userID) {
this.currentUserID = userID
uni.setStorageSync('userInfo', { userID })
+ console.log('使用传入的 userID:', userID)
} else {
+ console.log('未传入 userID,尝试从本地存储获取')
const userInfo = uni.getStorageSync('userInfo')
+ console.log('本地存储的 userInfo:', userInfo)
+
if (!userInfo?.userID) {
throw new Error('未找到用户信息,请先登录')
}
this.currentUserID = userInfo.userID
+ console.log('从本地存储获取到 userID:', this.currentUserID)
}
+
+ console.log('开始获取 userSig...')
this.currentUserSig = await this.getUserSig(this.currentUserID)
+ console.log('userSig 获取成功')
+
+ console.log('开始登录 TIM...')
await this.loginTIM()
+ console.log('TIM 登录成功')
} catch (error) {
console.error('获取用户信息失败:', error)
+ console.error('错误详情:', error.message || error)
this.triggerCallback('onError', `登录失败: ${error.message || error}`)
throw error // 重新抛出错误,让调用者知道登录失败
}