diff --git a/.gitignore b/.gitignore index 683e3f5..797bf55 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,4 @@ dist /.hbuilderx/ /.idea/ /database/ +/utils/utils.js \ No newline at end of file diff --git a/pages.json b/pages.json index c66f920..ae1c6aa 100644 --- a/pages.json +++ b/pages.json @@ -475,6 +475,13 @@ "navigationBarTitleText": "转诊消息", "enablePullDownRefresh": true } + }, + { + "path": "transfer/transfer-consultation", + "style": { + "navigationBarTitleText": "转诊咨询", + "enablePullDownRefresh": false + } } ] } diff --git a/request/api/transferPrescription.js b/request/api/transferPrescription.js index 13cc7e4..cc01bf4 100644 --- a/request/api/transferPrescription.js +++ b/request/api/transferPrescription.js @@ -34,3 +34,20 @@ export async function agreeTransferPrescriptionApi(params) { export async function rejectTransferPrescriptionApi(params) { return await post('/transfer-prescription/reject', params, 3) } + +/** + * 获取转诊问题列表(用于咨询页面) + * @returns {Promise<*>} + */ +export async function getTransferQuestionsApi() { + return await get('/transfer-prescription/get-questions', {}, 3) +} + +/** + * 提交转诊问题答案 + * @param params { transfer_id: number, answers: Array<{question_id: number, answer: string}> } + * @returns {Promise<*>} + */ +export async function submitTransferQuestionsApi(params) { + return await post('/transfer-prescription/submit-questions', params, 3) +} \ No newline at end of file diff --git a/subPackages/chat/chat.vue b/subPackages/chat/chat.vue index 739a967..03627c5 100644 --- a/subPackages/chat/chat.vue +++ b/subPackages/chat/chat.vue @@ -220,6 +220,20 @@ export default { }, onLoad: function (option) { + // 确保 room_id 存在 + if (!option.room_id) { + console.error('聊天页面缺少room_id参数'); + uni.showToast({ + title: '房间ID不能为空', + icon: 'none' + }); + setTimeout(() => { + uni.navigateBack(); + }, 1500); + return; + } + + // 先设置基础信息 this.doctorUserInfo = option; if (option.avatar) this.doctorAvatar = option.avatar; this.currentUserId = 'user-' + uni.getStorageSync('user_id') || 'user-2512'; @@ -228,6 +242,7 @@ export default { if (doctorId.includes('-type-')) doctorId = doctorId.split('-type-')[0]; this.doctorId = doctorId; + // 立即进入房间并设置ChatManager(确保消息能正确路由) if (typeof ChatManager !== 'undefined') { ChatManager.enterRoom(option.room_id); ChatManager.resetUnreadCount(option.room_id); @@ -244,6 +259,8 @@ export default { const nickName = this.doctorUserInfo.nick_name; if (nickName && nickName !== 'undefined' && nickName !== 'null') { uni.setNavigationBarTitle({ title: `与${nickName}医生的对话` }); + } else { + uni.setNavigationBarTitle({ title: '与医生的对话' }); } this.$nextTick(() => { @@ -264,6 +281,15 @@ export default { }, onShow() { + // 确保房间ID已设置(从ChatManager获取,作为备用) + if (!this.doctorUserInfo.room_id && typeof ChatManager !== 'undefined') { + const currentRoomId = ChatManager.getCurrentRoomId(); + if (currentRoomId) { + this.doctorUserInfo.room_id = currentRoomId; + } + } + + // 注册事件监听器 uni.$on('new-room-message', this.handleNewRoomMessage); uni.$on('load-room-message', this.handLoadMessageList); uni.$on('no-more-history', this.handNoMessageList); @@ -279,7 +305,12 @@ export default { mounted() { this.recorderManager = uni.getRecorderManager(); this.initRecorder(); - if (typeof webSocketManager !== 'undefined') webSocketManager.addMessageHandler(this.handleSocketMessage); + // 延迟注册WebSocket消息处理器,确保onLoad已执行完成,room_id已设置 + this.$nextTick(() => { + if (typeof webSocketManager !== 'undefined') { + webSocketManager.addMessageHandler(this.handleSocketMessage); + } + }); this.calculateScrollViewHeight(); }, @@ -487,7 +518,11 @@ export default { }, handleSocketMessage(data) { - if (data.room_id === this.doctorUserInfo.room_id) { + // 获取当前房间ID(优先使用doctorUserInfo.room_id,如果未设置则从ChatManager获取) + const currentRoomId = this.doctorUserInfo.room_id || (typeof ChatManager !== 'undefined' ? ChatManager.getCurrentRoomId() : null); + + // 如果房间ID匹配,或者消息的房间ID与当前房间ID匹配,则处理消息 + if (data.room_id && (data.room_id === currentRoomId || data.room_id === this.doctorUserInfo.room_id)) { this.addMessage(data); this.scrollToBottom(); } diff --git a/subPackages/chat/components/TransferMessageBubble.vue b/subPackages/chat/components/TransferMessageBubble.vue index 0ea2140..8dd0048 100644 --- a/subPackages/chat/components/TransferMessageBubble.vue +++ b/subPackages/chat/components/TransferMessageBubble.vue @@ -27,6 +27,24 @@ 转诊原因: {{ messageData.transfer_reason }} + + + + + + 咨询问题 + + + + {{ index + 1 }}. + {{ qa.question }} + + + {{ qa.answer === '是' ? '✓' : '✗' }} + {{ qa.answer }} + + + @@ -168,4 +186,95 @@ export default { background: rgba(239, 68, 68, 0.1); color: #dc2626; } + +/* 咨询问题区域 */ +.questions-section { + margin-top: 20rpx; + padding: 20rpx; + background: rgba(255, 255, 255, 0.6); + border-radius: 12rpx; + border: 2rpx solid #fed7aa; +} + +.section-title { + display: flex; + align-items: center; + gap: 8rpx; + margin-bottom: 16rpx; + padding-bottom: 12rpx; + border-bottom: 2rpx solid #fed7aa; +} + +.section-icon { + font-size: 28rpx; +} + +.section-text { + font-size: 28rpx; + font-weight: 600; + color: #1e293b; +} + +.question-item { + margin-bottom: 16rpx; + padding: 16rpx; + background: white; + border-radius: 8rpx; + border: 1rpx solid #e2e8f0; +} + +.question-item:last-child { + margin-bottom: 0; +} + +.question-text { + font-size: 26rpx; + color: #334155; + line-height: 1.6; + margin-bottom: 12rpx; +} + +.question-number { + font-weight: 600; + color: #0A84FF; + margin-right: 8rpx; +} + +.question-content { + color: #1e293b; +} + +.answer-text { + display: flex; + align-items: center; + gap: 8rpx; + font-size: 24rpx; + font-weight: 500; + padding: 8rpx 16rpx; + border-radius: 6rpx; + width: fit-content; +} + +.answer-yes { + background: #dcfce7; + color: #16a34a; +} + +.answer-yes .answer-icon { + color: #16a34a; +} + +.answer-no { + background: #fee2e2; + color: #dc2626; +} + +.answer-no .answer-icon { + color: #dc2626; +} + +.answer-icon { + font-size: 24rpx; + font-weight: bold; +} diff --git a/subPackages/transfer/transfer-consultation.vue b/subPackages/transfer/transfer-consultation.vue new file mode 100644 index 0000000..c57c275 --- /dev/null +++ b/subPackages/transfer/transfer-consultation.vue @@ -0,0 +1,639 @@ + + + + + diff --git a/subPackages/transfer/transfer-message.vue b/subPackages/transfer/transfer-message.vue index 777974a..53305ac 100644 --- a/subPackages/transfer/transfer-message.vue +++ b/subPackages/transfer/transfer-message.vue @@ -168,11 +168,21 @@ export default { const response = await agreeTransferPrescriptionApi({ id: item.id }) if (response.data.code === 0) { uni.showToast({ title: '已同意', icon: 'success' }) - this.getTransferList() + // 跳转到咨询页面,直接使用transfer_id传参 + setTimeout(() => { + uni.redirectTo({ + url: `/subPackages/transfer/transfer-consultation?transfer_id=${item.id}`, + fail: (err) => { + console.error('跳转失败:', err) + uni.showToast({ title: '跳转失败,请重试', icon: 'none' }) + } + }) + }, 1000) } else { uni.showToast({ title: response.data.message, icon: 'none' }) } } catch (e) { + console.error('同意转诊异常:', e) uni.showToast({ title: '操作失败', icon: 'none' }) } } diff --git a/utils/ws/websocket.js b/utils/ws/websocket.js index 77646a5..0a13ba9 100644 --- a/utils/ws/websocket.js +++ b/utils/ws/websocket.js @@ -38,6 +38,7 @@ export class WebSocketManager { /** * 重新绑定用户(登录后调用) + * 会先清理旧连接,再绑定新连接 */ rebindUser() { const userId = uni.getStorageSync('user_id'); @@ -50,12 +51,13 @@ export class WebSocketManager { this.clearCachedToken(); if (this.isConnected) { - // 如果已连接,直接绑定 - return this.bindUser(userId); + // 如果已连接,直接bind(Go后端会自动清理旧连接) + // 注意:不在这里调用unbind,因为unbind会关闭当前连接 + return this.bindUser(userId, true); } else { // 如果未连接,先连接再绑定 this.connect(); - // 连接成功后会在 onOpen 中自动绑定 + // 连接成功后会在 onOpen 中自动绑定(会自动清理旧连接) return true; } } @@ -86,7 +88,8 @@ export class WebSocketManager { // 绑定当前用户(使用正确的key:user_id) const userId = uni.getStorageSync('user_id'); if (userId) { - this.bindUser(userId); + // 连接打开后立即绑定,Go后端会自动清理旧连接 + this.bindUser(userId, true); } }); @@ -113,20 +116,56 @@ export class WebSocketManager { } /** - * 绑定用户(携带token进行认证) - * @param {string} userId 用户ID + * 解绑用户(清理旧连接) + * 注意:此方法会关闭当前连接,只应在需要完全断开时使用 + * @param {string} userId 用户ID(格式:user-xxx 或 数字) + * @returns {boolean} 是否发送成功 */ - bindUser(userId) { + unbindUser(userId) { + const token = this.getToken(); + if (!token) { + console.warn('解绑用户失败:token不存在,跳过解绑'); + return false; + } + // 确保userId格式正确(如果是数字,添加user-前缀) + const normalizedUserId = userId.toString().startsWith('user-') ? userId : `user-${userId}`; + console.log('发送unbind请求,清理旧连接:', normalizedUserId); + return this.send({ + request_type: 'unbind', + user_type: 'user', + sender_user_id: normalizedUserId, + token: token + }, false); // unbind不需要再次添加token + } + + /** + * 绑定用户(携带token进行认证) + * 在绑定前会自动清理旧连接(通过Go后端的clean_old_connections功能) + * @param {string} userId 用户ID(可以是数字或user-xxx格式) + * @param {boolean} cleanOldConnections 是否清理旧连接(默认true) + */ + bindUser(userId, cleanOldConnections = true) { const token = this.getToken(); if (!token) { console.error('绑定用户失败:token不存在'); return false; } + + // 确保userId格式正确(统一为user-xxx格式) + // 如果userId已经是user-xxx格式,保持不变;如果是数字,添加user-前缀 + const normalizedUserId = userId.toString().startsWith('user-') ? userId : `user-${userId}`; + + // 注意:不在bind前发送unbind,因为unbind会关闭当前连接 + // 清理旧连接的工作交给Go后端的clean_old_connections功能处理 + + // 发送bind请求,添加clean_old_connections标志告诉Go后端清理旧连接 + console.log('发送bind请求,绑定新连接:', normalizedUserId, 'cleanOldConnections:', cleanOldConnections); return this.send({ request_type: 'bind', user_type: 'user', - sender_user_id: userId, - token: token + sender_user_id: normalizedUserId, + token: token, + clean_old_connections: cleanOldConnections // 告诉Go后端清理旧连接 }); } @@ -199,11 +238,14 @@ export class WebSocketManager { this.getUserIdAndBindClientId(); }, 5000) } else { + // 直接发送bind请求,Go后端会自动清理旧连接 + // 注意:不在这里调用unbind,因为unbind会关闭当前连接 const bindMessage = { request_type: 'bind', user_type: 'user', sender_user_id: `user-${userId}`, - token: token + token: token, + clean_old_connections: true // 告诉Go后端清理旧连接 }; this.send(bindMessage); } @@ -227,7 +269,7 @@ export class WebSocketManager { this.cachedToken = null; // 通知应用层token过期 uni.$emit('ws-token-expired'); - // 尝试重新绑定 + // 尝试重新绑定(会自动清理旧连接) this.getUserIdAndBindClientId(); } return;