feat: 添加银行卡管理功能,包含银行卡编辑和用户银行卡查看组件
This commit is contained in:
@@ -40,7 +40,7 @@ export type TableFilterColumn = {
|
|||||||
key: string;
|
key: string;
|
||||||
title: string;
|
title: string;
|
||||||
component?: Component | VNode;
|
component?: Component | VNode;
|
||||||
componentProps?: Record<string, any>;
|
componentProps?: Record<string, any> | ((form: Record<string, any>) => Record<string, any>);
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TableFilterColumns = Array<TableFilterColumn>;
|
export type TableFilterColumns = Array<TableFilterColumn>;
|
||||||
|
|||||||
@@ -25,11 +25,13 @@ const props = withDefaults(
|
|||||||
columns?: boolean;
|
columns?: boolean;
|
||||||
};
|
};
|
||||||
filterColumns?: TableFilterColumns;
|
filterColumns?: TableFilterColumns;
|
||||||
|
filterColumnsCount?: number;
|
||||||
title?: string;
|
title?: string;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
title: '',
|
title: '',
|
||||||
showHeaderOperation: true,
|
showHeaderOperation: true,
|
||||||
|
filterColumnsCount: 4,
|
||||||
filterColumns: () => [],
|
filterColumns: () => [],
|
||||||
headerOperations: () => ({
|
headerOperations: () => ({
|
||||||
add: true,
|
add: true,
|
||||||
@@ -124,7 +126,12 @@ defineExpose({} as Expose);
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-5">
|
<div class="space-y-5">
|
||||||
<TableFilter v-if="filterColumns.length > 0" :columns="filterColumns" @confirm="handleSearch" />
|
<TableFilter
|
||||||
|
v-if="filterColumns.length > 0"
|
||||||
|
:columns="filterColumns"
|
||||||
|
:filter-columns-count="filterColumnsCount"
|
||||||
|
@confirm="handleSearch"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="rounded-lg bg-white p-5 space-y-5 dark:bg-container">
|
<div class="rounded-lg bg-white p-5 space-y-5 dark:bg-container">
|
||||||
<TableHeaderOperation
|
<TableHeaderOperation
|
||||||
@@ -139,6 +146,9 @@ defineExpose({} as Expose);
|
|||||||
<template #prefix>
|
<template #prefix>
|
||||||
<div class="text-lg font-bold">{{ title }}</div>
|
<div class="text-lg font-bold">{{ title }}</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template #suffix>
|
||||||
|
<slot name="header-operation-suffix" />
|
||||||
|
</template>
|
||||||
</TableHeaderOperation>
|
</TableHeaderOperation>
|
||||||
|
|
||||||
<NDataTable
|
<NDataTable
|
||||||
@@ -149,9 +159,10 @@ defineExpose({} as Expose);
|
|||||||
:data="tableData"
|
:data="tableData"
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
:bordered="false"
|
:bordered="false"
|
||||||
:on-update:page="handlePageChange"
|
:remote="true"
|
||||||
:on-update:page-size="handlePageSizeChange"
|
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
|
@update:page="handlePageChange"
|
||||||
|
@update:page-size="handlePageSizeChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { NInput } from 'naive-ui';
|
import { NInput } from 'naive-ui';
|
||||||
import type { TableFilterColumns } from '.';
|
import type { TableFilterColumn, TableFilterColumns } from '.';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
columns?: TableFilterColumns;
|
columns?: TableFilterColumns;
|
||||||
|
filterColumnsCount?: number;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'confirm', form: Record<string, any>): void;
|
(e: 'confirm', form: Record<string, any>): void;
|
||||||
@@ -14,8 +15,22 @@ const inlineForm: Record<string, any> = {};
|
|||||||
|
|
||||||
const form = ref<Record<string, any>>({});
|
const form = ref<Record<string, any>>({});
|
||||||
|
|
||||||
|
function transformProps(col: TableFilterColumn) {
|
||||||
|
if (typeof col.componentProps === 'object') {
|
||||||
|
return col.componentProps;
|
||||||
|
} else if (typeof col.componentProps === 'function') {
|
||||||
|
return col.componentProps(form.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
props.columns?.forEach(col => {
|
props.columns?.forEach(col => {
|
||||||
|
if (col.key.includes(',')) {
|
||||||
|
col.key.split(',').forEach(k => {
|
||||||
|
inlineForm[k] = null;
|
||||||
|
form.value[k] = null;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
inlineForm[col.key] = null;
|
inlineForm[col.key] = null;
|
||||||
form.value[col.key] = null;
|
form.value[col.key] = null;
|
||||||
});
|
});
|
||||||
@@ -33,14 +48,14 @@ function handleConfirm() {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="rounded-lg bg-white p-5 dark:bg-container">
|
<div class="rounded-lg bg-white p-5 dark:bg-container">
|
||||||
<NForm :label-width="80" label-align="left" label-placement="left">
|
<NForm :label-width="80" label-align="left" label-placement="left" :show-feedback="false">
|
||||||
<NGrid x-gap="20" :cols="4">
|
<NGrid x-gap="20" y-gap="10" :cols="filterColumnsCount || 4">
|
||||||
<NGi v-for="col in columns" :key="col.key">
|
<NGi v-for="col in columns" :key="col.key">
|
||||||
<NFormItem :label="col.title" :path="col.key">
|
<NFormItem :label="col.title" :path="col.key">
|
||||||
<component
|
<component
|
||||||
:is="col.component || NInput"
|
:is="col.component || NInput"
|
||||||
:value="form[col.key]"
|
:value="form[col.key]"
|
||||||
v-bind="col.componentProps"
|
v-bind="transformProps(col)"
|
||||||
@update:value="(val: any) => (form[col.key] = val)"
|
@update:value="(val: any) => (form[col.key] = val)"
|
||||||
/>
|
/>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
|
|||||||
@@ -28,12 +28,11 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
|||||||
notification: () => import("@/views/notification/index.vue"),
|
notification: () => import("@/views/notification/index.vue"),
|
||||||
robot_spot: () => import("@/views/robot/spot/index.vue"),
|
robot_spot: () => import("@/views/robot/spot/index.vue"),
|
||||||
rwa_product: () => import("@/views/rwa/product/index.vue"),
|
rwa_product: () => import("@/views/rwa/product/index.vue"),
|
||||||
rwa_producttype: () => import("@/views/rwa/productType/index.vue"),
|
rwa_producttype: () => import("@/views/rwa/producttype/index.vue"),
|
||||||
rwa_subscribe: () => import("@/views/rwa/subscribe/index.vue"),
|
rwa_subscribe: () => import("@/views/rwa/subscribe/index.vue"),
|
||||||
tokenization_product: () => import("@/views/tokenization/product/index.vue"),
|
tokenization_product: () => import("@/views/tokenization/product/index.vue"),
|
||||||
"tokenization_trading-pairs": () => import("@/views/tokenization/trading-pairs/index.vue"),
|
"tokenization_trading-pairs": () => import("@/views/tokenization/trading-pairs/index.vue"),
|
||||||
transfer: () => import("@/views/transfer/index.vue"),
|
transfer: () => import("@/views/transfer/index.vue"),
|
||||||
user_bankcard: () => import("@/views/user/bankcard/index.vue"),
|
|
||||||
user_list: () => import("@/views/user/list/index.vue"),
|
user_list: () => import("@/views/user/list/index.vue"),
|
||||||
withdraw_approved: () => import("@/views/withdraw/approved/index.vue"),
|
withdraw_approved: () => import("@/views/withdraw/approved/index.vue"),
|
||||||
withdraw_fiat: () => import("@/views/withdraw/fiat/index.vue"),
|
withdraw_fiat: () => import("@/views/withdraw/fiat/index.vue"),
|
||||||
|
|||||||
@@ -246,15 +246,6 @@ export const generatedRoutes: GeneratedRoute[] = [
|
|||||||
order: 4
|
order: 4
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
|
||||||
name: 'user_bankcard',
|
|
||||||
path: '/user/bankcard',
|
|
||||||
component: 'view.user_bankcard',
|
|
||||||
meta: {
|
|
||||||
title: 'user_bankcard',
|
|
||||||
i18nKey: 'route.user_bankcard'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'user_list',
|
name: 'user_list',
|
||||||
path: '/user/list',
|
path: '/user/list',
|
||||||
|
|||||||
@@ -186,7 +186,6 @@ const routeMap: RouteMap = {
|
|||||||
"tokenization_trading-pairs": "/tokenization/trading-pairs",
|
"tokenization_trading-pairs": "/tokenization/trading-pairs",
|
||||||
"transfer": "/transfer",
|
"transfer": "/transfer",
|
||||||
"user": "/user",
|
"user": "/user",
|
||||||
"user_bankcard": "/user/bankcard",
|
|
||||||
"user_list": "/user/list",
|
"user_list": "/user/list",
|
||||||
"withdraw": "/withdraw",
|
"withdraw": "/withdraw",
|
||||||
"withdraw_approved": "/withdraw/approved",
|
"withdraw_approved": "/withdraw/approved",
|
||||||
|
|||||||
2
src/typings/elegant-router.d.ts
vendored
2
src/typings/elegant-router.d.ts
vendored
@@ -40,7 +40,6 @@ declare module "@elegant-router/types" {
|
|||||||
"tokenization_trading-pairs": "/tokenization/trading-pairs";
|
"tokenization_trading-pairs": "/tokenization/trading-pairs";
|
||||||
"transfer": "/transfer";
|
"transfer": "/transfer";
|
||||||
"user": "/user";
|
"user": "/user";
|
||||||
"user_bankcard": "/user/bankcard";
|
|
||||||
"user_list": "/user/list";
|
"user_list": "/user/list";
|
||||||
"withdraw": "/withdraw";
|
"withdraw": "/withdraw";
|
||||||
"withdraw_approved": "/withdraw/approved";
|
"withdraw_approved": "/withdraw/approved";
|
||||||
@@ -127,7 +126,6 @@ declare module "@elegant-router/types" {
|
|||||||
| "tokenization_product"
|
| "tokenization_product"
|
||||||
| "tokenization_trading-pairs"
|
| "tokenization_trading-pairs"
|
||||||
| "transfer"
|
| "transfer"
|
||||||
| "user_bankcard"
|
|
||||||
| "user_list"
|
| "user_list"
|
||||||
| "withdraw_approved"
|
| "withdraw_approved"
|
||||||
| "withdraw_fiat"
|
| "withdraw_fiat"
|
||||||
|
|||||||
@@ -1,18 +1,24 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { h, useTemplateRef } from 'vue';
|
import { h, useTemplateRef } from 'vue';
|
||||||
import { useDialog, useMessage } from 'naive-ui';
|
|
||||||
import { client, safeClient } from '@/service/api';
|
import { client, safeClient } from '@/service/api';
|
||||||
import type { TableBaseColumns, TableFetchData, TableFilterColumns, TableInst } from '@/components/table';
|
import type { TableBaseColumns, TableFetchData, TableFilterColumns, TableInst } from '@/components/table';
|
||||||
import Edit from './components/edit.vue';
|
import Edit from './bankcard-edit.vue';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'UserBankCard'
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
userId?: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
const dialog = useDialog();
|
|
||||||
const message = useMessage();
|
|
||||||
const tableInst = useTemplateRef<TableInst>('tableInst');
|
const tableInst = useTemplateRef<TableInst>('tableInst');
|
||||||
|
|
||||||
const fetchData: TableFetchData = ({ pagination, filter }) => {
|
const fetchData: TableFetchData = ({ pagination, filter }) => {
|
||||||
return safeClient(() =>
|
return safeClient(() =>
|
||||||
client.api.admin.bank_account.get({
|
client.api.admin.bank_account.get({
|
||||||
query: {
|
query: {
|
||||||
|
userId: props.userId,
|
||||||
...pagination,
|
...pagination,
|
||||||
...filter
|
...filter
|
||||||
}
|
}
|
||||||
@@ -21,10 +27,6 @@ const fetchData: TableFetchData = ({ pagination, filter }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const columns: TableBaseColumns = [
|
const columns: TableBaseColumns = [
|
||||||
{
|
|
||||||
title: 'ID',
|
|
||||||
key: 'userId'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: '持卡人姓名',
|
title: '持卡人姓名',
|
||||||
key: 'accountName'
|
key: 'accountName'
|
||||||
@@ -46,11 +48,16 @@ const columns: TableBaseColumns = [
|
|||||||
key: 'isVerified',
|
key: 'isVerified',
|
||||||
render: (row: any) => (row.isVerified ? '是' : '否')
|
render: (row: any) => (row.isVerified ? '是' : '否')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '是否默认',
|
||||||
|
key: 'isDefault',
|
||||||
|
render: (row: any) => (row.isDefault ? '是' : '否')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
key: 'operation',
|
key: 'operation',
|
||||||
width: 160,
|
width: 150,
|
||||||
operations: (row: any) => [
|
operations: (row: any) => [
|
||||||
{
|
{
|
||||||
contentText: '编辑',
|
contentText: '编辑',
|
||||||
@@ -67,7 +74,7 @@ const columns: TableBaseColumns = [
|
|||||||
ghost: true,
|
ghost: true,
|
||||||
size: 'small',
|
size: 'small',
|
||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
dialog.create({
|
window.$dialog?.create({
|
||||||
title: '提示',
|
title: '提示',
|
||||||
positiveText: '是',
|
positiveText: '是',
|
||||||
negativeText: '否',
|
negativeText: '否',
|
||||||
@@ -79,7 +86,7 @@ const columns: TableBaseColumns = [
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
tableInst.value?.reload();
|
tableInst.value?.reload();
|
||||||
message.success('删除成功');
|
window.$message?.success('删除成功');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -100,17 +107,17 @@ const filterColumns: TableFilterColumns = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
function handleEdit(row: any) {
|
function handleEdit(row: any) {
|
||||||
const dialogInstance = dialog.create({
|
const dialogInstance = window.$dialog?.create({
|
||||||
title: '编辑银行卡信息',
|
title: '编辑银行卡信息',
|
||||||
content: () =>
|
content: () =>
|
||||||
h(Edit, {
|
h(Edit, {
|
||||||
data: row,
|
data: row,
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
dialogInstance.destroy();
|
dialogInstance?.destroy();
|
||||||
tableInst.value?.reload();
|
tableInst.value?.reload();
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
style: { width: '800px' },
|
style: { width: '600px' },
|
||||||
showIcon: false
|
showIcon: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -119,16 +126,12 @@ function handleEdit(row: any) {
|
|||||||
<template>
|
<template>
|
||||||
<TableBase
|
<TableBase
|
||||||
ref="tableInst"
|
ref="tableInst"
|
||||||
show-header-operation
|
:show-header-operation="false"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:filter-columns="filterColumns"
|
:filter-columns="filterColumns"
|
||||||
|
:filter-columns-count="3"
|
||||||
:fetch-data="fetchData"
|
:fetch-data="fetchData"
|
||||||
:scroll-x="800"
|
:scroll-x="1000"
|
||||||
:header-operations="{
|
|
||||||
add: false,
|
|
||||||
refresh: true,
|
|
||||||
columns: true
|
|
||||||
}"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -5,6 +5,7 @@ import { client, safeClient } from '@/service/api';
|
|||||||
import { DepositTypeEnum } from '@/enum';
|
import { DepositTypeEnum } from '@/enum';
|
||||||
import type { TableBaseColumns, TableFetchData, TableInst } from '@/components/table';
|
import type { TableBaseColumns, TableFetchData, TableInst } from '@/components/table';
|
||||||
import EditForm from './components/edit.vue';
|
import EditForm from './components/edit.vue';
|
||||||
|
import UserBankCard from './components/bankcard.vue';
|
||||||
|
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
@@ -58,16 +59,23 @@ const columns: TableBaseColumns = [
|
|||||||
title: '操作',
|
title: '操作',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
key: 'operation',
|
key: 'operation',
|
||||||
width: 100,
|
width: 200,
|
||||||
operations: (row: any) => [
|
operations: (row: any) => [
|
||||||
{
|
{
|
||||||
contentText: '编辑',
|
contentText: '编辑',
|
||||||
type: 'primary',
|
|
||||||
ghost: true,
|
ghost: true,
|
||||||
size: 'small',
|
size: 'small',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
handleEdit(row);
|
handleEdit(row);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contentText: '银行卡',
|
||||||
|
ghost: true,
|
||||||
|
size: 'small',
|
||||||
|
onClick: () => {
|
||||||
|
handleBankCard(row);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -111,6 +119,21 @@ function handleEdit(row: any) {
|
|||||||
showIcon: false
|
showIcon: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function handleBankCard(row: any) {
|
||||||
|
const dialogInstance = dialog.create({
|
||||||
|
title: '用户银行卡',
|
||||||
|
content: () =>
|
||||||
|
h(UserBankCard, {
|
||||||
|
userId: row.userId,
|
||||||
|
onClose: () => {
|
||||||
|
dialogInstance.destroy();
|
||||||
|
tableInst.value?.reload();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
style: { width: '1000px' },
|
||||||
|
showIcon: false
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
Reference in New Issue
Block a user