import { computed, effectScope, onScopeDispose, reactive, ref, watch } from 'vue';
import type { Ref } from 'vue';
import type { PaginationProps } from 'naive-ui';
import { cloneDeep } from 'lodash-es';
import { useBoolean, useHookTable } from '@sa/hooks';
import { useAppStore } from '@/store/modules/app';
import { $t } from '@/locales';
type TableData = NaiveUI.TableData;
type GetTableData = NaiveUI.GetTableData;
type TableColumn = NaiveUI.TableColumn;
export function useTable(config: NaiveUI.NaiveTableConfig) {
const scope = effectScope();
const appStore = useAppStore();
const isMobile = computed(() => appStore.isMobile);
const { apiFn, apiParams, immediate, showTotal } = config;
const SELECTION_KEY = '__selection__';
const EXPAND_KEY = '__expand__';
const {
loading,
empty,
data,
columns,
columnChecks,
reloadColumns,
getData,
searchParams,
updateSearchParams,
resetSearchParams: resetSearchParams0
} = useHookTable, TableColumn>>>({
apiFn,
apiParams,
columns: config.columns,
transformer: res => {
const { data: records = [], page: current = 1, size = 10, total = 0 } = res.data || {};
const recordsWithIndex = records.map((item, index) => {
return {
...item,
index: (current - 1) * size + index + 1
};
});
return {
data: recordsWithIndex,
pageNum: current,
pageSize: size,
total
};
},
getColumnChecks: cols => {
const checks: NaiveUI.TableColumnCheck[] = [];
cols.forEach(column => {
if (isTableColumnHasKey(column)) {
checks.push({
key: column.key as string,
title: column.title as string,
checked: true
});
} else if (column.type === 'selection') {
checks.push({
key: SELECTION_KEY,
title: $t('common.check'),
checked: true
});
} else if (column.type === 'expand') {
checks.push({
key: EXPAND_KEY,
title: $t('common.expandColumn'),
checked: true
});
}
});
return checks;
},
getColumns: (cols, checks) => {
const columnMap = new Map>>();
cols.forEach(column => {
if (isTableColumnHasKey(column)) {
columnMap.set(column.key as string, column);
} else if (column.type === 'selection') {
columnMap.set(SELECTION_KEY, column);
} else if (column.type === 'expand') {
columnMap.set(EXPAND_KEY, column);
}
});
const filteredColumns = checks
.filter(item => item.checked)
.map(check => columnMap.get(check.key) as TableColumn>);
return filteredColumns;
},
onFetched: async transformed => {
const { pageNum, pageSize, total } = transformed;
updatePagination({
page: pageNum,
pageSize,
itemCount: total
});
},
immediate
});
const pagination: PaginationProps = reactive({
page: 1,
pageSize: 10,
showSizePicker: true,
pageSizes: [10, 15, 20, 25, 30],
onUpdatePage: async (page: number) => {
pagination.page = page;
updateSearchParams({
page,
size: pagination.pageSize!
});
getData();
},
onUpdatePageSize: async (pageSize: number) => {
pagination.pageSize = pageSize;
pagination.page = 1;
updateSearchParams({
page: pagination.page,
size: pageSize
});
getData();
},
...(showTotal
? {
prefix: page => $t('datatable.itemCount', { total: page.itemCount })
}
: {})
});
// this is for mobile, if the system does not support mobile, you can use `pagination` directly
const mobilePagination = computed(() => {
const p: PaginationProps = {
...pagination,
pageSlot: isMobile.value ? 3 : 9,
prefix: !isMobile.value && showTotal ? pagination.prefix : undefined
};
return p;
});
function updatePagination(update: Partial) {
Object.assign(pagination, update);
}
scope.run(() => {
watch(
() => appStore.locale,
() => {
reloadColumns();
}
);
});
onScopeDispose(() => {
scope.stop();
});
const resetSearchParams = () => {
resetSearchParams0();
getData();
};
return {
loading,
empty,
data,
columns,
columnChecks,
reloadColumns,
pagination,
mobilePagination,
updatePagination,
getData,
searchParams,
updateSearchParams,
resetSearchParams
};
}
export function useTableOperate(data: Ref, getData: () => Promise) {
const { bool: drawerVisible, setTrue: openDrawer, setFalse: closeDrawer } = useBoolean();
const operateType = ref('add');
function handleAdd() {
operateType.value = 'add';
openDrawer();
}
/** the editing row data */
const editingData: Ref = ref(null);
function handleEdit(id: T['id']) {
operateType.value = 'edit';
const findItem = data.value.find(item => item.id === id) || null;
editingData.value = cloneDeep(findItem);
openDrawer();
}
/** the checked row keys of table */
const checkedRowKeys = ref([]);
/** the hook after the batch delete operation is completed */
async function onBatchDeleted() {
window.$message?.success($t('common.deleteSuccess'));
checkedRowKeys.value = [];
await getData();
}
/** the hook after the delete operation is completed */
async function onDeleted() {
window.$message?.success($t('common.deleteSuccess'));
await getData();
}
return {
drawerVisible,
openDrawer,
closeDrawer,
operateType,
handleAdd,
editingData,
handleEdit,
checkedRowKeys,
onBatchDeleted,
onDeleted
};
}
function isTableColumnHasKey(column: TableColumn): column is NaiveUI.TableColumnWithKey {
return Boolean((column as NaiveUI.TableColumnWithKey).key);
}