zydx-plus 1.36.646 → 1.36.648

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zydx-plus",
3
- "version": "1.36.646",
3
+ "version": "1.36.648",
4
4
  "description": "Vue.js",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -1,377 +1,557 @@
1
- <template>
2
- <div class="mind" :class="{'full-screen':!fullShow}" :ref="id">
3
- <div class="mind-table">
4
- <div class="table-left" v-if="!readOnly">
5
- <button :disabled="mindShow" @click="addNode">添加节点</button>
6
- <button :disabled="mindShow" @click="brotherNode">兄弟节点</button>
7
- <button :disabled="mindShow" @click="delNode">删除节点</button>
8
- <button :disabled="mindShow" @click="associativeLine">关联线</button>
9
- <button :disabled="lineShow" @click="lineStyle">关联样式</button>
10
- <button :disabled="mindShow" @click="nodeStyle">节点样式</button>
11
- <div class="mind-btn">
12
- <span>结构切换</span>
13
- <div class="mind-btn-list">
14
- <button @click="structure('logicalStructure')"
15
- :disabled="layoutList === 'logicalStructure' || layoutList === ''">向右结构
16
- </button>
17
- <button @click="structure('organizationStructure')" :disabled="layoutList === 'organizationStructure'">
18
- 向下结构
19
- </button>
20
- <button @click="structure('mindMap')" :disabled="layoutList === 'mindMap'">左右结构</button>
21
- </div>
22
- </div>
23
- <button :disabled="retShow" @click="ret">上一步</button>
24
- <button :disabled="forwardShow" @click="forward">下一步</button>
25
- <button @click="reset" v-if="resetShow">重置位置</button>
26
- <button v-if="protectShow" @click="preservation">保存</button>
27
- <button @click="fullTap(false)" v-if="fullShow&&full">全屏</button>
28
- <button @click="fullDel(true)" v-if="!fullShow">退出</button>
29
- </div>
30
- </div>
31
- <div :id="id" class="mindMapContainer"></div>
32
- <Tool v-model:open="styleStatus" :node="nodeData" @select="toolSelect"></Tool>
33
- <LineTool v-model:open="lineStyleStatus" :node="lineData" @select="lineToolSelect"></LineTool>
34
- </div>
35
- </template>
36
-
37
- <script>
38
-
39
- import MindMap from "simple-mind-map";
40
- import TouchEvent from 'simple-mind-map/src/plugins/TouchEvent.js'
41
- import AssociativeLine from 'simple-mind-map/src/plugins/AssociativeLine.js'
42
- import Export from 'simple-mind-map/src/plugins/Export.js'
43
- import Tool from "./tool.vue";
44
- import LineTool from "./lineTool.vue";
45
-
46
- MindMap.usePlugin(AssociativeLine)
47
- MindMap.usePlugin(TouchEvent)
48
- MindMap.usePlugin(Export)
49
-
50
- export default {
51
- components: {LineTool, Tool},
52
- name: "zydx-mind",
53
- data() {
54
- return {
55
- id: null,
56
- mindMap: null,
57
- mindShow: true,
58
- retShow: false,
59
- forwardShow: false,
60
- nodeData: null,
61
- lineData: null,
62
- colorShow: false,
63
- lineStyleStatus: false,
64
- lineShow: true,
65
- top: 0,
66
- activeNodes: null,
67
- defaultData: {
68
- "data": {
69
- "text": "根节点"
70
- },
71
- "children": []
72
- },
73
- fullShow: true,
74
- layoutList: '',
75
- updateInit: false,
76
- styleStatus: false,
77
- activeLineNode: null,
78
- activeLineToNode: null
79
- }
80
- },
81
- props: {
82
- data: { // 数据
83
- type: Object,
84
- default: {
85
- "data": {
86
- "text": "根节点"
87
- },
88
- "children": []
89
- }
90
- },
91
- readOnly: { // 只读
92
- type: Boolean,
93
- default: false
94
- },
95
- protectShow: {
96
- type: Boolean,
97
- default: true
98
- },
99
- updateStatus: {
100
- type: Boolean,
101
- default: false
102
- },
103
- resetShow: {
104
- type: Boolean,
105
- default: true
106
- },
107
- full: {
108
- type: Boolean,
109
- default: true
110
- }
111
- },
112
- beforeUnmount() {
113
- this.mindMap.destroy()
114
- this.mindMap = null
115
- },
116
- watch: {
117
- readOnly: {
118
- handler: function (val, oldVal) {
119
- this.mindMap?.setMode(val ? 'readonly' : 'edit')
120
- },
121
- deep: true,
122
- immediate: true
123
- },
124
- data: {
125
- handler: function (val) {
126
- if (this.updateInit) return
127
- if (this.updateStatus) this.updateInit = true
128
- if (Object.keys(val).length === 0) {
129
- this.mindMap?.setData(this.defaultData)
130
- } else {
131
- this.mindMap?.setData(this.msgFun(val))
132
- this.mindMap?.setLayout(val.layoutList || 'logicalStructure')
133
- }
134
- },
135
- immediate: true
136
- },
137
- shapeValue(e) { // 形状
138
- this.activeNodes.forEach(node => {
139
- node.setStyle('shape', e)
140
- })
141
- },
142
- },
143
- mounted() {
144
- this.id = this.randomId()
145
- setTimeout(() => {
146
- this.init()
147
- const resizeObserver = new ResizeObserver(this.debounce(this.resizeCallback, 300));
148
- resizeObserver.observe(this.$refs[this.id]);
149
- }, 0)
150
- window.onresize = () => {
151
- if (!document.fullscreenElement) {
152
- this.fullShow = true
153
- }
154
- this.mindMap?.resize()
155
- }
156
- },
157
- methods: {
158
- resizeCallback(entries) {
159
- entries.forEach(entry => {
160
- this.mindMap?.resize()
161
- });
162
- },
163
- debounce(fn, delay = 500) {
164
- let timer = null; // 定时器标识,用于重置延迟
165
-
166
- return function (...args) {
167
- // 每次触发时,清除之前的定时器(重置延迟)
168
- clearTimeout(timer);
169
- // 重新设置定时器,延迟执行目标函数
170
- timer = setTimeout(() => {
171
- fn.apply(this, args); // 保证this指向和参数传递正常
172
- }, delay);
173
- };
174
- },
175
- lineToolSelect(v) {
176
- const associativeLineStyle = this.activeLineNode.getData('associativeLineStyle') || {}
177
- const toNodeUid = this.activeLineToNode.getData('uid')
178
- const lineStyle = associativeLineStyle[toNodeUid] || {}
179
- this.activeLineNode.setData({
180
- associativeLineStyle: {
181
- ...associativeLineStyle,
182
- [toNodeUid]: {
183
- ...lineStyle,
184
- ...v
185
- }
186
- }
187
- })
188
- this.mindMap.associativeLine.updateActiveLineStyle()
189
- },
190
- toolSelect(v) {
191
- this.activeNodes.forEach(node => {
192
- node.setStyle(v.type, v.value)
193
- })
194
- },
195
- randomId() {
196
- const id = Math.random().toString(36).substr(2)
197
- return id.replace(/[0-9]/g, '')
198
- },
199
- fullScreen(element) {
200
- if (element.requestFullScreen) {
201
- element.requestFullScreen()
202
- } else if (element.webkitRequestFullScreen) {
203
- element.webkitRequestFullScreen()
204
- } else if (element.mozRequestFullScreen) {
205
- element.mozRequestFullScreen()
206
- }
207
- },
208
- cancelFullscreen() {
209
- if (document.exitFullscreen) {
210
- document.exitFullscreen();
211
- } else if (document.msExitFullscreen) {
212
- document.msExitFullscreen();
213
- } else if (document.mozCancelFullScreen) {
214
- document.mozCancelFullScreen();
215
- } else if (document.webkitExitFullscreen) {
216
- document.webkitExitFullscreen();
217
- }
218
- },
219
- fullDel(v) {
220
- this.fullShow = v
221
- this.mindMap.view.setTransformData({
222
- state: {scale: 1, x: 0, y: 0, sx: 0, sy: 0},
223
- transform: {
224
- a: 1,
225
- b: 0,
226
- c: 0,
227
- d: 1,
228
- e: 0,
229
- f: 0,
230
- originX: 0,
231
- originY: 0,
232
- rotate: 0,
233
- scaleX: 1,
234
- scaleY: 1,
235
- shear: 0,
236
- translateX: 0,
237
- translateY: 0
238
- }
239
- })
240
- this.cancelFullscreen()
241
- },
242
- // 全屏
243
- fullTap(v) {
244
- this.fullShow = v
245
- this.fullScreen(document.body)
246
- },
247
- msgFun(e) {
248
- if (e.msg) {
249
- return Object.keys(e.msg).length === 0 ? this.defaultData : e.msg
250
- } else {
251
- return Object.keys(e).length === 0 ? this.defaultData : e
252
- }
253
- },
254
- // 初始化
255
- init() {
256
- const that = this
257
- this.mindMap = new MindMap({
258
- el: document.getElementById(that.id),
259
- openPerformance: true,
260
- enableFreeDrag: false, // 是否开启自由拖拽
261
- enableNodeTransitionMove: false, // 是否开启节点过渡动画
262
- layout: that.data.layoutList || 'logicalStructure', // 节点布局方式
263
- maxHistoryCount: 100, // 最大历史记录数
264
- maxNodeCacheCount: 100, // 最大节点缓存数
265
- data: that.msgFun(that.data)
266
- });
267
- this.mindMap.setMode(this.readOnly ? 'readonly' : 'edit')
268
- // 节点点击
269
- this.mindMap.on('node_active', (node, activeNodeList) => {
270
- this.nodeData = node
271
- this.activeNodes = activeNodeList
272
- this.mindShow = !node
273
- if (node) {
274
- this.lineData = null
275
- this.lineShow = true
276
- }
277
- })
278
- // 后退前进
279
- this.mindMap.on('back_forward', (index, len) => {
280
- this.retShow = index <= 0;
281
- this.forwardShow = index >= len - 1
282
- })
283
- // 关联线点击
284
- this.mindMap.on('associative_line_click', (path, clickPath, node, toNode) => {
285
- this.activeLineNode = node
286
- this.activeLineToNode = toNode
287
- this.lineData = this.mindMap.associativeLine.getStyleConfig(node, toNode)
288
- this.lineShow = false
289
- })
290
- // 点击画布
291
- this.mindMap.on('draw_click', () => {
292
- this.lineStyleStatus = false
293
- this.styleStatus = false
294
- this.lineShow = true
295
- this.mindShow = true
296
- this.nodeData = null
297
- this.activeNodes = []
298
- this.lineData = null
299
- })
300
- // 数据改变
301
- this.mindMap.on('data_change', (data) => {
302
- this.$emit('dataChange', {
303
- data: data,
304
- url: ''
305
- })
306
- })
307
- },
308
- structure(v) {
309
- this.layoutList = v
310
- this.mindMap.setLayout(this.layoutList)
311
- },
312
- // 保存
313
- preservation() {
314
- let that = this
315
- this.styleStatus = false
316
- this.lineStyleStatus = false
317
- that.$emit('preservation', {
318
- data: {
319
- msg: that.mindMap.getData(),
320
- layoutList: this.layoutList
321
- },
322
- url: ''
323
- })
324
- },
325
- getContent() {
326
- let that = this
327
- return new Promise((rl, rs) => {
328
- rl({
329
- data: that.mindMap.getData(),
330
- url: ''
331
- })
332
- })
333
- },
334
- getImage(v) {
335
- const name = v ? v : 'mind'
336
- this.mindMap.export('png', true, name, true, false, null, true)
337
- },
338
- lineStyle() {
339
- this.lineStyleStatus = true
340
- this.styleStatus = false
341
- },
342
- nodeStyle() {
343
- this.styleStatus = true
344
- this.lineStyleStatus = false
345
- },
346
- // 关联线
347
- associativeLine() {
348
- this.mindMap.associativeLine.createLineFromActiveNode()
349
- },
350
- // 前进
351
- forward() {
352
- this.mindMap.execCommand('FORWARD')
353
- },
354
- // 返回
355
- ret() {
356
- this.mindMap.execCommand('BACK')
357
- },
358
- // 添加节点
359
- addNode() {
360
- this.mindMap.execCommand('INSERT_CHILD_NODE')
361
- },
362
- // 删除节点
363
- delNode() {
364
- this.mindMap.execCommand('REMOVE_NODE')
365
- },
366
- // 兄弟节点
367
- brotherNode() {
368
- this.mindMap.execCommand('INSERT_NODE')
369
- },
370
- reset() {
371
- this.mindMap.renderer.setRootNodeCenter()
372
- }
373
- }
374
- }
375
- </script>
376
-
377
- <style scoped src="./mind.css"></style>
1
+ <template>
2
+ <!--
3
+ 思维导图组件 - zydx-mind
4
+ 基于 simple-mind-map 封装,支持节点编辑、关联线、样式配置、撤销/重做、结构切换、保存/导出。
5
+ -->
6
+ <div class="mind" :class="{'full-screen':!fullShow}" :ref="id">
7
+ <div class="mind-table">
8
+ <!-- 工具栏(readOnly 模式下隐藏) -->
9
+ <div class="table-left" v-if="!readOnly">
10
+ <!-- 节点操作 -->
11
+ <button :disabled="mindShow" @click="addNode">添加节点</button>
12
+ <button :disabled="mindShow" @click="brotherNode">兄弟节点</button>
13
+ <button :disabled="mindShow" @click="delNode">删除节点</button>
14
+ <!-- 关联线操作 -->
15
+ <button :disabled="mindShow" @click="associativeLine">关联线</button>
16
+ <button :disabled="lineShow" @click="lineStyle">关联样式</button>
17
+ <!-- 节点样式 -->
18
+ <button :disabled="mindShow" @click="nodeStyle">节点样式</button>
19
+
20
+ <!-- 结构切换 -->
21
+ <div class="mind-btn">
22
+ <span>结构切换</span>
23
+ <div class="mind-btn-list">
24
+ <button @click="structure('logicalStructure')"
25
+ :disabled="layoutList === 'logicalStructure' || layoutList === ''">向右结构</button>
26
+ <button @click="structure('organizationStructure')" :disabled="layoutList === 'organizationStructure'">向下结构</button>
27
+ <button @click="structure('mindMap')" :disabled="layoutList === 'mindMap'">左右结构</button>
28
+ </div>
29
+ </div>
30
+
31
+ <!-- 撤销/重做 -->
32
+ <button :disabled="retShow" @click="ret">上一步</button>
33
+ <button :disabled="forwardShow" @click="forward">下一步</button>
34
+
35
+ <!-- 重置视角 / 保存 / 全屏 -->
36
+ <button @click="reset" v-if="resetShow">重置位置</button>
37
+ <button v-if="protectShow" @click="preservation">保存</button>
38
+ <button @click="fullTap(false)" v-if="fullShow&&full">全屏</button>
39
+ <button @click="fullDel(true)" v-if="!fullShow">退出</button>
40
+ </div>
41
+ </div>
42
+
43
+ <!-- 思维导图画布 -->
44
+ <div :id="id" class="mindMapContainer"></div>
45
+
46
+ <!-- 节点样式弹窗 -->
47
+ <Tool v-model:open="styleStatus" :node="nodeData" @select="toolSelect"></Tool>
48
+ <!-- 关联线样式弹窗 -->
49
+ <LineTool v-model:open="lineStyleStatus" :node="lineData" @select="lineToolSelect"></LineTool>
50
+ </div>
51
+ </template>
52
+
53
+ <script>
54
+ import MindMap from "simple-mind-map";
55
+ import TouchEvent from 'simple-mind-map/src/plugins/TouchEvent.js'
56
+ import AssociativeLine from 'simple-mind-map/src/plugins/AssociativeLine.js'
57
+ import Export from 'simple-mind-map/src/plugins/Export.js'
58
+ import Tool from "./tool.vue";
59
+ import LineTool from "./lineTool.vue";
60
+
61
+ // 注册插件
62
+ MindMap.usePlugin(AssociativeLine)
63
+ MindMap.usePlugin(TouchEvent)
64
+ MindMap.usePlugin(Export)
65
+
66
+ /**
67
+ * zydx-mind 思维导图组件
68
+ *
69
+ * 功能:
70
+ * 1. 基于 simple-mind-map 渲染可交互的思维导图
71
+ * 2. 支持添加/删除/兄弟节点、关联线绘制
72
+ * 3. 支持节点样式(文字/边框/背景/形状)和关联线样式编辑
73
+ * 4. 支持撤销/重做、结构切换(向右/向下/左右)
74
+ * 5. 支持只读/编辑模式切换
75
+ * 6. 支持全屏显示、重置视角、保存/导出
76
+ *
77
+ * @emits confirm 数据变更,payload: { data, url }
78
+ * @emits dataChange 数据变更,payload: { data, url }
79
+ * @emits preservation 保存事件,payload: { data: { msg, layoutList }, url }
80
+ */
81
+ export default {
82
+ components: { LineTool, Tool },
83
+ name: "zydx-mind",
84
+
85
+ data() {
86
+ return {
87
+ // ===== 实例标识 =====
88
+ /** 动态生成的唯一 ref 标识 */
89
+ id: null,
90
+
91
+ // ===== MindMap 实例 =====
92
+ /** simple-mind-map 实例 */
93
+ mindMap: null,
94
+
95
+ // ===== 工具栏状态 =====
96
+ /** 节点操作按钮禁用状态(未选中节点时禁用) */
97
+ mindShow: true,
98
+ /** 撤销按钮禁用状态 */
99
+ retShow: false,
100
+ /** 重做按钮禁用状态 */
101
+ forwardShow: false,
102
+ /** 关联线按钮禁用状态(点击关联线时禁用,防止对象混淆) */
103
+ lineShow: true,
104
+ /** 全屏状态标识 */
105
+ fullShow: true,
106
+ /** 当前布局类型 */
107
+ layoutList: '',
108
+
109
+ // ===== 样式弹窗状态 =====
110
+ /** 节点样式弹窗可见性 */
111
+ styleStatus: false,
112
+ /** 关联线样式弹窗可见性 */
113
+ lineStyleStatus: false,
114
+
115
+ // ===== 当前选中对象 =====
116
+ /** 当前激活节点(用于样式编辑) */
117
+ nodeData: null,
118
+ /** 当前激活的节点列表 */
119
+ activeNodes: null,
120
+ /** 关联线起点节点 */
121
+ activeLineNode: null,
122
+ /** 关联线终点节点 */
123
+ activeLineToNode: null,
124
+ /** 当前关联线样式数据 */
125
+ lineData: null,
126
+
127
+ // ===== 数据更新标志 =====
128
+ /** 是否已完成首次数据更新(用于 updateStatus 模式) */
129
+ updateInit: false,
130
+
131
+ // ===== 默认数据 =====
132
+ /** 无数据时的默认根节点 */
133
+ defaultData: {
134
+ "data": { "text": "根节点" },
135
+ "children": []
136
+ }
137
+ }
138
+ },
139
+
140
+ props: {
141
+ /** 思维导图数据 */
142
+ data: {
143
+ type: Object,
144
+ default: {
145
+ "data": { "text": "根节点" },
146
+ "children": []
147
+ }
148
+ },
149
+ /** 是否只读模式 */
150
+ readOnly: {
151
+ type: Boolean,
152
+ default: false
153
+ },
154
+ /** 是否显示保存按钮 */
155
+ protectShow: {
156
+ type: Boolean,
157
+ default: true
158
+ },
159
+ /** 是否启用数据更新模式(仅允许一次外部数据更新) */
160
+ updateStatus: {
161
+ type: Boolean,
162
+ default: false
163
+ },
164
+ /** 是否显示重置位置按钮 */
165
+ resetShow: {
166
+ type: Boolean,
167
+ default: true
168
+ },
169
+ /** 是否显示全屏按钮 */
170
+ full: {
171
+ type: Boolean,
172
+ default: true
173
+ }
174
+ },
175
+
176
+ watch: {
177
+ /**
178
+ * 监听只读模式切换
179
+ */
180
+ readOnly: {
181
+ handler: function (val, oldVal) {
182
+ this.mindMap?.setMode(val ? 'readonly' : 'edit')
183
+ },
184
+ deep: true,
185
+ immediate: true
186
+ },
187
+
188
+ /**
189
+ * 监听数据变化,更新导图内容
190
+ * 当 updateStatus 为 true 时,仅允许一次外部更新
191
+ */
192
+ data: {
193
+ handler: function (val) {
194
+ if (this.updateInit) return
195
+ if (this.updateStatus) this.updateInit = true
196
+ if (Object.keys(val).length === 0) {
197
+ this.mindMap?.setData(this.defaultData)
198
+ } else {
199
+ this.mindMap?.setData(this.msgFun(val))
200
+ this.mindMap?.setLayout(val.layoutList || 'logicalStructure')
201
+ }
202
+ },
203
+ immediate: true
204
+ }
205
+ },
206
+
207
+ mounted() {
208
+ // 生成唯一 ID,避免多实例 ref 冲突
209
+ this.id = this.randomId()
210
+
211
+ this.$nextTick(() => {
212
+ this.init()
213
+
214
+ // 监听容器尺寸变化,自动调整导图
215
+ const resizeObserver = new ResizeObserver(this.debounce(this.resizeCallback, 300));
216
+ resizeObserver.observe(this.$refs[this.id]);
217
+ })
218
+
219
+ // 监听窗口尺寸变化
220
+ window.addEventListener('resize', this.handleWindowResize)
221
+ },
222
+
223
+ beforeUnmount() {
224
+ // 移除窗口事件监听
225
+ window.removeEventListener('resize', this.handleWindowResize)
226
+ // 销毁 MindMap 实例
227
+ this.mindMap?.destroy()
228
+ this.mindMap = null
229
+ },
230
+
231
+ methods: {
232
+ /**
233
+ * 获取当前思维导图数据(Promise 形式)
234
+ * 供外部组件通过 $refs 调用
235
+ *
236
+ * @returns {Promise<{data: Object, url: string}>}
237
+ */
238
+ getContent() {
239
+ return new Promise((resolve, reject) => {
240
+ resolve({
241
+ data: this.mindMap.getData(),
242
+ url: ''
243
+ })
244
+ })
245
+ },
246
+
247
+ /**
248
+ * 导出思维导图为图片
249
+ *
250
+ * @param {string} [v='mind'] - 导出文件名
251
+ */
252
+ getImage(v) {
253
+ const name = v ? v : 'mind'
254
+ this.mindMap.export('png', true, name, true, false, null, true)
255
+ },
256
+
257
+ /**
258
+ * 保存思维导图数据
259
+ * 关闭所有弹窗后发出 preservation 事件
260
+ *
261
+ * @emits preservation
262
+ */
263
+ preservation() {
264
+ this.styleStatus = false
265
+ this.lineStyleStatus = false
266
+ this.$emit('preservation', {
267
+ data: {
268
+ msg: this.mindMap.getData(),
269
+ layoutList: this.layoutList
270
+ },
271
+ url: ''
272
+ })
273
+ },
274
+
275
+ /**
276
+ * 切换导图结构布局
277
+ *
278
+ * @param {string} v - 布局类型:logicalStructure / organizationStructure / mindMap
279
+ */
280
+ structure(v) {
281
+ this.layoutList = v
282
+ this.mindMap.setLayout(this.layoutList)
283
+ },
284
+
285
+ /** 添加子节点 */
286
+ addNode() {
287
+ this.mindMap.execCommand('INSERT_CHILD_NODE')
288
+ },
289
+
290
+ /** 添加兄弟节点 */
291
+ brotherNode() {
292
+ this.mindMap.execCommand('INSERT_NODE')
293
+ },
294
+
295
+ /** 删除当前节点 */
296
+ delNode() {
297
+ this.mindMap.execCommand('REMOVE_NODE')
298
+ },
299
+
300
+ /** 从当前节点创建关联线 */
301
+ associativeLine() {
302
+ this.mindMap.associativeLine.createLineFromActiveNode()
303
+ },
304
+
305
+ /** 打开关联线样式弹窗 */
306
+ lineStyle() {
307
+ this.lineStyleStatus = true
308
+ this.styleStatus = false
309
+ },
310
+
311
+ /** 打开节点样式弹窗 */
312
+ nodeStyle() {
313
+ this.styleStatus = true
314
+ this.lineStyleStatus = false
315
+ },
316
+
317
+ /** 撤销 */
318
+ ret() {
319
+ this.mindMap.execCommand('BACK')
320
+ },
321
+
322
+ /** 重做 */
323
+ forward() {
324
+ this.mindMap.execCommand('FORWARD')
325
+ },
326
+
327
+ /** 重置视口位置,将根节点居中 */
328
+ reset() {
329
+ this.mindMap.renderer.setRootNodeCenter()
330
+ },
331
+ /**
332
+ * 进入全屏
333
+ *
334
+ * @param {boolean} v - 全屏状态
335
+ */
336
+ fullTap(v) {
337
+ this.fullShow = v
338
+ this.fullScreen(document.body)
339
+ },
340
+
341
+ /**
342
+ * 退出全屏并重置变换
343
+ *
344
+ * @param {boolean} v - 全屏状态
345
+ */
346
+ fullDel(v) {
347
+ this.fullShow = v
348
+ // 重置画布变换状态
349
+ this.mindMap.view.setTransformData({
350
+ state: { scale: 1, x: 0, y: 0, sx: 0, sy: 0 },
351
+ transform: {
352
+ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0,
353
+ originX: 0, originY: 0, rotate: 0,
354
+ scaleX: 1, scaleY: 1, shear: 0,
355
+ translateX: 0, translateY: 0
356
+ }
357
+ })
358
+ this.cancelFullscreen()
359
+ },
360
+
361
+ /**
362
+ * 跨浏览器全屏 API
363
+ *
364
+ * @param {HTMLElement} element - 要全屏的元素
365
+ */
366
+ fullScreen(element) {
367
+ if (element.requestFullScreen) {
368
+ element.requestFullScreen()
369
+ } else if (element.webkitRequestFullScreen) {
370
+ element.webkitRequestFullScreen()
371
+ } else if (element.mozRequestFullScreen) {
372
+ element.mozRequestFullScreen()
373
+ }
374
+ },
375
+
376
+ /**
377
+ * 跨浏览器退出全屏 API
378
+ */
379
+ cancelFullscreen() {
380
+ if (document.exitFullscreen) {
381
+ document.exitFullscreen();
382
+ } else if (document.msExitFullscreen) {
383
+ document.msExitFullscreen();
384
+ } else if (document.mozCancelFullScreen) {
385
+ document.mozCancelFullScreen();
386
+ } else if (document.webkitExitFullscreen) {
387
+ document.webkitExitFullscreen();
388
+ }
389
+ },
390
+
391
+ /**
392
+ * 节点样式选择回调
393
+ * 将样式应用到所有选中的节点
394
+ *
395
+ * @param {{type: string, value: string|number}} v - 样式类型和值
396
+ */
397
+ toolSelect(v) {
398
+ this.activeNodes.forEach(node => {
399
+ node.setStyle(v.type, v.value)
400
+ })
401
+ },
402
+
403
+ /**
404
+ * 关联线样式选择回调
405
+ * 更新当前选中关联线的样式数据
406
+ *
407
+ * @param {Object} v - 关联线样式配置
408
+ */
409
+ lineToolSelect(v) {
410
+ const associativeLineStyle = this.activeLineNode.getData('associativeLineStyle') || {}
411
+ const toNodeUid = this.activeLineToNode.getData('uid')
412
+ const lineStyle = associativeLineStyle[toNodeUid] || {}
413
+ this.activeLineNode.setData({
414
+ associativeLineStyle: {
415
+ ...associativeLineStyle,
416
+ [toNodeUid]: { ...lineStyle, ...v }
417
+ }
418
+ })
419
+ this.mindMap.associativeLine.updateActiveLineStyle()
420
+ },
421
+
422
+ /**
423
+ * 窗口尺寸变化处理
424
+ */
425
+ handleWindowResize() {
426
+ if (!document.fullscreenElement) {
427
+ this.fullShow = true
428
+ }
429
+ this.mindMap?.resize()
430
+ },
431
+
432
+ // =========================================================================
433
+ // 工具方法
434
+ // =========================================================================
435
+
436
+ /**
437
+ * 解析数据格式,兼容嵌套 msg 字段
438
+ * 如果数据为空则返回默认数据
439
+ *
440
+ * @param {Object} e - 外部传入的数据
441
+ * @returns {Object} 导图数据
442
+ */
443
+ msgFun(e) {
444
+ if (e.msg) {
445
+ return Object.keys(e.msg).length === 0 ? this.defaultData : e.msg
446
+ } else {
447
+ return Object.keys(e).length === 0 ? this.defaultData : e
448
+ }
449
+ },
450
+
451
+ /**
452
+ * 生成纯字母随机 ID
453
+ *
454
+ * @returns {string}
455
+ */
456
+ randomId() {
457
+ const id = Math.random().toString(36).substr(2)
458
+ return id.replace(/[0-9]/g, '')
459
+ },
460
+
461
+ /**
462
+ * 防抖函数
463
+ *
464
+ * @param {Function} fn - 目标函数
465
+ * @param {number} delay - 延迟毫秒数,默认 500
466
+ * @returns {Function} 防抖后的函数
467
+ */
468
+ debounce(fn, delay = 500) {
469
+ let timer = null;
470
+ return function (...args) {
471
+ clearTimeout(timer);
472
+ timer = setTimeout(() => {
473
+ fn.apply(this, args);
474
+ }, delay);
475
+ };
476
+ },
477
+
478
+ /**
479
+ * 容器尺寸变化回调
480
+ *
481
+ * @param {ResizeObserverEntry[]} entries
482
+ */
483
+ resizeCallback(entries) {
484
+ entries.forEach(entry => {
485
+ this.mindMap?.resize()
486
+ });
487
+ },
488
+
489
+ /**
490
+ * 初始化 simple-mind-map 实例并注册事件监听
491
+ */
492
+ init() {
493
+ this.mindMap = new MindMap({
494
+ el: document.getElementById(this.id),
495
+ openPerformance: true,
496
+ enableFreeDrag: false,
497
+ enableNodeTransitionMove: false,
498
+ layout: this.data.layoutList || 'logicalStructure',
499
+ maxHistoryCount: 100,
500
+ maxNodeCacheCount: 100,
501
+ data: this.msgFun(this.data)
502
+ });
503
+
504
+ // 根据只读属性设置模式
505
+ this.mindMap.setMode(this.readOnly ? 'readonly' : 'edit')
506
+
507
+ // ---- 事件监听 ----
508
+
509
+ // 节点点击/激活
510
+ this.mindMap.on('node_active', (node, activeNodeList) => {
511
+ this.nodeData = node
512
+ this.activeNodes = activeNodeList
513
+ this.mindShow = !node
514
+ if (node) {
515
+ this.lineData = null
516
+ this.lineShow = true
517
+ }
518
+ })
519
+
520
+ // 撤销/重做状态更新
521
+ this.mindMap.on('back_forward', (index, len) => {
522
+ this.retShow = index <= 0;
523
+ this.forwardShow = index >= len - 1
524
+ })
525
+
526
+ // 关联线点击
527
+ this.mindMap.on('associative_line_click', (path, clickPath, node, toNode) => {
528
+ this.activeLineNode = node
529
+ this.activeLineToNode = toNode
530
+ this.lineData = this.mindMap.associativeLine.getStyleConfig(node, toNode)
531
+ this.lineShow = false
532
+ })
533
+
534
+ // 点击画布空白区域(取消所有选中)
535
+ this.mindMap.on('draw_click', () => {
536
+ this.lineStyleStatus = false
537
+ this.styleStatus = false
538
+ this.lineShow = true
539
+ this.mindShow = true
540
+ this.nodeData = null
541
+ this.activeNodes = []
542
+ this.lineData = null
543
+ })
544
+
545
+ // 数据变更通知父组件
546
+ this.mindMap.on('data_change', (data) => {
547
+ this.$emit('dataChange', {
548
+ data: data,
549
+ url: ''
550
+ })
551
+ })
552
+ }
553
+ }
554
+ }
555
+ </script>
556
+
557
+ <style scoped src="./mind.css"></style>
@@ -245,9 +245,6 @@ input[name='check'] {
245
245
  font-weight: 700;
246
246
  flex: 1;
247
247
  }
248
- .padd{
249
- padding-bottom: 24px;
250
- }
251
248
  .buts-disabled{
252
249
  color: #797979 !important;
253
250
  cursor: not-allowed;
@@ -6,7 +6,7 @@
6
6
  <div class="paper-choice" :class="{'array-ch': !styleText(item.testKey)}" v-for="(item,index) in value">
7
7
  <div class="subject">
8
8
  <!-- 题目标题区域:有题号展示题号,否则展示序号 -->
9
- <div class="subject-title" :class="{'padd': item.top !== 0}" v-if="item.subject">
9
+ <div class="subject-title" v-if="item.subject">
10
10
  <!-- 多选模式下的勾选框 -->
11
11
  <input v-if="multipleShow" type="checkbox" :disabled="item.disabled" :checked="item.checked" @change="checkboxChange($event,index)"
12
12
  name="check"/>
package/src/index.js CHANGED
@@ -89,7 +89,7 @@ function install(app) {
89
89
  }
90
90
 
91
91
  export default {
92
- version: '1.36.646',
92
+ version: '1.36.648',
93
93
  install,
94
94
  Calendar,
95
95
  Message,