@tmagic/editor 1.1.0-beta.8 → 1.1.1

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 (59) hide show
  1. package/dist/style.css +46 -0
  2. package/dist/tmagic-editor.mjs +1052 -873
  3. package/dist/tmagic-editor.mjs.map +1 -1
  4. package/dist/tmagic-editor.umd.js +1054 -872
  5. package/dist/tmagic-editor.umd.js.map +1 -1
  6. package/package.json +10 -10
  7. package/src/Editor.vue +31 -9
  8. package/src/components/ContentMenu.vue +4 -4
  9. package/src/components/Icon.vue +6 -20
  10. package/src/components/ScrollBar.vue +147 -0
  11. package/src/components/ScrollViewer.vue +89 -44
  12. package/src/components/ToolButton.vue +40 -138
  13. package/src/fields/UISelect.vue +2 -2
  14. package/src/index.ts +2 -0
  15. package/src/layouts/NavMenu.vue +156 -23
  16. package/src/layouts/PropsPanel.vue +49 -51
  17. package/src/layouts/sidebar/LayerMenu.vue +3 -3
  18. package/src/layouts/sidebar/LayerPanel.vue +39 -8
  19. package/src/layouts/workspace/PageBar.vue +1 -1
  20. package/src/layouts/workspace/Stage.vue +8 -86
  21. package/src/layouts/workspace/ViewerMenu.vue +6 -6
  22. package/src/layouts/workspace/Workspace.vue +133 -138
  23. package/src/services/componentList.ts +5 -0
  24. package/src/services/editor.ts +148 -76
  25. package/src/services/events.ts +8 -2
  26. package/src/services/props.ts +31 -52
  27. package/src/services/storage.ts +4 -0
  28. package/src/services/ui.ts +32 -30
  29. package/src/theme/nav-menu.scss +6 -0
  30. package/src/type.ts +28 -11
  31. package/src/utils/index.ts +1 -0
  32. package/src/utils/operator.ts +6 -60
  33. package/src/utils/props.ts +0 -3
  34. package/src/utils/scroll-viewer.ts +90 -158
  35. package/src/utils/stage.ts +91 -0
  36. package/types/Editor.vue.d.ts +17 -8
  37. package/types/components/ContentMenu.vue.d.ts +8 -8
  38. package/types/components/Icon.vue.d.ts +62 -12
  39. package/types/components/ScrollBar.vue.d.ts +83 -0
  40. package/types/components/ScrollViewer.vue.d.ts +131 -19
  41. package/types/components/ToolButton.vue.d.ts +56 -59
  42. package/types/index.d.ts +2 -0
  43. package/types/layouts/NavMenu.vue.d.ts +92 -23
  44. package/types/layouts/PropsPanel.vue.d.ts +25 -208
  45. package/types/layouts/sidebar/LayerMenu.vue.d.ts +7 -7
  46. package/types/layouts/sidebar/LayerPanel.vue.d.ts +17 -15
  47. package/types/layouts/workspace/Workspace.vue.d.ts +54 -4
  48. package/types/services/componentList.d.ts +1 -0
  49. package/types/services/editor.d.ts +7 -9
  50. package/types/services/events.d.ts +1 -0
  51. package/types/services/props.d.ts +41 -9
  52. package/types/services/storage.d.ts +1 -0
  53. package/types/services/ui.d.ts +3 -1
  54. package/types/type.d.ts +25 -11
  55. package/types/utils/index.d.ts +1 -0
  56. package/types/utils/operator.d.ts +1 -7
  57. package/types/utils/props.d.ts +0 -1
  58. package/types/utils/scroll-viewer.d.ts +16 -18
  59. package/types/utils/stage.d.ts +3 -0
@@ -38,7 +38,7 @@ import {
38
38
  isFixed,
39
39
  setLayout,
40
40
  } from '../utils/editor';
41
- import { beforePaste, beforeRemove, getAddParent } from '../utils/operator';
41
+ import { beforePaste, getAddParent } from '../utils/operator';
42
42
 
43
43
  import BaseService from './BaseService';
44
44
  import propsService from './props';
