Przeglądaj źródła

用户资金流列表页:订单号点击弹窗按交易类型显示详情

- 订单号列改为可点击链接,根据交易类型(type)分派不同后端接口
- 消费(type=3):调用 /washOrder/detail/{orderNo} 展示订单详情
- 充值(type=1):调用 /custom/payLog/byOutTradeNo/{orderNo} 展示支付记录详情
- 提现(type=2):调用 /finance/withdrawnRecord/{transactionId} 展示提现审核详情
- 新增 PayLogService.getByOutTradeNo 按商户订单号查询支付记录
- 新增 WithdrawnRecordService.detail 提现记录详情(含站点名称)
- 弹窗使用 el-descriptions 按类型条件渲染,loading 状态

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 2 dni temu
rodzic
commit
2af1bfe512

+ 117 - 0
admin-web/src/views/admin/finance/wallet-flow.vue

@@ -131,6 +131,12 @@
             <template v-else-if="['amount','grantsAmount','commission','beforeBalance','afterBalance','beforeGrantsBalance','afterGrantsBalance'].includes(field.prop)">
               {{ u.fmt.fmtMoney(row[field.prop]) }}
             </template>
+            <template v-else-if="field.prop==='orderNo'">
+              <el-button v-if="row.orderNo" link type="primary" @click="handleOrderNoClick(row)">
+                {{ row.orderNo }}
+              </el-button>
+              <span v-else>-</span>
+            </template>
             <template v-else>
               <div>{{ row[field.prop] }}</div>
             </template>
@@ -141,6 +147,77 @@
       <ext-page class="page-pager" v-model:value="state.pageQuery" @change="loadData(false)"/>
 
     </el-card>
