张田田 3 тижнів тому
батько
коміт
a606b7ad12

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

@@ -157,58 +157,10 @@
 .order-actions {
   display: flex;
   gap: 20rpx;
-  transition: none !important;
 }
 
 .order-actions .t-button {
   margin: 0 !important;
-  min-width: 120rpx !important;
-  width: 120rpx !important;
-}
-
-// 为立即支付按钮设置固定宽度,防止loading状态时宽度变化
-.order-actions .t-button[data-id] {
-  min-width: 120rpx !important;
-  width: 120rpx !important;
-}
-
-// 节流状态下的按钮样式
-.order-actions .t-button[disabled] {
-  opacity: 1 !important;
-  cursor: not-allowed !important;
-  background-color: #f5f5f5 !important;
-  border-color: #e5e5e5 !important;
-  color: #c0c0c0 !important;
-}
-
-// 针对 t-design 按钮的自定义样式
-.outline-btn {
-  background: #fff !important;
-  border: 1px solid #1890ff !important; // 主色边框
-  color: #1890ff !important; // 主色文字
-  box-shadow: none !important;
-  border-radius: 30rpx !important;
-  transition: none !important;
-  // margin-right: 20rpx !important;
-}
-
-// 让按钮内的 loading 和文字显式为品牌蓝
-.outline-btn .t-loading__spinner,
-.outline-btn .t-loading__text {
-  color: #1890ff !important;
-}
-.outline-btn .t-loading__spinner .t-loading__dot::before,
-.outline-btn .t-loading__spinner--dots .t-loading__dot,
-.outline-btn .t-loading__circular {
-  color: #1890ff !important;
-  background-color: #1890ff !important;
-}
-
-.outline-btn.cancel {
-  border-color: #ccc !important;
-  color: black !important;
-  margin-right: 20rpx;
-  transition: none !important;
 }
 
 .contact {

+ 3 - 3
miniprogram/module/article/pages/order-list/order-list.wxml

@@ -85,12 +85,12 @@
       <view class="order-footer">
         <view class="order-price">订单金额:<text class="order-amount">¥{{item.cost}}</text></view>
 
-        <view class="order-actions">
+        <view class="order-actions" style="--td-button-border-radius:30rpx;">
           <!-- 按状态显示不同按钮 -->
-          <t-button wx:if="{{item.orderStatus==='0'}}" size="small" type="default" class="outline-btn cancel" bindtap="onCancel" data-id="{{item.id}}" disabled="{{throttleTimers.cancel}}">
+          <t-button wx:if="{{item.orderStatus==='0'}}" size="small" type="default" class="outline-btn cancel" bindtap="onCancel" data-id="{{item.id}}" disabled="{{throttleTimers.cancel}}" style="--td-button-default-color:#000;--td-button-default-bg-color:#fff;--td-button-default-border-color:#ccc;" hover-class="none">
             取消订单
           </t-button>
-          <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 wx:if="{{item.orderStatus==='0'}}" size="small" type="primary" bindtap="onPay" class="outline-btn" data-id="{{item.id}}" disabled="{{(payingId===item.id) || throttleTimers.pay}}" style="--td-button-primary-color:#fff;--td-button-primary-bg-color:#1890ff;--td-button-primary-border-color:#1890ff;" hover-class="none">
             立即支付
           </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}}">

+ 8 - 2
miniprogram/module/order/components/after-sale-type-popup/after-sale-type-popup.scss

@@ -53,6 +53,12 @@
   color: #222;
 }
 
+.after-sale-type-btn-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 20rpx;
+}
+
 .after-sale-type-btn {
   border-radius: 10rpx;
   border: 2rpx solid #d7d7d7;
@@ -63,7 +69,7 @@
   font-size: 26rpx;
   color: #3a3a3a;
   background: #fff;
-  width: 240rpx;
+  padding: 0 36rpx;
   box-sizing: border-box;
 }
 
