Browse Source

fix: 小程序退款状态展示完善,待审核/部分退款/全额退款

- 订单列表:显示"退款审核中"/"已退 ¥X"/"已全额退款"状态标签
- 订单详情:显示退款进度提示(审核中/已退X元可继续/已全额)
- 退款页:待审核/已全额退款时显示状态横幅,禁止重复提交

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 2 weeks ago
parent
commit
2f10d5ec3a

+ 51 - 1
haha-mp/src/pages/orderDetail/orderDetail.vue

@@ -53,8 +53,22 @@
           </view>
         </view>
 
+        <!-- 退款状态提示 -->
+        <view v-if="order.refundStatus === 'PENDING'" class="refund-status-notice pending">
+          <text class="refund-notice-icon">⏳</text>
+          <text class="refund-notice-text">退款申请已提交,正在审核中</text>
+        </view>
+        <view v-else-if="order.refundAmount > 0 && order.refundAmount < (order.paidAmount || order.totalAmount || 0)" class="refund-status-notice partial">
+          <text class="refund-notice-icon">📋</text>
+          <text class="refund-notice-text">已退款 ¥{{ order.refundAmount.toFixed(2) }},可继续申请退款</text>
+        </view>
+        <view v-else-if="order.refundAmount > 0 && order.refundAmount >= (order.paidAmount || order.totalAmount || 0)" class="refund-status-notice full">
+          <text class="refund-notice-icon">✅</text>
+          <text class="refund-notice-text">已全额退款</text>
+        </view>
+
         <view class="card-footer-actions">
-          <button v-if="canRefund(order)" class="action-btn-outline" @click="applyRefund">申请退款</button>
+          <button v-if="canRefund(order) && order.refundStatus !== 'PENDING'" class="action-btn-outline" @click="applyRefund">申请退款</button>
         </view>
       </view>
 
@@ -435,6 +449,42 @@ const viewVideo = (url: string) => {
   font-weight: 700;
 }
 
+.refund-status-notice {
+  display: flex;
+  align-items: center;
+  gap: 12rpx;
+  margin: 0 32rpx 8rpx;
+  padding: 20rpx 24rpx;
+  border-radius: 12rpx;
+  font-size: 26rpx;
+
+  &.pending {
+    background-color: #fff7e6;
+    border: 1rpx solid #ffd591;
+    color: #d48806;
+  }
+
+  &.partial {
+    background-color: #e6f7ff;
+    border: 1rpx solid #91d5ff;
+    color: #096dd9;
+  }
+
+  &.full {
+    background-color: #f6ffed;
+    border: 1rpx solid #b7eb8f;
+    color: #389e0d;
+  }
+
+  .refund-notice-icon {
+    font-size: 28rpx;
+  }
+
+  .refund-notice-text {
+    flex: 1;
+  }
+}
+
 .card-footer-actions {
   display: flex;
   justify-content: flex-end;

+ 31 - 1
haha-mp/src/pages/orders/orders.vue

@@ -43,7 +43,11 @@
           </view>
         </view>
         <view class="order-footer">
-          <button v-if="canRefund(order)" class="action-btn refund-btn" @click.stop="applyRefund(order)">申请退款</button>
+          <!-- 退款状态 -->
+          <text v-if="order.refundStatus === 'PENDING'" class="refund-tag pending">退款审核中</text>
+          <text v-else-if="order.refundAmount > 0 && order.refundAmount < (order.paidAmount || order.totalAmount || 0)" class="refund-tag partial">已退 ¥{{ order.refundAmount.toFixed(2) }}</text>
+          <text v-else-if="order.refundAmount > 0 && order.refundAmount >= (order.paidAmount || order.totalAmount || 0)" class="refund-tag full">已全额退款</text>
+          <button v-else-if="canRefund(order)" class="action-btn refund-btn" @click.stop="applyRefund(order)">申请退款</button>
           <button class="action-btn detail-btn" @click.stop="viewOrderDetail(order)">订单详情</button>
         </view>
       </view>
@@ -325,4 +329,30 @@ const viewOrderDetail = (order: OrderInfo) => {
     background-color: $color-bg-secondary;
   }
 }
