├── public
├── favicon.ico
├── img
│ ├── logo.png
│ ├── fengji.png
│ ├── rotate.cur
│ ├── fj_base.png
│ └── fj_normal.png
└── index.html
├── babel.config.js
├── src
├── assets
│ ├── images
│ │ ├── dot.png
│ │ ├── logo.png
│ │ ├── rotate.cur
│ │ ├── water
│ │ │ ├── 冷却器.png
│ │ │ ├── 冷却塔.png
│ │ │ ├── 接头弯.png
│ │ │ ├── 料斗.png
│ │ │ ├── 水仓.png
│ │ │ ├── 水槽.png
│ │ │ ├── 水阀.png
│ │ │ ├── 消化池.png
│ │ │ ├── 管道直.png
│ │ │ ├── T形接头.png
│ │ │ ├── 工业传感器.png
│ │ │ └── 工业水泵.png
│ │ ├── baseImg
│ │ │ ├── floor.png
│ │ │ └── yohuo.png
│ │ └── electricity
│ │ │ ├── 断路器分闸.png
│ │ │ └── 断路器合闸.png
│ └── css
│ │ └── base.scss
├── store
│ ├── index.js
│ └── canvas.js
├── main.js
├── services
│ ├── electricity.js
│ ├── water.js
│ ├── plantIcon.js
│ └── canvas.js
├── router
│ └── index.js
├── App.vue
├── components
│ ├── CanvasContextMenu.vue
│ └── CanvasProps.vue
└── views
│ ├── config
│ ├── index.vue
│ └── workspace.vue
│ └── client
│ └── index.vue
├── .gitignore
├── README.md
└── package.json
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/public/img/logo.png
--------------------------------------------------------------------------------
/public/img/fengji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/public/img/fengji.png
--------------------------------------------------------------------------------
/public/img/rotate.cur:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/public/img/rotate.cur
--------------------------------------------------------------------------------
/public/img/fj_base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/public/img/fj_base.png
--------------------------------------------------------------------------------
/public/img/fj_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/public/img/fj_normal.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/src/assets/images/dot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/dot.png
--------------------------------------------------------------------------------
/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/logo.png
--------------------------------------------------------------------------------
/src/assets/images/rotate.cur:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/rotate.cur
--------------------------------------------------------------------------------
/src/assets/images/water/冷却器.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/冷却器.png
--------------------------------------------------------------------------------
/src/assets/images/water/冷却塔.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/冷却塔.png
--------------------------------------------------------------------------------
/src/assets/images/water/接头弯.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/接头弯.png
--------------------------------------------------------------------------------
/src/assets/images/water/料斗.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/料斗.png
--------------------------------------------------------------------------------
/src/assets/images/water/水仓.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/水仓.png
--------------------------------------------------------------------------------
/src/assets/images/water/水槽.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/水槽.png
--------------------------------------------------------------------------------
/src/assets/images/water/水阀.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/水阀.png
--------------------------------------------------------------------------------
/src/assets/images/water/消化池.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/消化池.png
--------------------------------------------------------------------------------
/src/assets/images/water/管道直.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/管道直.png
--------------------------------------------------------------------------------
/src/assets/images/water/T形接头.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/T形接头.png
--------------------------------------------------------------------------------
/src/assets/images/water/工业传感器.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/工业传感器.png
--------------------------------------------------------------------------------
/src/assets/images/water/工业水泵.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/water/工业水泵.png
--------------------------------------------------------------------------------
/src/assets/images/baseImg/floor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/baseImg/floor.png
--------------------------------------------------------------------------------
/src/assets/images/baseImg/yohuo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/baseImg/yohuo.png
--------------------------------------------------------------------------------
/src/assets/images/electricity/断路器分闸.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/electricity/断路器分闸.png
--------------------------------------------------------------------------------
/src/assets/images/electricity/断路器合闸.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XXM-cf/topology-gcf/HEAD/src/assets/images/electricity/断路器合闸.png
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | Vue.use(Vuex)
4 |
5 | import canvas from './canvas'
6 |
7 | const store = new Vuex.Store({
8 | modules: {
9 | canvas
10 | }
11 | })
12 |
13 | export default store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import store from './store'
5 | Vue.config.productionTip = false
6 | import ElementUI from 'element-ui'
7 | import 'element-ui/lib/theme-chalk/index.css';
8 | Vue.use(ElementUI, {
9 | size: 'small'
10 | })
11 | /* eslint-disable */
12 | new Vue({
13 | router,
14 | store,
15 | render: h => h(App),
16 | }).$mount('#app')
17 |
--------------------------------------------------------------------------------
/src/store/canvas.js:
--------------------------------------------------------------------------------
1 |
2 | const canvars = {
3 | namespaced: true,
4 | state: {
5 | data: {
6 | scale: 1,
7 | lineName: 'polyline',
8 | fromArrowType: '',
9 | toArrowType: '',
10 | locked: 0,
11 | lineStyle: 'default'
12 | },
13 | event: {
14 | name: '',
15 | data: null
16 | }
17 | },
18 | mutations: {
19 | setData (state, data) {
20 | state.data = data
21 | },
22 | setEvent (state, event) {
23 | state.event = event
24 | }
25 | }
26 | }
27 | export default canvars
--------------------------------------------------------------------------------
/src/services/electricity.js:
--------------------------------------------------------------------------------
1 | import p1 from '../assets/images/electricity/断路器分闸.png'
2 | import p2 from '../assets/images/electricity/断路器合闸.png'
3 | const arr = [
4 | { name: '断路器分闸', url: p1 },
5 | { name: '断路器合闸', url: p2 },
6 | ]
7 |
8 | const pipeImg = {
9 | group: '变配电',
10 | children: arr.map(item => {
11 | return {
12 | name: item.name,
13 | data: {
14 | rect: {
15 | width: 200,
16 | height: 80
17 | },
18 | name: 'image',
19 | image: item.url
20 | }
21 | }
22 | })
23 | }
24 | export default pipeImg
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | Vue.use(Router)
5 |
6 | export const constantRoutes = [
7 | {
8 | path: '/config',
9 | component: () => import('@/views/config/index')
10 | },
11 | {
12 | path: '/',
13 | component: () => import('@/views/config/index')
14 | },
15 | {
16 | path: '/client',
17 | component: () => import('@/views/client/index')
18 | }
19 | ]
20 | export default new Router({
21 | mode: 'history', // 去掉url中的#
22 | scrollBehavior: () => ({ y: 0 }),
23 | routes: [
24 | ...constantRoutes
25 | ]
26 | })
27 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | <%= htmlWebpackPlugin.options.title %>
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # topology-gcf
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Lints and fixes files
19 | ```
20 | npm run lint
21 | ```
22 |
23 | ### Customize configuration
24 | See [Configuration Reference](https://cli.vuejs.org/config/).
25 |
26 | ### 设计思想
27 | 工具化、与业务解耦
28 |
29 | ### 待完成
30 | - [ ] 图片上传
31 | - [ ] 多节点对齐(源码bug)
32 | - [ ] 音频、视频嵌入播放
33 | - [ ] 动画联动
34 | - [ ] 电梯效果
35 | - [ ] 水槽液位变化
36 |
37 |
38 |
39 | ### 完成功能点
40 |
41 | 画布配置
42 | - [x] 底图配置
43 | - [x] 禁用滚轮缩放
44 | - [x] 还原画布大小
45 | - [x] 缩放适配画布
46 |
47 | 节点
48 | - [x] 位置坐标、大小(宽高)
49 | - [x] 边框属性(样式、颜色、宽度)
50 | - [x] 背景色
51 | - [x] 透明度
52 |
53 | 线条
54 | - [x] 连接样式(直线、曲线、线段)
55 | - [x] 起始点箭头样式
56 | - [x] 起始点位置
57 | - [x] 连线颜色、宽度
58 | - [x] 边框颜色、宽度
59 | - [x] 整体透明度
60 |
61 | 图片
62 | - [x] 图片修改(本地)
63 |
64 | 文字
65 | - [x] 颜色
66 | - [x] 字号
67 | - [x] 样式(加粗、倾斜)
68 | - [x] 对齐(水平、垂直)
69 |
70 | 动画效果
71 | - [x] 旋转(顺时针、逆时针)
72 | - [x] 告警
73 | - [x] 自定义
74 | - [x] 水流(流速、颜色可修改)
75 | - [x] 圆点移动
76 |
77 | 媒体
78 | - [x] iframe 嵌入
79 |
80 | 定制需求
81 | - [x] 水管绘制
82 |
83 |
84 |
--------------------------------------------------------------------------------
/src/services/water.js:
--------------------------------------------------------------------------------
1 | import p1 from '../assets/images/water/工业传感器.png'
2 | import p2 from '../assets/images/water/工业水泵.png'
3 | import p3 from '../assets/images/water/管道直.png'
4 | import p4 from '../assets/images/water/接头弯.png'
5 | import p5 from '../assets/images/water/T形接头.png'
6 | import p6 from '../assets/images/water/水阀.png'
7 | import p7 from '../assets/images/water/冷却器.png'
8 | import p8 from '../assets/images/water/冷却塔.png'
9 | import p9 from '../assets/images/water/水仓.png'
10 | import p10 from '../assets/images/water/水槽.png'
11 | import p11 from '../assets/images/water/消化池.png'
12 | const arr = [
13 | { name: '工业传感器', url: p1 },
14 | { name: '工业水泵', url: p2 },
15 | { name: '管道直', url: p3 },
16 | { name: '接头弯', url: p4 },
17 | { name: 'T形接头', url: p5 },
18 | { name: '水阀', url: p6 },
19 | { name: '冷却器', url: p7 },
20 | { name: '冷却塔', url: p8 },
21 | { name: '水仓', url: p9 },
22 | { name: '水槽', url: p10 },
23 | { name: '消化池', url: p11 }
24 | ]
25 |
26 | const pipeImg = {
27 | group: '管道',
28 | children: arr.map(item => {
29 | return {
30 | name: item.name,
31 | data: {
32 | rect: {
33 | width: 100,
34 | height: 100
35 | },
36 | name: 'image',
37 | image: item.url
38 | }
39 | }
40 | })
41 | }
42 | export default pipeImg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "topology-gcf",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "core-js": "^3.6.4",
12 | "element-ui": "^2.13.0",
13 | "file-saver": "^2.0.2",
14 | "node-sass": "^4.13.1",
15 | "pug": "^2.0.4",
16 | "pug-plain-loader": "^1.0.0",
17 | "sass-loader": "^8.0.2",
18 | "scss": "^0.2.4",
19 | "scss-loader": "0.0.1",
20 | "topology-core": "^0.2.8-dev",
21 | "topology-flow-diagram": "0.0.3",
22 | "topology-layout": "0.0.3",
23 | "vue": "^2.6.11",
24 | "vue-router": "^3.1.6",
25 | "vuex": "^3.1.3"
26 | },
27 | "devDependencies": {
28 | "@vue/cli-plugin-babel": "~4.2.0",
29 | "@vue/cli-plugin-eslint": "~4.2.0",
30 | "@vue/cli-service": "~4.2.0",
31 | "babel-eslint": "^10.0.3",
32 | "eslint": "^6.7.2",
33 | "eslint-plugin-vue": "^6.1.2",
34 | "vue-template-compiler": "^2.6.11"
35 | },
36 | "eslintConfig": {
37 | "root": true,
38 | "env": {
39 | "node": true
40 | },
41 | "extends": [
42 | "plugin:vue/essential",
43 | "eslint:recommended"
44 | ],
45 | "parserOptions": {
46 | "parser": "babel-eslint"
47 | },
48 | "rules": {
49 | "no-unused-vars": "off"
50 | }
51 | },
52 | "browserslist": [
53 | "> 1%",
54 | "last 2 versions"
55 | ]
56 | }
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 | router-view
3 |
4 |
5 |
12 |
13 |
--------------------------------------------------------------------------------
/src/assets/css/base.scss:
--------------------------------------------------------------------------------
1 | @font-face { // 平面图图标
2 | font-family: 'iconfont'; /* project id 1776547 */
3 | src: url('//at.alicdn.com/t/font_1776547_3es98zmuy21.eot');
4 | src: url('//at.alicdn.com/t/font_1776547_3es98zmuy21.eot?#iefix') format('embedded-opentype'),
5 | url('//at.alicdn.com/t/font_1776547_3es98zmuy21.woff2') format('woff2'),
6 | url('//at.alicdn.com/t/font_1776547_3es98zmuy21.woff') format('woff'),
7 | url('//at.alicdn.com/t/font_1776547_3es98zmuy21.ttf') format('truetype'),
8 | url('//at.alicdn.com/t/font_1776547_3es98zmuy21.svg#iconfont') format('svg');
9 | }
10 |
11 | a {
12 | text-decoration: none;
13 | color: #314659;
14 | &:hover {
15 | color: #1890ff;
16 | }
17 | }
18 |
19 | .text-center {
20 | text-align: center;
21 | }
22 |
23 | .ml5 {
24 | margin-left: 0.05rem;
25 | }
26 |
27 | .ml30 {
28 | margin-left: 0.3rem;
29 | }
30 |
31 | .ml50 {
32 | margin-left: 0.5rem;
33 | }
34 |
35 | .mt5 {
36 | margin-top: 0.05rem;
37 | }
38 |
39 | .mt10 {
40 | margin-top: 0.1rem;
41 | }
42 |
43 | .mr5 {
44 | margin-right: 0.05rem;
45 | }
46 |
47 | .ph15 {
48 | padding-left: 0.15rem;
49 | padding-right: 0.15rem;
50 | }
51 |
52 | .pv10 {
53 | padding-top: 0.1rem;
54 | padding-bottom: 0.1rem;
55 | }
56 |
57 | .gray {
58 | color: #ccc;
59 | }
60 |
61 | .title {
62 | color: #0d1a26;
63 | font-weight: 600;
64 | }
65 |
66 | .flex {
67 | display: flex;
68 |
69 | &.column {
70 | flex-direction: column;
71 | }
72 |
73 | &.reverse {
74 | flex-direction: row-reverse;
75 | &.column {
76 | flex-direction: column-reverse;
77 | }
78 | }
79 |
80 | &.inline {
81 | display: inline-flex;
82 | }
83 |
84 | &.wrap {
85 | flex-wrap: wrap;
86 | }
87 |
88 | &.nowrap {
89 | flex-wrap: nowrap;
90 | }
91 |
92 | &.center {
93 | justify-content: center;
94 | }
95 |
96 | &.middle {
97 | align-items: center;
98 | }
99 |
100 | & > .full {
101 | flex-grow: 1;
102 | min-width: auto !important;
103 | width: auto !important;
104 | }
105 |
106 | &.grid > div {
107 | flex: 1;
108 | }
109 |
110 | label {
111 | flex-shrink: 0;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/services/plantIcon.js:
--------------------------------------------------------------------------------
1 | const arr = [
2 | {
3 | name: '空调机组',
4 | class: 'icon-kongtiaojizu',
5 | unicode: "\uecda"
6 | },
7 |
8 | {
9 | name: '手动报警',
10 | class: 'icon-shoudongbaojinganniu',
11 | unicode: "\uecdb"
12 | },
13 |
14 | {
15 | name: '枪机',
16 | class: 'icon-qiangji',
17 | unicode: "\uecdc"
18 | },
19 |
20 | {
21 | name: '双鉴探测',
22 | class: 'icon-shuangjiantance',
23 | unicode: "\uece7"
24 | },
25 |
26 | {
27 | name: '新风机组',
28 | class: 'icon-xinfengjizu',
29 | unicode: "\uecdf"
30 | },
31 |
32 | {
33 | name: '电表',
34 | class: 'icon-bianpeidian-dianbiao',
35 | unicode: "\uece1"
36 | },
37 |
38 | {
39 | name: '火警',
40 | class: 'icon-huojing',
41 | unicode: "\uece2"
42 | },
43 |
44 | {
45 | name: '温度计',
46 | class: 'icon-wenqi',
47 | unicode: "\uece3"
48 | },
49 |
50 | {
51 | name: '给水系统',
52 | class: 'icon-geishuixitong',
53 | unicode: "\uece4"
54 | },
55 |
56 | {
57 | name: '环境传感器',
58 | class: 'icon-huanjingchuanganqi',
59 | unicode: "\uece5"
60 | },
61 |
62 | {
63 | name: '集水井2',
64 | class: 'icon-jishuijing2',
65 | unicode: "\uece6"
66 | },
67 |
68 | {
69 | name: '电梯',
70 | class: 'icon-dianti',
71 | unicode: "\uece8"
72 | },
73 |
74 | {
75 | name: '集水井1',
76 | class: 'icon-jishuijing',
77 | unicode: "\uece9"
78 | },
79 |
80 | {
81 | name: '智能照明',
82 | class: 'icon-zhinengzhaoming',
83 | unicode: "\uecea"
84 | },
85 |
86 | {
87 | name: '门禁',
88 | class: 'icon-menjin',
89 | unicode: "\ueceb"
90 | },
91 |
92 | {
93 | name: '摄像头',
94 | class: 'icon-shexiangji',
95 | unicode: "\uecec"
96 | },
97 |
98 | {
99 | name: '烟感',
100 | class: 'icon-yangan',
101 | unicode: "\ueced"
102 | },
103 |
104 | {
105 | name: 'VAV',
106 | class: 'icon-VAVduolianjizu',
107 | unicode: "\uecee"
108 | },
109 |
110 | {
111 | name: '风机盘管',
112 | class: 'icon-FCUfengjipanguan',
113 | unicode: "\uecef"
114 | },
115 |
116 | {
117 | name: '排风机',
118 | class: 'icon-paifengji',
119 | unicode: "\uecf0"
120 | },
121 |
122 | {
123 | name: '水表',
124 | class: 'icon-shuibiao',
125 | unicode: "\uecf1"
126 | },
127 |
128 | {
129 | name: 'UPS',
130 | class: 'icon-UPSbujianduandianyuan',
131 | unicode: "\uecf2"
132 | },
133 |
134 | {
135 | name: 'VRF',
136 | class: 'icon-VRFduolianjizu',
137 | unicode: "\uecf3"
138 | },
139 |
140 | {
141 | name: '送风机',
142 | class: 'icon-songfengji',
143 | unicode: "\uecf4"
144 | },
145 |
146 | {
147 | name: '全热交换机',
148 | class: 'icon-quanrejiaohuanji',
149 | unicode: "\uecf5"
150 | },
151 |
152 | {
153 | name: '吊顶式空调',
154 | class: 'icon-diaodingshikongtiaojizu',
155 | unicode: "\uecf6"
156 | },
157 |
158 | {
159 | name: '功能广播',
160 | class: 'icon-gonggongguangbo',
161 | unicode: "\uecf7"
162 | },
163 |
164 | ]
165 |
166 | const pipeImg = {
167 | group: '设备图标',
168 | children: arr.map(item => {
169 | return {
170 | name: item.name,
171 | data: {
172 | rect: {
173 | width: 32,
174 | height: 32
175 | },
176 | borderColor: 'rgba(0,0,0,0)', // 去除边框
177 | strokeStyle: 'rgba(0,0,0,0)',
178 | icon: item.unicode,
179 | iconFamily: 'iconfont',
180 | iconColor: '#00dc94',
181 | iconClass: item.class,
182 | iconSize: 40,
183 | name: 'rectangle',
184 | borderRadius: 16
185 | }
186 | }
187 | })
188 | }
189 | export default pipeImg
--------------------------------------------------------------------------------
/src/components/CanvasContextMenu.vue:
--------------------------------------------------------------------------------
1 |
2 | .menus
3 | div
4 | a(:class='{disabled:!props.node && !props.nodes}', @click='onTop()') 置顶
5 | div
6 | a(:class='{disabled:!props.node && !props.nodes}', @click='onBottom()') 置底
7 | .line
8 | div(v-if='props.nodes')
9 | a(@click='onCombine()') 组合
10 | div
11 | a(@click='onCombine(true)') 包含
12 | div(v-if="props.node && props.node.name === 'combine'")
13 | a(@click='onUncombine()') 取消组合/包含
14 | div
15 | a(:class='{disabled:!props.node && !props.nodes}', @click='onLock()') {{ props.locked ? '解锁' : '锁定' }}
16 | .line
17 | div
18 | a(:class='{disabled:!props.node && !props.nodes && !props.line}', @click='onDel()') 删除
19 | .line
20 | div
21 | a.flex(@click='canvas.undo()')
22 | span.full 撤消
23 | span.ml50 Ctrl + Z
24 | div
25 | a(@click='canvas.redo()')
26 | | 恢复
27 | span.ml50 Ctrl + Shift+ Z
28 | .line
29 | div
30 | a.flex(@click='canvas.cut()')
31 | span.full 剪切
32 | span.ml50 Ctrl + X
33 | div
34 | a.flex(@click='canvas.copy()')
35 | span.full 复制
36 | span.ml50 Ctrl + C
37 | div
38 | a.flex(@click='canvas.parse()')
39 | span.full 粘贴
40 | span.ml50 Ctrl + V
41 | .line
42 | div
43 | a.flex(:class='{disabled:!props.node || !props.node.image}', @click='onCopyImage()')
44 | span.full 复制节点图片地址
45 |
46 |
47 |
132 |
133 |
174 |
--------------------------------------------------------------------------------
/src/views/config/index.vue:
--------------------------------------------------------------------------------
1 |
2 | .confing-layout
3 | .headers
4 | el-menu(mode='horizontal', @select='onMenu', background-color='#f8f8f8')
5 | el-submenu(index='file')
6 | template(slot='title') 文件
7 | el-menu-item(index='new') 新建文件
8 | el-menu-item(index='replace') 导入本地文件
9 | el-menu-item.separator
10 | el-menu-item(index='save') 保存到本地
11 | el-menu-item(index='savePng') 下载为PNG
12 | el-submenu(index='edit')
13 | template(slot='title') 编辑
14 | el-menu-item(index='undo') 撤消
15 | el-menu-item(index='redo') 重做
16 | el-menu-item.separator
17 | el-menu-item(index='copy') 复制
18 | el-menu-item(index='cut') 剪切
19 | el-menu-item(index='parse') 粘贴
20 |
21 | el-menu.full(mode='horizontal', background-color='#f8f8f8')
22 | el-menu-item(@click="handleView") 查看效果
23 |
24 | el-menu(mode='horizontal', background-color='#f8f8f8')
25 | el-menu-item 视图:{{scale}}%
26 | el-menu-item(index='scale', v-show="scale !== 100" @click="onState('scale',1)") 还原
27 | el-menu-item(index='locked', @click="onState('locked', locked ? 0 : 1)") {{ locked ? '解锁' : '锁定'}}
28 |
29 | el-submenu(index='lineName', title='默认连线类型')
30 | template(slot='title')
31 | i(:class='`iconfont icon-${lineName}`')
32 | el-menu-item(v-for='(item, index) in lineNames', :key='index', :index='`line-${item}`', @click="onState('lineName', item)")
33 | i(:class='`iconfont icon-${item}`')
34 |
35 | el-menu(mode='horizontal', background-color='#f8f8f8')
36 | el-submenu(index='fromArrowType', title='默认起点箭头')
37 | template(slot='title')
38 | i(:class='`iconfont icon-from-${fromArrowType}`')
39 | el-menu-item(v-for='(item, index) in arrowTypes', :key='index', :index='`fromArrowType-${item}`', @click="onState('fromArrowType', item)")
40 | i(:class='`iconfont icon-from-${item}`')
41 |
42 | el-menu(mode='horizontal', background-color='#f8f8f8')
43 | el-submenu(index='toArrowType', title='默认终点箭头')
44 | template(slot='title')
45 | i(:class='`iconfont icon-to-${toArrowType}`')
46 | el-menu-item(v-for='(item, index) in arrowTypes', :key='index', :index='`toArrowType-${item}`', @click="onState('toArrowType', item)")
47 | i(:class='`iconfont icon-to-${item}`')
48 |
49 | el-menu(mode='horizontal', background-color='#f8f8f8')
50 | el-submenu(index='lineStyle', title='连线样式')
51 | template(slot='title')
52 | span {{ lineStyle.label }}
53 | el-menu-item(v-for='(item, index) in lineStyleOptions', :key='item.value', @click="onState('lineStyle', item.value)")
54 | span {{ item.label }}
55 | workspace
56 |
57 |
58 |
150 |
151 |
156 |
--------------------------------------------------------------------------------
/src/services/canvas.js:
--------------------------------------------------------------------------------
1 | import { registerNode } from 'topology-core/middles'
2 | import {
3 | flowData,
4 | flowDataAnchors,
5 | flowDataIconRect,
6 | flowDataTextRect,
7 | flowSubprocess,
8 | flowSubprocessIconRect,
9 | flowSubprocessTextRect,
10 | flowDb,
11 | flowDbIconRect,
12 | flowDbTextRect,
13 | flowDocument,
14 | flowDocumentAnchors,
15 | flowDocumentIconRect,
16 | flowDocumentTextRect,
17 | flowInternalStorage,
18 | flowInternalStorageIconRect,
19 | flowInternalStorageTextRect,
20 | flowExternStorage,
21 | flowExternStorageAnchors,
22 | flowExternStorageIconRect,
23 | flowExternStorageTextRect,
24 | flowQueue,
25 | flowQueueIconRect,
26 | flowQueueTextRect,
27 | flowManually,
28 | flowManuallyAnchors,
29 | flowManuallyIconRect,
30 | flowManuallyTextRect,
31 | flowDisplay,
32 | flowDisplayAnchors,
33 | flowDisplayIconRect,
34 | flowDisplayTextRect,
35 | flowParallel,
36 | flowParallelAnchors,
37 | flowComment,
38 | flowCommentAnchors
39 | } from 'topology-flow-diagram'
40 |
41 | export function canvasRegister () {
42 | registerNode(
43 | 'flowData',
44 | flowData,
45 | flowDataAnchors,
46 | flowDataIconRect,
47 | flowDataTextRect
48 | )
49 | registerNode(
50 | 'flowSubprocess',
51 | flowSubprocess,
52 | null,
53 | flowSubprocessIconRect,
54 | flowSubprocessTextRect
55 | )
56 | registerNode('flowDb', flowDb, null, flowDbIconRect, flowDbTextRect)
57 | registerNode(
58 | 'flowDocument',
59 | flowDocument,
60 | flowDocumentAnchors,
61 | flowDocumentIconRect,
62 | flowDocumentTextRect
63 | )
64 | registerNode(
65 | 'flowInternalStorage',
66 | flowInternalStorage,
67 | null,
68 | flowInternalStorageIconRect,
69 | flowInternalStorageTextRect
70 | )
71 | registerNode(
72 | 'flowExternStorage',
73 | flowExternStorage,
74 | flowExternStorageAnchors,
75 | flowExternStorageIconRect,
76 | flowExternStorageTextRect
77 | )
78 | registerNode(
79 | 'flowQueue',
80 | flowQueue,
81 | null,
82 | flowQueueIconRect,
83 | flowQueueTextRect
84 | )
85 | registerNode(
86 | 'flowManually',
87 | flowManually,
88 | flowManuallyAnchors,
89 | flowManuallyIconRect,
90 | flowManuallyTextRect
91 | )
92 | registerNode(
93 | 'flowDisplay',
94 | flowDisplay,
95 | flowDisplayAnchors,
96 | flowDisplayIconRect,
97 | flowDisplayTextRect
98 | )
99 | registerNode('flowParallel', flowParallel, flowParallelAnchors, null, null)
100 | registerNode('flowComment', flowComment, flowCommentAnchors, null, null)
101 | }
102 | import water from './water'
103 | import plantIcon from './plantIcon'
104 | import electricity from './electricity'
105 | export const Tools = [
106 | plantIcon,
107 | water,
108 | electricity,
109 | {
110 | group: '基本形状',
111 | children: [
112 | {
113 | name: '矩形',
114 | icon: 'icon-rect',
115 | data: {
116 | rect: {
117 | width: 100,
118 | height: 100
119 | },
120 | paddingLeft: 10,
121 | paddingRight: 10,
122 | paddingTop: 10,
123 | paddingBottom: 10,
124 | name: 'rectangle',
125 | }
126 | },
127 | {
128 | name: '圆角矩形',
129 | icon: 'icon-rectangle',
130 | data: {
131 | text: '圆角矩形',
132 | rect: {
133 | width: 200,
134 | height: 50
135 | },
136 | paddingLeft: 10,
137 | paddingRight: 10,
138 | paddingTop: 10,
139 | paddingBottom: 10,
140 | borderRadius: 0.1,
141 | name: 'rectangle'
142 | }
143 | },
144 | {
145 | name: '圆',
146 | icon: 'icon-circle',
147 | data: {
148 | text: '圆',
149 | rect: {
150 | width: 100,
151 | height: 100
152 | },
153 | name: 'circle',
154 | textMaxLine: 1
155 | }
156 | },
157 | {
158 | name: '三角形',
159 | icon: 'icon-triangle',
160 | data: {
161 | text: '三角形',
162 | rect: {
163 | width: 100,
164 | height: 100
165 | },
166 | name: 'triangle'
167 | }
168 | },
169 | {
170 | name: '菱形',
171 | icon: 'icon-diamond',
172 | data: {
173 | text: '菱形',
174 | rect: {
175 | width: 100,
176 | height: 100
177 | },
178 | name: 'diamond'
179 | }
180 | },
181 | {
182 | name: '五边形',
183 | icon: 'icon-pentagon',
184 | data: {
185 | text: '五边形',
186 | rect: {
187 | width: 100,
188 | height: 100
189 | },
190 | name: 'pentagon'
191 | }
192 | },
193 | {
194 | name: '六边形',
195 | icon: 'icon-hexagon',
196 | data: {
197 | text: '六边形',
198 | rect: {
199 | width: 100,
200 | height: 100
201 | },
202 | paddingTop: 10,
203 | paddingBottom: 10,
204 | name: 'hexagon'
205 | }
206 | },
207 | {
208 | name: '五角星',
209 | icon: 'icon-pentagram',
210 | data: {
211 | text: '五角星',
212 | rect: {
213 | width: 100,
214 | height: 100
215 | },
216 | name: 'pentagram'
217 | }
218 | },
219 | {
220 | name: '左箭头',
221 | icon: 'icon-arrow-left',
222 | data: {
223 | text: '左箭头',
224 | rect: {
225 | width: 200,
226 | height: 100
227 | },
228 | name: 'leftArrow'
229 | }
230 | },
231 | {
232 | name: '右箭头',
233 | icon: 'icon-arrow-right',
234 | data: {
235 | text: '右箭头',
236 | rect: {
237 | width: 200,
238 | height: 100
239 | },
240 | name: 'rightArrow'
241 | }
242 | },
243 | {
244 | name: '双向箭头',
245 | icon: 'icon-twoway-arrow',
246 | data: {
247 | text: '双向箭头',
248 | rect: {
249 | width: 200,
250 | height: 100
251 | },
252 | name: 'twowayArrow'
253 | }
254 | },
255 | {
256 | name: '直线',
257 | icon: 'icon-line',
258 | data: {
259 | text: '直线',
260 | rect: {
261 | width: 100,
262 | height: 100,
263 | },
264 | name: 'line'
265 | }
266 | },
267 | {
268 | name: '云',
269 | icon: 'icon-cloud',
270 | data: {
271 | text: '云',
272 | rect: {
273 | width: 100,
274 | height: 100
275 | },
276 | name: 'cloud'
277 | }
278 | },
279 | {
280 | name: '消息框',
281 | icon: 'icon-msg',
282 | data: {
283 | text: '消息框',
284 | rect: {
285 | width: 100,
286 | height: 100
287 | },
288 | paddingLeft: 10,
289 | paddingRight: 10,
290 | paddingTop: 10,
291 | paddingBottom: 10,
292 | name: 'message'
293 | }
294 | },
295 | {
296 | name: '文档',
297 | icon: 'icon-file',
298 | data: {
299 | rect: {
300 | width: 80,
301 | height: 100
302 | },
303 | paddingLeft: 10,
304 | paddingRight: 10,
305 | paddingTop: 10,
306 | paddingBottom: 10,
307 | name: 'file'
308 | }
309 | },
310 | {
311 | name: '文字',
312 | icon: 'icon-text',
313 | data: {
314 | text: '示例文字',
315 | rect: {
316 | width: 160,
317 | height: 30
318 | },
319 | name: 'text'
320 | }
321 | },
322 |
323 | {
324 | name: 'cube',
325 | icon: 'icon-cube',
326 | data: {
327 | rect: {
328 | width: 50,
329 | height: 70
330 | },
331 | is3D: true,
332 | z: 10,
333 | zRotate: 10,
334 | fillStyle: '#dcdcdc',
335 | name: 'cube',
336 | icon: '\ue63c',
337 | iconFamily: 'topology',
338 | iconColor: '#777',
339 | iconSize: 30
340 | }
341 | },
342 | {
343 | name: '视频/网页',
344 | icon: 'icon-pc',
345 | data: {
346 | text: '视频/网页',
347 | rect: {
348 | width: 200,
349 | height: 200
350 | },
351 | paddingLeft: 10,
352 | paddingRight: 10,
353 | paddingTop: 10,
354 | paddingBottom: 10,
355 | name: 'div'
356 | }
357 | },
358 | {
359 | name: '图片',
360 | icon: 'icon-image',
361 | data: {
362 | rect: {
363 | width: 100,
364 | height: 100
365 | },
366 | name: 'image',
367 | image: '/img/logo.png'
368 | }
369 | }
370 | ]
371 | }
372 | ]
373 |
--------------------------------------------------------------------------------
/src/views/client/index.vue:
--------------------------------------------------------------------------------
1 |
2 | .client
3 | .headers
4 | el-menu(mode='horizontal', background-color='#f8f8f8' @select='onMenu')
5 | el-menu-item(index='back') 返回
6 | el-menu-item(index='open') 打开本地文件
7 |
8 | .canvas-container
9 | .tools
10 | h3 操作指令
11 | el-input(v-model="deviceId")
12 | el-button(@click="startAllAnimate()") 触发所有动画
13 | el-button(@click="endAllAnimate()") 结束所有动画
14 | el-button(@click="handle_startAnimate()") 触发节点动画
15 | el-button(@click="handle_endAnimate()") 停止节点动画
16 | el-button(@click="resizeCanvas()") 缩放适配
17 | p 平面图设备状态
18 | el-button(@click="handle_changeIcon('alarm')") 告警
19 | el-button(@click="handle_changeIcon('offline')") 离线
20 | el-button(@click="handle_changeIcon('fault')") 故障
21 | el-button(@click="handle_changeIcon('runing')") 运行
22 | el-button(@click="handle_changeIcon('normal')") 停止
23 | el-button(@click="handle_changeFont('alarm')") 文字告警
24 | #topology-canvas.full(ref="myCanvas" style="width:100%; height:100%")
25 | .business-container
26 | el-dialog(
27 | :visible.sync="isShowDetail"
28 | title="点击获取设备实时状态"
29 | )
30 | pre {{ nodeDetail }}
31 |
32 |
33 |
34 |
279 |
280 |
--------------------------------------------------------------------------------
/src/views/config/workspace.vue:
--------------------------------------------------------------------------------
1 |
2 | .page
3 | .tools
4 | el-collapse(v-model="activeNames")
5 | el-collapse-item(
6 | v-for='(item, index) in tools', :key='index'
7 | :title="item.group" Consistency :name="item.group")
8 | .buttons
9 | a(
10 | v-for='(btn, i) in item.children',
11 | :key='i',
12 | :title='btn.name',
13 | :class="{'imgContent' : btn.data.name === 'image'}"
14 | :draggable='btn.data',
15 | @dragstart='onDrag($event, btn)')
16 | .content
17 | img(
18 | v-if="btn.data.name === 'image'",
19 | :src='btn.data.image')
20 | i(v-else-if='btn.data.iconClass', :class='`iconfont ${btn.data.iconClass}`')
21 | i(v-else='', :class='`iconfont ${btn.icon}`' style="font-size:26px")
22 | //- i(class="iconfont icon-shidu")
23 | .name {{ btn.name }}
24 |
25 |
26 |
27 | #topology-canvas.full(@contextmenu='onContextMenu($event)')
28 |
29 | .props
30 | CanvasProps(
31 | :canvas='canvas'
32 | :options="canvasOptions"
33 | :props.sync='props'
34 | @change='onUpdateProps'
35 | @animateChange='onAnimateChange'
36 | @align="onAlignNodes"
37 | @changeOptions="onChangeOptions"
38 | @changeBaseImg='onSetBaseImg')
39 | .context-menu(v-if='contextmenu.left', :style='this.contextmenu')
40 | CanvasContextMenu(:canvas='canvas', :props.sync='props')
41 |
42 |
43 |
406 |
407 |
499 |
--------------------------------------------------------------------------------
/src/components/CanvasProps.vue:
--------------------------------------------------------------------------------
1 |
2 | .canvas-props
3 | h3.tips 操作栏
4 | .group
5 | .title 快捷操作
6 | .container
7 | .item.full-item
8 | el-button(@click="onAddPipeLine") 绘制水管
9 |
10 | .group
11 | .title 基础配置
12 | .container
13 | .item.full-item
14 | .label 选择底图
15 | el-select(v-model='baseImg', placeholder='选择底图', @change='handleBaseImg')
16 | el-option(v-for='item in baseImgList', :key='item.value', :label='item.label', :value='item.value')
17 | .item
18 | .label 禁用滚轮缩放
19 | el-switch(v-model="canvasOptions.disableScale" @change='onChangeOptions')
20 |
21 | //- .item
22 | //- .label 画布宽度(px)
23 | //- el-input-number(v-model="canvasOptions.width" @change='onChangeOptions')
24 | //- .item
25 | //- .label 画布高度(px)
26 | //- el-input-number(v-model="canvasOptions.height" @change='onChangeOptions')
27 | //- .item
28 | //- .label 选中颜色
29 | //- el-color-picker(v-model="canvasOptions.bkColor" @change='onChangeOptions')
30 | //- .item
31 | //- .label 线条/边框颜色
32 | //- el-color-picker(v-model="canvasOptions.color" @change='onChangeOptions')
33 | //- .item
34 | //- .label 活动层颜色
35 | //- el-color-picker(v-model="canvasOptions.hoverColor" @change='onChangeOptions')
36 |
37 | div(v-if="!props.node && !props.line && !props.multi")
38 | .bottom
39 | .title 小提示
40 | ul.group
41 | li 方向键:控制节点移动5个像素
42 | li Ctrl + 方向键:控制节点移动1个像素
43 | li Ctrl + 鼠标移动:移动整个画布
44 | li Ctrl + 鼠标滚轮:缩放
45 | li 添加或选中节点,右侧属性支持上传各种图片
46 |
47 | // 多节点对齐
48 | .props-container(v-if="props.multi")
49 | .group
50 | .title 节点对齐
51 | .item.full-item
52 | span(
53 | v-for="item of nodesAlgin" :key="item"
54 | style="padding-left: 20px;cursor: pointer")
55 | i(:class="`iconfont icon-align-${ item }`"
56 | @click="onNodesAlign(item)")
57 |
58 | // 线条属性
59 | .props-container(v-if="props.line")
60 | .group
61 | .title 业务属性
62 | .item.full-item
63 | .label 关联业务(点位)
64 | el-select(
65 | v-model='props.line.tags'
66 | multiple
67 | allow-create
68 | default-first-option
69 | placeholder='关联设备'
70 | @change='onChange')
71 | el-option(
72 | v-for='item in deviceList',
73 | :key='item.value',
74 | :label='item.label',
75 | :value='item.value')
76 | .group
77 | .title 位置和大小
78 | .container
79 | .item
80 | .label 起点X(px)
81 | el-input-number(v-model='props.line.from.x', controls-position='right', @change='onChange')
82 | .item
83 | .label 起点Y (px)
84 | el-input-number(v-model='props.line.from.y', controls-position='right', @change='onChange')
85 | .item
86 | .label 终点X(px)
87 | el-input-number(v-model='props.line.to.x', controls-position='right', @change='onChange')
88 | .item
89 | .label 终点Y (px)
90 | el-input-number(v-model='props.line.to.y', controls-position='right', @change='onChange')
91 |
92 | .group
93 | .title 线条属性
94 | .container
95 | .item
96 | .label 连线类型
97 | el-select(v-model='props.line.name', placeholder='选择连线类型', @change='onChange')
98 | el-option(v-for='item in lineTypeOptions', :key='item.value', :label='item.label', :value='item.value')
99 | span {{ item.label }}
100 | svg(xmlns="http://www.w3.org/2000/svg" version="1.1" style="width: 100px")
101 | g(fill="none" stroke="black" stroke-width="1")
102 | path(d="M0 9 l100 0" v-if="item.value === 'line'")
103 | path(d="M0 9 a100,50 0 0,1 85,0" v-if="item.value === 'curve'")
104 | path(d="M0 4 l40 0 l0 12 l40 0" v-if="item.value === 'polyline'")
105 | .item
106 | .label 连线样式
107 | el-select(v-model='props.line.dash', placeholder='选择连线类型', @change='onChange')
108 | el-option(v-for='index in 4', :key='index', :label='index', :value='index -1')
109 | svg(xmlns="http://www.w3.org/2000/svg" version="1.1" style="width: 100px")
110 | g(fill="none" stroke="black" stroke-width="1")
111 | path(d="M0 9 l85 0" v-if="index === 1")
112 | path(stroke-dasharray="5,5" d="M0 9 l85 0" v-if="index === 2")
113 | path(stroke-dasharray="10,10" d="M0 9 l85 0" v-if="index === 3")
114 | path(stroke-dasharray="10,10,2,10" d="M0 9 l85 0" v-if="index === 4")
115 | .item
116 | .label 连线颜色
117 | el-color-picker(v-model="props.line.strokeStyle" show-alpha @change='onChange')
118 | .item
119 | .label 连线宽度(px)
120 | el-input-number(v-model="props.line.lineWidth" @change='onChange')
121 | .item
122 | .label 边框颜色
123 | el-color-picker(v-model="props.line.borderColor" show-alpha @change='onChange')
124 | .item
125 | .label 边框宽度(px)
126 | el-input-number(v-model="props.line.borderWidth" @change='onChange')
127 | .item.full-item
128 | .label 透明度(0-1)
129 | el-input-number(:min="0" :max="1" v-model="props.line.globalAlpha" @change='onChange')
130 |
131 | .group
132 | .title 预设动画
133 | .container
134 | .item.full-item
135 | .label 动画效果
136 | el-select(v-model="props.line.animateType" @change='onChangeLineAnimate')
137 | el-option(
138 | v-for="item in lineAnimateOptions"
139 | :key="item.value"
140 | :label="item.label"
141 | :value="item.value")
142 | .item
143 | .label 动画效果
144 | el-color-picker(v-model="props.line.animateColor" show-alpha @change='onChangeLineAnimate')
145 | .item
146 | .label 圆点大小(px)
147 | el-input-number(v-model="props.line.animateDotSize" @change='onChangeLineAnimate')
148 | .item
149 | .label 动画速度
150 | el-input-number(
151 | :min="1" :max="5"
152 | v-model="props.line.animateSpan"
153 | @change='onChangeLineAnimate')
154 | .item
155 | .label 循环次数
156 | el-input-number(
157 | v-model="props.line.animateCycle"
158 | placeholder="<1表示无限循环"
159 | @change='onChangeLineAnimate')
160 |
161 | // 节点属性
162 | .props-container(v-if="props.node")
163 | .group
164 | .title 业务属性
165 | .item.full-item
166 | .label 关联业务(点位)
167 | el-select(
168 | v-model='props.node.tags',
169 | multiple
170 | allow-create
171 | default-first-option
172 | placeholder='关联设备'
173 | @change='onChange')
174 | el-option(
175 | v-for='item in deviceList',
176 | :key='item.value',
177 | :label='item.label',
178 | :value='item.value')
179 | .item.full-item
180 | .label 允许点击(查看设备详情)
181 | el-switch(v-model="currNodeEnable")
182 |
183 | .group
184 | .title 位置和大小
185 | .container
186 | .item
187 | .label X(px)
188 | el-input-number(v-model='props.node.rect.x', controls-position='right', @change='onChange')
189 | .item
190 | .label Y (px)
191 | el-input-number(v-model='props.node.rect.y', controls-position='right', @change='onChange')
192 |
193 | .item
194 | .label 宽(px)
195 | el-input-number(v-model='props.node.rect.width', controls-position='right', @change='onChange')
196 | .item
197 | .label 高(px)
198 | el-input-number(v-model='props.node.rect.height', controls-position='right', @change='onChange')
199 |
200 | .group
201 | .title 边框属性
202 | .container
203 | .item
204 | .label 边框样式
205 | el-select(v-model='props.node.dash', placeholder='选择连线类型', @change='onChange')
206 | el-option(v-for='index in 4', :key='index', :label='index', :value='index -1')
207 | svg(xmlns="http://www.w3.org/2000/svg" version="1.1" style="width: 100px")
208 | g(fill="none" stroke="black" stroke-width="1")
209 | path(d="M0 9 l85 0" v-if="index === 1")
210 | path(stroke-dasharray="5,5" d="M0 9 l85 0" v-if="index === 2")
211 | path(stroke-dasharray="10,10" d="M0 9 l85 0" v-if="index === 3")
212 | path(stroke-dasharray="10,10,2,10" d="M0 9 l85 0" v-if="index === 4")
213 | .item
214 | .label 边框颜色
215 | el-color-picker(v-model="props.node.strokeStyle" show-alpha @change='onChange')
216 | .item
217 | .label 边框宽度(px)
218 | el-input-number(v-model="props.node.lineWidth" show-alpha @change='onChange')
219 | .item
220 | .label 背景颜色
221 | el-color-picker(v-model="props.node.fillStyle" show-alpha @change='onChange')
222 | .item
223 | .label 透明度(0-1)
224 | el-input-number(v-model="props.node.globalAlpha" @change='onChange')
225 | .group
226 | .title 图片属性
227 | .item.full-item
228 | .label 图片链接(px)
229 | el-input(v-model='props.node.image', @change='onChange')
230 |
231 | .group
232 | .title 字体图标属性
233 | .container
234 | .item
235 | .label 图标大小(px)
236 | el-input-number(:min="6" :max="100" v-model='props.node.iconSize', @change='onChange')
237 | .item
238 | .label 图标颜色
239 | el-color-picker(v-model="props.node.iconColor" show-alpha @change='onChange')
240 |
241 | .group
242 | .title 文字属性
243 | .container
244 | .item
245 | .label 颜色
246 | el-color-picker(v-model="props.node.font.color" show-alpha @change='onChange')
247 | .item
248 | .label 大小(px)
249 | el-input-number(v-model="props.node.font.fontSize" @change='onChange')
250 | .item
251 | .label 加粗
252 | el-select(v-model="props.node.font.fontWeight" @change='onChange')
253 | el-option(
254 | v-for="item in fontWeightOptions"
255 | :key="item.value"
256 | :label="item.label"
257 | :value="item.value")
258 | .item
259 | .label 倾斜
260 | el-select(v-model="props.node.font.fontStyle" @change='onChange')
261 | el-option(
262 | v-for="item in fontStyleOptions"
263 | :key="item.value"
264 | :label="item.label"
265 | :value="item.value")
266 | .item
267 | .label 水平对齐
268 | el-select(v-model="props.node.font.textAlign" @change='onChange')
269 | el-option(
270 | v-for="item in textAlignOptions"
271 | :key="item.value"
272 | :label="item.label"
273 | :value="item.value")
274 | .item
275 | .label 垂直对齐
276 | el-select(v-model="props.node.font.textBaseline" @change='onChange')
277 | el-option(
278 | v-for="item in textBaselineOptions"
279 | :key="item.value"
280 | :label="item.label"
281 | :value="item.value")
282 | .item.full-item
283 | .label 文字内容
284 | el-input(type="textarea" v-model="props.node.text" @change='onChange')
285 |
286 | .group
287 | .title 预设动画
288 | .container
289 | .item.full-item
290 | .label 动画效果
291 | el-select(v-model="props.node.animateType" @change='onChangeAnimate')
292 | el-option(
293 | v-for="item in animateOptions"
294 | :key="item.value"
295 | :label="item.label"
296 | :value="item.value")
297 | .group
298 | .title 媒体资源
299 | .container
300 | .item.full-item
301 | .label 音频URL
302 | el-input(v-model="props.node.audio" @change='onChange')
303 | .item.full-item
304 | .label 视频URL
305 | el-input(v-model="props.node.video" @change='onChange')
306 | .item.full-item
307 | .label 联动视频地址
308 | el-select(v-model="props.node.video" @change='onChange')
309 | el-option(
310 | v-for="item in videoList"
311 | :key="item.value"
312 | :label="item.label"
313 | :value="item.value")
314 | .item.full-item
315 | .label 网页URL
316 | el-input(v-model="props.node.iframe" @change='onChange')
317 |
318 |
319 |
320 |
321 |
322 |
629 |
630 |
681 |
--------------------------------------------------------------------------------