mirror of
https://gitee.com/bootx/dax-pay-ui
synced 2026-08-11 15:15:34 +08:00
feat(order): 新增网关支付订单页,重构退款订单列表与工作台订单卡片,补齐东盟四语
This commit is contained in:
111
apps/daxpay-admin/src/api/payment/order/gateway-order.api.ts
Normal file
111
apps/daxpay-admin/src/api/payment/order/gateway-order.api.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import type { MchEntity, PageResult, Result } from '#/types/web';
|
||||
|
||||
import { defHttp } from '#/api/request';
|
||||
|
||||
/**
|
||||
* 网关支付业务订单管理 API
|
||||
*/
|
||||
export const GatewayOrderApi = {
|
||||
/**
|
||||
* 分页查询网关业务订单
|
||||
*/
|
||||
page(params: GatewayOrderQuery & { current?: number; size?: number }): Promise<Result<PageResult<GatewayOrderResult>>> {
|
||||
return defHttp.get({ url: '/admin/order/gateway-pay/page', params });
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据ID查询详情
|
||||
*/
|
||||
getById(id: string): Promise<Result<GatewayOrderResult>> {
|
||||
return defHttp.get({ url: '/admin/order/gateway-pay/get-by-id', params: { id } });
|
||||
},
|
||||
|
||||
/**
|
||||
* 同步支付状态
|
||||
*/
|
||||
sync(id: string): Promise<Result<GatewayPaySyncResult>> {
|
||||
return defHttp.post({ url: '/admin/order/gateway-pay/sync', params: { id } });
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭/撤销订单
|
||||
*/
|
||||
close(id: string, useCancel = false): Promise<Result<void>> {
|
||||
return defHttp.post({
|
||||
url: '/admin/order/gateway-pay/close',
|
||||
params: { id, useCancel },
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/** 网关订单查询参数 */
|
||||
export interface GatewayOrderQuery {
|
||||
mchNo?: string;
|
||||
appId?: string;
|
||||
/** 平台网关单号 */
|
||||
orderNo?: string;
|
||||
bizOrderNo?: string;
|
||||
title?: string;
|
||||
status?: string;
|
||||
gatewayType?: string;
|
||||
product?: string;
|
||||
capability?: string;
|
||||
storeNo?: string;
|
||||
createTimeStart?: string;
|
||||
createTimeEnd?: string;
|
||||
amountMin?: number;
|
||||
amountMax?: number;
|
||||
}
|
||||
|
||||
/** 网关订单结果 */
|
||||
export interface GatewayOrderResult extends MchEntity {
|
||||
orderNo?: string;
|
||||
bizOrderNo?: string;
|
||||
gatewayType?: string;
|
||||
source?: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
status?: string;
|
||||
notifyUrl?: string;
|
||||
returnUrl?: string;
|
||||
attach?: string;
|
||||
expiredTime?: string;
|
||||
amount?: number;
|
||||
currency?: string;
|
||||
channel?: string;
|
||||
method?: string;
|
||||
product?: string;
|
||||
limitPay?: string;
|
||||
clientEnv?: string;
|
||||
device?: string;
|
||||
payTime?: string;
|
||||
closeTime?: string;
|
||||
channelMchNo?: string;
|
||||
capability?: string;
|
||||
channelAppId?: string;
|
||||
clientIp?: string;
|
||||
storeNo?: string;
|
||||
extraParam?: string;
|
||||
// 资金凭证(详情)
|
||||
tradeNo?: string;
|
||||
outOrderNo?: string;
|
||||
fundStatus?: string;
|
||||
refundableBalance?: number;
|
||||
payBody?: string;
|
||||
payBodyType?: string;
|
||||
buyerId?: string;
|
||||
openid?: string;
|
||||
provider?: string;
|
||||
tradeProduct?: string;
|
||||
tradeWay?: string;
|
||||
bankType?: string;
|
||||
promotionType?: string;
|
||||
transOrderNo?: string;
|
||||
relationOrderNo?: string;
|
||||
errorMsg?: string;
|
||||
}
|
||||
|
||||
export interface GatewayPaySyncResult {
|
||||
orderStatus?: string;
|
||||
adjust?: boolean;
|
||||
}
|
||||
@@ -45,18 +45,18 @@ export interface NormalOrderQuery {
|
||||
mchNo?: string;
|
||||
/** 应用号 */
|
||||
appId?: string;
|
||||
/** 平台业务单号 */
|
||||
orderNo?: string;
|
||||
/** 商户业务单号 */
|
||||
bizOrderNo?: string;
|
||||
/** 订单标题 */
|
||||
title?: string;
|
||||
/** 业务状态 */
|
||||
status?: string;
|
||||
/** 支付通道 */
|
||||
channel?: string;
|
||||
/** 支付方式 */
|
||||
method?: string;
|
||||
/** 支付产品 */
|
||||
product?: string;
|
||||
/** 支付能力 */
|
||||
capability?: string;
|
||||
/** 门店号 */
|
||||
storeNo?: string;
|
||||
/** 创建时间-开始 */
|
||||
@@ -71,8 +71,12 @@ export interface NormalOrderQuery {
|
||||
|
||||
/** 业务订单结果(含详情联表字段) */
|
||||
export interface NormalOrderResult extends MchEntity {
|
||||
/** 平台业务单号 */
|
||||
orderNo?: string;
|
||||
/** 商户业务单号 */
|
||||
bizOrderNo?: string;
|
||||
/** 订单来源 */
|
||||
source?: string;
|
||||
/** 标题 */
|
||||
title?: string;
|
||||
/** 描述 */
|
||||
@@ -97,14 +101,14 @@ export interface NormalOrderResult extends MchEntity {
|
||||
method?: string;
|
||||
/** 支付产品 */
|
||||
product?: string;
|
||||
/** 支付能力 */
|
||||
capability?: string;
|
||||
/** 支付成功时间 */
|
||||
payTime?: string;
|
||||
/** 关闭时间 */
|
||||
closeTime?: string;
|
||||
/** 通道商户号 */
|
||||
channelMchNo?: string;
|
||||
/** 支付能力编码 */
|
||||
capability?: string;
|
||||
/** 通道应用 AppId */
|
||||
channelAppId?: string;
|
||||
/** 客户端IP */
|
||||
|
||||
@@ -53,12 +53,7 @@ export interface PayTradeQuery {
|
||||
status?: string;
|
||||
/** 交易形态 */
|
||||
tradeType?: string;
|
||||
/** 支付通道 */
|
||||
channel?: string;
|
||||
/** 支付方式 */
|
||||
method?: string;
|
||||
/** 支付产品 */
|
||||
product?: string;
|
||||
// pay_trade 无 channel/method/product 列,不可筛选
|
||||
/** 通道商户号 */
|
||||
channelMchNo?: string;
|
||||
/** 门店号 */
|
||||
@@ -142,6 +137,8 @@ export interface PayTradeResult extends MchEntity {
|
||||
/** 错误信息 */
|
||||
errorMsg?: string;
|
||||
// ===== 容器联表字段(详情) =====
|
||||
/** 容器平台业务单号 */
|
||||
containerOrderNo?: string;
|
||||
/** 商户业务单号 */
|
||||
bizOrderNo?: string;
|
||||
/** 订单标题 */
|
||||
|
||||
@@ -23,7 +23,7 @@ export const RefundOrderApi = {
|
||||
/**
|
||||
* 发起退款
|
||||
*/
|
||||
refund(data: PayRefundParam): Promise<Result<RefundOrderResult>> {
|
||||
refund(data: RefundParam): Promise<Result<RefundOrderResult>> {
|
||||
return defHttp.post({ url: '/admin/order/refund/refund', data });
|
||||
},
|
||||
|
||||
@@ -37,78 +37,57 @@ export const RefundOrderApi = {
|
||||
|
||||
/** 退款订单查询参数 */
|
||||
export interface RefundOrderQuery {
|
||||
/** 商户号 */
|
||||
mchNo?: string;
|
||||
/** 应用号 */
|
||||
appId?: string;
|
||||
/** 退款号 */
|
||||
refundNo?: string;
|
||||
/** 商户退款号 */
|
||||
bizRefundNo?: string;
|
||||
/** 原支付订单号 */
|
||||
orderNo?: string;
|
||||
/** 商户业务订单号 */
|
||||
/** 原支付资金交易号 */
|
||||
tradeNo?: string;
|
||||
/** 交易类型 normal/gateway */
|
||||
tradeType?: string;
|
||||
bizOrderNo?: string;
|
||||
/** 退款状态 */
|
||||
status?: string;
|
||||
/** 支付通道 */
|
||||
channel?: string;
|
||||
/** 门店号 */
|
||||
/** 支付产品 */
|
||||
product?: string;
|
||||
storeNo?: string;
|
||||
/** 创建时间-开始 */
|
||||
createTimeStart?: string;
|
||||
/** 创建时间-结束 */
|
||||
createTimeEnd?: string;
|
||||
}
|
||||
|
||||
/** 退款发起参数 */
|
||||
export interface PayRefundParam {
|
||||
/** 原支付订单号 */
|
||||
orderNo?: string;
|
||||
/** 商户业务订单号 */
|
||||
export interface RefundParam {
|
||||
/** 原支付资金交易号 */
|
||||
tradeNo?: string;
|
||||
bizOrderNo?: string;
|
||||
/** 退款金额(分) */
|
||||
amount: number;
|
||||
/** 退款原因 */
|
||||
reason?: string;
|
||||
/** 商户退款号(可选) */
|
||||
bizRefundNo?: string;
|
||||
}
|
||||
|
||||
/** 退款订单结果 */
|
||||
/** 退款订单结果(管理端不暴露 capability) */
|
||||
export interface RefundOrderResult extends MchEntity {
|
||||
/** 退款号 */
|
||||
refundNo?: string;
|
||||
/** 商户退款号 */
|
||||
bizRefundNo?: string;
|
||||
/** 标题 */
|
||||
title?: string;
|
||||
/** 原支付订单号 */
|
||||
orderNo?: string;
|
||||
/** 商户业务订单号 */
|
||||
tradeNo?: string;
|
||||
tradeType?: string;
|
||||
bizOrderNo?: string;
|
||||
/** 通道支付订单号 */
|
||||
outOrderNo?: string;
|
||||
/** 通道退款流水号 */
|
||||
outRefundNo?: string;
|
||||
/** 退款金额(分) */
|
||||
relationOrderNo?: string;
|
||||
amount?: number;
|
||||
/** 订单总金额(分) */
|
||||
orderAmount?: number;
|
||||
/** 退款原因 */
|
||||
currency?: string;
|
||||
reason?: string;
|
||||
/** 退款状态 */
|
||||
status?: string;
|
||||
/** 退款完成时间 */
|
||||
finishTime?: string;
|
||||
/** 支付通道 */
|
||||
channel?: string;
|
||||
/** 支付产品 */
|
||||
product?: string;
|
||||
/** 支付方式 */
|
||||
method?: string;
|
||||
/** 门店号 */
|
||||
channelMchNo?: string;
|
||||
channelAppId?: string;
|
||||
notifyUrl?: string;
|
||||
attach?: string;
|
||||
clientIp?: string;
|
||||
storeNo?: string;
|
||||
/** 错误信息 */
|
||||
errorMsg?: string;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"normal": {
|
||||
"title": "Perintah Pembayaran",
|
||||
"detail": "Detail Pesanan Pembayaran"
|
||||
"title": "Pembayaran Normal",
|
||||
"detail": "Detail Pembayaran Normal"
|
||||
},
|
||||
"gateway": {
|
||||
"title": "Pembayaran Gateway",
|
||||
"detail": "Detail Pembayaran Gateway"
|
||||
},
|
||||
"trade": {
|
||||
"title": "Perdagangan Dana",
|
||||
@@ -10,24 +14,30 @@
|
||||
"refund": {
|
||||
"title": "Pengembalian Dana Pesanan",
|
||||
"detail": "Detail Pengembalian Dana Pesanan",
|
||||
"statusLabel": "Refund Status",
|
||||
"section": {
|
||||
"identity": "Identity",
|
||||
"fund": "Fund",
|
||||
"amount": "Amount",
|
||||
"channel": "Channel",
|
||||
"notify": "Notify"
|
||||
},
|
||||
"status": {
|
||||
"init": "Awal",
|
||||
"progress": "Pengembalian dana",
|
||||
"success": "Kesuksesan",
|
||||
"fail": "Gagal",
|
||||
"close": "Tertutup"
|
||||
"progress": "Refunding",
|
||||
"success": "Success",
|
||||
"fail": "Failed",
|
||||
"close": "Closed"
|
||||
},
|
||||
"statusColor": {
|
||||
"init": "bawaan",
|
||||
"progress": "pengolahan",
|
||||
"success": "hijau",
|
||||
"fail": "merah",
|
||||
"close": "bawaan"
|
||||
"progress": "processing",
|
||||
"success": "green",
|
||||
"fail": "red",
|
||||
"close": "default"
|
||||
}
|
||||
},
|
||||
"field": {
|
||||
"bizOrderNo": "Nomor Pesanan Pedagang.",
|
||||
"tradeNo": "Nomor Perdagangan.",
|
||||
"tradeNo": "Fund Trade No.",
|
||||
"title": "Judul",
|
||||
"description": "Keterangan",
|
||||
"amount": "Jumlah (Yuan)",
|
||||
@@ -41,7 +51,7 @@
|
||||
"provider": "Penyedia",
|
||||
"outOrderNo": "Nomor Pesanan Saluran.",
|
||||
"transOrderNo": "Nomor Pesanan Trans.",
|
||||
"relationOrderNo": "Nomor Pesanan Relasi.",
|
||||
"relationOrderNo": "Channel Relation No.",
|
||||
"postedAmount": "Jumlah dibukukan (Yuan)",
|
||||
"refundableBalance": "Dapat dikembalikan (Yuan)",
|
||||
"payBody": "Badan Bayar",
|
||||
@@ -77,7 +87,7 @@
|
||||
"reason": "Alasan Pengembalian Dana",
|
||||
"finishTime": "Waktu Selesai",
|
||||
"orderAmount": "Jumlah Pesanan",
|
||||
"orderNo": "Nomor Pesanan Asli.",
|
||||
"orderNo": "Platform Order No.",
|
||||
"authCode": "Kode pembayaran",
|
||||
"merchant": "Merchant"
|
||||
},
|
||||
@@ -85,27 +95,33 @@
|
||||
"wait_pay": "Menunggu",
|
||||
"paid": "Dibayar",
|
||||
"closed": "Tertutup",
|
||||
"expired": "Kedaluwarsa"
|
||||
"expired": "Kedaluwarsa",
|
||||
"paying": "Paying",
|
||||
"failed": "Failed"
|
||||
},
|
||||
"fundStatus": {
|
||||
"init": "Awal",
|
||||
"processing": "Pengolahan",
|
||||
"success": "Kesuksesan",
|
||||
"fail": "Gagal",
|
||||
"close": "Tertutup"
|
||||
"close": "Tertutup",
|
||||
"cancel": "Cancelled"
|
||||
},
|
||||
"bizStatusColor": {
|
||||
"wait_pay": "oranye",
|
||||
"paid": "hijau",
|
||||
"closed": "bawaan",
|
||||
"expired": "merah"
|
||||
"expired": "merah",
|
||||
"paying": "processing",
|
||||
"failed": "red"
|
||||
},
|
||||
"fundStatusColor": {
|
||||
"init": "bawaan",
|
||||
"processing": "pengolahan",
|
||||
"success": "hijau",
|
||||
"fail": "merah",
|
||||
"close": "bawaan"
|
||||
"close": "bawaan",
|
||||
"cancel": "default"
|
||||
},
|
||||
"placeholder": {
|
||||
"bizOrderNo": "Masukkan nomor pesanan pedagang.",
|
||||
@@ -143,9 +159,6 @@
|
||||
"refundReasonPlaceholder": "Masukkan alasan pengembalian dana (opsional)",
|
||||
"refundAmountExceed": "Jumlah pengembalian dana tidak dapat melebihi jumlah yang dapat dikembalikan"
|
||||
},
|
||||
"tradeType": {
|
||||
"normal": "Pembayaran Biasa"
|
||||
},
|
||||
"method": {
|
||||
"jsapi": "JSAPI",
|
||||
"qrcode": "Kode QR",
|
||||
@@ -153,5 +166,13 @@
|
||||
"app": "APP",
|
||||
"barcode": "Kode Batang",
|
||||
"wap": "WAP"
|
||||
},
|
||||
"tradeType": {
|
||||
"normal": "Normal Pay",
|
||||
"gateway": "Gateway Pay"
|
||||
},
|
||||
"gatewayType": {
|
||||
"cashier": "Cashier",
|
||||
"aggregate": "Aggregate"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"normal": {
|
||||
"title": "Pesanan Pembayaran",
|
||||
"detail": "Butiran Pesanan Pembayaran"
|
||||
"title": "Bayaran Biasa",
|
||||
"detail": "Butiran Bayaran Biasa"
|
||||
},
|
||||
"gateway": {
|
||||
"title": "Bayaran Gerbang",
|
||||
"detail": "Butiran Bayaran Gerbang"
|
||||
},
|
||||
"trade": {
|
||||
"title": "Dagangan Dana",
|
||||
@@ -10,24 +14,30 @@
|
||||
"refund": {
|
||||
"title": "Bayaran Balik Pesanan",
|
||||
"detail": "Butiran Pesanan Bayaran Balik",
|
||||
"statusLabel": "Refund Status",
|
||||
"section": {
|
||||
"identity": "Identity",
|
||||
"fund": "Fund",
|
||||
"amount": "Amount",
|
||||
"channel": "Channel",
|
||||
"notify": "Notify"
|
||||
},
|
||||
"status": {
|
||||
"init": "Permulaan",
|
||||
"progress": "Membayar balik",
|
||||
"success": "Kejayaan",
|
||||
"fail": "gagal",
|
||||
"close": "tertutup"
|
||||
"progress": "Refunding",
|
||||
"success": "Success",
|
||||
"fail": "Failed",
|
||||
"close": "Closed"
|
||||
},
|
||||
"statusColor": {
|
||||
"init": "lalai",
|
||||
"progress": "pemprosesan",
|
||||
"success": "hijau",
|
||||
"fail": "merah",
|
||||
"close": "lalai"
|
||||
"progress": "processing",
|
||||
"success": "green",
|
||||
"fail": "red",
|
||||
"close": "default"
|
||||
}
|
||||
},
|
||||
"field": {
|
||||
"bizOrderNo": "Pesanan Saudagar No.",
|
||||
"tradeNo": "Perdagangan No.",
|
||||
"tradeNo": "Fund Trade No.",
|
||||
"title": "Tajuk",
|
||||
"description": "Penerangan",
|
||||
"amount": "Amaun(Yuan)",
|
||||
@@ -41,7 +51,7 @@
|
||||
"provider": "Pembekal",
|
||||
"outOrderNo": "Pesanan Saluran No.",
|
||||
"transOrderNo": "Pesanan Trans",
|
||||
"relationOrderNo": "Perintah Perhubungan No.",
|
||||
"relationOrderNo": "Channel Relation No.",
|
||||
"postedAmount": "Amaun diakaun(Yuan)",
|
||||
"refundableBalance": "Boleh dipulangkan(Yuan)",
|
||||
"payBody": "Badan Bayar",
|
||||
@@ -77,7 +87,7 @@
|
||||
"reason": "Sebab Bayaran Balik",
|
||||
"finishTime": "Tamat Masa",
|
||||
"orderAmount": "Jumlah Pesanan",
|
||||
"orderNo": "Pesanan Asal No.",
|
||||
"orderNo": "Platform Order No.",
|
||||
"authCode": "Kod pembayaran",
|
||||
"merchant": "Peniaga"
|
||||
},
|
||||
@@ -85,27 +95,33 @@
|
||||
"wait_pay": "Menunggu",
|
||||
"paid": "Dibayar",
|
||||
"closed": "tertutup",
|
||||
"expired": "Tamat tempoh"
|
||||
"expired": "Tamat tempoh",
|
||||
"paying": "Paying",
|
||||
"failed": "Failed"
|
||||
},
|
||||
"fundStatus": {
|
||||
"init": "Permulaan",
|
||||
"processing": "Memproses",
|
||||
"success": "Kejayaan",
|
||||
"fail": "gagal",
|
||||
"close": "tertutup"
|
||||
"close": "tertutup",
|
||||
"cancel": "Cancelled"
|
||||
},
|
||||
"bizStatusColor": {
|
||||
"wait_pay": "oren",
|
||||
"paid": "hijau",
|
||||
"closed": "lalai",
|
||||
"expired": "merah"
|
||||
"expired": "merah",
|
||||
"paying": "processing",
|
||||
"failed": "red"
|
||||
},
|
||||
"fundStatusColor": {
|
||||
"init": "lalai",
|
||||
"processing": "pemprosesan",
|
||||
"success": "hijau",
|
||||
"fail": "merah",
|
||||
"close": "lalai"
|
||||
"close": "lalai",
|
||||
"cancel": "default"
|
||||
},
|
||||
"placeholder": {
|
||||
"bizOrderNo": "Masukkan no pesanan peniaga.",
|
||||
@@ -143,9 +159,6 @@
|
||||
"refundReasonPlaceholder": "Masukkan sebab bayaran balik (pilihan)",
|
||||
"refundAmountExceed": "Jumlah bayaran balik tidak boleh melebihi jumlah yang boleh dikembalikan"
|
||||
},
|
||||
"tradeType": {
|
||||
"normal": "Bayaran Biasa"
|
||||
},
|
||||
"method": {
|
||||
"jsapi": "JSAPI",
|
||||
"qrcode": "Kod QR",
|
||||
@@ -153,5 +166,13 @@
|
||||
"app": "APP",
|
||||
"barcode": "Kod Bar",
|
||||
"wap": "WAP"
|
||||
},
|
||||
"tradeType": {
|
||||
"normal": "Normal Pay",
|
||||
"gateway": "Gateway Pay"
|
||||
},
|
||||
"gatewayType": {
|
||||
"cashier": "Cashier",
|
||||
"aggregate": "Aggregate"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"normal": {
|
||||
"title": "คำสั่งการชำระเงิน",
|
||||
"detail": "รายละเอียดการสั่งซื้อการชำระเงิน"
|
||||
"title": "ชำระเงินปกติ",
|
||||
"detail": "รายละเอียดชำระเงินปกติ"
|
||||
},
|
||||
"gateway": {
|
||||
"title": "ชำระเงินเกตเวย์",
|
||||
"detail": "รายละเอียดชำระเงินเกตเวย์"
|
||||
},
|
||||
"trade": {
|
||||
"title": "การซื้อขายกองทุน",
|
||||
@@ -10,24 +14,30 @@
|
||||
"refund": {
|
||||
"title": "การคืนเงินคำสั่งซื้อ",
|
||||
"detail": "รายละเอียดการขอคืนเงิน",
|
||||
"statusLabel": "Refund Status",
|
||||
"section": {
|
||||
"identity": "Identity",
|
||||
"fund": "Fund",
|
||||
"amount": "Amount",
|
||||
"channel": "Channel",
|
||||
"notify": "Notify"
|
||||
},
|
||||
"status": {
|
||||
"init": "อักษรย่อ",
|
||||
"progress": "การคืนเงิน",
|
||||
"success": "ความสำเร็จ",
|
||||
"fail": "ล้มเหลว",
|
||||
"close": "ปิด"
|
||||
"progress": "Refunding",
|
||||
"success": "Success",
|
||||
"fail": "Failed",
|
||||
"close": "Closed"
|
||||
},
|
||||
"statusColor": {
|
||||
"init": "ค่าเริ่มต้น",
|
||||
"progress": "กำลังประมวลผล",
|
||||
"success": "สีเขียว",
|
||||
"fail": "สีแดง",
|
||||
"close": "ค่าเริ่มต้น"
|
||||
"progress": "processing",
|
||||
"success": "green",
|
||||
"fail": "red",
|
||||
"close": "default"
|
||||
}
|
||||
},
|
||||
"field": {
|
||||
"bizOrderNo": "เลขที่ใบสั่งซื้อของผู้ขาย",
|
||||
"tradeNo": "หมายเลขการค้า",
|
||||
"tradeNo": "Fund Trade No.",
|
||||
"title": "ชื่อ",
|
||||
"description": "คำอธิบาย",
|
||||
"amount": "จำนวนเงิน(หยวน)",
|
||||
@@ -41,7 +51,7 @@
|
||||
"provider": "ผู้ให้บริการ",
|
||||
"outOrderNo": "ช่องทางการสั่งซื้อเลขที่",
|
||||
"transOrderNo": "หมายเลขคำสั่งทรานส์",
|
||||
"relationOrderNo": "ความสัมพันธ์เลขที่คำสั่ง",
|
||||
"relationOrderNo": "Channel Relation No.",
|
||||
"postedAmount": "ยอดเข้าบัญชี (หยวน)",
|
||||
"refundableBalance": "สามารถขอคืนเงินได้ (หยวน)",
|
||||
"payBody": "จ่ายร่างกาย",
|
||||
@@ -77,7 +87,7 @@
|
||||
"reason": "เหตุผลในการคืนเงิน",
|
||||
"finishTime": "เสร็จสิ้นเวลา",
|
||||
"orderAmount": "จำนวนการสั่งซื้อ",
|
||||
"orderNo": "หมายเลขคำสั่งซื้อเดิม",
|
||||
"orderNo": "Platform Order No.",
|
||||
"authCode": "รหัสชำระเงิน",
|
||||
"merchant": "ร้านค้า"
|
||||
},
|
||||
@@ -85,27 +95,33 @@
|
||||
"wait_pay": "ซึ่งรอคอย",
|
||||
"paid": "จ่าย",
|
||||
"closed": "ปิด",
|
||||
"expired": "หมดอายุแล้ว"
|
||||
"expired": "หมดอายุแล้ว",
|
||||
"paying": "Paying",
|
||||
"failed": "Failed"
|
||||
},
|
||||
"fundStatus": {
|
||||
"init": "อักษรย่อ",
|
||||
"processing": "กำลังประมวลผล",
|
||||
"success": "ความสำเร็จ",
|
||||
"fail": "ล้มเหลว",
|
||||
"close": "ปิด"
|
||||
"close": "ปิด",
|
||||
"cancel": "Cancelled"
|
||||
},
|
||||
"bizStatusColor": {
|
||||
"wait_pay": "ส้ม",
|
||||
"paid": "สีเขียว",
|
||||
"closed": "ค่าเริ่มต้น",
|
||||
"expired": "สีแดง"
|
||||
"expired": "สีแดง",
|
||||
"paying": "processing",
|
||||
"failed": "red"
|
||||
},
|
||||
"fundStatusColor": {
|
||||
"init": "ค่าเริ่มต้น",
|
||||
"processing": "กำลังประมวลผล",
|
||||
"success": "สีเขียว",
|
||||
"fail": "สีแดง",
|
||||
"close": "ค่าเริ่มต้น"
|
||||
"close": "ค่าเริ่มต้น",
|
||||
"cancel": "default"
|
||||
},
|
||||
"placeholder": {
|
||||
"bizOrderNo": "ป้อนหมายเลขคำสั่งซื้อของร้านค้า",
|
||||
@@ -143,9 +159,6 @@
|
||||
"refundReasonPlaceholder": "ป้อนเหตุผลการคืนเงิน (ไม่บังคับ)",
|
||||
"refundAmountExceed": "จำนวนเงินคืนต้องไม่เกินจำนวนเงินที่สามารถขอคืนได้"
|
||||
},
|
||||
"tradeType": {
|
||||
"normal": "ชำระเงินปกติ"
|
||||
},
|
||||
"method": {
|
||||
"jsapi": "JSAPI",
|
||||
"qrcode": "สแกนโค้ด",
|
||||
@@ -153,5 +166,13 @@
|
||||
"app": "APP",
|
||||
"barcode": "บาร์โค้ด",
|
||||
"wap": "WAP"
|
||||
},
|
||||
"tradeType": {
|
||||
"normal": "Normal Pay",
|
||||
"gateway": "Gateway Pay"
|
||||
},
|
||||
"gatewayType": {
|
||||
"cashier": "Cashier",
|
||||
"aggregate": "Aggregate"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"normal": {
|
||||
"title": "Lệnh thanh toán",
|
||||
"detail": "Chi tiết đơn hàng thanh toán"
|
||||
"title": "Thanh toán thường",
|
||||
"detail": "Chi tiết thanh toán thường"
|
||||
},
|
||||
"gateway": {
|
||||
"title": "Thanh toán cổng",
|
||||
"detail": "Chi tiết thanh toán cổng"
|
||||
},
|
||||
"trade": {
|
||||
"title": "Giao dịch quỹ",
|
||||
@@ -10,24 +14,30 @@
|
||||
"refund": {
|
||||
"title": "Lệnh hoàn tiền",
|
||||
"detail": "Chi tiết đơn hàng hoàn tiền",
|
||||
"statusLabel": "Refund Status",
|
||||
"section": {
|
||||
"identity": "Identity",
|
||||
"fund": "Fund",
|
||||
"amount": "Amount",
|
||||
"channel": "Channel",
|
||||
"notify": "Notify"
|
||||
},
|
||||
"status": {
|
||||
"init": "Ban đầu",
|
||||
"progress": "Hoàn tiền",
|
||||
"success": "Thành công",
|
||||
"fail": "Thất bại",
|
||||
"close": "Đã đóng"
|
||||
"progress": "Refunding",
|
||||
"success": "Success",
|
||||
"fail": "Failed",
|
||||
"close": "Closed"
|
||||
},
|
||||
"statusColor": {
|
||||
"init": "mặc định",
|
||||
"progress": "xử lý",
|
||||
"success": "màu xanh lá",
|
||||
"fail": "màu đỏ",
|
||||
"close": "mặc định"
|
||||
"progress": "processing",
|
||||
"success": "green",
|
||||
"fail": "red",
|
||||
"close": "default"
|
||||
}
|
||||
},
|
||||
"field": {
|
||||
"bizOrderNo": "Số đơn đặt hàng của người bán",
|
||||
"tradeNo": "Số giao dịch",
|
||||
"tradeNo": "Fund Trade No.",
|
||||
"title": "Tiêu đề",
|
||||
"description": "Sự miêu tả",
|
||||
"amount": "Số tiền(Nhân dân tệ)",
|
||||
@@ -41,7 +51,7 @@
|
||||
"provider": "nhà cung cấp",
|
||||
"outOrderNo": "Số thứ tự kênh",
|
||||
"transOrderNo": "Số đơn hàng chuyển khoản",
|
||||
"relationOrderNo": "Số thứ tự quan hệ",
|
||||
"relationOrderNo": "Channel Relation No.",
|
||||
"postedAmount": "Số đã ghi sổ(Nhân dân tệ)",
|
||||
"refundableBalance": "Có thể hoàn lại(Nhân dân tệ)",
|
||||
"payBody": "Cơ quan thanh toán",
|
||||
@@ -77,7 +87,7 @@
|
||||
"reason": "Lý do hoàn tiền",
|
||||
"finishTime": "Thời gian kết thúc",
|
||||
"orderAmount": "Số tiền đặt hàng",
|
||||
"orderNo": "Số đơn đặt hàng ban đầu",
|
||||
"orderNo": "Platform Order No.",
|
||||
"authCode": "Mã thanh toán",
|
||||
"merchant": "Thương nhân"
|
||||
},
|
||||
@@ -85,27 +95,33 @@
|
||||
"wait_pay": "Chờ",
|
||||
"paid": "Trả",
|
||||
"closed": "Đã đóng",
|
||||
"expired": "Hết hạn"
|
||||
"expired": "Hết hạn",
|
||||
"paying": "Paying",
|
||||
"failed": "Failed"
|
||||
},
|
||||
"fundStatus": {
|
||||
"init": "Ban đầu",
|
||||
"processing": "Xử lý",
|
||||
"success": "Thành công",
|
||||
"fail": "Thất bại",
|
||||
"close": "Đã đóng"
|
||||
"close": "Đã đóng",
|
||||
"cancel": "Cancelled"
|
||||
},
|
||||
"bizStatusColor": {
|
||||
"wait_pay": "quả cam",
|
||||
"paid": "màu xanh lá",
|
||||
"closed": "mặc định",
|
||||
"expired": "màu đỏ"
|
||||
"expired": "màu đỏ",
|
||||
"paying": "processing",
|
||||
"failed": "red"
|
||||
},
|
||||
"fundStatusColor": {
|
||||
"init": "mặc định",
|
||||
"processing": "xử lý",
|
||||
"success": "màu xanh lá",
|
||||
"fail": "màu đỏ",
|
||||
"close": "mặc định"
|
||||
"close": "mặc định",
|
||||
"cancel": "default"
|
||||
},
|
||||
"placeholder": {
|
||||
"bizOrderNo": "Nhập số đơn đặt hàng của người bán.",
|
||||
@@ -143,9 +159,6 @@
|
||||
"refundReasonPlaceholder": "Nhập lý do hoàn tiền (tùy chọn)",
|
||||
"refundAmountExceed": "Số tiền hoàn lại không được vượt quá số tiền được hoàn lại"
|
||||
},
|
||||
"tradeType": {
|
||||
"normal": "Thanh toán thường"
|
||||
},
|
||||
"method": {
|
||||
"jsapi": "JSAPI",
|
||||
"qrcode": "Quét mã",
|
||||
@@ -153,5 +166,13 @@
|
||||
"app": "APP",
|
||||
"barcode": "Mã vạch",
|
||||
"wap": "WAP"
|
||||
},
|
||||
"tradeType": {
|
||||
"normal": "Normal Pay",
|
||||
"gateway": "Gateway Pay"
|
||||
},
|
||||
"gatewayType": {
|
||||
"cashier": "Cashier",
|
||||
"aggregate": "Aggregate"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +1,83 @@
|
||||
<script lang="ts" setup>
|
||||
import type { DashboardData } from '../types';
|
||||
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
import { $t } from '@vben/locales';
|
||||
import { formatDateTime } from '@vben/utils';
|
||||
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
import { NormalOrderApi, type NormalOrderResult } from '#/api/payment/order/normal-order.api';
|
||||
import { channelI18nMap } from '#/enums/payment/channelEnum';
|
||||
|
||||
interface Props {
|
||||
/** 工作台聚合数据(支付订单暂无后端 API,保留以统一 widget props 契约) */
|
||||
/** 工作台聚合数据(支付订单独立拉数据,保留以统一 widget props 契约) */
|
||||
data?: DashboardData;
|
||||
}
|
||||
|
||||
defineOptions({ name: 'PayOrderListWidget' });
|
||||
|
||||
// 支付订单暂无后端 API,保留 data prop 以统一 widget 渲染契约
|
||||
// 支付订单独立拉取数据,不消费聚合统计;保留 data prop 以统一 widget 渲染契约
|
||||
withDefaults(defineProps<Props>(), {
|
||||
data: undefined,
|
||||
});
|
||||
|
||||
const { message } = useMessage();
|
||||
const router = useRouter();
|
||||
|
||||
// 订单状态枚举
|
||||
type OrderStatus = 'closed' | 'fail' | 'success';
|
||||
const loading = ref(false);
|
||||
const orders = ref<NormalOrderResult[]>([]);
|
||||
|
||||
interface MockOrder {
|
||||
// 订单号
|
||||
orderNo: string;
|
||||
// 商品标题
|
||||
title: string;
|
||||
// 金额(元)
|
||||
amount: string;
|
||||
// 状态
|
||||
status: OrderStatus;
|
||||
// 支付渠道 code(对应 payment.channel.common.*)
|
||||
channel: string;
|
||||
// 时间(mock 字符串,直接展示)
|
||||
time: string;
|
||||
/** 拉取最近支付订单(按创建时间倒序取 20 条) */
|
||||
async function load() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await NormalOrderApi.page({ current: 1, size: 20 });
|
||||
orders.value = res?.data?.records || [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 订单标题模板池
|
||||
const titlePool = [
|
||||
'会员包年套餐',
|
||||
'商品购买',
|
||||
'VIP月卡续费',
|
||||
'电子书-架构之道',
|
||||
'课程订阅-进阶',
|
||||
'实物商品-配件',
|
||||
'软件授权-年度',
|
||||
'礼品卡充值',
|
||||
'直播打赏',
|
||||
'云服务-包月',
|
||||
];
|
||||
const channelPool = ['wechat', 'alipay', 'unionPay'];
|
||||
// 状态权重:success 出现概率更高
|
||||
const statusPool: OrderStatus[] = ['success', 'success', 'success', 'fail', 'closed'];
|
||||
const amountPool = ['299.00', '59.90', '19.90', '45.00', '199.00', '128.00', '88.88', '599.00', '36.50', '1080.00'];
|
||||
onMounted(load);
|
||||
|
||||
// 生成 20 条 mock 订单数据(后端支付订单管理 API 就绪后替换为真实请求结果)
|
||||
const mockOrders: MockOrder[] = Array.from({ length: 20 }).map((_, i) => {
|
||||
// 日期从 06-27 往前推,每 4 条一天
|
||||
const day = String(27 - Math.floor(i / 4)).padStart(2, '0');
|
||||
const hour = String(8 + (i % 14)).padStart(2, '0');
|
||||
const min = String((i * 13) % 60).padStart(2, '0');
|
||||
const seq = String(1001 + i);
|
||||
return {
|
||||
orderNo: `PAY202606${day}${hour}${min}${seq}`,
|
||||
title: i >= titlePool.length ? `${titlePool[i % titlePool.length]!} #${seq}` : titlePool[i]!,
|
||||
amount: amountPool[i % amountPool.length]!,
|
||||
status: statusPool[i % statusPool.length]!,
|
||||
channel: channelPool[i % channelPool.length]!,
|
||||
time: `2026-06-${day} ${hour}:${min}`,
|
||||
} as MockOrder;
|
||||
});
|
||||
|
||||
/** 订单状态 → a-tag color 映射 */
|
||||
function statusColor(status: OrderStatus): string {
|
||||
if (status === 'success') return 'green';
|
||||
if (status === 'fail') return 'red';
|
||||
return 'default';
|
||||
/** 跳转到普通支付订单列表("更多"按钮) */
|
||||
function goAll() {
|
||||
router.push({ name: '/trade/pay-order/normal' }).catch(() => {});
|
||||
}
|
||||
|
||||
/** 订单状态 → i18n key */
|
||||
function statusLabel(status: OrderStatus): string {
|
||||
return $t(`dashboard.workspace.payOrder.status.${status}`);
|
||||
/** 金额分转元 */
|
||||
function formatAmount(amount?: number): string {
|
||||
if (amount === null || amount === undefined) return '-';
|
||||
return (amount / 100).toFixed(2);
|
||||
}
|
||||
|
||||
/** "更多"按钮:支付订单管理页尚未开发,提示开发中 */
|
||||
function handleMore() {
|
||||
message.info($t('dashboard.workspace.payOrder.developing'));
|
||||
/** 业务状态颜色:复用订单页 bizStatusColor 配置 */
|
||||
function statusColor(status?: string): string {
|
||||
return status ? $t(`payment.order.bizStatusColor.${status}`) : 'default';
|
||||
}
|
||||
|
||||
/** 业务状态文案:复用订单页 bizStatus 配置 */
|
||||
function statusLabel(status?: string): string {
|
||||
return status ? $t(`payment.order.bizStatus.${status}`) : '-';
|
||||
}
|
||||
|
||||
/** 支付通道展示名:channelI18nMap 取 i18n key 再翻译,无映射时降级原 code */
|
||||
function channelLabel(channel?: string): string {
|
||||
if (!channel) return '-';
|
||||
const i18nKey = channelI18nMap[channel];
|
||||
if (i18nKey) {
|
||||
const text = $t(i18nKey);
|
||||
if (text && text !== i18nKey) return text;
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
/** 时间格式化:优先支付成功时间,降级创建时间 */
|
||||
function fmtTime(order: NormalOrderResult): string {
|
||||
const time = order.payTime || order.createTime;
|
||||
if (!time) return '-';
|
||||
return formatDateTime(time) || '-';
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -100,27 +90,31 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #extra>
|
||||
<a-button type="link" size="small" @click="handleMore">{{ $t('common.more') }}</a-button>
|
||||
<a-button type="link" size="small" @click="goAll">{{ $t('common.more') }}</a-button>
|
||||
</template>
|
||||
|
||||
<a-skeleton v-if="loading" active :paragraph="{ rows: 5 }" />
|
||||
<a-empty v-else-if="orders.length === 0" class="!my-6" />
|
||||
<!-- 订单列表:固定高度滚动,与左右卡片等高协调 -->
|
||||
<ul class="pay-order-scroll flex max-h-[230px] flex-col gap-3 overflow-y-auto pr-1">
|
||||
<li v-for="(order, index) in mockOrders" :key="index" class="flex flex-col gap-1">
|
||||
<ul v-else class="pay-order-scroll flex max-h-[230px] flex-col gap-3 overflow-y-auto pr-1">
|
||||
<li v-for="(order, index) in orders" :key="order.id ?? index" class="flex flex-col gap-1">
|
||||
<!-- 行1:状态标签 + 标题 + 金额 -->
|
||||
<div class="flex items-center gap-2">
|
||||
<a-tag :color="statusColor(order.status)" class="!m-0 !shrink-0 text-xs">
|
||||
{{ statusLabel(order.status) }}
|
||||
</a-tag>
|
||||
<span class="text-foreground/80 flex-1 truncate text-sm">{{ order.title }}</span>
|
||||
<span class="text-foreground shrink-0 text-sm font-semibold tabular-nums">¥{{ order.amount }}</span>
|
||||
<span class="text-foreground/80 flex-1 truncate text-sm">{{ order.title || '-' }}</span>
|
||||
<span class="text-foreground shrink-0 text-sm font-semibold tabular-nums"
|
||||
>¥{{ formatAmount(order.amount) }}</span
|
||||
>
|
||||
</div>
|
||||
<!-- 行2:订单号 · 渠道 · 时间 -->
|
||||
<p class="text-foreground/40 truncate text-xs">
|
||||
<span>{{ order.orderNo }}</span>
|
||||
<span>{{ order.orderNo || '-' }}</span>
|
||||
<span class="mx-1">·</span>
|
||||
<span>{{ $t(`payment.channel.common.${order.channel}`) }}</span>
|
||||
<span>{{ channelLabel(order.channel) }}</span>
|
||||
<span class="mx-1">·</span>
|
||||
<span>{{ order.time }}</span>
|
||||
<span>{{ fmtTime(order) }}</span>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -113,7 +113,7 @@ export const ENTRY_CATALOG: QuickEntryMeta[] = [
|
||||
// 以下为可选扩展入口(默认不显示,用户在编辑抽屉按需添加)
|
||||
{
|
||||
key: 'payOrder',
|
||||
routeName: '/trade/normal-pay',
|
||||
routeName: '/trade/pay-order/normal',
|
||||
icon: 'lucide:receipt',
|
||||
titleKey: 'dashboard.workspace.quickEntry.payOrder',
|
||||
color: 'bg-blue-600',
|
||||
|
||||
529
apps/daxpay-admin/src/views/payment/order/GatewayOrderList.vue
Normal file
529
apps/daxpay-admin/src/views/payment/order/GatewayOrderList.vue
Normal file
@@ -0,0 +1,529 @@
|
||||
<script lang="ts" setup>
|
||||
import type { MenuProps } from 'antdv-next';
|
||||
import type { VxeTableInstance, VxeToolbarInstance } from 'vxe-table';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { IconifyIcon } from '@vben-core/icons';
|
||||
|
||||
import {
|
||||
GatewayOrderApi,
|
||||
type GatewayOrderQuery,
|
||||
type GatewayOrderResult,
|
||||
} from '#/api/payment/order/gateway-order.api';
|
||||
import { type RefundParam, RefundOrderApi } from '#/api/payment/order/refund-order.api';
|
||||
import { BQuery, type QueryField } from '#/components/query';
|
||||
import { PermCodes } from '#/constants/perm-codes';
|
||||
import { productI18nMap, productNameMap } from '#/enums/payment';
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
import { usePermission } from '#/hooks/usePermission';
|
||||
|
||||
defineOptions({ name: 'GatewayOrderList' });
|
||||
|
||||
const { confirm, message } = useMessage();
|
||||
const { hasPermission } = usePermission();
|
||||
|
||||
const loading = ref(false);
|
||||
const xTable = ref<VxeTableInstance>();
|
||||
const xToolbar = ref<VxeToolbarInstance>();
|
||||
|
||||
const queryForm = ref<GatewayOrderQuery>({});
|
||||
|
||||
const pageConfig = ref({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const tableData = ref<GatewayOrderResult[]>([]);
|
||||
|
||||
const drawerVisible = ref(false);
|
||||
const drawerLoading = ref(false);
|
||||
const detail = ref<GatewayOrderResult>({});
|
||||
const actionLoading = ref(false);
|
||||
|
||||
// 退款弹窗
|
||||
const refundVisible = ref(false);
|
||||
const refundLoading = ref(false);
|
||||
const refundFetching = ref(false);
|
||||
const refundFormRef = ref();
|
||||
const refundForm = ref<{ amount?: number; tradeNo?: string; reason?: string }>({ amount: undefined, reason: '' });
|
||||
const refundRow = ref<GatewayOrderResult | null>(null);
|
||||
const refundableYuan = computed(() => (refundRow.value?.refundableBalance ?? 0) / 100);
|
||||
const refundRules = computed(() => ({
|
||||
amount: [
|
||||
{ required: true, message: $t('payment.order.action.refundAmountPlaceholder') },
|
||||
{
|
||||
type: 'number',
|
||||
min: 0.01,
|
||||
message: $t('payment.order.action.refundAmountPlaceholder'),
|
||||
},
|
||||
{
|
||||
validator: async (_rule: unknown, value: number) => {
|
||||
if (value != null && value > refundableYuan.value) {
|
||||
return Promise.reject(new Error($t('payment.order.action.refundAmountExceed')));
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
// 网关业务状态
|
||||
const statusOptions = computed(() =>
|
||||
['wait_pay', 'paying', 'paid', 'failed', 'closed', 'expired'].map((v) => ({
|
||||
label: $t(`payment.order.bizStatus.${v}`),
|
||||
value: v,
|
||||
})),
|
||||
);
|
||||
|
||||
const gatewayTypeOptions = computed(() =>
|
||||
['cashier', 'aggregate'].map((v) => ({
|
||||
label: $t(`payment.order.gatewayType.${v}`),
|
||||
value: v,
|
||||
})),
|
||||
);
|
||||
|
||||
// 支付产品下拉
|
||||
const productOptions = computed(() =>
|
||||
Object.keys(productNameMap).map((code) => ({
|
||||
label: productLabel(code),
|
||||
value: code,
|
||||
})),
|
||||
);
|
||||
|
||||
const queryFields = computed<QueryField[]>(() => [
|
||||
{
|
||||
type: 'string',
|
||||
field: 'orderNo',
|
||||
name: $t('payment.order.field.orderNo'),
|
||||
placeholder: $t('payment.order.placeholder.orderNo'),
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
field: 'bizOrderNo',
|
||||
name: $t('payment.order.field.bizOrderNo'),
|
||||
placeholder: $t('payment.order.placeholder.bizOrderNo'),
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
field: 'status',
|
||||
name: $t('payment.order.field.bizStatus'),
|
||||
selectList: statusOptions.value,
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
field: 'gatewayType',
|
||||
// 网关类型
|
||||
name: $t('payment.order.field.gatewayType'),
|
||||
selectList: gatewayTypeOptions.value,
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
field: 'product',
|
||||
// 支付产品
|
||||
name: $t('payment.order.field.product'),
|
||||
selectList: productOptions.value,
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
field: 'capability',
|
||||
// 支付能力
|
||||
name: $t('payment.order.field.capability'),
|
||||
},
|
||||
{
|
||||
type: 'date_time_range',
|
||||
field: 'createTime',
|
||||
name: $t('payment.order.field.createTime'),
|
||||
startField: 'createTimeStart',
|
||||
endField: 'createTimeEnd',
|
||||
},
|
||||
]);
|
||||
|
||||
function queryPage() {
|
||||
loading.value = true;
|
||||
return GatewayOrderApi.page({
|
||||
current: pageConfig.value.currentPage,
|
||||
size: pageConfig.value.pageSize,
|
||||
...queryForm.value,
|
||||
})
|
||||
.then((res) => {
|
||||
tableData.value = res.data?.records || [];
|
||||
pageConfig.value.total = Number(res.data?.total) || 0;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
queryForm.value = {};
|
||||
pageConfig.value.currentPage = 1;
|
||||
queryPage();
|
||||
}
|
||||
|
||||
function handlePageChange({ currentPage, pageSize }: { currentPage: number; pageSize: number }) {
|
||||
pageConfig.value.currentPage = currentPage;
|
||||
pageConfig.value.pageSize = pageSize;
|
||||
queryPage();
|
||||
}
|
||||
|
||||
function formatAmount(amount?: number): string {
|
||||
if (amount === null || amount === undefined) return '-';
|
||||
return (amount / 100).toFixed(2);
|
||||
}
|
||||
|
||||
function statusColor(status?: string): string {
|
||||
return status ? $t(`payment.order.bizStatusColor.${status}`) : 'default';
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付产品展示名
|
||||
*/
|
||||
function productLabel(code?: string): string {
|
||||
if (!code) return '-';
|
||||
const i18nKey = productI18nMap[code];
|
||||
if (i18nKey) {
|
||||
const text = $t(i18nKey);
|
||||
if (text && text !== i18nKey) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
return productNameMap[code] || code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付能力展示名
|
||||
*/
|
||||
function capabilityLabel(code?: string): string {
|
||||
if (!code) return '-';
|
||||
const i18nKey = `payment.merchant.cashier.cashier.capabilities.${code}`;
|
||||
const text = $t(i18nKey);
|
||||
return text && text !== i18nKey ? text : code;
|
||||
}
|
||||
|
||||
async function handleView(row: GatewayOrderResult) {
|
||||
drawerVisible.value = true;
|
||||
drawerLoading.value = true;
|
||||
try {
|
||||
const { data } = await GatewayOrderApi.getById(row.id!);
|
||||
detail.value = data || {};
|
||||
} finally {
|
||||
drawerLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSync(row: GatewayOrderResult) {
|
||||
confirm({
|
||||
title: $t('payment.order.action.syncConfirmTitle'),
|
||||
content: $t('payment.order.action.syncConfirmContent'),
|
||||
onOk() {
|
||||
actionLoading.value = true;
|
||||
return GatewayOrderApi.sync(row.id!)
|
||||
.then(() => {
|
||||
message.success($t('payment.order.action.syncSuccess'));
|
||||
queryPage();
|
||||
})
|
||||
.finally(() => {
|
||||
actionLoading.value = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleClose(row: GatewayOrderResult) {
|
||||
confirm({
|
||||
title: $t('payment.order.action.closeConfirmTitle'),
|
||||
content: $t('payment.order.action.closeConfirmContent'),
|
||||
onOk() {
|
||||
actionLoading.value = true;
|
||||
return GatewayOrderApi.close(row.id!)
|
||||
.then(() => {
|
||||
message.success($t('payment.order.action.closeSuccess'));
|
||||
queryPage();
|
||||
})
|
||||
.finally(() => {
|
||||
actionLoading.value = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function openRefund(row: GatewayOrderResult) {
|
||||
refundRow.value = row;
|
||||
refundVisible.value = true;
|
||||
refundFetching.value = true;
|
||||
try {
|
||||
const { data } = await GatewayOrderApi.getById(row.id!);
|
||||
refundRow.value = data || row;
|
||||
refundForm.value = {
|
||||
tradeNo: data?.tradeNo,
|
||||
reason: '',
|
||||
amount: (data?.refundableBalance ?? 0) / 100,
|
||||
};
|
||||
} finally {
|
||||
refundFetching.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function submitRefund() {
|
||||
if (!refundRow.value) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await refundFormRef.value?.validate();
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
const amountYuan = refundForm.value.amount ?? 0;
|
||||
const param: RefundParam = {
|
||||
tradeNo: refundForm.value.tradeNo,
|
||||
bizOrderNo: refundRow.value.bizOrderNo,
|
||||
amount: Math.round(amountYuan * 100),
|
||||
reason: refundForm.value.reason,
|
||||
};
|
||||
confirm({
|
||||
title: $t('payment.order.action.refundConfirmTitle'),
|
||||
content: $t('payment.order.action.refundConfirmContent', { amount: amountYuan.toFixed(2) }),
|
||||
onOk() {
|
||||
refundLoading.value = true;
|
||||
return RefundOrderApi.refund(param)
|
||||
.then(() => {
|
||||
message.success($t('payment.order.action.refundSuccess'));
|
||||
refundVisible.value = false;
|
||||
queryPage();
|
||||
})
|
||||
.finally(() => {
|
||||
refundLoading.value = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function getActionMenu(row: GatewayOrderResult): MenuProps {
|
||||
const items: MenuProps['items'] = [];
|
||||
if (hasPermission(PermCodes.Trade.GatewayOrder.MANAGE)) {
|
||||
if (row.status === 'wait_pay' || row.status === 'paying') {
|
||||
items.push({ key: 'sync', label: $t('payment.order.action.sync') });
|
||||
items.push({ key: 'close', label: $t('payment.order.action.close'), danger: true });
|
||||
}
|
||||
if (row.status === 'paid') {
|
||||
items.push({ key: 'sync', label: $t('payment.order.action.sync') });
|
||||
if (hasPermission(PermCodes.Trade.Refund.MANAGE)) {
|
||||
items.push({ key: 'refund', label: $t('payment.order.action.refund'), danger: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
items,
|
||||
onClick: ({ key }) => {
|
||||
switch (key) {
|
||||
case 'sync': {
|
||||
handleSync(row);
|
||||
break;
|
||||
}
|
||||
case 'close': {
|
||||
handleClose(row);
|
||||
break;
|
||||
}
|
||||
case 'refund': {
|
||||
openRefund(row);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function handleDrawerClose() {
|
||||
drawerVisible.value = false;
|
||||
detail.value = {};
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
xTable.value?.connectToolbar(xToolbar.value as VxeToolbarInstance);
|
||||
queryPage();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="m-3 p-3 bg-background rounded-lg list-page-compact">
|
||||
<a-card>
|
||||
<BQuery :fields="queryFields" :query-params="queryForm" @query="queryPage" @reset="resetQuery" />
|
||||
</a-card>
|
||||
|
||||
<div class="mt-4">
|
||||
<a-card>
|
||||
<vxe-toolbar ref="xToolbar" custom refresh :refresh-options="{ queryMethod: queryPage }" />
|
||||
<vxe-table ref="xTable" :row-config="{ keyField: 'id' }" :data="tableData" :loading="loading">
|
||||
<vxe-column type="seq" :title="$t('common.seq')" width="60" align="center" />
|
||||
<vxe-column field="mchName" :title="$t('payment.order.field.merchant')" :min-width="160">
|
||||
<template #default="{ row }">
|
||||
<div class="flex flex-col">
|
||||
<span>{{ row.mchName || '-' }}</span>
|
||||
<span v-if="row.mchNo" class="text-xs text-muted-foreground">{{ row.mchNo }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="orderNo" :title="$t('payment.order.field.orderNo')" :min-width="200" show-overflow />
|
||||
<vxe-column field="bizOrderNo" :title="$t('payment.order.field.bizOrderNo')" :min-width="180" show-overflow />
|
||||
<vxe-column field="gatewayType" :title="$t('payment.order.field.gatewayType')" :min-width="100">
|
||||
<template #default="{ row }">
|
||||
{{ row.gatewayType ? $t(`payment.order.gatewayType.${row.gatewayType}`) : '-' }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="title" :title="$t('payment.order.field.title')" :min-width="140" show-overflow />
|
||||
<vxe-column field="amount" :title="$t('payment.order.field.amount')" :min-width="100" align="right">
|
||||
<template #default="{ row }">{{ formatAmount(row.amount) }}</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="status" :title="$t('payment.order.field.bizStatus')" :min-width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<a-tag :color="statusColor(row.status)">
|
||||
{{ $t(`payment.order.bizStatus.${row.status}`) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="product" :title="$t('payment.order.field.product')" :min-width="140" show-overflow>
|
||||
<template #default="{ row }">{{ productLabel(row.product) }}</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="capability" :title="$t('payment.order.field.capability')" :min-width="140" show-overflow>
|
||||
<template #default="{ row }">{{ capabilityLabel(row.capability) }}</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
field="createTime"
|
||||
:title="$t('payment.order.field.createTime')"
|
||||
:min-width="160"
|
||||
formatter="formatDateTime"
|
||||
/>
|
||||
<vxe-column :title="$t('common.operation')" width="160" fixed="right" :show-overflow="false">
|
||||
<template #default="{ row }">
|
||||
<a-space :size="2">
|
||||
<template #separator>
|
||||
<a-divider type="vertical" />
|
||||
</template>
|
||||
<a-button type="link" size="small" @click="handleView(row)">
|
||||
{{ $t('common.view') }}
|
||||
</a-button>
|
||||
<a-dropdown v-if="getActionMenu(row).items?.length" :menu="getActionMenu(row)">
|
||||
<a-button type="link" size="small">
|
||||
{{ $t('common.more') }}
|
||||
<IconifyIcon icon="ant-design:down-outlined" class="inline" />
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
<vxe-pager
|
||||
size="medium"
|
||||
:loading="loading"
|
||||
:current-page="pageConfig.currentPage"
|
||||
:page-size="pageConfig.pageSize"
|
||||
:total="pageConfig.total"
|
||||
@page-change="handlePageChange"
|
||||
/>
|
||||
</a-card>
|
||||
</div>
|
||||
|
||||
<a-drawer
|
||||
v-model:open="drawerVisible"
|
||||
:title="$t('payment.order.gateway.detail')"
|
||||
:size="900"
|
||||
@close="handleDrawerClose"
|
||||
>
|
||||
<a-spin :spinning="drawerLoading">
|
||||
<a-descriptions :column="2" size="small" bordered>
|
||||
<a-descriptions-item :label="$t('payment.order.field.merchant')">
|
||||
{{ detail.mchName || '-' }}
|
||||
<span v-if="detail.mchNo" class="text-muted-foreground"> ({{ detail.mchNo }})</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.orderNo')">
|
||||
{{ detail.orderNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.bizOrderNo')">
|
||||
{{ detail.bizOrderNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.tradeNo')">
|
||||
{{ detail.tradeNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.title')">
|
||||
{{ detail.title || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.bizStatus')">
|
||||
<a-tag :color="statusColor(detail.status)">
|
||||
{{ detail.status ? $t(`payment.order.bizStatus.${detail.status}`) : '-' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.amount')">
|
||||
{{ formatAmount(detail.amount) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.fundStatus')">
|
||||
{{ detail.fundStatus ? $t(`payment.order.fundStatus.${detail.fundStatus}`) : '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.product')">
|
||||
{{ productLabel(detail.product) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.capability')">
|
||||
{{ capabilityLabel(detail.capability) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.channel')">
|
||||
{{ detail.channel || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.method')">
|
||||
{{ detail.method || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.outOrderNo')">
|
||||
{{ detail.outOrderNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.refundableBalance')">
|
||||
{{ formatAmount(detail.refundableBalance) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.payTime')">
|
||||
{{ detail.payTime || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.clientIp')">
|
||||
{{ detail.clientIp || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.storeNo')">
|
||||
{{ detail.storeNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.errorMsg')" :span="2">
|
||||
{{ detail.errorMsg || '-' }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-spin>
|
||||
<template #footer>
|
||||
<a-button @click="handleDrawerClose">{{ $t('common.close') }}</a-button>
|
||||
</template>
|
||||
</a-drawer>
|
||||
|
||||
<!-- 退款弹窗 -->
|
||||
<a-modal
|
||||
v-model:open="refundVisible"
|
||||
:title="$t('payment.order.action.refund')"
|
||||
:confirm-loading="refundLoading"
|
||||
:ok-button-props="{ disabled: refundFetching || !refundForm.tradeNo }"
|
||||
@ok="submitRefund"
|
||||
@cancel="refundVisible = false"
|
||||
>
|
||||
<a-spin :spinning="refundFetching">
|
||||
<a-form ref="refundFormRef" layout="vertical" :model="refundForm" :rules="refundRules">
|
||||
<a-form-item :label="$t('payment.order.field.tradeNo')">
|
||||
<a-input :value="refundForm.tradeNo" disabled />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('payment.order.action.refundableBalanceLabel')">
|
||||
{{ refundableYuan.toFixed(2) }}
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('payment.order.action.refundAmountLabel')" name="amount">
|
||||
<a-input-number v-model:value="refundForm.amount" class="w-full" :min="0.01" :precision="2" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('payment.order.action.refundReasonLabel')" name="reason">
|
||||
<a-textarea v-model:value="refundForm.reason" :placeholder="$t('payment.order.action.refundReasonPlaceholder')" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
@@ -8,6 +8,7 @@
|
||||
import { RefundOrderApi, type RefundOrderQuery, type RefundOrderResult } from '#/api/payment/order/refund-order.api';
|
||||
import { BQuery, type QueryField } from '#/components/query';
|
||||
import { PermCodes } from '#/constants/perm-codes';
|
||||
import { productI18nMap, productNameMap } from '#/enums/payment';
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
import { usePermission } from '#/hooks/usePermission';
|
||||
|
||||
@@ -20,7 +21,6 @@
|
||||
const xTable = ref<VxeTableInstance>();
|
||||
const xToolbar = ref<VxeToolbarInstance>();
|
||||
|
||||
// 查询条件
|
||||
const queryForm = ref<RefundOrderQuery>({});
|
||||
|
||||
const pageConfig = ref({
|
||||
@@ -31,29 +31,35 @@
|
||||
|
||||
const tableData = ref<RefundOrderResult[]>([]);
|
||||
|
||||
// 详情抽屉
|
||||
const drawerVisible = ref(false);
|
||||
const drawerLoading = ref(false);
|
||||
const detail = ref<RefundOrderResult>({});
|
||||
const actionLoading = ref(false);
|
||||
|
||||
// 退款状态下拉
|
||||
// 退款状态(无 init)
|
||||
const statusOptions = computed(() =>
|
||||
['init', 'progress', 'success', 'fail', 'close'].map((v) => ({
|
||||
['progress', 'success', 'fail', 'close'].map((v) => ({
|
||||
label: $t(`payment.order.refund.status.${v}`),
|
||||
value: v,
|
||||
})),
|
||||
);
|
||||
|
||||
// 支付通道下拉(常用通道)
|
||||
const channelOptions = computed(() =>
|
||||
['alipay', 'wechat', 'douyin'].map((v) => ({
|
||||
label: $t(`payment.channel.common.${v}`),
|
||||
// 交易类型(原支付形态)
|
||||
const tradeTypeOptions = computed(() =>
|
||||
['normal', 'gateway'].map((v) => ({
|
||||
label: $t(`payment.order.tradeType.${v}`),
|
||||
value: v,
|
||||
})),
|
||||
);
|
||||
|
||||
// 查询字段
|
||||
// 支付产品
|
||||
const productOptions = computed(() =>
|
||||
Object.keys(productNameMap).map((code) => ({
|
||||
label: productLabel(code),
|
||||
value: code,
|
||||
})),
|
||||
);
|
||||
|
||||
const queryFields = computed<QueryField[]>(() => [
|
||||
{
|
||||
type: 'string',
|
||||
@@ -63,9 +69,10 @@
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
field: 'orderNo',
|
||||
name: $t('payment.order.field.orderNo'),
|
||||
placeholder: $t('payment.order.placeholder.orderNo'),
|
||||
field: 'tradeNo',
|
||||
// 资金交易号
|
||||
name: $t('payment.order.field.tradeNo'),
|
||||
placeholder: $t('payment.order.placeholder.tradeNo'),
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
@@ -76,14 +83,23 @@
|
||||
{
|
||||
type: 'list',
|
||||
field: 'status',
|
||||
name: $t('payment.order.field.bizStatus'),
|
||||
// 退款状态
|
||||
name: $t('payment.order.refund.statusLabel'),
|
||||
selectList: statusOptions.value,
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
field: 'channel',
|
||||
name: $t('payment.order.field.channel'),
|
||||
selectList: channelOptions.value,
|
||||
field: 'tradeType',
|
||||
// 交易类型
|
||||
name: $t('payment.order.field.tradeType'),
|
||||
selectList: tradeTypeOptions.value,
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
field: 'product',
|
||||
// 支付产品
|
||||
name: $t('payment.order.field.product'),
|
||||
selectList: productOptions.value,
|
||||
},
|
||||
{
|
||||
type: 'date_time_range',
|
||||
@@ -94,9 +110,6 @@
|
||||
},
|
||||
]);
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*/
|
||||
function queryPage() {
|
||||
loading.value = true;
|
||||
return RefundOrderApi.page({
|
||||
@@ -126,29 +139,33 @@
|
||||
queryPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* 金额分转元
|
||||
*/
|
||||
function formatAmount(amount?: number): string {
|
||||
if (amount === null || amount === undefined) return '-';
|
||||
return (amount / 100).toFixed(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款状态颜色
|
||||
*/
|
||||
function statusColor(status?: string): string {
|
||||
return status ? $t(`payment.order.refund.statusColor.${status}`) : 'default';
|
||||
}
|
||||
|
||||
function channelLabel(code?: string): string {
|
||||
function productLabel(code?: string): string {
|
||||
if (!code) return '-';
|
||||
return channelOptions.value.find((o) => o.value === code)?.label || code;
|
||||
const i18nKey = productI18nMap[code];
|
||||
if (i18nKey) {
|
||||
const text = $t(i18nKey);
|
||||
if (text && text !== i18nKey) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
return productNameMap[code] || code;
|
||||
}
|
||||
|
||||
function tradeTypeLabel(code?: string): string {
|
||||
if (!code) return '-';
|
||||
const text = $t(`payment.order.tradeType.${code}`);
|
||||
return text && text !== `payment.order.tradeType.${code}` ? text : code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看详情
|
||||
*/
|
||||
async function handleView(row: RefundOrderResult) {
|
||||
drawerVisible.value = true;
|
||||
drawerLoading.value = true;
|
||||
@@ -160,9 +177,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步退款状态
|
||||
*/
|
||||
function handleSync(row: RefundOrderResult) {
|
||||
confirm({
|
||||
title: $t('payment.order.action.syncConfirmTitle'),
|
||||
@@ -203,39 +217,35 @@
|
||||
<vxe-toolbar ref="xToolbar" custom refresh :refresh-options="{ queryMethod: queryPage }" />
|
||||
<vxe-table ref="xTable" :row-config="{ keyField: 'id' }" :data="tableData" :loading="loading">
|
||||
<vxe-column type="seq" :title="$t('common.seq')" width="60" align="center" />
|
||||
<!-- 商户: 名称上 + 号下小字两排 -->
|
||||
<vxe-column field="mchName" :title="$t('payment.order.field.merchant')" :min-width="160">
|
||||
<template #default="{ row }">
|
||||
<div class="flex flex-col">
|
||||
<span>{{ row.mchName || '-' }}</span>
|
||||
<span>{{ row.mchName || row.mchNo || '-' }}</span>
|
||||
<span v-if="row.mchNo" class="text-xs text-muted-foreground">{{ row.mchNo }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="refundNo" :title="$t('payment.order.field.refundNo')" :min-width="200" show-overflow />
|
||||
<vxe-column field="orderNo" :title="$t('payment.order.field.orderNo')" :min-width="200" show-overflow />
|
||||
<vxe-column field="tradeNo" :title="$t('payment.order.field.tradeNo')" :min-width="200" show-overflow />
|
||||
<vxe-column field="bizOrderNo" :title="$t('payment.order.field.bizOrderNo')" :min-width="180" show-overflow />
|
||||
<vxe-column field="amount" :title="$t('payment.order.field.amount')" :min-width="100" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ formatAmount(row.amount) }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="status" :title="$t('payment.order.field.bizStatus')" :min-width="100" align="center">
|
||||
<vxe-column field="status" :title="$t('payment.order.refund.statusLabel')" :min-width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<a-tag :color="statusColor(row.status)">
|
||||
{{ $t(`payment.order.refund.status.${row.status}`) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="channel" :title="$t('payment.order.field.channel')" :min-width="100">
|
||||
<template #default="{ row }">{{ channelLabel(row.channel) }}</template>
|
||||
<vxe-column field="tradeType" :title="$t('payment.order.field.tradeType')" :min-width="110">
|
||||
<template #default="{ row }">{{ tradeTypeLabel(row.tradeType) }}</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="product" :title="$t('payment.order.field.product')" :min-width="140" show-overflow>
|
||||
<template #default="{ row }">{{ productLabel(row.product) }}</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
field="finishTime"
|
||||
:title="$t('payment.order.field.finishTime')"
|
||||
:min-width="160"
|
||||
formatter="formatDateTime"
|
||||
/>
|
||||
<vxe-column
|
||||
field="createTime"
|
||||
:title="$t('payment.order.field.createTime')"
|
||||
@@ -275,18 +285,22 @@
|
||||
</a-card>
|
||||
</div>
|
||||
|
||||
<!-- 详情抽屉 -->
|
||||
<a-drawer
|
||||
v-model:open="drawerVisible"
|
||||
:title="$t('payment.order.refund.detail')"
|
||||
:size="700"
|
||||
:size="720"
|
||||
@close="handleDrawerClose"
|
||||
>
|
||||
<a-spin :spinning="drawerLoading">
|
||||
<a-descriptions :column="2" size="small" bordered>
|
||||
<!-- 身份信息 -->
|
||||
<div class="mb-4 text-sm font-medium">{{ $t('payment.order.refund.section.identity') }}</div>
|
||||
<a-descriptions :column="2" size="small" bordered class="mb-4">
|
||||
<a-descriptions-item :label="$t('payment.order.field.merchant')">
|
||||
{{ detail.mchName || '-' }}
|
||||
<span v-if="detail.mchNo" class="text-muted-foreground"> ({{ detail.mchNo }})</span>
|
||||
{{ detail.mchName || detail.mchNo || '-' }}
|
||||
<span v-if="detail.mchName && detail.mchNo" class="text-muted-foreground"> ({{ detail.mchNo }})</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.appId')">
|
||||
{{ detail.appId || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.refundNo')">
|
||||
{{ detail.refundNo || '-' }}
|
||||
@@ -294,32 +308,51 @@
|
||||
<a-descriptions-item :label="$t('payment.order.field.bizRefundNo')">
|
||||
{{ detail.bizRefundNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.orderNo')">
|
||||
{{ detail.orderNo || '-' }}
|
||||
<a-descriptions-item :label="$t('payment.order.field.title')" :span="2">
|
||||
{{ detail.title || '-' }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<!-- 关联资金 -->
|
||||
<div class="mb-4 text-sm font-medium">{{ $t('payment.order.refund.section.fund') }}</div>
|
||||
<a-descriptions :column="2" size="small" bordered class="mb-4">
|
||||
<a-descriptions-item :label="$t('payment.order.field.tradeNo')">
|
||||
{{ detail.tradeNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.tradeType')">
|
||||
{{ tradeTypeLabel(detail.tradeType) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.bizOrderNo')">
|
||||
{{ detail.bizOrderNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.outOrderNo')">
|
||||
{{ detail.outOrderNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.relationOrderNo')">
|
||||
{{ detail.relationOrderNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.outRefundNo')">
|
||||
{{ detail.outRefundNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.bizStatus')">
|
||||
</a-descriptions>
|
||||
|
||||
<!-- 金额与状态 -->
|
||||
<div class="mb-4 text-sm font-medium">{{ $t('payment.order.refund.section.amount') }}</div>
|
||||
<a-descriptions :column="2" size="small" bordered class="mb-4">
|
||||
<a-descriptions-item :label="$t('payment.order.refund.statusLabel')">
|
||||
<a-tag :color="statusColor(detail.status)">
|
||||
{{ detail.status ? $t(`payment.order.refund.status.${detail.status}`) : '-' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.currency')">
|
||||
{{ detail.currency || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.amount')">
|
||||
{{ formatAmount(detail.amount) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.orderAmount')">
|
||||
{{ formatAmount(detail.orderAmount) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.channel')">
|
||||
{{ channelLabel(detail.channel) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.method')">
|
||||
{{ detail.method || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.reason')" :span="2">
|
||||
{{ detail.reason || '-' }}
|
||||
</a-descriptions-item>
|
||||
@@ -333,6 +366,40 @@
|
||||
{{ detail.errorMsg || '-' }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<!-- 通道快照(产品为主,不展示能力) -->
|
||||
<div class="mb-4 text-sm font-medium">{{ $t('payment.order.refund.section.channel') }}</div>
|
||||
<a-descriptions :column="2" size="small" bordered class="mb-4">
|
||||
<a-descriptions-item :label="$t('payment.order.field.product')">
|
||||
{{ productLabel(detail.product) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.channel')">
|
||||
{{ detail.channel || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.channelMchNo')">
|
||||
{{ detail.channelMchNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.channelAppId')">
|
||||
{{ detail.channelAppId || '-' }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<!-- 通知与审计 -->
|
||||
<div class="mb-4 text-sm font-medium">{{ $t('payment.order.refund.section.notify') }}</div>
|
||||
<a-descriptions :column="2" size="small" bordered>
|
||||
<a-descriptions-item :label="$t('payment.order.field.notifyUrl')" :span="2">
|
||||
{{ detail.notifyUrl || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.attach')" :span="2">
|
||||
{{ detail.attach || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.clientIp')">
|
||||
{{ detail.clientIp || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="$t('payment.order.field.storeNo')">
|
||||
{{ detail.storeNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-spin>
|
||||
|
||||
<template #footer>
|
||||
|
||||
Reference in New Issue
Block a user