1084 lines
31 KiB
Vue
Raw Normal View History

2026-01-28 13:38:05 +08:00
<template>
2026-02-11 17:46:30 +08:00
<page-meta
:page-style="'overflow:' + (keyboardHeight > 0 ? 'hidden' : 'visible')"
></page-meta>
2026-02-11 14:38:28 +08:00
<view class="chat-page" :style="{ paddingBottom: keyboardHeight + 'px' }">
2026-02-03 11:20:32 +08:00
<!-- 患者信息栏 -->
<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>
2026-02-10 16:41:07 +08:00
<view
class="status-badge"
:class="chatStatusInfo.badgeClass"
v-if="chatStatusInfo.badgeText"
>
2026-02-03 11:20:32 +08:00
<text class="badge-text">{{ chatStatusInfo.badgeText }}</text>
</view>
</view>
</view>
2026-01-28 13:38:05 +08:00
<!-- 聊天消息区域 -->
<scroll-view
class="chat-content"
2026-02-11 17:46:30 +08:00
:style="{
bottom: (keyboardHeight > 0 ? keyboardHeight + 60 : 60) + 'px',
}"
2026-01-28 13:38:05 +08:00
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">
2026-02-03 11:20:32 +08:00
<!-- 发送者头像统一处理 -->
2026-01-28 13:38:05 +08:00
<image
v-if="message.flow === 'in'"
class="doctor-msg-avatar"
2026-02-03 11:20:32 +08:00
:src="getUserAvatar(message.from)"
2026-01-28 13:38:05 +08:00
mode="aspectFill"
/>
2026-02-03 11:20:32 +08:00
<!-- 发送者头像统一处理 -->
2026-01-28 13:38:05 +08:00
<image
v-if="message.flow === 'out'"
class="user-msg-avatar"
2026-02-03 11:20:32 +08:00
:src="getUserAvatar(message.from)"
2026-01-28 13:38:05 +08:00
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
2026-02-10 17:13:02 +08:00
:corpId="corpId"
2026-01-28 13:38:05 +08:00
: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>
<!-- 取消申请组件 -->
2026-01-28 14:01:24 +08:00
<ConsultCancel v-if="showConsultCancel" @cancel="handleCancelConsult" />
2026-01-28 13:38:05 +08:00
2026-01-28 16:20:19 +08:00
<!-- 咨询申请组件 -->
<ConsultApply v-if="showConsultApply" @apply="handleApplyConsult" />
2026-01-28 13:38:05 +08:00
<!-- 聊天输入组件 -->
<ChatInput
2026-01-28 16:20:19 +08:00
v-if="!isEvaluationPopupOpen && !showConsultCancel && !showConsultApply"
2026-01-28 13:38:05 +08:00
ref="chatInputRef"
:timChatManager="timChatManager"
:formatTime="formatTime"
2026-01-28 14:01:24 +08:00
:groupId="
chatInfo.conversationID
? chatInfo.conversationID.replace('GROUP', '')
: ''
"
2026-01-28 13:38:05 +08:00
:userId="openid"
2026-01-28 16:20:19 +08:00
:corpId="corpId.value"
2026-02-11 15:21:05 +08:00
:keyboardHeight="keyboardHeight"
2026-01-28 13:38:05 +08:00
@scrollToBottom="() => scrollToBottom(true)"
@messageSent="() => scrollToBottom(true)"
/>
</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";
2026-02-11 09:51:02 +08:00
import { globalUnreadListenerManager } from "@/utils/global-unread-listener.js";
2026-01-28 13:38:05 +08:00
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 ConsultCancel from "./components/consult-cancel.vue";
2026-01-28 16:20:19 +08:00
import ConsultApply from "./components/consult-apply.vue";
2026-01-28 13:38:05 +08:00
const timChatManager = globalTimChatManager;
2026-01-28 16:20:19 +08:00
// corpId 从群组信息中获取
const corpId = ref("");
2026-01-28 13:38:05 +08:00
// 获取登录状态
const { account, openid, isIMInitialized } = storeToRefs(useAccountStore());
const { initIMAfterLogin } = useAccountStore();
// 聊天输入组件引用
const chatInputRef = ref(null);
const groupId = ref("");
2026-02-03 11:20:32 +08:00
const { chatMember, getGroupInfo, getUserAvatar } = useGroupChat(groupId);
2026-01-28 13:38:05 +08:00
// 动态设置导航栏标题
2026-02-03 11:20:32 +08:00
const updateNavigationTitle = (title = "群聊") => {
2026-01-28 13:38:05 +08:00
uni.setNavigationBarTitle({
2026-02-03 11:20:32 +08:00
title: title,
2026-01-28 13:38:05 +08:00
});
};
// 聊天信息
const chatInfo = ref({
conversationID: "",
userID: "",
avatar: "/static/home/avatar.svg",
});
2026-02-11 14:38:28 +08:00
// 键盘高度
const keyboardHeight = ref(0);
2026-01-28 13:38:05 +08:00
// 评价弹窗状态
const isEvaluationPopupOpen = ref(false);
2026-01-28 16:20:19 +08:00
// 订单状态
const orderStatus = ref("");
2026-02-03 11:20:32 +08:00
// 患者信息
const patientInfo = ref({
name: "",
sex: "",
age: "",
mobile: "",
});
// 患者ID
const patientId = ref("");
// 聊天状态信息
const chatStatusInfo = ref({
show: false,
title: "",
detail: "",
badgeText: "",
badgeClass: "",
});
2026-01-28 16:20:19 +08:00
// 计算弹框显示状态
const showConsultCancel = computed(() => orderStatus.value === "pending");
const showConsultApply = computed(
() =>
orderStatus.value === "finished" ||
orderStatus.value === "cancelled" ||
2026-02-06 17:36:25 +08:00
orderStatus.value === "consult_ended"
2026-01-28 16:20:19 +08:00
);
2026-01-28 13:38:05 +08:00
// 消息列表相关状态
const messageList = ref([]);
const isLoading = ref(false);
const scrollIntoView = ref("");
// 分页加载相关状态
const isLoadingMore = ref(false);
const isCompleted = ref(false);
const lastFirstMessageId = ref("");
2026-02-11 17:46:30 +08:00
const isCallbacksInitialized = ref(false); // 标记回调是否已初始化
2026-01-28 13:38:05 +08:00
// 判断是否为系统消息
function isSystemMessage(message) {
if (message.type !== "TIMCustomElem") {
return false;
}
try {
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;
}
}
if (message.payload?.description === "系统消息标记") {
return true;
}
if (message.payload?.description === "SYSTEM_NOTIFICATION") {
return true;
}
} catch (error) {
console.error("判断系统消息失败:", error);
}
return false;
}
2026-01-28 16:20:19 +08:00
// 获取群组订单状态
const fetchGroupOrderStatus = async () => {
try {
2026-02-11 17:46:30 +08:00
const result = await api(
"getGroupListByGroupId",
{
groupId: groupId.value,
},
false
);
2026-01-28 16:20:19 +08:00
if (result.success && result.data) {
orderStatus.value = result.data.orderStatus || "";
corpId.value = result.data.corpId || "";
2026-02-10 16:41:07 +08:00
2026-02-03 11:20:32 +08:00
// 更新导航栏标题为团队名称
const teamName = result.data.team?.name || "群聊";
updateNavigationTitle(teamName);
2026-02-10 16:41:07 +08:00
2026-02-03 11:20:32 +08:00
// 更新患者信息
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();
}
2026-02-10 16:41:07 +08:00
2026-02-03 11:20:32 +08:00
// 更新聊天状态栏信息
updateChatStatusInfo(result.data);
2026-02-10 16:41:07 +08:00
2026-01-28 16:20:19 +08:00
console.log("获取群组订单状态:", {
orderStatus: orderStatus.value,
corpId: corpId.value,
2026-02-03 11:20:32 +08:00
teamName: teamName,
patientInfo: patientInfo.value,
2026-01-28 16:20:19 +08:00
});
} else {
console.error("获取群组订单状态失败:", result.message);
2026-01-28 13:38:05 +08:00
}
2026-01-28 16:20:19 +08:00
} catch (error) {
console.error("获取群组订单状态异常:", error);
2026-01-28 13:38:05 +08:00
}
2026-01-28 16:20:19 +08:00
};
2026-02-03 11:20:32 +08:00
// 更新聊天状态栏信息
const updateChatStatusInfo = (groupData) => {
const status = groupData.orderStatus || "";
2026-02-10 16:41:07 +08:00
2026-02-03 11:20:32 +08:00
let statusConfig = {
show: false,
title: "",
detail: "",
badgeText: "",
badgeClass: "",
};
2026-02-10 16:41:07 +08:00
2026-02-03 11:20:32 +08:00
switch (status) {
case "pending":
statusConfig = {
show: true,
title: "等待医生接受",
detail: "您的咨询申请已提交",
badgeText: "待处理",
badgeClass: "badge-pending",
};
break;
case "processing":
statusConfig = {
show: true,
title: "咨询进行中",
detail: "医生正在为您服务",
badgeText: "进行中",
badgeClass: "badge-processing",
};
break;
case "finished":
statusConfig = {
show: true,
title: "咨询已完成",
detail: "感谢您的咨询",
badgeText: "已完成",
badgeClass: "badge-finished",
};
break;
case "cancelled":
statusConfig = {
show: true,
title: "咨询已取消",
detail: "您已取消此次咨询",
badgeText: "已取消",
badgeClass: "badge-cancelled",
};
break;
case "rejected":
statusConfig = {
show: true,
title: "咨询已拒绝",
detail: "医生已拒绝您的咨询申请",
badgeText: "已拒绝",
badgeClass: "badge-rejected",
};
break;
default:
statusConfig.show = false;
}
2026-02-10 16:41:07 +08:00
2026-02-03 11:20:32 +08:00
chatStatusInfo.value = statusConfig;
};
// 处理系统消息接收
2026-01-28 16:20:19 +08:00
function handleSystemMessageReceived(message) {
try {
if (!message.payload?.data) return;
2026-01-28 13:38:05 +08:00
2026-01-28 16:20:19 +08:00
const data =
typeof message.payload.data === "string"
? JSON.parse(message.payload.data)
: message.payload.data;
if (data.type !== "system_message") return;
console.log("收到系统消息,类型:", data.messageType);
// 系统消息触发时,重新获取订单状态
fetchGroupOrderStatus();
} catch (error) {
console.error("处理系统消息失败:", error);
}
}
2026-01-28 13:38:05 +08:00
// 获取消息气泡样式类
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";
}
// 页面加载
2026-02-12 12:04:57 +08:00
onLoad(async (options) => {
2026-01-28 13:38:05 +08:00
groupId.value = options.groupID || "";
messageList.value = [];
isLoading.value = false;
if (options.conversationID) {
chatInfo.value.conversationID = options.conversationID;
timChatManager.setConversationID(options.conversationID);
console.log("设置当前会话ID:", options.conversationID);
}
if (options.userID) {
chatInfo.value.userID = options.userID;
}
2026-02-12 15:06:49 +08:00
await getGroupInfo(groupId.value);
2026-02-11 14:38:28 +08:00
// 监听键盘高度变化
uni.onKeyboardHeightChange((res) => {
console.log("键盘高度变化:", res.height);
2026-02-11 15:21:05 +08:00
const oldHeight = keyboardHeight.value;
2026-02-11 14:38:28 +08:00
keyboardHeight.value = res.height;
2026-02-11 17:46:30 +08:00
2026-02-11 15:21:05 +08:00
// 键盘弹出时从0变为非0自动滚动到底部
if (oldHeight === 0 && res.height > 0) {
nextTick(() => {
setTimeout(() => {
scrollToBottom(true);
}, 100);
});
}
2026-02-11 14:38:28 +08:00
});
2026-02-12 12:04:57 +08:00
// 先获取群组信息和成员信息,确保 chatMember 已初始化
2026-02-12 15:06:49 +08:00
2026-01-28 13:38:05 +08:00
checkLoginAndInitTIM();
updateNavigationTitle();
});
// 检查登录状态并初始化IM
const checkLoginAndInitTIM = async () => {
if (!isIMInitialized.value) {
uni.showLoading({
title: "连接中...",
});
2026-01-28 16:20:19 +08:00
const success = await initIMAfterLogin();
2026-01-28 13:38:05 +08:00
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 () => {
2026-02-11 17:46:30 +08:00
// 标记回调已初始化
isCallbacksInitialized.value = true;
2026-01-28 13:38:05 +08:00
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);
2026-01-28 16:20:19 +08:00
// 检查是否为系统消息,并处理状态更新
if (isSystemMessage(message)) {
handleSystemMessageReceived(message);
}
2026-01-28 13:38:05 +08:00
// 立即滚动到底部,不使用延迟
nextTick(() => {
scrollToBottom(true);
});
2026-01-28 17:51:31 +08:00
// 立即标记会话为已读确保未读数为0
2026-01-30 17:19:49 +08:00
if (
timChatManager.tim &&
timChatManager.isLoggedIn &&
chatInfo.value.conversationID
) {
2026-01-28 17:51:31 +08:00
timChatManager.tim
.setMessageRead({
conversationID: chatInfo.value.conversationID,
})
2026-02-11 09:51:02 +08:00
.then(async () => {
2026-01-28 17:51:31 +08:00
console.log("✓ 收到新消息后已标记为已读");
2026-02-11 09:51:02 +08:00
// 标记为已读后,立即刷新 tabBar 徽章
2026-02-12 12:04:57 +08:00
// await globalUnreadListenerManager.refreshBadge();
2026-01-28 17:51:31 +08:00
})
.catch((error) => {
console.error("✗ 标记已读失败:", error);
});
}
2026-01-28 13:38:05 +08:00
}
});
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.value = uniqueMessages;
console.log(
"消息列表已更新,原始",
messages.length,
"条,过滤后",
uniqueMessages.length,
"条消息"
);
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);
}
});
};
// 加载消息列表
2026-01-28 16:20:19 +08:00
const loadMessageList = async () => {
2026-01-28 13:38:05 +08:00
if (isLoading.value) {
console.log("正在加载中,跳过重复加载");
return;
}
console.log(
"【loadMessageList】开始加载消息会话ID:",
chatInfo.value.conversationID
);
isLoading.value = true;
uni.showLoading({
title: "加载中...",
mask: false,
});
2026-01-28 16:20:19 +08:00
// 获取群组订单状态
await fetchGroupOrderStatus();
2026-02-10 16:41:07 +08:00
timChatManager.enterConversation(chatInfo.value.conversationID);
2026-01-28 13:38:05 +08:00
2026-01-28 17:51:31 +08:00
// 标记会话为已读 - 确保清空未读数
2026-01-28 13:38:05 +08:00
if (
timChatManager.tim &&
timChatManager.isLoggedIn &&
chatInfo.value.conversationID
) {
2026-01-28 17:51:31 +08:00
console.log("标记会话为已读:", chatInfo.value.conversationID);
2026-01-28 13:38:05 +08:00
timChatManager.tim
.setMessageRead({
conversationID: chatInfo.value.conversationID,
})
2026-02-11 09:51:02 +08:00
.then(async () => {
2026-01-28 17:51:31 +08:00
console.log("✓ 会话已标记为已读:", chatInfo.value.conversationID);
2026-02-11 09:51:02 +08:00
// 标记为已读后,立即刷新 tabBar 徽章
2026-02-12 12:04:57 +08:00
// await globalUnreadListenerManager.refreshBadge();
2026-01-28 13:38:05 +08:00
})
.catch((error) => {
2026-01-28 17:51:31 +08:00
console.error("✗ 标记会话已读失败:", error);
2026-01-28 13:38:05 +08:00
});
}
};
// 语音播放相关
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({
2026-02-03 11:20:32 +08:00
url: "/pages/login/login",
2026-01-28 13:38:05 +08:00
});
return;
}
if (!isIMInitialized.value) {
checkLoginAndInitTIM();
} else if (timChatManager.tim && !timChatManager.isLoggedIn) {
2026-02-11 17:46:30 +08:00
// IM未登录尝试重连
timChatManager.ensureIMConnection().then(() => {
// 重连成功后重新注册回调
if (timChatManager.isLoggedIn && chatInfo.value.conversationID) {
console.log("✓ 重连成功,重新注册消息监听回调");
initTIMCallbacks();
timChatManager.setConversationID(chatInfo.value.conversationID);
}
});
2026-02-10 16:41:07 +08:00
} else if (
timChatManager.tim &&
timChatManager.isLoggedIn &&
chatInfo.value.conversationID
2026-02-11 17:46:30 +08:00
) {
// 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);
});
}
2026-02-10 16:41:07 +08:00
startIMMonitoring(30000);
2026-02-11 17:46:30 +08:00
}
2026-01-28 13:38:05 +08:00
});
// 页面隐藏
onHide(() => {
stopIMMonitoring();
2026-01-30 17:19:49 +08:00
// 清空当前会话ID避免离开页面后收到的消息被错误标记为已读
timChatManager.currentConversationID = null;
console.log("✓ 页面隐藏已清空当前会话ID");
2026-02-11 17:46:30 +08:00
2026-02-12 12:04:57 +08:00
// // 页面隐藏时刷新 tabBar 徽章,确保显示正确的未读数
// if (globalUnreadListenerManager.isInitialized) {
// globalUnreadListenerManager.refreshBadge();
// }
2026-01-28 13:38:05 +08:00
});
// 处理取消申请
const handleCancelConsult = async () => {
try {
uni.showModal({
2026-01-28 14:01:24 +08:00
title: "提示",
content: "确定要取消咨询申请吗?",
2026-01-28 13:38:05 +08:00
success: async (res) => {
if (res.confirm) {
uni.showLoading({
title: "处理中...",
});
try {
2026-01-28 14:01:24 +08:00
// 调用取消咨询申请接口
const result = await api("cancelConsultApplication", {
groupId: groupId.value,
2026-01-28 16:20:19 +08:00
corpId: corpId.value,
2026-01-28 13:38:05 +08:00
});
2026-01-28 14:01:24 +08:00
uni.hideLoading();
if (result.success) {
2026-01-28 16:20:19 +08:00
// 重新获取订单状态
await fetchGroupOrderStatus();
uni.showToast({
title: "已取消申请",
icon: "success",
2026-01-28 13:38:05 +08:00
});
2026-01-28 16:20:19 +08:00
// 延迟返回首页
setTimeout(() => {
uni.switchTab({
url: "/pages/home/home",
});
}, 1500);
2026-01-28 13:38:05 +08:00
} else {
2026-01-28 14:01:24 +08:00
throw new Error(result.message || "取消申请失败");
2026-01-28 13:38:05 +08:00
}
} catch (error) {
console.error("取消申请失败:", error);
uni.hideLoading();
uni.showToast({
title: error.message || "操作失败",
icon: "none",
});
}
}
2026-01-28 14:01:24 +08:00
},
2026-01-28 13:38:05 +08:00
});
} catch (error) {
console.error("取消申请失败:", error);
uni.showToast({
title: error.message || "操作失败",
icon: "none",
});
}
};
2026-01-28 16:20:19 +08:00
// 处理咨询申请
const handleApplyConsult = async () => {
2026-01-28 13:38:05 +08:00
try {
2026-01-28 16:20:19 +08:00
uni.showModal({
title: "提示",
content: "确定要重新申请咨询吗?",
success: async (res) => {
if (res.confirm) {
uni.showLoading({
title: "申请中...",
});
try {
// 获取当前群组信息提取客户ID和corpId
2026-02-11 17:46:30 +08:00
const groupInfo = await api(
"getGroupListByGroupId",
{
groupId: groupId.value,
},
false
);
2026-01-28 16:20:19 +08:00
if (!groupInfo.success || !groupInfo.data) {
throw new Error("获取群组信息失败");
}
const customerId = groupInfo.data.customerId;
const groupCorpId = groupInfo.data.corpId;
if (!customerId) {
throw new Error("无法获取客户信息");
}
// 调用创建咨询群组接口(重新申请)
const result = await api("createConsultGroup", {
teamId: groupInfo.data.teamId || "",
corpId: groupCorpId || corpId.value,
customerId: customerId,
customerImUserId: openid.value,
});
uni.hideLoading();
if (result.success) {
const { groupId: newGroupId, isExisting } = result.data;
// 重新获取订单状态
await fetchGroupOrderStatus();
uni.showToast({
title: isExisting ? "已重新发起申请" : "申请已发送",
icon: "success",
});
// 如果是新群组,跳转到新的聊天页面
if (!isExisting && newGroupId !== groupId.value) {
setTimeout(() => {
uni.redirectTo({
url: `/pages/message/index?conversationID=GROUP${newGroupId}&groupID=${newGroupId}`,
});
}, 1500);
} else {
// 刷新当前页面消息
setTimeout(() => {
loadMessageList();
}, 1000);
}
} else {
throw new Error(result.message || "申请失败");
}
} catch (error) {
console.error("申请失败:", error);
uni.hideLoading();
uni.showToast({
title: error.message || "操作失败",
icon: "none",
});
}
}
2026-01-28 13:38:05 +08:00
},
});
} catch (error) {
2026-01-28 16:20:19 +08:00
console.error("申请失败:", error);
2026-01-28 13:38:05 +08:00
uni.showToast({
title: error.message || "操作失败",
icon: "none",
});
}
};
// 页面卸载
onUnmounted(() => {
clearMessageCache();
2026-02-11 14:38:28 +08:00
// 移除键盘监听
uni.offKeyboardHeightChange();
2026-01-28 13:38:05 +08:00
timChatManager.setCallback("onSDKReady", null);
timChatManager.setCallback("onSDKNotReady", null);
timChatManager.setCallback("onMessageReceived", null);
timChatManager.setCallback("onMessageListLoaded", null);
timChatManager.setCallback("onError", null);
});
</script>
<style scoped lang="scss">
@import "./chat.scss";
</style>