c
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
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:
@@ -1,6 +0,0 @@
|
||||
echo Start running commit-msg hook...
|
||||
|
||||
# Check whether the git commit information is standardized
|
||||
pnpm exec commitlint --edit "$1"
|
||||
|
||||
echo Run commit-msg hook done.
|
||||
@@ -1,7 +0,0 @@
|
||||
# update `.vscode/vben-admin.code-workspace` file
|
||||
pnpm vsh code-workspace --auto-commit
|
||||
|
||||
# Format and submit code according to lintstagedrc.js configuration
|
||||
pnpm exec lint-staged
|
||||
|
||||
echo Run pre-commit hook done.
|
||||
@@ -111,10 +111,16 @@ export namespace AgentApi {
|
||||
agent_id: number;
|
||||
withdraw_no: string;
|
||||
amount: number;
|
||||
actual_amount: number; // 实际到账金额(扣税后)
|
||||
tax_amount: number; // 扣税金额
|
||||
status: number;
|
||||
payee_account: string;
|
||||
remark: string;
|
||||
create_time: string;
|
||||
withdraw_type: number; // 提现类型:1-支付宝,2-银行卡
|
||||
bank_card_no?: string; // 银行卡号
|
||||
bank_name?: string; // 开户支行
|
||||
payee_name?: string; // 收款人姓名
|
||||
}
|
||||
|
||||
export interface AgentWithdrawalList {
|
||||
@@ -128,6 +134,8 @@ export namespace AgentApi {
|
||||
agent_id?: number;
|
||||
status?: number;
|
||||
withdraw_no?: string;
|
||||
status?: number;
|
||||
withdraw_no?: string;
|
||||
}
|
||||
|
||||
// 代理上级抽佣相关接口
|
||||
@@ -446,6 +454,24 @@ async function updateAgentMembershipConfig(
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 银行卡提现审核
|
||||
*/
|
||||
export interface ReviewBankCardWithdrawalParams {
|
||||
withdrawal_id: number;
|
||||
action: 1 | 2; // 1-确认, 2-拒绝
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
async function reviewBankCardWithdrawal(
|
||||
params: ReviewBankCardWithdrawalParams,
|
||||
) {
|
||||
return requestClient.post<{ success: boolean }>(
|
||||
'/agent/agent-withdrawal/bank-card/review',
|
||||
params,
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
getAgentCommissionDeductionList,
|
||||
getAgentCommissionList,
|
||||
@@ -457,6 +483,7 @@ export {
|
||||
getAgentRewardList,
|
||||
getAgentWithdrawalList,
|
||||
getMembershipRechargeOrderList,
|
||||
reviewBankCardWithdrawal,
|
||||
updateAgentMembershipConfig,
|
||||
updateAgentProductionConfig,
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ export const overridesPreferences = defineOverridesPreferences({
|
||||
source: 'https://ctrlph.tianyuandb.com/logo.png',
|
||||
},
|
||||
copyright: {
|
||||
companyName: '海南天远大数据科技有限公司',
|
||||
companyName: '海南海宇大数据有限公司',
|
||||
companySiteLink: 'https://www.tianyuandb.com',
|
||||
date: '2025',
|
||||
icp: '琼ICP备2024048057号-1',
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
|
||||
type WithdrawalMethod = 'alipay' | 'bank' | 'wechat';
|
||||
type WithdrawalStatus = 'approved' | 'failed' | 'paid' | 'pending' | 'rejected';
|
||||
|
||||
export function useWithdrawalColumns(): VxeTableGridOptions['columns'] {
|
||||
return [
|
||||
{
|
||||
@@ -15,39 +12,88 @@ export function useWithdrawalColumns(): VxeTableGridOptions['columns'] {
|
||||
title: '提现金额',
|
||||
field: 'amount',
|
||||
width: 120,
|
||||
formatter: ({ cellValue }) => `¥${cellValue.toFixed(2)}`,
|
||||
formatter: ({ cellValue }) => `¥${cellValue?.toFixed(2) || '0.00'}`,
|
||||
},
|
||||
{
|
||||
title: '提现方式',
|
||||
field: 'method',
|
||||
width: 120,
|
||||
formatter: ({ cellValue }: { cellValue: WithdrawalMethod }) => {
|
||||
const methodMap: Record<WithdrawalMethod, string> = {
|
||||
alipay: '支付宝',
|
||||
wechat: '微信',
|
||||
bank: '银行卡',
|
||||
title: '提现类型',
|
||||
field: 'withdraw_type',
|
||||
width: 100,
|
||||
formatter: ({ cellValue }) => {
|
||||
const typeMap: Record<number, string> = {
|
||||
1: '支付宝',
|
||||
2: '银行卡',
|
||||
};
|
||||
return methodMap[cellValue] || cellValue;
|
||||
return typeMap[cellValue] || '未知';
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '收款账号',
|
||||
field: 'account',
|
||||
width: 180,
|
||||
title: '收款信息',
|
||||
field: 'payee_info',
|
||||
width: 200,
|
||||
formatter: ({ row }) => {
|
||||
if (row.withdraw_type === 1) {
|
||||
// 支付宝提现
|
||||
return row.payee_account || '-';
|
||||
} else if (row.withdraw_type === 2) {
|
||||
// 银行卡提现
|
||||
if (row.bank_card_no) {
|
||||
const cardNo = row.bank_card_no.replaceAll(/\s/g, '');
|
||||
const masked =
|
||||
cardNo.length > 8
|
||||
? `${cardNo.slice(0, 4)} **** **** ${cardNo.slice(
|
||||
Math.max(0, cardNo.length - 4),
|
||||
)}`
|
||||
: cardNo;
|
||||
return `${masked}${row.bank_name ? ` (${row.bank_name})` : ''}`;
|
||||
}
|
||||
return '-';
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '收款人',
|
||||
field: 'payee_name',
|
||||
width: 120,
|
||||
formatter: ({ cellValue, row }) => {
|
||||
if (row.withdraw_type === 2 && cellValue) {
|
||||
return cellValue;
|
||||
}
|
||||
return '-';
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
field: 'status',
|
||||
width: 100,
|
||||
formatter: ({ cellValue }: { cellValue: WithdrawalStatus }) => {
|
||||
const statusMap: Record<WithdrawalStatus, string> = {
|
||||
pending: '待审核',
|
||||
approved: '已通过',
|
||||
rejected: '已拒绝',
|
||||
paid: '已打款',
|
||||
failed: '打款失败',
|
||||
formatter: ({ cellValue }) => {
|
||||
const statusMap: Record<number, string> = {
|
||||
1: '申请中',
|
||||
2: '成功',
|
||||
3: '失败',
|
||||
};
|
||||
return statusMap[cellValue] || cellValue;
|
||||
return statusMap[cellValue] || '未知';
|
||||
},
|
||||
cellRender: {
|
||||
name: 'VxeTag',
|
||||
props: ({ row }) => {
|
||||
const statusConfig: Record<
|
||||
number,
|
||||
{ content: string; type: string }
|
||||
> = {
|
||||
1: { type: 'warning', content: '申请中' },
|
||||
2: { type: 'success', content: '成功' },
|
||||
3: { type: 'error', content: '失败' },
|
||||
};
|
||||
const config = statusConfig[row.status] || {
|
||||
type: 'info',
|
||||
content: '未知',
|
||||
};
|
||||
return {
|
||||
type: config.type,
|
||||
content: config.content,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -55,20 +101,19 @@ export function useWithdrawalColumns(): VxeTableGridOptions['columns'] {
|
||||
field: 'create_time',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '审核时间',
|
||||
field: 'audit_time',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '打款时间',
|
||||
field: 'pay_time',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
field: 'remark',
|
||||
width: 200,
|
||||
formatter: ({ cellValue }) => cellValue || '-',
|
||||
},
|
||||
{
|
||||
align: 'center',
|
||||
slots: { default: 'operation' },
|
||||
field: 'operation',
|
||||
fixed: 'right',
|
||||
title: '操作',
|
||||
width: 120,
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -76,14 +121,13 @@ export function useWithdrawalColumns(): VxeTableGridOptions['columns'] {
|
||||
export function useWithdrawalFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'method',
|
||||
label: '提现方式',
|
||||
fieldName: 'withdraw_type',
|
||||
label: '提现类型',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '支付宝', value: 'alipay' },
|
||||
{ label: '微信', value: 'wechat' },
|
||||
{ label: '银行卡', value: 'bank' },
|
||||
{ label: '支付宝', value: 1 },
|
||||
{ label: '银行卡', value: 2 },
|
||||
],
|
||||
allowClear: true,
|
||||
},
|
||||
@@ -94,11 +138,9 @@ export function useWithdrawalFormSchema(): VbenFormSchema[] {
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '待审核', value: 'pending' },
|
||||
{ label: '已通过', value: 'approved' },
|
||||
{ label: '已拒绝', value: 'rejected' },
|
||||
{ label: '已打款', value: 'paid' },
|
||||
{ label: '打款失败', value: 'failed' },
|
||||
{ label: '申请中', value: 1 },
|
||||
{ label: '成功', value: 2 },
|
||||
{ label: '失败', value: 3 },
|
||||
],
|
||||
allowClear: true,
|
||||
},
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { Page, useVbenDrawer } from '@vben/common-ui';
|
||||
import { Button, Space } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getAgentWithdrawalList } from '#/api/agent';
|
||||
|
||||
import ReviewModal from './modules/review-modal.vue';
|
||||
import { useWithdrawalColumns, useWithdrawalFormSchema } from './data';
|
||||
|
||||
interface Props {
|
||||
@@ -24,13 +26,35 @@ const queryParams = computed(() => ({
|
||||
...(props.agentId ? { agent_id: props.agentId } : {}),
|
||||
}));
|
||||
|
||||
const [Grid] = useVbenVxeGrid({
|
||||
// 审核弹窗
|
||||
const [ReviewDrawer, reviewDrawerApi] = useVbenDrawer({
|
||||
connectedComponent: ReviewModal,
|
||||
destroyOnClose: true,
|
||||
});
|
||||
|
||||
// 操作处理
|
||||
function onActionClick(e: any) {
|
||||
const { code, row } = e;
|
||||
switch (code) {
|
||||
case 'review':
|
||||
// 打开审核弹窗
|
||||
reviewDrawerApi.setData(row).open();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新列表
|
||||
function onRefresh() {
|
||||
gridApi.query();
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useWithdrawalFormSchema(),
|
||||
submitOnChange: true,
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useWithdrawalColumns(),
|
||||
columns: useWithdrawalColumns(onActionClick),
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({
|
||||
@@ -53,12 +77,32 @@ const [Grid] = useVbenVxeGrid({
|
||||
total: 'total',
|
||||
},
|
||||
},
|
||||
toolbarConfig: {
|
||||
custom: true,
|
||||
export: false,
|
||||
refresh: { code: 'query' },
|
||||
search: true,
|
||||
zoom: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page :auto-content-height="!agentId">
|
||||
<Grid :table-title="agentId ? '提现记录列表' : '所有提现记录'" />
|
||||
<ReviewDrawer @success="onRefresh" />
|
||||
<Grid :table-title="agentId ? '提现记录列表' : '所有提现记录'">
|
||||
<template #operation="{ row }">
|
||||
<Space>
|
||||
<Button
|
||||
v-if="row.withdraw_type === 2 && row.status === 1"
|
||||
type="link"
|
||||
@click="onActionClick({ code: 'review', row })"
|
||||
>
|
||||
审核
|
||||
</Button>
|
||||
</Space>
|
||||
</template>
|
||||
</Grid>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenDrawer } from '@vben/common-ui';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { reviewBankCardWithdrawal } from '#/api/agent';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'success'): void;
|
||||
}>();
|
||||
|
||||
const formData = ref<any>(null);
|
||||
|
||||
const [Form, formApi] = useVbenForm({
|
||||
schema: [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'withdraw_no',
|
||||
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: 'bank_card_no',
|
||||
label: '银行卡号',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'bank_name',
|
||||
label: '开户支行',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'payee_name',
|
||||
label: '收款人姓名',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'RadioGroup',
|
||||
fieldName: 'action',
|
||||
label: '审核操作',
|
||||
defaultValue: 1,
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '确认提现', value: 1 },
|
||||
{ label: '拒绝提现', value: 2 },
|
||||
],
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
component: 'Textarea',
|
||||
fieldName: 'remark',
|
||||
label: '备注',
|
||||
componentProps: {
|
||||
rows: 4,
|
||||
placeholder: '拒绝提现时,请填写拒绝原因',
|
||||
maxLength: 200,
|
||||
showCount: true,
|
||||
style: { width: '100%' },
|
||||
},
|
||||
},
|
||||
],
|
||||
showDefaultActions: false,
|
||||
});
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
async onConfirm() {
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) return;
|
||||
|
||||
if (!formData.value?.id) {
|
||||
message.error('提现记录ID不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
const values = await formApi.getValues<{
|
||||
action: 1 | 2;
|
||||
remark: string;
|
||||
}>();
|
||||
|
||||
// 验证拒绝时必须填写原因
|
||||
if (values.action === 2 && !values.remark?.trim()) {
|
||||
message.error('拒绝提现必须填写拒绝原因');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await reviewBankCardWithdrawal({
|
||||
action: values.action,
|
||||
remark: values.remark || '',
|
||||
withdrawal_id: formData.value.id,
|
||||
});
|
||||
message.success(values.action === 1 ? '确认提现成功' : '拒绝提现成功');
|
||||
drawerApi.close();
|
||||
emit('success');
|
||||
} catch (error: any) {
|
||||
message.error(error?.message || '操作失败');
|
||||
}
|
||||
},
|
||||
onOpenChange(isOpen) {
|
||||
if (isOpen) {
|
||||
const data = drawerApi.getData<any>();
|
||||
formApi.resetForm();
|
||||
if (data) {
|
||||
formData.value = data;
|
||||
// 设置表单初始值
|
||||
formApi.setValues({
|
||||
withdraw_no: data.withdraw_no || '',
|
||||
amount: data.amount || 0,
|
||||
tax_amount: data.tax_amount || 0,
|
||||
actual_amount: data.actual_amount || 0,
|
||||
bank_card_no: data.bank_card_no || '',
|
||||
bank_name: data.bank_name || '',
|
||||
payee_name: data.payee_name || '',
|
||||
action: 1, // 默认选择确认
|
||||
remark: '',
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const getDrawerTitle = computed(() => {
|
||||
return `银行卡提现审核 ${formData.value?.withdraw_no || ''}`;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Drawer :title="getDrawerTitle" width="600">
|
||||
<Form />
|
||||
</Drawer>
|
||||
</template>
|
||||
@@ -10,10 +10,10 @@ export default defineConfig(async () => {
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
// mock代理目标地址
|
||||
// target: 'http://localhost:8888/api',
|
||||
target: 'http://localhost:8888/api',
|
||||
// target: 'https://www.tianyuandb.com/api',
|
||||
// target: 'https://www.zhinengcha.cn/api',
|
||||
target: 'https://www.quannengcha./api',
|
||||
// target: 'https://www.quannengcha./api',
|
||||
ws: true,
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user