@@ -64,11 +64,15 @@ class Editor extends BaseService {
64
64
  'select',
65
65
  'doAdd',
66
66
  'add',
67
+ 'doRemove',
67
68
  'remove',
69
+ 'doUpdate',
68
70
  'update',
69
71
  'sort',
70
72
  'copy',
71
73
  'paste',
74
+ 'doPaste',
75
+ 'duAlignCenter',
72
76
  'alignCenter',
73
77
  'moveLayer',
74
78
  'moveToContainer',
@@ -293,17 +297,27 @@ class Editor extends BaseService {
293
297
  throw new Error('app下不能添加组件');
294
298
  }
295
299
 
300
+ if (parent.id !== curNode.id) {
301
+ const index = parent.items.indexOf(curNode);
302
+ parent?.items?.splice(index + 1, 0, node);
303
+ } else {
304
+ // 新增节点添加到配置中
305
+ parent?.items?.push(node);
306
+ }
307
+
296
308
  const layout = await this.getLayout(toRaw(parent), node as MNode);
297
309
  node.style = getInitPositionStyle(node.style, layout);
298
310
 
299
- await stage?.add({ config: cloneDeep(node), parent: cloneDeep(parent), root: cloneDeep(root) });
311
+ await stage?.add({
312
+ config: cloneDeep(node),
313
+ parent: cloneDeep(parent),
314
+ parentId: parent.id,
315
+ root: cloneDeep(root),
316
+ });
300
317
 
301
318
  node.style = fixNodePosition(node, parent, stage);
302
319
 
303
- await stage?.update({ config: cloneDeep(node), root: cloneDeep(root) });
304
-
305
- // 新增节点添加到配置中
306
- parent?.items?.push(node);
320
+ await stage?.update({ config: cloneDeep(node), parentId: parent.id, root: cloneDeep(root) });
307
321
 
308
322
  this.addModifiedNodeId(node.id);
309
323
 
@@ -319,9 +333,6 @@ class Editor extends BaseService {
319
333
  public async add(addNode: AddMNode | MNode[], parent?: MContainer | null): Promise<MNode | MNode[]> {
320
334
  const stage = this.get<StageCore | null>('stage');
321
335
 
322
- const parentNode = parent && typeof parent !== 'function' ? parent : getAddParent(addNode);
323
- if (!parentNode) throw new Error('未找到父元素');
324
-
325
336
  // 新增多个组件只存在于粘贴多个组件,粘贴的是一个完整的config,所以不再需要getPropsValue
326
337
  const addNodes = [];
327
338
  if (!Array.isArray(addNode)) {
@@ -334,7 +345,13 @@ class Editor extends BaseService {
334
345
  addNodes.push(...addNode);
335
346
  }
336
347
 
337
- const newNodes = await Promise.all(addNodes.map((node) => this.doAdd(node, parentNode)));
348
+ const newNodes = await Promise.all(
349
+ addNodes.map((node) => {
350
+ const parentNode = parent && typeof parent !== 'function' ? parent : getAddParent(node);
351
+ if (!parentNode) throw new Error('未找到父元素');
352
+ return this.doAdd(node, parentNode);
353
+ }),
354
+ );
338
355
 
339
356
  if (newNodes.length > 1) {
340
357
  const newNodeIds = newNodes.map((node) => node.id);
@@ -356,7 +373,49 @@ class Editor extends BaseService {
356
373
 
357
374
  this.emit('add', newNodes);
358
375
 
359
- return newNodes.length > 1 ? newNodes[0] : newNodes;
376
+ return Array.isArray(addNode) ? newNodes : newNodes[0];
377
+ }
378
+
379
+ public async doRemove(node: MNode): Promise<void> {
380
+ const root = this.get<MApp | null>('root');
381
+
382
+ if (!root) throw new Error('没有root');
383
+
384
+ const { parent, node: curNode } = this.getNodeInfo(node.id);
385
+
386
+ if (!parent || !curNode) throw new Error('找不要删除的节点');
387
+
388
+ const index = getNodeIndex(curNode, parent);
389
+
390
+ if (typeof index !== 'number' || index === -1) throw new Error('找不要删除的节点');
391
+
392
+ parent.items?.splice(index, 1);
393
+ const stage = this.get<StageCore | null>('stage');
394
+ stage?.remove({ id: node.id, parentId: parent.id, root: cloneDeep(root) });
395
+
396
+ if (node.type === NodeType.PAGE) {
397
+ this.state.pageLength -= 1;
398
+
399
+ if (root.items[0]) {
400
+ await this.select(root.items[0]);
401
+ stage?.select(root.items[0].id);
402
+ } else {
403
+ this.set('nodes', [root]);
404
+ this.set('parent', null);
405
+ this.set('page', null);
406
+ this.set('stage', null);
407
+ this.set('highlightNode', null);
408
+ this.resetModifiedNodeId();
409
+ historyService.reset();
410
+
411
+ return;
412
+ }
413
+ } else {
414
+ await this.select(parent);
415
+ stage?.select(parent.id);
416
+ }
417
+
418
+ this.addModifiedNodeId(parent.id);
360
419
  }
361
420
 
362
421
  /**
@@ -364,50 +423,18 @@ class Editor extends BaseService {
364
423
  * @param {Object} node
365
424
  * @return {Object} 删除的组件配置
366
425
  */
367
- public async remove(nodeOrNodeList: MNode | MNode[]): Promise<MNode | MNode[]> {
368
- if (Array.isArray(nodeOrNodeList)) {
369
- // 多选批量删除
370
- const nodes = nodeOrNodeList;
371
- return this.multiRemove(nodes);
372
- }
373
- const node = nodeOrNodeList;
374
- const removeParent = await beforeRemove(node);
375
- // 删除的是页面
376
- if (!removeParent) return node;
377
- // 更新历史记录
378
- this.addModifiedNodeId(removeParent.id);
379
- this.pushHistoryState();
426
+ public async remove(nodeOrNodeList: MNode | MNode[]): Promise<void> {
427
+ const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
380
428
 
381
- this.emit('remove', node);
429
+ await Promise.all(nodes.map((node) => this.doRemove(node)));
382
430
 
383
- return node;
384
- }
385
-
386
- /**
387
- * 批量删除
388
- * @param nodes 批量删除的节点
389
- * @returns 批量删除的节点
390
- */
391
- public async multiRemove(nodes: MNode[]): Promise<MNode[]> {
392
- await Promise.all(
393
- nodes.map(async (removeNode) => {
394
- await beforeRemove(removeNode);
395
- }),
396
- );
397
- const nodeIds = nodes.map((node) => node.id);
398
- this.addModifiedNodeId(nodeIds.join('-'));
431
+ // 更新历史记录
399
432
  this.pushHistoryState();
400
433
 
401
- this.emit('multiRemove', nodes);
402
- return nodes;
434
+ this.emit('remove', nodes);
403
435
  }
404
436
 
405
- /**
406
- * 更新节点
407
- * @param config 新的节点配置,配置中需要有id信息
408
- * @returns 更新后的节点配置
409
- */
410
- public async update(config: MNode): Promise<MNode> {
437
+ public async doUpdate(config: MNode) {
411
438
  if (!config?.id) throw new Error('没有配置或者配置缺少id值');
412
439
 
413
440
  const info = this.getNodeInfo(config.id, false);
@@ -453,18 +480,36 @@ class Editor extends BaseService {
453
480
  nodes.splice(targetIndex, 1, newConfig);
454
481
  this.set('nodes', nodes);
455
482
 
456
- this.get<StageCore | null>('stage')?.update({ config: cloneDeep(newConfig), root: cloneDeep(this.get('root')) });
483
+ this.get<StageCore | null>('stage')?.update({
484
+ config: cloneDeep(newConfig),
485
+ parentId: parent.id,
486
+ root: cloneDeep(this.get('root')),
487
+ });
457
488
 
458
489
  if (newConfig.type === NodeType.PAGE) {
459
490
  this.set('page', newConfig);
460
491
  }
461
492
 
462
493
  this.addModifiedNodeId(newConfig.id);
494
+
495
+ return newConfig;
496
+ }
497
+
498
+ /**
499
+ * 更新节点
500
+ * @param config 新的节点配置,配置中需要有id信息
501
+ * @returns 更新后的节点配置
502
+ */
503
+ public async update(config: MNode | MNode[]): Promise<MNode | MNode[]> {
504
+ const nodes = Array.isArray(config) ? config : [config];
505
+
506
+ const newNodes = await Promise.all(nodes.map((node) => this.doUpdate(node)));
507
+
463
508
  this.pushHistoryState();
464
509
 
465
- this.emit('update', newConfig);
510
+ this.emit('update', newNodes);
466
511
 
467
- return newConfig;
512
+ return Array.isArray(config) ? newNodes : newNodes[0];
468
513
  }
469
514
 
470
515
  /**
@@ -486,7 +531,11 @@ class Editor extends BaseService {
486
531
  await this.update(parent);
487
532
  await this.select(node);
488
533
 
489
- this.get<StageCore | null>('stage')?.update({ config: cloneDeep(node), root: cloneDeep(this.get('root')) });
534
+ this.get<StageCore | null>('stage')?.update({
535
+ config: cloneDeep(node),
536
+ parentId: parent.id,
537
+ root: cloneDeep(this.get('root')),
538
+ });
490
539
 
491
540
  this.addModifiedNodeId(parent.id);
492
541
  this.pushHistoryState();
@@ -513,25 +562,28 @@ class Editor extends BaseService {
513
562
 
514
563
  if (!Array.isArray(config)) return;
515
564
 
516
- const pasteConfigs = await beforePaste(position, config);
565
+ const pasteConfigs = await this.doPaste(config, position);
517
566
 
518
567
  return this.add(pasteConfigs);
519
568
  }
520
569
 
521
- /**
522
- * 将指点节点设置居中
523
- * @param config 组件节点配置
524
- * @returns 当前组件节点配置
525
- */
526
- public async alignCenter(config: MNode): Promise<MNode | void> {
527
- const parent = this.get<MContainer>('parent');
528
- const node = this.get<MNode>('node');
529
- const layout = await this.getLayout(toRaw(parent), toRaw(node));
570
+ public async doPaste(config: MNode[], position: PastePosition = {}): Promise<MNode[]> {
571
+ const pasteConfigs = await beforePaste(position, cloneDeep(config));
572
+ return pasteConfigs;
573
+ }
574
+
575
+ public async doAlignCenter(config: MNode): Promise<MNode> {
576
+ const parent = this.getParentById(config.id);
577
+
578
+ if (!parent) throw new Error('找不到父节点');
579
+
580
+ const node = cloneDeep(toRaw(config));
581
+ const layout = await this.getLayout(parent, node);
530
582
  if (layout === Layout.RELATIVE) {
531
- return;
583
+ return config;
532
584
  }
533
585
 
534
- if (!node.style) return;
586
+ if (!node.style) return config;
535
587
 
536
588
  const stage = this.get<StageCore>('stage');
537
589
  const doc = stage?.renderer.contentWindow?.document;
@@ -546,15 +598,25 @@ class Editor extends BaseService {
546
598
  node.style.left = (parent.style.width - node.style.width) / 2;
547
599
  }
548
600
 
549
- await this.update(node);
550
- this.get<StageCore | null>('stage')?.update({
551
- config: cloneDeep(toRaw(node)),
552
- root: cloneDeep(this.get<MApp>('root')),
553
- });
554
- this.addModifiedNodeId(config.id);
555
- this.pushHistoryState();
601
+ return node;
602
+ }
603
+
604
+ /**
605
+ * 将指点节点设置居中
606
+ * @param config 组件节点配置
607
+ * @returns 当前组件节点配置
608
+ */
609
+ public async alignCenter(config: MNode | MNode[]): Promise<MNode | MNode[]> {
610
+ const nodes = Array.isArray(config) ? config : [config];
611
+ const stage = this.get<StageCore | null>('stage');
612
+
613
+ const newNodes = await Promise.all(nodes.map((node) => this.doAlignCenter(node)));
614
+
615
+ const newNode = await this.update(newNodes);
556
616
 
557
- return config;
617
+ await stage?.multiSelect(newNodes.map((node) => node.id));
618
+
619
+ return newNode;
558
620
  }
559
621
 
560
622
  /**
@@ -563,7 +625,7 @@ class Editor extends BaseService {
563
625
  */
564
626
  public async moveLayer(offset: number | LayerOffset): Promise<void> {
565
627
  const parent = this.get<MContainer>('parent');
566
- const node = this.get('node');
628
+ const node = this.get<MNode>('node');
567
629
  const brothers: MNode[] = parent?.items || [];
568
630
  const index = brothers.findIndex((item) => `${item.id}` === `${node?.id}`);
569
631
 
@@ -575,10 +637,15 @@ class Editor extends BaseService {
575
637
  brothers.splice(index + parseInt(`${offset}`, 10), 0, brothers.splice(index, 1)[0]);
576
638
  }
577
639
 
640
+ const grandparent = this.getParentById(parent.id);
578
641
  this.get<StageCore | null>('stage')?.update({
579
642
  config: cloneDeep(toRaw(parent)),
643
+ parentId: grandparent?.id,
580
644
  root: cloneDeep(this.get<MApp>('root')),
581
645
  });
646
+
647
+ this.addModifiedNodeId(parent.id);
648
+ this.pushHistoryState();
582
649
  }
583
650
 
584
651
  /**
@@ -597,7 +664,7 @@ class Editor extends BaseService {
597
664
  const index = getNodeIndex(node, parent);
598
665
  parent.items?.splice(index, 1);
599
666
 
600
- await stage.remove({ id: node.id, root });
667
+ await stage.remove({ id: node.id, parentId: parent.id, root });
601
668
 
602
669
  const layout = await this.getLayout(target);
603
670
 
@@ -612,7 +679,8 @@ class Editor extends BaseService {
612
679
 
613
680
  await stage.select(targetId);
614
681
 
615
- await stage.update({ config: cloneDeep(target), root });
682
+ const targetParent = this.getParentById(target.id);
683
+ await stage.update({ config: cloneDeep(target), parentId: targetParent?.id, root });
616
684
 
617
685
  await this.select(newConfig);
618
686
  stage.select(newConfig.id);
@@ -673,6 +741,10 @@ class Editor extends BaseService {
673
741
  this.set('nodes', []);
674
742
  this.set('page', null);
675
743
  this.set('parent', null);
744
+ this.set('stage', null);
745
+ this.set('highlightNode', null);
746
+ this.set('modifiedNodeIds', new Map());
747
+ this.set('pageLength', new Map());
676
748
  }
677
749
 
678
750
  public resetModifiedNodeId() {
@@ -26,8 +26,8 @@ import type { ComponentGroup } from '../type';
26
26
 
27
27
  import BaseService from './BaseService';
28
28
 
29
- const eventMap: Record<string, EventOption[]> = reactive({});
30
- const methodMap: Record<string, EventOption[]> = reactive({});
29
+ let eventMap: Record<string, EventOption[]> = reactive({});
30
+ let methodMap: Record<string, EventOption[]> = reactive({});
31
31
 
32
32
  class Events extends BaseService {
33
33
  constructor() {
@@ -75,6 +75,12 @@ class Events extends BaseService {
75
75
  public getMethod(type: string) {
76
76
  return cloneDeep(methodMap[type] || DEFAULT_METHODS);
77
77
  }
78
+
79
+ public destroy() {
80
+ eventMap = reactive({});
81
+ methodMap = reactive({});
82
+ this.removeAllListeners();
83
+ }
78
84
  }
79
85
 
80
86
  export type EventsService = Events;
@@ -20,12 +20,11 @@ import { reactive } from 'vue';
20
20
  import { cloneDeep, mergeWith } from 'lodash-es';
21
21
 
22
22
  import type { FormConfig } from '@tmagic/form';
23
- import type { Id, MComponent, MNode, MPage } from '@tmagic/schema';
24
- import { NodeType } from '@tmagic/schema';
25
- import { isPop, toLine } from '@tmagic/utils';
23
+ import type { MComponent, MNode } from '@tmagic/schema';
24
+ import { toLine } from '@tmagic/utils';
26
25
 
27
26
  import type { PropsState } from '../type';
28
- import { DEFAULT_CONFIG, fillConfig } from '../utils/props';
27
+ import { fillConfig } from '../utils/props';
29
28
 
30
29
  import BaseService from './BaseService';
31
30
 
@@ -43,6 +42,7 @@ class Props extends BaseService {
43
42
  'getPropsValue',
44
43
  'createId',
45
44
  'setNewItemId',
45
+ 'fillConfig',
46
46
  'getDefaultPropsValue',
47
47
  ]);
48
48
  }
@@ -54,13 +54,17 @@ class Props extends BaseService {
54
54
  this.emit('props-configs-change');
55
55
  }
56
56
 
57
+ public async fillConfig(config: FormConfig) {
58
+ return fillConfig(config);
59
+ }
60
+
57
61
  /**
58
62
  * 为指定类型组件设置组件属性表单配置
59
63
  * @param type 组件类型
60
64
  * @param config 组件属性表单配置
61
65
  */
62
- public setPropsConfig(type: string, config: FormConfig) {
63
- this.state.propsConfigMap[type] = fillConfig(Array.isArray(config) ? config : [config]);
66
+ public async setPropsConfig(type: string, config: FormConfig) {
67
+ this.state.propsConfigMap[type] = await this.fillConfig(Array.isArray(config) ? config : [config]);
64
68
  }
65
69
 
66
70
  /**
@@ -73,7 +77,7 @@ class Props extends BaseService {
73
77
  return await this.getPropsConfig('button');
74
78
  }
75
79
 
76
- return cloneDeep(this.state.propsConfigMap[type] || DEFAULT_CONFIG);
80
+ return cloneDeep(this.state.propsConfigMap[type] || (await this.fillConfig([])));
77
81
  }
78
82
 
79
83
  public setPropsValues(values: Record<string, MNode>) {
@@ -125,19 +129,6 @@ class Props extends BaseService {
125
129
  };
126
130
  }
127
131
 
128
- /**
129
- * 生成指定位数的GUID,无【-】格式
130
- * @param digit 位数,默认值8
131
- * @returns
132
- */
133
- guid(digit = 8): string {
134
- return 'x'.repeat(digit).replace(/[xy]/g, (c) => {
135
- const r = (Math.random() * 16) | 0;
136
- const v = c == 'x' ? r : (r & 0x3) | 0x8;
137
- return v.toString(16);
138
- });
139
- }
140
-
141
132
  public async createId(type: string | number): Promise<string> {
142
133
  return `${type}_${this.guid()}`;
143
134
  }
@@ -147,19 +138,12 @@ class Props extends BaseService {
147
138
  * @param {Object} config 组件配置
148
139
  */
149
140
  /* eslint no-param-reassign: ["error", { "props": false }] */
150
- public async setNewItemId(config: MNode, parent?: MPage) {
151
- const oldId = config.id;
152
-
141
+ public async setNewItemId(config: MNode) {
153
142
  config.id = await this.createId(config.type || 'component');
154
143
 
155
- // 只有弹窗在页面下的一级子元素才有效
156
- if (isPop(config) && parent?.type === NodeType.PAGE) {
157
- updatePopId(oldId, config.id, parent);
158
- }
159
-
160
144
  if (config.items && Array.isArray(config.items)) {
161
145
  for (const item of config.items) {
162
- await this.setNewItemId(item, config as MPage);
146
+ await this.setNewItemId(item);
163
147
  }
164
148
  }
165
149
 
@@ -186,31 +170,26 @@ class Props extends BaseService {
186
170
  name: type,
187
171
  };
188
172
  }
189
- }
190
173
 
191
- /**
192
- * 复制页面时,需要把组件下关联的弹窗id换测复制出来的弹窗的id
193
- * @param {number} oldId 复制的源弹窗id
194
- * @param {number} popId 新的弹窗id
195
- * @param {Object} pageConfig 页面配置
196
- */
197
- const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => {
198
- pageConfig.items?.forEach((config) => {
199
- if (config.pop === oldId) {
200
- config.pop = popId;
201
- return;
202
- }
203
-
204
- if (config.popId === oldId) {
205
- config.popId = popId;
206
- return;
207
- }
174
+ public destroy() {
175
+ this.state.propsConfigMap = {};
176
+ this.state.propsValueMap = {};
177
+ this.removeAllListeners();
178
+ }
208
179
 
209
- if (Array.isArray(config.items)) {
210
- updatePopId(oldId, popId, config as MPage);
211
- }
212
- });
213
- };
180
+ /**
181
+ * 生成指定位数的GUID,无【-】格式
182
+ * @param digit 位数,默认值8
183
+ * @returns
184
+ */
185
+ private guid(digit = 8): string {
186
+ return 'x'.repeat(digit).replace(/[xy]/g, (c) => {
187
+ const r = (Math.random() * 16) | 0;
188
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
189
+ return v.toString(16);
190
+ });
191
+ }
192
+ }
214
193
 
215
194
  export type PropsService = Props;
216
195
 
@@ -107,6 +107,10 @@ export class WebStorage extends BaseService {
107
107
  storage.setItem(`${options.namespace || namespace}:${key}`, item);
108
108
  }
109
109
 
110
+ public destroy() {
111
+ this.removeAllListeners();
112
+ }
113
+
110
114
  private getValueAndProtocol(value: string | null) {
111
115
  let protocol = '';
112
116
 
@@ -64,16 +64,6 @@ class Ui extends BaseService {
64
64
  center: 'auto',
65
65
  });
66
66
  });
67
-
68
- const columnWidthCacheData = globalThis.localStorage.getItem(COLUMN_WIDTH_STORAGE_KEY);
69
- if (columnWidthCacheData) {
70
- try {
71
- const columnWidthCache = JSON.parse(columnWidthCacheData);
72
- this.setColumnWidth(columnWidthCache);
73
- } catch (e) {
74
- console.error(e);
75
- }
76
- }
77
67
  }
78
68
 
79
69
  public set<T = any>(name: keyof UiState, value: T) {
@@ -98,21 +88,49 @@ class Ui extends BaseService {
98
88
  }
99
89
 
100
90
  (state as any)[name] = value;
101
-
102
- if (name === 'stageContainerRect') {
103
- state.zoom = this.calcZoom();
104
- }
105
91
  }
106
92
 
107
93
  public get<T>(name: keyof typeof state): T {
108
94
  return (state as any)[name];
109
95
  }
110
96
 
97
+ public initColumnWidth() {
98
+ const columnWidthCacheData = globalThis.localStorage.getItem(COLUMN_WIDTH_STORAGE_KEY);
99
+ if (columnWidthCacheData) {
100
+ try {
101
+ const columnWidthCache = JSON.parse(columnWidthCacheData);
102
+ this.setColumnWidth(columnWidthCache);
103
+ } catch (e) {
104
+ console.error(e);
105
+ }
106
+ }
107
+ }
108
+
111
109
  public zoom(zoom: number) {
112
110
  this.set('zoom', (this.get<number>('zoom') * 100 + zoom * 100) / 100);
113
111
  if (this.get<number>('zoom') < 0.1) this.set('zoom', 0.1);
114
112
  }
115
113
 
114
+ public calcZoom() {
115
+ const { stageRect, stageContainerRect } = state;
116
+ const { height, width } = stageContainerRect;
117
+ if (!width || !height) return 1;
118
+
119
+ // 30为标尺的大小
120
+ const stageWidth = stageRect.width + 30;
121
+ const stageHeight = stageRect.height + 30;
122
+
123
+ if (width > stageWidth && height > stageHeight) {
124
+ return 1;
125
+ }
126
+ // 60/80是为了不要让画布太过去贴住四周(这样好看些)
127
+ return Math.min((width - 60) / stageWidth || 1, (height - 80) / stageHeight || 1);
128
+ }
129
+
130
+ public destroy() {
131
+ this.removeAllListeners();
132
+ }
133
+
116
134
  private setColumnWidth({ left, center, right }: SetColumnWidth) {
117
135
  const columnWidth = {
118
136
  ...toRaw(this.get<GetColumnWidth>('columnWidth')),
@@ -150,22 +168,6 @@ class Ui extends BaseService {
150
168
  };
151
169
  state.zoom = this.calcZoom();
152
170
  }
153
-
154
- private calcZoom() {
155
- const { stageRect, stageContainerRect } = state;
156
- const { height, width } = stageContainerRect;
157
- if (!width || !height) return 1;
158
-
159
- // 30为标尺的大小
160
- const stageWidth = stageRect.width + 30;
161
- const stageHeight = stageRect.height + 30;
162
-
163
- if (width > stageWidth && height > stageHeight) {
164
- return 1;
165
- }
166
- // 60/80是为了不要让画布太过去贴住四周(这样好看些)
167
- return Math.min((width - 60) / stageWidth || 1, (height - 80) / stageHeight || 1);
168
- }
169
171
  }
170
172
 
171
173
  export type UiService = Ui;
@@ -69,5 +69,11 @@
69
69
  .menu-item-text {
70
70
  color: $--nav-color;
71
71
  }
72
+
73
+ &.rule {
74
+ .el-icon {
75
+ transform: rotate(-90deg);
76
+ }
77
+ }
72
78
  }
73
79
  }