Forráskód Böngészése

Merge branch 'release/2.3.0'

张田田 3 hónapja
szülő
commit
77fcdd37c9
74 módosított fájl, 5897 hozzáadás és 271 törlés
  1. 1 0
      .cloudbase/container/debug.json
  2. 12 0
      miniprogram/app.json
  3. BIN
      miniprogram/assets/bg/bg_dialog@2x.png
  4. BIN
      miniprogram/assets/bg/bg_home.png
  5. BIN
      miniprogram/assets/bg/bg_user@2x.png
  6. BIN
      miniprogram/assets/bg/health-file.bg.png
  7. BIN
      miniprogram/assets/bg/pic_body@2x.png
  8. BIN
      miniprogram/assets/icon/all@3x.png
  9. BIN
      miniprogram/assets/icon/deal@3x.png
  10. BIN
      miniprogram/assets/icon/delivery@3x.png
  11. BIN
      miniprogram/assets/icon/icon_footprint@3x.png
  12. BIN
      miniprogram/assets/icon/obligation@3x.png
  13. BIN
      miniprogram/module/article/assets/servicePag.png
  14. 2 1
      miniprogram/module/article/pages/confirm-receiving/confirm-receiving.json
  15. 17 6
      miniprogram/module/article/pages/confirm-receiving/confirm-receiving.scss
  16. 78 58
      miniprogram/module/article/pages/confirm-receiving/confirm-receiving.ts
  17. 10 18
      miniprogram/module/article/pages/confirm-receiving/confirm-receiving.wxml
  18. 37 56
      miniprogram/module/article/pages/manage-address/manage-address.ts
  19. 1 0
      miniprogram/module/article/pages/order-detail/order-detail.ts
  20. 124 0
      miniprogram/module/article/pages/order-list/order-list.scss
  21. 92 42
      miniprogram/module/article/pages/order-list/order-list.ts
  22. 50 7
      miniprogram/module/article/pages/order-list/order-list.wxml
  23. 1 1
      miniprogram/module/article/pages/success-page/success-page.scss
  24. 4 1
      miniprogram/module/article/pages/success-page/success-page.ts
  25. 8 0
      miniprogram/module/article/request.ts
  26. 89 0
      miniprogram/module/care/pages/care/verifyRecord.scss
  27. 39 8
      miniprogram/module/care/pages/care/verifyRecord.ts
  28. 51 2
      miniprogram/module/care/pages/care/verifyRecord.wxml
  29. 5 5
      miniprogram/module/care/pages/careDetail/careDetail.wxml
  30. 54 15
      miniprogram/module/care/pages/offlineTreatment/offlineTreatment.scss
  31. 70 5
      miniprogram/module/care/pages/offlineTreatment/offlineTreatment.ts
  32. 27 18
      miniprogram/module/care/pages/offlineTreatment/offlineTreatment.wxml
  33. 1 1
      miniprogram/module/care/request.ts
  34. BIN
      miniprogram/module/health/assets/image/bg_interview@2x.png
  35. BIN
      miniprogram/module/health/assets/image/health-report.png
  36. BIN
      miniprogram/module/health/assets/image/pic_body@2x.png
  37. BIN
      miniprogram/module/health/assets/image/pic_tongue@2x.png
  38. 1 1
      miniprogram/module/health/components/care-record/care-record.ts
  39. 38 0
      miniprogram/module/health/pages/scheme/scheme.scss
  40. 18 0
      miniprogram/module/health/pages/scheme/scheme.ts
  41. 7 0
      miniprogram/module/health/pages/scheme/scheme.wxml
  42. 49 0
      miniprogram/module/order/assets/iconfont/iconfont.wxss
  43. 10 0
      miniprogram/module/order/pages/appointment-success/appointment-success.json
  44. 105 0
      miniprogram/module/order/pages/appointment-success/appointment-success.scss
  45. 31 0
      miniprogram/module/order/pages/appointment-success/appointment-success.ts
  46. 37 0
      miniprogram/module/order/pages/appointment-success/appointment-success.wxml
  47. 10 0
      miniprogram/module/order/pages/appointment/appointment.json
  48. 255 0
      miniprogram/module/order/pages/appointment/appointment.scss
  49. 291 0
      miniprogram/module/order/pages/appointment/appointment.ts
  50. 53 0
      miniprogram/module/order/pages/appointment/appointment.wxml
  51. 8 0
      miniprogram/module/order/pages/confirme-order/confirme-order.json
  52. 569 0
      miniprogram/module/order/pages/confirme-order/confirme-order.scss
  53. 480 0
      miniprogram/module/order/pages/confirme-order/confirme-order.ts
  54. 98 0
      miniprogram/module/order/pages/confirme-order/confirme-order.wxml
  55. 8 0
      miniprogram/module/order/pages/order-detail/order-detail.json
  56. 564 0
      miniprogram/module/order/pages/order-detail/order-detail.scss
  57. 253 0
      miniprogram/module/order/pages/order-detail/order-detail.ts
  58. 142 0
      miniprogram/module/order/pages/order-detail/order-detail.wxml
  59. 8 0
      miniprogram/module/order/pages/other-detail/other-detail.json
  60. 675 0
      miniprogram/module/order/pages/other-detail/other-detail.scss
  61. 405 0
      miniprogram/module/order/pages/other-detail/other-detail.ts
  62. 193 0
      miniprogram/module/order/pages/other-detail/other-detail.wxml
  63. 8 0
      miniprogram/module/order/pages/select-goods/select-goods.json
  64. 276 0
      miniprogram/module/order/pages/select-goods/select-goods.scss
  65. 260 0
      miniprogram/module/order/pages/select-goods/select-goods.ts
  66. 56 0
      miniprogram/module/order/pages/select-goods/select-goods.wxml
  67. 71 0
      miniprogram/module/order/request.ts
  68. 20 9
      miniprogram/pages/home/home.scss
  69. 28 1
      miniprogram/pages/home/home.ts
  70. 12 8
      miniprogram/pages/home/home.wxml
  71. 1 1
      miniprogram/pages/home/vertical-steps/index.scss
  72. 1 1
      miniprogram/pages/mine/mine.scss
  73. 22 6
      miniprogram/pages/mine/mine.ts
  74. 61 0
      miniprogram/utils/util.ts

+ 1 - 0
.cloudbase/container/debug.json

@@ -0,0 +1 @@
+{"containers":[],"config":{}}

+ 12 - 0
miniprogram/app.json

@@ -85,6 +85,18 @@
         "pages/careDetail/careDetail",
         "pages/reportRecord/reportRecord"
       ]
+    },
+    {
+      "name": "order",
+      "root": "module/order",
+      "pages": [
+        "pages/select-goods/select-goods",
+        "pages/order-detail/order-detail",
+        "pages/other-detail/other-detail",
+        "pages/confirme-order/confirme-order",
+        "pages/appointment/appointment",
+        "pages/appointment-success/appointment-success"
+      ]
     }
   ],
   "preloadRule": {

BIN
miniprogram/assets/bg/bg_dialog@2x.png


BIN
miniprogram/assets/bg/bg_home.png


BIN
miniprogram/assets/bg/bg_user@2x.png


BIN
miniprogram/assets/bg/health-file.bg.png


BIN
miniprogram/assets/bg/pic_body@2x.png


BIN
miniprogram/assets/icon/all@3x.png


BIN
miniprogram/assets/icon/deal@3x.png


BIN
miniprogram/assets/icon/delivery@3x.png


BIN
miniprogram/assets/icon/icon_footprint@3x.png


BIN
miniprogram/assets/icon/obligation@3x.png


BIN
miniprogram/module/article/assets/servicePag.png


+ 2 - 1
miniprogram/module/article/pages/confirm-receiving/confirm-receiving.json

@@ -4,6 +4,7 @@
   "usingComponents": {
     "t-button": "tdesign-miniprogram/button/button",
     "t-navbar": "tdesign-miniprogram/navbar/navbar",
-    "t-icon": "tdesign-miniprogram/icon/icon"
+    "t-icon": "tdesign-miniprogram/icon/icon",
+    "t-checkbox": "tdesign-miniprogram/checkbox/checkbox"
   }
 }

+ 17 - 6
miniprogram/module/article/pages/confirm-receiving/confirm-receiving.scss

@@ -1,10 +1,11 @@
 @import "../../../../themes/page.scss";
 @import "../../searc-list.scss";
-/* module/diet/pages/diet-info/diet-info.wxss */
+/* module/article/pages/confirm-receiving/confirm-receiving.scss */
 
 
 .confirm-receive-container {
-  background: #f7f8fa;
+  // background: #f7f8fa;
+  background: white;
   display: flex;
   flex-direction: column;
   align-items: stretch;
@@ -17,23 +18,33 @@
   display: flex;
   background: #fff;
   border-radius: 20rpx;
-  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04);
+  // box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04);
   margin: 0 24rpx 24rpx 24rpx;
   padding: 24rpx;
