张田田 před 3 měsíci
rodič
revize
34a248e121

binární
miniprogram/module/article/assets/servicePag.png


+ 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;
+  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;
+}

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

@@ -0,0 +1,247 @@
+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: "306",
+    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) => {
+              // 合计的商品件数
+              totalGoodsCount += 1;
+              return {
+                id: item.id || '',
+                name: item.conditioningProgramName || '',
+                description: (() => {
+                  const dose = item?.convertDose ?? '';
+                  const unit = item?.convertUnit ?? '';
+                  return `${dose} ${unit}`;
+                })(),
+                image: item.conditioningProgramPhoto || '',
+                price: item.totalPrice || 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?.remark);
+      if (payResult) {
+        const paymentParams = payResult;
+        handleWeChatPayment(paymentParams, (res: any) => {
+          // 支付成功,跳转到成功页面
+          wx.redirectTo({
+            url: "/module/article/pages/success-page/success-page?title=订单支付成功",
+          });
+        }, (error: any) => {
+          console.error(error,'支付失败:===', error)
+          this.setData({ isPaymentLoading: false });
+          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.createTime || ''}}</text>
+      </view>
+    </view>
+
+    <!-- 服务包详情 -->
+    <view class="info-card">
+      <view class="info-item">
+        <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">
+        <text class="info-label">开具医生</text>
+        <text class="info-value">{{orderDetail.operateBy || ''}}</text>
+      </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">
+        <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"
+  }
+}

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

@@ -0,0 +1,641 @@
+@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;
+}
+.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;
+}
+
+.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: 24rpx 32rpx;
+  background: #fff;
+  border-radius: 0;
+  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: 8rpx;
+  gap: 12rpx;
+}
+
+.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: 24rpx;
+  font-weight: 400;
+  color: #ff9500;
+  flex-shrink: 0;
+  white-space: nowrap;
+}
+
+// 快递信息
+.express-info {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 20rpx 32rpx;
+
+  .express-text {
+    font-size: 28rpx;
+    color: #333;
+    // flex: 1;
+    padding: 10rpx;
+    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;
+  }
+}
+
+// 确认收货按钮
+.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;
+}
+// 选择地址的css
+.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;
+}

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

@@ -0,0 +1,381 @@
+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/select-goods.ts
+Page({
+  behaviors: [PageContainerBehavior, DictionariesBehavior],
+  data: {
+    title: "",
+    id: "306",
+    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 type = item?.conditioningProgramDetail?.pricingType;
+            return {
+              id: item.id || '',
+              name: item.conditioningProgramName || '',
+              description: (() => {
+                const convertDose = item?.conditioningProgramDetail?.cpFixedPricingRule?.convertDose
+                const dose =
+                  type === '0' ? convertDose : type === '1' ? 1 :
+                    '';
+                const unit = item?.conditioningProgramDetail?.cpFixedPricingRule?.convertUnit ?? '次';
+                return `${dose} ${unit}`;
+              })(),
+              sellType: item?.sellType || '', //商品类型
+              isOffline: item?.isOffline || '', //是否线下
+              //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: type === '0' ? item?.unitPrice : type === '1' ? item?.totalPrice : '',
+              quantity: item?.totalMeasure || 0,
+              statusClass: this.getStatusClass(item?.sellType, item?.progress, item?.receiptStatus),
+              statusText: this.getGoodsStatusText(item?.sellType, item?.progress, item?.receiptStatus),
+            }
+          });
+        };
+
+        // 分别处理三个数组
+        const sellTypeFirstItems = processItems(res.data?.sellTypeFirstItems || []);
+        const sellTypeSecondItems = processItems(res.data?.sellTypeSecondItems || []);
+        const sellTypeThirdItems = processItems(res.data?.sellTypeThirdItems || []);
+
+        this.setData({
+          sellTypeFirstItems,
+          sellTypeSecondItems,
+          sellTypeThirdItems,
+        });
+      }
+    } 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 && 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 });
+          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 "";
+  },
+
+  // 获取商品状态文本
+  // sellType: 商品类型 1-实体商品 2-线下服务 3-线上权益
+  // progress: 进度状态(用于线下服务和线上权益):0-进行中 1-已完成 2-未开始
+  // receiptStatus: 收货状态(用于实体商品):0-待发货 1-已发货 2-已收货
+  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": "/assets/icon/express/postal.png", // 邮政速递
+      "1": "/assets/icon/express/sf.png", // 顺丰速运
+      "2": "/assets/icon/express/jd.png", // 京东快递
+      "3": "/assets/icon/express/zto.png", // 中通快递
+      "4": "/assets/icon/express/yto.png", // 圆通速递
+      "5": "/assets/icon/express/sto.png", // 申通快递
+      "6": "/assets/icon/express/yd.png", // 韵达快递
+      "7": "/assets/icon/express/jitu.png", // 极兔速递
+    };
+    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 { id, index } = e.currentTarget.dataset;
+    wx.showModal({
+      title: '确认收货',
+      content: '确认已收到该商品?',
+      success: (res) => {
+        if (res.confirm) {
+          // TODO: 调用确认收货接口
+          wx.showToast({
+            title: '确认收货成功',
+            icon: 'success'
+          });
+          // 更新状态
+          const key = `sellTypeFirstItems[${index}].receiptStatus`;
+          this.setData({
+            [key]: '2',
+            [`sellTypeFirstItems[${index}].statusText`]: '已收货',
+            [`sellTypeFirstItems[${index}].statusClass`]: 'status-completed'
+          });
+        }
+      }
+    });
+  },
+
+});

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

