2026-02-11 15:21:05 +08:00

1037 lines
29 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
<page-meta :page-style="'overflow:' + (keyboardHeight > 0 ? 'hidden' : 'visible')"></page-meta>
<view class="chat-page" :style="{ paddingBottom: keyboardHeight + 'px' }">
<!-- 患者信息栏 -->
<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="status-badge"
:class="chatStatusInfo.badgeClass"
v-if="chatStatusInfo.badgeText"
>
<text class="badge-text">{{ chatStatusInfo.badgeText }}</text>
</view>
</view>
</view>
<!-- 聊天消息区域 -->
<scroll-view
class="chat-content"
:style="{ bottom: (keyboardHeight > 0 ? keyboardHeight + 120 : 120) + 'px' }"
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
:corpId="corpId"
: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>
<!-- 取消申请组件 -->
<ConsultCancel v-if="showConsultCancel" @cancel="handleCancelConsult" />
<!-- 咨询申请组件 -->
<ConsultApply v-if="showConsultApply" @apply="handleApplyConsult" />
<!-- 聊天输入组件 -->
<ChatInput
v-if="!isEvaluationPopupOpen && !showConsultCancel && !showConsultApply"
ref="chatInputRef"
:timChatManager="timChatManager"
:formatTime="formatTime"
:groupId="
chatInfo.conversationID
? chatInfo.conversationID.replace('GROUP', '')
: ''
"
:userId="openid"
:corpId="corpId.value"
:keyboardHeight="keyboardHeight"
@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";
import { globalUnreadListenerManager } from "@/utils/global-unread-listener.js";
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";
import ConsultApply from "./components/consult-apply.vue";
const timChatManager = globalTimChatManager;
// corpId 从群组信息中获取
const corpId = ref("");
// 获取登录状态
const { account, openid, isIMInitialized } = storeToRefs(useAccountStore());
const { initIMAfterLogin } = useAccountStore();
// 聊天输入组件引用
const chatInputRef = ref(null);
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 keyboardHeight = ref(0);
// 评价弹窗状态
const isEvaluationPopupOpen = ref(false);
// 订单状态
const orderStatus = ref("");
// 患者信息
const patientInfo = ref({
name: "",
sex: "",
age: "",
mobile: "",
});
// 患者ID
const patientId = ref("");
// 聊天状态信息
const chatStatusInfo = ref({
show: false,
title: "",
detail: "",
badgeText: "",
badgeClass: "",
});
// 计算弹框显示状态
const showConsultCancel = computed(() => orderStatus.value === "pending");
const showConsultApply = computed(
() =>
orderStatus.value === "finished" ||
orderStatus.value === "cancelled" ||
orderStatus.value === "consult_ended"
);
// 消息列表相关状态
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 {
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;
}
// 获取群组订单状态
const fetchGroupOrderStatus = async () => {
try {
const result = await api("getGroupListByGroupId", {
groupId: groupId.value,
});
if (result.success && result.data) {
orderStatus.value = result.data.orderStatus || "";
corpId.value = result.data.corpId || "";
// 更新导航栏标题为团队名称
const teamName = result.data.team?.name || "群聊";
updateNavigationTitle(teamName);
// 更新患者信息
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();
}
// 更新聊天状态栏信息
updateChatStatusInfo(result.data);
console.log("获取群组订单状态:", {
orderStatus: orderStatus.value,
corpId: corpId.value,
teamName: teamName,
patientInfo: patientInfo.value,
});
} else {
console.error("获取群组订单状态失败:", result.message);
}
} catch (error) {
console.error("获取群组订单状态异常:", error);
}
};
// 更新聊天状态栏信息
const updateChatStatusInfo = (groupData) => {
const status = groupData.orderStatus || "";
let statusConfig = {
show: false,
title: "",
detail: "",
badgeText: "",
badgeClass: "",
};
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;
}
chatStatusInfo.value = statusConfig;
};
// 处理系统消息接收
function handleSystemMessageReceived(message) {
try {
if (!message.payload?.data) return;
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);
}
}
// 获取消息气泡样式类
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) => {
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;
}
// 监听键盘高度变化
uni.onKeyboardHeightChange((res) => {
console.log("键盘高度变化:", res.height);
const oldHeight = keyboardHeight.value;
keyboardHeight.value = res.height;
// 键盘弹出时从0变为非0自动滚动到底部
if (oldHeight === 0 && res.height > 0) {
nextTick(() => {
setTimeout(() => {
scrollToBottom(true);
}, 100);
});
}
});
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 () => {
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)) {
handleSystemMessageReceived(message);
}
// 立即滚动到底部,不使用延迟
nextTick(() => {
scrollToBottom(true);
});
// 立即标记会话为已读确保未读数为0
if (
timChatManager.tim &&
timChatManager.isLoggedIn &&
chatInfo.value.conversationID
) {
timChatManager.tim
.setMessageRead({
conversationID: chatInfo.value.conversationID,
})
.then(async () => {
console.log(" 收到新消息后已标记为已读");
// 标记为已读后,立即刷新 tabBar 徽章
await globalUnreadListenerManager.refreshBadge();
})
.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.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);
}
});
};
// 加载消息列表
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);
// 标记会话为已读 - 确保清空未读数
if (
timChatManager.tim &&
timChatManager.isLoggedIn &&
chatInfo.value.conversationID
) {
console.log("标记会话为已读:", chatInfo.value.conversationID);
timChatManager.tim
.setMessageRead({
conversationID: chatInfo.value.conversationID,
})
.then(async () => {
console.log(" 会话已标记为已读:", chatInfo.value.conversationID);
// 标记为已读后,立即刷新 tabBar 徽章
await globalUnreadListenerManager.refreshBadge();
})
.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/login/login",
});
return;
}
if (!isIMInitialized.value) {
checkLoginAndInitTIM();
} else if (timChatManager.tim && !timChatManager.isLoggedIn) {
timChatManager.ensureIMConnection();
} else if (
timChatManager.tim &&
timChatManager.isLoggedIn &&
chatInfo.value.conversationID
)
startIMMonitoring(30000);
});
// 页面隐藏
onHide(() => {
stopIMMonitoring();
// 清空当前会话ID避免离开页面后收到的消息被错误标记为已读
timChatManager.currentConversationID = null;
console.log(" 页面隐藏已清空当前会话ID");
// 页面隐藏时刷新 tabBar 徽章,确保显示正确的未读数
if (globalUnreadListenerManager.isInitialized) {
globalUnreadListenerManager.refreshBadge();
}
});
// 处理取消申请
const handleCancelConsult = async () => {
try {
uni.showModal({
title: "提示",
content: "确定要取消咨询申请吗",
success: async (res) => {
if (res.confirm) {
uni.showLoading({
title: "处理中...",
});
try {
// 调用取消咨询申请接口
const result = await api("cancelConsultApplication", {
groupId: groupId.value,
corpId: corpId.value,
});
uni.hideLoading();
if (result.success) {
// 重新获取订单状态
await fetchGroupOrderStatus();
uni.showToast({
title: "已取消申请",
icon: "success",
});
// 延迟返回首页
setTimeout(() => {
uni.switchTab({
url: "/pages/home/home",
});
}, 1500);
} else {
throw new Error(result.message || "取消申请失败");
}
} catch (error) {
console.error("取消申请失败:", error);
uni.hideLoading();
uni.showToast({
title: error.message || "操作失败",
icon: "none",
});
}
}
},
});
} catch (error) {
console.error("取消申请失败:", error);
uni.showToast({
title: error.message || "操作失败",
icon: "none",
});
}
};
// 处理咨询申请
const handleApplyConsult = async () => {
try {
uni.showModal({
title: "提示",
content: "确定要重新申请咨询吗",
success: async (res) => {
if (res.confirm) {
uni.showLoading({
title: "申请中...",
});
try {
// 获取当前群组信息提取客户ID和corpId
const groupInfo = await api("getGroupListByGroupId", {
groupId: groupId.value,
});
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",
});
}
}
},
});
} catch (error) {
console.error("申请失败:", error);
uni.showToast({
title: error.message || "操作失败",
icon: "none",
});
}
};
// 页面卸载
onUnmounted(() => {
clearMessageCache();
// 移除键盘监听
uni.offKeyboardHeightChange();
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>