@@ -92,7 +98,7 @@
 
 .after-sale-type-card__left {
   flex-shrink: 0;
-  margin-right: 20rpx;
+  // margin-right: 20rpx;
 }
 
 .after-sale-type-card__icon {

+ 35 - 7
miniprogram/module/order/components/after-sale-type-popup/after-sale-type-popup.ts

@@ -1,27 +1,55 @@
+import { Get } from "../../../../lib/request/method";
 Component({
+  behaviors: [],
   properties: {
     visible: { type: Boolean, value: false },
     siteOption: {
       type: Object,
       value: {
-        name: "肝血虚穴位站点",
-        price: 80,
-        meta1: "10贴",
-        meta2: "3",
+        name: "",
+        price: 0,
+        meta1: "",
+        meta2: "",
       },
     },
   },
   data: {
-    selectedKey: "refund",
+    selectedKey: "",
+    afterSaleTypes: [] as Array<{ label: string; value: string }>,
   },
   observers: {
     visible(v: boolean) {
-      if (v) {
-        this.setData({ selectedKey: "refund" });
+      if (v && this.data.afterSaleTypes.length > 0) {
+        this.setData({ selectedKey: this.data.afterSaleTypes[0].value });
       }
     },
   },
+  lifetimes: {
+    attached() {
+      this.fetchAfterSaleTypes();
+    },
+  },
   methods: {
+    async fetchAfterSaleTypes() {
+      try {
+        const res = await Get<any[]>("/dict/getDicts");
+        const afterSaleDict = (res as any)?.data?.find(
+          (item: any) => item.dictType === "aftersale_type"
+        );
+        if (afterSaleDict?.items?.length) {
+          const types = afterSaleDict.items.map((item: any) => ({
+            label: item.dictLabel,
+            value: item.dictValue,
+          }));
+          this.setData({
+            afterSaleTypes: types,
+            selectedKey: types[0].value,
+          });
+        }
+      } catch {
+        wx.showToast({ title: "获取售后类型失败", icon: "none" });
+      }
+    },
     onPopupVisibleChange(e: WechatMiniprogram.CustomEvent<{ visible: boolean }>) {
       if (!e?.detail?.visible) {
         this.triggerEvent("close");

+ 10 - 5
miniprogram/module/order/components/after-sale-type-popup/after-sale-type-popup.wxml

@@ -15,11 +15,16 @@
     <view class="after-sale-popup__content">
       <view class="after-sale-popup__label">请选择售后类型:</view>
 
-      <view
-        class="after-sale-type-btn after-sale-type-btn--active"
-        data-type="refund"
-      >
-        仅退款
+      <view class="after-sale-type-btn-list">
+        <view
+          wx:for="{{afterSaleTypes}}"
+          wx:key="value"
+          class="after-sale-type-btn {{selectedKey === item.value ? 'after-sale-type-btn--active' : ''}}"
+          data-type="{{item.value}}"
+          bindtap="onSelectType"
+        >
+          {{item.label}}
+        </view>
       </view>
 
       <view

+ 61 - 11
miniprogram/module/order/components/refund-confirm-popup/refund-confirm-popup.ts

@@ -1,3 +1,4 @@
+import { Get } from "../../../../lib/request/method";
 Component({
   properties: {
     visible: { type: Boolean, value: false },
@@ -7,30 +8,80 @@ Component({
     goodsMeta1: { type: String, value: "" },
     goodsMeta2: { type: String, value: "" },
     refundReason: { type: String, value: "" },
-    refundStatus: { type: String, value: "received" },
+    refundStatus: { type: String, value: "" },
     refundAmount: { type: Number, value: 0 },
     maxAmount: { type: Number, value: 0 },
     proofImages: { type: Array, value: [] },
+    showReceiptStatus: { type: Boolean, value: true },
   },
   data: {
     statusPickerVisible: false,
-    statusPickerOptions: [
-      { label: "已收到货", value: "received" },
-      { label: "未收到货", value: "not-received" },
-    ],
-    statusPickerValue: ["received"],
+    statusPickerOptions: [] as Array<{ label: string; value: string }>,
+    statusPickerValue: [] as string[],
+    statusLabel: "",
     // 退款金额编辑器(整屏弹窗)
     amountEditorVisible: false,
     amountInput: "",
   },
   observers: {
     refundStatus(v: string) {
-      (this as any).setData({
-        statusPickerValue: [v === "not-received" ? "not-received" : "received"],
-      });
+      const options = (this as any).data?.statusPickerOptions || [];
+      const matched = options.find((item: any) => item.value === v);
+      if (matched) {
+        (this as any).setData({
+          statusPickerValue: [v],
+          statusLabel: matched.label,
+        });
+      }
+    },
+    visible(v: boolean) {
+      if (v && (this as any).data?.statusPickerOptions?.length) {
+        const currentValue = (this as any).data?.statusPickerValue?.[0];
+        if (currentValue) {
+          (this as any).triggerEvent("changeStatus", { status: currentValue });
+        }
+      }
+    },
+  },
+  lifetimes: {
+    attached() {
+      (this as any).fetchStatusOptions();
     },
   },
   methods: {
+    getStatusLabel(value: string): string {
+      const options = (this as any).data?.statusPickerOptions || [];
+      return options.find((item: any) => item.value === value)?.label || "";
+    },
+    async fetchStatusOptions() {
+      try {
+        const res = await Get<any[]>("/dict/getDicts");
+        const dict = (res as any)?.data?.find(
+          (item: any) => item.dictType === "aftersale_receipt_status"
+        );
+        if (dict?.items?.length) {
+          const options = dict.items.map((item: any) => ({
+            label: item.dictLabel,
+            value: item.dictValue,
+          }));
+          // 默认选中最后一个(未收到货)
+          const lastOption = options[options.length - 1];
+          const current = (this as any).data?.refundStatus;
+          const matched = options.find((item: any) => item.value === current);
+          const value = matched ? current : lastOption.value;
+          const label = matched ? matched.label : lastOption.label;
+          (this as any).setData({
+            statusPickerOptions: options,
+            statusPickerValue: [value],
+            statusLabel: label,
+          });
+          // 回传默认值给父页面
+          (this as any).triggerEvent("changeStatus", { status: value });
+        }
+      } catch {
+        wx.showToast({ title: "获取商品状态失败", icon: "none" });
+      }
+    },
     onPopupVisibleChange(e: WechatMiniprogram.CustomEvent<{ visible: boolean }>) {
       if (!e?.detail?.visible) {
         (this as any).triggerEvent("close");
@@ -49,8 +100,7 @@ Component({
     },
     onStatusPickerChange(e: any) {
       const valueArr = e?.detail?.value as Array<string | number> | undefined;
-      const value0 = valueArr?.[0];
-      const status = value0 === "not-received" ? "not-received" : "received";
+      const status = String(valueArr?.[0] ?? "");
       (this as any).triggerEvent("changeStatus", { status });
       (this as any).setData({ statusPickerVisible: false });
     },

+ 2 - 2
miniprogram/module/order/components/refund-confirm-popup/refund-confirm-popup.wxml

@@ -26,10 +26,10 @@
         </view>
       </view>
 
-      <view class="form-row">
+      <view class="form-row" wx:if="{{showReceiptStatus}}">
         <text class="label">商品状态</text>
         <view class="value select" bindtap="onOpenStatusPicker">
-          {{refundStatus === 'received' ? '已收到货' : '未收到货'}}
+          {{statusLabel}}
           <t-icon name="chevron-right" class="arrow-icon" size="30rpx" color="#b0b0b0" />
         </view>
       </view>

+ 25 - 10
miniprogram/module/order/components/refund-reason-popup/refund-reason-popup.ts

@@ -1,3 +1,4 @@
+import { Get } from "../../../../lib/request/method";
 Component({
   properties: {
     visible: { type: Boolean, value: false },
@@ -5,16 +6,7 @@ Component({
   },
   data: {
     selectedReason: "",
-    reasons: [
-      "商品信息描述不符",
-      "与商家协商一致退款",
-      "质量问题",
-      "少件(含缺少配件)",
-      "包装/商品破损/污渍",
-      "未按约定时间发货",
-      "发票问题",
-      "卖家发错货",
-    ],
+    reasons: [] as Array<{ label: string; value: string }>,
   },
   observers: {
     visible(v: boolean) {
@@ -23,7 +15,30 @@ Component({
       }
     },
   },
+  lifetimes: {
+    attached() {
+      this.fetchReasons();
+    },
+  },
   methods: {
+    async fetchReasons() {
+      try {
+        const res = await Get<any[]>("/dict/getDicts");
+        const dict = (res as any)?.data?.find(
+          (item: any) => item.dictType === "aftersale_reason"
+        );
+        if (dict?.items?.length) {
+          this.setData({
+            reasons: dict.items.map((item: any) => ({
+              label: item.dictLabel,
+              value: item.dictValue,
+            })),
+          });
+        }
+      } catch {
+        wx.showToast({ title: "获取退款原因失败", icon: "none" });
+      }
+    },
     onPopupVisibleChange(e: WechatMiniprogram.CustomEvent<{ visible: boolean }>) {
       if (!e?.detail?.visible) {
         this.triggerEvent("close");

+ 3 - 3
miniprogram/module/order/components/refund-reason-popup/refund-reason-popup.wxml

@@ -18,9 +18,9 @@
       <t-radio-group value="{{selectedReason}}" bind:change="onSelectReason">
         <t-radio
           wx:for="{{reasons}}"
-          wx:key="index"
-          value="{{item}}"
-          label="{{item}}"
+          wx:key="value"
+          value="{{item.value}}"
+          label="{{item.label}}"
           placement="right"
           icon="circle"
           class="custom-radio"

+ 50 - 54
miniprogram/module/order/pages/negotiation-history/negotiation-history.ts

@@ -1,62 +1,58 @@
+import { getAfterSaleNegotiationHistoryMethod } from "../../request";
+
 Page({
   data: {
-    historyList: [
-      {
-        type: 'platform',
-        avatar: 'https://tdesign.gtimg.com/mobile/demos/avatar1.png',
-        name: '平台',
-        time: '2025-02-19 14:30:35',
-        lines: [
-          '【标题】退款成功',
-          '【内容】退款金额 ¥240.00 已原路退回您的账户。'
-        ]
-      },
-      {
-        type: 'platform',
-        avatar: 'https://tdesign.gtimg.com/mobile/demos/avatar1.png',
-        name: '平台',
-        time: '2025-02-19 14:30:35',
-        lines: [
-          '【标题】平台已经同意了申请',
-          '【内容】请耐心等待财务确认打款,退款将原路退回您的账户中。'
-        ]
-      },
-      {
-        type: 'user',
-        avatar: 'https://tdesign.gtimg.com/mobile/demos/avatar2.png',
-        name: '谢芳',
-        time: '2025-02-19 14:30:27',
-        actionTitle: '发起了退款申请',
-        details: [
-          { label: '商品状态', value: '已收到货' },
-          { label: '退款金额', value: '¥240.00' },
-          { label: '退款原因', value: '与卖家协商一致' },
-          { label: '退款说明', value: 'uudksjj' }
-        ],
-        images: [
-          'https://ts1.tc.mm.bing.net/th/id/OIP-C.Dt8zun07_LEEoSPMONuoogHaLH?w=193&h=290&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
-          'https://ts1.tc.mm.bing.net/th/id/OIP-C.Dt8zun07_LEEoSPMONuoogHaLH?w=193&h=290&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
-          'https://ts1.tc.mm.bing.net/th/id/OIP-C.cnR8hVXoKhGmqMTDVwe1FgHaLH?w=193&h=290&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
-          'https://ts1.tc.mm.bing.net/th/id/OIP-C.Dt8zun07_LEEoSPMONuoogHaLH?w=193&h=290&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
-          'https://ts1.tc.mm.bing.net/th/id/OIP-C.Dt8zun07_LEEoSPMONuoogHaLH?w=193&h=290&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
-          'https://ts1.tc.mm.bing.net/th/id/OIP-C.Dt8zun07_LEEoSPMONuoogHaLH?w=193&h=290&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2',
+    historyList: [] as Array<any>,
+  },
 
-        ]
-      },
-      {
-        type: 'platform',
-        avatar: 'https://tdesign.gtimg.com/mobile/demos/avatar1.png',
-        name: '平台',
-        time: '2025-02-19 14:30:35',
-        lines: [
-          '【标题】平台拒绝了申请'
-        ]
-      }
-    ]
+  onLoad(options: any) {
+    if (options.id) {
+      this.loadHistory(options.id);
+    }
   },
 
-  onLoad() {
-    // 实际项目中会在这里请求接口拿到由于协商历史列表
+  async loadHistory(id: string) {
+    wx.showLoading({ title: '加载中' });
+    try {
+      const res = await getAfterSaleNegotiationHistoryMethod(Number(id));
+      const list = (res as any)?.data || [];
+      const historyList = list.map((item: any) => {
+        if (item.progress === '0') {
+          // 发起售后 - 用户操作
+          const content = item.aftersaleContent || {};
+          const details: Array<{ label: string; value: string }> = [];
+          if (content.receiptStatusStr) details.push({ label: '商品状态', value: content.receiptStatusStr });
+          if (content.applyAmount) details.push({ label: '退款金额', value: `¥${content.applyAmount}` });
+          if (content.reason) details.push({ label: '退款原因', value: content.reason });
+          if (content.remark) details.push({ label: '退款说明', value: content.remark });
+          return {
+            type: 'user',
+            avatar: '',
+            name: item.createBy || '用户',
+            time: item.createTime || '',
+            actionTitle: '发起了退款申请',
+            details,
+            images: content.voucherImgs || [],
+          };
+        } else {
+          // 平台操作
+          const lines: string[] = [];
+          if (item.title) lines.push(`【标题】${item.title}`);
+          if (item.content) lines.push(`【内容】${item.content}`);
+          return {
+            type: 'platform',
+            avatar: '',
+            name: '平台',
+            time: item.createTime || '',
+            lines,
+          };
+        }
+      });
+      this.setData({ historyList });
+    } catch (error: any) {
+      wx.showToast({ title: error.errMsg || '获取协商历史失败', icon: 'none' });
+    }
+    wx.hideLoading();
   },
 
   previewImage(e: any) {

+ 8 - 6
miniprogram/module/order/pages/other-detail/other-detail.scss

@@ -277,13 +277,15 @@
   text-align: center;
   background-color: #e8e8e8;
   color: #666;
+}
 
-  &.disabled-btn {
-    background-color: transparent;
-    color: #fa5151;
-    font-weight: 600;
-    padding: 12rpx 10rpx;
-  }
+.btn-aftersale-status {
+  padding: 12rpx 10rpx;
+  border-radius: 12rpx;
+  font-size: 26rpx;
+  text-align: center;
+  color: #fa5151;
+  font-weight: 600;
 }
 
 .btn-review {

+ 46 - 21
miniprogram/module/order/pages/other-detail/other-detail.ts

@@ -4,7 +4,7 @@ import { handleWeChatPayment } from "../../../../utils/util";
 import {
   getTickleContext,
 } from "../../../../core/behavior/tickle.behavior";
-import { getOrderDetailMethod, orderPayMethod } from "../../request";
+import { getOrderDetailMethod, orderPayMethod, applyAfterSaleMethod } from "../../request";
 // module/order/pages/select-goods/other-detail.ts
 Page({
   behaviors: [PageContainerBehavior, DictionariesBehavior],
@@ -45,7 +45,7 @@ Page({
     refundSubmitSuccessPopupVisible: false,
     selectedAfterSaleType: "",
     selectedRefundReason: "",
-    refundStatus: "received", // received | not-received
+    refundStatus: "",
     refundMaxAmount: 0,
     refundAmount: 0,
     refundDesc: "",
@@ -55,6 +55,10 @@ Page({
       price: 0,
       meta1: "",
       meta2: "",
+      image: "",
+      patientConditioningProgramId: "",
+      patientConditioningRecordId: "",
+      sellType: "",
     },
   },
   onLoad(options: any) {
@@ -188,8 +192,9 @@ Page({
               statusText: this.getGoodsStatusText(item?.sellType, item?.progress, item?.receiptStatus, item.expressStatus),
               isCanEvaluate: item?.isCanEvaluate, //是否可以评价 false-否 true-是
               evaluateTime: item?.evaluateTime, //有评价时间就是已评价,是空就是未评价
-              // [测试数据] 实体商品模拟”退款申请中”,线下服务和线上权益模拟”申请售后”
-              afterSaleStatus: item?.sellType === '1' ? 1 : 0,
+              isShowAftersaleButton: item?.isShowAftersaleButton || false,
+              aftersaleProgressStr: item?.aftersaleProgressStr || '',
+              aftersaleProgress: item?.aftersaleProgress,
             }
           });
         };
@@ -295,13 +300,7 @@ Page({
     // 仅用于 catchtap 阻止冒泡,避免触发父级 goAppointment
   },
   onApplyAfterSale(e: any) {
-    const { status, goods } = e.currentTarget.dataset;
-    if (status === 1) {
-      wx.navigateTo({
-        url: "/module/order/pages/refund-processing/refund-processing"
-      });
-      return;
-    }
+    const { goods } = e.currentTarget.dataset;
     this.setData({
       afterSaleSiteOption: {
         image: goods.image || '',
@@ -309,12 +308,22 @@ Page({
         price: goods.price,
         meta1: goods.description || '',
         meta2: `x${goods.quantity}`,
+        patientConditioningProgramId: goods.id || '',
+        patientConditioningRecordId: goods.patientConditioningRecordId || '',
+        sellType: goods.sellType || '',
       },
       refundMaxAmount: goods.price || 0,
       refundAmount: goods.price || 0,
       afterSalePopupVisible: true,
     });
+  },
 
+  // 点击退款状态,跳转到售后详情页
+  onAftersaleProgress(e: any) {
+    const { goods } = e.currentTarget.dataset;
+    wx.navigateTo({
+      url: `/module/order/pages/refund-processing/refund-processing?id=${goods.id}`,
+    });
   },
 
   onAfterSalePopupClose() {
@@ -348,7 +357,6 @@ Page({
       selectedRefundReason: reason,
       refundReasonPopupVisible: false,
       refundConfirmPopupVisible: true,
-      refundStatus: "received",
       refundAmount: this.data.refundMaxAmount,
     });
   },
@@ -357,8 +365,8 @@ Page({
     this.setData({ refundConfirmPopupVisible: false });
   },
 
-  onChangeRefundStatus(e: WechatMiniprogram.CustomEvent<{ status: "received" | "not-received" }>) {
-    this.setData({ refundStatus: e.detail?.status || "received" });
+  onChangeRefundStatus(e: WechatMiniprogram.CustomEvent<{ status: string }>) {
+    this.setData({ refundStatus: e.detail?.status || "" });
   },
 
   onOpenRefundReasonAgain() {
@@ -386,7 +394,7 @@ Page({
     });
   },
 
-  onSubmitRefundApply() {
+  async onSubmitRefundApply() {
     if (!this.data.selectedRefundReason) {
       wx.showToast({ title: "请选择退款原因", icon: "none" });
       return;
@@ -395,12 +403,29 @@ Page({
       wx.showToast({ title: "请上传凭证图片", icon: "none" });
       return;
     }
-    this.setData({
-      refundConfirmPopupVisible: false,
-    });
-    wx.navigateTo({
-      url: "/module/order/pages/refund-success/refund-success",
-    });
+    wx.showLoading({ title: "提交中" });
+    const { afterSaleSiteOption, selectedAfterSaleType, refundStatus, selectedRefundReason, refundAmount, refundProofImages, refundDesc } = this.data;
+    const params = {
+      patientConditioningRecordId: (afterSaleSiteOption as any).patientConditioningRecordId,
+      patientConditioningProgramId: (afterSaleSiteOption as any).patientConditioningProgramId,
+      type: selectedAfterSaleType,
+      receiptStatus: (afterSaleSiteOption as any).sellType === '1' ? refundStatus : '',
+      reason: selectedRefundReason,
+      applyAmount: refundAmount,
+      voucherImgs: refundProofImages,
+      remark: refundDesc,
+    };
+    console.log(params, "参数111")
+    try {
+      await applyAfterSaleMethod(params);
+      this.setData({ refundConfirmPopupVisible: false });
+      wx.navigateTo({
+        url: "/module/order/pages/refund-success/refund-success",
+      });
+    } catch (error: any) {
+      wx.showToast({ title: error.errMsg || "提交失败", icon: "none" });
+    }
+    wx.hideLoading();
   },
   onReview(e: WechatMiniprogram.TouchEvent) {
     console.log(e.currentTarget.dataset);

+ 10 - 12
miniprogram/module/order/pages/other-detail/other-detail.wxml

@@ -43,11 +43,10 @@
               <view class="confirm-receipt-btn" wx:if="{{goods.receiptStatus === '1'}}" bindtap="onConfirmReceipt" data-patientConditioningRecordId="{{goods.patientConditioningRecordId}}" data-index="{{goodsIndex}}">
                 确认收货
               </view>
-              <!-- 申请售后 + 评价 -->
+              <!-- 申请售后 + 退款状态 + 评价 -->
               <view class="action-btns">
-                <view class="btn-aftersale {{goods.afterSaleStatus === 1 ? 'disabled-btn' : ''}}" catchtap="onApplyAfterSale" data-status="{{goods.afterSaleStatus}}" data-goods="{{goods}}">
-                  {{goods.afterSaleStatus === 1 ? '退款申请中' : '申请售后'}}
-                </view>
+                <view class="btn-aftersale" wx:if="{{goods.isShowAftersaleButton}}" catchtap="onApplyAfterSale" data-goods="{{goods}}">申请售后</view>
+                <view class="btn-aftersale-status" wx:elif="{{goods.aftersaleProgressStr}}" catchtap="onAftersaleProgress" data-goods="{{goods}}">{{goods.aftersaleProgressStr}}</view>
                 <view class="btn-review" catchtap="onReview" data-goods="{{goods}}" wx:if="{{goods.isCanEvaluate}}">{{goods.evaluateTime?"已评价":"评价"}}</view>
               </view>
             </view>
@@ -76,11 +75,10 @@
                 <view class="goods-desc" wx:if="{{goods.description}}">{{goods.description}}</view>
                 <view class="quantity-text">x{{goods.quantity}}</view>
               </view>
-              <!-- 申请售后 + 评价 -->
+              <!-- 申请售后 + 退款状态 + 评价 -->
               <view class="action-btns" catchtap="preventTap">
-                <view class="btn-aftersale {{goods.afterSaleStatus === 1 ? 'disabled-btn' : ''}}" catchtap="onApplyAfterSale" data-status="{{goods.afterSaleStatus}}" data-goods="{{goods}}">
-                  {{goods.afterSaleStatus === 1 ? '退款申请中' : '申请售后'}}
-                </view>
+                <view class="btn-aftersale" wx:if="{{goods.isShowAftersaleButton}}" catchtap="onApplyAfterSale" data-goods="{{goods}}">申请售后</view>
+                <view class="btn-aftersale-status" wx:elif="{{goods.aftersaleProgressStr}}" catchtap="onAftersaleProgress" data-goods="{{goods}}">{{goods.aftersaleProgressStr}}</view>
                 <view class="btn-review" catchtap="onReview" data-goods="{{goods}}" wx:if="{{goods.isCanEvaluate}}">{{goods.evaluateTime?"已评价":"评价"}}</view>
               </view>
             </view>
@@ -109,11 +107,10 @@
                 <view class="goods-desc" wx:if="{{goods.description}}">{{goods.description}}</view>
                 <view class="quantity-text">x{{goods.quantity}}</view>
               </view>
-              <!-- 申请售后 + 评价 -->
+              <!-- 申请售后 + 退款状态 + 评价 -->
               <view class="action-btns">
-                <view class="btn-aftersale {{goods.afterSaleStatus === 1 ? 'disabled-btn' : ''}}" catchtap="onApplyAfterSale" data-status="{{goods.afterSaleStatus}}" data-goods="{{goods}}">
-                  {{goods.afterSaleStatus === 1 ? '退款申请中' : '申请售后'}}
-                </view>
+                <view class="btn-aftersale" wx:if="{{goods.isShowAftersaleButton}}" catchtap="onApplyAfterSale" data-goods="{{goods}}">申请售后</view>
+                <view class="btn-aftersale-status" wx:elif="{{goods.aftersaleProgressStr}}" catchtap="onAftersaleProgress" data-goods="{{goods}}">{{goods.aftersaleProgressStr}}</view>
                 <view class="btn-review" catchtap="onReview" data-goods="{{goods}}" wx:if="{{goods.isCanEvaluate}}">{{goods.evaluateTime?"已评价":"评价"}}</view>
               </view>
             </view>
@@ -241,6 +238,7 @@
   refund-amount="{{refundAmount}}"
   max-amount="{{refundMaxAmount}}"
   proof-images="{{refundProofImages}}"
+  show-receipt-status="{{afterSaleSiteOption.sellType === '1'}}"
   bind:close="onRefundConfirmClose"
   bind:changeStatus="onChangeRefundStatus"
   bind:editReason="onOpenRefundReasonAgain"

+ 120 - 48
miniprogram/module/order/pages/refund-processing/refund-processing.ts

@@ -1,46 +1,112 @@
+import { getAfterSaleDetailMethod, cancelAfterSaleMethod, updateAfterSaleMethod } from "../../request";
+
+// progress 数字转页面状态
+const progressToState: Record<string, string> = {
+  '0': 'processing',
+  '1': 'revoked',
+  '2': 'rejected',
+  '3': 'approved',
+  '4': 'completed',
+};
+
 Page({
   data: {
+    id: '',
+    aftersaleId: '',
     pageTitle: '商家处理',
-    refundState: 'processing', // 测试数据:processing, approved, revoked, rejected, 或 completed
-    days: '06',
-    hours: '23',
-    minutes: '43',
-    seconds: '59',
+    refundState: '',
+    days: '00',
+    hours: '00',
+    minutes: '00',
+    seconds: '00',
     goods: {
-      name: "肝血贴穴位贴",
-      meta1: "10贴",
-      price: "240",
-      image: ""
+      name: "",
+      meta1: "",
+      price: "",
+      image: "",
     },
     refundDetail: {
-      reason: "少件(含缺少配件)",
-      amount: "240.00",
-      finishTime: "2025-02-19 20:30:27",
-      applyTime: "2025-02-19 14:30:27",
-      refundNo: "7364647828273462271"
+      reason: "",
+      amount: "",
+      finishTime: "",
+      applyTime: "",
+      refundNo: "",
     },
+    // 协商历史标题和内容
+    negotiateTitle: "",
+    negotiateContent: "",
+    // 拒绝状态处理截止时间
+    handleEndTime: "",
     refundDestination: {
       type: '退回微信',
-      account: '梅*** 158******26'
+      account: '',
     },
     // 弹窗状态
     refundReasonPopupVisible: false,
     refundConfirmPopupVisible: false,
     refundProofPopupVisible: false,
-    refundStatus: 'received',
-    refundMaxAmount: '240',
-    refundProofImages: [],
+    refundStatus: '',
+    refundMaxAmount: '0',
+    refundProofImages: [] as string[],
   },
 
   timer: null as any,
 
-  onLoad() {
-    this.updatePageTitle();
-    if (this.data.refundState === 'processing' || this.data.refundState === 'rejected') {
-      this.startCountdown();
+  onLoad(options: any) {
+    if (options.id) {
+      this.setData({ id: options.id });
+      this.loadDetail(options.id);
+    }
+  },
+
+  onShow() {
+    if (this.data.id && this.data.refundState) {
+      this.loadDetail(this.data.id);
     }
   },
 
+  async loadDetail(id: string) {
+    wx.showLoading({ title: '加载中' });
+    try {
+      const res = await getAfterSaleDetailMethod(id);
+      const detail = (res as any)?.data;
+      if (!detail) return;
+
+      const refundState = progressToState[String(detail.progress)] || 'processing';
+
+      this.setData({
+        aftersaleId: detail.id || '',
+        refundState,
+        goods: {
+          name: detail.conditioningProgramName || '',
+          meta1: detail.convertDose ? `${detail.convertDose}${detail.convertUnit || '次'}` : '',
+          price: String(detail.applyAmount || 0),
+          image: detail.conditioningProgramPhoto || '',
+        },
+        refundDetail: {
+          reason: detail.reason || '',
+          amount: String(detail.reviewAmount || detail.applyAmount || 0),
+          finishTime: detail.finishTime || '',
+          applyTime: detail.applyTime || '',
+          refundNo: detail.ref || '',
+        },
+        negotiateTitle: detail.title || '',
+        negotiateContent: detail.content || '',
+        handleEndTime: detail.handleEndTime || '',
+        refundMaxAmount: String(detail.applyAmount || 0),
+        refundProofImages: detail.voucherImgs || [],
+      });
+
+      this.updatePageTitle();
+      if (refundState === 'processing' || refundState === 'rejected') {
+        this.startCountdown();
+      }
+    } catch (error: any) {
+      wx.showToast({ title: error.errMsg || '获取详情失败', icon: 'none' });
+    }
+    wx.hideLoading();
+  },
+
   updatePageTitle() {
     let title = '商家处理';
     if (this.data.refundState === 'revoked') {
@@ -58,32 +124,38 @@ Page({
   },
 
   startCountdown() {
-    // 模拟真实的倒计时,预设当前剩余时间(处理中通常为48小时,拒绝重填通常为7天)
-    const targetHours = this.data.refundState === 'rejected' ? 7 * 24 : 48;
-    const targetTime = new Date().getTime() + targetHours * 60 * 60 * 1000 - 1000;
-
-    this.timer = setInterval(() => {
-      const now = new Date().getTime();
-      const diff = targetTime - now;
+    if (this.timer) clearInterval(this.timer);
 
+    const setTime = (diff: number) => {
       if (diff <= 0) {
-        clearInterval(this.timer);
         this.setData({ days: '00', hours: '00', minutes: '00', seconds: '00' });
         return;
       }
-
       const d = Math.floor(diff / (1000 * 60 * 60 * 24));
       const h = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
       const m = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
       const s = Math.floor((diff % (1000 * 60)) / 1000);
-
       this.setData({
         days: d < 10 ? '0' + d : String(d),
         hours: h < 10 ? '0' + h : String(h),
         minutes: m < 10 ? '0' + m : String(m),
         seconds: s < 10 ? '0' + s : String(s),
       });
-    }, 1000);
+    };
+
+    if (this.data.refundState === 'rejected' && this.data.handleEndTime) {
+      // rejected:倒计时到处理截止时间
+      const target = new Date(this.data.handleEndTime.replace(/-/g, '/')).getTime();
+      const update = () => setTime(target - new Date().getTime());
+      update();
+      this.timer = setInterval(update, 1000);
+    } else {
+      // processing:已过去的时间
+      const applyTime = new Date(this.data.refundDetail.applyTime.replace(/-/g, '/')).getTime();
+      const update = () => setTime(new Date().getTime() - applyTime);
+      update();
+      this.timer = setInterval(update, 1000);
+    }
   },
 
   // 修改申请:打开确认弹窗
@@ -91,7 +163,6 @@ Page({
     this.setData({ refundConfirmPopupVisible: true });
   },
 
-  // 确认弹窗处理
   onRefundConfirmClose() {
     this.setData({ refundConfirmPopupVisible: false });
   },
@@ -131,7 +202,6 @@ Page({
     }, 1000);
   },
 
-  // 原因弹窗处理
   onRefundReasonPopupClose() {
     this.setData({ refundReasonPopupVisible: false });
   },
@@ -144,7 +214,6 @@ Page({
     });
   },
 
-  // 凭证弹窗处理
   onRefundProofPopupClose() {
     this.setData({ refundProofPopupVisible: false });
   },
@@ -159,7 +228,7 @@ Page({
 
   onViewHistory() {
     wx.navigateTo({
-      url: '/module/order/pages/negotiation-history/negotiation-history'
+      url: `/module/order/pages/negotiation-history/negotiation-history?id=${this.data.aftersaleId}`
     });
   },
 
@@ -174,10 +243,8 @@ Page({
 
   onCallService() {
     wx.makePhoneCall({
-      phoneNumber: '400-123-4567', // 替换为真实的客服电话
-      fail: () => {
-        // 用户取消拨打
-      }
+      phoneNumber: '400-123-4567',
+      fail: () => { }
     });
   },
 
@@ -187,14 +254,19 @@ Page({
       content: '撤销退款申请后,可以再次发起退款申请(总共可发起2次)',
       confirmText: '确定撤销',
       cancelText: '暂不撤销',
-      success: (res) => {
+      success: async (res) => {
         if (res.confirm) {
-          wx.showToast({ title: '已撤销', icon: 'success' });
-          setTimeout(() => {
-            wx.redirectTo({
-              url: '/module/article/pages/success-page/success-page?title=撤销退款申请成功'
-            });
-          }, 1500);
+          try {
+            await cancelAfterSaleMethod(Number(this.data.aftersaleId));
+            wx.showToast({ title: '已撤销', icon: 'success' });
+            setTimeout(() => {
+              wx.redirectTo({
+                url: '/module/article/pages/success-page/success-page?title=撤销退款申请成功'
+              });
+            }, 1500);
+          } catch (error: any) {
+            wx.showToast({ title: error.errMsg || '撤销失败', icon: 'none' });
+          }
         }
       }
     });

+ 11 - 11
miniprogram/module/order/pages/refund-processing/refund-processing.wxml

@@ -22,10 +22,10 @@
     <block wx:elif="{{refundState === 'approved'}}">
       <view class="approved-title">同意退款</view>
       <view class="approved-time">{{refundDetail.applyTime}}</view>
-      
-      <view class="approved-content">
-        <view class="content-row">【标题】平台同意了您的退款申请</view>
-        <view class="content-row">【内容】请耐心等待财务确认打款,退款将原路退回您的账户中。</view>
+
+      <view class="approved-content" wx:if="{{negotiateTitle || negotiateContent}}">
+        <view class="content-row" wx:if="{{negotiateTitle}}">【标题】{{negotiateTitle}}</view>
+        <view class="content-row" wx:if="{{negotiateContent}}">【内容】{{negotiateContent}}</view>
       </view>
     </block>
 
@@ -38,10 +38,10 @@
     <block wx:elif="{{refundState === 'rejected'}}">
       <view class="approved-title">拒绝退款(请在{{days}}天{{hours}}小时{{minutes}}分钟内处理)</view>
       <view class="approved-time">{{refundDetail.applyTime}}</view>
-      
-      <view class="approved-content">
-        <view class="content-row">【标题】平台拒绝了您的退款申请</view>
-        <view class="content-row">【内容】商品已经核销3次,麻烦修改退款金额为¥200</view>
+
+      <view class="approved-content" wx:if="{{negotiateTitle || negotiateContent}}">
+        <view class="content-row" wx:if="{{negotiateTitle}}">【标题】{{negotiateTitle}}</view>
+        <view class="content-row" wx:if="{{negotiateContent}}">【内容】{{negotiateContent}}</view>
       </view>
     </block>
 
@@ -114,11 +114,11 @@
       </view>
     </view>
 
-    <!-- 客服按钮(放在列表下方或绝对定位) -->
-    <view class="service-action" bindtap="onCallService">
+    <!-- 客服按钮(暂时注释) -->
+    <!-- <view class="service-action" bindtap="onCallService">
       <t-icon name="service" size="44rpx" color="#333" />
       <text class="service-text">客服</text>
-    </view>
+    </view> -->
   </view>
 </scroll-view>
 

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

@@ -103,4 +103,44 @@ export function getLogisticsMethod(id:number){
       return data;
     },
   });
+}
+// 申请售后
+export function applyAfterSaleMethod(data: any) {
+  return Post(`/patientCrManage/addAftersale`, data, {
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
+}
+// 获取售后详情  患者调理方案ID
+export function getAfterSaleDetailMethod(id: string) {
+  return Post(`/patientCrManage/getAftersaleDetail/${id}`, {
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
+}
+// 获取售后协商历史 患者调理方案ID
+export function getAfterSaleNegotiationHistoryMethod(id: number) {
+  return Post(`/patientCrManage/getAftersaleLog/${id}`, {
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
+}
+// 订单商品售后撤销
+export function cancelAfterSaleMethod(id: number) {
+  return Post(`/patientCrManage/revokeAftersale/${id}`, {
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
+}
+// 订单商品售后修改
+export function updateAfterSaleMethod(data: any) {
+  return Post(`/patientCrManage/updateAftersale`, data, {
+    transform({ data }: AnyObject) {
+      return data;
+    },
+  });
 }