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