Răsfoiți Sursa

feat: 退款管理页订单编号支持点击查看订单详情弹窗

- 订单编号改为蓝色可点击链接样式
- 点击弹窗展示订单基本信息(金额/支付状态/门店/设备/时间等)
- 展示订单商品明细表格(图片/名称/单价/数量/小计)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 2 săptămâni în urmă
părinte
comite
a9be26ed2b
1 a modificat fișierele cu 112 adăugiri și 2 ștergeri
  1. 112 2
      haha-admin-web/src/views/order/refund/utils/hook.tsx

+ 112 - 2
haha-admin-web/src/views/order/refund/utils/hook.tsx

@@ -15,7 +15,8 @@ import {
 import {
   getRefundApplicationList,
   getRefundApplicationDetail,
-  reviewRefundApplication
+  reviewRefundApplication,
+  getOrderById
 } from "@/api/order";
 import type { RefundApplicationItem, RefundApplicationSearchForm } from "../../utils/types";
 import { type Ref, ref, reactive, onMounted } from "vue";
@@ -41,7 +42,16 @@ export function useRefund(tableRef: Ref) {
 
   const columns: TableColumnList = [
     { label: "申请编号", prop: "applicationNo", minWidth: 160 },
-    { label: "订单编号", prop: "orderNo", minWidth: 160 },
+    {
+      label: "订单编号",
+      prop: "orderNo",
+      minWidth: 160,
+      cellRenderer: ({ row }: any) => (
+        <el-button link type="primary" size="small" onClick={() => handleOrderDetail(row)}>
+          {row.orderNo}
+        </el-button>
+      )
+    },
     { label: "用户ID", prop: "userId", minWidth: 80 },
     {
       label: "退款金额",
@@ -124,6 +134,105 @@ export function useRefund(tableRef: Ref) {
     handleCurrentPageChange(val, pagination, onSearch);
   }
 
+  async function handleOrderDetail(row: RefundApplicationItem) {
+    try {
+      const { data } = await getOrderById(row.orderId);
+      const order = data as any;
+
+      const payStatusMap: Record<string, { text: string; type: string }> = {
+        "UNPAID": { text: "未支付", type: "warning" },
+        "PAID": { text: "已支付", type: "success" },
+        "PARTIAL_REFUND": { text: "部分退款", type: "warning" },
+        "REFUND": { text: "全额退款", type: "danger" }
+      };
+      const ps = payStatusMap[order.payStatus] || { text: "未知", type: "info" };
+
+      addDialog({
+        title: `订单详情 - ${row.orderNo}`,
+        width: "700px",
+        draggable: true,
+        closeOnClickModal: false,
+        contentRenderer: () => (
+          <div style="max-height: 70vh; overflow-y: auto; padding: 0 4px;">
+            <div style="font-size: 15px; font-weight: 600; margin-bottom: 10px; color: var(--el-text-color-primary);">基本信息</div>
+            <ElDescriptions column={2} border size="small">
+              <ElDescriptionsItem label="订单编号">{order.orderNo || "-"}</ElDescriptionsItem>
+              <ElDescriptionsItem label="支付订单号">{order.outTradeNo || "-"}</ElDescriptionsItem>
+              <ElDescriptionsItem label="用户ID">{order.userId || "-"}</ElDescriptionsItem>
+              <ElDescriptionsItem label="手机号">{order.phone || "-"}</ElDescriptionsItem>
+              <ElDescriptionsItem label="订单总金额">
+                ¥{(order.totalAmount || 0).toFixed(2)}
+              </ElDescriptionsItem>
+              <ElDescriptionsItem label="实付金额">
+                <span style="color: #f56c6c; font-weight: 600;">¥{(order.paidAmount || order.totalAmount || 0).toFixed(2)}</span>
+              </ElDescriptionsItem>
+              <ElDescriptionsItem label="优惠金额">
+                ¥{(order.discountAmount || 0).toFixed(2)}
+              </ElDescriptionsItem>
+              <ElDescriptionsItem label="支付状态">
+                <el-tag type={ps.type as any} size="small">{ps.text}</el-tag>
+              </ElDescriptionsItem>
+              <ElDescriptionsItem label="支付方式">{order.payType || "-"}</ElDescriptionsItem>
+              <ElDescriptionsItem label="门店">{order.storeName || order.shopName || "-"}</ElDescriptionsItem>
+              <ElDescriptionsItem label="设备ID">{order.deviceId || "-"}</ElDescriptionsItem>
+              <ElDescriptionsItem label="下单时间">
+                {order.createTime ? dayjs(order.createTime).format("YYYY-MM-DD HH:mm:ss") : "-"}
+              </ElDescriptionsItem>
+              <ElDescriptionsItem label="支付时间">
+                {order.payTime ? dayjs(order.payTime).format("YYYY-MM-DD HH:mm:ss") : "-"}
+              </ElDescriptionsItem>
+              {order.confidence != null && (
+                <ElDescriptionsItem label="识别置信度">{order.confidence}%</ElDescriptionsItem>
+              )}
+            </ElDescriptions>
+
+            {order.products && order.products.length > 0 && (
+              <>
+                <div style="font-size: 15px; font-weight: 600; margin: 14px 0 10px; color: var(--el-text-color-primary);">订单商品</div>
+                <ElTable data={order.products} border size="small" style="width: 100%">
+                  <ElTableColumn label="商品名称" min-width={160}>
+                    {{
+                      default: ({ row: r }: any) => (
+                        <div style="display: flex; align-items: center; gap: 8px;">
+                          {r.pic ? (
+                            <ElImage src={r.pic} style="width: 40px; height: 40px; border-radius: 4px; flex-shrink: 0;" fit="cover">
+                              {{ error: () => (<div style="width: 40px; height: 40px; background: #f5f5f5; border-radius: 4px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: #999;">暂无</div>) }}
+                            </ElImage>
+                          ) : (
+                            <div style="width: 40px; height: 40px; background: #f5f5f5; border-radius: 4px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: #999; flex-shrink: 0;">暂无</div>
+                          )}
+                          <span>{r.productName}</span>
+                        </div>
+                      )
+                    }}
+                  </ElTableColumn>
+                  <ElTableColumn label="单价" width={90} align="right"
+                    v-slots={{ default: ({ row: r }: any) => <span>¥{(r.price || 0).toFixed(2)}</span> }}
+                  />
+                  <ElTableColumn label="数量" width={80} align="center"
+                    v-slots={{ default: ({ row: r }: any) => <span>×{r.productNum || 1}</span> }}
+                  />
+                  <ElTableColumn label="小计" width={100} align="right"
+                    v-slots={{
+                      default: ({ row: r }: any) => (
+                        <span style="color: #e6a23c; font-weight: 600;">
+                          ¥{((r.price || 0) * (r.productNum || 1)).toFixed(2)}
+                        </span>
+                      )
+                    }}
+                  />
+                </ElTable>
+              </>
+            )}
+          </div>
+        ),
+        hideFooter: true
+      });
+    } catch (error) {
+      message("获取订单详情失败", { type: "error" });
+    }
+  }
+
   async function handleDetail(row: RefundApplicationItem) {
     try {
       const { data } = await getRefundApplicationDetail(row.id);
@@ -297,6 +406,7 @@ export function useRefund(tableRef: Ref) {
     pagination,
     onSearch,
     resetForm,
+    handleOrderDetail,
     handleDetail,
     handleApprove,
     handleReject,