Files
school-developer/src/hooks/tableColumn.ts
2026-02-09 20:03:42 +08:00

225 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ref, computed, onMounted, nextTick } from 'vue'
import { useRoute } from 'vue-router'
import { getTableConfigFromLocal, saveTableConfigToLocal, updateUserTableConfig } from '/@/api/admin/usertable'
/**
* 表格列配置类型
*/
export interface TableColumn {
prop?: string
label?: string
icon?: any
width?: number | string
minWidth?: number | string
showOverflowTooltip?: boolean
align?: 'left' | 'center' | 'right'
alwaysShow?: boolean
fixed?: boolean | 'left' | 'right'
[key: string]: any
}
/**
* useTableColumnControl Hook
*
* 用于统一管理表格列的显示/隐藏和排序功能
*
* @param tableColumns 表格列配置数组
* @param options 可选配置项
* @returns 返回列控制相关的状态和方法
*
* @example
* ```ts
* const tableColumns = [
* { prop: 'name', label: '姓名', icon: User },
* { prop: 'age', label: '年龄', icon: Calendar }
* ]
*
* const {
* visibleColumns,
* visibleColumnsSorted,
* checkColumnVisible,
* handleColumnChange,
* handleColumnOrderChange
* } = useTableColumnControl(tableColumns)
* ```
*/
export function useTableColumnControl(
tableColumns: TableColumn[],
options?: {
/** 是否在挂载时自动加载配置,默认为 true */
autoLoad?: boolean
/** 自定义存储 key默认使用路由路径 */
storageKey?: string
}
) {
const route = useRoute()
const { autoLoad = true, storageKey: customStorageKey } = options || {}
// 生成存储 key
const getStorageKey = () => {
if (customStorageKey) {
return customStorageKey
}
const routePath = route.path.replace(/^\//, '').replace(/\//g, '-')
return `table-columns-${routePath}`
}
// 当前显示的列
const visibleColumns = ref<string[]>([])
// 列排序顺序
const columnOrder = ref<string[]>([])
/**
* 从本地统一存储加载配置
*/
const loadSavedConfig = () => {
const storageKey = getStorageKey()
const savedConfig = getTableConfigFromLocal(storageKey)
// 获取所有有效的列 key
const validColumns = tableColumns
.filter(col => !col.alwaysShow && !col.fixed)
.map(col => col.prop || col.label || '')
.filter(Boolean)
// 加载可见列配置
if (savedConfig && savedConfig.visibleColumns) {
const filteredSaved = savedConfig.visibleColumns.filter((col: string) => validColumns.includes(col))
visibleColumns.value = filteredSaved.length > 0 ? filteredSaved : validColumns
} else {
visibleColumns.value = validColumns
}
// 加载列排序配置
if (savedConfig && savedConfig.columnOrder) {
columnOrder.value = savedConfig.columnOrder.filter((key: string) => validColumns.includes(key))
// 补充缺失的列
validColumns.forEach(key => {
if (!columnOrder.value.includes(key)) {
columnOrder.value.push(key)
}
})
} else {
columnOrder.value = validColumns
}
}
/**
* 列显示控制函数
* @param prop 列的 prop 或 label
* @returns 是否可见
*/
const checkColumnVisible = (prop: string): boolean => {
if (visibleColumns.value.length === 0) {
return true
}
return visibleColumns.value.includes(prop)
}
/**
* 列变化处理
* @param value 新的可见列数组
*/
const handleColumnChange = (value: string[]) => {
visibleColumns.value = value
const storageKey = getStorageKey()
// 过滤掉 alwaysShow 和 fixed 的列
const selectableColumns = value.filter(col => {
const column = tableColumns.find(c => (c.prop || c.label) === col)
return column && !column.alwaysShow && !column.fixed
})
// 保存到本地统一存储
saveTableConfigToLocal(storageKey, { visibleColumns: selectableColumns })
// 异步保存到后端
updateUserTableConfig(storageKey, { visibleColumns: selectableColumns }).catch(() => {})
}
/**
* 列排序变化处理
* @param order 新的列排序数组
*/
const handleColumnOrderChange = (order: string[]) => {
columnOrder.value = order
const storageKey = getStorageKey()
// 保存到本地统一存储
saveTableConfigToLocal(storageKey, { columnOrder: order })
// 异步保存到后端
updateUserTableConfig(storageKey, { columnOrder: order }).catch(() => {})
}
/**
* 排序后的表格列
* 根据 visibleColumns 和 columnOrder 计算最终显示的列
*/
const visibleColumnsSorted = computed(() => {
// 如果 visibleColumns 为空,显示所有列(初始化时)
if (visibleColumns.value.length === 0) {
return tableColumns.filter(col => !col.alwaysShow && !col.fixed)
}
// 过滤出可见的列
const columns = tableColumns.filter(col => {
const key = col.prop || col.label || ''
return visibleColumns.value.includes(key)
})
// 如果有排序配置,按排序顺序排列
if (columnOrder.value.length > 0) {
const orderedColumns: TableColumn[] = []
const unorderedColumns: TableColumn[] = []
// 先按保存的顺序添加列
columnOrder.value.forEach(key => {
const col = columns.find(c => (c.prop || c.label) === key)
if (col) {
orderedColumns.push(col)
}
})
// 添加未在排序列表中的列(新增的列)
columns.forEach(col => {
const key = col.prop || col.label || ''
if (!columnOrder.value.includes(key)) {
unorderedColumns.push(col)
}
})
return [...orderedColumns, ...unorderedColumns]
}
return columns
})
// 自动加载配置
if (autoLoad) {
loadSavedConfig()
onMounted(() => {
nextTick(() => {
if (visibleColumns.value.length === 0) {
loadSavedConfig()
}
})
})
}
return {
/** 当前可见的列 key 数组 */
visibleColumns,
/** 列排序顺序 */
columnOrder,
/** 排序后的可见列配置数组 */
visibleColumnsSorted,
/** 检查列是否可见 */
checkColumnVisible,
/** 列变化处理函数 */
handleColumnChange,
/** 列排序变化处理函数 */
handleColumnOrderChange,
/** 手动加载配置 */
loadSavedConfig
}
}