stellar-ui-plus 1.17.21 → 1.17.23

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.
@@ -29,6 +29,7 @@
29
29
  | `maxHeight` | 表格最大高度 | `number / string` | - | - | - |
30
30
  | `selectionIconColor` | 配置选择项图标色 | `object` | - | - | - |
31
31
  | `isPopover` | 是否为超出单元格时气泡显示内容 | `boolean` | - | - | - |
32
+ | `popoverLine` | 单元格开启isPopover时,超过多少行才显示省略提示 | `number / string` | - | - | - |
32
33
 
33
34
 
34
35
  #### Events
@@ -45,7 +45,8 @@ const tableProps = {
45
45
  type: Object as PropType<typeof SELECTION_COLOR_CONFIG>,
46
46
  default: () => SELECTION_COLOR_CONFIG,
47
47
  },
48
- isPopover: [Boolean, null],
48
+ isPopover: [Boolean, null], // 单元格是否开启内容超长时省略显示并长按显示提示
49
+ popoverLine: { type: [Number, String], default: 1 }, // 单元格开启isPopover时,超过多少行才显示省略提示
49
50
  };
50
51
 
51
52
  export type TableProps = ExtractPropTypes<typeof tableProps>;
@@ -158,6 +158,11 @@
158
158
  "description": "是否为超出单元格时气泡显示内容",
159
159
  "type": "boolean"
160
160
  },
161
+ {
162
+ "name": "popoverLine",
163
+ "description": "单元格开启isPopover时,超过多少行才显示省略提示",
164
+ "type": "number | string"
165
+ },
161
166
  {
162
167
  "name": "[event]select",
163
168
  "description": "当用户手动勾选数据行的 Checkbox 时触发的事件",
@@ -1,10 +1,11 @@
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
 
@@ -66,6 +67,7 @@ const cmpRootStyle = computed(() => {
66
67
  '--table-height': utils.addUnit(props.height as string),
67
68
  '--table-max-height': utils.addUnit(props.maxHeight as string),
68
69
  '--ste-theme-color': utils.Color.hex2rgba(getColor().steThemeColor),
70
+ '--ste-table-popover-line': props.popoverLine,
69
71
  };
70
72
  return style;
71
73
  });
@@ -91,32 +93,73 @@ const cmpShowFixedPlaceholder = computed(() => {
91
93
  return props.fixed || props.height || Number(props.height) > 0 || props.maxHeight || Number(props.maxHeight) > 0;
92
94
  });
93
95
 
