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

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 (29) hide show
  1. package/README.md +45 -45
  2. package/package.json +14 -14
  3. package/src/components/AddMembers/index.vue +157 -157
  4. package/src/components/AuditSteps/index.vue +140 -140
  5. package/src/components/DemoComponent/index.vue +20 -20
  6. package/src/components/EditableTable/README.md +147 -147
  7. package/src/components/EditableTable/bizHooks/index.ts +17 -0
  8. package/src/components/EditableTable/{useCellHover.ts → bizHooks/useCellHover.ts} +71 -71
  9. package/src/components/EditableTable/{useColumnHeaderOperation.ts → bizHooks/useColumnHeaderOperation.ts} +326 -325
  10. package/src/components/EditableTable/{useDefaultOperation.ts → bizHooks/useDefaultOperation.ts} +95 -95
  11. package/src/components/EditableTable/{useDragSort.ts → bizHooks/useDragSort.ts} +290 -290
  12. package/src/components/EditableTable/{usePagination.ts → bizHooks/usePagination.ts} +30 -30
  13. package/src/components/EditableTable/{useRowBgColor.ts → bizHooks/useRowBgColor.ts} +43 -50
  14. package/src/components/EditableTable/{useViewSetting.ts → bizHooks/useViewSetting.ts} +118 -119
  15. package/src/components/EditableTable/features/bizColorSelect.vue +65 -0
  16. package/src/components/EditableTable/features/bizEditCell.vue +44 -0
  17. package/src/components/EditableTable/features/bizTableHeaderPopover.vue +202 -0
  18. package/src/components/EditableTable/features/bizViewSettingDialog.vue +137 -0
  19. package/src/components/EditableTable/index.less +733 -724
  20. package/src/components/EditableTable/index.vue +630 -914
  21. package/src/components/Ellipsis/MultilineEllipsis.vue +141 -141
  22. package/src/components/Ellipsis/index.vue +119 -119
  23. package/src/components/LxTable/index.vue +296 -296
  24. package/src/components/PopoverForm/index.vue +66 -66
  25. package/src/components/SearchForm/index.vue +243 -243
  26. package/src/components/SearchSelect/index.vue +153 -153
  27. package/src/components/index.ts +24 -24
  28. package/src/components/singleMessage/index.ts +44 -44
  29. /package/src/components/EditableTable/{types.ts → types/index.ts} +0 -0
