张田田 4 ماه پیش
والد
کامیت
7c614e3f4f
38فایلهای تغییر یافته به همراه1654 افزوده شده و 46 حذف شده
  1. 2 1
      miniprogram/app.config.ts
  2. 1 1
      miniprogram/app.json
  3. 10 0
      miniprogram/module/care/pages/careDetail/careDetail.ts
  4. 1 1
      miniprogram/module/care/pages/careDetail/careDetail.wxml
  5. 3 2
      miniprogram/module/chats/common.scss
  6. 3 0
      miniprogram/module/chats/components/guide/guide.scss
  7. 20 0
      miniprogram/module/chats/components/guide/guide.ts
  8. 13 1
      miniprogram/module/chats/components/guide/guide.wxml
  9. 11 0
      miniprogram/module/chats/components/message-consult/message-consult.json
  10. 142 0
      miniprogram/module/chats/components/message-consult/message-consult.scss
  11. 565 0
      miniprogram/module/chats/components/message-consult/message-consult.ts
  12. 72 0
      miniprogram/module/chats/components/message-consult/message-consult.wxml
  13. 2 1
      miniprogram/module/chats/components/questionnaire/questionnaire.json
  14. 56 4
      miniprogram/module/chats/components/questionnaire/questionnaire.ts
  15. 5 1
      miniprogram/module/chats/components/questionnaire/questionnaire.wxml
  16. 3 0
      miniprogram/module/chats/pages/analysis/analysis.json
  17. 1 0
      miniprogram/module/chats/pages/analysis/analysis.scss
  18. 66 0
      miniprogram/module/chats/pages/analysis/analysis.ts
  19. 2 0
      miniprogram/module/chats/pages/analysis/analysis.wxml
  20. 8 0
      miniprogram/module/chats/pages/consultation-record/consultation-record.json
  21. 151 0
      miniprogram/module/chats/pages/consultation-record/consultation-record.scss
  22. 126 0
      miniprogram/module/chats/pages/consultation-record/consultation-record.ts
  23. 78 0
      miniprogram/module/chats/pages/consultation-record/consultation-record.wxml
  24. 12 5
      miniprogram/module/chats/pages/index/index.ts
  25. BIN
      miniprogram/module/health/assets/icon/icon_consult@2x.png
  26. 6 0
      miniprogram/module/health/components/chat-record/chat-record.json
  27. 67 0
      miniprogram/module/health/components/chat-record/chat-record.scss
  28. 26 0
      miniprogram/module/health/components/chat-record/chat-record.ts
  29. 21 0
      miniprogram/module/health/components/chat-record/chat-record.wxml
  30. 2 1
      miniprogram/module/health/pages/home/home.json
  31. 38 0
      miniprogram/module/health/pages/home/home.scss
  32. 2 0
      miniprogram/module/health/pages/home/home.wxml
  33. 49 2
      miniprogram/pages/home/home.scss
  34. 43 1
      miniprogram/pages/home/home.ts
  35. 5 0
      miniprogram/pages/home/home.wxml
  36. 35 18
      miniprogram/pages/home/request.ts
  37. 6 6
      miniprogram/pages/mine/mine.ts
  38. 1 1
      miniprogram/pages/mine/mine.wxml

+ 2 - 1
miniprogram/app.config.ts

@@ -5,7 +5,8 @@ const env = miniProgram.envVersion;
 console.log("env",env)
 console.log("env",env)
 let host = "wx2.hzliuzhi.com";
 let host = "wx2.hzliuzhi.com";
 if (env === "trial") {
 if (env === "trial") {
-  host = "test.hzliuzhi.com";
+  // host = "test.hzliuzhi.com";
+  host = "wx.hzliuzhi.com:4433";
 } else if (env === "develop") {
 } else if (env === "develop") {
   // host = "wx2.hzliuzhi.com";
   // host = "wx2.hzliuzhi.com";
   host = "wx.hzliuzhi.com:4433";
   host = "wx.hzliuzhi.com:4433";

+ 1 - 1
miniprogram/app.json

@@ -4,7 +4,7 @@
     {
     {
       "name": "chats",
       "name": "chats",
       "root": "module/chats",
       "root": "module/chats",
-      "pages": ["pages/index/index"]
+      "pages": ["pages/index/index", "pages/analysis/analysis", "pages/consultation-record/consultation-record"]
     },
     },
     {
     {
       "name": "health",
       "name": "health",

+ 10 - 0
miniprogram/module/care/pages/careDetail/careDetail.ts

@@ -98,6 +98,16 @@ Page({
 
 
     return processedReports;
     return processedReports;
   },
   },
+//健康咨询记录
+onChatRecord(e: any) {
+  const item = e.currentTarget.dataset.item;
+  console.log(item,"咨询记录数据",e)
+  if (item) {
+  wx.navigateTo({
+      url: `/module/chats/pages/consultation-record/consultation-record?item=${encodeURIComponent(JSON.stringify(item))}`,
+    });
+  }
+},
 
 
   onCardRecord(e: any) {
   onCardRecord(e: any) {
     const id = e.currentTarget.dataset.id;
     const id = e.currentTarget.dataset.id;

+ 1 - 1
miniprogram/module/care/pages/careDetail/careDetail.wxml

@@ -178,7 +178,7 @@
                     <text style="color:black" wx:else>{{item.totalMeasure}}次</text>
                     <text style="color:black" wx:else>{{item.totalMeasure}}次</text>
                   </text>
                   </text>
                 </view>
                 </view>
-                <view class="link" bindtap="onReport" data-id="{{item.id}}" wx:if="{{false}}">
+                <view class="link" bindtap="onChatRecord" data-item="{{item.consults}}" wx:if="{{item.consults && item.consults.length>0}}">
                   咨询记录</view>
                   咨询记录</view>
               </view>
               </view>
               <view class="scheme-row">
               <view class="scheme-row">

+ 3 - 2
miniprogram/module/chats/common.scss

@@ -18,7 +18,7 @@
     }
     }
 
 
     .chat-card__content {
     .chat-card__content {
-      width: calc(90% - var(--avatar-size));
+      // width: calc(90% - var(--avatar-size));
       // border-color: #1B4F34;
       // border-color: #1B4F34;
     }
     }
   }
   }
@@ -49,7 +49,8 @@
   }
   }
 
 
   &__content {
   &__content {
-    max-width: calc(80% - $size);
+    // max-width: calc(80% - $size);
+    max-width: calc(90% - var(--avatar-size));
     // background-color: rgba(255, 255, 255, 0.04);
     // background-color: rgba(255, 255, 255, 0.04);
     background-color: white;
     background-color: white;
     border-radius: 0px 10px 10px 10px;
     border-radius: 0px 10px 10px 10px;

+ 3 - 0
miniprogram/module/chats/components/guide/guide.scss

@@ -2,6 +2,9 @@
 @import '../../common.scss';
 @import '../../common.scss';
 
 
 /* module/chats/components/guide/guide.wxss */
 /* module/chats/components/guide/guide.wxss */
+.chat-card__content{
+  border-radius: 0 10px 10px 10px 10px !important;
+}
 .steward-wrapper {
 .steward-wrapper {
   // --primary-color: #38FF6E;
   // --primary-color: #38FF6E;
   --primary-color: #1D6FF6;
   --primary-color: #1D6FF6;

+ 20 - 0
miniprogram/module/chats/components/guide/guide.ts

@@ -77,6 +77,26 @@ Component({
         }
         }
       }
       }
     },
     },
