Merge branch 'main' of http://1.117.67.95:3000/team/tyc-admin-v2
This commit is contained in:
@@ -588,6 +588,8 @@ export interface ReviewBankCardWithdrawalParams {
|
||||
withdrawal_id: number;
|
||||
action: 1 | 2; // 1-确认, 2-拒绝
|
||||
remark?: string;
|
||||
/** 扣税比例,如 0.06 表示 6%,不传则默认 6% */
|
||||
tax_rate?: number;
|
||||
}
|
||||
|
||||
async function reviewBankCardWithdrawal(
|
||||
|
||||
@@ -13,6 +13,11 @@ export namespace OrderQueryApi {
|
||||
order_id: number;
|
||||
user_id: number;
|
||||
product_name: string;
|
||||
order_no?: string;
|
||||
platform_order_id?: string;
|
||||
payment_status?: string;
|
||||
pay_time?: string;
|
||||
refund_time?: string;
|
||||
query_params: Recordable<any>;
|
||||
query_data: QueryItem[];
|
||||
create_time: string;
|
||||
@@ -29,6 +34,11 @@ export namespace OrderQueryApi {
|
||||
order_id: number;
|
||||
user_id: number;
|
||||
product_name: string;
|
||||
order_no?: string;
|
||||
platform_order_id?: string;
|
||||
payment_status?: string;
|
||||
pay_time?: string;
|
||||
refund_time?: string;
|
||||
query_params: Recordable<any>;
|
||||
query_data: QueryItem[];
|
||||
create_time: string;
|
||||
|
||||
@@ -14,6 +14,13 @@ export function useWithdrawalColumns(): VxeTableGridOptions['columns'] {
|
||||
width: 120,
|
||||
formatter: ({ cellValue }) => `¥${cellValue?.toFixed(2) || '0.00'}`,
|
||||
},
|
||||
{
|
||||
title: '扣税比例',
|
||||
field: 'tax_rate',
|
||||
width: 90,
|
||||
formatter: ({ cellValue }) =>
|
||||
cellValue != null ? `${(Number(cellValue) * 100).toFixed(1)}%` : '-',
|
||||
},
|
||||
{
|
||||
title: '扣税金额',
|
||||
field: 'tax_amount',
|
||||
|
||||
@@ -40,6 +40,10 @@ function onActionClick(e: any) {
|
||||
// 打开审核弹窗
|
||||
reviewDrawerApi.setData(row).open();
|
||||
break;
|
||||
case 'detail':
|
||||
// 已审核记录:仅查看详情(只读)
|
||||
reviewDrawerApi.setData({ ...row, _isDetailView: true }).open();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +102,13 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
>
|
||||
审核
|
||||
</Button>
|
||||
<Button
|
||||
v-if="row.status === 2 || row.status === 3"
|
||||
type="link"
|
||||
@click="onActionClick({ code: 'detail', row })"
|
||||
>
|
||||
详情
|
||||
</Button>
|
||||
</Space>
|
||||
</template>
|
||||
</Grid>
|
||||
|
||||
@@ -14,98 +14,30 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const formData = ref<any>(null);
|
||||
// 用于纯文字展示与实时计算:当前选择的审核操作、扣税比例
|
||||
const currentAction = ref<1 | 2>(1);
|
||||
const currentTaxRatePercent = ref(6);
|
||||
|
||||
// 表单配置(包含所有字段)
|
||||
const typeMap: Record<number, string> = {
|
||||
1: '支付宝',
|
||||
2: '银行卡',
|
||||
};
|
||||
|
||||
// 根据当前扣税比例与提现金额实时计算
|
||||
const previewTaxAmount = computed(() => {
|
||||
const amount = formData.value?.amount;
|
||||
if (amount == null || typeof amount !== 'number') return 0;
|
||||
const rate = currentTaxRatePercent.value / 100;
|
||||
return Math.round(amount * rate * 100) / 100;
|
||||
});
|
||||
const previewActualAmount = computed(() => {
|
||||
const amount = formData.value?.amount;
|
||||
if (amount == null || typeof amount !== 'number') return 0;
|
||||
return Math.round((amount - previewTaxAmount.value) * 100) / 100;
|
||||
});
|
||||
|
||||
// 表单只保留:审核操作、扣税比例、备注
|
||||
const getFormSchema = (): VbenFormSchema[] => [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'withdraw_no',
|
||||
label: '提现单号',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'withdraw_type',
|
||||
label: '提现类型',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
fieldName: 'amount',
|
||||
label: '提现金额',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
min: 0,
|
||||
precision: 2,
|
||||
style: { width: '100%' },
|
||||
addonBefore: '¥',
|
||||
},
|
||||
},
|
||||
// 银行卡和支付宝通用字段:扣税金额
|
||||
{
|
||||
component: 'InputNumber' ,
|
||||
fieldName: 'tax_amount',
|
||||
label: '扣税金额',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
min: 0,
|
||||
precision: 2,
|
||||
style: { width: '100%' },
|
||||
addonBefore: '¥',
|
||||
},
|
||||
},
|
||||
// 银行卡和支付宝通用字段:实际转账金额
|
||||
{
|
||||
component: 'InputNumber',
|
||||
fieldName: 'actual_amount',
|
||||
label: '实际转账金额',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
min: 0,
|
||||
precision: 2,
|
||||
style: { width: '100%' },
|
||||
addonBefore: '¥',
|
||||
},
|
||||
},
|
||||
// 银行卡和支付宝都有:收款账号
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'payee_account',
|
||||
label: '收款账号',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
// 银行卡提现特有字段:开户支行
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'bank_name',
|
||||
label: '开户支行',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
dependencies: {
|
||||
show: (values) => values.withdraw_type === '银行卡',
|
||||
triggerFields: ['withdraw_type'],
|
||||
},
|
||||
},
|
||||
// 银行卡提现特有字段:收款人姓名
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'payee_name',
|
||||
label: '收款人姓名',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
dependencies: {
|
||||
show: (values) => values.withdraw_type === '银行卡',
|
||||
triggerFields: ['withdraw_type'],
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'RadioGroup',
|
||||
fieldName: 'action',
|
||||
@@ -116,9 +48,34 @@ const getFormSchema = (): VbenFormSchema[] => [
|
||||
{ label: '确认提现', value: 1 },
|
||||
{ label: '拒绝提现', value: 2 },
|
||||
],
|
||||
onChange: (v: number) => {
|
||||
currentAction.value = v as 1 | 2;
|
||||
},
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
fieldName: 'tax_rate_percent',
|
||||
label: '扣税比例(%)',
|
||||
defaultValue: 6,
|
||||
componentProps: {
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 0.5,
|
||||
precision: 1,
|
||||
style: { width: '100%' },
|
||||
addonAfter: '%',
|
||||
placeholder: '默认 6',
|
||||
onChange: (v: number | null) => {
|
||||
currentTaxRatePercent.value = v ?? 6;
|
||||
},
|
||||
},
|
||||
dependencies: {
|
||||
show: (values) => values.action === 1,
|
||||
triggerFields: ['action'],
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'Textarea',
|
||||
fieldName: 'remark',
|
||||
@@ -142,6 +99,10 @@ const [Form, formApi] = useVbenForm({
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
class: 'agent-withdrawal-review-drawer',
|
||||
async onConfirm() {
|
||||
if (formData.value?._isDetailView) {
|
||||
drawerApi.close();
|
||||
return;
|
||||
}
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) return;
|
||||
|
||||
@@ -153,6 +114,7 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||
const values = await formApi.getValues<{
|
||||
action: 1 | 2;
|
||||
remark: string;
|
||||
tax_rate_percent?: number;
|
||||
}>();
|
||||
|
||||
// 验证拒绝时必须填写原因
|
||||
@@ -161,11 +123,18 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||
return;
|
||||
}
|
||||
|
||||
// 确认时:扣税比例(%)转成小数,如 6 -> 0.06,不传则默认 6%
|
||||
const taxRate =
|
||||
values.action === 1 && values.tax_rate_percent != null
|
||||
? Number(values.tax_rate_percent) / 100
|
||||
: undefined;
|
||||
|
||||
try {
|
||||
await reviewBankCardWithdrawal({
|
||||
action: values.action,
|
||||
remark: values.remark || '',
|
||||
withdrawal_id: formData.value.id,
|
||||
...(taxRate != null && { tax_rate: taxRate }),
|
||||
});
|
||||
message.success(values.action === 1 ? '确认提现成功' : '拒绝提现成功');
|
||||
drawerApi.close();
|
||||
@@ -180,35 +149,16 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||
formApi.resetForm();
|
||||
if (data) {
|
||||
formData.value = data;
|
||||
|
||||
// 根据提现类型设置不同的表单初始值
|
||||
const typeMap: Record<number, string> = {
|
||||
1: '支付宝',
|
||||
2: '银行卡',
|
||||
};
|
||||
const initialValues: any = {
|
||||
withdraw_no: data.withdraw_no || '',
|
||||
withdraw_type: typeMap[data.withdraw_type] || '未知',
|
||||
amount: data.amount || 0,
|
||||
action: 1, // 默认选择确认
|
||||
remark: '',
|
||||
};
|
||||
|
||||
// 银行卡提现特有字段
|
||||
if (data.withdraw_type === 2) {
|
||||
initialValues.tax_amount = data.tax_amount || 0;
|
||||
initialValues.actual_amount = data.actual_amount || 0;
|
||||
initialValues.payee_account = data.bank_card_no || '';
|
||||
initialValues.bank_name = data.bank_name || '';
|
||||
initialValues.payee_name = data.payee_name || '';
|
||||
} else {
|
||||
// 支付宝提现
|
||||
initialValues.tax_amount = data.tax_amount || 0;
|
||||
initialValues.actual_amount = data.actual_amount || 0;
|
||||
initialValues.payee_account = data.payee_account || '';
|
||||
currentAction.value = 1;
|
||||
currentTaxRatePercent.value = 6;
|
||||
if (!data._isDetailView) {
|
||||
const initialValues: any = {
|
||||
action: 1,
|
||||
tax_rate_percent: 6,
|
||||
remark: '',
|
||||
};
|
||||
formApi.setValues(initialValues);
|
||||
}
|
||||
|
||||
formApi.setValues(initialValues);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -220,14 +170,91 @@ const getDrawerTitle = computed(() => {
|
||||
2: '银行卡',
|
||||
};
|
||||
const typeName = typeMap[formData.value?.withdraw_type] || '未知';
|
||||
return `${typeName}提现审核 ${formData.value?.withdraw_no || ''}`;
|
||||
const suffix = formData.value?._isDetailView ? '详情' : '审核';
|
||||
return `${typeName}提现${suffix} ${formData.value?.withdraw_no || ''}`;
|
||||
});
|
||||
|
||||
const isDetailView = computed(() => !!formData.value?._isDetailView);
|
||||
|
||||
const statusMap: Record<number, string> = {
|
||||
1: '申请中',
|
||||
2: '成功',
|
||||
3: '失败',
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Drawer :title="getDrawerTitle" :width="800">
|
||||
<div class="agent-withdrawal-review-content">
|
||||
<Form />
|
||||
<!-- 只读信息:纯文字展示 -->
|
||||
<div v-if="formData" class="review-info-block">
|
||||
<div class="info-row">
|
||||
<span class="info-label">提现单号:</span>
|
||||
<span class="info-value">{{ formData.withdraw_no ?? '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">提现类型:</span>
|
||||
<span class="info-value">{{ typeMap[formData.withdraw_type] ?? '未知' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">状态:</span>
|
||||
<span class="info-value">{{ statusMap[formData.status] ?? '未知' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">提现金额:</span>
|
||||
<span class="info-value">¥{{ (formData.amount ?? 0).toFixed(2) }}</span>
|
||||
</div>
|
||||
<!-- 详情模式:展示已保存的扣税/实际到账 -->
|
||||
<template v-if="isDetailView">
|
||||
<div class="info-row">
|
||||
<span class="info-label">扣税比例:</span>
|
||||
<span class="info-value">{{ formData.tax_rate != null ? ((formData.tax_rate * 100).toFixed(1) + '%') : '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">扣税金额:</span>
|
||||
<span class="info-value">¥{{ (formData.tax_amount ?? 0).toFixed(2) }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">实际转账金额:</span>
|
||||
<span class="info-value">¥{{ (formData.actual_amount ?? 0).toFixed(2) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 审核模式:随扣税比例实时计算 -->
|
||||
<template v-else-if="currentAction === 1">
|
||||
<div class="info-row highlight">
|
||||
<span class="info-label">扣税金额:</span>
|
||||
<span class="info-value">¥{{ previewTaxAmount.toFixed(2) }}</span>
|
||||
<span class="info-hint">(随扣税比例实时计算)</span>
|
||||
</div>
|
||||
<div class="info-row highlight">
|
||||
<span class="info-label">实际转账金额:</span>
|
||||
<span class="info-value">¥{{ previewActualAmount.toFixed(2) }}</span>
|
||||
<span class="info-hint">(随扣税比例实时计算)</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="info-row">
|
||||
<span class="info-label">收款账号:</span>
|
||||
<span class="info-value">{{
|
||||
formData.withdraw_type === 2 ? (formData.bank_card_no ?? '-') : (formData.payee_account ?? '-')
|
||||
}}</span>
|
||||
</div>
|
||||
<template v-if="formData.withdraw_type === 2">
|
||||
<div class="info-row">
|
||||
<span class="info-label">开户支行:</span>
|
||||
<span class="info-value">{{ formData.bank_name ?? '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">收款人姓名:</span>
|
||||
<span class="info-value">{{ formData.payee_name ?? '-' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="isDetailView && formData.remark" class="info-row">
|
||||
<span class="info-label">备注:</span>
|
||||
<span class="info-value">{{ formData.remark }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Form v-if="!isDetailView" />
|
||||
</div>
|
||||
</Drawer>
|
||||
</template>
|
||||
@@ -239,6 +266,46 @@ const getDrawerTitle = computed(() => {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.review-info-block {
|
||||
margin-bottom: 20px;
|
||||
padding: 16px;
|
||||
background: var(--ant-color-fill-quaternary);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.info-row.highlight .info-value {
|
||||
font-weight: 600;
|
||||
color: var(--ant-color-primary);
|
||||
}
|
||||
|
||||
.info-label {
|
||||
flex-shrink: 0;
|
||||
width: 120px;
|
||||
color: var(--ant-color-text-secondary);
|
||||
}
|
||||
|
||||
.info-value {
|
||||
flex: 1;
|
||||
color: var(--ant-color-text);
|
||||
}
|
||||
|
||||
.info-hint {
|
||||
margin-left: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--ant-color-text-tertiary);
|
||||
}
|
||||
|
||||
.agent-withdrawal-review-content :deep(.ant-form-item) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,34 @@ function getQueryStateConfig(state: string) {
|
||||
);
|
||||
}
|
||||
|
||||
// 支付状态文案
|
||||
const paymentStatusMap: Record<string, string> = {
|
||||
pending: '待支付',
|
||||
paid: '已支付',
|
||||
refunded: '已退款',
|
||||
refunding: '退款中',
|
||||
closed: '已关闭',
|
||||
failed: '支付失败',
|
||||
};
|
||||
function getPaymentStatusLabel(status: string | undefined) {
|
||||
if (!status) return '-';
|
||||
return paymentStatusMap[status] ?? status;
|
||||
}
|
||||
|
||||
// 支付状态颜色
|
||||
const paymentStatusColorMap: Record<string, string> = {
|
||||
pending: 'warning',
|
||||
paid: 'success',
|
||||
refunded: 'default',
|
||||
refunding: 'processing',
|
||||
closed: 'default',
|
||||
failed: 'error',
|
||||
};
|
||||
function getPaymentStatusColor(status: string | undefined) {
|
||||
if (!status) return 'default';
|
||||
return paymentStatusColorMap[status] ?? 'default';
|
||||
}
|
||||
|
||||
// 字段名称映射
|
||||
const fieldNameMap: Record<string, string> = {
|
||||
// 基础字段
|
||||
@@ -143,6 +171,23 @@ onMounted(() => {
|
||||
<Descriptions.Item label="产品名称">
|
||||
{{ queryDetail.product_name }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="商户订单号">
|
||||
{{ queryDetail.order_no ?? '-' }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="支付订单号">
|
||||
{{ queryDetail.platform_order_id ?? '-' }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="支付状态">
|
||||
<Tag :color="getPaymentStatusColor(queryDetail.payment_status)">
|
||||
{{ getPaymentStatusLabel(queryDetail.payment_status) }}
|
||||
</Tag>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="支付时间">
|
||||
{{ queryDetail.pay_time ?? '-' }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="退款时间">
|
||||
{{ queryDetail.refund_time ?? '-' }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="创建时间">
|
||||
{{ queryDetail.create_time }}
|
||||
</Descriptions.Item>
|
||||
|
||||
Reference in New Issue
Block a user