@jnrs/lingshu-smart 2.2.6 → 2.2.8

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 (174) hide show
  1. package/dist/App.vue.d.ts +2 -1
  2. package/dist/App.vue.js +30 -0
  3. package/dist/assets/data/editor_default.d.ts +8 -1
  4. package/dist/assets/data/editor_default.js +59 -0
  5. package/dist/assets/data/editor_default_setting.d.ts +16 -0
  6. package/dist/assets/data/editor_default_setting.js +58 -0
  7. package/dist/assets/data/editor_preset.d.ts +8 -1
  8. package/dist/assets/data/editor_preset.js +51 -0
  9. package/dist/assets/data/editor_preset_menu.d.ts +9 -0
  10. package/dist/assets/data/editor_preset_menu.js +290 -0
  11. package/dist/components/editor/ControlBar/CaseManger.vue.d.ts +3 -15
  12. package/dist/components/editor/ControlBar/CaseManger.vue.js +465 -0
  13. package/dist/components/editor/ControlBar/CaseTitleEdit.vue.d.ts +2 -411
  14. package/dist/components/editor/ControlBar/CaseTitleEdit.vue.js +108 -0
  15. package/dist/components/editor/ControlBar/ExportImportDialog.vue.d.ts +3 -2
  16. package/dist/components/editor/ControlBar/ExportImportDialog.vue.js +280 -0
  17. package/dist/components/editor/ControlBar/MainButton.vue.d.ts +3 -2
  18. package/dist/components/editor/ControlBar/MainButton.vue.js +183 -0
  19. package/dist/components/editor/ControlBar/StepButton.vue.d.ts +2 -1
  20. package/dist/components/editor/ControlBar/StepButton.vue.js +147 -0
  21. package/dist/components/editor/ControlBar/StepRecordVisualizer.vue.d.ts +2 -1
  22. package/dist/components/editor/ControlBar/StepRecordVisualizer.vue.js +98 -0
  23. package/dist/components/editor/DrawingBoard.vue.d.ts +2 -1
  24. package/dist/components/editor/DrawingBoard.vue.js +31 -0
  25. package/dist/components/editor/MenuCard/Equipments.vue.d.ts +2 -1
  26. package/dist/components/editor/MenuCard/Equipments.vue.js +129 -0
  27. package/dist/components/editor/MenuCard/Layers.vue.d.ts +2 -1
  28. package/dist/components/editor/MenuCard/Layers.vue.js +201 -0
  29. package/dist/components/editor/MenuCard/index.vue.d.ts +2 -1
  30. package/dist/components/editor/MenuCard/index.vue.js +84 -0
  31. package/dist/components/editor/OptionCard/Equipment/Base.vue.d.ts +2 -1
  32. package/dist/components/editor/OptionCard/Equipment/Base.vue.js +96 -0
  33. package/dist/components/editor/OptionCard/Equipment/Binds.vue.d.ts +3 -0
  34. package/dist/components/editor/OptionCard/Equipment/Binds.vue.js +443 -0
  35. package/dist/components/editor/OptionCard/Equipment/Bot.vue.d.ts +3 -0
  36. package/dist/components/editor/OptionCard/Equipment/Bot.vue.js +81 -0
  37. package/dist/components/editor/OptionCard/Equipment/DataSets.vue.d.ts +2 -1
  38. package/dist/components/editor/OptionCard/Equipment/DataSets.vue.js +304 -0
  39. package/dist/components/editor/OptionCard/Equipment/DockStore.vue.d.ts +3 -0
  40. package/dist/components/editor/OptionCard/Equipment/DockStore.vue.js +597 -0
  41. package/dist/components/editor/OptionCard/Equipment/Interaction.vue.d.ts +2 -1
  42. package/dist/components/editor/OptionCard/Equipment/Interaction.vue.js +287 -0
  43. package/dist/components/editor/OptionCard/Equipment/Position.backup.vue.d.ts +3 -0
  44. package/dist/components/editor/OptionCard/Equipment/Position.backup.vue.js +440 -0
  45. package/dist/components/editor/OptionCard/Equipment/Position.vue.d.ts +2 -1
  46. package/dist/components/editor/OptionCard/Equipment/Position.vue.js +436 -0
  47. package/dist/components/editor/OptionCard/Equipment/StationSlotGroup.vue.d.ts +2 -1
  48. package/dist/components/editor/OptionCard/Equipment/StationSlotGroup.vue.js +1131 -0
  49. package/dist/components/editor/OptionCard/Equipment/Store.vue.d.ts +3 -0
  50. package/dist/components/editor/OptionCard/Equipment/Store.vue.js +453 -0
  51. package/dist/components/editor/OptionCard/Equipment/Trailer.vue.d.ts +3 -0
  52. package/dist/components/editor/OptionCard/Equipment/Trailer.vue.js +1109 -0
  53. package/dist/components/editor/OptionCard/Equipment/index.vue.d.ts +2 -1
  54. package/dist/components/editor/OptionCard/Equipment/index.vue.js +100 -0
  55. package/dist/components/editor/OptionCard/Equipment/models/MachineTool.vue.d.ts +3 -0
  56. package/dist/components/editor/OptionCard/Equipment/models/MachineTool.vue.js +99 -0
  57. package/dist/components/editor/OptionCard/Equipment/models/Rail.vue.d.ts +3 -0
  58. package/dist/components/editor/OptionCard/Equipment/models/Rail.vue.js +225 -0
  59. package/dist/components/editor/OptionCard/Equipment/models/SingleGripperRobot.vue.d.ts +3 -0
  60. package/dist/components/editor/OptionCard/Equipment/models/SingleGripperRobot.vue.js +99 -0
  61. package/dist/components/editor/OptionCard/Scene/Background.vue.d.ts +2 -1
  62. package/dist/components/editor/OptionCard/Scene/Background.vue.js +543 -0
  63. package/dist/components/editor/OptionCard/Scene/index.vue.d.ts +2 -1
  64. package/dist/components/editor/OptionCard/Scene/index.vue.js +200 -0
  65. package/dist/components/editor/OptionCard/index.vue.d.ts +2 -1
  66. package/dist/components/editor/OptionCard/index.vue.js +73 -0
  67. package/dist/components/editor/index.vue.d.ts +4 -13
  68. package/dist/components/editor/index.vue.js +156 -0
  69. package/dist/components/index.d.ts +2 -2
  70. package/dist/components/index.js +4 -25440
  71. package/dist/components/preview/index.vue.d.ts +6 -5
  72. package/dist/components/preview/index.vue.js +104 -0
  73. package/dist/composables/useStepRecord.d.ts +12 -4
  74. package/dist/composables/useStepRecord.js +135 -0
  75. package/dist/constants/options.d.ts +8 -1
  76. package/dist/constants/options.js +55 -0
  77. package/dist/controller/AppController.d.ts +10 -3
  78. package/dist/controller/AppController.js +168 -0
  79. package/dist/controller/EditorController.d.ts +9 -2
  80. package/dist/controller/EditorController.js +173 -0
  81. package/dist/index.js +1 -1
  82. package/dist/locales/en.js +5 -0
  83. package/dist/locales/i18next.d.ts +1 -1
  84. package/dist/locales/i18next.js +6 -0
  85. package/dist/locales/index.d.ts +2 -2
  86. package/dist/locales/index.js +3 -13
  87. package/dist/locales/zhCn.js +5 -0
  88. package/dist/main.d.ts +3 -0
  89. package/dist/main.js +13 -0
  90. package/dist/playground/EditPageDemo.vue.d.ts +2 -1
  91. package/dist/playground/EditPageDemo.vue.js +57 -0
  92. package/dist/playground/ViewPageDemo.vue.d.ts +2 -27
  93. package/dist/playground/ViewPageDemo.vue.js +277 -0
  94. package/dist/stores/index.js +3 -0
  95. package/dist/stores/useAppStore.d.ts +13 -6
  96. package/dist/stores/useAppStore.js +78 -0
  97. package/dist/stores/useDataStore.d.ts +18 -11
  98. package/dist/stores/useDataStore.js +116 -0
  99. package/dist/stores/useEditorStore.d.ts +27 -20
  100. package/dist/stores/useEditorStore.js +263 -0
  101. package/dist/types/app.types.d.ts +1 -1
  102. package/dist/types/app.types.js +2 -0
  103. package/dist/types/base.types.d.ts +4 -2
  104. package/dist/types/base.types.js +1 -0
  105. package/dist/types/components/config.types.d.ts +11 -3
  106. package/dist/types/components/config.types.js +1 -0
  107. package/dist/types/components/operating.types.d.ts +1 -1
  108. package/dist/types/components/operating.types.js +1 -0
  109. package/dist/types/enums.d.ts +5 -2
  110. package/dist/types/enums.js +46 -0
  111. package/dist/types/guards.d.ts +12 -2
  112. package/dist/types/guards.js +28 -0
  113. package/dist/types/index.d.ts +2 -2
  114. package/dist/types/index.js +8 -0
  115. package/dist/types/models/config.types.d.ts +74 -29
  116. package/dist/types/models/config.types.js +1 -0
  117. package/dist/types/models/operating.types.d.ts +83 -17
  118. package/dist/types/models/operating.types.js +1 -0
  119. package/dist/ui/abstract/ComponentAbs.d.ts +9 -2
  120. package/dist/ui/abstract/ComponentAbs.js +64 -0
  121. package/dist/ui/abstract/ModelAbs.d.ts +12 -2
  122. package/dist/ui/abstract/ModelAbs.js +119 -0
  123. package/dist/ui/components/Entrance.d.ts +8 -1
  124. package/dist/ui/components/Entrance.js +83 -0
  125. package/dist/ui/components/Light.d.ts +26 -3
  126. package/dist/ui/components/Light.js +167 -0
  127. package/dist/ui/components/Progress.d.ts +8 -1
  128. package/dist/ui/components/Progress.js +84 -0
  129. package/dist/ui/components/Resource.d.ts +8 -1
  130. package/dist/ui/components/Resource.js +70 -0
  131. package/dist/ui/components/StationSlot.d.ts +24 -2
  132. package/dist/ui/components/StationSlot.js +207 -0
  133. package/dist/ui/components/StationSlotGroup.d.ts +8 -1
  134. package/dist/ui/components/StationSlotGroup.js +110 -0
  135. package/dist/ui/factories/createGlass.d.ts +9 -1
  136. package/dist/ui/factories/createGlass.js +51 -0
  137. package/dist/ui/factories/createModel.d.ts +9 -2
  138. package/dist/ui/factories/createModel.js +35 -0
  139. package/dist/ui/factories/createShadow.d.ts +12 -4
  140. package/dist/ui/factories/createShadow.js +52 -0
  141. package/dist/ui/factories/createText.d.ts +7 -0
  142. package/dist/ui/factories/createText.js +46 -0
  143. package/dist/ui/models/CleaningMachine.d.ts +14 -0
  144. package/dist/ui/models/CleaningMachine.js +141 -0
  145. package/dist/ui/models/DoubleJointRobot.d.ts +23 -0
  146. package/dist/ui/models/DoubleJointRobot.js +545 -0
  147. package/dist/ui/models/LoadingStation.d.ts +16 -0
  148. package/dist/ui/models/LoadingStation.js +167 -0
  149. package/dist/ui/models/MachineTool.d.ts +5 -4
  150. package/dist/ui/models/MachineTool.js +184 -0
  151. package/dist/ui/models/MarkingMachine.d.ts +16 -0
  152. package/dist/ui/models/MarkingMachine.js +148 -0
  153. package/dist/ui/models/Rail.d.ts +15 -0
  154. package/dist/ui/models/Rail.js +117 -0
  155. package/dist/ui/models/ResourceStore.d.ts +12 -0
  156. package/dist/ui/models/ResourceStore.js +101 -0
  157. package/dist/ui/models/SingleBot.d.ts +20 -0
  158. package/dist/ui/models/SingleBot.js +202 -0
  159. package/dist/ui/models/SingleGripperRobot.d.ts +19 -0
  160. package/dist/ui/models/SingleGripperRobot.js +272 -0
  161. package/dist/ui/models/SingleJointRobot.d.ts +22 -0
  162. package/dist/ui/models/SingleJointRobot.js +346 -0
  163. package/dist/ui/shapes/NamePlate.d.ts +10 -1
  164. package/dist/ui/shapes/NamePlate.js +85 -0
  165. package/dist/ui/shapes/ScrewHole.d.ts +8 -1
  166. package/dist/ui/shapes/ScrewHole.js +57 -0
  167. package/dist/ui/shapes/Texture.d.ts +12 -3
  168. package/dist/ui/shapes/Texture.js +51 -0
  169. package/dist/ui/utils/attr.d.ts +10 -3
  170. package/dist/ui/utils/attr.js +50 -0
  171. package/dist/utils/index.js +92 -0
  172. package/dist/utils/type-guards.d.ts +1 -1
  173. package/dist/utils/type-guards.js +105 -0
  174. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import { ICase, ILayer, ILayerOperating, InteractiveUi } from '../../types';
