uview-plus 3.4.77 → 3.4.79
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.
- package/changelog.md +6 -0
- package/components/u-table2/u-table2.vue +364 -225
- package/package.json +1 -1
package/changelog.md
CHANGED
|
@@ -1,99 +1,159 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<view
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<view class="u-table-
|
|
6
|
-
<view
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
col.align ? 'u-text-' + col.align : '',
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
col
|
|
13
|
-
|
|
14
|
-
<slot name="header" :column="col" :columnIndex="colIndex" :level="1">
|
|
15
|
-
</slot>
|
|
16
|
-
<text v-if="!$slots['header']">{{ col.title }}</text>
|
|
17
|
-
<template v-if="col.sortable">
|
|
18
|
-
<slot name="headerSort" :sortStatus="getSortValue(col.key)" :column="col"
|
|
19
|
-
:columnIndex="colIndex" :level="1">
|
|
2
|
+
<view class="u-table2">
|
|
3
|
+
<scroll-view scroll-x class="u-table2-content" :style="{ height: height ? height + 'px' : 'auto' }" @scroll="onScroll">
|
|
4
|
+
<!-- 表头 -->
|
|
5
|
+
<view v-if="showHeader" class="u-table-header" :class="{ 'u-table-sticky': fixedHeader }" :style="{minWidth: scrollWidth}">
|
|
6
|
+
<view class="u-table-row">
|
|
7
|
+
<view v-for="(col, colIndex) in columns" :key="col.key" class="u-table-cell"
|
|
8
|
+
:style="headerColStyle(col)"
|
|
9
|
+
:class="[col.align ? 'u-text-' + col.align : '',
|
|
10
|
+
headerCellClassName ? headerCellClassName(col) : '',
|
|
11
|
+
getFixedClass(col)
|
|
12
|
+
]" @click="handleHeaderClick(col)">
|
|
13
|
+
<slot name="header" :column="col" :columnIndex="colIndex" :level="1">
|
|
20
14
|
</slot>
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
<text v-if="!$slots['header']">{{ col.title }}</text>
|
|
16
|
+
<template v-if="col.sortable">
|
|
17
|
+
<slot name="headerSort" :sortStatus="getSortValue(col.key)" :column="col"
|
|
18
|
+
:columnIndex="colIndex" :level="1">
|
|
19
|
+
</slot>
|
|
20
|
+
<view v-if="!$slots['headerSort']">
|
|
21
|
+
{{ getSortIcon(col.key) }}
|
|
22
|
+
</view>
|
|
23
|
+
</template>
|
|
24
|
+
</view>
|
|
25
25
|
</view>
|
|
26
26
|
</view>
|
|
27
|
-
</view>
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
28
|
+
<!-- 表体 -->
|
|
29
|
+
<view class="u-table-body" :style="{ minWidth: scrollWidth, maxHeight: maxHeight ? maxHeight + 'px' : 'none' }">
|
|
30
|
+
<template v-if="data && data.length > 0">
|
|
31
|
+
<template v-for="(row, index) in sortedData" :key="row[rowKey] || index">
|
|
32
|
+
<view class="u-table-row" :class="[highlightCurrentRow && currentRow === row ? 'u-table-row-highlight' : '',
|
|
33
|
+
rowClassName ? rowClassName(row, index) : '',
|
|
34
|
+
stripe && index % 2 === 1 ? 'u-table-row-zebra' : ''
|
|
35
|
+
]" @click="handleRowClick(row)">
|
|
36
|
+
<view v-for="(col, colIndex) in columns" :key="col.key"
|
|
37
|
+
class="u-table-cell" :class="[col.align ? 'u-text-' + col.align : '',
|
|
38
|
+
cellClassName ? cellClassName(row, col) : '',
|
|
39
|
+
getFixedClass(col)
|
|
40
|
+
]" :style="cellStyleInner({row: row, column: col,
|
|
41
|
+
rowIndex: index, columnIndex: colIndex, level: 0})">
|
|
42
|
+
<!-- 复选框列 -->
|
|
43
|
+
<view v-if="col.type === 'selection'">
|
|
44
|
+
<checkbox :checked="isSelected(row)"
|
|
45
|
+
@click.stop="toggleSelect(row)" />
|
|
46
|
+
</view>
|
|
47
|
+
|
|
48
|
+
<!-- 树形结构展开图标 -->
|
|
49
|
+
<view v-else-if="col.type === 'expand'" @click.stop="toggleExpand(row)">
|
|
50
|
+
{{ isExpanded(row) ? '▼' : '▶' }}
|
|
51
|
+
</view>
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
<!-- 默认插槽或文本 -->
|
|
54
|
+
<slot name="cell" :row="row" :column="col"
|
|
55
|
+
:rowIndex="index" :columnIndex="colIndex">
|
|
56
|
+
<view class="u-table-cell_content">
|
|
57
|
+
{{ row[col.key] }}
|
|
58
|
+
</view>
|
|
59
|
+
</slot>
|
|
56
60
|
</view>
|
|
61
|
+
</view>
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
<!-- 子级渲染 -->
|
|
64
|
+
<template v-if="isExpanded(row) && row[treeProps.children] && row[treeProps.children].length">
|
|
65
|
+
<view v-for="childRow in row[treeProps.children]" :key="childRow[rowKey]"
|
|
66
|
+
class="u-table-row u-table-row-child">
|
|
67
|
+
<view v-for="(col2, col2Index) in columns" :key="col2.key" class="u-table-cell"
|
|
68
|
+
:style="cellStyleInner({row: childRow, column: col2,
|
|
69
|
+
rowIndex: index, columnIndex: col2Index, level: 1})">
|
|
70
|
+
<slot name="cell" :row="childRow" :column="col2" :prow="row"
|
|
71
|
+
:rowIndex="index" :columnIndex="col2Index" :level="1">
|
|
72
|
+
<view class="u-table-cell_content">
|
|
73
|
+
{{ childRow[col2.key] }}
|
|
74
|
+
</view>
|
|
75
|
+
</slot>
|
|
63
76
|
</view>
|
|
77
|
+
</view>
|
|
78
|
+
</template>
|
|
79
|
+
</template>
|
|
80
|
+
</template>
|
|
81
|
+
<template v-else>
|
|
82
|
+
<slot name="empty">
|
|
83
|
+
</slot>
|
|
84
|
+
<view v-if="!$slots['empty']" class="u-table-empty">{{ emptyText }}</view>
|
|
85
|
+
</template>
|
|
86
|
+
</view>
|
|
87
|
+
</scroll-view>
|
|
88
|
+
|
|
89
|
+
<!-- 固定列浮动视图 -->
|
|
90
|
+
<view v-if="showFixedColumnShadow" class="u-table-fixed-shadow" :style="{ height: tableHeight }">
|
|
91
|
+
<!-- 表头 -->
|
|
92
|
+
<view v-if="showHeader" class="u-table-header" :class="{ 'u-table-sticky': fixedHeader }" :style="{minWidth: scrollWidth}">
|
|
93
|
+
<view class="u-table-row">
|
|
94
|
+
<view v-for="(col, colIndex) in visibleFixedLeftColumns" :key="col.key" class="u-table-cell"
|
|
95
|
+
:style="headerColStyle(col)"
|
|
96
|
+
:class="[col.align ? 'u-text-' + col.align : '',
|
|
97
|
+
headerCellClassName ? headerCellClassName(col) : '',
|
|
98
|
+
getFixedClass(col)
|
|
99
|
+
]" @click="handleHeaderClick(col)">
|
|
100
|
+
<slot name="header" :column="col" :columnIndex="colIndex" :level="1">
|
|
101
|
+
</slot>
|
|
102
|
+
<text v-if="!$slots['header']">{{ col.title }}</text>
|
|
103
|
+
<template v-if="col.sortable">
|
|
104
|
+
<slot name="headerSort" :sortStatus="getSortValue(col.key)" :column="col"
|
|
105
|
+
:columnIndex="colIndex" :level="1">
|
|
64
106
|
</slot>
|
|
65
|
-
|
|
107
|
+
<view v-if="!$slots['headerSort']">
|
|
108
|
+
{{ getSortIcon(col.key) }}
|
|
109
|
+
</view>
|
|
110
|
+
</template>
|
|
66
111
|
</view>
|
|
112
|
+
</view>
|
|
113
|
+
</view>
|
|
67
114
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
115
|
+
<!-- 表体 -->
|
|
116
|
+
<view class="u-table-body" :style="{ minWidth: scrollWidth, maxHeight: maxHeight ? maxHeight + 'px' : 'none' }">
|
|
117
|
+
<template v-if="data && data.length > 0">
|
|
118
|
+
<template v-for="(row, index) in sortedData" :key="row[rowKey] || index">
|
|
119
|
+
<view class="u-table-row" :class="[highlightCurrentRow && currentRow === row ? 'u-table-row-highlight' : '',
|
|
120
|
+
rowClassName ? rowClassName(row, index) : '',
|
|
121
|
+
stripe && index % 2 === 1 ? 'u-table-row-zebra' : ''
|
|
122
|
+
]" @click="handleRowClick(row)">
|
|
123
|
+
<view v-for="(col, colIndex) in visibleFixedLeftColumns" :key="col.key"
|
|
124
|
+
class="u-table-cell" :class="[col.align ? 'u-text-' + col.align : '',
|
|
125
|
+
cellClassName ? cellClassName(row, col) : '',
|
|
126
|
+
getFixedClass(col)
|
|
127
|
+
]" :style="cellStyleInner({row: row, column: col,
|
|
128
|
+
rowIndex: index, columnIndex: colIndex, level: 0})">
|
|
129
|
+
<!-- 复选框列 -->
|
|
130
|
+
<view v-if="col.type === 'selection'">
|
|
131
|
+
<checkbox :checked="isSelected(row)"
|
|
132
|
+
@click.stop="toggleSelect(row)" />
|
|
133
|
+
</view>
|
|
134
|
+
|
|
135
|
+
<!-- 树形结构展开图标 -->
|
|
136
|
+
<view v-else-if="col.type === 'expand'" @click.stop="toggleExpand(row)">
|
|
137
|
+
{{ isExpanded(row) ? '▼' : '▶' }}
|
|
138
|
+
</view>
|
|
139
|
+
|
|
140
|
+
<!-- 默认插槽或文本 -->
|
|
141
|
+
<slot name="cell" :row="row" :column="col"
|
|
142
|
+
:rowIndex="index" :columnIndex="colIndex">
|
|
77
143
|
<view class="u-table-cell_content">
|
|
78
|
-
{{
|
|
144
|
+
{{ row[col.key] }}
|
|
79
145
|
</view>
|
|
80
146
|
</slot>
|
|
81
147
|
</view>
|
|
82
148
|
</view>
|
|
83
149
|
</template>
|
|
84
150
|
</template>
|
|
85
|
-
</
|
|
86
|
-
<template v-else>
|
|
87
|
-
<slot name="empty">
|
|
88
|
-
</slot>
|
|
89
|
-
<view v-if="!$slots['empty']" class="u-table-empty">{{ emptyText }}</view>
|
|
90
|
-
</template>
|
|
151
|
+
</view>
|
|
91
152
|
</view>
|
|
92
153
|
</view>
|
|
93
154
|
</template>
|
|
94
155
|
|
|
95
156
|
<script>
|
|
96
|
-
import { ref, watch, computed } from 'vue'
|
|
97
157
|
import { addUnit, sleep } from '../../libs/function/index';
|
|
98
158
|
|
|
99
159
|
export default {
|
|
@@ -241,26 +301,155 @@ export default {
|
|
|
241
301
|
],
|
|
242
302
|
data() {
|
|
243
303
|
return {
|
|
244
|
-
scrollWidth: 'auto'
|
|
304
|
+
scrollWidth: 'auto',
|
|
305
|
+
// 将setup中的ref转换为data属性
|
|
306
|
+
expandedKeys: [...this.expandRowKeys],
|
|
307
|
+
selectedRows: [],
|
|
308
|
+
sortConditions: [],
|
|
309
|
+
currentRow: null,
|
|
310
|
+
scrollLeft: 0, // 新增滚动位置数据
|
|
311
|
+
showFixedColumnShadow: false, // 是否显示固定列阴影
|
|
312
|
+
fixedLeftColumns: [], // 左侧固定列
|
|
313
|
+
tableHeight: 'auto', // 表格高度
|
|
314
|
+
rowHeight: 40 // 行高
|
|
245
315
|
}
|
|
246
316
|
},
|
|
247
317
|
mounted() {
|
|
248
318
|
this.getComponentWidth()
|
|
319
|
+
// 处理currentRowKey初始化
|
|
320
|
+
if (this.currentRowKey !== null) {
|
|
321
|
+
const found = this.data.find(item => item[this.rowKey] === this.currentRowKey);
|
|
322
|
+
if (found) {
|
|
323
|
+
this.currentRow = found;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// 获取固定列
|
|
327
|
+
this.fixedLeftColumns = this.columns.filter(col => col.fixed === 'left');
|
|
328
|
+
},
|
|
329
|
+
computed: {
|
|
330
|
+
// 将setup中的computed转换为computed属性
|
|
331
|
+
filteredData() {
|
|
332
|
+
return this.data.filter(row => {
|
|
333
|
+
return Object.keys(this.filters).every(key => {
|
|
334
|
+
const filter = this.filters[key];
|
|
335
|
+
if (!filter) return true;
|
|
336
|
+
return row[key]?.toString().includes(filter.toString());
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
},
|
|
340
|
+
sortedData() {
|
|
341
|
+
if (!this.sortConditions.length) return this.filteredData;
|
|
342
|
+
|
|
343
|
+
const data = [...this.filteredData];
|
|
344
|
+
|
|
345
|
+
return data.sort((a, b) => {
|
|
346
|
+
for (const condition of this.sortConditions) {
|
|
347
|
+
const { field, order } = condition;
|
|
348
|
+
let valA = a[field];
|
|
349
|
+
let valB = b[field];
|
|
350
|
+
|
|
351
|
+
if (this.sortMethod) {
|
|
352
|
+
const result = this.sortMethod(a, b, field);
|
|
353
|
+
if (result !== 0) return result * (order === 'ascending' ? 1 : -1);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (valA < valB) return order === 'ascending' ? -1 : 1;
|
|
357
|
+
if (valA > valB) return order === 'ascending' ? 1 : -1;
|
|
358
|
+
}
|
|
359
|
+
return 0;
|
|
360
|
+
});
|
|
361
|
+
},
|
|
362
|
+
// 计算当前应该显示的固定左侧列
|
|
363
|
+
visibleFixedLeftColumns() {
|
|
364
|
+
if (this.scrollLeft <= 0) {
|
|
365
|
+
return [];
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
let totalWidth = 0;
|
|
369
|
+
let fixedWidth = 0;
|
|
370
|
+
const visibleColumns = [];
|
|
371
|
+
|
|
372
|
+
// 遍历所有列,不仅仅是固定列
|
|
373
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
374
|
+
const col = this.columns[i];
|
|
375
|
+
const colWidth = col.width ? parseInt(col.width) : 100; // 默认宽度100px
|
|
376
|
+
|
|
377
|
+
// 如果是固定列且滚动位置足够显示该列
|
|
378
|
+
if (col.fixed === 'left' && this.scrollLeft > totalWidth - fixedWidth) {
|
|
379
|
+
visibleColumns.push(col);
|
|
380
|
+
fixedWidth += colWidth;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
totalWidth += colWidth;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return visibleColumns;
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
watch: {
|
|
390
|
+
// 将setup中的watch转换为watch属性
|
|
391
|
+
expandRowKeys: {
|
|
392
|
+
handler(newVal) {
|
|
393
|
+
this.expandedKeys = [...newVal];
|
|
394
|
+
},
|
|
395
|
+
immediate: true
|
|
396
|
+
},
|
|
397
|
+
currentRowKey: {
|
|
398
|
+
handler(newVal) {
|
|
399
|
+
const found = this.data.find(item => item[this.rowKey] === newVal);
|
|
400
|
+
if (found) {
|
|
401
|
+
this.currentRow = found;
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
immediate: true
|
|
405
|
+
},
|
|
406
|
+
columns: {
|
|
407
|
+
handler() {
|
|
408
|
+
// this.fixedLeftColumns = this.columns.filter(col => col.fixed === 'left');
|
|
409
|
+
},
|
|
410
|
+
deep: true,
|
|
411
|
+
immediate: false
|
|
412
|
+
}
|
|
249
413
|
},
|
|
250
|
-
computed: {
|
|
251
|
-
},
|
|
252
414
|
methods: {
|
|
253
415
|
addUnit,
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
416
|
+
onScroll(e) {
|
|
417
|
+
this.scrollLeft = e.detail.scrollLeft;
|
|
418
|
+
// 获取所有左侧固定列
|
|
419
|
+
this.fixedLeftColumns = this.columns.filter(col => col.fixed === 'left');
|
|
420
|
+
// 计算是否需要显示固定列阴影
|
|
421
|
+
if (this.fixedLeftColumns.length > 0) {
|
|
422
|
+
this.showFixedColumnShadow = this.scrollLeft > 0;
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
|
|
426
|
+
getFixedShadowStyle(col, index) {
|
|
427
|
+
let style = {
|
|
428
|
+
width: col.width ? addUnit(col.width) : 'auto',
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
if (col?.style) {
|
|
432
|
+
style = {...style, ...col?.style};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return style;
|
|
436
|
+
},
|
|
437
|
+
|
|
438
|
+
getFixedClass(col) {
|
|
439
|
+
return ''; // 不再使用原来的固定列样式类
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
headerColStyle(col) {
|
|
443
|
+
let style = {
|
|
444
|
+
width: col.width ? addUnit(col.width) : 'auto',
|
|
445
|
+
flex: col.width ? 'none' : 1
|
|
446
|
+
};
|
|
447
|
+
if (col?.style) {
|
|
448
|
+
style = {...style, ...col?.style};
|
|
449
|
+
}
|
|
450
|
+
return style;
|
|
451
|
+
},
|
|
452
|
+
|
|
264
453
|
setCellStyle(e) {
|
|
265
454
|
this.cellStyle = e
|
|
266
455
|
},
|
|
@@ -285,172 +474,99 @@ export default {
|
|
|
285
474
|
this.$uGetRect('.u-table-row').then(size => {
|
|
286
475
|
this.scrollWidth = size.width + 'px'
|
|
287
476
|
})
|
|
477
|
+
|
|
478
|
+
// 获取表格高度
|
|
479
|
+
this.$uGetRect('.u-table2').then(size => {
|
|
480
|
+
this.tableHeight = size.height + 'px';
|
|
481
|
+
})
|
|
288
482
|
},
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
// 当前高亮行
|
|
296
|
-
const currentRow = ref(null);
|
|
297
|
-
|
|
298
|
-
watch(
|
|
299
|
-
() => props.expandRowKeys,
|
|
300
|
-
newVal => {
|
|
301
|
-
expandedKeys.value = [...newVal];
|
|
483
|
+
// 将setup中的函数转换为methods
|
|
484
|
+
handleRowClick(row) {
|
|
485
|
+
if (this.highlightCurrentRow) {
|
|
486
|
+
const oldRow = this.currentRow;
|
|
487
|
+
this.currentRow = row;
|
|
488
|
+
this.$emit('current-change', row, oldRow);
|
|
302
489
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
() => props.currentRowKey,
|
|
307
|
-
newVal => {
|
|
308
|
-
const found = props.data.find(item => item[props.rowKey] === newVal);
|
|
309
|
-
if (found) {
|
|
310
|
-
currentRow.value = found;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
);
|
|
314
|
-
|
|
315
|
-
// 过滤后的数据
|
|
316
|
-
const filteredData = computed(() => {
|
|
317
|
-
return props.data.filter(row => {
|
|
318
|
-
return Object.keys(props.filters).every(key => {
|
|
319
|
-
const filter = props.filters[key];
|
|
320
|
-
if (!filter) return true;
|
|
321
|
-
return row[key]?.toString().includes(filter.toString());
|
|
322
|
-
});
|
|
323
|
-
});
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
// 排序后的数据
|
|
327
|
-
const sortedData = computed(() => {
|
|
328
|
-
if (!sortConditions.value.length) return filteredData.value;
|
|
329
|
-
|
|
330
|
-
const data = [...filteredData.value];
|
|
331
|
-
|
|
332
|
-
return data.sort((a, b) => {
|
|
333
|
-
for (const condition of sortConditions.value) {
|
|
334
|
-
const { field, order } = condition;
|
|
335
|
-
let valA = a[field];
|
|
336
|
-
let valB = b[field];
|
|
337
|
-
|
|
338
|
-
if (props.sortMethod) {
|
|
339
|
-
const result = props.sortMethod(a, b, field);
|
|
340
|
-
if (result !== 0) return result * (order === 'ascending' ? 1 : -1);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (valA < valB) return order === 'ascending' ? -1 : 1;
|
|
344
|
-
if (valA > valB) return order === 'ascending' ? 1 : -1;
|
|
345
|
-
}
|
|
346
|
-
return 0;
|
|
347
|
-
});
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
function handleRowClick(row) {
|
|
351
|
-
if (props.highlightCurrentRow) {
|
|
352
|
-
const oldRow = currentRow.value;
|
|
353
|
-
currentRow.value = row;
|
|
354
|
-
emit('current-change', row, oldRow);
|
|
355
|
-
}
|
|
356
|
-
emit('row-click', row);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function handleHeaderClick(column) {
|
|
490
|
+
this.$emit('row-click', row);
|
|
491
|
+
},
|
|
492
|
+
handleHeaderClick(column) {
|
|
360
493
|
if (!column.sortable) return;
|
|
361
494
|
|
|
362
|
-
const index = sortConditions.
|
|
495
|
+
const index = this.sortConditions.findIndex(c => c.field === column.key);
|
|
363
496
|
let newOrder = 'ascending';
|
|
364
497
|
|
|
365
498
|
if (index >= 0) {
|
|
366
|
-
if (sortConditions
|
|
499
|
+
if (this.sortConditions[index].order === 'ascending') {
|
|
367
500
|
newOrder = 'descending';
|
|
368
501
|
} else {
|
|
369
|
-
sortConditions.
|
|
370
|
-
emit('sort-change', sortConditions
|
|
502
|
+
this.sortConditions.splice(index, 1);
|
|
503
|
+
this.$emit('sort-change', this.sortConditions);
|
|
371
504
|
return;
|
|
372
505
|
}
|
|
373
506
|
}
|
|
374
507
|
|
|
375
|
-
if (!
|
|
376
|
-
sortConditions
|
|
508
|
+
if (!this.multiSort) {
|
|
509
|
+
this.sortConditions = [{ field: column.key, order: newOrder }];
|
|
377
510
|
} else {
|
|
378
511
|
if (index >= 0) {
|
|
379
|
-
sortConditions
|
|
512
|
+
this.sortConditions[index].order = newOrder;
|
|
380
513
|
} else {
|
|
381
|
-
sortConditions.
|
|
514
|
+
this.sortConditions.push({ field: column.key, order: newOrder });
|
|
382
515
|
}
|
|
383
516
|
}
|
|
384
517
|
|
|
385
|
-
emit('sort-change', sortConditions
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const cond = sortConditions.value.find(c => c.field === field);
|
|
518
|
+
this.$emit('sort-change', this.sortConditions);
|
|
519
|
+
},
|
|
520
|
+
getSortIcon(field) {
|
|
521
|
+
const cond = this.sortConditions.find(c => c.field === field);
|
|
390
522
|
if (!cond) return '';
|
|
391
523
|
return cond.order === 'ascending' ? '↑' : '↓';
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const cond = sortConditions.value.find(c => c.field === field);
|
|
524
|
+
},
|
|
525
|
+
getSortValue(field) {
|
|
526
|
+
const cond = this.sortConditions.find(c => c.field === field);
|
|
396
527
|
if (!cond) return '';
|
|
397
528
|
return cond.order === 'ascending';
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const index = selectedRows.value.findIndex(r => r[props.rowKey] === row[props.rowKey]);
|
|
529
|
+
},
|
|
530
|
+
toggleSelect(row) {
|
|
531
|
+
const index = this.selectedRows.findIndex(r => r[this.rowKey] === row[this.rowKey]);
|
|
402
532
|
if (index >= 0) {
|
|
403
|
-
selectedRows.
|
|
533
|
+
this.selectedRows.splice(index, 1);
|
|
404
534
|
} else {
|
|
405
|
-
selectedRows.
|
|
535
|
+
this.selectedRows.push(row);
|
|
406
536
|
}
|
|
407
|
-
emit('selection-change', selectedRows
|
|
408
|
-
emit('select', row);
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const key = row[props.rowKey];
|
|
417
|
-
const index = expandedKeys.value.indexOf(key);
|
|
537
|
+
this.$emit('selection-change', this.selectedRows);
|
|
538
|
+
this.$emit('select', row);
|
|
539
|
+
},
|
|
540
|
+
isSelected(row) {
|
|
541
|
+
return this.selectedRows.some(r => r[this.rowKey] === row[this.rowKey]);
|
|
542
|
+
},
|
|
543
|
+
toggleExpand(row) {
|
|
544
|
+
const key = row[this.rowKey];
|
|
545
|
+
const index = this.expandedKeys.indexOf(key);
|
|
418
546
|
if (index === -1) {
|
|
419
|
-
expandedKeys.
|
|
547
|
+
this.expandedKeys.push(key);
|
|
420
548
|
} else {
|
|
421
|
-
expandedKeys.
|
|
549
|
+
this.expandedKeys.splice(index, 1);
|
|
422
550
|
}
|
|
423
|
-
emit('expand-change', expandedKeys
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
return expandedKeys.value.includes(row[props.rowKey]);
|
|
551
|
+
this.$emit('expand-change', this.expandedKeys);
|
|
552
|
+
},
|
|
553
|
+
isExpanded(row) {
|
|
554
|
+
return this.expandedKeys.includes(row[this.rowKey]);
|
|
428
555
|
}
|
|
429
|
-
|
|
430
|
-
return {
|
|
431
|
-
currentRow,
|
|
432
|
-
sortedData,
|
|
433
|
-
expandedKeys,
|
|
434
|
-
selectedRows,
|
|
435
|
-
sortConditions,
|
|
436
|
-
handleRowClick,
|
|
437
|
-
handleHeaderClick,
|
|
438
|
-
getSortValue,
|
|
439
|
-
getSortIcon,
|
|
440
|
-
toggleSelect,
|
|
441
|
-
isSelected,
|
|
442
|
-
toggleExpand,
|
|
443
|
-
isExpanded
|
|
444
|
-
};
|
|
445
556
|
}
|
|
446
557
|
};
|
|
447
558
|
</script>
|
|
448
559
|
|
|
449
560
|
<style lang="scss" scoped>
|
|
561
|
+
.u-table2-wrapper {
|
|
562
|
+
position: relative;
|
|
563
|
+
}
|
|
564
|
+
|
|
450
565
|
.u-table2 {
|
|
451
566
|
width: auto;
|
|
452
567
|
overflow: auto;
|
|
453
568
|
white-space: nowrap;
|
|
569
|
+
position: relative;
|
|
454
570
|
|
|
455
571
|
.u-table-header {
|
|
456
572
|
min-width: 100% !important;
|
|
@@ -461,6 +577,7 @@ export default {
|
|
|
461
577
|
.u-table-body {
|
|
462
578
|
min-width: 100% !important;
|
|
463
579
|
width: fit-content;
|
|
580
|
+
position: relative;
|
|
464
581
|
}
|
|
465
582
|
|
|
466
583
|
.u-table-sticky {
|
|
@@ -475,6 +592,8 @@ export default {
|
|
|
475
592
|
align-items: center;
|
|
476
593
|
border-bottom: 1rpx solid #ebeef5;
|
|
477
594
|
overflow: hidden;
|
|
595
|
+
position: relative;
|
|
596
|
+
min-height: 40px;
|
|
478
597
|
}
|
|
479
598
|
|
|
480
599
|
.u-table-cell {
|
|
@@ -488,18 +607,6 @@ export default {
|
|
|
488
607
|
text-overflow: ellipsis;
|
|
489
608
|
}
|
|
490
609
|
|
|
491
|
-
.u-table-fixed-left {
|
|
492
|
-
position: sticky;
|
|
493
|
-
left: 0;
|
|
494
|
-
z-index: 9;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
.u-table-fixed-right {
|
|
498
|
-
position: sticky;
|
|
499
|
-
right: 0;
|
|
500
|
-
z-index: 9;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
610
|
.u-table-row-zebra {
|
|
504
611
|
background-color: #fafafa;
|
|
505
612
|
}
|
|
@@ -526,4 +633,36 @@ export default {
|
|
|
526
633
|
text-align: right;
|
|
527
634
|
}
|
|
528
635
|
}
|
|
529
|
-
|
|
636
|
+
|
|
637
|
+
// 固定列浮动视图
|
|
638
|
+
.u-table-fixed-shadow {
|
|
639
|
+
position: absolute;
|
|
640
|
+
top: 0;
|
|
641
|
+
left: 0;
|
|
642
|
+
width: auto;
|
|
643
|
+
z-index: 20;
|
|
644
|
+
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.15);
|
|
645
|
+
overflow: hidden;
|
|
646
|
+
background-color: #ffffff;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.u-table-fixed-row {
|
|
650
|
+
display: flex;
|
|
651
|
+
flex-direction: row;
|
|
652
|
+
align-items: center;
|
|
653
|
+
border-bottom: 1rpx solid #ebeef5;
|
|
654
|
+
position: relative;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.u-table-fixed-cell {
|
|
658
|
+
flex: 1;
|
|
659
|
+
display: flex;
|
|
660
|
+
flex-direction: row;
|
|
661
|
+
padding: 5px 4px;
|
|
662
|
+
font-size: 14px;
|
|
663
|
+
white-space: nowrap;
|
|
664
|
+
overflow: hidden;
|
|
665
|
+
text-overflow: ellipsis;
|
|
666
|
+
background-color: #fff;
|
|
667
|
+
}
|
|
668
|
+
</style>
|
package/package.json
CHANGED