This commit is contained in:
2025-12-16 20:20:53 +07:00
commit 2e651f1c89
315 changed files with 33529 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
import { h } from 'vue';
import type { ButtonProps, DataTableColumns } from 'naive-ui';
import { NButton, NSpace } from 'naive-ui';
import type { TableColumn } from 'naive-ui/es/data-table/src/interface';
import type { safeClient } from '@/service/api';
import type TableBase from './table-base.vue';
export type TableBaseColumns<T = any> = Array<
TableColumn<T> & {
operations?: (row: T) => Array<Partial<ButtonProps> & { contentText: string }>;
key: string;
title: string;
}
>;
export type TableInst = InstanceType<typeof TableBase>;
export interface Pagination {
limit: number;
offset: number;
}
export type TableFetchData = (page: Pagination) => ReturnType<typeof safeClient>;
export function transformColumns<T = any>(columns: TableBaseColumns<T>): DataTableColumns<T> {
return columns.map(col => {
return {
...col,
render: col.operations
? (row: T) =>
h(NSpace, null, {
default: () => col.operations!(row).map(item => h(NButton, item, { default: () => item.contentText }))
})
: undefined
} as TableColumn<T>;
});
}
export function transformHeaderColumns<T = any>(columns: TableBaseColumns<T>): NaiveUI.TableColumnCheck[] {
return columns
.filter(col => {
return !col.fixed;
})
.map(col => ({
key: col.key,
title: col.title,
checked: true,
visible: true
}));
}

View File

@@ -0,0 +1,73 @@
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import type { PaginationProps } from 'naive-ui';
import { type TableBaseColumns, type TableFetchData, transformColumns, transformHeaderColumns } from '.';
const props = defineProps<{
fetchData: TableFetchData;
columns: TableBaseColumns;
showHeaderOperation?: boolean;
}>();
const emit = defineEmits<{
(e: 'add'): void;
(e: 'refresh'): void;
(e: 'delete'): void;
}>();
const tableData = ref<any[]>([]);
const dataTableColumns = transformColumns(props.columns);
const headerTableColumns = transformHeaderColumns(props.columns);
const pagination = ref<PaginationProps>({
page: 1,
pageSize: 10,
itemCount: 0,
showSizePicker: true,
pageSizes: [10, 20, 50, 100]
});
async function loadData() {
const page = pagination.value.page || 1;
const pageSize = pagination.value.pageSize || 10;
const { data } = await props.fetchData({
limit: pageSize,
offset: (page - 1) * pageSize
});
tableData.value = (data.value as any).data;
pagination.value.itemCount = (data.value as any).pagination.total;
}
function handlePageChange(curPage: number) {
pagination.value.page = curPage;
loadData();
}
onMounted(() => {
loadData();
});
defineExpose({
reload: loadData
});
</script>
<template>
<div class="space-y-5">
<TableHeaderOperation
v-if="showHeaderOperation"
:columns="headerTableColumns"
@add="emit('add')"
@refresh="emit('refresh')"
@delete="emit('delete')"
/>
<NDataTable
:columns="dataTableColumns"
:data="tableData"
:pagination="pagination"
:bordered="false"
:on-update:page="handlePageChange"
/>
</div>
</template>
<style lang="css" scoped></style>