@cloudbase/weda-ui-mp 3.15.8 → 3.16.0

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,14 +1,17 @@
1
1
  import destr from '../../../utils/destr';
2
- import deepEqual from '../../../utils/deepEqual';
3
2
  import { callDataSourceApi, callWedaApi } from '../../../utils/tcb';
3
+ import { arrayToMap } from '../../../utils/tool';
4
+ import lodashGet from 'lodash.get';
5
+ import deepEqual from '../../../utils/deepEqual';
4
6
  import { getDefaultQuery } from '../../../utils/getModelParams';
5
- import { isFormatNeedFetch, isSingleForeignFormat } from './formats-util';
7
+ import { isFormatNeedFetch, isFormatWithFilterable } from './formats-util';
8
+ import { textToString } from '../../../utils/platform';
6
9
 
7
- const STATUS_CLOSED = -1;
10
+ const STATUS_CLOSED = 0;
8
11
  const STATUS_LOADING = 1;
9
12
  const STATUS_FAILED = 2;
10
- const STATUS_EMPTY = 3;
11
-
13
+ const SEARCH_STATUS_EMPTY = 3;
14
+ const STATUS_EMPTY = -1;
12
15
  Component({
13
16
  options: {
14
17
  virtualHost: true,
@@ -19,10 +22,6 @@ Component({
19
22
  type: String,
20
23
  value: '请选择',
21
24
  },
22
- mode: {
23
- type: String,
24
- value: 'selector',
25
- },
26
25
  disabled: {
27
26
  type: Boolean,
28
27
  value: false,
@@ -74,10 +73,6 @@ Component({
74
73
  type: Boolean,
75
74
  value: true,
76
75
  },
77
- staticSearchable: {
78
- type: Boolean,
79
- value: true,
80
- },
81
76
  supportManyRelated: {
82
77
  type: Boolean,
83
78
  value: false,
@@ -94,174 +89,76 @@ Component({
94
89
  type: Boolean,
95
90
  value: false,
96
91
  },
92
+ searchable: {
93
+ type: Boolean,
94
+ value: true,
95
+ },
96
+ filterable: {
97
+ type: Boolean,
98
+ value: false,
99
+ },
97
100
  },
98
101
  data: {
99
102
  selectRange: [],
100
- start: '',
101
- end: '',
102
- value: '',
103
- displayValue: '',
104
- isSearch: false,
105
- records: [],
106
- searchRecords: [],
103
+ value: null,
107
104
  loadStatus: 0,
108
- searchStatus: 0,
109
105
  option: [],
110
- searchOption: [],
111
106
  _queryCondition: {},
112
107
  queryParam: { select: { $master: true } },
113
- chooseIndexValue: '',
114
- chooseIndexLable: '',
115
- isTurnPages: false,
116
- pageNo: 1,
117
- prevWhere: null,
108
+ currentPageNo: 1,
109
+ _filterable: false,
110
+ hasNextPage: true,
118
111
  },
119
112
  lifetimes: {
120
113
  attached() {
121
- const { range, format } = this.properties;
122
- let selectRange, start, end, displayValue;
123
-
124
- if (isFormatNeedFetch(format)) {
125
- selectRange = this.data.option.map((item) => item.label);
126
- } else {
127
- selectRange = range.map((item) => item.label);
128
- }
129
- if (isSingleForeignFormat(format)) {
130
- this.setData({
131
- isTurnPages: true,
132
- });
133
- } else if (format === 'x-enum') {
134
- this.setData({
135
- isTurnPages: false,
136
- });
137
- } else {
138
- // 默认
139
- this.setData({
140
- option: range,
141
- loadStatus: range.length > 0 ? 0 : STATUS_CLOSED,
142
- });
114
+ const { range, filterable, format, defaultValue } = this.properties;
115
+ const label = this.getLabels(defaultValue, range);
116
+ console.log(filterable, format);
117
+ if (this.data.value?.[0] === '1') {
118
+ console.log(filterable);
119
+ console.log('99');
143
120
  }
144
121
 
145
122
  this.setData({
146
- selectRange,
147
- start,
148
- end,
149
- displayValue,
123
+ option: range,
124
+ _filterable: format && isFormatWithFilterable(format) ? true : filterable,
125
+ value: [].concat(defaultValue),
126
+ displayValue: label,
150
127
  });
128
+ this._initFetchData({ searchValue: '' });
129
+ },
130
+ detached() {
131
+ const id = this.data.timeId;
132
+ if (id !== '') {
133
+ clearTimeout(id);
134
+ }
151
135
  },
152
136
  },
153
137
  observers: {
154
- 'defaultValue, option': function (defaultValue, option) {
155
- const { range, mode, placeholder, format } = this.properties;
156
-
157
- if (
158
- deepEqual(
159
- {
160
- defaultValue,
161
- option,
162
- range,
163
- mode,
164
- placeholder,
165
- format,
166
- },
167
- this.data.__prev,
168
- )
169
- ) {
138
+ defaultValue: function (defaultValue) {
139
+ const _value = [].concat(defaultValue);
140
+ if (deepEqual(_value, this.data.value)) {
170
141
  return;
171
142
  }
172
-
173
- let value, displayValue;
174
- switch (mode) {
175
- case 'selector': {
176
- // TODO: == 故意的
177
- if (!isFormatNeedFetch(format)) {
178
- const index = range.findIndex((item) => item.value == defaultValue);
179
- // 小程序picker组件,value值表示选择了 range 中的第几个(下标从 0 开始),类型为number
180
- value = index < 0 ? 0 : index;
181
- displayValue = index < 0 ? defaultValue : range[index].label;
182
- // 更新选中值
183
- this.setData({
184
- chooseIndexValue: index < 0 ? defaultValue : range[index].value,
185
- chooseIndexLable: displayValue,
186
- });
187
- } else {
188
- const { chooseIndexValue } = this.data;
189
- const currentValue = defaultValue;
190
- const index = option.findIndex((item) => item.value == currentValue);
191
- if (
192
- !chooseIndexValue &&
193
- this.data.option.length > 0 &&
194
- index === -1 &&
195
- defaultValue &&
196
- defaultValue.length > 0
197
- ) {
198
- // 没查找到,接口查找
199
- this._fetchData({ defaultValue, isUpdate: true });
200
- // 再次判断
201
- if (this.data.chooseIndexValue && this.data.chooseIndexValue.length > 0) {
202
- // 找到了
203
- displayValue = this.data.chooseIndexLable;
204
- }
205
- } else {
206
- value = index < 0 ? 0 : index;
207
- displayValue = index < 0 ? currentValue : option[index].label;
208
- }
209
- // 更新value
210
- this.setData({
211
- chooseIndexValue: currentValue,
212
- chooseIndexLable: displayValue,
213
- });
214
- }
215
- break;
216
- }
217
- default: {
218
- break;
219
- }
220
- }
221
143
  this.setData({
222
- displayValue,
223
- value,
224
- __prev: {
225
- defaultValue,
226
- option,
227
- range,
228
- mode,
229
- placeholder,
230
- format,
231
- },
144
+ value: _value,
232
145
  });
233
- },
234
- range: function (range) {
235
- // 防止range在不改变的情况下重新对option赋值,导致触发option的observer改变选中值
236
- if (JSON.stringify(this.data.oldRange) === JSON.stringify(range)) return;
237
- this.data.oldRange = range;
238
- const { mode, format } = this.properties;
239
- let selectRange = '';
240
- switch (mode) {
241
- case 'selector': {
242
- if (!isFormatNeedFetch(format)) {
243
- selectRange = range.map((item) => item.label);
244
- const stringRange = range.map((item) => ({
245
- ...item,
246
- value: String(item.value),
247
- }));
248
- // 默认
249
- this.setData({
250
- option: stringRange,
251
- loadStatus: range.length > 0 ? 0 : STATUS_CLOSED,
252
- });
253
- }
254
- break;
255
- }
256
- default: {
257
- break;
258
- }
146
+ if (_value.filter((i) => textToString(i)).length) {
147
+ this._initFetchData({ searchValue: '' });
259
148
  }
260
- if (selectRange != '') {
261
- this.setData({
262
- selectRange,
263
- });
149
+ },
150
+ 'value,range': function (value, range) {
151
+ let _option = this.data.option;
152
+ if (!isFormatNeedFetch(this.data.format)) {
153
+ _option = range;
264
154
  }
155
+ const label = this.getLabels(value, _option);
156
+ const checkRange = this.getChecks(value, _option);
157
+ // 默认
158
+ this.setData({
159
+ option: checkRange,
160
+ displayValue: label,
161
+ });
265
162
  },
266
163
  enumName: function (enumName) {
267
164
  if (this.properties.format === 'x-enum' && enumName) {
@@ -279,115 +176,52 @@ Component({
279
176
  return;
280
177
  }
281
178
 
282
- const { format, dataSourceName } = this.properties;
283
- this.setData({ queryParam: _queryParam });
284
- if (
285
- isSingleForeignFormat(format) &&
286
- dataSourceName &&
287
- !this.data.isSearch // 防止多次执行对搜索影响
288
- ) {
289
- this.setData({
290
- records: [],
291
- option: [],
292
- pageNo: 1,
293
- });
294
- this._fetchData({ queryParam: _queryParam });
295
- }
179
+ this.setData({ queryParam: _queryParam }, () => {
180
+ this._initFetchData({ queryParam: _queryParam });
181
+ });
296
182
  },
297
- records: function (records) {
298
- const { primaryField } = this.properties;
299
- if (records && records.length !== 0 && primaryField) {
300
- const option = records.map((item) => {
301
- return {
302
- label: item[primaryField] || item._id,
303
- value: item._id,
304
- name: item[primaryField] || item._id,
305
- };
306
- });
307
- this.setData({ selectRange: option.map((item) => item.label), option });
308
- } else {
183
+ format: function (format) {
184
+ if (isFormatWithFilterable(format)) {
185
+ // 关联关系,自定义查询规则,不走前端过滤
309
186
  this.setData({
310
- selectRange: [].map((item) => item.label),
311
- option: [],
312
- });
313
- }
314
- },
315
- searchRecords: function (searchRecords) {
316
- const { primaryField } = this.properties;
317
- if (searchRecords && searchRecords.length !== 0 && primaryField) {
318
- const option = searchRecords.map((item) => {
319
- return {
320
- label: item[primaryField] || item._id,
321
- value: item._id,
322
- name: item[primaryField] || item._id,
323
- };
187
+ _filterable: true,
324
188
  });
325
- this.setData({ searchOption: option });
326
189
  }
327
190
  },
328
- option: function (options) {
329
- this.triggerEvent('changeOptions', { value: { options } });
191
+ },
192
+ methods: {
193
+ onClosePicker: function () {
194
+ this.setData({
195
+ allPickerShow: false,
196
+ });
197
+ this._initFetchData({ searchValue: '' });
330
198
  },
331
- 'format,defaultValue': function (format, defaultValue) {
199
+ onOpenPicker: function () {
200
+ if (this.data.disabled === true) return;
332
201
  this.setData({
333
- formatNeedFetch: isFormatNeedFetch(format),
202
+ allPickerShow: true,
334
203
  });
335
- if (isFormatNeedFetch(format)) {
336
- this._fetchData({ defaultValue });
337
- }
204
+ this.triggerEvent('focus');
338
205
  },
339
- },
340
- methods: {
341
206
  // 最终选择的选项
342
207
  onSelectPicker: function (e) {
343
- if (this.data.disabled === true) {
344
- return;
345
- }
346
- if (e.detail?.label) {
347
- this.setData({
348
- chooseIndexLable: e.detail.label,
349
- value: e.detail.label,
350
- });
351
- }
352
- if (e.detail?.value) {
353
- this.setData({
354
- chooseIndexValue: e.detail.value,
355
- });
356
- }
357
- if (e.detail?.clear === 'true') {
358
- this.setData({
359
- chooseIndexValue: null,
360
- chooseIndexLable: null,
361
- value: null,
362
- displayValue: '',
363
- });
364
- }
365
- const { displayValue, chooseIndexLable, allPickerShow } = this.data;
366
- this.setData({
367
- allPickerShow: !allPickerShow,
368
- displayValue: chooseIndexLable === '' ? displayValue : chooseIndexLable,
369
- });
370
- const { isSearch, option, searchOption, chooseIndexValue } = this.data;
371
- if (chooseIndexValue && chooseIndexLable !== displayValue) {
372
- const index = (isSearch ? searchOption : option)?.findIndex((item) => item.value === chooseIndexValue);
373
- this.onChange({ detail: { value: index < 0 ? 0 : index } });
374
- } else if (e.detail?.clear === 'true') {
375
- this.onChange({ detail: { value: null } });
376
- }
377
- if (searchOption.length <= 0 && (this.data.dataSourceName?.length > 0 || isFormatNeedFetch(this.data.format))) {
378
- this._fetchData({});
208
+ if (this.data.disabled === true) return;
209
+ if (this.data.multiple) {
210
+ const value = e.detail.map((v) => v.value);
211
+ const options = e.detail.map((v) => ({ label: v.label, value: v.value, extra: { ...v } }));
212
+
213
+ this.setData({ value, allPickerShow: false });
214
+ this.onChange({ detail: { value, context: { options } } });
215
+ } else {
216
+ this.setData({ value: [].concat(e.detail.value), allPickerShow: false });
217
+ this.onChange({ detail: { value: e.detail.value, context: { option: e.detail } } });
379
218
  }
380
219
  },
381
220
  // 获取数据列表:关联关系和主子明细
382
- _fetchData: async function ({
383
- queryParam = this.data.queryParam,
384
- searchValue = '',
385
- defaultValue = '',
386
- pageNo = 1,
387
- isUpdate = false,
388
- }) {
389
- const { dataSourceName, viewId, records, searchRecords } = this.data;
221
+ _fetchData: async function ({ queryParam = this.data.queryParam, searchValue = '', pageNo = 1, _init = false }) {
222
+ const { dataSourceName, viewId, primaryField } = this.data;
390
223
  if (!dataSourceName) return;
224
+ this.setData({ loadStatus: STATUS_LOADING });
391
225
  // 默认筛选条件
392
226
  let _filter = destr(this.data.queryParam.filter) ?? {};
393
227
  // 根据搜索值查询
@@ -395,21 +229,13 @@ Component({
395
229
  const search = this.data.ignoreCase ? '$search_ci' : '$search';
396
230
  _filter = {
397
231
  where: {
398
- $and: [_filter.where, { $and: [{ [this.data.primaryField]: { [`${search}`]: searchValue } }] }],
232
+ $and: [_filter.where, { $and: [{ [primaryField]: { [`${search}`]: searchValue } }] }],
399
233
  },
400
234
  };
401
235
  }
402
- // 查找默认值选项,用于回显
403
- if (defaultValue) {
404
- _filter = {
405
- where: {
406
- $and: [{ $and: [{ _id: { $search: defaultValue } }] }],
407
- },
408
- };
409
- }
410
-
236
+ const records = _init ? [] : this.data.option;
411
237
  let pageSize = 50;
412
- let data = await callDataSourceApi({
238
+ let res = await callDataSourceApi({
413
239
  dataSourceName: dataSourceName,
414
240
  viewId: viewId,
415
241
  methodName: 'wedaGetRecordsV2',
@@ -420,76 +246,100 @@ Component({
420
246
  pageSize: pageSize,
421
247
  },
422
248
  });
423
- const results = data?.records;
424
- if (isUpdate && results && results.length > 0) {
425
- this.setData({
426
- chooseIndexLable: results[0][this.properties.primaryField] || results[0]._id,
427
- chooseIndexValue: results[0]._id,
428
- displayValue: results[0][this.properties.primaryField] || results[0]._id,
249
+ const results = res?.records.map((item) => ({
250
+ ...item,
251
+ label: item[primaryField],
252
+ value: item._id,
253
+ }));
254
+
255
+ let finalRecords = records.concat(results || []);
256
+ finalRecords = this.getUniqueOption(finalRecords);
257
+ const { value } = this.data;
258
+ const unchecked = value?.filter((i) => i && !finalRecords.find((j) => i === j.value));
259
+ // 跨页勾选回显示
260
+ if (unchecked?.length) {
261
+ const uncheckedItem = await this.fetchItem(unchecked);
262
+ uncheckedItem?.forEach((i) => {
263
+ if (i) {
264
+ finalRecords.unshift(i);
265
+ }
429
266
  });
430
- return;
431
267
  }
432
- let status = 0;
268
+ const label = this.getLabels(value, finalRecords);
269
+ const stringRange = this.getChecks(value, finalRecords);
270
+ let status = STATUS_CLOSED;
433
271
  if (!results) {
434
272
  status = STATUS_FAILED;
435
- } else if (results.length === 0) {
436
- status = STATUS_EMPTY;
273
+ } else if (finalRecords.length === 0) {
274
+ status = SEARCH_STATUS_EMPTY;
437
275
  }
438
- const isSearch = this.data.isSearch;
439
- if (this.data.records.length === 0 && results?.length === 0) {
440
- // 当异常的时候,主要为了不引起records的observer变化变化设置默认值
441
- this.setData(isSearch ? { searchStatus: status } : { loadStatus: STATUS_CLOSED });
442
- } else {
443
- this.setData(
444
- isSearch
445
- ? {
446
- searchRecords: searchRecords.concat(
447
- (results ?? []).filter((item) => searchRecords.findIndex((r) => r._id === item._id) < 0) || [],
448
- ),
449
- records: records.concat(
450
- (results ?? []).filter((item) => records.findIndex((r) => r._id === item._id) < 0) || [],
451
- ),
452
- searchStatus: status,
453
- }
454
- : {
455
- searchRecords: searchRecords.concat(
456
- (results ?? []).filter((item) => searchRecords.findIndex((r) => r._id === item._id) < 0) || [],
457
- ),
458
- records: records.concat(
459
- (results ?? []).filter((item) => records.findIndex((r) => r._id === item._id) < 0) || [],
460
- ),
461
- loadStatus: status,
462
- },
463
- );
464
- }
465
- },
466
- _childFetchData: function (data) {
467
- const { isSearch, pageNo, searchValue } = data.detail;
276
+ // 默认
468
277
  this.setData({
469
- isSearch,
278
+ option: stringRange,
279
+ displayValue: label,
280
+ loadStatus: status,
281
+ currentPageNo: pageNo,
282
+ hasNextPage: stringRange?.length < res?.total,
470
283
  });
471
- if (isSearch) {
472
- if (pageNo === 1) {
473
- this.setData({
474
- searchRecords: [],
475
- searchOption: [],
476
- searchStatus: STATUS_LOADING,
477
- });
478
- }
479
- this._fetchData({ searchValue, pageNo });
480
- } else {
481
- if (pageNo === 1) {
482
- this.setData({
483
- records: [],
484
- option: [],
485
- loadStatus: STATUS_LOADING,
486
- });
487
- }
488
- this.setData({
489
- pageNo,
284
+ this.triggerEvent('updateSelect', { value: value, option: stringRange });
285
+ },
286
+ _childFetchData: function (data) {
287
+ if (this.data.hasNextPage) {
288
+ const { pageNo, searchValue } = data.detail;
289
+ this._fetchData({ pageNo, searchValue });
290
+ }
291
+ },
292
+ getLabels: function (values, options) {
293
+ let labels = values;
294
+ if (Array.isArray(values) && Array.isArray(options)) {
295
+ const rm = arrayToMap(options, 'value');
296
+ labels = values.map((d) => {
297
+ const obj = rm[d];
298
+ let item = lodashGet(obj, 'text') ?? lodashGet(obj, 'label') ?? d;
299
+ return textToString(item);
490
300
  });
491
- this._fetchData({ pageNo });
492
301
  }
302
+ if (this.data.multiple) {
303
+ return labels.join(',');
304
+ } else {
305
+ return labels?.[0];
306
+ }
307
+ },
308
+ getChecks: function (values, options) {
309
+ const _values = Array.isArray(values) ? values : [];
310
+ const _options = Array.isArray(options) ? options : [];
311
+ const stringRange = _options.map((item) => {
312
+ const obj = _values.find((el) => el === item.value);
313
+ const check = !!obj;
314
+ const value = String(item.value);
315
+ return { ...item, value, check };
316
+ });
317
+ return stringRange;
318
+ },
319
+ fetchItem: async function (values) {
320
+ const { queryParam, dataSourceName, primaryField } = this.data;
321
+ const _filter = {
322
+ where: {
323
+ $and: [{ $or: values.map((i) => ({ _id: { $search: i } })) }],
324
+ },
325
+ };
326
+ let data = await callDataSourceApi({
327
+ dataSourceName: dataSourceName,
328
+ methodName: 'wedaGetRecordsV2',
329
+ params: {
330
+ ...queryParam,
331
+ filter: _filter,
332
+ pageNumber: 1,
333
+ pageSize: 200,
334
+ },
335
+ });
336
+ return (
337
+ data?.records?.map((item) => ({
338
+ ...item,
339
+ label: item[primaryField],
340
+ value: item._id,
341
+ })) || []
342
+ );
493
343
  },
494
344
  // 获取通用选项集列表
495
345
  _fetchEnumData: async function () {
@@ -501,6 +351,7 @@ Component({
501
351
  PageSize: 10,
502
352
  },
503
353
  });
354
+
504
355
  const config = destr(data?.Items?.[0]?.Config) ?? [];
505
356
  const option = config.map((item) => {
506
357
  return {
@@ -512,34 +363,47 @@ Component({
512
363
  this.setData({
513
364
  selectRange: option.map((item) => item.label),
514
365
  option,
515
- searchOption: option,
516
- loadStatus: option.length > 0 ? 0 : STATUS_CLOSED,
366
+ loadStatus: option.length > 0 ? 0 : STATUS_EMPTY,
517
367
  });
518
368
  },
519
- onChange(e) {
520
- const { range, mode, format } = this.properties;
521
- let displayValue;
522
-
523
- if (!isFormatNeedFetch(format)) {
524
- const data = e.detail?.value != null ? range[e.detail.value] : { label: null, value: null };
525
- this.triggerEvent('change', { ...data, value: data.value, context: { option: data } });
526
- displayValue = data.label;
527
- } else {
528
- const { isSearch, searchOption, option } = this.data;
529
- const opt = isSearch ? searchOption : option;
530
- const data = e.detail?.value != null ? opt[e.detail.value] : { label: null, value: null };
531
- this.triggerEvent('change', { ...data, value: data.value, context: { option: data } });
532
-
533
- displayValue = this.properties.displayValue;
369
+ getUniqueOption: function (option) {
370
+ const optionMap = option.reduce((acc, item) => {
371
+ if (!acc[item.value]) {
372
+ acc[item.value] = item;
373
+ }
374
+ return acc;
375
+ }, {});
376
+ const uniqueOption = Object.values(optionMap)?.filter((item) => textToString(item?.value));
377
+ return uniqueOption;
378
+ },
379
+ // 初始化搜索数据,包括属性变化/搜索值变化
380
+ _initFetchData: function ({ queryParam = this.data.queryParam, searchValue = '' }) {
381
+ clearTimeout(this.data.fetchTimed);
382
+ if (!isFormatWithFilterable(this.data.format)) {
383
+ return;
534
384
  }
535
-
536
- this.setData({ displayValue });
385
+ this.setData({ option: [], pageNo: 1, status: STATUS_LOADING });
386
+ // eslint-disable-next-line rulesdir/no-timer
387
+ this.data.fetchTimed = setTimeout(() => {
388
+ this._fetchData({ queryParam, searchValue, _init: true });
389
+ }, 200);
390
+ },
391
+ onChange(e) {
392
+ this.triggerEvent('change', e.detail);
393
+ this.triggerEvent('updateSelect', { value: e.detail.value, option: this.data.option });
537
394
  },
538
395
  onCancel(e) {
539
396
  this.triggerEvent('cancel', e.detail);
540
397
  },
541
398
  onSearch(event) {
542
- this.triggerEvent('search', { value: event.detail.value });
399
+ const { noEvent, value: searchValue } = event.detail;
400
+
401
+ // 取消不触发搜索事件
402
+ if (!noEvent) {
403
+ this.triggerEvent('search', { value: searchValue });
404
+ }
405
+
406
+ this._initFetchData({ searchValue: event.detail.value });
543
407
  },
544
408
  },
545
409
  });
@@ -2,7 +2,7 @@
2
2
  "component": true,
3
3
  "styleIsolation": "shared",
4
4
  "usingComponents": {
5
- "dropdownSelect": "../../form/select/dropdown-select",
5
+ "dropdownSelect": "./dropdown-select",
6
6
  "wd-form-item-read-only": "../../wd-form-item-read-only"
7
7
  }
8
8
  }