vue-wiring-diagram 1.0.6 → 1.0.7
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/dist/style.css +1 -1
- package/dist/vue-wiring-diagram.es.js +15173 -14983
- package/dist/vue-wiring-diagram.umd.js +42 -42
- package/package.json +1 -1
- package/packages/components/baseShape.js +1 -1
- package/packages/components/editor/index.vue +72 -40
- package/packages/components/image-control/image-form.vue +152 -7
- package/packages/components/image-control/image-management.vue +48 -3
- package/packages/components/settings.js +0 -10
- package/packages/http.js +10 -1
- package/packages/styles/editor.scss +11 -0
package/package.json
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
</template>
|
|
24
24
|
</el-dropdown>
|
|
25
25
|
</div>
|
|
26
|
-
<div class="action">
|
|
26
|
+
<div class="action" style="margin-right: 50px">
|
|
27
27
|
<el-tooltip content="预览" placement="bottom">
|
|
28
28
|
<el-button size="small" :icon="View" @click="viewJson">
|
|
29
29
|
</el-button>
|
|
@@ -89,6 +89,8 @@ import {portsOptions} from "../portsOptions.js";
|
|
|
89
89
|
import {Document, View, ArrowDown} from "@element-plus/icons-vue";
|
|
90
90
|
import WiringDiagramPreview from "../preview/index.vue";
|
|
91
91
|
import ImageManagement from "../image-control/image-management.vue";
|
|
92
|
+
import {get} from "packages/http.js";
|
|
93
|
+
import towerPoles from "packages/assets/image/tower-poles.svg";
|
|
92
94
|
|
|
93
95
|
defineOptions({
|
|
94
96
|
name: 'editor'
|
|
@@ -290,7 +292,18 @@ const stencil = ref()
|
|
|
290
292
|
const initStencil = () => {
|
|
291
293
|
stencil.value = new Stencil({
|
|
292
294
|
target: graph.value,
|
|
293
|
-
...stencilOptions
|
|
295
|
+
...stencilOptions,
|
|
296
|
+
groups: [
|
|
297
|
+
{
|
|
298
|
+
name: '基础组件',
|
|
299
|
+
graphPadding: 30
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
search(cell, keyword) {
|
|
303
|
+
return cell.label?.indexOf(keyword) !== -1
|
|
304
|
+
},
|
|
305
|
+
placeholder: '搜索',
|
|
306
|
+
notFoundText: '未找到匹配项',
|
|
294
307
|
})
|
|
295
308
|
const text = graph.value.createNode({
|
|
296
309
|
...textOptions
|
|
@@ -299,47 +312,66 @@ const initStencil = () => {
|
|
|
299
312
|
item.ports = portsOptions
|
|
300
313
|
return graph.value.createNode(item)
|
|
301
314
|
})
|
|
302
|
-
const image = imageOptions.map(item => {
|
|
303
|
-
item.ports = portsOptions
|
|
304
|
-
return graph.value.createNode(item)
|
|
305
|
-
})
|
|
306
315
|
stencil.value.load([text, ...baseShapes], '基础组件')
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
nodes.forEach(node => {
|
|
314
|
-
const div = document.createElement('div');
|
|
315
|
-
div.className = 'node-label';
|
|
316
|
-
// 添加 hover 事件监听器
|
|
317
|
-
node.addEventListener('mouseenter', (e) => {
|
|
318
|
-
div.style.position = 'absolute';
|
|
319
|
-
div.innerText = Math.random().toString(36).substring(2, 7);
|
|
320
|
-
div.style.fontSize = '12px';
|
|
321
|
-
div.style.backgroundColor = '#000';
|
|
322
|
-
div.style.color = '#fff';
|
|
323
|
-
div.style.padding = '2px 4px';
|
|
324
|
-
div.style.borderRadius = '4px';
|
|
325
|
-
div.style.zIndex = '9999';
|
|
326
|
-
div.style.textAlign = 'center';
|
|
327
|
-
div.style.width = div.innerText.length * 12 + 'px';
|
|
328
|
-
const divWidth = Number(div.style.width.substring(0, div.style.width.length - 2));
|
|
329
|
-
div.style.top = e.target.getBoundingClientRect().bottom + 4 + 'px';
|
|
330
|
-
div.style.left = e.target.getBoundingClientRect().left + e.target.getBoundingClientRect().width / 2 - divWidth / 2 + 'px';
|
|
331
|
-
document.body.appendChild(div);
|
|
316
|
+
get('/cny/custom/groupList').then(res => {
|
|
317
|
+
const data = res?.data || []
|
|
318
|
+
data?.forEach(group => {
|
|
319
|
+
stencil.value.addGroup({
|
|
320
|
+
name: group?.groupName,
|
|
321
|
+
graphPadding: 30
|
|
332
322
|
})
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
323
|
+
const image = group?.pictureList.map(item => {
|
|
324
|
+
const nodeOption = {
|
|
325
|
+
shape: 'image',
|
|
326
|
+
imageUrl: item?.imageUrl,
|
|
327
|
+
ports: portsOptions,
|
|
328
|
+
width: 64,
|
|
329
|
+
height: 64,
|
|
330
|
+
label: item.imageName
|
|
331
|
+
}
|
|
332
|
+
return graph.value.createNode(nodeOption)
|
|
339
333
|
})
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
334
|
+
stencil.value.load(image, group?.groupName)
|
|
335
|
+
document.getElementById('stencil').appendChild(stencil.value.container)
|
|
336
|
+
})
|
|
337
|
+
}).finally(() => {
|
|
338
|
+
// 添加 hover 事件监听器
|
|
339
|
+
setTimeout(() => {
|
|
340
|
+
const nodes = stencil.value.container.querySelectorAll('.x6-node');
|
|
341
|
+
nodes.forEach((node,index) => {
|
|
342
|
+
if(index > baseShape.length) {
|
|
343
|
+
const text = node.querySelector('text');
|
|
344
|
+
node.style.position = 'relative';
|
|
345
|
+
if(text) {
|
|
346
|
+
text.style.display = 'none';
|
|
347
|
+
// text 为 svg 控制位置
|
|
348
|
+
text.setAttribute('x', '0%');
|
|
349
|
+
text.setAttribute('y', '30%');
|
|
350
|
+
text.style.fontSize = '12px';
|
|
351
|
+
text.style.fontWeight = 'bold';
|
|
352
|
+
text.style.fill = '#ffffff';
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// 添加 hover 事件监听器
|
|
356
|
+
node.addEventListener('mouseenter', (e) => {
|
|
357
|
+
if(index > baseShape.length) {
|
|
358
|
+
const text = node.querySelector('text');
|
|
359
|
+
if(text) {
|
|
360
|
+
text.style.display = 'block';
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
})
|
|
364
|
+
node.addEventListener('mouseleave', (e) => {
|
|
365
|
+
if(index > baseShape.length) {
|
|
366
|
+
const text = node.querySelector('text');
|
|
367
|
+
if(text) {
|
|
368
|
+
text.style.display = 'none';
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
})
|
|
372
|
+
});
|
|
373
|
+
}, 20)
|
|
374
|
+
})
|
|
343
375
|
}
|
|
344
376
|
|
|
345
377
|
/**
|
|
@@ -4,14 +4,44 @@
|
|
|
4
4
|
*/
|
|
5
5
|
<template>
|
|
6
6
|
<div class="form-container">
|
|
7
|
-
<el-form ref="form" :model="model" :rules="rules" label-width="90px" label-suffix=":"
|
|
8
|
-
|
|
7
|
+
<el-form ref="form" :model="model" :rules="rules" label-width="90px" label-suffix=":">
|
|
8
|
+
<el-form-item label="图片名称" prop="imageName">
|
|
9
|
+
<el-input v-model="model.imageName" placeholder="请输入图片名称"></el-input>
|
|
10
|
+
</el-form-item>
|
|
11
|
+
<el-form-item label="排序" prop="sort">
|
|
12
|
+
<el-input-number v-model="model.sort" :min="0" :max="999" :step="1" controls-position="right"/>
|
|
13
|
+
</el-form-item>
|
|
14
|
+
<el-form-item label="是否显示" prop="isShow">
|
|
15
|
+
<el-switch v-model="model.isShow" :active-value="1" :inactive-value="0" active-color="#13ce66" inactive-color="#ff4949"/>
|
|
16
|
+
</el-form-item>
|
|
17
|
+
<el-form-item label="上传" prop="image">
|
|
18
|
+
<el-upload
|
|
19
|
+
action=""
|
|
20
|
+
list-type="picture"
|
|
21
|
+
class="avatar-uploader"
|
|
22
|
+
:show-file-list="false"
|
|
23
|
+
:on-change="changeImage"
|
|
24
|
+
:auto-upload="false"
|
|
25
|
+
>
|
|
26
|
+
<el-image v-if="imageUrl" :src="imageUrl" fit="cover" style="width: 64px; height: 64px;"/>
|
|
27
|
+
<el-icon v-else class="avatar-uploader-icon">
|
|
28
|
+
<Plus/>
|
|
29
|
+
</el-icon>
|
|
30
|
+
</el-upload>
|
|
31
|
+
</el-form-item>
|
|
32
|
+
<div class="footer">
|
|
33
|
+
<el-button type="primary" @click="saveBtnClick">保存</el-button>
|
|
34
|
+
<el-button @click="cancelBtnClick">取消</el-button>
|
|
35
|
+
</div>
|
|
36
|
+
</el-form>
|
|
9
37
|
</div>
|
|
10
38
|
</template>
|
|
11
39
|
|
|
12
40
|
<script setup>
|
|
13
|
-
import {reactive, ref} from 'vue'
|
|
14
|
-
import {ElMessage} from
|
|
41
|
+
import {onMounted, reactive, ref, shallowRef} from 'vue'
|
|
42
|
+
import {ElMessage} from "element-plus";
|
|
43
|
+
import {instance, post, upload} from "packages/http.js";
|
|
44
|
+
import {Plus} from "@element-plus/icons-vue";
|
|
15
45
|
|
|
16
46
|
const emits = defineEmits(['close'])
|
|
17
47
|
const props = defineProps({
|
|
@@ -22,11 +52,126 @@ const props = defineProps({
|
|
|
22
52
|
}
|
|
23
53
|
}
|
|
24
54
|
})
|
|
25
|
-
const form =
|
|
26
|
-
const model = reactive({
|
|
27
|
-
|
|
55
|
+
const form = shallowRef(null)
|
|
56
|
+
const model = reactive({
|
|
57
|
+
groupId: '',
|
|
58
|
+
id: '',
|
|
59
|
+
imageName: '',
|
|
60
|
+
sort: 0,
|
|
61
|
+
isShow: 1,
|
|
62
|
+
imageUrl: '',
|
|
63
|
+
})
|
|
64
|
+
const rules = ({
|
|
65
|
+
imageName: [
|
|
66
|
+
{required: true, message: '请输入图片名称', trigger: 'blur'},
|
|
67
|
+
{min: 1, max: 20, message: '长度在 1 到 20 个字符', trigger: 'blur'}
|
|
68
|
+
],
|
|
69
|
+
sort: [
|
|
70
|
+
{required: true, message: '请输入排序', trigger: 'blur'},
|
|
71
|
+
{type: 'number', message: '排序必须为数字值'}
|
|
72
|
+
]
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const imageUrl = ref('')
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 图片改变事件
|
|
79
|
+
* @param file
|
|
80
|
+
*/
|
|
81
|
+
const changeImage = (file) => {
|
|
82
|
+
if (file.raw.type !== 'image/svg+xml') {
|
|
83
|
+
ElMessage.error('上传图片只能是 svg 格式!');
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const formData = new FormData();
|
|
87
|
+
formData.append('file', file.raw);
|
|
88
|
+
upload('/cny/file/fileUpload', formData).then(res => {
|
|
89
|
+
if (res?.isOk) {
|
|
90
|
+
imageUrl.value = instance.defaults.baseURL + '/cny/upload/' + res?.data
|
|
91
|
+
model.imageUrl = res?.data
|
|
92
|
+
} else {
|
|
93
|
+
ElMessage.error(res?.msg || '上传失败')
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 保存按钮点击事件
|
|
101
|
+
*/
|
|
102
|
+
const saveBtnClick = () => {
|
|
103
|
+
console.log(model)
|
|
104
|
+
form.value.validate((valid) => {
|
|
105
|
+
if (valid) {
|
|
106
|
+
post('/cny/custom/savePicture', model).then(res => {
|
|
107
|
+
if (res?.isOk) {
|
|
108
|
+
ElMessage.success('保存成功')
|
|
109
|
+
emits('close', true)
|
|
110
|
+
} else {
|
|
111
|
+
ElMessage.error(res?.msg || '保存失败')
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
} else {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 取消按钮点击事件
|
|
122
|
+
*/
|
|
123
|
+
const cancelBtnClick = () => {
|
|
124
|
+
emits('close', false)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
onMounted(() => {
|
|
128
|
+
if (props.payload?.id) {
|
|
129
|
+
model.id = props.payload.id
|
|
130
|
+
model.imageName = props.payload.imageName
|
|
131
|
+
model.sort = props.payload.sort
|
|
132
|
+
model.isShow = props.payload.isShow
|
|
133
|
+
model.imageUrl = props.payload.imageUrl
|
|
134
|
+
imageUrl.value = model.imageUrl
|
|
135
|
+
}
|
|
136
|
+
model.groupId = props.payload.groupId
|
|
137
|
+
})
|
|
28
138
|
</script>
|
|
29
139
|
|
|
30
140
|
<style scoped lang="scss">
|
|
141
|
+
@use "../../styles/dialog.scss";
|
|
142
|
+
|
|
143
|
+
.avatar-uploader {
|
|
144
|
+
width: 64px;
|
|
145
|
+
height: 64px;
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
:deep(.el-upload) {
|
|
149
|
+
width: 100%;
|
|
150
|
+
height: 100%;
|
|
151
|
+
border: 1px dashed rgb(35, 100, 221);
|
|
152
|
+
border-radius: 6px;
|
|
153
|
+
cursor: pointer;
|
|
154
|
+
position: relative;
|
|
155
|
+
overflow: hidden;
|
|
156
|
+
transition: var(--el-transition-duration-fast);
|
|
157
|
+
|
|
158
|
+
:deep(.el-upload:hover) {
|
|
159
|
+
border-color: var(--el-color-primary);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.el-icon {
|
|
163
|
+
color: rgb(35, 100, 221);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
:deep(.el-icon).avatar-uploader-icon {
|
|
168
|
+
font-size: 28px;
|
|
169
|
+
color: rgb(35, 100, 221);
|
|
170
|
+
width: 178px;
|
|
171
|
+
height: 178px;
|
|
172
|
+
text-align: center;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
31
176
|
|
|
32
177
|
</style>
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
<div style="padding: 0 10px;display: flex;flex-direction: column;gap: 5px;align-items: flex-start">
|
|
12
12
|
<el-button type="primary" size="small" @click="addPicture(props.row.id)">新增图片</el-button>
|
|
13
13
|
<el-table :data="props.row.pictureList" border size="small">
|
|
14
|
+
<el-table-column label="名称" prop="imageName" align="center"></el-table-column>
|
|
14
15
|
<el-table-column label="图片" prop="imageUrl" align="center">
|
|
15
16
|
<template #default="scope">
|
|
16
17
|
<img :src="scope.row.imageUrl" alt="" style="width: 64px; height: 64px;">
|
|
@@ -22,6 +23,12 @@
|
|
|
22
23
|
{{ scope.row.isShow === 1 ? '是' : '否' }}
|
|
23
24
|
</template>
|
|
24
25
|
</el-table-column>
|
|
26
|
+
<el-table-column label="操作" align="center">
|
|
27
|
+
<template #default="scope">
|
|
28
|
+
<el-button type="primary" size="small" @click="editPicture(scope.row)">编辑</el-button>
|
|
29
|
+
<el-button type="danger" size="small" @click="deletePicture(scope.row.id)">删除</el-button>
|
|
30
|
+
</template>
|
|
31
|
+
</el-table-column>
|
|
25
32
|
</el-table>
|
|
26
33
|
</div>
|
|
27
34
|
</template>
|
|
@@ -42,11 +49,11 @@
|
|
|
42
49
|
</el-table>
|
|
43
50
|
<el-dialog v-model="groupDialog.show" :title="groupDialog.title" width="300" :close-on-click-modal="false" :close-on-press-escape="false"
|
|
44
51
|
>
|
|
45
|
-
<group-form :payload="groupDialog.payload" @close="closeDialog"/>
|
|
52
|
+
<group-form v-if="groupDialog.show" :payload="groupDialog.payload" @close="closeDialog"/>
|
|
46
53
|
</el-dialog>
|
|
47
54
|
<el-dialog v-model="imageDialog.show" :title="imageDialog.title" width="300" :close-on-click-modal="false" :close-on-press-escape="false"
|
|
48
55
|
>
|
|
49
|
-
<image-form :payload="imageDialog.payload" @close="closeDialog"/>
|
|
56
|
+
<image-form v-if="imageDialog.show" :payload="imageDialog.payload" @close="closeDialog"/>
|
|
50
57
|
</el-dialog>
|
|
51
58
|
</div>
|
|
52
59
|
</template>
|
|
@@ -55,7 +62,7 @@
|
|
|
55
62
|
import {onMounted, reactive} from "vue";
|
|
56
63
|
import groupForm from "./group-form.vue";
|
|
57
64
|
import imageForm from "./image-form.vue";
|
|
58
|
-
import {get, del} from "../../http.js";
|
|
65
|
+
import {get, del, instance} from "../../http.js";
|
|
59
66
|
import {ElMessage, ElMessageBox} from "element-plus";
|
|
60
67
|
|
|
61
68
|
// 数据集
|
|
@@ -143,6 +150,44 @@ const addPicture = (id) => {
|
|
|
143
150
|
}
|
|
144
151
|
}
|
|
145
152
|
|
|
153
|
+
/**
|
|
154
|
+
* 编辑图片
|
|
155
|
+
* @param row
|
|
156
|
+
*/
|
|
157
|
+
const editPicture = (row) => {
|
|
158
|
+
imageDialog.show = true
|
|
159
|
+
imageDialog.title = '编辑图片'
|
|
160
|
+
imageDialog.payload = {
|
|
161
|
+
id: row.id,
|
|
162
|
+
groupId: row.groupId,
|
|
163
|
+
imageName: row.imageName,
|
|
164
|
+
sort: row.sort,
|
|
165
|
+
isShow: row.isShow,
|
|
166
|
+
imageUrl: row.imageUrl
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* 删除图片
|
|
172
|
+
* @param id
|
|
173
|
+
*/
|
|
174
|
+
const deletePicture = (id) => {
|
|
175
|
+
ElMessageBox.confirm('是否确定要删除该图片?', '提示', {
|
|
176
|
+
confirmButtonText: '确定',
|
|
177
|
+
cancelButtonText: '取消',
|
|
178
|
+
type: 'warning'
|
|
179
|
+
}).then(() => {
|
|
180
|
+
del('/cny/custom/removePicture/' + id).then(res => {
|
|
181
|
+
if (res.code === 200) {
|
|
182
|
+
ElMessage.success('删除成功')
|
|
183
|
+
loadImageRecord()
|
|
184
|
+
} else {
|
|
185
|
+
ElMessage.error(res.msg || '删除失败')
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
|
|
146
191
|
/**
|
|
147
192
|
* 关闭弹窗
|
|
148
193
|
* @param action
|
package/packages/http.js
CHANGED
|
@@ -6,7 +6,7 @@ import {ElMessage} from "element-plus";
|
|
|
6
6
|
let baseURL = 'http://localhost:8001'
|
|
7
7
|
|
|
8
8
|
// 创建一个 axios 实例
|
|
9
|
-
const instance = axios.create({
|
|
9
|
+
export const instance = axios.create({
|
|
10
10
|
baseURL: baseURL, // 你的 API 基础 URL
|
|
11
11
|
timeout: 10000, // 请求超时时间
|
|
12
12
|
headers: {
|
|
@@ -93,3 +93,12 @@ export const put = (url, data = {}) => {
|
|
|
93
93
|
export const del = (url, params = {}) => {
|
|
94
94
|
return instance.delete(url, {params});
|
|
95
95
|
};
|
|
96
|
+
|
|
97
|
+
// 上传文件
|
|
98
|
+
export const upload = (url, data = {}) => {
|
|
99
|
+
return instance.post(url, data, {
|
|
100
|
+
headers: {
|
|
101
|
+
'Content-Type': 'multipart/form-data',
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
};
|
|
@@ -54,6 +54,17 @@
|
|
|
54
54
|
:deep(.x6-widget-stencil-title) {
|
|
55
55
|
display: none;
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
:deep(.x6-widget-stencil.searchable > .x6-widget-stencil-content) {
|
|
59
|
+
top: 50px
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
:deep(.x6-widget-stencil-search-text){
|
|
63
|
+
background: rgba(35, 100, 221, 0.3);
|
|
64
|
+
color: #ffffff;
|
|
65
|
+
border-radius: 5px;
|
|
66
|
+
border: 1px solid rgb(35, 100, 221);
|
|
67
|
+
}
|
|
57
68
|
}
|
|
58
69
|
|
|
59
70
|
#controls {
|