vue-wiring-diagram 1.1.25 → 1.1.26
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/README.md +93 -93
- package/dist/style.css +1 -1
- package/dist/vue-wiring-diagram.es.js +4502 -4489
- package/dist/vue-wiring-diagram.umd.js +35 -35
- package/package.json +1 -1
- package/packages/components/Shortcuts.vue +31 -31
- package/packages/components/baseShape.js +62 -62
- package/packages/components/common.js +105 -105
- package/packages/components/edge-control/arrow-line.vue +292 -292
- package/packages/components/edge-control/condition.vue +110 -110
- package/packages/components/edge-control/default-line.vue +156 -156
- package/packages/components/edge-control/index.vue +94 -94
- package/packages/components/edge-control/pipe-line.vue +354 -354
- package/packages/components/editor/index.vue +590 -590
- package/packages/components/enums.js +80 -80
- package/packages/components/graph-control/index.vue +121 -121
- package/packages/components/image-control/group-form.vue +114 -114
- package/packages/components/image-control/image-condition.vue +117 -117
- package/packages/components/image-control/image-form.vue +184 -184
- package/packages/components/image-control/image-management.vue +213 -213
- package/packages/components/image-control/index.vue +290 -290
- package/packages/components/portsOptions.js +21 -21
- package/packages/components/preview/index.vue +399 -400
- package/packages/components/settings.js +262 -262
- package/packages/components/text-control/index.vue +472 -457
- package/packages/components/tools.js +256 -256
- package/packages/http.js +104 -104
- package/packages/index.js +43 -43
- package/packages/styles/animation.scss +27 -27
- package/packages/styles/dialog.scss +4 -4
- package/packages/styles/editor.scss +165 -165
- package/packages/styles/elPath.scss +257 -257
|
@@ -1,400 +1,399 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @Author: HuaYJ
|
|
3
|
-
* @Date: 2024/12/10 10:01
|
|
4
|
-
*/
|
|
5
|
-
<template>
|
|
6
|
-
<div style="width: 100%; height: 100%;position: relative">
|
|
7
|
-
<div id="preview-container" ref="previewRef" @dblclick="zoomToFit"></div>
|
|
8
|
-
<div class="spinner" v-if="loading">
|
|
9
|
-
<div class="spinner1"></div>
|
|
10
|
-
</div>
|
|
11
|
-
</div>
|
|
12
|
-
</template>
|
|
13
|
-
|
|
14
|
-
<script setup>
|
|
15
|
-
import {onMounted, onUnmounted, ref, shallowRef} from "vue";
|
|
16
|
-
import {Graph} from "@antv/x6";
|
|
17
|
-
import {getData, getRealData, showPorts} from "../common.js";
|
|
18
|
-
import {ElMessage} from "element-plus";
|
|
19
|
-
import {defaultMatch, defaultText, setPipeDirection, setSunCloudImageUrl} from "packages/components/tools.js";
|
|
20
|
-
import {ARROWFORWARD, FLASHING} from "packages/components/enums.js";
|
|
21
|
-
import {arrowBackward, arrowForward, backgroundOptions, gridOptions} from "packages/components/settings.js";
|
|
22
|
-
import {isSunOs} from "packages";
|
|
23
|
-
|
|
24
|
-
defineOptions({
|
|
25
|
-
name: 'wiring-diagram-preview'
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
const props = defineProps({
|
|
29
|
-
id: {
|
|
30
|
-
type: String,
|
|
31
|
-
default: ''
|
|
32
|
-
},
|
|
33
|
-
background: {
|
|
34
|
-
type: Object,
|
|
35
|
-
default: () => {
|
|
36
|
-
return {}
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
grid: {
|
|
40
|
-
type: Object,
|
|
41
|
-
default: () => {
|
|
42
|
-
return {}
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
data: {
|
|
46
|
-
type: Object,
|
|
47
|
-
default: () => {
|
|
48
|
-
return {}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
// 画布
|
|
54
|
-
const graph = ref()
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* 初始化画布
|
|
58
|
-
*/
|
|
59
|
-
const initGraph = () => {
|
|
60
|
-
window.__x6_instances__ = []
|
|
61
|
-
const container = document.getElementById('preview-container')
|
|
62
|
-
graph.value = new Graph({
|
|
63
|
-
container: container,
|
|
64
|
-
autoResize: true, // 画布自适应
|
|
65
|
-
panning: true, // 画布可拖动
|
|
66
|
-
mousewheel: true, // 画布可缩放
|
|
67
|
-
connecting: {
|
|
68
|
-
router: 'orth',
|
|
69
|
-
connectionPoint: {
|
|
70
|
-
name: 'anchor',
|
|
71
|
-
},
|
|
72
|
-
anchor: 'center',
|
|
73
|
-
},
|
|
74
|
-
interacting: {
|
|
75
|
-
nodeMovable: false,
|
|
76
|
-
magnetConnectable: false,
|
|
77
|
-
edgeMovable: false,
|
|
78
|
-
edgeLabelMovable: false,
|
|
79
|
-
arrowheadMovable: false,
|
|
80
|
-
vertexMovable: false,
|
|
81
|
-
vertexAddable: false,
|
|
82
|
-
vertexDeletable: false,
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
window.__x6_instances__.push(container)
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* 画布空白区域双击事件
|
|
89
|
-
*/
|
|
90
|
-
graph.value.on('blank:dblclick', () => {
|
|
91
|
-
setFieldData()
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
graph.value.on('render:done', () => {
|
|
95
|
-
showPorts("#preview-container", false)
|
|
96
|
-
zoomToFit()
|
|
97
|
-
})
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* 渲染数据
|
|
102
|
-
*/
|
|
103
|
-
const renderData = async () => {
|
|
104
|
-
let background, grid, data;
|
|
105
|
-
if (props.id) {
|
|
106
|
-
const options = await getData(props.id)
|
|
107
|
-
background = options?.background || backgroundOptions;
|
|
108
|
-
grid = options?.grid || gridOptions;
|
|
109
|
-
data = options?.data || {cells: []};
|
|
110
|
-
} else {
|
|
111
|
-
background = props.background;
|
|
112
|
-
grid = {};
|
|
113
|
-
data = props.data;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
graph.value.drawBackground(background);
|
|
117
|
-
graph.value.drawGrid(grid);
|
|
118
|
-
graph.value.fromJSON(data);
|
|
119
|
-
refreshData()
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// 定时器
|
|
123
|
-
const timer = ref(null)
|
|
124
|
-
// 节点
|
|
125
|
-
const cells = ref([])
|
|
126
|
-
// 参数
|
|
127
|
-
const allFields = ref([])
|
|
128
|
-
// 标志位判断组件是否已销毁
|
|
129
|
-
const isDestroyed = ref(false)
|
|
130
|
-
// 加载中
|
|
131
|
-
const loading = ref(false)
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* 刷新数据
|
|
135
|
-
*/
|
|
136
|
-
const refreshData = () => {
|
|
137
|
-
cells.value = graph.value.getCells().filter(cell => cell?.data?.type === 'text' || cell?.data?.type === 'pipe' || cell?.data?.type === 'arrow' || cell?.data?.type == 'image' )
|
|
138
|
-
cells.value.forEach(item => {
|
|
139
|
-
if (item?.data?.fields?.length) {
|
|
140
|
-
allFields.value.push({id: item?.id, fields: item?.data.fields})
|
|
141
|
-
}
|
|
142
|
-
})
|
|
143
|
-
setFieldData()
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// 是否允许刷新数据
|
|
147
|
-
const isAllowRefresh = ref(true)
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* 设置字段数据
|
|
151
|
-
* @returns {Promise<void>}
|
|
152
|
-
*/
|
|
153
|
-
const setFieldData = async () => {
|
|
154
|
-
loading.value = true
|
|
155
|
-
if (!allFields.value.length) {
|
|
156
|
-
loading.value = false
|
|
157
|
-
return
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (!isAllowRefresh.value) {
|
|
161
|
-
ElMessage.warning('数据正在更新中,请稍后再试')
|
|
162
|
-
return
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (timer.value) {
|
|
166
|
-
clearInterval(timer.value)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
isAllowRefresh.value = false
|
|
170
|
-
console.log('字段数据', allFields.value)
|
|
171
|
-
await getDataBatch(allFields.value)
|
|
172
|
-
|
|
173
|
-
if (isDestroyed.value) {
|
|
174
|
-
return
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
timer.value = setTimeout(() => {
|
|
178
|
-
setFieldData()
|
|
179
|
-
}, 10000)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* 分批次获取数据 每批次获取最多 10 条数据
|
|
184
|
-
* @param fields 字段数组
|
|
185
|
-
* @param batch
|
|
186
|
-
*/
|
|
187
|
-
const getDataBatch = async (fields, batch = 0) => {
|
|
188
|
-
let size = 5 // 每批次获取数量
|
|
189
|
-
if (isDestroyed.value) {
|
|
190
|
-
return
|
|
191
|
-
}
|
|
192
|
-
if (fields.length > batch * size) {
|
|
193
|
-
const batchData = fields.slice(batch * size, batch * size + size)
|
|
194
|
-
console.log('批次:', batch, '数据:', batchData)
|
|
195
|
-
batch++
|
|
196
|
-
setRealData(await getRealData(batchData))
|
|
197
|
-
await getDataBatch(fields, batch)
|
|
198
|
-
} else {
|
|
199
|
-
loading.value = false
|
|
200
|
-
isAllowRefresh.value = true
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* 根据不同类型设置实时数据
|
|
206
|
-
*/
|
|
207
|
-
const setRealData = (realData) => {
|
|
208
|
-
realData?.forEach(item => {
|
|
209
|
-
const cell = graph.value.getCellById(item.id)
|
|
210
|
-
if (cell.data.type === 'text') {
|
|
211
|
-
cell.label = replaceAllTemplateLiteralsWithArray(cell.data.content, item.fields)
|
|
212
|
-
}
|
|
213
|
-
if (cell.data.type === 'pipe') {
|
|
214
|
-
console.log('管道详情', cell, item.fields?.[0].value)
|
|
215
|
-
setPipe(cell, item.fields?.[0].value)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (cell.data.type === 'arrow') {
|
|
219
|
-
setArrow(cell, item.fields?.[0].value)
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (cell.shape === 'image') {
|
|
223
|
-
console.log('图片详情', cell, item.fields)
|
|
224
|
-
setImage(cell, item.fields)
|
|
225
|
-
}
|
|
226
|
-
})
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* 替换模板字符串
|
|
231
|
-
* @param str 模板字符串
|
|
232
|
-
* @param fields 替换数组
|
|
233
|
-
* @returns {*}
|
|
234
|
-
*/
|
|
235
|
-
const replaceAllTemplateLiteralsWithArray = (str, fields) => {
|
|
236
|
-
let index = 0
|
|
237
|
-
return str.replace(defaultMatch, () => {
|
|
238
|
-
const field = fields.find(item => item.index === index)
|
|
239
|
-
index++
|
|
240
|
-
if (field) {
|
|
241
|
-
return field.value
|
|
242
|
-
} else {
|
|
243
|
-
return defaultText
|
|
244
|
-
}
|
|
245
|
-
})
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* 设置管道
|
|
250
|
-
* @param cell
|
|
251
|
-
* @param value
|
|
252
|
-
*/
|
|
253
|
-
const setPipe = (cell, value) => {
|
|
254
|
-
if (!cell.data.isCondition) {
|
|
255
|
-
return false
|
|
256
|
-
}
|
|
257
|
-
console.log('进入设置管道阶段start:', cell)
|
|
258
|
-
console.log('管道条件判断设置:', cell.data.condition)
|
|
259
|
-
for (let i = 0; i < cell.data.condition.length; i++) {
|
|
260
|
-
console.log('┌──────单个设置管道阶段start:───────┐')
|
|
261
|
-
console.log('条件:', cell.data.condition[i])
|
|
262
|
-
console.log('判断条件是否通过:', Number(value) > cell.data.condition[i].min && Number(value) < cell.data.condition[i].max)
|
|
263
|
-
if (Number(value) > cell.data.condition[i].min && Number(value) < cell.data.condition[i].max) {
|
|
264
|
-
console.log('管道条件判断设置的动画:', setPipeDirection(cell.data.condition[i].direction))
|
|
265
|
-
cell.attr('pipe/style/animation', setPipeDirection(cell.data.condition[i].direction))
|
|
266
|
-
console.log('设置过后的属性:', cell)
|
|
267
|
-
console.log('└────────单个条件结束判断────────┘')
|
|
268
|
-
return false
|
|
269
|
-
}
|
|
270
|
-
console.log('└─────────单个条件结束判断───────┘')
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* 设置箭头
|
|
275
|
-
* @param cell
|
|
276
|
-
* @param value
|
|
277
|
-
*/
|
|
278
|
-
const setArrow = (cell, value) => {
|
|
279
|
-
console.log(cell, value)
|
|
280
|
-
if (!cell.data.isCondition) {
|
|
281
|
-
return false
|
|
282
|
-
}
|
|
283
|
-
for (let i = 0; i < cell.data.condition.length; i++) {
|
|
284
|
-
if (Number(value) > cell.data.condition[i].min && Number(value) < cell.data.condition[i].max) {
|
|
285
|
-
cell.attr('arrow/style/animation', cell.data.condition[i].animation === FLASHING ? 'flashing 2s infinite linear' : '')
|
|
286
|
-
cell.attr('arrow/d', cell.data.condition[i].direction === ARROWFORWARD ? arrowForward : arrowBackward)
|
|
287
|
-
cell.attr('arrow/display', cell.data.condition[i].display)
|
|
288
|
-
return false
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* 设置图片 - 支持条件控制更换元件
|
|
295
|
-
* @param cell 图片单元格
|
|
296
|
-
* @param fields 设备字段数据
|
|
297
|
-
*/
|
|
298
|
-
const setImage = (cell, fields) => {
|
|
299
|
-
if (!cell.data.isCondition) {
|
|
300
|
-
return false
|
|
301
|
-
}
|
|
302
|
-
console.log('进入设置图片阶段:', cell)
|
|
303
|
-
console.log('图片条件判断设置:', cell.data.condition)
|
|
304
|
-
console.log('设备字段数据:', fields)
|
|
305
|
-
|
|
306
|
-
// 如果没有字段数据,直接返回
|
|
307
|
-
if (!fields || fields.length === 0) {
|
|
308
|
-
return false
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// 获取设备值(图片目前只支持单设备)
|
|
312
|
-
const field = fields[0]
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
</style>
|
|
1
|
+
/**
|
|
2
|
+
* @Author: HuaYJ
|
|
3
|
+
* @Date: 2024/12/10 10:01
|
|
4
|
+
*/
|
|
5
|
+
<template>
|
|
6
|
+
<div style="width: 100%; height: 100%;position: relative">
|
|
7
|
+
<div id="preview-container" ref="previewRef" @dblclick="zoomToFit"></div>
|
|
8
|
+
<div class="spinner" v-if="loading">
|
|
9
|
+
<div class="spinner1"></div>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
import {onMounted, onUnmounted, ref, shallowRef} from "vue";
|
|
16
|
+
import {Graph} from "@antv/x6";
|
|
17
|
+
import {getData, getRealData, showPorts} from "../common.js";
|
|
18
|
+
import {ElMessage} from "element-plus";
|
|
19
|
+
import {defaultMatch, defaultText, setPipeDirection, setSunCloudImageUrl} from "packages/components/tools.js";
|
|
20
|
+
import {ARROWFORWARD, FLASHING} from "packages/components/enums.js";
|
|
21
|
+
import {arrowBackward, arrowForward, backgroundOptions, gridOptions} from "packages/components/settings.js";
|
|
22
|
+
import {isSunOs} from "packages";
|
|
23
|
+
|
|
24
|
+
defineOptions({
|
|
25
|
+
name: 'wiring-diagram-preview'
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const props = defineProps({
|
|
29
|
+
id: {
|
|
30
|
+
type: String,
|
|
31
|
+
default: ''
|
|
32
|
+
},
|
|
33
|
+
background: {
|
|
34
|
+
type: Object,
|
|
35
|
+
default: () => {
|
|
36
|
+
return {}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
grid: {
|
|
40
|
+
type: Object,
|
|
41
|
+
default: () => {
|
|
42
|
+
return {}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
data: {
|
|
46
|
+
type: Object,
|
|
47
|
+
default: () => {
|
|
48
|
+
return {}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// 画布
|
|
54
|
+
const graph = ref()
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 初始化画布
|
|
58
|
+
*/
|
|
59
|
+
const initGraph = () => {
|
|
60
|
+
window.__x6_instances__ = []
|
|
61
|
+
const container = document.getElementById('preview-container')
|
|
62
|
+
graph.value = new Graph({
|
|
63
|
+
container: container,
|
|
64
|
+
autoResize: true, // 画布自适应
|
|
65
|
+
panning: true, // 画布可拖动
|
|
66
|
+
mousewheel: true, // 画布可缩放
|
|
67
|
+
connecting: {
|
|
68
|
+
router: 'orth',
|
|
69
|
+
connectionPoint: {
|
|
70
|
+
name: 'anchor',
|
|
71
|
+
},
|
|
72
|
+
anchor: 'center',
|
|
73
|
+
},
|
|
74
|
+
interacting: {
|
|
75
|
+
nodeMovable: false,
|
|
76
|
+
magnetConnectable: false,
|
|
77
|
+
edgeMovable: false,
|
|
78
|
+
edgeLabelMovable: false,
|
|
79
|
+
arrowheadMovable: false,
|
|
80
|
+
vertexMovable: false,
|
|
81
|
+
vertexAddable: false,
|
|
82
|
+
vertexDeletable: false,
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
window.__x6_instances__.push(container)
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 画布空白区域双击事件
|
|
89
|
+
*/
|
|
90
|
+
graph.value.on('blank:dblclick', () => {
|
|
91
|
+
setFieldData()
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
graph.value.on('render:done', () => {
|
|
95
|
+
showPorts("#preview-container", false)
|
|
96
|
+
zoomToFit()
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 渲染数据
|
|
102
|
+
*/
|
|
103
|
+
const renderData = async () => {
|
|
104
|
+
let background, grid, data;
|
|
105
|
+
if (props.id) {
|
|
106
|
+
const options = await getData(props.id)
|
|
107
|
+
background = options?.background || backgroundOptions;
|
|
108
|
+
grid = options?.grid || gridOptions;
|
|
109
|
+
data = options?.data || {cells: []};
|
|
110
|
+
} else {
|
|
111
|
+
background = props.background;
|
|
112
|
+
grid = {};
|
|
113
|
+
data = props.data;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
graph.value.drawBackground(background);
|
|
117
|
+
graph.value.drawGrid(grid);
|
|
118
|
+
graph.value.fromJSON(data);
|
|
119
|
+
refreshData()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 定时器
|
|
123
|
+
const timer = ref(null)
|
|
124
|
+
// 节点
|
|
125
|
+
const cells = ref([])
|
|
126
|
+
// 参数
|
|
127
|
+
const allFields = ref([])
|
|
128
|
+
// 标志位判断组件是否已销毁
|
|
129
|
+
const isDestroyed = ref(false)
|
|
130
|
+
// 加载中
|
|
131
|
+
const loading = ref(false)
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 刷新数据
|
|
135
|
+
*/
|
|
136
|
+
const refreshData = () => {
|
|
137
|
+
cells.value = graph.value.getCells().filter(cell => cell?.data?.type === 'text' || cell?.data?.type === 'pipe' || cell?.data?.type === 'arrow' || cell?.data?.type == 'image' )
|
|
138
|
+
cells.value.forEach(item => {
|
|
139
|
+
if (item?.data?.fields?.length) {
|
|
140
|
+
allFields.value.push({id: item?.id, fields: item?.data.fields})
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
setFieldData()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 是否允许刷新数据
|
|
147
|
+
const isAllowRefresh = ref(true)
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 设置字段数据
|
|
151
|
+
* @returns {Promise<void>}
|
|
152
|
+
*/
|
|
153
|
+
const setFieldData = async () => {
|
|
154
|
+
loading.value = true
|
|
155
|
+
if (!allFields.value.length) {
|
|
156
|
+
loading.value = false
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!isAllowRefresh.value) {
|
|
161
|
+
ElMessage.warning('数据正在更新中,请稍后再试')
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (timer.value) {
|
|
166
|
+
clearInterval(timer.value)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
isAllowRefresh.value = false
|
|
170
|
+
console.log('字段数据', allFields.value)
|
|
171
|
+
await getDataBatch(allFields.value)
|
|
172
|
+
|
|
173
|
+
if (isDestroyed.value) {
|
|
174
|
+
return
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
timer.value = setTimeout(() => {
|
|
178
|
+
setFieldData()
|
|
179
|
+
}, 10000)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 分批次获取数据 每批次获取最多 10 条数据
|
|
184
|
+
* @param fields 字段数组
|
|
185
|
+
* @param batch
|
|
186
|
+
*/
|
|
187
|
+
const getDataBatch = async (fields, batch = 0) => {
|
|
188
|
+
let size = 5 // 每批次获取数量
|
|
189
|
+
if (isDestroyed.value) {
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
if (fields.length > batch * size) {
|
|
193
|
+
const batchData = fields.slice(batch * size, batch * size + size)
|
|
194
|
+
console.log('批次:', batch, '数据:', batchData)
|
|
195
|
+
batch++
|
|
196
|
+
setRealData(await getRealData(batchData))
|
|
197
|
+
await getDataBatch(fields, batch)
|
|
198
|
+
} else {
|
|
199
|
+
loading.value = false
|
|
200
|
+
isAllowRefresh.value = true
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 根据不同类型设置实时数据
|
|
206
|
+
*/
|
|
207
|
+
const setRealData = (realData) => {
|
|
208
|
+
realData?.forEach(item => {
|
|
209
|
+
const cell = graph.value.getCellById(item.id)
|
|
210
|
+
if (cell.data.type === 'text') {
|
|
211
|
+
cell.label = replaceAllTemplateLiteralsWithArray(cell.data.content, item.fields)
|
|
212
|
+
}
|
|
213
|
+
if (cell.data.type === 'pipe') {
|
|
214
|
+
console.log('管道详情', cell, item.fields?.[0].value)
|
|
215
|
+
setPipe(cell, item.fields?.[0].value)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (cell.data.type === 'arrow') {
|
|
219
|
+
setArrow(cell, item.fields?.[0].value)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (cell.shape === 'image') {
|
|
223
|
+
console.log('图片详情', cell, item.fields)
|
|
224
|
+
setImage(cell, item.fields)
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 替换模板字符串
|
|
231
|
+
* @param str 模板字符串
|
|
232
|
+
* @param fields 替换数组
|
|
233
|
+
* @returns {*}
|
|
234
|
+
*/
|
|
235
|
+
const replaceAllTemplateLiteralsWithArray = (str, fields) => {
|
|
236
|
+
let index = 0
|
|
237
|
+
return str.replace(defaultMatch, () => {
|
|
238
|
+
const field = fields.find(item => item.index === index)
|
|
239
|
+
index++
|
|
240
|
+
if (field) {
|
|
241
|
+
return field.value
|
|
242
|
+
} else {
|
|
243
|
+
return defaultText
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* 设置管道
|
|
250
|
+
* @param cell
|
|
251
|
+
* @param value
|
|
252
|
+
*/
|
|
253
|
+
const setPipe = (cell, value) => {
|
|
254
|
+
if (!cell.data.isCondition) {
|
|
255
|
+
return false
|
|
256
|
+
}
|
|
257
|
+
console.log('进入设置管道阶段start:', cell)
|
|
258
|
+
console.log('管道条件判断设置:', cell.data.condition)
|
|
259
|
+
for (let i = 0; i < cell.data.condition.length; i++) {
|
|
260
|
+
console.log('┌──────单个设置管道阶段start:───────┐')
|
|
261
|
+
console.log('条件:', cell.data.condition[i])
|
|
262
|
+
console.log('判断条件是否通过:', Number(value) > cell.data.condition[i].min && Number(value) < cell.data.condition[i].max)
|
|
263
|
+
if (Number(value) > cell.data.condition[i].min && Number(value) < cell.data.condition[i].max) {
|
|
264
|
+
console.log('管道条件判断设置的动画:', setPipeDirection(cell.data.condition[i].direction))
|
|
265
|
+
cell.attr('pipe/style/animation', setPipeDirection(cell.data.condition[i].direction))
|
|
266
|
+
console.log('设置过后的属性:', cell)
|
|
267
|
+
console.log('└────────单个条件结束判断────────┘')
|
|
268
|
+
return false
|
|
269
|
+
}
|
|
270
|
+
console.log('└─────────单个条件结束判断───────┘')
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 设置箭头
|
|
275
|
+
* @param cell
|
|
276
|
+
* @param value
|
|
277
|
+
*/
|
|
278
|
+
const setArrow = (cell, value) => {
|
|
279
|
+
console.log(cell, value)
|
|
280
|
+
if (!cell.data.isCondition) {
|
|
281
|
+
return false
|
|
282
|
+
}
|
|
283
|
+
for (let i = 0; i < cell.data.condition.length; i++) {
|
|
284
|
+
if (Number(value) > cell.data.condition[i].min && Number(value) < cell.data.condition[i].max) {
|
|
285
|
+
cell.attr('arrow/style/animation', cell.data.condition[i].animation === FLASHING ? 'flashing 2s infinite linear' : '')
|
|
286
|
+
cell.attr('arrow/d', cell.data.condition[i].direction === ARROWFORWARD ? arrowForward : arrowBackward)
|
|
287
|
+
cell.attr('arrow/display', cell.data.condition[i].display)
|
|
288
|
+
return false
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* 设置图片 - 支持条件控制更换元件
|
|
295
|
+
* @param cell 图片单元格
|
|
296
|
+
* @param fields 设备字段数据
|
|
297
|
+
*/
|
|
298
|
+
const setImage = (cell, fields) => {
|
|
299
|
+
if (!cell.data.isCondition) {
|
|
300
|
+
return false
|
|
301
|
+
}
|
|
302
|
+
console.log('进入设置图片阶段:', cell)
|
|
303
|
+
console.log('图片条件判断设置:', cell.data.condition)
|
|
304
|
+
console.log('设备字段数据:', fields)
|
|
305
|
+
|
|
306
|
+
// 如果没有字段数据,直接返回
|
|
307
|
+
if (!fields || fields.length === 0) {
|
|
308
|
+
return false
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// 获取设备值(图片目前只支持单设备)
|
|
312
|
+
const field = fields[0]
|
|
313
|
+
const value = Number(field.value)
|
|
314
|
+
|
|
315
|
+
// 根据条件判断更换图片
|
|
316
|
+
for (let i = 0; i < cell.data.condition.length; i++) {
|
|
317
|
+
const condition = cell.data.condition[i]
|
|
318
|
+
console.log(cell.data,'cell.data55555555');
|
|
319
|
+
if (value > condition.min && value < condition.max) {
|
|
320
|
+
if (condition.imageUrl) {
|
|
321
|
+
console.log('更换图片为:', setSunCloudImageUrl(condition?.imageUrl))
|
|
322
|
+
cell.attr('image/xlink:href', isSunOs ? condition?.imageUrl : setSunCloudImageUrl(condition?.imageUrl))
|
|
323
|
+
}
|
|
324
|
+
return false
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
console.log('未匹配到条件,保持原图片')
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* \@description 画布自适应
|
|
333
|
+
*/
|
|
334
|
+
const zoomToFit = () => {
|
|
335
|
+
graph.value.zoomToFit({maxScale: 1.4, padding: 20})
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const previewRef = shallowRef()
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* 监听浏览器窗口变化
|
|
342
|
+
*/
|
|
343
|
+
const watchBrowser = () => {
|
|
344
|
+
const observer = new ResizeObserver(() => {
|
|
345
|
+
zoomToFit()
|
|
346
|
+
})
|
|
347
|
+
observer.observe(previewRef.value)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
onMounted(() => {
|
|
351
|
+
isDestroyed.value = false
|
|
352
|
+
initGraph()
|
|
353
|
+
renderData()
|
|
354
|
+
watchBrowser()
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
onUnmounted(() => {
|
|
359
|
+
isDestroyed.value = true
|
|
360
|
+
clearInterval(timer.value)
|
|
361
|
+
})
|
|
362
|
+
</script>
|
|
363
|
+
|
|
364
|
+
<style lang="scss">
|
|
365
|
+
@use "../../styles/animation.scss";
|
|
366
|
+
|
|
367
|
+
#preview-container {
|
|
368
|
+
position: relative;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.spinner {
|
|
372
|
+
position: absolute;
|
|
373
|
+
top: 10px;
|
|
374
|
+
left: 10px;
|
|
375
|
+
background-image: linear-gradient(rgb(186, 66, 255) 35%, rgb(0, 225, 255));
|
|
376
|
+
width: 20px;
|
|
377
|
+
height: 20px;
|
|
378
|
+
animation: spinning82341 1.7s linear infinite;
|
|
379
|
+
text-align: center;
|
|
380
|
+
border-radius: 50px;
|
|
381
|
+
filter: blur(1px);
|
|
382
|
+
box-shadow: 0px -5px 50px 0px rgb(186, 66, 255), 0px 5px 50px 0px rgb(0, 225, 255);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.spinner1 {
|
|
386
|
+
background-color: rgb(36, 36, 36);
|
|
387
|
+
width: 20px;
|
|
388
|
+
height: 20px;
|
|
389
|
+
border-radius: 50px;
|
|
390
|
+
filter: blur(4px);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
@keyframes spinning82341 {
|
|
394
|
+
to {
|
|
395
|
+
transform: rotate(360deg);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
</style>
|