f
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled

This commit is contained in:
2026-02-01 18:36:43 +08:00
parent 62e532846e
commit db85f77ea8
3 changed files with 205 additions and 120 deletions

View File

@@ -14,6 +14,13 @@ export function useWithdrawalColumns(): VxeTableGridOptions['columns'] {
width: 120, width: 120,
formatter: ({ cellValue }) => `¥${cellValue?.toFixed(2) || '0.00'}`, formatter: ({ cellValue }) => `¥${cellValue?.toFixed(2) || '0.00'}`,
}, },
{
title: '扣税比例',
field: 'tax_rate',
width: 90,
formatter: ({ cellValue }) =>
cellValue != null ? `${(Number(cellValue) * 100).toFixed(1)}%` : '-',
},
{ {
title: '扣税金额', title: '扣税金额',
field: 'tax_amount', field: 'tax_amount',

View File

@@ -40,6 +40,10 @@ function onActionClick(e: any) {
// 打开审核弹窗 // 打开审核弹窗
reviewDrawerApi.setData(row).open(); reviewDrawerApi.setData(row).open();
break; break;
case 'detail':
// 已审核记录:仅查看详情(只读)
reviewDrawerApi.setData({ ...row, _isDetailView: true }).open();
break;
} }
} }
@@ -98,6 +102,13 @@ const [Grid, gridApi] = useVbenVxeGrid({
> >
审核 审核
</Button> </Button>
<Button
v-if="row.status === 2 || row.status === 3"
type="link"
@click="onActionClick({ code: 'detail', row })"
>
详情
</Button>
</Space> </Space>
</template> </template>
</Grid> </Grid>

View File

@@ -14,98 +14,30 @@ const emit = defineEmits<{
}>(); }>();
const formData = ref<any>(null); 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[] => [ 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', component: 'RadioGroup',
fieldName: 'action', fieldName: 'action',
@@ -116,9 +48,34 @@ const getFormSchema = (): VbenFormSchema[] => [
{ label: '确认提现', value: 1 }, { label: '确认提现', value: 1 },
{ label: '拒绝提现', value: 2 }, { label: '拒绝提现', value: 2 },
], ],
onChange: (v: number) => {
currentAction.value = v as 1 | 2;
},
}, },
rules: 'required', 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', component: 'Textarea',
fieldName: 'remark', fieldName: 'remark',
@@ -142,6 +99,10 @@ const [Form, formApi] = useVbenForm({
const [Drawer, drawerApi] = useVbenDrawer({ const [Drawer, drawerApi] = useVbenDrawer({
class: 'agent-withdrawal-review-drawer', class: 'agent-withdrawal-review-drawer',
async onConfirm() { async onConfirm() {
if (formData.value?._isDetailView) {
drawerApi.close();
return;
}
const { valid } = await formApi.validate(); const { valid } = await formApi.validate();
if (!valid) return; if (!valid) return;
@@ -153,6 +114,7 @@ const [Drawer, drawerApi] = useVbenDrawer({
const values = await formApi.getValues<{ const values = await formApi.getValues<{
action: 1 | 2; action: 1 | 2;
remark: string; remark: string;
tax_rate_percent?: number;
}>(); }>();
// 验证拒绝时必须填写原因 // 验证拒绝时必须填写原因
@@ -161,11 +123,18 @@ const [Drawer, drawerApi] = useVbenDrawer({
return; return;
} }
// 确认时:扣税比例(%)转成小数,如 6 -> 0.06,不传则默认 6%
const taxRate =
values.action === 1 && values.tax_rate_percent != null
? Number(values.tax_rate_percent) / 100
: undefined;
try { try {
await reviewBankCardWithdrawal({ await reviewBankCardWithdrawal({
action: values.action, action: values.action,
remark: values.remark || '', remark: values.remark || '',
withdrawal_id: formData.value.id, withdrawal_id: formData.value.id,
...(taxRate != null && { tax_rate: taxRate }),
}); });
message.success(values.action === 1 ? '确认提现成功' : '拒绝提现成功'); message.success(values.action === 1 ? '确认提现成功' : '拒绝提现成功');
drawerApi.close(); drawerApi.close();
@@ -180,35 +149,16 @@ const [Drawer, drawerApi] = useVbenDrawer({
formApi.resetForm(); formApi.resetForm();
if (data) { if (data) {
formData.value = data; formData.value = data;
currentAction.value = 1;
// 根据提现类型设置不同的表单初始值 currentTaxRatePercent.value = 6;
const typeMap: Record<number, string> = { if (!data._isDetailView) {
1: '支付宝', const initialValues: any = {
2: '银行卡', action: 1,
}; tax_rate_percent: 6,
const initialValues: any = { remark: '',
withdraw_no: data.withdraw_no || '', };
withdraw_type: typeMap[data.withdraw_type] || '未知', formApi.setValues(initialValues);
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 || '';
} }
formApi.setValues(initialValues);
} }
} }
}, },
@@ -220,14 +170,91 @@ const getDrawerTitle = computed(() => {
2: '银行卡', 2: '银行卡',
}; };
const typeName = typeMap[formData.value?.withdraw_type] || '未知'; 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> </script>
<template> <template>
<Drawer :title="getDrawerTitle" :width="800"> <Drawer :title="getDrawerTitle" :width="800">
<div class="agent-withdrawal-review-content"> <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> </div>
</Drawer> </Drawer>
</template> </template>
@@ -239,6 +266,46 @@ const getDrawerTitle = computed(() => {
overflow-y: auto; 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) { .agent-withdrawal-review-content :deep(.ant-form-item) {
margin-bottom: 16px; margin-bottom: 16px;
} }