message-consult.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. interface ConsultMessage {
  2. id: string; // 咨询记录详情ID
  3. consultRecordId: number; //咨询记录ID
  4. sender: "user" | "agent" | "human" | "system";
  5. sendType: string; // 发送类型 1-患者 2-医生 3-系统 4-AI
  6. messageType: "1" | "2"; // 1文本 2 图片
  7. messageContent?: string; // 消息内容
  8. sendTime?: string; // 发送消息的时间
  9. }
  10. import { Post } from "../../../../lib/request/method";
  11. import { upload } from "../../../../lib/request/upload";
  12. import dayjs from "dayjs";
  13. // sendType映射: 1-患者 2-医生 3-系统 4-AI
  14. const sendTypeMap: Record<string, "user" | "agent" | "human" | "system"> = {
  15. "1": "user", // 患者
  16. "2": "human", // 医生
  17. "3": "system", // 系统
  18. "4": "agent", // AI
  19. };
  20. // 计算底部安全区位置(rpx)
  21. function calculateSafeBottomRpx(): number {
  22. const systemInfo = wx.getSystemInfoSync();
  23. // 获取窗口的高度
  24. const windowHeight = systemInfo.windowHeight;
  25. // 获取安全区底部的高度
  26. const safeAreaBottom = systemInfo.safeArea?.bottom ?? windowHeight;
  27. const safeBottom = windowHeight - safeAreaBottom;
  28. //将px转为rpx
  29. return (750 / systemInfo.windowWidth) * safeBottom;
  30. }
  31. // 判断消息是否为真正的咨询结束消息(排除30分钟提醒消息)
  32. function isConsultEndMessage(msg: ConsultMessage): boolean {
  33. if (msg.sendType !== "3" || !msg.messageContent) {
  34. return false;
  35. }
  36. const content = msg.messageContent;
  37. // 排除30分钟提醒消息(包含"30分钟"和"5分钟后")
  38. const isReminder =
  39. content.includes("30分钟") &&
  40. (content.includes("5分钟后") || content.includes("将在"));
  41. // 判断是否为真正的咨询结束消息
  42. const isRealEnd = content.includes("咨询结束") && !isReminder;
  43. return isRealEnd;
  44. }
  45. // 获取的聊天消息为ConsultMessage格式 提取为一个公共的方法
  46. function transformMessage(item: AnyObject): ConsultMessage {
  47. const sender = sendTypeMap[item.sendType];
  48. return {
  49. id: `msg-${item.id}`,
  50. consultRecordId: item.consultRecordId,
  51. sender,
  52. sendTime: item.sendTime || "",
  53. sendType: item.sendType,
  54. messageType: item.messageType as "1" | "2",
  55. messageContent: item.messageContent || "",
  56. };
  57. }
  58. Component({
  59. properties: {},
  60. data: {
  61. messages: [] as ConsultMessage[],
  62. inputText: "",
  63. inputFocus: true,
  64. inputBoxBottom: 0,
  65. baseInputBottom: 0,
  66. keepFocus: true,
  67. _kbTimer: 0 as any,
  68. _keyboardHeight: 0, // 当前键盘高度
  69. isTransferredToHuman: false, // 是否已转人工
  70. consultEnded: false, // 是否已结束咨询
  71. _pollTimer: 0 as any, // 5秒轮询最新消息定时器
  72. textareaHeight: 80, // textarea 高度(rpx),初始值与 min-height 一致
  73. },
  74. lifetimes: {
  75. async attached() {
  76. const safeBottomRpx = calculateSafeBottomRpx();
  77. const tabBarHeight = 100; // rpx
  78. const baseBottom = safeBottomRpx + tabBarHeight;
  79. console.log("baseBottom==输入框的位置", baseBottom);
  80. // 获取咨询中的id
  81. const consultId = wx.getStorageSync("consultId");
  82. let messages: ConsultMessage[] = [];
  83. if (consultId) {
  84. try {
  85. // 获取所有消息的数据
  86. const res = await Post(`/consultManage/getAllMsgs/${consultId}`);
  87. if (res.data && res.data.length > 0) {
  88. messages = res.data.map((item: AnyObject) =>
  89. transformMessage(item)
  90. );
  91. }
  92. } catch (error: any) {
  93. wx.showToast({
  94. title: error?.errMsg || "获取历史消息失败",
  95. icon: "none",
  96. });
  97. }
  98. }
  99. // 检查历史消息中是否有真正的咨询结束消息(排除30分钟提醒消息)
  100. const hasEndMessage = messages.some((msg: ConsultMessage) =>
  101. isConsultEndMessage(msg)
  102. );
  103. const consultEnded = hasEndMessage || wx.getStorageSync("consultEnded");
  104. console.log(
  105. "安全区的距离",
  106. safeBottomRpx,
  107. "consultEnded==是否已结束咨询",
  108. consultEnded
  109. );
  110. this.setData({
  111. baseInputBottom: baseBottom,
  112. inputBoxBottom: baseBottom,
  113. messages,
  114. consultEnded: !!consultEnded,
  115. });
  116. console.log("baseBottom==输入框的位置", baseBottom);
  117. this.triggerEvent("boxBottom", { inputBoxBottom: baseBottom });
  118. // 监听键盘高度变化事件
  119. let lastHeight = 0;
  120. const kbHandler = (res: any) => {
  121. const height = res?.height ?? 0;
  122. if (!this.data.inputFocus) {
  123. lastHeight = 0;
  124. } else {
  125. lastHeight = Math.max(lastHeight, height); // 记录键盘最大高度
  126. }
  127. console.log("height==键盘高度", height, "lastHeight=====", lastHeight);
  128. // 如果键盘高度没有实际变化,不更新位置
  129. if (this.data._keyboardHeight && lastHeight) {
  130. return;
  131. }
  132. // 清除之前的定时器
  133. if (this.data._kbTimer) {
  134. clearTimeout(this.data._kbTimer);
  135. }
  136. // 键盘展开时立即更新位置,确保没有空隙
  137. // 键盘收起时稍微延迟,避免与输入框高度变化冲突
  138. let _kbTimer = setTimeout(() => {
  139. console.log("lastHeight==键盘高度 zx", lastHeight);
  140. this._updateInputPosition(lastHeight);
  141. }, 300);
  142. this.setData({ _kbTimer: _kbTimer });
  143. };
  144. wx.onKeyboardHeightChange?.(kbHandler);
  145. (this as any)._kbHandler = kbHandler;
  146. // 渲染完成后再触发一次聚焦,确保键盘弹起
  147. this._ensureFocus();
  148. // 如果咨询未结束,启动轮询最新消息
  149. if (!consultEnded) {
  150. this._startPolling();
  151. }
  152. },
  153. detached() {
  154. // 清理监听和定时器
  155. if ((this as any)._kbHandler) {
  156. wx.offKeyboardHeightChange?.((this as any)._kbHandler);
  157. }
  158. if (this.data._kbTimer) {
  159. clearTimeout(this.data._kbTimer);
  160. }
  161. // 清理轮询定时器
  162. this._stopPolling();
  163. },
  164. },
  165. methods: {
  166. // 滚动到底部-
  167. _scrollToBottom() {
  168. this.triggerEvent("scroll", { id: "bottom" });
  169. },
  170. // 收起键盘并更新位置
  171. _hideKeyboardAndUpdatePosition() {
  172. wx.hideKeyboard?.();
  173. this.setData({
  174. inputFocus: false,
  175. keepFocus: false,
  176. });
  177. this._updateInputPosition(0);
  178. },
  179. // 统一的位置更新方法
  180. _updateInputPosition(keyboardHeight: number) {
  181. // 避免重复更新相同高度(10px 容差)
  182. if (
  183. Math.abs(keyboardHeight - this.data._keyboardHeight) < 10 &&
  184. Math.abs(this.data.inputBoxBottom - this.data.baseInputBottom) < 10 &&
  185. keyboardHeight === 0
  186. ) {
  187. return;
  188. }
  189. const systemInfo = wx.getSystemInfoSync();
  190. const rpx2px = systemInfo.windowWidth / 750;
  191. // 键盘高度是 px,转换为 rpx
  192. const keyboardHeightRpx =
  193. keyboardHeight > 0 ? keyboardHeight / rpx2px : 0;
  194. // 计算输入框底部位置
  195. // 键盘展开时:面板紧贴键盘(bottom = 键盘高度),确保没有空隙
  196. // 键盘收起时:保留 tabbar 距离(baseInputBottom 已包含安全区 + 100rpx tabbar)
  197. const nextBottom =
  198. keyboardHeight > 0 ? keyboardHeightRpx : this.data.baseInputBottom;
  199. // 避免重复更新相同位置(1rpx 容差,更精确)
  200. if (Math.abs(nextBottom - this.data.inputBoxBottom) < 1) {
  201. return;
  202. }
  203. // 更新位置
  204. this.setData({
  205. inputBoxBottom: nextBottom,
  206. _keyboardHeight: keyboardHeight,
  207. });
  208. // 通知父组件更新底部 padding
  209. this.triggerEvent("boxBottom", { inputBoxBottom: nextBottom });
  210. // 键盘弹出时平滑滚动到底部
  211. if (keyboardHeight > 0) {
  212. this.triggerEvent("scroll", { id: "bottom" });
  213. }
  214. },
  215. _ensureFocus() {
  216. if (!this.data.keepFocus) return;
  217. this.setData({ inputFocus: false });
  218. wx.nextTick?.(() => {
  219. setTimeout(() => {
  220. if (this.data.keepFocus) this.setData({ inputFocus: true });
  221. }, 120);
  222. });
  223. },
  224. tapPanel() {
  225. if (!this.data.inputFocus && this.data.keepFocus) {
  226. this._ensureFocus();
  227. }
  228. },
  229. endConsult() {
  230. // 收起键盘并更新位置
  231. this._hideKeyboardAndUpdatePosition();
  232. wx.showModal({
  233. title: "",
  234. content: "确定要结束本次咨询?",
  235. cancelText: "继续咨询",
  236. confirmText: "结束",
  237. }).then((res: any) => {
  238. if (res.confirm) {
  239. // 确认结束
  240. this._endConsult();
  241. } else {
  242. // 继续咨询,恢复聚焦
  243. this.setData({ keepFocus: true });
  244. this._ensureFocus();
  245. }
  246. });
  247. },
  248. async _endConsult() {
  249. // 格式化日期时间,格式:MM-DD HH:mm:ss(与系统消息格式一致)
  250. const endDate = dayjs().format("MM-DD HH:mm:ss");
  251. // 手动添加系统消息样式的结束时间
  252. const consultId = wx.getStorageSync("consultId");
  253. this._appendMessage({
  254. id: `end-time-${Date.now()}`,
  255. consultRecordId: consultId || 0,
  256. sender: "system",
  257. sendType: "3",
  258. messageType: "1",
  259. messageContent: "咨询结束",
  260. sendTime: endDate,
  261. });
  262. // 调用结束咨询接口
  263. if (consultId) {
  264. try {
  265. await Post(`/consultManage/end/${consultId}`);
  266. } catch (error: any) {
  267. wx.showToast({
  268. title: error?.errMsg || "结束咨询失败",
  269. icon: "none",
  270. });
  271. }
  272. }
  273. // 设置结束状态
  274. this.setData({ consultEnded: true });
  275. // 更新本地存储:标记咨询已结束
  276. wx.setStorageSync("consultEnded", true);
  277. //咨询结束之后 需要清除咨询id
  278. wx.removeStorageSync("consultId");
  279. // 停止轮询最新消息
  280. this._stopPolling();
  281. // 收起键盘
  282. wx.hideKeyboard?.();
  283. // 重置底部位置为正常值(tabbar 高度 + 安全区高度)
  284. const safeBottomRpx = calculateSafeBottomRpx();
  285. const tabBarHeight = 100; // rpx
  286. const normalBottom = tabBarHeight + safeBottomRpx;
  287. // 通知父组件重置 paddingBottom,避免菜单下方有大的距离
  288. this.triggerEvent("boxBottom", { inputBoxBottom: normalBottom });
  289. // 通知父组件显示guide菜单组件
  290. this.triggerEvent("consultEvent", { type: "end" });
  291. // 滚动到底部
  292. this._scrollToBottom();
  293. },
  294. handleInput(event: any) {
  295. const value = event.detail.value;
  296. this.setData({ inputText: value });
  297. // 内容为空时,立即重置为最小高度
  298. if (!value || value.trim() === "") {
  299. if (this.data.textareaHeight !== 80) {
  300. this.setData({ textareaHeight: 80 });
  301. }
  302. }
  303. },
  304. onLineChange(event: any) {
  305. const minHeight = 80; // 最小高度(rpx)
  306. const maxHeight = 200; // 最大高度(rpx)
  307. const lineCount = event.detail.lineCount || 1;
  308. // 如果输入框为空,直接设置为最小高度
  309. if (!this.data.inputText || this.data.inputText.trim() === "") {
  310. if (this.data.textareaHeight !== minHeight) {
  311. this.setData({ textareaHeight: minHeight });
  312. }
  313. return;
  314. }
  315. // 单行时保持最小高度,不更新
  316. if (lineCount === 1) {
  317. // 只有当当前高度不是最小高度时才更新
  318. if (this.data.textareaHeight !== minHeight) {
  319. this.setData({ textareaHeight: minHeight });
  320. }
  321. return;
  322. }
  323. // 多行时才动态计算高度
  324. // 字体大小 28rpx,行高 1.9,所以每行实际高度约为 28 * 1.9 ≈ 53rpx
  325. const lineHeight = 53; // 每行高度(rpx)
  326. const padding = 24; // 上下 padding 总和(12rpx * 2 = 24rpx)
  327. // 计算高度:行数 * 行高 + 上下 padding
  328. const calculatedHeight = lineCount * lineHeight + padding;
  329. // 限制在 minHeight 和 maxHeight 之间
  330. const finalHeight = Math.max(
  331. minHeight,
  332. Math.min(maxHeight, calculatedHeight)
  333. );
  334. // 只在高度确实需要变化时更新(阈值设为 3rpx,减少频繁更新和跳动)
  335. if (Math.abs(this.data.textareaHeight - finalHeight) > 3) {
  336. this.setData({ textareaHeight: finalHeight });
  337. }
  338. },
  339. onInputFocus(event: any) {
  340. const keyboardHeight = event.detail.height ?? 0;
  341. // 设置 focus 状态
  342. this.setData({
  343. inputFocus: true,
  344. keepFocus: true,
  345. });
  346. // 立即更新位置
  347. this._updateInputPosition(keyboardHeight);
  348. },
  349. onInputBlur() {
  350. console.log("onInputBlur==输入框失焦");
  351. // 设置 focus 状态
  352. this.setData({
  353. inputFocus: false,
  354. });
  355. clearTimeout(this.data._kbTimer);
  356. // 延迟恢复位置,确保键盘完全收起
  357. setTimeout(() => {
  358. this._updateInputPosition(0);
  359. }, 100);
  360. },
  361. // 启动轮询最新消息
  362. _startPolling() {
  363. // 如果咨询已结束,不启动轮询
  364. if (this.data.consultEnded) return;
  365. // 清除之前的轮询定时器
  366. this._stopPolling();
  367. // 每5秒轮询一次
  368. const timer = setInterval(() => {
  369. // 如果咨询已结束,停止轮询
  370. if (this.data.consultEnded) {
  371. this._stopPolling();
  372. return;
  373. }
  374. this._getLatestMessages();
  375. }, 5000);
  376. this.setData({ _pollTimer: timer });
  377. },
  378. // 停止轮询最新消息
  379. _stopPolling() {
  380. if (this.data._pollTimer) {
  381. clearInterval(this.data._pollTimer);
  382. this.setData({ _pollTimer: 0 });
  383. }
  384. },
  385. // 获取最新消息
  386. async _getLatestMessages() {
  387. const consultId = wx.getStorageSync("consultId");
  388. if (!consultId) return;
  389. try {
  390. // 获取最新消息
  391. const res = await Post(`/consultManage/getLatestMsgs/${consultId}`);
  392. // 如果有最新消息要追加到消息列表
  393. if (res.data && Array.isArray(res.data) && res.data.length > 0) {
  394. const newMessages = res.data.map((item: AnyObject) =>
  395. transformMessage(item)
  396. );
  397. const allMessages = [...this.data.messages, ...newMessages];
  398. this.setData({ messages: allMessages });
  399. // 检查是否有真正的咨询结束消息(排除30分钟提醒消息)
  400. const hasEndMessage = newMessages.some((msg: ConsultMessage) =>
  401. isConsultEndMessage(msg)
  402. );
  403. // 如果收到真正的咨询结束消息,更新状态并停止轮询
  404. // 注意:30分钟提醒消息不会触发此逻辑,会继续轮询等待真正的结束消息
  405. if (hasEndMessage && !this.data.consultEnded) {
  406. this.setData({ consultEnded: true });
  407. wx.setStorageSync("consultEnded", true);
  408. this._stopPolling();
  409. // 收起键盘
  410. wx.hideKeyboard?.();
  411. // 重置底部位置为正常值(tabbar 高度 + 安全区高度)
  412. const safeBottomRpx = calculateSafeBottomRpx();
  413. const tabBarHeight = 100; // rpx
  414. const normalBottom = tabBarHeight + safeBottomRpx;
  415. // 通知父组件重置 paddingBottom
  416. this.triggerEvent("boxBottom", { inputBoxBottom: normalBottom });
  417. // 通知父组件显示guide菜单组件
  418. this.triggerEvent("consultEvent", { type: "end" });
  419. }
  420. //如果有最新消息要滚动到底部
  421. this._scrollToBottom();
  422. }
  423. } catch (error: any) {
  424. wx.showToast({
  425. title: error?.errMsg || "获取最新消息失败",
  426. icon: "none",
  427. });
  428. }
  429. },
  430. // 发送消息到后端
  431. async _sendMessage(messageType: "1" | "2", messageContent: string) {
  432. const consultId = wx.getStorageSync("consultId");
  433. if (!consultId) {
  434. wx.showToast({ title: "咨询ID不存在", icon: "none" });
  435. return;
  436. }
  437. try {
  438. await Post(`/consultManage/sendConsultMsg`, {
  439. consultRecordId: consultId,
  440. messageType,
  441. messageContent,
  442. }).then(() => {
  443. // 发送成功后获取最新消息
  444. // 重置轮询定时器,避免短时间内重复调用
  445. this._stopPolling();
  446. this._getLatestMessages();
  447. // 重新启动轮询,避免重复调用
  448. setTimeout(() => {
  449. if (!this.data.consultEnded) {
  450. this._startPolling();
  451. }
  452. }, 5000);
  453. });
  454. } catch (error: any) {
  455. wx.showToast({
  456. title: error?.errMsg || "发送失败,请重试",
  457. icon: "none",
  458. });
  459. }
  460. },
  461. async sendText() {
  462. const text = this.data.inputText.trim();
  463. // 至少要有一个内容才能发送
  464. if (!text) {
  465. wx.showToast({ title: "发送内容不能为空", icon: "none" });
  466. return;
  467. }
  468. const consultId = wx.getStorageSync("consultId");
  469. // 先添加用户消息到界面
  470. const messageId = `user-text-${Date.now()}`;
  471. this._appendMessage({
  472. id: messageId,
  473. consultRecordId: consultId || 0,
  474. sender: "user",
  475. sendType: "1",
  476. messageType: "1",
  477. messageContent: text,
  478. });
  479. // 平滑滚动到底部,确保新消息可见
  480. this._scrollToBottom();
  481. // 发送信息
  482. this._sendMessage("1", text);
  483. // 清空输入框,保持键盘展开状态
  484. // 同时重置高度为最小高度,确保立即恢复
  485. this.setData({
  486. inputText: "",
  487. textareaHeight: 80, // 重置为最小高度
  488. });
  489. },
  490. async chooseImage() {
  491. // 保存当前焦点状态,选择图片后恢复
  492. const wasFocused = this.data.inputFocus;
  493. const currentKeyboardHeight = this.data._keyboardHeight;
  494. // 临时收起键盘,选择图片需要系统界面
  495. this._hideKeyboardAndUpdatePosition();
  496. try {
  497. const res = await wx.chooseMedia({
  498. count: 1,
  499. mediaType: ["image"],
  500. sourceType: ["album", "camera"],
  501. });
  502. const files = res.tempFiles ?? [];
  503. const file = files[0];
  504. if (!file?.tempFilePath) return;
  505. const imagePath = file.tempFilePath;
  506. // 直接发送图片
  507. await this._sendImageMessage(imagePath);
  508. // 如果之前键盘是展开的,选择图片后恢复键盘
  509. if (wasFocused) {
  510. wx.nextTick?.(() => {
  511. setTimeout(() => {
  512. this.setData({
  513. inputFocus: true,
  514. keepFocus: true,
  515. });
  516. // 恢复键盘位置
  517. if (currentKeyboardHeight > 0) {
  518. this._updateInputPosition(currentKeyboardHeight);
  519. }
  520. }, 200);
  521. });
  522. }
  523. } catch (error: any) {
  524. // 用户取消选择图片时不提示错误
  525. if (error.errMsg && !error.errMsg.includes("cancel")) {
  526. console.error("选择图片失败", error);
  527. }
  528. // 取消时也恢复键盘(如果之前是展开的)
  529. if (wasFocused) {
  530. wx.nextTick?.(() => {
  531. setTimeout(() => {
  532. this.setData({
  533. inputFocus: true,
  534. keepFocus: true,
  535. });
  536. // 恢复键盘位置
  537. if (currentKeyboardHeight > 0) {
  538. this._updateInputPosition(currentKeyboardHeight);
  539. }
  540. }, 200);
  541. });
  542. }
  543. }
  544. },
  545. // 发送图片
  546. async _sendImageMessage(imagePath: string) {
  547. const consultId = wx.getStorageSync("consultId");
  548. try {
  549. // 先添加图片消息到界面(显示本地路径)
  550. const messageId = `user-image-${Date.now()}`;
  551. this._appendMessage({
  552. id: messageId,
  553. consultRecordId: consultId || 0,
  554. sender: "user",
  555. sendType: "1",
  556. messageType: "2",
  557. messageContent: imagePath, // 先用本地路径,上传后更新
  558. });
  559. // 上传图片
  560. const imageUrl = await upload({
  561. params: { name: "file", file: imagePath },
  562. transform({ data }: any) {
  563. return data?.url || data;
  564. },
  565. });
  566. // 发送图片消息
  567. await this._sendMessage("2", imageUrl);
  568. // 更新消息中的图片URL(从本地路径更新为服务器URL)
  569. const messages = this.data.messages;
  570. const messageIndex = messages.findIndex(
  571. (msg: ConsultMessage) => msg.id === messageId
  572. );
  573. if (messageIndex !== -1) {
  574. messages[messageIndex].messageContent = imageUrl;
  575. this.setData({ messages });
  576. }
  577. // 平滑滚动到底部,确保新消息可见
  578. this._scrollToBottom();
  579. } catch (error: any) {
  580. wx.showToast({
  581. title: error?.errMsg || "图片上传失败",
  582. icon: "none",
  583. });
  584. }
  585. },
  586. // 预览图片
  587. previewImage(e: any) {
  588. const currentUrl = e.currentTarget.dataset.url;
  589. // 获取所有图片消息的 URL 列表
  590. const urls = this.data.messages
  591. .filter(
  592. (msg: ConsultMessage) => msg.messageType === "2" && msg.messageContent
  593. )
  594. .map((msg: ConsultMessage) => msg.messageContent!);
  595. wx.previewImage({
  596. current: currentUrl, // 当前显示图片的链接
  597. urls: urls.length > 0 ? urls : [currentUrl], // 需要预览的图片链接列表
  598. fail: (err) => {
  599. wx.showToast({
  600. title: err?.errMsg || "预览图片失败",
  601. icon: "none",
  602. });
  603. },
  604. });
  605. },
  606. _appendMessage(message: ConsultMessage) {
  607. // 把获取的最新的消息追加到所有消息后面
  608. const messages = [...this.data.messages, message];
  609. this.setData({ messages });
  610. },
  611. },
  612. });