@ibiz-template/runtime 0.5.0-beta.2 → 0.5.0-beta.4

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.
Files changed (63) hide show
  1. package/dist/index.esm.js +774 -633
  2. package/dist/index.system.min.js +1 -4
  3. package/out/controller/common/control/md-control.controller.d.ts +10 -0
  4. package/out/controller/common/control/md-control.controller.d.ts.map +1 -1
  5. package/out/controller/common/control/md-control.controller.js +37 -0
  6. package/out/controller/control/data-view/data-view.controller.d.ts +8 -7
  7. package/out/controller/control/data-view/data-view.controller.d.ts.map +1 -1
  8. package/out/controller/control/data-view/data-view.controller.js +9 -21
  9. package/out/controller/control/form/edit-form/edit-form.controller.d.ts +20 -0
  10. package/out/controller/control/form/edit-form/edit-form.controller.d.ts.map +1 -1
  11. package/out/controller/control/form/edit-form/edit-form.controller.js +53 -8
  12. package/out/controller/control/grid/grid/grid.controller.d.ts +10 -0
  13. package/out/controller/control/grid/grid/grid.controller.d.ts.map +1 -1
  14. package/out/controller/control/grid/grid/grid.controller.js +16 -14
  15. package/out/controller/control/list/list.controller.d.ts +8 -7
  16. package/out/controller/control/list/list.controller.d.ts.map +1 -1
  17. package/out/controller/control/list/list.controller.js +9 -21
  18. package/out/controller/control/md-ctrl/md-ctrl.controller.d.ts +0 -9
  19. package/out/controller/control/md-ctrl/md-ctrl.controller.d.ts.map +1 -1
  20. package/out/controller/control/md-ctrl/md-ctrl.controller.js +0 -23
  21. package/out/controller/control/search-bar/search-bar.controller.d.ts +9 -1
  22. package/out/controller/control/search-bar/search-bar.controller.d.ts.map +1 -1
  23. package/out/controller/control/search-bar/search-bar.controller.js +34 -11
  24. package/out/controller/control/tree/tree.controller.d.ts +13 -5
  25. package/out/controller/control/tree/tree.controller.d.ts.map +1 -1
  26. package/out/controller/control/tree/tree.controller.js +39 -22
  27. package/out/controller/hub.controller.d.ts.map +1 -1
  28. package/out/controller/hub.controller.js +11 -2
  29. package/out/global/global-util/global-util.d.ts +1 -2
  30. package/out/global/global-util/global-util.d.ts.map +1 -1
  31. package/out/global/global-util/global-util.js +1 -2
  32. package/out/interface/controller/state/control/i-search-bar.state.d.ts +1 -5
  33. package/out/interface/controller/state/control/i-search-bar.state.d.ts.map +1 -1
  34. package/out/interface/service/i-data-entity/i-data-entity.d.ts +17 -0
  35. package/out/interface/service/i-data-entity/i-data-entity.d.ts.map +1 -1
  36. package/out/service/app-data-entity/app-data-entity.d.ts +9 -0
  37. package/out/service/app-data-entity/app-data-entity.d.ts.map +1 -1
  38. package/out/service/app-data-entity/app-data-entity.js +41 -11
  39. package/out/service/dto/method.dto.js +1 -1
  40. package/out/service/utils/de-cache/de-cache.d.ts.map +1 -1
  41. package/out/service/utils/de-cache/de-cache.js +3 -0
  42. package/out/ui-action/provider/loginout-ui-action-provider.js +1 -1
  43. package/out/utils/index.d.ts +1 -0
  44. package/out/utils/index.d.ts.map +1 -1
  45. package/out/utils/index.js +1 -0
  46. package/package.json +6 -6
  47. package/src/controller/common/control/md-control.controller.ts +46 -0
  48. package/src/controller/control/data-view/data-view.controller.ts +12 -19
  49. package/src/controller/control/form/edit-form/edit-form.controller.ts +51 -7
  50. package/src/controller/control/grid/grid/grid.controller.ts +20 -12
  51. package/src/controller/control/list/list.controller.ts +12 -19
  52. package/src/controller/control/md-ctrl/md-ctrl.controller.ts +0 -22
  53. package/src/controller/control/search-bar/search-bar.controller.ts +45 -11
  54. package/src/controller/control/tree/tree.controller.ts +62 -26
  55. package/src/controller/hub.controller.ts +11 -2
  56. package/src/global/global-util/global-util.ts +1 -3
  57. package/src/interface/controller/state/control/i-search-bar.state.ts +1 -6
  58. package/src/interface/service/i-data-entity/i-data-entity.ts +19 -0
  59. package/src/service/app-data-entity/app-data-entity.ts +46 -11
  60. package/src/service/dto/method.dto.ts +1 -1
  61. package/src/service/utils/de-cache/de-cache.ts +3 -0
  62. package/src/ui-action/provider/loginout-ui-action-provider.ts +1 -1
  63. package/src/utils/index.ts +1 -0