@@ -0,0 +1,178 @@
+<!--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 class="goods-item-wrapper" wx:for="{{sellTypeFirstItems}}" wx:for-item="goods" wx:for-index="goodsIndex" wx:key="id">
+        <!-- 快递信息 -->
+        <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;">
+              快件{{goodsIndex + 1}}
+              <image class="express-icon" src="{{goods.expressTypeIcon}}" mode="aspectFit" wx:if="{{goods.expressTypeIcon}}"></image>
+            </view>
+            <view style="color:#9b9797">{{goods.expressTypeName}} {{goods.expressNo}}</view>
+          </view>
+          <text class="express-arrow">></text>
+        </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>
+              <view class="goods-status {{goods.statusClass}}" wx:if="{{goods.statusText && orderStatus !== 'closed'}}">{{goods.statusText}}</view>
+            </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-text">x{{goods.quantity}}</view>
+            </view>
+            <!-- 确认收货按钮 -->
+            <view class="confirm-receipt-btn" wx:if="{{goods.receiptStatus === '1'}}" bindtap="onConfirmReceipt" data-id="{{goods.id}}" data-index="{{goodsIndex}}">
+              确认收货
+            </view>
+          </view>
+        </view>
+      </view>
+    </view>
+
+
+
+    <!-- 线下服务商品 -->
+    <view class="goods-list" wx:if="{{sellTypeSecondItems.length > 0}}">
+      <view class="category-title">线下服务商品</view>
+      <view class="goods-item" wx:for="{{sellTypeSecondItems}}" 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">
+          <view class="goods-name-row">
+            <text class="goods-name">{{goods.name}}</text>
+            <view class="goods-status {{goods.statusClass}}" wx:if="{{goods.statusText && orderStatus !== 'closed'}}">{{goods.statusText}}</view>
+          </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-text">x{{goods.quantity}}</view>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- 线上权益商品 -->
+    <view class="goods-list" wx:if="{{sellTypeThirdItems.length > 0}}">
+      <view class="category-title">线上权益商品</view>
+      <view class="goods-item" wx:for="{{sellTypeThirdItems}}" 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">
+          <view class="goods-name-row">
+            <text class="goods-name">{{goods.name}}</text>
+            <view class="goods-status {{goods.statusClass}}" wx:if="{{goods.statusText && orderStatus !== 'closed'}}">{{goods.statusText}}</view>
+          </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-text">x{{goods.quantity}}</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">实付款:</text>
+      <text class="price-value payable-value">¥{{orderDetail.realAmount}}</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.createTime || ''}}</text>
+      </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-item" wx:if="{{orderStatus==='completed'}}">
+        <text class="info-label">成交时间</text>
+        <text class="info-value">{{orderDetail.finishTime || ''}}</text>
+      </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-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">
+        <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">
+        <text class="info-label">开具医生</text>
+        <text class="info-value">{{orderDetail.operateBy || ''}}</text>
+      </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">
+        <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"
+  }
+}

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

