stellar-ui-plus 1.17.21 → 1.17.22
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,13 +1,17 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { computed, watch, ref, type CSSProperties } from 'vue';
|
|
2
|
+
import { computed, watch, ref, type CSSProperties, toRaw, nextTick } from 'vue';
|
|
3
3
|
import propsData, { TABLE_KEY, tableEmits, CHECK_ICON_SIZE, SELECTION_COLOR_CONFIG, type TableProps } from './props';
|
|
4
4
|
import utils from '../../utils/utils';
|
|
5
5
|
import { useProvide } from '../../utils/mixin';
|
|
6
6
|
import useData from './useData';
|
|
7
7
|
import type { TableColumnProps } from '../ste-table-column/props';
|
|
8
|
+
import { groupByKeys } from './utils';
|
|
8
9
|
import { useColorStore } from '../../store/color';
|
|
9
10
|
let { getColor } = useColorStore();
|
|
10
11
|
|
|
12
|
+
let tableLength = 0;
|
|
13
|
+
let uuid = utils.guid();
|
|
14
|
+
|
|
11
15
|
const componentName = `ste-table`;
|
|
12
16
|
defineOptions({
|
|
13
17
|
name: componentName,
|
|
@@ -91,32 +95,74 @@ const cmpShowFixedPlaceholder = computed(() => {
|
|
|
91
95
|
return props.fixed || props.height || Number(props.height) > 0 || props.maxHeight || Number(props.maxHeight) > 0;
|
|
92
96
|
});
|
|
93
97
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
const dataChangeFun = (fullLength: number = 0, val: any) => {
|
|
99
|
+
tableLength = val.length;
|
|
100
|
+
// 由于没有数据时会导致插槽无法渲染,然后表头无法显示,所以在无数据时先给默认值,让表头能渲染,再加延时,恢复成原来的数据
|
|
101
|
+
if (val.length === 0) {
|
|
102
|
+
tableData.value = [{}];
|
|
103
|
+
} else {
|
|
104
|
+
if (fullLength > 0) {
|
|
105
|
+
tableData.value = ensureArrayLength(10, val) as Obj[];
|
|
100
106
|
} else {
|
|
101
107
|
tableData.value = val as Obj[];
|
|
102
108
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
}
|
|
110
|
+
initRowData();
|
|
111
|
+
calcSum();
|
|
112
|
+
initSelection();
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
watch(
|
|
116
|
+
() => props.data,
|
|
117
|
+
val => {
|
|
118
|
+
dataChangeFun(0, val);
|
|
109
119
|
},
|
|
110
120
|
{ immediate: true, deep: true }
|
|
111
121
|
);
|
|
112
122
|
|
|
123
|
+
let lastChildrenCount = 0;
|
|
124
|
+
let lastChangeTime = 0;
|
|
125
|
+
let processTimer: any = null;
|
|
113
126
|
watch(
|
|
114
127
|
() => internalChildren,
|
|
115
|
-
|
|
116
|
-
|
|
128
|
+
val => {
|
|
129
|
+
const currentTime = Date.now();
|
|
130
|
+
const currentCount = val.length;
|
|
131
|
+
|
|
132
|
+
// 最后一次子元素变动时再执行初始化
|
|
133
|
+
if (processTimer) clearTimeout(processTimer);
|
|
134
|
+
|
|
135
|
+
// 如果内容没有变化,并且距离上次变化已经超过300ms
|
|
136
|
+
if (currentCount === lastChildrenCount && currentTime - lastChangeTime > 300 && currentCount > 0) {
|
|
137
|
+
console.log('内容已稳定,执行初始化');
|
|
138
|
+
|
|
117
139
|
initColumns();
|
|
118
140
|
initRowData();
|
|
119
|
-
}
|
|
141
|
+
} else {
|
|
142
|
+
// 更新最后一次变化的记录
|
|
143
|
+
lastChildrenCount = currentCount;
|
|
144
|
+
lastChangeTime = currentTime;
|
|
145
|
+
|
|
146
|
+
// 设置一个较短的延迟检查
|
|
147
|
+
processTimer = setTimeout(() => {
|
|
148
|
+
// 触发延迟检查
|
|
149
|
+
if (val.length === lastChildrenCount) {
|
|
150
|
+
initColumns();
|
|
151
|
+
initRowData();
|
|
152
|
+
|
|
153
|
+
// #ifdef MP-WEIXIN
|
|
154
|
+
const group = groupByKeys(val.map(e => e.props) as any);
|
|
155
|
+
if (group[0].length > tableData.value.length) {
|
|
156
|
+
// 由于uni-app 编译到微信小程序时,如果使用循环插槽导致插槽节点不会消失,所以使用折中办法,强行补全数据再还原
|
|
157
|
+
dataChangeFun(group[0].length, tableData.value);
|
|
158
|
+
nextTick(() => {
|
|
159
|
+
tableData.value = props.data as any;
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
// #endif
|
|
163
|
+
}
|
|
164
|
+
}, 50); // 从1000ms减少到400ms
|
|
165
|
+
}
|
|
120
166
|
},
|
|
121
167
|
{ immediate: true, deep: true }
|
|
122
168
|
);
|
|
@@ -153,22 +199,70 @@ function initColumns() {
|
|
|
153
199
|
}
|
|
154
200
|
});
|
|
155
201
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
202
|
+
// 创建一个全新的数组,包含全新的普通对象
|
|
203
|
+
const finalColumns = [];
|
|
204
|
+
|
|
205
|
+
for (let i = 0; i < tempResult.length; i++) {
|
|
206
|
+
const e = tempResult[i];
|
|
207
|
+
const propsData = toRaw(e.props);
|
|
208
|
+
|
|
209
|
+
// 创建一个全新的对象
|
|
210
|
+
const newColumn: TableColumnProps = {} as TableColumnProps;
|
|
211
|
+
|
|
212
|
+
// 复制所有属性
|
|
213
|
+
for (const key in propsData) {
|
|
214
|
+
(newColumn as any)[key] = propsData[key];
|
|
159
215
|
}
|
|
160
|
-
|
|
161
|
-
|
|
216
|
+
|
|
217
|
+
// 特别处理 label
|
|
218
|
+
if (!newColumn.label && props.header && typeof props.header === 'function') {
|
|
219
|
+
const labelValue = props.header(newColumn, tableData.value);
|
|
220
|
+
// 强制设置 label,确保不会丢失
|
|
221
|
+
newColumn.label = labelValue;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
finalColumns.push(newColumn);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 直接赋值
|
|
228
|
+
columns.value = finalColumns;
|
|
229
|
+
|
|
162
230
|
calcSum();
|
|
163
231
|
loadSelectType();
|
|
164
232
|
loadCanCheckArr();
|
|
165
233
|
}
|
|
166
234
|
|
|
235
|
+
/**
|
|
236
|
+
* 确保数组达到指定数量,不足则补充空对象
|
|
237
|
+
* @param targetCount 目标数量
|
|
238
|
+
* @param array 需要处理的数组
|
|
239
|
+
* @returns 处理后的数组
|
|
240
|
+
*/
|
|
241
|
+
function ensureArrayLength<T>(targetCount: number, array: T[]): T[] {
|
|
242
|
+
// 创建数组副本,避免修改原数组
|
|
243
|
+
const result = [...array];
|
|
244
|
+
|
|
245
|
+
// 计算需要补充的元素数量
|
|
246
|
+
const shortfall = targetCount - result.length;
|
|
247
|
+
|
|
248
|
+
// 如果数组长度已经够了或超出,直接返回原数组
|
|
249
|
+
if (shortfall <= 0) {
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 补充空对象到数组
|
|
254
|
+
for (let i = 0; i < shortfall; i++) {
|
|
255
|
+
result.push({} as T);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
|
|
167
261
|
defineExpose({ clearSelection, toggleAllSelection, toggleRowSelection, getSelection });
|
|
168
262
|
</script>
|
|
169
263
|
|
|
170
264
|
<template>
|
|
171
|
-
<view class="ste-table-root" :class="[cmpRootClass]" :style="[cmpRootStyle]">
|
|
265
|
+
<view class="ste-table-root" :class="[cmpRootClass]" :style="[cmpRootStyle]" v-if="tableData.length > 0" :id="'ste-table-' + uuid">
|
|
172
266
|
<view class="ste-table-content">
|
|
173
267
|
<view class="fixed-placeholder" v-if="cmpShowFixedPlaceholder" />
|
|
174
268
|
<view class="ste-table-header" :class="[getHeaderRowClass()]" :style="[getHeaderRowStyle() as CSSProperties]" v-if="showHeader">
|
|
@@ -211,7 +305,7 @@ defineExpose({ clearSelection, toggleAllSelection, toggleRowSelection, getSelect
|
|
|
211
305
|
:key="rowIndex"
|
|
212
306
|
@click="rowClick(row, $event)"
|
|
213
307
|
>
|
|
214
|
-
<slot :row="row"></slot>
|
|
308
|
+
<slot :row="row" name="default"></slot>
|
|
215
309
|
</view>
|
|
216
310
|
<view class="ste-table-row sum" v-if="showSummary">
|
|
217
311
|
<view class="ste-table-cell" v-for="(column, index) in columns" :key="index" :class="[getHeaderCellClass(column, 0)]">
|
|
@@ -238,7 +332,6 @@ defineExpose({ clearSelection, toggleAllSelection, toggleRowSelection, getSelect
|
|
|
238
332
|
:class="[getRowClass(row, rowIndex)]"
|
|
239
333
|
:style="[getRowStyle(row, rowIndex) as CSSProperties]"
|
|
240
334
|
v-for="(row, rowIndex) in tableData"
|
|
241
|
-
:key="rowIndex"
|
|
242
335
|
@click="rowClick(row, $event)"
|
|
243
336
|
>
|
|
244
337
|
<slot :row="row"></slot>
|
|
@@ -1,11 +1,68 @@
|
|
|
1
|
-
type
|
|
2
|
-
|
|
1
|
+
import type { TableColumnProps } from '../ste-table-column/props';
|
|
2
|
+
import { toRaw } from 'vue';
|
|
3
|
+
|
|
4
|
+
type StyleOrClassFunction<T> = (params: object) => T;
|
|
5
|
+
type StyleOrClass<T> = T | StyleOrClassFunction<T> | undefined;
|
|
6
|
+
interface ColumnItem extends TableColumnProps {
|
|
7
|
+
[key: string]: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 根据对象的 key 值将数组分组
|
|
12
|
+
* @param arr 要分组的数组
|
|
13
|
+
* @returns 分组后的二维数组
|
|
14
|
+
*/
|
|
15
|
+
function groupByKeys(arr: ColumnItem[]): ColumnItem[][] {
|
|
16
|
+
// 如果数组为空,直接返回空数组
|
|
17
|
+
if (!arr.length) return [];
|
|
18
|
+
|
|
19
|
+
const result: ColumnItem[][] = [];
|
|
20
|
+
const usedIndices = new Set<number>();
|
|
21
|
+
|
|
22
|
+
// 遍历数组
|
|
23
|
+
for (let i = 0; i < arr.length; i++) {
|
|
24
|
+
// 如果当前元素已经被分组,则跳过
|
|
25
|
+
if (usedIndices.has(i)) continue;
|
|
26
|
+
|
|
27
|
+
const currentItem = toRaw(arr[i]);
|
|
28
|
+
const group: ColumnItem[] = [currentItem];
|
|
29
|
+
usedIndices.add(i);
|
|
30
|
+
|
|
31
|
+
// 查找与当前元素匹配的其他元素
|
|
32
|
+
for (let j = i + 1; j < arr.length; j++) {
|
|
33
|
+
if (usedIndices.has(j)) continue;
|
|
34
|
+
|
|
35
|
+
const compareItem = toRaw(arr[j]);
|
|
36
|
+
let isMatch = true;
|
|
37
|
+
|
|
38
|
+
// 比较两个对象的所有属性
|
|
39
|
+
for (const key in currentItem) {
|
|
40
|
+
// 如果属性值都为空,认为它们相等
|
|
41
|
+
const currentValue = currentItem[key] || '';
|
|
42
|
+
const compareValue = compareItem[key] || '';
|
|
43
|
+
|
|
44
|
+
if (currentValue !== compareValue) {
|
|
45
|
+
isMatch = false;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 确保两个对象的属性数量相同
|
|
51
|
+
if (isMatch && Object.keys(currentItem).length === Object.keys(compareItem).length) {
|
|
52
|
+
group.push(compareItem);
|
|
53
|
+
usedIndices.add(j);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
result.push(group);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
3
62
|
|
|
4
63
|
function getStyleOrClass<T extends string | object>(fun: StyleOrClass<T>, params: object = {}): T | undefined {
|
|
5
|
-
|
|
6
|
-
return
|
|
7
|
-
else
|
|
8
|
-
return fun
|
|
64
|
+
if (typeof fun === 'function' && fun instanceof Function) return (fun as StyleOrClassFunction<T>)(params);
|
|
65
|
+
else return fun;
|
|
9
66
|
}
|
|
10
67
|
|
|
11
|
-
export { getStyleOrClass }
|
|
68
|
+
export { getStyleOrClass, groupByKeys };
|