|
|
@@ -0,0 +1,640 @@
|
|
|
+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; // 发送消息的时间
|
|
|
+}
|
|
|
+import { Post } from "../../../../lib/request/method";
|
|
|
+import { upload } from "../../../../lib/request/upload";
|
|
|
+import dayjs from "dayjs";
|
|
|
+
|
|
|
+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;
|
|
|
+ //将px转为rpx
|
|
|
+ return (750 / systemInfo.windowWidth) * safeBottom;
|
|
|
+}
|
|
|
+
|
|
|
+function isConsultEndMessage(msg: ConsultMessage): boolean {
|
|
|
+ if (msg.sendType !== "3" || !msg.messageContent) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const content = msg.messageContent;
|
|
|
+ const isReminder =
|
|
|
+ content.includes("30分钟") &&
|
|
|
+ (content.includes("5分钟后") || content.includes("将在"));
|
|
|
+ const isRealEnd = content.includes("咨询结束") && !isReminder;
|
|
|
+ return isRealEnd;
|
|
|
+}
|
|
|
+
|
|
|
+// Markdown 转换功能已移除,直接显示原始文本
|
|
|
+
|
|
|
+// 获取的聊天消息为ConsultMessage格式
|
|
|
+function transformMessage(item: AnyObject): ConsultMessage {
|
|
|
+ const sender = sendTypeMap[item.sendType];
|
|
|
+ return {
|
|
|
+ id: `msg-${item.id}`,
|
|
|
+ consultRecordId: item.consultRecordId,
|
|
|
+ sender,
|
|
|
+ sendTime: item.sendTime || "",
|
|
|
+ sendType: item.sendType,
|
|
|
+ messageType: item.messageType as "1" | "2",
|
|
|
+ messageContent: item.messageContent || "",
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+Component({
|
|
|
+ properties: {},
|
|
|
+ data: {
|
|
|
+ messages: [] as ConsultMessage[],
|
|
|
+ inputText: "",
|
|
|
+ inputFocus: true,
|
|
|
+ inputBoxBottom: 0,
|
|
|
+ baseInputBottom: 0,
|
|
|
+ keepFocus: true,
|
|
|
+ _keyboardHeight: 0, // 当前键盘高度
|
|
|
+ isTransferredToHuman: false, // 是否已转人工
|
|
|
+ consultEnded: false, // 是否已结束咨询
|
|
|
+ _pollTimer: 0 as any, // 5秒轮询最新消息定时器
|
|
|
+ textareaHeight: 80, // textarea 高度(rpx),初始值与 min-height 一致
|
|
|
+ },
|
|
|
+
|
|
|
+ lifetimes: {
|
|
|
+ async attached() {
|
|
|
+ const safeBottomRpx = calculateSafeBottomRpx();
|
|
|
+ const tabBarHeight = 100; // rpx
|
|
|
+ const baseBottom = safeBottomRpx + tabBarHeight;
|
|
|
+ console.log("baseBottom==输入框的位置", baseBottom);
|
|
|
+ // 获取咨询中的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) => {
|
|
|
+ const msg = transformMessage(item);
|
|
|
+ // 不再进行 Markdown 转换,直接使用原始文本
|
|
|
+ return msg;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ wx.showToast({
|
|
|
+ title: error?.errMsg || "获取历史消息失败",
|
|
|
+ icon: "none",
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查历史消息中是否有真正的咨询结束消息
|
|
|
+ const hasEndMessage = messages.some((msg: ConsultMessage) =>
|
|
|
+ isConsultEndMessage(msg)
|
|
|
+ );
|
|
|
+
|
|
|
+ const consultEnded = hasEndMessage || wx.getStorageSync("consultEnded");
|
|
|
+ console.log(
|
|
|
+ "安全区的距离",
|
|
|
+ safeBottomRpx,
|
|
|
+ "consultEnded==是否已结束咨询",
|
|
|
+ consultEnded
|
|
|
+ );
|
|
|
+ this.setData({
|
|
|
+ baseInputBottom: baseBottom,
|
|
|
+ inputBoxBottom: baseBottom,
|
|
|
+ messages,
|
|
|
+ consultEnded: !!consultEnded,
|
|
|
+ });
|
|
|
+ console.log("baseBottom==输入框的位置", baseBottom);
|
|
|
+ this.triggerEvent("boxBottom", { inputBoxBottom: baseBottom });
|
|
|
+ const kbHandler = (res: any) => {
|
|
|
+ const height = res?.height ?? 0;
|
|
|
+
|
|
|
+ // 键盘收起时,直接更新位置
|
|
|
+ if (height === 0) {
|
|
|
+ this._updateInputPosition(0);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.data.inputFocus || this.data.keepFocus) {
|
|
|
+ this._updateInputPosition(height);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ wx.onKeyboardHeightChange?.(kbHandler);
|
|
|
+ (this as any)._kbHandler = kbHandler;
|
|
|
+
|
|
|
+ this._ensureFocus();
|
|
|
+
|
|
|
+ const systemInfo = wx.getSystemInfoSync();
|
|
|
+ const isHarmonyOS =
|
|
|
+ systemInfo.system &&
|
|
|
+ systemInfo.system.toLowerCase().includes("harmony");
|
|
|
+ console.log("isHarmonyOS==是否是鸿蒙系统", isHarmonyOS);
|
|
|
+ const delayTime = isHarmonyOS ? 300 : 0;
|
|
|
+
|
|
|
+ if (delayTime > 0) {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (this.data._keyboardHeight > 0 && this.data.keepFocus) {
|
|
|
+ this._updateInputPosition(this.data._keyboardHeight);
|
|
|
+ }
|
|
|
+ }, delayTime);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果咨询未结束,启动轮询最新消息
|
|
|
+ if (!consultEnded) {
|
|
|
+ this._startPolling();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ detached() {
|
|
|
+ // 清理监听
|
|
|
+ if ((this as any)._kbHandler) {
|
|
|
+ wx.offKeyboardHeightChange?.((this as any)._kbHandler);
|
|
|
+ }
|
|
|
+ this._stopPolling();
|
|
|
+ },
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ _scrollToBottom() {
|
|
|
+ this.triggerEvent("scroll", { id: "bottom" });
|
|
|
+ },
|
|
|
+ _hideKeyboardAndUpdatePosition() {
|
|
|
+ wx.hideKeyboard?.();
|
|
|
+ this.setData({
|
|
|
+ inputFocus: false,
|
|
|
+ keepFocus: false,
|
|
|
+ });
|
|
|
+ this._updateInputPosition(0);
|
|
|
+ },
|
|
|
+ _updateInputPosition(keyboardHeight: number) {
|
|
|
+ const systemInfo = wx.getSystemInfoSync();
|
|
|
+ const rpx2px = systemInfo.windowWidth / 750;
|
|
|
+
|
|
|
+ const keyboardHeightRpx =
|
|
|
+ keyboardHeight > 0 ? keyboardHeight / rpx2px : 0;
|
|
|
+
|
|
|
+ const nextBottom =
|
|
|
+ keyboardHeight > 0 ? keyboardHeightRpx : this.data.baseInputBottom;
|
|
|
+
|
|
|
+ // 避免重复更新相同位置(容差1rpx)
|
|
|
+ if (Math.abs(nextBottom - this.data.inputBoxBottom) < 1) {
|
|
|
+ if (keyboardHeight !== this.data._keyboardHeight) {
|
|
|
+ this.setData({ _keyboardHeight: keyboardHeight });
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.setData({
|
|
|
+ inputBoxBottom: nextBottom,
|
|
|
+ _keyboardHeight: keyboardHeight,
|
|
|
+ });
|
|
|
+
|
|
|
+ this.triggerEvent("boxBottom", { inputBoxBottom: nextBottom });
|
|
|
+
|
|
|
+ if (keyboardHeight > 0) {
|
|
|
+ this.triggerEvent("scroll", { id: "bottom" });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ _ensureFocus() {
|
|
|
+ if (!this.data.keepFocus) return;
|
|
|
+ this.setData({ inputFocus: false });
|
|
|
+ wx.nextTick?.(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (this.data.keepFocus) {
|
|
|
+ this.setData({ inputFocus: true });
|
|
|
+ setTimeout(() => {
|
|
|
+ if (this.data._keyboardHeight > 0 && this.data.inputFocus) {
|
|
|
+ this._updateInputPosition(this.data._keyboardHeight);
|
|
|
+ }
|
|
|
+ }, 150);
|
|
|
+ }
|
|
|
+ }, 120);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ tapPanel() {
|
|
|
+ if (!this.data.inputFocus && this.data.keepFocus) {
|
|
|
+ this._ensureFocus();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ endConsult() {
|
|
|
+ // 收起键盘并更新位置
|
|
|
+ this._hideKeyboardAndUpdatePosition();
|
|
|
+ wx.showModal({
|
|
|
+ title: "",
|
|
|
+ content: "确定要结束本次咨询?",
|
|
|
+ cancelText: "继续咨询",
|
|
|
+ confirmText: "结束",
|
|
|
+ }).then((res: any) => {
|
|
|
+ if (res.confirm) {
|
|
|
+ // 确认结束
|
|
|
+ this._endConsult();
|
|
|
+ } else {
|
|
|
+ // 继续咨询,恢复聚焦
|
|
|
+ this.setData({ keepFocus: true });
|
|
|
+ this._ensureFocus();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ async _endConsult() {
|
|
|
+ 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,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 调用结束咨询接口
|
|
|
+ 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);
|
|
|
+ wx.removeStorageSync("consultId");
|
|
|
+ this._stopPolling();
|
|
|
+
|
|
|
+ // 收起键盘
|
|
|
+ wx.hideKeyboard?.();
|
|
|
+
|
|
|
+ // 重置底部位置为正常值(tabbar 高度 + 安全区高度)
|
|
|
+ const safeBottomRpx = calculateSafeBottomRpx();
|
|
|
+ const tabBarHeight = 100; // rpx
|
|
|
+ const normalBottom = tabBarHeight + safeBottomRpx;
|
|
|
+
|
|
|
+ this.triggerEvent("boxBottom", { inputBoxBottom: normalBottom });
|
|
|
+
|
|
|
+ // 通知父组件显示guide菜单组件
|
|
|
+ this.triggerEvent("consultEvent", { type: "end" });
|
|
|
+
|
|
|
+ // 滚动到底部
|
|
|
+ this._scrollToBottom();
|
|
|
+ },
|
|
|
+ handleInput(event: any) {
|
|
|
+ const value = event.detail.value;
|
|
|
+ this.setData({ inputText: value });
|
|
|
+
|
|
|
+ // 内容为空时,立即重置为最小高度
|
|
|
+ if (!value || value.trim() === "") {
|
|
|
+ if (this.data.textareaHeight !== 80) {
|
|
|
+ this.setData({ textareaHeight: 80 });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLineChange(event: any) {
|
|
|
+ const minHeight = 80; // 最小高度(rpx)
|
|
|
+ const maxHeight = 200; // 最大高度(rpx)
|
|
|
+ const lineCount = event.detail.lineCount || 1;
|
|
|
+
|
|
|
+ // 如果输入框为空,直接设置为最小高度
|
|
|
+ if (!this.data.inputText || this.data.inputText.trim() === "") {
|
|
|
+ if (this.data.textareaHeight !== minHeight) {
|
|
|
+ this.setData({ textareaHeight: minHeight });
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (lineCount === 1) {
|
|
|
+ if (this.data.textareaHeight !== minHeight) {
|
|
|
+ this.setData({ textareaHeight: minHeight });
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const lineHeight = 53; // 每行高度(rpx)
|
|
|
+ const padding = 24;
|
|
|
+
|
|
|
+ const calculatedHeight = lineCount * lineHeight + padding;
|
|
|
+ const finalHeight = Math.max(
|
|
|
+ minHeight,
|
|
|
+ Math.min(maxHeight, calculatedHeight)
|
|
|
+ );
|
|
|
+
|
|
|
+ if (Math.abs(this.data.textareaHeight - finalHeight) > 3) {
|
|
|
+ this.setData({ textareaHeight: finalHeight });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onInputFocus(event: any) {
|
|
|
+ const keyboardHeight = event.detail.height ?? 0;
|
|
|
+
|
|
|
+ // 设置 focus 状态
|
|
|
+ this.setData({
|
|
|
+ inputFocus: true,
|
|
|
+ keepFocus: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (keyboardHeight > 0) {
|
|
|
+ this._updateInputPosition(keyboardHeight);
|
|
|
+ } else {
|
|
|
+ if (this.data._keyboardHeight > 0) {
|
|
|
+ // 延迟一点时间,等待键盘完全弹起后再更新
|
|
|
+ setTimeout(() => {
|
|
|
+ if (this.data.inputFocus && this.data._keyboardHeight > 0) {
|
|
|
+ this._updateInputPosition(this.data._keyboardHeight);
|
|
|
+ }
|
|
|
+ }, 100);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onInputBlur() {
|
|
|
+ console.log("onInputBlur==输入框失焦");
|
|
|
+
|
|
|
+ // 设置 focus 状态
|
|
|
+ this.setData({
|
|
|
+ inputFocus: false,
|
|
|
+ });
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ if (!this.data.inputFocus) {
|
|
|
+ this._updateInputPosition(0);
|
|
|
+ }
|
|
|
+ }, 100);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 启动轮询最新消息
|
|
|
+ _startPolling() {
|
|
|
+ if (this.data.consultEnded) return;
|
|
|
+ this._stopPolling();
|
|
|
+ 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) => {
|
|
|
+ const msg = transformMessage(item);
|
|
|
+ // 不再进行 Markdown 转换,直接使用原始文本
|
|
|
+ return msg;
|
|
|
+ });
|
|
|
+ const allMessages = [...this.data.messages, ...newMessages];
|
|
|
+ this.setData({ messages: allMessages });
|
|
|
+
|
|
|
+ const hasEndMessage = newMessages.some((msg: ConsultMessage) =>
|
|
|
+ isConsultEndMessage(msg)
|
|
|
+ );
|
|
|
+
|
|
|
+ if (hasEndMessage && !this.data.consultEnded) {
|
|
|
+ this.setData({ consultEnded: true });
|
|
|
+ wx.setStorageSync("consultEnded", true);
|
|
|
+ this._stopPolling();
|
|
|
+
|
|
|
+ // 收起键盘
|
|
|
+ wx.hideKeyboard?.();
|
|
|
+
|
|
|
+ const safeBottomRpx = calculateSafeBottomRpx();
|
|
|
+ const tabBarHeight = 100; // rpx
|
|
|
+ const normalBottom = tabBarHeight + safeBottomRpx;
|
|
|
+
|
|
|
+ this.triggerEvent("boxBottom", { inputBoxBottom: normalBottom });
|
|
|
+
|
|
|
+ // 通知父组件显示guide菜单组件
|
|
|
+ this.triggerEvent("consultEvent", { type: "end" });
|
|
|
+ }
|
|
|
+
|
|
|
+ this._scrollToBottom();
|
|
|
+ }
|
|
|
+ } 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,
|
|
|
+ }).then(() => {
|
|
|
+ this._stopPolling();
|
|
|
+ this._getLatestMessages();
|
|
|
+ setTimeout(() => {
|
|
|
+ if (!this.data.consultEnded) {
|
|
|
+ this._startPolling();
|
|
|
+ }
|
|
|
+ }, 5000);
|
|
|
+ });
|
|
|
+ } 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,
|
|
|
+ });
|
|
|
+ this._scrollToBottom();
|
|
|
+ // 发送信息
|
|
|
+ this._sendMessage("1", text);
|
|
|
+
|
|
|
+ // 保存当前键盘状态
|
|
|
+ const wasFocused = this.data.inputFocus;
|
|
|
+ const currentKeyboardHeight = this.data._keyboardHeight;
|
|
|
+
|
|
|
+ this.setData({
|
|
|
+ inputText: "",
|
|
|
+ textareaHeight: 80,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!wasFocused) {
|
|
|
+ this.setData({
|
|
|
+ inputFocus: false,
|
|
|
+ keepFocus: false,
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ if (currentKeyboardHeight > 0) {
|
|
|
+ this._updateInputPosition(currentKeyboardHeight);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async chooseImage() {
|
|
|
+ const wasFocused = this.data.inputFocus;
|
|
|
+ const currentKeyboardHeight = this.data._keyboardHeight;
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ if (wasFocused) {
|
|
|
+ wx.nextTick?.(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.setData({
|
|
|
+ inputFocus: true,
|
|
|
+ keepFocus: true,
|
|
|
+ });
|
|
|
+ // 恢复键盘位置
|
|
|
+ if (currentKeyboardHeight > 0) {
|
|
|
+ this._updateInputPosition(currentKeyboardHeight);
|
|
|
+ }
|
|
|
+ }, 200);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ if (error.errMsg && !error.errMsg.includes("cancel")) {
|
|
|
+ console.error("选择图片失败", error);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (wasFocused) {
|
|
|
+ wx.nextTick?.(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.setData({
|
|
|
+ inputFocus: true,
|
|
|
+ keepFocus: true,
|
|
|
+ });
|
|
|
+ // 恢复键盘位置
|
|
|
+ if (currentKeyboardHeight > 0) {
|
|
|
+ this._updateInputPosition(currentKeyboardHeight);
|
|
|
+ }
|
|
|
+ }, 200);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 发送图片
|
|
|
+ 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,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 上传图片
|
|
|
+ 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;
|
|
|
+ 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 });
|
|
|
+ },
|
|
|
+ },
|
|
|
+});
|