@@ -0,0 +1,274 @@
+@import '../../../../themes/t.cell.scss';
+@import '../../../../themes/page.scss';
+
+/* module/order/pages/select-goods/select-goods.wxss */
+.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;
+  // border-bottom: 1rpx solid #f0f0f0;
+}
+
+.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;
+}

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

@@ -0,0 +1,320 @@
+import DictionariesBehavior from "../../../../core/behavior/dictionaries.behavior";
+import PageContainerBehavior from "../../../../core/behavior/page-container.behavior";
+import tickleBehavior, {
+  getTickleContext,
+} from "../../../../core/behavior/tickle.behavior";
+
+// module/order/pages/select-goods/select-goods.ts
+Component({
+  behaviors: [PageContainerBehavior, DictionariesBehavior, tickleBehavior],
+  lifetimes: {
+    attached() {
+      // 初始化商品数据(示例数据,实际应从接口获取)
+      this.initGoodsData();
+    },
+  },
+  properties: {
+    schemeId: { type: String, value: "" },
+  },
+  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: {
+    // 初始化商品数据
+    initGoodsData() {
+      // 示例数据,实际应从接口获取
+      const goodsList = [
+        {
+          category: "穴位贴敷",
+          goods: [
+            {
+              id: "1",
+              name: "肝血虚穴位贴",
+              description: "20贴",
+              image: "/assets/icon/icon_file@3x.png",
+              price: 100,
+              quantity: 1,
+              checked: true,
+            }
+          ]
+        },
+        {
+          category: "运动",
+          goods: [
+            {
+              id: "2",
+              name: "五禽戏",
+              image: "/assets/icon/icon_file@3x.png",
+              price: 0,
+              quantity: 1,
+              checked: true,
+              badge: "1",
+            },
+            {
+              id: "3",
+              name: "颈椎操",
+              image: "/assets/icon/icon_file@3x.png",
+              price: 0,
+              quantity: 1,
+              checked: true,
+            }
+          ]
+        },
+        {
+          category: "茶饮",
+          goods: [
+            {
+              id: "4",
+              name: "元气茶",
+              description: "30包",
+              image: "/assets/icon/icon_file@3x.png",
+              price: 80,
+              quantity: 1,
+              checked: true,
+            },
+            {
+              id: "5",
+              name: "芡实米仁燕麦粥",
+              description: "21袋",
+              image: "/assets/icon/icon_file@3x.png",
+              price: 1.5,
+              quantity: 1,
+              checked: true,
+            }
+          ]
+        }
+      ];
+      
+      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 (checked && goods.price === 0 && goods.quantity !== 1) {
+        goods.quantity = 1;
+      }
+      
+      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,
+          quantity: 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) {
+        if (type === "plus") {
+          // 已经是1,不能再加
+          return;
+        } else if (type === "minus") {
+          // 减到0时自动取消勾选,但不能小于1(如果已勾选)
+          if (goods.quantity === 1) {
+            goods.quantity = 0;
+            goods.checked = false;
+          } else {
+            goods.quantity = 1; // 确保始终为1
+          }
+        }
+      } 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 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;
+        } else {
+          goods.quantity = value;
+        }
+      } 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 < 1 && goods.checked) {
+          // 如果已勾选但数量小于1,设置为1
+          goods.quantity = 1;
+        } else if (goods.quantity === 0) {
+          // 数量为0,取消勾选
+          goods.checked = false;
+        }
+      } 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: any[] = [];
+      
+      // 收集选中的商品
+      goodsList.forEach((category: any) => {
+        category.goods.forEach((goods: any) => {
+          if (goods.checked && goods.quantity > 0) {
+            selectedGoods.push({
+              ...goods,
+              category: category.category
+            });
+          }
+        });
+      });
+      
+      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/confirm-order/confirm-order`,
+        fail: (err) => {
+          // 如果确认订单页面不存在,提示用户
+          getTickleContext.call(this).showWarnMessage("确认订单页面不存在,请先创建该页面");
+        }
+      });
+    },
+    
+    // 隐私相关方法
+    onPrivacySetting() {},
+    onAgree() {},
+    onDisagree() {},
+  },
+});

+ 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="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 wx:if="{{goods.price !== 0}}" 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>
+          <!-- 单价为0时直接显示X1 -->
+          <view wx:else class="quantity-text">x1</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>

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

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