@ctzy-web-client/data-model 1.0.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.
@@ -0,0 +1,678 @@
1
+ import { cloneDeep, isEqual, unset, set, get } from 'lodash';
2
+ import { EventDispatcher, aesEncrypt } from '@ctzy-web-client/support';
3
+ import FilterColumn from './FilterColumn';
4
+ import { Where } from './where/Where';
5
+ import { sortColumn } from '../utils';
6
+
7
+ export class FilterPanel extends EventDispatcher {
8
+ /** @type {FilterColumn[]} */
9
+ _filterColumns = [];
10
+
11
+ /** @type {string[]} */
12
+ _selectedColumnAttrNames = [];
13
+
14
+ _searchValue = '';
15
+
16
+ _searchAttr = '';
17
+
18
+ fieldSearchValue = '';
19
+
20
+ _filterParams = {};
21
+
22
+ existComponent = false;
23
+
24
+ _inited = false;
25
+
26
+ _ready = false;
27
+
28
+ _isChange = false;
29
+
30
+ _allowTriggerParamsChange = 0;
31
+
32
+ _searchFields = [];
33
+
34
+ whereForFilter = false;
35
+
36
+ whereParamName = '';
37
+
38
+ encryptCondition = true;
39
+
40
+ get isInited() {
41
+ return this._inited;
42
+ }
43
+
44
+ get ready() {
45
+ if (!this._inited) {
46
+ return false;
47
+ }
48
+
49
+ return this.existComponent ? this._ready : true;
50
+ }
51
+
52
+ set ready(value) {
53
+ if (!this._inited) {
54
+ return;
55
+ }
56
+
57
+ if (this.ready || this._ready === value) {
58
+ return;
59
+ }
60
+
61
+ this._ready = value;
62
+
63
+ this.emit('ready');
64
+ }
65
+
66
+ /**
67
+ * @memberof FilterPanel
68
+ */
69
+ constructor(dataTable) {
70
+ super();
71
+
72
+ this.dataTable = dataTable;
73
+ this.originFilterParams = {};
74
+ this.originSearchValue = '';
75
+ }
76
+
77
+ _formatFilterColumn(extendFieldInfo) {
78
+ const baseFilterColumnConfig = {
79
+ name: extendFieldInfo.name,
80
+ attrName: extendFieldInfo.name,
81
+ isExtend: true,
82
+ default: extendFieldInfo.defaultValue,
83
+ formComponent: extendFieldInfo.component,
84
+ closable: true,
85
+ title: extendFieldInfo.title,
86
+ fullAttrName: `${this.dataTable.extendField}.${extendFieldInfo.name}`,
87
+ };
88
+
89
+ if (['BwaSelect'].includes(extendFieldInfo.component)) {
90
+ baseFilterColumnConfig.component = 'BwaSingleMenuCondition';
91
+ baseFilterColumnConfig.componentProps = extendFieldInfo.extendInfo;
92
+ }
93
+
94
+ if (['BwaMultiSelect'].includes(extendFieldInfo.component)) {
95
+ baseFilterColumnConfig.component = 'BwaMultipleMenuCondition';
96
+ baseFilterColumnConfig.componentProps = extendFieldInfo.extendInfo;
97
+ }
98
+
99
+ if (
100
+ ['BwaUserSelect'].includes(
101
+ extendFieldInfo.component
102
+ )
103
+ ) {
104
+ baseFilterColumnConfig.component = 'BwaSingleUserCondition';
105
+ }
106
+
107
+ if (
108
+ ['BwaUserMultiSelect'].includes(
109
+ extendFieldInfo.component
110
+ )
111
+ ) {
112
+ baseFilterColumnConfig.component = 'BwaMultiUserCondition';
113
+ }
114
+
115
+ return baseFilterColumnConfig;
116
+ }
117
+
118
+ _parseFilterColumns(extendFieldInfos, filterColumnConfigs) {
119
+ const allowComponents = [
120
+ 'BwaSelect',
121
+ 'BwaMultiSelect',
122
+ 'BwaUserSelect',
123
+ 'BwaUserMultiSelect',
124
+ ];
125
+ extendFieldInfos = extendFieldInfos
126
+ .filter((extendFieldInfo) => extendFieldInfo.type != 1)
127
+ .filter((extendFieldInfo) =>
128
+ allowComponents.includes(extendFieldInfo.component)
129
+ );
130
+
131
+ const attrNames = Array.from(
132
+ new Set(filterColumnConfigs.map((config) => config.attrName))
133
+ );
134
+
135
+ extendFieldInfos = extendFieldInfos.filter(
136
+ (extendFieldInfo) => !attrNames.includes(extendFieldInfo.name)
137
+ );
138
+
139
+ const formatedExtendColumnConfigs = extendFieldInfos.map((item) =>
140
+ this._formatFilterColumn(item)
141
+ );
142
+
143
+ return [...filterColumnConfigs, ...formatedExtendColumnConfigs];
144
+ }
145
+
146
+ init(extendFieldInfos, filterColumnConfigs, filterColumnsOrder) {
147
+
148
+ if (this._inited) {
149
+ return;
150
+ }
151
+
152
+ this._inited = true;
153
+
154
+ filterColumnConfigs = this._parseFilterColumns(
155
+ extendFieldInfos,
156
+ filterColumnConfigs
157
+ );
158
+
159
+ const filterColumns = sortColumn(
160
+ (filterColumnConfigs || []).map(
161
+ (filterColumnConfig) => new FilterColumn(this, filterColumnConfig)
162
+ ),
163
+ filterColumnsOrder
164
+ );
165
+
166
+ this.setColumns(filterColumns);
167
+
168
+ this._selectedColumnAttrNames = this.getAppliedColumns().map(
169
+ (column) => column.fullAttrName
170
+ );
171
+
172
+ this._filterParams = {
173
+ ...this._getDefaultParams(),
174
+ ...this._filterParams,
175
+ };
176
+
177
+ this.changeOriginFilterParams();
178
+
179
+ this._inited = true;
180
+
181
+ this.emit('initCompleted');
182
+ }
183
+
184
+ setSearchFields(searchFields) {
185
+ this._searchFields = searchFields.slice();
186
+ }
187
+
188
+ getSearchFields() {
189
+ return this._searchFields.slice();
190
+ }
191
+
192
+ changeOriginFilterParams(originFilterParams = this.getFilterParams()) {
193
+ this.originFilterParams = cloneDeep(originFilterParams);
194
+
195
+ this._checkChange();
196
+ }
197
+
198
+ changeOriginSearchValue(originSearchValue = this.getSearchValue()) {
199
+ this.originSearchValue = originSearchValue;
200
+
201
+ this._checkChange();
202
+ }
203
+
204
+ isChange() {
205
+ return this._isChange;
206
+ }
207
+
208
+ setIsChange(isChange) {
209
+ if (this._isChange === isChange) {
210
+ return;
211
+ }
212
+
213
+ this._isChange = isChange;
214
+ }
215
+
216
+ _checkChange() {
217
+ this.setIsChange(
218
+ !isEqual(this.originFilterParams, this.getFilterParams()) ||
219
+ this.originSearchValue !== this.getSearchValue()
220
+ );
221
+ }
222
+
223
+ noTriggerParamsChange(callback) {
224
+ this._allowTriggerParamsChange++;
225
+
226
+ callback?.();
227
+
228
+ this._allowTriggerParamsChange--;
229
+ }
230
+
231
+ getSearchValue() {
232
+ return this._searchValue;
233
+ }
234
+
235
+ _triggerParamsChange() {
236
+ if (this._allowTriggerParamsChange > 0) {
237
+ return;
238
+ }
239
+
240
+ this.emit('params-change');
241
+ }
242
+
243
+ setSeachValue(value, isSearch = false) {
244
+ this._searchValue = value;
245
+
246
+ this._checkChange();
247
+
248
+ if (!isSearch) {
249
+ this._triggerParamsChange();
250
+ }
251
+ }
252
+
253
+ setFilterParam(column, value, isSearch = false) {
254
+ if (this.getFilterParam(column) === value) {
255
+ return;
256
+ }
257
+
258
+ // const filterParams = this.getFilterParams();
259
+
260
+ set(this._filterParams, column.fullAttrName, value);
261
+
262
+ this._checkChange();
263
+
264
+ if (!isSearch) {
265
+ this._triggerParamsChange();
266
+ }
267
+
268
+ // this._setFilterParams(filterParams);
269
+
270
+ this.emit('change-search-value');
271
+ }
272
+
273
+ getFilterParam(column) {
274
+ return get(this._filterParams, column.fullAttrName);
275
+ }
276
+
277
+ setSearchAttr(searchAttr) {
278
+ this._searchAttr = searchAttr;
279
+ }
280
+
281
+ getSearchAttr() {
282
+ return this._searchAttr;
283
+ }
284
+
285
+ _setFilterParams(filterParams, ignoreEmit = false) {
286
+ this._filterParams = cloneDeep(filterParams);
287
+
288
+ this._checkChange();
289
+
290
+ if (!ignoreEmit) {
291
+ this._triggerParamsChange();
292
+ }
293
+ }
294
+
295
+ getFilterParams() {
296
+ return this._filterParams;
297
+ }
298
+
299
+ /**
300
+ * @param {FilterColumn} filterColumn
301
+ * @memberof FilterPanel
302
+ */
303
+ appliedColumn(filterColumn) {
304
+ this._setFilterParams(
305
+ {
306
+ ...this._getDefaultParams(),
307
+ ...this.getFilterParams(),
308
+ },
309
+ true
310
+ );
311
+ }
312
+
313
+ /**
314
+ * @param {FilterColumn} filterColumn
315
+ * @memberof FilterPanel
316
+ */
317
+ cancelAppliedColumn(filterColumn) {
318
+ const filterParams = {
319
+ ...this._getDefaultParams(),
320
+ ...this.getFilterParams(),
321
+ };
322
+
323
+ unset(filterParams, filterColumn.fullAttrName);
324
+
325
+ this._setFilterParams(filterParams, true);
326
+ }
327
+
328
+ _getDefaultParams() {
329
+ const filterParams = {};
330
+
331
+ for (const filterColumn of this.getVisibelColumns()) {
332
+ set(
333
+ filterParams,
334
+ filterColumn.fullAttrName,
335
+ typeof filterColumn.default === 'function'
336
+ ? filterColumn.default()
337
+ : filterColumn.default
338
+ );
339
+ }
340
+
341
+ return filterParams;
342
+ }
343
+
344
+ resetFilterParams() {
345
+ this.noTriggerParamsChange(() => {
346
+ this._setFilterParams(this.originFilterParams);
347
+ this.setSeachValue('');
348
+ });
349
+
350
+ this._triggerParamsChange();
351
+ }
352
+
353
+ /**
354
+ * @param {FilterColumn} filterColumn
355
+ * @memberof FilterPanel
356
+ */
357
+ addColumn(filterColumn) {
358
+ if (this.getColumn(filterColumn.fullAttrName)) {
359
+ throw new Error(
360
+ '无法添加两个字段名称一样的字段:' + filterColumn.fullAttrName
361
+ );
362
+ }
363
+
364
+ this._filterColumns.push(filterColumn);
365
+ }
366
+
367
+ /**
368
+ *
369
+ * @param {FilterColumn} filterColumn
370
+ * @memberof FilterPanel
371
+ */
372
+ removeColumn(filterColumn) {
373
+ this._filterColumns = this._filterColumns.filter(
374
+ (column) => column.attrName !== filterColumn.attrName
375
+ );
376
+ }
377
+
378
+ /**
379
+ * @param {string} name
380
+ * @memberof FilterPanel
381
+ */
382
+ getColumn(name) {
383
+ return (
384
+ this.getColumns().find((column) => column.fullAttrName === name) ?? null
385
+ );
386
+ }
387
+
388
+ /**
389
+ * @param {FilterColumn[]} fillterColumns
390
+ * @memberof FilterPanel
391
+ */
392
+ setColumns(fillterColumns) {
393
+ this._filterColumns = [];
394
+ for (let filterColumn of fillterColumns) {
395
+ this.addColumn(filterColumn);
396
+ }
397
+ }
398
+
399
+ getColumns() {
400
+ return this._filterColumns.slice();
401
+ }
402
+
403
+ getVisibelColumns() {
404
+ return this.getColumns().filter((column) => column.visible);
405
+ }
406
+
407
+ getFxiedColumns() {
408
+ return this.getVisibelColumns().filter((column) => !column.closable);
409
+ }
410
+
411
+ getClosableColumns() {
412
+ return this.getColumns().filter((column) => column.closable);
413
+ }
414
+
415
+ getSearchClosableColumns() {
416
+ const closableColumns = this.getClosableColumns();
417
+
418
+ return closableColumns.filter((column) => {
419
+ return (
420
+ column.title.includes(this.fieldSearchValue) ||
421
+ column.fullAttrName.toLocaleLowerCase().includes(this.fieldSearchValue)
422
+ );
423
+ });
424
+ }
425
+
426
+ getSelectedColumnAttrNames() {
427
+ return this._selectedColumnAttrNames.slice();
428
+ }
429
+
430
+ setSelectedColumnAttrNames(v) {
431
+ this._selectedColumnAttrNames = v;
432
+
433
+ for (let column of this.getClosableColumns()) {
434
+ column.visible = this._selectedColumnAttrNames.includes(
435
+ column.fullAttrName
436
+ );
437
+ }
438
+
439
+ this.emit('selected-column-change');
440
+ }
441
+
442
+ closeColumn(column) {
443
+ const selectedColumnAttrNames = this.getSelectedColumnAttrNames().filter(
444
+ (name) => name !== column.fullAttrName
445
+ );
446
+
447
+ this.setSelectedColumnAttrNames(selectedColumnAttrNames);
448
+ }
449
+
450
+ getSelectedColumns() {
451
+ return this._selectedColumnAttrNames
452
+ .map((attrName) => this.getColumn(attrName))
453
+ .filter(Boolean)
454
+ .filter((column) => column.closable);
455
+ }
456
+
457
+ getAppliedColumns() {
458
+ return this.getFxiedColumns()
459
+ .concat(this.getSelectedColumns())
460
+ .filter((column) => column.visible);
461
+ }
462
+
463
+ _parseWhereAttrMapping(where, column, params) {
464
+ const keys = Object.keys(column.attrMapping || {});
465
+
466
+ if (!keys.length) {
467
+ return;
468
+ }
469
+
470
+ let group = null;
471
+
472
+ if (column.twoFieldsDatePicker) {
473
+ const startInfo = column.attrMapping?.start;
474
+ const endInfo = column.attrMapping?.end;
475
+
476
+ if (!startInfo || !endInfo) {
477
+ return;
478
+ }
479
+
480
+ const startName = startInfo.name
481
+ .replace('${name}', column.name)
482
+ .replace('${key}', 'start');
483
+
484
+ const endName = endInfo.name
485
+ .replace('${name}', column.name)
486
+ .replace('${key}', 'end');
487
+
488
+ const object = get(
489
+ params,
490
+ this._formatFilterParamName(column.fullAttrName)
491
+ );
492
+
493
+ const start = get(object || {}, 'start');
494
+ const end = get(object || {}, 'end');
495
+
496
+ if (start && end) {
497
+ const group = where.addGroup();
498
+
499
+ const startGroup = group.addOrGroup();
500
+
501
+ const endGroup = group.addOrGroup();
502
+
503
+ startGroup.addCondition(startName, '>=', start);
504
+ startGroup.addCondition(startName, '<=', end);
505
+
506
+ endGroup.addCondition(endName, '>=', start);
507
+ endGroup.addCondition(endName, '<=', end);
508
+ }
509
+
510
+ return;
511
+ }
512
+
513
+ for (const key of keys) {
514
+ const info = column.attrMapping[key];
515
+
516
+ if (!info || typeof info !== 'object') {
517
+ continue;
518
+ }
519
+
520
+ const name = info.name
521
+ .replace('${name}', column.name)
522
+ .replace('${key}', key);
523
+
524
+ const object = get(
525
+ params,
526
+ this._formatFilterParamName(column.fullAttrName)
527
+ );
528
+ const value = get(object || {}, key);
529
+
530
+ if (value) {
531
+ group = group || where.addGroup();
532
+
533
+ switch (column.conditionOper) {
534
+ case 'OR':
535
+ group.addOrCondition(name, info.op, value);
536
+ break;
537
+ case 'AND':
538
+ default:
539
+ group.addCondition(name, info.op, value);
540
+ }
541
+ }
542
+ }
543
+ }
544
+
545
+ /**
546
+ * 获取where条件
547
+ * @param {Object} params 参数
548
+ * @returns {Where} where条件
549
+ */
550
+ _getWhere(params) {
551
+ const where = new Where();
552
+
553
+ const columns = this.getAppliedColumns();
554
+
555
+ for (const column of columns) {
556
+ const key = this._formatFilterParamName(column.fullAttrName);
557
+ const value = get(params, key);
558
+
559
+ if (Array.isArray(value)) {
560
+ if (value.length === 0) {
561
+ continue;
562
+ }
563
+
564
+ const isMultipleColumn = [
565
+ 'BwaMultiSelect',
566
+ 'BwaUserMultiSelect',
567
+ ].includes(column.formComponent);
568
+
569
+ where.addCondition(
570
+ key,
571
+ isMultipleColumn ? 'json_contains' : 'in',
572
+ value
573
+ );
574
+ continue;
575
+ }
576
+
577
+ if (typeof value === 'object') {
578
+ if (!value) {
579
+ continue;
580
+ }
581
+
582
+ this._parseWhereAttrMapping(where, column, params);
583
+
584
+ continue;
585
+ }
586
+
587
+ if (value) {
588
+ where.addCondition(key, '=', value);
589
+ }
590
+ }
591
+
592
+ if (this.getSearchFields().length) {
593
+ if (this.getSearchValue()) {
594
+ const group = where.addGroup();
595
+
596
+ for (let field of this.getSearchFields()) {
597
+ group.addOrCondition(field, 'like', `%${this.getSearchValue()}%`);
598
+ }
599
+ }
600
+ }
601
+
602
+ return this.encryptCondition
603
+ ? aesEncrypt(JSON.stringify(where), 'bwa-mkbl')
604
+ : JSON.stringify(where);
605
+ }
606
+
607
+ _formatFilterParamName(paramName) {
608
+ const column = this.getColumn(paramName);
609
+
610
+ if (!column) {
611
+ return paramName;
612
+ }
613
+
614
+ let segments = column.fullAttrName.split('.');
615
+ segments.pop();
616
+
617
+ return [...segments, column.name].join('.');
618
+ }
619
+
620
+ _formatFilterParam(params, column, value) {
621
+ const key = this._formatFilterParamName(column.fullAttrName);
622
+
623
+ if (
624
+ value &&
625
+ !Array.isArray(value) &&
626
+ typeof value === 'object' &&
627
+ column.attrMapping &&
628
+ typeof column.attrMapping === 'object' &&
629
+ Object.values(column.attrMapping).every(
630
+ (value) => typeof value === 'string'
631
+ )
632
+ ) {
633
+ for (const key of Reflect.ownKeys(column.attrMapping)) {
634
+ set(params, column.attrMapping[key], value[key]);
635
+ }
636
+ return;
637
+ }
638
+
639
+ set(params, key, value);
640
+ }
641
+
642
+ _getAjaxFilterParams() {
643
+ const filterParams = this.getFilterParams();
644
+
645
+ const columns = this.getColumns();
646
+
647
+ const params = {};
648
+
649
+ for (const column of columns) {
650
+ this._formatFilterParam(
651
+ params,
652
+ column,
653
+ get(filterParams, column.fullAttrName)
654
+ );
655
+ }
656
+
657
+ return params;
658
+ }
659
+
660
+ getAjaxParams() {
661
+ let ajaxFilterParams = this._getAjaxFilterParams();
662
+
663
+ if (this.whereForFilter) {
664
+ return {
665
+ [this.whereParamName]: this._getWhere(ajaxFilterParams),
666
+ };
667
+ }
668
+
669
+ if (this.getSearchAttr()) {
670
+ ajaxFilterParams = {
671
+ [this.getSearchAttr()]: this.getSearchValue(),
672
+ ...ajaxFilterParams,
673
+ };
674
+ }
675
+
676
+ return ajaxFilterParams;
677
+ }
678
+ }