zhou zhou
9 小时以前 fec285d150b377d004e47f0973d298b92fe4c711
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
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 }