@@ -54,6 +54,17 @@ export class EditFormController
54
54
  >;
55
55
  }
56
56
 
57
+ /**
58
+ * 表单旧数据
59
+ *
60
+ * @author zk
61
+ * @date 2023-12-20 11:12:43
62
+ * @protected
63
+ * @type {IData}
64
+ * @memberof FormController
65
+ */
66
+ protected oldData: IData = new ControlVO();
67
+
57
68
  /**
58
69
  * 初始化方法
59
70
  *
@@ -212,6 +223,8 @@ export class EditFormController
212
223
 
213
224
  this.state.modified = false;
214
225
  this.state.data = res.data;
226
+ // 缓存旧数据
227
+ this.oldData = this.data.clone();
215
228
  this.formStateNotify(FormNotifyState.LOAD);
216
229
 
217
230
  await this.evt.emit('onLoadSuccess', undefined);
@@ -276,6 +289,8 @@ export class EditFormController
276
289
  } else {
277
290
  mergeInLeft(this.data, res.data);
278
291
  }
292
+ // 保存结束后更新旧数据
293
+ this.oldData = this.data.clone();
279
294
  this.data.tempsrfkey = this.data.srfkey;
280
295
  }
281
296
  this.state.modified = false;
@@ -510,16 +525,45 @@ export class EditFormController
510
525
  * @return {*} {Promise<void>}
511
526
  */