+    // 在线咨询
+    async handleE() {
+      const { patient } = await getPatients(/*this.data.patientId*/);
+      if (!patient) await toCertificationPage();
+      else {
+        if (this.data.active) {
+          // 清除之前的咨询结束状态,开始新咨询
+          wx.setStorageSync("consultEnded", false);
+          wx.setStorageSync("lastConsultTime", Date.now());
+          
+          wx.setStorageSync("isAnalysis", 5);
+          this.triggerEvent("next", {
+            component: "questionnaire",
+            scroll: true,
+          });
+          this.triggerEvent("nextType", { MessageType: 3 });
+          
+        }
+      }
+    },
     async handleB() {
     async handleB() {
       const { patient } = await getPatients(/*this.data.patientId*/);
       const { patient } = await getPatients(/*this.data.patientId*/);
       if (!patient) {
       if (!patient) {

+ 13 - 1
miniprogram/module/chats/components/guide/guide.wxml

@@ -37,7 +37,7 @@
       <t-icon name="chevron-right" color="#CCCCCC" size="40rpx" slot="note" />
       <t-icon name="chevron-right" color="#CCCCCC" size="40rpx" slot="note" />
     </t-cell>
     </t-cell>
     <t-cell 
     <t-cell 
-      t-class="cell-border-gradient no-border {{_.getClassName(active)}}" 
+      t-class="cell-border-gradient {{_.getClassName(active)}}" 
       t-class-hover="custom-cell-hover"
       t-class-hover="custom-cell-hover"
        t-class-title="health-analysis-title"
        t-class-title="health-analysis-title"
       title="3、健康信息管理" 
       title="3、健康信息管理" 
@@ -47,6 +47,18 @@
     >
     >
       <t-icon name="chevron-right" color="#CCCCCC" size="40rpx" slot="note" />
       <t-icon name="chevron-right" color="#CCCCCC" size="40rpx" slot="note" />
     </t-cell>
     </t-cell>
+      <t-cell 
+      t-class="cell-border-gradient no-border {{_.getClassName(active)}}" 
+      t-class-hover="custom-cell-hover"
+       t-class-title="health-analysis-title"
+      title="4、在线咨询" 
+      hover="{{active}}" 
+      bind:tap="handleE"
+      style="--td-cell-hover-color: #F5F5F5;"
+    >
+      <t-icon name="chevron-right" color="#CCCCCC" size="40rpx" slot="note" />
+    </t-cell>
+    
           <!-- 
           <!-- 
   <t-cell 
   <t-cell 
       t-class="{{_.getClassName(active)}}" 
       t-class="{{_.getClassName(active)}}" 

+ 11 - 0
miniprogram/module/chats/components/message-consult/message-consult.json

@@ -0,0 +1,11 @@
+{
+  "renderer": "skyline",
+  "component": true,
+  "pureDataPattern": "^_",
+  "usingComponents": {
+    "t-cell": "tdesign-miniprogram/cell/cell",
+    "t-icon": "tdesign-miniprogram/icon/icon",
+    "user-avatar": "../../../../components/user-avatar/user-avatar"
+  }
+}
+

+ 142 - 0
miniprogram/module/chats/components/message-consult/message-consult.scss

@@ -0,0 +1,142 @@
+@import '../../../../themes/t.cell.scss';
+@import '../../common.scss';
+
+.consult-wrapper {
+  padding-bottom: 180rpx;
+  
+  &.consult-ended {
+    padding-bottom: 0;
+  }
+}
+
+.message-content {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  min-height: 72rpx;
+  font-size: 28rpx;
+  color: #333;
+}
+
+.message-image {
+  width: 200rpx;
+  height: 200rpx;
+  border-radius: 16rpx;
+  display: block;
+}
+
+.input-panel {
+  position: fixed;
+  left: 0;
+  right: 0;
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  padding: 16rpx 24rpx;
+  box-sizing: border-box;
+  z-index: 10;
+  transition: bottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  will-change: bottom;
+}
+
+.action-bar {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin-bottom: 12rpx;
+  gap: 24rpx;
+}
+
+.action-btn {
+  display: inline-flex;
+  align-items: center;
+  padding: 0 24rpx;
+  height: 64rpx;
+  line-height: 64rpx;
+  border-radius: 12rpx;
+  font-size: 30rpx;
+}
+
+.action-btn.secondary {
+  color: black;
+}
+
+.action-btn.danger {
+  color: #1d6ff6;
+}
+
+.action-text {
+  margin-left: 8rpx;
+}
+
+.input-row {
+  display: flex;
+  align-items: center;
+}
+
+.text-input {
+  flex: 1;
+  height: 76rpx;
+  line-height: 76rpx;
+  padding: 0 24rpx;
+  background: #ffffff;
+  border-radius: 12rpx;
+  border: 1rpx solid #e6e6e6;
+  color: #333333;
+}
+
+.send-btn {
+  margin-left: 20rpx;
+  padding: 0 28rpx;
+  height: 76rpx;
+  line-height: 76rpx;
+  background: #1d6ff6;
+  color: #ffffff;
+  border-radius: 12rpx;
+  font-size: 28rpx;
+}
+
+.media-bar {
+  margin-top: 5rpx;
+}
+
+.media-btn {
+  display: inline-flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  background: #ffffff;
+  // border: 1rpx solid #e6e6e6;
+  border-radius: 12rpx;
+  padding:0 5rpx;
+}
+
+.media-text {
+  // margin-top: 8rpx;
+  color: #1d6ff6;
+  font-size: 26rpx;
+}
+
+/* 系统消息样式 */
+.system-wrapper {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin: 6px 0;
+
+  .title {
+    padding: 4px 12px;
+    font-size: 12px;
+    color: #999999;
+    border-radius: 5px;
+  }
+
+  .date {
+    font-size: 12px;
+    color: #999;
+    margin-bottom: 6px;
+  }
+}
+.chat-box{
+  padding:15rpx 0 15rpx 30rpx !important;
+}

+ 565 - 0
miniprogram/module/chats/components/message-consult/message-consult.ts

@@ -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);
+    },
+  },
+});

+ 72 - 0
miniprogram/module/chats/components/message-consult/message-consult.wxml

@@ -0,0 +1,72 @@
+<wxs module="_">
+  module.exports.isUser = function (sender) {
+    return sender === 'user'
+  }
+  module.exports.isHuman = function (sender) {
+    return sender === 'human'
+  }
+  module.exports.isSystem = function (sender) {
+    return sender === 'system'
+  }
+</wxs>
+<!--module/chats/components/message-consult/message-consult.wxml-->
+<view class="consult-wrapper {{consultEnded ? 'consult-ended' : ''}}">
+  <block wx:for="{{messages}}" wx:key="id">
+    <!-- 系统消息样式 -->
+    <view wx:if="{{_.isSystem(item.sender)}}" class="system-wrapper">
+      <view class="date">{{item.sendTime}}</view>
+      <view class="title">{{item.messageContent}}</view>
+    </view>
+    <!-- 普通消息 -->
+    <view wx:else class="chat-card {{_.isUser(item.sender) ? 'right' : 'left'}}">
+      <view class="chat-card__avatar ">
+        <user-avatar wx:if="{{_.isUser(item.sender)}}"></user-avatar>
+        <user-avatar wx:elif="{{_.isHuman(item.sender)}}"></user-avatar>
+        <image wx:else src="../../assets/robot.png" mode="aspectFill" />
+      </view>
+      <view class="chat-card__content {{item.messageType === '2' ? 'image-message' : 'text-message'}}">
+        <block wx:if="{{item.messageType === '1'}}">
+          <t-cell t-class="cell-border-gradient" bordered="{{false}}" class="chat-box">
+            <view slot="title" class="message-content">
+              <text>{{item.messageContent}}</text>
+            </view>
+          </t-cell>
+        </block>
+        <block wx:elif="{{item.messageType === '2'}}">
+          <image class="message-image" src="{{item.messageContent}}"
+           mode="aspectFill" show-menu-by-longpress="true"
+           bind:tap="previewImage" 
+           data-url="{{item.messageContent}}" />
+        </block>
+      </view>
+    </view>
+  </block>
+</view>
+
+<view class="input-panel" style="bottom: {{inputBoxBottom}}rpx;" bind:tap="tapPanel" wx:if="{{!consultEnded}}">
+  <view class="action-bar">
+    <view class="action-btn danger" bind:tap="endConsult">结束咨询</view>
+  </view>
+  <view class="input-row">
+    <input
+      class="text-input"
+      placeholder="请输入内容"
+      bind:input="handleInput"
+      value="{{inputText}}"
+      confirm-type="send"
+      bindconfirm="sendText"
+      adjust-position="{{false}}"
+      bind:focus="onInputFocus"
+      bind:blur="onInputBlur"
+      focus="{{inputFocus}}"
+    />
+    <view class="send-btn" bind:tap="sendText">发送</view>
+  </view>
+  <view class="media-bar">
+    <view class="media-btn" bind:tap="chooseImage">
+      <t-icon name="camera" size="44rpx" color="#1D6FF6" />
+      <text class="media-text">上传图片</text>
+    </view>
+  </view>
+</view>
+

