@lx-frontend/wrap-element-ui 1.0.0-beta.7 → 1.0.1-7.beta-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +2 -2
  2. package/package.json +6 -5
  3. package/src/components/EditableTable/bizHooks/index.ts +7 -0
  4. package/src/components/EditableTable/{useCellHover.ts → bizHooks/useCellHover.ts} +1 -1
  5. package/src/components/EditableTable/bizHooks/useColumnHeaderOperation.ts +329 -0
  6. package/src/components/EditableTable/{useDefaultOperation.ts → bizHooks/useDefaultOperation.ts} +2 -2
  7. package/src/components/EditableTable/{useDragSort.ts → bizHooks/useDragSort.ts} +4 -4
  8. package/src/components/EditableTable/{usePagination.ts → bizHooks/usePagination.ts} +3 -3
  9. package/src/components/EditableTable/{useRowBgColor.ts → bizHooks/useRowBgColor.ts} +9 -16
  10. package/src/components/EditableTable/bizHooks/useViewSetting.ts +125 -0
  11. package/src/components/EditableTable/features/bizColorSelect.vue +63 -0
  12. package/src/components/EditableTable/features/bizEditCell.vue +44 -0
  13. package/src/components/EditableTable/features/bizTableHeaderPopover/BizCheckboxFilter.vue +40 -0
  14. package/src/components/EditableTable/features/bizTableHeaderPopover/BizColorRadioFilter.vue +56 -0
  15. package/src/components/EditableTable/features/bizTableHeaderPopover/BizDoubleDatePickerFilter.vue +91 -0
  16. package/src/components/EditableTable/features/bizTableHeaderPopover/BizInputFilter.vue +26 -0
  17. package/src/components/EditableTable/features/bizTableHeaderPopover/BizMonthDayPicker.helper.ts +131 -0
  18. package/src/components/EditableTable/features/bizTableHeaderPopover/BizMonthDayPicker.vue +115 -0
  19. package/src/components/EditableTable/features/bizTableHeaderPopover/BizRadioFilter.vue +39 -0
  20. package/src/components/EditableTable/features/bizTableHeaderPopover/BizSortFilter.vue +50 -0
  21. package/src/components/EditableTable/features/bizTableHeaderPopover/index.vue +155 -0
  22. package/src/components/EditableTable/features/bizTableOperatePopover.vue +67 -0
  23. package/src/components/EditableTable/features/bizViewSettingDialog.vue +137 -0
  24. package/src/components/EditableTable/index.less +524 -428
  25. package/src/components/EditableTable/index.vue +167 -456
  26. package/src/components/EditableTable/{types.ts → types/index.ts} +176 -116
  27. package/src/components/SearchForm/index.vue +7 -4
  28. package/src/components/SearchForm/types/index.ts +63 -0
  29. package/src/components/EditableTable/useColumnHeaderOperation.ts +0 -326
  30. package/src/components/EditableTable/useViewSetting.ts +0 -119