+
+    <!-- 详情弹窗 (按类型展示) -->
+    <el-dialog
+        v-model="orderDialog.visible"
+        :title="orderDialog.title"
+        width="680px"
+        destroy-on-close
+        :close-on-click-modal="false"
+        align-center>
+      <!-- 消费订单详情 -->
+      <el-descriptions v-if="orderDialog.type === 3" v-loading="orderDialog.loading" :column="2" border size="default">
+        <el-descriptions-item label="订单号" :span="2">{{ orderDialog.data.orderId }}</el-descriptions-item>
+        <el-descriptions-item label="设备编号">{{ orderDialog.data.shortId }}</el-descriptions-item>
+        <el-descriptions-item label="消费站点">{{ orderDialog.data.stationName }}</el-descriptions-item>
+        <el-descriptions-item label="消费金额">{{ u.fmt.fmtMoney(orderDialog.data.amount) }}</el-descriptions-item>
+        <el-descriptions-item label="实收金额">{{ u.fmt.fmtMoney(orderDialog.data.amountReceived) }}</el-descriptions-item>
+        <el-descriptions-item label="优惠金额">{{ u.fmt.fmtMoney(orderDialog.data.discountAmount) }}</el-descriptions-item>
+        <el-descriptions-item label="优惠方式">
+          <ext-d-label v-if="orderDialog.data.discountType" type="Activity.discountType" :model-value="orderDialog.data.discountType" />
+        </el-descriptions-item>
+        <el-descriptions-item label="充值款支付">{{ u.fmt.fmtMoney(orderDialog.data.rechargePayment) }}</el-descriptions-item>
+        <el-descriptions-item label="赠款支付">{{ u.fmt.fmtMoney(orderDialog.data.grantsPayment) }}</el-descriptions-item>
+        <el-descriptions-item label="订单状态">
+          <ext-d-label v-if="orderDialog.data.orderStatus != null" type="Order.status" :model-value="orderDialog.data.orderStatus" />
+        </el-descriptions-item>
+        <el-descriptions-item label="支付状态">
+          <ext-d-label v-if="orderDialog.data.payStatus != null" type="Order.pay" :model-value="orderDialog.data.payStatus" />
+        </el-descriptions-item>
+        <el-descriptions-item label="开始时间">{{ orderDialog.data.startTime }}</el-descriptions-item>
+        <el-descriptions-item label="结束时间">{{ orderDialog.data.endTime }}</el-descriptions-item>
+        <el-descriptions-item label="关机方式" :span="2">
+          <ext-d-label v-if="orderDialog.data.closeType" type="Order.closeType" :model-value="orderDialog.data.closeType" />
+        </el-descriptions-item>
+        <el-descriptions-item label="停止原因" :span="2">{{ orderDialog.data.stopReason }}</el-descriptions-item>
+      </el-descriptions>
+      <!-- 充值记录详情 -->
+      <el-descriptions v-else-if="orderDialog.type === 1" v-loading="orderDialog.loading" :column="2" border size="default">
+        <el-descriptions-item label="商户订单号" :span="2">{{ orderDialog.data.outTradeNo }}</el-descriptions-item>
+        <el-descriptions-item label="微信交易号" :span="2">{{ orderDialog.data.transactionId }}</el-descriptions-item>
+        <el-descriptions-item label="支付金额">{{ u.fmt.fmtMoney(orderDialog.data.total) }}</el-descriptions-item>
+        <el-descriptions-item label="用户实付">{{ u.fmt.fmtMoney(orderDialog.data.payerTotal) }}</el-descriptions-item>
+        <el-descriptions-item label="交易类型">{{ orderDialog.data.tradeType }}</el-descriptions-item>
+        <el-descriptions-item label="交易状态">{{ orderDialog.data.tradeState }}</el-descriptions-item>
+        <el-descriptions-item label="银行类型">{{ orderDialog.data.bankType }}</el-descriptions-item>
+        <el-descriptions-item label="支付完成时间">{{ orderDialog.data.successTime }}</el-descriptions-item>
+        <el-descriptions-item label="创建时间">{{ orderDialog.data.createTime }}</el-descriptions-item>
+      </el-descriptions>
+      <!-- 提现记录详情 -->
+      <el-descriptions v-else-if="orderDialog.type === 2" v-loading="orderDialog.loading" :column="2" border size="default">
+        <el-descriptions-item label="所属站点" :span="2">{{ orderDialog.data.stationName }}</el-descriptions-item>
+        <el-descriptions-item label="提现金额">{{ u.fmt.fmtMoney(orderDialog.data.withdrawnAmount) }}</el-descriptions-item>
+        <el-descriptions-item label="审核状态">
+          <el-tag v-if="orderDialog.data.status === 0" type="info" size="small">待审核</el-tag>
+          <el-tag v-else-if="orderDialog.data.status === 1" type="success" size="small">审核通过</el-tag>
+          <el-tag v-else-if="orderDialog.data.status === 2" type="danger" size="small">审核失败</el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="打款状态">
+          <el-tag v-if="orderDialog.data.paymentStatus === 0" type="warning" size="small">未打款</el-tag>
+          <el-tag v-else-if="orderDialog.data.paymentStatus === 1" type="success" size="small">已打款</el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="审核人">{{ orderDialog.data.reviewer }}</el-descriptions-item>
+        <el-descriptions-item label="审核时间">{{ orderDialog.data.reviewTime }}</el-descriptions-item>
+        <el-descriptions-item label="打款人">{{ orderDialog.data.payer }}</el-descriptions-item>
+        <el-descriptions-item label="打款时间">{{ orderDialog.data.paymentTime }}</el-descriptions-item>
+        <el-descriptions-item label="创建时间">{{ orderDialog.data.createTime }}</el-descriptions-item>
+        <el-descriptions-item label="备注" :span="2">{{ orderDialog.data.remark }}</el-descriptions-item>
+      </el-descriptions>
+      <template #footer>
+        <el-button @click="orderDialog.visible = false">关 闭</el-button>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
@@ -150,6 +227,7 @@ import {$get} from "/@/utils/request";
 import u from "/@/utils/u"
 
 import ExtPage from '/@/components/form/ExtPage.vue'
