feat: 增加表头操作功能,支持动态控制操作按钮显示;优化银行卡信息展示

This commit is contained in:
2025-12-22 04:05:17 +07:00
parent 23b9997bd3
commit 672d7c8958
4 changed files with 69 additions and 33 deletions

View File

@@ -18,6 +18,7 @@ export default defineConfig(
ignores: ['/^icon-/'] ignores: ['/^icon-/']
} }
], ],
'vue/no-duplicate-attr-inheritance': 'off',
'unocss/order-attributify': 'off' 'unocss/order-attributify': 'off'
} }
} }

View File

@@ -9,6 +9,12 @@ interface Props {
itemAlign?: NaiveUI.Align; itemAlign?: NaiveUI.Align;
disabledDelete?: boolean; disabledDelete?: boolean;
loading?: boolean; loading?: boolean;
operations?: {
add?: boolean;
refresh?: boolean;
delete?: boolean;
columns?: boolean;
};
} }
defineProps<Props>(); defineProps<Props>();
@@ -43,27 +49,34 @@ function refresh() {
<slot name="prefix"></slot> <slot name="prefix"></slot>
<div class="space-x-5"> <div class="space-x-5">
<slot name="default"> <slot name="default">
<NButton size="small" ghost type="primary" @click="add"> <NButton v-if="operations?.add" size="small" ghost type="primary" @click="add">
<template #icon> <template #icon>
<icon-ic-round-plus class="text-icon" /> <icon-ic-round-plus class="text-icon" />
</template> </template>
{{ $t('common.add') }} {{ $t('common.add') }}
</NButton> </NButton>
<NButton size="small" ghost type="error" :disabled="disabledDelete" @click="batchDelete"> <NButton
v-if="operations?.delete"
size="small"
ghost
type="error"
:disabled="disabledDelete"
@click="batchDelete"
>
<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>
</slot> </slot>
<NButton size="small" @click="refresh"> <NButton v-if="operations?.refresh" size="small" @click="refresh">
<template #icon> <template #icon>
<icon-mdi-refresh class="text-icon" :class="{ 'animate-spin': loading }" /> <icon-mdi-refresh class="text-icon" :class="{ 'animate-spin': loading }" />
</template> </template>
{{ $t('common.refresh') }} {{ $t('common.refresh') }}
</NButton> </NButton>
<TableColumnSetting v-model:columns="columns" /> <TableColumnSetting v-if="operations?.columns" v-model:columns="columns" />
</div> </div>
<slot name="suffix"></slot> <slot name="suffix"></slot>
</NSpace> </NSpace>

View File

@@ -1,7 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref } from 'vue'; import type { ComponentInstance } from 'vue';
import { getCurrentInstance, onMounted, ref } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import type { DataTableColumns, PaginationProps } from 'naive-ui'; import type { DataTableColumns, NDataTable, PaginationProps } from 'naive-ui';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { import {
type TableBaseColumns, type TableBaseColumns,
@@ -22,10 +23,23 @@ const props = withDefaults(
fetchData: TableFetchData; fetchData: TableFetchData;
columns: TableBaseColumns; columns: TableBaseColumns;
showHeaderOperation?: boolean; showHeaderOperation?: boolean;
headerOperations?: {
add?: boolean;
refresh?: boolean;
delete?: boolean;
columns?: boolean;
};
filterColumns?: TableFilterColumns; filterColumns?: TableFilterColumns;
}>(), }>(),
{ {
filterColumns: () => [] showHeaderOperation: true,
filterColumns: () => [],
headerOperations: () => ({
add: true,
refresh: true,
delete: false,
columns: true
})
} }
); );
const emit = defineEmits<{ const emit = defineEmits<{
@@ -43,6 +57,7 @@ const pagination = ref<PaginationProps>({
showSizePicker: true, showSizePicker: true,
pageSizes: [10, 20, 50, 100] pageSizes: [10, 20, 50, 100]
}); });
const vm = getCurrentInstance()!;
async function loadData(query?: Record<string, any>) { async function loadData(query?: Record<string, any>) {
loading.value = true; loading.value = true;
@@ -87,14 +102,22 @@ function handleUpdateColumns(columns: TableColumnCheck[]) {
dataTableColumns.value = sortedColumns as DataTableColumns; dataTableColumns.value = sortedColumns as DataTableColumns;
} }
function tableRef(exposed: any) {
vm.exposed = {
reload: loadData,
...exposed
};
}
onMounted(() => { onMounted(() => {
loadData(); loadData();
}); });
defineExpose({ interface Expose extends ComponentInstance<typeof NDataTable> {
reload: loadData reload: typeof loadData;
}); }
defineExpose({} as Expose);
</script> </script>
<template> <template>
@@ -104,6 +127,7 @@ defineExpose({
<div class="rounded-lg bg-white p-5 space-y-5 dark:bg-white/10"> <div class="rounded-lg bg-white p-5 space-y-5 dark:bg-white/10">
<TableHeaderOperation <TableHeaderOperation
v-if="showHeaderOperation" v-if="showHeaderOperation"
:operations="headerOperations"
:columns="headerTableColumns" :columns="headerTableColumns"
@update:columns="handleUpdateColumns" @update:columns="handleUpdateColumns"
@add="emit('add')" @add="emit('add')"
@@ -116,7 +140,7 @@ defineExpose({
</TableHeaderOperation> </TableHeaderOperation>
<NDataTable <NDataTable
:row-key="row => (row as any).id" :ref="tableRef"
:loading="loading" :loading="loading"
:scroll-x="2000" :scroll-x="2000"
:columns="dataTableColumns" :columns="dataTableColumns"
@@ -125,6 +149,7 @@ defineExpose({
:bordered="false" :bordered="false"
:on-update:page="handlePageChange" :on-update:page="handlePageChange"
:on-update:page-size="handlePageSizeChange" :on-update:page-size="handlePageSizeChange"
v-bind="$attrs"
/> />
</div> </div>
</div> </div>

View File

@@ -1,8 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useTemplateRef } from 'vue'; import { useTemplateRef } from 'vue';
import { NDatePicker, useDialog, useMessage } from 'naive-ui'; import { useDialog, useMessage } from 'naive-ui';
import { client, safeClient } from '@/service/api'; import { client, safeClient } from '@/service/api';
import type { TableBaseColumns, TableFetchData, TableInst } from '@/components/table'; import type { TableBaseColumns, TableFetchData, TableFilterColumns, TableInst } from '@/components/table';
const dialog = useDialog(); const dialog = useDialog();
const message = useMessage(); const message = useMessage();
@@ -24,29 +24,21 @@ const columns: TableBaseColumns = [
title: 'ID', title: 'ID',
key: 'userId' key: 'userId'
}, },
{
title: '用户名',
key: 'accountName'
},
{ {
title: '银行卡名称', title: '银行卡名称',
key: 'bankName' key: 'bankName'
}, },
{ {
title: '银行号', title: '银行号',
key: 'bankCode' key: 'bankCode'
}, },
{ {
title: '账户名', title: '风险等级',
key: 'accountName' key: 'riskStatus'
},
{
title: 'maskAccountNumber',
key: 'maskAccountNumber'
},
{
title: 'country',
key: 'country'
},
{
title: 'branchName',
key: 'branchName'
}, },
{ {
title: '操作', title: '操作',
@@ -57,6 +49,7 @@ const columns: TableBaseColumns = [
{ {
contentText: '编辑', contentText: '编辑',
type: 'primary', type: 'primary',
ghost: true,
onClick: () => { onClick: () => {
tableInst.value?.reload(); tableInst.value?.reload();
} }
@@ -65,7 +58,6 @@ const columns: TableBaseColumns = [
contentText: '删除', contentText: '删除',
type: 'error', type: 'error',
ghost: true, ghost: true,
size: 'small',
onClick: async () => { onClick: async () => {
dialog.create({ dialog.create({
title: '提示', title: '提示',
@@ -94,15 +86,20 @@ const filterColumns: TableFilterColumns = [
key: 'bankName' key: 'bankName'
}, },
{ {
title: '银行号', title: '银行号',
key: 'bankCode', key: 'bankCode'
component: NDatePicker
} }
]; ];
</script> </script>
<template> <template>
<TableBase ref="tableInst" :columns="columns" :filter-columns="filterColumns" :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>