package/README.md CHANGED
@@ -34,9 +34,9 @@ export default {
34
34
 
35
35
  ### 开发指南
36
36
 
37
- 新增或修改组件时,使用 `pnpm sb:dev` 可以实时预览 stories。
37
+ 新增或修改组件时,使用 `pnpm dev` 可以实时预览 stories。
38
38
 
39
- 开发完成后,可以使用 `pnpm sb:dist` 预览打包后的组件是否能正常工作。与 `pnpm sb:dev` 的区别在于,该命令修改了组件的引用地址,指向了打包后的组件。该命令不能实时预览修改。
39
+ 开发完成后,可以使用 `pnpm dist` 预览打包后的组件是否能正常工作。与 `pnpm dev` 的区别在于,该命令修改了组件的引用地址,指向了打包后的组件。该命令不能实时预览修改。
40
40
 
41
41
  `build:lib`命令用于打包组件库,生成组件代码及类型定义文件。
42
42
 
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@lx-frontend/wrap-element-ui",
3
- "version": "1.0.0-beta.7",
3
+ "version": "1.0.17.beta-2",
4
4
  "description": "wrap-element-ui",
5
5
  "author": "",
6
6
  "main": "src/components/index.ts",
7
7
  "private": false,
8
8
  "scripts": {
9
9
  "clean": "rimraf dist",
10
- "sb:dev": "cross-env MODE=development storybook dev -p 6006",
11
- "sb:dist": "cross-env MODE=production pnpm build:lib && storybook dev -p 6006",
10
+ "dev": "cross-env MODE=development storybook dev -p 6006",
11
+ "dist": "cross-env MODE=production pnpm build:lib && storybook dev -p 6006",
12
12
  "build:lib": "pnpm clean && vite build",
13
13
  "build:sb": "cross-env MODE=production rimraf storybook-static && pnpm build:lib && storybook build",
14
14
  "preview": "serve ./storybook-static",
@@ -22,7 +22,8 @@
22
22
  "package.json",
23
23
  "src/components"
24
24
  ],
25
- "dependencies": {
25
+ "peerDependencies": {
26
+ "dayjs": "^1.11.13",
26
27
  "element-ui": "^2.15.14",
27
28
  "lodash": "^4.17.21",
28
29
  "vue": "~2.7.16"
@@ -69,4 +70,4 @@
69
70
  "vite-tsconfig-paths": "^4.3.2",
70
71
  "vue-template-compiler": "^2.6.10"
71
72
  }
72
- }
73
+ }
@@ -0,0 +1,7 @@
1
+ export * from './usePagination';
2
+ export * from './useCellHover';
3
+ export * from './useViewSetting';
4
+ export * from './useRowBgColor';
5
+ export * from './useDefaultOperation';
6
+ export * from './useColumnHeaderOperation';
7
+ export * from './useDragSort';
@@ -2,7 +2,7 @@ import debounce from 'lodash/debounce';
2
2
  import throttle from 'lodash/throttle';
3
3
  import { onBeforeUnmount, onMounted, ref } from 'vue'
4
4
 
