更新表格组件,新增过滤功能,调整数据获取逻辑,优化界面布局
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
# backend service base url, test environment
|
# backend service base url, test environment
|
||||||
VITE_SERVICE_BASE_URL=http://192.168.1.36:9527
|
VITE_SERVICE_BASE_URL=http://192.168.1.36:9528
|
||||||
|
|
||||||
# other backend service base url, test environment
|
# other backend service base url, test environment
|
||||||
VITE_OTHER_SERVICE_BASE_URL= `{}`
|
VITE_OTHER_SERVICE_BASE_URL= `{}`
|
||||||
|
|||||||
@@ -39,8 +39,9 @@ function refresh() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSpace :align="itemAlign" wrap justify="end" class="lt-sm:w-200px">
|
<NSpace :align="itemAlign" justify="space-between" wrap class="lt-sm:w-200px">
|
||||||
<slot name="prefix"></slot>
|
<slot name="prefix"></slot>
|
||||||
|
<div class="space-x-5">
|
||||||
<slot name="default">
|
<slot name="default">
|
||||||
<NButton size="small" ghost type="primary" @click="add">
|
<NButton size="small" ghost type="primary" @click="add">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@@ -48,17 +49,13 @@ function refresh() {
|
|||||||
</template>
|
</template>
|
||||||
{{ $t('common.add') }}
|
{{ $t('common.add') }}
|
||||||
</NButton>
|
</NButton>
|
||||||
<NPopconfirm @positive-click="batchDelete">
|
|
||||||
<template #trigger>
|
<NButton size="small" ghost type="error" :disabled="disabledDelete" @click="batchDelete">
|
||||||
<NButton size="small" ghost type="error" :disabled="disabledDelete">
|
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<icon-ic-round-delete class="text-icon" />
|
<icon-ic-round-delete class="text-icon" />
|
||||||
</template>
|
</template>
|
||||||
{{ $t('common.batchDelete') }}
|
{{ $t('common.batchDelete') }}
|
||||||
</NButton>
|
</NButton>
|
||||||
</template>
|
|
||||||
{{ $t('common.confirmDelete') }}
|
|
||||||
</NPopconfirm>
|
|
||||||
</slot>
|
</slot>
|
||||||
<NButton size="small" @click="refresh">
|
<NButton size="small" @click="refresh">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@@ -67,6 +64,7 @@ function refresh() {
|
|||||||
{{ $t('common.refresh') }}
|
{{ $t('common.refresh') }}
|
||||||
</NButton>
|
</NButton>
|
||||||
<TableColumnSetting v-model:columns="columns" />
|
<TableColumnSetting v-model:columns="columns" />
|
||||||
|
</div>
|
||||||
<slot name="suffix"></slot>
|
<slot name="suffix"></slot>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { Component, VNode } from 'vue';
|
||||||
import { h } from 'vue';
|
import { h } from 'vue';
|
||||||
import type { ButtonProps, DataTableColumn, DataTableColumns } from 'naive-ui';
|
import type { ButtonProps, DataTableColumn, DataTableColumns } from 'naive-ui';
|
||||||
import { NButton, NSpace } from 'naive-ui';
|
import { NButton, NSpace } from 'naive-ui';
|
||||||
@@ -24,12 +25,27 @@ export interface Pagination {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TableFetchData = (page: Pagination) => ReturnType<typeof safeClient>;
|
export type TableFetchData = (query: {
|
||||||
|
pagination: Pagination;
|
||||||
|
filter?: Record<string, any>;
|
||||||
|
}) => ReturnType<typeof safeClient>;
|
||||||
|
|
||||||
|
export type TableFilterColumn = {
|
||||||
|
key: string;
|
||||||
|
title: string;
|
||||||
|
component?: Component | VNode;
|
||||||
|
componentProps?: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TableFilterColumns = Array<TableFilterColumn>;
|
||||||
|
|
||||||
export function transformColumns<T = InternalRowData>(columns: TableBaseColumns<T>): DataTableColumns<T> {
|
export function transformColumns<T = InternalRowData>(columns: TableBaseColumns<T>): DataTableColumns<T> {
|
||||||
return columns.map(col => {
|
return columns.map(col => {
|
||||||
return {
|
return {
|
||||||
...col,
|
...col,
|
||||||
|
ellipsis: {
|
||||||
|
tooltip: true
|
||||||
|
},
|
||||||
render: col.operations
|
render: col.operations
|
||||||
? (row: T) =>
|
? (row: T) =>
|
||||||
h(NSpace, null, {
|
h(NSpace, null, {
|
||||||
|
|||||||
@@ -1,12 +1,25 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import type { PaginationProps } from 'naive-ui';
|
import { useRoute } from 'vue-router';
|
||||||
import { type TableBaseColumns, type TableFetchData, transformColumns, transformHeaderColumns } from '.';
|
import type { DataTableColumns, PaginationProps } from 'naive-ui';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import {
|
||||||
|
type TableBaseColumns,
|
||||||
|
type TableFetchData,
|
||||||
|
type TableFilterColumns,
|
||||||
|
transformColumns,
|
||||||
|
transformHeaderColumns
|
||||||
|
} from '.';
|
||||||
|
import type { TableColumnCheck } from '~/packages/hooks/src';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const title = t(route.meta.i18nKey as string);
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
fetchData: TableFetchData;
|
fetchData: TableFetchData;
|
||||||
columns: TableBaseColumns;
|
columns: TableBaseColumns;
|
||||||
showHeaderOperation?: boolean;
|
showHeaderOperation?: boolean;
|
||||||
|
filterColumns?: TableFilterColumns;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'add'): void;
|
(e: 'add'): void;
|
||||||
@@ -15,8 +28,8 @@ const emit = defineEmits<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const tableData = ref<any[]>([]);
|
const tableData = ref<any[]>([]);
|
||||||
const dataTableColumns = transformColumns(props.columns);
|
const dataTableColumns = ref<DataTableColumns>(transformColumns(props.columns));
|
||||||
const headerTableColumns = transformHeaderColumns(props.columns);
|
const headerTableColumns = ref<NaiveUI.TableColumnCheck[]>(transformHeaderColumns(props.columns));
|
||||||
const pagination = ref<PaginationProps>({
|
const pagination = ref<PaginationProps>({
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@@ -25,12 +38,15 @@ const pagination = ref<PaginationProps>({
|
|||||||
pageSizes: [10, 20, 50, 100]
|
pageSizes: [10, 20, 50, 100]
|
||||||
});
|
});
|
||||||
|
|
||||||
async function loadData() {
|
async function loadData(query?: Record<string, any>) {
|
||||||
const page = pagination.value.page || 1;
|
const page = pagination.value.page || 1;
|
||||||
const pageSize = pagination.value.pageSize || 10;
|
const pageSize = pagination.value.pageSize || 10;
|
||||||
const { data } = await props.fetchData({
|
const { data } = await props.fetchData({
|
||||||
|
pagination: {
|
||||||
pageIndex: page,
|
pageIndex: page,
|
||||||
pageSize
|
pageSize
|
||||||
|
},
|
||||||
|
filter: query
|
||||||
});
|
});
|
||||||
|
|
||||||
tableData.value = (data.value as any).data;
|
tableData.value = (data.value as any).data;
|
||||||
@@ -45,6 +61,19 @@ function handlePageSizeChange(curPageSize: number) {
|
|||||||
pagination.value.pageSize = curPageSize;
|
pagination.value.pageSize = curPageSize;
|
||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
|
function handleSearch(form: Record<string, any>) {
|
||||||
|
pagination.value.page = 1;
|
||||||
|
loadData(form);
|
||||||
|
}
|
||||||
|
function handleUpdateColumns(columns: TableColumnCheck[]) {
|
||||||
|
headerTableColumns.value = columns;
|
||||||
|
const sortKeys = columns.map(col => col.key);
|
||||||
|
|
||||||
|
const currentColumns: DataTableColumns = [...dataTableColumns.value];
|
||||||
|
const sortedColumns = sortKeys.map(key => currentColumns.find(col => (col as any).key === key)).filter(Boolean);
|
||||||
|
|
||||||
|
dataTableColumns.value = sortedColumns as DataTableColumns;
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadData();
|
loadData();
|
||||||
@@ -57,14 +86,24 @@ defineExpose({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-5">
|
<div class="space-y-5">
|
||||||
|
<TableFilter :columns="filterColumns" @confirm="handleSearch" />
|
||||||
|
|
||||||
|
<div class="rounded-lg bg-white p-5 space-y-5">
|
||||||
<TableHeaderOperation
|
<TableHeaderOperation
|
||||||
v-if="showHeaderOperation"
|
v-if="showHeaderOperation"
|
||||||
:columns="headerTableColumns"
|
:columns="headerTableColumns"
|
||||||
|
@update:columns="handleUpdateColumns"
|
||||||
@add="emit('add')"
|
@add="emit('add')"
|
||||||
@refresh="emit('refresh')"
|
@refresh="loadData()"
|
||||||
@delete="emit('delete')"
|
@delete="emit('delete')"
|
||||||
/>
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<div class="text-lg font-bold">{{ title }}</div>
|
||||||
|
</template>
|
||||||
|
</TableHeaderOperation>
|
||||||
|
|
||||||
<NDataTable
|
<NDataTable
|
||||||
|
:scroll-x="2000"
|
||||||
:columns="dataTableColumns"
|
:columns="dataTableColumns"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
@@ -73,6 +112,7 @@ defineExpose({
|
|||||||
:on-update:page-size="handlePageSizeChange"
|
:on-update:page-size="handlePageSizeChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="css" scoped></style>
|
<style lang="css" scoped></style>
|
||||||
|
|||||||
47
src/components/table/table-filter.vue
Normal file
47
src/components/table/table-filter.vue
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { NInput } from 'naive-ui';
|
||||||
|
import type { TableFilterColumns } from '.';
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
columns?: TableFilterColumns;
|
||||||
|
}>();
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'confirm', form: Record<string, any>): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const form = ref<Record<string, any>>({});
|
||||||
|
|
||||||
|
function handleReset() {
|
||||||
|
form.value = {};
|
||||||
|
emit('confirm', form.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleConfirm() {
|
||||||
|
emit('confirm', form.value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="rounded-lg bg-white p-5">
|
||||||
|
<div class="mb-5">搜索</div>
|
||||||
|
|
||||||
|
<NForm :label-width="80" label-align="left" label-placement="left">
|
||||||
|
<NGrid x-gap="20" :cols="4">
|
||||||
|
<NGi v-for="col in columns" :key="col.key">
|
||||||
|
<NFormItem :label="col.title" :path="col.key">
|
||||||
|
<component :is="col.component || NInput" v-model:value="form[col.key]" v-bind="col.componentProps" />
|
||||||
|
</NFormItem>
|
||||||
|
</NGi>
|
||||||
|
<NGi>
|
||||||
|
<NSpace>
|
||||||
|
<NButton type="primary" ghost @click="handleReset">重置</NButton>
|
||||||
|
<NButton type="primary" @click="handleConfirm">搜索</NButton>
|
||||||
|
</NSpace>
|
||||||
|
</NGi>
|
||||||
|
</NGrid>
|
||||||
|
</NForm>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="css" scoped></style>
|
||||||
2
src/typings/components.d.ts
vendored
2
src/typings/components.d.ts
vendored
@@ -91,6 +91,7 @@ declare module 'vue' {
|
|||||||
SystemLogo: typeof import('./../components/common/system-logo.vue')['default']
|
SystemLogo: typeof import('./../components/common/system-logo.vue')['default']
|
||||||
TableBase: typeof import('./../components/table/table-base.vue')['default']
|
TableBase: typeof import('./../components/table/table-base.vue')['default']
|
||||||
TableColumnSetting: typeof import('./../components/advanced/table-column-setting.vue')['default']
|
TableColumnSetting: typeof import('./../components/advanced/table-column-setting.vue')['default']
|
||||||
|
TableFilter: typeof import('./../components/table/table-filter.vue')['default']
|
||||||
TableHeaderOperation: typeof import('./../components/advanced/table-header-operation.vue')['default']
|
TableHeaderOperation: typeof import('./../components/advanced/table-header-operation.vue')['default']
|
||||||
ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
|
ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
|
||||||
WaveBg: typeof import('./../components/custom/wave-bg.vue')['default']
|
WaveBg: typeof import('./../components/custom/wave-bg.vue')['default']
|
||||||
@@ -178,6 +179,7 @@ declare global {
|
|||||||
const SystemLogo: typeof import('./../components/common/system-logo.vue')['default']
|
const SystemLogo: typeof import('./../components/common/system-logo.vue')['default']
|
||||||
const TableBase: typeof import('./../components/table/table-base.vue')['default']
|
const TableBase: typeof import('./../components/table/table-base.vue')['default']
|
||||||
const TableColumnSetting: typeof import('./../components/advanced/table-column-setting.vue')['default']
|
const TableColumnSetting: typeof import('./../components/advanced/table-column-setting.vue')['default']
|
||||||
|
const TableFilter: typeof import('./../components/table/table-filter.vue')['default']
|
||||||
const TableHeaderOperation: typeof import('./../components/advanced/table-header-operation.vue')['default']
|
const TableHeaderOperation: typeof import('./../components/advanced/table-header-operation.vue')['default']
|
||||||
const ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
|
const ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
|
||||||
const WaveBg: typeof import('./../components/custom/wave-bg.vue')['default']
|
const WaveBg: typeof import('./../components/custom/wave-bg.vue')['default']
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { h, ref, useTemplateRef } from 'vue';
|
import { useTemplateRef } from 'vue';
|
||||||
import { NInputNumber, useDialog, useMessage } from 'naive-ui';
|
import { NDatePicker, useDialog, useMessage } from 'naive-ui';
|
||||||
import { client, safeClient } from '@/service/api';
|
import { client, safeClient } from '@/service/api';
|
||||||
import { DepositTypeEnum } from '@/enum';
|
import type { TableBaseColumns, TableFetchData, TableFilterColumns, TableInst } from '@/components/table';
|
||||||
import type { TableBaseColumns, TableFetchData, TableInst } from '@/components/table';
|
|
||||||
|
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const message = useMessage();
|
const message = useMessage();
|
||||||
const tableInst = useTemplateRef<TableInst>('tableInst');
|
const tableInst = useTemplateRef<TableInst>('tableInst');
|
||||||
|
|
||||||
const fetchData: TableFetchData = () => {
|
const fetchData: TableFetchData = ({ pagination, filter }) => {
|
||||||
return safeClient(() =>
|
return safeClient(() =>
|
||||||
client.api.admin.rwa.issuance.products.get({
|
client.api.admin.rwa.issuance.products.get({
|
||||||
query: {}
|
query: {
|
||||||
|
...pagination,
|
||||||
|
...filter
|
||||||
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -23,7 +25,7 @@ const columns: TableBaseColumns = [
|
|||||||
key: 'id'
|
key: 'id'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'code',
|
title: 'Code',
|
||||||
key: 'code'
|
key: 'code'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -31,64 +33,99 @@ const columns: TableBaseColumns = [
|
|||||||
key: 'name'
|
key: 'name'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'description',
|
title: '估值',
|
||||||
key: 'description'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'estimatedValue',
|
|
||||||
key: 'estimatedValue'
|
key: 'estimatedValue'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'categoryId',
|
title: '产品分类',
|
||||||
key: 'categoryId'
|
key: 'categoryId'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'createdBy',
|
title: '创建人',
|
||||||
key: 'createdBy'
|
key: 'createdBy'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'createdAt',
|
||||||
|
render: (row: any) => {
|
||||||
|
return new Date(row.createdAt).toLocaleDateString();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
key: 'status'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '描述',
|
||||||
|
key: 'description'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
key: 'operation',
|
key: 'operation',
|
||||||
width: 160,
|
width: 230,
|
||||||
operations: (row: any) => [
|
operations: (row: any) => [
|
||||||
{
|
{
|
||||||
contentText: '编辑',
|
contentText: '批准',
|
||||||
type: 'primary',
|
size: 'small',
|
||||||
onClick: () => {
|
onClick: async () => {
|
||||||
|
safeClient(() =>
|
||||||
|
client.api.admin.rwa.issuance.approve.post({
|
||||||
|
productId: row.id as string
|
||||||
|
})
|
||||||
|
);
|
||||||
tableInst.value?.reload();
|
tableInst.value?.reload();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
contentText: '删除',
|
contentText: '拒绝',
|
||||||
type: 'error',
|
|
||||||
ghost: true,
|
|
||||||
size: 'small',
|
size: 'small',
|
||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
dialog.create({
|
|
||||||
title: '提示',
|
|
||||||
positiveText: '是',
|
|
||||||
negativeText: '否',
|
|
||||||
content: '确认删除该银行信息?',
|
|
||||||
onPositiveClick: async () => {
|
|
||||||
safeClient(() =>
|
safeClient(() =>
|
||||||
client.api.admin.deposit.reject({ orderId: row.id as string }).post({
|
client.api.admin.rwa.issuance.reject.post({
|
||||||
reviewNote: '管理员拒绝充值'
|
productId: row.id as string,
|
||||||
|
rejectionReason: '不符合要求'
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
// tableInst.value?.reload();
|
tableInst.value?.reload();
|
||||||
message.success('删除成功');
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
{
|
||||||
|
contentText: '编辑',
|
||||||
|
size: 'small',
|
||||||
|
onClick: () => {
|
||||||
|
tableInst.value?.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const filterColumns: TableFilterColumns = [
|
||||||
|
{
|
||||||
|
title: '产品名称',
|
||||||
|
key: 'name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '产品Code',
|
||||||
|
key: 'Code'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'createdAt',
|
||||||
|
component: NDatePicker
|
||||||
|
}
|
||||||
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<TableBase ref="tableInst" :columns="columns" :fetch-data="fetchData" />
|
<TableBase
|
||||||
|
ref="tableInst"
|
||||||
|
show-header-operation
|
||||||
|
:columns="columns"
|
||||||
|
:filter-columns="filterColumns"
|
||||||
|
:fetch-data="fetchData"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="css" scoped></style>
|
<style lang="css" scoped></style>
|
||||||
|
|||||||
Reference in New Issue
Block a user