diff --git a/App.vue b/App.vue index 7fe422c..bffc016 100644 --- a/App.vue +++ b/App.vue @@ -15,15 +15,15 @@ export default { onHide: function () { console.log("App Hide"); // 小程序退出时退出腾讯IM登录 - try { - if (globalTimChatManager && globalTimChatManager.tim) { - console.log('小程序退出,开始退出腾讯IM'); - globalTimChatManager.destroy(); - console.log('腾讯IM退出成功'); - } - } catch (error) { - console.error('退出腾讯IM失败:', error); - } + // try { + // if (globalTimChatManager && globalTimChatManager.tim) { + // console.log('小程序退出,开始退出腾讯IM'); + // globalTimChatManager.destroy(); + // console.log('腾讯IM退出成功'); + // } + // } catch (error) { + // console.error('退出腾讯IM失败:', error); + // } }, }; diff --git a/pages/message/chat.scss b/pages/message/chat.scss index 62ece8f..a885920 100644 --- a/pages/message/chat.scss +++ b/pages/message/chat.scss @@ -120,7 +120,6 @@ $primary-color: #0877F1; } .system-message { - // background-color: #f0f0f0; border-radius: 16rpx; padding: 12rpx; margin: 20rpx 24rpx; @@ -141,7 +140,7 @@ $primary-color: #0877F1; } .message-item { - margin-bottom: 16rpx; + margin-bottom: 30rpx; } .message-content { @@ -162,14 +161,14 @@ $primary-color: #0877F1; width: 60rpx; height: 60rpx; border-radius: 50%; - margin-top: 28rpx; // 向下移动与气泡箭头对齐 + margin-top: 10rpx; } .user-msg-avatar { width: 60rpx; height: 60rpx; border-radius: 50%; - margin-top: 28rpx; // 向下移动与气泡箭头对齐 + margin-top: 10rpx; } // 消息气泡容器 @@ -1040,6 +1039,19 @@ $primary-color: #0877F1; object-fit: cover; /* 保持图片比例,裁剪多余部分 */ } +/* 图片消息气泡 - 无背景色 */ +.image-bubble { + background: transparent !important; + padding: 0 !important; + border-radius: 0 !important; +} + +/* 移除图片消息气泡的小三角 */ +.image-bubble::before, +.image-bubble::after { + display: none !important; +} + .message-right .message-card { margin-right: 8rpx; } diff --git a/pages/message/components/chat-input.vue b/pages/message/components/chat-input.vue index f103256..571e398 100644 --- a/pages/message/components/chat-input.vue +++ b/pages/message/components/chat-input.vue @@ -146,8 +146,9 @@ const sendTextMessage = async () => { }; // 发送图片消息 -const sendImageMessage = async (imageUrl) => { - await sendMessage('image', imageUrl); +const sendImageMessage = async (imageFile) => { + console.log('chat-input sendImageMessage 被调用,参数:', imageFile); + await sendMessage('image', imageFile); }; // 发送语音消息 @@ -164,6 +165,7 @@ const sendMessage = async (messageType, data) => { () => validateBeforeSend(false, false, props.timChatManager), () => { showMorePanel.value = false; + // 发送成功后滚动到底部 emit('messageSent'); }, cloudCustomData.value @@ -197,7 +199,13 @@ const toggleMorePanel = () => { // 处理图片选择 const showImagePicker = () => { chooseImage( - (res) => sendImageMessage(res), + (res) => { + console.log('选择图片成功,返回数据:', res); + // 提取实际的文件对象 + const imageFile = res.tempFiles && res.tempFiles.length > 0 ? res.tempFiles[0] : res; + console.log('准备发送图片:', imageFile); + sendImageMessage(imageFile); + }, (err) => { console.error('选择图片失败:', err); if (!err.errMsg?.includes('permission') && !err.errMsg?.includes('auth') && !err.errMsg?.includes('拒绝') && !err.errMsg?.includes('未授权')) { @@ -213,7 +221,13 @@ const showImagePicker = () => { const takePhoto = () => { takePhotoUtil( - (res) => sendImageMessage(res), + (res) => { + console.log('拍照成功,返回数据:', res); + // 提取实际的文件对象 + const imageFile = res.tempFiles && res.tempFiles.length > 0 ? res.tempFiles[0] : res; + console.log('准备发送图片:', imageFile); + sendImageMessage(imageFile); + }, (err) => { console.error('拍照失败:', err); if (!err.errMsg?.includes('permission') && !err.errMsg?.includes('auth') && !err.errMsg?.includes('拒绝') && !err.errMsg?.includes('未授权')) { @@ -315,10 +329,10 @@ const sendSurveyMessage = async () => { const morePanelButtons = [ { text: '照片', icon: '/static/home/photo.png', action: showImagePicker }, { text: '拍摄', icon: '/static/home/video.png', action: takePhoto }, - // { text: '病情', icon: '/static/home/doctor.png', action: sendSymptomMessage }, - // { text: '处方', icon: '/static/home/doctor.png', action: sendPrescriptionMessage }, - // { text: '续方', icon: '/static/home/doctor.png', action: sendRefillMessage }, - // { text: '问卷', icon: '/static/home/doctor.png', action: sendSurveyMessage } + // { text: '病情', icon: '/static/home/avatar.svg', action: sendSymptomMessage }, + // { text: '处方', icon: '/static/home/avatar.svg', action: sendPrescriptionMessage }, + // { text: '续方', icon: '/static/home/avatar.svg', action: sendRefillMessage }, + // { text: '问卷', icon: '/static/home/avatar.svg', action: sendSurveyMessage } ]; function handleInputFocus() { diff --git a/pages/message/components/head-card.vue b/pages/message/components/head-card.vue index cc94bc4..568b64e 100644 --- a/pages/message/components/head-card.vue +++ b/pages/message/components/head-card.vue @@ -45,7 +45,7 @@ const props = defineProps({ }) const hasFilledDescription = computed(() => props.order && ('description' in props.order)); -const avatar = computed(() => props.doctorInfo?.avatar || '/static/home/doctor.png') +const avatar = computed(() => props.doctorInfo?.avatar || '/static/home/avatar.svg') function addSymptomDescription() { if (!hasFilledDescription.value) { diff --git a/pages/message/index.vue b/pages/message/index.vue index c84fce7..19d0432 100644 --- a/pages/message/index.vue +++ b/pages/message/index.vue @@ -50,19 +50,19 @@ - + - + @@ -113,8 +113,8 @@ v-if="!isEvaluationPopupOpen" :timChatManager="timChatManager" :formatTime="formatTime" - @scrollToBottom="scrollToBottom" - @messageSent="scrollToBottom" + @scrollToBottom="() => scrollToBottom(true)" + @messageSent="() => scrollToBottom(true)" /> @@ -170,7 +170,7 @@ const updateNavigationTitle = () => { const chatInfo = ref({ conversationID: "", userID: "", - avatar: "/static/home/doctor.png", + avatar: "/static/home/avatar.svg", }); // 评价弹窗状态 @@ -196,6 +196,11 @@ function isSystemMessage(message) { // 获取消息气泡样式类 function getBubbleClass(message) { + // 图片消息不需要气泡背景 + if (message.type === "TIMImageElem") { + return "image-bubble"; + } + if (message.type === "TIMCustomElem") { return message.flow === "out" ? "user-bubble" : "doctor-bubble-blue"; } @@ -279,10 +284,9 @@ const initTIMCallbacks = async () => { if (!existingMessage) { messageList.value.push(message); console.log("✓ 添加消息到列表,当前消息数量:", messageList.value.length); + // 立即滚动到底部,不使用延迟 nextTick(() => { - setTimeout(() => { - scrollToBottom(); - }, 100); + scrollToBottom(true); }); } }); @@ -473,13 +477,24 @@ const playVoice = (message) => { }; // 滚动到底部 -const scrollToBottom = () => { +const scrollToBottom = (immediate = false) => { if (messageList.value.length > 0) { const lastMessage = messageList.value[messageList.value.length - 1]; - scrollIntoView.value = ``; - setTimeout(() => { - scrollIntoView.value = `msg-${lastMessage.ID}`; - }, 300); + const targetId = `msg-${lastMessage.ID}`; + + if (immediate) { + // 立即滚动:先清空再设置,触发滚动 + scrollIntoView.value = ''; + nextTick(() => { + scrollIntoView.value = targetId; + }); + } else { + // 正常滚动,使用短延迟确保DOM更新 + scrollIntoView.value = ''; + setTimeout(() => { + scrollIntoView.value = targetId; + }, 50); + } } }; diff --git a/pages/message/message.vue b/pages/message/message.vue index 7e1d423..0cacc4d 100644 --- a/pages/message/message.vue +++ b/pages/message/message.vue @@ -122,20 +122,15 @@ const initIM = async () => { // 加载会话列表 const loadConversationList = async () => { if (loading.value) return; - - loading.value = true; + // loading.value = true; try { console.log("开始加载群聊列表"); - - // 检查 globalTimChatManager 是否存在 if (!globalTimChatManager || !globalTimChatManager.getGroupList) { throw new Error("IM管理器未初始化"); } - // 直接调用getGroupList,它会自动等待SDK就绪 const result = await globalTimChatManager.getGroupList(); - if (result && result.success && result.groupList) { conversationList.value = result.groupList .map((group) => ({ @@ -220,34 +215,72 @@ const extractMessagePreview = (message) => { return "暂无消息"; }; -// 设置消息监听,实时更新列表 -const setupMessageListener = () => { +// 设置会话列表监听,实时更新列表 +const setupConversationListener = () => { if (!globalTimChatManager) return; + // 监听会话列表更新事件 + globalTimChatManager.setCallback("onConversationListUpdated", (eventData) => { + console.log("会话列表更新事件:", eventData); + + // 如果是新消息导致的会话更新 + if (eventData.reason === "NEW_MESSAGE_RECEIVED_IN_CURRENT_CONVERSATION" || + eventData.reason === "NEW_MESSAGE_RECEIVED") { + const conversation = eventData.conversation; + if (!conversation) return; + + const conversationID = conversation.conversationID; + const conversationIndex = conversationList.value.findIndex( + (conv) => conv.conversationID === conversationID + ); + + if (conversationIndex !== -1) { + // 更新现有会话 + const existingConversation = conversationList.value[conversationIndex]; + existingConversation.lastMessage = conversation.lastMessage || "暂无消息"; + existingConversation.lastMessageTime = conversation.lastMessageTime || Date.now(); + existingConversation.unreadCount = conversation.unreadCount || 0; + + // 将该会话移到顶部 + const [updatedConversation] = conversationList.value.splice( + conversationIndex, + 1 + ); + conversationList.value.unshift(updatedConversation); + + console.log("已更新会话:", existingConversation.name); + } else { + // 新会话,添加到列表顶部 + conversationList.value.unshift({ + conversationID: conversationID, + groupID: conversation.groupID || conversationID.replace("GROUP", ""), + name: conversation.name || "问诊群聊", + avatar: conversation.avatar || "/static/default-avatar.png", + lastMessage: conversation.lastMessage || "暂无消息", + lastMessageTime: conversation.lastMessageTime || Date.now(), + unreadCount: conversation.unreadCount || 0, + }); + + console.log("已添加新会话"); + } + } + }); + + // 监听消息接收事件(用于更新未读数) globalTimChatManager.setCallback("onMessageReceived", (message) => { console.log("消息列表页面收到新消息:", message); - // 找到对应的会话并更新 + // 找到对应的会话并更新未读数 const conversationID = message.conversationID; const conversationIndex = conversationList.value.findIndex( (conv) => conv.conversationID === conversationID ); if (conversationIndex !== -1) { - // 更新现有会话 const conversation = conversationList.value[conversationIndex]; - conversation.lastMessage = extractMessagePreview(message); - conversation.lastMessageTime = message.lastTime || Date.now(); + // 只更新未读数,其他信息由 onConversationListUpdated 事件处理 conversation.unreadCount = (conversation.unreadCount || 0) + 1; - - // 将该会话移到顶部 - const [updatedConversation] = conversationList.value.splice( - conversationIndex, - 1 - ); - conversationList.value.unshift(updatedConversation); - - console.log("已更新会话:", conversation.name); + console.log("已更新会话未读数:", conversation.name); } }); }; @@ -341,11 +374,11 @@ onShow(async () => { return; } - // 先设置消息监听 - setupMessageListener(); - - // 加载消息列表 + // 先加载初始会话列表 await loadConversationList(); + + // 再设置监听器,后续通过事件更新列表 + setupConversationListener(); } catch (error) { console.error("页面初始化失败:", error); uni.showToast({ @@ -359,6 +392,7 @@ onShow(async () => { onHide(() => { // 移除消息监听 if (globalTimChatManager) { + globalTimChatManager.setCallback("onConversationListUpdated", null); globalTimChatManager.setCallback("onMessageReceived", null); } }); diff --git a/static/icon/changyongyu.png b/static/icon/changyongyu.png new file mode 100644 index 0000000..7e6de39 Binary files /dev/null and b/static/icon/changyongyu.png differ diff --git a/static/icon/fuzhenyuyue.png b/static/icon/fuzhenyuyue.png new file mode 100644 index 0000000..8609748 Binary files /dev/null and b/static/icon/fuzhenyuyue.png differ diff --git a/static/icon/icon-chinese-rx.png b/static/icon/icon-chinese-rx.png new file mode 100644 index 0000000..10ee891 Binary files /dev/null and b/static/icon/icon-chinese-rx.png differ diff --git a/static/icon/icon-western-rx.png b/static/icon/icon-western-rx.png new file mode 100644 index 0000000..00cb9a8 Binary files /dev/null and b/static/icon/icon-western-rx.png differ diff --git a/static/icon/jieshuzixun.png b/static/icon/jieshuzixun.png new file mode 100644 index 0000000..1e36ede Binary files /dev/null and b/static/icon/jieshuzixun.png differ diff --git a/static/icon/kaichufang.png b/static/icon/kaichufang.png new file mode 100644 index 0000000..647f267 Binary files /dev/null and b/static/icon/kaichufang.png differ diff --git a/static/icon/kaiyizhu.png b/static/icon/kaiyizhu.png new file mode 100644 index 0000000..e47bc0c Binary files /dev/null and b/static/icon/kaiyizhu.png differ diff --git a/static/icon/kaizhongyao.png b/static/icon/kaizhongyao.png new file mode 100644 index 0000000..f9d649e Binary files /dev/null and b/static/icon/kaizhongyao.png differ diff --git a/static/icon/paizhao.png b/static/icon/paizhao.png new file mode 100644 index 0000000..170af2a Binary files /dev/null and b/static/icon/paizhao.png differ diff --git a/static/icon/quxiaobingtuikuan.png b/static/icon/quxiaobingtuikuan.png new file mode 100644 index 0000000..97c24a3 Binary files /dev/null and b/static/icon/quxiaobingtuikuan.png differ diff --git a/static/icon/xuanjiaowenzhang.png b/static/icon/xuanjiaowenzhang.png new file mode 100644 index 0000000..dffdb37 Binary files /dev/null and b/static/icon/xuanjiaowenzhang.png differ diff --git a/static/icon/zhaopian.png b/static/icon/zhaopian.png new file mode 100644 index 0000000..d31c0de Binary files /dev/null and b/static/icon/zhaopian.png differ diff --git a/static/icon/zhenliaoyijian.png b/static/icon/zhenliaoyijian.png new file mode 100644 index 0000000..08851f4 Binary files /dev/null and b/static/icon/zhenliaoyijian.png differ diff --git a/store/account.js b/store/account.js index bbc9c94..44e6e47 100644 --- a/store/account.js +++ b/store/account.js @@ -15,7 +15,7 @@ export default defineStore("accountStore", () => { const isIMInitialized = ref(false); // 医生信息 const doctorInfo = ref(null); - + async function login(phoneCode = '') { if (loading.value) return; loading.value = true; @@ -39,8 +39,8 @@ export default defineStore("accountStore", () => { } account.value = res.data; openid.value = res.data.openid; - await getDoctorInfo(openid.value); - + + // 登录成功后初始化腾讯IM try { console.log('开始初始化腾讯IM,userID:', res.data.openid); @@ -51,7 +51,7 @@ export default defineStore("accountStore", () => { console.error('腾讯IM初始化失败:', imError); // IM初始化失败不影响登录流程 } - + await getDoctorInfo(openid.value); return res.data } } @@ -61,7 +61,7 @@ export default defineStore("accountStore", () => { } loading.value = false } - + async function getDoctorInfo() { try { const res = await api('getCorpMemberData', { @@ -88,7 +88,7 @@ export default defineStore("accountStore", () => { return false; } } - + // 退出登录 async function logout() { try { @@ -101,7 +101,7 @@ export default defineStore("accountStore", () => { } catch (error) { console.error('退出腾讯IM失败:', error); } - + // 清空账户信息 account.value = null; openid.value = ""; diff --git a/utils/chat-utils.js b/utils/chat-utils.js index 01164ee..f172069 100644 --- a/utils/chat-utils.js +++ b/utils/chat-utils.js @@ -486,6 +486,8 @@ export const sendCustomMessage = async (messageData, timChatManager, validateBef * @param {function} onSuccess - 成功回调 */ export const sendMessage = async (messageType, data, timChatManager, validateBeforeSend, onSuccess, cloudCustomData) => { + console.log('chat-utils sendMessage 被调用:', { messageType, data }); + if (!validateBeforeSend()) { return; } @@ -497,7 +499,9 @@ export const sendMessage = async (messageType, data, timChatManager, validateBef result = await timChatManager.sendTextMessage(data, cloudCustomData); break; case 'image': + console.log('准备发送图片消息,数据:', data); result = await timChatManager.sendImageMessage(data, cloudCustomData); + console.log('图片消息发送结果:', result); break; case 'voice': result = await timChatManager.sendVoiceMessage(data.file, data.duration,cloudCustomData); @@ -508,6 +512,7 @@ export const sendMessage = async (messageType, data, timChatManager, validateBef } if (result && result.success) { + console.log('消息发送成功'); if (onSuccess) onSuccess(); } else { console.error('发送消息失败:', result?.error); diff --git a/utils/tim-chat.js b/utils/tim-chat.js index 631aec1..d57d8ce 100644 --- a/utils/tim-chat.js +++ b/utils/tim-chat.js @@ -427,27 +427,18 @@ class TimChatManager { userID: this.currentUserID, userSig: this.currentUserSig }).then(() => { - console.log('腾讯IM登录成功') + console.log('腾讯IM登录请求成功,等待SDK_READY事件...') this.isLoggingIn = false - this.isLoggedIn = true + // 不在这里设置 isLoggedIn = true,等待 onSDKReady 事件 this.reconnectAttempts = 0 - // 启动心跳检测 - this.startHeartbeat() - - // 启动登录状态检测 - this.startLoginStatusCheck() - - // 触发登录状态变化回调 + // 触发登录状态变化回调(登录中状态) this.triggerCallback('onLoginStatusChanged', { - isLoggedIn: true, + isLoggedIn: false, userID: this.currentUserID, - reason: 'LOGIN_SUCCESS' + reason: 'LOGIN_REQUESTED', + message: '登录请求成功,等待SDK就绪...' }) - - // 获取会话列表(确保连接正常) - this.getConversationList() - resolve() }).catch(error => { console.error('腾讯IM登录失败:', error) @@ -691,7 +682,6 @@ class TimChatManager { }) this.startLoginStatusCheck() this.startHeartbeat() // 启动心跳检测 - this.getConversationList() } // SDK Not Ready 事件 @@ -712,11 +702,8 @@ class TimChatManager { event.data.forEach(message => { const existingMessage = this.messageList.find(msg => msg.ID === message.ID) if (existingMessage) return - if (!this.filterMessage(message)) return - const convertedMessage = this.convertMessageFormat(message) - // 确保使用消息本身的conversationID,而不是当前会话ID if (!convertedMessage.conversationID) { convertedMessage.conversationID = message.conversationID } @@ -731,30 +718,22 @@ class TimChatManager { messageType: convertedMessage.type, from: convertedMessage.from }) - console.log(event) - - // 缓存功能已移除 - // 判断是否为当前会话的消息(必须有currentConversationID且匹配才显示) const isCurrentConversation = this.currentConversationID && messageConversationID === this.currentConversationID - console.log('消息会话匹配检查:', { isCurrentConversation, hasCurrentConversationID: !!this.currentConversationID, conversationIDMatch: messageConversationID === this.currentConversationID }) - if (isCurrentConversation) { // 当前会话的消息,触发回调 console.log('✓ 消息属于当前会话,触发显示') this.triggerCallback('onMessageReceived', convertedMessage) - // 处理已读状态 if (this.currentConversationID) { this.markConversationAsRead(this.currentConversationID) } - this.triggerCallback('onConversationListUpdated', { reason: 'NEW_MESSAGE_RECEIVED_IN_CURRENT_CONVERSATION', conversation: { @@ -928,7 +907,6 @@ class TimChatManager { return true } - // 启动心跳检测(优化版:使用配置常量) startHeartbeat() { this.stopHeartbeat() @@ -952,14 +930,26 @@ class TimChatManager { return } + // 确保方法存在 + if (typeof this.tim.getConversationList !== 'function') { + console.log('⏸ 心跳检测:SDK方法不可用,跳过检测') + return + } + this.tim.getConversationList() .then(() => { if (this.heartbeatFailCount > 0) { - console.log(`💚 心跳恢复正常(之前失败${this.heartbeatFailCount}次)`) + console.log(`� 心跳恢复正常(之前失败${this.heartbeatFailCount}次)`) } this.heartbeatFailCount = 0 // 重置失败计数 }) .catch((error) => { + // 如果是SDK未就绪错误,不计入失败次数(这是临时状态) + if (error && error.message && error.message.includes('sdk not ready')) { + console.log('⏸ 心跳检测:SDK未就绪,跳过本次检测') + return + } + this.heartbeatFailCount++ console.error(`💔 心跳失败 (${this.heartbeatFailCount}/${MAX_HEARTBEAT_FAIL}):`, error.message) @@ -1009,14 +999,6 @@ class TimChatManager { setTimeout(checkSDKReady, 500) return } - - this.tim.getConversationList({ withGroupInfo: 1, withAllFields: 1 }).then(response => { - if (this.conversationID) { - this.enterConversation(this.conversationID) - } - }).catch(error => { - console.error('获取会话列表失败:', error) - }) } // 获取群聊列表 @@ -1032,18 +1014,21 @@ class TimChatManager { let waitTime = 0 const maxWaitTime = 30000 // 最多等待30秒 const checkInterval = 1000 // 每秒检查一次 + let timeoutHandle = null const checkSDKReady = () => { if (this.isLoggedIn) { console.log('SDK已ready,开始获取群聊列表') + if (timeoutHandle) clearTimeout(timeoutHandle) this.getGroupListInternal().then(resolve).catch(reject) } else if (waitTime >= maxWaitTime) { console.error('等待SDK就绪超时') + if (timeoutHandle) clearTimeout(timeoutHandle) reject(new Error('SDK初始化超时,请检查网络连接')) } else { waitTime += checkInterval console.log(`等待SDK就绪... (${Math.floor(waitTime / 1000)}/${Math.floor(maxWaitTime / 1000)}秒)`) - setTimeout(checkSDKReady, checkInterval) + timeoutHandle = setTimeout(checkSDKReady, checkInterval) } } @@ -1060,124 +1045,104 @@ class TimChatManager { return new Promise((resolve, reject) => { console.log('开始获取群聊列表') - // 确保SDK已就绪再调用getConversationList - const ensureSDKReady = () => { - if (!this.isLoggedIn) { - console.log('SDK未就绪,等待中...') - setTimeout(ensureSDKReady, 500) - return - } + // 直接调用,SDK就绪检查已在getGroupList()中完成 + this.tim.getConversationList() + .then(async (conversationResponse) => { + console.log('获取会话列表成功') + + const groupConversations = conversationResponse.data.conversationList.filter(conversation => { + return conversation.conversationID && conversation.conversationID.startsWith('GROUP') + }) - this.tim.getConversationList().then(async (conversationResponse) => { - console.clear() - console.log('获取会话列表成功:', conversationResponse) - const groupConversations = conversationResponse.data.conversationList.filter(conversation => { - return conversation.conversationID && conversation.conversationID.startsWith('GROUP') - }) + console.log('群聊会话列表数量:', groupConversations.length) - console.log('群聊会话列表:', groupConversations) - - const groupsWithInfo = await Promise.all( - groupConversations.map(async (conversation) => { - const groupName = typeof conversation.groupProfile.name === 'string' ? conversation.groupProfile.name : conversation.groupProfile.name; - const [doctorId, patientName] = groupName.split('|') - try { - const groupID = conversation.conversationID.replace('GROUP', '') - let groupInfo = { - groupID: groupID, - name: '问诊群聊', - avatar: '/static/home/doctor.png', - memberCount: 0 - } + // 先获取一次群组列表,避免在循环中重复调用 + let allGroups = [] + try { + const groupListResponse = await this.tim.getGroupList() + allGroups = groupListResponse.data.groupList || [] + } catch (error) { + console.error('获取群组列表失败:', error) + } + const groupsWithInfo = await Promise.all( + groupConversations.map(async (conversation) => { try { - const groupListResponse = await this.tim.getGroupList() - const group = groupListResponse.data.groupList.find(g => g.groupID === groupID) - if (group) { - groupInfo = { - ...groupInfo, - name: group.name || '问诊群聊', - memberCount: group.memberCount || 0 + const groupName = conversation.groupProfile?.name || '' + const [doctorId, patientName] = groupName.split('|') + const groupID = conversation.conversationID.replace('GROUP', '') + + // 从已获取的群组列表中查找 + const group = allGroups.find(g => g.groupID === groupID) + const groupInfo = { + groupID: groupID, + name: group?.name || '问诊群聊', + avatar: '/static/home/avatar.svg', + memberCount: group?.memberCount || 0 + } + + const lastMessage = conversation.lastMessage + let lastMessageText = '暂无消息' + let lastMessageTime = Date.now() + + if (lastMessage) { + if (lastMessage.type === 'TIMTextElem') { + lastMessageText = lastMessage.payload.text + } else if (lastMessage.type === 'TIMImageElem') { + lastMessageText = '[图片]' + } else if (lastMessage.type === 'TIMSoundElem') { + lastMessageText = '[语音]' + } else if (lastMessage.type === 'TIMCustomElem') { + lastMessageText = lastMessage.payload.data || '[自定义消息]' + } else { + lastMessageText = '[未知消息类型]' } + + lastMessageTime = (lastMessage.lastTime || lastMessage.time || 0) * 1000 + } + + return { + ...groupInfo, + groupID: groupID, + doctorId, + patientName, + conversationID: conversation.conversationID, + lastMessage: lastMessageText, + lastMessageTime: lastMessageTime, + unreadCount: conversation.unreadCount || 0 } } catch (error) { - console.error(`获取群组 ${groupID} 信息失败:`, error) - } - - const lastMessage = conversation.lastMessage - let lastMessageText = '' - let lastMessageTime = Date.now() - - if (lastMessage) { - console.log(`群聊 ${groupID} 最后一条消息:`, lastMessage) - - if (lastMessage.type === 'TIMTextElem') { - lastMessageText = lastMessage.payload.text - } else if (lastMessage.type === 'TIMImageElem') { - lastMessageText = '[图片]' - } else if (lastMessage.type === 'TIMSoundElem') { - lastMessageText = '[语音]' - } else if (lastMessage.type === 'TIMCustomElem') { - lastMessageText = lastMessage.payload.data ? lastMessage.payload.data : '[自定义消息]' - } else { - lastMessageText = '[未知消息类型]' + console.error(`处理群聊会话失败:`, error) + return { + groupID: conversation.conversationID, + name: conversation.groupProfile?.name || '问诊群聊', + doctorId: '', + patientName: '', + avatar: '/static/home/avatar.svg', + lastMessage: '获取失败', + lastMessageTime: Date.now(), + unreadCount: conversation.unreadCount || 0, + memberCount: 0 } + } + }) + ) - if (lastMessage.lastTime) { - lastMessageTime = lastMessage.lastTime * 1000 - } else if (lastMessage.time) { - lastMessageTime = lastMessage.time * 1000 - } - } else { - console.log(`群聊 ${groupID} 没有最后一条消息`) - lastMessageText = '暂无消息' - } - - return { - ...groupInfo, - groupID: groupID, - doctorId, - patientName, - conversationID: conversation.conversationID, - lastMessage: lastMessageText, - lastMessageTime: lastMessageTime, - unreadCount: conversation.unreadCount || 0 - } - } catch (error) { - console.error(`处理群聊会话失败:`, error) - return { - groupID: conversation.conversationID, - name: conversation.groupProfile.name, - doctorId, - patientName, - avatar: '/static/home/avatar.svg', - lastMessage: '获取失败', - lastMessageTime: Date.now(), - unreadCount: conversation.unreadCount || 0, - memberCount: 0 - } - } + console.log('处理后的群聊列表数量:', groupsWithInfo.length) + resolve({ + success: true, + groupList: groupsWithInfo, + totalCount: groupsWithInfo.length, + data: conversationResponse.data }) - ) - - console.log('处理后的群聊列表:', groupsWithInfo) - resolve({ - success: true, - groupList: groupsWithInfo, - totalCount: groupsWithInfo.length, - data: conversationResponse.data }) - }).catch((imError) => { - console.error('获取会话列表失败:', imError) - reject({ - success: false, - error: imError + .catch((imError) => { + console.error('获取会话列表失败:', imError) + reject({ + success: false, + error: imError + }) }) - }) - } - - // 开始检查SDK就绪状态 - ensureSDKReady() }) } @@ -1564,7 +1529,7 @@ class TimChatManager { payload: this.convertDBPayloadToIMPayload(msgType, msgBody.MsgContent), lastTime: lastTime, status: 'success', - avatar: flow === 'in' ? '/static/home/doctor.png' : '/static/center/user-avatar.png', + avatar: flow === 'in' ? '/static/home/avatar.svg' : '/static/center/user-avatar.png', conversationID: this.currentConversationID, MsgSeq: dbMsg.MsgSeq, // 保留 MsgSeq 用于分页 } @@ -2074,29 +2039,42 @@ class TimChatManager { if (!this.tim) { this.triggerCallback('onError', 'IM未初始化') - return + return { success: false, error: 'IM未初始化' } } - if (!this.conversation) { - this.triggerCallback('onError', '群聊会话不存在') - return { success: false, error: '群聊会话不存在' } + // 检查登录状态 + if (!this.isLoggedIn) { + console.error('IM未登录,无法发送消息'); + this.triggerCallback('onError', 'IM未登录,请稍后重试') + return { success: false, error: 'IM未登录' } } - let groupID = null - if (this.conversation.groupProfile && this.conversation.groupProfile.groupID) { - groupID = this.conversation.groupProfile.groupID - } else if (this.conversation.conversationID) { - groupID = this.conversation.conversationID.replace('GROUP', '') + // 优先使用 currentConversationID,如果没有则尝试从 conversation 获取 + let conversationID = this.currentConversationID; + if (!conversationID && this.conversation) { + conversationID = this.conversation.conversationID; + } + + if (!conversationID) { + console.error('会话ID不存在'); + this.triggerCallback('onError', '会话不存在,请重新进入聊天') + return { success: false, error: '会话ID不存在' } + } + + // 从 conversationID 提取 groupID + let groupID = null; + if (conversationID.startsWith('GROUP')) { + groupID = conversationID.replace('GROUP', ''); + } else if (this.conversation?.groupProfile?.groupID) { + groupID = this.conversation.groupProfile.groupID; } if (!groupID) { + console.error('无法获取群聊ID,conversationID:', conversationID); this.triggerCallback('onError', '无法获取群聊ID') return { success: false, error: '无法获取群聊ID' } } - // 确保使用当前会话的conversationID - const conversationID = this.conversation.conversationID || this.currentConversationID - const localMessage = { ID: `local_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, flow: 'out', @@ -2127,39 +2105,75 @@ class TimChatManager { } catch (error) { console.error('文本消息发送失败:', error) localMessage.status = 'failed' + + // 如果是因为未登录导致的失败,尝试重连 + if (error.message && (error.message.includes('not login') || error.message.includes('sdk not ready'))) { + console.log('检测到未登录错误,尝试重连...'); + this.isLoggedIn = false; + this.ensureIMConnection(); + } + return { success: false, error } } } // 发送图片消息 async sendImageMessage(imageFile) { + console.log('sendImageMessage 被调用,参数:', imageFile); + if (!this.tim) { this.triggerCallback('onError', 'IM未初始化') - return + return { success: false, error: 'IM未初始化' } } - if (!this.conversation) { - this.triggerCallback('onError', '群聊会话不存在') - return { success: false, error: '群聊会话不存在' } + // 检查登录状态 + if (!this.isLoggedIn) { + console.error('IM未登录,无法发送消息'); + this.triggerCallback('onError', 'IM未登录,请稍后重试') + return { success: false, error: 'IM未登录' } } - let groupID = null - if (this.conversation.groupProfile && this.conversation.groupProfile.groupID) { - groupID = this.conversation.groupProfile.groupID - } else if (this.conversation.conversationID) { - groupID = this.conversation.conversationID.replace('GROUP', '') + // 优先使用 currentConversationID,如果没有则尝试从 conversation 获取 + let conversationID = this.currentConversationID; + if (!conversationID && this.conversation) { + conversationID = this.conversation.conversationID; + } + + if (!conversationID) { + console.error('会话ID不存在'); + this.triggerCallback('onError', '会话不存在,请重新进入聊天') + return { success: false, error: '会话ID不存在' } + } + + // 从 conversationID 提取 groupID + let groupID = null; + if (conversationID.startsWith('GROUP')) { + groupID = conversationID.replace('GROUP', ''); + } else if (this.conversation?.groupProfile?.groupID) { + groupID = this.conversation.groupProfile.groupID; } if (!groupID) { + console.error('无法获取群聊ID,conversationID:', conversationID); this.triggerCallback('onError', '无法获取群聊ID') return { success: false, error: '无法获取群聊ID' } } - // 确保使用当前会话的conversationID - const conversationID = this.conversation.conversationID || this.currentConversationID + console.log('发送图片消息,conversationID:', conversationID, 'groupID:', groupID); + + // 处理文件对象 - 确保获取正确的文件 + let actualFile = imageFile; + if (imageFile?.tempFiles?.length > 0) { + actualFile = imageFile.tempFiles[0]; + console.log('从 tempFiles 中提取文件:', actualFile); + } else if (imageFile?.tempFilePath) { + // 如果已经是单个文件对象 + actualFile = imageFile; + console.log('使用单个文件对象:', actualFile); + } // 获取图片尺寸信息 - const imageInfo = await this.getImageInfo(imageFile); + const imageInfo = await this.getImageInfo(actualFile); const localMessage = { ID: `local_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, @@ -2167,7 +2181,7 @@ class TimChatManager { type: 'TIMImageElem', payload: { imageInfoArray: [{ - url: this.getImageUrl(imageFile), + url: this.getImageUrl(actualFile), width: imageInfo.width, height: imageInfo.height }] @@ -2186,19 +2200,33 @@ class TimChatManager { // 触发消息接收回调,让UI立即显示 this.triggerCallback('onMessageReceived', localMessage) + console.log('准备创建 TIM 图片消息,groupID:', groupID, 'file:', actualFile); + const message = this.tim.createImageMessage({ to: groupID, conversationType: TIM.TYPES.CONV_GROUP, - payload: { file: imageFile } + payload: { file: actualFile } }) + console.log('TIM 图片消息已创建:', message); + try { - await this.tim.sendMessage(message) + console.log('开始发送图片消息...'); + const sendResult = await this.tim.sendMessage(message); + console.log('图片消息发送成功:', sendResult); localMessage.status = 'success' return { success: true, message: localMessage } } catch (error) { console.error('图片消息发送失败:', error) localMessage.status = 'failed' + + // 如果是因为未登录导致的失败,尝试重连 + if (error.message && (error.message.includes('not login') || error.message.includes('sdk not ready'))) { + console.log('检测到未登录错误,尝试重连...'); + this.isLoggedIn = false; + this.ensureIMConnection(); + } + return { success: false, error } } } @@ -2207,29 +2235,42 @@ class TimChatManager { async sendVoiceMessage(voiceFile, duration) { if (!this.tim) { this.triggerCallback('onError', 'IM未初始化') - return + return { success: false, error: 'IM未初始化' } } - if (!this.conversation) { - this.triggerCallback('onError', '群聊会话不存在') - return { success: false, error: '群聊会话不存在' } + // 检查登录状态 + if (!this.isLoggedIn) { + console.error('IM未登录,无法发送消息'); + this.triggerCallback('onError', 'IM未登录,请稍后重试') + return { success: false, error: 'IM未登录' } } - let groupID = null - if (this.conversation.groupProfile && this.conversation.groupProfile.groupID) { - groupID = this.conversation.groupProfile.groupID - } else if (this.conversation.conversationID) { - groupID = this.conversation.conversationID.replace('GROUP', '') + // 优先使用 currentConversationID,如果没有则尝试从 conversation 获取 + let conversationID = this.currentConversationID; + if (!conversationID && this.conversation) { + conversationID = this.conversation.conversationID; + } + + if (!conversationID) { + console.error('会话ID不存在'); + this.triggerCallback('onError', '会话不存在,请重新进入聊天') + return { success: false, error: '会话ID不存在' } + } + + // 从 conversationID 提取 groupID + let groupID = null; + if (conversationID.startsWith('GROUP')) { + groupID = conversationID.replace('GROUP', ''); + } else if (this.conversation?.groupProfile?.groupID) { + groupID = this.conversation.groupProfile.groupID; } if (!groupID) { + console.error('无法获取群聊ID,conversationID:', conversationID); this.triggerCallback('onError', '无法获取群聊ID') return { success: false, error: '无法获取群聊ID' } } - // 确保使用当前会话的conversationID - const conversationID = this.conversation.conversationID || this.currentConversationID - const localMessage = { ID: `local_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, flow: 'out', @@ -2262,6 +2303,14 @@ class TimChatManager { } catch (error) { console.error('语音消息发送失败:', error) localMessage.status = 'failed' + + // 如果是因为未登录导致的失败,尝试重连 + if (error.message && (error.message.includes('not login') || error.message.includes('sdk not ready'))) { + console.log('检测到未登录错误,尝试重连...'); + this.isLoggedIn = false; + this.ensureIMConnection(); + } + return { success: false, error } } } @@ -2270,29 +2319,42 @@ class TimChatManager { async sendCustomMessage(messageData) { if (!this.tim) { this.triggerCallback('onError', 'IM未初始化') - return + return { success: false, error: 'IM未初始化' } } - if (!this.conversation) { - this.triggerCallback('onError', '群聊会话不存在') - return { success: false, error: '群聊会话不存在' } + // 检查登录状态 + if (!this.isLoggedIn) { + console.error('IM未登录,无法发送消息'); + this.triggerCallback('onError', 'IM未登录,请稍后重试') + return { success: false, error: 'IM未登录' } } - let groupID = null - if (this.conversation.groupProfile && this.conversation.groupProfile.groupID) { - groupID = this.conversation.groupProfile.groupID - } else if (this.conversation.conversationID) { - groupID = this.conversation.conversationID.replace('GROUP', '') + // 优先使用 currentConversationID,如果没有则尝试从 conversation 获取 + let conversationID = this.currentConversationID; + if (!conversationID && this.conversation) { + conversationID = this.conversation.conversationID; + } + + if (!conversationID) { + console.error('会话ID不存在'); + this.triggerCallback('onError', '会话不存在,请重新进入聊天') + return { success: false, error: '会话ID不存在' } + } + + // 从 conversationID 提取 groupID + let groupID = null; + if (conversationID.startsWith('GROUP')) { + groupID = conversationID.replace('GROUP', ''); + } else if (this.conversation?.groupProfile?.groupID) { + groupID = this.conversation.groupProfile.groupID; } if (!groupID) { + console.error('无法获取群聊ID,conversationID:', conversationID); this.triggerCallback('onError', '无法获取群聊ID') return { success: false, error: '无法获取群聊ID' } } - // 确保使用当前会话的conversationID - const conversationID = this.conversation.conversationID || this.currentConversationID - const localMessage = { ID: `local_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, flow: 'out', @@ -2330,6 +2392,14 @@ class TimChatManager { } catch (error) { console.error('自定义消息发送失败:', error) localMessage.status = 'failed' + + // 如果是因为未登录导致的失败,尝试重连 + if (error.message && (error.message.includes('not login') || error.message.includes('sdk not ready'))) { + console.log('检测到未登录错误,尝试重连...'); + this.isLoggedIn = false; + this.ensureIMConnection(); + } + return { success: false, error } } } @@ -2364,7 +2434,7 @@ class TimChatManager { payload: timMessage.payload, lastTime: lastTime, status: timMessage.status || 'success', - avatar: timMessage.flow === 'in' ? '/static/home/doctor.png' : '/static/center/user-avatar.png', + avatar: timMessage.flow === 'in' ? '/static/home/avatar.svg' : '/static/center/user-avatar.png', // 优先使用消息本身的conversationID,确保消息归属正确的会话 conversationID: timMessage.conversationID } @@ -2408,12 +2478,19 @@ class TimChatManager { } getImageUrl(imageFile) { + // 处理 tempFiles 数组格式 if (imageFile?.tempFiles?.length > 0) { return imageFile.tempFiles[0].tempFilePath } + // 处理单个文件对象 + if (imageFile?.tempFilePath) { + return imageFile.tempFilePath + } + // 处理字符串路径 if (typeof imageFile === 'string') { return imageFile } + console.warn('无法获取图片URL,使用默认图片:', imageFile); return '/static/home/photo.png' } @@ -2422,17 +2499,22 @@ class TimChatManager { return new Promise((resolve) => { let imagePath = ''; - // 获取图片路径 + // 获取图片路径 - 处理多种格式 if (imageFile?.tempFiles?.length > 0) { imagePath = imageFile.tempFiles[0].tempFilePath; + } else if (imageFile?.tempFilePath) { + imagePath = imageFile.tempFilePath; } else if (typeof imageFile === 'string') { imagePath = imageFile; } else { + console.warn('无法获取图片路径,使用默认尺寸:', imageFile); // 默认尺寸 resolve({ width: 400, height: 300 }); return; } + console.log('获取图片信息,路径:', imagePath); + // 使用uni.getImageInfo获取图片尺寸 uni.getImageInfo({ src: imagePath,