import { computed, ref, toRaw, type Ref } from 'vue'; import { DEFAULT_SORT_CONFIG } from './const'; import type { Order, SortConfig, SortOption, SortState, StkTableColumn, UniqKey } from './types/index'; import { tableSort } from './utils/index'; /** * 排序切换顺序 * 循环顺序:null → desc → asc → null → ... */ const SORT_SWITCH_ORDER: Order[] = [null, 'desc', 'asc'] as const; /** * 排序 Hook * 管理表格排序状态和相关操作 * @param props 表格 props * @param colKeyGen 列 key 生成函数 * @param tableHeaderLast 表头最后一行(叶子节点) * @param dataSourceCopy 数据源副本 ref * @param initDataSource 初始化数据源函数 * @param emits 事件发射函数 * @returns 排序相关状态和方法 */ export function useSorter
>( props: any, emits: any, colKeyGen: Ref<(col: StkTableColumn
) => string>, tableHeaderLast: Ref[]>, dataSourceCopy: Ref, initDataSource: (data?: DT[], option?: { forceSort?: boolean }) => void, ) { /** 多列排序状态数组 */ const sortStates = ref[]>([]); /** 是否启用多列排序 */ const isMultiSort = computed(() => props.sortConfig.multiSort ?? false); /** 多列排序限制 */ const multiSortLimit = computed(() => props.sortConfig.multiSortLimit ?? 3); /** 对外暴露:当前排序的列 key(只读计算属性) */ const sortCol = computed(() => sortStates.value[0]?.dataIndex); /** * 获取列的排序状态 */ function getColumnSortState(colKey: UniqKey): SortState
| undefined { return sortStates.value[getSortStateIndex(colKey)] as SortState
| undefined; } /** * 获取列的排序状态索引 */ function getSortStateIndex(colKey: UniqKey): number { return sortStates.value.findIndex(s => s.key === colKey || s.dataIndex === colKey); } function getTableCol(state: { key?: SortState
['key']; dataIndex: SortState
['dataIndex'] }) { return tableHeaderLast.value.find(c => (state.key && colKeyGen.value(c) === state.key) || c.dataIndex === state.dataIndex); } /** * 获取排序列信息 */ function getSortColumns(): { key: keyof DT | undefined; order: Order }[] { return sortStates.value.map(s => ({ key: s.key || s.dataIndex, order: s.order })); } /** * 添加或更新排序状态到 sortStates * @param newState 新的排序状态 * @param mode '1' - 追加模式(多列排序),0 - 替换模式(单列排序) */ function addOrUpdateSortState(newState: SortState
, mode?: 1 | 0) { const existingIndex = getSortStateIndex(newState.key || newState.dataIndex); if (existingIndex >= 0) { // 移除已存在的相同列 sortStates.value.splice(existingIndex, 1); } if (mode && isMultiSort.value) { // 多列排序模式:检查数量限制,然后添加到最前面 if (sortStates.value.length >= multiSortLimit.value) { sortStates.value.pop(); } sortStates.value.unshift(newState as any); } else { sortStates.value = [newState as any]; } } /** * 更新排序状态(点击表头时调用) */ function updateSortState(col: StkTableColumn
, sortConfig: SortConfig
): Order { const colKey = colKeyGen.value(col); const existingIndex = getSortStateIndex(colKey); let newOrder: Order; const defaultSort = sortConfig.defaultSort; if (existingIndex >= 0) { const currentOrder = sortStates.value[existingIndex].order; if (currentOrder && defaultSort && (defaultSort.key === colKey || defaultSort.dataIndex === col.dataIndex)) { // If click default sort column const defaultSwitchOrder = SORT_SWITCH_ORDER.filter(order => order !== null); const currentIndex = defaultSwitchOrder.indexOf(currentOrder); newOrder = defaultSwitchOrder[(currentIndex + 1) % defaultSwitchOrder.length]; } else { // Click other column const currentIndex = SORT_SWITCH_ORDER.indexOf(currentOrder); newOrder = SORT_SWITCH_ORDER[(currentIndex + 1) % 3]; } if (newOrder) { const updatedState = { ...sortStates.value[existingIndex], order: newOrder }; addOrUpdateSortState(updatedState as any, 1); } else { sortStates.value.splice(existingIndex, 1); // Delete sort state if (defaultSort?.order) { // Has default sort const defaultSortCol = getTableCol(defaultSort); const { key, sortField, sortType } = defaultSortCol || {}; addOrUpdateSortState({ key, sortField, sortType, ...defaultSort }, 1); } } } else { newOrder = SORT_SWITCH_ORDER[1]; const newState: SortState
= { key: colKey, dataIndex: col.dataIndex, sortField: col.sortField, sortType: col.sortType, order: newOrder, }; addOrUpdateSortState(newState, 1); } return newOrder; } /** * 对数据源执行排序 * tableSort 内部会根据 sortChildren 配置自动处理树形递归排序 */ function sortData(dataSource: DT[]): DT[] { if (!sortStates.value.length) return dataSource; const sortConfig = { ...DEFAULT_SORT_CONFIG, ...props.sortConfig }; let result = dataSource.slice(); // 从后往前排序,这样前面的排序优先级更高 for (let i = sortStates.value.length - 1; i >= 0; i--) { const state = sortStates.value[i]; const col = getTableCol(state); if (col && state.order) { const colSortConfig = { ...sortConfig, ...col.sortConfig }; result = tableSort(col, state.order, result, colSortConfig); } } return result; } /** * 表头点击排序 */ function onColumnSort(col: StkTableColumn
| undefined | null) { if (!col) { console.warn('onColumnSort: not found col:', col); return; } if (!col.sorter) { // 点击表头触发的排序,如果列没有配置 sorter 则不处理。setSorter 触发的排序则保持通行。 return; } const sortConfig: SortConfig
= { ...DEFAULT_SORT_CONFIG, ...props.sortConfig, ...col.sortConfig }; const order = updateSortState(col, sortConfig); if (!props.sortRemote) { initDataSource(); } emits('sort-change', col, order, toRaw(dataSourceCopy.value), sortConfig); } /** * 设置表头排序状态 */ function setSorter( colKey: string, order: Order, option: { sortOption?: SortOption
; force?: boolean; silent?: boolean; sort?: boolean; append?: boolean } = {}, ): DT[] { const newOption = { silent: true, sortOption: null, sort: true, append: false, ...option }; const colKeyGenValue = colKeyGen.value; let column: StkTableColumn
| undefined; if (order) { column = newOption.sortOption || tableHeaderLast.value.find(it => colKeyGenValue(it) === colKey); if (column) { const newState: SortState
= { key: colKey, dataIndex: column.dataIndex, sortField: column.sortField, sortType: column.sortType, order, }; const mode = newOption.append && isMultiSort.value ? 1 : 0; addOrUpdateSortState(newState, mode); } } else { sortStates.value = []; } if (newOption.sort && dataSourceCopy.value?.length) { if (!props.sortRemote || newOption.force) { initDataSource(props.dataSource, { forceSort: newOption.force }); } } if (!newOption.silent) { if (!column) { column = newOption.sortOption || tableHeaderLast.value.find(it => colKeyGenValue(it) === colKey); } if (column) { emits('sort-change', column, order, toRaw(dataSourceCopy.value), props.sortConfig); } else { console.warn('Can not find column by key:', colKey); } } return dataSourceCopy.value; } /** * 重置排序器 */ function resetSorter() { sortStates.value = []; initDataSource(); } /** * 处理默认排序 */ function dealDefaultSorter() { if (!props.sortConfig.defaultSort) return; const { key, dataIndex, order, silent } = { silent: true, ...props.sortConfig.defaultSort }; setSorter((key || dataIndex) as string, order, { force: false, silent }); } // 只返回需要在组件外部使用的方法和状态 return [sortStates, sortCol, onColumnSort, setSorter, resetSorter, getSortColumns, dealDefaultSorter, getColumnSortState, sortData] as const; }