@@ -1,915 +1,631 @@
1
- <template>
2
- <div class="editable-table">
3
- <div class="view-setting">
4
- <div
5
- v-if="!hideViewSettingBtn"
6
- class="view-setting__btn-wrapper"
7
- >
8
- <div
9
- class="view-setting__btn btn-pointer"
10
- @click="handleViewSettingShow"
11
- >
12
- <i class="el-icon-setting" />
13
- <div class="view-setting__btn-text">
14
- 显示设置
15
- </div>
16
- </div>
17
- </div>
18
-
19
- <el-dialog
20
- title="显示设置"
21
- :visible.sync="viewSettingVisible"
22
- width="750px"
23
- top="12vh"
24
- :close-on-click-modal="false"
25
- :append-to-body="true"
26
- custom-class="view-setting__dialog"
27
- >
28
- <div class="view-setting__content">
29
- <div class="view-setting__content-left">
30
- <div class="view-setting__content-left-title">
31
- 表头设置
32
- </div>
33
- <div class="view-setting__checkbox-wrapper">
34
- <el-checkbox-group v-model="columnsToBeShown">
35
- <el-checkbox
36
- v-for="item in columnConfig"
37
- :key="item.label"
38
- :label="item.prop"
39
- :disabled="item.isAlwaysShow"
40
- >
41
- <div class="view-setting__content-left-item">
42
- {{ item.label }}
43
- </div>
44
- </el-checkbox>
45
- </el-checkbox-group>
46
- </div>
47
- </div>
48
- <div class="view-setting__content-right">
49
- <div class="view-setting__content-right-title">
50
- 已选择
51
- <div class="view-setting__selected-count">
52
- {{ columnsToBeShown.length }}
53
- </div>
54
- </div>
55
- <div class="view-setting__content-right-frize">
56
- 冻结前
57
- <el-input
58
- class="view-setting__content-right-input"
59
- :value="tempLeftFixedColumnCount"
60
- @input="handleInputTempLeftFixedColumnCount"
61
- />
62
-
63
- </div>
64
- <div class="view-setting__content-right-selected">
65
- <div
66
- v-for="(item, index) in viewSettingDragSortOptions"
67
- :key="item.prop"
68
- class="view-setting__selected-item view-setting-draggable-item"
69
- >
70
- <div class="view-setting__selected-item-left">
71
- <div
72
- class="view-setting-drag-target view-setting__icon-wrapper"
73
- :data-index="index"
74
- >
75
- <div
76
- class="view-setting-drag-target editable-table-drag-icon"
77
- :data-index="index"
78
- />
79
- </div>
80
- <div class="view-setting__selected-item-name">
81
- {{ item.label }}
82
- </div>
83
- </div>
84
- <div
85
- :class="['view-setting__selected-item-close', item.isAlwaysShow ? 'view-setting__selected-item-close--disabled' : '']"
86
- @click="handleColumnClose(item)"
87
- >
88
- <i class="el-icon-close" />
89
- </div>
90
- </div>
91
- </div>
92
- </div>
93
- </div>
94
- <template #footer>
95
- <el-button @click="handleViewSettingClose">
96
- 取消
97
- </el-button>
98
- <el-button
99
- type="primary"
100
- @click="handleViewSettingConfirm"
101
- >
102
- 确认
103
- </el-button>
104
- </template>
105
- </el-dialog>
106
- </div>
107
-
108
- <!-- 列表展示,属性透传,列编辑 -->
109
- <el-table
110
- ref="tableDomRef"
111
- v-loading="loading"
112
- :data="dataList"
113
- :row-style="setRowStyle"
114
- :row-class-name="setRowClassName"
115
- :cell-class-name="setCellClassName"
116
- :show-summary="summaryList.length > 0"
117
- :summary-method="tableSummaryMethod"
118
- v-bind="$attrs"
119
- border
120
- @selection-change="handleSelectionChange"
121
- @cell-mouse-enter="debouncedHoverHandler"
122
- @header-dragend="doTableLayout"
123
- >
124
- <el-table-column
125
- v-if="rowDragAble"
126
- width="30px"
127
- class-name="editable-table__drag-cell no-inner-cell-border"
128
- :fixed="leftFixedColumnCount > 0 ? 'left' : ''"
129
- >
130
- <template #default="scope">
131
- <div
132
- class="row-drag-target editable-table__drag-icon"
133
- :data-index="scope.$index"
134
- @mousedown="currScope = scope"
135
- >
136
- <div
137
- :data-index="scope.$index"
138
- class="row-drag-target editable-table-drag-icon"
139
- />
140
- </div>
141
- </template>
142
- </el-table-column>
143
- <!-- 展开行 -->
144
- <el-table-column
145
- v-if="hasExpandRow"
146
- width="30px"
147
- type="expand"
148
- :fixed="leftFixedColumnCount > 0 ? 'left' : ''"
149
- class-name="no-inner-cell-border"
150
- >
151
- <template #default="scope">
152
- <slot
153
- name="expand"
154
- v-bind="scope"
155
- />
156
- </template>
157
- </el-table-column>
158
- <!-- 选择列 -->
159
- <el-table-column
160
- v-if="hasSelectionColumn"
161
- width="45px"
162
- align="center"
163
- type="selection"
164
- :fixed="leftFixedColumnCount > 0 ? 'left' : ''"
165
- class-name="no-inner-cell-border"
166
- />
167
- <!-- 编号列 -->
168
- <el-table-column
169
- v-if="hasIndexColumn"
170
- min-width="30px"
171
- type="index"
172
- :fixed="leftFixedColumnCount > 0 ? 'left' : ''"
173
- class-name="no-inner-cell-border"
174
- />
175
- <!-- 颜色选择列 -->
176
- <el-table-column
177
- v-if="colorList && colorList.length > 0"
178
- width="22px"
179
- class-name="editable-table__color-column no-inner-cell-border"
180
- :fixed="leftFixedColumnCount > 0 ? 'left' : ''"
181
- >
182
- <template #header>
183
- <div class="editable-table__color-icon" />
184
- </template>
185
- <template #default="scope">
186
- <el-popover
187
- ref="colorPopoverRef"
188
- placement="right"
189
- trigger="click"
190
- popper-class="color-popover"
191
- >
192
- <div class="color-list">
193
- <div
194
- v-for="color in colorList"
195
- :key="color.id"
196
- class="color-list__item"
197
- :style="{ backgroundColor: color.sampleColor }"
198
- @click="handleColorChange(color.id, scope)"
199
- >
200
- <span :style="{color: color.textColor}">{{ color.name }}</span>
201
- </div>
202
- </div>
203
- <template slot="reference">
204
- <!-- 没有这个包裹的div标签,在拖动换行之后,无法调起颜色选择弹窗 -->
205
- <div>
206
- <div
207
- v-if="isDefaultColor(scope.row.colorId)"
208
- class="editable-table__color-icon"
209
- />
210
- <div
211
- v-else
212
- class="editable-table__selected-color"
213
- :style="{ backgroundColor: getColorById(scope.row.colorId, 'sample') }"
214
- />
215
- </div>
216
- </template>
217
- </el-popover>
218
- </template>
219
- </el-table-column>
220
- <!-- 这里的key很重要,必须保证每次生成的key都不一样,这样列排序功能才能生效,否则,即使actualColumns数组元素顺序发生变化,列顺序也不会改变。原因未知 -->
221
- <el-table-column
222
- v-for="(column, index) in actualColumns"
223
- :key="column.prop + index"
224
- resizable
225
- class-name="editable-table__data-column"
226
- :filtered-value="Array.isArray(filteredValue[column.prop]) ? filteredValue[column.prop] : []"
227
- v-bind="getColumnBindProps(column)"
228
- >
229
- <template
230
- v-if="showColumnHeadSortIcon(column)"
231
- #header="scope"
232
- >
233
- <el-popover
234
- ref="sortFilterPopoverRef"
235
- placement="bottom"
236
- trigger="click"
237
- popper-class="editable-table__sort-filter"
238
- :data-prop="column.prop"
239
- @show="handleHeaderPopoverShow(column)"
240
- >
241
- <template slot="reference">
242
- <!-- 筛选中,或排序中,高亮 -->
243
- <span :class="['editable-table__sort-reference', isColumnHeadActive(column) && 'editable-table__sort-reference--active']">
244
- {{ column.label }}
245
- <div :class="['editable-table__sort-icon', isColumnHeadActive(column) && 'editable-table__sort-icon--active']" />
246
- </span>
247
- </template>
248
- <div class="sort-filter">
249
- <div class="sort-filter__column-title">
250
- {{ column.label }}
251
- </div>
252
- <div
253
- v-if="column.isColumnSortable"
254
- class="sort-filter__sort"
255
- >
256
- <div class="sort-filter__sort-title">
257
- 排序
258
- </div>
259
- <div class="sort-filter__sort-btns">
260
- <el-button
261
- :class="['sort-filter__sort-btn', tempSortingColumn?.prop === column.prop && tempSortType === 'ascending' && 'sort-filter__sort-btn--active']"
262
- @click="handleSort('ascending', column)"
263
- >
264
- 升序
265
- </el-button>
266
- <el-button
267
- :class="['sort-filter__sort-btn', tempSortingColumn?.prop === column.prop && tempSortType === 'descending' && 'sort-filter__sort-btn--active']"
268
- @click="handleSort('descending', column)"
269
- >
270
- 降序
271
- </el-button>
272
- </div>
273
- </div>
274
- <div
275
- v-if="column.search && !Array.isArray(column.search)"
276
- class="sort-filter__search"
277
- >
278
- <div class="sort-filter__search-title">
279
- 搜索
280
- </div>
281
- <el-input
282
- v-model="tempSearchValue[column.prop]"
283
- class="sort-filter__search-input"
284
- placeholder="请输入内容"
285
- />
286
- </div>
287
-
288
- <div
289
- v-if="column.search && Array.isArray(column.search)"
290
- class="sort-filter__search"
291
- style="display: flex;flex-direction: column;gap: 12px;"
292
- >
293
- <div
294
- v-for="item in column.search"
295
- :key="item.prop"
296
- >
297
- <div class="sort-filter__search-title">
298
- {{ item.label }}
299
- </div>
300
- <el-input
301
- v-model="tempSearchValue[item.prop]"
302
- class="sort-filter__search-input"
303
- placeholder="请输入内容"
304
- />
305
- </div>
306
- </div>
307
-
308
- <div
309
- v-if="column.filters && ((Array.isArray(column.filters) ? column.filters : column.filters.options).length > 0)"
310
- class="sort-filter__filter"
311
- >
312
- <div class="sort-filter__filter-title">
313
- 筛选
314
- </div>
315
- <el-checkbox-group
316
- v-if="column.filters && (Array.isArray(column.filters) || column.filters.type === 'checkbox')"
317
- v-model="tempFilteredValue[column.prop]"
318
- class="sort-filter__filter-checkbox-group"
319
- >
320
- <el-checkbox
321
- v-for="item in (Array.isArray(column.filters) ? column.filters : column.filters.options)"
322
- :key="item.value"
323
- :label="item.value"
324
- class="sort-filter__filter-checkbox"
325
- >
326
- <slot
327
- :name="column.prop + '-filter-item'"
328
- v-bind="item"
329
- >
330
- {{ item.text }}
331
- </slot>
332
- </el-checkbox>
333
- </el-checkbox-group>
334
-
335
- <el-radio-group
336
- v-if="column.filters && !Array.isArray(column.filters) && column.filters.type === 'radio'"
337
- v-model="tempFilteredValue[column.prop]"
338
- style="display: flex;flex-direction: column;gap: 6px;"
339
- >
340
- <el-radio
341
- v-for="item in column.filters.options"
342
- :key="item.value"
343
- :label="item.value"
344
- >
345
- <slot
346
- :name="column.prop + '-filter-item'"
347
- v-bind="item"
348
- >
349
- {{ item.text }}
350
- </slot>
351
- </el-radio>
352
- </el-radio-group>
353
- </div>
354
- <div
355
- v-if="column.summary"
356
- class="sort-filter__filter"
357
- >
358
- <div class="sort-filter__filter-title">
359
- 统计
360
- </div>
361
- <el-checkbox-group
362
- v-model="tempSummaryList"
363
- class="sort-filter__filter-checkbox-group"
364
- >
365
- <el-checkbox
366
- :label="column.prop"
367
- class="sort-filter__filter-checkbox"
368
- >
369
- <slot
370
- :name="column.prop + '-summay-item'"
371
- v-bind="column"
372
- >
373
- {{ column.label }}
374
- </slot>
375
- </el-checkbox>
376
- </el-checkbox-group>
377
- </div>
378
- <div class="sort-filter__footer">
379
- <el-button
380
- class="sort-filter__reset-btn"
381
- @click="handleHeaderOperationReset(column, scope)"
382
- >
383
- 重置
384
- </el-button>
385
- <el-button
386
- class="sort-filter__confirm-btn"
387
- type="primary"
388
- @click="handleHeaderOperationConfirm(column, scope)"
389
- >
390
- 确定
391
- </el-button>
392
- </div>
393
- </div>
394
- </el-popover>
395
- </template>
396
- <!-- 默认操作按钮,defaultOperations属性不为空数组时展示。编辑状态下隐藏 -->
397
- <template
398
- v-if="column.prop === '$$operation'"
399
- #default="scope"
400
- >
401
- <el-popover
402
- v-if="editingRowIndex !== scope.$index"
403
- ref="operationPopoverRef"
404
- placement="bottom"
405
- trigger="click"
406
- popper-class="operation-popover"
407
- >
408
- <div
409
- slot="reference"
410
- class="operation-popover__operation-reference btn-pointer"
411
- >
412
- <el-button :class="['operation-popover__operation-btn', hoveringCellInfo.rowIndex === scope.$index && 'operation-popover__operation-btn--active']">
413
- 操作
414
- </el-button>
415
- </div>
416
- <div class="operation-popover__operation">
417
- <div
418
- v-if="defaultOperations.includes('delete')"
419
- class="operation-popover__operation-item btn-pointer"
420
- @click="handleDelete(scope.row, scope.$index)"
421
- >
422
- 删除
423
- </div>
424
- <div
425
- v-if="defaultOperations.includes('edit')"
426
- class="operation-popover__operation-item btn-pointer"
427
- @click="handleEdit(scope)"
428
- >
429
- 编辑
430
- </div>
431
- <div
432
- v-if="defaultOperations.includes('top')"
433
- class="operation-popover__operation-item btn-pointer"
434
- @click="handleRowPinToTop(scope)"
435
- >
436
- 置顶
437
- </div>
438
- <slot
439
- name="custom-operation"
440
- v-bind="scope"
441
- />
442
- </div>
443
- </el-popover>
444
- <div
445
- v-else
446
- class="operation-popover__save-cancel"
447
- >
448
- <div
449
- class="btn-pointer operation-popover__btn"
450
- @click="handleEditSave(scope.row)"
451
- >
452
- 保存
453
- </div>
454
- <div
455
- class="btn-pointer operation-popover__btn"
456
- @click="handleEditCancel(scope.row)"
457
- >
458
- 取消
459
- </div>
460
- </div>
461
- </template>
462
- <!-- 默认渲染、非编辑态,不需要特殊处理,el-table负责渲染 -->
463
- <!-- 自定义插槽 -->
464
- <template
465
- v-else-if="column.slotName"
466
- #default="scope"
467
- >
468
- <!-- 非编辑态 -->
469
- <slot
470
- v-if="scope.$index !== editingRowIndex"
471
- v-bind="scope"
472
- :name="column.slotName"
473
- />
474
- <!-- 编辑态 -->
475
- <template v-else-if="scope.$index === editingRowIndex">
476
- <!-- 自定义编辑 -->
477
- <slot
478
- v-if="column.editSlotName"
479
- v-bind="{scope, column}"
480
- :name="column.editSlotName"
481
- />
482
- <!-- 内置编辑类型 -->
483
- <div v-else-if="column.editType">
484
- <div v-if="column.editType === 'input'">
485
- <el-input
486
- v-model="editingRowData[column.prop]"
487
- clearable
488
- />
489
- </div>
490
- <div v-if="column.editType === 'select'">
491
- <el-select v-model="editingRowData[column.prop]">
492
- <el-option
493
- v-for="item in column.selectOptions"
494
- :key="item.label"
495
- :label="item.label"
496
- :value="item.value"
497
- />
498
- </el-select>
499
- </div>
500
- <el-date-picker
501
- v-if="column.editType === 'date'"
502
- v-model="editingRowData[column.prop]"
503
- type="date"
504
- placeholder="选择日期"
505
- />
506
- </div>
507
- <!-- 不支持编辑 -->
508
- <slot
509
- v-else
510
- v-bind="scope"
511
- :name="column.slotName"
512
- />
513
- </template>
514
- </template>
515
- <!-- 默认渲染列,编辑态 -->
516
- <template
517
- v-else-if="editingRowIndex !== -1"
518
- #default="scope"
519
- >
520
- <!-- 当前行编辑中,内置编辑类型 -->
521
- <template v-if="editingRowIndex === scope.$index && column.editType">
522
- <div v-if="column.editType === 'input'">
523
- <el-input
524
- v-model="editingRowData[column.prop]"
525
- clearable
526
- type="text"
527
- />
528
- </div>
529
- <div v-if="column.editType === 'select'">
530
- <el-select v-model="editingRowData[column.prop]">
531
- <el-option
532
- v-for="item in column.selectOptions"
533
- :key="item.value"
534
- :label="item.label"
535
- :value="item.value"
536
- />
537
- </el-select>
538
- </div>
539
- <div v-if="column.editType === 'date'">
540
- <el-date-picker
541
- v-model="editingRowData[column.prop]"
542
- type="date"
543
- placeholder="选择日期"
544
- />
545
- </div>
546
- </template>
547
- <!-- 当前行编辑中,自定义编辑类型 -->
548
- <slot
549
- v-else-if="column.editSlotName && scope.$index === editingRowIndex"
550
- v-bind="scope"
551
- :name="column.editSlotName"
552
- />
553
- <!-- 当前行非编辑中 -->
554
- <template v-else>
555
- {{ column.formatter ? column.formatter(scope.row, column, scope.row[column.prop], scope.$index) : scope.row[column.prop] }}
556
- </template>
557
- </template>
558
- <!-- hover状态渲染 -->
559
- <template
560
- v-else-if="column.hoverSlotName"
561
- #default="scope"
562
- >
563
- <slot
564
- v-if="scope.$index === hoveringCellInfo.rowIndex && column.prop === hoveringCellInfo.columnProperty"
565
- v-bind="scope"
566
- :name="column.hoverSlotName"
567
- />
568
- <slot
569
- v-else-if="column.slotName"
570
- v-bind="scope"
571
- :name="column.slotName"
572
- />
573
- <template v-else>
574
- {{ column.formatter ? column.formatter(scope.row, column, scope.row[column.prop], scope.$index) : scope.row[column.prop] }}
575
- </template>
576
- </template>
577
- </el-table-column>
578
- </el-table>
579
- <div class="pagination-wrap">
580
- <div>共{{ total }}项数据</div>
581
- <el-pagination
582
- background
583
- layout="sizes, prev, pager, next, jumper"
584
- :page-sizes="[10, 15, 30, 60, 100]"
585
- :page-size.sync="pageSize"
586
- :pager-count="11"
587
- :current-page="currentPage"
588
- :total="total"
589
- @size-change="handlePageSizeChange"
590
- @current-change="handleCurrPageChange"
591
- />
592
- </div>
593
- </div>
594
- </template>
595
-
596
- <script lang="ts" setup>
597
- import { computed, nextTick, ref, watch } from 'vue';
598
- import { Message } from 'element-ui'
599
- import usePagination from './usePagination';
600
- import useCellHover from './useCellHover';
601
- import useViewSetting from './useViewSetting';
602
- import useRowBgColor from './useRowBgColor';
603
- import useDefaultOperation from './useDefaultOperation'
604
- import useColumnHeaderOperation from './useColumnHeaderOperation';
605
- import useDragSort from './useDragSort';
606
- import { ITableDataItem, IColumnConfig, IDefaultOperationType, IColorList } from './types';
607
-
608
- // defineProps泛型参数如果从外部传入,编译报错
609
- interface IProps {
610
- /** 表格数据 */
611
- dataList: ITableDataItem[];
612
- /** 列配置 */
613
- columnConfig: IColumnConfig[];
614
- /** 是否展示展开行 */
615
- hasExpandRow?: boolean;
616
- /** 是否展示序号 */
617
- hasIndexColumn?: boolean;
618
- /** 是否展示选择列 */
619
- hasSelectionColumn?: boolean;
620
- /** 是否支持行拖拽 */
621
- rowDragAble?: boolean;
622
- /** 表格总条数 */
623
- total: number;
624
- /** 自定义列操作,当前支持行编辑(edit),删除(delete),置顶(top) */
625
- defaultOperations?: IDefaultOperationType[];
626
- /** 行背景色列表 */
627
- colorList?: IColorList;
628
- /** 左侧固定列数 */
629
- leftFixedCount?: number;
630
- /** 性能优化参数,调整拖拽的范围 */
631
- dragSemiRange?: number;
632
- /** 是否显示加载 */
633
- loading?: boolean;
634
- /** 是否隐藏显示设置按钮 */
635
- hideViewSettingBtn?: boolean
636
- /** 设置的缓存的key */
637
- settingStorgeKey?: string
638
- /** 前端排序,默认关闭 */
639
- localSort?: boolean
640
- /** 前端过滤,默认关闭 */
641
- localFilter?: boolean
642
- /** 页码 */
643
- currentPage: number
644
- }
645
-
646
- interface IEmits {
647
- /** 行选中 */
648
- (e: 'selection-change', selection: any): void
649
- /** 修改行背景色 */
650
- (e: 'row-bg-change', param: {colorId: number; row: ITableDataItem; rowIndex: number}): void
651
- /** 行拖拽放置事件 */
652
- (e: 'row-drag-drop', param: { row: any; fromIndex: number; toIndex: number; page: number; size: number;}): void
653
- /** 行删除 */
654
- (e: 'row-delete', param: { row: any; index: number; page: number; size: number; }): void
655
- /** 点击编辑按钮立即触发 */
656
- (e: 'row-edit', param: { row: any, index: number; page: number; size: number;}): void
657
- /** 行置顶 */
658
- (e: 'row-pin-to-top', param: { row: any, rawIndex: number; page: number; size: number;}): void
659
- /** 行编辑保存 */
660
- (e: 'row-edit-save', param: { page: number; size: number; row: any; changedData: Record<string, any>; }): void
661
- /** 行编辑取消 */
662
- (e: 'row-edit-cancel', param: { row: any; page: number; size: number;}): void
663
- /** 页码改变 */
664
- (e: 'page-change', param: { page: number, size: number }): void
665
- /** 查询 */
666
- (e: 'search', param: Record<string, any>): void
667
- /** 排序 */
668
- (e: 'sort-change', param: { order: 'descending' | 'ascending' | null, prop: string }): void
669
- }
670
-
671
- const props = withDefaults(defineProps<IProps>(), {
672
- dataList: () => [],
673
- columnConfig: () => [],
674
- hasExpandRow: false,
675
- hasIndexColumn: false,
676
- hasSelectionColumn: false,
677
- rowDragAble: false,
678
- total: 0,
679
- defaultOperations: () => [],
680
- colorList: () => [],
681
- leftFixedCount: 1,
682
- dragSemiRange: 15,
683
- loading: false,
684
- hideViewSettingBtn: false,
685
- settingStorgeKey: '',
686
- localSort: false,
687
- localFilter: false,
688
- currentPage: 1,
689
- })
690
-
691
- // 同defineProps一样,不支持泛型参数从外部导入
692
- const emit = defineEmits<IEmits>()
693
-
694
- const showingColumns = ref<string[]>([]); // 表格中实际展示的列
695
-
696
- const actualColumns = computed(() => {
697
- const res: IColumnConfig[] = [];
698
- let cnt = leftFixedColumnCount.value
699
-
700
- // 列排序和列过滤
701
- for (const prop of showingColumns.value) {
702
- const rawItem = props.columnConfig.find(c => c.prop === prop) ?? {} as IColumnConfig;
703
- const item: IColumnConfig = {
704
- ...rawItem,
705
- isColumnSortable: rawItem.sortable,
706
- sortable: inSorting.value ? rawItem.sortable : false
707
- };
708
- if (cnt > 0) {
709
- item.fixed = 'left';
710
- // eslint-disable-next-line no-plusplus
711
- cnt--;
712
- } else {
713
- item.fixed = undefined;
714
- }
715
- res.push(item);
716
- }
717
-
718
- // 使用默认操作项,添加默认操作列。该列在编辑模式下隐藏
719
- if (props.defaultOperations && props.defaultOperations.length > 0) {
720
- res.push({
721
- label: '操作',
722
- prop: '$$operation',
723
- 'min-width': '100px',
724
- fixed: 'right'
725
- });
726
- }
727
-
728
- return res;
729
- })
730
-
731
- const sortFilterPopoverRef = ref<any>(null);
732
- const tableDomRef = ref<any>(null);
733
- const currScope = ref<any>(null);
734
-
735
- /************ 分页相关 *************/
736
- const beforePageChange = () => {
737
- searchValue.value = {};
738
- }
739
- const {
740
- pageSize,
741
- handleCurrPageChange,
742
- handlePageSizeChange,
743
- } = usePagination({
744
- emit,
745
- beforePageChange
746
- })
747
-
748
- /************ 表格单元格hover事件相关 ************ */
749
- const {
750
- hoveringCellInfo,
751
- setCellClassName,
752
- debouncedHoverHandler
753
- } = useCellHover(tableDomRef)
754
-
755
- /************ 行背景色设置相关 ************ */
756
- const {
757
- isDefaultColor,
758
- getColorById,
759
- setRowStyle,
760
- handleColorChange,
761
- colorPopoverRef
762
- } = useRowBgColor({
763
- colorList: props.colorList,
764
- emit
765
- })
766
-
767
- /************ 默认的操作相关 ************ */
768
- const {
769
- operationPopoverRef,
770
- editingRowData,
771
- editingRowIndex,
772
- handleDelete,
773
- handleEdit,
774
- handleEditSave,
775
- handleEditCancel,
776
- handleRowPinToTop,
777
- closeAllExpandedRows
778
- } = useDefaultOperation({
779
- emit,
780
- tableDomRef,
781
- pageSize,
782
- props,
783
- hasExpandRow: props.hasExpandRow
784
- })
785
-
786
- /************ 显示设置相关 ************ */
787
- const {
788
- viewSettingDragSortOptions,
789
- columnsToBeShown,
790
- viewSettingVisible,
791
- leftFixedColumnCount,
792
- tempLeftFixedColumnCount,
793
- handleInputTempLeftFixedColumnCount,
794
- handleViewSettingShow,
795
- handleViewSettingClose,
796
- handleViewSettingConfirm
797
- } = useViewSetting({
798
- tableDomRef,
799
- showingColumns,
800
- actualColumns,
801
- props
802
- })
803
-
804
- /************ 列头部操作相关 ************ */
805
- const {
806
- setSort,
807
- clearSort,
808
- setSearchParams,
809
- isColumnHeadActive,
810
- handleSort,
811
- handleHeaderPopoverShow,
812
- handleHeaderOperationConfirm,
813
- handleHeaderOperationReset,
814
- summaryList,
815
- tableSummaryMethod,
816
- filteredValue,
817
- showColumnHeadSortIcon,
818
- tempSortingColumn,
819
- tempSearchValue,
820
- tempFilteredValue,
821
- tempSummaryList,
822
- tempSortType,
823
- sortingColumn,
824
- isColumnFiltering,
825
- searchValue,
826
- inSorting,
827
- } = useColumnHeaderOperation({
828
- tableDomRef,
829
- sortFilterPopoverRef,
830
- props,
831
- emit,
832
- showingColumns,
833
- })
834
-
835
- /************ 表格行拖拽和显示设置列拖拽 ************ */
836
- const beforeDragStart = () => {
837
- // 如果有列存在排序,不允许拖拽
838
- if (sortingColumn.value) {
839
- Message.warning('已有列正在排序,不允许拖拽。');
840
- return false;
841
- }
842
-
843
- // 如果有列存在筛选,不允许拖拽
844
- if (isColumnFiltering.value) {
845
- Message.warning('已有列正在筛选,不允许拖拽。');
846
- return false;
847
- }
848
-
849
- editingRowIndex.value = -1; // 关闭编辑状态
850
-
851
- return true
852
- }
853
-
854
- useDragSort({
855
- emit,
856
- props,
857
- viewSettingDragSortOptions,
858
- beforeDragStart,
859
- pageSize,
860
- currScope,
861
- tableDomRef,
862
- })
863
-
864
- const doTableLayout = async () => {
865
- await nextTick();
866
- tableDomRef.value?.doLayout();
867
- }
868
-
869
- // 过滤出自定义属性,将其它属性全部透传给 el-table-column
870
- const getColumnBindProps = (column: IColumnConfig) => {
871
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
872
- const { editAble, editType, slotName, inputType, options, filters, ...rest } = column;
873
- return rest;
874
- }
875
-
876
- const setRowClassName = (scope) => {
877
- return `
878
- custom-row-classname
879
- custom-row-classname-${scope.rowIndex}
880
- ${scope.row.isPinned ? 'custom-row-classname-pinned' : ''}
881
- `
882
- }
883
-
884
- const handleSelectionChange = (e) => {
885
- emit('selection-change', e);
886
- }
887
-
888
- const handleColumnClose = (item) => {
889
- if (item.isAlwaysShow) return;
890
- columnsToBeShown.value = columnsToBeShown.value.filter(c => c !== item.prop);
891
- }
892
-
893
- defineExpose({
894
- closeAllExpandedRows,
895
- openViewSetting: handleViewSettingShow,
896
- elTableRef: tableDomRef,
897
- setSort,
898
- clearSort,
899
- setSearchParams,
900
- })
901
-
902
- // loading 结束和页码变化时滚动到顶部
903
- watch([
904
- () => props.loading,
905
- () => props.currentPage,
906
- ], ([loading]) => {
907
- if (loading) return;
908
- tableDomRef.value.$el.querySelector('.el-table__body-wrapper').scrollTop = 0
909
- })
910
-
911
- </script>
912
-
913
- <style lang="less">
914
- @import './index.less';
1
+ <template>
2
+ <div class="editable-table">
3
+ <div class="view-setting">
4
+ <div
5
+ v-if="!hideViewSettingBtn"
6
+ class="view-setting__btn-wrapper"
7
+ >
8
+ <div
9
+ class="view-setting__btn btn-pointer"
10
+ @click="handleViewSettingShow"
11
+ >
12
+ <i class="el-icon-setting" />
13
+ <div class="view-setting__btn-text">
14
+ 显示设置
15
+ </div>
16
+ </div>
17
+ </div>
18
+
19
+ <biz-view-setting-dialog
20
+ ref="bizViewSettingDialogRef"
21
+ :props="props"
22
+ :actual-columns="actualColumns"
23
+ :showing-columns="showingColumns"
24
+ :view-setting-drag-sort-options="viewSettingDragSortOptions"
25
+ @update:leftFixedColumnCount="(val) => { leftFixedColumnCount = val }"
26
+ @update:showingColumns="(val) => { showingColumns = val }"
27
+ @update:viewSettingDragSortOptions="(val) => { viewSettingDragSortOptions = val }"
28
+ @tableDoLayout="doTableLayout"
29
+ />
30
+ </div>
31
+
32
+ <!-- 列表展示,属性透传,列编辑 -->
33
+ <el-table
34
+ ref="tableDomRef"
35
+ v-loading="loading"
36
+ :data="dataList"
37
+ :row-style="setRowStyle"
38
+ :row-class-name="setRowClassName"
39
+ :cell-class-name="setCellClassName"
40
+ :show-summary="summaryList.length > 0"
41
+ :summary-method="tableSummaryMethod"
42
+ v-bind="$attrs"
43
+ border
44
+ @selection-change="handleSelectionChange"
45
+ @cell-mouse-enter="debouncedHoverHandler"
46
+ @header-dragend="doTableLayout"
47
+ >
48
+ <el-table-column
49
+ v-if="rowDragAble"
50
+ width="30px"
51
+ class-name="editable-table__drag-cell no-inner-cell-border"
52
+ :fixed="leftFixedColumnCount > 0 ? 'left' : false"
53
+ >
54
+ <template #default="scope">
55
+ <div
56
+ class="row-drag-target editable-table__drag-icon"
57
+ :data-index="scope.$index"
58
+ @mousedown="currScope = scope"
59
+ >
60
+ <div
61
+ :data-index="scope.$index"
62
+ class="row-drag-target editable-table-drag-icon"
63
+ />
64
+ </div>
65
+ </template>
66
+ </el-table-column>
67
+ <!-- 展开行 -->
68
+ <el-table-column
69
+ v-if="hasExpandRow"
70
+ width="30px"
71
+ type="expand"
72
+ :fixed="leftFixedColumnCount > 0 ? 'left' : false"
73
+ class-name="no-inner-cell-border"
74
+ >
75
+ <template #default="scope">
76
+ <slot
77
+ name="expand"
78
+ v-bind="scope"
79
+ />
80
+ </template>
81
+ </el-table-column>
82
+ <!-- 选择列 -->
83
+ <el-table-column
84
+ v-if="hasSelectionColumn"
85
+ width="45px"
86
+ align="center"
87
+ type="selection"
88
+ :fixed="leftFixedColumnCount > 0 ? 'left' : false"
89
+ class-name="no-inner-cell-border"
90
+ />
91
+ <!-- 编号列 -->
92
+ <el-table-column
93
+ v-if="hasIndexColumn"
94
+ min-width="30px"
95
+ type="index"
96
+ :fixed="leftFixedColumnCount > 0 ? 'left' : false"
97
+ class-name="no-inner-cell-border"
98
+ />
99
+ <!-- 颜色选择列 -->
100
+ <el-table-column
101
+ v-if="colorList && colorList.length > 0"
102
+ width="22px"
103
+ class-name="editable-table__color-column no-inner-cell-border"
104
+ :fixed="leftFixedColumnCount > 0 ? 'left' : false"
105
+ >
106
+ <template #header>
107
+ <div class="editable-table__color-icon" />
108
+ </template>
109
+ <template #default="scope">
110
+ <biz-color-select
111
+ :color-list="colorList"
112
+ :scope="scope"
113
+ @row-bg-change="(params) => emit('row-bg-change', params)"
114
+ />
115
+ </template>
116
+ </el-table-column>
117
+ <!-- 这里的key很重要,必须保证每次生成的key都不一样,这样列排序功能才能生效,否则,即使actualColumns数组元素顺序发生变化,列顺序也不会改变。原因未知 -->
118
+ <el-table-column
119
+ v-for="(column, index) in actualColumns"
120
+ :key="column.prop + index"
121
+ resizable
122
+ class-name="editable-table__data-column"
123
+ :filtered-value="Array.isArray(filteredValue[column.prop]) ? filteredValue[column.prop] : []"
124
+ v-bind="getColumnBindProps(column)"
125
+ >
126
+ <template
127
+ v-if="showColumnHeadSortIcon(column)"
128
+ #header="scope"
129
+ >
130
+ <biz-table-header-popover
131
+ ref="sortFilterPopoverRef"
132
+ :head-active="isColumnHeadActive(column)"
133
+ :column="column"
134
+ :showing-columns="showingColumns"
135
+ :temp-summary-list="tempSummaryList"
136
+ :temp-sorting-column="tempSortingColumn"
137
+ :temp-sort-type="tempSortType"
138
+ :temp-filtered-value="tempFilteredValue"
139
+ :temp-search-value="tempSearchValue"
140
+ @update:tempSummaryList="val => { tempSummaryList = val }"
141
+ @update:tempFilteredValue="(key, value) => { tempFilteredValue[key] = value }"
142
+ @update:tempSearchValue="(key, value) => { tempSearchValue[key] = value }"
143
+ @popover-show="() => handleHeaderPopoverShow(column)"
144
+ @update:sort="(type) => handleSort(type, column)"
145
+ @reset="() => handleHeaderOperationReset(column, scope)"
146
+ @confirm="() => handleHeaderOperationConfirm(column, scope)"
147
+ >
148
+ <template #filter-item="item">
149
+ <slot
150
+ :name="column.prop + '-filter-item'"
151
+ v-bind="item"
152
+ >
153
+ {{ item.text }}
154
+ </slot>
155
+ </template>
156
+ <template #summay-item>
157
+ <slot
158
+ :name="column.prop + '-summay-item'"
159
+ v-bind="column"
160
+ >
161
+ {{ column.label }}
162
+ </slot>
163
+ </template>
164
+ </biz-table-header-popover>
165
+ </template>
166
+ <!-- 默认操作按钮,defaultOperations属性不为空数组时展示。编辑状态下隐藏 -->
167
+ <template
168
+ v-if="column.prop === '$$operation'"
169
+ #default="scope"
170
+ >
171
+ <el-popover
172
+ v-if="editingRowIndex !== scope.$index"
173
+ ref="operationPopoverRef"
174
+ placement="bottom"
175
+ trigger="click"
176
+ popper-class="operation-popover"
177
+ >
178
+ <div
179
+ slot="reference"
180
+ class="operation-popover__operation-reference btn-pointer"
181
+ >
182
+ <el-button :class="['operation-popover__operation-btn', hoveringCellInfo.rowIndex === scope.$index && 'operation-popover__operation-btn--active']">
183
+ 操作
184
+ </el-button>
185
+ </div>
186
+ <div class="operation-popover__operation">
187
+ <div
188
+ v-if="defaultOperations.includes('delete')"
189
+ class="operation-popover__operation-item btn-pointer"
190
+ @click="handleDelete(scope.row, scope.$index)"
191
+ >
192
+ 删除
193
+ </div>
194
+ <div
195
+ v-if="defaultOperations.includes('edit')"
196
+ class="operation-popover__operation-item btn-pointer"
197
+ @click="handleEdit(scope)"
198
+ >
199
+ 编辑
200
+ </div>
201
+ <div
202
+ v-if="defaultOperations.includes('top')"
203
+ class="operation-popover__operation-item btn-pointer"
204
+ @click="handleRowPinToTop(scope)"
205
+ >
206
+ 置顶
207
+ </div>
208
+ <slot
209
+ name="custom-operation"
210
+ v-bind="scope"
211
+ />
212
+ </div>
213
+ </el-popover>
214
+ <div
215
+ v-else
216
+ class="operation-popover__save-cancel"
217
+ >
218
+ <div
219
+ class="btn-pointer operation-popover__btn"
220
+ @click="handleEditSave(scope.row)"
221
+ >
222
+ 保存
223
+ </div>
224
+ <div
225
+ class="btn-pointer operation-popover__btn"
226
+ @click="handleEditCancel(scope.row)"
227
+ >
228
+ 取消
229
+ </div>
230
+ </div>
231
+ </template>
232
+ <!-- 默认渲染、非编辑态,不需要特殊处理,el-table负责渲染 -->
233
+ <!-- 自定义插槽 -->
234
+ <template
235
+ v-else-if="column.slotName"
236
+ #default="scope"
237
+ >
238
+ <!-- 非编辑态 -->
239
+ <slot
240
+ v-if="scope.$index !== editingRowIndex"
241
+ v-bind="scope"
242
+ :name="column.slotName"
243
+ />
244
+ <!-- 编辑态 -->
245
+ <template v-else-if="scope.$index === editingRowIndex">
246
+ <!-- 自定义编辑 -->
247
+ <slot
248
+ v-if="column.editSlotName"
249
+ v-bind="{scope, column}"
250
+ :name="column.editSlotName"
251
+ />
252
+ <!-- 内置编辑类型 -->
253
+ <biz-edit-cell
254
+ v-else-if="column.editType"
255
+ v-model="editingRowData[column.prop]"
256
+ :column="column"
257
+ />
258
+ <!-- 不支持编辑 -->
259
+ <slot
260
+ v-else
261
+ v-bind="scope"
262
+ :name="column.slotName"
263
+ />
264
+ </template>
265
+ </template>
266
+ <!-- 默认渲染列,编辑态 -->
267
+ <template
268
+ v-else-if="editingRowIndex !== -1"
269
+ #default="scope"
270
+ >
271
+ <!-- 当前行编辑中,内置编辑类型 -->
272
+ <biz-edit-cell
273
+ v-if="editingRowIndex === scope.$index && column.editType"
274
+ v-model="editingRowData[column.prop]"
275
+ :column="column"
276
+ />
277
+ <!-- 当前行编辑中,自定义编辑类型 -->
278
+ <slot
279
+ v-else-if="column.editSlotName && scope.$index === editingRowIndex"
280
+ v-bind="scope"
281
+ :name="column.editSlotName"
282
+ />
283
+ <!-- 当前行非编辑中 -->
284
+ <template v-else>
285
+ {{ column.formatter ? column.formatter(scope.row, column, scope.row[column.prop], scope.$index) : scope.row[column.prop] }}
286
+ </template>
287
+ </template>
288
+ <!-- hover状态渲染 -->
289
+ <template
290
+ v-else-if="column.hoverSlotName"
291
+ #default="scope"
292
+ >
293
+ <slot
294
+ v-if="scope.$index === hoveringCellInfo.rowIndex && column.prop === hoveringCellInfo.columnProperty"
295
+ v-bind="scope"
296
+ :name="column.hoverSlotName"
297
+ />
298
+ <slot
299
+ v-else-if="column.slotName"
300
+ v-bind="scope"
301
+ :name="column.slotName"
302
+ />
303
+ <template v-else>
304
+ {{ column.formatter ? column.formatter(scope.row, column, scope.row[column.prop], scope.$index) : scope.row[column.prop] }}
305
+ </template>
306
+ </template>
307
+ </el-table-column>
308
+ </el-table>
309
+ <div class="pagination-wrap">
310
+ <div>共{{ total }}项数据</div>
311
+ <el-pagination
312
+ background
313
+ layout="sizes, prev, pager, next, jumper"
314
+ :page-sizes="[10, 15, 30, 60, 100]"
315
+ :page-size.sync="pageSize"
316
+ :pager-count="11"
317
+ :current-page="currentPage"
318
+ :total="total"
319
+ @size-change="handlePageSizeChange"
320
+ @current-change="handleCurrPageChange"
321
+ />
322
+ </div>
323
+ </div>
324
+ </template>
325
+
326
+ <script lang="ts" setup>
327
+ import BizColorSelect from './features/bizColorSelect.vue';
328
+ import BizViewSettingDialog from './features/bizViewSettingDialog.vue'
329
+ import BizTableHeaderPopover from './features/bizTableHeaderPopover.vue'
330
+ import BizEditCell from './features/bizEditCell.vue'
331
+
332
+ import { computed, nextTick, ref, watch } from 'vue';
333
+ import { Message } from 'element-ui';
334
+
335
+ import {
336
+ usePagination,
337
+ useCellHover,
338
+ useRowBgColor,
339
+ useDefaultOperation,
340
+ useColumnHeaderOperation,
341
+ useDragSort,
342
+ } from './bizHooks'
343
+
344
+ import { ITableDataItem, IColumnConfig, IDefaultOperationType, IColorList } from './types';
345
+
346
+ // defineProps泛型参数如果从外部传入,编译报错
347
+ interface IProps {
348
+ /** 表格数据 */
349
+ dataList: ITableDataItem[];
350
+ /** 列配置 */
351
+ columnConfig: IColumnConfig[];
352
+ /** 是否展示展开行 */
353
+ hasExpandRow?: boolean;
354
+ /** 是否展示序号 */
355
+ hasIndexColumn?: boolean;
356
+ /** 是否展示选择列 */
357
+ hasSelectionColumn?: boolean;
358
+ /** 是否支持行拖拽 */
359
+ rowDragAble?: boolean;
360
+ /** 表格总条数 */
361
+ total: number;
362
+ /** 自定义列操作,当前支持行编辑(edit),删除(delete),置顶(top) */
363
+ defaultOperations?: IDefaultOperationType[];
364
+ /** 行背景色列表 */
365
+ colorList?: IColorList;
366
+ /** 左侧固定列数 */
367
+ leftFixedCount?: number;
368
+ /** 性能优化参数,调整拖拽的范围 */
369
+ dragSemiRange?: number;
370
+ /** 是否显示加载 */
371
+ loading?: boolean;
372
+ /** 是否隐藏显示设置按钮 */
373
+ hideViewSettingBtn?: boolean
374
+ /** 设置的缓存的key */
375
+ settingStorgeKey?: string
376
+ /** 前端排序,默认关闭 */
377
+ localSort?: boolean
378
+ /** 前端过滤,默认关闭 */
379
+ localFilter?: boolean
380
+ /** 页码 */
381
+ currentPage: number
382
+ }
383
+
384
+ interface IEmits {
385
+ /** 行选中 */
386
+ (e: 'selection-change', selection: any): void
387
+ /** 修改行背景色 */
388
+ (e: 'row-bg-change', param: {colorId: number; row: ITableDataItem; rowIndex: number}): void
389
+ /** 行拖拽放置事件 */
390
+ (e: 'row-drag-drop', param: { row: any; fromIndex: number; toIndex: number; page: number; size: number;}): void
391
+ /** 行删除 */
392
+ (e: 'row-delete', param: { row: any; index: number; page: number; size: number; }): void
393
+ /** 点击编辑按钮立即触发 */
394
+ (e: 'row-edit', param: { row: any, index: number; page: number; size: number;}): void
395
+ /** 行置顶 */
396
+ (e: 'row-pin-to-top', param: { row: any, rawIndex: number; page: number; size: number;}): void
397
+ /** 行编辑保存 */
398
+ (e: 'row-edit-save', param: { page: number; size: number; row: any; changedData: Record<string, any>; }): void
399
+ /** 行编辑取消 */
400
+ (e: 'row-edit-cancel', param: { row: any; page: number; size: number;}): void
401
+ /** 页码改变 */
402
+ (e: 'page-change', param: { page: number, size: number }): void
403
+ /** 查询 */
404
+ (e: 'search', param: Record<string, any>): void
405
+ /** 排序 */
406
+ (e: 'sort-change', param: { order: 'descending' | 'ascending' | null, prop: string }): void
407
+ }
408
+
409
+ const props = withDefaults(defineProps<IProps>(), {
410
+ dataList: () => [],
411
+ columnConfig: () => [],
412
+ hasExpandRow: false,
413
+ hasIndexColumn: false,
414
+ hasSelectionColumn: false,
415
+ rowDragAble: false,
416
+ total: 0,
417
+ defaultOperations: () => [],
418
+ colorList: () => [],
419
+ leftFixedCount: 1,
420
+ dragSemiRange: 15,
421
+ loading: false,
422
+ hideViewSettingBtn: false,
423
+ settingStorgeKey: '',
424
+ localSort: false,
425
+ localFilter: false,
426
+ currentPage: 1,
427
+ });
428
+
429
+ // 同defineProps一样,不支持泛型参数从外部导入
430
+ const emit = defineEmits<IEmits>();
431
+
432
+ const showingColumns = ref<string[]>([]); // 表格中实际展示的列
433
+ const leftFixedColumnCount = ref(0) // 左侧固定列数量
434
+ const viewSettingDragSortOptions = ref<IColumnConfig[]>([])
435
+
436
+ const actualColumns = computed(() => {
437
+ const res: IColumnConfig[] = [];
438
+ let cnt = leftFixedColumnCount.value;
439
+
440
+ // 列排序和列过滤
441
+ for (const prop of showingColumns.value) {
442
+ const rawItem = props.columnConfig.find(c => c.prop === prop) ?? {} as IColumnConfig;
443
+ const item: IColumnConfig = {
444
+ ...rawItem,
445
+ isColumnSortable: rawItem.sortable,
446
+ sortable: inSorting.value ? rawItem.sortable : false
447
+ };
448
+ if (cnt > 0) {
449
+ item.fixed = 'left';
450
+ // eslint-disable-next-line no-plusplus
451
+ cnt--;
452
+ } else {
453
+ item.fixed = undefined;
454
+ }
455
+ res.push(item);
456
+ }
457
+
458
+ // 使用默认操作项,添加默认操作列。该列在编辑模式下隐藏
459
+ if (props.defaultOperations && props.defaultOperations.length > 0) {
460
+ res.push({
461
+ label: '操作',
462
+ prop: '$$operation',
463
+ 'min-width': '100px',
464
+ fixed: 'right'
465
+ });
466
+ }
467
+
468
+ return res;
469
+ });
470
+
471
+ const sortFilterPopoverRef = ref<any>(null);
472
+ const tableDomRef = ref<any>(null);
473
+ const currScope = ref<any>(null);
474
+
475
+ /************ 分页相关 *************/
476
+ const beforePageChange = () => {
477
+ searchValue.value = {};
478
+ };
479
+ const {
480
+ pageSize,
481
+ handleCurrPageChange,
482
+ handlePageSizeChange,
483
+ } = usePagination({
484
+ emit,
485
+ beforePageChange
486
+ });
487
+
488
+ /************ 表格单元格hover事件相关 ************ */
489
+ const {
490
+ hoveringCellInfo,
491
+ setCellClassName,
492
+ debouncedHoverHandler
493
+ } = useCellHover(tableDomRef);
494
+
495
+ /************ 行背景色设置相关 ************ */
496
+ const {
497
+ setRowStyle,
498
+ } = useRowBgColor({
499
+ colorList: props.colorList,
500
+ emit
501
+ });
502
+
503
+ /************ 默认的操作相关 ************ */
504
+ const {
505
+ operationPopoverRef,
506
+ editingRowData,
507
+ editingRowIndex,
508
+ handleDelete,
509
+ handleEdit,
510
+ handleEditSave,
511
+ handleEditCancel,
512
+ handleRowPinToTop,
513
+ closeAllExpandedRows
514
+ } = useDefaultOperation({
515
+ emit,
516
+ tableDomRef,
517
+ pageSize,
518
+ props,
519
+ hasExpandRow: props.hasExpandRow
520
+ });
521
+
522
+ /************ 列头部操作相关 ************ */
523
+ const {
524
+ setSort,
525
+ clearSort,
526
+ setSearchParams,
527
+ isColumnHeadActive,
528
+ handleSort,
529
+ handleHeaderPopoverShow,
530
+ handleHeaderOperationConfirm,
531
+ handleHeaderOperationReset,
532
+ summaryList,
533
+ tableSummaryMethod,
534
+ filteredValue,
535
+ showColumnHeadSortIcon,
536
+ tempSortingColumn,
537
+ tempSearchValue,
538
+ tempFilteredValue,
539
+ tempSummaryList,
540
+ tempSortType,
541
+ sortingColumn,
542
+ isColumnFiltering,
543
+ searchValue,
544
+ inSorting,
545
+ } = useColumnHeaderOperation({
546
+ tableDomRef,
547
+ sortFilterPopoverRef,
548
+ props,
549
+ emit,
550
+ showingColumns,
551
+ });
552
+
553
+ /************ 表格行拖拽和显示设置列拖拽 ************ */
554
+ const beforeDragStart = () => {
555
+ // 如果有列存在排序,不允许拖拽
556
+ if (sortingColumn.value) {
557
+ Message.warning('已有列正在排序,不允许拖拽。');
558
+ return false;
559
+ }
560
+
561
+ // 如果有列存在筛选,不允许拖拽
562
+ if (isColumnFiltering.value) {
563
+ Message.warning('已有列正在筛选,不允许拖拽。');
564
+ return false;
565
+ }
566
+
567
+ editingRowIndex.value = -1; // 关闭编辑状态
568
+
569
+ return true;
570
+ };
571
+
572
+ useDragSort({
573
+ emit,
574
+ props,
575
+ viewSettingDragSortOptions,
576
+ beforeDragStart,
577
+ pageSize,
578
+ currScope,
579
+ tableDomRef,
580
+ });
581
+
582
+ const doTableLayout = async () => {
583
+ await nextTick();
584
+ tableDomRef.value?.doLayout();
585
+ };
586
+
587
+ // 过滤出自定义属性,将其它属性全部透传给 el-table-column
588
+ const getColumnBindProps = (column: IColumnConfig) => {
589
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
590
+ const { editAble, editType, slotName, inputType, options, filters, ...rest } = column;
591
+ return rest;
592
+ };
593
+
594
+ const setRowClassName = (scope) => {
595
+ return `
596
+ custom-row-classname
597
+ custom-row-classname-${scope.rowIndex}
598
+ ${scope.row.isPinned ? 'custom-row-classname-pinned' : ''}
599
+ `;
600
+ };
601
+
602
+ const handleSelectionChange = (e) => {
603
+ emit('selection-change', e);
604
+ };
605
+
606
+ const bizViewSettingDialogRef = ref(null as unknown as InstanceType<typeof BizViewSettingDialog>)
607
+ const handleViewSettingShow = () => bizViewSettingDialogRef.value.open()
608
+
609
+ defineExpose({
610
+ closeAllExpandedRows,
611
+ openViewSetting: handleViewSettingShow,
612
+ elTableRef: tableDomRef,
613
+ setSort,
614
+ clearSort,
615
+ setSearchParams,
616
+ });
617
+
618
+ // loading 结束和页码变化时滚动到顶部
619
+ watch([
620
+ () => props.loading,
621
+ () => props.currentPage,
622
+ ], ([loading]) => {
623
+ if (loading) return;
624
+ tableDomRef.value.$el.querySelector('.el-table__body-wrapper').scrollTop = 0;
625
+ });
626
+
627
+ </script>
628
+
629
+ <style lang="less">
630
+ @import './index.less';
915
631
  </style>