1
+ import type { ICase, ILayer, ILayerOperating, InteractiveUi } from '@/types';
2
2
  export interface PreviewActions {
3
3
  /**
4
4
  * 加载案例列表
@@ -28,10 +28,11 @@ type __VLS_Props = {
28
28
  */
29
29
  caseUuid?: string;
30
30
  };
31
- declare const _default: import('vue').DefineComponent<__VLS_Props, {
32
- currentCase: import('vue').Ref<ICase | null | undefined, ICase | null | undefined>;
31
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {
32
+ currentCase: import("vue").Ref<ICase | null | undefined, ICase | null | undefined>;
33
33
  operating: (data: ILayerOperating) => void;
34
- }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
34
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
35
35
  actions: PreviewActions;
36
- }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
36
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
37
+ declare const _default: typeof __VLS_export;
37
38
  export default _default;
@@ -0,0 +1,104 @@
1
+ import { vLoading } from 'element-plus';
2
+ import { onMounted, onUnmounted, watch } from 'vue';
3
+ import { storeToRefs } from 'pinia';
4
+ import { debounce } from '@jnrs/shared/lodash';
5
+ import { useDataStore, useAppStore } from '@/stores';
6
+ const sharedStore = useDataStore();
7
+ const previewStore = useAppStore();
8
+ const { casesLoading, cases } = storeToRefs(sharedStore);
9
+ const { updateCases } = sharedStore;
10
+ const { currentCase } = storeToRefs(previewStore);
11
+ const { initContainer, resizeContainer, destroyContainer, operating } = previewStore;
12
+ const props = withDefaults(defineProps(), {
13
+ actions: () => ({})
14
+ });
15
+ // 加载 cases 数据
16
+ const handleLoadCases = async () => {
17
+ if (!props.actions.loadCases) {
18
+ console.warn('加载 cases 数据失败,请先配置 loadCases 方法');
19
+ return false;
20
+ }
21
+ casesLoading.value = true;
22
+ try {
23
+ const res = await props.actions.loadCases();
24
+ updateCases(res);
25
+ }
26
+ catch (error) {
27
+ console.error('loadCases:', error);
28
+ }
29
+ finally {
30
+ casesLoading.value = false;
31
+ }
32
+ };
33
+ // 重置窗口大小
34
+ const resize = debounce(() => {
35
+ resizeContainer();
36
+ }, 500);
37
+ watch(() => props.caseUuid, async (caseUuid) => {
38
+ if (caseUuid) {
39
+ // 先获取 sharedStore 内的方案列表数据,没有的话就进行获取
40
+ if (!cases.value || cases.value.length === 0) {
41
+ await handleLoadCases();
42
+ }
43
+ initContainer({
44
+ appDomId: 'lingshu-smart-previewApp',
45
+ appEditable: false,
46
+ actions: {
47
+ onTap: props.actions.onTap,
48
+ onMenuTap: props.actions.onMenuTap,
49
+ onDragEnd: props.actions.onDragEnd
50
+ }
51
+ }, caseUuid);
52
+ }
53
+ }, { immediate: false });
54
+ onMounted(async () => {
55
+ window.addEventListener('resize', resize);
56
+ });
57
+ onUnmounted(() => {
58
+ destroyContainer();
59
+ window.removeEventListener('resize', resize);
60
+ });
61
+ const __VLS_exposed = {
62
+ currentCase,
63
+ operating
64
+ };
65
+ defineExpose(__VLS_exposed);
66
+ debugger; /* PartiallyEnd: #3632/scriptSetup.vue */
67
+ const __VLS_defaults = {
68
+ actions: () => ({})
69
+ };
70
+ const __VLS_ctx = {
71
+ ...{},
72
+ ...{},
73
+ ...{},
74
+ ...{},
75
+ };
76
+ let __VLS_components;
77
+ let __VLS_directives;
78
+ __VLS_asFunctionalElement(__VLS_intrinsics.div, __VLS_intrinsics.div)({
79
+ ...{ class: "lingshu-smart" },
80
+ 'element-loading-background': "rgba(0, 0, 0, 0.5)",
81
+ 'element-loading-text': "方案加载中",
82
+ });
83
+ __VLS_asFunctionalDirective(__VLS_directives.vLoading)(null, { ...__VLS_directiveBindingRestFields, value: (__VLS_ctx.casesLoading) }, null, null);
84
+ // @ts-ignore
85
+ [vLoading, casesLoading,];
86
+ __VLS_asFunctionalElement(__VLS_intrinsics.canvas, __VLS_intrinsics.canvas)({
87
+ id: "lingshu-smart-previewApp",
88
+ });
89
+ if (!__VLS_ctx.currentCase) {
90
+ // @ts-ignore
91
+ [currentCase,];
92
+ __VLS_asFunctionalElement(__VLS_intrinsics.div, __VLS_intrinsics.div)({
93
+ ...{ class: "preset" },
94
+ });
95
+ __VLS_asFunctionalElement(__VLS_intrinsics.i, __VLS_intrinsics.i)({});
96
+ }
97
+ /** @type {__VLS_StyleScopedClasses['lingshu-smart']} */ ;
98
+ /** @type {__VLS_StyleScopedClasses['preset']} */ ;
99
+ const __VLS_export = (await import('vue')).defineComponent({
100
+ setup: () => (__VLS_exposed),
101
+ __typeProps: {},
102
+ props: {},
103
+ });
104
+ export default {};
@@ -1,19 +1,27 @@
1
- import { EnumStepType } from '../types';
1
+ /**
2
+ * @Author : TanRui
3
+ * @WeChat : Tan578853789
4
+ * @File : useStepRecord.ts
5
+ * @Date : 2026/03/05
6
+ * @Desc. : 编辑操作记录 Hook (撤销/重做 + 跳转任意历史点)
7
+ * TODO: 未来可迁移至 IndexedDB 以支持持久化
8
+ */
9
+ import { EnumStepType } from '@/types';
2
10
  interface OperationRecordItem {
3
11
  hash: string;
4
12
  data: string;
5
13
  }
