@zhangqingcq/vgce 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. package/README.md +3 -1
  2. package/dist/vgce.js +5 -12
  3. package/dist/vgce.umd.cjs +2 -2
  4. package/package.json +3 -2
  5. package/src/App.vue +11 -0
  6. package/src/assets/base.less +49 -0
  7. package/src/assets/icons/add.svg +1 -0
  8. package/src/assets/icons/delete.svg +12 -0
  9. package/src/assets/icons/export.svg +1 -0
  10. package/src/assets/icons/group.svg +13 -0
  11. package/src/assets/icons/import.svg +1 -0
  12. package/src/assets/icons/lock.svg +7 -0
  13. package/src/assets/icons/menu-fold.svg +9 -0
  14. package/src/assets/icons/menu-unfold.svg +9 -0
  15. package/src/assets/icons/preview.svg +6 -0
  16. package/src/assets/icons/redo.svg +8 -0
  17. package/src/assets/icons/return.svg +8 -0
  18. package/src/assets/icons/rotate.svg +1 -0
  19. package/src/assets/icons/save.svg +9 -0
  20. package/src/assets/icons/setting.svg +6 -0
  21. package/src/assets/icons/undo.svg +7 -0
  22. package/src/assets/icons/ungroup.svg +16 -0
  23. package/src/assets/icons/unlock.svg +7 -0
  24. package/src/assets/main.less +6 -0
  25. package/src/assets/svgs/alternator.svg +8 -0
  26. package/src/assets/svgs/bot-12.svg +1 -0
  27. package/src/assets/svgs/bot-2.svg +1 -0
  28. package/src/assets/svgs/bot-3.svg +1 -0
  29. package/src/assets/svgs/bot-7.svg +1 -0
  30. package/src/assets/svgs/bot-9.svg +94 -0
  31. package/src/assets/svgs/car.svg +1 -0
  32. package/src/assets/svgs/circuit-breaker.svg +11 -0
  33. package/src/assets/svgs/clock-a.svg +23 -0
  34. package/src/assets/svgs/common-table.svg +7 -0
  35. package/src/assets/svgs/el-button.svg +10 -0
  36. package/src/assets/svgs/el-tag.svg +13 -0
  37. package/src/assets/svgs/hospital.svg +1 -0
  38. package/src/assets/svgs/house.svg +1 -0
  39. package/src/assets/svgs/light.svg +24 -0
  40. package/src/assets/svgs/now-time.svg +9 -0
  41. package/src/assets/svgs/package.svg +1 -0
  42. package/src/assets/svgs/pie-charts.svg +10 -0
  43. package/src/assets/svgs/progress-a.svg +1 -0
  44. package/src/assets/svgs/reservoir.svg +10 -0
  45. package/src/assets/svgs/svg-text.svg +5 -0
  46. package/src/assets/svgs/switch-a.svg +5 -0
  47. package/src/assets/svgs/traction-transformer.svg +11 -0
  48. package/src/components/ace-edit/index.ts +27 -0
  49. package/src/components/config/index.ts +450 -0
  50. package/src/components/config/types.ts +25 -0
  51. package/src/components/svg-analysis/index.vue +11 -0
  52. package/src/components/svg-editor/center-panel/index.vue +867 -0
  53. package/src/components/svg-editor/center-panel/types.ts +11 -0
  54. package/src/components/svg-editor/component-tree/index.vue +33 -0
  55. package/src/components/svg-editor/connection-line/index.vue +125 -0
  56. package/src/components/svg-editor/connection-panel/index.vue +198 -0
  57. package/src/components/svg-editor/export-json/index.vue +37 -0
  58. package/src/components/svg-editor/handle-panel/index.vue +342 -0
  59. package/src/components/svg-editor/import-json/index.vue +37 -0
  60. package/src/components/svg-editor/index.vue +280 -0
  61. package/src/components/svg-editor/left-panel/index.vue +83 -0
  62. package/src/components/svg-editor/right-panel/code-edit-modal.vue +50 -0
  63. package/src/components/svg-editor/right-panel/common-animate.vue +96 -0
  64. package/src/components/svg-editor/right-panel/condition.vue +101 -0
  65. package/src/components/svg-editor/right-panel/dynamic-el-form-item.vue +97 -0
  66. package/src/components/svg-editor/right-panel/index.vue +304 -0
  67. package/src/components/svg-editor/right-panel/list.vue +86 -0
  68. package/src/components/svg-editor/top-panel/index.vue +139 -0
  69. package/src/components/svg-editor/types.ts +22 -0
  70. package/src/components/svg-viewer/index.vue +340 -0
  71. package/src/components/vue3-ruler-tool/index.vue +506 -0
  72. package/src/config/files/clock-a.vue +66 -0
  73. package/src/config/files/common-table.vue +49 -0
  74. package/src/config/files/light-a.vue +72 -0
  75. package/src/config/files/now-time.vue +53 -0
  76. package/src/config/files/pie-charts.vue +72 -0
  77. package/src/config/files/progress.vue +40 -0
  78. package/src/config/files/svg-text.vue +39 -0
  79. package/src/config/files/switch-a.vue +45 -0
  80. package/src/config/index.ts +28 -0
  81. package/src/config/svg/animation/index.ts +8 -0
  82. package/src/config/svg/animation/reservoir.ts +32 -0
  83. package/src/config/svg/custom/clock-a.ts +23 -0
  84. package/src/config/svg/custom/index.ts +11 -0
  85. package/src/config/svg/custom/light.ts +29 -0
  86. package/src/config/svg/custom/svg-text.ts +54 -0
  87. package/src/config/svg/custom/switch-a.ts +29 -0
  88. package/src/config/svg/index.ts +12 -0
  89. package/src/config/svg/stateful/circuit-breaker.ts +38 -0
  90. package/src/config/svg/stateful/index.ts +8 -0
  91. package/src/config/svg/stateless/alternator.ts +28 -0
  92. package/src/config/svg/stateless/bot-12.ts +22 -0
  93. package/src/config/svg/stateless/bot-2.ts +22 -0
  94. package/src/config/svg/stateless/bot-3.ts +22 -0
  95. package/src/config/svg/stateless/bot-7.ts +22 -0
  96. package/src/config/svg/stateless/bot-9.ts +22 -0
  97. package/src/config/svg/stateless/car.ts +22 -0
  98. package/src/config/svg/stateless/hospital.ts +22 -0
  99. package/src/config/svg/stateless/house.ts +22 -0
  100. package/src/config/svg/stateless/index.ts +30 -0
  101. package/src/config/svg/stateless/package.ts +22 -0
  102. package/src/config/svg/stateless/traction-transformer.ts +28 -0
  103. package/src/config/types.ts +126 -0
  104. package/src/config/vue/component/button.ts +57 -0
  105. package/src/config/vue/component/common-table.ts +124 -0
  106. package/src/config/vue/component/index.ts +13 -0
  107. package/src/config/vue/component/now-time.ts +29 -0
  108. package/src/config/vue/component/progress.ts +29 -0
  109. package/src/config/vue/component/tag.ts +46 -0
  110. package/src/config/vue/echarts/index.ts +8 -0
  111. package/src/config/vue/echarts/pie-charts.ts +60 -0
  112. package/src/config/vue/index.ts +5 -0
  113. package/src/hooks.ts +47 -0
  114. package/src/index.ts +14 -0
  115. package/src/main.ts +15 -0
  116. package/src/router.ts +24 -0
  117. package/src/stores/config/index.ts +44 -0
  118. package/src/stores/config/types.ts +27 -0
  119. package/src/stores/global/index.ts +109 -0
  120. package/src/stores/global/types.ts +115 -0
  121. package/src/stores/main.ts +10 -0
  122. package/src/stores/svg-edit-layout/index.ts +17 -0
  123. package/src/stores/svg-edit-layout/types.ts +8 -0
  124. package/src/stores/system/index.ts +174 -0
  125. package/src/stores/system/types.ts +43 -0
  126. package/src/utils/fetch.ts +351 -0
  127. package/src/utils/file-read-write.ts +26 -0
  128. package/src/utils/index.ts +397 -0
  129. package/src/utils/mqtt-net.ts +48 -0
  130. package/src/utils/proxy.ts +7 -0
  131. package/src/utils/scale-core.ts +214 -0
  132. package/src/utils/types.ts +13 -0
  133. package/src/views/EditorS.vue +18 -0
  134. package/src/views/Preview.vue +12 -0
