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 }
|