+ 2 - 1
miniprogram/module/chats/components/questionnaire/questionnaire.json

@@ -13,6 +13,7 @@
     "message-report": "../message-report/message-report",
     "message-report": "../message-report/message-report",
     "message-again":"../message-again/message-again",
     "message-again":"../message-again/message-again",
     "message-follow":"../message-follow/message-follow",
     "message-follow":"../message-follow/message-follow",
-    "message-count":"../message-count/message-count"
+    "message-count":"../message-count/message-count",
+    "message-consult":"../message-consult/message-consult"
   }
   }
 }
 }

+ 56 - 4
miniprogram/module/chats/components/questionnaire/questionnaire.ts

@@ -13,7 +13,8 @@ interface Message {
     | "report"
     | "report"
     | "again"
     | "again"
     | "follow"
     | "follow"
-    | "count";
+    | "count"
+    | "consult";
 
 
   payload: AnyObject;
   payload: AnyObject;
 }
 }
@@ -33,7 +34,8 @@ Component({
     attached: function () {
     attached: function () {
       let isAnalysis: number;
       let isAnalysis: number;
       isAnalysis = wx.getStorageSync("isAnalysis");
       isAnalysis = wx.getStorageSync("isAnalysis");
-      if (isAnalysis === 3 || isAnalysis === 4) {
+      console.log("isAnalysis", isAnalysis);
+      if (isAnalysis === 3 || isAnalysis === 4 || isAnalysis === 5) {
         // 对话管家
         // 对话管家
         this._start();
         this._start();
       } else if (isAnalysis === 2) {
       } else if (isAnalysis === 2) {
@@ -69,6 +71,7 @@ Component({
     _timestamp: Date.now(),
     _timestamp: Date.now(),
     // 防止 _next 被并发/重复触发(例如 classify === 'tongue' 时)
     // 防止 _next 被并发/重复触发(例如 classify === 'tongue' 时)
     _requesting: false,
     _requesting: false,
+    consultStarted: false,
   },
   },
   observers: {
   observers: {
     "messages.**"(messages) {
     "messages.**"(messages) {
@@ -98,6 +101,9 @@ Component({
         Object.assign(questions[index], event.detail);
         Object.assign(questions[index], event.detail);
         this.setData({ "_next.questions": questions });
         this.setData({ "_next.questions": questions });
         this._next();
         this._next();
+      } else if (isAnalysis === 5) {
+        // 在线咨询暂不需要在问卷组件中处理回答
+        return;
       } else {
       } else {
         // 随访
         // 随访
         this._createMessage({
         this._createMessage({
@@ -108,6 +114,18 @@ Component({
       }
       }
     },
     },
     async _start() {
     async _start() {
+      const isAnalysis = wx.getStorageSync("isAnalysis");
+      if (isAnalysis === 5) {
+        this.setData({
+          [`_next.classify`]: "",
+          [`_next.dialogId`]: "",
+          [`_next.questions`]: [],
+          _timestamp: Date.now(),
+          consultStarted: false,
+        });
+        this._next();
+        return;
+      }
       try {
       try {
         // 获取剩余次数
         // 获取剩余次数
         const count = await Post(
         const count = await Post(
@@ -157,6 +175,7 @@ Component({
         [`_next.classify`]: "",
         [`_next.classify`]: "",
         [`_next.dialogId`]: "",
         [`_next.dialogId`]: "",
         [`_next.questions`]: [],
         [`_next.questions`]: [],
+        consultStarted: false,
       });
       });
       // 对于 isAnalysis === 4 的情况,不创建新的 guide 组件,直接触发滚动
       // 对于 isAnalysis === 4 的情况,不创建新的 guide 组件,直接触发滚动
       // 对于 isAnalysis === 3 的情况,仍然创建 guide 组件显示三个业务选项
       // 对于 isAnalysis === 3 的情况,仍然创建 guide 组件显示三个业务选项
@@ -201,13 +220,36 @@ Component({
         }
         }
       }
       }
       try {
       try {
-        // messageType 1 是随访。messageType 2 是健康评估和对话管家
+        // messageType 1 是随访。messageType 2 是健康评估和对话管家。messageType 3 是在线咨询
+        console.log("this.data.messageType", this.data.messageType);
         if (this.data.messageType === 1) {
         if (this.data.messageType === 1) {
           this._createMessage({
           this._createMessage({
             id: `again.${Date.now()}`,
             id: `again.${Date.now()}`,
             type: "again",
             type: "again",
             payload: { title: "" },
             payload: { title: "" },
           });
           });
+        } else if (this.data.messageType === 3) {
+          // 在线咨询
+          // 开始咨询,如果咨询已经开始,则不重新开始
+          if (!this.data.consultStarted) {
+            try {
+              // 开始咨询  获取咨询id
+              const res = await Post(`/consultManage/start`);
+              if (res.data) {
+                // 存储咨询中的id
+                wx.setStorageSync("consultId", res.data);
+                this._createMessage({
+                  id: `consult.${Date.now()}`,
+                  type: "consult",
+                  payload: { title: "咨询开始" },
+                });
+                this.setData({ consultStarted: true });
+                this.triggerEvent("to");
+              }
+            } catch (error) {
+              console.error("咨询开始失败", error);
+            }
+          }
         } else if (this.data.messageType === 2) {
         } else if (this.data.messageType === 2) {
           let data: any = {};
           let data: any = {};
           const res = await Post(
           const res = await Post(
@@ -217,7 +259,7 @@ Component({
           data = res.data;
           data = res.data;
 
 
           data.nextQuestions?.forEach((question: any, index: number) => {
           data.nextQuestions?.forEach((question: any, index: number) => {
-            // isAnalysis 2是随访  3健康管家 4健康评估
+            // isAnalysis 2是随访  3健康管家 4健康评估 5在线咨询
             if (isAnalysis === 2) {
             if (isAnalysis === 2) {
               // 随访
               // 随访
               if (question.css === "tongue") {
               if (question.css === "tongue") {
@@ -356,5 +398,15 @@ Component({
         [`messages.${index - 1}`]: body,
         [`messages.${index - 1}`]: body,
       });
       });
     },
     },
+    // 处理咨询事件
+    handleConsultEvent(event: { detail: { type: string } }) {
+      if (event.detail.type === "end") {
+        // 结束咨询时,通知父组件显示guide菜单组件
+        this.triggerEvent("next", { component: "guide", scroll: true });
+        setTimeout(() => {
+          this.triggerEvent("to");
+        }, 100);
+      }
+    },
   },
   },
 });
 });

+ 5 - 1
miniprogram/module/chats/components/questionnaire/questionnaire.wxml

@@ -10,7 +10,11 @@
 <block wx:for="{{messages}}" wx:key="id">
 <block wx:for="{{messages}}" wx:key="id">
   <message-again wx:if="{{_.show(item,'again')}}" bind:nextType="nextType" workId="{{workId}}" bind:boxBottom="boxBottom" bind:scroll="scroll"/>
   <message-again wx:if="{{_.show(item,'again')}}" bind:nextType="nextType" workId="{{workId}}" bind:boxBottom="boxBottom" bind:scroll="scroll"/>
   <message-count wx:elif="{{_.show(item,'count')}}" payload="{{item.payload}}" id="{{item.id}}" active="{{_.active(lastId,item.id)}}" bind:next="handle" /> 
   <message-count wx:elif="{{_.show(item,'count')}}" payload="{{item.payload}}" id="{{item.id}}" active="{{_.active(lastId,item.id)}}" bind:next="handle" /> 
-  <message-analysis wx:elif="{{_.show(item,'analysis')}}" active="{{_.active(lastId,item.id)}}" id="{{item.id}}" payload="{{item.payload}}" bind:next="handle" messageType="{{messageType}}" />
+  <message-analysis wx:elif="{{_.show(item,'analysis')}}" active="{{_.active(lastId,item.id)}}" id="{{item.id}}"
+   payload="{{item.payload}}" 
+  bind:next="handle"
+   messageType="{{messageType}}" />
+  <message-consult wx:elif="{{_.show(item,'consult')}}" id="{{item.id}}" active="{{_.active(lastId,item.id)}}" bind:boxBottom="boxBottom" bind:scroll="scroll" bind:consultEvent="handleConsultEvent" />
   <message-follow wx:elif="{{_.show(item,'follow')}}" bind:nextType="nextType" workId="{{workId}}" bind:boxBottom="boxBottom" />
   <message-follow wx:elif="{{_.show(item,'follow')}}" bind:nextType="nextType" workId="{{workId}}" bind:boxBottom="boxBottom" />
   <message-select wx:elif="{{_.show(item,'select')}}" active="{{_.active(lastId,item.id)}}" id="{{item.id}}" payload="{{item.payload}}" bind:next="handle" />
   <message-select wx:elif="{{_.show(item,'select')}}" active="{{_.active(lastId,item.id)}}" id="{{item.id}}" payload="{{item.payload}}" bind:next="handle" />
   <message-text wx:elif="{{_.show(item,'text')}}" active="{{_.active(lastId,item.id)}}" id="{{item.id}}" payload="{{item.payload}}" bind:next="handle" />
   <message-text wx:elif="{{_.show(item,'text')}}" active="{{_.active(lastId,item.id)}}" id="{{item.id}}" payload="{{item.payload}}" bind:next="handle" />

+ 3 - 0
miniprogram/module/chats/pages/analysis/analysis.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 1 - 0
miniprogram/module/chats/pages/analysis/analysis.scss

@@ -0,0 +1 @@
+/* module/chats/pages/analysis/analysis.wxss */

+ 66 - 0
miniprogram/module/chats/pages/analysis/analysis.ts

@@ -0,0 +1,66 @@
+// module/chats/pages/analysis/analysis.ts
+Page({
+
+  /**
+   * 页面的初始数据
+   */
+  data: {
+
+  },
+
+  /**
+   * 生命周期函数--监听页面加载
+   */
+  onLoad() {
+
+  },
+
+  /**
+   * 生命周期函数--监听页面初次渲染完成
+   */
+  onReady() {
+
+  },
+
+  /**
+   * 生命周期函数--监听页面显示
+   */
+  onShow() {
+
+  },
+
+  /**
+   * 生命周期函数--监听页面隐藏
+   */
+  onHide() {
+
+  },
+
+  /**
+   * 生命周期函数--监听页面卸载
+   */
+  onUnload() {
+
+  },
+
+  /**
+   * 页面相关事件处理函数--监听用户下拉动作
+   */
+  onPullDownRefresh() {
+
+  },
+
+  /**
+   * 页面上拉触底事件的处理函数
+   */
+  onReachBottom() {
+
+  },
+
+  /**
+   * 用户点击右上角分享
+   */
+  onShareAppMessage() {
+
+  }
+})

+ 2 - 0
miniprogram/module/chats/pages/analysis/analysis.wxml

@@ -0,0 +1,2 @@
+<!--module/chats/pages/analysis/analysis.wxml-->
+<text>module/chats/pages/analysis/analysis.wxml</text>

+ 8 - 0
miniprogram/module/chats/pages/consultation-record/consultation-record.json

@@ -0,0 +1,8 @@
+{
+  "renderer": "skyline",
+  "component": true,
+  "usingComponents": {
+    "t-navbar": "tdesign-miniprogram/navbar/navbar",
+    "t-avatar": "tdesign-miniprogram/avatar/avatar"
+  }
+}

+ 151 - 0
miniprogram/module/chats/pages/consultation-record/consultation-record.scss

@@ -0,0 +1,151 @@
+@import "../../../../themes/page.scss";
+
+/* module/chats/pages/consultation-record/consultation-record.wxss */
+
+.page-scroll__container {
+  box-sizing: border-box;
+  overflow-y: auto;
+  padding-top: 10px;
+  background-color: #f5f5f5;
+}
+
+.consultation-container {
+  padding: 40rpx 30rpx;
+  background-color: #ffffff;
+}
+
+.consultation-session {
+  margin-bottom: 60rpx;
+
+  &:last-child {
+    margin-bottom: 0;
+  }
+}
+
+.timestamp {
+  text-align: center;
+  font-size: 24rpx;
+  color: #999999;
+  margin: 0rpx 0 10rpx;
+}
+
+.status-message {
+  text-align: center;
+  font-size: 24rpx;
+  color: #999999;
+  margin: 15rpx 0 15rpx 0;
+}
+
+.messages-list {
+  display: flex;
+  flex-direction: column;
+  gap: 30rpx;
+}
+
+.message-item {
+  display: flex;
+  align-items: flex-start;
+  margin: 20rpx 0 20rpx 0;
+
+  &--agent {
+    justify-content: flex-start;
+  }
+
+  &--user {
+    justify-content: flex-end;
+  }
+}
+
+.message-avatar {
+  flex-shrink: 0;
+}
+
+.message-bubble {
+  max-width: 500rpx;
+  padding: 20rpx 24rpx;
+  border-radius: 12rpx;
+  position: relative;
+  word-wrap: break-word;
+  margin-left: 20rpx;
+
+  &--agent {
+    background-color: #ffffff;
+    border: 1rpx solid #e5e5e5;
+
+    // 三角形尾巴(指向左侧头像)
+    &::before {
+      content: "";
+      position: absolute;
+      left: -10rpx;
+      top: 16rpx;
+      width: 0;
+      height: 0;
+      border-top: 10rpx solid transparent;
+      border-bottom: 10rpx solid transparent;
+      border-right: 10rpx solid #ffffff;
+      z-index: 2;
+    }
+
+    // 三角形边框
+    &::after {
+      content: "";
+      position: absolute;
+      left: -11rpx;
+      top: 16rpx;
+      width: 0;
+      height: 0;
+      border-top: 10rpx solid transparent;
+      border-bottom: 10rpx solid transparent;
+      border-right: 10rpx solid #e5e5e5;
+      z-index: 1;
+    }
+  }
+
+  &--user {
+    background-color: #409eff;
+    margin-right: 20rpx;
+    // 三角形尾巴(指向右侧头像)
+    &::before {
+      content: "";
+      position: absolute;
+      right: -10rpx;
+      top: 16rpx;
+      width: 0;
+      height: 0;
+      border-top: 10rpx solid transparent;
+      border-bottom: 10rpx solid transparent;
+      border-left: 10rpx solid #409eff;
+    }
+  }
+}
+
+.message-text {
+  font-size: 28rpx;
+  color: #000000;
+  line-height: 1.5;
+  word-wrap: break-word;
+
+  &--user {
+    color: #ffffff;
+  }
+}
+.message-item--system {
+  width: 100%;
+  align-items: center;
+  justify-content: center;
+  .message-bubble--system {
+    width: 100%;
+    text-align: center;
+    .message-text--system {
+      color: #999999 !important;
+      font-size: 24rpx;
+    }
+  }
+}
+.message-image {
+  width: 200rpx;
+  height: 200rpx;
+  background: transparent !important;
+  display: block;
+  border-radius: 8rpx;
+}

+ 126 - 0
miniprogram/module/chats/pages/consultation-record/consultation-record.ts

@@ -0,0 +1,126 @@
+import PageContainerBehavior from "../../../../core/behavior/page-container.behavior";
+import { Post } from "../../../../lib/request/method";
+// module/chats/pages/consultation-record/consultation-record.ts
+
+Page({
+  behaviors: [PageContainerBehavior],
+  properties: {},
+  data: {
+    //有item传过来不分页
+    //是否分页
+    isPage: false,
+    page: 1,
+    pageSize: 2,
+    hasMore: true,
+    isLoading: false,
+    consultationList: [] as Array<{
+      id: number;
+      startTime: string;
+      endTime: string;
+      manualTime: string; //转人工的时间
+      items: Array<{
+        id: number; //咨询记录id
+        consultRecordId: number; //咨询记录id
+        messageContent: string;
+        sendTime: string; //发送时间
+        sendType: string; //	发送类型 1-患者 2-医生 3-系统 4-AI
+        messageType: string; //	消息类型 1-文本 2-图片
+        isRead: string;
+      }>;
+    }>,
+  },
+  observers: {},
+  onLoad(options: any) {
+    console.log(options, "咨询记录数据");
+    if (options.item) {
+      const item = JSON.parse(decodeURIComponent(options.item));
+      this.setData({
+        consultationList: item,
+        isPage: false,
+      });
+    } else {
+      this.setData({
+        isPage: true,
+      });
+      this.loadData();
+    }
+  },
+  // 获取聊天记录的数据
+  async loadData() {
+    if (this.data.isLoading || !this.data.hasMore) return;
+    this.setData({ isLoading: true });
+    try {
+      const res = await Post(
+        `/consultManage/pageConsult?pageNum=${this.data.page}&pageSize=${this.data.pageSize}`,
+        {}
+      );
+      console.log("res=咨询记录列表", res.data.data);
+
+      if (res.data && res.data.data && res.data.data.length > 0) {
+        // 追加新数据到现有列表
+        const newList =
+          this.data.page === 1
+            ? res.data.data
+            : [...this.data.consultationList, ...res.data.data];
+
+        // 判断是否还有更多数据
+        // 方式1: 如果有 total 字段,通过比较已加载数量和总数判断
+        // 方式2: 如果返回的数据长度小于 pageSize,说明没有更多数据了
+        let hasMoreData = false;
+        if (res.data.total !== undefined && res.data.total !== null) {
+          hasMoreData = newList.length < res.data.total;
+        } else {
+          // 如果返回的数据长度等于 pageSize,可能还有更多数据
+          hasMoreData = res.data.data.length >= this.data.pageSize;
+        }
+
+        this.setData({
+          consultationList: newList,
+          page: this.data.page + 1,
+          hasMore: hasMoreData,
+          isLoading: false,
+        });
+      } else {
+        // 没有数据时,第一页清空列表,后续页保留已有数据
+        this.setData({
+          ...(this.data.page === 1 && { consultationList: [] }),
+          hasMore: false,
+          isLoading: false,
+        });
+      }
+    } catch (error) {
+      console.error("加载咨询记录失败", error);
+      this.setData({
+        isLoading: false,
+      });
+    }
+  },
+
+  onScrollToLower() {
+    console.log("onScrollToLower");
+    if (this.data.isPage) {
+      this.loadData();
+    }
+  },
+  //预览图片
+  previewImage(e: any) {
+    const currentUrl = e.currentTarget.dataset.url;
+    // 获取所有咨询记录中所有图片消息的 URL 列表
+    const urls: string[] = [];
+    this.data?.consultationList?.forEach((consultation) => {
+      consultation?.items?.forEach((item) => {
+        if (item?.messageType === "2" && item?.messageContent) {
+          urls.push(item?.messageContent);
+        }
+      });
+    });
+
+    wx.previewImage({
+      current: currentUrl, // 当前显示图片的链接
+      urls: urls.length > 0 ? urls : [currentUrl], // 需要预览的图片链接列表
+      fail: (err) => {
+        console.error("预览图片失败", err);
+      },
+    });
+  },
+});

+ 78 - 0
miniprogram/module/chats/pages/consultation-record/consultation-record.wxml

@@ -0,0 +1,78 @@
+<!--module/chats/pages/consultation-record/consultation-record.wxml-->
+<t-navbar title="咨询记录" left-arrow />
+<scroll-view 
+  id="scrollview" 
+  class="page-scroll__container" 
+  type="list" 
+  scroll-y 
+  enhanced="{{true}}" 
+  enable-passive 
+  style="height: calc(100vh - 180rpx);"
+  bindscrolltolower="onScrollToLower"
+  lower-threshold="{{50}}"
+>
+  <view class="consultation-container">
+    <block wx:for="{{consultationList}}" wx:key="id">
+      <!-- 开始咨询 -->
+      <view class="consultation-session">
+        <view class="timestamp">{{item.startTime}}</view>
+        <view class="status-message">开始咨询</view>
+        
+        <!-- 消息列表 -->
+        <view class="messages-list">
+          <block wx:for="{{item.items}}" wx:key="id" wx:for-item="message">
+            <!-- 系统消息 -->
+            <view wx:if="{{message.sendType === '3'}}" class="message-item message-item--system">
+              <view class="message-bubble message-bubble--system">
+                  <view class="timestamp">{{item.startTime}}</view>
+                <text class="message-text message-text--system">{{message.messageContent}}</text>
+              </view>
+            </view>
+            
+            <!-- 患者消息 (sendType === '1') - 右侧显示 -->
+            <view wx:elif="{{message.sendType === '1'}}" class="message-item message-item--user">
+              <view class="message-bubble {{message.messageType==='1'?'message-bubble--user':''}}">
+                <!-- 文本消息 -->
+                <block wx:if="{{message.messageType === '1'}}">
+                  <text class="message-text message-text--user">{{message.messageContent}}</text>
+                </block>
+                <!-- 图片消息 -->
+                <block wx:elif="{{message.messageType === '2'}}">
+                  <image class="message-image" src="{{message.messageContent}}" mode="aspectFill" show-menu-by-longpress="true" bind:tap="previewImage" data-url="{{message.messageContent}}" />
+                </block>
+              </view>
+              <t-avatar class="message-avatar" icon="user" size="40px" />
+            </view>
+            
+            <!-- 医生/AI消息 (sendType === '2' 或 '4') - 左侧显示 -->
+            <view wx:else class="message-item message-item--agent">
+              <t-avatar class="message-avatar message-avatar--agent" icon="{{message.sendType === '2' ? 'user' : 'service'}}" size="40px" />
+              <view class="message-bubble {{message.messageType==='1'?'message-bubble--agent':''}}">
+                <!-- 文本消息 -->
+                <block wx:if="{{message.messageType === '1'}}">
+                  <text class="message-text">{{message.messageContent}}</text>
+                </block>
+                <!-- 图片消息 -->
+                <block wx:elif="{{message.messageType === '2'}}">
+                  <image class="message-image" src="{{message.messageContent}}" mode="aspectFill" show-menu-by-longpress="true" bind:tap="previewImage" data-url="{{message.messageContent}}" />
+                </block>
+              </view>
+            </view>
+          </block>
+        </view>
+        
+        <!-- 咨询结束 -->
+        <view class="timestamp">{{item.endTime}}</view>
+        <view class="status-message">咨询结束</view>
+      </view>
+    </block>
+    
+    <!-- 加载更多/无更多数据提示 -->
+    <view class="loading-container" style="text-align: center; padding: 20rpx; color: #999; font-size: 24rpx;" wx:if="{{isPage}}">
+      <view wx:if="{{isLoading}}">加载中...</view>
+      <view wx:elif="{{!hasMore}}">没有更多数据了</view>
+    </view>
+  </view>
+</scroll-view>
+
+  

+ 12 - 5
miniprogram/module/chats/pages/index/index.ts

@@ -42,7 +42,7 @@ Component({
       const safeBottom = windowHeight - safeAreaBottom; // 安全区底部距离(px)
       const safeBottom = windowHeight - safeAreaBottom; // 安全区底部距离(px)
       const safeBottomRpx = (750 / systemInfo.windowWidth) * safeBottom; // rpx
       const safeBottomRpx = (750 / systemInfo.windowWidth) * safeBottom; // rpx
       this.setData({
       this.setData({
-        paddingBottom: this.data.paddingBottom+safeBottomRpx,
+        paddingBottom: this.data.paddingBottom + safeBottomRpx,
       });
       });
     },
     },
     ready() {
     ready() {
@@ -67,7 +67,7 @@ Component({
     inputBoxBottom: 0,
     inputBoxBottom: 0,
     tabbarValue: "/module/chats/pages/index/index",
     tabbarValue: "/module/chats/pages/index/index",
     analysisCount: 0,
     analysisCount: 0,
-    paddingBottom: 100,  // 底部tabbar高度是100
+    paddingBottom: 100, // 底部tabbar高度是100
   },
   },
   observers: {
   observers: {
     "messages.**"(messages) {
     "messages.**"(messages) {
@@ -108,17 +108,24 @@ Component({
     scrollIntoView(event?: ScrollIntoViewEvent) {
     scrollIntoView(event?: ScrollIntoViewEvent) {
       clearTimeout(getScrollcontext.call(this).timer);
       clearTimeout(getScrollcontext.call(this).timer);
       const id = event?.detail ?? this.data.lastId;
       const id = event?.detail ?? this.data.lastId;
-      const doScroll = (scroll: WechatMiniprogram.ScrollViewContext | undefined) => {
+      const doScroll = (
+        scroll: WechatMiniprogram.ScrollViewContext | undefined
+      ) => {
         if (!scroll) return;
         if (!scroll) return;
         if (id === "bottom") {
         if (id === "bottom") {
-          scroll.scrollTo({ top: Number.MAX_SAFE_INTEGER, animated: true });
+          // scroll.scrollTo({ top: Number.MAX_SAFE_INTEGER, animated: true });
+          scroll.scrollTo({
+            top: Number.MAX_SAFE_INTEGER,
+            animated: false,
+          });
         } else if (id) {
         } else if (id) {
           scroll.scrollIntoView(`#${id}`, { alignment: "end" });
           scroll.scrollIntoView(`#${id}`, { alignment: "end" });
         }
         }
         // 再补一次,处理内容异步渲染晚于滚动触发的情况
         // 再补一次,处理内容异步渲染晚于滚动触发的情况
         setTimeout(() => {
         setTimeout(() => {
           if (id === "bottom") {
           if (id === "bottom") {
-            scroll.scrollTo({ top: Number.MAX_SAFE_INTEGER, animated: true });
+            // scroll.scrollTo({ top: Number.MAX_SAFE_INTEGER, animated: true });
+            scroll.scrollTo({ top: Number.MAX_SAFE_INTEGER, animated: false });
           } else if (id) {
           } else if (id) {
             scroll.scrollIntoView(`#${id}`, { alignment: "end" });
             scroll.scrollIntoView(`#${id}`, { alignment: "end" });
           }
           }

BIN
miniprogram/module/health/assets/icon/icon_consult@2x.png


+ 6 - 0
miniprogram/module/health/components/chat-record/chat-record.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+    "t-icon": "tdesign-miniprogram/icon/icon"
+  }
+}

+ 67 - 0
miniprogram/module/health/components/chat-record/chat-record.scss

@@ -0,0 +1,67 @@
+@import "../../../../themes//t.cell.scss";
+@import "../../report-common.scss";
+@import "../../../../themes/card.scss";
+/* module/health/components/follow-evaluation/follow-evaluation.wxss */
+.card-wrapper {
+  margin: 0 0rpx 60rpx 0;
+}
+.constitution-container {
+  border-radius: 30rpx !important;
+  background: linear-gradient(180deg, #D6E4F5 0%, #F3F4F6 100%);
+  overflow: hidden;
+}
+
+.text-title {
+  font-size: 16px;
+  color: black;
+  font-weight: 500;
+}
+
+.card-title {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20rpx;
+  margin-left: 30rpx;
+}
+
+.icon-title {
+  width: 20px;
+  height: 20px;
+  margin-right: 10rpx;
+}
+
+.card-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 10rpx;
+  padding: 20px 0 10px 0 !important;
+}
+
+
+.header-icon {
+  border: 1.5rpx dashed #1976d2;
+  border-radius: 8rpx;
+  background: #fff;
+  margin-right: 16rpx;
+  padding: 6rpx;
+}
+.header-title {
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #222;
+}
+.more-link {
+  position: absolute;
+  right: 32rpx;
+  color: #1976d2;
+  font-size: 24rpx;
+  display: flex;
+  align-items: center;
+}
+
+.constitution-box{
+  background-image: url('https://wx.hzliuzhi.com:4433/manager/file/statics/2025/08/21/WechatIMG731_20250821155626A830.jpg');
+  background-size: cover;
+  background-position: center;
+}

+ 26 - 0
miniprogram/module/health/components/chat-record/chat-record.ts

@@ -0,0 +1,26 @@
+// module/health/components/chat-record/chat-record.ts
+Component({
+  behaviors: ["wx://form-field-group"],
+  lifetimes: {
+    attached() {
+    },
+  },
+  methods: {
+
+    // 更多记录
+    onMore() {
+      wx.navigateTo({
+        url: "/module/chats/pages/consultation-record/consultation-record",
+      });
+    },
+ 
+  },
+  properties: {},
+
+  /**
+   * 组件的初始数据
+   */
+  data: {
+  },
+  observers: {},
+});

+ 21 - 0
miniprogram/module/health/components/chat-record/chat-record.wxml

@@ -0,0 +1,21 @@
+<wxs module="_">
+
+</wxs>
+<!--module/health/components/care-scheme/care-scheme.wxml-->
+<view class="card-wrapper" bindtap="onMore">
+  <view class="constitution-container">
+    <view class="card-header constitution-box">
+      <view class="card-title">
+        <view>
+          <image src="../../assets/icon/icon_consult@2x.png" class="icon-title" />
+        </view>
+        <view class="text-title">咨询记录</view>
+      </view>
+      <view class="more-link">
+      <t-icon t-class="icon" name="chevron-right-double-s" size="24px" />
+      </view>
+      <slot name="extra"></slot>
+    </view>
+ 
+  </view>
+</view>

+ 2 - 1
miniprogram/module/health/pages/home/home.json

@@ -13,6 +13,7 @@
     "follow-record": "../../components/follow-record/follow-record",
     "follow-record": "../../components/follow-record/follow-record",
     "care-scheme": "../../components/care-scheme/care-scheme",
     "care-scheme": "../../components/care-scheme/care-scheme",
     "nodrug-therapy": "../../components/nodrug-therapy/nodrug-therapy",
     "nodrug-therapy": "../../components/nodrug-therapy/nodrug-therapy",
-    "care-record": "../../components/care-record/care-record"
+    "care-record": "../../components/care-record/care-record",
+    "chat-record": "../../components/chat-record/chat-record"
   }
   }
 }
 }

+ 38 - 0
miniprogram/module/health/pages/home/home.scss

@@ -32,4 +32,42 @@
     height: 128px;
     height: 128px;
     margin-left: 8px;
     margin-left: 8px;
   }
   }
+}
+.card-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 10rpx;
+  padding: 20px 0 0px 0 !important;
+  margin-top: 20rpx;
+}
+.constitution-box{
+  background-image: url('https://wx.hzliuzhi.com:4433/manager/file/statics/2025/08/21/WechatIMG731_20250821155626A830.jpg');
+  background-size: cover;
+  background-position: center;
+}
+.card-title {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20rpx;
+  margin-left: 30rpx;
+}
+
+.icon-title {
+  width: 20px;
+  height: 20px;
+  margin-right: 10rpx;
+}
+.text-title {
+  font-size: 16px;
+  color: black;
+  font-weight: 500;
+}
+.more-link {
+  position: absolute;
+  right: 32rpx;
+  color: #1976d2;
+  font-size: 24rpx;
+  display: flex;
+  align-items: center;
 }
 }

+ 2 - 0
miniprogram/module/health/pages/home/home.wxml

@@ -25,6 +25,8 @@
     <care-record></care-record>
     <care-record></care-record>
     <!--线下非药物治疗-->
     <!--线下非药物治疗-->
     <nodrug-therapy></nodrug-therapy>
     <nodrug-therapy></nodrug-therapy>
+     <!--咨询记录-->
+<chat-record></chat-record>
   </scroll-view>
   </scroll-view>
 </view>
 </view>
 <t-message id="{{$messageId}}"></t-message>
 <t-message id="{{$messageId}}"></t-message>

+ 49 - 2
miniprogram/pages/home/home.scss

@@ -5,7 +5,7 @@
 
 
 .body-img {
 .body-img {
   position: relative;
   position: relative;
-
+  pointer-events: none;
   .body-bg-image {
   .body-bg-image {
     position: absolute;
     position: absolute;
     top: 0;
     top: 0;
@@ -136,6 +136,7 @@
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
   margin-bottom: 15rpx;
   margin-bottom: 15rpx;
+  position: relative;
 }
 }
 
 
 .report-container {
 .report-container {
@@ -427,10 +428,12 @@ $scale: 0.5;
   padding-bottom: calc(100rpx + env(safe-area-inset-bottom));
   padding-bottom: calc(100rpx + env(safe-area-inset-bottom));
   box-sizing: border-box;
   box-sizing: border-box;
 }
 }
-.user-pageBox{
+
+.user-pageBox {
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
 }
 }
+
 .care-container {
 .care-container {
   margin-top: 10px;
   margin-top: 10px;
   border-radius: 12rpx;
   border-radius: 12rpx;
@@ -465,12 +468,14 @@ $scale: 0.5;
   border-bottom: 1px solid #f0f0f0;
   border-bottom: 1px solid #f0f0f0;
   padding: 24rpx 20rpx;
   padding: 24rpx 20rpx;
 }
 }
+
 .detail-box {
 .detail-box {
   display: flex;
   display: flex;
   flex-direction: column;
   flex-direction: column;
   align-items: center;
   align-items: center;
   justify-content: center;
   justify-content: center;
 }
 }
+
 .item-main {
 .item-main {
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
@@ -521,11 +526,13 @@ $scale: 0.5;
   display: block;
   display: block;
   margin: 10rpx auto 12rpx auto;
   margin: 10rpx auto 12rpx auto;
 }
 }
+
 .flex {
 .flex {
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
+
 .item-detail {
 .item-detail {
   font-size: 28rpx;
   font-size: 28rpx;
   color: #222;
   color: #222;
@@ -536,12 +543,14 @@ $scale: 0.5;
   justify-content: space-between;
   justify-content: space-between;
   align-items: center;
   align-items: center;
 }
 }
+
 .item-box {
 .item-box {
   display: flex;
   display: flex;
   flex-direction: column;
   flex-direction: column;
   justify-content: center;
   justify-content: center;
   padding-top: 10px;
   padding-top: 10px;
 }
 }
+
 .verify-record {
 .verify-record {
   cursor: pointer;
   cursor: pointer;
   color: #1976d2;
   color: #1976d2;
@@ -615,10 +624,12 @@ $scale: 0.5;
   0% {
   0% {
     transform: rotate(0deg);
     transform: rotate(0deg);
   }
   }
+
   100% {
   100% {
     transform: rotate(360deg);
     transform: rotate(360deg);
   }
   }
 }
 }
+
 .healthyAnalyze {
 .healthyAnalyze {
   font-size: 40rpx;
   font-size: 40rpx;
   text-align: center;
   text-align: center;
@@ -633,3 +644,39 @@ $scale: 0.5;
   height: 180rpx;
   height: 180rpx;
   width: 100%;
   width: 100%;
 }
 }
+
+.chat-status {
+  pointer-events: auto;
+  display: inline-flex;
+  align-items: center;
+  background: #e5eaff;
+  box-shadow: 0rpx 6rpx 6rpx 0rpx rgba(43, 78, 135, 0.12);
+  border: 2rpx solid rgba(29, 111, 246, 0.3);
+  border-radius: 40rpx 0rpx 0rpx 40rpx;
+  padding: 15rpx 30rpx 15rpx 30rpx;
+  position: absolute !important;
+  right: 0;
+  top: 25rpx;
+  color: #1d6ff6;
+  font-weight: 500;
+  font-size: 24rpx;
+  z-index: 999999;
+  &__dot {
+    width: 20rpx;
+    height: 20rpx;
+    background-color: #6df28c; // 绿色圆点
+    border-radius: 50%;
+    position: absolute;
+    left: -5rpx;
+    top: -5rpx;
+    border: 2rpx solid #ffffff;
+    z-index: 10;
+  }
+
+  &__text {
+    font-size: 22rpx;
+    color: #1f457f; // 深蓝色文字
+    line-height: 1;
+    white-space: nowrap;
+  }
+}

+ 43 - 1
miniprogram/pages/home/home.ts

@@ -25,6 +25,7 @@ import {
   getCareList,
   getCareList,
 } from "./request";
 } from "./request";
 import { toCertificationPage, toChats } from "./router";
 import { toCertificationPage, toChats } from "./router";
+import { Post } from "../../lib/request/method";
 // import { useLocation } from "../../lib/use/use-location";
 // import { useLocation } from "../../lib/use/use-location";
 
 
 Page({
 Page({
@@ -80,6 +81,10 @@ Page({
       type: "image" | "video";
       type: "image" | "video";
       src: string;
       src: string;
     }>,
     }>,
+    // 是否在咨询中
+    isConsulting: false,
+    // 是否有新消息
+    hasNewMessage: false,
   },
   },
   behaviors: [
   behaviors: [
     PageContainerBehavior,
     PageContainerBehavior,
@@ -177,6 +182,8 @@ Page({
         url: "/module/user/pages/user-certification/user-certification?type=home",
         url: "/module/user/pages/user-certification/user-certification?type=home",
       });
       });
     }
     }
+    // 检查咨询状态
+    this.checkConsultationStatus();
     // 如果用户没有手机号每次进入页面都提示  点击跳到注册页补充
     // 如果用户没有手机号每次进入页面都提示  点击跳到注册页补充
     // todo 要先判断用户有没有手机号 isPerfectInfo是true 就出来弹窗提示用户
     // todo 要先判断用户有没有手机号 isPerfectInfo是true 就出来弹窗提示用户
     // if ((this.data.patient as any)?.isPerfectInfo ?? true) {
     // if ((this.data.patient as any)?.isPerfectInfo ?? true) {
@@ -704,6 +711,41 @@ Page({
     wx.setStorageSync("showGuideActive", 1);
     wx.setStorageSync("showGuideActive", 1);
     wx.setStorageSync("isAnalysis", 3);
     wx.setStorageSync("isAnalysis", 3);
   },
   },
+  // 检查咨询状态
+  async checkConsultationStatus() {
+    const res = await Post("/consultManage/getConsultIng");
+    const isConsulting = !!res.data;
+    if (isConsulting) {
+      // 保存咨询id,标记咨询未结束
+      wx.setStorageSync("consultId", res.data);
+      wx.setStorageSync("consultEnded", false);
+      // 判断是否有新消息(只有在有咨询时才判断) 调获取新消息
+      const isNew = await Post(`/consultManage/getLatestMsgs/${res?.data}`);
+      const hasNewMessage = isNew?.data?.length > 0;
+      this.setData({
+        isConsulting: true,
+        hasNewMessage: hasNewMessage,
+      });
+    } else {
+      // 没有咨询,清理相关数据
+      wx.setStorageSync("consultEnded", true);
+      wx.removeStorageSync("consultId");
+      this.setData({
+        isConsulting: false,
+        hasNewMessage: false,
+      });
+    }
+  },
+  // 跳转到咨询页面
+  goToConsultation() {
+    // 跳转之后 未读的消息变为已读 就没有最新消息了 不显示绿点
+    this.setData({ hasNewMessage: false });
+    // 跳转到咨询页面,显示 message-consult 组件
+    wx.navigateTo({
+      url: `/module/chats/pages/index/index?component=questionnaire&messageType=3`,
+    });
+    wx.setStorageSync("isAnalysis", 5);
+  },
   async isGoPunchcard(e: any) {
   async isGoPunchcard(e: any) {
     const { id, signintime } = e.currentTarget.dataset;
     const { id, signintime } = e.currentTarget.dataset;
     // 已经打卡了
     // 已经打卡了
@@ -810,7 +852,7 @@ Page({
    */
    */
   onCarouselFullscreenChange(e: { detail?: { fullScreen?: boolean } }) {
   onCarouselFullscreenChange(e: { detail?: { fullScreen?: boolean } }) {
     console.log(e, "全屏模式");
     console.log(e, "全屏模式");
-    const fullScreen = !!(e.detail?.fullScreen);
+    const fullScreen = !!e.detail?.fullScreen;
     this.setData({
     this.setData({
       tabbarHidden: fullScreen,
       tabbarHidden: fullScreen,
     });
     });

+ 5 - 0
miniprogram/pages/home/home.wxml

@@ -21,6 +21,11 @@
     </view>
     </view>
 
 
     <view class="body-img">
     <view class="body-img">
+      <!-- 咨询中的状态-->
+      <view class="chat-status" wx:if="{{isConsulting}}" bind:tap="goToConsultation">
+        <view class="chat-status__dot" wx:if="{{hasNewMessage}}"></view>
+        <text class="chat-status__text">咨询中...</text>
+      </view>
       <!-- 使用 image 标签确保图片清晰度 -->
       <!-- 使用 image 标签确保图片清晰度 -->
       <image class="body-bg-image" src="../../assets/bg/pic_body@2x.png" mode="aspectFit" />
       <image class="body-bg-image" src="../../assets/bg/pic_body@2x.png" mode="aspectFit" />
       <view class="header-container">
       <view class="header-container">

+ 35 - 18
miniprogram/pages/home/request.ts

@@ -39,12 +39,14 @@ export function getPatients(id?: string) {
 
 
     return { patient, patients: data };
     return { patient, patients: data };
   };
   };
-  return Post("/mobileAccountManage/getPatsByAid", {}, { transform }).then(res => {
-    const patientId = res.patient?.patientId;
-    if (patientId) wx.setStorageSync("patientId", patientId);
-    else wx.removeStorageSync("patientId");
-    return res;
-  });
+  return Post("/mobileAccountManage/getPatsByAid", {}, { transform }).then(
+    (res) => {
+      const patientId = res.patient?.patientId;
+      if (patientId) wx.setStorageSync("patientId", patientId);
+      else wx.removeStorageSync("patientId");
+      return res;
+    }
+  );
 }
 }
 
 
 export async function getPatientDescription(patient: {
 export async function getPatientDescription(patient: {
@@ -159,7 +161,10 @@ export function getPatientPhone() {
   );
   );
 }
 }
 // 获取订单列表
 // 获取订单列表
-export function getOrderList(patientId: string | number, progress: string | number) {
+export function getOrderList(
+  patientId: string | number,
+  progress: string | number
+) {
   return Post(
   return Post(
     `/patientCrManage/pagePcrOrders`,
     `/patientCrManage/pagePcrOrders`,
     { patientId, status: 0, progress },
     { patientId, status: 0, progress },
@@ -179,7 +184,11 @@ export function getRecordCountMethod() {
   });
   });
 }
 }
 // 获取患者线上调理方案打卡记录
 // 获取患者线上调理方案打卡记录
-export function getPatientOnlineRecord(id: string | number, startDate: string, endDate: string) {
+export function getPatientOnlineRecord(
+  id: string | number,
+  startDate: string,
+  endDate: string
+) {
   return Get(`/patientCrManage/ponlineCp/${id}`, {
   return Get(`/patientCrManage/ponlineCp/${id}`, {
     params: { startDate, endDate },
     params: { startDate, endDate },
     transform({ data }: AnyObject) {
     transform({ data }: AnyObject) {
@@ -189,17 +198,25 @@ export function getPatientOnlineRecord(id: string | number, startDate: string, e
 }
 }
 // 线上调理方案补卡
 // 线上调理方案补卡
 export function addPatientOnlineRecord(id: string | number) {
 export function addPatientOnlineRecord(id: string | number) {
-  return Post(`/patientCrManage/clockIn/repair/${id}`, {}, {
-    transform({ data }: AnyObject) {
-      return data;
-    },
-  });
+  return Post(
+    `/patientCrManage/clockIn/repair/${id}`,
+    {},
+    {
+      transform({ data }: AnyObject) {
+        return data;
+      },
+    }
+  );
 }
 }
 // 线上调理方案打卡
 // 线上调理方案打卡
 export function addPatientOnlineRecordClockIn(id: string | number) {
 export function addPatientOnlineRecordClockIn(id: string | number) {
-  return Post(`/patientCrManage/clockIn/${id}`, {}, {
-    transform({ data }: AnyObject) {
-      return data;
-    },
-  });
+  return Post(
+    `/patientCrManage/clockIn/${id}`,
+    {},
+    {
+      transform({ data }: AnyObject) {
+        return data;
+      },
+    }
+  );
 }
 }

+ 6 - 6
miniprogram/pages/mine/mine.ts

@@ -227,13 +227,13 @@ Page({
   },
   },
   onConsultationTap() {
   onConsultationTap() {
     // 跳转到咨询记录页面
     // 跳转到咨询记录页面
-    wx.showToast({
-      title: "敬请期待",
-      icon: "none",
-    });
-    // wx.navigateTo({
-    //   url: '/module/article/pages/consultation-record/consultation-record'
+    // wx.showToast({
+    //   title: "敬请期待",
+    //   icon: "none",
     // });
     // });
+    wx.navigateTo({
+      url: '/module/chats/pages/consultation-record/consultation-record'
+    });
   },
   },
   onTreatmentTap() {
   onTreatmentTap() {
     // 跳转到线下非药物治疗页面
     // 跳转到线下非药物治疗页面

+ 1 - 1
miniprogram/pages/mine/mine.wxml

@@ -6,7 +6,7 @@
       <view class="head-box">
       <view class="head-box">
         <t-avatar class="avatar-example" size="64px">W</t-avatar>
         <t-avatar class="avatar-example" size="64px">W</t-avatar>
         <view class="name-box">
         <view class="name-box">
-        <view class="name" wx:if="{{loaded}}">{{patient ? patient.name : '未登录'}}</view>
+          <view class="name" wx:if="{{loaded}}">{{patient ? patient.name : '未登录'}}</view>
           <view class="phone" wx:if="{{loaded && phone}}">{{phone}}</view>
           <view class="phone" wx:if="{{loaded && phone}}">{{phone}}</view>
         </view>
         </view>
       </view>
       </view>