import { ref, computed, watch } from 'vue' import { $t } from '@/locales' const SPECIAL_COLUMNS = { selection: { prop: '__selection__', label: $t('table.column.selection') }, expand: { prop: '__expand__', label: $t('table.column.expand') }, index: { prop: '__index__', label: $t('table.column.index') } } const getColumnKey = (col) => SPECIAL_COLUMNS[col.type]?.prop ?? col.prop const getColumnVisibility = (col) => { if (col.visible !== void 0) { return col.visible } return col.checked ?? true } const getColumnChecks = (columns) => columns.map((col) => { const special = col.type && SPECIAL_COLUMNS[col.type] const visibility = getColumnVisibility(col) if (special) { return { ...col, prop: special.prop, label: special.label, checked: true, visible: true } } return { ...col, checked: visibility, visible: visibility } }) function useTableColumns(columnsFactory) { const dynamicColumns = ref(columnsFactory()) const columnChecks = ref(getColumnChecks(dynamicColumns.value)) watch( dynamicColumns, (newCols) => { const visibilityMap = new Map( columnChecks.value.map((c) => [getColumnKey(c), getColumnVisibility(c)]) ) const newChecks = getColumnChecks(newCols).map((c) => { const key = getColumnKey(c) const visibility = visibilityMap.has(key) ? visibilityMap.get(key) : getColumnVisibility(c) return { ...c, checked: visibility, visible: visibility } }) columnChecks.value = newChecks }, { deep: true } ) const columns = computed(() => { const colMap = new Map(dynamicColumns.value.map((c) => [getColumnKey(c), c])) return columnChecks.value .filter((c) => getColumnVisibility(c)) .map((c) => colMap.get(getColumnKey(c))) .filter(Boolean) }) const setDynamicColumns = (updater) => { const copy = [...dynamicColumns.value] const result = updater(copy) dynamicColumns.value = Array.isArray(result) ? result : copy } return { columns, columnChecks, /** * 新增列(支持单个或批量) */ addColumn: (column, index) => setDynamicColumns((cols) => { const next = [...cols] const columnsToAdd = Array.isArray(column) ? column : [column] const insertIndex = typeof index === 'number' && index >= 0 && index <= next.length ? index : next.length next.splice(insertIndex, 0, ...columnsToAdd) return next }), /** * 删除列(支持单个或批量) */ removeColumn: (prop) => setDynamicColumns((cols) => { const propsToRemove = Array.isArray(prop) ? prop : [prop] return cols.filter((c) => !propsToRemove.includes(getColumnKey(c))) }), /** * 更新列(支持单个或批量) */ updateColumn: (prop, updates) => { if (Array.isArray(prop)) { setDynamicColumns((cols) => { const map = new Map(prop.map((u) => [u.prop, u.updates])) return cols.map((c) => { const key = getColumnKey(c) const upd = map.get(key) return upd ? { ...c, ...upd } : c }) }) } else if (updates) { setDynamicColumns((cols) => cols.map((c) => (getColumnKey(c) === prop ? { ...c, ...updates } : c)) ) } }, /** * 切换列显示状态(支持单个或批量) */ toggleColumn: (prop, visible) => { const propsToToggle = Array.isArray(prop) ? prop : [prop] const next = [...columnChecks.value] propsToToggle.forEach((p) => { const i = next.findIndex((c) => getColumnKey(c) === p) if (i > -1) { const currentVisibility = getColumnVisibility(next[i]) const newVisibility = visible ?? !currentVisibility next[i] = { ...next[i], checked: newVisibility, visible: newVisibility } } }) columnChecks.value = next }, /** * 重置所有列 */ resetColumns: () => { dynamicColumns.value = columnsFactory() }, /** * 批量更新列(兼容旧版本) * @deprecated 推荐使用 updateColumn 的数组模式 */ batchUpdateColumns: (updates) => setDynamicColumns((cols) => { const map = new Map(updates.map((u) => [u.prop, u.updates])) return cols.map((c) => { const key = getColumnKey(c) const upd = map.get(key) return upd ? { ...c, ...upd } : c }) }), /** * 重新排序列 */ reorderColumns: (fromIndex, toIndex) => setDynamicColumns((cols) => { if ( fromIndex < 0 || fromIndex >= cols.length || toIndex < 0 || toIndex >= cols.length || fromIndex === toIndex ) { return cols } const next = [...cols] const [moved] = next.splice(fromIndex, 1) next.splice(toIndex, 0, moved) return next }), /** * 获取列配置 */ getColumnConfig: (prop) => dynamicColumns.value.find((c) => getColumnKey(c) === prop), /** * 获取所有列配置 */ getAllColumns: () => [...dynamicColumns.value] } } export { getColumnChecks, getColumnKey, getColumnVisibility, useTableColumns }