5
- export default function useCellHover(tableDomRef) {
5
+ export function useCellHover(tableDomRef) {
6
6
 
7
7
  // 鼠标悬浮的行
8
8
  const hoveringCellInfo = ref<{
@@ -0,0 +1,329 @@
1
+ import { computed, nextTick, ref, Ref, watch } from 'vue'
2
+ import {
3
+ FilterListType,
4
+ IColumnConfig,
5
+ IEmits,
6
+ IFilterInput,
7
+ IProps
8
+ } from '../types';
9
+
10
+ interface IUseColumnHeaderOperationParams {
11
+ props: IProps
12
+ tableDomRef: any
13
+ emit: IEmits;
14
+ showingColumns: Ref<string[]>
15
+ }
16
+
17
+ export function useColumnHeaderOperation({ props, tableDomRef, emit, showingColumns }: IUseColumnHeaderOperationParams) {
18
+ // column如果有sortable属性,点击列头部,会直接触发排序,为了在弹窗点确定时再触发排序,需要阻止点击立即排序
19
+ // 所以,初始渲染时,将sortable设置为false,在触发排序逻辑时再设置成真实的值,再利用el-table自身的排序逻辑触发排序
20
+ const inSorting = ref(false);
21
+
22
+ // 生效中的排序配置
23
+ const sortType = ref<'ascending' | 'descending' | null>(null);
24
+ const sortProp = ref('')
25
+
26
+ // 临时的排序配置
27
+ const tempSortType = ref<'ascending' | 'descending' | ''>('');
28
+ const tempSortProp = ref('')
29
+
30
+ // 生效中的过滤配置 和 临时过滤配置
31
+ const filteredValue = ref<Record<string, string | number | number[] | string[]>>({});
32
+ const tempFilteredValue = ref<Record<string, string | number | number[] | string[]>>({});
33
+
34
+ // 生效中的统计配置 和 临时统计配置
35
+ const tempSummaryList = ref<string[]>([]);
36
+ const summaryList = ref<string[]>([]);
37
+
38
+ const isColumnFiltering = computed(() => {
39
+ return Object.keys(tempFilteredValue.value).some(
40
+ (key) => {
41
+ const value = tempFilteredValue.value[key]
42
+ if (Array.isArray(value)) return value.length
43
+ return value;
44
+ }
45
+ )
46
+ });
47
+
48
+ const showColumnHeadSortIcon = ({ isColumnSortable, filters }: IColumnConfig) => {
49
+ return isColumnSortable || (filters && Array.isArray(filters) && filters.length > 0)
50
+ }
51
+
52
+ watch(
53
+ () => props.columnConfig,
54
+ (val) => {
55
+ val?.forEach(v => handleResetFilterValue(v));
56
+ tempFilteredValue.value = { ...filteredValue.value };
57
+ },
58
+ { immediate: true }
59
+ )
60
+
61
+ const tableSummaryMethod = (param) => {
62
+ const { columns, data } = param;
63
+ const sums: (string | number)[] = []
64
+ columns.forEach((column, index) => {
65
+ if (index === 0) {
66
+ sums[index] = '合计';
67
+ return;
68
+ }
69
+ if (!summaryList.value.includes(column.property)) {
70
+ sums[index] = '';
71
+ } else {
72
+ const values = data.map(item => item[column.property]);
73
+ // 找到对应列的summaryMethod函数
74
+ const summaryMethod = props.columnConfig.find(c => c.prop === column.property)?.summaryMethod ?? (() => '');
75
+ sums[index] = summaryMethod(values);
76
+ }
77
+ })
78
+
79
+ return sums
80
+ }
81
+
82
+ const isColumnHeadActive = ({ prop, filters, _sortable }: IColumnConfig) => {
83
+ const hasFilters = filters && Array.isArray(filters) && filters.length > 0
84
+ const currentFilterActive = hasFilters && filters?.some(
85
+ (item) => {
86
+ if (item.type === 'doubleDatePicker' || item.type === 'monthDayPicker') {
87
+ const [start, end] = item.prop
88
+ return !!(filteredValue.value[start] || filteredValue.value[end])
89
+ }
90
+
91
+ if (item.type === 'checkbox') {
92
+ return !!(filteredValue.value[item.prop] as any[]).length
93
+ }
94
+
95
+ return !!filteredValue.value[item.prop]
96
+ }
97
+ )
98
+
99
+ const isUseSort = Array.isArray(_sortable)
100
+ ? _sortable.some(v => v.prop === sortProp.value)
101
+ : sortProp.value === prop
102
+
103
+ return currentFilterActive || isUseSort|| summaryList.value.includes(prop);
104
+ }
105
+
106
+ const handleHeaderPopoverShow = (column: IColumnConfig) => {
107
+ // 关闭其他的排序和筛选弹窗(理论上不写也能关闭其他,但是就是有些列会出现两个弹窗同时出现的情况)
108
+ closeSortAndFilterPopover(column.prop);
109
+ tempFilteredValue.value = { ...filteredValue.value };
110
+ tempSortType.value = sortType.value || '';
111
+ tempSortProp.value = sortProp.value || '';
112
+ // 临时合计项设置成实际的合计项
113
+ tempSummaryList.value = [...summaryList.value];
114
+ }
115
+
116
+ const closeSortAndFilterPopover = (exceptProp?: string) => {
117
+ document.querySelectorAll('span[data-popper-name]').forEach((item: any) => {
118
+ if (!exceptProp || exceptProp !== item.dataset.prop) {
119
+ item?.__vue__?.doClose?.();
120
+ }
121
+ });
122
+ }
123
+
124
+ const handleSort = (type: 'ascending' | 'descending', prop: string) => {
125
+ tempSortType.value = type;
126
+ tempSortProp.value = prop;
127
+ }
128
+
129
+ const columnMap = computed(() => {
130
+ const obj: Record<string, IColumnConfig> = {}
131
+ props.columnConfig.forEach(column => {
132
+ obj[column.prop] = column
133
+ })
134
+
135
+ return obj
136
+ })
137
+
138
+ const emitSearch = () => {
139
+ const params: Record<string, any> = {};
140
+
141
+ const processFilter = (filters: FilterListType) => {
142
+ filters.forEach((item) => {
143
+ if (item.type === 'doubleDatePicker' || item.type === 'monthDayPicker') {
144
+ const [start, end] = item.prop
145
+ params[start] = filteredValue.value[start];
146
+ params[end] = filteredValue.value[end];
147
+ } else {
148
+ params[item.prop] = filteredValue.value[item.prop];
149
+ }
150
+ });
151
+ }
152
+
153
+ // 仅提交显示的列的相关数据
154
+ showingColumns.value.forEach(prop => {
155
+ const { filters = [] } = columnMap.value[prop] as IColumnConfig;
156
+ processFilter(filters);
157
+ });
158
+
159
+ if (props.colorFilterConfig) {
160
+ const { filters = [] } = props.colorFilterConfig;
161
+ processFilter(filters);
162
+ }
163
+
164
+ Object.keys(params).forEach(key => {
165
+ if (params[key] === undefined) delete params[key];
166
+ });
167
+
168
+ emit('search', {
169
+ ...params,
170
+ page: 1
171
+ });
172
+ };
173
+
174
+
175
+ const handleHeaderOperationConfirm = async (column: IColumnConfig) => {
176
+ const inputFilters = (column.filters ?? []).filter(
177
+ (item): item is IFilterInput => item.type === 'input'
178
+ );
179
+
180
+ const hasValidatorError = inputFilters.some(
181
+ (item) => item.validator
182
+ && !item.validator((tempFilteredValue.value[item.prop] as string).trim())
183
+ )
184
+
185
+ if (hasValidatorError) {
186
+ return
187
+ }
188
+
189
+ inputFilters.forEach(
190
+ (item) => {
191
+ if (!tempFilteredValue.value[item.prop]) tempFilteredValue.value[item.prop] = ''
192
+ }
193
+ )
194
+
195
+ summaryList.value = [...tempSummaryList.value];
196
+ sortProp.value = tempSortProp.value || '';
197
+ sortType.value = tempSortType.value || null;
198
+
199
+ if (sortProp.value) { // 确认时提交排序
200
+ if (props.localSort) {
201
+ // 恢复列配置的sortable属性,只有列配置的sortable为true,才能用下面的sort方法
202
+ inSorting.value = true;
203
+ await nextTick();
204
+ tableDomRef.value?.sort(sortProp.value, sortType.value);
205
+ inSorting.value = false
206
+ } else {
207
+ emit('sort-change', { order: sortType.value, prop: sortProp.value });
208
+ }
209
+ }
210
+
211
+ filteredValue.value = { ...tempFilteredValue.value };
212
+
213
+ emitSearch();
214
+ closeSortAndFilterPopover();
215
+ await nextTick()
216
+ tableDomRef.value?.doLayout();
217
+ }
218
+
219
+ const clearSort = () => {
220
+ sortProp.value = '';
221
+ sortType.value = null;
222
+ if (props.localSort) { // 前端过滤
223
+ tableDomRef.value?.clearSort();
224
+ } else { // 接口过滤
225
+ emit('sort-change', { order: null, prop: '' });
226
+ }
227
+ }
228
+
229
+ const setSort = (params: { order: 'ascending' | 'descending', prop: string }) => {
230
+ const column = props.columnConfig.find(c => Array.isArray(c.sortable)
231
+ ? c.sortable.some(v => v.prop === params.prop)
232
+ : c.prop === params.prop);
233
+
234
+ if (column) {
235
+ sortProp.value = params.prop
236
+ sortType.value = params.order;
237
+ if (props.localSort) {
238
+ tableDomRef.value?.sort(params.prop, params.order);
239
+ }
240
+ }
241
+ }
242
+
243
+ function handleResetFilterValue (column: IColumnConfig) {
244
+ (column.filters || [])
245
+ .forEach(
246
+ (item) => {
247
+ if (item.type === 'radio' || item.type === 'checkbox') {
248
+ if (item.defaultValue) {
249
+ filteredValue.value[item.prop] = item.defaultValue
250
+ } else {
251
+ filteredValue.value[item.prop] = item.type === 'radio' ? '' : []
252
+ }
253
+ } else if (item.type === 'doubleDatePicker' || item.type === 'monthDayPicker') {
254
+ const [start, end] = item.prop
255
+ filteredValue.value[start] = '';
256
+ filteredValue.value[end] = '';
257
+ } else {
258
+ filteredValue.value[item.prop] = ''
259
+ }
260
+ }
261
+ )
262
+ }
263
+
264
+ const handleHeaderOperationReset = async (column: IColumnConfig) => {
265
+ if (
266
+ sortProp.value &&
267
+ (Array.isArray(column._sortable)
268
+ ? column._sortable.some(v => v.prop === sortProp.value)
269
+ : sortProp.value === column.prop)
270
+ ) {
271
+ clearSort();
272
+ }
273
+
274
+ // 合计
275
+ summaryList.value = summaryList.value.filter(item => item !== column.prop);
276
+
277
+ handleResetFilterValue(column)
278
+ emitSearch();
279
+ closeSortAndFilterPopover();
280
+ await nextTick();
281
+ tableDomRef.value?.doLayout();
282
+ }
283
+
284
+ const setSearchParams = (params: Record<string, any>) => {
285
+ const _filteredValue = {};
286
+
287
+ // 设置搜索和过滤参数时,如果使用 showingColumns 遍历,会导致通过外部设置未显示的列的搜索和过滤参数丢失
288
+ [props.colorFilterConfig, ...props.columnConfig].forEach(column => {
289
+ (column?.filters ?? [])
290
+ .forEach(
291
+ (item) => {
292
+ if (item.type === 'doubleDatePicker' || item.type === 'monthDayPicker') {
293
+ const [start, end] = item.prop
294
+ _filteredValue[start] = params[start]
295
+ _filteredValue[end] = params[end]
296
+ } else if (item.type === 'checkbox') {
297
+ _filteredValue[item.prop] = params[item.prop] ?? item.defaultValue ?? []
298
+ } else {
299
+ _filteredValue[item.prop] = params[item.prop] ?? ''
300
+ }
301
+ }
302
+ )
303
+ })
304
+
305
+ filteredValue.value = { ...filteredValue.value, ..._filteredValue }
306
+ }
307
+
308
+ return {
309
+ setSort,
310
+ clearSort,
311
+ setSearchParams,
312
+ isColumnHeadActive,
313
+ handleHeaderPopoverShow,
314
+ handleSort,
315
+ handleHeaderOperationConfirm,
316
+ handleHeaderOperationReset,
317
+ summaryList,
318
+ tableSummaryMethod,
319
+ filteredValue,
320
+ showColumnHeadSortIcon,
321
+ tempSortProp,
322
+ tempFilteredValue,
323
+ tempSummaryList,
324
+ tempSortType,
325
+ sortProp,
326
+ isColumnFiltering,
327
+ inSorting,
328
+ }
329
+ }
@@ -1,5 +1,5 @@
1
1
  import { Ref, ref } from "vue"
2
- import { IEmits, IProps } from "./types"
2
+ import { IEmits, IProps } from "../types"
3
3
 
4
4
  interface IParams {
5
5
  emit: IEmits;
@@ -9,7 +9,7 @@ interface IParams {
9
9
  hasExpandRow: boolean
10
10
  }
11
11
 
12
- export default function useDefaultOperation({ emit, pageSize, props, tableDomRef, hasExpandRow }: IParams) {
12
+ export function useDefaultOperation({ emit, pageSize, props, tableDomRef, hasExpandRow }: IParams) {
13
13
  const operationPopoverRef = ref<any>(null);
14
14
  const editingRowData = ref<Record<string, any>>({});
15
15
  const editingRowIndex = ref<number>(-1);
@@ -1,5 +1,5 @@
1
1
  import { onBeforeUnmount, onMounted, ref, Ref } from 'vue';
2
- import { IColumnConfig, IDraggingData, IEmits, IProps } from "./types"
2
+ import { IColumnConfig, IDraggingData, IEmits, IProps } from "../types"
3
3
  import throttle from "lodash/throttle"
4
4
 
5
5
  interface IUseDragSortParams {
@@ -11,7 +11,7 @@ interface IUseDragSortParams {
11
11
  pageSize: Ref<number>
12
12
  tableDomRef: Ref<any>
13
13
  }
14
- export default function useDragSort({ props, emit, viewSettingDragSortOptions, pageSize, beforeDragStart, currScope, tableDomRef }: IUseDragSortParams) {
14
+ export function useDragSort({ props, emit, viewSettingDragSortOptions, pageSize, beforeDragStart, currScope, tableDomRef }: IUseDragSortParams) {
15
15
 
16
16
  const draggingData = ref<IDraggingData>({}); // 拖拽相关数据
17
17
  const isMouseDown = ref(false);
@@ -46,7 +46,7 @@ export default function useDragSort({ props, emit, viewSettingDragSortOptions, p
46
46
  handleDragMouseDown(e, +target.dataset.index);
47
47
  }
48
48
 
49
- if ([...target.classList].includes('view-setting-drag-target')) {
49
+ if ([...target.classList].includes('editable-table-view-setting-drag-target')) {
50
50
  dragType.value = 'view-setting';
51
51
  // 处理显示设置拖拽
52
52
  handleViewSettingDragMouseDown(e, +target.dataset.index);
@@ -208,7 +208,7 @@ export default function useDragSort({ props, emit, viewSettingDragSortOptions, p
208
208
  }
209
209
 
210
210
  const handleViewSettingDragMouseDown = (event, index) => {
211
- const rowDoms = [...document.getElementsByClassName('view-setting-draggable-item')]
211
+ const rowDoms = [...document.getElementsByClassName('editable-table-view-setting-draggable-item')]
212
212
  .reduce((pre, item, index) => ({ ...pre, [index]: [item] }), {});
213
213
  draggingData.value.isDragging = true;
214
214
  draggingData.value.rowDoms = rowDoms;
@@ -1,12 +1,12 @@
1
1
  import { ref } from "vue"
2
- import { IEmits } from "./types"
2
+ import { IEmits } from "../types"
3
3
 
4
4
  interface IParams {
5
5
  emit: IEmits
6
6
  beforePageChange: () => void
7
7
  }
8
8
 
9
- export default function usePagination({ emit, beforePageChange }: IParams) {
9
+ export function usePagination({ emit, beforePageChange }: IParams) {
10
10
 
11
11
  const pageSize = ref(10);
12
12
 
@@ -28,4 +28,4 @@ export default function usePagination({ emit, beforePageChange }: IParams) {
28
28
  handlePageSizeChange,
29
29
  handleCurrPageChange,
30
30
  }
31
- }
31
+ }
@@ -1,32 +1,29 @@
1
- import { ref, nextTick } from "vue"
2
- import { IColorList, IEmits } from "./types"
1
+ import { IColorList, IEmits } from '../types';
3
2
 
4
3
  interface IUseRowBgColorParams {
5
4
  colorList: IColorList;
6
5
  emit: IEmits;
7
6
  }
8
7
 
9
- export default function useRowBgColor({ colorList, emit }: IUseRowBgColorParams) {
10
- const colorPopoverRef = ref<any>(null);
11
-
8
+ export function useRowBgColor({ colorList, emit }: IUseRowBgColorParams) {
12
9
  const isDefaultColor = (id: number) => {
13
10
  if (!id) {
14
11
  // 没有颜色id,则认为是默认色
15
12
  return true;
16
13
  }
17
14
  return colorList.find(c => +c.id === +id)?.default;
18
- }
15
+ };
19
16
 
20
17
  const getColorById = (id: number, type: 'bg' | 'sample' = 'bg') => {
21
18
  return colorList.find(c => +c.id === +id)?.[`${type}Color`] || '';
22
- }
19
+ };
23
20
 
24
21
  const setRowStyle = (scope) => {
25
22
  const row = scope.row;
26
23
  return {
27
- backgroundColor: row.colorId ? getColorById(row.colorId) : ''
28
- }
29
- }
24
+ backgroundColor: row.__static_bg_color__ ?? (row.colorId ? getColorById(row.colorId) : '')
25
+ };
26
+ };
30
27
 
31
28
  const handleColorChange = async (colorId: number, scope) => {
32
29
  const { row, $index: rowIndex, store } = scope;
@@ -36,16 +33,12 @@ export default function useRowBgColor({ colorList, emit }: IUseRowBgColorParams)
36
33
  newList.splice(rowIndex, 1, curRow);
37
34
  store.states.data = newList;
38
35
  emit('row-bg-change', { colorId, row, rowIndex });
39
- await nextTick();
40
- // TODO: 为什么不是数组?为什么关闭弹窗不生效了?
41
- colorPopoverRef.value?.doClose();
42
- }
36
+ };
43
37
 
44
38
  return {
45
39
  isDefaultColor,
46
40
  getColorById,
47
41
  setRowStyle,
48
42
  handleColorChange,
49
- colorPopoverRef
50
- }
43
+ };
51
44
  }
@@ -0,0 +1,125 @@
1
+ import { ref, watch, Ref, computed, nextTick } from "vue"
2
+ import { IColumnConfig, IProps } from "../types"
3
+
4
+ interface IViewSettingParams {
5
+ showingColumns: Ref<string[]>
6
+ actualColumns: Ref<IColumnConfig[]>
7
+ viewSettingDragSortOptions: Ref<IColumnConfig[]>
8
+ props: IProps
9
+ emit: {
10
+ (e: 'update:leftFixedColumnCount', val: number): void
11
+ (e: 'update:showingColumns', val: string[]): void
12
+ (e: 'update:viewSettingDragSortOptions', val: IColumnConfig[]): void
13
+ (e: 'tableDoLayout'): void
14
+ }
15
+ }
16
+
17
+ export function useViewSetting({
18
+ showingColumns,
19
+ actualColumns,
20
+ props,
21
+ viewSettingDragSortOptions,
22
+ emit
23
+ }: IViewSettingParams) {
24
+ const columnsToBeShown = ref<string[]>([]); // 显示设置弹窗中勾选的列
25
+ const viewSettingVisible = ref(false);
26
+ const leftFixedColumnCount = ref(0);
27
+ const tempLeftFixedColumnCount = ref(0);
28
+
29
+ const updateShowingColumns = (val: string[]) => emit('update:showingColumns', val);
30
+
31
+ const storageKey = computed(() => `@lx-frontend/wrap-element-ui/table_setting_cloumns/${props.settingStorgeKey || (location.pathname === '/' ? location.hash : location.pathname)}`);
32
+
33
+ const saveSettingToStorge = async() => {
34
+ await nextTick()
35
+ localStorage.setItem(storageKey.value, JSON.stringify({
36
+ showingColumns: showingColumns.value,
37
+ leftFixedColumnCount: leftFixedColumnCount.value
38
+ }))
39
+ };
40
+
41
+ const handleViewSettingShow = () => {
42
+ emit('update:viewSettingDragSortOptions', [...actualColumns.value.filter(v => v?.prop !== '$$operation')]);
43
+ tempLeftFixedColumnCount.value = leftFixedColumnCount.value;
44
+ viewSettingVisible.value = true;
45
+ columnsToBeShown.value = [...showingColumns.value];
46
+ }
47
+
48
+ const handleViewSettingClose = () => {
49
+ viewSettingVisible.value = false;
50
+ }
51
+
52
+ const handleViewSettingConfirm = async () => {
53
+ viewSettingVisible.value = false;
54
+ updateShowingColumns(viewSettingDragSortOptions.value.map(c => c.prop));
55
+ leftFixedColumnCount.value = tempLeftFixedColumnCount.value;
56
+ await saveSettingToStorge()
57
+ emit('tableDoLayout')
58
+ }
59
+
60
+ const handleInputTempLeftFixedColumnCount = (value: string) => {
61
+ const _value = Number(value)
62
+ if (isNaN(_value)) return
63
+ tempLeftFixedColumnCount.value = Math.max(0, Math.min(columnsToBeShown.value.length, Math.floor(_value)))
64
+ }
65
+
66
+ watch(
67
+ () => props.columnConfig,
68
+ async(val) => {
69
+ const _keys = new Set(val.map(c => (c.prop)));
70
+ const _cache = localStorage.getItem(storageKey.value);
71
+ const setColumns = () => updateShowingColumns(val.filter(v => !v.defaultHide).map(c => c.prop));
72
+ if (!_cache) {
73
+ setColumns();
74
+ leftFixedColumnCount.value = props.leftFixedCount as number;
75
+ } else {
76
+ try {
77
+ // 缓存数据字段可能随着更新导致对不上,清理无效数据,防止出问题
78
+ const cache = JSON.parse(_cache);
79
+ if (!cache.showingColumns || !Array.isArray(cache.showingColumns)) {
80
+ setColumns();
81
+ } else {
82
+ updateShowingColumns(cache.showingColumns.filter(key => _keys.has(key)))
83
+ }
84
+ const _leftFixedColumnCount = Number(cache?.leftFixedColumnCount)
85
+ leftFixedColumnCount.value = isNaN(_leftFixedColumnCount) ? (props.leftFixedCount as number) : _leftFixedColumnCount;
86
+ // 写入清理后的数据
87
+ saveSettingToStorge();
88
+ } catch (error) {
89
+ console.error(error);
90
+ localStorage.removeItem(storageKey.value);
91
+ setColumns();
92
+ }
93
+ }
94
+ },
95
+ { immediate: true }
96
+ )
97
+
98
+ watch(columnsToBeShown, (val, oldVal) => {
99
+ if (val.length === oldVal?.length) return // 排序调整时不做处理,避免出现死循环
100
+ const _map = new Map<string, IColumnConfig>()
101
+ props.columnConfig.forEach(c => _map.set(c.prop, c))
102
+ // 展示时保留顺序
103
+ emit('update:viewSettingDragSortOptions', val.map(prop => _map.get(prop)!))
104
+ if (tempLeftFixedColumnCount.value > val.length) tempLeftFixedColumnCount.value = val.length
105
+ }, { immediate: true })
106
+
107
+ // 拖拽调整排序时,同时更新勾选数组的顺序,避免出现拖拽排序操作过程后再勾选新列时被还原成拖拽前的顺序的问题
108
+ watch(viewSettingDragSortOptions, (val, oldVal) => {
109
+ if (!val.length || val.length !== oldVal?.length) return // 不是排序调整
110
+ columnsToBeShown.value = val.map(c => c.prop)
111
+ }, { deep: true })
112
+
113
+ watch(leftFixedColumnCount, (val) => emit('update:leftFixedColumnCount', val), { immediate: true });
114
+
115
+ return {
116
+ columnsToBeShown,
117
+ viewSettingVisible,
118
+ leftFixedColumnCount,
119
+ tempLeftFixedColumnCount,
120
+ handleInputTempLeftFixedColumnCount,
121
+ handleViewSettingShow,
122
+ handleViewSettingClose,
123
+ handleViewSettingConfirm,
124
+ }
125
+ }