@@ -0,0 +1,342 @@
1
+ <!-- 旋转缩放组件 -->
2
+ <script lang="ts" setup>
3
+ import { pinia } from '@/hooks'
4
+ import { useSvgEditLayoutStore } from '@/stores/svg-edit-layout'
5
+ import { ref } from 'vue'
6
+ import { useGlobalStore } from '@/stores/global'
7
+ import { EGlobalStoreIntention, EMouseInfoState, EScaleInfoType } from '@/stores/global/types'
8
+ import type { IDoneJson } from '@/stores/global/types'
9
+ import { getCoordinateOffset } from '@/utils'
10
+
11
+ const props = defineProps<{ itemInfo: IDoneJson }>()
12
+ const globalStore = useGlobalStore(pinia)
13
+ const svgEditLayoutStore = useSvgEditLayoutStore(pinia)
14
+ const offset = ref(4)
15
+ const fill = ref('#4F80FF')
16
+ const angle_to_cursor = [
17
+ {
18
+ start: 338,
19
+ end: 23,
20
+ cursor: 'nw',
21
+ type: EScaleInfoType.TopLeft
22
+ },
23
+ {
24
+ start: 23,
25
+ end: 68,
26
+ cursor: 'n',
27
+ type: EScaleInfoType.TopCenter
28
+ },
29
+ {
30
+ start: 68,
31
+ end: 113,
32
+ cursor: 'ne',
33
+ type: EScaleInfoType.TopRight
34
+ },
35
+ {
36
+ start: 293,
37
+ end: 338,
38
+ cursor: 'w',
39
+ type: EScaleInfoType.Left
40
+ },
41
+ {
42
+ start: 113,
43
+ end: 158,
44
+ cursor: 'e',
45
+ type: EScaleInfoType.Right
46
+ },
47
+ {
48
+ start: 248,
49
+ end: 293,
50
+ cursor: 'sw',
51
+ type: EScaleInfoType.BottomLeft
52
+ },
53
+ {
54
+ start: 203,
55
+ end: 248,
56
+ cursor: 's',
57
+ type: EScaleInfoType.BottomCenter
58
+ },
59
+ {
60
+ start: 158,
61
+ end: 203,
62
+ cursor: 'se',
63
+ type: EScaleInfoType.BottomRight
64
+ }
65
+ ]
66
+ const onHandleMouseDown = (type: EScaleInfoType, e: MouseEvent) => {
67
+ console.log('onHandleMouseDown', e)
68
+ const { clientX, clientY } = e
69
+ e.stopPropagation()
70
+ globalStore.intention = EGlobalStoreIntention.Zoom
71
+ globalStore.setMouseInfo({
72
+ state: EMouseInfoState.Down,
73
+ position_x: clientX - svgEditLayoutStore.center_offset.x,
74
+ position_y: clientY - svgEditLayoutStore.center_offset.y,
75
+ now_position_x: clientX - svgEditLayoutStore.center_offset.x,
76
+ now_position_y: clientY - svgEditLayoutStore.center_offset.y,
77
+ new_position_x: 0,
78
+ new_position_y: 0
79
+ })
80
+ globalStore.setScaleInfo({
81
+ type: type,
82
+ scale_times: {
83
+ x: props.itemInfo.scale_x,
84
+ y: props.itemInfo.scale_y
85
+ },
86
+ scale_item_info: {
87
+ x: props.itemInfo.x,
88
+ y: props.itemInfo.y
89
+ },
90
+ symmetric_point: {
91
+ x:
92
+ props.itemInfo.client.x +
93
+ Math.abs(clientX - svgEditLayoutStore.center_offset.x - props.itemInfo.client.x) *
94
+ (clientX - svgEditLayoutStore.center_offset.x < props.itemInfo.client.x ? 1 : -1),
95
+ y:
96
+ props.itemInfo.client.y +
97
+ Math.abs(clientY - svgEditLayoutStore.center_offset.y - props.itemInfo.client.y) *
98
+ (clientY - svgEditLayoutStore.center_offset.y < props.itemInfo.client.y ? 1 : -1)
99
+ }
100
+ })
101
+ }
102
+ const onRotateCircleMouseDown = (e: MouseEvent) => {
103
+ const { clientX, clientY } = e
104
+ e.stopPropagation()
105
+ globalStore.intention = EGlobalStoreIntention.Rotate
106
+ globalStore.rotate_info = {
107
+ angle: props.itemInfo.rotate
108
+ }
109
+ globalStore.setMouseInfo({
110
+ state: EMouseInfoState.Down,
111
+ position_x: clientX - svgEditLayoutStore.center_offset.x,
112
+ position_y: clientY - svgEditLayoutStore.center_offset.y,
113
+ now_position_x: clientX - svgEditLayoutStore.center_offset.x,
114
+ now_position_y: clientY - svgEditLayoutStore.center_offset.y,
115
+ new_position_x: 0,
116
+ new_position_y: 0
117
+ })
118
+ }
119
+ /**
120
+ * 获取旋转之后的光标样式
121
+ * @param init_angle 初始角度 360/8=45
122
+ */
123
+ const getCursor = (init_angle: number) => {
124
+ const now_init_angle = (init_angle + props.itemInfo.rotate) % 360
125
+ const find_cursor = angle_to_cursor.find((f) => f.start <= now_init_angle && f.end > now_init_angle)
126
+ if (!find_cursor) {
127
+ return {
128
+ cursor: 'nw-resize',
129
+ type: EScaleInfoType.TopLeft
130
+ }
131
+ }
132
+ return {
133
+ cursor: find_cursor.cursor + '-resize',
134
+ type: find_cursor.type
135
+ }
136
+ }
137
+ </script>
138
+
139
+ <template>
140
+ <g style="vector-effect: non-scaling-stroke">
141
+ <rect
142
+ id="resize_tl"
143
+ width="8"
144
+ height="8"
145
+ :fill="fill"
146
+ :style="{ cursor: getCursor(0).cursor, 'vector-effect': 'non-scaling-stroke' }"
147
+ pointer-events="all"
148
+ :x="
149
+ props.itemInfo.actual_bound.x -
150
+ offset -
151
+ getCoordinateOffset(props.itemInfo.actual_bound.width, props.itemInfo.scale_x)
152
+ "
153
+ :y="
154
+ props.itemInfo.actual_bound.y -
155
+ offset -
156
+ getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y)
157
+ "
158
+ stroke="rgba(0,0,0,0)"
159
+ @mousedown="onHandleMouseDown(EScaleInfoType.TopLeft, $event)"
160
+ >
161
+ </rect>
162
+ <circle
163
+ :cx="props.itemInfo.actual_bound.x + props.itemInfo.actual_bound.width / 2"
164
+ :cy="
165
+ props.itemInfo.actual_bound.y -
166
+ offset -
167
+ getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y) -
168
+ 24
169
+ "
170
+ :r="4"
171
+ class="rotate-circle"
172
+ @mousedown="onRotateCircleMouseDown"
173
+ />
174
+ <line
175
+ :x1="props.itemInfo.actual_bound.x + props.itemInfo.actual_bound.width / 2"
176
+ :y1="
177
+ props.itemInfo.actual_bound.y -
178
+ offset -
179
+ getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y)
180
+ "
181
+ :x2="props.itemInfo.actual_bound.x + props.itemInfo.actual_bound.width / 2"
182
+ :y2="
183
+ props.itemInfo.actual_bound.y -
184
+ offset -
185
+ getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y) -
186
+ 20
187
+ "
188
+ :style="{ stroke: fill, 'stroke-width': 2 }"
189
+ />
190
+ <rect
191
+ id="resize_tc"
192
+ width="8"
193
+ height="8"
194
+ :fill="fill"
195
+ :style="{ cursor: getCursor(45).cursor, 'vector-effect': 'non-scaling-stroke' }"
196
+ pointer-events="all"
197
+ :x="props.itemInfo.actual_bound.x + props.itemInfo.actual_bound.width / 2 - offset"
198
+ :y="
199
+ props.itemInfo.actual_bound.y -
200
+ offset -
201
+ getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y)
202
+ "
203
+ stroke="rgba(0,0,0,0)"
204
+ @mousedown="onHandleMouseDown(EScaleInfoType.TopCenter, $event)"
205
+ ></rect>
206
+ <rect
207
+ id="resize_tr"
208
+ width="8"
209
+ height="8"
210
+ :fill="fill"
211
+ :style="{ cursor: getCursor(90).cursor, 'vector-effect': 'non-scaling-stroke' }"
212
+ pointer-events="all"
213
+ :x="
214
+ props.itemInfo.actual_bound.x +
215
+ props.itemInfo.actual_bound.width -
216
+ offset +
217
+ getCoordinateOffset(props.itemInfo.actual_bound.width, props.itemInfo.scale_x)
218
+ "
219
+ :y="
220
+ props.itemInfo.actual_bound.y -
221
+ offset -
222
+ getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y)
223
+ "
224
+ stroke="rgba(0,0,0,0)"
225
+ @mousedown="onHandleMouseDown(EScaleInfoType.TopRight, $event)"
226
+ ></rect>
227
+ <rect
228
+ id="resize_l"
229
+ width="8"
230
+ height="8"
231
+ :fill="fill"
232
+ :style="{ cursor: getCursor(315).cursor, 'vector-effect': 'non-scaling-stroke' }"
233
+ pointer-events="all"
234
+ :x="
235
+ props.itemInfo.actual_bound.x -
236
+ offset -
237
+ getCoordinateOffset(props.itemInfo.actual_bound.width, props.itemInfo.scale_x)
238
+ "
239
+ :y="
240
+ props.itemInfo.actual_bound.y -
241
+ offset +
242
+ (props.itemInfo.actual_bound.height * props.itemInfo.scale_y) / 2 -
243
+ getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y)
244
+ "
245
+ stroke="rgba(0,0,0,0)"
246
+ @mousedown="onHandleMouseDown(EScaleInfoType.Left, $event)"
247
+ ></rect>
248
+ <rect
249
+ id="resize_r"
250
+ width="8"
251
+ height="8"
252
+ :fill="fill"
253
+ :style="{ cursor: getCursor(135).cursor, 'vector-effect': 'non-scaling-stroke' }"
254
+ pointer-events="all"
255
+ :x="
256
+ props.itemInfo.actual_bound.x -
257
+ offset +
258
+ props.itemInfo.actual_bound.width +
259
+ getCoordinateOffset(props.itemInfo.actual_bound.width, props.itemInfo.scale_x)
260
+ "
261
+ :y="
262
+ props.itemInfo.actual_bound.y -
263
+ offset +
264
+ (props.itemInfo.actual_bound.height * props.itemInfo.scale_y) / 2 -
265
+ getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y)
266
+ "
267
+ stroke="rgba(0,0,0,0)"
268
+ @mousedown="onHandleMouseDown(EScaleInfoType.Right, $event)"
269
+ ></rect>
270
+ <rect
271
+ id="resize_bl"
272
+ width="8"
273
+ height="8"
274
+ :fill="fill"
275
+ :style="{ cursor: getCursor(270).cursor, 'vector-effect': 'non-scaling-stroke' }"
276
+ pointer-events="all"
277
+ :x="
278
+ props.itemInfo.actual_bound.x -
279
+ offset -
280
+ getCoordinateOffset(props.itemInfo.actual_bound.width, props.itemInfo.scale_x)
281
+ "
282
+ :y="
283
+ props.itemInfo.actual_bound.y -
284
+ offset +
285
+ props.itemInfo.actual_bound.height * props.itemInfo.scale_y -
286
+ getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y)
287
+ "
288
+ stroke="rgba(0,0,0,0)"
289
+ @mousedown="onHandleMouseDown(EScaleInfoType.BottomLeft, $event)"
290
+ ></rect>
291
+ <rect
292
+ id="resize_bc"
293
+ width="8"
294
+ height="8"
295
+ :fill="fill"
296
+ :style="{ cursor: getCursor(225).cursor, 'vector-effect': 'non-scaling-stroke' }"
297
+ pointer-events="all"
298
+ :x="props.itemInfo.actual_bound.x - offset + props.itemInfo.actual_bound.width / 2"
299
+ :y="
300
+ props.itemInfo.actual_bound.y -
301
+ offset +
302
+ props.itemInfo.actual_bound.height +
303
+ getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y)
304
+ "
305
+ stroke="rgba(0,0,0,0)"
306
+ @mousedown="onHandleMouseDown(EScaleInfoType.BottomCenter, $event)"
307
+ ></rect>
308
+ <rect
309
+ id="resize_br"
310
+ width="8"
311
+ height="8"
312
+ :fill="fill"
313
+ :style="{ cursor: getCursor(180).cursor, 'vector-effect': 'non-scaling-stroke' }"
314
+ pointer-events="all"
315
+ :x="
316
+ props.itemInfo.actual_bound.x -
317
+ offset +
318
+ props.itemInfo.actual_bound.width +
319
+ getCoordinateOffset(props.itemInfo.actual_bound.width, props.itemInfo.scale_x)
320
+ "
321
+ :y="
322
+ props.itemInfo.actual_bound.y -
323
+ offset +
324
+ props.itemInfo.actual_bound.height +
325
+ getCoordinateOffset(props.itemInfo.actual_bound.height, props.itemInfo.scale_y)
326
+ "
327
+ stroke="rgba(0,0,0,0)"
328
+ @mousedown="onHandleMouseDown(EScaleInfoType.BottomRight, $event)"
329
+ ></rect>
330
+ </g>
331
+ </template>
332
+
333
+ <style scoped>
334
+ .rotate-circle {
335
+ stroke: v-bind('fill');
336
+ stroke-width: 1;
337
+ fill-opacity: 0;
338
+ cursor:
339
+ url('@/assets/icons/rotate.svg') 12 12,
340
+ auto;
341
+ }
342
+ </style>
@@ -0,0 +1,37 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { VAceEditor } from 'vue3-ace-editor'
4
+ import '@/components/ace-edit'
5
+
6
+ import { useImportDataModel } from '@/hooks'
7
+ import { ElMessage } from 'element-plus'
8
+ const content = ref<string>('')
9
+
10
+ const setVal = (d: any) => {
11
+ content.value = d
12
+ }
13
+ const onImportJson = () => {
14
+ if (useImportDataModel(content.value)) {
15
+ ElMessage.success('导入成功')
16
+ }
17
+ }
18
+ defineExpose({
19
+ setVal,
20
+ onImportJson
21
+ })
22
+ </script>
23
+
24
+ <template>
25
+ <v-ace-editor
26
+ v-model:value="content"
27
+ lang="json"
28
+ theme="kr_theme"
29
+ style="height: 400px"
30
+ :options="{
31
+ useWorker: true,
32
+ enableBasicAutocompletion: true,
33
+ enableSnippets: true,
34
+ enableLiveAutocompletion: true
35
+ }"
36
+ />
37
+ </template>
@@ -0,0 +1,280 @@
1
+ <script setup lang="ts">
2
+ import { getCurrentInstance, onMounted, reactive, ref } from 'vue'
3
+ import {
4
+ ElContainer,
5
+ ElHeader,
6
+ ElAside,
7
+ ElMain,
8
+ ElScrollbar,
9
+ ElDialog,
10
+ ElButton,
11
+ ElUpload,
12
+ ElMessage,
13
+ ElMessageBox
14
+ } from 'element-plus'
15
+ import 'element-plus/dist/index.css'
16
+ import 'animate.css'
17
+ import TopPanel from '@/components/svg-editor/top-panel/index.vue'
18
+ import LeftPanel from '@/components/svg-editor/left-panel/index.vue'
19
+ import CenterPanel from '@/components/svg-editor/center-panel/index.vue'
20
+ import RightPanel from '@/components/svg-editor/right-panel/index.vue'
21
+ import ExportJson from '@/components/svg-editor/export-json/index.vue'
22
+ import ImportJson from '@/components/svg-editor/import-json/index.vue'
23
+ import Vue3RulerTool from '@/components/vue3-ruler-tool/index.vue'
24
+ import { EVisibleConfKey } from '@/components/svg-editor/types'
25
+ import type { IVisibleConf, IDataModel } from '@/components/svg-editor/types'
26
+ import type { IConfig } from '@/config/types'
27
+ import { EGlobalStoreIntention } from '@/stores/global/types'
28
+ import type { IDoneJson } from '@/stores/global/types'
29
+ import { pinia } from '@/hooks'
30
+ import { useSvgEditLayoutStore } from '@/stores/svg-edit-layout'
31
+ import { useImportDataModel } from '@/hooks'
32
+ import { useGlobalStore } from '@/stores/global'
33
+ import { useConfigStore } from '@/stores/config'
34
+ import { fileRead, fileWrite } from '@/utils/file-read-write'
35
+
36
+ const props = withDefaults(defineProps<{ customToolbar?: IConfig; data?: string; saveFile?: boolean }>(), {
37
+ saveFile: false
38
+ })
39
+ const presetLine = ref([])
40
+ const input = (list: any) => {
41
+ presetLine.value = list
42
+ }
43
+ const globalStore = useGlobalStore(pinia)
44
+ const svgEditLayoutStore = useSvgEditLayoutStore(pinia)
45
+ const configStore = useConfigStore(pinia)
46
+ const importJsonRef = ref<InstanceType<typeof ImportJson>>()
47
+ const visible_conf: IVisibleConf = reactive({
48
+ [EVisibleConfKey.ExportJson]: false,
49
+ [EVisibleConfKey.ImportJson]: false,
50
+ [EVisibleConfKey.ImportFile]: false
51
+ })
52
+ const emits = defineEmits(['onReturn', 'onPreview', 'onSave'])
53
+ const changeVisible = (key: EVisibleConfKey, val: boolean) => {
54
+ visible_conf[key] = val
55
+ }
56
+
57
+ const onImportJson = ref()
58
+ onImportJson.value = () => {
59
+ importJsonRef.value!.onImportJson()
60
+ changeVisible(EVisibleConfKey.ImportJson, false)
61
+ }
62
+
63
+ const onImportFile = (f: File) => {
64
+ if (['text/plain', 'application/json'].indexOf(f.type) < 0) {
65
+ ElMessage.error('仅支持的格式:txt、json')
66
+ return false
67
+ }
68
+ fileRead(f).then((r) => {
69
+ importJsonRef.value!.setVal(r)
70
+ ElMessage.success('文件读取成功!')
71
+ })
72
+ return false
73
+ }
74
+ const setGraphNodeJson = (done_json: IDoneJson[]) => {
75
+ globalStore.setDoneJson(done_json)
76
+ }
77
+ onMounted(() => {
78
+ if (props.data) {
79
+ useImportDataModel(props.data)
80
+ } else {
81
+ globalStore.setDoneJson([])
82
+ }
83
+ globalStore.intention = EGlobalStoreIntention.None
84
+ })
85
+ defineExpose({
86
+ setGraphNodeJson
87
+ })
88
+
89
+ const { appContext } = getCurrentInstance()!
90
+
91
+ function save(d: IDataModel) {
92
+ if (props.saveFile) {
93
+ ElMessageBox.prompt('请输入文件名', '保存', { cancelButtonText: '取消', confirmButtonText: '保存' }, appContext)
94
+ .then((r: any) => {
95
+ fileWrite(d, r.value.trim())
96
+ emits('onSave', d)
97
+ })
98
+ .catch((e: any) => {
99
+ console.log(e)
100
+ })
101
+ } else {
102
+ emits('onSave', d)
103
+ }
104
+ }
105
+ </script>
106
+ <template>
107
+ <div>
108
+ <el-container>
109
+ <el-header class="top-el-header">
110
+ <top-panel
111
+ @change-visible="changeVisible"
112
+ @on-return="emits('onReturn')"
113
+ @on-preview="(val: IDataModel) => emits('onPreview', val)"
114
+ @on-save="save"
115
+ ></top-panel>
116
+ </el-header>
117
+ <el-container class="middle">
118
+ <el-aside class="side-nav" :class="svgEditLayoutStore.left_nav ? 'show-nav' : 'hide-nav'">
119
+ <el-scrollbar class="el-scroll-pc">
120
+ <left-panel class="content-left" :custom-toolbar="props.customToolbar" />
121
+ </el-scrollbar>
122
+ </el-aside>
123
+ <el-main class="middle main">
124
+ <div class="canvas-main-pc">
125
+ <Vue3RulerTool
126
+ class="canvas-main-pc"
127
+ :value="presetLine"
128
+ :step-length="50"
129
+ :parent="true"
130
+ :is-scale-revise="false"
131
+ v-model:visible="configStore.svg.ruler"
132
+ @input="input"
133
+ >
134
+ <center-panel></center-panel>
135
+ </Vue3RulerTool>
136
+ </div>
137
+ </el-main>
138
+ <el-aside class="side-nav" :class="svgEditLayoutStore.right_nav ? 'show-nav' : 'hide-nav'">
139
+ <el-scrollbar class="el-scroll-pc">
140
+ <right-panel></right-panel>
141
+ </el-scrollbar>
142
+ </el-aside>
143
+ </el-container>
144
+ </el-container>
145
+ <el-dialog class="modal-full" v-model="visible_conf.ImportJson" title="导入数据" width="60%" destroy-on-close>
146
+ <import-json ref="importJsonRef"></import-json>
147
+ <template #footer>
148
+ <el-upload
149
+ :beforeUpload="onImportFile"
150
+ style="display: inline-flex; margin-right: 12px"
151
+ :multiple="false"
152
+ :show-file-list="false"
153
+ :limit="1"
154
+ >
155
+ <el-button @click="changeVisible(EVisibleConfKey.ImportFile, true)">读取文件</el-button>
156
+ </el-upload>
157
+ <el-button type="primary" @click="onImportJson">导入数据</el-button>
158
+ </template>
159
+ </el-dialog>
160
+ <el-dialog class="modal-full" v-model="visible_conf.ExportJson" title="导出" width="60%" destroy-on-close>
161
+ <export-json></export-json>
162
+ </el-dialog>
163
+ </div>
164
+ </template>
165
+ <style scoped lang="less">
166
+ @headerHeight: 45px;
167
+ .el-scroll-pc {
168
+ height: calc(100vh - @headerHeight - 1px);
169
+ }
170
+
171
+ .canvas-main-pc {
172
+ width: 100%;
173
+ height: 100%;
174
+ margin: 0 auto;
175
+ }
176
+
177
+ .middle {
178
+ height: calc(100vh - @headerHeight - 1px);
179
+
180
+ &.main {
181
+ margin: 0 5px;
182
+ background-color: #ffffff;
183
+ padding: 0 2px;
184
+ }
185
+
186
+ .side-nav {
187
+ @showLeftNavWidth: 260px;
188
+ @hideLeftNavWidth: 0;
189
+ position: relative;
190
+ overflow: inherit;
191
+ transition: all 0.5s;
192
+ // background-color: rgb(250, 251, 253);
193
+ box-shadow: 0 0 2px #dfcfcf;
194
+
195
+ .content-left {
196
+ overflow: hidden;
197
+ margin: 0 1vh;
198
+ }
199
+
200
+ &.show-nav {
201
+ flex: 0 0 @showLeftNavWidth;
202
+ min-width: @showLeftNavWidth;
203
+ max-width: @showLeftNavWidth;
204
+ }
205
+
206
+ &.hide-nav {
207
+ flex: 0 0 @hideLeftNavWidth;
208
+ min-width: @hideLeftNavWidth;
209
+ max-width: @hideLeftNavWidth;
210
+ }
211
+ }
212
+ }
213
+
214
+ .top-el-header {
215
+ display: flex;
216
+ flex-direction: row;
217
+ align-items: center;
218
+ box-shadow: 0 0 2px #dfcfcf;
219
+ margin-bottom: 1px;
220
+ height: @headerHeight;
221
+ }
222
+
223
+ .bottom-el-footer {
224
+ box-shadow: 0 -1px 0 0 #dfcfcf;
225
+ margin-top: 10px;
226
+ }
227
+
228
+ .contextMenu {
229
+ position: absolute;
230
+ z-index: 99999;
231
+ background: #ffffff;
232
+ padding: 5px 0;
233
+ margin: 0;
234
+ display: block;
235
+ border-radius: 5px;
236
+ box-shadow: 2px 5px 10px rgba(0, 0, 0, 0.3);
237
+
238
+ li {
239
+ list-style: none;
240
+ padding: 0;
241
+ margin: 0;
242
+ }
243
+
244
+ .shortcut {
245
+ width: 115px;
246
+ text-align: right;
247
+ float: right;
248
+ }
249
+
250
+ p {
251
+ text-decoration: none;
252
+ display: block;
253
+ padding: 0 15px 1px 20px;
254
+ margin: 0;
255
+ user-select: none;
256
+ -webkit-user-select: none;
257
+ }
258
+
259
+ p:hover {
260
+ background-color: #0cf;
261
+ color: #ffffff;
262
+ cursor: default;
263
+ }
264
+
265
+ .disabled {
266
+ color: #999;
267
+ }
268
+
269
+ .disabled:hover {
270
+ color: #999;
271
+ background-color: transparent;
272
+ }
273
+
274
+ li.separator {
275
+ border-top: solid 1px #e3e3e3;
276
+ padding-top: 5px;
277
+ margin-top: 5px;
278
+ }
279
+ }
280
+ </style>