-  align-items: flex-start;
+  align-items: center;
   gap: 24rpx;
 }
 .goods-img {
-  width: 120rpx;
-  height: 120rpx;
+  width: 140rpx;
+  height: 140rpx;
   border-radius: 12rpx;
   object-fit: cover;
   margin-right: 16rpx;
+
 }
 .goods-info {
   flex: 1;
   display: flex;
   flex-direction: column;
+  justify-content: space-between;
+  margin-left: 10rpx;
+  min-height: 115rpx;
+}
+
+.goods-checkbox {
+  flex-shrink: 0;
+  display: flex;
+  align-items: center;
   justify-content: center;
 }
 .goods-title {

+ 78 - 58
miniprogram/module/article/pages/confirm-receiving/confirm-receiving.ts

@@ -1,74 +1,94 @@
 import PageContainerBehavior from "../../../../core/behavior/page-container.behavior";
-import tickleBehavior, { getTickleContext } from "../../../../core/behavior/tickle.behavior";
-import { getOrderDetailMethod, orderConfirmMethod } from "../../request";
-// module/diet/pages/delivery-address/delivery-address.ts
+import tickleBehavior from "../../../../core/behavior/tickle.behavior";
+import { orderConfirmReceiptMethod } from "../../request";
+// module/article/pages/confirm-receiving/confirm-receiving.ts
 Page({
   behaviors: [
     PageContainerBehavior,
     tickleBehavior,
   ],
-  async onLoad(options:any) {
-    console.log("onLoad",options)
-    if(options.orderId){
-      this.setData({ id: options.orderId });
-      await this.load(options.orderId);
+  data: {
+    patientConditioningRecordId: '',
+    orderId: '',
+    goodsList: [] as Array<{
+      id: number;
+      name: string;
+      description: string;
+      image: string;
+      checked: boolean;
+    }>
+  },
+  async onLoad(options: any) {
+    console.log("onLoad", options)
+    if (options.patientConditioningRecordId) {
+      this.setData({ patientConditioningRecordId: options.patientConditioningRecordId });
+    }
+    if (options.goodsList) {
+      const goodsList = JSON.parse(decodeURIComponent(options.goodsList));
+      // 为每个商品添加 checked 属性,默认全部选中
+      const goodsListWithChecked = goodsList.map((item: any) => ({
+        ...item,
+        checked: true
+      }));
+      this.setData({ goodsList: goodsListWithChecked });
     }
-  
+    console.log("goodsList", this.data.goodsList)
   },
   properties: {
   },
-  data: {
-    id: '',
-    goodsList: []
+  copyExpressNo(e: any) {
+    wx.setClipboardData({
+      data: e.currentTarget.dataset.no,
+      success: () => wx.showToast({ title: '已复制', icon: 'none' })
+    });
+  },
+  onCancel() {
+    // 关闭弹窗或返回
+    wx.navigateBack();
   },
-    async load(id:string) {
-      wx.showLoading({ title: '加载中' });
-      try {
-        const res = await getOrderDetailMethod(id);
-        console.log("res",res)  
-        if(res && res.data && res.data.items && res.data.items.length > 0){
-          this.setData({ goodsList: res.data.items });
-        }else{
-          this.setData({ goodsList: [] });
+  // 商品复选框变化
+  onGoodsCheckChange(e: any) {
+    const { index } = e.currentTarget.dataset;
+    const checked = e.detail.checked;
+    const goodsList = this.data.goodsList;
+    goodsList[index].checked = checked;
+    this.setData({ goodsList });
+  },
+  // 确认收货逻辑
+  async onConfirmReceiving() {
+    // 获取选中的商品id数组
+    const selectedIds = this.data.goodsList
+      .filter((item: any) => item.checked)
+      .map((item: any) => item.id);
+
+    if (selectedIds.length === 0) {
+      wx.showToast({ title: '请至少选择一个商品', icon: 'none' });
+      return;
+    }
+    console.log(selectedIds, "selectedIds======选中的商品id")
+    let that = this;
+    wx.showModal({
+      title: '提示',
+      content: '确认收货后,订单将无法修改,请确认无误后再进行操作',
+      success: (res) => {
+        if (res.confirm) {
+          that.confirmReceiving(selectedIds);
         }
-        console.log("goodsList",this.data.goodsList)
-      } catch (error:any) {
-        getTickleContext.call(this).showWarnMessage(error.errMsg);
       }
-      wx.hideLoading();
-    },
-    copyExpressNo(e:any) {
-      wx.setClipboardData({
-        data: e.currentTarget.dataset.no,
-        success: () => wx.showToast({ title: '已复制', icon: 'none' })
-      });
-    },
-    onCancel() {
-      // 关闭弹窗或返回
-      wx.navigateBack();
-    },
-    // 确认收货逻辑
-    async onConfirmReceiving() {
-      let that = this;
-      wx.showModal({
-        title: '提示',
-        content: '确认收货后,订单将无法修改,请确认无误后再进行操作',
-        success: (res) => {
-          if (res.confirm) {
-            that.confirmReceiving();
-          }
-        }
-      });
-    },
-    async confirmReceiving() {
-      try {
-        await orderConfirmMethod(this.data.id);
-        // wx.showToast({ title: '确认收货成功', icon: 'success' });
-        wx.navigateTo({
-          url: "/module/article/pages/success-page/success-page?title=确认收货成功",
+    });
+  },
+  async confirmReceiving(selectedIds: number[]) {
+    try {
+      await orderConfirmReceiptMethod(this.data.patientConditioningRecordId, selectedIds);
+      wx.showToast({ title: '收货成功', icon: 'success' });
+      setTimeout(() => {
+        wx.redirectTo({
+          url: "/module/article/pages/success-page/success-page?title=收货成功",
         });
-      } catch (error:any) {
-        getTickleContext.call(this).showWarnMessage(error.errMsg);
-      }
+      }, 1000);
+
+    } catch (error: any) {
+      wx.showToast({ title: error.errMsg || '收货失败', icon: 'none' });
     }
+  }
 })

+ 10 - 18
miniprogram/module/article/pages/confirm-receiving/confirm-receiving.wxml

@@ -1,25 +1,17 @@
-<!--module/diet/pages/delivery-address/delivery-address.wxml-->
+<!--module/article/pages/confirm-receiving/confirm-receiving.wxml-->
 <t-navbar title="确认收货" left-arrow />
 <scroll-view class="page-scroll__container" type="list" scroll-y style="{{containerStyle}}">
 <view class="confirm-receive-container">
   <!-- 商品物流卡片列表 -->
   <view class="order-goods-list">
-    <view class="goods-card" wx:for="{{goodsList}}" wx:key="id" wx:if="{{item.conditioningProgramDetail.isDelivery==='Y'}}">
-      <image class="goods-img" src="{{item.conditioningProgramDetail.photo}}" mode="aspectFill" />
+    <view class="goods-card" wx:for="{{goodsList}}" wx:key="id" wx:for-index="index">
+      <image class="goods-img" src="{{item.image}}" mode="aspectFill" />
       <view class="goods-info">
-        <view class="goods-title">{{item.conditioningProgramDetail.name}}</view>
-        <view class="goods-count">× {{item.totalMeasure}}</view>
-        <view class="goods-express" wx:if="{{false}}">
-          <text class="express-label">快递:</text>
-          <block wx:if="{{item.expressNo}}">
-            <text class="express-no" bindtap="copyExpressNo" data-no="{{item.expressNo}}">
-              {{item.expressNo}}
-            </text>
-          </block>
-          <block wx:else>
-            <text class="express-none">暂无物流信息</text>
-          </block>
-        </view>
+        <view class="goods-title">{{item.name}}</view>
+        <view class="goods-count">× {{item.description}}</view>
+      </view>
+      <view class="goods-checkbox">
+        <t-checkbox checked="{{item.checked}}" bind:change="onGoodsCheckChange" data-index="{{index}}" style="padding:0" />
       </view>
     </view>
   </view>
@@ -32,8 +24,8 @@
 
   <!-- 底部按钮 -->
   <view class="confirm-footer">
-    <t-button theme="default" class="footer-btn" bindtap="onCancel">取消</t-button>
-    <t-button theme="primary" class="footer-btn" bindtap="onConfirmReceiving">确</t-button>
+    <!-- <t-button theme="default" class="footer-btn" bindtap="onCancel">取消</t-button> -->
+    <t-button theme="primary" class="footer-btn" bindtap="onConfirmReceiving">确</t-button>
   </view>
 </view>
 </scroll-view>

+ 37 - 56
miniprogram/module/article/pages/manage-address/manage-address.ts

@@ -40,29 +40,36 @@ Page({
       liaison: address.liaison,
       phone: address.phone,
     };
-    console.log(id, data, "更新订单地址");
-    const res = await orderPayAddressMethod(id, data);
-    console.log(res, "更新订单地址");
+    await orderPayAddressMethod(id, data);
   },
   // 选择地址
   async selectAddress(e: any) {
     const item = e.currentTarget.dataset.item;
     const type = wx.getStorageSync("type");
     const orderId = wx.getStorageSync("orderId");
-    console.log(type, "页面切换type", item);
     const pages = getCurrentPages();
-    console.log(pages, "pages");
+
+
+    const findTargetPageIndex = (targetRoute: string) => {
+      for (let i = pages.length - 1; i >= 0; i--) {
+        if (pages[i].route === targetRoute) {
+          return pages.length - 1 - i; // 需要返回的层级数
+        }
+      }
+      return -1;
+    };
+
     if (type === "orderDetail") {
       // 订单详情 切换地址
-      const orderPage = pages.find(
-        (page) =>
-          page.route === "module/article/pages/order-detail/order-detail"
-      );
-      console.log(orderPage, "orderPage");
       try {
         await this.updataOrderAddress(orderId, item);
-        if (orderPage) {
-          // orderPage.setData({ selectedAddress: item });
+        const targetRoute = "module/order/pages/order-detail/order-detail";
+        const delta = findTargetPageIndex(targetRoute);
+        if (delta > 0) {
+          // 返回到目标页面
+          wx.navigateBack({ delta });
+        } else {
+          // 如果找不到目标页面,返回到上一页
           wx.navigateBack();
         }
       } catch (error: any) {
@@ -70,55 +77,33 @@ Page({
       }
     } else if (type === "orderList") {
       // 订单列表 切换地址
-      const findPage = pages.find(
-        (page) => page.route === "module/article/pages/order-list/order-list"
-      );
-      console.log(findPage, "orderPage", orderId,item);
       try {
         await this.updataOrderAddress(orderId, item);
-        if (findPage) {
-          // orderPage.setData({ selectedAddress: item });
-          console.log("orderPage8888");
-          // wx.navigateBack({
-            // delta: 1,
-            // fail: () => {
-            //   console.log("orderPage9999");
-              wx.redirectTo({
-                url: "/"+findPage.route+"?tab=pending",
-              });
-            // },
-          // });
-        
+        const targetRoute = "module/article/pages/order-list/order-list";
+        const delta = findTargetPageIndex(targetRoute);
+        if (delta > 0) {
+          wx.navigateBack({ delta });
+        } else {
+          wx.navigateBack();
         }
       } catch (error: any) {
         getTickleContext.call(this).showWarnMessage(error.errMsg);
       }
+    } else if (type === "confirmeOrder") {
+      wx.setStorageSync('selectedAddress', item);
+      // 确认订单页面 切换地址
+      const confirmeOrderPage = pages.find(
+        (page: any) =>
+          page.route === "module/order/pages/confirme-order/confirme-order"
+      );
+      if (confirmeOrderPage) {
+        wx.redirectTo({
+          url: "/" + confirmeOrderPage.route + "?isDefault=1",
+        });
+      }
     } else {
       // 其他页面 切换地址
-      console.log("其他页面");
     }
-    // 获取上一页的数据
-    // const pages = getCurrentPages();
-    // if (pages.length > 1) {
-    //   const prevPage = pages[pages.length - 2];
-    //   console.log(prevPage.route, "上一页");
-    //   // 订单详情 切换地址
-    //   if (prevPage.route === "module/article/pages/order-detail/order-detail") {
-    //     // 设置上一页的数据
-    //     prevPage.setData({ selectedAddress: item });
-    //     wx.navigateBack();
-    //     // 订单列表切换地址
-    //   } else if (
-    //     prevPage.route === "module/article/pages/order-list/order-list"
-    //   ) {
-    //     prevPage.setData({
-    //       selectedAddress: e.currentTarget.dataset.address,
-    //     });
-    //     wx.navigateBack();
-    //   } else {
-    //     console.log("其他页面不返回");
-    //   }
-    //   }
   },
   // 搜索
   onSearchChange(e: any) {
@@ -160,7 +145,6 @@ Page({
     try {
       // 获取所有的地址列表
       const res = await getAddressListMethod("", "");
-      console.log(res, "res====");
       if (res && res.length > 0) {
         res.forEach((item: any) => {
           item.fullAddress = `${item.provinceName} ${item.cityName} ${item.areaName} ${item.detailAddress}`;
@@ -172,7 +156,6 @@ Page({
           allAddressList: res, // 原始
         });
       } else {
-        console.log(111);
         this.setData({
           noResult: true,
           addressList: [],
@@ -188,7 +171,6 @@ Page({
   onImportWechatAddress() {
     wx.chooseAddress({
       success: (res) => {
-        console.log(res, "导入微信地址");
         // 拼接参数
         const params = encodeURIComponent(
           JSON.stringify({
@@ -202,7 +184,6 @@ Page({
             detailAddress: res.detailInfoNew,
           })
         );
-        console.log(params, "微信地址的拼接");
         wx.navigateTo({
           url: `/module/article/pages/add-address/add-address?imported=${params}`,
         });

+ 1 - 0
miniprogram/module/article/pages/order-detail/order-detail.ts

@@ -12,6 +12,7 @@ import {
 Page({
   behaviors: [PageContainerBehavior, tickleBehavior],
   onLoad(options: any) {
+    console.log(options, "options");
     if (options.id) {
       this.setData({ id: options.id });
     }

+ 124 - 0
miniprogram/module/article/pages/order-list/order-list.scss

@@ -228,4 +228,128 @@
 
 .name {
   margin-right: 20rpx;
+}
+
+/* 服务包列表样式 */
+.service-packages {
+  margin-bottom: 24rpx;
+}
+
+.service-package-item {
+  display: flex;
+  align-items: flex-start;
+  margin-bottom: 20rpx;
+  padding-bottom: 20rpx;
+  
+  &:not(:last-child) {
+    // border-bottom: 1px solid #f0f0f0;
+  }
+  
+  &:last-child {
+    margin-bottom: 0;
+    padding-bottom: 0;
+  }
+}
+
+.service-package-img {
+  width: 120rpx;
+  height: 120rpx;
+  border-radius: 8rpx;
+  margin-right: 20rpx;
+  flex-shrink: 0;
+  background-color: #f5f5f5;
+}
+
+.service-package-placeholder {
+  width: 120rpx;
+  height: 120rpx;
+  border-radius: 8rpx;
+  margin-right: 20rpx;
+  background-color: #f5f5f5;
+  border: 1px solid #e8e8e8;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+}
+.servicepag-des{
+  display: flex;
+    align-items: center;
+    justify-content: space-between;
+}
+.placeholder-icon {
+  font-size: 40rpx;
+  opacity: 0.3;
+}
+
+.service-package-info {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  min-height: 120rpx;
+}
+
+.service-package-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  margin-bottom: 15rpx;
+  width: 100%;
+}
+
+.service-package-name {
+  font-size: 28rpx;
+  font-weight: 500;
+  color: #333;
+  line-height: 1.4;
+  flex: 1;
+}
+
+.service-package-price {
+  font-size: 28rpx;
+  color: #333;
+  font-weight: 500;
+  margin-left: 16rpx;
+  white-space: nowrap;
+}
+
+.service-package-detail {
+  font-size: 24rpx;
+  color: #666;
+  margin-bottom: 8rpx;
+  line-height: 1.5;
+}
+
+.service-package-quantity {
+  font-size: 24rpx;
+  color: #666;
+  text-align: right;
+  line-height: 1.5;
+}
+
+/* 展开/收起按钮 */
+.expand-toggle {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 16rpx 0;
+  color: #1890ff;
+  font-size: 26rpx;
+  cursor: pointer;
+  user-select: none;
+}
+
+.expand-text {
+  margin-right: 8rpx;
+}
+
+.expand-icon {
+  font-size: 20rpx;
+  transition: transform 0.3s ease;
+  transform: rotate(0deg);
+  
+  &.expanded {
+    transform: rotate(180deg);
+  }
 }

+ 92 - 42
miniprogram/module/article/pages/order-list/order-list.ts

@@ -2,11 +2,13 @@ import PageContainerBehavior from "../../../../core/behavior/page-container.beha
 import tickleBehavior, {
   getTickleContext,
 } from "../../../../core/behavior/tickle.behavior";
+import { handleWeChatPayment } from "../../../../utils/util";
 import {
   orderListMethod,
   orderCancelMethod,
   orderPayMethod,
 } from "../../request";
+
 // module/article/pages/order-list/order-list.ts
 Page({
   behaviors: [PageContainerBehavior, tickleBehavior],
@@ -20,7 +22,8 @@ Page({
     id: "",
     statusObj: {
       0: "待付款",
-      6: "待收货",
+      // 6: "待收货",
+      6: "已付款",
       345: "交易成功",
       2: "交易关闭",
     },
@@ -35,15 +38,15 @@ Page({
     payingId: '',
     showAddress: false,
     // 节流控制
-    throttleTimers: {} as Record<string, boolean>, // 存储各个按钮的节流定时器
+    throttleTimers: {} as Record<string, boolean>,
+    expandedItems: {} as Record<string, boolean>,
   },
   computed: {},
-  // 节流函数 - 防止短时间内重复点击
+  // 节流 - 防止短时间内重复点击
   throttle(func: Function, delay: number = 1000, key: string = "default") {
     return (...args: any[]) => {
       // 如果该按钮正在节流中,直接返回
       if (this.data.throttleTimers[key]) {
-        console.log(`按钮 ${key} 正在节流中,忽略点击`);
         return;
       }
 
@@ -67,26 +70,15 @@ Page({
   },
   onLoad(options: any) {
     // 读取 tab 参数,默认为 all
-    console.log(options, "options");
     const tab = options?.tab || "all";
     this.setData({ currentTab: tab });
-    // this.filterOrdersList(tab);
   },
   onShow() {
     this.filterOrdersList(this.data.currentTab);
-    // 读取地址
-    // if (JSON.stringify(this.data.selectedAddress) !== "{}") {
-    //   this.setData({
-    //     name: this.data.selectedAddress?.liaison,
-    //     phone: this.data.selectedAddress?.phone,
-    //     address: this.data.selectedAddress?.fullAddress,
-    //   });
-    // }
   },
   // 切换tab
   onTabChange(event: any) {
     const type = event.detail.value;
-    console.log(type, "传来的type");
     this.setData({ currentTab: type });
     this.filterOrdersList(type);
   },
@@ -119,14 +111,39 @@ Page({
         } else {
           item.showAddress = true;
         }
+        if (item.items && Array.isArray(item.items)) {
+          item.items = item.items.map((subItem: any) => {
+            return {
+              id: subItem.id || '',
+              name: subItem.conditioningProgramName || '',
+              description: (() => {
+                const dose = subItem?.convertDose ?? '1';
+                const unit = subItem?.convertUnit ?? '次';
+                return `${dose} ${unit}`;
+              })(),
+              photo: subItem.conditioningProgramPhoto || '',
+              price: subItem.unitPrice || 0,
+              quantity: subItem?.totalMeasure || 0,
+            }
+          });
+        }
+      });
+      // 批量初始化展开状态为false(默认折叠)
+      const expandedItems: Record<string, boolean> = {};
+      res.data.forEach((item: any) => {
+        if (!this.data.expandedItems[item.id]) {
+          expandedItems[item.id] = false;
+        }
       });
+      if (Object.keys(expandedItems).length > 0) {
+        this.setData({ expandedItems: { ...this.data.expandedItems, ...expandedItems } });
+      }
       this.setData({ orders: res.data });
     }
   },
   // 过滤订单l列表
   filterOrdersList(type: any) {
     // 根据当前选中的标签过滤订单
-    console.log(type, "根据传来的type获取不同状态下的列表");
     switch (type) {
       // 全部订单
       case "all":
@@ -136,14 +153,18 @@ Page({
       case "pending":
         this.getOrderList("0");
         break;
-      // 待收货订单
-      case "received":
+      // 已付款订单
+      case "paid":
         this.getOrderList("6");
         break;
       // 交易完成订单
       case "completed":
         this.getOrderList("345");
         break;
+      // 交易关闭订单
+      case "closed":
+        this.getOrderList("2");
+        break;
       default:
         break;
     }
@@ -156,13 +177,36 @@ Page({
         if (this.data.payingId) return; // 防重复
         this.setData({ paying: true, payingId: orderId });
         try {
-          await orderPayMethod(orderId);
-          wx.navigateTo({
-            url: "/module/article/pages/success-page/success-page?title=订单支付成功",
-          });
+          // 调用支付接口
+          const payResult = await orderPayMethod(orderId);
+          if (payResult && payResult.data) {
+            const paymentParams = payResult.data;
+            handleWeChatPayment(paymentParams, (res: any) => {
+              // 支付成功,跳转到成功页面
+              wx.redirectTo({
+                url: "/module/article/pages/success-page/success-page?title=订单支付成功",
+              });
+            }, (error: any) => {
+              this.setData({ paying: false, payingId: '' });
+              if (error.errMsg === 'requestPayment:fail cancel') {
+                wx.showToast({
+                  title: "支付已取消",
+                  icon: "none",
+                });
+              } else {
+                wx.showToast({
+                  title: error.errMsg || "支付失败,请重试",
+                  icon: "none",
+                });
+              }
+            });
+          } else {
+            wx.showToast({
+              title: payResult.errMsg,
+              icon: "none",
+            });
+          }
         } catch (error: any) {
-          this.setData({ paying: false, payingId: '' });
-          // getTickleContext.call(this).showWarnMessage(error.errMsg);
           wx.showToast({
             title: error.errMsg,
             icon: "none",
@@ -179,15 +223,10 @@ Page({
   onSeeLogistics: function (e: any) {
     return this.throttle(
       (event: any) => {
-        console.log(event, "查看物流");
         wx.showToast({
           title: "暂未开通",
           icon: "none",
         });
-        // const id = event.currentTarget.dataset.id;
-        // wx.navigateTo({
-        //   url: `/module/article/pages/see-logistics/see-logistics?id=${id}`,
-        // });
       },
       2000,
       "logistics"
@@ -199,8 +238,7 @@ Page({
       (event: any) => {
         const orderStatus = event.currentTarget.dataset.status;
         const id = event.currentTarget.dataset.id;
-        console.log(orderStatus, "切换地址");
-        // 根据订单状态判断是否可以切换地址. 待支付状态下可以切换地址
+        // 根据订单状态判断是否可以切换地址. 待付款状态下可以切换地址
         if (orderStatus === "0") {
           wx.navigateTo({
             url:
@@ -252,7 +290,6 @@ Page({
   onConfirmReceiving: function (e: any) {
     return this.throttle(
       (event: any) => {
-        console.log(event, "确认收货");
         const orderId = event.currentTarget.dataset.id;
         wx.navigateTo({
           url: `/module/article/pages/confirm-receiving/confirm-receiving?orderId=${orderId}`,
@@ -284,16 +321,29 @@ Page({
   // 订单详情
   onOrderDetail(e: any) {
     const id = e.currentTarget.dataset.id;
-    // const status = e.currentTarget.dataset.status;
-    wx.navigateTo({
-      url: `/module/article/pages/order-detail/order-detail?id=${id}`,
-    });
+    const status = e.currentTarget.dataset.status;
+    if (status === '0') {
+      wx.navigateTo({
+        url: `/module/order/pages/order-detail/order-detail?id=${id}&status=${status}`,
+      });
+    } else {
+      wx.navigateTo({
+        url: `/module/order/pages/other-detail/other-detail?id=${id}&status=${status}`,
+      });
+    }
   },
   //回到我的页面
-goMine() {
-  console.log("goMine");
-  wx.redirectTo({
-    url: "/pages/mine/mine",
-  });
-}
+  goMine() {
+    wx.redirectTo({
+      url: "/pages/mine/mine",
+    });
+  },
+  // 切换服务包展开/收起
+  toggleServicePackages(e: any) {
+    const orderId = e.currentTarget.dataset.id;
+    const currentExpanded = this.data.expandedItems[orderId] || false;
+    this.setData({
+      [`expandedItems[${orderId}]`]: !currentExpanded,
+    });
+  },
 });

+ 50 - 7
miniprogram/module/article/pages/order-list/order-list.wxml

@@ -3,16 +3,17 @@
 <t-tabs value="{{currentTab}}" bindchange="onTabChange">
   <t-tab-panel label="全部" value="all" />
   <t-tab-panel label="待付款" value="pending" />
-  <t-tab-panel label="待收货" value="received" />
+  <t-tab-panel label="已付款" value="paid" />
   <t-tab-panel label="交易成功" value="completed" />
+    <!-- <t-tab-panel label="交易关闭" value=closed" /> -->
 </t-tabs>
 
 <scroll-view class="page-scroll__container" scroll-y>
   <block wx:for="{{orders}}" wx:key="id">
-    <view class="order-card" bindtap="onOrderDetail" data-id="{{item.id}}" data-status="{{item.status}}">
+    <view class="order-card" bindtap="onOrderDetail" data-id="{{item.id}}" data-status="{{item.orderStatus}}">
       <view class="order-header">
         <view>
-          <text wx:if="{{false}}">订单编号:{{item.orderId}}</text>
+          <text wx:if="{{item.orderNo}}">订单编号:{{item.orderNo}}</text>
         </view>
         <text class="order-status {{statusClassObj[item.orderStatus]}}">{{statusObj[item.orderStatus]}}</text>
       </view>
@@ -31,6 +32,7 @@
       </view>
       <view class="order-body">
         <image src="{{item.photo}}" class="order-img" wx:if="{{item.photo}}" />
+        <image src="../../assets/servicePag.png" class="order-img" wx:else />
         <view class="order-info">
           <text class="order-title">{{item.conditioningWrapName || ''}}</text>
           <text class="order-doctor" wx:if="{{item.operateBy}}">开具医生:<text style="color:black">{{item.operateBy}}</text></text>
@@ -39,6 +41,47 @@
       </view>
 
       <view class="line"></view>
+      <!-- 服务包列表 -->
+      <view class="service-packages">
+        <view 
+          class="service-package-item" 
+          wx:for="{{item.items}}" 
+          wx:key="id"
+          wx:for-item="package"
+          wx:for-index="packageIndex"
+          wx:if="{{packageIndex < 2 || expandedItems[item.id]}}"
+        >
+          <image 
+            src="{{package.photo}}" 
+            class="service-package-img" 
+            wx:if="{{package.photo}}" 
+            mode="aspectFill"
+          />
+          <view class="service-package-placeholder" wx:else>
+            <text class="placeholder-icon">📦</text>
+          </view>
+          <view class="service-package-info">
+            <view class="service-package-header">
+              <text class="service-package-name">{{package.name}}</text>
+              <text class="service-package-price" wx:if="{{package.price > 0}}">¥{{package.price}}</text>
+            </view>
+            <view class="servicepag-des">
+            <text class="service-package-detail" wx:if="{{package.description}}">{{package.description}}</text>
+            <text class="service-package-quantity" wx:if="{{package.quantity > 0}}">x{{package.quantity}}</text>
+            </view>
+          </view>
+        </view>
+        <!-- 展开/收起按钮 -->
+        <view 
+          class="expand-toggle" 
+          wx:if="{{item.items && item.items.length > 2}}"
+          catchtap="toggleServicePackages"
+          data-id="{{item.id}}"
+        >
+          <text class="expand-text">{{expandedItems[item.id] ? '收起' : '展开'}}</text>
+          <text class="expand-icon {{expandedItems[item.id] ? 'expanded' : ''}}">▼</text>
+        </view>
+      </view>
       <view class="order-footer">
         <view class="order-price">订单金额:<text class="order-amount">¥{{item.cost}}</text></view>
 
@@ -50,12 +93,12 @@
           <t-button wx:if="{{item.orderStatus==='0'}}" size="small" type="primary" bindtap="onPay" class="outline-btn" data-id="{{item.id}}" disabled="{{(payingId===item.id) || throttleTimers.pay}}">
             立即支付
           </t-button>
-          <t-button wx:if="{{item.orderStatus==='6' || item.orderStatus==='345'}}" size="small" type="default" class="outline-btn cancel" bindtap="onSeeLogistics" data-id="{{item.id}}" disabled="{{throttleTimers.logistics}}">
+          <!-- <t-button wx:if="{{item.orderStatus==='6' || item.orderStatus==='345'}}" size="small" type="default" class="outline-btn cancel" bindtap="onSeeLogistics" data-id="{{item.id}}" disabled="{{throttleTimers.logistics}}">
             查看物流
-          </t-button>
-          <t-button wx:if="{{item.orderStatus==='6'}}" size="small" type="default" class="outline-btn" bindtap="onConfirmReceiving" data-id="{{item.id}}" disabled="{{throttleTimers.confirmReceiving}}">
+          </t-button> -->
+          <!-- <t-button wx:if="{{item.orderStatus==='6'}}" size="small" type="default" class="outline-btn" bindtap="onConfirmReceiving" data-id="{{item.id}}" disabled="{{throttleTimers.confirmReceiving}}">
             确认收货
-          </t-button>
+          </t-button> -->
 
         </view>
       </view>

+ 1 - 1
miniprogram/module/article/pages/success-page/success-page.scss

@@ -1,6 +1,6 @@
 @import "../../../../themes/page.scss";
 @import "../../searc-list.scss";
-/* module/diet/pages/diet-info/diet-info.wxss */
+/* module/diet/pages/success-page/success-page.wxss */
 
 .page-scroll__container {
   background: white;

+ 4 - 1
miniprogram/module/article/pages/success-page/success-page.ts

@@ -24,7 +24,10 @@ Page({
     }
   },
     onBackOrderList() {
-      wx.redirectTo({ url: '/module/article/pages/order-list/order-list' });
+      // wx.redirectTo({ url: '/module/article/pages/order-list/order-list' });
+      // 先到「我的」再自动进订单列表,这样订单列表返回时栈上是「我的」
+      wx.setStorageSync("fromSuccessToOrderList", "1");
+      wx.redirectTo({ url: "/pages/mine/mine" });
     },
     async load() {
       wx.showLoading({ title: '加载中' });

+ 8 - 0
miniprogram/module/article/request.ts

@@ -188,6 +188,14 @@ export function orderConfirmMethod(id: string) {
     },
   });
 }
+//新的确认收货接口
+export function orderConfirmReceiptMethod(patientConditioningRecordId: string,integers:number[]) {
+  return Post(`/patientCrManage/confirmReceipt/${patientConditioningRecordId}`, integers,{
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
+}
 // 获取足迹列表
 export function getFootPrintListMethod() {
   return Post(`/patientInfoManage/getMyFootprint`, {

+ 89 - 0
miniprogram/module/care/pages/care/verifyRecord.scss

@@ -70,3 +70,92 @@
     font-size: 28rpx;
   }
 }
+// 预约成功卡片
+.appointment-success-card {
+  background: #fff;
+  border-radius: 16rpx;
+  // margin: 24rpx;
+  padding: 30rpx 32rpx 40rpx;
+  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
+  margin-bottom: 20rpx;
+}
+
+.appointment-success-title {
+  font-size: 48rpx;
+  font-weight: 600;
+  color: #000;
+  text-align: center;
+  margin-bottom: 30rpx;
+}
+
+// 二维码容器
+.qr-code-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin-bottom: 50rpx;
+}
+
+.qr-code-image {
+  width: 400rpx;
+  height: 400rpx;
+  background: #fff;
+}
+
+.qr-code-placeholder {
+  width: 260rpx;
+  height: 260rpx;
+  background: #f5f5f5;
+  border: 2rpx dashed #ddd;
+  border-radius: 8rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.qr-code-text {
+  font-size: 28rpx;
+  color: #999;
+}
+
+// 预约信息
+.appointment-info {
+  margin-bottom: 50rpx;
+  margin-left: 100rpx;
+}
+
+.info-item {
+  display: flex;
+  align-items: flex-start;
+  margin-bottom: 25rpx;
+  font-size: 30rpx;
+  line-height: 1.8;
+}
+
+.info-label {
+  color: #000;
+  margin-right: 16rpx;
+  // min-width: 180rpx;
+  flex-shrink: 0;
+}
+
+.info-value {
+  color: #000;
+  flex: 1;
+  word-break: break-all;
+  font-weight: 600;
+}
+
+// 提示信息
+// .appointment-tip {
+//   margin-top: 50rpx;
+//   padding-top: 40rpx;
+//   border-top: 1rpx solid #eee;
+// }
+
+.tip-text {
+  font-size: 26rpx;
+  color: #000;
+  line-height: 1.8;
+  text-align: center;
+}

+ 39 - 8
miniprogram/module/care/pages/care/verifyRecord.ts

@@ -1,10 +1,31 @@
-import {  Post } from "../../../../lib/request/method";
+import { Post } from "../../../../lib/request/method";
 Page({
-  onLoad(options: { id: number }) {
+  data: {
+    id: "",
+    recordList: [],
+    showAppointmentSuccess: true,
+    qrCodeUrl: "",
+    appointmentInfo: {
+      operateTime: '',
+      operateDuration: '',
+      conditioningProgramSupplierName: '',
+      cpSupplierDetailAddress: '',
+      cpSupplierPhone: '',
+      cpSupplierQrCode: '',
+    },
+    showAppointmentInfo: false,
+  },
+  onLoad(options: any) {
     if (options.id) {
       this.getVerifyRecordList(options.id);
     }
   },
+  // 生成二维码
+  generateQRCode(qrCodeUrl: any) {
+    this.setData({
+      qrCodeUrl
+    });
+  },
   // 获取核销记录列表
   async getVerifyRecordList(id: number) {
     try {
@@ -17,9 +38,22 @@ Page({
           },
         }
       );
-      if (res && res.length > 0) {
+      if (res && res.patientConditioningSwagItemOffline && JSON.stringify(res.patientConditioningSwagItemOffline) !== '{}') {
         this.setData({
-          recordList: res,
+          showAppointmentInfo: true,
+        });
+        this.setData({
+          appointmentInfo: res.patientConditioningSwagItemOffline,
+        });
+        this.generateQRCode(this.data.appointmentInfo.cpSupplierQrCode);
+      } else {
+        this.setData({
+          showAppointmentInfo: false,
+        });
+      }
+      if (res && res.patientConditioningSwagItemOfflines && res.patientConditioningSwagItemOfflines.length > 0) {
+        this.setData({
+          recordList: res.patientConditioningSwagItemOfflines,
         });
       } else {
         this.setData({
@@ -30,8 +64,5 @@ Page({
       console.error("核销记录列表", error);
     }
   },
-  data: {
-    id: "",
-    recordList: [],
-  },
+
 });

+ 51 - 2
miniprogram/module/care/pages/care/verifyRecord.wxml

@@ -1,6 +1,49 @@
 <t-navbar title="核销记录" left-arrow />
 <scroll-view class="page-container" scroll-y>
- 
+  <!-- 预约成功卡片 -->
+    <view class="appointment-success-card" wx:if="{{showAppointmentInfo}}">
+      <!-- 标题 -->
+      <view class="appointment-success-title">预约成功</view>
+      
+      <!-- 二维码 -->
+      <view class="qr-code-container" wx:if="{{qrCodeUrl}}">
+        <image 
+          class="qr-code-image" 
+          src="{{qrCodeUrl}}" 
+          mode="aspectFit"
+        />
+      </view>
+      
+      <!-- 预约详情 -->
+      <view class="appointment-info">
+        <view class="info-item" wx:if="{{appointmentInfo.arrangeTime}}">
+          <text class="info-label">开始服务时间:</text>
+          <text class="info-value">{{appointmentInfo.arrangeTime}}</text>
+        </view>
+        <view class="info-item" wx:if="{{appointmentInfo.arrangeDuration}}">
+          <text class="info-label">服务时长:</text>
+          <text class="info-value">{{appointmentInfo.arrangeDuration}}分钟</text>
+        </view>
+        <view class="info-item" wx:if="{{appointmentInfo.conditioningProgramSupplierName}}">
+          <text class="info-label">服务机构:</text>
+          <text class="info-value" wx:if="{{appointmentInfo.pieTime}}">{{appointmentInfo.conditioningProgramSupplierName}}</text>
+          <text class="info-value" wx:else>待分配</text>
+        </view>
+        <view class="info-item" wx:if="{{appointmentInfo.cpSupplierDetailAddress}}">
+          <text class="info-label">服务地址:</text>
+          <text class="info-value">{{appointmentInfo.cpSupplierDetailAddress}}</text>
+        </view>
+        <view class="info-item" wx:if="{{appointmentInfo.cpSupplierPhone}}">
+          <text class="info-label">联系电话:</text>
+          <text class="info-value">{{appointmentInfo.cpSupplierPhone}}</text>
+        </view>
+      </view>
+      
+      <!-- 提示信息 -->
+      <view class="appointment-tip">
+        <text class="tip-text">为了保证您的服务体验,请提前5分钟到达门店</text>
+      </view>
+    </view>
 <view class="verify-record-page" wx:if="{{recordList.length>0}}">
   <block wx:for="{{recordList}}" wx:key="id">
     <view class="record-card">
@@ -12,6 +55,12 @@
         <text class="label">操作人:</text>
         <text style="color:black">{{item.operateBy}}</text>
       </view>
+       <!-- 新增加的一列--机构 -->
+        <view class="record-row" wx:if="{{item.operateBy}}">
+        <text class="label">机构:</text>
+        <text style="color:black">{{item.operateBy}}</text>
+      </view>
+       <!-- end -->
       <view class="record-row" wx:if="{{item.feedback}}">
         <text class="label">治疗备注:</text>
         <text style="color:black">{{item.feedback}}</text>
@@ -28,6 +77,6 @@
   </block>
 </view>
  <view wx:else class="empty-state">
-    <text class="empty-text">暂无数据</text>
+    <text class="empty-text">暂无核销数据</text>
   </view>
 </scroll-view>

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

@@ -55,7 +55,7 @@
           </view>
           <view wx:for="{{careDetail.items}}" wx:key="id">
             <!-- 线下操作-->
-            <view class="scheme-card" wx:if="{{item.conditioningProgramDetail.isOffline && item.conditioningProgramDetail.isOffline==='Y'}}">
+            <view class="scheme-card" wx:if="{{item.conditioningProgramDetail.sellType && item.conditioningProgramDetail.sellType==='2'}}">
               <view class="scheme-title" wx:if="{{item.conditioningProgramDetail && item.conditioningProgramDetail.name && item.conditioningProgramDetail.name!=='null'}}">{{item.conditioningProgramDetail.name}}</view>
               <view class="divider"></view>
               <view class="carousel-box" wx:if="{{item.carouselMediaList && item.carouselMediaList.length > 0}}">
@@ -78,7 +78,7 @@
                     <text style="color:black">{{item.totalMeasure}}次</text>
                   </text>
                 </text>
-                <text class="link" bindtap="onRecord" data-id="{{item.id}}" wx:if="{{item.conditioningProgramDetail.isOffline && item.conditioningProgramDetail.isOffline==='Y'}}">核销记录</text>
+                <text class="link" bindtap="onRecord" data-id="{{item.id}}" wx:if="{{item.conditioningProgramDetail.sellType && item.conditioningProgramDetail.sellType==='2'}}">核销记录</text>
               </view>
               <view class="scheme-row">
                 <text class="text-gray">频次:</text>
@@ -97,7 +97,7 @@
               </view>
             </view>
             <!-- 线上操作 -->
-            <view class="scheme-card" wx:if="{{item.conditioningProgramDetail.isOffline && item.conditioningProgramDetail.isOffline==='N'}}">
+            <view class="scheme-card" wx:if="{{item.conditioningProgramDetail.sellType && item.conditioningProgramDetail.sellType!=='2'}}">
               <view class="scheme-title">{{item.conditioningProgramDetail.name}}</view>
               <view class="divider"></view>
               <view class="carousel-box" wx:if="{{item.carouselMediaList && item.carouselMediaList.length > 0}}">
@@ -112,7 +112,7 @@
               </view>
               <view class="scheme-row light">
                 <text class="text-gray">数量:</text>
-                <text>{{item.totalMeasure}}{{item.conditioningProgramDetail.cpFixedPricingRule.convertUnit}}</text>
+                <text>{{item.totalMeasure}}{{item.pricingUnit}}</text>
 
               </view>
               <view class="scheme-row between">
@@ -120,7 +120,7 @@
                   <text class="label between">频次:</text>
                   <text>每{{item.frequencyType}}天{{item.frequencyMeasure}}{{item.conditioningProgramDetail.cpFixedPricingRule.convertUnit}}</text>
                 </text>
-                <view class="link" bindtap="onCardRecord" data-id="{{item.id}}" wx:if="{{item.conditioningProgramDetail.isOffline && item.conditioningProgramDetail.isOffline==='N'}}">打卡记录</view>
+                <view class="link" bindtap="onCardRecord" data-id="{{item.id}}" wx:if="{{item.conditioningProgramDetail.sellType && item.conditioningProgramDetail.sellType!=='2'}}">打卡记录</view>
 
               </view>
               <view class="desc-row" wx:if="{{item.remark}}">

+ 54 - 15
miniprogram/module/care/pages/offlineTreatment/offlineTreatment.scss

@@ -1,20 +1,15 @@
 .page-container {
   background-color: #f3f3f3;
   padding-top: 10px;
-  height: calc(100vh - 44px);
+  // height: calc(100vh - 44px);
+  height: calc(100vh - 180rpx); // 减去 navbar 和 tabs 的高度(约 180rpx)
+  flex: 1;
+  overflow-y: hidden;
   box-sizing: border-box;
-  -webkit-overflow-scrolling: touch;
+  // box-sizing: border-box;
+  // -webkit-overflow-scrolling: touch;
   /* 兼容底部安全区,增加额外内边距防遮挡 */
-  padding-bottom: calc(env(safe-area-inset-bottom) + 24rpx);
-}
-
-.offline-treatment-page {
-  background: #f6f7fa;
-  min-height: 100vh;
-}
-
-.page-container {
-  padding: 24rpx 0;
+  // padding-bottom: calc(env(safe-area-inset-bottom) + 24rpx);
 }
 
 .treatment-card {
@@ -51,10 +46,16 @@
   align-items: center;
   background: #fff;
   border-radius: 16rpx;
-  margin: 0 24rpx 32rpx 24rpx;
+  margin: 0 15rpx 20rpx 15rpx;
   padding: 24rpx 54rpx 18rpx 24rpx;
   box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
   font-size: 28rpx;
+  transition: background-color 0.3s ease;
+}
+
+.treatment-detail-card--highlighted {
+  background: #f9e8f6;
+  border: 1rpx solid #f9e8f6;
 }
 
 .row {
@@ -77,13 +78,16 @@
   font-size: 28rpx;
   font-weight: 500;
   margin-bottom: 20rpx;
+  text-align: center;
 }
 
 .status.done {
   color: #43A047;
   margin-left: 16rpx;
 }
-
+.center{
+  text-align: center;
+}
 .count {
   margin-left: 16rpx;
   color: #222;
@@ -100,5 +104,40 @@
 
 /* 底部安全区占位,确保列表最后一项不被遮挡 */
 .safe-bottom-spacer {
-  height: calc(env(safe-area-inset-bottom) + 24rpx);
+  height: calc(env(safe-area-inset-bottom) + 48rpx);
+  min-height: 48rpx;
+  flex: none;
+}
+
+/* 预约相关样式 */
+.appointment-action {
+  margin-top: 100rpx;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.appointment-btn {
+  padding: 12rpx 32rpx;
+  background: linear-gradient(135deg, #1d6ff6 0%, #4a90ff 100%);
+  color: #fff;
+  font-size: 26rpx;
+  font-weight: 500;
+  border-radius: 20rpx;
+  box-shadow: 0 2rpx 8rpx rgba(29, 111, 246, 0.3);
+  transition: all 0.3s ease;
+  
+  &:active {
+    opacity: 0.9;
+    transform: scale(0.98);
+  }
+}
+
+.appointment-tag {
+  padding: 12rpx 32rpx;
+  background: #fff;
+  color: #f44336;
+  font-size: 24rpx;
+  font-weight: 500;
+  border: 1rpx solid #f44336;
+  border-radius: 20rpx;
 }

+ 70 - 5
miniprogram/module/care/pages/offlineTreatment/offlineTreatment.ts

@@ -10,9 +10,19 @@ Page({
     currentTab: "",
     treatmentList: [],
     isLoading: false,
+    treatmentId: "",
   },
-  onLoad() {
-    this.getOfflineTreatmentList("");
+  async onLoad(options: any) {
+    console.log(options, '传过来的参数')
+    if (options.id) {
+      this.setData({
+        treatmentId: options.id,
+      });
+    }
+    // await this.getOfflineTreatmentList("");
+  },
+  async onShow() {
+    await this.getOfflineTreatmentList("");
   },
   // 跳转到核销记录
   onRecord(e: any) {
@@ -23,6 +33,38 @@ Page({
       });
     }
   },
+  // 去预约
+  goAppointment(e: any) {
+
+    const { item } = e.currentTarget.dataset;
+    const { offlineId, conditioningProgramName, offlineDuration, itemImgSecond, estimatedStartDate } = item;
+    const goodsInfo = {
+      name: conditioningProgramName || '',
+      duration: offlineDuration || 0,
+      image: itemImgSecond || '',
+      offlineId: offlineId || '',
+      serviceTime: estimatedStartDate || '',
+    }
+    console.log(goodsInfo, "goodsInfo======去预约页面")
+    if (offlineId) {
+      // 去预约页面
+      wx.navigateTo({
+        url: `/module/order/pages/appointment/appointment?goodsInfo=${JSON.stringify(goodsInfo)}`,
+      });
+    } else {
+      wx.showToast({
+        title: "线下服务ID不能为空",
+        icon: "none",
+      });
+    }
+    // const id = e.currentTarget.dataset.id;
+    // if (id) {
+    //   // 跳转到预约页面,传递项目id
+    //   wx.navigateTo({
+    //     url: `/module/care/pages/careDetail/careDetail?id=${id}`,
+    //   });
+    // }
+  },
   onTabChange(e: any) {
     const progress = e.detail.value;
     this.setData({
@@ -37,10 +79,33 @@ Page({
     this.setData({ isLoading: true });
     try {
       const res = await getOfflineTreatmentListMethod(progress);
-      const list = res && res.data ? res.data : [];
-      // 只有在数据加载完成后才更新列表
-      this.setData({ treatmentList: list, isLoading: false });
+      console.log(res.data, "res.data")
+      // 确保 res.data 是数组,避免 undefined 或 null 导致的错误
+      const list = Array.isArray(res?.data) ? res.data : [];
+      // 如果传入了treatmentId,标记匹配的项目为高亮并置顶
+      const treatmentId = this.data.treatmentId;
+      console.log(treatmentId, "treatmentId")
+      console.log(list, "list")
+      if (treatmentId && list.length > 0) {
+        const highlightedList = list.map((item: any) => ({
+          ...item,
+          isHighlighted: item.id === treatmentId || String(item.id) === String(treatmentId),
+        }));
+        // 将高亮的项目移到最前面
+        const highlightedItem = highlightedList.find((item: any) => item.isHighlighted);
+        const otherItems = highlightedList.filter((item: any) => !item.isHighlighted);
+        const sortedList = highlightedItem ? [highlightedItem, ...otherItems] : highlightedList;
+        console.log(sortedList, "sortedList")
+
+        this.setData({ treatmentList: sortedList, isLoading: false });
+      } else {
+        // 只有在数据加载完成后才更新列表
+        this.setData({ treatmentList: list, isLoading: false });
+      }
     } catch (error: any) {
+
+      console.error('获取数据失败:', error);
+      // 只有在真正出错时才显示错误提示
       wx.showToast({
         title: error.errMsg || "获取数据失败",
         icon: "none",

+ 27 - 18
miniprogram/module/care/pages/offlineTreatment/offlineTreatment.wxml

@@ -1,5 +1,4 @@
 <t-navbar title="{{i18n.offlineTreatment.title}}" left-arrow />
-<view class="offline-treatment-page">
   <t-tabs value="{{currentTab}}" bind:change="onTabChange">
     <t-tab-panel label="全部" value=""></t-tab-panel>
     <t-tab-panel label="{{i18n.offlineTreatment.ing}}" value="0"></t-tab-panel>
@@ -9,49 +8,59 @@
     <view wx:if="{{isLoading}}">
       <t-loading theme="spinner" text="加载中..." size="24" />
     </view>
-    <view wx:elif="{{treatmentList.length>0}}"> 
+   <view wx:elif="{{treatmentList.length>0}}">
       <block wx:for="{{treatmentList}}" wx:key="id">
-        <view class="treatment-detail-card" bindtap="onRecord" data-id="{{item.id}}">
+        <view class="treatment-detail-card {{item.isHighlighted ? 'treatment-detail-card--highlighted' : ''}}" bindtap="onRecord" data-id="{{item.id}}">
           <view>
-            <view class="row between">
+            <view class="row between" wx:if="{{item.conditioningProgramName}}">
               <text class="label bold">项目:{{item.conditioningProgramName}}</text>
             </view>
-            <view class="row">
+            <view class="row" wx:if="{{item.operateBy}}">
               <text class="sub-label">开具人:</text>
               {{item.operateBy}}
             </view>
-            <view class="row">
+            <view class="row" wx:if="{{item.estimatedStartDate}}">
               <text class="sub-label">开始时间:</text>
               {{item.estimatedStartDate}}
             </view>
             <view class="row">
               <text class="sub-label">频次:</text>
-              每{{item.frequencyType}}天{{item.frequencyMeasure}}{{item.convertUnit}}
+              每{{item.frequencyType}}天{{item.frequencyMeasure}}{{item.convertUnit?item.convertUnit: '次'}}
             </view>
-            <view class="row" wx:if="{{item.arrangeDate}}">
+            <view class="row">
               <text class="sub-label">下次时间:</text>
-              {{item.arrangeDate}}
+              {{item.arrangeDate?item.arrangeDate: '-'}} {{item.arrangeTime ?item.arrangeTime: ''}}{{item.applyTime?'(已预约)':''}}
             </view>
-            <view class="row" wx:if="{{item.conditioningProgramSupplierName}}">
+            <view class="row" wx:if="{{item.pieTime}}">
               <text class="sub-label">机构:</text>
-              {{item.conditioningProgramSupplierName}}
+              {{item.conditioningProgramSupplierName || '-'}}
             </view>
             <view class="divider"></view>
           </view>
-          <view style="margin-top:-80px">
+          <view>
             <view class="status" style="color:{{item.status === 'doing' ? '#F44336' : '#43A047'}}">
               {{item.progress === '0' ? '进行中' : '已完成'}}
             </view>
-            <view>{{item.finishCount}}/{{item.totalMeasure}}</view>
+            <view class="center">{{item.finishCount}}/{{item.totalMeasure}}</view>
+            <!-- 预约按钮/标签 -->
+            <view class="appointment-action" wx:if="{{item.progress === '0'}}">
+              <!-- 已预约:显示标签 -->
+              <view class="appointment-tag" wx:if="{{item.applyTime}}">
+                已预约
+              </view>
+              <!-- 未预约:显示按钮 -->
+              <view class="appointment-btn" wx:else catchtap="goAppointment" data-id="{{item.id}}"
+               data-item="{{item}}">
+                去预约
+              </view>
+            </view>
           </view>
         </view>
       </block>
-      <!-- 底部安全区占位 -->
-      <view class="safe-bottom-spacer"></view>
     </view>
     <view wx:elif="{{!isLoading && treatmentList.length === 0}}">
       <t-empty icon="info-circle-filled" description="暂无数据" />
     </view>
-
-  </scroll-view>
-</view>
+    <!-- 底部安全区占位 -->
+    <view class="safe-bottom-spacer"></view>
+  </scroll-view>

+ 1 - 1
miniprogram/module/care/request.ts

@@ -15,7 +15,7 @@ export function healthReportListMethod() {
 }
 // 线下非药物治疗
 export function getOfflineTreatmentListMethod(progress: string) {
-  return Post(`/patientCrManage/pagePofflineCp`, {progress}, {
+  return Post(`/patientCrManage/pagePofflineCp?pageNum=1&pageSize=1000000000`, { progress }, {
     transform({ data }: AnyObject) {
       return data;
     }

BIN
miniprogram/module/health/assets/image/bg_interview@2x.png


BIN
miniprogram/module/health/assets/image/health-report.png


BIN
miniprogram/module/health/assets/image/pic_body@2x.png


BIN
miniprogram/module/health/assets/image/pic_tongue@2x.png


+ 1 - 1
miniprogram/module/health/components/care-record/care-record.ts

@@ -27,7 +27,7 @@ Component({
       const name = e.currentTarget.dataset.name;
       if (id) {
         wx.navigateTo({
-          url: `/module/care/pages/careDetail/careDetail?id=${id}&name=${name}`,
+          url: `/module/care/pages/careDetail/careDetail?id=${id}&name=${name ? name : ''}`,
         });
       } else {
         wx.showToast({

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

@@ -200,4 +200,42 @@
   width: 100%;
   max-width: 500rpx;
   height: 500rpx;
+}
+
+// 底部去购买按钮
+.scheme-bottom-buy-btn {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  width: 100%;
+  min-height: 98rpx;
+  // background: linear-gradient(90deg, #1d6ff6 0%, #4a90ff 100%);
+  background: white;
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  z-index: 100;
+  box-shadow: 0 -4rpx 20rpx rgba(29, 111, 246, 0.2);
+  box-sizing: border-box;
+  padding-top: 24rpx;
+  padding-right: 32rpx;
+  
+  .buy-btn-text {
+    color: #ffffff;
+    font-size: 30rpx;
+    letter-spacing: 2rpx;
+    line-height: 1.2;
+    text-align: center;
+    background: #1d6ff6;
+    padding: 10px 30px;
+    border-radius: 5px;
+  }
+}
+
+// 底部占位,避免内容被按钮遮盖(98rpx按钮高度 + 安全区域)
+.scheme-bottom-placeholder {
+  height: 150rpx;
+  width: 100%;
+  box-sizing: border-box;
 }

+ 18 - 0
miniprogram/module/health/pages/scheme/scheme.ts

@@ -6,6 +6,7 @@ import TickleBehavior, {
 
 // module/health/pages/scheme/scheme.ts
 import { healthSchemeMethod } from "../../request";
+
 import { toReportPage } from "../../router";
 Component({
   behaviors: [I18nBehavior, PageContainerBehavior, TickleBehavior],
@@ -48,6 +49,23 @@ Component({
     toReportPage() {
       toReportPage(this.data.id);
     },
+    // 跳转到商品选择页面
+    goToProductPage() {
+      wx.setStorageSync('healthAnalysisReportId', this.data.id);
+      if (this.data.id) {
+        wx.redirectTo({
+          url: `/module/order/pages/select-goods/select-goods?healthAnalysisReportId=${this.data.id}`,
+          fail: (err) => {
+            getTickleContext.call(this).showWarnMessage(err.errMsg || "跳转失败");
+          },
+        });
+      } else {
+        wx.showToast({
+          title: "健康评估报告ID不能为空",
+          icon: "none",
+        });
+      }
+    },
     // 去购买
     goBuy(this: any, e: any) {
       const item = e.currentTarget.dataset.item || {};

+ 7 - 0
miniprogram/module/health/pages/scheme/scheme.wxml

@@ -42,7 +42,14 @@
         </view>
       </view>
     </view>
+    <!-- 底部占位,避免内容被按钮遮盖 -->
+    <view class="scheme-bottom-placeholder"></view>
   </scroll-view>
+  
+  <!-- 底部固定去购买按钮 -->
+  <view class="scheme-bottom-buy-btn" style="padding-bottom: {{container.safeBottomOffset-10}}px;" bindtap="goToProductPage" wx:if="{{true}}">
+    <view class="buy-btn-text">去购买</view>
+  </view>
 </view>
 <t-message id="{{$messageId}}"></t-message>
 

+ 49 - 0
miniprogram/module/order/assets/iconfont/iconfont.wxss

@@ -0,0 +1,49 @@
+/* 在线链接服务仅供平台体验和调试使用,平台不承诺服务的稳定性,企业客户需下载字体包自行发布使用并做好备份。 */
+@font-face {
+  font-family: 'iconfont';  /* Project id 5122513 */
+  src: 
+       url('//at.alicdn.com/t/c/font_5122513_0xmr1776dij.woff2?t=1770111604394') format('woff2'),
+       url('//at.alicdn.com/t/c/font_5122513_0xmr1776dij.woff?t=1770111604394') format('woff'),
+       url('//at.alicdn.com/t/c/font_5122513_0xmr1776dij.ttf?t=1770111604394') format('truetype');
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-zhongtong:before {
+  content: "\e600";
+}
+
+.icon-yuantongkuaidi:before {
+  content: "\e611";
+}
+
+.icon-shunfengkuaidi:before {
+  content: "\e8e3";
+}
+
+.icon-jitukuaidi:before {
+  content: "\e6a4";
+}
+
+.icon-yunda:before {
+  content: "\e64a";
+}
+
+.icon-shentong:before {
+  content: "\e64d";
+}
+
+.icon-youzhengkuaidi:before {
+  content: "\e708";
+}
+
+.icon-jingdong:before {
+  content: "\e603";
+}
+

+ 10 - 0
miniprogram/module/order/pages/appointment-success/appointment-success.json

@@ -0,0 +1,10 @@
+{
+  "renderer": "skyline",
+  "component": true,
+  "usingComponents": {
+    "t-navbar": "tdesign-miniprogram/navbar/navbar",
+    "van-calendar": "@vant/weapp/calendar/index",
+    "van-cell": "@vant/weapp/cell/index",
+    "van-icon": "@vant/weapp/icon/index"
+  }
+}

+ 105 - 0
miniprogram/module/order/pages/appointment-success/appointment-success.scss

@@ -0,0 +1,105 @@
+@import "../../../../themes/t.cell.scss";
+@import "../../../../themes/page.scss";
+
+/* module/order/pages/confirme-order/confirme-order.wxss */
+.page-scroll__container {
+  flex: 0 1 auto;
+  height: var(--page-container-safeHeight, 100vh);
+  background: #f2f2f2;
+  padding-bottom: 120rpx;
+  padding-top: 20rpx;
+}
+
+// 成功页面容器
+.success-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 40rpx;
+  // min-height: calc(100vh - 200rpx);
+  background: white;
+}
+
+// 标题
+.success-title {
+  font-size: 48rpx;
+  font-weight: 600;
+  color: #000;
+  margin-bottom: 50rpx;
+  text-align: center;
+}
+
+// 预约详情
+.appointment-details {
+  width: 100%;
+  margin-bottom: 80rpx;
+}
+
+.detail-item {
+  display: flex;
+  align-items: center;
+  margin-bottom: 32rpx;
+  font-size: 32rpx;
+  line-height: 1.5;
+}
+
+.detail-label {
+  color: #000;
+  margin-right: 16rpx;
+  // min-width: 200rpx;
+}
+
+.detail-value {
+  color: #000;
+  flex: 1;
+  font-weight: bold;
+}
+
+// 提示信息
+.tip-message {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  margin-top: auto;
+  padding: 0 40rpx;
+}
+
+.tip-text {
+  font-size: 28rpx;
+  color: #000;
+  line-height: 1.6;
+  text-align: center;
+}
+
+// 返回按钮
+.return-footer {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  width: 100%;
+  background: #fff;
+  padding: 20rpx 40rpx;
+  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
+  z-index: 100;
+  box-sizing: border-box;
+}
+
+.return-btn {
+  width: 100%;
+  height: 88rpx;
+  line-height: 88rpx;
+  text-align: center;
+  // background: #4a90ff;
+  background: linear-gradient(135deg, #1d6ff6 0%, #4a90ff 100%);
+  color: #fff;
+  font-size: 32rpx;
+  font-weight: 500;
+  border-radius: 44rpx;
+  transition: all 0.3s ease;
+
+  &:active {
+    opacity: 0.9;
+    transform: scale(0.98);
+  }
+}

+ 31 - 0
miniprogram/module/order/pages/appointment-success/appointment-success.ts

@@ -0,0 +1,31 @@
+import PageContainerBehavior from "../../../../core/behavior/page-container.behavior";
+import DictionariesBehavior from "../../../../core/behavior/dictionaries.behavior";
+import tickleBehavior from "../../../../core/behavior/tickle.behavior";
+
+// module/order/pages/appointment-success/appointment-success.ts
+Page({
+  behaviors: [PageContainerBehavior, DictionariesBehavior, tickleBehavior],
+  data: {
+    appointmentInfo: {
+    },
+  },
+  onLoad(options: any) {
+    if(options.goodsInfo){
+      const goodsInfo = JSON.parse(options.goodsInfo);
+      console.log(goodsInfo, "goodsInfo")
+      this.setData({
+        appointmentInfo: goodsInfo,
+      });
+    }
+    
+  },
+  // 返回非药物治疗页面
+  onReturn() {
+    // 返回到非药物治疗页面,传递预约成功参数
+    const { appointmentInfo } = this.data;
+    console.log(appointmentInfo, "appointmentInfo")
+    wx.redirectTo({
+      url: `/module/care/pages/offlineTreatment/offlineTreatment?id=${appointmentInfo?.id}`,
+    });
+  },
+})

+ 37 - 0
miniprogram/module/order/pages/appointment-success/appointment-success.wxml

@@ -0,0 +1,37 @@
+<!--module/order/pages/confirme-success/confirme-success.wxml-->
+<t-navbar title="预约成功" left-arrow />
+<scroll-view class="page-scroll__container" type="list" scroll-y style="{{containerStyle}}">
+  <view class="success-container">
+    <!-- 标题 -->
+    <view class="success-title">预约成功</view>
+
+    <!-- 预约详情 -->
+    <view class="appointment-details">
+      <view class="detail-item">
+        <text class="detail-label">预约项目:</text>
+        <text class="detail-value">{{appointmentInfo.name}}</text>
+      </view>
+      <view class="detail-item">
+        <text class="detail-label">开始服务时间:</text>
+        <text class="detail-value">{{appointmentInfo.appointmentTime}}</text>
+      </view>
+      <view class="detail-item">
+        <text class="detail-label">服务时长:</text>
+        <text class="detail-value">{{appointmentInfo.duration}}分钟</text>
+      </view>
+    </view>
+
+    <!-- 提示信息 -->
+    <view class="tip-message">
+      <text class="tip-text">请保持电话畅通, 30分钟内将有工作人员与您联</text>
+      <text class="tip-text">系</text>
+    </view>
+  </view>
+</scroll-view>
+
+<!-- 返回按钮 -->
+<view class="return-footer" style="padding-bottom: {{container.safeBottomOffset}}px;">
+  <view class="return-btn" bindtap="onReturn">
+    返回
+  </view>
+</view>

+ 10 - 0
miniprogram/module/order/pages/appointment/appointment.json

@@ -0,0 +1,10 @@
+{
+  "renderer": "skyline",
+  "component": true,
+  "usingComponents": {
+    "t-navbar": "tdesign-miniprogram/navbar/navbar",
+    "t-icon": "tdesign-miniprogram/icon/icon",
+    "t-calendar": "tdesign-miniprogram/calendar/calendar",
+    "van-calendar": "@vant/weapp/calendar/index"
+  }
+}

+ 255 - 0
miniprogram/module/order/pages/appointment/appointment.scss

@@ -0,0 +1,255 @@
+@import "../../../../themes/t.cell.scss";
+@import "../../../../themes/page.scss";
+
+/* module/order/pages/appointment/appointment.wxss */
+.page-scroll__container {
+  flex: 0 1 auto;
+  height: var(--page-container-safeHeight, 100vh);
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+
+// 服务信息卡片
+.service-card {
+  display: flex;
+  align-items: center;
+  background: #fff;
+  margin: 20rpx;
+  padding: 24rpx;
+  border-radius: 16rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
+}
+
+.service-image {
+  width: 120rpx;
+  height: 120rpx;
+  border-radius: 12rpx;
+  margin-right: 24rpx;
+  flex-shrink: 0;
+  background: #f5f5f5;
+}
+
+.service-placeholder {
+  width: 120rpx;
+  height: 120rpx;
+  border-radius: 12rpx;
+  margin-right: 24rpx;
+  flex-shrink: 0;
+  background: #f5f5f5;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 48rpx;
+}
+
+.service-info {
+  flex: 1;
+  display: flex;
+  // flex-direction: column;
+  align-items: center;
+  justify-content: space-between;
+  gap: 12rpx;
+}
+
+.service-name {
+  font-size: 32rpx;
+  font-weight: 500;
+  color: #333;
+}
+
+.service-duration {
+  font-size: 28rpx;
+  color: #666;
+}
+
+// 时间选择卡片
+.time-selection-card {
+  background: #fff;
+  margin: 0 20rpx 20rpx 20rpx;
+  // padding: 32rpx;
+  padding: 20rpx;
+  border-radius: 16rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
+}
+
+.time-selection-header {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+  background: white;
+  border-radius: 12rpx;
+  padding: 24rpx 32rpx;
+}
+
+.time-selection-title {
+  font-size: 30rpx;
+  font-weight: 500;
+  color: black;
+  text-align: center;
+  width: 100%;
+}
+
+.time-selection-icon {
+  position: absolute;
+  right: 32rpx;
+  top: 50%;
+  transform: translateY(-50%);
+  display: flex;
+  align-items: center;
+}
+
+// 日期选择器
+.date-selector {
+  display: flex;
+  gap: 12rpx;
+  margin-bottom: 32rpx;
+  overflow-x: auto;
+  padding-bottom: 8rpx;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.date-item {
+  flex-shrink: 0;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 16rpx 18rpx;
+  border-radius: 12rpx;
+  // background: #f7f8fa;
+  background: white;
+  border: 2rpx solid transparent;
+  transition: all 0.3s ease;
+  // min-width: 100rpx;
+
+  &:active {
+    transform: scale(0.95);
+  }
+}
+
+.date-item--selected {
+  // 选中状态样式在子元素中定义
+  position: relative;
+}
+
+.date-label {
+  font-size: 24rpx;
+  color: #666;
+  margin-bottom: 6rpx;
+}
+
+.date-item--selected .date-label {
+  color: #4caf50;
+  font-weight: 600;
+}
+
+.date-value {
+  font-size: 26rpx;
+  color: #333;
+  font-weight: 500;
+}
+
+.date-item--selected .date-value {
+  color: #4caf50;
+  font-weight: 600;
+}
+
+// 时间选择网格 - 5行5列表格
+.time-grid {
+  display: flex;
+  flex-wrap: wrap;
+  border: 1rpx solid #e0e0e0;
+  border-radius: 0;
+  background: #fff;
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.time-slot {
+  width: 20%;
+  text-align: center;
+  font-size: 28rpx;
+  color: #000;
+  background: #fff;
+  border-right: 1rpx solid #e0e0e0;
+  border-bottom: 1rpx solid #e0e0e0;
+  border-radius: 0;
+  transition: all 0.3s ease;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  min-height: 88rpx;
+  box-sizing: border-box;
+  padding: 0;
+  flex-shrink: 0;
+
+  // 每行最后一个去掉右边框
+  &:nth-child(5n) {
+    border-right: none;
+  }
+
+  // 最后一行去掉下边框
+  &:nth-child(n+21) {
+    border-bottom: none;
+  }
+
+  &:active:not(.time-slot--disabled):not(.time-slot--selected) {
+    background: #fafafa;
+  }
+}
+
+.time-slot--selected {
+  background: #1d6ff6 !important;
+  border-color: #1d6ff6 !important;
+  color: #fff !important;
+  font-weight: 500;
+  z-index: 1;
+  position: relative;
+}
+
+.time-slot--disabled {
+  background: #fff;
+  border-color: #e0e0e0;
+  color: #ccc;
+  opacity: 0.6;
+}
+
+// 底部安全区占位
+.safe-bottom-spacer {
+  height: 120rpx;
+}
+
+// 提交按钮
+.submit-footer {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  width: 100%;
+  background: #fff;
+  padding: 20rpx;
+  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
+  z-index: 100;
+  box-sizing: border-box;
+}
+
+.submit-btn {
+  width: 100%;
+  height: 88rpx;
+  line-height: 88rpx;
+  text-align: center;
+  background: linear-gradient(135deg, #1d6ff6 0%, #4a90ff 100%);
+  color: #fff;
+  font-size: 32rpx;
+  font-weight: 600;
+  border-radius: 44rpx;
+  box-shadow: 0 4rpx 12rpx rgba(29, 111, 246, 0.3);
+  transition: all 0.3s ease;
+
+  &:active {
+    opacity: 0.9;
+    transform: scale(0.98);
+    box-shadow: 0 2rpx 8rpx rgba(29, 111, 246, 0.4);
+  }
+}

+ 291 - 0
miniprogram/module/order/pages/appointment/appointment.ts

@@ -0,0 +1,291 @@
+import PageContainerBehavior from "../../../../core/behavior/page-container.behavior";
+import DictionariesBehavior from "../../../../core/behavior/dictionaries.behavior";
+import tickleBehavior from "../../../../core/behavior/tickle.behavior";
+import { patientOfflineTreatmentAppointmentMethod } from "../../request";
+// module/order/pages/appointment/appointment.ts
+Page({
+  behaviors: [PageContainerBehavior, DictionariesBehavior, tickleBehavior],
+  data: {
+    goodsInfo: { appointmentTime: '' },
+    dateList: [] as Array<{
+      label: string;
+      dateStr: string;
+      date: string;
+      isSelected: boolean;
+    }>,
+    timeSlots: [] as Array<{
+      time: string;
+      isSelected: boolean;
+      isDisabled: boolean;
+    }>,
+    selectedDate: "",
+    selectedTime: "",
+    show: false,
+    date: '',
+    offlineId: "",
+  },
+  onLoad(options: any) {
+    // 初始化日期列表(从今天开始5天)
+    this.initDateList();
+    if (options.goodsInfo) {
+      const goodsInfo = JSON.parse(options.goodsInfo);
+      this.setData({
+        goodsInfo: goodsInfo,
+        offlineId: goodsInfo.offlineId,
+      });
+    }
+  },
+  // 初始化日期列表
+  initDateList(startDate?: Date) {
+    const dateList: Array<{
+      label: string;
+      dateStr: string;
+      date: string;
+      isSelected: boolean;
+    }> = [];
+    const baseDate = startDate || new Date();
+    // 设置时间为0点,避免时区问题
+    baseDate.setHours(0, 0, 0, 0);
+    const today = new Date();
+    today.setHours(0, 0, 0, 0);
+    const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
+
+    for (let i = 0; i < 5; i++) {
+      const date = new Date(baseDate);
+      date.setDate(baseDate.getDate() + i);
+
+      const month = date.getMonth() + 1;
+      const day = date.getDate();
+      const weekDay = weekDays[date.getDay()];
+
+      // 判断相对今天的位置
+      const diffDays = Math.floor((date.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));
+      let label = '';
+      if (diffDays === 0) {
+        label = '今天';
+      } else if (diffDays === 1) {
+        label = '明天';
+      } else {
+        label = weekDay;
+      }
+
+      const dateStr = `${month}月${day}日`;
+      const dateValue = `${date.getFullYear()}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
+
+      dateList.push({
+        label,
+        dateStr,
+        date: dateValue,
+        isSelected: i === 0, // 默认选中第一个
+      });
+    }
+
+    this.setData({
+      dateList,
+      selectedDate: dateList[0].date, // 默认选中第一个日期
+    });
+
+    // 初始化时间列表,传入默认选中的日期
+    this.initTimeSlots(dateList[0].date);
+  },
+  // 初始化时间列表 - 固定8:00-20:00
+  initTimeSlots(selectedDate?: string) {
+    const timeSlots: Array<{
+      time: string;
+      isSelected: boolean;
+      isDisabled: boolean;
+    }> = [];
+
+    const now = new Date();
+    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
+    const selectedDateObj = selectedDate ? new Date(selectedDate) : today;
+    const selectedDateOnly = new Date(selectedDateObj.getFullYear(), selectedDateObj.getMonth(), selectedDateObj.getDate());
+
+    // 判断选中的日期是否是今天
+    const isToday = selectedDateOnly.getTime() === today.getTime();
+    const currentHour = now.getHours();
+    const currentMinute = now.getMinutes();
+
+    // 从08:00到20:00,每30分钟一个时间段
+    for (let hour = 8; hour <= 20; hour++) {
+      for (let minute = 0; minute < 60; minute += 30) {
+        if (timeSlots.length >= 25) break; // 限制为25个时间段
+        const timeStr = `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
+
+        // 如果是今天,需要判断时间是否已过去
+        let isDisabled = false;
+        if (isToday) {
+          // 如果时间已过去,禁用
+          if (hour < currentHour || (hour === currentHour && minute <= currentMinute)) {
+            isDisabled = true;
+          }
+        }
+
+        timeSlots.push({
+          time: timeStr,
+          isSelected: false,
+          isDisabled,
+        });
+      }
+    }
+
+    this.setData({ timeSlots });
+  },
+  // 选择日期
+  onDateSelect(e: any) {
+    const index = e.currentTarget.dataset.index;
+    const dateList = this.data.dateList.map((item, i) => ({
+      ...item,
+      isSelected: i === index,
+    }));
+
+    const selectedDate = dateList[index].date;
+
+    // 重新初始化时间列表,根据选中的日期禁用已过去的时间
+    this.initTimeSlots(selectedDate);
+
+    this.setData({
+      dateList,
+      selectedDate,
+      // 切换日期时清空已选时间
+      selectedTime: "",
+    });
+  },
+  // 选择时间
+  onTimeSelect(e: any) {
+    const index = e.currentTarget.dataset.index;
+    const time = e.currentTarget.dataset.time;
+    const timeSlot = this.data.timeSlots[index];
+
+    // 如果时间段被禁用,不处理
+    if (timeSlot && timeSlot.isDisabled) {
+      return;
+    }
+
+    // 每次只能选择一个时间段,点击新的会取消之前的选择
+    const timeSlots = this.data.timeSlots.map((item, i) => ({
+      ...item,
+      isSelected: i === index, // 只有当前点击的为选中状态
+    }));
+
+    this.setData({
+      timeSlots,
+      selectedTime: time,
+    });
+  },
+  // 提交预约
+  async onSubmit() {
+
+    if (!this.data.selectedDate) {
+      wx.showToast({
+        title: "请选择日期",
+        icon: "none",
+      });
+      return;
+    }
+    if (!this.data.selectedTime) {
+      wx.showToast({
+        title: "请选择时间",
+        icon: "none",
+      });
+      return;
+    }
+    console.log(this.data.selectedDate, "this.data.selectedDate", this.data.selectedTime, "this.data.selectedTime", this.data.offlineId, "this.data.offlineId")
+
+    const appointmentTime = `${this.data.selectedDate} ${this.data.selectedTime}`;
+    console.log(appointmentTime, "appointmentTime");
+    console.log(this.data.offlineId, "this.data.offlineId");
+    this.setData({
+      goodsInfo: {
+        ...this.data.goodsInfo,
+        appointmentTime: `${this.data.selectedDate} ${this.data.selectedTime}`,
+      },
+    });
+    try {
+      await patientOfflineTreatmentAppointmentMethod(this.data.offlineId, appointmentTime);
+      wx.showToast({
+        title: '预约成功',
+        icon: 'success',
+      });
+      setTimeout(() => {
+        wx.redirectTo({
+          url: `/module/order/pages/appointment-success/appointment-success?goodsInfo=${JSON.stringify(this.data.goodsInfo)}`,
+        });
+      }, 1000);
+
+    } catch (error: any) {
+      wx.showToast({
+        title: error.errMsg || "预约失败",
+        icon: "none",
+      });
+      console.log(error, "error")
+    }
+  },
+
+  // 打开日历弹窗
+  onOpenCalendar() {
+    console.log('onOpenCalendar');
+    this.setData({ show: true });
+  },
+  // 关闭日历弹窗
+  onClose() {
+    this.setData({ show: false });
+  },
+  // 格式化日期
+  formatDate(date: any) {
+    date = new Date(date);
+    return `${date.getMonth() + 1}/${date.getDate()}`;
+  },
+  // 确认选择日期
+  onConfirm(event: any) {
+    const selectedDate = event.detail;
+    console.log('选择的日期:', selectedDate);
+
+    if (selectedDate) {
+      // 解析日期
+      const dateObj = new Date(selectedDate);
+      dateObj.setHours(0, 0, 0, 0);
+
+      // 格式化日期字符串用于比较
+      const dateValue = `${dateObj.getFullYear()}-${String(dateObj.getMonth() + 1).padStart(2, '0')}-${String(dateObj.getDate()).padStart(2, '0')}`;
+
+      // 检查选择的日期是否在当前展示的5天中
+      const existingDateIndex = this.data.dateList.findIndex(item => item.date === dateValue);
+
+      if (existingDateIndex !== -1) {
+        // 如果选择的日期在已展示的5天中,只更新选中状态
+        const dateList = this.data.dateList.map((item, index) => ({
+          ...item,
+          isSelected: index === existingDateIndex,
+        }));
+
+        // 重新初始化时间列表,根据选中的日期禁用已过去的时间
+        this.initTimeSlots(dateValue);
+
+        // 清空已选时间
+        this.setData({
+          show: false,
+          dateList,
+          selectedDate: dateValue,
+          date: this.formatDate(selectedDate),
+          selectedTime: "",
+        });
+      } else {
+        // 如果选择的日期不在已展示的5天中,重新生成日期列表
+        this.initDateList(dateObj);
+
+        // 重新初始化时间列表,根据选中的日期禁用已过去的时间
+        this.initTimeSlots(dateValue);
+
+        // 清空已选时间
+        this.setData({
+          show: false,
+          date: this.formatDate(selectedDate),
+          selectedTime: "",
+        });
+      }
+    } else {
+      this.setData({ show: false });
+    }
+  },
+});

+ 53 - 0
miniprogram/module/order/pages/appointment/appointment.wxml

@@ -0,0 +1,53 @@
+<!--module/order/pages/appointment/appointment.wxml-->
+<t-navbar title="预约" left-arrow />
+<scroll-view class="page-scroll__container" type="list" scroll-y style="{{containerStyle}}">
+  <!-- 服务信息卡片 -->
+  <view class="service-card">
+    <image class="service-image" src="{{goodsInfo.image}}" mode="aspectFill" wx:if="{{goodsInfo.image}}" />
+    <view class="service-placeholder" wx:else>
+      <text class="placeholder-icon">📦</text>
+    </view>
+    <view class="service-info">
+      <text class="service-name">{{goodsInfo.name}}</text>
+      <text class="service-duration">{{goodsInfo.duration}}分钟</text>
+    </view>
+  </view>
+
+  <!-- 时间选择区域 -->
+  <view class="time-selection-card">
+    <view class="time-selection-header">
+      <text class="time-selection-title">请选择开始服务时间</text>
+      <view class="time-selection-icon" bindtap="onOpenCalendar">
+        <t-icon name="calendar" size="40rpx" color="#000" />
+      </view>
+    </view>
+
+    <!-- 日期选择 -->
+    <view class="date-selector">
+      <view class="date-item {{item.isSelected ? 'date-item--selected' : ''}}" wx:for="{{dateList}}" wx:key="date" bindtap="onDateSelect" data-index="{{index}}">
+        <text class="date-label">{{item.label}}</text>
+        <text class="date-value">{{item.dateStr}}</text>
+      </view>
+    </view>
+
+    <!-- 时间选择网格 -->
+    <view class="time-grid">
+      <view class="time-slot {{item.isSelected ? 'time-slot--selected' : ''}} {{item.isDisabled ? 'time-slot--disabled' : ''}}" wx:for="{{timeSlots}}" wx:key="time" bindtap="onTimeSelect" data-index="{{index}}" data-time="{{item.time}}">
+        {{item.time}}
+      </view>
+    </view>
+  </view>
+
+  <!-- 底部安全区占位 -->
+  <view class="safe-bottom-spacer"></view>
+
+</scroll-view>
+
+<!-- 提交按钮 -->
+<view class="submit-footer" style="padding-bottom: {{container.safeBottomOffset}}px;">
+  <view class="submit-btn" bindtap="onSubmit">
+    提交预约
+  </view>
+</view>
+<!-- 日期选择弹窗 -->
+<van-calendar show="{{ show }}" show-title title="日期选择" bind:close="onClose" bind:confirm="onConfirm" color="#1d6ff6" />

+ 8 - 0
miniprogram/module/order/pages/confirme-order/confirme-order.json

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

+ 569 - 0
miniprogram/module/order/pages/confirme-order/confirme-order.scss

@@ -0,0 +1,569 @@
+@import "../../../../themes/t.cell.scss";
+@import "../../../../themes/page.scss";
+
+/* module/order/pages/confirme-order/confirme-order.wxss */
+.page-scroll__container {
+  flex: 0 1 auto;
+  height: var(--page-container-safeHeight, 100vh);
+  background: #f7f8fa;
+  padding-bottom: 210rpx;
+}
+
+.bottom {
+  padding-bottom: 0;
+}
+.service-package-placeholder {
+  width: 160rpx;
+  height: 160rpx;
+  border-radius: 8rpx;
+  margin-right: 20rpx;
+  background-color: #f5f5f5;
+  border: 1px solid #e8e8e8;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+}
+.goods-list {
+  background: transparent;
+  margin-bottom: 20rpx;
+  padding: 0 20rpx;
+}
+
+.category-title {
+  padding: 28rpx 32rpx 0rpx;
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+  background: #fff;
+  position: sticky;
+  top: 0;
+  z-index: 10;
+  border-radius: 10rpx 10rpx 0 0;
+  margin-bottom: 0;
+}
+
+.goods-item {
+  display: flex;
+  align-items: center;
+  padding: 32rpx;
+  // margin: 0 20rpx 20rpx;
+  background: #fff;
+  border-radius: 0 0 16rpx 16rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
+  transition: all 0.3s ease;
+  padding-bottom: 10px;
+  &:active {
+    transform: scale(0.98);
+    box-shadow: 0 1rpx 8rpx rgba(0, 0, 0, 0.06);
+  }
+}
+
+.goods-checkbox {
+  margin-right: 24rpx;
+  margin-top: 8rpx;
+  flex-shrink: 0;
+}
+
+.goods-image {
+  width: 180rpx;
+  height: 180rpx;
+  border-radius: 12rpx;
+  background: #f5f5f5;
+  margin-right: 24rpx;
+  flex-shrink: 0;
+  border: 1rpx solid #f0f0f0;
+}
+
+.goods-info {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  min-width: 0;
+  justify-content: space-between;
+  min-height: 180rpx;
+}
+.goods-name-row {
+  display: flex;
+  align-items: center;
+  margin-bottom: 12rpx;
+  flex-wrap: wrap;
+}
+.goods-name {
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+  flex: 1;
+  min-width: 0;
+  line-height: 1.4;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+  line-clamp: 2;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.goods-desc {
+  font-size: 26rpx;
+  color: #999;
+  margin-bottom: 20rpx;
+  line-height: 1.4;
+}
+.goods-price-row {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-top: auto;
+}
+.goods-price-info {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  // justify-content: center;
+  flex-shrink: 0;
+  height: 160rpx;
+}
+
+.goods-price {
+  font-size: 36rpx;
+  font-weight: 700;
+  color: #ff4444;
+  letter-spacing: -0.5rpx;
+}
+
+.quantity-selector {
+  display: flex;
+  align-items: center;
+  border: 2rpx solid #e8e8e8;
+  border-radius: 12rpx;
+  overflow: hidden;
+  background: #fff;
+  box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.04);
+}
+
+.quantity-btn {
+  width: 64rpx;
+  height: 64rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: #f8f8f8;
+  font-size: 36rpx;
+  font-weight: 500;
+  color: #333;
+  user-select: none;
+  transition: all 0.2s ease;
+  position: relative;
+
+  &.minus {
+    border-right: 1rpx solid #e8e8e8;
+  }
+
+  &.plus {
+    border-left: 1rpx solid #e8e8e8;
+  }
+
+  &:active:not(.disabled) {
+    background: #1d6ff6;
+    color: #fff;
+    transform: scale(0.95);
+  }
+
+  &.disabled {
+    opacity: 0.4;
+    background: #f5f5f5;
+    color: #ccc;
+    cursor: not-allowed;
+  }
+}
+
+.quantity-input {
+  width: 90rpx;
+  height: 64rpx;
+  text-align: center;
+  font-size: 30rpx;
+  font-weight: 500;
+  color: #333;
+  background: #fff;
+  border: none;
+  padding: 0;
+
+  &[disabled] {
+    background: #f8f8f8;
+    color: #999;
+    opacity: 0.6;
+  }
+}
+
+.quantity-text {
+  font-size: 26rpx;
+  font-weight: 400;
+  color: #666;
+}
+
+.footer-placeholder {
+  height: 120rpx;
+}
+
+.footer-bar {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  width: 100%;
+  min-height: 100rpx;
+  background: #fff;
+  display: flex;
+  align-items: center;
+  padding: 20rpx 10rpx 0 0;
+  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
+  z-index: 100;
+  box-sizing: border-box;
+  border-top: 1rpx solid #f0f0f0;
+}
+
+.footer-left {
+  flex-shrink: 0;
+  margin-right: 32rpx;
+}
+
+.footer-center {
+  flex: 1;
+  display: flex;
+  align-items: baseline;
+  font-size: 28rpx;
+  color: #333;
+  line-height: 1.4;
+  padding-left: 20px;
+}
+
+.footer-text {
+  color: #666;
+  font-size: 26rpx;
+}
+
+.footer-price {
+  color: #ff4444;
+  font-weight: 700;
+  font-size: 36rpx;
+  margin-left: 8rpx;
+  letter-spacing: -0.5rpx;
+}
+
+.footer-right {
+  flex-shrink: 0;
+  padding-right: 10px;
+}
+
+.checkout-btn {
+  line-height: 76rpx;
+  text-align: center;
+  background: linear-gradient(135deg, #1d6ff6 0%, #4a90ff 100%);
+  color: #fff;
+  font-size: 30rpx;
+  font-weight: 600;
+  border-radius: 38rpx;
+  box-shadow: 0 4rpx 12rpx rgba(29, 111, 246, 0.3);
+  transition: all 0.3s ease;
+  padding: 0 20px;
+  user-select: none;
+  &:active:not(.checkout-btn--loading) {
+    opacity: 0.9;
+    transform: scale(0.98);
+    box-shadow: 0 2rpx 8rpx rgba(29, 111, 246, 0.4);
+  }
+
+  &.checkout-btn--loading {
+    opacity: 0.7;
+    pointer-events: none;
+    cursor: not-allowed;
+  }
+}
+.t-checkbox--block {
+  padding: 0 !important;
+}
+// 选择地址的css
+.info-box {
+  padding: 10rpx 20rpx 10rpx 20rpx;
+  background: #f7f8fa;
+}
+.show-bttom {
+  padding: 20rpx;
+}
+.delivery-address {
+  font-weight: 500;
+  font-size: 30rpx;
+  color: #333;
+  padding: 23rpx 20rpx;
+}
+
+.order-no {
+  font-size: 28rpx;
+  color: black;
+  margin: 24rpx 0 0 0;
+}
+
+.address-card {
+  background: #fff;
+  border-radius: 16rpx;
+  overflow: hidden;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
+
+  &.address-card--clickable {
+    cursor: pointer;
+    transition: all 0.3s ease;
+
+    &:active {
+      opacity: 0.8;
+      transform: scale(0.98);
+    }
+  }
+
+  &.address-card--disabled {
+    opacity: 0.9;
+    pointer-events: none;
+  }
+}
+
+.address-content {
+  display: flex;
+  align-items: flex-start;
+  padding: 25rpx 24rpx;
+  position: relative;
+}
+
+.address-icon-wrapper {
+  flex-shrink: 0;
+  width: 64rpx;
+  height: 64rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 10rpx;
+  border-radius: 50%;
+}
+
+.address-icon {
+  width: 36rpx;
+  height: 36rpx;
+}
+
+.address-info {
+  flex: 1;
+  min-width: 0;
+  display: flex;
+  flex-direction: column;
+  gap: 12rpx;
+}
+
+.address-header {
+  display: flex;
+  align-items: center;
+  gap: 24rpx;
+  flex-wrap: wrap;
+}
+
+.address-name {
+  font-weight: 500;
+  font-size: 30rpx;
+  color: #333;
+  line-height: 1.4;
+  margin-right: 20rpx;
+}
+
+.address-phone {
+  font-weight: 400;
+  font-size: 28rpx;
+  color: #333;
+  line-height: 1.4;
+}
+
+.address-detail {
+  color: #666;
+  font-size: 26rpx;
+  line-height: 1.6;
+  word-break: break-all;
+}
+
+.address-actions {
+  flex-shrink: 0;
+  display: flex;
+  align-items: center;
+  gap: 20rpx;
+  margin-left: 16rpx;
+}
+
+.edit-icon {
+  font-size: 32rpx;
+  color: #666;
+  opacity: 0.7;
+}
+
+.arrow-icon {
+  font-size: 40rpx;
+  color: #ccc;
+  margin-left: 10rpx;
+}
+
+.price-total-wrapper {
+  padding: 0 20rpx 24rpx;
+  margin-top: -24rpx;
+}
+
+.price-total {
+  display: flex;
+  justify-content: flex-end;
+  align-items: baseline;
+  background: #fff;
+  border-radius: 10rpx;
+  padding: 32rpx;
+
+  .price-value {
+    font-size: 40rpx;
+    color: black;
+    font-weight: 600;
+  }
+}
+
+// 价格汇总区域
+.price-summary-section {
+  padding: 0 20rpx 20rpx;
+  background: #f7f8fa;
+}
+
+.price-summary-card {
+  background: #fff;
+  border-radius: 10rpx;
+  padding: 32rpx;
+  display: flex;
+  gap: 24rpx;
+}
+
+.price-row {
+  justify-content: flex-end;
+  align-items: baseline;
+}
+
+.price-label {
+  font-size: 30rpx;
+  color: #333;
+  font-weight: 400;
+}
+
+.payable-value {
+  font-size: 40rpx;
+  color: #333;
+  font-weight: 700;
+}
+
+// 订单信息区域
+.order-info-section {
+  padding: 0 20rpx 40rpx;
+  background: #f7f8fa;
+  margin-bottom: 40rpx;
+}
+
+.info-card {
+  background: #fff;
+  border-radius: 0;
+  margin-bottom: 0;
+  padding: 0 32rpx;
+  overflow: hidden;
+  margin-top: 20rpx;
+  border-radius: 10rpx;
+
+  &:first-child {
+    margin-top: 0;
+  }
+}
+
+.info-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 32rpx 0;
+  min-height: 88rpx;
+  box-sizing: border-box;
+}
+
+.info-label {
+  font-size: 28rpx;
+  color: #333;
+  font-weight: 400;
+  flex-shrink: 0;
+}
+
+.info-value {
+  font-size: 28rpx;
+  color: #333;
+  text-align: right;
+  flex: 1;
+  word-break: break-all;
+  margin-left: 24rpx;
+}
+
+.info-value-row {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  flex: 1;
+  gap: 16rpx;
+  margin-left: 24rpx;
+}
+
+.copy-btn {
+  font-size: 28rpx;
+  color: #1d6ff6;
+  flex-shrink: 0;
+  margin-left: 10px;
+}
+
+.info-divider {
+  height: 1rpx;
+  background: #f0f0f0;
+  margin: 0;
+  width: 100%;
+}
+
+// 备注相关样式
+.remark-item {
+  padding: 32rpx 0 40rpx;
+  display: flex;
+  flex-direction: column;
+}
+
+.remark-input-wrapper {
+  margin-top: 20rpx;
+  position: relative;
+  width: 100%;
+}
+
+.remark-textarea {
+  width: 100%;
+  min-height: 160rpx;
+  padding: 20rpx;
+  font-size: 28rpx;
+  color: #333;
+  background: #f7f8fa;
+  border-radius: 8rpx;
+  box-sizing: border-box;
+  line-height: 1.6;
+  border: 1rpx solid #e8e8e8;
+
+  &:focus {
+    border-color: #1d6ff6;
+    background: #fff;
+  }
+}
+
+.remark-count {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 12rpx;
+}
+
+.remark-count-text {
+  font-size: 24rpx;
+  color: #999;
+}

+ 480 - 0
miniprogram/module/order/pages/confirme-order/confirme-order.ts

@@ -0,0 +1,480 @@
+import DictionariesBehavior from "../../../../core/behavior/dictionaries.behavior";
+import PageContainerBehavior from "../../../../core/behavior/page-container.behavior";
+import { handleWeChatPayment } from "../../../../utils/util";
+import { getAddressListMethod, purchaseOfflineTreatmentMethod } from "../../request";
+import tickleBehavior, {
+  getTickleContext,
+} from "../../../../core/behavior/tickle.behavior";
+
+// module/order/pages/confirme-order/confirme-order.ts
+Page({
+  behaviors: [PageContainerBehavior, DictionariesBehavior, tickleBehavior],
+  properties: {},
+  data: {
+    totalGoodsCount: 0,
+    goodsList: [] as Array<{
+      category: string;
+      goods: Array<{
+        id: string;
+        name: string;
+        description?: string;
+        image: string;
+        price: number;
+        quantity: number;
+        checked: boolean;
+      }>;
+    }>,
+    selectAll: true,
+    selectedCount: 0,
+    totalPrice: 0,
+    remark: '',
+    remarkLength: 0,
+    showDetail: false,
+    isPaymentLoading: false, // 支付加载状态
+    name: "",
+    phone: "",
+    address: "",
+    isDefault: '',
+    provinceName: '',
+    cityName: '',
+    areaName: '',
+  },
+  onLoad(options: any) {
+    if (options.isDefault) {
+      this.setData({
+        isDefault: options.isDefault,
+      });
+    }
+    this.load('');
+  },
+  onShow() {
+    //先接收用户选择的地址,如果接收到用户选择的地址就用用户选择的,如果没有则使用默认地址
+    const selectedAddress = wx.getStorageSync('selectedAddress');
+    if (selectedAddress && this.data.isDefault === '1') {
+      this.setData({
+        showDetail: false,
+        name: selectedAddress.liaison || "",
+        phone: selectedAddress.phone || "",
+        address: `${selectedAddress.provinceName || ""}${selectedAddress.cityName || ""}${selectedAddress.areaName || ""}${selectedAddress.detailAddress || ""}`,
+        provinceName: selectedAddress.provinceName || "",
+        cityName: selectedAddress.cityName || "",
+        areaName: selectedAddress.areaName || "",
+      });
+    } else {
+      this.getDefaultAddress();
+    }
+  },
+  onHide() {
+    wx.removeStorageSync('selectedAddress');
+  },
+  observers: {
+    'goodsList': function () {
+      this.calculateSummary();
+    }
+  },
+  // 获取用户的默认地址
+  async getDefaultAddress() {
+    wx.showLoading({ title: "加载中" });
+    try {
+      // 获取所有的地址列表
+      const res = await getAddressListMethod("", "");
+      if (res && res.length > 0) {
+        res.forEach((item: any) => {
+          item.fullAddress = `${item.provinceName} ${item.cityName} ${item.areaName} ${item.detailAddress}`;
+          item.tag = item.tagList[0] || "";
+        });
+
+        // 过滤出默认地址
+        const defaultAddress = res.find((item: any) => item.isDefault === "Y");
+
+        if (defaultAddress) {
+          // 有默认地址,直接渲染在页面上
+          this.setData({
+            showDetail: false,
+            name: defaultAddress.liaison || "",
+            phone: defaultAddress.phone || "",
+            address: `${defaultAddress.provinceName || ""}${defaultAddress.cityName || ""}${defaultAddress.areaName || ""}${defaultAddress.detailAddress || ""}`,
+            addressList: res, // 保存所有地址列表,用于修改地址时使用
+            provinceName: defaultAddress.provinceName || "",
+            cityName: defaultAddress.cityName || "",
+            areaName: defaultAddress.areaName || "",
+          });
+        } else {
+          // 没有默认地址,显示"请选择配送地址"
+          this.setData({
+            showDetail: true,
+            name: "",
+            phone: "",
+            address: "",
+            addressList: res, // 保存所有地址列表,用于修改地址时使用
+          });
+        }
+      } else {
+        // 没有地址数据
+        this.setData({
+          showDetail: true,
+          name: "",
+          phone: "",
+          address: "",
+          addressList: [],
+        });
+      }
+    } catch (error: any) {
+      getTickleContext.call(this).showWarnMessage(error.errMsg);
+      // 出错时也显示"请选择配送地址"
+      this.setData({
+        showDetail: true,
+        name: "",
+        phone: "",
+        address: "",
+        addressList: [],
+      });
+    }
+    wx.hideLoading();
+  },
+  // 切换收货地址
+  changeAddress() {
+    wx.navigateTo({
+      url:
+        "/module/article/pages/manage-address/manage-address?type=confirmeOrder",
+    });
+  },
+  // 订单详情
+  async load(_id: string) {
+    wx.showLoading({ title: "加载中" });
+    try {
+      // 使用存储的selectedGoods数据渲染商品列表
+      const selectedGoods = wx.getStorageSync('selectedGoods') || [];
+      const totalPrice = wx.getStorageSync('totalPrice') || 0;
+
+      if (selectedGoods && selectedGoods.length > 0) {
+        // 使用存储的数据渲染商品列表
+        const goodsList = selectedGoods;
+        let totalGoodsCount = 0;
+        goodsList.forEach((category: any) => {
+          if (category.goods && Array.isArray(category.goods)) {
+            totalGoodsCount += category.goods.length;
+          }
+        });
+        this.setData({
+          goodsList,
+          totalGoodsCount,
+          totalPrice: parseFloat(totalPrice.toString()),
+        });
+        this.calculateSummary();
+      } else {
+        // 如果没有存储数据,提示用户
+        wx.showToast({
+          title: "暂无商品数据",
+          icon: "none",
+        });
+      }
+    } catch (error: any) {
+      wx.showToast({
+        title: error.errMsg || "加载失败",
+        icon: "none",
+      });
+    }
+    wx.hideLoading();
+  },
+
+  // 立即支付
+  async onPayment() {
+    if (this.data.isPaymentLoading) {
+      return;
+    }
+    this.setData({ isPaymentLoading: true });
+    try {
+      // 调用支付接口
+      const items = this.data.goodsList.map((item: any) => {
+        return item.goods.map((goods: any) => {
+          return {
+            id: goods.id,
+            quantity: goods.quantity,
+          };
+        });
+      }).flat();
+      const healthAnalysisReportId = wx.getStorageSync('healthAnalysisReportId');
+      const params = {
+        healthAnalysisReportId: healthAnalysisReportId,
+        items,
+        remark: this.data.remark || '',
+        liaison: this.data.name || '',
+        phone: this.data.phone || '',
+        detailAddress: this.data.address || '',
+        provinceName: this.data.provinceName || '',
+        cityName: this.data.cityName || '',
+        areaName: this.data.areaName || '',
+      };
+      if (!healthAnalysisReportId) {
+        wx.showToast({
+          title: "健康评估报告ID不能为空",
+          icon: "none",
+        });
+        this.setData({ isPaymentLoading: false });
+        return;
+      }
+      const payResult: any = await purchaseOfflineTreatmentMethod(params);
+      if (payResult) {
+        const paymentParams = payResult;
+        handleWeChatPayment(paymentParams, (_res: any) => {
+          // 支付成功,跳转到成功页面
+          wx.redirectTo({
+            url: "/module/article/pages/success-page/success-page?title=订单支付成功",
+          });
+        }, (error: any) => {
+          this.setData({ isPaymentLoading: false });
+          if (error?.errMsg === 'requestPayment:fail cancel') {
+            // 支付取消跳到支付订单页面
+            wx.navigateBack({ delta: 1 });
+          }
+          // wx.showToast({
+          //   title: error?.errMsg || error?.message || "支付失败,请重试",
+          //   icon: "none",
+          // });
+        });
+      } else {
+        wx.showToast({
+          title: "支付失败",
+          icon: "none",
+        });
+      }
+    } catch (error: any) {
+      wx.showToast({
+        title: error.errMsg,
+        icon: "none",
+      });
+    } finally {
+      this.setData({ isPaymentLoading: false });
+    }
+  },
+
+  // 商品复选框变化
+  onGoodsCheckChange(e: any) {
+    const { categoryIndex, goodsIndex } = e.currentTarget.dataset;
+    const checked = e.detail.checked;
+    const goodsList = this.data.goodsList;
+    const goods = goodsList[categoryIndex].goods[goodsIndex];
+
+    goods.checked = checked;
+
+    // 如果勾选且数量为0,设置为1
+    if (checked && goods.quantity === 0) {
+      goods.quantity = 1;
+    }
+
+    // 单价为0的商品,如果勾选,确保数量为1
+    if (checked && goods.price === 0 && goods.quantity !== 1) {
+      goods.quantity = 1;
+    }
+
+    this.setData({ goodsList });
+    this.calculateSummary();
+  },
+
+  // 数量变化(加减按钮)
+  onQuantityChange(e: any) {
+    const { categoryIndex, goodsIndex, type } = e.currentTarget.dataset;
+    const goodsList = this.data.goodsList;
+    const goods = goodsList[categoryIndex].goods[goodsIndex];
+
+    // 单价为0的商品数量最多只能是1
+    if (goods.price === 0) {
+      if (type === "plus") {
+        // 如果数量已经是1或更多,不能再加
+        if (goods.quantity >= 1) {
+          return;
+        }
+        // 如果数量为0,增加到1
+        goods.quantity = 1;
+        goods.checked = true;
+        this.setData({ goodsList });
+        this.calculateSummary();
+      } else if (type === "minus") {
+        // 点击减号,数量为1时弹出确认对话框
+        if (goods.quantity === 1) {
+          wx.showModal({
+            title: '提示',
+            content: '您想要删除该商品吗?',
+            success: (res) => {
+              if (res.confirm) {
+                // 用户确认删除
+                this.removeGoods(categoryIndex, goodsIndex);
+              }
+              // 用户取消,不做任何操作,保持数量为1
+            }
+          });
+        } else if (goods.quantity === 0) {
+          // 已经是0,不能再减
+          return;
+        } else {
+          // 其他情况(理论上不应该出现),确保数量不超过1
+          goods.quantity = Math.min(1, goods.quantity - 1);
+          this.setData({ goodsList });
+          this.calculateSummary();
+        }
+      }
+    } else {
+      // 非0价格商品的正常逻辑
+      if (type === "plus") {
+        const newQuantity = goods.quantity + 1;
+        goods.quantity = newQuantity;
+        if (!goods.checked) {
+          goods.checked = true;
+        }
+        this.setData({ goodsList });
+        this.calculateSummary();
+      } else if (type === "minus") {
+        // 点击减号
+        if (goods.quantity === 1) {
+          // 数量为1时,点击减号会变为0,弹出确认对话框
+          wx.showModal({
+            title: '提示',
+            content: '您想要删除该商品吗?',
+            success: (res) => {
+              if (res.confirm) {
+                // 用户确认删除
+                this.removeGoods(categoryIndex, goodsIndex);
+              }
+              // 用户取消,不做任何操作,保持数量为1
+            }
+          });
+        } else {
+          // 数量大于1,正常减少
+          const newQuantity = goods.quantity - 1;
+          goods.quantity = newQuantity;
+          this.setData({ goodsList });
+          this.calculateSummary();
+        }
+      }
+    }
+  },
+
+  // 删除商品
+  removeGoods(categoryIndex: number, goodsIndex: number) {
+    const goodsList = JSON.parse(JSON.stringify(this.data.goodsList)); // 深拷贝
+    const category = goodsList[categoryIndex];
+
+    // 从该分类中删除商品
+    category.goods.splice(goodsIndex, 1);
+
+    // 如果该分类没有商品了,删除该分类
+    if (category.goods.length === 0) {
+      goodsList.splice(categoryIndex, 1);
+    }
+
+    this.setData({ goodsList });
+    this.calculateSummary();
+  },
+
+  // 数量输入
+  onQuantityInput(e: any) {
+    const { categoryIndex, goodsIndex } = e.currentTarget.dataset;
+    const value = parseInt(e.detail.value) || 0;
+    const goodsList = this.data.goodsList;
+    const goods = goodsList[categoryIndex].goods[goodsIndex];
+
+    // 单价为0的商品数量最多只能是1
+    if (goods.price === 0) {
+      if (value > 1) {
+        goods.quantity = 1;
+      } else if (value < 0) {
+        goods.quantity = 0;
+        goods.checked = false;
+      } else {
+        goods.quantity = value;
+        // 如果数量为0,取消勾选
+        if (value === 0) {
+          goods.checked = false;
+        } else if (value > 0 && !goods.checked) {
+          goods.checked = true;
+        }
+      }
+    } else {
+      goods.quantity = Math.max(0, value);
+    }
+
+    this.setData({ goodsList });
+  },
+
+  // 数量输入失焦
+  onQuantityBlur(e: any) {
+    const { categoryIndex, goodsIndex } = e.currentTarget.dataset;
+    const goodsList = this.data.goodsList;
+    const goods = goodsList[categoryIndex].goods[goodsIndex];
+
+    // 单价为0的商品数量最多只能是1
+    if (goods.price === 0) {
+      if (goods.quantity > 1) {
+        goods.quantity = 1;
+      } else if (goods.quantity === 0) {
+        // 数量为0,取消勾选
+        goods.checked = false;
+      } else if (goods.quantity > 0 && goods.quantity <= 1) {
+        // 数量在0-1之间,如果已勾选但数量小于1,设置为1
+        if (goods.checked && goods.quantity < 1) {
+          goods.quantity = 1;
+        } else if (!goods.checked && goods.quantity > 0) {
+          // 如果数量大于0但未勾选,自动勾选
+          goods.checked = true;
+        }
+      }
+    } else {
+      // 非0价格商品的逻辑
+      if (goods.quantity === 0) {
+        goods.checked = false;
+      } else if (!goods.checked) {
+        // 如果数量大于0且未勾选,自动勾选
+        goods.checked = true;
+      }
+    }
+
+    this.setData({ goodsList });
+    this.calculateSummary();
+  },
+
+  // 计算汇总信息
+  calculateSummary() {
+    const goodsList = this.data.goodsList;
+    let selectedCount = 0;
+    let totalGoodsCount = 0; // 所有选中商品的总数量
+    let totalPrice = 0;
+    let allChecked = true;
+
+    goodsList.forEach((category: any) => {
+      category.goods.forEach((goods: any) => {
+        if (goods.checked && goods.quantity > 0) {
+          selectedCount++; // 已选件数 = 选中的商品种类数
+          totalGoodsCount += goods.quantity; // 累加所有选中商品的数量
+          totalPrice += goods.price * goods.quantity;
+        }
+        if (!goods.checked || goods.quantity === 0) {
+          allChecked = false;
+        }
+      });
+    });
+
+    this.setData({
+      selectedCount,
+      totalPrice: parseFloat(totalPrice.toFixed(2)),
+      selectAll: allChecked,
+      totalGoodsCount: totalGoodsCount
+    });
+
+  },
+
+  // 备注输入处理
+  onRemarkInput(e: any) {
+    const value = e.detail.value;
+    const length = value.length;
+
+    // 限制最大长度为200
+    if (length > 200) {
+      return;
+    }
+    this.setData({
+      remark: value,
+      remarkLength: length
+    });
+  },
+});

+ 98 - 0
miniprogram/module/order/pages/confirme-order/confirme-order.wxml

@@ -0,0 +1,98 @@
+<!--module/order/pages/confirme-order/confirme-order.wxml-->
+<t-navbar title="确认订单" left-arrow />
+<scroll-view class="page-scroll__container bottom" type="list" scroll-y style="{{containerStyle}}">
+  <view class="info-box {{ showDetail ? ' ' : 'show-bttom' }}">
+    <!-- 收货人信息卡片 -->
+    <view class="address-card address-card--disabled" bindtap="changeAddress">
+      <view class="delivery-address" wx:if="{{showDetail}}">
+        请选择配送地址
+      </view>
+      <view class="address-content" wx:else>
+        <!-- 左侧位置图标 -->
+        <view class="address-icon-wrapper">
+          <image class="address-icon" src="/assets/icon/icon_location@3x.png" mode="aspectFit" />
+        </view>
+        <!-- 中间地址信息 -->
+        <view class="address-info">
+          <view class="address-header">
+            <text class="address-name">{{name}}</text>
+            <text class="address-phone">{{phone}}</text>
+          </view>
+          <view class="address-detail">
+            {{address}}
+          </view>
+        </view>
+        <!-- 右侧操作图标 -->
+        <view class="address-actions">
+          <t-icon name="edit" class="edit-icon" />
+          <text class="arrow-icon">›</text>
+        </view>
+      </view>
+    </view>
+  </view>
+  <!-- 商品列表 -->
+  <view class="goods-list" wx:for="{{goodsList}}" wx:key="category">
+    <!-- 分类标题 -->
+    <view class="category-title">{{item.category}}</view>
+
+    <!-- 商品项 -->
+    <view class="goods-item" wx:for="{{item.goods}}" wx:for-item="goods" wx:for-index="goodsIndex" wx:key="id">
+      <!-- 复选框 -->
+      <view class="goods-checkbox">
+        <t-checkbox checked="{{goods.checked}}" bind:change="onGoodsCheckChange" data-category-index="{{index}}" data-goods-index="{{goodsIndex}}" style="padding:0" />
+      </view>
+
+      <!-- 商品图片 -->
+      <image class="goods-image" src="{{goods.image}}" mode="aspectFill" />
+
+      <!-- 商品信息 -->
+      <view class="goods-info">
+        <view class="goods-name-row">
+          <text class="goods-name">{{goods.name}}</text>
+        </view>
+        <view class="goods-desc" wx:if="{{goods.description}}">{{goods.description}}</view>
+        <view class="goods-price-row">
+          <text class="goods-price">¥{{goods.price}}</text>
+          <!-- 数量选择器 -->
+          <view class="quantity-selector">
+            <view class="quantity-btn minus {{goods.quantity <= 1 ? 'disabled' : ''}}" bind:tap="onQuantityChange" data-category-index="{{index}}" data-goods-index="{{goodsIndex}}" data-type="minus">-</view>
+            <input class="quantity-input" type="number" value="{{goods.quantity}}" bind:input="onQuantityInput" bind:blur="onQuantityBlur" data-category-index="{{index}}" data-goods-index="{{goodsIndex}}" />
+            <view class="quantity-btn plus {{goods.price === 0 && goods.quantity >= 1 ? 'disabled' : ''}}" bind:tap="onQuantityChange" data-category-index="{{index}}" data-goods-index="{{goodsIndex}}" data-type="plus">+</view>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+
+
+  <view class="order-info-section">
+    <!-- 备注 -->
+    <view class="info-card">
+      <view class="remark-item">
+        <text class="info-label">备注</text>
+        <view class="remark-input-wrapper">
+          <textarea class="remark-textarea" placeholder="请输入您需要备注的内容" value="{{remark}}" maxlength="200" bindinput="onRemarkInput" auto-height show-confirm-bar="{{false}}" />
+          <view class="remark-count">
+            <text class="remark-count-text">{{remarkLength}}/200</text>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+
+</scroll-view>
+
+<!-- 立即支付 -->
+<view class="footer-bar" style="padding-bottom:  {{container.safeBottomOffset}}px;">
+  <view class="footer-center">
+    <text class="footer-text" style="margin-right:10px">共{{totalGoodsCount}}件 </text>
+    <text class="footer-text">合计: </text>
+    <text class="footer-price">¥{{totalPrice}}</text>
+  </view>
+  <view class="footer-right">
+    <view class="checkout-btn {{isPaymentLoading ? 'checkout-btn--loading' : ''}}" bind:tap="onPayment">
+      <text wx:if="{{isPaymentLoading}}">支付中...</text>
+      <text wx:else>立即支付</text>
+    </view>
+  </view>
+</view>

+ 8 - 0
miniprogram/module/order/pages/order-detail/order-detail.json

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

+ 564 - 0
miniprogram/module/order/pages/order-detail/order-detail.scss

@@ -0,0 +1,564 @@
+@import "../../../../themes/t.cell.scss";
+@import "../../../../themes/page.scss";
+
+/* module/order/pages/order-detail/order-detail.wxss */
+.page-scroll__container {
+  flex: 0 1 auto;
+  height: var(--page-container-safeHeight, 100vh);
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+
+.bottom {
+  padding-bottom: 0;
+}
+.service-package-placeholder {
+  width: 160rpx;
+  height: 160rpx;
+  border-radius: 8rpx;
+  margin-right: 20rpx;
+  background-color: #f5f5f5;
+  border: 1px solid #e8e8e8;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+}
+.goods-list {
+  background: transparent;
+  margin-bottom: 20rpx;
+  padding: 0 20rpx;
+}
+
+.category-title {
+  padding: 28rpx 32rpx 0rpx;
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+  background: #fff;
+  position: sticky;
+  top: 0;
+  z-index: 10;
+  border-radius: 10rpx 10rpx 0 0;
+  margin-bottom: 0;
+}
+
+.goods-item {
+  display: flex;
+  align-items: center;
+  padding: 24rpx 32rpx;
+  background: #fff;
+  border-radius: 0;
+  transition: all 0.3s ease;
+
+  &:last-child {
+    border-radius: 0 0 10rpx 10rpx;
+    margin-bottom: 20rpx;
+    border-bottom: none;
+  }
+
+  &:not(:last-child) {
+    border-bottom: 1rpx solid #f0f0f0;
+  }
+
+  &:active {
+    background: #f7f8fa;
+  }
+}
+
+.goods-checkbox {
+  margin-right: 24rpx;
+  margin-top: 8rpx;
+  flex-shrink: 0;
+}
+
+.goods-image {
+  width: 160rpx;
+  height: 160rpx;
+  border-radius: 8rpx;
+  background: #f5f5f5;
+  margin-right: 24rpx;
+  flex-shrink: 0;
+  border: 1rpx solid #f0f0f0;
+}
+
+.goods-info {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  // min-width: 0;
+  margin-right: 24rpx;
+  height: 160rpx;
+}
+
+.goods-name {
+  font-size: 30rpx;
+  font-weight: 500;
+  color: #333;
+  line-height: 1.5;
+  margin-bottom: 30rpx;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+  line-clamp: 2;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.goods-desc {
+  font-size: 26rpx;
+  color: #666;
+  line-height: 1.4;
+}
+
+.goods-price-info {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  // justify-content: center;
+  flex-shrink: 0;
+  height: 160rpx;
+}
+
+.goods-price {
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+  letter-spacing: -0.5rpx;
+  margin-bottom: 40rpx;
+}
+
+.quantity-selector {
+  display: flex;
+  align-items: center;
+  border: 2rpx solid #e8e8e8;
+  border-radius: 12rpx;
+  overflow: hidden;
+  background: #fff;
+  box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.04);
+}
+
+.quantity-btn {
+  width: 64rpx;
+  height: 64rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: #f8f8f8;
+  font-size: 36rpx;
+  font-weight: 500;
+  color: #333;
+  user-select: none;
+  transition: all 0.2s ease;
+  position: relative;
+
+  &.minus {
+    border-right: 1rpx solid #e8e8e8;
+  }
+
+  &.plus {
+    border-left: 1rpx solid #e8e8e8;
+  }
+
+  &:active:not(.disabled) {
+    background: #1d6ff6;
+    color: #fff;
+    transform: scale(0.95);
+  }
+
+  &.disabled {
+    opacity: 0.4;
+    background: #f5f5f5;
+    color: #ccc;
+    cursor: not-allowed;
+  }
+}
+
+.quantity-input {
+  width: 90rpx;
+  height: 64rpx;
+  text-align: center;
+  font-size: 30rpx;
+  font-weight: 500;
+  color: #333;
+  background: #fff;
+  border: none;
+  padding: 0;
+
+  &[disabled] {
+    background: #f8f8f8;
+    color: #999;
+    opacity: 0.6;
+  }
+}
+
+.quantity-text {
+  font-size: 26rpx;
+  font-weight: 400;
+  color: #666;
+}
+
+.footer-placeholder {
+  height: 120rpx;
+}
+
+.footer-bar {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  width: 100%;
+  min-height: 100rpx;
+  background: #fff;
+  display: flex;
+  align-items: center;
+  padding: 20rpx 10rpx 0 0;
+  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
+  z-index: 100;
+  box-sizing: border-box;
+  border-top: 1rpx solid #f0f0f0;
+}
+
+.footer-left {
+  flex-shrink: 0;
+  margin-right: 32rpx;
+}
+
+.footer-center {
+  flex: 1;
+  display: flex;
+  align-items: baseline;
+  font-size: 28rpx;
+  color: #333;
+  line-height: 1.4;
+  padding-left: 20px;
+}
+
+.footer-text {
+  color: #666;
+  font-size: 26rpx;
+}
+
+.footer-price {
+  color: #ff4444;
+  font-weight: 700;
+  font-size: 36rpx;
+  margin-left: 8rpx;
+  letter-spacing: -0.5rpx;
+}
+
+.footer-right {
+  flex-shrink: 0;
+  padding-right: 10px;
+}
+
+.checkout-btn {
+  line-height: 76rpx;
+  text-align: center;
+  background: linear-gradient(135deg, #1d6ff6 0%, #4a90ff 100%);
+  color: #fff;
+  font-size: 30rpx;
+  font-weight: 600;
+  border-radius: 38rpx;
+  box-shadow: 0 4rpx 12rpx rgba(29, 111, 246, 0.3);
+  transition: all 0.3s ease;
+  padding: 0 20px;
+  user-select: none;
+  &:active:not(.checkout-btn--loading) {
+    opacity: 0.9;
+    transform: scale(0.98);
+    box-shadow: 0 2rpx 8rpx rgba(29, 111, 246, 0.4);
+  }
+
+  &.checkout-btn--loading {
+    opacity: 0.7;
+    pointer-events: none;
+    cursor: not-allowed;
+  }
+}
+.t-checkbox--block {
+  padding: 0 !important;
+}
+// 选择地址的css
+.info-box {
+  padding: 10rpx 20rpx 20rpx 20rpx;
+  background: #f7f8fa;
+}
+.show-bttom{
+  padding: 20rpx;
+}
+.delivery-address {
+  font-weight: 500;
+  font-size: 30rpx;
+  color: #333;
+  padding: 23rpx 20rpx;
+}
+
+.order-no {
+  font-size: 28rpx;
+  color: black;
+  margin: 24rpx 0 0 0;
+}
+
+.address-card {
+  background: #fff;
+  border-radius: 16rpx;
+  overflow: hidden;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
+
+  &.address-card--clickable {
+    cursor: pointer;
+    transition: all 0.3s ease;
+
+    &:active {
+      opacity: 0.8;
+      transform: scale(0.98);
+    }
+  }
+
+  &.address-card--disabled {
+    opacity: 0.9;
+    pointer-events: none;
+  }
+}
+
+.address-content {
+  display: flex;
+  align-items: flex-start;
+  padding: 25rpx 24rpx;
+  position: relative;
+}
+
+.address-icon-wrapper {
+  flex-shrink: 0;
+  width: 64rpx;
+  height: 64rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 10rpx;
+  border-radius: 50%;
+}
+
+.address-icon {
+  width: 36rpx;
+  height: 36rpx;
+}
+
+.address-info {
+  flex: 1;
+  min-width: 0;
+  display: flex;
+  flex-direction: column;
+  gap: 12rpx;
+}
+
+.address-header {
+  display: flex;
+  align-items: center;
+  gap: 24rpx;
+  flex-wrap: wrap;
+}
+
+.address-name {
+  font-weight: 500;
+  font-size: 30rpx;
+  color: #333;
+  line-height: 1.4;
+  margin-right: 20rpx;
+}
+
+.address-phone {
+  font-weight: 400;
+  font-size: 28rpx;
+  color: #333;
+  line-height: 1.4;
+}
+
+.address-detail {
+  color: #666;
+  font-size: 26rpx;
+  line-height: 1.6;
+  word-break: break-all;
+}
+
+.address-actions {
+  flex-shrink: 0;
+  display: flex;
+  align-items: center;
+  gap: 20rpx;
+  margin-left: 16rpx;
+}
+
+.edit-icon {
+  font-size: 32rpx;
+  color: #666;
+  opacity: 0.7;
+}
+
+.arrow-icon {
+  font-size: 40rpx;
+  color: #ccc;
+  margin-left: 10rpx;
+}
+
+.price-total-wrapper {
+  padding: 0 20rpx 24rpx;
+  margin-top: -24rpx;
+}
+
+.price-total {
+  display: flex;
+  justify-content: flex-end;
+  align-items: baseline;
+  background: #fff;
+  border-radius: 10rpx;
+  padding: 32rpx;
+
+  .price-value {
+    font-size: 40rpx;
+    color: black;
+    font-weight: 600;
+  }
+}
+
+// 价格汇总区域
+.price-summary-section {
+  padding: 0 20rpx 20rpx;
+  background: #f7f8fa;
+}
+
+.price-summary-card {
+  background: #fff;
+  border-radius: 10rpx;
+  padding: 32rpx;
+  display: flex;
+  gap: 24rpx;
+}
+
+.price-row {
+  justify-content: flex-end;
+  align-items: baseline;
+}
+
+.price-label {
+  font-size: 30rpx;
+  color: #333;
+  font-weight: 400;
+}
+
+.payable-value {
+  font-size: 40rpx;
+  color: #333;
+  font-weight: 700;
+}
+
+// 订单信息区域
+.order-info-section {
+  padding: 0 20rpx 20rpx;
+  background: #f7f8fa;
+}
+
+.info-card {
+  background: #fff;
+  border-radius: 0;
+  margin-bottom: 0;
+  padding: 0 32rpx;
+  overflow: hidden;
+  margin-top: 20rpx;
+  border-radius: 10rpx;
+
+  &:first-child {
+    margin-top: 0;
+  }
+}
+
+.info-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 32rpx 0;
+  min-height: 88rpx;
+  box-sizing: border-box;
+}
+
+.info-label {
+  font-size: 28rpx;
+  color: #333;
+  font-weight: 400;
+  flex-shrink: 0;
+}
+
+.info-value {
+  font-size: 28rpx;
+  color: #333;
+  text-align: right;
+  flex: 1;
+  word-break: break-all;
+  margin-left: 24rpx;
+}
+
+.info-value-row {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  flex: 1;
+  gap: 16rpx;
+  margin-left: 24rpx;
+}
+
+.copy-btn {
+  font-size: 28rpx;
+  color: #1d6ff6;
+  flex-shrink: 0;
+  margin-left: 10px;
+}
+
+.info-divider {
+  height: 1rpx;
+  background: #f0f0f0;
+  margin: 0;
+  width: 100%;
+}
+
+// 备注相关样式
+.remark-item {
+  padding: 32rpx 0;
+  display: flex;
+  flex-direction: column;
+}
+
+.remark-input-wrapper {
+  margin-top: 20rpx;
+  position: relative;
+  width: 100%;
+}
+
+.remark-textarea {
+  width: 100%;
+  min-height: 120rpx;
+  padding: 20rpx;
+  font-size: 28rpx;
+  color: #333;
+  background: #f7f8fa;
+  border-radius: 8rpx;
+  box-sizing: border-box;
+  line-height: 1.6;
+  border: 1rpx solid #e8e8e8;
+
+  &:focus {
+    border-color: #1d6ff6;
+    background: #fff;
+  }
+}
+
+.remark-count {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 12rpx;
+}
+
+.remark-count-text {
+  font-size: 24rpx;
+  color: #999;
+}

+ 253 - 0
miniprogram/module/order/pages/order-detail/order-detail.ts

@@ -0,0 +1,253 @@
+import DictionariesBehavior from "../../../../core/behavior/dictionaries.behavior";
+import PageContainerBehavior from "../../../../core/behavior/page-container.behavior";
+import { handleWeChatPayment } from "../../../../utils/util";
+import tickleBehavior, {
+  getTickleContext,
+} from "../../../../core/behavior/tickle.behavior";
+import { getOrderDetailMethod, orderPayMethod } from "../../request";
+// module/order/pages/select-goods/select-goods.ts
+Page({
+  behaviors: [PageContainerBehavior, DictionariesBehavior, tickleBehavior],
+  properties: {
+    schemeId: { type: String, value: "" },
+  },
+  data: {
+    title: "",
+    id: "",
+    totalGoodsCount: 0,
+    goodsList: [] as Array<{
+      category: string;
+      goods: Array<{
+        id: string;
+        name: string;
+        description?: string;
+        image: string;
+        price: number;
+      }>;
+    }>,
+    selectAll: true,
+    selectedCount: 0,
+    totalPrice: 0,
+    orderDetail: {},
+    remarkLength: 0,
+    showDetail: false,
+    isPaymentLoading: false, // 支付加载状态
+    orderStatus: "", // 订单状态:pending, paid, closed, completed
+  },
+  onLoad(options: any) {
+    const remark = (this.data.orderDetail as any)?.remark || '';
+    this.setData({
+      remarkLength: remark.length
+    });
+    if (options.id) {
+      this.setData({ id: options.id });
+    }
+    if (options.status) {
+      this.statusType(options.status);
+    }
+
+  },
+  onShow() {
+    if (this.data.id) {
+      this.load(this.data.id);
+    }
+  },
+  observers: {},
+  // 切换收货地址
+  changeAddress(_event: any) {
+    // 只有待付款状态才能切换地址
+    if (this.data.orderStatus !== "pending") {
+      return;
+    }
+    wx.navigateTo({
+      url:
+        "/module/article/pages/manage-address/manage-address?type=orderDetail&orderId=" +
+        this.data.id,
+    });
+  },
+  statusType(status: any) {
+    const code = status == null ? "" : String(status);
+    switch (code) {
+      case "0":
+        this.setData({ orderStatus: "pending", title: "待付款" });
+        break;
+      case "6":
+        this.setData({ orderStatus: "received", title: "已付款" });
+        break;
+      case "2":
+        this.setData({ orderStatus: "closed", title: "交易关闭" });
+        break;
+      case "345":
+        this.setData({ orderStatus: "completed", title: "交易成功" });
+        break;
+      default:
+        this.setData({ orderStatus: "", title: "" });
+        break;
+    }
+  },
+  // 订单详情
+  async load(id: string) {
+    wx.showLoading({ title: "加载中" });
+    try {
+      const res = await getOrderDetailMethod(id);
+      if (res && res.data) {
+        this.setData({ orderDetail: res.data });
+        if (
+          !res.data.liaison ||
+          !res.data.phone ||
+          !res.data.provinceName ||
+          !res.data.cityName ||
+          !res.data.areaName ||
+          !res.data.detailAddress
+        ) {
+          this.setData({
+            showDetail: true,
+          });
+        } else {
+          this.setData({
+            showDetail: false,
+          });
+          this.setData({
+            name: res.data.liaison ? `${res.data.liaison}` : "",
+            phone: res.data.phone ? `${res.data.phone}` : "",
+            address: `${res.data.provinceName}${res.data.cityName ? `${res.data.cityName}` : ""
+              }${res.data.areaName ? `${res.data.areaName}` : ""}${res.data.detailAddress ? `${res.data.detailAddress}` : ""
+              }`,
+          });
+        }
+        // 0:待付款
+        // 2 交易关闭
+        // 6 已付款
+        // 345  交易成功
+        this.statusType(res.data.orderStatus);
+        const groupForPendingPay = res.data?.groupForPendingPay || {};
+        const goodsList: any[] = [];
+        let totalGoodsCount = 0;
+
+        // 遍历 groupForPendingPay
+        Object.keys(groupForPendingPay).forEach((categoryName: string) => {
+          const categoryItems = groupForPendingPay[categoryName] || [];
+          if (categoryItems.length > 0) {
+            const goods = categoryItems.map((item: any) => {
+              const pricingType = item?.conditioningProgramDetail?.pricingType; //0是一口价 1按穴位/经络次数计费
+              // 合计的商品件数
+              totalGoodsCount += 1;
+              return {
+                id: item.id || '',
+                name: item.conditioningProgramName || '',
+                description: (() => {
+                  const dose = item?.convertDose ?? '';
+                  const unit = item?.convertUnit ?? '';
+                  return pricingType === '0' ? `${dose} ${unit}` : `1次`;
+                })(),
+
+                image: item.conditioningProgramPhoto || '',
+                // price: item.totalPrice || 0,
+                price: item?.unitPrice || 0,
+                quantity: item?.totalMeasure || 0,
+              };
+            });
+
+            goodsList.push({
+              category: categoryName,
+              goods: goods
+            });
+          }
+        });
+        this.setData({ goodsList, totalGoodsCount });
+      }
+    } catch (error: any) {
+      wx.showToast({
+        title: error.errMsg,
+        icon: "none",
+      });
+    }
+    wx.hideLoading();
+  },
+
+  // 立即支付
+  async onPayment() {
+    if (this.data.isPaymentLoading) {
+      return;
+    }
+    this.setData({ isPaymentLoading: true });
+    try {
+      // 调用支付接口
+      const payResult = await orderPayMethod(this.data.id, (this.data.orderDetail as any)?.remark || '');
+      if (payResult) {
+        const paymentParams = payResult;
+        handleWeChatPayment(paymentParams, (res: any) => {
+          // 支付成功,跳转到成功页面
+          wx.redirectTo({
+            url: "/module/article/pages/success-page/success-page?title=订单支付成功",
+          });
+        }, (error: any) => {
+          this.setData({ isPaymentLoading: false });
+          if (error?.errMsg === 'requestPayment:fail cancel') {
+          // 支付取消跳到支付订单页面
+            wx.navigateBack({ delta: 1 });
+          }
+          console.log(error, '支付失败');
+          // wx.showToast({
+          //   title: error?.errMsg || error?.message || "支付失败,请重试",
+          //   icon: "none",
+          // });
+        });
+      } else {
+        wx.showToast({
+          title: payResult.errMsg,
+          icon: "none",
+        });
+      }
+    } catch (error: any) {
+      wx.showToast({
+        title: error.errMsg,
+        icon: "none",
+      });
+    } finally {
+      this.setData({ isPaymentLoading: false });
+    }
+  },
+
+  // 备注输入处理
+  onRemarkInput(e: any) {
+    const value = e.detail.value;
+    const length = value.length;
+
+    // 限制最大长度为200
+    if (length > 200) {
+      return;
+    }
+
+    this.setData({
+      'orderDetail.remark': value,
+      remarkLength: length
+    });
+  },
+
+  // 复制订单号
+  copyOrderNo(e: any) {
+    const orderNo = e.currentTarget.dataset.orderno;
+    if (!orderNo) {
+      getTickleContext.call(this).showWarnMessage("订单号为空");
+      return;
+    }
+    wx.setClipboardData({
+      data: orderNo,
+      success: () => {
+        wx.showToast({
+          title: '已复制',
+          icon: 'none'
+        });
+      }
+    });
+  },
+
+  // 返回上一页
+  onGoBack() {
+    wx.navigateBack({
+      delta: 1
+    });
+  },
+
+});

+ 142 - 0
miniprogram/module/order/pages/order-detail/order-detail.wxml

@@ -0,0 +1,142 @@
+<!--module/order/pages/select-goods/select-goods.wxml-->
+<t-navbar title="{{title}}" left-arrow />
+<scroll-view class="page-scroll__container {{orderStatus==='pending'?'':'bottom'}}" type="list" scroll-y style="{{containerStyle}}">
+  <view class="info-box {{ showDetail ? 'show-bttom' : '' }}">
+    <!-- 收货人信息卡片 -->
+    <view class="address-card {{orderStatus==='pending' ? 'address-card--clickable' : 'address-card--disabled'}}" bindtap="{{orderStatus==='pending' ? 'changeAddress' : ''}}" wx:if="{{orderDetail.isDelivery==='Y'}}" data-status="{{orderDetail.orderStatus}}">
+      <view class="delivery-address" wx:if="{{showDetail}}">
+        请选择配送地址
+      </view>
+      <view class="address-content" wx:else>
+        <!-- 左侧位置图标 -->
+        <view class="address-icon-wrapper">
+          <image class="address-icon" src="/assets/icon/icon_location@3x.png" mode="aspectFit" />
+        </view>
+        <!-- 中间地址信息 -->
+        <view class="address-info">
+          <view class="address-header">
+            <text class="address-name">{{name}}</text>
+            <text class="address-phone">{{phone}}</text>
+          </view>
+          <view class="address-detail">
+            {{address}}
+          </view>
+        </view>
+        <!-- 右侧操作图标 -->
+        <view class="address-actions" wx:if="{{orderStatus==='pending'}}">
+          <t-icon name="edit" class="edit-icon" />
+          <text class="arrow-icon">›</text>
+        </view>
+      </view>
+    </view>
+  </view>
+  <!-- 商品列表 -->
+  <view class="goods-list" wx:for="{{goodsList}}" wx:key="category">
+    <!-- 分类标题 -->
+    <view class="category-title">{{item.category}}</view>
+
+    <!-- 商品项 -->
+    <view class="goods-item" wx:for="{{item.goods}}" wx:for-item="goods" wx:for-index="goodsIndex" wx:key="id">
+      <!-- 商品图片 -->
+      <image class="goods-image" src="{{goods.image}}" mode="aspectFill" wx:if="{{goods.image}}" />
+      <view class="service-package-placeholder" wx:else>
+        <text class="placeholder-icon">📦</text>
+      </view>
+      <!-- 商品信息 -->
+      <view class="goods-info">
+        <text class="goods-name">{{goods.name}}</text>
+        <text class="goods-desc" wx:if="{{goods.description}}">{{goods.description}}</text>
+      </view>
+
+      <!-- 价格和数量(右侧) -->
+      <view class="goods-price-info">
+        <text class="goods-price">¥{{goods.price}}</text>
+        <view class="quantity-text">x{{goods.quantity}}</view>
+      </view>
+    </view>
+  </view>
+  <!-- 商品总价 -->
+  <view class="price-total-wrapper">
+    <view class="price-total">
+      <text class="price-label">商品总价:</text>
+      <text class="price-value">¥{{orderDetail.cost}}</text>
+    </view>
+  </view>
+  <!-- 实际付款 -->
+  <view class="price-summary-section">
+    <view class="price-summary-card price-row">
+      <text class="price-label">应付款:</text>
+      <text class="price-value payable-value">¥{{orderDetail.cost}}</text>
+    </view>
+  </view>
+
+  <view class="order-info-section">
+    <!-- 备注 -->
+    <view class="info-card">
+      <view class="remark-item">
+        <text class="info-label">备注</text>
+        <view class="remark-input-wrapper">
+          <textarea class="remark-textarea" placeholder="请输入备注信息" value="{{orderDetail.remark}}" maxlength="200" bindinput="onRemarkInput" auto-height show-confirm-bar="{{false}}" disabled="{{orderStatus!=='pending'}}" />
+          <view class="remark-count">
+            <text class="remark-count-text">{{remarkLength}}/200</text>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- 订单详情 -->
+    <view class="info-card">
+      <view class="info-item" wx:if="{{orderDetail.orderNo}}">
+        <text class="info-label" style="font-weight:600">订单编号</text>
+        <view class="info-value-row">
+          <text class="info-value" style="color:#9b9797">{{orderDetail.orderNo || ''}}</text>
+          <text class="copy-btn" bindtap="copyOrderNo" data-orderno="{{orderDetail.orderNo}}">复制</text>
+        </view>
+      </view>
+      <view class="info-divider"></view>
+      <view class="info-item">
+        <text class="info-label">创建时间</text>
+        <text class="info-value" style="color:#9b9797">{{orderDetail.operateTime || ''}}</text>
+      </view>
+    </view>
+
+    <!-- 服务包详情 -->
+    <view class="info-card">
+      <view class="info-item" wx:if="{{orderDetail.conditioningWrapName}}">
+        <text class="info-label" style="font-weight:600">服务包</text>
+        <text class="info-value">{{orderDetail.conditioningWrapName || ''}}</text>
+      </view>
+      <view class="info-divider"></view>
+      <view class="info-item" wx:if="{{orderDetail.operateBy}}">
+        <text class="info-label">开具医生</text>
+        <text class="info-value">{{orderDetail.operateBy || ''}}</text>
+      </view>
+      <view class="info-divider"></view>
+      <view class="info-item" wx:if="{{orderDetail.operateTime}}">
+        <text class="info-label">开具时间</text>
+        <text class="info-value">{{orderDetail.operateTime || ''}}</text>
+      </view>
+      <view class="info-divider"></view>
+      <view class="info-item" wx:if="{{orderDetail.estimatedStartDate}}">
+        <text class="info-label">开始调养日期</text>
+        <text class="info-value">{{orderDetail.estimatedStartDate || ''}}</text>
+      </view>
+    </view>
+  </view>
+
+</scroll-view>
+
+<!-- 立即支付 -->
+<view class="footer-bar" style="padding-bottom: {{orderStatus==='pending' ? container.safeBottomOffset : 0}}px;" wx:if="{{orderStatus==='pending'}}">
+  <view class="footer-center">
+    <text class="footer-text" style="margin-right:10px">共{{totalGoodsCount}}件 </text>
+    <text class="footer-text">合计: </text>
+    <text class="footer-price">¥{{orderDetail.cost}}</text>
+  </view>
+  <view class="footer-right">
+    <view class="checkout-btn {{isPaymentLoading ? 'checkout-btn--loading' : ''}}" bind:tap="onPayment">
+      <text wx:if="{{isPaymentLoading}}">支付中...</text>
+      <text wx:else>立即支付</text>
+    </view>
+  </view>
+</view>

+ 8 - 0
miniprogram/module/order/pages/other-detail/other-detail.json

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

+ 675 - 0
miniprogram/module/order/pages/other-detail/other-detail.scss

@@ -0,0 +1,675 @@
+@import "../../../../themes/t.cell.scss";
+@import "../../../../themes/page.scss";
+@import "../../assets/iconfont/iconfont.wxss";
+
+/* module/order/pages/order-detail/order-detail.wxss */
+.page-scroll__container {
+  flex: 0 1 auto;
+  height: var(--page-container-safeHeight, 100vh);
+  background: #f7f8fa;
+}
+
+.service-package-placeholder {
+  width: 160rpx;
+  height: 160rpx;
+  border-radius: 8rpx;
+  margin-right: 20rpx;
+  background-color: #f5f5f5;
+  border: 1px solid #e8e8e8;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+}
+
+.price-total-wrapper {
+  padding: 0 20rpx 24rpx;
+  margin-top: -24rpx;
+}
+
+.price-total {
+  display: flex;
+  justify-content: flex-end;
+  align-items: baseline;
+  background: #fff;
+  // border: 2rpx solid #ff4444;
+  border-radius: 10rpx;
+  padding: 32rpx;
+  // box-shadow: 0 2rpx 8rpx rgba(255, 68, 68, 0.1);
+
+  .price-value {
+    font-size: 40rpx;
+    color: black;
+    font-weight: 600;
+  }
+}
+
+.goods-list {
+  background: transparent;
+  margin-bottom: 24rpx;
+  padding: 0 20rpx;
+}
+
+.category-title {
+  padding: 24rpx 32rpx;
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+  background: #fff;
+  position: sticky;
+  top: 0;
+  z-index: 10;
+  border-radius: 16rpx 16rpx 0 0;
+  margin-bottom: 0;
+  text-align: center;
+}
+.offline-title {
+  padding-left: 32rpx;
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+  background: #fff;
+  position: sticky;
+  top: 0;
+  z-index: 10;
+  text-align: left;
+}
+.goods-item-wrapper {
+  background: #fff;
+
+  &:last-child .goods-item {
+    border-radius: 0 0 16rpx 16rpx;
+    border-bottom: none;
+  }
+}
+
+.goods-item {
+  display: flex;
+  align-items: flex-start;
+  padding: 10rpx 32rpx;
+  background: #fff;
+  border-radius: 0 0 16rpx 16rpx;
+  transition: all 0.3s ease;
+
+  &:not(:last-child) {
+    border-bottom: 1rpx solid #f0f0f0;
+  }
+
+  &:active {
+    background: #f7f8fa;
+  }
+}
+
+.goods-checkbox {
+  margin-right: 24rpx;
+  margin-top: 8rpx;
+  flex-shrink: 0;
+}
+
+.goods-image {
+  width: 160rpx;
+  height: 160rpx;
+  border-radius: 12rpx;
+  background: #f5f5f5;
+  margin-right: 24rpx;
+  flex-shrink: 0;
+  border: 1rpx solid #f0f0f0;
+  overflow: hidden;
+}
+
+.goods-info {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  min-width: 0;
+  // justify-content: space-between;
+  min-height: 160rpx;
+}
+
+.goods-name-row {
+  display: flex;
+  align-items: flex-start;
+  justify-content: space-between;
+  margin-bottom: 30rpx;
+  gap: 12rpx;
+}
+
+.goods-desc-row {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.goods-name {
+  font-size: 30rpx;
+  font-weight: 500;
+  color: #333;
+  flex: 1;
+  min-width: 0;
+  line-height: 1.5;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+  line-clamp: 2;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.goods-badge {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  min-width: 36rpx;
+  height: 36rpx;
+  padding: 0 10rpx;
+  background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
+  color: #333;
+  font-size: 22rpx;
+  font-weight: 600;
+  border-radius: 18rpx;
+  margin-left: 12rpx;
+  box-shadow: 0 2rpx 4rpx rgba(255, 215, 0, 0.3);
+}
+
+.goods-desc {
+  font-size: 26rpx;
+  color: #666;
+  margin-bottom: 12rpx;
+  line-height: 1.4;
+}
+
+.goods-price-row {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-top: auto;
+  margin-bottom: 12rpx;
+}
+
+.goods-price {
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+  letter-spacing: -0.5rpx;
+}
+
+.goods-status {
+  font-size: 30rpx;
+  font-weight: 400;
+  color: #ff9500;
+  flex-shrink: 0;
+  white-space: nowrap;
+  background: white;
+  padding: 0 30rpx 0 0;
+  text-align: end;
+}
+
+// 快递信息
+.express-info {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 10rpx 20rpx 0 20rpx;
+  background: white;
+
+  .express-text {
+    font-size: 28rpx;
+    color: #333;
+    // flex: 1;
+    padding: 8rpx 20rpx;
+    border-radius: 10rpx;
+    border: 1px solid lightgray;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .express-arrow {
+    font-size: 32rpx;
+    color: black;
+    margin-left: 12rpx;
+    font-weight: 300;
+  }
+}
+
+// 快递图标样式
+.express-icon {
+  width: 40rpx;
+  height: 40rpx;
+  margin-right: 10rpx;
+  flex-shrink: 0;
+}
+
+// 确认收货按钮
+.confirm-receipt-btn {
+  margin-top: 16rpx;
+  padding: 12rpx 24rpx;
+  // background: #1d6ff6;
+  border: 1px solid #1d6ff6;
+  color: #1d6ff6;
+  // color: #fff;
+  font-size: 26rpx;
+  text-align: center;
+  border-radius: 8rpx;
+  align-self: flex-end;
+
+  &:active {
+    background: #1556c4;
+    opacity: 0.8;
+  }
+}
+
+.quantity-selector {
+  display: flex;
+  align-items: center;
+  border: 2rpx solid #e8e8e8;
+  border-radius: 12rpx;
+  overflow: hidden;
+  background: #fff;
+  box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.04);
+}
+
+.quantity-btn {
+  width: 64rpx;
+  height: 64rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: #f8f8f8;
+  font-size: 36rpx;
+  font-weight: 500;
+  color: #333;
+  user-select: none;
+  transition: all 0.2s ease;
+  position: relative;
+
+  &.minus {
+    border-right: 1rpx solid #e8e8e8;
+  }
+
+  &.plus {
+    border-left: 1rpx solid #e8e8e8;
+  }
+
+  &:active:not(.disabled) {
+    background: #1d6ff6;
+    color: #fff;
+    transform: scale(0.95);
+  }
+
+  &.disabled {
+    opacity: 0.4;
+    background: #f5f5f5;
+    color: #ccc;
+    cursor: not-allowed;
+  }
+}
+
+.quantity-input {
+  width: 90rpx;
+  height: 64rpx;
+  text-align: center;
+  font-size: 30rpx;
+  font-weight: 500;
+  color: #333;
+  background: #fff;
+  border: none;
+  padding: 0;
+
+  &[disabled] {
+    background: #f8f8f8;
+    color: #999;
+    opacity: 0.6;
+  }
+}
+
+.quantity-text {
+  font-size: 28rpx;
+  font-weight: 400;
+  color: #666;
+  padding: 0;
+}
+
+.footer-placeholder {
+  height: 120rpx;
+}
+
+.footer-bar {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  width: 100%;
+  min-height: 100rpx;
+  background: #fff;
+  display: flex;
+  align-items: center;
+  padding: 20rpx 10rpx 0 0;
+  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
+  z-index: 100;
+  box-sizing: border-box;
+  border-top: 1rpx solid #f0f0f0;
+}
+
+.footer-left {
+  flex-shrink: 0;
+  margin-right: 32rpx;
+}
+
+.footer-center {
+  flex: 1;
+  display: flex;
+  align-items: baseline;
+  font-size: 28rpx;
+  color: #333;
+  line-height: 1.4;
+  padding-left: 20px;
+}
+
+.footer-text {
+  color: #666;
+  font-size: 26rpx;
+}
+
+.footer-price {
+  color: #ff4444;
+  font-weight: 700;
+  font-size: 36rpx;
+  margin-left: 8rpx;
+  letter-spacing: -0.5rpx;
+}
+
+.footer-right {
+  flex-shrink: 0;
+  padding-right: 10px;
+}
+
+.checkout-btn {
+  line-height: 76rpx;
+  text-align: center;
+  background: linear-gradient(135deg, #1d6ff6 0%, #4a90ff 100%);
+  color: #fff;
+  font-size: 30rpx;
+  font-weight: 600;
+  border-radius: 38rpx;
+  box-shadow: 0 4rpx 12rpx rgba(29, 111, 246, 0.3);
+  transition: all 0.3s ease;
+  padding: 0 20px;
+  user-select: none;
+
+  &:active:not(.checkout-btn--loading) {
+    opacity: 0.9;
+    transform: scale(0.98);
+    box-shadow: 0 2rpx 8rpx rgba(29, 111, 246, 0.4);
+  }
+
+  &.checkout-btn--loading {
+    opacity: 0.7;
+    pointer-events: none;
+    cursor: not-allowed;
+  }
+}
+
+.t-checkbox--block {
+  padding: 0 !important;
+}
+
+.info-box {
+  padding: 10rpx;
+}
+
+.delivery-address {
+  font-weight: 500;
+  font-size: 30rpx;
+  color: #333;
+  padding: 30rpx 20rpx;
+}
+
+.order-no {
+  font-size: 28rpx;
+  color: black;
+  margin: 24rpx 0 0 0;
+}
+
+.address-card {
+  background: #fff;
+  border-radius: 16rpx;
+  overflow: hidden;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
+
+  &.address-card--clickable {
+    cursor: pointer;
+    transition: all 0.3s ease;
+
+    &:active {
+      opacity: 0.8;
+      transform: scale(0.98);
+    }
+  }
+
+  &.address-card--disabled {
+    opacity: 0.9;
+    pointer-events: none;
+  }
+}
+
+.address-content {
+  display: flex;
+  align-items: flex-start;
+  padding: 32rpx 24rpx;
+  position: relative;
+}
+
+.address-icon-wrapper {
+  flex-shrink: 0;
+  width: 64rpx;
+  height: 64rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 10rpx;
+  border-radius: 50%;
+}
+
+.address-icon {
+  width: 36rpx;
+  height: 36rpx;
+}
+
+.address-info {
+  flex: 1;
+  min-width: 0;
+  display: flex;
+  flex-direction: column;
+  gap: 12rpx;
+}
+
+.address-header {
+  display: flex;
+  align-items: center;
+  gap: 24rpx;
+  flex-wrap: wrap;
+}
+
+.address-name {
+  font-weight: 500;
+  font-size: 30rpx;
+  color: #333;
+  line-height: 1.4;
+  margin-right: 20rpx;
+}
+
+.address-phone {
+  font-weight: 400;
+  font-size: 28rpx;
+  color: #333;
+  line-height: 1.4;
+}
+
+.address-detail {
+  color: #666;
+  font-size: 26rpx;
+  line-height: 1.6;
+  word-break: break-all;
+}
+
+.address-actions {
+  flex-shrink: 0;
+  display: flex;
+  align-items: center;
+  gap: 20rpx;
+  margin-left: 16rpx;
+}
+
+.edit-icon {
+  font-size: 32rpx;
+  color: #666;
+  opacity: 0.7;
+}
+
+.arrow-icon {
+  font-size: 40rpx;
+  color: #ccc;
+  margin-left: 10rpx;
+}
+
+// 价格汇总区域
+.price-summary-section {
+  padding: 0 20rpx 20rpx;
+  background: #f7f8fa;
+}
+
+.price-summary-card {
+  background: #fff;
+  border-radius: 10rpx;
+  padding: 32rpx;
+  display: flex;
+  gap: 24rpx;
+}
+
+.price-row {
+  justify-content: flex-end;
+  align-items: baseline;
+}
+
+.price-label {
+  font-size: 30rpx;
+  color: #333;
+  font-weight: 400;
+}
+
+.payable-value {
+  font-size: 40rpx;
+  color: #333;
+  font-weight: 700;
+}
+
+// 订单信息区域
+.order-info-section {
+  padding: 0 20rpx 20rpx;
+  background: #f7f8fa;
+}
+
+.info-card {
+  background: #fff;
+  border-radius: 0;
+  margin-bottom: 0;
+  padding: 0 32rpx;
+  overflow: hidden;
+  margin-top: 20rpx;
+  border-radius: 10rpx;
+
+  &:first-child {
+    margin-top: 0;
+  }
+}
+
+.info-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 32rpx 0;
+  min-height: 88rpx;
+  box-sizing: border-box;
+}
+
+.info-label {
+  font-size: 28rpx;
+  color: #333;
+  font-weight: 400;
+  flex-shrink: 0;
+}
+
+.info-value {
+  font-size: 28rpx;
+  color: #333;
+  text-align: right;
+  flex: 1;
+  word-break: break-all;
+  margin-left: 24rpx;
+}
+
+.info-value-row {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  flex: 1;
+  gap: 16rpx;
+  margin-left: 24rpx;
+}
+
+.copy-btn {
+  font-size: 28rpx;
+  color: #1d6ff6;
+  flex-shrink: 0;
+  margin-left: 10px;
+}
+
+.info-divider {
+  height: 1rpx;
+  background: #f0f0f0;
+  margin: 0;
+  width: 100%;
+}
+
+// 备注相关样式
+.remark-item {
+  padding: 32rpx 0;
+  display: flex;
+  flex-direction: column;
+}
+
+.remark-input-wrapper {
+  margin-top: 20rpx;
+  position: relative;
+  width: 100%;
+}
+
+.remark-textarea {
+  width: 100%;
+  min-height: 120rpx;
+  padding: 20rpx;
+  font-size: 28rpx;
+  color: #333;
+  background: #f7f8fa;
+  border-radius: 8rpx;
+  box-sizing: border-box;
+  line-height: 1.6;
+  border: 1rpx solid #e8e8e8;
+
+  &:focus {
+    border-color: #1d6ff6;
+    background: #fff;
+  }
+}
+
+.remark-count {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 12rpx;
+}
+
+.remark-count-text {
+  font-size: 24rpx;
+  color: #999;
+}

+ 405 - 0
miniprogram/module/order/pages/other-detail/other-detail.ts

@@ -0,0 +1,405 @@
+import DictionariesBehavior from "../../../../core/behavior/dictionaries.behavior";
+import PageContainerBehavior from "../../../../core/behavior/page-container.behavior";
+import { handleWeChatPayment } from "../../../../utils/util";
+import {
+  getTickleContext,
+} from "../../../../core/behavior/tickle.behavior";
+import { getOrderDetailMethod, orderPayMethod } from "../../request";
+// module/order/pages/select-goods/other-detail.ts
+Page({
+  behaviors: [PageContainerBehavior, DictionariesBehavior],
+  data: {
+    title: "",
+    id: "",
+    totalGoodsCount: 0,
+    goodsList: [] as Array<{
+      category: string;
+      goods: Array<{
+        id: string;
+        name: string;
+        description?: string;
+        image: string;
+        price: number;
+        quantity: number;
+        status?: string;
+        statusClass?: string;
+      }>;
+    }>,
+    // 三个分类的商品列表
+    sellTypeFirstItems: [] as Array<any>, // 实体商品(快递类型在上,线下取货类型在下)
+    sellTypeSecondItems: [] as Array<any>, // 线下服务
+    sellTypeThirdItems: [] as Array<any>, // 线上权益
+    selectAll: true,
+    selectedCount: 0,
+    totalPrice: 0,
+    orderDetail: {},
+    remarkLength: 0,
+    showDetail: false,
+    isPaymentLoading: false,
+    orderStatus: "", // 订单状态:pending, paid, closed, completed
+  },
+  onLoad(options: any) {
+    const remark = (this.data.orderDetail as any)?.remark || '';
+    this.setData({
+      remarkLength: remark.length
+    });
+    if (options.id) {
+      this.setData({ id: options.id });
+    }
+    if (options.status) {
+      this.statusType(options.status);
+    }
+
+  },
+  onShow() {
+    if (this.data.id) {
+      this.load(this.data.id);
+    }
+  },
+  observers: {},
+  statusType(status: any) {
+    const code = status == null ? "" : String(status);
+    switch (code) {
+      case "0":
+        this.setData({ orderStatus: "pending", title: "待付款" });
+        break;
+      case "6":
+        this.setData({ orderStatus: "received", title: "已付款" });
+        break;
+      case "2":
+        this.setData({ orderStatus: "closed", title: "交易关闭" });
+        break;
+      case "345":
+        this.setData({ orderStatus: "completed", title: "交易成功" });
+        break;
+      default:
+        this.setData({ orderStatus: "", title: "" });
+        break;
+    }
+  },
+  // 订单详情
+  async load(id: string) {
+    wx.showLoading({ title: "加载中" });
+    try {
+      const res = await getOrderDetailMethod(id);
+      if (res && res.data) {
+
+        this.setData({ orderDetail: res.data });
+        if (
+          !res.data.liaison ||
+          !res.data.phone ||
+          !res.data.provinceName ||
+          !res.data.cityName ||
+          !res.data.areaName ||
+          !res.data.detailAddress
+        ) {
+          this.setData({
+            showDetail: true,
+          });
+        } else {
+          this.setData({
+            showDetail: false,
+          });
+          this.setData({
+            name: res.data.liaison ? `${res.data.liaison}` : "",
+            phone: res.data.phone ? `${res.data.phone}` : "",
+            address: `${res.data.provinceName}${res.data.cityName ? `${res.data.cityName}` : ""
+              }${res.data.areaName ? `${res.data.areaName}` : ""}${res.data.detailAddress ? `${res.data.detailAddress}` : ""
+              }`,
+          });
+        }
+        // 0:待付款
+        // 2 交易关闭
+        // 6 待收货
+        // 345  交易成功
+        this.statusType(res.data.orderStatus);
+
+        // 处理三个分类的商品数据
+        const processItems = (items: any[]) => {
+          if (!items || !Array.isArray(items)) {
+            return [];
+          }
+          return items.map((item: any) => {
+            // 0是一口价 1按穴位/经络次数计费
+            const pricingType = item?.conditioningProgramDetail?.pricingType;
+            return {
+              id: item.id || '',
+              patientConditioningRecordId: item?.patientConditioningRecordId || '',//调理记录id
+              name: item.conditioningProgramName || '',
+              description: (() => {
+                const convertDose = item?.conditioningProgramDetail?.cpFixedPricingRule?.convertDose
+                const dose = convertDose ?? '';
+                const unit = item?.conditioningProgramDetail?.cpFixedPricingRule?.convertUnit ?? '次';
+                return pricingType === '0' ? `${dose} ${unit}` : `1次`;
+              })(),
+              sellType: item?.sellType || '', //商品类型 1-实体商品 2-线下服务 3-线上权益
+              //start实体商品所用到的字段
+              receiptStatus: item?.receiptStatus || '', //收货状态 0-待发货 1-已发货 2-已收货 这个字段用于实体商品的收获状态
+              receiptTime: item?.receiptTime || '', //收货时间
+              receiptType: item?.receiptType || '', //收货类型 0-快递 1-线下取货
+              expressType: item?.expressType || '', //快递类型 0-邮政速递 1-顺丰速运 2-京东快递 3-中通快递 4-圆通速递 5-申通快递 6-韵达快递 7-极兔速递
+              expressNo: item?.expressNo || '', //快递单号
+              expressTypeName: this.getExpressTypeName(item?.expressType), //快递公司名称
+              expressTypeIcon: this.getExpressTypeIcon(item?.expressType), //快递公司图标
+              //end实体商品所用到的字段
+              progress: item?.progress || '', //进度 0-进行中 1-已完成 2-未开始 3-已取消 这个字段用于线下服务商品以及线上权益商品的进度状态
+              image: item.conditioningProgramPhoto || '',
+              price: item?.unitPrice || 0,
+              quantity: item?.totalMeasure || 0,
+              statusClass: this.getStatusClass(item?.sellType, item?.progress, item?.receiptStatus),
+              statusText: this.getGoodsStatusText(item?.sellType, item?.progress, item?.receiptStatus),
+            }
+          });
+        };
+
+        // 分别处理三个数组
+        let sellTypeFirstItems = processItems(res.data?.sellTypeFirstItems || []);
+        const sellTypeSecondItems = processItems(res.data?.sellTypeSecondItems || []);
+        const sellTypeThirdItems = processItems(res.data?.sellTypeThirdItems || []);
+
+        // 对实体商品进行排序:快递类型(receiptType === '0')在上,线下取货类型(receiptType === '1')在下
+        sellTypeFirstItems = sellTypeFirstItems.sort((a: any, b: any) => {
+          const aType = a.receiptType || '';
+          const bType = b.receiptType || '';
+          if (aType === '0' && bType === '1') {
+            return -1;
+          }
+          if (aType === '1' && bType === '0') {
+            return 1;
+          }
+          return 0;
+        });
+
+        this.setData({
+          sellTypeFirstItems,
+          sellTypeSecondItems,
+          sellTypeThirdItems,
+        });
+      }
+    } catch (error: any) {
+      wx.showToast({
+        title: error.errMsg,
+        icon: "none",
+      });
+    }
+    wx.hideLoading();
+  },
+
+  // 去预约
+  goAppointment(e: any) {
+    const { id } = e.currentTarget.dataset;
+    // 去非药物治疗页面
+    wx.navigateTo({
+      url: `/module/care/pages/offlineTreatment/offlineTreatment?id=${id}`,
+    });
+  },
+  // 立即支付
+  async onPayment() {
+    if (this.data.isPaymentLoading) {
+      return;
+    }
+    this.setData({ isPaymentLoading: true });
+
+    try {
+      // 调用支付接口
+      const payResult = await orderPayMethod(this.data.id, (this.data.orderDetail as any)?.remark);
+      if (payResult && payResult.data) {
+        const paymentParams = payResult.data;
+        handleWeChatPayment(paymentParams, (res: any) => {
+          // 支付成功,跳转到成功页面
+          wx.redirectTo({
+            url: "/module/article/pages/success-page/success-page?title=订单支付成功",
+          });
+        }, (error: any) => {
+          this.setData({ isPaymentLoading: false });
+          if (error?.errMsg === 'requestPayment:fail cancel') {
+           // 支付取消跳到支付订单页面
+            wx.navigateBack({ delta: 1 });
+          }
+          // wx.showToast({
+          //   title: error.errMsg,
+          //   icon: "none",
+          // });
+        });
+      } else {
+        wx.showToast({
+          title: payResult.errMsg,
+          icon: "none",
+        });
+      }
+    } catch (error: any) {
+      wx.showToast({
+        title: error.errMsg,
+        icon: "none",
+      });
+    } finally {
+      this.setData({ isPaymentLoading: false });
+    }
+  },
+
+  // 备注输入处理
+  onRemarkInput(e: any) {
+    const value = e.detail.value;
+    const length = value.length;
+
+    // 限制最大长度为200
+    if (length > 200) {
+      return;
+    }
+
+    this.setData({
+      'orderDetail.remark': value,
+      remarkLength: length
+    });
+  },
+
+  // 复制订单号
+  copyOrderNo(e: any) {
+    const orderNo = e.currentTarget.dataset.orderno;
+    if (!orderNo) {
+      getTickleContext.call(this).showWarnMessage("订单号为空");
+      return;
+    }
+    wx.setClipboardData({
+      data: orderNo,
+      success: () => {
+        wx.showToast({
+          title: '已复制',
+          icon: 'none'
+        });
+      }
+    });
+  },
+
+  // 获取状态类名
+  // sellType: 商品类型 1-实体商品 2-线下服务 3-线上权益
+  // progress: 进度状态(用于线下服务和线上权益):0-进行中 1-已完成 2-未开始
+  // receiptStatus: 收货状态(用于实体商品):0-待发货 1-已发货 2-已收货
+  getStatusClass(sellType?: string | number, progress?: string | number, receiptStatus?: string | number): string {
+    const type = String(sellType || '');
+    // 实体商品 (sellType === 1) 使用 receiptStatus(三种状态)
+    if (type === "1") {
+      const status = String(receiptStatus || '');
+      if (status === "0") {
+        return "status-pending"; // 待发货
+      } else if (status === "1") {
+        return "status-received"; // 已发货
+      } else if (status === "2") {
+        return "status-completed"; // 已收货
+      }
+    }
+    // 线下服务 (sellType === 2) 和线上权益 (sellType === 3) 使用 progress(三种状态)
+    else if (type === "2" || type === "3") {
+      const status = String(progress || '');
+      if (status === "0") {
+        return "status-pending"; // 进行中
+      } else if (status === "1") {
+        return "status-completed"; // 已完成
+      } else if (status === "2") {
+        return "status-closed"; // 未开始
+      }
+    }
+    return "";
+  },
+
+  // 获取商品状态文本
+  getGoodsStatusText(sellType?: string | number, progress?: string | number, receiptStatus?: string | number): string {
+    const type = String(sellType || '');
+    // 实体商品 (sellType === 1) 使用 receiptStatus(三种状态)
+    if (type === "1") {
+      const status = String(receiptStatus || '');
+      if (status === "0") {
+        return "待发货";
+      } else if (status === "1") {
+        return "已发货";
+      } else if (status === "2") {
+        return "已收货";
+      }
+    }
+    // 线下服务 (sellType === 2) 和线上权益 (sellType === 3) 使用 progress(三种状态)
+    else if (type === "2" || type === "3") {
+      const status = String(progress || '');
+      if (status === "0") {
+        return "进行中";
+      } else if (status === "1") {
+        return "已完成";
+      } else if (status === "2") {
+        return "未开始";
+      }
+    }
+    return "";
+  },
+
+  // 获取快递公司名称
+  getExpressTypeName(expressType?: string | number): string {
+    const expressTypeMap: Record<string, string> = {
+      "0": "邮政速递",
+      "1": "顺丰速运",
+      "2": "京东快递",
+      "3": "中通快递",
+      "4": "圆通速递",
+      "5": "申通快递",
+      "6": "韵达快递",
+      "7": "极兔速递",
+    };
+    return expressTypeMap[String(expressType || '')] || "";
+  },
+
+  // 获取快递公司图标
+  getExpressTypeIcon(expressType?: string | number): string {
+    const expressIconMap: Record<string, string> = {
+      "0": "icon-youzhengkuaidi", // 邮政速递
+      "1": "icon-shunfengkuaidi", // 顺丰速运
+      "2": "icon-jingdong", // 京东快递
+      "3": "icon-zhongtong", // 中通快递
+      "4": "icon-yuantongkuaidi", // 圆通速递
+      "5": "icon-shentong", // 申通快递
+      "6": "icon-yunda", // 韵达快递
+      "7": "icon-jitukuaidi", // 极兔速递
+    };
+    return expressIconMap[String(expressType || '')] || "";
+  },
+
+  // 获取订单状态文本
+  getStatusText(status: string | number): string {
+    const statusTextMap: Record<string, string> = {
+      "0": "待付款",
+      "6": "已付款",
+      "2": "交易关闭",
+      "345": "交易成功",
+    };
+    return statusTextMap[String(status)] || "";
+  },
+
+  // 确认收货
+  onConfirmReceipt(e: any) {
+    const { patientconditioningrecordid } = e.currentTarget.dataset;
+    if (patientconditioningrecordid) {
+      const shippedGoods = this.data.sellTypeFirstItems.filter((item: any) => item.receiptStatus === '1');
+
+      if (shippedGoods.length === 0) {
+        wx.showToast({
+          title: '没有可确认收货的商品',
+          icon: 'none'
+        });
+        return;
+      }
+      //  去确认收货页面
+      wx.navigateTo({
+        url: `/module/article/pages/confirm-receiving/confirm-receiving?patientConditioningRecordId=${patientconditioningrecordid as string}&goodsList=${encodeURIComponent(JSON.stringify(shippedGoods))}`,
+        fail: (err) => {
+          wx.showToast({
+            title: err.errMsg || '跳转失败',
+            icon: 'none'
+          });
+        }
+      });
+    } else {
+      wx.showToast({
+        title: '调理记录id为空',
+        icon: 'none'
+      });
+    }
+  },
+
+});

+ 193 - 0
miniprogram/module/order/pages/other-detail/other-detail.wxml

@@ -0,0 +1,193 @@
+<!--module/order/pages/select-goods/select-goods.wxml-->
+<t-navbar title="{{title}}" left-arrow />
+<scroll-view class="page-scroll__container" type="list" scroll-y style="{{containerStyle}}">
+  <view class="info-box">
+  </view>
+  <!-- 实体商品 -->
+  <view>
+    <view class="goods-list" wx:if="{{sellTypeFirstItems.length > 0}}">
+      <view class="category-title">实体商品</view>
+      <view wx:for="{{sellTypeFirstItems}}" wx:for-item="goods" wx:for-index="goodsIndex" wx:key="id">
+        <!-- 线下取货小标题:当遇到第一个线下取货商品时显示 -->
+        <view class="offline-title" wx:if="{{goods.receiptType === '1' && (goodsIndex === 0 || sellTypeFirstItems[goodsIndex - 1].receiptType === '0')}}">线下取货</view>
+        <!-- 快递信息 -->
+        <view class="express-info" wx:if="{{goods.receiptType === '0' && goods.expressTypeName && goods.expressNo && goods.receiptStatus === '1'}}">
+          <view class="express-text">
+            <view style="font-weight:600;margin-right: 10rpx;display: flex;align-items: center;">
+             <text style="font-size: 25rpx;"> 快件{{goodsIndex + 1}}</text>
+              <i class="iconfont {{goods.expressTypeIcon}}" style="font-size:15px" wx:if="{{goods.expressTypeIcon}}"></i>
+            </view>
+            <view style="color:#9b9797;font-size: 25rpx;">{{goods.expressTypeName}} {{goods.expressNo}}</view>
+          </view>
+           <t-icon name="chevron-right" color="#000" size="40rpx" slot="note" />
+        </view>
+        <view>
+          <view class="goods-status {{goods.statusClass}}" wx:if="{{goods.statusText && orderStatus !== 'closed'}}">{{goods.statusText}}</view>
+          <view class="goods-item">
+            <image class="goods-image" src="{{goods.image}}" mode="aspectFill" wx:if="{{goods.image}}" />
+            <view class="service-package-placeholder" wx:else>
+              <text class="placeholder-icon">📦</text>
+            </view>
+            <view class="goods-info">
+              <view class="goods-name-row">
+                <text class="goods-name">{{goods.name}}</text>
+                <text class="goods-price">¥{{goods.price}}</text>
+              </view>
+              <view class="goods-desc-row">
+                <view class="goods-desc" wx:if="{{goods.description}}">{{goods.description}}</view>
+                <view class="quantity-text">x{{goods.quantity}}</view>
+              </view>
+              <!-- 确认收货按钮 -->
+              <view class="confirm-receipt-btn" wx:if="{{goods.receiptStatus === '1'}}" bindtap="onConfirmReceipt" data-patientConditioningRecordId="{{goods.patientConditioningRecordId}}" data-index="{{goodsIndex}}">
+                确认收货
+              </view>
+            </view>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- 线下服务商品 -->
+    <view class="goods-list" wx:if="{{sellTypeSecondItems.length > 0}}">
+      <view class="category-title">线下服务商品</view>
+      <view wx:for="{{sellTypeSecondItems}}" wx:for-item="goods" wx:for-index="goodsIndex" wx:key="id" data-id="{{goods.id}}" bindtap="goAppointment">
+        <view>
+          <view class="goods-status {{goods.statusClass}}" wx:if="{{goods.statusText && orderStatus !== 'closed'}}">{{goods.statusText}}</view>
+          <view class="goods-item">
+            <image class="goods-image" src="{{goods.image}}" mode="aspectFill" wx:if="{{goods.image}}" />
+            <view class="service-package-placeholder" wx:else>
+              <text class="placeholder-icon">📦</text>
+            </view>
+            <view class="goods-info">
+              <view class="goods-name-row">
+                <text class="goods-name">{{goods.name}}</text>
+                <text class="goods-price">¥{{goods.price}}</text>
+              </view>
+              <view class="goods-desc-row">
+                <view class="goods-desc" wx:if="{{goods.description}}">{{goods.description}}</view>
+                <view class="quantity-text">x{{goods.quantity}}</view>
+              </view>
+            </view>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- 线上权益商品 -->
+    <view class="goods-list" wx:if="{{sellTypeThirdItems.length > 0}}">
+      <view class="category-title">线上权益商品</view>
+      <view wx:for="{{sellTypeThirdItems}}" wx:for-item="goods" wx:for-index="goodsIndex" wx:key="id">
+        <view>
+          <view class="goods-status {{goods.statusClass}}" wx:if="{{goods.statusText && orderStatus !== 'closed'}}">{{goods.statusText}}</view>
+          <view class="goods-item">
+            <image class="goods-image" src="{{goods.image}}" mode="aspectFill" wx:if="{{goods.image}}" />
+            <view class="service-package-placeholder" wx:else>
+              <text class="placeholder-icon">📦</text>
+            </view>
+            <view class="goods-info">
+              <view class="goods-name-row">
+                <text class="goods-name">{{goods.name}}</text>
+                <text class="goods-price">¥{{goods.price}}</text>
+              </view>
+              <view class="goods-desc-row">
+                <view class="goods-desc" wx:if="{{goods.description}}">{{goods.description}}</view>
+                <view class="quantity-text">x{{goods.quantity}}</view>
+              </view>
+            </view>
+          </view>
+        </view>
+      </view>
+    </view>
+    <!-- 商品总价 -->
+    <view class="price-total-wrapper">
+      <view class="price-total">
+        <text class="price-label">商品总价:</text>
+        <text class="price-value">¥{{orderDetail.cost}}</text>
+      </view>
+    </view>
+  </view>
+  <!-- 实际付款 -->
+  <view class="price-summary-section">
+    <view class="price-summary-card price-row">
+      <text class="price-label">{{orderStatus==='closed'?'应付款':'实付款'}}:</text>
+      <text class="price-value payable-value">¥{{orderStatus === 'received' ? orderDetail.realAmount : orderDetail.cost}}</text>
+    </view>
+  </view>
+
+  <!--  最下方的信息 -->
+  <view class="order-info-section">
+    <!-- 备注 -->
+    <view class="info-card">
+      <view class="remark-item">
+        <text class="info-label">备注</text>
+        <view class="remark-input-wrapper">
+          <textarea class="remark-textarea" placeholder="请输入备注信息" value="{{orderDetail.remark || '无'}}" maxlength="200" bindinput="onRemarkInput" auto-height show-confirm-bar="{{false}}" disabled="{{orderStatus!=='pending'}}" />
+          <view class="remark-count">
+            <text class="remark-count-text" wx:if="{{orderDetail.remark}}">{{remarkLength}}/200</text>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- 订单详情 -->
+    <view class="info-card">
+      <view class="info-item" wx:if="{{orderDetail.orderNo}}">
+        <text class="info-label" style="font-weight:600">订单编号</text>
+        <view class="info-value-row">
+          <text class="info-value">{{orderDetail.orderNo || ''}}</text>
+          <text class="copy-btn" bindtap="copyOrderNo" data-orderno="{{orderDetail.orderNo}}">复制</text>
+        </view>
+      </view>
+      <view class="info-divider"></view>
+      <view class="info-item">
+        <text class="info-label">创建时间</text>
+        <text class="info-value">{{orderDetail.operateTime || ''}}</text>
+      </view>
+       <view class="info-divider"></view>
+      <view class="info-item" wx:if="{{orderStatus!=='closed'}}">
+        <text class="info-label">付款时间</text>
+        <text class="info-value">{{orderDetail.payTime || ''}}</text>
+      </view>
+       <view class="info-divider" wx:if="{{orderStatus!=='closed'}}"></view>
+      <view class="info-item" wx:if="{{orderStatus==='completed'}}">
+        <text class="info-label">成交时间</text>
+        <text class="info-value">{{orderDetail.finishTime || ''}}</text>
+      </view>
+       <view class="info-divider" wx:if="{{orderStatus==='completed'}}"></view>
+      <view class="info-item" wx:if="{{orderStatus==='closed'}}">
+        <text class="info-label">关闭时间</text>
+        <text class="info-value">{{orderDetail.cancelTime || ''}}</text>
+      </view>
+       <view class="info-divider" wx:if="{{orderStatus==='closed'}}"></view>
+      <view class="info-item" wx:if="{{orderStatus!=='closed'}}">
+        <text class="info-label">微信交易号</text>
+        <text class="info-value">{{orderDetail.payTransactionNo || ''}}</text>
+      </view>
+    </view>
+
+    <!-- 服务包详情 -->
+    <view class="info-card">
+      <view class="info-item" wx:if="{{orderDetail.conditioningWrapName}}">
+        <text class="info-label" style="font-weight:600">服务包</text>
+        <text class="info-value">{{orderDetail.conditioningWrapName || ''}}</text>
+      </view>
+      <view class="info-divider" wx:if="{{orderDetail.operateBy}}"></view>
+      <view class="info-item" wx:if="{{orderDetail.operateBy}}">
+        <text class="info-label">开具医生</text>
+        <text class="info-value">{{orderDetail.operateBy || ''}}</text>
+      </view>
+      <view class="info-divider" wx:if="{{orderDetail.operateTime}}"></view>
+      <view class="info-item" wx:if="{{orderDetail.operateTime}}">
+        <text class="info-label">开具时间</text>
+        <text class="info-value">{{orderDetail.operateTime || ''}}</text>
+      </view>
+      <view class="info-divider" wx:if="{{orderDetail.estimatedStartDate}}"></view>
+      <view class="info-item" wx:if="{{orderDetail.estimatedStartDate}}">
+        <text class="info-label">开始调养日期</text>
+        <text class="info-value">{{orderDetail.estimatedStartDate || ''}}</text>
+      </view>
+    </view>
+  </view>
+
+
+</scroll-view>

+ 8 - 0
miniprogram/module/order/pages/select-goods/select-goods.json

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

+ 276 - 0
miniprogram/module/order/pages/select-goods/select-goods.scss

@@ -0,0 +1,276 @@
+@import '../../../../themes/t.cell.scss';
+@import '../../../../themes/page.scss';
+
+/* module/order/pages/select-goods/select-goods.wxss */
+.info-box {
+  padding: 10rpx;
+}
+.page-scroll__container {
+  flex: 0 1 auto;
+  height: var(--page-container-safeHeight, 100vh);
+  background: #f7f8fa;
+  padding-bottom: 120rpx;
+}
+
+.goods-list {
+  background: transparent;
+  margin-bottom: 20rpx;
+}
+
+.category-title {
+  padding: 28rpx 32rpx 20rpx;
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #333;
+  background: #fff;
+  position: sticky;
+  top: 0;
+  z-index: 10;
+}
+
+.goods-item {
+  display: flex;
+  align-items: center;
+  padding: 32rpx;
+  // margin: 0 20rpx 20rpx;
+  background: #fff;
+  border-radius: 16rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
+  transition: all 0.3s ease;
+  padding-bottom: 10px;
+  &:active {
+    transform: scale(0.98);
+    box-shadow: 0 1rpx 8rpx rgba(0, 0, 0, 0.06);
+  }
+}
+
+.goods-checkbox {
+  margin-right: 24rpx;
+  margin-top: 8rpx;
+  flex-shrink: 0;
+}
+
+.goods-image {
+  width: 180rpx;
+  height: 180rpx;
+  border-radius: 12rpx;
+  background: #f5f5f5;
+  margin-right: 24rpx;
+  flex-shrink: 0;
+  border: 1rpx solid #f0f0f0;
+}
+
+.goods-info {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  min-width: 0;
+  justify-content: space-between;
+  min-height: 180rpx;
+}
+
+.goods-name-row {
+  display: flex;
+  align-items: center;
+  margin-bottom: 12rpx;
+  flex-wrap: wrap;
+}
+
+.goods-name {
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+  flex: 1;
+  min-width: 0;
+  line-height: 1.4;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+  line-clamp: 2;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.goods-badge {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  min-width: 36rpx;
+  height: 36rpx;
+  padding: 0 10rpx;
+  background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
+  color: #333;
+  font-size: 22rpx;
+  font-weight: 600;
+  border-radius: 18rpx;
+  margin-left: 12rpx;
+  box-shadow: 0 2rpx 4rpx rgba(255, 215, 0, 0.3);
+}
+
+.goods-desc {
+  font-size: 26rpx;
+  color: #999;
+  margin-bottom: 20rpx;
+  line-height: 1.4;
+}
+
+.goods-price-row {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-top: auto;
+}
+
+.goods-price {
+  font-size: 36rpx;
+  font-weight: 700;
+  color: #ff4444;
+  letter-spacing: -0.5rpx;
+}
+
+.quantity-selector {
+  display: flex;
+  align-items: center;
+  border: 2rpx solid #e8e8e8;
+  border-radius: 12rpx;
+  overflow: hidden;
+  background: #fff;
+  box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.04);
+}
+
+.quantity-btn {
+  width: 64rpx;
+  height: 64rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: #f8f8f8;
+  font-size: 36rpx;
+  font-weight: 500;
+  color: #333;
+  user-select: none;
+  transition: all 0.2s ease;
+  position: relative;
+  
+  &.minus {
+    border-right: 1rpx solid #e8e8e8;
+  }
+  
+  &.plus {
+    border-left: 1rpx solid #e8e8e8;
+  }
+  
+  &:active:not(.disabled) {
+    background: #1d6ff6;
+    color: #fff;
+    transform: scale(0.95);
+  }
+  
+  &.disabled {
+    opacity: 0.4;
+    background: #f5f5f5;
+    color: #ccc;
+    cursor: not-allowed;
+  }
+}
+
+.quantity-input {
+  width: 90rpx;
+  height: 64rpx;
+  text-align: center;
+  font-size: 30rpx;
+  font-weight: 500;
+  color: #333;
+  background: #fff;
+  border: none;
+  padding: 0;
+  
+  &[disabled] {
+    background: #f8f8f8;
+    color: #999;
+    opacity: 0.6;
+  }
+}
+
+.quantity-text {
+  font-size: 30rpx;
+  font-weight: 500;
+  color: #666;
+  padding: 0 16rpx;
+}
+
+.footer-placeholder {
+  height: 120rpx;
+}
+
+.footer-bar {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  width: 100%;
+  min-height: 100rpx;
+  background: #fff;
+  display: flex;
+  align-items: center;
+  padding: 10rpx 10rpx 0 0;
+  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
+  z-index: 100;
+  box-sizing: border-box;
+  border-top: 1rpx solid #f0f0f0;
+}
+
+.footer-left {
+  flex-shrink: 0;
+  margin-right: 32rpx;
+}
+
+.footer-center {
+  flex: 1;
+  display: flex;
+  align-items: baseline;
+  font-size: 28rpx;
+  color: #333;
+  line-height: 1.4;
+}
+
+.footer-text {
+  color: #666;
+  font-size: 26rpx;
+}
+
+.footer-price {
+  color: #ff4444;
+  font-weight: 700;
+  font-size: 36rpx;
+  margin-left: 8rpx;
+  letter-spacing: -0.5rpx;
+}
+
+.footer-right {
+  flex-shrink: 0;
+  margin-left: 24rpx;
+}
+
+.checkout-btn {
+  min-width: 160rpx;
+  height: 76rpx;
+  line-height: 76rpx;
+  text-align: center;
+  background: linear-gradient(135deg, #1d6ff6 0%, #4a90ff 100%);
+  color: #fff;
+  font-size: 30rpx;
+  font-weight: 600;
+  border-radius: 38rpx;
+  box-shadow: 0 4rpx 12rpx rgba(29, 111, 246, 0.3);
+  transition: all 0.3s ease;
+  
+  &:active {
+    opacity: 0.9;
+    transform: scale(0.98);
+    box-shadow: 0 2rpx 8rpx rgba(29, 111, 246, 0.4);
+  }
+}
+.t-checkbox--block {
+  padding: 0!important;
+}

+ 260 - 0
miniprogram/module/order/pages/select-goods/select-goods.ts

@@ -0,0 +1,260 @@
+import DictionariesBehavior from "../../../../core/behavior/dictionaries.behavior";
+import PageContainerBehavior from "../../../../core/behavior/page-container.behavior";
+import tickleBehavior, {
+  getTickleContext,
+} from "../../../../core/behavior/tickle.behavior";
+import { getOfflineTreatmentListMethod } from "../../request";
+// module/order/pages/select-goods/select-goods.ts
+Component({
+  behaviors: [PageContainerBehavior, DictionariesBehavior, tickleBehavior],
+  lifetimes: {
+    attached() {
+      const healthAnalysisReportId = wx.getStorageSync('healthAnalysisReportId'); 
+      if(healthAnalysisReportId){
+        this.getOfflineTreatmentList(healthAnalysisReportId);
+      }
+    },
+  },
+  data: {
+    goodsList: [] as Array<{
+      category: string;
+      goods: Array<{
+        id: string;
+        name: string;
+        description?: string;
+        image: string;
+        price: number;
+        quantity: number;
+        checked: boolean;
+        badge?: string;
+      }>;
+    }>,
+    selectAll: true,
+    selectedCount: 0,
+    totalPrice: 0,
+  },
+  observers: {
+    'goodsList': function () {
+      this.calculateSummary();
+    }
+  },
+  methods: {
+    async getOfflineTreatmentList(healthAnalysisReportId: string) {
+      const res = await getOfflineTreatmentListMethod(healthAnalysisReportId);
+      const goodsList: any[] = [];
+      Object.keys(res).forEach((categoryName: string) => {
+        const categoryItems = res[categoryName] || [];
+        if (categoryItems.length > 0) {
+          const goods = categoryItems.map((item: any) => {
+            return {
+              id: item.id || '',
+              name: item.name || '', //商品名称
+              description: (() => {
+                const dose = item?.cpFixedPricingRule?.convertDose ?? '';
+                const unit = item?.cpFixedPricingRule?.convertUnit ?? '';
+                return `${dose} ${unit}`;
+              })(),
+              image: item.itemImgSecond || '', //商品图片
+              price: item.cpFixedPricingRule?.unitPrice || 0, //商品单价
+              quantity: 1, //商品数量
+              checked: true, //是否选中
+            };
+          });
+          goodsList.push({
+            category: categoryName,
+            goods: goods,
+          });
+        }
+      });
+      this.setData({ goodsList });
+      this.calculateSummary();
+    },
+
+    // 商品复选框变化
+    onGoodsCheckChange(e: any) {
+      const { categoryIndex, goodsIndex } = e.currentTarget.dataset;
+      const checked = e.detail.checked;
+      const goodsList = this.data.goodsList;
+      const goods = goodsList[categoryIndex].goods[goodsIndex];
+
+      goods.checked = checked;
+
+      // 如果勾选且数量为0,设置为1
+      if (checked && goods.quantity === 0) {
+        goods.quantity = 1;
+      }
+
+      // 单价为0的商品,如果勾选,数量固定为1
+      if (goods.price === 0) {
+        if (checked) {
+        goods.quantity = 1;
+        } else {
+          goods.quantity = 0;
+        }
+      }
+
+      this.setData({ goodsList });
+      this.calculateSummary();
+    },
+
+    // 全选变化
+    onSelectAllChange(e: any) {
+      const checked = e.detail.checked;
+      const goodsList = this.data.goodsList.map(category => ({
+        ...category,
+        goods: category.goods.map(goods => ({
+          ...goods,
+          checked: checked,
+          // 0元商品:选中时数量为1,未选中时数量为0
+          // 非0元商品:选中时如果数量为0则设为1,否则保持原数量
+          quantity: goods.price === 0 
+            ? (checked ? 1 : 0)
+            : (checked && goods.quantity === 0 ? 1 : goods.quantity)
+        }))
+      }));
+
+      this.setData({
+        goodsList,
+        selectAll: checked
+      });
+      this.calculateSummary();
+    },
+
+    // 数量变化(加减按钮)
+    onQuantityChange(e: any) {
+      const { categoryIndex, goodsIndex, type } = e.currentTarget.dataset;
+      const goodsList = this.data.goodsList;
+      const goods = goodsList[categoryIndex].goods[goodsIndex];
+
+      // 单价为0的商品数量固定为1(如果被选中)
+      if (goods.price === 0) {
+        // 0元商品数量固定为1,不允许通过按钮修改
+            return;
+      } else {
+        // 非0价格商品的正常逻辑
+        let newQuantity = goods.quantity;
+
+        if (type === "plus") {
+          newQuantity = goods.quantity + 1;
+        } else if (type === "minus") {
+          newQuantity = Math.max(0, goods.quantity - 1);
+        }
+
+        goods.quantity = newQuantity;
+
+        // 如果数量为0,自动取消勾选
+        if (newQuantity === 0) {
+          goods.checked = false;
+        } else if (!goods.checked) {
+          // 如果数量大于0且未勾选,自动勾选
+          goods.checked = true;
+        }
+      }
+
+      this.setData({ goodsList });
+      this.calculateSummary();
+    },
+
+    // 数量输入
+    onQuantityInput(e: any) {
+      const { categoryIndex, goodsIndex } = e.currentTarget.dataset;
+      const goodsList = this.data.goodsList;
+      const goods = goodsList[categoryIndex].goods[goodsIndex];
+
+      // 单价为0的商品数量固定为1,不允许修改
+      if (goods.price === 0) {
+        // 保持数量为1
+          goods.quantity = 1;
+        this.setData({ goodsList });
+        return;
+      }
+
+      const value = parseInt(e.detail.value) || 0;
+        goods.quantity = Math.max(0, value);
+
+      this.setData({ goodsList });
+    },
+
+    // 数量输入失焦
+    onQuantityBlur(e: any) {
+      const { categoryIndex, goodsIndex } = e.currentTarget.dataset;
+      const goodsList = this.data.goodsList;
+      const goods = goodsList[categoryIndex].goods[goodsIndex];
+
+      // 单价为0的商品数量固定为1(如果被选中)
+      if (goods.price === 0) {
+        // 如果被选中,数量固定为1
+        if (goods.checked) {
+          goods.quantity = 1;
+        } else {
+          // 如果未选中,数量为0
+          goods.quantity = 0;
+        }
+      } else {
+        // 非0价格商品的逻辑
+        if (goods.quantity === 0) {
+          goods.checked = false;
+        } else if (!goods.checked) {
+          // 如果数量大于0且未勾选,自动勾选
+          goods.checked = true;
+        }
+      }
+
+      this.setData({ goodsList });
+      this.calculateSummary();
+    },
+
+    // 计算汇总信息
+    calculateSummary() {
+      const goodsList = this.data.goodsList;
+      let selectedCount = 0;
+      let totalPrice = 0;
+      let allChecked = true;
+
+      goodsList.forEach((category: any) => {
+        category.goods.forEach((goods: any) => {
+          if (goods.checked && goods.quantity > 0) {
+            selectedCount++; // 已选件数 = 选中的商品种类数
+            totalPrice += goods.price * goods.quantity;
+          }
+          if (!goods.checked || goods.quantity === 0) {
+            allChecked = false;
+          }
+        });
+      });
+
+      this.setData({
+        selectedCount,
+        totalPrice: totalPrice.toFixed(2),
+        selectAll: allChecked
+      });
+    },
+
+    // 结算
+    onCheckout() {
+      const goodsList = this.data.goodsList;
+      // 过滤出选中的商品
+      const selectedGoods = goodsList.map((category: any) => ({
+        category: category.category,
+        goods: category.goods.filter((goods: any) => goods.checked && goods.quantity > 0)
+      })).filter((category: any) => category.goods.length > 0);
+
+      if (selectedGoods.length === 0) {
+        getTickleContext.call(this).showWarnMessage("请至少选择一件商品");
+        return;
+      }
+
+      // 跳转到确认订单页面
+      wx.setStorageSync('selectedGoods', selectedGoods);
+      wx.setStorageSync('totalPrice', this.data.totalPrice);
+      wx.navigateTo({
+        url: `/module/order/pages/confirme-order/confirme-order`,
+        fail: (err) => {
+          getTickleContext.call(this).showWarnMessage(err.errMsg || "跳转失败");
+        },
+      });
+    },
+
+  }
+
+});

+ 56 - 0
miniprogram/module/order/pages/select-goods/select-goods.wxml

@@ -0,0 +1,56 @@
+<!--module/order/pages/select-goods/select-goods.wxml-->
+<t-navbar title="选择商品" left-arrow />
+<scroll-view class="page-scroll__container" type="list" scroll-y style="{{containerStyle}}">
+  <view class="info-box"></view>
+  <!-- 商品列表 -->
+  <view class="goods-list" wx:for="{{goodsList}}" wx:key="category">
+    <!-- 分类标题 -->
+    <view class="category-title">{{item.category}}</view>
+
+    <!-- 商品项 -->
+    <view class="goods-item" wx:for="{{item.goods}}" wx:for-item="goods" wx:for-index="goodsIndex" wx:key="id">
+      <!-- 复选框 -->
+      <view class="goods-checkbox">
+        <t-checkbox checked="{{goods.checked}}" bind:change="onGoodsCheckChange" data-category-index="{{index}}" data-goods-index="{{goodsIndex}}" style="padding:0" />
+      </view>
+
+      <!-- 商品图片 -->
+      <image class="goods-image" src="{{goods.image}}" mode="aspectFill" />
+
+      <!-- 商品信息 -->
+      <view class="goods-info">
+        <view class="goods-name-row">
+          <text class="goods-name">{{goods.name}}</text>
+        </view>
+        <view class="goods-desc" wx:if="{{goods.description}}">{{goods.description}}</view>
+        <view class="goods-price-row">
+          <text class="goods-price">¥{{goods.price}}</text>
+          <!-- 0元商品只显示数量1,非0元商品显示数量选择器 -->
+          <view wx:if="{{goods.price === 0}}" class="quantity-text">x1</view>
+          <view wx:else class="quantity-selector">
+            <view class="quantity-btn minus {{goods.quantity <= 1 ? 'disabled' : ''}}" bind:tap="onQuantityChange" data-category-index="{{index}}" data-goods-index="{{goodsIndex}}" data-type="minus">-</view>
+            <input class="quantity-input" type="number" value="{{goods.quantity}}" bind:input="onQuantityInput" bind:blur="onQuantityBlur" data-category-index="{{index}}" data-goods-index="{{goodsIndex}}" />
+            <view class="quantity-btn plus" bind:tap="onQuantityChange" data-category-index="{{index}}" data-goods-index="{{goodsIndex}}" data-type="plus">+</view>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+
+  <!-- 底部占位 -->
+  <view class="footer-placeholder"></view>
+</scroll-view>
+
+<!-- 底部固定栏 -->
+<view class="footer-bar" style="padding-bottom: {{container.safeBottomOffset}}px;">
+  <view class="footer-left">
+    <t-checkbox checked="{{selectAll}}" bind:change="onSelectAllChange" label="全选" />
+  </view>
+  <view class="footer-center">
+    <text class="footer-text">已选{{selectedCount}}件 合计: </text>
+    <text class="footer-price">¥{{totalPrice}}</text>
+  </view>
+  <view class="footer-right">
+    <view class="checkout-btn" bind:tap="onCheckout">结算</view>
+  </view>
+</view>

+ 71 - 0
miniprogram/module/order/request.ts

@@ -0,0 +1,71 @@
+import { Get, Post } from "../../lib/request/method";
+
+// 获取订单详情
+export function getOrderDetailMethod(id: string) {
+  return Post(`/patientCrManage/getPcrDetailById/${id}`, {
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
+}
+
+// 订单支付接口
+export function orderPayMethod(id: string, remark: string) {
+  return Post(`/patientCrManage/payPcr/${id}`, { remark: remark }, {
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
+}
+
+// 确认收货
+export function orderConfirmReceiptMethod(id: string) {
+  return Post(`/patientCrManage/confirmReceipt/${id}`, {
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
+}
+//患者线下调理方案预约
+export function patientOfflineTreatmentAppointmentMethod(offlineId: string, time: string) {
+  return Post(`/patientCrManage/pofflineCpApply/${offlineId}`, {}, {
+    params: {
+      time,
+    },
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
+}
+// 根据健康分析报告ID获取可自行购买的调理方案
+export function getOfflineTreatmentListMethod(healthAnalysisReportId: string) {
+  return Post(`/patientCrManage/getCpsByHrepId/${healthAnalysisReportId}`, {}, {
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
+}
+
+// 自行购买调理方案
+export function purchaseOfflineTreatmentMethod(data: any) {
+  return Post(`/patientCrManage/buyCps`, data, {
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
+}
+// 获取所有地址列表
+export function getAddressListMethod(id: string, keyWord: string) {
+  return Post(
+    `/patientCrManage/patAddress/all`,
+    {
+      id,
+      keyWord,
+    },
+    {
+      transform({ data }: AnyObject) {
+        return data;
+      },
+    }
+  );
+}

+ 20 - 9
miniprogram/pages/home/home.scss

@@ -22,8 +22,8 @@
   > view:not(.chat-status),
   > text,
   > image {
-    position: relative;
-    z-index: 1;
+    // position: relative;
+    // z-index: 1;
   }
 }
 
@@ -158,7 +158,7 @@
     // 渐变蓝色
     width: 95%;
     border-radius: 6px;
-    margin: auto;
+    // margin: auto;
 
     .report-img {
       width: 35rpx;
@@ -198,8 +198,8 @@ $scale: 0.5;
   position: relative;
   align-items: center;
   padding: 0 8px;
-  width: 254px * $scale;
-  height: 66px * $scale;
+  // width: 254px * $scale;
+  // height: 66px * $scale;
   box-sizing: border-box;
 
   .user {
@@ -539,7 +539,8 @@ $scale: 0.5;
 
 .item-next-time {
   color: #2ec4b6;
-  margin-left: 16rpx;
+  font-size: 28rpx;
+  // margin-left: 16rpx;
 }
 
 .item-arrow {
@@ -598,11 +599,12 @@ $scale: 0.5;
   cursor: pointer;
   color: #1976d2;
   border: 1px solid #1976d2;
-  padding: 7rpx 20px;
+  padding: 7rpx 10px;
   border-radius: 10rpx;
-  width: 17%;
+  // width: 17%;
   text-align: center;
-  margin-right: 10px;
+  // margin-right: 10px;
+  margin-bottom: 20rpx;
 }
 
 .carousel-container {
@@ -723,3 +725,12 @@ $scale: 0.5;
     white-space: nowrap;
   }
 }
+.right-btn {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
+}
+.ins-box {
+  display: flex;
+  align-items: center;
+}

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

@@ -37,6 +37,7 @@ Page({
       report: { title: '报告' },
       healthTeach: { title: '' },
     },
+    NoteTitle: "",
     isShowComplete: true,
     careList: [],
     displayList: [] as {
@@ -245,6 +246,7 @@ Page({
     }>
   ) {
     const { careList, allExpanded } = this.data;
+    console.log(careList, "careList")
     let newDisplayList: any[] =
       allExpanded || careList.length <= 4 ? careList : careList.slice(0, 4);
 
@@ -267,6 +269,7 @@ Page({
     this.setData({
       displayList: newDisplayList,
     });
+    console.log(this.data.displayList, "this.data.displayList11111")
   },
   toggleAll() {
     this.setData(
@@ -293,6 +296,25 @@ Page({
       });
     }
   },
+  // 去预约
+  onAppointment(e: any) {
+    const id = e.currentTarget.dataset.id;
+    if (id) {
+      wx.navigateTo({
+        url: `/module/care/pages/offlineTreatment/offlineTreatment?id=${id}`,
+      });
+    }
+  },
+  // 长按复制机构名称
+  onCopyInstitutionName(e: any) {
+    const name = e.currentTarget.dataset.name;
+    if (name) {
+      wx.setClipboardData({
+        data: name,
+        success: () => wx.showToast({ title: "已复制", icon: "none" }),
+      });
+    }
+  },
   onClose() {
     this.setData({
       isShowPopup: false,
@@ -330,11 +352,14 @@ Page({
         this.setData({
           popupList: res,
           isShowPopup: true,
+          NoteTitle: res[0].title,
         });
+
       } else {
         this.setData({
           popupList: [],
           isShowPopup: false,
+          NoteTitle: "",
         });
       }
     });
@@ -389,8 +414,9 @@ Page({
           console.log(error);
         }
       } else {
+        const status = 'pending';
         // 随访
-        wx.redirectTo({ url: `${page}?id=${id}` });
+        wx.navigateTo({ url: `${page}?id=${id}&status=${status}` });
       }
     } finally {
       setTimeout(() => {
@@ -1012,6 +1038,7 @@ Page({
       this.setData({
         displayList: newDisplayList,
       });
+      console.log(this.data.displayList, "this.data.displayList")
     }
   },
 

+ 12 - 8
miniprogram/pages/home/home.wxml

@@ -17,7 +17,7 @@
       <view class="follow-box" bind:tap="showFollowPopup">
         <image src="../../assets/bg/icon_notice@3x.png" mode="heightFix" class="notice-icon" />
         <view class="pieces">{{popupList.length}}</view>
-        <view class="follow-text" wx:if="{{isShowPopup}}">{{popupList[0].title}}</view>
+        <view class="follow-text" wx:if="{{NoteTitle}}">{{NoteTitle}}</view>
       </view>
       <view class="tool-bar-wrapper">
         <view class="tool" wx:if="{{location.description}}">
@@ -92,7 +92,7 @@
               <view class="item-main" bindtap="toggleItem" data-index="{{index}}">
                 <text class="dot"></text>
                 <text class="item-title">{{item.conditioningProgramName}}</text>
-                <text class="item-next-time" wx:if="{{item.arrangeDate && item.isOffline==='Y'}}">下一次时间:{{item.arrangeDate}}</text>
+                <text class="item-next-time" wx:if="{{item.arrangeDate && item.sellType==='2'}}">下一次时间:{{item.arrangeDate}}{{item.applyTime?'(已预约)':''}}</text>
                 <t-icon name="{{item.expanded ? 'chevron-up' : 'chevron-down'}}" size="24rpx" class="item-arrow" color="#C0C4CC" />
               </view>
               <!-- 这里放详细内容 -->
@@ -105,21 +105,25 @@
                     <media-carousel mediaList="{{item.carouselMediaList}}" showIndicator="{{true}}" autoplay="{{true}}" interval="{{4000}}" circular="{{true}}" bind:fullscreenchange="onCarouselFullscreenChange" itemId="{{item.id}}" />
                   </view>
                   <view class="item-box">
-                    <view class="flex" wx:if="{{item.arrangeDate && item.isOffline==='Y'}}"><text>下一次时间:</text><text>{{item.arrangeDate}}</text></view>
+                    <view class="flex" wx:if="{{item.arrangeDate && item.sellType==='2'}}"><text>下一次时间:</text><text>{{item.arrangeDate}}</text></view>
                     <view class="flex">
-                      <text wx:if="{{item.isOffline==='Y'}}">已完成:<text style="color:#2ec4b6">{{item.finishCount}}次</text><text style="margin:0 5px">/</text>
+                      <text wx:if="{{item.sellType==='2'}}">已完成:<text style="color:#2ec4b6">{{item.finishCount}}次</text><text style="margin:0 5px">/</text>
                         <text>{{item.totalMeasure}}次</text></text>
 
                     </view>
-                    <view>频次:每{{item.frequencyType}}天{{item.frequencyMeasure}}{{item.convertUnit}}</view>
+                    <view>频次:每{{item.frequencyType}}天{{item.frequencyMeasure}}{{item.convertUnit?item.convertUnit:'次'}}</view>
                     <view>开具医生:{{item.operateBy}}</view>
-                    <view wx:if="{{item.isOffline==='Y'}}">机构:{{item.conditioningProgramSupplierName}}</view>
+                    <view wx:if="{{item.sellType==='2'}}" class="ins-box"><text>机构:</text><text class="copyable-text" catchlongpress="onCopyInstitutionName" data-name="{{item.conditioningProgramSupplierName}}">
+                    {{item.conditioningProgramSupplierName?item.conditioningProgramSupplierName:'-'}}</text></view>
                   </view>
                 </view>
-                <view data-id="{{item.id}}" wx:if="{{item.isOffline==='N'}}" class="verify-record" bindtap="isGoPunchcard" data-signinTime="{{item.signinTime}}">{{
+                <view data-id="{{item.id}}" wx:if="{{item.sellType!=='2'}}" class="verify-record" bindtap="isGoPunchcard" data-signinTime="{{item.signinTime}}">{{
                       item.signinTime?'已打卡':'打卡'
                     }}</view>
-                <view catchtap="onRecord" data-id="{{item.id}}" wx:if="{{item.isOffline==='Y'}}" class="verify-record">核销记录</view>
+                    <view class="right-btn">
+                <view catchtap="onRecord" data-id="{{item.id}}" wx:if="{{item.sellType==='2'}}" class="verify-record">预约/核销记录</view>
+                <view catchtap="{{item.applyTime?'':'onAppointment'}}" data-id="{{item.id}}" wx:if="{{item.sellType==='2'}}" class="{{item.applyTime?'':'verify-record'}}">{{item.applyTime?'':'预约'}}</view>
+                </view>
               </view>
             </view>
           </block>

+ 1 - 1
miniprogram/pages/home/vertical-steps/index.scss

@@ -3,7 +3,7 @@
   flex-direction: column;
   padding: 24rpx 0;
   // margin-left: 50rpx;
-  margin-top: 24rpx;
+  // margin-top: 24rpx;
 }
 .health-status-item {
   display: flex;

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

@@ -89,7 +89,7 @@ background-color: #F5F6F7;
 .order-container{
   background: #fff;
   border-radius: 16rpx;
-  padding: 20rpx 40rpx 20rpx 0rpx;
+  padding: 20rpx 0 20rpx 0rpx;
 }
 .knowledge-box{
   background: #fff;

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

@@ -33,10 +33,10 @@ Page({
       },
       {
         url: "../../assets/icon/delivery@3x.png",
-        name: "待收货",
+        name: "已付款",
         count: 0,
         type: 2,
-        tab: "received",
+        tab: "paid",
       },
       {
         url: "../../assets/icon/deal@3x.png",
@@ -45,11 +45,18 @@ Page({
         type: 3,
         tab: "completed",
       },
+      // {
+      //   url: "../../assets/icon/delivery@3x.png",
+      //   name: "交易关闭",
+      //   count: 0,
+      //   type: 4,
+      //   tab: "closed",
+      // },
       {
         url: "../../assets/icon/all@3x.png",
         name: "全部",
         count: 0,
-        type: 4,
+        type: 5,
         tab: "all",
       },
     ],
@@ -103,9 +110,10 @@ Page({
       if (res && res.data) {
         this.setData({
           "mineOrderList[0].count": res.data.pendingPayment,
-          "mineOrderList[1].count": res.data.pendingReceiptGoods,
-          // "mineOrderList[2].count": res.data.successTrade,
-          // "mineOrderList[3].count": res.data.total,
+          // "mineOrderList[1].count": res.data.pendingReceiptGoods,//已付款
+          // "mineOrderList[2].count": res.data.successTrade,//交易成功
+          // "mineOrderList[3].count": res.data.closeTrade,//交易关闭
+          // "mineOrderList[3].count": res.data.total,//全部
         });
       }
     } catch (error: any) {
@@ -215,6 +223,14 @@ Page({
   onShow() {
     // 如果需要每次显示页面时刷新数据,可以在这里调用 load
     this.load();
+    // 从支付成功页点「返回订单列表」时,自动打开订单列表,返回时回到本页
+    const fromSuccess = wx.getStorageSync("fromSuccessToOrderList");
+    if (fromSuccess) {
+      wx.removeStorageSync("fromSuccessToOrderList");
+      wx.navigateTo({
+        url: "/module/article/pages/order-list/order-list?tab=all",
+      });
+    }
   },
   // 足迹
   toFootPrintPage() {

+ 61 - 0
miniprogram/utils/util.ts

@@ -110,4 +110,65 @@ export function fromHealthReportSymptom(data: Partial<HealthReportDTO>, config =
     }
   }
   return result;
+}
+
+/**
+ * 唤起微信支付
+ * @param {Object} paymentParams - 支付参数对象
+ * @param {string} paymentParams.timeStamp - 时间戳
+ * @param {string} paymentParams.packageVal - 统一下单接口返回的 prepay_id 参数值,格式为 "prepay_id=xxx"(兼容 packageValue)
+ * @param {string} paymentParams.packageValue - 统一下单接口返回的 prepay_id 参数值,格式为 "prepay_id=xxx"(API返回的字段名)
+ * @param {string} paymentParams.paySign - 支付签名
+ * @param {string} paymentParams.nonceStr - 随机字符串
+ * @param {string} paymentParams.signType - 签名类型,默认为 'RSA'
+ * @param {string} paymentParams.appId - 小程序 appId(可选)
+ * @param {Function} onSuccess - 支付成功回调函数
+ * @param {Function} onFail - 支付失败回调函数
+ */
+export const handleWeChatPayment = (paymentParams: any, onSuccess: any, onFail: any = () => {}) => {
+  // 兼容 packageValue 和 packageVal 两种字段名
+  const packageVal = paymentParams.packageValue || paymentParams.packageVal
+ 
+  // 验证支付参数
+  if (!paymentParams || !paymentParams.timeStamp || !packageVal || !paymentParams.paySign) {
+    const error = new Error('支付参数不完整')
+    console.error('支付参数错误:', error)
+    if (onFail) {
+      onFail(error)
+    }
+    return
+  }
+
+  // wx.showLoading({
+  //   title: '正在调起支付...',
+  //   mask: true
+  // })
+
+  wx.requestPayment({
+    provider: 'wxpay',
+    timeStamp: String(paymentParams.timeStamp), // 确保是字符串类型
+    nonceStr: paymentParams.nonceStr,
+    package: packageVal, // 兼容 packageValue 和 packageVal
+    signType: paymentParams.signType || 'RSA',
+    paySign: paymentParams.paySign,
+    success: (res) => {
+      wx.hideLoading()
+      if (onSuccess) {
+        onSuccess(res)
+      }
+    },
+    fail: (err) => {
+      if (onFail) {
+        onFail(err)
+      }
+      if (err.errMsg === 'requestPayment:fail cancel') {
+        wx.showToast({
+          title: '支付已取消',
+          icon: 'none'
+        })
+      } else {
+        console.error('支付失败:', err)
+      }
+    }
+  })
 }