+
+.refund-tag {
+  padding: 8rpx 20rpx;
+  border-radius: 8rpx;
+  font-size: 24rpx;
+  font-weight: 500;
+  margin-right: auto;
+
+  &.pending {
+    color: $color-warning;
+    background-color: #fff7e6;
+    border: 1rpx solid #ffd591;
+  }
+
+  &.partial {
+    color: $color-info;
+    background-color: #e6f7ff;
+    border: 1rpx solid #91d5ff;
+  }
+
+  &.full {
+    color: $color-text-secondary;
+    background-color: $color-bg-secondary;
+    border: 1rpx solid $color-border;
+  }
+}
 </style>

+ 92 - 1
haha-mp/src/pages/refund/refund.vue

@@ -1,7 +1,15 @@
 <template>
   <view class="container">
+    <!-- 退款状态提示 -->
+    <view v-if="refundDisabled" class="refund-status-banner">
+      <text class="banner-icon">{{ refundBannerIcon }}</text>
+      <text class="banner-title">{{ refundBannerTitle }}</text>
+      <text class="banner-desc">{{ refundBannerDesc }}</text>
+      <button class="banner-back-btn" @click="goBack">返回订单详情</button>
+    </view>
+
     <!-- 退款商品选择 -->
-    <view class="section-block product-section">
+    <view v-if="!refundDisabled" class="section-block product-section">
       <text class="section-title">选择退款商品</text>
       <view class="product-list">
         <view
@@ -226,6 +234,34 @@ const refundExpireText = computed(() => {
   }
 });
 
+// 是否禁用退款(待审核 / 已全额退款)
+const refundDisabled = computed(() => {
+  if (!orderInfo.value.id) return false;
+  if (orderInfo.value.refundStatus === 'PENDING') return true;
+  const paid = orderInfo.value.paidAmount || orderInfo.value.totalAmount || 0;
+  const refunded = orderInfo.value.refundAmount || 0;
+  return refunded >= paid;
+});
+
+const refundBannerIcon = computed(() => {
+  if (orderInfo.value.refundStatus === 'PENDING') return '⏳';
+  return '✅';
+});
+
+const refundBannerTitle = computed(() => {
+  if (orderInfo.value.refundStatus === 'PENDING') return '退款审核中';
+  return '已全额退款';
+});
+
+const refundBannerDesc = computed(() => {
+  if (orderInfo.value.refundStatus === 'PENDING') return '您的退款申请已提交,正在审核中,请耐心等待';
+  return '该订单已全额退款,无需再次申请';
+});
+
+const goBack = () => {
+  uni.navigateBack();
+};
+
 const selectedReason = ref('');
 const refundRemark = ref('');
 const customRefundAmount = ref<string>('');
@@ -295,6 +331,17 @@ const loadOrderDetail = async () => {
     const detail = await getOrderDetail({ orderId: orderId.value });
     orderInfo.value = detail;
 
+    // 检查是否已全额退款
+    const paidAmount = detail.paidAmount || detail.totalAmount || 0;
+    if ((detail.refundAmount || 0) >= paidAmount) {
+      return; // refundDisabled computed will show banner
+    }
+
+    // 检查是否有待审核的退款申请
+    if (detail.refundStatus === 'PENDING') {
+      return; // refundDisabled computed will show banner
+    }
+
     if (detail.payTime) {
       const payTime = new Date(detail.payTime);
       const now = new Date();
@@ -416,6 +463,50 @@ const submitRefund = async () => {
   padding-bottom: 40rpx;
 }
 
+/* 退款状态横幅 */
+.refund-status-banner {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 60rpx 40rpx;
+  margin: 30rpx;
+  background-color: $color-bg-primary;
+  border-radius: 16rpx;
+  text-align: center;
+
+  .banner-icon {
+    font-size: 80rpx;
+    margin-bottom: 24rpx;
+  }
+
+  .banner-title {
+    font-size: 36rpx;
+    font-weight: 600;
+    color: $color-text-primary;
+    margin-bottom: 16rpx;
+  }
+
+  .banner-desc {
+    font-size: 28rpx;
+    color: $color-text-secondary;
+    line-height: 1.6;
+    margin-bottom: 40rpx;
+  }
+
+  .banner-back-btn {
+    background-color: $color-bg-secondary;
+    border: 1rpx solid $color-border;
+    border-radius: 10rpx;
+    font-size: 28rpx;
+    color: $color-text-primary;
+    padding: 20rpx 60rpx;
+
+    &::after {
+      border: none;
+    }
+  }
+}
+
 .product-section {
   margin-bottom: 20rpx;
   padding-bottom: 20rpx;