512
527
  async autoSave(): Promise<void> {
513
- if (this.model.enableAutoSave) {
514
- // 自动保存静默,报错直接控制台输出
515
- try {
516
- await this.save({ silent: true, noFillBack: true });
517
- } catch (error) {
518
- ibiz.log.error(error);
519
- }
528
+ if (!this.model.enableAutoSave) {
529
+ return;
530
+ }
531
+ // todo 临时模型数据 节流保存
532
+ const { demand } = this.model as IData;
533
+ // 自动保存静默,报错直接控制台输出
534
+ const saveParam: FormSaveParams = { silent: true, noFillBack: true };
535
+ if (demand) {
536
+ saveParam.data = this.getDiffData();
537
+ }
538
+ try {
539
+ await this.save(saveParam);
540
+ } catch (error) {
541
+ ibiz.log.error(error);
520
542
  }
521
543
  }
522
544
 
545
+ /**
546
+ * 比较旧数据跟当前数据的差异返回差异数据
547
+ *
548
+ * @author zk
549
+ * @date 2023-12-20 10:12:06
550
+ * @protected
551
+ * @return {*} {IData}
552
+ * @memberof EditFormController
553
+ */
554
+ protected getDiffData(): IData {
555
+ const { data } = this.state;
556
+ const diffData: IData = {};
557
+ Object.keys(data).forEach(key => {
558
+ // 值不一致 || 属性为主键
559
+ if (data[key] !== this.oldData[key] || key === data.srfkeyfield) {
560
+ diffData[key] = data[key];
561
+ }
562
+ });
563
+ diffData.srfuf = data.srfuf;
564
+ return new ControlVO(diffData, (this.oldData as ControlVO).$dataUIMap);
565
+ }
566
+
523
567
  /**
524
568
  * 设置simple模式的数据
525
569
  * @author lxm
@@ -844,6 +844,22 @@ export class GridController
844
844
  this.evt.emit('onRowEditChange', { row });
845
845
  }
846
846
 
847
+ /**
848
+ * 获取部件默认排序模型
849
+ * @return {*}
850
+ * @author: zhujiamin
851
+ * @Date: 2023-12-28 18:43:27
852
+ */
853
+ getSortModel(): {
854
+ minorSortAppDEFieldId: string | undefined;
855
+ minorSortDir: string | undefined;
856
+ } {
857
+ return {
858
+ minorSortAppDEFieldId: this.model.minorSortAppDEFieldId,
859
+ minorSortDir: this.model.minorSortDir,
860
+ };
861
+ }
862
+
847
863
  /**
848
864
  * 设置排序
849
865
  *
@@ -853,19 +869,11 @@ export class GridController
853
869
  * @param {string} order 排序顺序
854
870
  */
855
871
  setSort(fieldId?: string, order?: 'asc' | 'desc'): void {
856
- if (fieldId && order) {
857
- const fieldName = this.fieldIdNameMap.get(fieldId)!.toLowerCase();
858
- super.setSort(fieldName, order);
859
- } else {
860
- // 设置默认排序或者置空
861
- const { minorSortAppDEFieldId, minorSortDir } = this.model;
862
- if (minorSortAppDEFieldId && minorSortDir) {
863
- const fieldName = this.fieldIdNameMap.get(minorSortAppDEFieldId)!;
864
- this.state.sortQuery = `${fieldName.toLowerCase()},${minorSortDir.toLowerCase()}`;
865
- } else {
866
- this.state.sortQuery = '';
867
- }
872
+ let fieldName;
873
+ if (fieldId) {
874
+ fieldName = this.fieldIdNameMap.get(fieldId)!.toLowerCase();
868
875
  }
876
+ super.setSort(fieldName, order);
869
877
  }
870
878
 
871
879
  /**
@@ -29,26 +29,19 @@ export class ListController
29
29
  }
30
30
 
31
31
  /**
32
- * 设置排序
33
- *
34
- * @author lxm
35
- * @date 2022-09-28 13:09:44
36
- * @param {string} key 排序字段
37
- * @param {string} order 排序顺序
32
+ * 获取部件默认排序模型
33
+ * @return {*}
34
+ * @author: zhujiamin
35
+ * @Date: 2023-12-28 18:43:27
38
36
  */
39
- setSort(key?: string, order?: 'asc' | 'desc'): void {
40
- if (key && order) {
41
- super.setSort(key, order);
42
- } else {
43
- // 设置默认排序或者置空
44
- const { minorSortAppDEFieldId, minorSortDir } = this.model;
45
- if (minorSortAppDEFieldId && minorSortDir) {
46
- const fieldName = this.fieldIdNameMap.get(minorSortAppDEFieldId)!;
47
- this.state.sortQuery = `${fieldName.toLowerCase()},${minorSortDir.toLowerCase()}`;
48
- } else {
49
- this.state.sortQuery = '';
50
- }
51
- }
37
+ getSortModel(): {
38
+ minorSortAppDEFieldId: string | undefined;
39
+ minorSortDir: string | undefined;
40
+ } {
41
+ return {
42
+ minorSortAppDEFieldId: this.model.minorSortAppDEFieldId,
43
+ minorSortDir: this.model.minorSortDir,
44
+ };
52
45
  }
53
46
 
54
47
  /**
@@ -53,28 +53,6 @@ export class MDCtrlController
53
53
  this.setSort();
54
54
  }
55
55
 
56
- /**
57
- * 设置排序
58
- *
59
- * @author lxm
60
- * @date 2022-09-28 13:09:44
61
- * @param {string} key 排序字段
62
- * @param {string} order 排序顺序
63
- */
64
- setSort(key?: string, order?: 'asc' | 'desc'): void {
65
- if (key && order) {
66
- super.setSort(key, order);
67
- } else {
68
- // 设置默认排序或者置空
69
- const { minorSortAppDEFieldId, minorSortDir } = this.model;
70
- if (minorSortAppDEFieldId && minorSortDir) {
71
- this.state.sortQuery = `${minorSortAppDEFieldId.toLowerCase()},${minorSortDir.toLowerCase()}`;
72
- } else {
73
- this.state.sortQuery = '';
74
- }
75
- }
76
- }
77
-
78
56
  /**
79
57
  * 加载更多
80
58
  * @author lxm
@@ -1,4 +1,8 @@
1
- import { mergeInLeft, recursiveIterate } from '@ibiz-template/core';
1
+ import {
2
+ RuntimeError,
3
+ mergeInLeft,
4
+ recursiveIterate,
5
+ } from '@ibiz-template/core';
2
6
  import { IAppDataEntity, ISearchBar } from '@ibiz/model-core';
3
7
  import { isNil } from 'ramda';
4
8
  import {
@@ -269,7 +273,7 @@ export class SearchBarController
269
273
  }
270
274
 
271
275
  /**
272
- * 格式化过滤项
276
+ * 格式化过滤项 (后续如果修改这里的逻辑记得把下方的反推函数parseFilters也跟着修改!)
273
277
  * @author lxm
274
278
  * @date 2023-10-16 03:45:41
275
279
  * @param {IFilterNode} node
@@ -293,6 +297,34 @@ export class SearchBarController
293
297
  };
294
298
  }
295
299
 
300
+ /**
301
+ * 根据格式化后的过滤项反推出过滤项树节点数据集合
302
+ * @param {IData} data
303
+ * @return {*}
304
+ * @author: zhujiamin
305
+ * @Date: 2023-12-28 09:47:45
306
+ */
307
+ parseFilters(data: IData): IFilterNode {
308
+ if (data.condtype === 'GROUP') {
309
+ return {
310
+ leaf: false,
311
+ logicType: data.condop === 'AND' ? 'AND' : 'OR',
312
+ children: (data.searchconds || []).map((item: IData) =>
313
+ this.parseFilters(item),
314
+ ),
315
+ };
316
+ }
317
+ if (data.condtype === 'DEFIELD') {
318
+ return {
319
+ leaf: true,
320
+ field: data.fieldname || null,
321
+ valueOP: data.condop || null,
322
+ value: data.value || null,
323
+ };
324
+ }
325
+ throw new RuntimeError(`无效的condtype:${data.condtype}`);
326
+ }
327
+
296
328
  /**
297
329
  * 获取初始过滤项树节点数据集合
298
330
  * @return {*}
@@ -340,10 +372,6 @@ export class SearchBarController
340
372
  tempGroup.searchGroupData.columnstates =
341
373
  tempData.theme_model.columnstates;
342
374
  }
343
- if (tempData.theme_model.filternodes) {
344
- tempGroup.searchGroupData.filternodes =
345
- tempData.theme_model.filternodes;
346
- }
347
375
  if (tempData.theme_model.searchconds) {
348
376
  tempGroup.searchGroupData.searchconds =
349
377
  tempData.theme_model.searchconds;
@@ -353,7 +381,7 @@ export class SearchBarController
353
381
  tempGroup.show = tempData.valid_flag === '1';
354
382
  }
355
383
  } catch (error) {
356
- ibiz.log.error(error);
384
+ ibiz.log.error(`${item.data}非标准JSON格式:`, error);
357
385
  }
358
386
  }
359
387
  return tempGroup;
@@ -411,11 +439,9 @@ export class SearchBarController
411
439
  if (this.grid && this.state.selectedSearchGroupItem) {
412
440
  const filters = this.calcFilters();
413
441
  const saveParams = {
414
- filternodes: this.state.filterNodes,
415
442
  searchconds: filters,
416
443
  sort: this.grid.state.sortQuery,
417
444
  columnstates: this.grid.state.columnStates,
418
- show: this.state.selectedSearchGroupItem.show,
419
445
  };
420
446
  // 根据是否保存过决定是更新还是新建
421
447
  if (this.state.selectedSearchGroupItem.saved) {
@@ -459,8 +485,16 @@ export class SearchBarController
459
485
  groupItem.show = true;
460
486
  }
461
487
  }
462
- if (groupItem.searchGroupData && groupItem.searchGroupData.filternodes) {
463
- this.state.filterNodes = groupItem.searchGroupData.filternodes;
488
+ if (
489
+ groupItem.searchGroupData &&
490
+ groupItem.searchGroupData.searchconds &&
491
+ groupItem.searchGroupData.searchconds.length > 0
492
+ ) {
493
+ // 根据后台标准的searchconds计算出 前端回显的树形结构FilterNodes
494
+ const filterNodes = groupItem.searchGroupData.searchconds.map(item =>
495
+ this.parseFilters(item),
496
+ );
497
+ this.state.filterNodes = filterNodes;
464
498
  } else {
465
499
  this.state.filterNodes = this.getOriginFilterNodes();
466
500
  }
@@ -6,6 +6,7 @@ import {
6
6
  } from '@ibiz-template/core';
7
7
  import {
8
8
  IDETBUIActionItem,
9
+ IDEToolbarItem,
9
10
  IDETree,
10
11
  IDETreeDataSetNode,
11
12
  IDETreeNode,
@@ -21,11 +22,7 @@ import { UIActionUtil } from '../../../ui-action';
21
22
  import { MDControlController } from '../../common';
22
23
  import { ContextMenuController } from '../context-menu';
23
24
  import { TreeService } from './tree.service';
24
- import {
25
- calcDeCodeNameById,
26
- getChildNodeRSs,
27
- getUIActionItemsByActionLevel,
28
- } from '../../../model';
25
+ import { calcDeCodeNameById, getChildNodeRSs } from '../../../model';
29
26
  import { ControllerEvent } from '../../utils';
30
27
 
31
28
  export type DropNodeRS = {
@@ -81,11 +78,19 @@ export class TreeController<
81
78
  dropNodeRss = new Map<string, DropNodeRS[]>();
82
79
 
83
80
  /**
84
- * 节点对应的上下文菜单里第一个行为级别为常用操作的项
81
+ * 节点上下文解析后信息`
85
82
  * @author lxm
86
- * @date 2023-12-19 03:14:03
83
+ * @date 2023-12-29 10:38:37
87
84
  */
88
- nodeClickTBUIActionItem = new Map<string, IDETBUIActionItem>();
85
+ contextMenuInfos: {
86
+ [p: string]: {
87
+ /**
88
+ * 上下文菜单里第一个行为级别为常用操作的项
89
+ */
90
+ clickTBUIActionItem?: IDETBUIActionItem;
91
+ onlyOneActionItem: boolean;
92
+ };
93
+ } = {};
89
94
 
90
95
  protected initState(): void {
91
96
  super.initState();
@@ -208,11 +213,29 @@ export class TreeController<
208
213
  */
209
214
  protected initNodeClickTBUIActionItem(): void {
210
215
  this.model.detreeNodes?.forEach(node => {
211
- if (node.decontextMenu?.detoolbarItems?.length) {
212
- const items = getUIActionItemsByActionLevel(node.decontextMenu, 200);
213
- if (items.length > 0) {
214
- this.nodeClickTBUIActionItem.set(node.id!, items[0]);
215
- }
216
+ const contextMenu = node.decontextMenu;
217
+ if (contextMenu?.detoolbarItems?.length) {
218
+ let itemNum = 0;
219
+ const items: IDETBUIActionItem[] = [];
220
+
221
+ recursiveIterate(
222
+ contextMenu,
223
+ (item: IDEToolbarItem) => {
224
+ if (item.itemType === 'DEUIACTION') {
225
+ itemNum += 1;
226
+ const uiItem = item as IDETBUIActionItem;
227
+ if (uiItem.actionLevel === 200) {
228
+ items.push(uiItem);
229
+ }
230
+ }
231
+ },
232
+ { childrenFields: ['detoolbarItems'] },
233
+ );
234
+
235
+ this.contextMenuInfos[node.id!] = {
236
+ onlyOneActionItem: itemNum === 1,
237
+ clickTBUIActionItem: items[0],
238
+ };
216
239
  }
217
240
  });
218
241
  }
@@ -325,9 +348,15 @@ export class TreeController<
325
348
  event: MouseEvent,
326
349
  ): Promise<void> {
327
350
  // 节点有配置常用操作的上下文菜单时,触发界面行为,后续逻辑都不走
328
- if (this.nodeClickTBUIActionItem.has(nodeData.nodeId)) {
329
- const item = this.nodeClickTBUIActionItem.get(nodeData.nodeId)!;
330
- return this.doUIAction(item.uiactionId!, nodeData, event, item.appId);
351
+ const clickActionItem =
352
+ this.contextMenuInfos[nodeData.nodeId]?.clickTBUIActionItem;
353
+ if (clickActionItem) {
354
+ return this.doUIAction(
355
+ clickActionItem.uiactionId!,
356
+ nodeData,
357
+ event,
358
+ clickActionItem.appId,
359
+ );
331
360
  }
332
361
 
333
362
  // 导航的时候,没有导航视图的时候,节点后续点击逻辑都不走,也不选中
@@ -632,16 +661,23 @@ export class TreeController<
632
661
  );
633
662
  }
634
663
  // * 前后的情况
635
- if (draggingNode.parent?.id !== dropNode.parent?.id) {
636
- // 父不一样的时候需要判断能否移入到对方的父节点内
637
- return !!this.findDropNodeRS(
638
- dropNode.parent!.nodeId!,
639
- draggingNodeModel.appDataEntityId!,
640
- );
664
+
665
+ // 父相同的情况下,就是排序,看当前节点是否能排序
666
+ if (draggingNode.parent?.id === dropNode.parent?.id) {
667
+ const currentNodeModel = this.getNodeModel(dropNode.nodeId)!;
668
+ return currentNodeModel?.allowOrder === true;
641
669
  }
642
- // 父相同的情况下,就是排序,看是否能排序
643
- const parentNodeModel = this.getNodeModel(dropNode.nodeId)!;
644
- return parentNodeModel?.allowOrder === true;
670
+
671
+ // 没有父就是根节点,根节点没有上层关系,无法换父
672
+ if (!dropNode.parent) {
673
+ return false;
674
+ }
675
+
676
+ // 父不一样的时候需要判断能否移入到对方的父节点内
677
+ return !!this.findDropNodeRS(
678
+ dropNode.parent!.nodeId!,
679
+ draggingNodeModel.appDataEntityId!,
680
+ );
645
681
  }
646
682
 
647
683
  /**
@@ -688,7 +724,7 @@ export class TreeController<
688
724
  const modifiedNodeDatas: ITreeNodeData[] = [];
689
725
  const draggingNodeModel = this.getNodeModel(draggingNode.nodeId)!;
690
726
  const dropInNode = dropType === 'inner' ? dropNode : dropNode.parent!;
691
- const isChangedParent = dropNode.parent?.id !== draggingNode.parent?.id;
727
+ const isChangedParent = dropNode?.id !== draggingNode.parent?.id;
692
728
  let orderNodeModel = this.getNodeModel(dropNode.nodeId)!;
693
729
 
694
730
  // * 处理切换父节点
@@ -16,7 +16,16 @@ export class HubController implements IHubController {
16
16
  return ibiz.auth.login(loginName, password);
17
17
  }
18
18
 
19
- logout(): Promise<boolean> {
20
- return ibiz.auth.logout();
19
+ async logout(): Promise<boolean> {
20
+ const bol = await ibiz.auth.logout();
21
+ if (bol) {
22
+ // todo: 匿名登录临时处理退出,后续需要优化
23
+ const l = window.location;
24
+ if (l.search.indexOf('isAnonymous=true') !== -1) {
25
+ const href = `${l.origin}${l.pathname}${l.hash}`;
26
+ window.history.replaceState({}, '', href);
27
+ }
28
+ }
29
+ return bol;
21
30
  }
22
31
  }
@@ -6,11 +6,9 @@ import {
6
6
  HandlebarsUtil,
7
7
  RawValueUtil,
8
8
  ThemeUtil,
9
- } from '../../utils';
10
- import {
11
9
  DefaultErrorHandler,
12
10
  ErrorHandlerCenter,
13
- } from '../../utils/error-handler';
11
+ } from '../../utils';
14
12
 
15
13
  /**
16
14
  * 全局工具方法或对象
@@ -140,15 +140,10 @@ export interface ISearchGroupData {
140
140
  */
141
141
  columnstates?: Array<IColumnState>;
142
142
 
143
- /**
144
- * 过滤项树节点数据集合
145
- */
146
- filternodes?: Array<IFilterNode>;
147
-
148
143
  /**
149
144
  * 自定义搜索条件
150
145
  */
151
- searchconds?: IData;
146
+ searchconds?: IData[];
152
147
 
153
148
  /**
154
149
  * 表格排序查询条件
@@ -1,3 +1,4 @@
1
+ import { HistoryList } from '@ibiz-template/core';
1
2
  import { Srfuf } from '../../../service';
2
3
 
3
4
  /**
@@ -93,6 +94,15 @@ export interface IDataEntity {
93
94
  */
94
95
  srfuf: Srfuf;
95
96
 
97
+ /**
98
+ * 数据历史记录,可用于撤销操作
99
+ *
100
+ * @author chitanda
101
+ * @date 2023-12-28 21:12:08
102
+ * @type {HistoryList<IData>}
103
+ */
104
+ readonly history: HistoryList<IData>;
105
+
96
106
  /**
97
107
  * 提供当前数据克隆操作,返回克隆后的当前实例
98
108
  *
@@ -105,10 +115,19 @@ export interface IDataEntity {
105
115
  /**
106
116
  * 将指定的数据对象或者实体数据对象的属性值赋值到当前实体
107
117
  *
118
+ * @description 该方法会先创建一次历史记录,销毁此对象时必须调用 history.destroy() 方法
108
119
  * @author chitanda
109
120
  * @date 2023-05-16 17:05:26
110
121
  * @param {(IData | IDataEntity)} data
111
122
  * @return {*} {IDataEntity}
112
123
  */
113
124
  assign(data: IData | IDataEntity): IDataEntity;
125
+
126
+ /**
127
+ * 销毁当前实体对象
128
+ *
129
+ * @author chitanda
130
+ * @date 2023-12-28 21:12:40
131
+ */
132
+ destroy(): void;
114
133
  }
@@ -3,7 +3,7 @@
3
3
  /* eslint-disable max-classes-per-file */
4
4
  import { IAppDataEntity } from '@ibiz/model-core';
5
5
  import { clone, isNil } from 'ramda';
6
- import { DataTypes } from '@ibiz-template/core';
6
+ import { DataTypes, HistoryList } from '@ibiz-template/core';
7
7
  import { createUUID } from 'qx-util';
8
8
  import { Srfuf } from '../constant';
9
9
  import { findModelChild } from '../../model';
@@ -24,6 +24,8 @@ export class AppDataEntity implements IDataEntity {
24
24
 
25
25
  protected declare _entity: IAppDataEntity;
26
26
 
27
+ declare history: HistoryList<IData>;
28
+
27
29
  declare srfdeid: string;
28
30
 
29
31
  declare srfdecodename: string;
@@ -51,6 +53,9 @@ export class AppDataEntity implements IDataEntity {
51
53
  * @param {(IData | AppDataEntity)} [data={}]
52
54
  */
53
55
  constructor(entity: IAppDataEntity, data: IData | AppDataEntity = {}) {
56
+ let history = new HistoryList<IData>(
57
+ data instanceof AppDataEntity ? clone(data._data) : clone(data),
58
+ );
54
59
  Object.defineProperty(this, '_entity', {
55
60
  enumerable: false,
56
61
  configurable: true,
@@ -59,7 +64,19 @@ export class AppDataEntity implements IDataEntity {
59
64
  Object.defineProperty(this, '_data', {
60
65
  enumerable: false,
61
66
  configurable: true,
62
- value: data instanceof AppDataEntity ? clone(data._data) : clone(data),
67
+ get() {
68
+ return history.data;
69
+ },
70
+ });
71
+ Object.defineProperty(this, 'history', {
72
+ enumerable: false,
73
+ configurable: true,
74
+ set(v) {
75
+ history = v;
76
+ },
77
+ get() {
78
+ return history;
79
+ },
63
80
  });
64
81
  Object.defineProperty(this, 'srfdeid', {
65
82
  get() {
@@ -139,17 +156,19 @@ export class AppDataEntity implements IDataEntity {
139
156
  * @protected
140
157
  */
141
158
  protected defineProperties(): void {
142
- const { _data, convertVal } = this;
159
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
160
+ const self = this; // _data 不可以解构,或重新声明变量会断掉引用
161
+ const { convertVal } = this;
143
162
  const properties: { [key: string]: PropertyDescriptor } = {};
144
- const keys = Object.keys(_data);
163
+ const keys = Object.keys(this._data);
145
164
  keys.forEach(key => {
146
165
  properties[key] = {
147
166
  enumerable: true,
148
167
  set(val: unknown): void {
149
- _data[key] = val;
168
+ self._data[key] = val;
150
169
  },
151
170
  get(): any {
152
- return _data[key];
171
+ return self._data[key];
153
172
  },
154
173
  };
155
174
  });
@@ -158,14 +177,14 @@ export class AppDataEntity implements IDataEntity {
158
177
  properties[key] = {
159
178
  enumerable: true,
160
179
  set(val: unknown): void {
161
- _data[key] = convertVal(val, field.stdDataType);
180
+ self._data[key] = convertVal(val, field.stdDataType);
162
181
  },
163
182
  get(): any {
164
- return _data[key];
183
+ return self._data[key];
165
184
  },
166
185
  };
167
186
  // 初始值转换
168
- _data[key] = convertVal(_data[key], field.stdDataType);
187
+ self._data[key] = convertVal(self._data[key], field.stdDataType);
169
188
  });
170
189
  Object.defineProperties(this, properties);
171
190
  }
@@ -178,8 +197,9 @@ export class AppDataEntity implements IDataEntity {
178
197
  * @return {*} {AppDataEntity}
179
198
  */
180
199
  clone(): AppDataEntity {
181
- const entity = new AppDataEntity(this._entity, this._data);
200
+ const entity = new AppDataEntity(this._entity);
182
201
  entity.srfkey = this.srfkey;
202
+ entity.history = clone(this.history);
183
203
  return entity;
184
204
  }
185
205
 
@@ -203,10 +223,25 @@ export class AppDataEntity implements IDataEntity {
203
223
  delete _data[key];
204
224
  }
205
225
  });
206
- Object.assign(this._data, _data);
226
+ this.history.assign(_data);
207
227
  return this;
208
228
  }
209
229
 
230
+ /**
231
+ * 实体对象销毁
232
+ *
233
+ * @author chitanda
234
+ * @date 2023-12-28 21:12:24
235
+ */
236
+ destroy(): void {
237
+ this.history.destroy();
238
+ Object.defineProperty(this, '_entity', {
239
+ enumerable: false,
240
+ configurable: true,
241
+ value: null,
242
+ });
243
+ }
244
+
210
245
  /**
211
246
  * 根据属性的数据类型转换值
212
247
  * @author lxm
@@ -215,7 +215,7 @@ export class MethodDto {
215
215
  });
216
216
  await dto.sets(context, items);
217
217
  // 删除下边一行代码,DTO 的属性也不能直接删除。界面上表单类似重复器的地方会用到,保存时也需要由界面提供
218
- delete datum[key];
218
+ // delete datum[key];
219
219
  } else {
220
220
  await dto.sets(context, []);
221
221
  }
@@ -442,6 +442,9 @@ export class DECache {
442
442
  * @date 2023-12-22 13:12:17
443
443
  */
444
444
  clear(): void {
445
+ this.cacheMap.forEach(item => {
446
+ item.destroy();
447
+ });
445
448
  this.cacheMap.clear();
446
449
  }
447
450