94
- watch(
95
- () => props.data,
96
- val => {
97
- // 由于没有数据时会导致插槽无法渲染,然后表头无法显示,所以在无数据时先给默认值,让表头能渲染,再加延时,恢复成原来的数据
98
- if (val.length === 0) {
99
- tableData.value = [{}];
96
+ const dataChangeFun = (fullLength: number = 0, val: any) => {
97
+ // 由于没有数据时会导致插槽无法渲染,然后表头无法显示,所以在无数据时先给默认值,让表头能渲染,再加延时,恢复成原来的数据
98
+ if (val.length === 0) {
99
+ tableData.value = [{}];
100
+ } else {
101
+ if (fullLength > 0) {
102
+ tableData.value = ensureArrayLength(10, val) as Obj[];
100
103
  } else {
101
104
  tableData.value = val as Obj[];
102
105
  }
103
- initRowData();
104
- calcSum();
105
- initSelection();
106
- setTimeout(() => {
107
- tableData.value = val as Obj[];
108
- });
106
+ }
107
+ initRowData();
108
+ calcSum();
109
+ initSelection();
110
+ };
111
+
112
+ watch(
113
+ () => props.data,
114
+ val => {
115
+ dataChangeFun(0, val);
109
116
  },
110
117
  { immediate: true, deep: true }
111
118
  );
112
119
 
120
+ let lastChildrenCount = 0;
121
+ let lastChangeTime = 0;
122
+ let processTimer: any = null;
113
123
  watch(
114
124
  () => internalChildren,
115
- () => {
116
- setTimeout(() => {
125
+ val => {
126
+ const currentTime = Date.now();
127
+ const currentCount = val.length;
128
+
129
+ // 最后一次子元素变动时再执行初始化
130
+ if (processTimer) clearTimeout(processTimer);
131
+
132
+ // 如果内容没有变化,并且距离上次变化已经超过300ms
133
+ if (currentCount === lastChildrenCount && currentTime - lastChangeTime > 300 && currentCount > 0) {
134
+ console.log('内容已稳定,执行初始化');
135
+
117
136
  initColumns();
118
137
  initRowData();
119
- }, 200);
138
+ } else {
139
+ // 更新最后一次变化的记录
140
+ lastChildrenCount = currentCount;
141
+ lastChangeTime = currentTime;
142
+
143
+ // 设置一个较短的延迟检查
144
+ processTimer = setTimeout(() => {
145
+ // 触发延迟检查
146
+ if (val.length === lastChildrenCount) {
147
+ initColumns();
148
+ initRowData();
149
+
150
+ // #ifdef MP-WEIXIN
151
+ const group = groupByKeys(val.map(e => e.props) as any);
152
+ if (group[0].length > tableData.value.length) {
153
+ // 由于uni-app 编译到微信小程序时,如果使用循环插槽导致插槽节点不会消失,所以使用折中办法,强行补全数据再还原
154
+ dataChangeFun(group[0].length, tableData.value);
155
+ nextTick(() => {
156
+ tableData.value = props.data as any;
157
+ });
158
+ }
159
+ // #endif
160
+ }
161
+ }, 50); // 从1000ms减少到400ms
162
+ }
120
163
  },
121
164
  { immediate: true, deep: true }
122
165
  );
@@ -153,17 +196,65 @@ function initColumns() {
153
196
  }
154
197
  });
155
198
 
156
- columns.value = tempResult.map(e => {
157
- if (!e.props.label && props.header && typeof props.header === 'function') {
158
- e.props.label = props.header(e.props, tableData.value);
199
+ // 创建一个全新的数组,包含全新的普通对象
200
+ const finalColumns = [];
201
+
202
+ for (let i = 0; i < tempResult.length; i++) {
203
+ const e = tempResult[i];
204
+ const propsData = toRaw(e.props);
205
+
206
+ // 创建一个全新的对象
207
+ const newColumn: TableColumnProps = {} as TableColumnProps;
208
+
209
+ // 复制所有属性
210
+ for (const key in propsData) {
211
+ (newColumn as any)[key] = propsData[key];
159
212
  }
160
- return e.props;
161
- }) as TableColumnProps[];
213
+
214
+ // 特别处理 label
215
+ if (!newColumn.label && props.header && typeof props.header === 'function') {
216
+ const labelValue = props.header(newColumn, tableData.value);
217
+ // 强制设置 label,确保不会丢失
218
+ newColumn.label = labelValue;
219
+ }
220
+
221
+ finalColumns.push(newColumn);
222
+ }
223
+
224
+ // 直接赋值
225
+ columns.value = finalColumns;
226
+
162
227
  calcSum();
163
228
  loadSelectType();
164
229
  loadCanCheckArr();
165
230
  }
166
231
 
232
+ /**
233
+ * 确保数组达到指定数量,不足则补充空对象
234
+ * @param targetCount 目标数量
235
+ * @param array 需要处理的数组
236
+ * @returns 处理后的数组
237
+ */
238
+ function ensureArrayLength<T>(targetCount: number, array: T[]): T[] {
239
+ // 创建数组副本,避免修改原数组
240
+ const result = [...array];
241
+
242
+ // 计算需要补充的元素数量
243
+ const shortfall = targetCount - result.length;
244
+
245
+ // 如果数组长度已经够了或超出,直接返回原数组
246
+ if (shortfall <= 0) {
247
+ return result;
248
+ }
249
+
250
+ // 补充空对象到数组
251
+ for (let i = 0; i < shortfall; i++) {
252
+ result.push({} as T);
253
+ }
254
+
255
+ return result;
256
+ }
257
+
167
258
  defineExpose({ clearSelection, toggleAllSelection, toggleRowSelection, getSelection });
168
259
  </script>
169
260
 
@@ -211,7 +302,7 @@ defineExpose({ clearSelection, toggleAllSelection, toggleRowSelection, getSelect
211
302
  :key="rowIndex"
212
303
  @click="rowClick(row, $event)"
213
304
  >
214
- <slot :row="row"></slot>
305
+ <slot :row="row" name="default"></slot>
215
306
  </view>
216
307
  <view class="ste-table-row sum" v-if="showSummary">
217
308
  <view class="ste-table-cell" v-for="(column, index) in columns" :key="index" :class="[getHeaderCellClass(column, 0)]">
@@ -238,7 +329,6 @@ defineExpose({ clearSelection, toggleAllSelection, toggleRowSelection, getSelect
238
329
  :class="[getRowClass(row, rowIndex)]"
239
330
  :style="[getRowStyle(row, rowIndex) as CSSProperties]"
240
331
  v-for="(row, rowIndex) in tableData"
241
- :key="rowIndex"
242
332
  @click="rowClick(row, $event)"
243
333
  >
244
334
  <slot :row="row"></slot>
@@ -1,11 +1,68 @@
1
- type StyleOrClassFunction<T> = (params: object) => T
2
- type StyleOrClass<T> = T | StyleOrClassFunction<T> | undefined
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
- if (typeof fun === 'function' && fun instanceof Function)
6
- return (fun as StyleOrClassFunction<T>)(params)
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 };
@@ -153,7 +153,7 @@ function cellClick(this: any, event: any) {
153
153
  <template v-if="!parentProps.isPopover">
154
154
  {{ cellText() }}
155
155
  </template>
156
- <table-popover v-else :text="cellText()"></table-popover>
156
+ <table-popover v-else :text="cellText()" :line="parentProps.popoverLine"></table-popover>
157
157
  </view>
158
158
  </slot>
159
159
  <view class="cell-box" v-else>
@@ -9,6 +9,10 @@ const props = defineProps({
9
9
  type: [String, null],
10
10
  default: '',
11
11
  },
12
+ line: {
13
+ type: [Number, String],
14
+ default: 1,
15
+ }, // 配置超过多少行后才显示
12
16
  });
13
17
 
14
18
  const instance = getCurrentInstance() as unknown as ComponentPublicInstance;
@@ -38,7 +42,7 @@ const checkTextOverflow = async () => {
38
42
  let textData = await utils.querySelector<false>('.measure-text', instance);
39
43
 
40
44
  if (containerData && textData && textData.width && containerData.width) {
41
- isTextOverflow.value = textData.width > containerData.width;
45
+ isTextOverflow.value = textData.width > containerData.width * Number(props.line);
42
46
  }
43
47
  };
44
48
 
@@ -141,9 +145,13 @@ const doHide = () => {
141
145
  }
142
146
 
143
147
  .ellipsis-box {
144
- white-space: nowrap;
148
+ display: -webkit-box;
149
+ -webkit-line-clamp: var(--ste-table-popover-line);
150
+ line-clamp: var(--ste-table-popover-line);
151
+ -webkit-box-orient: vertical;
145
152
  overflow: hidden;
146
153
  text-overflow: ellipsis;
154
+ word-break: break-word;
147
155
  // #ifdef H5
148
156
  user-select: none;
149
157
  // #endif
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stellar-ui-plus",
3
- "version": "1.17.21",
3
+ "version": "1.17.23",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "license": "MIT",