element-ui-pro-components-test 1.5.0

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 (53) hide show
  1. package/CHANGELOG.md +0 -0
  2. package/LICENSE +21 -0
  3. package/README.md +0 -0
  4. package/lib/dialog-form.js +1175 -0
  5. package/lib/editable-pro-table.js +2080 -0
  6. package/lib/element-ui-pro-components.common.js +193 -0
  7. package/lib/index.js +1 -0
  8. package/lib/locale/index.js +44 -0
  9. package/lib/locale/lang/en.js +46 -0
  10. package/lib/locale/lang/zh-CN.js +46 -0
  11. package/lib/pro-form.js +1036 -0
  12. package/lib/pro-table.js +2779 -0
  13. package/lib/theme-chalk/editable-pro-table.css +1 -0
  14. package/lib/theme-chalk/index.css +1 -0
  15. package/lib/theme-chalk/pro-table.css +1 -0
  16. package/lib/umd/locale/en.js +67 -0
  17. package/lib/umd/locale/zh-CN.js +67 -0
  18. package/lib/utils/breakpoints.js +68 -0
  19. package/lib/utils/debounce.js +20 -0
  20. package/lib/utils/form.js +108 -0
  21. package/package.json +78 -0
  22. package/packages/dialog-form/index.js +9 -0
  23. package/packages/dialog-form/src/components/Submitter.vue +47 -0
  24. package/packages/dialog-form/src/index.vue +404 -0
  25. package/packages/editable-pro-table/index.js +9 -0
  26. package/packages/editable-pro-table/src/components/Editable.vue +203 -0
  27. package/packages/editable-pro-table/src/components/FormItem.vue +193 -0
  28. package/packages/editable-pro-table/src/components/RecordCreator.vue +43 -0
  29. package/packages/editable-pro-table/src/components/RenderCell.vue +181 -0
  30. package/packages/editable-pro-table/src/index.vue +805 -0
  31. package/packages/pro-form/index.js +9 -0
  32. package/packages/pro-form/src/components/Submitter.vue +47 -0
  33. package/packages/pro-form/src/index.vue +309 -0
  34. package/packages/pro-table/index.js +9 -0
  35. package/packages/pro-table/src/components/ColumnAlignSettings.vue +77 -0
  36. package/packages/pro-table/src/components/ColumnSettings.vue +172 -0
  37. package/packages/pro-table/src/components/ColumnSettingsItem.vue +401 -0
  38. package/packages/pro-table/src/components/svg/ArrowIcon.vue +16 -0
  39. package/packages/pro-table/src/components/svg/HolderIcon.vue +17 -0
  40. package/packages/pro-table/src/components/svg/SettingIcon.vue +20 -0
  41. package/packages/pro-table/src/components/svg/VerticalAlginBottomIcon.vue +17 -0
  42. package/packages/pro-table/src/components/svg/VerticalAlginMiddleIcon.vue +17 -0
  43. package/packages/pro-table/src/components/svg/VerticalAlignTopIcon.vue +17 -0
  44. package/packages/pro-table/src/index.vue +934 -0
  45. package/src/components/custom-render/index.vue +16 -0
  46. package/src/components/pro-form-item/index.vue +129 -0
  47. package/src/index.js +57 -0
  48. package/src/locale/index.js +47 -0
  49. package/src/locale/lang/en.js +46 -0
  50. package/src/locale/lang/zh-CN.js +46 -0
  51. package/src/utils/breakpoints.js +61 -0
  52. package/src/utils/debounce.js +22 -0
  53. package/src/utils/form.js +94 -0