6
14
  export declare function useStepRecord(): {
7
15
  MAX_OPERATION_RECORD_LENGTH: number;
8
- operationRecord: import('vue').Ref<{
16
+ operationRecord: import("vue").Ref<{
9
17
  hash: string;
10
18
  data: string;
11
19
  }[], OperationRecordItem[] | {
12
20
  hash: string;
13
21
  data: string;
14
22
  }[]>;
15
- currentOperationRecordIndex: import('vue').Ref<number, number>;
16
- operationRecordStatus: import('vue').ComputedRef<{
23
+ currentOperationRecordIndex: import("vue").Ref<number, number>;
24
+ operationRecordStatus: import("vue").ComputedRef<{
17
25
  canUndo: boolean;
18
26
  canRedo: boolean;
19
27
  totalSteps: number;
@@ -0,0 +1,135 @@
1
+ /**
2
+ * @Author : TanRui
3
+ * @WeChat : Tan578853789
4
+ * @File : useStepRecord.ts
5
+ * @Date : 2026/03/05
6
+ * @Desc. : 编辑操作记录 Hook (撤销/重做 + 跳转任意历史点)
7
+ * TODO: 未来可迁移至 IndexedDB 以支持持久化
8
+ */
9
+ import { EnumStepType } from '@/types';
10
+ import { storeToRefs } from 'pinia';
11
+ import { ref, computed, watch, nextTick } from 'vue';
12
+ import { debounce, cloneDeep } from '@jnrs/shared/lodash';
13
+ import objectHash from 'object-hash';
14
+ import { useDataStore } from '@/stores';
15
+ const MAX_OPERATION_RECORD_LENGTH = 10;
16
+ export function useStepRecord() {
17
+ const sharedStore = useDataStore();
18
+ const { cases } = storeToRefs(sharedStore);
19
+ const { updateCases } = sharedStore;
20
+ const operationRecord = ref([]);
21
+ const currentOperationRecordIndex = ref(-1);
22
+ const isRecordingLocked = ref(false);
23
+ const operationRecordStatus = computed(() => {
24
+ const len = operationRecord.value.length;
25
+ return {
26
+ canUndo: currentOperationRecordIndex.value > 0,
27
+ canRedo: currentOperationRecordIndex.value < len - 1,
28
+ totalSteps: len,
29
+ currentIndex: currentOperationRecordIndex.value
30
+ };
31
+ });
32
+ const recordOperation = debounce((caseData, hash) => {
33
+ if (!caseData || !hash)
34
+ return;
35
+ const caseDataString = JSON.stringify(caseData);
36
+ const currentLen = operationRecord.value.length;
37
+ if (currentOperationRecordIndex.value === currentLen - 1) {
38
+ if (currentLen >= MAX_OPERATION_RECORD_LENGTH) {
39
+ operationRecord.value.shift();
40
+ // 如果移除了最旧项,索引需同步调整(但此时在末尾,不影响)
41
+ }
42
+ if (currentLen > 0 && operationRecord.value[currentLen - 1]?.hash === hash) {
43
+ return;
44
+ }
45
+ operationRecord.value.push({ hash, data: caseDataString });
46
+ currentOperationRecordIndex.value = operationRecord.value.length - 1;
47
+ }
48
+ else {
49
+ // 在历史中间操作:截断后续
50
+ operationRecord.value.splice(currentOperationRecordIndex.value + 1);
51
+ operationRecord.value.push({ hash, data: caseDataString });
52
+ currentOperationRecordIndex.value = operationRecord.value.length - 1;
53
+ }
54
+ }, 300);
55
+ const applyStateFromIndex = (index) => {
56
+ const record = operationRecord.value[index];
57
+ try {
58
+ const caseData = JSON.parse(record.data);
59
+ updateCases(caseData);
60
+ }
61
+ catch (e) {
62
+ console.error('Failed to parse step record', e);
63
+ }
64
+ };
65
+ const handleOperationRecordChange = (type) => {
66
+ const { canUndo, canRedo } = operationRecordStatus.value;
67
+ if (type === EnumStepType.UNDO && !canUndo)
68
+ return;
69
+ if (type === EnumStepType.REDO && !canRedo)
70
+ return;
71
+ isRecordingLocked.value = true;
72
+ if (type === EnumStepType.UNDO) {
73
+ currentOperationRecordIndex.value -= 1;
74
+ }
75
+ else if (type === EnumStepType.REDO) {
76
+ currentOperationRecordIndex.value += 1;
77
+ }
78
+ applyStateFromIndex(currentOperationRecordIndex.value);
79
+ nextTick(() => {
80
+ isRecordingLocked.value = false;
81
+ });
82
+ };
83
+ /**
84
+ * 跳转到任意历史步骤(不修改历史记录,仅切换状态)
85
+ * @param index 目标历史索引(0-based)
86
+ */
87
+ const jumpToStep = (index) => {
88
+ const len = operationRecord.value.length;
89
+ if (len === 0 || index < 0 || index >= len) {
90
+ return;
91
+ }
92
+ // 加锁,防止触发 watch 记录
93
+ isRecordingLocked.value = true;
94
+ currentOperationRecordIndex.value = index;
95
+ applyStateFromIndex(index);
96
+ nextTick(() => {
97
+ isRecordingLocked.value = false;
98
+ });
99
+ };
100
+ const resetFlags = (data) => {
101
+ if (!Array.isArray(data))
102
+ return;
103
+ data.forEach((item) => {
104
+ if (item && typeof item === 'object') {
105
+ if (Array.isArray(item.layers)) {
106
+ item.layers.forEach((layer) => {
107
+ if (layer && typeof layer === 'object') {
108
+ layer.selected = false;
109
+ }
110
+ });
111
+ }
112
+ }
113
+ });
114
+ };
115
+ watch(cases, (nv) => {
116
+ if (isRecordingLocked.value || !nv)
117
+ return;
118
+ const nvClone = cloneDeep(nv);
119
+ resetFlags(nvClone);
120
+ const casesNvHash = objectHash(nvClone);
121
+ const currentRecord = currentOperationRecordIndex.value >= 0 ? operationRecord.value[currentOperationRecordIndex.value] : null;
122
+ if (currentRecord && currentRecord.hash === casesNvHash) {
123
+ return;
124
+ }
125
+ recordOperation(nvClone, casesNvHash);
126
+ }, { deep: true, immediate: true });
127
+ return {
128
+ MAX_OPERATION_RECORD_LENGTH,
129
+ operationRecord,
130
+ currentOperationRecordIndex,
131
+ operationRecordStatus,
132
+ handleOperationRecordChange,
133
+ jumpToStep
134
+ };
135
+ }
@@ -1,4 +1,11 @@
1
- import { ICase, IModel } from '../types';
1
+ /**
2
+ * @Author : TanRui
3
+ * @WeChat : Tan578853789
4
+ * @File : options.ts
5
+ * @Date : 2026/01/21
6
+ * @Desc. : 编辑页面的初始值配置
7
+ */
8
+ import type { ICase, IModel } from '@/types';
2
9
  /**
3
10
  * 新方案默认值
4
11
  */
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @Author : TanRui
3
+ * @WeChat : Tan578853789
4
+ * @File : options.ts
5
+ * @Date : 2026/01/21
6
+ * @Desc. : 编辑页面的初始值配置
7
+ */
8
+ /**
9
+ * 新方案默认值
10
+ */
11
+ export const CASE_INIT = {
12
+ uuid: '',
13
+ title: '',
14
+ isActive: false,
15
+ layers: [],
16
+ scene: {
17
+ width: 1920,
18
+ height: 1080,
19
+ zoomType: 'fit',
20
+ fill: {
21
+ type: 'solid',
22
+ color: '#000',
23
+ opacity: 1,
24
+ stops: []
25
+ },
26
+ texture: ''
27
+ }
28
+ };
29
+ /**
30
+ * 新图层默认值
31
+ */
32
+ export const DEFAULT_LAYER = {
33
+ rawData: {
34
+ id: ''
35
+ },
36
+ uuid: '',
37
+ equipmentName: '',
38
+ width: 0,
39
+ height: 0,
40
+ x: 0,
41
+ y: 0,
42
+ percentX: 0,
43
+ percentY: 0,
44
+ rotation: 0,
45
+ scale: 1,
46
+ zIndex: 1,
47
+ // 交互状态
48
+ visible: true,
49
+ clickable: true,
50
+ menuClickable: true,
51
+ draggable: false,
52
+ // 编辑状态
53
+ editable: true,
54
+ selected: false
55
+ };
@@ -1,4 +1,11 @@
1
- import { IScene, ILayer, IContainer, ILayerOperating } from '../types';
1
+ /**
2
+ * @Author : TanRui
3
+ * @WeChat : Tan578853789
4
+ * @File : AppController.ts
5
+ * @Date : 2026/02/05
6
+ * @Desc. : 主画布、模型容器控制器
7
+ */
8
+ import type { IScene, ILayer, IContainer, ILayerOperating } from '@/types';
2
9
  import { App } from 'leafer';
3
10
  export declare class AppController {
4
11
  app: App;
@@ -12,8 +19,8 @@ export declare class AppController {
12
19
  destroy(): void;
13
20
  setZoom(zoomType?: 'fit' | number, duration?: number): void;
14
21
  setTree(data?: IScene): void;
15
- findAll(condition: string): import('leafer').IUI[];
16
- findOne(condition: string): import('leafer').IUI | undefined;
22
+ findAll(condition: string): import("leafer").IUI[];
23
+ findOne(condition: string): import("leafer").IUI | undefined;
17
24
  removeOne(condition: string): void;
18
25
  clearAll(): void;
19
26
  removeModelById(uuid: string): void;
@@ -0,0 +1,168 @@
1
+ /**
2
+ * @Author : TanRui
3
+ * @WeChat : Tan578853789
4
+ * @File : AppController.ts
5
+ * @Date : 2026/02/05
6
+ * @Desc. : 主画布、模型容器控制器
7
+ */
8
+ import { createModel } from '@/ui/factories/createModel';
9
+ import { App, Box } from 'leafer';
10
+ const INIT_TREE_CONFIG = {
11
+ width: window.innerWidth,
12
+ height: window.innerHeight,
13
+ fill: undefined,
14
+ zoomType: 'fit'
15
+ };
16
+ export class AppController {
17
+ app;
18
+ treeBoxUI = null; // 主容器
19
+ modelsMap; // 模型容器映射,key 为 uuid,value 为模型实例
20
+ businessMap; // 业务模型映射,key 为 `${className}_${businessId}`,value 为模型实例
21
+ appEditable; // 是否可编辑
22
+ actions; // 事件处理
23
+ constructor(options = {}) {
24
+ const { appDomId, autoStart = true, appEditable = false, actions = {} } = options;
25
+ this.appEditable = appEditable;
26
+ this.actions = actions;
27
+ this.app = new App({
28
+ view: appDomId || window,
29
+ start: autoStart,
30
+ ground: {},
31
+ tree: { type: appEditable ? 'design' : 'game' },
32
+ editor: appEditable ? {} : undefined,
33
+ maxFPS: 60,
34
+ fill: '#424242',
35
+ pointer: {
36
+ preventDefault: true,
37
+ preventDefaultMenu: true
38
+ }
39
+ });
40
+ const treeBoxUI = new Box({
41
+ ...INIT_TREE_CONFIG,
42
+ id: 'treeBoxUI',
43
+ stroke: appEditable ? { type: 'solid', color: 'rgb(242, 195, 79)' } : null
44
+ });
45
+ this.treeBoxUI = treeBoxUI;
46
+ this.app.tree.add(treeBoxUI);
47
+ this.modelsMap = new Map();
48
+ this.businessMap = new Map();
49
+ this.setZoom();
50
+ }
51
+ // 启动/重启引擎
52
+ start() {
53
+ this.app.start();
54
+ }
55
+ // 销毁引擎,默认采用异步销毁,不会立即执行
56
+ destroy() {
57
+ this.clearAll();
58
+ this.app.destroy();
59
+ }
60
+ // 控制视图的缩放
61
+ setZoom(zoomType = 'fit', duration = 0.5) {
62
+ requestAnimationFrame(() => {
63
+ if (zoomType === 'fit') {
64
+ const padding = this.appEditable ? [30, 10, 10, 30] : 0;
65
+ this.app.tree.zoom('fit', padding, false, duration);
66
+ }
67
+ else {
68
+ this.app.tree.zoom(zoomType, 0, false, duration);
69
+ }
70
+ });
71
+ }
72
+ // 修改 tree 配置,不传参数则重置为默认配置
73
+ setTree(data) {
74
+ if (data) {
75
+ this.treeBoxUI?.set({
76
+ width: data.width,
77
+ height: data.height,
78
+ fill: data.fill
79
+ });
80
+ this.setZoom(data.zoomType);
81
+ }
82
+ else {
83
+ this.setTree(INIT_TREE_CONFIG);
84
+ this.setZoom();
85
+ }
86
+ }
87
+ // tree 层查找元素,返回数组
88
+ findAll(condition) {
89
+ return this.treeBoxUI?.find(condition) || [];
90
+ }
91
+ // tree 层查找一个元素,返回匹配到的第一个元素
92
+ findOne(condition) {
93
+ return this.treeBoxUI?.findOne(condition);
94
+ }
95
+ // tree 层移除指定的子元素
96
+ removeOne(condition) {
97
+ this.treeBoxUI?.remove(condition);
98
+ }
99
+ // tree 层清空所有元素(移除 + 销毁)
100
+ clearAll() {
101
+ this.modelsMap.clear();
102
+ this.businessMap.clear();
103
+ this.treeBoxUI?.clear();
104
+ }
105
+ // 根据 uuid 移除模型
106
+ removeModelById(uuid) {
107
+ const model = this.modelsMap.get(uuid);
108
+ if (model) {
109
+ model.destroyUI();
110
+ this.modelsMap.delete(uuid);
111
+ const businessId = model.config.rawData?.id;
112
+ if (businessId) {
113
+ this.businessMap.delete(businessId);
114
+ }
115
+ }
116
+ }
117
+ // 根据类型和配置添加模型
118
+ addModel(modelConfig) {
119
+ const model = createModel(modelConfig);
120
+ // 存储模型绑定事件
121
+ if (this.actions) {
122
+ model.init().setEventHandler({
123
+ onTap: (layer, data) => {
124
+ this.actions.onTap?.(layer, data);
125
+ },
126
+ onMenuTap: (layer, e) => {
127
+ this.actions.onMenuTap?.(layer, e);
128
+ },
129
+ onDragEnd: (layer, e) => {
130
+ this.actions.onDragEnd?.(layer, e);
131
+ }
132
+ });
133
+ }
134
+ // 添加到树
135
+ if (this.treeBoxUI && model.ui) {
136
+ this.treeBoxUI.add(model.ui);
137
+ }
138
+ const uuid = modelConfig.uuid;
139
+ const businessId = modelConfig.rawData?.id;
140
+ // 存储模型引用
141
+ if (uuid) {
142
+ this.modelsMap.set(uuid, model);
143
+ }
144
+ // 存储业务模型引用
145
+ if (businessId) {
146
+ this.businessMap.set(`${modelConfig.className}_${businessId}`, model);
147
+ }
148
+ }
149
+ // 移除并重新添加模型
150
+ rerenderModel(modelConfig) {
151
+ if (modelConfig.uuid) {
152
+ this.removeModelById(modelConfig.uuid);
153
+ }
154
+ this.addModel(modelConfig);
155
+ }
156
+ // 模型操作
157
+ operating(data) {
158
+ const layer = this.businessMap.get(`${data.className}_${data.id}`);
159
+ if (!layer) {
160
+ console.warn('模型操作失败: 模型未匹配到', {
161
+ className: data.className,
162
+ id: data.id
163
+ });
164
+ return;
165
+ }
166
+ layer.handleOperation(data);
167
+ }
168
+ }
@@ -1,5 +1,12 @@
1
- import { ILayer } from '../types';
2
- import { AppController } from './AppController';
1
+ /**
2
+ * @Author : TanRui
3
+ * @WeChat : Tan578853789
4
+ * @File : EditorController.ts
5
+ * @Date : 2025/02/26
6
+ * @Desc. : 图形编辑类
7
+ */
8
+ import type { ILayer } from '@/types';
9
+ import type { AppController } from './AppController';
3
10
  interface EditorOptions {
4
11
  container: AppController;
5
12
  zoomMin?: number;