+import ExtDLabel from "/@/components/form/ExtDLabel.vue";
 
 const typeTagMap: Record<number, { text: string; type: string }> = {
   1: { text: "充值", type: "success" },
@@ -230,6 +308,45 @@ const buildParams = () => {
   return params;
 };
 
+const typeTitles: Record<number, string> = { 1: '充值详情', 2: '提现详情', 3: '订单详情' };
+
+const orderDialog = reactive({
+  visible: false,
+  loading: false,
+  type: 0,
+  title: '',
+  data: {} as any,
+});
+
+const handleOrderNoClick = (row: any) => {
+  const type = row.type as number;
+  orderDialog.type = type;
+  orderDialog.title = typeTitles[type] || '交易详情';
+  orderDialog.visible = true;
+  orderDialog.loading = true;
+  orderDialog.data = {};
+
+  let url = '';
+  if (type === 1) {
+    // 充值:orderNo 对应 pay_log 的 outTradeNo
+    url = `/custom/payLog/byOutTradeNo/${row.orderNo}`;
+  } else if (type === 2) {
+    // 提现:transactionId 是 withdrawn_record 的 id
+    url = `/finance/withdrawnRecord/${row.transactionId}`;
+  } else {
+    // 消费:orderNo 是 wash_order 的 orderId
+    url = `/washOrder/detail/${row.orderNo}`;
+  }
+
+  $get(url).then((res: any) => {
+    orderDialog.data = res;
+  }).catch(() => {
+    orderDialog.data = {};
+  }).finally(() => {
+    orderDialog.loading = false;
+  });
+};
+
 // 初始化表格数据
 const loadData = (refresh: boolean = false) => {
   if (refresh) {

+ 13 - 0
car-wash-admin/src/main/java/com/kym/admin/controller/CustomController.java

@@ -8,6 +8,7 @@ import com.kym.service.PayLogService;
 import com.kym.service.UserService;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -43,4 +44,16 @@ public class CustomController {
         return R.success(payLogService.listRecharge(params));
     }
 
+    @SysLog("充值记录详情")
+    @GetMapping("/payLog/{id}")
+    public R<?> payLogDetail(@PathVariable Long id) {
+        return R.success(payLogService.getById(id));
+    }
+
+    @SysLog("充值记录详情(按商户订单号)")
+    @GetMapping("/payLog/byOutTradeNo/{outTradeNo}")
+    public R<?> payLogDetailByOutTradeNo(@PathVariable String outTradeNo) {
+        return R.success(payLogService.getByOutTradeNo(outTradeNo));
+    }
+
 }

+ 6 - 0
car-wash-admin/src/main/java/com/kym/admin/controller/FinanceController.java

@@ -197,4 +197,10 @@ public class FinanceController {
         return R.success(walletDetailService.listAdminWalletDetail(params));
     }
 
+    @SysLog("提现记录详情")
+    @GetMapping("/withdrawnRecord/{id}")
+    public R<?> withdrawnRecordDetail(@PathVariable Long id) {
+        return R.success(withdrawnRecordService.detail(id));
+    }
+
 }

+ 2 - 0
car-wash-service/src/main/java/com/kym/service/PayLogService.java

@@ -18,4 +18,6 @@ public interface PayLogService extends MPJBaseService<PayLog> {
 
     PageBean<CustomRechargeVo> listRecharge(CommonQueryParam params);
 
+    PayLog getByOutTradeNo(String outTradeNo);
+
 }

+ 2 - 0
car-wash-service/src/main/java/com/kym/service/WithdrawnRecordService.java

@@ -19,6 +19,8 @@ public interface WithdrawnRecordService extends MyBaseService<WithdrawnRecord> {
 
     PageBean<WithdrawnRecordVo> listWithdrawnRecords(WithdrawnQueryParam params);
 
+    WithdrawnRecordVo detail(Long id);
+
     void reviewWithdrawn(WithdrawnQueryParam params);
 
     @Transactional

+ 5 - 0
car-wash-service/src/main/java/com/kym/service/impl/PayLogServiceImpl.java

@@ -31,4 +31,9 @@ public class PayLogServiceImpl extends MPJBaseServiceImpl<PayLogMapper, PayLog>
         return new PageBean<>(list);
     }
 
+    @Override
+    public PayLog getByOutTradeNo(String outTradeNo) {
+        return lambdaQuery().eq(PayLog::getOutTradeNo, outTradeNo).one();
+    }
+
 }

+ 12 - 0
car-wash-service/src/main/java/com/kym/service/impl/WithdrawnRecordServiceImpl.java

@@ -37,6 +37,18 @@ public class WithdrawnRecordServiceImpl extends MyBaseServiceImpl<WithdrawnRecor
         this.stationAccountService = stationAccountService;
     }
 
+    @Override
+    public WithdrawnRecordVo detail(Long id) {
+        var record = getById(id);
+        if (record == null) {
+            return null;
+        }
+        var vo = new WithdrawnRecordVo();
+        BeanUtils.copyProperties(record, vo);
+        vo.setStationName(KymCache.INSTANCE.getStationNameById(record.getStationId()));
+        return vo;
+    }
+
     @Override
     public PageBean<WithdrawnRecordVo> listWithdrawnRecords(WithdrawnQueryParam params) {
         PageHelper.startPage(params.getPageNum(), params.getPageSize());