ol-base-components 2.8.12 → 2.8.13

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.
@@ -1,914 +1,913 @@
1
- <template>
2
- <div class="table_list_fix">
3
- <!-- 扩展性内容 -->
4
- <slot name="content_context" />
5
- <template
6
- v-if="
7
- btnlist.length ||
8
- tableData.options.headTool ||
9
- tableData.options.refreshBtn ||
10
- tableData.options.downloadBtn
11
- "
12
- >
13
- <div v-if="showBtnBox" class="btnbox">
14
- <!-- 左侧按钮 -->
15
- <div>
16
- <el-button
17
- v-for="(btn, index) in btnlist"
18
- :key="index"
19
- size="small"
20
- :type="btn.types ? btn.types : 'primary'"
21
- @click="btn.method"
22
- >
23
- <i v-if="btn.icon" :class="btn.icon" />
24
- {{ btn.title }}
25
- </el-button>
26
- </div>
27
- <!-- 右侧工具按钮 -->
28
- <div class="toolbox">
29
- <el-dropdown
30
- v-if="tableData.options.headTool"
31
- class="avatar-container right-menu-item hover-effect"
32
- trigger="click"
33
- >
34
- <div class="avatar-wrapper">
35
- <div class="layui-table-tool-self">
36
- <i class="el-icon-s-operation" />
37
- </div>
38
- </div>
39
- <el-dropdown-menu slot="dropdown" style="padding: 5px">
40
- <el-checkbox-group v-model="checkedTableColumns">
41
- <el-checkbox
42
- v-for="column in checkedTableList"
43
- :key="column.prop"
44
- class="checkbox"
45
- :label="column.prop"
46
- >{{ column.label }}
47
- </el-checkbox>
48
- </el-checkbox-group>
49
- </el-dropdown-menu>
50
- </el-dropdown>
51
- <div
52
- v-if="tableData.options.refreshBtn"
53
- class="avatar-container right-menu-item hover-effect el-dropdown"
54
- @click="refreshTable"
55
- >
56
- <div class="avatar-wrapper">
57
- <div class="layui-table-tool-self">
58
- <i class="el-icon-refresh" />
59
- </div>
60
- </div>
61
- </div>
62
- <div
63
- v-if="tableData.options.downloadBtn"
64
- class="avatar-container right-menu-item hover-effect el-dropdown"
65
- @click="printTable"
66
- >
67
- <div class="avatar-wrapper">
68
- <div class="layui-table-tool-self">
69
- <i class="el-icon-printer" />
70
- </div>
71
- </div>
72
- </div>
73
- </div>
74
- </div>
75
- </template>
76
-
77
- <!-- 表格 -->
78
- <div class="tablebox" :key="tableData.columns.length">
79
- <el-table
80
- :ref="tableRef"
81
- v-loading="tableData.loading"
82
- border
83
- v-bind="tableData.options"
84
- :data="tableData.rows"
85
- style="width: 100%"
86
- height="100%"
87
- :default-sort="tableData.sort"
88
- v-on="tableEvents"
89
- @selection-change="SelectionChange"
90
- @select="select"
91
- @select-all="selectAll"
92
- @row-click="rowClick"
93
- >
94
- <el-table-column
95
- v-if="tableData.options && tableData.options.index"
96
- width="60"
97
- align="center"
98
- type="index"
99
- :index="computeTableIndex"
100
- label="序号"
101
- />
102
- <el-table-column
103
- v-if="tableData.options && tableData.options.selection"
104
- width="60"
105
- align="center"
106
- type="selection"
107
- label=""
108
- />
109
- <!-- 新增插槽,允许父组件自定义表头 -->
110
- <!-- <template v-if="tableData.options && tableData.options.useSlotHeader">
111
- <slot
112
- name="table-columns"
113
- :columns="bindTableColumns"
114
- >
115
- <template v-for="(item, index) in bindTableColumns">
116
- <my-table-column
117
- :column="item"
118
- :key="index"
119
- />
120
- </template>
121
- </slot>
122
- </template> -->
123
- <!-- 防止之前逻辑出现纰漏,故保留之前逻辑再扩展自定义插槽方式渲染 -->
124
- <!-- <template v-else> -->
125
- <!-- <template v-for="(item, index) in bindTableColumns">
126
- <el-table-column
127
- :key="index"
128
- :label="item.label"
129
- :prop="item.prop"
130
- :min-width="item.minWidth || '150px'"
131
- :show-overflow-tooltip="item.overHidden || true"
132
- :type="item.type || 'normal'"
133
- v-bind="{
134
- align: 'center',
135
- width: item.width,
136
- fixed: item.fixed || false,
137
- sortable: item.sortable || false,
138
- ...item.attrs,
139
- }"
140
- >
141
- <template v-slot:header>
142
- <el-tooltip
143
- :content="`${item.label} ${item.prop}`"
144
- placement="top"
145
- >
146
- <span>{{ item.label }}</span>
147
- </el-tooltip>
148
- </template>
149
- <template
150
- v-if="item.render"
151
- v-slot="scope"
152
- >
153
- <render-dom :render="() => item.render(scope.row)" />
154
- </template>
155
- <template
156
- v-else-if="item.renderSlot"
157
- v-slot="scope"
158
- >
159
- <slot
160
- :row="scope.row"
161
- :name="item.prop"
162
- />
163
- </template>
164
- </el-table-column>
165
- </template> -->
166
- <!-- </template> -->
167
-
168
- <template v-for="(item, index) in this.tableData.columns">
169
- <TableColumn
170
- :column="item"
171
- :key="`${item.prop || item.label}-${item.show}-${index}`"
172
- :id="`${item.prop}-${item.show}-${index}`"
173
- >
174
- <template v-for="(slotFn, name) in $scopedSlots" v-slot:[name]="slotProps">
175
- <slot :name="name" v-bind="slotProps" />
176
- </template>
177
- </TableColumn>
178
- </template>
179
- <el-table-column
180
- v-if="tableData.operates && tableData.operates.length > 0"
181
- label="操作"
182
- align="center"
183
- v-bind="tableData.operatesAttrs"
184
- >
185
- <template slot-scope="scope">
186
- <div class="operate-group">
187
- <template v-for="(btn, key) in tableData.operates">
188
- <span
189
- v-if="!btn.isShow || (btn.isShow && btn.isShow(scope.row, scope.$index))"
190
- :key="key"
191
- >
192
- <el-button
193
- :style="btn.style || ''"
194
- :size="btn.size || 'small'"
195
- :type="btn.type || `text`"
196
- :icon="btn.icon"
197
- :plain="btn.plain"
198
- :disabled="btn.disabled && btn.disabled(scope.row, scope.$index)"
199
- @click.stop="btn.method(scope.row, scope.$index)"
200
- >{{ btn.label
201
- }}{{ tableData.operates.length >= 2 ? "&nbsp;&nbsp;" : "" }}</el-button
202
- >
203
- </span>
204
- </template>
205
- </div> </template
206
-
207
- </el-table-column>
208
- <div slot="empty" class="empty">
209
- <img v-if="tableData.rows.length == 0" :src="nodata" />
210
- </div>
211
- </el-table>
212
- </div>
213
- <!-- 分页 -->
214
- <div class="pagebox">
215
- <el-row>
216
- <el-col :span="24">
217
- <el-pagination
218
- v-if="paginations.pagetionShow && paginations.total > 0"
219
- :current-page.sync="paginations.page"
220
- :page-sizes="paginations.page_sizes || pageSizes"
221
- :page-size="paginations.limit"
222
- layout="total, sizes, prev, pager, next, jumper,slot"
223
- :total="paginations.total"
224
- @size-change="handleSizeChange"
225
- @current-change="handleindexChange"
226
- >
227
- <div
228
- v-if="paginations.refresh"
229
- :key="1"
230
- class="avatar-container right-menu-item hover-effect el-dropdown"
231
- style="margin-left: 10px"
232
- @click="refreshTableBTN"
233
- >
234
- <div class="avatar-wrapper">
235
- <div class="layui-table-tool-self">
236
- <i class="el-icon-refresh" />
237
- </div>
238
- </div>
239
- </div>
240
- </el-pagination>
241
- </el-col>
242
- </el-row>
243
- </div>
244
- <printTemplate v-show="false" class="printTemplate" :print-list-obj="printListObj" />
245
- </div>
246
- </template>
247
- <script>
248
- import { getData } from "../../index.js";
249
- import nodata from "./nodata.jpg";
250
- import printTemplate from "./printTable.vue";
251
- import TableColumn from "./TableColumn.vue";
252
- export default {
253
- name: "table",
254
- components: {
255
- printTemplate,
256
- TableColumn,
257
- // 函数式组件注册
258
- renderDom: {
259
- functional: true,
260
- props: {
261
- render: Function,
262
- },
263
- render(createElement, renDom) {
264
- return <div>{renDom.props.render()}</div>;
265
- },
266
- },
267
- // myTableColumn: {
268
- // functional: true,
269
- // props: {
270
- // column: { type: Object, required: true }
271
- // },
272
- // render(h, ctx) {
273
- // const col = ctx.props.column;
274
-
275
- // // 多级表头处理
276
- // if (col.children && col.children.length) {
277
- // return h(
278
- // 'el-table-column',
279
- // {
280
- // props: {
281
- // label: col.label,
282
- // align: 'center',
283
- // ...col.attrs,
284
- // }
285
- // },
286
- // col.children.map((child, idx) =>
287
- // h(ctx.parent.$options.components.myTableColumn, {
288
- // props: { column: child },
289
- // key: idx
290
- // })
291
- // )
292
- // );
293
- // }
294
-
295
- // // 单列表头处理
296
- // return h(
297
- // 'el-table-column',
298
- // {
299
- // props: {
300
- // label: col.label,
301
- // prop: col.prop,
302
- // minWidth: col.minWidth || '150px',
303
- // showOverflowTooltip: col.overHidden || true,
304
- // type: col.type || 'normal',
305
- // align: 'center',
306
- // width: col.width,
307
- // fixed: col.fixed || false,
308
- // sortable: col.sortable || false,
309
- // ...col.attrs
310
- // }
311
- // },
312
- // [
313
- // // 表头插槽 - 添加 el-tooltip
314
- // h('template', { slot: 'header' }, [
315
- // h('el-tooltip', {
316
- // props: {
317
- // content: `${col.label} ${col.prop}`,
318
- // placement: 'top'
319
- // }
320
- // }, [
321
- // h('span', col.label)
322
- // ])
323
- // ]),
324
- // // 内容插槽 - 支持自定义渲染
325
- // col.render ? h('template', { slot: 'default' }, {
326
- // render: (scope) => h(ctx.parent.$options.components.renderDom, {
327
- // props: { render: () => col.render(scope.row) }
328
- // })
329
- // }) : null,
330
- // // 插槽渲染
331
- // col.renderSlot ? h('template', { slot: 'default' }, {
332
- // render: (scope) => ctx.parent.$scopedSlots[col.prop] ?
333
- // ctx.parent.$scopedSlots[col.prop](scope) : null
334
- // }) : null
335
- // ].filter(Boolean)
336
- // );
337
- // }
338
- // }
339
- },
340
- model: {
341
- prop: "multipleSelection",
342
- event: "SelectionChange",
343
- },
344
- props: {
345
- url: {
346
- type: String,
347
- default: "",
348
- }, // 接口地址
349
- printListObj: {
350
- type: Object,
351
- default: () => {
352
- return {
353
- title: "",
354
- tableHeader: "",
355
- tableData: "",
356
- };
357
- },
358
- }, // 打印参数
359
- btnlist: Array,
360
- outTable: {
361
- type: Object,
362
- default: () => {
363
- return {
364
- tableProp: {},
365
- };
366
- },
367
- },
368
- // exportBut: {
369
- // type: Array,
370
- // default: [],
371
- // },
372
- // 表格传的形式
373
- tableData: {
374
- type: Object,
375
- default: () => {
376
- return {
377
- loading: false,
378
- options: {
379
- selection: null, // 多选框
380
- index: null, // 序号
381
- headTool: true, // 开启头部工具栏
382
- refreshBtn: true, // 开启表格头部刷新按钮
383
- downloadBtn: true, // 开启表格头部下载按钮
384
- }, // 序号和复选框
385
- rows: [], // 表数据
386
- columns: [], // 表头
387
- operates: [], // 表格里面的操作按钮
388
- // tableHeightDiff: 300,
389
- operatesAttrs: {},
390
- };
391
- },
392
- },
393
- tableDataShow: {
394
- type: Boolean,
395
- default: true,
396
- },
397
- pageSizes: {
398
- type: Array,
399
- default: () => {
400
- return [20, 30, 40, 60, 100, 200];
401
- },
402
- },
403
- paginations: {
404
- // 显示复选框,
405
- type: Object,
406
- default: () => {
407
- return {
408
- page: 1, // 当前位于那页面
409
- total: 0, // 总数
410
- limit: 30, // 一页显示多少条
411
- pagetionShow: true,
412
- };
413
- },
414
- },
415
- emptyImg: {
416
- // 显示复选框,
417
- type: Boolean,
418
- default: false,
419
- },
420
- tableEvents: Object,
421
- showBtnBox: {
422
- type: Boolean,
423
- default: true,
424
- },
425
- //获取swagger后的钩子,返回swagger结构数据。用于处理swagger数据
426
- swaggerColumnsProcessor: {
427
- type: Function,
428
- default: null,
429
- },
430
- // swagger与本地columns合并完成后的钩子,允许父组件二次处理columns,一般用于不影响顺序的属性修改。区别于直接column中添加
431
- mergedColumnsProcessor: {
432
- type: Function,
433
- default: null,
434
- },
435
- },
436
-
437
- data() {
438
- return {
439
- nodata,
440
- tableRef: this.tableData.tableRef || "tableRef", // ref
441
- toggleRowFlage: this.tableData.toggleRowFlage || false, // 点击行高亮select标识
442
- // screenWidth: 0,
443
- // tableHeight:
444
- // document.documentElement.clientHeight - this.tableData.tableHeightDiff,
445
- pagetionShow: this.paginations.pagetionShow || true,
446
- twinPage: 1,
447
- columnsWatcher: null,
448
- key: 0,
449
- };
450
- },
451
- computed: {
452
- bindTableColumns() {
453
- return this.tableData.columns.filter(column =>
454
- Object.keys(column).includes("show") ? column.show : true
455
- );
456
- },
457
-
458
- checkedTableList: {
459
- get() {
460
- // 返回选中的列名
461
- return this.getAllColumnsWithProp(this.tableData.columns);
462
- },
463
- },
464
- /* 这里使用了getter和setter,这样写的好处不用自己手动监听复选框的选中事件 */
465
- checkedTableColumns: {
466
- get() {
467
- // 返回选中的列名
468
- return this.getAllLabelsWithProp();
469
- },
470
- set(checked) {
471
- this.setColumnsShow(checked);
472
- this.$nextTick(() => {
473
- this.$refs.tableRef.doLayout();
474
- });
475
- },
476
- },
477
- },
478
- created() {
479
- // 通过swagger完善columns
480
- this.init();
481
- },
482
- // 组件销毁时清理监听器
483
- beforeDestroy() {
484
- this.stopColumnsWatching();
485
- },
486
- methods: {
487
- // init() {
488
- // // 从 IndexedDB 中获取 Swagger 数据
489
- // getData().then((swaggerData) => {
490
- // const swaggerColumns = swaggerData.paths[this.url].get.responses["200"].content['application/json'].schema.properties.items.items.properties;
491
-
492
- // Object.keys(swaggerColumns).forEach(key => {
493
- // const item = swaggerColumns[key];
494
- // let tempItem = this.tableData.columns.find((e) => e.prop == key);
495
- // if (tempItem) {
496
- // tempItem = { ...item, ...tempItem };
497
- // } else if (item.description) {
498
- // this.tableData.columns.push({
499
- // prop: key,
500
- // label: item.description,
501
- // show: true,
502
- // sortable: false,
503
- // attrs: {}
504
- // });
505
- // }
506
- // });
507
- // console.log(`\x1b[36m\x1b[4mol插件-表格`, this.tableData.columns)
508
- // }).catch((error) => {
509
- // console.error("获取 Swagger 数据失败:", error);
510
- // });
511
- // },
512
- // 支持多级表头 useSlotHeader: true,且支持排序,通过columns中的顺序实现
513
- // columns: [
514
- // {
515
- // label: '一级表头',
516
- // children: [{ prop: 'bindStateEnum', label: '112' }, { prop: 'tagNumber' }]
517
- // },
518
- // {
519
- // prop: "remark",
520
- // label: "备注123",
521
- // },
522
- // ],
523
- init() {
524
- // 从 IndexedDB 中获取 Swagger 数据
525
- getData()
526
- .then(async swaggerData => {
527
- let swaggerColumns =
528
- swaggerData.paths[this.url].get.responses["200"].content["application/json"].schema
529
- .properties.items.items.properties;
530
- if (typeof this.swaggerColumnsProcessor === "function") {
531
- try {
532
- const res = await this.swaggerColumnsProcessor({ swaggerColumns });
533
- swaggerColumns = res;
534
- } catch (err) {}
535
- }
536
- // 递归映射函数
537
- const mapSwaggerToColumns = columns => {
538
- columns.forEach(column => {
539
- if (column.children && column.children.length) {
540
- mapSwaggerToColumns(column.children);
541
- } else {
542
- if (column.prop && swaggerColumns[column.prop]) {
543
- const swaggerItem = swaggerColumns[column.prop];
544
- this.$set(column, "label", swaggerItem.description);
545
- if (!Object.keys(column).includes("show")) this.$set(column, "show", true);
546
- }
547
- }
548
- });
549
- };
550
- // 自定义columns数据
551
- mapSwaggerToColumns(this.tableData.columns);
552
-
553
- Object.keys(swaggerColumns).forEach(key => {
554
- const item = swaggerColumns[key];
555
- const existingColumn = this.findColumnByProp(this.tableData.columns, key);
556
- if (!existingColumn && item.description) {
557
- const obj = {
558
- prop: key,
559
- label: item.description,
560
- show: true,
561
- sortable: false,
562
- attrs: {},
563
- };
564
- // 如果是枚举值直接转成Desc结尾的,swagger中没有Desc但是后端接口会返回带Desc的字段,用于前端展示枚举值的中文
565
- if (item.enum && Array.isArray(item.enum)) {
566
- obj.prop = `${key}Desc`;
567
- obj.label = item.description.replace(/(枚举|枚举值)/g, "");
568
- }
569
- this.tableData.columns.push(obj);
570
- }
571
- });
572
- // 根据beforeProp排序
573
- this.sortColumns(this.tableData.columns);
574
-
575
- // 添加show, 最后添加show是为了后期swagger可能会增加show字段(扩展)
576
- // 递归根据当前是否有show键名,没有show就添加show:true
577
- const addShow = columns => {
578
- columns.forEach(column => {
579
- if (!column.hasOwnProperty("show")) this.$set(column, "show", true);
580
- if (column.children && column.children.length) {
581
- addShow(column.children);
582
- } else {
583
- if (!column.hasOwnProperty("show")) {
584
- // 用set修改
585
- this.$set(column, "show", true);
586
- }
587
- }
588
- });
589
- };
590
- // 添加show,这里的show只显示隐藏,通过checkbox能实现显示隐藏。如果不想checkbox中出现可添加hidden(这是区别于老框架的逻辑)
591
- addShow(this.tableData.columns);
592
- console.log(`\x1b[36m\x1b[4mol插件-表格`, this.tableData.columns);
593
-
594
- // 合并完成后,暴露处理钩子
595
- if (typeof this.mergedColumnsProcessor === "function") {
596
- try {
597
- await this.mergedColumnsProcessor({
598
- columns: this.tableData.columns,
599
- });
600
- } catch (e) {}
601
- }
602
-
603
- // init 执行完成后,添加深度监听
604
- this.startColumnsWatching();
605
- })
606
- .catch(error => {
607
- console.error("获取 Swagger 数据失败:", error);
608
- });
609
- },
610
- // 多级表头顺序调整,只争对有多级表头的且包含beforeProp字段的,规则:通过多级表头的beforeProp字段将整个多级表头移到这个字段位置之后。(只会一级出现beforeProp,多级中的排序都要手动实现)
611
- sortColumns(columns) {
612
- let index = 0;
613
- columns.forEach(column => {
614
- if (!column.beforeProp) {
615
- column.sort = index;
616
- index++;
617
- const tempItem = columns.find(e => e.beforeProp == column.prop);
618
- if (tempItem) {
619
- tempItem.sort = index;
620
- index++;
621
- }
622
- }
623
- });
624
- columns.sort((a, b) => a.sort - b.sort);
625
- },
626
- // 递归查找列配置的辅助方法
627
- findColumnByProp(columns, prop) {
628
- for (const column of columns) {
629
- if (column.children && column.children.length) {
630
- const found = this.findColumnByProp(column.children, prop);
631
- if (found) return found;
632
- } else if (column.prop === prop) {
633
- return column;
634
- }
635
- }
636
- return null;
637
- },
638
- radioChange() {
639
- this.$emit("radioChange", this.twinPage);
640
- },
641
- // 刷新表格
642
- refreshTable() {
643
- const view = this.$router.history.current;
644
- this.$store.dispatch("tagsView/delCachedView", view).then(() => {
645
- const { fullPath } = view;
646
- this.$nextTick(() => {
647
- this.$router.replace({
648
- path: "/redirect" + fullPath,
649
- });
650
- });
651
- });
652
- this.$emit("refreshTable");
653
- },
654
- printTable() {
655
- console.log("printTable");
656
- if (this.tableData.rows.length <= 0) return;
657
- this.printListObj.title = this.$router.history.current.name;
658
- this.printListObj.tableHeader = this.tableData.columns;
659
- this.printListObj.tableData = this.tableData.rows;
660
- console.log(this.printListObj);
661
- setTimeout(() => {
662
- $(".printTemplate").show();
663
- $(".printTemplate").jqprint();
664
- $(".printTemplate").hide();
665
- }, 50);
666
- this.$emit("printTable");
667
- },
668
- selectAll(val) {
669
- this.$emit("selectAll", val);
670
- },
671
- select(val, row) {
672
- this.$emit("selectTab", val, row);
673
- },
674
- refreshTableBTN() {
675
- this.$emit("refreshTableBTN");
676
- },
677
- rowClick(row, column) {
678
- if (column.label === "操作") return; // 操作列不处罚行点击事件
679
- this.$emit("rowClick", row);
680
- if (
681
- this.tableData.columns.every(item => {
682
- return item.label !== "是否只出样件";
683
- })
684
- ) {
685
- // 为true时 点击行高亮select
686
- this.$refs.tableRef.toggleRowSelection(row);
687
- }
688
- },
689
- computeTableIndex(index) {
690
- return (this.paginations.page - 1) * this.paginations.limit + index + 1;
691
- },
692
- // 挑选的数据
693
- SelectionChange(val) {
694
- this.multipleSelection = val;
695
- this.$emit("SelectionChange", val);
696
- },
697
- // 分页选择
698
- handleSizeChange(val) {
699
- this.paginations.limit = val;
700
- this.$emit("handleSizeChange", val);
701
- },
702
- handleindexChange(val) {
703
- this.paginations.page = val;
704
- this.$emit("handleindexChange", val);
705
- },
706
- getCheckboxList() {
707
- return this.tableData.column;
708
- },
709
- setCheckboxList(val) {},
710
-
711
- getAllColumnsWithProp(columns) {
712
- const result = [];
713
- const propMap = new Map(); // 使用Map存储prop -> column的映射
714
-
715
- const traverse = cols => {
716
- cols.forEach(column => {
717
- if (column.children && column.children.length) {
718
- // 如果有子列,递归处理子列
719
- traverse(column.children);
720
- } else if (column.prop) {
721
- // 如果包含prop属性且未重复,添加到结果数组
722
- if (!propMap.has(column.prop)) {
723
- propMap.set(column.prop, column);
724
- result.push(column);
725
- }
726
- }
727
- });
728
- };
729
-
730
- traverse(columns);
731
- return result;
732
- },
733
-
734
- // checkbox的显示隐藏
735
- getAllLabelsWithProp() {
736
- const result = [];
737
-
738
- const traverse = cols => {
739
- cols.forEach(column => {
740
- if (column.children && column.children.length) {
741
- // 如果有子列,递归处理子列
742
- traverse(column.children);
743
- } else if (column.prop && column.show) {
744
- // 如果包含prop属性且未重复,添加到结果数组
745
- if (!result.includes(column.prop) && column.show) {
746
- result.push(column.prop);
747
- }
748
- }
749
- });
750
- };
751
- traverse(this.tableData.columns);
752
- return result;
753
- },
754
- setColumnsShow(checkedList) {
755
- // 递归更新tableData.columns的show属性
756
- const traverse = cols => {
757
- cols.forEach(column => {
758
- if (column.children && column.children.length) {
759
- traverse(column.children);
760
- } else if (column.prop) {
761
- // 用set修改
762
- if (checkedList.includes(column.prop)) {
763
- this.$set(column, "show", true);
764
- } else {
765
- this.$set(column, "show", false);
766
- }
767
- }
768
- });
769
- };
770
- traverse(this.tableData.columns);
771
- },
772
-
773
- // 开启 columns 监听,(二级菜单是递归组件,数据变化dom没有发送变化,故监听直接更新dom)
774
- startColumnsWatching() {
775
- this.stopColumnsWatching();
776
- this.columnsWatcher = this.$watch("tableData.columns", () => (this.key += 1), {
777
- deep: true, // 深度监听
778
- immediate: false,
779
- });
780
- },
781
-
782
- // 停止 columns 监听
783
- stopColumnsWatching() {
784
- if (this.columnsWatcher) {
785
- this.columnsWatcher();
786
- this.columnsWatcher = null;
787
- }
788
- },
789
- },
790
- };
791
- </script>
792
-
793
- <style lang="scss" scoped>
794
- .table_list_fix {
795
- overflow: auto;
796
- flex: 1;
797
- display: flex;
798
- flex-direction: column;
799
- justify-content: space-between;
800
- padding: 10px;
801
- gap: 10px;
802
-
803
- ::v-deep .el-table {
804
- td {
805
- padding: 0px;
806
-
807
- div {
808
- line-height: 28px;
809
- font-size: 12px;
810
- }
811
- }
812
-
813
- th {
814
- padding: 0px;
815
- background: #f5f7fa;
816
- div {
817
- line-height: 28px;
818
- color: #909399;
819
- font-size: 12px;
820
- }
821
- }
822
- }
823
-
824
- .btn-operates {
825
- margin: 10px 0px 10px 15px;
826
-
827
- ::v-deep a {
828
- color: #fff;
829
- text-decoration: none;
830
- display: inline-block;
831
- margin: 0px 5px;
832
- ::v-deep .el-button {
833
- width: 100%;
834
- padding: 7px;
835
- font-size: 13px;
836
- }
837
- }
838
- }
839
- }
840
-
841
- .table-header {
842
- padding-top: 10px;
843
-
844
- .table-header_button {
845
- text-align: right;
846
- float: right;
847
- margin-bottom: 12px;
848
- line-height: 40px;
849
- }
850
- }
851
-
852
- .newjump {
853
- text-decoration: none;
854
- color: dodgerblue;
855
- }
856
-
857
- .tablebox {
858
- box-sizing: border-box;
859
- flex: 1;
860
- overflow: auto;
861
- }
862
-
863
- ::v-deep .el-table__body tr.current-row > td {
864
- background-color: rgb(24, 144, 255) !important;
865
- color: #fff;
866
- }
867
-
868
- ::v-deep .redrow {
869
- background: #fde6e6 !important;
870
- }
871
-
872
- .btnbox {
873
- width: 100%;
874
- display: flex;
875
- align-items: center;
876
- justify-content: space-between;
877
-
878
- .upload-demo {
879
- display: -webkit-inline-box;
880
- margin-left: 10px;
881
- }
882
-
883
- .el-form-item {
884
- margin-bottom: 0px;
885
- }
886
- }
887
-
888
- .layui-table-tool-self {
889
- display: block;
890
- width: 26px;
891
- height: 26px;
892
- padding: 5px;
893
- line-height: 16px;
894
- text-align: center;
895
- color: #333;
896
- border: 1px solid #ccc;
897
- cursor: pointer;
898
- }
899
-
900
- .checkbox {
901
- display: block;
902
- }
903
- // 操作列按钮布局
904
- .operate-group {
905
- display: flex;
906
- align-items: center;
907
- justify-content: space-around;
908
- }
909
- .toolbox {
910
- display: flex;
911
- gap: 10px;
912
- }
913
- </style>
914
-
1
+ <template>
2
+ <div class="table_list_fix">
3
+ <!-- 扩展性内容 -->
4
+ <slot name="content_context" />
5
+ <template
6
+ v-if="
7
+ btnlist.length ||
8
+ tableData.options.headTool ||
9
+ tableData.options.refreshBtn ||
10
+ tableData.options.downloadBtn
11
+ "
12
+ >
13
+ <div v-if="showBtnBox" class="btnbox">
14
+ <!-- 左侧按钮 -->
15
+ <div>
16
+ <el-button
17
+ v-for="(btn, index) in btnlist"
18
+ :key="index"
19
+ size="small"
20
+ :type="btn.types ? btn.types : 'primary'"
21
+ @click="btn.method"
22
+ >
23
+ <i v-if="btn.icon" :class="btn.icon" />
24
+ {{ btn.title }}
25
+ </el-button>
26
+ </div>
27
+ <!-- 右侧工具按钮 -->
28
+ <div class="toolbox">
29
+ <el-dropdown
30
+ v-if="tableData.options.headTool"
31
+ class="avatar-container right-menu-item hover-effect"
32
+ trigger="click"
33
+ >
34
+ <div class="avatar-wrapper">
35
+ <div class="layui-table-tool-self">
36
+ <i class="el-icon-s-operation" />
37
+ </div>
38
+ </div>
39
+ <el-dropdown-menu slot="dropdown" style="padding: 5px">
40
+ <el-checkbox-group v-model="checkedTableColumns">
41
+ <el-checkbox
42
+ v-for="column in checkedTableList"
43
+ :key="column.prop"
44
+ class="checkbox"
45
+ :label="column.prop"
46
+ >{{ column.label }}
47
+ </el-checkbox>
48
+ </el-checkbox-group>
49
+ </el-dropdown-menu>
50
+ </el-dropdown>
51
+ <div
52
+ v-if="tableData.options.refreshBtn"
53
+ class="avatar-container right-menu-item hover-effect el-dropdown"
54
+ @click="refreshTable"
55
+ >
56
+ <div class="avatar-wrapper">
57
+ <div class="layui-table-tool-self">
58
+ <i class="el-icon-refresh" />
59
+ </div>
60
+ </div>
61
+ </div>
62
+ <div
63
+ v-if="tableData.options.downloadBtn"
64
+ class="avatar-container right-menu-item hover-effect el-dropdown"
65
+ @click="printTable"
66
+ >
67
+ <div class="avatar-wrapper">
68
+ <div class="layui-table-tool-self">
69
+ <i class="el-icon-printer" />
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ </template>
76
+
77
+ <!-- 表格 -->
78
+ <div class="tablebox" :key="tableData.columns.length">
79
+ <el-table
80
+ :ref="tableRef"
81
+ v-loading="tableData.loading"
82
+ border
83
+ v-bind="tableData.options"
84
+ :data="tableData.rows"
85
+ style="width: 100%"
86
+ height="100%"
87
+ :default-sort="tableData.sort"
88
+ v-on="tableEvents"
89
+ @selection-change="SelectionChange"
90
+ @select="select"
91
+ @select-all="selectAll"
92
+ @row-click="rowClick"
93
+ >
94
+ <el-table-column
95
+ v-if="tableData.options && tableData.options.index"
96
+ width="60"
97
+ align="center"
98
+ type="index"
99
+ :index="computeTableIndex"
100
+ label="序号"
101
+ />
102
+ <el-table-column
103
+ v-if="tableData.options && tableData.options.selection"
104
+ width="60"
105
+ align="center"
106
+ type="selection"
107
+ label=""
108
+ />
109
+ <!-- 新增插槽,允许父组件自定义表头 -->
110
+ <!-- <template v-if="tableData.options && tableData.options.useSlotHeader">
111
+ <slot
112
+ name="table-columns"
113
+ :columns="bindTableColumns"
114
+ >
115
+ <template v-for="(item, index) in bindTableColumns">
116
+ <my-table-column
117
+ :column="item"
118
+ :key="index"
119
+ />
120
+ </template>
121
+ </slot>
122
+ </template> -->
123
+ <!-- 防止之前逻辑出现纰漏,故保留之前逻辑再扩展自定义插槽方式渲染 -->
124
+ <!-- <template v-else> -->
125
+ <!-- <template v-for="(item, index) in bindTableColumns">
126
+ <el-table-column
127
+ :key="index"
128
+ :label="item.label"
129
+ :prop="item.prop"
130
+ :min-width="item.minWidth || '150px'"
131
+ :show-overflow-tooltip="item.overHidden || true"
132
+ :type="item.type || 'normal'"
133
+ v-bind="{
134
+ align: 'center',
135
+ width: item.width,
136
+ fixed: item.fixed || false,
137
+ sortable: item.sortable || false,
138
+ ...item.attrs,
139
+ }"
140
+ >
141
+ <template v-slot:header>
142
+ <el-tooltip
143
+ :content="`${item.label} ${item.prop}`"
144
+ placement="top"
145
+ >
146
+ <span>{{ item.label }}</span>
147
+ </el-tooltip>
148
+ </template>
149
+ <template
150
+ v-if="item.render"
151
+ v-slot="scope"
152
+ >
153
+ <render-dom :render="() => item.render(scope.row)" />
154
+ </template>
155
+ <template
156
+ v-else-if="item.renderSlot"
157
+ v-slot="scope"
158
+ >
159
+ <slot
160
+ :row="scope.row"
161
+ :name="item.prop"
162
+ />
163
+ </template>
164
+ </el-table-column>
165
+ </template> -->
166
+ <!-- </template> -->
167
+
168
+ <template v-for="(item, index) in this.tableData.columns">
169
+ <TableColumn
170
+ :column="item"
171
+ :key="`${item.prop || item.label}-${item.show}-${index}`"
172
+ :id="`${item.prop}-${item.show}-${index}`"
173
+ >
174
+ <template v-for="(slotFn, name) in $scopedSlots" v-slot:[name]="slotProps">
175
+ <slot :name="name" v-bind="slotProps" />
176
+ </template>
177
+ </TableColumn>
178
+ </template>
179
+ <el-table-column
180
+ v-if="tableData.operates && tableData.operates.length > 0"
181
+ label="操作"
182
+ align="center"
183
+ v-bind="tableData.operatesAttrs"
184
+ >
185
+ <template slot-scope="scope">
186
+ <div class="operate-group">
187
+ <template v-for="(btn, key) in tableData.operates">
188
+ <span
189
+ v-if="!btn.isShow || (btn.isShow && btn.isShow(scope.row, scope.$index))"
190
+ :key="key"
191
+ >
192
+ <el-button
193
+ :style="btn.style || ''"
194
+ :size="btn.size || 'small'"
195
+ :type="btn.type || `text`"
196
+ :icon="btn.icon"
197
+ :plain="btn.plain"
198
+ :disabled="btn.disabled && btn.disabled(scope.row, scope.$index)"
199
+ @click.stop="btn.method(scope.row, scope.$index)"
200
+ >{{ btn.label
201
+ }}{{ tableData.operates.length >= 2 ? "&nbsp;&nbsp;" : "" }}</el-button
202
+ >
203
+ </span>
204
+ </template>
205
+ </div> </template
206
+
207
+ </el-table-column>
208
+ <div slot="empty" class="empty">
209
+ <img v-if="tableData.rows.length == 0" :src="nodata" />
210
+ </div>
211
+ </el-table>
212
+ </div>
213
+ <!-- 分页 -->
214
+ <div class="pagebox">
215
+ <el-row>
216
+ <el-col :span="24">
217
+ <el-pagination
218
+ v-if="paginations.pagetionShow && paginations.total > 0"
219
+ :current-page.sync="paginations.page"
220
+ :page-sizes="paginations.page_sizes || pageSizes"
221
+ :page-size="paginations.limit"
222
+ layout="total, sizes, prev, pager, next, jumper,slot"
223
+ :total="paginations.total"
224
+ @size-change="handleSizeChange"
225
+ @current-change="handleindexChange"
226
+ >
227
+ <div
228
+ v-if="paginations.refresh"
229
+ :key="1"
230
+ class="avatar-container right-menu-item hover-effect el-dropdown"
231
+ style="margin-left: 10px"
232
+ @click="refreshTableBTN"
233
+ >
234
+ <div class="avatar-wrapper">
235
+ <div class="layui-table-tool-self">
236
+ <i class="el-icon-refresh" />
237
+ </div>
238
+ </div>
239
+ </div>
240
+ </el-pagination>
241
+ </el-col>
242
+ </el-row>
243
+ </div>
244
+ <printTemplate v-show="false" class="printTemplate" :print-list-obj="printListObj" />
245
+ </div>
246
+ </template>
247
+ <script>
248
+ import { getData } from "../../index.js";
249
+ import nodata from "./nodata.jpg";
250
+ import printTemplate from "./printTable.vue";
251
+ import TableColumn from "./TableColumn.vue";
252
+ export default {
253
+ name: "table",
254
+ components: {
255
+ printTemplate,
256
+ TableColumn,
257
+ // 函数式组件注册
258
+ renderDom: {
259
+ functional: true,
260
+ props: {
261
+ render: Function,
262
+ },
263
+ render(createElement, renDom) {
264
+ return <div>{renDom.props.render()}</div>;
265
+ },
266
+ },
267
+ // myTableColumn: {
268
+ // functional: true,
269
+ // props: {
270
+ // column: { type: Object, required: true }
271
+ // },
272
+ // render(h, ctx) {
273
+ // const col = ctx.props.column;
274
+
275
+ // // 多级表头处理
276
+ // if (col.children && col.children.length) {
277
+ // return h(
278
+ // 'el-table-column',
279
+ // {
280
+ // props: {
281
+ // label: col.label,
282
+ // align: 'center',
283
+ // ...col.attrs,
284
+ // }
285
+ // },
286
+ // col.children.map((child, idx) =>
287
+ // h(ctx.parent.$options.components.myTableColumn, {
288
+ // props: { column: child },
289
+ // key: idx
290
+ // })
291
+ // )
292
+ // );
293
+ // }
294
+
295
+ // // 单列表头处理
296
+ // return h(
297
+ // 'el-table-column',
298
+ // {
299
+ // props: {
300
+ // label: col.label,
301
+ // prop: col.prop,
302
+ // minWidth: col.minWidth || '150px',
303
+ // showOverflowTooltip: col.overHidden || true,
304
+ // type: col.type || 'normal',
305
+ // align: 'center',
306
+ // width: col.width,
307
+ // fixed: col.fixed || false,
308
+ // sortable: col.sortable || false,
309
+ // ...col.attrs
310
+ // }
311
+ // },
312
+ // [
313
+ // // 表头插槽 - 添加 el-tooltip
314
+ // h('template', { slot: 'header' }, [
315
+ // h('el-tooltip', {
316
+ // props: {
317
+ // content: `${col.label} ${col.prop}`,
318
+ // placement: 'top'
319
+ // }
320
+ // }, [
321
+ // h('span', col.label)
322
+ // ])
323
+ // ]),
324
+ // // 内容插槽 - 支持自定义渲染
325
+ // col.render ? h('template', { slot: 'default' }, {
326
+ // render: (scope) => h(ctx.parent.$options.components.renderDom, {
327
+ // props: { render: () => col.render(scope.row) }
328
+ // })
329
+ // }) : null,
330
+ // // 插槽渲染
331
+ // col.renderSlot ? h('template', { slot: 'default' }, {
332
+ // render: (scope) => ctx.parent.$scopedSlots[col.prop] ?
333
+ // ctx.parent.$scopedSlots[col.prop](scope) : null
334
+ // }) : null
335
+ // ].filter(Boolean)
336
+ // );
337
+ // }
338
+ // }
339
+ },
340
+ model: {
341
+ prop: "multipleSelection",
342
+ event: "SelectionChange",
343
+ },
344
+ props: {
345
+ url: {
346
+ type: String,
347
+ default: "",
348
+ }, // 接口地址
349
+ printListObj: {
350
+ type: Object,
351
+ default: () => {
352
+ return {
353
+ title: "",
354
+ tableHeader: "",
355
+ tableData: "",
356
+ };
357
+ },
358
+ }, // 打印参数
359
+ btnlist: Array,
360
+ outTable: {
361
+ type: Object,
362
+ default: () => {
363
+ return {
364
+ tableProp: {},
365
+ };
366
+ },
367
+ },
368
+ // exportBut: {
369
+ // type: Array,
370
+ // default: [],
371
+ // },
372
+ // 表格传的形式
373
+ tableData: {
374
+ type: Object,
375
+ default: () => {
376
+ return {
377
+ loading: false,
378
+ options: {
379
+ selection: null, // 多选框
380
+ index: null, // 序号
381
+ headTool: true, // 开启头部工具栏
382
+ refreshBtn: true, // 开启表格头部刷新按钮
383
+ downloadBtn: true, // 开启表格头部下载按钮
384
+ }, // 序号和复选框
385
+ rows: [], // 表数据
386
+ columns: [], // 表头
387
+ operates: [], // 表格里面的操作按钮
388
+ // tableHeightDiff: 300,
389
+ operatesAttrs: {},
390
+ };
391
+ },
392
+ },
393
+ tableDataShow: {
394
+ type: Boolean,
395
+ default: true,
396
+ },
397
+ pageSizes: {
398
+ type: Array,
399
+ default: () => {
400
+ return [20, 30, 40, 60, 100, 200];
401
+ },
402
+ },
403
+ paginations: {
404
+ // 显示复选框,
405
+ type: Object,
406
+ default: () => {
407
+ return {
408
+ page: 1, // 当前位于那页面
409
+ total: 0, // 总数
410
+ limit: 30, // 一页显示多少条
411
+ pagetionShow: true,
412
+ };
413
+ },
414
+ },
415
+ emptyImg: {
416
+ // 显示复选框,
417
+ type: Boolean,
418
+ default: false,
419
+ },
420
+ tableEvents: Object,
421
+ showBtnBox: {
422
+ type: Boolean,
423
+ default: true,
424
+ },
425
+ //获取swagger后的钩子,返回swagger结构数据。用于处理swagger数据
426
+ swaggerColumnsProcessor: {
427
+ type: Function,
428
+ default: null,
429
+ },
430
+ // swagger与本地columns合并完成后的钩子,允许父组件二次处理columns,一般用于不影响顺序的属性修改。区别于直接column中添加
431
+ mergedColumnsProcessor: {
432
+ type: Function,
433
+ default: null,
434
+ },
435
+ },
436
+
437
+ data() {
438
+ return {
439
+ nodata,
440
+ tableRef: this.tableData.tableRef || "tableRef", // ref
441
+ toggleRowFlage: this.tableData.toggleRowFlage || false, // 点击行高亮select标识
442
+ // screenWidth: 0,
443
+ // tableHeight:
444
+ // document.documentElement.clientHeight - this.tableData.tableHeightDiff,
445
+ pagetionShow: this.paginations.pagetionShow || true,
446
+ twinPage: 1,
447
+ columnsWatcher: null,
448
+ key: 0,
449
+ };
450
+ },
451
+ computed: {
452
+ bindTableColumns() {
453
+ return this.tableData.columns.filter(column =>
454
+ Object.keys(column).includes("show") ? column.show : true
455
+ );
456
+ },
457
+
458
+ checkedTableList: {
459
+ get() {
460
+ // 返回选中的列名
461
+ return this.getAllColumnsWithProp(this.tableData.columns);
462
+ },
463
+ },
464
+ /* 这里使用了getter和setter,这样写的好处不用自己手动监听复选框的选中事件 */
465
+ checkedTableColumns: {
466
+ get() {
467
+ // 返回选中的列名
468
+ return this.getAllLabelsWithProp();
469
+ },
470
+ set(checked) {
471
+ this.setColumnsShow(checked);
472
+ this.$nextTick(() => {
473
+ this.$refs.tableRef.doLayout();
474
+ });
475
+ },
476
+ },
477
+ },
478
+ created() {
479
+ // 通过swagger完善columns
480
+ this.init();
481
+ },
482
+ // 组件销毁时清理监听器
483
+ beforeDestroy() {
484
+ this.stopColumnsWatching();
485
+ },
486
+ methods: {
487
+ // init() {
488
+ // // 从 IndexedDB 中获取 Swagger 数据
489
+ // getData().then((swaggerData) => {
490
+ // const swaggerColumns = swaggerData.paths[this.url].get.responses["200"].content['application/json'].schema.properties.items.items.properties;
491
+
492
+ // Object.keys(swaggerColumns).forEach(key => {
493
+ // const item = swaggerColumns[key];
494
+ // let tempItem = this.tableData.columns.find((e) => e.prop == key);
495
+ // if (tempItem) {
496
+ // tempItem = { ...item, ...tempItem };
497
+ // } else if (item.description) {
498
+ // this.tableData.columns.push({
499
+ // prop: key,
500
+ // label: item.description,
501
+ // show: true,
502
+ // sortable: false,
503
+ // attrs: {}
504
+ // });
505
+ // }
506
+ // });
507
+ // console.log(`\x1b[36m\x1b[4mol插件-表格`, this.tableData.columns)
508
+ // }).catch((error) => {
509
+ // console.error("获取 Swagger 数据失败:", error);
510
+ // });
511
+ // },
512
+ // 支持多级表头 useSlotHeader: true,且支持排序,通过columns中的顺序实现
513
+ // columns: [
514
+ // {
515
+ // label: '一级表头',
516
+ // children: [{ prop: 'bindStateEnum', label: '112' }, { prop: 'tagNumber' }]
517
+ // },
518
+ // {
519
+ // prop: "remark",
520
+ // label: "备注123",
521
+ // },
522
+ // ],
523
+ init() {
524
+ // 从 IndexedDB 中获取 Swagger 数据
525
+ getData()
526
+ .then(async swaggerData => {
527
+ let swaggerColumns =
528
+ swaggerData.paths[this.url].get.responses["200"].content["application/json"].schema
529
+ .properties.items.items.properties;
530
+ if (typeof this.swaggerColumnsProcessor === "function") {
531
+ try {
532
+ const res = await this.swaggerColumnsProcessor({ swaggerColumns });
533
+ swaggerColumns = res;
534
+ } catch (err) {}
535
+ }
536
+ // 递归映射函数
537
+ const mapSwaggerToColumns = columns => {
538
+ columns.forEach(column => {
539
+ if (column.children && column.children.length) {
540
+ mapSwaggerToColumns(column.children);
541
+ } else {
542
+ if (column.prop && swaggerColumns[column.prop]) {
543
+ const swaggerItem = swaggerColumns[column.prop];
544
+ this.$set(column, "label", swaggerItem.description);
545
+ if (!Object.keys(column).includes("show")) this.$set(column, "show", true);
546
+ }
547
+ }
548
+ });
549
+ };
550
+ // 自定义columns数据
551
+ mapSwaggerToColumns(this.tableData.columns);
552
+
553
+ Object.keys(swaggerColumns).forEach(key => {
554
+ const item = swaggerColumns[key];
555
+ const existingColumn = this.findColumnByProp(this.tableData.columns, key);
556
+ if (!existingColumn && item.description) {
557
+ const obj = {
558
+ prop: key,
559
+ label: item.description,
560
+ show: true,
561
+ sortable: false,
562
+ attrs: {},
563
+ };
564
+ // 如果是枚举值直接转成Desc结尾的,swagger中没有Desc但是后端接口会返回带Desc的字段,用于前端展示枚举值的中文
565
+ if (item.enum && Array.isArray(item.enum)) {
566
+ obj.prop = `${key}Desc`;
567
+ obj.label = item.description.replace(/(枚举|枚举值)/g, "");
568
+ }
569
+ this.tableData.columns.push(obj);
570
+ }
571
+ });
572
+ // 根据beforeProp排序
573
+ this.sortColumns(this.tableData.columns);
574
+
575
+ // 添加show, 最后添加show是为了后期swagger可能会增加show字段(扩展)
576
+ // 递归根据当前是否有show键名,没有show就添加show:true
577
+ const addShow = columns => {
578
+ columns.forEach(column => {
579
+ if (!column.hasOwnProperty("show")) this.$set(column, "show", true);
580
+ if (column.children && column.children.length) {
581
+ addShow(column.children);
582
+ } else {
583
+ if (!column.hasOwnProperty("show")) {
584
+ // 用set修改
585
+ this.$set(column, "show", true);
586
+ }
587
+ }
588
+ });
589
+ };
590
+ // 添加show,这里的show只显示隐藏,通过checkbox能实现显示隐藏。如果不想checkbox中出现可添加hidden(这是区别于老框架的逻辑)
591
+ addShow(this.tableData.columns);
592
+ console.log(`\x1b[36m\x1b[4mol插件-表格`, this.tableData.columns);
593
+
594
+ // 合并完成后,暴露处理钩子
595
+ if (typeof this.mergedColumnsProcessor === "function") {
596
+ try {
597
+ await this.mergedColumnsProcessor({
598
+ columns: this.tableData.columns,
599
+ });
600
+ } catch (e) {}
601
+ }
602
+
603
+ // init 执行完成后,添加深度监听
604
+ this.startColumnsWatching();
605
+ })
606
+ .catch(error => {
607
+ console.error("获取 Swagger 数据失败:", error);
608
+ });
609
+ },
610
+ // 多级表头顺序调整,只争对有多级表头的且包含beforeProp字段的,规则:通过多级表头的beforeProp字段将整个多级表头移到这个字段位置之后。(只会一级出现beforeProp,多级中的排序都要手动实现)
611
+ sortColumns(columns) {
612
+ let index = 0;
613
+ columns.forEach(column => {
614
+ if (!column.beforeProp) {
615
+ column.sort = index;
616
+ index++;
617
+ const tempItem = columns.find(e => e.beforeProp == column.prop);
618
+ if (tempItem) {
619
+ tempItem.sort = index;
620
+ index++;
621
+ }
622
+ }
623
+ });
624
+ columns.sort((a, b) => a.sort - b.sort);
625
+ },
626
+ // 递归查找列配置的辅助方法
627
+ findColumnByProp(columns, prop) {
628
+ for (const column of columns) {
629
+ if (column.children && column.children.length) {
630
+ const found = this.findColumnByProp(column.children, prop);
631
+ if (found) return found;
632
+ } else if (column.prop === prop) {
633
+ return column;
634
+ }
635
+ }
636
+ return null;
637
+ },
638
+ radioChange() {
639
+ this.$emit("radioChange", this.twinPage);
640
+ },
641
+ // 刷新表格
642
+ refreshTable() {
643
+ const view = this.$router.history.current;
644
+ this.$store.dispatch("tagsView/delCachedView", view).then(() => {
645
+ const { fullPath } = view;
646
+ this.$nextTick(() => {
647
+ this.$router.replace({
648
+ path: "/redirect" + fullPath,
649
+ });
650
+ });
651
+ });
652
+ this.$emit("refreshTable");
653
+ },
654
+ printTable() {
655
+ console.log("printTable");
656
+ if (this.tableData.rows.length <= 0) return;
657
+ this.printListObj.title = this.$router.history.current.name;
658
+ this.printListObj.tableHeader = this.tableData.columns;
659
+ this.printListObj.tableData = this.tableData.rows;
660
+ console.log(this.printListObj);
661
+ setTimeout(() => {
662
+ $(".printTemplate").show();
663
+ $(".printTemplate").jqprint();
664
+ $(".printTemplate").hide();
665
+ }, 50);
666
+ this.$emit("printTable");
667
+ },
668
+ selectAll(val) {
669
+ this.$emit("selectAll", val);
670
+ },
671
+ select(val, row) {
672
+ this.$emit("selectTab", val, row);
673
+ },
674
+ refreshTableBTN() {
675
+ this.$emit("refreshTableBTN");
676
+ },
677
+ rowClick(row, column) {
678
+ if (column.label === "操作") return; // 操作列不处罚行点击事件
679
+ this.$emit("rowClick", row);
680
+ if (
681
+ this.tableData.columns.every(item => {
682
+ return item.label !== "是否只出样件";
683
+ })
684
+ ) {
685
+ // 为true时 点击行高亮select
686
+ this.$refs.tableRef.toggleRowSelection(row);
687
+ }
688
+ },
689
+ computeTableIndex(index) {
690
+ return (this.paginations.page - 1) * this.paginations.limit + index + 1;
691
+ },
692
+ // 挑选的数据
693
+ SelectionChange(val) {
694
+ this.multipleSelection = val;
695
+ this.$emit("SelectionChange", val);
696
+ },
697
+ // 分页选择
698
+ handleSizeChange(val) {
699
+ this.paginations.limit = val;
700
+ this.$emit("handleSizeChange", val);
701
+ },
702
+ handleindexChange(val) {
703
+ this.paginations.page = val;
704
+ this.$emit("handleindexChange", val);
705
+ },
706
+ getCheckboxList() {
707
+ return this.tableData.column;
708
+ },
709
+ setCheckboxList(val) {},
710
+
711
+ getAllColumnsWithProp(columns) {
712
+ const result = [];
713
+ const propMap = new Map(); // 使用Map存储prop -> column的映射
714
+
715
+ const traverse = cols => {
716
+ cols.forEach(column => {
717
+ if (column.children && column.children.length) {
718
+ // 如果有子列,递归处理子列
719
+ traverse(column.children);
720
+ } else if (column.prop) {
721
+ // 如果包含prop属性且未重复,添加到结果数组
722
+ if (!propMap.has(column.prop)) {
723
+ propMap.set(column.prop, column);
724
+ result.push(column);
725
+ }
726
+ }
727
+ });
728
+ };
729
+
730
+ traverse(columns);
731
+ return result;
732
+ },
733
+
734
+ // checkbox的显示隐藏
735
+ getAllLabelsWithProp() {
736
+ const result = [];
737
+
738
+ const traverse = cols => {
739
+ cols.forEach(column => {
740
+ if (column.children && column.children.length) {
741
+ // 如果有子列,递归处理子列
742
+ traverse(column.children);
743
+ } else if (column.prop && column.show) {
744
+ // 如果包含prop属性且未重复,添加到结果数组
745
+ if (!result.includes(column.prop) && column.show) {
746
+ result.push(column.prop);
747
+ }
748
+ }
749
+ });
750
+ };
751
+ traverse(this.tableData.columns);
752
+ return result;
753
+ },
754
+ setColumnsShow(checkedList) {
755
+ // 递归更新tableData.columns的show属性
756
+ const traverse = cols => {
757
+ cols.forEach(column => {
758
+ if (column.children && column.children.length) {
759
+ traverse(column.children);
760
+ } else if (column.prop) {
761
+ // 用set修改
762
+ if (checkedList.includes(column.prop)) {
763
+ this.$set(column, "show", true);
764
+ } else {
765
+ this.$set(column, "show", false);
766
+ }
767
+ }
768
+ });
769
+ };
770
+ traverse(this.tableData.columns);
771
+ },
772
+
773
+ // 开启 columns 监听,(二级菜单是递归组件,数据变化dom没有发送变化,故监听直接更新dom)
774
+ startColumnsWatching() {
775
+ this.stopColumnsWatching();
776
+ this.columnsWatcher = this.$watch("tableData.columns", () => (this.key += 1), {
777
+ deep: true, // 深度监听
778
+ immediate: false,
779
+ });
780
+ },
781
+
782
+ // 停止 columns 监听
783
+ stopColumnsWatching() {
784
+ if (this.columnsWatcher) {
785
+ this.columnsWatcher();
786
+ this.columnsWatcher = null;
787
+ }
788
+ },
789
+ },
790
+ };
791
+ </script>
792
+
793
+ <style lang="scss" scoped>
794
+ .table_list_fix {
795
+ overflow: auto;
796
+ flex: 1;
797
+ display: flex;
798
+ flex-direction: column;
799
+ justify-content: space-between;
800
+ padding: 10px;
801
+ gap: 10px;
802
+
803
+ ::v-deep .el-table {
804
+ td {
805
+ padding: 0px;
806
+
807
+ div {
808
+ line-height: 28px;
809
+ font-size: 12px;
810
+ }
811
+ }
812
+
813
+ th {
814
+ padding: 0px;
815
+ background: #f5f7fa;
816
+ div {
817
+ line-height: 28px;
818
+ color: #909399;
819
+ font-size: 12px;
820
+ }
821
+ }
822
+ }
823
+
824
+ .btn-operates {
825
+ margin: 10px 0px 10px 15px;
826
+
827
+ ::v-deep a {
828
+ color: #fff;
829
+ text-decoration: none;
830
+ display: inline-block;
831
+ margin: 0px 5px;
832
+ ::v-deep .el-button {
833
+ width: 100%;
834
+ padding: 7px;
835
+ font-size: 13px;
836
+ }
837
+ }
838
+ }
839
+ }
840
+
841
+ .table-header {
842
+ padding-top: 10px;
843
+
844
+ .table-header_button {
845
+ text-align: right;
846
+ float: right;
847
+ margin-bottom: 12px;
848
+ line-height: 40px;
849
+ }
850
+ }
851
+
852
+ .newjump {
853
+ text-decoration: none;
854
+ color: dodgerblue;
855
+ }
856
+
857
+ .tablebox {
858
+ box-sizing: border-box;
859
+ flex: 1;
860
+ overflow: auto;
861
+ }
862
+
863
+ ::v-deep .el-table__body tr.current-row > td {
864
+ background-color: rgb(24, 144, 255) !important;
865
+ color: #fff;
866
+ }
867
+
868
+ ::v-deep .redrow {
869
+ background: #fde6e6 !important;
870
+ }
871
+
872
+ .btnbox {
873
+ width: 100%;
874
+ display: flex;
875
+ align-items: center;
876
+ justify-content: space-between;
877
+
878
+ .upload-demo {
879
+ display: -webkit-inline-box;
880
+ margin-left: 10px;
881
+ }
882
+
883
+ .el-form-item {
884
+ margin-bottom: 0px;
885
+ }
886
+ }
887
+
888
+ .layui-table-tool-self {
889
+ display: block;
890
+ width: 26px;
891
+ height: 26px;
892
+ padding: 5px;
893
+ line-height: 16px;
894
+ text-align: center;
895
+ color: #333;
896
+ border: 1px solid #ccc;
897
+ cursor: pointer;
898
+ }
899
+
900
+ .checkbox {
901
+ display: block;
902
+ }
903
+ // 操作列按钮布局
904
+ .operate-group {
905
+ display: flex;
906
+ align-items: center;
907
+ justify-content: space-around;
908
+ }
909
+ .toolbox {
910
+ display: flex;
911
+ gap: 10px;
912
+ }
913
+ </style>