225 lines
6.2 KiB
TypeScript
225 lines
6.2 KiB
TypeScript
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
|
||
}
|
||
}
|
||
|