uview-plus 3.4.78 → 3.4.80
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/tableRow.vue +0 -0
- package/components/u-table2/u-table2.vue +381 -226
- package/package.json +1 -1
package/changelog.md
CHANGED
|
File without changes
|
|
@@ -1,99 +1,175 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
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>
|
|
149
|
+
<!-- 子级渲染 -->
|
|
150
|
+
<template v-if="isExpanded(row) && row[treeProps.children] && row[treeProps.children].length">
|
|
151
|
+
<view v-for="childRow in row[treeProps.children]" :key="childRow[rowKey]"
|
|
152
|
+
class="u-table-row u-table-row-child">
|
|
153
|
+
<view v-for="(col2, col2Index) in visibleFixedLeftColumns" :key="col2.key" class="u-table-cell"
|
|
154
|
+
:style="cellStyleInner({row: childRow, column: col2,
|
|
155
|
+
rowIndex: index, columnIndex: col2Index, level: 1})">
|
|
156
|
+
<slot name="cell" :row="childRow" :column="col2" :prow="row"
|
|
157
|
+
:rowIndex="index" :columnIndex="col2Index" :level="1">
|
|
158
|
+
<view class="u-table-cell_content">
|
|
159
|
+
{{ childRow[col2.key] }}
|
|
160
|
+
</view>
|
|
161
|
+
</slot>
|
|
162
|
+
</view>
|
|
163
|
+
</view>
|
|
164
|
+
</template>
|
|
83
165
|
</template>
|
|
84
166
|
</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>
|
|
167
|
+
</view>
|
|
91
168
|
</view>
|
|
92
|
-
</
|
|
169
|
+
</view>
|
|
93
170
|
</template>
|
|
94
171
|
|
|
95
172
|
<script>
|
|
96
|
-
import { ref, watch, computed } from 'vue'
|
|
97
173
|
import { addUnit, sleep } from '../../libs/function/index';
|
|
98
174
|
|
|
99
175
|
export default {
|
|
@@ -241,26 +317,155 @@ export default {
|
|
|
241
317
|
],
|
|
242
318
|
data() {
|
|
243
319
|
return {
|
|
244
|
-
scrollWidth: 'auto'
|
|
320
|
+
scrollWidth: 'auto',
|
|
321
|
+
// 将setup中的ref转换为data属性
|
|
322
|
+
expandedKeys: [...this.expandRowKeys],
|
|
323
|
+
selectedRows: [],
|
|
324
|
+
sortConditions: [],
|
|
325
|
+
currentRow: null,
|
|
326
|
+
scrollLeft: 0, // 新增滚动位置数据
|
|
327
|
+
showFixedColumnShadow: false, // 是否显示固定列阴影
|
|
328
|
+
fixedLeftColumns: [], // 左侧固定列
|
|
329
|
+
tableHeight: 'auto', // 表格高度
|
|
330
|
+
rowHeight: 40 // 行高
|
|
245
331
|
}
|
|
246
332
|
},
|
|
247
333
|
mounted() {
|
|
248
334
|
this.getComponentWidth()
|
|
335
|
+
// 处理currentRowKey初始化
|
|
336
|
+
if (this.currentRowKey !== null) {
|
|
337
|
+
const found = this.data.find(item => item[this.rowKey] === this.currentRowKey);
|
|
338
|
+
if (found) {
|
|
339
|
+
this.currentRow = found;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// 获取固定列
|
|
343
|
+
this.fixedLeftColumns = this.columns.filter(col => col.fixed === 'left');
|
|
344
|
+
},
|
|
345
|
+
computed: {
|
|
346
|
+
// 将setup中的computed转换为computed属性
|
|
347
|
+
filteredData() {
|
|
348
|
+
return this.data.filter(row => {
|
|
349
|
+
return Object.keys(this.filters).every(key => {
|
|
350
|
+
const filter = this.filters[key];
|
|
351
|
+
if (!filter) return true;
|
|
352
|
+
return row[key]?.toString().includes(filter.toString());
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
},
|
|
356
|
+
sortedData() {
|
|
357
|
+
if (!this.sortConditions.length) return this.filteredData;
|
|
358
|
+
|
|
359
|
+
const data = [...this.filteredData];
|
|
360
|
+
|
|
361
|
+
return data.sort((a, b) => {
|
|
362
|
+
for (const condition of this.sortConditions) {
|
|
363
|
+
const { field, order } = condition;
|
|
364
|
+
let valA = a[field];
|
|
365
|
+
let valB = b[field];
|
|
366
|
+
|
|
367
|
+
if (this.sortMethod) {
|
|
368
|
+
const result = this.sortMethod(a, b, field);
|
|
369
|
+
if (result !== 0) return result * (order === 'ascending' ? 1 : -1);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (valA < valB) return order === 'ascending' ? -1 : 1;
|
|
373
|
+
if (valA > valB) return order === 'ascending' ? 1 : -1;
|
|
374
|
+
}
|
|
375
|
+
return 0;
|
|
376
|
+
});
|
|
377
|
+
},
|
|
378
|
+
// 计算当前应该显示的固定左侧列
|
|
379
|
+
visibleFixedLeftColumns() {
|
|
380
|
+
if (this.scrollLeft <= 0) {
|
|
381
|
+
return [];
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
let totalWidth = 0;
|
|
385
|
+
let fixedWidth = 0;
|
|
386
|
+
const visibleColumns = [];
|
|
387
|
+
|
|
388
|
+
// 遍历所有列,不仅仅是固定列
|
|
389
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
390
|
+
const col = this.columns[i];
|
|
391
|
+
const colWidth = col.width ? parseInt(col.width) : 100; // 默认宽度100px
|
|
392
|
+
|
|
393
|
+
// 如果是固定列且滚动位置足够显示该列
|
|
394
|
+
if (col.fixed === 'left' && this.scrollLeft > totalWidth - fixedWidth) {
|
|
395
|
+
visibleColumns.push(col);
|
|
396
|
+
fixedWidth += colWidth;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
totalWidth += colWidth;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return visibleColumns;
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
watch: {
|
|
406
|
+
// 将setup中的watch转换为watch属性
|
|
407
|
+
expandRowKeys: {
|
|
408
|
+
handler(newVal) {
|
|
409
|
+
this.expandedKeys = [...newVal];
|
|
410
|
+
},
|
|
411
|
+
immediate: true
|
|
412
|
+
},
|
|
413
|
+
currentRowKey: {
|
|
414
|
+
handler(newVal) {
|
|
415
|
+
const found = this.data.find(item => item[this.rowKey] === newVal);
|
|
416
|
+
if (found) {
|
|
417
|
+
this.currentRow = found;
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
immediate: true
|
|
421
|
+
},
|
|
422
|
+
columns: {
|
|
423
|
+
handler() {
|
|
424
|
+
// this.fixedLeftColumns = this.columns.filter(col => col.fixed === 'left');
|
|
425
|
+
},
|
|
426
|
+
deep: true,
|
|
427
|
+
immediate: false
|
|
428
|
+
}
|
|
249
429
|
},
|
|
250
|
-
computed: {
|
|
251
|
-
},
|
|
252
430
|
methods: {
|
|
253
431
|
addUnit,
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
432
|
+
onScroll(e) {
|
|
433
|
+
this.scrollLeft = e.detail.scrollLeft;
|
|
434
|
+
// 获取所有左侧固定列
|
|
435
|
+
this.fixedLeftColumns = this.columns.filter(col => col.fixed === 'left');
|
|
436
|
+
// 计算是否需要显示固定列阴影
|
|
437
|
+
if (this.fixedLeftColumns.length > 0) {
|
|
438
|
+
this.showFixedColumnShadow = this.scrollLeft > 0;
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
getFixedShadowStyle(col, index) {
|
|
443
|
+
let style = {
|
|
444
|
+
width: col.width ? addUnit(col.width) : 'auto',
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
if (col?.style) {
|
|
448
|
+
style = {...style, ...col?.style};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return style;
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
getFixedClass(col) {
|
|
455
|
+
return ''; // 不再使用原来的固定列样式类
|
|
456
|
+
},
|
|
457
|
+
|
|
458
|
+
headerColStyle(col) {
|
|
459
|
+
let style = {
|
|
460
|
+
width: col.width ? addUnit(col.width) : 'auto',
|
|
461
|
+
flex: col.width ? 'none' : 1
|
|
462
|
+
};
|
|
463
|
+
if (col?.style) {
|
|
464
|
+
style = {...style, ...col?.style};
|
|
465
|
+
}
|
|
466
|
+
return style;
|
|
467
|
+
},
|
|
468
|
+
|
|
264
469
|
setCellStyle(e) {
|
|
265
470
|
this.cellStyle = e
|
|
266
471
|
},
|
|
@@ -285,172 +490,99 @@ export default {
|
|
|
285
490
|
this.$uGetRect('.u-table-row').then(size => {
|
|
286
491
|
this.scrollWidth = size.width + 'px'
|
|
287
492
|
})
|
|
493
|
+
|
|
494
|
+
// 获取表格高度
|
|
495
|
+
// this.$uGetRect('.u-table2').then(size => {
|
|
496
|
+
// this.tableHeight = size.height + 'px';
|
|
497
|
+
// })
|
|
288
498
|
},
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
// 当前高亮行
|
|
296
|
-
const currentRow = ref(null);
|
|
297
|
-
|
|
298
|
-
watch(
|
|
299
|
-
() => props.expandRowKeys,
|
|
300
|
-
newVal => {
|
|
301
|
-
expandedKeys.value = [...newVal];
|
|
302
|
-
}
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
watch(
|
|
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);
|
|
499
|
+
// 将setup中的函数转换为methods
|
|
500
|
+
handleRowClick(row) {
|
|
501
|
+
if (this.highlightCurrentRow) {
|
|
502
|
+
const oldRow = this.currentRow;
|
|
503
|
+
this.currentRow = row;
|
|
504
|
+
this.$emit('current-change', row, oldRow);
|
|
355
505
|
}
|
|
356
|
-
emit('row-click', row);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function handleHeaderClick(column) {
|
|
506
|
+
this.$emit('row-click', row);
|
|
507
|
+
},
|
|
508
|
+
handleHeaderClick(column) {
|
|
360
509
|
if (!column.sortable) return;
|
|
361
510
|
|
|
362
|
-
const index = sortConditions.
|
|
511
|
+
const index = this.sortConditions.findIndex(c => c.field === column.key);
|
|
363
512
|
let newOrder = 'ascending';
|
|
364
513
|
|
|
365
514
|
if (index >= 0) {
|
|
366
|
-
if (sortConditions
|
|
515
|
+
if (this.sortConditions[index].order === 'ascending') {
|
|
367
516
|
newOrder = 'descending';
|
|
368
517
|
} else {
|
|
369
|
-
sortConditions.
|
|
370
|
-
emit('sort-change', sortConditions
|
|
518
|
+
this.sortConditions.splice(index, 1);
|
|
519
|
+
this.$emit('sort-change', this.sortConditions);
|
|
371
520
|
return;
|
|
372
521
|
}
|
|
373
522
|
}
|
|
374
523
|
|
|
375
|
-
if (!
|
|
376
|
-
sortConditions
|
|
524
|
+
if (!this.multiSort) {
|
|
525
|
+
this.sortConditions = [{ field: column.key, order: newOrder }];
|
|
377
526
|
} else {
|
|
378
527
|
if (index >= 0) {
|
|
379
|
-
sortConditions
|
|
528
|
+
this.sortConditions[index].order = newOrder;
|
|
380
529
|
} else {
|
|
381
|
-
sortConditions.
|
|
530
|
+
this.sortConditions.push({ field: column.key, order: newOrder });
|
|
382
531
|
}
|
|
383
532
|
}
|
|
384
533
|
|
|
385
|
-
emit('sort-change', sortConditions
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const cond = sortConditions.value.find(c => c.field === field);
|
|
534
|
+
this.$emit('sort-change', this.sortConditions);
|
|
535
|
+
},
|
|
536
|
+
getSortIcon(field) {
|
|
537
|
+
const cond = this.sortConditions.find(c => c.field === field);
|
|
390
538
|
if (!cond) return '';
|
|
391
539
|
return cond.order === 'ascending' ? '↑' : '↓';
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const cond = sortConditions.value.find(c => c.field === field);
|
|
540
|
+
},
|
|
541
|
+
getSortValue(field) {
|
|
542
|
+
const cond = this.sortConditions.find(c => c.field === field);
|
|
396
543
|
if (!cond) return '';
|
|
397
544
|
return cond.order === 'ascending';
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const index = selectedRows.value.findIndex(r => r[props.rowKey] === row[props.rowKey]);
|
|
545
|
+
},
|
|
546
|
+
toggleSelect(row) {
|
|
547
|
+
const index = this.selectedRows.findIndex(r => r[this.rowKey] === row[this.rowKey]);
|
|
402
548
|
if (index >= 0) {
|
|
403
|
-
selectedRows.
|
|
549
|
+
this.selectedRows.splice(index, 1);
|
|
404
550
|
} else {
|
|
405
|
-
selectedRows.
|
|
551
|
+
this.selectedRows.push(row);
|
|
406
552
|
}
|
|
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);
|
|
553
|
+
this.$emit('selection-change', this.selectedRows);
|
|
554
|
+
this.$emit('select', row);
|
|
555
|
+
},
|
|
556
|
+
isSelected(row) {
|
|
557
|
+
return this.selectedRows.some(r => r[this.rowKey] === row[this.rowKey]);
|
|
558
|
+
},
|
|
559
|
+
toggleExpand(row) {
|
|
560
|
+
const key = row[this.rowKey];
|
|
561
|
+
const index = this.expandedKeys.indexOf(key);
|
|
418
562
|
if (index === -1) {
|
|
419
|
-
expandedKeys.
|
|
563
|
+
this.expandedKeys.push(key);
|
|
420
564
|
} else {
|
|
421
|
-
expandedKeys.
|
|
565
|
+
this.expandedKeys.splice(index, 1);
|
|
422
566
|
}
|
|
423
|
-
emit('expand-change', expandedKeys
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
return expandedKeys.value.includes(row[props.rowKey]);
|
|
567
|
+
this.$emit('expand-change', this.expandedKeys);
|
|
568
|
+
},
|
|
569
|
+
isExpanded(row) {
|
|
570
|
+
return this.expandedKeys.includes(row[this.rowKey]);
|
|
428
571
|
}
|
|
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
572
|
}
|
|
446
573
|
};
|
|
447
574
|
</script>
|
|
448
575
|
|
|
449
576
|
<style lang="scss" scoped>
|
|
577
|
+
.u-table2-wrapper {
|
|
578
|
+
position: relative;
|
|
579
|
+
}
|
|
580
|
+
|
|
450
581
|
.u-table2 {
|
|
451
582
|
width: auto;
|
|
452
583
|
overflow: auto;
|
|
453
584
|
white-space: nowrap;
|
|
585
|
+
position: relative;
|
|
454
586
|
|
|
455
587
|
.u-table-header {
|
|
456
588
|
min-width: 100% !important;
|
|
@@ -461,6 +593,7 @@ export default {
|
|
|
461
593
|
.u-table-body {
|
|
462
594
|
min-width: 100% !important;
|
|
463
595
|
width: fit-content;
|
|
596
|
+
position: relative;
|
|
464
597
|
}
|
|
465
598
|
|
|
466
599
|
.u-table-sticky {
|
|
@@ -475,6 +608,8 @@ export default {
|
|
|
475
608
|
align-items: center;
|
|
476
609
|
border-bottom: 1rpx solid #ebeef5;
|
|
477
610
|
overflow: hidden;
|
|
611
|
+
position: relative;
|
|
612
|
+
min-height: 40px;
|
|
478
613
|
}
|
|
479
614
|
|
|
480
615
|
.u-table-cell {
|
|
@@ -488,18 +623,6 @@ export default {
|
|
|
488
623
|
text-overflow: ellipsis;
|
|
489
624
|
}
|
|
490
625
|
|
|
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
626
|
.u-table-row-zebra {
|
|
504
627
|
background-color: #fafafa;
|
|
505
628
|
}
|
|
@@ -526,4 +649,36 @@ export default {
|
|
|
526
649
|
text-align: right;
|
|
527
650
|
}
|
|
528
651
|
}
|
|
529
|
-
|
|
652
|
+
|
|
653
|
+
// 固定列浮动视图
|
|
654
|
+
.u-table-fixed-shadow {
|
|
655
|
+
position: absolute;
|
|
656
|
+
top: 0;
|
|
657
|
+
left: 0;
|
|
658
|
+
width: auto;
|
|
659
|
+
z-index: 20;
|
|
660
|
+
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.15);
|
|
661
|
+
overflow: hidden;
|
|
662
|
+
background-color: #ffffff;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
.u-table-fixed-row {
|
|
666
|
+
display: flex;
|
|
667
|
+
flex-direction: row;
|
|
668
|
+
align-items: center;
|
|
669
|
+
border-bottom: 1rpx solid #ebeef5;
|
|
670
|
+
position: relative;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
.u-table-fixed-cell {
|
|
674
|
+
flex: 1;
|
|
675
|
+
display: flex;
|
|
676
|
+
flex-direction: row;
|
|
677
|
+
padding: 5px 4px;
|
|
678
|
+
font-size: 14px;
|
|
679
|
+
white-space: nowrap;
|
|
680
|
+
overflow: hidden;
|
|
681
|
+
text-overflow: ellipsis;
|
|
682
|
+
background-color: #fff;
|
|
683
|
+
}
|
|
684
|
+
</style>
|
package/package.json
CHANGED