@@ -0,0 +1,934 @@
1
+ <template>
2
+ <div class="pro-table">
3
+ <!-- 搜索表单 -->
4
+ <!-- start -->
5
+ <template v-if="search">
6
+ <el-form
7
+ class="pro-table__form"
8
+ :label-width="searchProps.labelWidth"
9
+ :label-position="searchProps.labelPosition"
10
+ :model="form"
11
+ :size="defaultSize"
12
+ :class="searchProps.className"
13
+ >
14
+ <!-- 栅格化布局 -->
15
+ <!-- start -->
16
+ <el-row v-bind="searchProps.rowProps">
17
+ <el-col
18
+ v-for="(formItem, index) in formItems"
19
+ v-bind="searchProps.colProps"
20
+ :style="{ display: index >= searchCount ? 'none' : '' }"
21
+ :key="formItem.prop || formItem.key"
22
+ >
23
+ <!-- ProFormItem -->
24
+ <!-- start -->
25
+ <ProFormItem
26
+ :form="form"
27
+ :formItem="formItem"
28
+ >
29
+ <template #[formItem.prop]>
30
+ <slot :name="formItem.prop" v-bind="{ form, formItem }"></slot>
31
+ </template>
32
+ </ProFormItem>
33
+ <!-- end -->
34
+ </el-col>
35
+ <!-- button -->
36
+ <!-- start -->
37
+ <el-col v-bind="searchColConfig" class="search-wrapper" key="search">
38
+ <el-button icon="el-icon-refresh" :size="defaultSize" @click="handleReset">{{ searchProps.resetText }}</el-button>
39
+ <el-button
40
+ type="primary"
41
+ icon="el-icon-search"
42
+ :loading="loading"
43
+ :size="defaultSize"
44
+ @click="handleSearch"
45
+ >{{ searchProps.searchText }}</el-button
46
+ >
47
+ <template v-if="showExpandToggle">
48
+ <el-button class="btn-collapse" type="text" :size="defaultSize" @click="handleCollapse">
49
+ {{ collapsed ? t('elProComponents.proTable.expand') : t('elProComponents.proTable.collapse') }}
50
+ <ArrowIcon
51
+ style="transition: 0.3s"
52
+ :style="{ transform: `rotate(${collapsed ? 0 : 0.5}turn)` }"
53
+ />
54
+ </el-button>
55
+ </template>
56
+ </el-col>
57
+ <!-- end -->
58
+ </el-row>
59
+ </el-form>
60
+ </template>
61
+ <!-- end -->
62
+ <!-- 标题栏 -->
63
+ <!-- start -->
64
+ <div v-if="$slots.default || columnSettings" class="pro-table__toolbar">
65
+ <slot></slot>
66
+ <!-- 列设置 -->
67
+ <!-- start -->
68
+ <div v-if="columnSettings" class="pro-table__toolbar-items">
69
+ <ColumnSettings :columns="settingColumns" :columnSettings="initializedColumnSettings" />
70
+ </div>
71
+ <!-- end -->
72
+ </div>
73
+ <!-- end -->
74
+ <el-table
75
+ ref="tableRef"
76
+ class="pro-table__table"
77
+ :class="className"
78
+ v-loading="loading"
79
+ :data="dataSource"
80
+ v-bind="initializedTableProps"
81
+ v-on="initializedTableEvents"
82
+ :key="tableKey"
83
+ >
84
+ <el-table-column
85
+ v-for="column in normalizedColumns"
86
+ v-bind="{
87
+ ...column,
88
+ nonElColumnProps: undefined,
89
+ }"
90
+ :key="column.prop || column.nonElColumnProps.key || `${column.type}-col`"
91
+ >
92
+ <template v-if="column.nonElColumnProps.renderCellHeader" #header="scope">
93
+ <!-- 覆写头部 -->
94
+ <!-- start -->
95
+ <CustomRender :render="() => column.nonElColumnProps.renderCellHeader(scope)" />
96
+ <!-- end -->
97
+ </template>
98
+ <template v-if="column.nonElColumnProps.renderCell" #default="scope">
99
+ <!-- 自定义 render -->
100
+ <!-- start -->
101
+ <CustomRender :render="() => column.nonElColumnProps.renderCell(scope)" />
102
+ <!-- end -->
103
+ </template>
104
+ <template v-else-if="column.nonElColumnProps.valueEnum" #default="scope">
105
+ <!-- valueEnum -->
106
+ <!-- start -->
107
+ <span>
108
+ {{ getOptionLabel(column, scope) }}
109
+ </span>
110
+ <!-- end -->
111
+ </template>
112
+ </el-table-column>
113
+ </el-table>
114
+ <el-pagination
115
+ class="pro-table__pagination"
116
+ v-bind="initializedPaginationProps"
117
+ @current-change="handleCurrentChange"
118
+ @size-change="handleSizeChange"
119
+ />
120
+ </div>
121
+ </template>
122
+
123
+ <script>
124
+ import { setPlaceholder, setSelectOptions, setCascaderOptions } from 'element-ui-pro-components/src/utils/form'
125
+ import { defaultColConfig, BREAKPOINT_ORDER, GRID_COLUMNS, calculateCurrentSpan } from "element-ui-pro-components/src/utils/breakpoints"
126
+ import { debounce } from "element-ui-pro-components/src/utils/debounce"
127
+ import ProFormItem from '@/components/pro-form-item'
128
+ import ArrowIcon from "./components/svg/ArrowIcon"
129
+ import CustomRender from '@/components/custom-render'
130
+ import ColumnSettings from './components/ColumnSettings'
131
+ import { t } from 'element-ui-pro-components/src/locale'
132
+
133
+ export default {
134
+ name: 'ProTable',
135
+ components: {
136
+ ProFormItem,
137
+ CustomRender,
138
+ ArrowIcon,
139
+ ColumnSettings
140
+ },
141
+ provide() {
142
+ if (!this.columnSettings) {
143
+ return
144
+ }
145
+
146
+ return {
147
+ // 监听列设置修改
148
+ onColumnSettingsChange: this.onColumnSettingsChange,
149
+ }
150
+ },
151
+ props: {
152
+ // 搜索表单
153
+ search: {
154
+ type: [Boolean, Object],
155
+ default: true
156
+ },
157
+ // el-table 的类名
158
+ className: {
159
+ type: String,
160
+ },
161
+ // el-table 的数据
162
+ dataSource: {
163
+ type: Array
164
+ },
165
+ // 表格数据请求加载状态
166
+ loading: {
167
+ type: Boolean
168
+ },
169
+ // 数据总条数
170
+ total: {
171
+ type: Number,
172
+ default: 0
173
+ },
174
+ // el-table attributes 的配置
175
+ tableProps: {
176
+ type: Object,
177
+ default: () => ({})
178
+ },
179
+ // el-table events 的配置
180
+ tableEvents: {
181
+ type: Object,
182
+ default: () => ({})
183
+ },
184
+ // 列定义
185
+ columns: {
186
+ type: Array,
187
+ required: true,
188
+ default: () => []
189
+ },
190
+ // el-pagination attributes 的配置
191
+ paginationProps: {
192
+ type: Object,
193
+ default: () => ({})
194
+ },
195
+ // 分页参数字段映射配置
196
+ paginationMapping: {
197
+ type: Object,
198
+ default: () => ({})
199
+ },
200
+ // 表单默认值
201
+ initialValues: {
202
+ type: Object,
203
+ default: () => ({})
204
+ },
205
+ // 默认的 size
206
+ defaultSize: {
207
+ type: String,
208
+ validator: function (value) {
209
+ return ['medium', 'small', 'mini'].includes(value)
210
+ },
211
+ },
212
+ // 是否需要手动触发首次请求
213
+ manualRequest: {
214
+ type: Boolean,
215
+ default: false
216
+ },
217
+ // 列设置
218
+ columnSettings: {
219
+ type: [Boolean, Object],
220
+ default: true
221
+ }
222
+ },
223
+ computed: {
224
+ // search 初始化
225
+ searchProps() {
226
+ const { search } = this
227
+ if (search) {
228
+ const defaultSearch = {
229
+ searchText: t('elProComponents.proTable.search'),
230
+ resetText: t('elProComponents.proTable.reset'),
231
+ labelWidth: "80px",
232
+ rowProps: {
233
+ gutter: 8,
234
+ },
235
+ colProps: defaultColConfig,
236
+ collapsed: true, // 默认收起
237
+ defaultExpandedRows: 2,
238
+ };
239
+
240
+ if (typeof search === "object") {
241
+ return {
242
+ ...defaultSearch,
243
+ ...this.search,
244
+ collapsed: search.collapsed ?? search.defaultCollapsed ?? defaultSearch.collapsed,
245
+ }
246
+ }
247
+
248
+ return {
249
+ ...defaultSearch,
250
+ };
251
+ }
252
+
253
+ return false
254
+ },
255
+ // 表单项
256
+ formItems() {
257
+ const { columns } = this
258
+ return (
259
+ columns
260
+ // 过滤 隐藏的 & 无表单类型的
261
+ .filter((item) => !item.hideInSearch && (!!item.valueType || item.renderField) )
262
+ // 权重大排序在前
263
+ .sort((a, b) => b.order - a.order)
264
+ // 筛选
265
+ .map((col) => {
266
+ const {
267
+ label,
268
+ prop,
269
+ formItemProps = {},
270
+ renderLabel,
271
+ valueType,
272
+ renderField,
273
+ fieldProps = {},
274
+ fieldEvents,
275
+ initialValue,
276
+ } = col
277
+ // 设置 el-form-item
278
+ formItemProps.label = formItemProps.label || label
279
+ formItemProps.prop = formItemProps.prop || prop
280
+
281
+ // 设置 placeholder
282
+ setPlaceholder(fieldProps, valueType)
283
+
284
+ // 设置 select options
285
+ setSelectOptions(col, this.cachedOptions)
286
+
287
+ // 设置 cascader options
288
+ setCascaderOptions(fieldProps, col, this.cachedOptions)
289
+
290
+ return {
291
+ ...formItemProps,
292
+ renderLabel,
293
+ valueType,
294
+ renderField,
295
+ fieldProps,
296
+ fieldEvents,
297
+ options: col.options,
298
+ initialValue,
299
+ }
300
+ })
301
+ )
302
+ },
303
+ // 表单项总个数
304
+ totalSearchCount() {
305
+ return this.formItems.length
306
+ },
307
+ // 标准化列定义配置
308
+ normalizedColumns() {
309
+ const { columns, initializedColumnSettings, columnSettingsRule } = this
310
+ let normalizedColumns = columns
311
+ // 筛选隐藏项
312
+ .filter(item => !item.hideInTable)
313
+ .map((col) => {
314
+ // 筛选 el-column 属性
315
+ const {
316
+ formItemProps,
317
+ renderLabel,
318
+ valueType,
319
+ renderField,
320
+ fieldProps,
321
+ fieldEvents,
322
+ options,
323
+ valueEnum,
324
+ optionLoader,
325
+ initialValue,
326
+ order,
327
+ hideInSearch,
328
+ renderCellHeader,
329
+ renderCell,
330
+ disabled,
331
+ key,
332
+ ...keys
333
+ } = col
334
+ return {
335
+ ...keys,
336
+ nonElColumnProps: {
337
+ valueEnum,
338
+ renderCellHeader,
339
+ renderCell,
340
+ key,
341
+ disabled
342
+ }
343
+ }
344
+ })
345
+
346
+ // 合并列设置规则
347
+ if (initializedColumnSettings && columnSettingsRule?.length) {
348
+ normalizedColumns = normalizedColumns.map(col => {
349
+ const rule = columnSettingsRule.find(item => (col.prop || col.nonElColumnProps.key) === item.prop)
350
+ if (rule) {
351
+ const { checkable, fixed, index } = rule
352
+ col.nonElColumnProps = {
353
+ ...col.nonElColumnProps,
354
+ checkable,
355
+ index
356
+ }
357
+ return { ...col, fixed }
358
+ }
359
+
360
+ return col
361
+ })
362
+ }
363
+
364
+ // 列设置处理
365
+ const { draggable, checkable } = initializedColumnSettings
366
+
367
+ // 支持拖拽排序
368
+ if (draggable) {
369
+ normalizedColumns.sort((a, b) => a.nonElColumnProps.index - b.nonElColumnProps.index)
370
+ }
371
+
372
+ // 支持显示/隐藏列
373
+ if (checkable) {
374
+ normalizedColumns = normalizedColumns.filter(item => item.nonElColumnProps.checkable || !!item.type)
375
+ }
376
+
377
+ return normalizedColumns
378
+ },
379
+ // 列设置的列表项
380
+ settingColumns() {
381
+ const { columnSettings } = this
382
+ if (!columnSettings) {
383
+ return []
384
+ }
385
+ const { columnSettingsRule, columns } = this
386
+
387
+ return columnSettingsRule.map((rule) => {
388
+ const col = columns.find(item => rule.prop === (item.prop || item.key))
389
+ if (col) {
390
+ const { label, disabled } = col
391
+ return { ...rule, label, disabled }
392
+ }
393
+
394
+ return rule
395
+ })
396
+ },
397
+ // columnSettings 初始化
398
+ initializedColumnSettings() {
399
+ const { columnSettings } = this
400
+ if (columnSettings) {
401
+ const defaultColumnSettings = {
402
+ columnSetting: t('elProComponents.tableToolBar.columnSetting'),
403
+ columnDisplay: t('elProComponents.tableToolBar.columnDisplay'),
404
+ resetText: t('elProComponents.tableToolBar.reset'),
405
+ draggable: true,
406
+ checkable: true
407
+ }
408
+
409
+ // 如果不是对象,返回默认值
410
+ if (typeof columnSettings === 'object') {
411
+ // 合并基本设置
412
+ return {
413
+ ...defaultColumnSettings,
414
+ ...columnSettings
415
+ }
416
+ }
417
+
418
+ return defaultColumnSettings
419
+ }
420
+
421
+ return false
422
+ },
423
+ // tableProps 初始化
424
+ initializedTableProps() {
425
+ const { tableProps, defaultSize } = this
426
+ return {
427
+ size: defaultSize,
428
+ ...tableProps
429
+ }
430
+ },
431
+ // tableEvents 初始化
432
+ initializedTableEvents() {
433
+ return {
434
+ 'sort-change': this.sortChange, // 排序
435
+ ...this.tableEvents
436
+ }
437
+ },
438
+ // paginationProps 初始化
439
+ initializedPaginationProps() {
440
+ return {
441
+ "page-sizes": [10, 20, 30, 50],
442
+ layout: "total, sizes, prev, pager, next, jumper",
443
+ "hide-on-single-page": true,
444
+ ...this.paginationProps,
445
+ "current-page": this.pageNum,
446
+ "page-size": this.pageSize,
447
+ total: this.total,
448
+ }
449
+ },
450
+ },
451
+ data() {
452
+ return {
453
+ cachedOptions: {}, // 下拉数据 { [prop]: data }
454
+ form: this.initForm(), // 表单数据
455
+ showExpandToggle: false, // 是否显示展开、收起
456
+ searchColConfig: defaultColConfig, // search Col 配置
457
+ collapsed: true, // 展开、收起
458
+ searchCount: 0, // 收起展示的表单个数收起展示的表单个数
459
+ tableKey: 1, // table key
460
+ pageNum: 1, // 页码
461
+ pageSize: this.paginationProps["page-size"] || 10, // 页数
462
+ columnSettingsRule: [], // 列设置规则
463
+ }
464
+ },
465
+ watch: {
466
+ // 监听表单项总个数
467
+ totalSearchCount() {
468
+ this.calculateSearchLayout()
469
+ },
470
+ // 监听 search.collapsed
471
+ "search.collapsed": function (newValue) {
472
+ if (newValue !== this.collapsed) {
473
+ this.handleCollapse()
474
+ }
475
+ },
476
+ },
477
+ created() {
478
+ // 获取异步数据
479
+ this.getOptions()
480
+ // 是否手动执行
481
+ if (!this.manualRequest) {
482
+ this.handleSearch()
483
+ }
484
+ // 开启列设置
485
+ if (this.columnSettings) {
486
+ this.columnSettingsRule = this.initializeColumnSettingsRule()
487
+ }
488
+ },
489
+ mounted() {
490
+ // 是否支持响应式
491
+ const isResponsive = this.isResponsive()
492
+ // 计算是否需要展开、收起以及位置
493
+ this.calculateSearchLayout(isResponsive)
494
+
495
+ // 监听 window 宽度变化
496
+ if (isResponsive) {
497
+ // window 宽度变化防抖
498
+ this.debounceResize = debounce(this.resize)
499
+ // 监听 window resize
500
+ window.addEventListener("resize", this.debounceResize)
501
+ }
502
+ },
503
+ methods: {
504
+ /**
505
+ * @desc 多语言支持
506
+ */
507
+ t(key) {
508
+ return t(key)
509
+ },
510
+ /**
511
+ * @desc 获取异步下拉数据
512
+ */
513
+ getOptions() {
514
+ const { columns } = this
515
+ for (const column of columns) {
516
+ const { prop, fieldProps = {}, optionLoader } = column
517
+ if (optionLoader && typeof optionLoader === "function") {
518
+ optionLoader().then((res) => {
519
+ const key = fieldProps.prop || prop
520
+ this.cachedOptions = {
521
+ ...this.cachedOptions,
522
+ [key]: res,
523
+ }
524
+ })
525
+ }
526
+ }
527
+ },
528
+ /**
529
+ * @desc 初始化表单数据
530
+ */
531
+ initForm() {
532
+ const { columns } = this
533
+ // 兼容
534
+ if (!columns.length) {
535
+ return {}
536
+ }
537
+
538
+ const data = columns
539
+ // 筛选表单类型
540
+ .filter((item) => !!item.valueType)
541
+ .reduce((accu, cur) => {
542
+ const { prop, fieldProps = {}, initialValue } = cur
543
+ const key = fieldProps.prop || prop
544
+ if (!key) {
545
+ return accu
546
+ }
547
+
548
+ return {
549
+ ...accu,
550
+ [key]: initialValue,
551
+ }
552
+ }, {})
553
+
554
+ return { ...this.initialValues, ...data }
555
+ },
556
+ /**
557
+ * @desc 是否需要支持响应式
558
+ * @returns {boolean}
559
+ */
560
+ isResponsive() {
561
+ const { searchProps: { colProps } } = this
562
+ const keys = Object.keys(colProps)
563
+ return keys.some((key) => BREAKPOINT_ORDER.includes(key))
564
+ },
565
+ /**
566
+ * @desc 计算搜索区域的布局配置(展开/收起状态)
567
+ * @param {boolean} isResponsive 是否是响应式
568
+ */
569
+ calculateSearchLayout(isResponsive = false) {
570
+ const { searchProps: { colProps, defaultExpandedRows }, totalSearchCount } = this
571
+
572
+ // 1. 计算每个表单项所占的栅格跨度
573
+ this.cachedSpanPerField = isResponsive
574
+ ? calculateCurrentSpan(colProps)
575
+ : (colProps.span || 8)
576
+
577
+ // 2. 计算最大可展示的表单项数量
578
+ this.maxVisibleFields = Math.floor(
579
+ (GRID_COLUMNS / this.cachedSpanPerField) * defaultExpandedRows
580
+ ) - 1
581
+
582
+ // 3. 判断是否需要显示展开/收起按钮
583
+ this.showExpandToggle = totalSearchCount > this.maxVisibleFields
584
+
585
+ if (this.showExpandToggle) {
586
+ this.collapsed = this.searchProps.collapsed
587
+ }
588
+
589
+ // 4. 更新布局配置
590
+ this.updateSearchLayout()
591
+ },
592
+ /**
593
+ * @desc 更新搜索按钮的位置
594
+ */
595
+ updateSearchLayout() {
596
+ const { searchProps: { colProps }, cachedSpanPerField } = this
597
+
598
+ // 1. 计算可见的表单项数量
599
+ this.searchCount = this.showExpandToggle && this.collapsed
600
+ ? this.maxVisibleFields
601
+ : this.totalSearchCount
602
+
603
+ // 2. 计算搜索按钮的位置
604
+ const restSpan = GRID_COLUMNS - ((cachedSpanPerField * this.searchCount) % GRID_COLUMNS)
605
+
606
+ // 3. 计算偏差值 offset
607
+ const offset = restSpan - cachedSpanPerField
608
+
609
+ this.searchColConfig = { ...colProps, offset }
610
+ },
611
+ /**
612
+ * @desc 宽度变化
613
+ * @param {Array} entries 监听元素数据
614
+ */
615
+ resize() {
616
+ // 重新计算
617
+ this.calculateSearchLayout(true)
618
+ },
619
+ /**
620
+ * @desc 点击展开、收起
621
+ */
622
+ handleCollapse() {
623
+ this.collapsed = !this.collapsed
624
+ this.$emit("onCollapse", this.collapsed)
625
+ if (this.showExpandToggle) {
626
+ // 更新展开、收起的位置
627
+ this.updateSearchLayout()
628
+ }
629
+ },
630
+ /**s
631
+ * @desc 获取选择器枚举标签
632
+ * @param {Object} column 列数据
633
+ * @param {Object} row 行数据
634
+ */
635
+ getOptionLabel(column, scope) {
636
+ return column.nonElColumnProps.valueEnum instanceof Map
637
+ ? column.nonElColumnProps.valueEnum.get(scope.row?.[column.prop])
638
+ : column.nonElColumnProps.valueEnum[scope.row?.[column.prop]]
639
+ },
640
+ /**s
641
+ * @desc 表单请求参数(分页)
642
+ */
643
+ getParams() {
644
+ const { pageNum, pageSize, paginationMapping: { pageKey, sizeKey } } = this
645
+ return {
646
+ ...this.form,
647
+ [pageKey || "pageNum"]: pageNum,
648
+ [sizeKey || "pageSize"]: pageSize,
649
+ }
650
+ },
651
+ /**
652
+ * @desc 重置
653
+ */
654
+ handleReset() {
655
+ this.form = this.initForm()
656
+ // 重置第一页
657
+ this.pageNum = 1
658
+ this.$emit("onParams", this.getParams())
659
+ this.$emit("onReset")
660
+ },
661
+ /**
662
+ * @desc 查询
663
+ */
664
+ handleSearch() {
665
+ // 重置第一页
666
+ this.pageNum = 1
667
+ const params = this.getParams()
668
+ this.$emit("onParams", params)
669
+ this.$emit("onSubmit", params)
670
+ },
671
+ /**
672
+ * @desc 刷新
673
+ * @param {boolean} resetPageIndex 是否重置页码
674
+ */
675
+ reload(resetPageIndex = true) {
676
+ if (resetPageIndex) {
677
+ this.pageNum = 1
678
+ }
679
+
680
+ this.$emit("onParams", this.getParams())
681
+ },
682
+ /**
683
+ * @desc 排序
684
+ * @param {String} prop 属性
685
+ * @param {String} order 升序: ASC 倒序: DESC
686
+ */
687
+ sortChange({ prop, order }) {
688
+ // 重置第一页
689
+ this.pageNum = 1
690
+ this.$emit("onParams", { ...this.getParams(), prop, order })
691
+ },
692
+ /**
693
+ * @desc 监听页码修改
694
+ * @param {Number} page 页码
695
+ */
696
+ handleCurrentChange(page) {
697
+ this.pageNum = page
698
+ this.$emit("onParams", this.getParams())
699
+ },
700
+ /**
701
+ * @desc 监听页数修改
702
+ * @param {Number} pageSize 页数
703
+ */
704
+ handleSizeChange(pageSize) {
705
+ this.pageSize = pageSize
706
+ // 重置页码(防止分页组件自动计算页码)
707
+ this.pageNum = 1
708
+
709
+ this.$emit("onParams", this.getParams())
710
+ },
711
+ /**
712
+ * @desc 获取 table ref
713
+ */
714
+ getTableRef() {
715
+ return this.$refs.tableRef
716
+ },
717
+ /**
718
+ * @desc 初始化列设置
719
+ */
720
+ initializeColumnSettingsRule() {
721
+ return this.columns
722
+ // 过滤隐藏的 && (columnConfig.prop || columnConfig.key)
723
+ .filter((item) => !item.hideInTable && (item.prop || item.key))
724
+ .map((col, index) => {
725
+ const { prop, key, fixed } = col
726
+ return {
727
+ prop: prop || key,
728
+ fixed,
729
+ checkable: true,
730
+ index,
731
+ }
732
+ })
733
+ },
734
+ /**
735
+ * @desc 全选、取消全选
736
+ * @param {Boolean} checked 勾选状态
737
+ */
738
+ checkAllRule(checked) {
739
+ this.columnSettingsRule = this.columnSettingsRule.map(rule => {
740
+ const col = this.columns.find(item => (item.prop || item.key) === rule.prop )
741
+ if (col) {
742
+ return { ...rule, checkable: !col.disabled ? checked : rule.checkable }
743
+ }
744
+
745
+ return rule
746
+ })
747
+ },
748
+ /**
749
+ * @desc 单个勾选、取消勾选
750
+ * @param {String} prop 标识
751
+ * @param {Boolean} checked 勾选状态
752
+ */
753
+ checkRule(prop, checked) {
754
+ const { columnSettingsRule } = this
755
+ const index = columnSettingsRule.findIndex((item) => item.prop === prop)
756
+ if (index !== -1) {
757
+ columnSettingsRule.splice(index, 1, {
758
+ ...columnSettingsRule[index],
759
+ checkable: checked,
760
+ })
761
+ }
762
+ },
763
+ /**
764
+ * @desc 固定位置修改
765
+ * @param {String} prop 属性
766
+ * @param {String | undefined} fixed 固定位置
767
+ */
768
+ handleAlignRule(prop, fixed) {
769
+ const { columnSettingsRule } = this
770
+ const index = columnSettingsRule.findIndex((item) => item.prop === prop)
771
+ if (index !== -1) {
772
+ const rule = columnSettingsRule[index]
773
+ columnSettingsRule.splice(index, 1, { ...rule, fixed })
774
+ }
775
+ },
776
+ /**
777
+ * @desc 重置列设置规则
778
+ */
779
+ handleResetRule() {
780
+ this.columnSettingsRule = this.initializeColumnSettingsRule()
781
+ },
782
+ /**
783
+ * @desc 拖拽更新
784
+ * @param {String} fromProp 拖拽开始列
785
+ * @param {String} toProp 释放目标列
786
+ * @param {Boolean} isAfter 是否拖拽到分组的最后一列
787
+ */
788
+ handleDropRule(fromProp, toProp, isAfter = false) {
789
+ const { columnSettingsRule } = this
790
+ const fromIndex = columnSettingsRule.findIndex(item => (item.prop || item.key) === fromProp)
791
+ if (fromIndex === -1) {
792
+ return
793
+ }
794
+ const toIndex = columnSettingsRule.findIndex(item => (item.prop || item.key) === toProp)
795
+ if (toIndex === -1) {
796
+ return
797
+ }
798
+ // 向上拖拽
799
+ const isUp = fromIndex > toIndex
800
+ // 开始移动下标
801
+ const startIndex = isUp ? toIndex : fromIndex + 1
802
+ // 结束移动下标
803
+ const endIndex = isUp ? fromIndex : isAfter ? toIndex + 1 : toIndex
804
+ // 移动
805
+ for (let i = startIndex; i < endIndex; ++i) {
806
+ const column = columnSettingsRule[i]
807
+ columnSettingsRule.splice(i, 1, { ...column, index: isUp ? column.index + 1 : column.index - 1 })
808
+ }
809
+
810
+ const fromColumn = columnSettingsRule[fromIndex]
811
+ if (isUp) {
812
+ // 先删除 后插入
813
+ columnSettingsRule.splice(fromIndex, 1)
814
+ columnSettingsRule.splice(toIndex, 0, { ...fromColumn, index: toIndex })
815
+ } else {
816
+ // 先插入 后删除
817
+ columnSettingsRule.splice(endIndex, 0 , { ...fromColumn, index: endIndex - 1 })
818
+ columnSettingsRule.splice(fromIndex, 1)
819
+ }
820
+ },
821
+ /**
822
+ * @desc el-table 列的数量发生变化时需要重新布局
823
+ */
824
+ doLayout() {
825
+ this.$nextTick(() => {
826
+ // 对 Table 进行重新布局
827
+ this.$refs.tableRef?.doLayout()
828
+ })
829
+ },
830
+ /**
831
+ * @desc el-table 重新渲染
832
+ */
833
+ updateTableKey() {
834
+ this.tableKey = Math.random().toString().slice(2, 8)
835
+ this.$nextTick(() => {
836
+ this.$emit('onKeyChange')
837
+ })
838
+ },
839
+ /**
840
+ * @desc 监听列设置修改
841
+ * @param { Object } data 数据
842
+ * @param {String} data.event 事件类型
843
+ */
844
+ onColumnSettingsChange(data) {
845
+ const { event, prop, checked, fixed, fromProp, toProp, isAfter } = data;
846
+ // 勾选或取消勾选
847
+ switch (event) {
848
+ case "checkAll":
849
+ this.checkAllRule(checked)
850
+ this.doLayout()
851
+ break
852
+ case "check":
853
+ this.checkRule(prop, checked)
854
+ this.doLayout()
855
+ break
856
+ case "align":
857
+ this.handleAlignRule(prop, fixed)
858
+ break
859
+ case "reset":
860
+ this.handleResetRule()
861
+ // 更新 table key
862
+ this.updateTableKey()
863
+ break
864
+ case 'drop':
865
+ this.handleDropRule(fromProp, toProp, isAfter)
866
+ // 更新 table key
867
+ this.updateTableKey()
868
+ break
869
+ default:
870
+ break
871
+ }
872
+ },
873
+ },
874
+ beforeDestroy() {
875
+ // 清除 resize
876
+ window.removeEventListener("resize", this.resize)
877
+ // 取消防抖
878
+ this.debounceResize?.cancel()
879
+ },
880
+ }
881
+ </script>
882
+
883
+ <style lang="less" scoped>
884
+ .pro-table__form {
885
+ margin-block-end: 16px;
886
+ background-color: #fff;
887
+
888
+ ::v-deep .el-form-item__content {
889
+ .el-select,
890
+ .el-input-number,
891
+ .el-date-editor,
892
+ .el-cascader {
893
+ width: 100%;
894
+ }
895
+ }
896
+
897
+ .search-wrapper {
898
+ display: flex;
899
+ align-items: center;
900
+ justify-content: flex-end;
901
+ }
902
+
903
+ .btn-collapse.el-button {
904
+ margin-left: 16px;
905
+
906
+ ::v-deep span {
907
+ display: inline-flex;
908
+ gap: 0.5em;
909
+ align-items: center;
910
+ }
911
+ }
912
+ }
913
+
914
+ .pro-table__toolbar {
915
+ display: flex;
916
+ justify-content: space-between;
917
+ padding-bottom: 16px;
918
+
919
+ .pro-table__toolbar-items {
920
+ display: flex;
921
+ gap: 8px;
922
+ align-items: center;
923
+ margin-left: auto;
924
+ }
925
+ }
926
+
927
+ .pro-table__pagination {
928
+ margin: 16px 0;
929
+ margin-block-end: 0;
930
+ display: flex;
931
+ justify-content: flex-end;
932
+ }
933
+ </style>
934
+