ykt-wxapp/pages/message/index.vue
2026-02-12 11:44:28 +08:00

1189 lines
34 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="chat-page">
<!-- 患者信息栏 -->
<view class="patient-info-bar" v-if="patientInfo.name">
<view class="patient-info-content">
<view class="patient-basic-info">
<text class="patient-name">{{ patientInfo.name }}</text>
<text class="patient-detail"
>{{ patientInfo.sex }} · {{ patientInfo.age }}</text
>
</view>
<view class="patient-detail-btn" @click="handleViewPatientDetail">
<text class="detail-btn-text">查看档案</text>
</view>
</view>
</view>
<!-- 聊天消息区域 -->
<scroll-view
class="chat-content"
scroll-y="true"
enhanced="true"
bounces="false"
:scroll-into-view="scrollIntoView"
@scroll="onScroll"
@scrolltoupper="handleScrollToUpper"
ref="chatScrollView"
>
<!-- 加载更多提示 -->
<view class="load-more-tip" v-if="messageList.length >= 15">
<view class="loading" v-if="isLoadingMore">
<text class="loading-text">加载中...</text>
</view>
<view class="load-tip" v-else-if="!isCompleted">
<text class="tip-text"> 上滑加载更多</text>
</view>
<view class="load-tip" v-else>
<text class="completed-text">已加载全部消息</text>
</view>
</view>
<!-- 聊天消息列表 -->
<view class="message-list" @click="closeMorePanel">
<view
v-for="(message, index) in messageList"
:key="message.ID"
:id="`msg-${message.ID}`"
class="message-item"
:class="{
'message-right': message.flow === 'out',
'message-left': message.flow === 'in',
}"
>
<!-- 时间分割线 -->
<view
v-if="shouldShowTime(message, index, messageList)"
class="time-divider"
>
<text class="time-text">{{ formatTime(message.lastTime) }}</text>
</view>
<view v-if="isSystemMessage(message)">
<SystemMessage :message="message" />
</view>
<!-- 消息内容 -->
<view v-else class="message-content">
<image
v-if="message.flow === 'in'"
class="doctor-msg-avatar"
:src="getUserAvatar(message.from)"
mode="aspectFill"
/>
<image
v-if="message.flow === 'out'"
class="user-msg-avatar"
:src="getUserAvatar(message.from)"
mode="aspectFill"
/>
<!-- 消息内容区域 -->
<view class="message-bubble-container">
<!-- 用户名显示 -->
<view
class="username-label"
:class="{
left: message.flow === 'in',
right: message.flow === 'out',
}"
>
<text class="username-text">{{
chatMember[message.from]?.name
}}</text>
</view>
<view class="message-bubble" :class="getBubbleClass(message)">
<!-- 消息内容 -->
<MessageTypes
:message="message"
:formatTime="formatTime"
:playingVoiceId="playingVoiceId"
@playVoice="playVoice"
@previewImage="previewImage"
@viewDetail="(message) => handleViewDetail(message)"
/>
</view>
</view>
<!-- 发送状态 -->
<view v-if="message.flow === 'out'" class="message-status">
<text
v-if="message.status === 'failed'"
class="status-text failed"
>发送失败</text
>
</view>
</view>
</view>
</view>
</scroll-view>
<!-- 接受问诊组件 -->
<ConsultAccept
v-if="showConsultAccept"
@accept="handleAcceptConsult"
@reject="handleRejectConsult"
/>
<!-- 拒绝原因对话框 -->
<RejectReasonModal
:visible="showRejectReasonModal"
@confirm="handleRejectReasonConfirm"
@cancel="handleRejectReasonCancel"
/>
<!-- 聊天输入组件 -->
<ChatInput
v-if="!isEvaluationPopupOpen && !showConsultAccept"
ref="chatInputRef"
:timChatManager="timChatManager"
:formatTime="formatTime"
:groupId="
chatInfo.conversationID
? chatInfo.conversationID.replace('GROUP', '')
: ''
"
:userId="openid"
:teamId="teamId"
:patientId="patientId"
:corpId="corpId"
:patientInfo="patientInfo"
:orderStatus="orderStatus"
:isGenerating="isGenerating"
@scrollToBottom="() => scrollToBottom(true)"
@messageSent="() => scrollToBottom(true)"
@endConsult="handleEndConsult"
@openConsult="handleOpenConsult"
>
<!-- AI助手按钮组插槽 -->
<template #ai-assistant>
<AIAssistantButtons
v-if="orderStatus === 'processing'"
ref="aiAssistantRef"
:groupId="groupId"
:patientAccountId="chatInfo.userID || ''"
:patientId="patientId"
:corpId="corpId"
@streamText="handleStreamText"
@clearInput="handleClearInput"
@generatingStateChange="handleGeneratingStateChange"
/>
</template>
</ChatInput>
</view>
</template>
<script setup>
import { ref, onUnmounted, nextTick, watch, computed } from "vue";
import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
import { storeToRefs } from "pinia";
import useAccountStore from "@/store/account.js";
import { globalTimChatManager } from "@/utils/tim-chat.js";
import { handleFollowUpMessages } from "@/utils/send-message-helper";
import {
startIMMonitoring,
stopIMMonitoring,
} from "@/utils/im-status-manager.js";
import {
getVoiceUrl,
validateVoiceUrl,
createAudioContext,
showMessage,
formatTime,
shouldShowTime,
previewImage,
throttle,
clearMessageCache,
handleViewDetail,
checkIMConnectionStatus,
} from "@/utils/chat-utils.js";
import api 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";
import AIAssistantButtons from "./components/ai-assistant-buttons.vue";
const timChatManager = globalTimChatManager;
const PENDING_FOLLOWUP_SEND_STORAGE_KEY = "ykt_followup_pending_send";
const pendingFollowUpSendConsumed = ref(false);
const initialMessageListLoaded = ref(false);
const isCallbacksInitialized = ref(false); // 标记回调是否已初始化
function normalizeGroupId(v) {
const s = String(v || "").trim();
if (!s) return "";
return s.startsWith("GROUP") ? s.slice(5) : s;
}
async function tryConsumePendingFollowUpSend() {
if (pendingFollowUpSendConsumed.value) return;
// 等待 IM 就绪与首屏消息加载完成,避免发送的本地消息被列表回调覆盖
if (!timChatManager?.isLoggedIn) return;
if (!initialMessageListLoaded.value) return;
const raw = uni.getStorageSync(PENDING_FOLLOWUP_SEND_STORAGE_KEY);
const payload = raw && typeof raw === "object" ? raw : null;
if (!payload) return;
const createdAt = Number(payload.createdAt || 0) || 0;
// 过期就清理,避免误发送
if (createdAt && Date.now() - createdAt > 5 * 60 * 1000) {
uni.removeStorageSync(PENDING_FOLLOWUP_SEND_STORAGE_KEY);
return;
}
const payloadConversationID = String(payload.conversationID || "");
const payloadGroupId = normalizeGroupId(payload.groupId || "");
const currentConversationID = String(chatInfo.value.conversationID || "");
const currentGroupId = normalizeGroupId(groupId.value || "");
// 必须匹配当前会话,才允许发送
if (!payloadConversationID || payloadConversationID !== currentConversationID)
return;
if (payloadGroupId && currentGroupId && payloadGroupId !== currentGroupId)
return;
const messages = Array.isArray(payload.messages) ? payload.messages : [];
const context =
payload.context && typeof payload.context === "object"
? payload.context
: {};
if (!messages.length) {
uni.removeStorageSync(PENDING_FOLLOWUP_SEND_STORAGE_KEY);
return;
}
pendingFollowUpSendConsumed.value = true;
// 先清理再发,避免页面重复初始化导致二次发送
uni.removeStorageSync(PENDING_FOLLOWUP_SEND_STORAGE_KEY);
await nextTick();
const ok = await handleFollowUpMessages(messages, context);
if (ok) {
uni.showToast({ title: "消息已发送", icon: "success" });
} else {
uni.showToast({ title: "部分发送失败", icon: "none" });
}
}
// 获取环境变量
const env = __VITE_ENV__;
const corpId = env.MP_CORP_ID || "";
// 获取登录状态
const { account, openid, isIMInitialized } = storeToRefs(useAccountStore());
const { initIMAfterLogin } = useAccountStore();
// 聊天输入组件引用
const chatInputRef = ref(null);
const aiAssistantRef = ref(null);
const isGenerating = ref(false);
const groupId = ref("");
const { chatMember, getGroupInfo, getUserAvatar } = useGroupChat(groupId);
// 动态设置导航栏标题
const updateNavigationTitle = (title = "群聊") => {
uni.setNavigationBarTitle({
title: title,
});
};
// 聊天信息
const chatInfo = ref({
conversationID: "",
userID: "",
avatar: "/static/home/avatar.svg",
});
// 评价弹窗状态
const isEvaluationPopupOpen = ref(false);
// 订单状态
const orderStatus = ref("");
// 患者信息
const patientInfo = ref({
name: "",
sex: "",
age: "",
mobile: "",
});
// 患者ID
const patientId = ref("");
const teamId = ref("");
// 计算弹框显示状态 - 只有 pending 状态才显示接受问诊组件
const showConsultAccept = computed(() => orderStatus.value === "pending");
// 拒绝原因对话框状态
const showRejectReasonModal = ref(false);
// 消息列表相关状态
const messageList = ref([]);
const isLoading = ref(false);
const scrollIntoView = ref("");
// 分页加载相关状态
const isLoadingMore = ref(false);
const isCompleted = ref(false);
const lastFirstMessageId = ref("");
// 判断是否为系统消息
function isSystemMessage(message) {
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;
}
// 获取群组订单状态
const fetchGroupOrderStatus = async () => {
try {
const result = await api("getGroupListByGroupId", {
groupId: groupId.value,
});
if (result.success && result.data) {
orderStatus.value = result.data.orderStatus || "";
// 更新导航栏标题为团队名称
const teamName = result.data.team?.name || "群聊";
updateNavigationTitle(teamName);
teamId.value =
result.data.teamId ||
result.data.team?.teamId ||
result.data.team?._id ||
"";
// 更新患者信息
if (result.data.patient) {
patientInfo.value = {
name: result.data.patient.name || "",
sex: result.data.patient.sex || "",
age: result.data.patient.age || "",
mobile: result.data.patient.mobile || "",
};
}
// 更新患者ID
if (result.data.patientId) {
patientId.value = result.data.patientId.toString();
}
console.log("获取群组订单状态:", {
orderStatus: orderStatus.value,
teamName: teamName,
patientInfo: patientInfo.value,
groupId: groupId.value,
});
} else {
console.error("获取群组订单状态失败:", result.message);
}
} catch (error) {
console.error("获取群组订单状态异常:", error);
}
};
// 获取消息气泡样式类
function getBubbleClass(message) {
// 图片消息不需要气泡背景
if (message.type === "TIMImageElem") {
return "image-bubble";
}
if (message.type === "TIMCustomElem") {
return message.flow === "out" ? "" : "";
}
return message.flow === "out" ? "user-bubble" : "doctor-bubble";
}
// 页面加载
onLoad((options) => {
const decodeQueryValue = (v) => {
const s = typeof v === "string" ? v : String(v || "");
if (!s) return "";
try {
return decodeURIComponent(s);
} catch (e) {
return s;
}
};
const rawGroupId = decodeQueryValue(options.groupID || "");
groupId.value = rawGroupId.startsWith("GROUP")
? rawGroupId.replace(/^GROUP/, "")
: rawGroupId;
messageList.value = [];
isLoading.value = false;
if (options.conversationID) {
const cid = decodeQueryValue(options.conversationID);
chatInfo.value.conversationID = cid;
timChatManager.setConversationID(cid);
console.log("设置当前会话ID:", cid);
}
if (options.userID) {
chatInfo.value.userID = decodeQueryValue(options.userID);
}
checkLoginAndInitTIM();
updateNavigationTitle();
});
// 检查登录状态并初始化IM
const checkLoginAndInitTIM = async () => {
if (!isIMInitialized.value) {
uni.showLoading({
title: "连接中...",
});
const success = await initIMAfterLogin();
uni.hideLoading();
// if (!success) {
// uni.showToast({
// title: "IM连接失败请重试",
// icon: "none",
// });
// return;
// }
} else if (!timChatManager.isLoggedIn) {
uni.showLoading({
title: "重连中...",
});
const reconnected = await timChatManager.ensureIMConnection();
uni.hideLoading();
if (!reconnected) {
return;
}
}
initTIMCallbacks();
};
// 初始化IM回调函数
const initTIMCallbacks = async () => {
// 标记回调已初始化
isCallbacksInitialized.value = true;
timChatManager.setCallback("onSDKReady", () => {
if (messageList.value.length === 0 && !isLoading.value) {
loadMessageList();
}
});
timChatManager.setCallback("onSDKNotReady", () => {});
timChatManager.setCallback("onMessageReceived", (message) => {
console.log("页面收到消息:", {
messageID: message.ID,
conversationID: message.conversationID,
currentConversationID: chatInfo.value.conversationID,
type: message.type,
flow: message.flow,
});
// 验证消息属于当前群聊
if (message.conversationID !== chatInfo.value.conversationID) {
console.log("⚠️ 消息不属于当前群聊,已过滤");
return;
}
// 检查消息是否已存在
const existingMessage = messageList.value.find(
(msg) => msg.ID === message.ID
);
if (!existingMessage) {
messageList.value.push(message);
console.log("✓ 添加消息到列表,当前消息数量:", messageList.value.length);
// 如果是系统消息,重新获取订单状态
if (isSystemMessage(message)) {
fetchGroupOrderStatus();
}
// 立即滚动到底部,不使用延迟
nextTick(() => {
scrollToBottom(true);
});
// 立即标记会话为已读确保未读数为0
if (
timChatManager.tim &&
timChatManager.isLoggedIn &&
chatInfo.value.conversationID
) {
timChatManager.tim
.setMessageRead({
conversationID: chatInfo.value.conversationID,
})
.then(() => {
console.log("✓ 收到新消息后已标记为已读");
})
.catch((error) => {
console.error("✗ 标记已读失败:", error);
});
}
}
});
timChatManager.setCallback("onMessageSent", (data) => {
const { messageID, status } = data;
const message = messageList.value.find((msg) => msg.ID === messageID);
if (message) {
message.status = status;
console.log("更新消息状态:", messageID, status);
}
});
timChatManager.setCallback("onMessageListLoaded", (data) => {
console.log("【onMessageListLoaded】收到消息列表回调");
uni.hideLoading();
let messages = [];
if (typeof data === "object" && data.messages) {
messages = data.messages;
} else {
messages = data;
}
isLoading.value = false;
// 去重处理 + 严格过滤当前群聊的消息
const uniqueMessages = [];
const seenIds = new Set();
messages.forEach((message) => {
const belongsToCurrentConversation =
message.conversationID === chatInfo.value.conversationID;
if (
message.ID &&
!seenIds.has(message.ID) &&
belongsToCurrentConversation
) {
seenIds.add(message.ID);
uniqueMessages.push(message);
}
});
// 合并现有 messageList避免首屏加载覆盖刚发送的本地消息
const merged = [];
const mergedSeen = new Set();
const existing = Array.isArray(messageList.value) ? messageList.value : [];
for (const m of existing) {
if (!m || !m.ID) continue;
if (m.conversationID !== chatInfo.value.conversationID) continue;
if (mergedSeen.has(m.ID)) continue;
mergedSeen.add(m.ID);
merged.push(m);
}
for (const m of uniqueMessages) {
if (!m || !m.ID) continue;
if (mergedSeen.has(m.ID)) continue;
mergedSeen.add(m.ID);
merged.push(m);
}
merged.sort((a, b) => {
const ta = Number(a?.lastTime || a?.time || 0) || 0;
const tb = Number(b?.lastTime || b?.time || 0) || 0;
return ta - tb;
});
messageList.value = merged;
console.log(
"消息列表已更新,原始",
messages.length,
"条,过滤后",
messageList.value.length,
"条消息"
);
if (!data.isPullUp && !data.isRefresh) {
initialMessageListLoaded.value = true;
// 首屏加载完成后再尝试消费待发送 payload
tryConsumePendingFollowUpSend();
}
isCompleted.value = data.isCompleted || false;
isLoadingMore.value = false;
nextTick(() => {
if (data.isRefresh) {
console.log("后台刷新完成,保持当前滚动位置");
return;
}
if (data.isPullUp && lastFirstMessageId.value) {
console.log(
"上拉加载完成,定位到加载前的第一条消息:",
lastFirstMessageId.value
);
setTimeout(() => {
scrollIntoView.value = `msg-${lastFirstMessageId.value}`;
lastFirstMessageId.value = "";
}, 100);
return;
}
if (!data.isPullUp) {
setTimeout(() => {
scrollToBottom();
setTimeout(() => {
scrollToBottom();
}, 100);
}, 200);
}
});
});
timChatManager.setCallback("onError", (error) => {
console.error("TIM错误:", error);
uni.showToast({
title: error,
icon: "none",
});
});
nextTick(() => {
if (timChatManager.tim && timChatManager.isLoggedIn) {
setTimeout(() => {
loadMessageList();
}, 50);
} else if (timChatManager.tim) {
let checkCount = 0;
const checkInterval = setInterval(() => {
checkCount++;
if (timChatManager.isLoggedIn) {
clearInterval(checkInterval);
loadMessageList();
} else if (checkCount > 10) {
clearInterval(checkInterval);
showMessage("IM登录超时请重新进入");
}
}, 1000);
}
});
};
// 加载消息列表
const loadMessageList = async () => {
if (isLoading.value) {
console.log("正在加载中,跳过重复加载");
return;
}
console.log(
"【loadMessageList】开始加载消息会话ID:",
chatInfo.value.conversationID
);
isLoading.value = true;
uni.showLoading({
title: "加载中...",
mask: false,
});
// 获取群组订单状态
await fetchGroupOrderStatus();
timChatManager.enterConversation(chatInfo.value.conversationID || "test1");
// 若从病历回访记录带入待发送内容,则进入会话后自动发送
tryConsumePendingFollowUpSend();
// 标记会话为已读 - 确保清空未读数
if (
timChatManager.tim &&
timChatManager.isLoggedIn &&
chatInfo.value.conversationID
) {
console.log("标记会话为已读:", chatInfo.value.conversationID);
timChatManager.tim
.setMessageRead({
conversationID: chatInfo.value.conversationID,
})
.then(() => {
console.log("✓ 会话已标记为已读:", chatInfo.value.conversationID);
})
.catch((error) => {
console.error("✗ 标记会话已读失败:", error);
});
}
};
// 语音播放相关
let currentAudioContext = null;
const playingVoiceId = ref(null);
// 播放语音
const playVoice = (message) => {
if (playingVoiceId.value === message.ID && currentAudioContext) {
currentAudioContext.stop();
currentAudioContext.destroy();
currentAudioContext = null;
playingVoiceId.value = null;
return;
}
if (currentAudioContext) {
currentAudioContext.stop();
currentAudioContext.destroy();
currentAudioContext = null;
}
const voiceUrl = getVoiceUrl(message);
if (!validateVoiceUrl(voiceUrl)) return;
playingVoiceId.value = message.ID;
currentAudioContext = createAudioContext(voiceUrl);
currentAudioContext.onEnded(() => {
currentAudioContext = null;
playingVoiceId.value = null;
});
currentAudioContext.onError(() => {
currentAudioContext = null;
playingVoiceId.value = null;
});
currentAudioContext.play();
};
// 滚动到底部
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 = "";
nextTick(() => {
scrollIntoView.value = targetId;
});
} else {
// 正常滚动使用短延迟确保DOM更新
scrollIntoView.value = "";
setTimeout(() => {
scrollIntoView.value = targetId;
}, 50);
}
}
};
// 关闭功能栏
const closeMorePanel = () => {
uni.$emit("closeMorePanel");
};
// 滚动事件
const onScroll = throttle((e) => {
// 滚动处理
}, 100);
// 处理上滑加载更多
const handleScrollToUpper = async () => {
console.log("【handleScrollToUpper】触发上滑事件准备加载更多");
console.log(
" 当前状态: isLoadingMore=",
isLoadingMore.value,
"isCompleted=",
isCompleted.value
);
if (isLoadingMore.value || isCompleted.value) {
console.log(
" ⏭️ 跳过加载isLoadingMore=",
isLoadingMore.value,
"isCompleted=",
isCompleted.value
);
return;
}
if (messageList.value.length < 15) {
console.log(" ⏭️ 消息数量不足15条跳过加载更多");
return;
}
if (messageList.value.length > 0) {
lastFirstMessageId.value = messageList.value[0].ID;
console.log(" 📍 记录当前第一条消息ID:", lastFirstMessageId.value);
}
isLoadingMore.value = true;
try {
console.log(" 📡 调用 timChatManager.loadMoreMessages()");
const result = await timChatManager.loadMoreMessages();
console.log(" 📥 加载结果:", result);
if (result.success) {
console.log(` ✅ 加载更多成功,新增 ${result.count} 条消息`);
} else {
console.log(" ⚠️ 加载失败:", result.message || result.error);
if (result.message === "已加载全部消息") {
console.log(" ✅ 已加载全部消息");
isCompleted.value = true;
}
}
} catch (error) {
console.error(" ❌ 加载更多失败:", error);
uni.showToast({
title: "加载失败,请重试",
icon: "none",
});
} finally {
isLoadingMore.value = false;
console.log(" 🏁 加载完成isLoadingMore 设置为 false");
}
};
// 页面显示
onShow(() => {
if (!account.value || !openid.value) {
uni.redirectTo({
url: "/pages-center/login/login",
});
return;
}
if (!isIMInitialized.value) {
checkLoginAndInitTIM();
} else if (timChatManager.tim && !timChatManager.isLoggedIn) {
// IM未登录尝试重连
timChatManager.ensureIMConnection().then(() => {
// 重连成功后重新注册回调
if (timChatManager.isLoggedIn && chatInfo.value.conversationID) {
console.log("✓ 重连成功,重新注册消息监听回调");
initTIMCallbacks();
timChatManager.setConversationID(chatInfo.value.conversationID);
}
});
} else if (
timChatManager.tim &&
timChatManager.isLoggedIn &&
chatInfo.value.conversationID
) {
// IM已登录只需要重新设置会话ID不重新注册回调避免影响正在发送的消息
console.log("✓ 页面显示重新设置当前会话ID");
timChatManager.setConversationID(chatInfo.value.conversationID);
// 如果回调未初始化,才进行初始化
if (!isCallbacksInitialized.value) {
console.log("✓ 回调未初始化,进行初始化");
initTIMCallbacks();
}
// 标记会话为已读
if (timChatManager.tim && timChatManager.isLoggedIn) {
timChatManager.tim
.setMessageRead({
conversationID: chatInfo.value.conversationID,
})
.then(() => {
console.log("✓ 页面显示时已标记会话为已读");
})
.catch((error) => {
console.error("✗ 标记会话已读失败:", error);
});
}
startIMMonitoring(30000);
}
// 监听回访任务发送事件
uni.$on("send-followup-message", handleSendFollowUpMessage);
});
// 处理发送回访任务消息
const handleSendFollowUpMessage = async (data) => {
try {
if (chatInputRef.value) {
// 将回访计划内容设置到输入框
chatInputRef.value.setInputText(data.content);
// 延迟后自动发送
setTimeout(() => {
if (chatInputRef.value) {
chatInputRef.value.sendTextMessageFromPhrase(data.content);
}
}, 100);
}
} catch (error) {
console.error("发送回访任务消息失败:", error);
uni.showToast({
title: "发送失败,请重试",
icon: "none",
});
}
};
// 页面隐藏
onHide(() => {
stopIMMonitoring();
// 清空当前会话ID避免离开页面后收到的消息被错误标记为已读
timChatManager.currentConversationID = null;
console.log("✓ 页面隐藏已清空当前会话ID");
});
const sendCommonPhrase = (content) => {
if (chatInputRef.value) {
// 覆盖输入框内容,而不是直接发送
chatInputRef.value.setInputText(content);
}
};
// 处理流式文本输入
const handleStreamText = (char) => {
if (chatInputRef.value) {
chatInputRef.value.appendStreamText(char);
}
};
// 处理清空输入框
const handleClearInput = () => {
if (chatInputRef.value) {
chatInputRef.value.clearInputText();
}
};
// 处理生成状态变化
const handleGeneratingStateChange = (generating) => {
isGenerating.value = generating;
};
// 暴露方法给常用语页面调用
defineExpose({
sendCommonPhrase,
});
// 处理接受问诊
const handleAcceptConsult = async () => {
try {
uni.showLoading({
title: "处理中...",
});
// 调用后端接口接受问诊
const result = await api("acceptConsultation", {
groupId: groupId.value,
adminAccount: account.value?.userId || "",
extraData: {
acceptedBy: account.value?.userId || "",
acceptedByName: account.value?.name || "医生",
},
});
uni.hideLoading();
if (result.success) {
// 重新获取订单状态
await fetchGroupOrderStatus();
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 handleRejectConsult = () => {
// 显示拒绝原因选择对话框
showRejectReasonModal.value = true;
};
// 处理拒绝原因确认
const handleRejectReasonConfirm = async (reason) => {
try {
showRejectReasonModal.value = false;
uni.showLoading({
title: "处理中...",
});
// 获取医生信息
const memberName = account.value?.name || "医生";
// 获取群组ID
const currentGroupId = chatInfo.value.conversationID.replace("GROUP", "");
// 调用后端接口发送拒绝消息
const result = await api("rejectConsultation", {
groupId: currentGroupId,
memberName,
reason,
});
uni.hideLoading();
if (result.success) {
// 重新获取订单状态
await fetchGroupOrderStatus();
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 handleViewPatientDetail = () => {
if (!patientId.value) {
uni.showToast({
title: "患者信息不完整",
icon: "none",
});
return;
}
uni.navigateTo({
url: `/pages/case/archive-detail?id=${patientId.value}`,
});
};
// 处理结束问诊
const handleEndConsult = async () => {
try {
uni.showLoading({
title: "处理中...",
});
// 调用结束问诊接口,直接传入 groupId
const result = await api("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",
});
}
};
// 处理开启会话
const handleOpenConsult = async () => {
try {
uni.showLoading({
title: "处理中...",
});
// 调用开启会话接口
const result = await api("openConsultation", {
groupId: groupId.value,
adminAccount: account.value?.userId || "",
extraData: {
openedBy: account.value?.userId || "",
openedByName: account.value?.name || "医生",
openReason: "重新开启会话",
},
});
uni.hideLoading();
if (result.success) {
// 重新获取订单状态
await fetchGroupOrderStatus();
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();
timChatManager.setCallback("onSDKReady", null);
timChatManager.setCallback("onSDKNotReady", null);
timChatManager.setCallback("onMessageReceived", null);
timChatManager.setCallback("onMessageListLoaded", null);
timChatManager.setCallback("onError", null);
// 移除回访任务发送事件监听
uni.$off("send-followup-message", handleSendFollowUpMessage);
});
</script>
<style scoped lang="scss">
@import "./chat.scss";
</style>