|
|
@@ -0,0 +1,565 @@
|
|
|
+interface ConsultMessage {
|
|
|
+ id: string; // 咨询记录详情ID
|
|
|
+ consultRecordId: number; //咨询记录ID
|
|
|
+ sender: "user" | "agent" | "human" | "system";
|
|
|
+ sendType: string; // 发送类型 1-患者 2-医生 3-系统 4-AI
|
|
|
+ messageType: "1" | "2"; // 1文本 2 图片
|
|
|
+ messageContent?: string; // 消息内容
|
|
|
+ sendTime?: string; // 发送时间
|
|
|
+ createdAt: number;
|
|
|
+}
|
|
|
+import { Post } from "../../../../lib/request/method";
|
|
|
+import { upload } from "../../../../lib/request/upload";
|
|
|
+import dayjs from "dayjs";
|
|
|
+
|
|
|
+// sendType映射: 1-患者 2-医生 3-系统 4-AI
|
|
|
+const sendTypeMap: Record<string, "user" | "agent" | "human" | "system"> = {
|
|
|
+ "1": "user", // 患者
|
|
|
+ "2": "human", // 医生
|
|
|
+ "3": "system", // 系统
|
|
|
+ "4": "agent", // AI
|
|
|
+};
|
|
|
+
|
|
|
+// 计算底部安全区位置(rpx)
|
|
|
+function calculateSafeBottomRpx(): number {
|
|
|
+ const systemInfo = wx.getSystemInfoSync();
|
|
|
+ const windowHeight = systemInfo.windowHeight;
|
|
|
+ const safeAreaBottom = systemInfo.safeArea?.bottom ?? windowHeight;
|
|
|
+ const safeBottom = windowHeight - safeAreaBottom;
|
|
|
+ return (750 / systemInfo.windowWidth) * safeBottom;
|
|
|
+}
|
|
|
+
|
|
|
+// 获取的聊天消息为ConsultMessage格式 提取为一个公共的方法
|
|
|
+function transformMessage(item: AnyObject): ConsultMessage {
|
|
|
+ const sender = sendTypeMap[item.sendType] || "user";
|
|
|
+ const sendTime = item.sendTime || "";
|
|
|
+ const createdAt = sendTime ? dayjs(sendTime).valueOf() : Date.now();
|
|
|
+ return {
|
|
|
+ id: `msg-${item.id || item.consultRecordId}-${createdAt}`,
|
|
|
+ consultRecordId: item.consultRecordId,
|
|
|
+ sender,
|
|
|
+ sendType: item.sendType,
|
|
|
+ messageType: item.messageType as "1" | "2",
|
|
|
+ messageContent: item.messageContent || "",
|
|
|
+ createdAt,
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+Component({
|
|
|
+ properties: {},
|
|
|
+ data: {
|
|
|
+ messages: [] as ConsultMessage[],
|
|
|
+ inputText: "",
|
|
|
+ inputFocus: true,
|
|
|
+ inputBoxBottom: 0,
|
|
|
+ baseInputBottom: 0,
|
|
|
+ keepFocus: true,
|
|
|
+ _kbTimer: 0 as any,
|
|
|
+ _keyboardHeight: 0, // 当前键盘高度
|
|
|
+ isTransferredToHuman: false, // 是否已转人工
|
|
|
+ consultEnded: false, // 是否已结束咨询
|
|
|
+ _pollTimer: 0 as any, // 5秒轮询最新消息定时器
|
|
|
+ },
|
|
|
+
|
|
|
+ lifetimes: {
|
|
|
+ async attached() {
|
|
|
+ const safeBottomRpx = calculateSafeBottomRpx();
|
|
|
+ const tabBarHeight = 100; // rpx
|
|
|
+ const baseBottom = safeBottomRpx + tabBarHeight;
|
|
|
+ // 获取咨询中的id
|
|
|
+ const consultId = wx.getStorageSync("consultId");
|
|
|
+ let messages: ConsultMessage[] = [];
|
|
|
+
|
|
|
+ if (consultId) {
|
|
|
+ try {
|
|
|
+ // 获取所有消息的数据
|
|
|
+ const res = await Post(`/consultManage/getAllMsgs/${consultId}`);
|
|
|
+ if (res.data && res.data.length > 0) {
|
|
|
+ messages = res.data.map((item: AnyObject) =>
|
|
|
+ transformMessage(item)
|
|
|
+ );
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ wx.showToast({
|
|
|
+ title: error?.errMsg || "获取历史消息失败",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查历史消息中是否有真正的咨询结束消息(排除30分钟提醒消息)
|
|
|
+ const hasEndMessage = messages.some((msg: ConsultMessage) => {
|
|
|
+ if (msg.sendType !== "3" || !msg.messageContent) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const content = msg.messageContent;
|
|
|
+ // 排除30分钟提醒消息(包含"30分钟"和"5分钟后")
|
|
|
+ const isReminder =
|
|
|
+ content.includes("30分钟") &&
|
|
|
+ (content.includes("5分钟后") || content.includes("将在"));
|
|
|
+ // 判断是否为真正的咨询结束消息
|
|
|
+ const isRealEnd =
|
|
|
+ (content.includes("咨询结束") || content.includes("咨询已结束")) &&
|
|
|
+ !isReminder;
|
|
|
+ return isRealEnd;
|
|
|
+ });
|
|
|
+
|
|
|
+ const consultEnded = hasEndMessage || wx.getStorageSync("consultEnded");
|
|
|
+
|
|
|
+ this.setData({
|
|
|
+ baseInputBottom: baseBottom,
|
|
|
+ inputBoxBottom: baseBottom,
|
|
|
+ messages,
|
|
|
+ consultEnded: !!consultEnded,
|
|
|
+ });
|
|
|
+ this.triggerEvent("boxBottom", { inputBoxBottom: baseBottom });
|
|
|
+ // 键盘高度监听作为位置同步的补充
|
|
|
+ const kbHandler = (res: any) => {
|
|
|
+ const height = res?.height ?? 0;
|
|
|
+ // 清除之前的定时器
|
|
|
+ if (this.data._kbTimer) {
|
|
|
+ clearTimeout(this.data._kbTimer);
|
|
|
+ }
|
|
|
+
|
|
|
+ const timer = setTimeout(() => {
|
|
|
+ this._updateInputPosition(height);
|
|
|
+ }, 50) as unknown as number;
|
|
|
+
|
|
|
+ this.setData({ _kbTimer: timer });
|
|
|
+ };
|
|
|
+
|
|
|
+ wx.onKeyboardHeightChange?.(kbHandler);
|
|
|
+ (this as any)._kbHandler = kbHandler;
|
|
|
+
|
|
|
+ // 渲染完成后再触发一次聚焦,确保键盘弹起
|
|
|
+ this._ensureFocus();
|
|
|
+
|
|
|
+ // 如果咨询未结束,启动轮询最新消息
|
|
|
+ if (!consultEnded) {
|
|
|
+ this._startPolling();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ detached() {
|
|
|
+ // 清理监听和定时器
|
|
|
+ if ((this as any)._kbHandler) {
|
|
|
+ wx.offKeyboardHeightChange?.((this as any)._kbHandler);
|
|
|
+ }
|
|
|
+ if (this.data._kbTimer) {
|
|
|
+ clearTimeout(this.data._kbTimer);
|
|
|
+ }
|
|
|
+ // 清理轮询定时器
|
|
|
+ this._stopPolling();
|
|
|
+ },
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 滚动到底部
|
|
|
+ _scrollToBottom(delay: number = 100) {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.triggerEvent("scroll", { id: "bottom" });
|
|
|
+ }, delay);
|
|
|
+ },
|
|
|
+ // 收起键盘并更新位置
|
|
|
+ _hideKeyboardAndUpdatePosition() {
|
|
|
+ wx.hideKeyboard?.();
|
|
|
+ this.setData({
|
|
|
+ inputFocus: false,
|
|
|
+ keepFocus: false,
|
|
|
+ });
|
|
|
+ this._updateInputPosition(0);
|
|
|
+ },
|
|
|
+ // 统一的位置更新方法
|
|
|
+ _updateInputPosition(keyboardHeight: number) {
|
|
|
+ // 避免重复更新相同高度(10px 容差)
|
|
|
+ if (
|
|
|
+ Math.abs(keyboardHeight - this.data._keyboardHeight) < 10 &&
|
|
|
+ Math.abs(this.data.inputBoxBottom - this.data.baseInputBottom) < 10 &&
|
|
|
+ keyboardHeight === 0
|
|
|
+ ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const systemInfo = wx.getSystemInfoSync();
|
|
|
+ const keyboardHeightRpx = (750 / systemInfo.windowWidth) * keyboardHeight;
|
|
|
+
|
|
|
+ // 计算输入框底部位置
|
|
|
+ // 键盘展开时:面板紧贴键盘,不加 tabbar 距离
|
|
|
+ // 键盘收起时:保留 tabbar 距离(baseInputBottom 已包含安全区 + 100rpx tabbar)
|
|
|
+ const nextBottom =
|
|
|
+ keyboardHeight > 0 ? keyboardHeightRpx : this.data.baseInputBottom;
|
|
|
+
|
|
|
+ // 避免重复更新相同位置(5rpx 容差)
|
|
|
+ if (Math.abs(nextBottom - this.data.inputBoxBottom) < 5) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新位置
|
|
|
+ this.setData({
|
|
|
+ inputBoxBottom: nextBottom,
|
|
|
+ _keyboardHeight: keyboardHeight,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 通知父组件更新底部 padding
|
|
|
+ this.triggerEvent("boxBottom", { inputBoxBottom: nextBottom });
|
|
|
+
|
|
|
+ // 键盘弹出时平滑滚动到底部
|
|
|
+ if (keyboardHeight > 0) {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.triggerEvent("scroll", { id: "bottom" });
|
|
|
+ }, 150);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ _ensureFocus() {
|
|
|
+ if (!this.data.keepFocus) return;
|
|
|
+ this.setData({ inputFocus: false });
|
|
|
+ wx.nextTick?.(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (this.data.keepFocus) this.setData({ inputFocus: true });
|
|
|
+ }, 120);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ tapPanel() {
|
|
|
+ if (!this.data.inputFocus && this.data.keepFocus) {
|
|
|
+ this._ensureFocus();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ endConsult() {
|
|
|
+ // 收起键盘并更新位置
|
|
|
+ this._hideKeyboardAndUpdatePosition();
|
|
|
+ wx.showModal({
|
|
|
+ title: "",
|
|
|
+ content: "确定要结束本次咨询?",
|
|
|
+ cancelText: "继续咨询",
|
|
|
+ confirmText: "结束",
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ if (res.confirm) {
|
|
|
+ // 确认结束
|
|
|
+ this._endConsult();
|
|
|
+ } else {
|
|
|
+ // 继续咨询,恢复聚焦
|
|
|
+ this.setData({ keepFocus: true });
|
|
|
+ this._ensureFocus();
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ // 弹窗异常时不做处理
|
|
|
+ });
|
|
|
+ },
|
|
|
+ async _endConsult() {
|
|
|
+ // 格式化日期时间,格式:MM-DD HH:mm:ss(与系统消息格式一致)
|
|
|
+ const endDate = dayjs().format("MM-DD HH:mm:ss");
|
|
|
+
|
|
|
+ // 手动添加系统消息样式的结束时间
|
|
|
+ const consultId = wx.getStorageSync("consultId");
|
|
|
+ this._appendMessage({
|
|
|
+ id: `end-time-${Date.now()}`,
|
|
|
+ consultRecordId: consultId || 0,
|
|
|
+ sender: "system",
|
|
|
+ sendType: "3",
|
|
|
+ messageType: "1",
|
|
|
+ messageContent: "咨询结束",
|
|
|
+ sendTime: endDate,
|
|
|
+ createdAt: Date.now(),
|
|
|
+ });
|
|
|
+
|
|
|
+ // 调用结束咨询接口
|
|
|
+ if (consultId) {
|
|
|
+ try {
|
|
|
+ await Post(`/consultManage/end/${consultId}`);
|
|
|
+ } catch (error: any) {
|
|
|
+ wx.showToast({
|
|
|
+ title: error?.errMsg || "结束咨询失败",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置结束状态
|
|
|
+ this.setData({ consultEnded: true });
|
|
|
+
|
|
|
+ // 更新本地存储:标记咨询已结束
|
|
|
+ wx.setStorageSync("consultEnded", true);
|
|
|
+
|
|
|
+ // 停止轮询最新消息
|
|
|
+ this._stopPolling();
|
|
|
+
|
|
|
+ // 收起键盘
|
|
|
+ wx.hideKeyboard?.();
|
|
|
+
|
|
|
+ // 重置底部位置为正常值(tabbar 高度 + 安全区高度)
|
|
|
+ const safeBottomRpx = calculateSafeBottomRpx();
|
|
|
+ const tabBarHeight = 100; // rpx
|
|
|
+ const normalBottom = tabBarHeight + safeBottomRpx;
|
|
|
+
|
|
|
+ // 通知父组件重置 paddingBottom,避免菜单下方有大的距离
|
|
|
+ this.triggerEvent("boxBottom", { inputBoxBottom: normalBottom });
|
|
|
+
|
|
|
+ // 通知父组件显示guide菜单组件
|
|
|
+ this.triggerEvent("consultEvent", { type: "end" });
|
|
|
+
|
|
|
+ // 滚动到底部
|
|
|
+ // this._scrollToBottom();
|
|
|
+ },
|
|
|
+ handleInput(event: any) {
|
|
|
+ this.setData({ inputText: event.detail.value });
|
|
|
+ },
|
|
|
+ onInputFocus(event: any) {
|
|
|
+ const keyboardHeight = event.detail.height ?? 0;
|
|
|
+
|
|
|
+ // 设置 focus 状态
|
|
|
+ this.setData({
|
|
|
+ inputFocus: true,
|
|
|
+ keepFocus: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 立即更新位置
|
|
|
+ this._updateInputPosition(keyboardHeight);
|
|
|
+ },
|
|
|
+ onInputBlur() {
|
|
|
+ // 设置 focus 状态
|
|
|
+ this.setData({
|
|
|
+ inputFocus: false,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 立即恢复位置(键盘高度为 0)
|
|
|
+ this._updateInputPosition(0);
|
|
|
+ },
|
|
|
+ // 启动轮询最新消息
|
|
|
+ _startPolling() {
|
|
|
+ // 如果咨询已结束,不启动轮询
|
|
|
+ if (this.data.consultEnded) return;
|
|
|
+ // 清除之前的轮询定时器
|
|
|
+ this._stopPolling();
|
|
|
+ // 每5秒轮询一次
|
|
|
+ const timer = setInterval(() => {
|
|
|
+ // 如果咨询已结束,停止轮询
|
|
|
+ if (this.data.consultEnded) {
|
|
|
+ this._stopPolling();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this._getLatestMessages();
|
|
|
+ }, 5000);
|
|
|
+ this.setData({ _pollTimer: timer });
|
|
|
+ },
|
|
|
+ // 停止轮询最新消息
|
|
|
+ _stopPolling() {
|
|
|
+ if (this.data._pollTimer) {
|
|
|
+ clearInterval(this.data._pollTimer);
|
|
|
+ this.setData({ _pollTimer: 0 });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 获取最新消息
|
|
|
+ async _getLatestMessages() {
|
|
|
+ const consultId = wx.getStorageSync("consultId");
|
|
|
+ if (!consultId) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ // 获取最新消息
|
|
|
+ const res = await Post(`/consultManage/getLatestMsgs/${consultId}`);
|
|
|
+ // 如果有最新消息要追加到消息列表
|
|
|
+ if (res.data && Array.isArray(res.data) && res.data.length > 0) {
|
|
|
+ const newMessages = res.data.map((item: AnyObject) =>
|
|
|
+ transformMessage(item)
|
|
|
+ );
|
|
|
+ const allMessages = [...this.data.messages, ...newMessages];
|
|
|
+ this.setData({ messages: allMessages });
|
|
|
+
|
|
|
+ // 检查是否有真正的咨询结束消息(排除30分钟提醒消息)
|
|
|
+ // 30分钟提醒消息特征:包含"30分钟"和"5分钟后"等关键词
|
|
|
+ // 真正的结束消息:包含"咨询结束"但不包含"5分钟后"、"将"等表示未来的词
|
|
|
+ const hasEndMessage = newMessages.some((msg: ConsultMessage) => {
|
|
|
+ if (msg.sendType !== "3" || !msg.messageContent) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const content = msg.messageContent;
|
|
|
+ // 排除30分钟提醒消息(包含"30分钟"和"5分钟后")
|
|
|
+ const isReminder =
|
|
|
+ content.includes("30分钟") &&
|
|
|
+ (content.includes("5分钟后") || content.includes("将在"));
|
|
|
+ // 判断是否为真正的咨询结束消息
|
|
|
+ const isRealEnd =
|
|
|
+ (content.includes("咨询结束") ||
|
|
|
+ content.includes("咨询已结束")) &&
|
|
|
+ !isReminder;
|
|
|
+ return isRealEnd;
|
|
|
+ });
|
|
|
+
|
|
|
+ // 如果收到真正的咨询结束消息,更新状态并停止轮询
|
|
|
+ // 注意:30分钟提醒消息不会触发此逻辑,会继续轮询等待真正的结束消息
|
|
|
+ if (hasEndMessage && !this.data.consultEnded) {
|
|
|
+ this.setData({ consultEnded: true });
|
|
|
+ wx.setStorageSync("consultEnded", true);
|
|
|
+ this._stopPolling();
|
|
|
+
|
|
|
+ // 收起键盘
|
|
|
+ wx.hideKeyboard?.();
|
|
|
+
|
|
|
+ // 重置底部位置为正常值(tabbar 高度 + 安全区高度)
|
|
|
+ const safeBottomRpx = calculateSafeBottomRpx();
|
|
|
+ const tabBarHeight = 100; // rpx
|
|
|
+ const normalBottom = tabBarHeight + safeBottomRpx;
|
|
|
+
|
|
|
+ // 通知父组件重置 paddingBottom
|
|
|
+ this.triggerEvent("boxBottom", { inputBoxBottom: normalBottom });
|
|
|
+
|
|
|
+ // 通知父组件显示guide菜单组件
|
|
|
+ this.triggerEvent("consultEvent", { type: "end" });
|
|
|
+ }
|
|
|
+
|
|
|
+ //如果有最新消息要滚动到底部
|
|
|
+ this._scrollToBottom(100);
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ wx.showToast({
|
|
|
+ title: error?.errMsg || "获取最新消息失败",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 发送消息到后端
|
|
|
+ async _sendMessage(messageType: "1" | "2", messageContent: string) {
|
|
|
+ const consultId = wx.getStorageSync("consultId");
|
|
|
+ if (!consultId) {
|
|
|
+ wx.showToast({ title: "咨询ID不存在", icon: "none" });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await Post(`/consultManage/sendConsultMsg`, {
|
|
|
+ consultRecordId: consultId,
|
|
|
+ messageType,
|
|
|
+ messageContent,
|
|
|
+ });
|
|
|
+ // 发送成功后获取最新消息
|
|
|
+ await this._getLatestMessages();
|
|
|
+ } catch (error: any) {
|
|
|
+ wx.showToast({
|
|
|
+ title: error?.errMsg || "发送失败,请重试",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async sendText() {
|
|
|
+ const text = this.data.inputText.trim();
|
|
|
+ // 至少要有一个内容才能发送
|
|
|
+ if (!text) {
|
|
|
+ wx.showToast({ title: "发送内容不能为空", icon: "none" });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const consultId = wx.getStorageSync("consultId");
|
|
|
+ // 先添加用户消息到界面
|
|
|
+ const messageId = `user-text-${Date.now()}`;
|
|
|
+ this._appendMessage({
|
|
|
+ id: messageId,
|
|
|
+ consultRecordId: consultId || 0,
|
|
|
+ sender: "user",
|
|
|
+ sendType: "1",
|
|
|
+ messageType: "1",
|
|
|
+ messageContent: text,
|
|
|
+ createdAt: Date.now(),
|
|
|
+ });
|
|
|
+ // 发送信息
|
|
|
+ this._sendMessage("1", text);
|
|
|
+
|
|
|
+ // 清空输入框,保持键盘展开状态
|
|
|
+ this.setData({ inputText: "" });
|
|
|
+ // 平滑滚动到底部,确保新消息可见
|
|
|
+ this._scrollToBottom();
|
|
|
+ },
|
|
|
+ async chooseImage() {
|
|
|
+ // 收起键盘并更新位置
|
|
|
+ this._hideKeyboardAndUpdatePosition();
|
|
|
+ try {
|
|
|
+ const res = await wx.chooseMedia({
|
|
|
+ count: 1,
|
|
|
+ mediaType: ["image"],
|
|
|
+ sourceType: ["album", "camera"],
|
|
|
+ });
|
|
|
+ const files = res.tempFiles ?? [];
|
|
|
+ const file = files[0];
|
|
|
+ if (!file?.tempFilePath) return;
|
|
|
+ const imagePath = file.tempFilePath;
|
|
|
+ // 直接发送图片
|
|
|
+ await this._sendImageMessage(imagePath);
|
|
|
+ } catch (error: any) {
|
|
|
+ // 用户取消选择图片时不提示错误
|
|
|
+ if (error.errMsg && !error.errMsg.includes("cancel")) {
|
|
|
+ console.error("选择图片失败", error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 发送图片
|
|
|
+ async _sendImageMessage(imagePath: string) {
|
|
|
+ const consultId = wx.getStorageSync("consultId");
|
|
|
+ try {
|
|
|
+ // 先添加图片消息到界面(显示本地路径)
|
|
|
+ const messageId = `user-image-${Date.now()}`;
|
|
|
+ this._appendMessage({
|
|
|
+ id: messageId,
|
|
|
+ consultRecordId: consultId || 0,
|
|
|
+ sender: "user",
|
|
|
+ sendType: "1",
|
|
|
+ messageType: "2",
|
|
|
+ messageContent: imagePath, // 先用本地路径,上传后更新
|
|
|
+ createdAt: Date.now(),
|
|
|
+ });
|
|
|
+
|
|
|
+ // 上传图片
|
|
|
+ const imageUrl = await upload({
|
|
|
+ params: { name: "file", file: imagePath },
|
|
|
+ transform({ data }: any) {
|
|
|
+ return data?.url || data;
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ // 发送图片消息
|
|
|
+ await this._sendMessage("2", imageUrl);
|
|
|
+
|
|
|
+ // 更新消息中的图片URL(从本地路径更新为服务器URL)
|
|
|
+ const messages = this.data.messages;
|
|
|
+ const messageIndex = messages.findIndex(
|
|
|
+ (msg: ConsultMessage) => msg.id === messageId
|
|
|
+ );
|
|
|
+ if (messageIndex !== -1) {
|
|
|
+ messages[messageIndex].messageContent = imageUrl;
|
|
|
+ this.setData({ messages });
|
|
|
+ }
|
|
|
+ // 平滑滚动到底部,确保新消息可见
|
|
|
+ this._scrollToBottom();
|
|
|
+ } catch (error: any) {
|
|
|
+ wx.showToast({
|
|
|
+ title: error?.errMsg || "图片上传失败",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 预览图片
|
|
|
+ previewImage(e: any) {
|
|
|
+ const currentUrl = e.currentTarget.dataset.url;
|
|
|
+ // 获取所有图片消息的 URL 列表
|
|
|
+ const urls = this.data.messages
|
|
|
+ .filter(
|
|
|
+ (msg: ConsultMessage) => msg.messageType === "2" && msg.messageContent
|
|
|
+ )
|
|
|
+ .map((msg: ConsultMessage) => msg.messageContent!);
|
|
|
+
|
|
|
+ wx.previewImage({
|
|
|
+ current: currentUrl, // 当前显示图片的链接
|
|
|
+ urls: urls.length > 0 ? urls : [currentUrl], // 需要预览的图片链接列表
|
|
|
+ fail: (err) => {
|
|
|
+ wx.showToast({
|
|
|
+ title: err?.errMsg || "预览图片失败",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ },
|
|
|
+ });
|
|
|
+ },
|
|
|
+ _appendMessage(message: ConsultMessage) {
|
|
|
+ // 把获取的最新的消息追加到所有消息后面
|
|
|
+ const messages = [...this.data.messages, message];
|
|
|
+ this.setData({ messages });
|
|
|
+ // 延迟滚动,确保消息渲染完成后再滚动
|
|
|
+ this._scrollToBottom(100);
|
|
|
+ },
|
|
|
+ },
|
|
|
+});
|