Compare commits

..

No commits in common. 'dev_xq_0.0.1' and 'master' have entirely different histories.

@ -1,175 +0,0 @@
# STOMP 集成完成
## 已创建的文件
### 核心文件
1. **`src/utils/stompService.ts`** - STOMP 核心服务
- 完整的 STOMP 客户端封装(基于 @stomp/stompjs
- 支持连接、订阅、发布
- 自动重连机制
- 服务注册和消息分发
### 示例文件
2. **`src/utils/STOMP_USAGE.md`** - 详细使用文档
- API 文档
- 使用示例
- 迁移指南
- 故障排除
3. **`src/services/nodeService.ts`** - Node 服务示例
- 展示如何封装业务服务
- 设备节点管理
- 消息处理逻辑
4. **`src/components/StompDemo.vue`** - Vue 组件示例
- 完整的演示界面
- 连接控制
- 消息发送和日志
## 快速开始
### 1. 在 main.ts 中初始化
```typescript
import { createApp } from 'vue';
import App from './App.vue';
import { stompService } from './utils/stompService';
const app = createApp(App);
// 连接 STOMP 服务器默认地址ws://localhost:8080/stomp-endpoint
stompService.connect({
// 可选配置
// brokerUrl: 'ws://your-server:8080/stomp-endpoint',
// username: 'admin',
// password: 'password',
reconnectDelay: 5000
});
app.mount('#app');
```
### 2. 在组件中使用
```vue
<script lang="ts" setup>
import { onMounted } from 'vue';
import { stompService, MqttCmd } from '@/utils/stompService';
onMounted(() => {
// 注册服务
stompService.registerService('myService', {
mqttReady() {
console.log('STOMP 已就绪');
},
msgNode(value) {
console.log('收到 Node 消息:', value);
}
});
});
// 发送消息
function sendCommand() {
stompService.send('/app/web/write', MqttCmd.Control, {
nodeId: 'node-001',
action: 'turnOn'
});
}
</script>
```
### 3. 查看演示
`StompDemo.vue` 组件添加到您的路由中:
```typescript
// router/index.ts
import StompDemo from '@/components/StompDemo.vue';
{
path: '/stomp-demo',
name: 'StompDemo',
component: StompDemo
}
```
然后访问 `/stomp-demo` 查看演示界面。
## 主要特性
**自动重连** - 连接丢失后自动重连(默认 5 秒间隔)
**服务注册** - 支持多个业务服务注册
**消息分发** - 自动将消息分发到对应服务
**TypeScript** - 完整的类型支持
**错误处理** - 完善的错误处理和日志
**易于扩展** - 可轻松添加新服务
## 消息命令类型
```typescript
MqttCmd = {
Channel: 'channel', // 通道状态
NodeInit: 'nodeInit', // Node 初始化
Node: 'node', // Node 更新
User: 'user', // 用户登录
Control: 'control', // 控制命令
VideoInit: 'videoInit', // 视频初始化
VideoCtl: 'videoCtl', // 视频控制
Lock: 'lock', // 锁控
Alarm: 'alarm', // 告警
Info: 'info', // 通知提示
SocketDebugger: 'socketDebugger' // 调试
}
```
## 从 ExtJS 迁移
### ExtJS 版本
```javascript
Rec.mqtt.connect();
Rec.service.node = { msgNode: function(data) {} };
Rec.mqtt.send(cmd, value);
```
### Vue 版本
```typescript
import { stompService } from '@/utils/stompService';
stompService.connect();
stompService.registerService('node', { msgNode: (data) => {} });
stompService.send('/app/web/write', cmd, value);
```
## 连接地址
**默认连接地址:**
- 开发环境:`ws://localhost:8080/stomp-endpoint`
- 生产环境:`ws://your-domain/stomp-endpoint`
**自定义连接地址:**
```typescript
stompService.connect({
brokerUrl: 'ws://192.168.1.100:8080/stomp-endpoint'
});
```
## 注意事项
1. **连接时机**: 建议在 `main.ts` 中应用启动时连接
2. **服务注册**: 在组件的 `onMounted` 生命周期注册
3. **资源清理**: 组件卸载时根据需要清理
4. **TypeScript**: 所有方法都有完整类型定义
## 需要帮助?
- 查看 `src/utils/STOMP_USAGE.md` 获取详细文档
- 查看 `src/components/StompDemo.vue` 获取完整示例
- 查看 `src/services/nodeService.ts` 获取服务封装示例
## 下一步
1. 根据您的业务需求创建相应的服务
2. 将现有的 ExtJS 服务迁移到新的架构
3. 添加更多错误处理和日志记录
4. 实现消息持久化和离线缓存

567
package-lock.json generated

@ -8,7 +8,6 @@
"name": "maotu", "name": "maotu",
"version": "0.3.1", "version": "0.3.1",
"dependencies": { "dependencies": {
"@stomp/stompjs": "^7.3.0",
"@tweenjs/tween.js": "^25.0.0", "@tweenjs/tween.js": "^25.0.0",
"@vueuse/core": "^10.6.1", "@vueuse/core": "^10.6.1",
"ace-builds": "^1.32.0", "ace-builds": "^1.32.0",
@ -23,24 +22,19 @@
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"less": "^4.2.0", "less": "^4.2.0",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"mqtt": "^5.15.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"sockjs-client": "^1.6.1",
"sortablejs": "^1.15.7",
"stats.js": "^0.17.0", "stats.js": "^0.17.0",
"three": "^0.182.0", "three": "^0.182.0",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-echarts": "^6.6.5", "vue-echarts": "^6.6.5",
"vue-router": "^4.2.5", "vue-router": "^4.2.5",
"vue3-ace-editor": "^2.2.4", "vue3-ace-editor": "^2.2.4"
"vuedraggable": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@rushstack/eslint-patch": "^1.3.3", "@rushstack/eslint-patch": "^1.3.3",
"@tsconfig/node18": "^18.2.2", "@tsconfig/node18": "^18.2.2",
"@types/jsdom": "^21.1.3", "@types/jsdom": "^21.1.3",
"@types/node": "^18.18.5", "@types/node": "^18.18.5",
"@types/sortablejs": "^1.15.9",
"@types/three": "^0.182.0", "@types/three": "^0.182.0",
"@vitejs/plugin-vue": "^4.4.0", "@vitejs/plugin-vue": "^4.4.0",
"@vue/eslint-config-prettier": "^8.0.0", "@vue/eslint-config-prettier": "^8.0.0",
@ -553,9 +547,9 @@
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.29.2", "version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.2.tgz", "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.28.6.tgz",
"integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -2090,12 +2084,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@stomp/stompjs": {
"version": "7.3.0",
"resolved": "https://registry.npmmirror.com/@stomp/stompjs/-/stompjs-7.3.0.tgz",
"integrity": "sha512-nKMLoFfJhrQAqkvvKd1vLq/cVBGCMwPRCD0LqW7UT1fecRx9C3GoKEIR2CYwVuErGeZu8w0kFkl2rlhPlqHVgQ==",
"license": "Apache-2.0"
},
"node_modules/@tootallnate/once": { "node_modules/@tootallnate/once": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/@tootallnate/once/-/once-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/@tootallnate/once/-/once-2.0.0.tgz",
@ -2207,6 +2195,7 @@
"version": "18.19.130", "version": "18.19.130",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-18.19.130.tgz", "resolved": "https://registry.npmmirror.com/@types/node/-/node-18.19.130.tgz",
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~5.26.4" "undici-types": "~5.26.4"
@ -2218,15 +2207,6 @@
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==", "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/readable-stream": {
"version": "4.0.23",
"resolved": "https://registry.npmmirror.com/@types/readable-stream/-/readable-stream-4.0.23.tgz",
"integrity": "sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/semver": { "node_modules/@types/semver": {
"version": "7.7.1", "version": "7.7.1",
"resolved": "https://registry.npmmirror.com/@types/semver/-/semver-7.7.1.tgz", "resolved": "https://registry.npmmirror.com/@types/semver/-/semver-7.7.1.tgz",
@ -2234,13 +2214,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/sortablejs": {
"version": "1.15.9",
"resolved": "https://registry.npmmirror.com/@types/sortablejs/-/sortablejs-1.15.9.tgz",
"integrity": "sha512-7HP+rZGE2p886PKV9c9OJzLBI6BBJu1O7lJGYnPyG3fS4/duUCcngkNCjsLwIMV+WMqANe3tt4irrXHSIe68OQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/stats.js": { "node_modules/@types/stats.js": {
"version": "0.17.4", "version": "0.17.4",
"resolved": "https://registry.npmmirror.com/@types/stats.js/-/stats.js-0.17.4.tgz", "resolved": "https://registry.npmmirror.com/@types/stats.js/-/stats.js-0.17.4.tgz",
@ -2301,15 +2274,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/ws": {
"version": "8.18.1",
"resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.18.1.tgz",
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "6.21.0", "version": "6.21.0",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz",
@ -3376,18 +3340,6 @@
"node": "^14.17.0 || ^16.13.0 || >=18.0.0" "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
} }
}, },
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"license": "MIT",
"dependencies": {
"event-target-shim": "^5.0.0"
},
"engines": {
"node": ">=6.5"
}
},
"node_modules/ace-builds": { "node_modules/ace-builds": {
"version": "1.43.5", "version": "1.43.5",
"resolved": "https://registry.npmmirror.com/ace-builds/-/ace-builds-1.43.5.tgz", "resolved": "https://registry.npmmirror.com/ace-builds/-/ace-builds-1.43.5.tgz",
@ -3860,26 +3812,6 @@
"node": ">= 0.6.0" "node": ">= 0.6.0"
} }
}, },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/baseline-browser-mapping": { "node_modules/baseline-browser-mapping": {
"version": "2.9.14", "version": "2.9.14",
"resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz", "resolved": "https://registry.npmmirror.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz",
@ -3922,34 +3854,6 @@
"url": "https://github.com/sponsors/antfu" "url": "https://github.com/sponsors/antfu"
} }
}, },
"node_modules/bl": {
"version": "6.1.6",
"resolved": "https://registry.npmmirror.com/bl/-/bl-6.1.6.tgz",
"integrity": "sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg==",
"license": "MIT",
"dependencies": {
"@types/readable-stream": "^4.0.0",
"buffer": "^6.0.3",
"inherits": "^2.0.4",
"readable-stream": "^4.2.0"
}
},
"node_modules/bl/node_modules/readable-stream": {
"version": "4.7.0",
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-4.7.0.tgz",
"integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
"license": "MIT",
"dependencies": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/bluebird": { "node_modules/bluebird": {
"version": "3.7.2", "version": "3.7.2",
"resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz", "resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz",
@ -3987,24 +3891,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/broker-factory": {
"version": "3.1.14",
"resolved": "https://registry.npmmirror.com/broker-factory/-/broker-factory-3.1.14.tgz",
"integrity": "sha512-L45k5HMbPIrMid0nTOZ/UPXG/c0aRuQKVrSDFIb1zOkvfiyHgYmIjc3cSiN1KwQIvRDOtKE0tfb3I9EZ3CmpQQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"fast-unique-numbers": "^9.0.27",
"tslib": "^2.8.1",
"worker-factory": "^7.0.49"
}
},
"node_modules/broker-factory/node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/browserslist": { "node_modules/browserslist": {
"version": "4.28.1", "version": "4.28.1",
"resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.1.tgz", "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.28.1.tgz",
@ -4040,36 +3926,6 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
} }
}, },
"node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"license": "MIT"
},
"node_modules/cac": { "node_modules/cac": {
"version": "6.7.14", "version": "6.7.14",
"resolved": "https://registry.npmmirror.com/cac/-/cac-6.7.14.tgz", "resolved": "https://registry.npmmirror.com/cac/-/cac-6.7.14.tgz",
@ -4420,12 +4276,6 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/commist": {
"version": "3.2.0",
"resolved": "https://registry.npmmirror.com/commist/-/commist-3.2.0.tgz",
"integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==",
"license": "MIT"
},
"node_modules/component-emitter": { "node_modules/component-emitter": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmmirror.com/component-emitter/-/component-emitter-1.3.1.tgz", "resolved": "https://registry.npmmirror.com/component-emitter/-/component-emitter-1.3.1.tgz",
@ -4456,21 +4306,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/concat-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/concat-stream/-/concat-stream-2.0.0.tgz",
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
"engines": [
"node >= 6.0"
],
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.0.2",
"typedarray": "^0.0.6"
}
},
"node_modules/confbox": { "node_modules/confbox": {
"version": "0.2.2", "version": "0.2.2",
"resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.2.2.tgz", "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.2.2.tgz",
@ -4848,6 +4683,7 @@
"version": "4.4.3", "version": "4.4.3",
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
@ -5875,33 +5711,6 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmmirror.com/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"license": "MIT",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/eventsource": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/eventsource/-/eventsource-2.0.2.tgz",
"integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==",
"license": "MIT",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/expand-brackets": { "node_modules/expand-brackets": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmmirror.com/expand-brackets/-/expand-brackets-2.1.4.tgz", "resolved": "https://registry.npmmirror.com/expand-brackets/-/expand-brackets-2.1.4.tgz",
@ -6063,25 +5872,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-unique-numbers": {
"version": "9.0.27",
"resolved": "https://registry.npmmirror.com/fast-unique-numbers/-/fast-unique-numbers-9.0.27.tgz",
"integrity": "sha512-nDA9ADeINN8SA2u2wCtU+siWFTTDqQR37XvgPIDDmboWQeExz7X0mImxuaN+kJddliIqy2FpVRmnvRZ+j8i1/A==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"tslib": "^2.8.1"
},
"engines": {
"node": ">=18.2.0"
}
},
"node_modules/fast-unique-numbers/node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/fastq": { "node_modules/fastq": {
"version": "1.20.1", "version": "1.20.1",
"resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.20.1.tgz", "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.20.1.tgz",
@ -6092,18 +5882,6 @@
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
}, },
"node_modules/faye-websocket": {
"version": "0.11.4",
"resolved": "https://registry.npmmirror.com/faye-websocket/-/faye-websocket-0.11.4.tgz",
"integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
"license": "Apache-2.0",
"dependencies": {
"websocket-driver": ">=0.5.1"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/fflate": { "node_modules/fflate": {
"version": "0.8.2", "version": "0.8.2",
"resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.2.tgz", "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.2.tgz",
@ -6804,12 +6582,6 @@
"he": "bin/he" "he": "bin/he"
} }
}, },
"node_modules/help-me": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/help-me/-/help-me-5.0.0.tgz",
"integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==",
"license": "MIT"
},
"node_modules/hookable": { "node_modules/hookable": {
"version": "5.5.3", "version": "5.5.3",
"resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz", "resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz",
@ -6864,12 +6636,6 @@
"dev": true, "dev": true,
"license": "BSD-2-Clause" "license": "BSD-2-Clause"
}, },
"node_modules/http-parser-js": {
"version": "0.5.10",
"resolved": "https://registry.npmmirror.com/http-parser-js/-/http-parser-js-0.5.10.tgz",
"integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==",
"license": "MIT"
},
"node_modules/http-proxy-agent": { "node_modules/http-proxy-agent": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
@ -6912,26 +6678,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "BSD-3-Clause"
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz",
@ -7015,6 +6761,7 @@
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/ini": { "node_modules/ini": {
@ -7039,15 +6786,6 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/ip-address": {
"version": "10.1.0",
"resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-10.1.0.tgz",
"integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
"license": "MIT",
"engines": {
"node": ">= 12"
}
},
"node_modules/is-accessor-descriptor": { "node_modules/is-accessor-descriptor": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", "resolved": "https://registry.npmmirror.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz",
@ -7685,16 +7423,6 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/js-sdsl": {
"version": "4.3.0",
"resolved": "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.3.0.tgz",
"integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/js-sdsl"
}
},
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
@ -8030,6 +7758,7 @@
"version": "10.4.3", "version": "10.4.3",
"resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/magic-string": { "node_modules/magic-string": {
@ -8217,6 +7946,7 @@
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
@ -8304,65 +8034,6 @@
"pathe": "^2.0.1" "pathe": "^2.0.1"
} }
}, },
"node_modules/mqtt": {
"version": "5.15.0",
"resolved": "https://registry.npmmirror.com/mqtt/-/mqtt-5.15.0.tgz",
"integrity": "sha512-KC+wAssYk83Qu5bT8YDzDYgUJxPhbLeVsDvpY2QvL28PnXYJzC2WkKruyMUgBAZaQ7h9lo9k2g4neRNUUxzgMw==",
"license": "MIT",
"dependencies": {
"@types/readable-stream": "^4.0.21",
"@types/ws": "^8.18.1",
"commist": "^3.2.0",
"concat-stream": "^2.0.0",
"debug": "^4.4.1",
"help-me": "^5.0.0",
"lru-cache": "^10.4.3",
"minimist": "^1.2.8",
"mqtt-packet": "^9.0.2",
"number-allocator": "^1.0.14",
"readable-stream": "^4.7.0",
"rfdc": "^1.4.1",
"socks": "^2.8.6",
"split2": "^4.2.0",
"worker-timers": "^8.0.23",
"ws": "^8.18.3"
},
"bin": {
"mqtt": "build/bin/mqtt.js",
"mqtt_pub": "build/bin/pub.js",
"mqtt_sub": "build/bin/sub.js"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/mqtt-packet": {
"version": "9.0.2",
"resolved": "https://registry.npmmirror.com/mqtt-packet/-/mqtt-packet-9.0.2.tgz",
"integrity": "sha512-MvIY0B8/qjq7bKxdN1eD+nrljoeaai+qjLJgfRn3TiMuz0pamsIWY2bFODPZMSNmabsLANXsLl4EMoWvlaTZWA==",
"license": "MIT",
"dependencies": {
"bl": "^6.0.8",
"debug": "^4.3.4",
"process-nextick-args": "^2.0.1"
}
},
"node_modules/mqtt/node_modules/readable-stream": {
"version": "4.7.0",
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-4.7.0.tgz",
"integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
"license": "MIT",
"dependencies": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/mrmime": { "node_modules/mrmime": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.1.tgz",
@ -8377,6 +8048,7 @@
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/muggle-string": { "node_modules/muggle-string": {
@ -8651,16 +8323,6 @@
"url": "https://github.com/fb55/nth-check?sponsor=1" "url": "https://github.com/fb55/nth-check?sponsor=1"
} }
}, },
"node_modules/number-allocator": {
"version": "1.0.14",
"resolved": "https://registry.npmmirror.com/number-allocator/-/number-allocator-1.0.14.tgz",
"integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==",
"license": "MIT",
"dependencies": {
"debug": "^4.3.1",
"js-sdsl": "4.3.0"
}
},
"node_modules/nwsapi": { "node_modules/nwsapi": {
"version": "2.2.23", "version": "2.2.23",
"resolved": "https://registry.npmmirror.com/nwsapi/-/nwsapi-2.2.23.tgz", "resolved": "https://registry.npmmirror.com/nwsapi/-/nwsapi-2.2.23.tgz",
@ -9425,21 +9087,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1" "url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/process": {
"version": "0.11.10",
"resolved": "https://registry.npmmirror.com/process/-/process-0.11.10.tgz",
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"license": "MIT"
},
"node_modules/proto-list": { "node_modules/proto-list": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmmirror.com/proto-list/-/proto-list-1.2.4.tgz", "resolved": "https://registry.npmmirror.com/proto-list/-/proto-list-1.2.4.tgz",
@ -9518,6 +9165,7 @@
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmmirror.com/querystringify/-/querystringify-2.2.0.tgz", "resolved": "https://registry.npmmirror.com/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/queue-microtask": { "node_modules/queue-microtask": {
@ -9575,6 +9223,7 @@
"version": "3.6.2", "version": "3.6.2",
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"inherits": "^2.0.3", "inherits": "^2.0.3",
@ -9707,6 +9356,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/resize-detector": { "node_modules/resize-detector": {
@ -9939,6 +9589,7 @@
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true,
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@ -10338,16 +9989,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/smart-buffer": {
"version": "4.2.0",
"resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz",
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
"license": "MIT",
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
}
},
"node_modules/snapdragon": { "node_modules/snapdragon": {
"version": "0.8.2", "version": "0.8.2",
"resolved": "https://registry.npmmirror.com/snapdragon/-/snapdragon-0.8.2.tgz", "resolved": "https://registry.npmmirror.com/snapdragon/-/snapdragon-0.8.2.tgz",
@ -10473,54 +10114,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/sockjs-client": {
"version": "1.6.1",
"resolved": "https://registry.npmmirror.com/sockjs-client/-/sockjs-client-1.6.1.tgz",
"integrity": "sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==",
"license": "MIT",
"dependencies": {
"debug": "^3.2.7",
"eventsource": "^2.0.2",
"faye-websocket": "^0.11.4",
"inherits": "^2.0.4",
"url-parse": "^1.5.10"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://tidelift.com/funding/github/npm/sockjs-client"
}
},
"node_modules/sockjs-client/node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.1"
}
},
"node_modules/socks": {
"version": "2.8.7",
"resolved": "https://registry.npmmirror.com/socks/-/socks-2.8.7.tgz",
"integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==",
"license": "MIT",
"dependencies": {
"ip-address": "^10.0.1",
"smart-buffer": "^4.2.0"
},
"engines": {
"node": ">= 10.0.0",
"npm": ">= 3.0.0"
}
},
"node_modules/sortablejs": {
"version": "1.15.7",
"resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.15.7.tgz",
"integrity": "sha512-Kk8wLQPlS+yi1ZEf48a4+fzHa4yxjC30M/Sr2AnQu+f/MPwvvX9XjZ6OWejiz8crBsLwSq8GHqaxaET7u6ux0A==",
"license": "MIT"
},
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
@ -10612,15 +10205,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/split2": {
"version": "4.2.0",
"resolved": "https://registry.npmmirror.com/split2/-/split2-4.2.0.tgz",
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
"license": "ISC",
"engines": {
"node": ">= 10.x"
}
},
"node_modules/sprintf-js": { "node_modules/sprintf-js": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz", "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz",
@ -10734,6 +10318,7 @@
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"safe-buffer": "~5.2.0" "safe-buffer": "~5.2.0"
@ -11741,12 +11326,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
"license": "MIT"
},
"node_modules/typedarray.prototype.slice": { "node_modules/typedarray.prototype.slice": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmmirror.com/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.5.tgz", "resolved": "https://registry.npmmirror.com/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.5.tgz",
@ -11840,6 +11419,7 @@
"version": "5.26.5", "version": "5.26.5",
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz", "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/union-value": { "node_modules/union-value": {
@ -12030,6 +11610,7 @@
"version": "1.5.10", "version": "1.5.10",
"resolved": "https://registry.npmmirror.com/url-parse/-/url-parse-1.5.10.tgz", "resolved": "https://registry.npmmirror.com/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"querystringify": "^2.1.1", "querystringify": "^2.1.1",
@ -12050,6 +11631,7 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/utrie": { "node_modules/utrie": {
@ -12532,24 +12114,6 @@
"vue": "^3" "vue": "^3"
} }
}, },
"node_modules/vuedraggable": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz",
"integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
"license": "MIT",
"dependencies": {
"sortablejs": "1.14.0"
},
"peerDependencies": {
"vue": "^3.0.1"
}
},
"node_modules/vuedraggable/node_modules/sortablejs": {
"version": "1.14.0",
"resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.14.0.tgz",
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==",
"license": "MIT"
},
"node_modules/w3c-xmlserializer": { "node_modules/w3c-xmlserializer": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmmirror.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", "resolved": "https://registry.npmmirror.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
@ -12582,29 +12146,6 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/websocket-driver": {
"version": "0.7.4",
"resolved": "https://registry.npmmirror.com/websocket-driver/-/websocket-driver-0.7.4.tgz",
"integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
"license": "Apache-2.0",
"dependencies": {
"http-parser-js": ">=0.5.1",
"safe-buffer": ">=5.1.0",
"websocket-extensions": ">=0.1.1"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/websocket-extensions": {
"version": "0.1.4",
"resolved": "https://registry.npmmirror.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/whatwg-encoding": { "node_modules/whatwg-encoding": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
@ -12781,77 +12322,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/worker-factory": {
"version": "7.0.49",
"resolved": "https://registry.npmmirror.com/worker-factory/-/worker-factory-7.0.49.tgz",
"integrity": "sha512-lW7tpgy6aUv2dFsQhv1yv+XFzdkCf/leoKRTGMPVK5/die6RrUjqgJHJf556qO+ZfytNG6wPXc17E8zzsOLUDw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"fast-unique-numbers": "^9.0.27",
"tslib": "^2.8.1"
}
},
"node_modules/worker-factory/node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/worker-timers": {
"version": "8.0.31",
"resolved": "https://registry.npmmirror.com/worker-timers/-/worker-timers-8.0.31.tgz",
"integrity": "sha512-ngkq5S6JuZyztom8tDgBzorLo9byhBMko/sXfgiUD945AuzKGg1GCgDMCC3NaYkicLpGKXutONM36wEX8UbBCA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"tslib": "^2.8.1",
"worker-timers-broker": "^8.0.16",
"worker-timers-worker": "^9.0.14"
}
},
"node_modules/worker-timers-broker": {
"version": "8.0.16",
"resolved": "https://registry.npmmirror.com/worker-timers-broker/-/worker-timers-broker-8.0.16.tgz",
"integrity": "sha512-JyP3AvUGyPGbBGW7XiUewm2+0pN/aYo1QpVf5kdXAfkDZcN3p7NbWrG6XnyDEpDIvfHk/+LCnOW/NsuiU9riYA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"broker-factory": "^3.1.14",
"fast-unique-numbers": "^9.0.27",
"tslib": "^2.8.1",
"worker-timers-worker": "^9.0.14"
}
},
"node_modules/worker-timers-broker/node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/worker-timers-worker": {
"version": "9.0.14",
"resolved": "https://registry.npmmirror.com/worker-timers-worker/-/worker-timers-worker-9.0.14.tgz",
"integrity": "sha512-/qF06C60sXmSLfUl7WglvrDIbspmPOM8UrG63Dnn4bi2x4/DfqHS/+dxF5B+MdHnYO5tVuZYLHdAodrKdabTIg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.2",
"tslib": "^2.8.1",
"worker-factory": "^7.0.49"
}
},
"node_modules/worker-timers-worker/node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/worker-timers/node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/wrap-ansi": { "node_modules/wrap-ansi": {
"version": "8.1.0", "version": "8.1.0",
"resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
@ -12964,6 +12434,7 @@
"version": "8.19.0", "version": "8.19.0",
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.19.0.tgz", "resolved": "https://registry.npmmirror.com/ws/-/ws-8.19.0.tgz",
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"

@ -29,7 +29,6 @@
}, },
"typings": "dist/export.d.ts", "typings": "dist/export.d.ts",
"dependencies": { "dependencies": {
"@stomp/stompjs": "^7.3.0",
"@tweenjs/tween.js": "^25.0.0", "@tweenjs/tween.js": "^25.0.0",
"@vueuse/core": "^10.6.1", "@vueuse/core": "^10.6.1",
"ace-builds": "^1.32.0", "ace-builds": "^1.32.0",
@ -44,24 +43,19 @@
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"less": "^4.2.0", "less": "^4.2.0",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"mqtt": "^5.15.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"sockjs-client": "^1.6.1",
"sortablejs": "^1.15.7",
"stats.js": "^0.17.0", "stats.js": "^0.17.0",
"three": "^0.182.0", "three": "^0.182.0",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-echarts": "^6.6.5", "vue-echarts": "^6.6.5",
"vue-router": "^4.2.5", "vue-router": "^4.2.5",
"vue3-ace-editor": "^2.2.4", "vue3-ace-editor": "^2.2.4"
"vuedraggable": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@rushstack/eslint-patch": "^1.3.3", "@rushstack/eslint-patch": "^1.3.3",
"@tsconfig/node18": "^18.2.2", "@tsconfig/node18": "^18.2.2",
"@types/jsdom": "^21.1.3", "@types/jsdom": "^21.1.3",
"@types/node": "^18.18.5", "@types/node": "^18.18.5",
"@types/sortablejs": "^1.15.9",
"@types/three": "^0.182.0", "@types/three": "^0.182.0",
"@vitejs/plugin-vue": "^4.4.0", "@vitejs/plugin-vue": "^4.4.0",
"@vue/eslint-config-prettier": "^8.0.0", "@vue/eslint-config-prettier": "^8.0.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

@ -4,7 +4,6 @@
<!-- <VueThreeMachine /> --> <!-- <VueThreeMachine /> -->
<!-- <vueThreeEquipment /> --> <!-- <vueThreeEquipment /> -->
<!-- <VueGradeGauge /> --> <!-- <VueGradeGauge /> -->
<!-- <StompDemo /> -->
<el-config-provider :locale="zhCn"> <el-config-provider :locale="zhCn">
<router-view /> <router-view />
</el-config-provider> </el-config-provider>
@ -18,9 +17,6 @@ import { leftAsideStore } from '@/export';
import viewIndex from '@/layout/view_index.vue'; import viewIndex from '@/layout/view_index.vue';
import zhCn from 'element-plus/es/locale/lang/zh-cn'; import zhCn from 'element-plus/es/locale/lang/zh-cn';
// xq // xq
// F:\vue\workspace\maotu-webtopo\src\components\StompDemo.vue
// import StompDemo from '@/components/StompDemo.vue';
import VueMyTest from '@/components/my-test.vue'; import VueMyTest from '@/components/my-test.vue';
import VueMyButton from '@/components/my-button.vue'; import VueMyButton from '@/components/my-button.vue';
import vueInstrument from '@/components/vue-xq-test/vue-instrument.vue'; import vueInstrument from '@/components/vue-xq-test/vue-instrument.vue';
@ -50,20 +46,6 @@ import VueThreeGroundFloor from '@/components/vue-xq-test/vue-three-groundFloor.
import vueThreeEquipment from '@/components/three-components/vue-three-equipment.vue'; import vueThreeEquipment from '@/components/three-components/vue-three-equipment.vue';
import vueThreeFireControl from '@/components/three-components/vue-three-fire-control.vue'; import vueThreeFireControl from '@/components/three-components/vue-three-fire-control.vue';
import vueThreeSubstation from '@/components/three-components/vue-three-substation.vue'; import vueThreeSubstation from '@/components/three-components/vue-three-substation.vue';
import vueThreeTransformer from '@/components/three-components/vue-three-transformer.vue';
import VueNitrogenInjection from '@/components/vue-xq-test/vue-nitrogen-injection.vue';
import VueThreeNitrogen from '@/components/three-components/vue-three-nitrogen.vue';
import VueTableNitrogen from '@/components/vue-components/vue-table-nitrogen.vue';
import VueFlowChart from '@/components/vue-components/vue-flow-chart.vue';
import VueInfoDetector from '@/components/vue-components/vue-info-detector.vue';
import VueTableFireHydrant from '@/components/vue-components/vue-table-fire-hydrant.vue';
import VueTableFireHydrantInfo from '@/components/vue-components/vue-table-fire-hydrant-info.vue';
import VueThreeBuilding from '@/components/three-components/vue-three-building.vue';
import VueExtinguisherTable from '@/components/vue-components/vue-extinguisher-table.vue';
import VueIlluminationTable from '@/components/vue-components/vue-illumination-table.vue';
import VueStrInfo from '@/components/vue-components/vue-str-info.vue';
// src\components\vue-components\vue-test-controller.vue
import VueTestController from '@/components/vue-components/vue-test-controller.vue';
// //
import VueGradeGauge from '@/components/vue-components/echarts-grade-gauge.vue'; import VueGradeGauge from '@/components/vue-components/echarts-grade-gauge.vue';
@ -75,7 +57,7 @@ import VueGuagePieChart from '@/components/vue-components/echarts-pie-chart.vue'
// src\components\vue-components\vue-signal-monitoring.vue // src\components\vue-components\vue-signal-monitoring.vue
import VueSignalMonitoring from '@/components/vue-components/vue-signal-monitoring.vue'; import VueSignalMonitoring from '@/components/vue-components/vue-signal-monitoring.vue';
import VueImgImmobilization from '@/components/vue-components/vue-img-immobilization.vue'; import VueImgImmobilization from '@/components/vue-components/vue-img-immobilization.vue';
import VueCharacters from '@/components/vue-components/vue-characters.vue';
const instance = getCurrentInstance(); const instance = getCurrentInstance();
instance?.appContext.app.component('vue-my-button', VueMyButton); instance?.appContext.app.component('vue-my-button', VueMyButton);
@ -107,27 +89,13 @@ instance?.appContext.app.component('vue-my-three-test', VueThreeTest);
instance?.appContext.app.component('vue-my-three-ground-floor', VueThreeGroundFloor); instance?.appContext.app.component('vue-my-three-ground-floor', VueThreeGroundFloor);
instance?.appContext.app.component('vue-my-three-fire-control', vueThreeFireControl); instance?.appContext.app.component('vue-my-three-fire-control', vueThreeFireControl);
instance?.appContext.app.component('vue-my-three-substation', vueThreeSubstation); instance?.appContext.app.component('vue-my-three-substation', vueThreeSubstation);
instance?.appContext.app.component('vue-my-three-transformer', vueThreeTransformer);
instance?.appContext.app.component('vue-my-nitrogen-injection', VueNitrogenInjection);
instance?.appContext.app.component('vue-my-three-nitrogen', VueThreeNitrogen);
instance?.appContext.app.component('vue-my-table-nitrogen', VueTableNitrogen);
instance?.appContext.app.component('vue-my-flow-chart', VueFlowChart);
instance?.appContext.app.component('vue-my-info-detector', VueInfoDetector);
instance?.appContext.app.component('vue-my-table-fire-hydrant', VueTableFireHydrant);
instance?.appContext.app.component('vue-my-table-fire-hydrant-info', VueTableFireHydrantInfo);
instance?.appContext.app.component('vue-my-three-building', VueThreeBuilding);
instance?.appContext.app.component('vue-my-extinguisher-table', VueExtinguisherTable);
instance?.appContext.app.component('vue-my-illumination-table', VueIlluminationTable);
instance?.appContext.app.component('vue-my-str-info', VueStrInfo);
instance?.appContext.app.component('vue-my-test-controller', VueTestController);
instance?.appContext.app.component('vue-grade-gauge', VueGradeGauge); instance?.appContext.app.component('vue-grade-gauge', VueGradeGauge);
instance?.appContext.app.component('vue-guage-line-chart', VueGuageLineChart); instance?.appContext.app.component('vue-guage-line-chart', VueGuageLineChart);
instance?.appContext.app.component('vue-guage-bar-chart', VueGuageBarChart); instance?.appContext.app.component('vue-guage-bar-chart', VueGuageBarChart);
instance?.appContext.app.component('vue-guage-pie-chart', VueGuagePieChart); instance?.appContext.app.component('vue-guage-pie-chart', VueGuagePieChart);
instance?.appContext.app.component('vue-img-immobilization', VueImgImmobilization); instance?.appContext.app.component('vue-img-immobilization', VueImgImmobilization);
instance?.appContext.app.component('vue-signal-monitoring', VueSignalMonitoring); instance?.appContext.app.component('vue-signal-monitoring', VueSignalMonitoring);
instance?.appContext.app.component('vue-characters', VueCharacters);
// instance?.appContext.app.component('vue-my-grade-gauge', VueGradeGauge); // instance?.appContext.app.component('vue-my-grade-gauge', VueGradeGauge);
@ -187,52 +155,6 @@ leftAsideStore.registerConfig('vue四遥组件', [
thumbnail: '/svgs/info.svg', thumbnail: '/svgs/info.svg',
props: {} props: {}
}, },
{
id: 'vue-characters',
title: '遥信文字',
type: 'vue',
thumbnail: '/svgs/info.svg',
props: {
moduleType: {
type: 'inputTypeTag',
val: '遥信',
title: '四遥类型'
},
moduleId: {
type: 'inputSelectId',
val: '',
title: '绑定ID'
},
showInfo: {
type: 'switch',
val: true,
title: '显示详情'
},
location: {
type: 'select',
val: 'bottom',
title: '名称位置',
options: [
{
value: 'top',
label: '上'
},
{
value: 'bottom',
label: '下'
},
{
value: 'left',
label: '左'
},
{
value: 'right',
label: '右'
}
]
}
}
},
{ {
id: 'vue-my-signal-gaudy', id: 'vue-my-signal-gaudy',
title: 'vue遥信02', title: 'vue遥信02',
@ -249,11 +171,6 @@ leftAsideStore.registerConfig('vue四遥组件', [
val: '', val: '',
title: '绑定ID' title: '绑定ID'
}, },
showInfo: {
type: 'switch',
val: false,
title: '显示详情'
},
location: { location: {
type: 'select', type: 'select',
val: 'bottom', val: 'bottom',
@ -313,16 +230,6 @@ leftAsideStore.registerConfig('vue四遥组件', [
val: '--', val: '--',
title: '绑定ID' title: '绑定ID'
}, },
showInfo: {
type: 'switch',
val: false,
title: '显示详情'
},
showText: {
type: 'switch',
val: false,
title: '显示文字'
},
location: { location: {
type: 'select', type: 'select',
val: 'bottom', val: 'bottom',
@ -348,44 +255,6 @@ leftAsideStore.registerConfig('vue四遥组件', [
} }
} }
}, },
{
id: 'vue-my-str-info',
title: 'vue遥测-模式',
type: 'vue',
thumbnail: '/svgs/num-info.svg',
props: {
moduleType: {
type: 'inputTypeTag',
val: '遥测',
title: '四遥类型'
},
moduleId: {
type: 'inputSelectId',
val: '--',
title: '绑定ID'
},
showStart: {
type: 'switch',
val: false,
title: '显示状态'
},
showModel: {
type: 'switch',
val: true,
title: '显示模式'
},
showVal: {
type: 'switch',
val: false,
title: '显示值'
},
showText: {
type: 'switch',
val: false,
title: '显示名称'
}
}
},
{ {
id: 'vue-my-regulator', id: 'vue-my-regulator',
title: 'vue遥调', title: 'vue遥调',
@ -403,19 +272,6 @@ leftAsideStore.registerConfig('vue四遥组件', [
title: '绑定ID' title: '绑定ID'
} }
} }
},
{
id: 'vue-my-test-controller',
title: '测试组件',
type: 'vue',
thumbnail: '/svgs/regulator.svg',
props: {
moduleId: {
type: 'inputSelectId',
val: '--',
title: '绑定ID'
}
}
} }
]); ]);
@ -589,17 +445,6 @@ leftAsideStore.registerConfig('vue公共组件', [
label: '火灾报警主机' label: '火灾报警主机'
} }
] ]
},
isSwitch: {
type: 'switch',
val: true,
title: '辅助框'
},
testStr: {
type: 'map',
val: {},
title: '测试',
disabled: true
} }
} }
}, },
@ -918,45 +763,6 @@ leftAsideStore.registerConfig('vue3D组件', [
val: '--' val: '--'
} }
} }
},
{
id: 'vue-my-three-transformer',
title: '3d-变压器',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
dataSource: {
title: '数据源',
type: 'input',
val: '--'
}
}
},
{
id: 'vue-my-three-nitrogen',
title: '3d-排油注氮',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
dataSource: {
title: '数据源',
type: 'input',
val: '--'
}
}
},
{
id: 'vue-my-three-building',
title: '3d-一楼',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
dataSource: {
title: '数据源',
type: 'input',
val: '--'
}
}
} }
]); ]);
@ -1190,268 +996,6 @@ leftAsideStore.registerConfig('vue组件', [
title: '标题' title: '标题'
} }
} }
},
{
id: 'vue-my-nitrogen-injection',
title: '变压器排油注氮灭火-光字牌',
type: 'vue',
thumbnail: '/svgs/table-base.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: 'Segoe UI',
options: [
{
value: 'Segoe UI',
label: 'Segoe UI'
},
{
value: '微软雅黑',
label: '微软雅黑'
},
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 14,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#000000',
title: '文字颜色'
}
}
},
{
id: 'vue-my-table-nitrogen',
title: '2号主变排油灭氮-运行信息(表格)',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#ffffff',
title: '文字颜色'
}
}
},
{
id: 'vue-my-info-detector',
title: '2号主变排油灭氮-火灾探测器基本信息',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#ffffff',
title: '文字颜色'
}
}
},
{
id: 'vue-my-flow-chart',
title: '2号主变排油灭氮-操作流程',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#ffffff',
title: '文字颜色'
}
}
},
{
id: 'vue-my-table-fire-hydrant',
title: '消火栓系统-运行信息(表格)',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#ffffff',
title: '文字颜色'
}
}
},
{
id: 'vue-my-table-fire-hydrant-info',
title: '消火栓系统-消火栓信息(表格)',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
},
testColor: {
type: 'color',
val: '#ffffff',
title: '文字颜色'
}
}
},
{
id: 'vue-my-extinguisher-table',
title: '灭火器配置-灭火器信息(表格)',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
}
}
},
{
id: 'vue-my-illumination-table',
title: '消防应急-运行信息(表格)',
type: 'vue',
thumbnail: '/svgs/table-only.svg',
props: {
fontFamily: {
title: '字体',
type: 'select',
val: '黑体',
options: [
{
value: '黑体',
label: '黑体'
},
{
value: '宋体',
label: '宋体'
}
]
},
fontSize: {
type: 'number',
val: 12,
title: '字体大小'
}
}
} }
]); ]);

@ -45,8 +45,8 @@
--el-box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, 0.36), 0px 8px 20px rgba(0, 0, 0, 0.72); --el-box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, 0.36), 0px 8px 20px rgba(0, 0, 0, 0.72);
--el-box-shadow-light: 0px 0px 12px rgba(0, 0, 0, 0.72); --el-box-shadow-light: 0px 0px 12px rgba(0, 0, 0, 0.72);
--el-box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, 0.72); --el-box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, 0.72);
--el-box-shadow-dark: --el-box-shadow-dark: 0px 16px 48px 16px rgba(0, 0, 0, 0.72), 0px 12px 32px #000000,
0px 16px 48px 16px rgba(0, 0, 0, 0.72), 0px 12px 32px #000000, 0px 8px 16px -8px #000000; 0px 8px 16px -8px #000000;
--el-bg-color-page: #0a0a0a; --el-bg-color-page: #0a0a0a;
--el-bg-color: #141414; --el-bg-color: #141414;
--el-bg-color-overlay: #1d1e1f; --el-bg-color-overlay: #1d1e1f;

@ -1,221 +0,0 @@
<template>
<el-card class="stomp-demo">
<template #header>
<div class="card-header">
<span>STOMP 连接演示</span>
<el-tag :type="isConnected ? 'success' : 'danger'">
{{ isConnected ? '已连接' : '未连接' }}
</el-tag>
</div>
</template>
<!-- 连接控制 -->
<div class="control-section">
<el-tag :type="isConnected ? 'success' : 'danger'" size="large">
{{ isConnected ? 'MQTT 已连接' : 'MQTT 未连接' }}
</el-tag>
<el-button type="primary" @click="reconnect" :disabled="isConnected">重新连接</el-button>
</div>
<!-- 消息发送 -->
<div class="message-section">
<h3>发送消息</h3>
<el-form :model="messageForm" label-width="80px" size="small">
<el-form-item label="命令类型">
<el-select v-model="messageForm.cmd" style="width: 100%">
<el-option
v-for="item in cmdOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="消息内容">
<el-input
v-model="messageForm.value"
type="textarea"
:rows="4"
placeholder='例如:{"nodeId": "node-001", "action": "turnOn"}'
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="sendMessage" :disabled="!isConnected"> 发送 </el-button>
</el-form-item>
</el-form>
</div>
<!-- 消息日志 -->
<div class="log-section">
<h3>消息日志</h3>
<el-table :data="messageLogs" style="width: 100%" max-height="300" size="small">
<el-table-column prop="time" label="时间" width="180" />
<el-table-column prop="cmd" label="命令" width="150" />
<el-table-column prop="direction" label="方向" width="80">
<template #default="{ row }">
<el-tag :type="row.direction === '发送' ? 'primary' : 'success'" size="small">
{{ row.direction }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="content" label="内容" />
</el-table>
<el-button size="small" @click="clearLogs" style="margin-top: 10px"> 清空日志 </el-button>
</div>
</el-card>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { stompService, MqttCmd, type StompMessage } from '../utils/stompService';
//
const isConnected = ref(false);
//
const messageForm = reactive({
cmd: MqttCmd.Control,
value: ''
});
//
const cmdOptions = [
{ label: '控制命令', value: MqttCmd.Control },
{ label: 'Node 更新', value: MqttCmd.Node },
{ label: '告警', value: MqttCmd.Alarm },
{ label: '通知', value: MqttCmd.Info },
{ label: '通道状态', value: MqttCmd.Channel }
];
//
const messageLogs = ref<
Array<{
time: string;
cmd: number;
direction: string;
content: string;
}>
>([]);
//
const addLog = (cmd: string, direction: string, content: string) => {
messageLogs.value.unshift({
time: new Date().toLocaleTimeString(),
cmd,
direction,
content: typeof content === 'string' ? content : JSON.stringify(content)
});
//
if (messageLogs.value.length > 50) {
messageLogs.value.pop();
}
};
//
const clearLogs = () => {
messageLogs.value = [];
};
// STOMP
const reconnect = () => {
stompService.disconnect();
setTimeout(() => {
stompService.connect({
reconnectDelay: 5000
});
ElMessage.info('正在重新连接 MQTT...');
}, 1000);
};
//
const sendMessage = () => {
if (!isConnected.value) {
ElMessage.warning('请先连接 STOMP');
return;
}
try {
const valueObj = JSON.parse(messageForm.value || '{}');
stompService.send('/app/web/write', messageForm.cmd, valueObj);
addLog(messageForm.cmd, '发送', valueObj);
ElMessage.success('消息已发送');
} catch (error) {
ElMessage.error('消息格式错误,请输入有效的 JSON');
}
};
//
onMounted(() => {
//
stompService.registerService('demoComponent', {
mqttReady() {
console.log('[Demo] MQTT 已就绪');
isConnected.value = true;
},
onConnectionLost() {
console.log('[Demo] MQTT 连接丢失');
isConnected.value = false;
ElMessage.warning('MQTT 连接已断开,正在重连...');
}
});
// Node
stompService.registerService('demoNode', {
msgNodeInit(value) {
addLog(MqttCmd.NodeInit, '接收', value);
},
msgNode(value) {
addLog(MqttCmd.Node, '接收', value);
}
});
//
stompService.registerService('demoAlarm', {
alarm(value) {
addLog(MqttCmd.Alarm, '接收', value);
ElMessage.warning(`收到告警:${JSON.stringify(value)}`);
}
});
});
//
onUnmounted(() => {
// MQTT
console.log('[Demo] 组件卸载');
});
</script>
<style scoped>
.stomp-demo {
margin: 20px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.control-section {
margin-bottom: 20px;
display: flex;
gap: 10px;
}
.message-section,
.log-section {
margin-top: 20px;
}
h3 {
margin: 10px 0;
font-size: 14px;
color: var(--el-text-color-primary);
}
</style>

@ -65,6 +65,7 @@
<el-sub-menu <el-sub-menu
:index="menu.children[0].name" :index="menu.children[0].name"
v-if="menu.children && menu.children.length > 1" v-if="menu.children && menu.children.length > 1"
@click="handleSubMenuClick(menu.children[0])"
> >
<template #title> <template #title>
<el-icon> <el-icon>
@ -112,7 +113,6 @@ const props = withDefaults(
function isStairRoute(routeName: string) { function isStairRoute(routeName: string) {
if (stairRouteNames.includes(routeName)) { if (stairRouteNames.includes(routeName)) {
console.log('getStairRoute:', routeName);
emitter.emit('getStairRoute', routeName); emitter.emit('getStairRoute', routeName);
} }
} }
@ -120,7 +120,6 @@ function isStairRoute(routeName: string) {
const router = useRouter(); const router = useRouter();
function headerCliek(val: any) { function headerCliek(val: any) {
console.log('node01:', val.index);
if (stairRouteNames.includes(val.index)) { if (stairRouteNames.includes(val.index)) {
isStairRoute(val.index); isStairRoute(val.index);
} else { } else {
@ -137,17 +136,7 @@ function headerCliek(val: any) {
} }
function handleSubMenuTitleClick(menu: any) { function handleSubMenuTitleClick(menu: any) {
console.log('node02:', menu.name);
if (stairRouteNames.includes(menu.name)) {
isStairRoute(menu.name); isStairRoute(menu.name);
} else {
stairRouteChildrenMap.forEach((children: string[], parent: string) => {
if (children.includes(menu.name)) {
isStairRoute(parent);
}
});
}
// //
router.push({ router.push({
name: menu.name, name: menu.name,
@ -157,7 +146,6 @@ function handleSubMenuTitleClick(menu: any) {
// //
function handleSubMenuClick(menu: any) { function handleSubMenuClick(menu: any) {
console.log('node03:', menu.name);
if (stairRouteNames.includes(menu.name)) { if (stairRouteNames.includes(menu.name)) {
isStairRoute(menu.name); isStairRoute(menu.name);
// //

Binary file not shown.

@ -162,8 +162,8 @@ import { computed, ref } from 'vue';
import SvgAnalysis from '@/components/mt-edit/components/svg-analysis/index.vue'; import SvgAnalysis from '@/components/mt-edit/components/svg-analysis/index.vue';
import { blobToBase64 } from '@/components/mt-edit/utils'; import { blobToBase64 } from '@/components/mt-edit/utils';
function viewGload() { function viewGload(){
console.log('xxx:', globalStore); console.log("xxx:",globalStore);
} }
type RightAsideProps = { type RightAsideProps = {

@ -116,24 +116,6 @@
height="80%" height="80%"
width="60%" width="60%"
> >
<div class="m-4">
<el-row>
<el-col :span="2"> 分区 </el-col>
<el-col :span="8">
<el-cascader
v-model="selectedPartition"
:options="options"
:props="props2"
clearable
@change="handlePartitionChange"
/>
</el-col>
<el-col :span="14">
<el-button type="primary" @click="getDataSource"></el-button>
</el-col>
</el-row>
</div>
<el-table :data="filteredData" :max-height="450"> <el-table :data="filteredData" :max-height="450">
<el-table-column type="index" label="序号" /> <el-table-column type="index" label="序号" />
<el-table-column prop="modeId" label="遥ID" /> <el-table-column prop="modeId" label="遥ID" />
@ -204,7 +186,6 @@ import {
ElColorPicker, ElColorPicker,
ElIcon, ElIcon,
ElButton, ElButton,
ElMessage,
type UploadFile type UploadFile
} from 'element-plus'; } from 'element-plus';
import { Search } from '@element-plus/icons-vue'; import { Search } from '@element-plus/icons-vue';
@ -212,8 +193,6 @@ import JsonEdit from './json-edit.vue';
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { modelApi, BASE_URL } from '@/utils/request'; import { modelApi, BASE_URL } from '@/utils/request';
import imageModel from '@/components/mt-edit/components/layout/base-panel/imageModel.vue'; import imageModel from '@/components/mt-edit/components/layout/base-panel/imageModel.vue';
import { globalStore } from '@/components/mt-edit/store/global';
import { type DataItem } from '@/components/mt-edit/store/types';
type SelectItemPropsSettingProps = { type SelectItemPropsSettingProps = {
propsInfo: ILeftAsideConfigItemPublicProps | undefined; propsInfo: ILeftAsideConfigItemPublicProps | undefined;
}; };
@ -235,7 +214,7 @@ interface RecServiceType {
} }
interface ExtendedParentWindow extends Window { interface ExtendedParentWindow extends Window {
globalData: Map<string, DataItem> | Record<string, DataItem>; Rec?: RecServiceType;
} }
const selectItemPropsSettingProps = withDefaults(defineProps<SelectItemPropsSettingProps>(), {}); const selectItemPropsSettingProps = withDefaults(defineProps<SelectItemPropsSettingProps>(), {});
@ -264,32 +243,24 @@ function setInputTagVal() {
const item = selectItemPropsSettingProps.propsInfo[key]; const item = selectItemPropsSettingProps.propsInfo[key];
if (item.type === 'inputTypeTag') { if (item.type === 'inputTypeTag') {
inputTypeTagValue.value = item.val; inputTypeTagValue.value = item.val;
console.log('inputTypeTagValue:', inputTypeTagValue.value);
break;
} }
} }
} }
let attrItem: any; let attrItem: any;
const dialogTableVisible = ref(false); const dialogTableVisible = ref(false);
function handleIconClick(obj: any) {
async function handleIconClick(obj: any) {
console.log('inputTypeTagValue11:', inputTypeTagValue.value);
console.log('handleIconClick:', obj);
attrItem = obj;
await getAllTree(); //
assembleList(); assembleList();
dialogTableVisible.value = true; // attrItem = obj;
dialogTableVisible.value = true;
} }
let attrImg: any; let attrImg: any;
// //
const onImageDialog = (obj: any) => { const onImageDialog = (obj: any) => {
console.log('xxxxx:', obj);
dialogImageVisible.value = true; dialogImageVisible.value = true;
attrImg = obj; attrImg = obj;
}; };
function bindingImg(obj: any) { function bindingImg(obj: any) {
console.log('绑定图片', obj, attrImg); console.log('绑定图片', obj, attrImg);
attrImg.val = obj.id; attrImg.val = obj.id;
@ -299,22 +270,6 @@ function bindingImg(obj: any) {
let modelIds = ref<string[]>([]); let modelIds = ref<string[]>([]);
//
const selectedPartition = ref<string[]>([]);
//
const handlePartitionChange = (value: string[]) => {
console.log('选中的分区数据:', value);
// value
// [' ID', ' ID', ...]
//
if (value && value.length > 0) {
const lastValue = value[value.length - 1];
console.log('最后选中的值:', lastValue);
//
}
};
function handleEdit(obj: any) { function handleEdit(obj: any) {
console.log('绑定', modelIds.value); console.log('绑定', modelIds.value);
dialogTableVisible.value = false; dialogTableVisible.value = false;
@ -361,39 +316,22 @@ const filterTag = (value: number, row: any) => {
// //
const filteredData = computed(() => { const filteredData = computed(() => {
debugger;
if (!search.value) { if (!search.value) {
return gridData.value; return gridData;
} }
return gridData.value.filter((item) => { return gridData.filter((item) => {
return item.name.toLowerCase().includes(search.value.toLowerCase()); return item.name.toLowerCase().includes(search.value.toLowerCase());
}); });
}); });
//
function assembleList() { function assembleList() {
debugger; // debugger;
let code: number | undefined; let code: number | undefined;
setInputTagVal();
// globalDataRaw
gridData.value.splice(0, gridData.value.length);
if (inputTypeTagValue.value !== undefined) code = getNameForNode(inputTypeTagValue.value); if (inputTypeTagValue.value !== undefined) code = getNameForNode(inputTypeTagValue.value);
// gridData.splice(0, gridData.length);
if (gridDataSource.value && gridDataSource.value.length > 0) {
if (code === undefined) {
// code
return;
} else {
// code
gridData.value = gridDataSource.value.filter((item) => item.bType === code);
console.log('new_gridData:', gridData.value);
return;
}
}
let globalDataRaw = (window as unknown as ExtendedParentWindow).globalData; let globalDataRaw = (window.parent as ExtendedParentWindow).Rec?.service.node.runtimes;
// let globalDataRaw = (window.parent as ExtendedParentWindow).Rec?.service.node.runtimes;
// 访 globalData Map // 访 globalData Map
// const globalDataRaw = (window as any).globalData; // const globalDataRaw = (window as any).globalData;
@ -407,7 +345,7 @@ function assembleList() {
let modeId = key; let modeId = key;
let name = data.node.name; let name = data.node.name;
let bType = data.bType; let bType = data.bType;
gridData.value.push({ modeId, name, bType }); gridData.push({ modeId, name, bType });
} }
}); });
} else { } else {
@ -419,7 +357,7 @@ function assembleList() {
let modeId = key; let modeId = key;
let name = data.node.name; let name = data.node.name;
let bType = data.bType; let bType = data.bType;
gridData.value.push({ modeId, name, bType }); gridData.push({ modeId, name, bType });
} }
} }
} }
@ -432,73 +370,7 @@ interface GridDataItem {
bType: number; bType: number;
} }
const gridData = ref<GridDataItem[]>([]); const gridData: GridDataItem[] = [];
const gridDataSource = ref<GridDataItem[]>([]);
const props2 = {
multiple: false,
checkStrictly: true
};
async function getDataSource() {
debugger
let cls = '-1';
if (selectedPartition.value && selectedPartition.value.length > 0)
cls = selectedPartition.value[selectedPartition.value.length - 1];
let response = await modelApi.getNodeByCls_get(cls);
if (response.code != 200 || response.data == null) {
ElMessage.error(response.message);
} else {
let code: number | undefined;
setInputTagVal();
if (inputTypeTagValue.value !== undefined) code = getNameForNode(inputTypeTagValue.value);
gridDataSource.value.splice(0, gridDataSource.value.length);
gridData.value.splice(0, gridData.value.length);
response.data.forEach((item: any) => {
console.log('item:', item);
gridDataSource.value.push({
modeId: item.id,
name: item.name,
bType: item.btype
});
if (code == undefined || code == item.btype) {
gridData.value.push({
modeId: item.id,
name: item.name,
bType: item.btype
});
}
});
ElMessage.success('接口请求成功');
console.log('gridData:', gridData.value);
}
}
async function getAllTree() {
const response = await modelApi.allTree_get();
if (response.code != 200 || response.data == null) {
ElMessage.error(response.message);
} else {
// id value
options = convertTreeData(response.data);
ElMessage.success('树接口请求成功');
}
}
//
function convertTreeData(data: any[]): any[] {
return data.map((item) => ({
value: item.id.toString(), // id value
label: item.label,
children: item.children ? convertTreeData(item.children) : []
}));
}
let options: any[] = [];
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

@ -534,8 +534,7 @@ watch(
</script> </script>
<style scoped> <style scoped>
.cursor-remove { .cursor-remove {
cursor: cursor: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPgoJPGcgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS1kYXNoYXJyYXk9IjIyIiBzdHJva2UtZGFzaG9mZnNldD0iMjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIj4KCQk8cGF0aCBkPSJNMTkgNUw1IDE5Ij48YW5pbWF0ZSBmaWxsPSJmcmVlemUiIGF0dHJpYnV0ZU5hbWU9InN0cm9rZS1kYXNob2Zmc2V0IiBiZWdpbj0iMC4zcyIgZHVyPSIwLjNzIiB2YWx1ZXM9IjIyOzAiLz48L3BhdGg+CgkJPHBhdGggZD0iTTUgNUwxOSAxOSI+PGFuaW1hdGUgZmlsbD0iZnJlZXplIiBhdHRyaWJ1dGVOYW1lPSJzdHJva2UtZGFzaG9mZnNldCIgZHVyPSIwLjNzIiB2YWx1ZXM9IjIyOzAiLz48L3BhdGg+Cgk8L2c+Cjwvc3ZnPg==),
url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPgoJPGcgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS1kYXNoYXJyYXk9IjIyIiBzdHJva2UtZGFzaG9mZnNldD0iMjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIj4KCQk8cGF0aCBkPSJNMTkgNUw1IDE5Ij48YW5pbWF0ZSBmaWxsPSJmcmVlemUiIGF0dHJpYnV0ZU5hbWU9InN0cm9rZS1kYXNob2Zmc2V0IiBiZWdpbj0iMC4zcyIgZHVyPSIwLjNzIiB2YWx1ZXM9IjIyOzAiLz48L3BhdGg+CgkJPHBhdGggZD0iTTUgNUwxOSAxOSI+PGFuaW1hdGUgZmlsbD0iZnJlZXplIiBhdHRyaWJ1dGVOYW1lPSJzdHJva2UtZGFzaG9mZnNldCIgZHVyPSIwLjNzIiB2YWx1ZXM9IjIyOzAiLz48L3BhdGg+Cgk8L2c+Cjwvc3ZnPg==),
auto; auto;
} }
</style> </style>

@ -10,8 +10,7 @@ export type ILeftAsideConfigItemPublicPropsType =
| 'upload' | 'upload'
| 'inputSelectId' | 'inputSelectId'
| 'inputTypeTag' //inputTypeTag 必须和 inputSelectId 一起使用 | 'inputTypeTag' //inputTypeTag 必须和 inputSelectId 一起使用
| 'inputSelectImgId' | 'inputSelectImgId';
| 'map'; //使用这个类型 disabled必须为true(必须隐藏)
// 开放注册配置 // 开放注册配置
export type ILeftAsideConfigItemPublicProps = Record< export type ILeftAsideConfigItemPublicProps = Record<
string, string,

@ -1,190 +0,0 @@
<template>
<div class="container">
<!-- 排油注氮 -->
<!-- 3D 场景 -->
<div class="div3D" ref="div3D" v-show="show3D"></div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
// threejs
import {
AxesHelper,
Color,
PerspectiveCamera,
Scene,
WebGLRenderer,
EquirectangularReflectionMapping,
Group
} from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
const div3D = ref<HTMLDivElement>();
//
const scene = new Scene();
//
const show3D = ref(true);
//
const camera = new PerspectiveCamera(
25,
div3D.value?.clientWidth! / div3D.value?.clientHeight!,
0.05,
1000
); // 1
camera.position.set(0, 14, 13.5);
camera.lookAt(0, 0, 0);
scene.add(camera);
//
const render = new WebGLRenderer({ antialias: true }); // 齿
render.setClearColor(new Color('#131519'));
//
const controls = new OrbitControls(camera, render.domElement);
//
// controls.enableZoom = false;
// controls.autoRotate = false;
// controls.enablePan = false; //
controls.autoRotateSpeed = 1;
controls.dampingFactor = 0.2;
controls.rotateSpeed = 0.3; // 1.0
controls.enableDamping = true;
controls.enableRotate = true;
controls.minDistance = 1; //
// 4545
// 4545
controls.minPolarAngle = Math.PI / 4; // 45 (π/4)
controls.maxPolarAngle = (Math.PI * 3) / 4; // 45 (3π/4)
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
loader.setDRACOLoader(dracoLoader);
let meshArr: Group[] = [];
// F:\vue\workspace\maotu-webtopo\public\models\complexBuilding\complexBuilding.gltf
loader.load('/models/complexBuilding/complexBuilding.gltf', (gltf: any) => {
gltf.scene.position.y = -6;
scene.add(gltf.scene);
});
//
const rgbELoader = new RGBELoader().load(
'/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr',
(envMap: any) => {
envMap.mapping = EquirectangularReflectionMapping;
scene.environment = envMap;
}
);
//
// const axes = new AxesHelper(20);
// scene.add(axes);
//
function handleResize() {
if (!div3D.value) return;
const container = div3D.value;
const width = container.clientWidth;
const height = container.clientHeight;
//
camera.aspect = width / height;
camera.updateProjectionMatrix();
//
render.setSize(width, height);
}
function init() {
requestAnimationFrame(init);
controls.update();
render.render(scene, camera);
}
onMounted(() => {
//
handleResize();
//
init();
//
div3D.value?.appendChild(render.domElement);
//
const resizeObserver = new ResizeObserver(handleResize);
if (div3D.value) {
resizeObserver.observe(div3D.value);
}
// 便
(window as any)._resizeObserver = resizeObserver;
});
onUnmounted(() => {
//
if ((window as any)._resizeObserver) {
(window as any)._resizeObserver.disconnect();
delete (window as any)._resizeObserver;
}
});
</script>
<style scoped>
.container {
width: 100%;
height: 100%;
position: relative;
}
.div3D {
width: 100%;
height: 100%;
position: relative;
}
.principle-diagram {
position: absolute;
top: 10%;
right: 0;
width: 45%;
height: 45%;
z-index: 50;
display: flex;
justify-content: center;
align-items: center;
/* transition: all 0.3s ease; */
}
/* 只显示原理图时的样式 */
.principle-diagram.principle-only {
top: 0;
right: 0;
width: 100%;
height: 100%;
border-radius: 0;
box-shadow: none;
}
.principle-img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.control-buttons {
position: absolute;
top: 2%;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: row;
gap: 0.5%;
z-index: 100;
}
</style>

@ -1,190 +0,0 @@
<template>
<div class="container">
<!-- 排油注氮 -->
<!-- 3D 场景 -->
<div class="div3D" ref="div3D" v-show="show3D"></div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
// threejs
import {
AxesHelper,
Color,
PerspectiveCamera,
Scene,
WebGLRenderer,
EquirectangularReflectionMapping,
Group
} from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
const div3D = ref<HTMLDivElement>();
//
const scene = new Scene();
//
const show3D = ref(true);
//
const camera = new PerspectiveCamera(
25,
div3D.value?.clientWidth! / div3D.value?.clientHeight!,
0.05,
1000
); // 1
camera.position.set(10, 10, -35);
camera.lookAt(0, 0, 0);
scene.add(camera);
//
const render = new WebGLRenderer({ antialias: true }); // 齿
render.setClearColor(new Color('#131519'));
//
const controls = new OrbitControls(camera, render.domElement);
//
// controls.enableZoom = false;
// controls.autoRotate = false;
// controls.enablePan = false; //
controls.autoRotateSpeed = 1;
controls.dampingFactor = 0.2;
controls.rotateSpeed = 0.3; // 1.0
controls.enableDamping = true;
controls.enableRotate = true;
controls.minDistance = 1; //
// 4545
// 4545
controls.minPolarAngle = Math.PI / 4; // 45 (π/4)
controls.maxPolarAngle = (Math.PI * 3) / 4; // 45 (3π/4)
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
loader.setDRACOLoader(dracoLoader);
let meshArr: Group[] = [];
// F:\vue\workspace\maotu-webtopo\public\models\nitrogenInjection\nitrogenInjection.bin
loader.load('/models/nitrogenInjection/nitrogenInjection.gltf', (gltf: any) => {
gltf.scene.position.y = -6;
scene.add(gltf.scene);
});
//
const rgbELoader = new RGBELoader().load(
'/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr',
(envMap: any) => {
envMap.mapping = EquirectangularReflectionMapping;
scene.environment = envMap;
}
);
//
// const axes = new AxesHelper(20);
// scene.add(axes);
//
function handleResize() {
if (!div3D.value) return;
const container = div3D.value;
const width = container.clientWidth;
const height = container.clientHeight;
//
camera.aspect = width / height;
camera.updateProjectionMatrix();
//
render.setSize(width, height);
}
function init() {
requestAnimationFrame(init);
controls.update();
render.render(scene, camera);
}
onMounted(() => {
//
handleResize();
//
init();
//
div3D.value?.appendChild(render.domElement);
//
const resizeObserver = new ResizeObserver(handleResize);
if (div3D.value) {
resizeObserver.observe(div3D.value);
}
// 便
(window as any)._resizeObserver = resizeObserver;
});
onUnmounted(() => {
//
if ((window as any)._resizeObserver) {
(window as any)._resizeObserver.disconnect();
delete (window as any)._resizeObserver;
}
});
</script>
<style scoped>
.container {
width: 100%;
height: 100%;
position: relative;
}
.div3D {
width: 100%;
height: 100%;
position: relative;
}
.principle-diagram {
position: absolute;
top: 10%;
right: 0;
width: 45%;
height: 45%;
z-index: 50;
display: flex;
justify-content: center;
align-items: center;
/* transition: all 0.3s ease; */
}
/* 只显示原理图时的样式 */
.principle-diagram.principle-only {
top: 0;
right: 0;
width: 100%;
height: 100%;
border-radius: 0;
box-shadow: none;
}
.principle-img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.control-buttons {
position: absolute;
top: 2%;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: row;
gap: 0.5%;
z-index: 100;
}
</style>

@ -13,7 +13,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'; import { ref, onMounted, onUnmounted } from 'vue';
// threejs //threejs
import { import {
AxesHelper, AxesHelper,
Color, Color,
@ -85,53 +85,45 @@ const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader(); const dracoLoader = new DRACOLoader();
loader.setDRACOLoader(dracoLoader); loader.setDRACOLoader(dracoLoader);
let meshArr: Group[] = []; let meshArr: Group[] = [];
// public\models\nitrogenInjection\nitrogenInjection.gltf
loader.load('/models/substation/substation.gltf', (gltf: any) => { loader.load('/models/substation/substation.gltf', (gltf: any) => {
//
loadedModel = gltf.scene;
scene.add(gltf.scene); scene.add(gltf.scene);
const loadTime = Date.now() - startTime; const loadTime = Date.now() - startTime;
// //
// controls.update(); controls.update();
render.render(scene, camera); render.render(scene, camera);
console.log(`大场景模型已加载并显示,总耗时:${loadTime}ms`); console.log(`大场景模型已加载并显示,总耗时:${loadTime}ms`);
loading.value = false; loading.value = false;
}); });
// // //
// const ambientLight = new AmbientLight('#ffffff', 1.2); // 0.6 1.0 const ambientLight = new AmbientLight('#ffffff', 1.2); // 0.6 1.0
// scene.add(ambientLight); scene.add(ambientLight);
// // //
// const directionalLight = new DirectionalLight('#ffffff', 1.4); // 0.2 0.8 const directionalLight = new DirectionalLight('#ffffff', 1.4); // 0.2 0.8
// scene.add(directionalLight); scene.add(directionalLight);
// directionalLight.position.set(20, 20, 10); directionalLight.position.set(20, 20, 10);
// // // // //
// const pointLight = new PointLight('#ffffff', 1.4, 1800); // 0.5 1.0 const pointLight = new PointLight('#ffffff', 1.4, 1800); // 0.5 1.0
// scene.add(pointLight); scene.add(pointLight);
// pointLight.position.set(0, 40, 0); pointLight.position.set(0, 40, 0);
// 便 // //
const rgbELoader = new RGBELoader().load( // const rgbELoader = new RGBELoader().load(
'/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr', // '/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr',
(envMap: any) => { // (envMap: any) => {
envMap.mapping = EquirectangularReflectionMapping; // envMap.mapping = EquirectangularReflectionMapping;
scene.environment = envMap; // scene.environment = envMap;
envMapTexture = envMap; // // }
} // );
);
// //
const timeline1 = gsap.timeline(); const timeline1 = gsap.timeline();
const timeline2 = gsap.timeline(); const timeline2 = gsap.timeline();
// 便
let loadedModel: any = null;
let envMapTexture: any = null;
// //
function tranlate(position: Vector3, target: Vector3) { function tranlate(position: Vector3, target: Vector3) {
timeline1.to(camera.position, { timeline1.to(camera.position, {
@ -198,98 +190,11 @@ onMounted(() => {
}); });
onUnmounted(() => { onUnmounted(() => {
console.log('开始清理 Three.js 资源...'); //
// 1.
// requestAnimationFrame
// 2. ResizeObserver
if ((window as any)._resizeObserver) { if ((window as any)._resizeObserver) {
(window as any)._resizeObserver.disconnect(); (window as any)._resizeObserver.disconnect();
delete (window as any)._resizeObserver; delete (window as any)._resizeObserver;
} }
// 3. GSAP
timeline1.pause();
timeline1.clear();
timeline2.pause();
timeline2.clear();
gsap.globalTimeline.clear();
// 4. DOM
if (div3D.value && render.domElement.parentNode === div3D.value) {
div3D.value.removeChild(render.domElement);
}
// 5.
controls.dispose();
// 6.
if (loadedModel) {
loadedModel.traverse((child: any) => {
if (child.isMesh) {
//
if (child.geometry) {
child.geometry.dispose();
}
//
if (child.material) {
const materials = Array.isArray(child.material) ? child.material : [child.material];
materials.forEach((material: any) => {
//
[
'map',
'normalMap',
'roughnessMap',
'metalnessMap',
'emissiveMap',
'aoMap',
'displacementMap'
].forEach((key) => {
if (material[key]) {
material[key].dispose();
}
});
//
material.dispose();
});
}
}
});
//
scene.remove(loadedModel);
}
// 7.
if (envMapTexture) {
envMapTexture.dispose();
}
// 8.
scene.traverse((child: any) => {
if (child.isLight) {
child.dispose();
}
});
// 9.
while (scene.children.length > 0) {
scene.remove(scene.children[0]);
}
// 10.
render.dispose();
render.forceContextLoss();
render.domElement.remove();
// 11.
scene.clear();
console.log('Three.js 资源清理完成');
}); });
</script> </script>
@ -309,7 +214,6 @@ onUnmounted(() => {
top: 50%; top: 50%;
left: 2%; left: 2%;
transform: translateY(-50%); /* 垂直居中 */ transform: translateY(-50%); /* 垂直居中 */
transform: translateZ(0);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 20px; gap: 20px;

@ -77,18 +77,15 @@ scene.add(camera);
// //
const render = new WebGLRenderer({ const render = new WebGLRenderer({
antialias: true, // 齿 antialias: false, // 齿
powerPreference: 'high-performance', powerPreference: 'high-performance', // 使GPU
stencil: false, stencil: false, //
depth: true, depth: true,
logarithmicDepthBuffer: true, logarithmicDepthBuffer: true //
precision: 'mediump' // 使
}); });
render.setClearColor(new Color('#131519')); render.setClearColor(new Color('#131519'));
render.setPixelRatio(Math.min(window.devicePixelRatio, 2)); //
// //
render.shadowMap.enabled = false; render.shadowMap.enabled = false; //
render.shadowMap.autoUpdate = false; //
// //
const controls = new OrbitControls(camera, render.domElement); const controls = new OrbitControls(camera, render.domElement);
@ -97,14 +94,15 @@ const controls = new OrbitControls(camera, render.domElement);
// controls.autoRotate = false; // controls.autoRotate = false;
// controls.enablePan = false; // // controls.enablePan = false; //
controls.autoRotateSpeed = 1; controls.autoRotateSpeed = 1;
controls.dampingFactor = 0.05; // controls.dampingFactor = 0.2;
controls.rotateSpeed = 0.5; // controls.rotateSpeed = 0.3; // 1.0
controls.enableDamping = false; // controls.enableDamping = true;
controls.enableRotate = true; controls.enableRotate = true;
controls.minDistance = 1; controls.minDistance = 1; //
// // 4545
controls.minPolarAngle = Math.PI / 4; // 4545
controls.maxPolarAngle = (Math.PI * 3) / 4; controls.minPolarAngle = Math.PI / 4; // 45 (π/4)
controls.maxPolarAngle = (Math.PI * 3) / 4; // 45 (3π/4)
const loader = new GLTFLoader(); const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader(); const dracoLoader = new DRACOLoader();
@ -139,29 +137,16 @@ loader.load(
async (gltf: any) => { async (gltf: any) => {
console.log('文件下载完成,开始解析模型...'); console.log('文件下载完成,开始解析模型...');
// //
const mergedMeshes: any[] = [];
gltf.scene.traverse((child: any) => { gltf.scene.traverse((child: any) => {
if (child.isMesh) { if (child.isMesh) {
// //
child.frustumCulled = true; child.frustumCulled = true; //
if (child.material) { if (child.material) {
// //
child.material.side = 0; child.material.side = 0; // FrontSide -
child.material.needsUpdate = true;
//
if (child.material.map) {
child.material.map.minFilter = THREE.LinearMipMapLinearFilter;
child.material.map.magFilter = THREE.LinearFilter;
} }
} }
// 使
mergedMeshes.push(child);
}
}); });
// //
@ -175,8 +160,7 @@ loader.load(
} }
const loadTime = Date.now() - startTime; const loadTime = Date.now() - startTime;
console.log(`大场景模型完全加载并显示,总耗时:${loadTime}ms`); console.log(`大场景模型完全加载并显示,总耗时: ${loadTime}ms`);
console.log(`模型网格数量:${mergedMeshes.length}`);
}, },
// //
(xhr) => { (xhr) => {
@ -204,17 +188,14 @@ nextTick(() => {
} }
}); });
// //
setTimeout(() => { const rgbELoader = new RGBELoader().load(
const rgbELoader = new RGBELoader().load(
'/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr', '/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr',
(envMap: any) => { (envMap: any) => {
envMap.mapping = EquirectangularReflectionMapping; envMap.mapping = EquirectangularReflectionMapping;
scene.environment = envMap; scene.environment = envMap;
console.log('环境贴图加载完成');
} }
); );
}, 500); // 500ms
// //
const timeline1 = gsap.timeline(); const timeline1 = gsap.timeline();
@ -261,8 +242,7 @@ function handleResize() {
function init() { function init() {
requestAnimationFrame(init); requestAnimationFrame(init);
// controls.update();
// controls.update(); //
render.render(scene, camera); render.render(scene, camera);
} }

@ -1,230 +0,0 @@
<template>
<div class="container">
<!-- 3D 场景 -->
<div class="div3D" ref="div3D" v-show="show3D"></div>
<!-- 原理图 -->
<div
class="principle-diagram"
v-if="showPrinciple"
:class="{ 'principle-only': showPrincipleOnly }"
>
<img src="/models/transformer/yuanli.png" alt="原理图" class="principle-img" />
</div>
</div>
<!-- 固定位置的控制按钮 -->
<div class="control-buttons">
<el-button type="primary" @click="toggle3D"></el-button>
<el-button type="primary" @click="togglePrinciple"></el-button>
<el-button type="primary" @click="showBoth"></el-button>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
// threejs
import {
AxesHelper,
Color,
PerspectiveCamera,
Scene,
WebGLRenderer,
EquirectangularReflectionMapping,
Group
} from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
const div3D = ref<HTMLDivElement>();
//
const scene = new Scene();
//
const show3D = ref(true);
const showPrinciple = ref(false);
const showPrincipleOnly = ref(false); //
//
const toggle3D = () => {
console.log('点击三维图切换');
show3D.value = true;
showPrinciple.value = false;
showPrincipleOnly.value = false;
console.log('show3D:', show3D.value, 'showPrinciple:', showPrinciple.value);
};
const togglePrinciple = () => {
console.log('点击原理图切换');
showPrinciple.value = true;
show3D.value = false;
showPrincipleOnly.value = true;
console.log('show3D:', show3D.value, 'showPrinciple:', showPrinciple.value);
};
const showBoth = () => {
show3D.value = true;
showPrinciple.value = true;
showPrincipleOnly.value = false;
};
//
const camera = new PerspectiveCamera(
25,
div3D.value?.clientWidth! / div3D.value?.clientHeight!,
0.05,
1000
); // 1
camera.position.set(35, 10, 20);
camera.lookAt(0, 0, 0);
scene.add(camera);
//
const render = new WebGLRenderer({ antialias: true }); // 齿
render.setClearColor(new Color('#131519'));
//
const controls = new OrbitControls(camera, render.domElement);
//
// controls.enableZoom = false;
// controls.autoRotate = false;
// controls.enablePan = false; //
controls.autoRotateSpeed = 1;
controls.dampingFactor = 0.2;
controls.rotateSpeed = 0.3; // 1.0
controls.enableDamping = true;
controls.enableRotate = true;
controls.minDistance = 1; //
// 4545
// 4545
controls.minPolarAngle = Math.PI / 4; // 45 (π/4)
controls.maxPolarAngle = (Math.PI * 3) / 4; // 45 (3π/4)
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
loader.setDRACOLoader(dracoLoader);
let meshArr: Group[] = [];
loader.load('/models/transformer/transformer.gltf', (gltf: any) => {
gltf.scene.position.y = -3;
scene.add(gltf.scene);
});
//
const rgbELoader = new RGBELoader().load(
'/models/texture/Alex_Hart-Nature_Lab_Bones_2k.hdr',
(envMap: any) => {
envMap.mapping = EquirectangularReflectionMapping;
scene.environment = envMap;
}
);
//
// const axes = new AxesHelper(20);
// scene.add(axes);
//
function handleResize() {
if (!div3D.value) return;
const container = div3D.value;
const width = container.clientWidth;
const height = container.clientHeight;
//
camera.aspect = width / height;
camera.updateProjectionMatrix();
//
render.setSize(width, height);
}
function init() {
requestAnimationFrame(init);
controls.update();
render.render(scene, camera);
}
onMounted(() => {
//
handleResize();
//
init();
//
div3D.value?.appendChild(render.domElement);
//
const resizeObserver = new ResizeObserver(handleResize);
if (div3D.value) {
resizeObserver.observe(div3D.value);
}
// 便
(window as any)._resizeObserver = resizeObserver;
});
onUnmounted(() => {
//
if ((window as any)._resizeObserver) {
(window as any)._resizeObserver.disconnect();
delete (window as any)._resizeObserver;
}
});
</script>
<style scoped>
.container {
width: 100%;
height: 100%;
position: relative;
}
.div3D {
width: 100%;
height: 100%;
position: relative;
}
.principle-diagram {
position: absolute;
top: 10%;
right: 0;
width: 45%;
height: 45%;
z-index: 50;
display: flex;
justify-content: center;
align-items: center;
/* transition: all 0.3s ease; */
}
/* 只显示原理图时的样式 */
.principle-diagram.principle-only {
top: 0;
right: 0;
width: 100%;
height: 100%;
border-radius: 0;
box-shadow: none;
}
.principle-img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.control-buttons {
position: absolute;
top: 2%;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: row;
gap: 0.5%;
z-index: 100;
}
</style>

@ -1,77 +0,0 @@
<template>
<div class="vue-characters"></div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import { useNodeByModelsStore } from '@/components/mt-edit/store/nodeByModels';
const nodeByModelsStore = useNodeByModelsStore();
const double = ref(-1);
const boolean = ref(false);
const alarms = ref(false);
const text = ref('正常');
const props = defineProps({
moduleType: {
type: String,
default: '--'
},
moduleId: {
type: String,
default: '--'
},
definitionItemJson: {
type: Object,
default: () => ({})
},
location: {
type: String,
default: 'bottom'
}
});
const getSting = (data: any) => {};
function getModuleById(moduleId: string) {
const globalData = (window as any).globalData;
if (!globalData || moduleId == undefined || moduleId == '' || props.moduleId == '--') {
console.warn('globalData 未初始化');
return null;
}
// 访
if (globalData instanceof Map) {
// Map
return globalData.get(moduleId);
} else {
//
return globalData[moduleId];
}
}
function loadingModuleById() {
let module = getModuleById(props.moduleId);
if (props.moduleId !== '' && props.moduleId !== undefined && props.moduleId !== '--' && module) {
if (module) {
console.log('当前的module', module);
double.value = module.double;
boolean.value = module.double;
getSting({
double: double.value,
boolean: boolean.value,
alarms: alarms.value,
...module
});
}
}
}
watch(
() => props.moduleId,
(newVal, oldVal) => {
loadingModuleById();
nodeByModelsStore.change(newVal, oldVal, props.definitionItemJson.id);
}
);
</script>
<style scoped>
.vue-characters {
width: 100%;
height: 100%;
}
</style>

@ -1,305 +0,0 @@
<template>
<div class="table-container">
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">运行信息</h2>
<div class="table-wrapper" v-loading="tableArr.length === 0">
<!-- :span-method="objectSpanMethods" -->
<el-table
:data="tableArr"
style="width: 100%"
:span-method="objectSpanMethods"
class="full-height-table"
>
<el-table-column prop="floorArea" label="所在区域" />
<el-table-column prop="equipmentPlace" label="配置地点" />
<el-table-column prop="equipmentName" label="设备名称" />
<el-table-column prop="equipmentSpecification" label="规格型号" />
<el-table-column prop="equipmentNumber" label="编号" />
<el-table-column prop="vender" label="设备厂家" />
</el-table>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import type { TableColumnCtx } from 'element-plus';
import { computed, onMounted, onUnmounted, ref, watch, reactive } from 'vue';
import emitter from '@/utils/emitter';
import { ro } from 'element-plus/es/locales.mjs';
const props = defineProps({
fontFamily: {
type: String,
default: '黑体'
},
fontSize: {
type: Number,
default: 12
},
testColor: {
type: String,
default: '#ffffff'
},
definitionItemJson: {
type: Object,
default: () => ({})
}
});
//
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {}
});
interface Equipment {
equipmentPlace: string; //
equipmentName: string; //
equipmentSpecification: string; //
equipmentNumber: string; //
vender: string; //
}
interface FloorObj {
floorArea: string; //
equipments: Equipment[];
}
let tableArr = ref<any[]>([]);
let spanMap = ref<Map<string, number>>(new Map<string, number>());
//
async function dataInit() {
floorData.forEach((floor) => {
floor.equipments.forEach((equipment) => {
tableArr.value.push({
floorArea: floor.floorArea,
equipmentPlace: equipment.equipmentPlace,
equipmentName: equipment.equipmentName,
equipmentSpecification: equipment.equipmentSpecification,
equipmentNumber: equipment.equipmentNumber,
vender: equipment.vender
});
});
if (!spanMap.value.has(floor.floorArea))
spanMap.value.set(floor.floorArea, floor.equipments.length);
});
console.log('spanMap', spanMap.value);
}
//
let floorStartIndex = ref<Map<string, number>>(new Map<string, number>());
//
function objectSpanMethods({ rowIndex, columnIndex }: any) {
if (columnIndex === 0) {
// ""
const floorArea = tableArr.value[rowIndex].floorArea;
//
if (!floorStartIndex.value.has(floorArea)) {
floorStartIndex.value.set(floorArea, rowIndex);
}
//
if (floorStartIndex.value.get(floorArea) === rowIndex) {
return [spanMap.value.get(floorArea) || 1, 1];
} else {
//
return [0, 0];
}
}
return [1, 1];
}
// onMounted
onMounted(async () => {
await dataInit();
});
onUnmounted(() => {
emitter.off('binding-data-update');
});
//
const floorData: FloorObj[] = [
{
floorArea: '生产综合楼1楼',
equipments: [
{
equipmentPlace: '蓄电池室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '220kV保护室',
equipmentName: '氧化碳灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '380V配电室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '35kV高压室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '2号接地变室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '110kV电缆室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '2号站用变室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '生产综合楼1楼走廊',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
}
]
},
{
floorArea: '生产综合楼2楼',
equipments: [
{
equipmentPlace: '110kVGIS室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '110kV保护室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '主控制室',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
},
{
equipmentPlace: '生产综合楼2楼',
equipmentName: '干粉灭火器',
equipmentSpecification: 'MFZ4',
equipmentNumber: '1、2号',
vender: '天河消防厂'
}
]
}
];
</script>
<style scoped>
.table-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.full-height-table {
flex: 1;
height: 100%;
}
.full-height-table :deep(.el-table__body-wrapper) {
flex: 1;
overflow-y: auto;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.operation-btn {
width: 60px;
min-width: 50px;
padding: 8px 12px;
height: 30px;
}
/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
font-size: 13px;
font-weight: bold;
}
/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
}
/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
</style>

@ -1,174 +0,0 @@
<template>
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">操作流程</h2>
<div class="cardBody">
<el-steps
style="max-width: 100%"
:active="4"
align-center
direction="vertical"
finish-status="success"
>
<el-step description="变压器故障起火" />
<el-step>
<template #description>
保护动作
<div class="parallel-box">
<el-tag type="primary">重瓦斯动作</el-tag>
<el-tag type="success">温控器动作</el-tag>
<el-tag type="primary">压力释放动作</el-tag>
<el-tag type="primary">火灾探测器动作</el-tag>
</div>
</template>
</el-step>
<el-step description="排油阀开启" />
<el-step description="注氮阀开启" />
<el-step description="注氮阀关闭" />
<el-step description="注氮 10 分钟以上达到防爆灭火效果" />
</el-steps>
</div>
<div class="button-group">
<el-button type="primary" size="small">手动启动</el-button>
<el-button type="primary" size="small">手动停止</el-button>
<el-button type="primary" size="small">紧急停止</el-button>
</div>
</el-card>
</template>
<script setup lang="ts"></script>
<style scoped>
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.cardBody {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
overflow-y: auto;
}
/* 并行步骤框 */
.parallel-box {
display: flex;
flex-direction: column;
gap: 15px;
margin-top: 15px;
margin-bottom: 15px;
}
/* el-tag 样式调整 */
.parallel-box :deep(.el-tag) {
text-align: left;
padding: 8px 16px;
width: 60%;
}
/* 并行步骤样式 */
.parallel-steps {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 10px;
padding: 10px;
background: rgba(255, 255, 255, 0.05);
border-radius: 6px;
}
/* 按钮组样式 */
.button-group {
display: flex;
gap: 1%;
justify-content: center;
margin-top: 15px;
}
.step-item {
padding: 8px 12px;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: #ffffff;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
text-align: center;
}
.step-title {
font-weight: bold;
font-size: 14px;
}
/* 操作区域 */
.operation-area {
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 8px;
padding: 15px;
background: rgba(255, 255, 255, 0.05);
margin-top: 20px;
}
.area-title {
margin: 0 0 15px 0;
font-size: 14px;
font-weight: bold;
color: #4facfe;
text-align: center;
}
.buttons {
display: flex;
gap: 15px;
justify-content: center;
margin-bottom: 15px;
}
.notes {
display: flex;
justify-content: space-between;
gap: 20px;
}
.note {
margin: 0;
font-size: 11px;
color: #f5576c;
line-height: 1.6;
flex: 1;
}
.note-label {
font-weight: bold;
color: #f093fb;
}
/* 响应式 */
@media (max-width: 768px) {
.notes {
flex-direction: column;
}
}
</style>

@ -1,305 +0,0 @@
<template>
<div class="table-container">
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">运行信息</h2>
<div class="table-wrapper" v-loading="tableArr.length === 0">
<!-- :span-method="objectSpanMethods" -->
<el-table
:data="tableArr"
style="width: 100%"
:span-method="objectSpanMethods"
class="full-height-table"
>
<el-table-column prop="floorArea" label="所在区域" />
<el-table-column prop="equipmentPlace" label="设备地点" />
<el-table-column prop="fireproofDoor" label="防火门" />
<el-table-column prop="indicate" label="疏散指示" />
<el-table-column prop="illumination" label="应急照明" />
<el-table-column prop="control" label="应急照明控制" />
</el-table>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import type { TableColumnCtx } from 'element-plus';
import { computed, onMounted, onUnmounted, ref, watch, reactive } from 'vue';
import emitter from '@/utils/emitter';
import { ro } from 'element-plus/es/locales.mjs';
const props = defineProps({
fontFamily: {
type: String,
default: '黑体'
},
fontSize: {
type: Number,
default: 12
},
testColor: {
type: String,
default: '#ffffff'
},
definitionItemJson: {
type: Object,
default: () => ({})
}
});
//
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {}
});
interface Equipment {
equipmentPlace: string; //
fireproofDoor: string; //
indicate: string; //
illumination: string; //
control: boolean; // true false
}
interface FloorObj {
floorArea: string; //
equipments: Equipment[];
}
let tableArr = ref<any[]>([]);
let spanMap = ref<Map<string, number>>(new Map<string, number>());
//
async function dataInit() {
floorData.forEach((floor) => {
floor.equipments.forEach((equipment) => {
tableArr.value.push({
floorArea: floor.floorArea,
equipmentPlace: equipment.equipmentPlace,
fireproofDoor: equipment.fireproofDoor,
indicate: equipment.indicate,
illumination: equipment.illumination,
control: equipment.control
});
});
if (!spanMap.value.has(floor.floorArea))
spanMap.value.set(floor.floorArea, floor.equipments.length);
});
console.log('spanMap', spanMap.value);
}
//
let floorStartIndex = ref<Map<string, number>>(new Map<string, number>());
//
function objectSpanMethods({ rowIndex, columnIndex }: any) {
if (columnIndex === 0) {
// ""
const floorArea = tableArr.value[rowIndex].floorArea;
//
if (!floorStartIndex.value.has(floorArea)) {
floorStartIndex.value.set(floorArea, rowIndex);
}
//
if (floorStartIndex.value.get(floorArea) === rowIndex) {
return [spanMap.value.get(floorArea) || 1, 1];
} else {
//
return [0, 0];
}
}
return [1, 1];
}
// onMounted
onMounted(async () => {
await dataInit();
});
onUnmounted(() => {
emitter.off('binding-data-update');
});
//
const floorData: FloorObj[] = [
{
floorArea: '生产综合楼1楼',
equipments: [
{
equipmentPlace: '蓄电池室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '220kV保护室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '380V配电室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '110kV电缆室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '220kV保护室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '380V配电室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '35kV高压室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '2号接地变室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '2号站用变室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
}
]
},
{
floorArea: '生产综合楼2楼',
equipments: [
{
equipmentPlace: '110kVGIS室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '110kV保护室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
},
{
equipmentPlace: '主控制室',
fireproofDoor: '关闭',
indicate: '亮',
illumination: '不亮',
control: true
}
]
}
];
</script>
<style scoped>
.table-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.full-height-table {
flex: 1;
height: 100%;
}
.full-height-table :deep(.el-table__body-wrapper) {
flex: 1;
overflow-y: auto;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.operation-btn {
width: 60px;
min-width: 50px;
padding: 8px 12px;
height: 30px;
}
/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
font-size: 13px;
font-weight: bold;
}
/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
}
/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
</style>

@ -37,12 +37,17 @@ const props = defineProps({
} }
}); });
onUnmounted(() => { onUnmounted(() => {
console.log('组件卸载'); console.log('组件卸载');
}); });
// //
onMounted(() => {}); onMounted(() => {
});
</script> </script>
<style scoped> <style scoped>

@ -1,138 +0,0 @@
<template>
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">火灾探测器基本信息</h2>
<div class="cardBody">
<el-row :gutter="20" style="height: 100%">
<el-col :span="12" class="image-col">
<img src="/imgs/xianqvan.png" style="width: 100%; height: 100%" />
</el-col>
<el-col :span="12">
<el-row class="info-row">
<el-col :span="10" class="info-label">厂家</el-col>
<el-col :span="12"><el-tag size="small">海湾公司</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">型号</el-col>
<el-col :span="12"><el-tag size="small">CTI-155X</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">投运日期</el-col>
<el-col :span="12"><el-tag size="small">2012-08-08</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">使用环境</el-col>
<el-col :span="12"><el-tag size="small">温度 -5~45</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">火灾响应规模</el-col>
<el-col :span="12"><el-tag size="small">10mm</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">测量温度精度</el-col>
<el-col :span="12"><el-tag size="small">1</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">定位精度</el-col>
<el-col :span="12"><el-tag size="small">1 </el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">类型</el-col>
<el-col :span="12"><el-tag size="small">定温式</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">报警温度</el-col>
<el-col :span="12"><el-tag size="small">85</el-tag></el-col>
</el-row>
<el-row class="info-row">
<el-col :span="10" class="info-label">标准</el-col>
<el-col :span="12"><el-tag size="small">GB16280-2014</el-tag></el-col>
</el-row>
</el-col>
</el-row>
</div>
</el-card>
</template>
<script setup lang="ts"></script>
<style scoped>
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.cardBody {
width: 100%;
height: 100%;
}
/* el-row 高度继承 */
.cardBody :deep(.el-row) {
/* height: 100%; */
}
/* el-col 高度继承 */
.cardBody :deep(.el-col) {
/* height: 100%;
display: flex;
align-items: stretch; */
}
/* 图片列样式 */
.image-col {
height: 100%;
display: flex;
}
/* 探测器图片样式 */
.detector-image {
width: 100%;
height: 100%;
object-fit: contain;
}
/* 信息行样式 */
.info-row {
margin-bottom: 2%;
}
/* 标签样式 */
.info-label {
font-size: 12px;
color: #ffffff;
}
/* el-tag 样式 */
.info-row :deep(.el-tag) {
font-size: 11px;
}
</style>

@ -1,289 +0,0 @@
<template>
<!-- 四遥遥测 -->
<button @click="console.log('data:', nodeByModelsStore.nodeMap)">点击</button>
<el-row :gutter="20" width="100%">
<el-col :span="24" justify="center" align="middle">
<el-tag :type="color" effect="plain" style="width: 100%">
<div style="display: flex; justify-content: space-around; align-items: center; width: 100%">
<el-divider direction="vertical"></el-divider>
<div v-if="showStart">
{{ nodeStatus }}
<el-divider direction="vertical"></el-divider>
</div>
<div v-if="showModel">
{{ nodeModel }}
<el-divider direction="vertical"></el-divider>
</div>
<div v-if="showVal">
{{ nodeValue }}
<el-divider direction="vertical"></el-divider>
</div>
</div>
</el-tag>
</el-col>
</el-row>
<el-row :gutter="20" v-if="showText">
<el-col :span="24" justify="center" align="middle"
><el-tag type="primary">{{ modeName }}</el-tag></el-col
>
</el-row>
</template>
<script lang="ts" setup>
import { onMounted, ref, computed, onUnmounted, watch } from 'vue';
import { useNodeByModelsStore } from '@/components/mt-edit/store/nodeByModels';
import emitter from '@/utils/emitter';
// F:\vue\workspace\maotu-webtopo\src\utils\config.ts
import { Rec, getIndex, getNodeStatus, getNodeColor } from '@/utils/config';
const nodeByModelsStore = useNodeByModelsStore();
onMounted(() => {
loadingModuleById();
saveodeByModels();
});
onUnmounted(() => {
console.log('组件卸载');
deleteByModels();
emitter.off(props.definitionItemJson.id);
});
const props = defineProps({
moduleType: {
type: String,
default: '--'
},
moduleId: {
type: String,
default: '--'
},
definitionItemJson: {
type: Object,
default: () => ({})
},
showStart: {
type: Boolean,
default: false
},
showModel: {
type: Boolean,
default: true
},
showVal: {
type: Boolean,
default: false
},
showText: {
type: Boolean,
default: false
}
});
console.log('itemjson:', props.definitionItemJson.id);
function saveodeByModels() {
if (props.moduleId == '' || props.moduleId == undefined || props.moduleId == '--') return;
nodeByModelsStore.saveOrUpdate(props.moduleId, props.definitionItemJson.id);
}
function deleteByModels() {
if (props.moduleId == '' || props.moduleId == undefined || props.moduleId == '--') return;
nodeByModelsStore.delete(props.moduleId, props.definitionItemJson.id);
}
watch(
() => props.moduleId,
(newVal, oldVal) => {
loadingModuleById();
nodeByModelsStore.change(newVal, oldVal, props.definitionItemJson.id);
}
);
emitter.on(props.definitionItemJson.id, (value) => {
console.log('触发事件', value);
loadingModuleById();
});
let moduleUnit = ref<string>();
let modeName = ref<string>();
let percentage = ref<number>();
let color = ref<string>('info');
let nodeStatus = ref<string>('未知状态');
let nodeModel = ref<string>('无模式');
let nodeValue = ref<string>('--');
function getModuleById(moduleId: string) {
const globalData = (window as any).globalData;
if (!globalData || moduleId == undefined || moduleId == '' || props.moduleId == '--') {
console.warn('globalData 未初始化');
return null;
}
return globalData.get(moduleId);
}
function loadingModuleById() {
// 使访 globalData
let module = getModuleById(props.moduleId);
if (props.moduleId !== '' && props.moduleId !== undefined && props.moduleId !== '--' && module) {
if (module) {
console.log('dddd');
modeName.value = module.node.name;
percentage.value = module.double;
moduleUnit.value = module.node.unit;
color.value = getNodeColor(module.sig);
nodeStatus.value = getNodeStatus(module.sig);
nodeModel.value = computedNodeModel();
nodeValue.value = computedVal.value;
}
}
}
function computedNodeModel(): string {
if (props.moduleId == '' || props.moduleId == undefined || props.moduleId == '--') return '--';
let runTimeNode = getModuleById(props.moduleId);
if (!runTimeNode) return '--';
//
if (runTimeNode.node.etype == 0 || runTimeNode.node.etype == 2) {
return '无模式';
}
console.log('runTimeNode.node.etype', runTimeNode.node.etype);
console.log('runTimeNode.valInt', runTimeNode.valInt);
console.log('getIndex(runTimeNode.bType)', getIndex(runTimeNode.bType));
let val = Rec.EnumTypeValFun![runTimeNode.node.etype](
runTimeNode.valInt,
getIndex(runTimeNode.bType)
);
return val;
}
//
let computedModel = computed({
//
get() {
if (props.moduleId == '' || props.moduleId == undefined || props.moduleId == '--') return '--';
let runTimeNode = getModuleById(props.moduleId);
if (!runTimeNode) return '--';
//
if (runTimeNode.node.etype == 0 || runTimeNode.node.etype == 2) {
return '无模式';
}
console.log('runTimeNode.node.etype', runTimeNode.node.etype);
console.log('runTimeNode.valInt', runTimeNode.valInt);
console.log('getIndex(runTimeNode.bType)', getIndex(runTimeNode.bType));
let val = Rec.EnumTypeValFun![runTimeNode.node.etype](
runTimeNode.valInt,
getIndex(runTimeNode.bType)
);
return val;
},
//
set() {}
});
//
let computedStatus = computed({
//
get() {
if (props.moduleId == '' || props.moduleId == undefined || props.moduleId == '--')
return '未知状态';
let runTimeNode = getModuleById(props.moduleId);
if (!runTimeNode) return '未知状态';
let val = getNodeStatus(runTimeNode.sig);
return val;
},
//
set() {}
});
//
let computedVal = computed({
//
get() {
if (percentage.value == undefined && moduleUnit.value == undefined) return '--';
//
const formattedValue =
percentage.value != null && !Number.isInteger(percentage.value)
? percentage.value.toFixed(2)
: (percentage.value?.toString() ?? '--');
return formattedValue + '' + moduleUnit.value;
},
//
set() {}
});
function test() {
console.log(getModuleById(props.moduleId));
}
const customFormat = () => {
//
if (percentage.value == undefined && moduleUnit.value == undefined) return '--';
return percentage.value + '' + moduleUnit.value;
};
</script>
<style scoped>
/* 设置固定宽度和文本省略 */
.ellipsis-tag {
width: 65px; /* 设置固定宽度 */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
align-items: center; /* 水平居中 */
}
.flex-center {
display: flex;
flex-direction: column; /* 垂直排列 */
justify-content: center; /* 垂直居中 */
align-items: center; /* 水平居中 */
}
.el-statistic {
/* 控制文字大小 */
--el-statistic-content-font-size: 16px;
}
.elColInfo {
text-align: center;
}
:deep(.el-progress__text) {
/* 控制文字大小 */
font-size: 16px !important;
}
.demo-progress .el-progress--line {
margin-bottom: 15px;
max-width: 500px;
}
.demo-progress .el-progress--circle {
margin-right: 15px;
}
.fontStyle {
color: rgb(51, 126, 204);
}
h3 {
margin: 0;
padding: 0;
text-align: center;
/* padding-top: 5px;
padding-bottom: 5px; */
}
.demo-radius .radius {
height: 28px;
min-width: 66px;
width: fit-content;
border: 2px solid rgba(51, 125, 204, 0.205);
border-radius: 0;
padding: 0 8px;
box-sizing: border-box;
}
</style>

@ -1,225 +0,0 @@
<template>
<div class="table-container">
<!-- 2号主变 -->
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">消火栓信息</h2>
<div class="table-wrapper" v-loading="arr.length === 0">
<el-table
:data="arr"
style="width: 100%"
class="full-height-table"
@cell-click="handleCellClick"
>
<el-table-column prop="equipmentName" label="设备名称" />
<el-table-column prop="equipmentModel" label="规格型号" />
<el-table-column prop="equipmentPlace" label="设备位置" />
<el-table-column prop="manufacturers" label="厂家" />
</el-table>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, onUnmounted } from 'vue';
import emitter from '@/utils/emitter';
//
/// <reference path="../../../global.d.ts" />
function handleCellClick(obj: any) {
console.log('点击:', obj);
emitter.emit('binding-obj-facility-move', obj.id);
}
emitter.on('binding-data-update', () => {
console.log('@@binding-data-update');
dataInit();
});
const props = defineProps({
fontFamily: {
type: String,
default: '黑体'
},
fontSize: {
type: Number,
default: 12
},
testColor: {
type: String,
default: '#ffffff'
},
definitionItemJson: {
type: Object,
default: () => ({})
}
});
console.log('父传子itemjson:', props.definitionItemJson);
//
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {}
});
//
async function dataInit() {}
// onMounted
onMounted(async () => {
await dataInit();
});
onUnmounted(() => {
emitter.off('binding-data-update');
});
//node
interface EquipmentNode {
equipmentName: string; //
equipmentModel: string; //
equipmentPlace: string; //
manufacturers: string; //
}
//
// equipmentState 0 1
// currentState 0 1 2 3 4 5 6 7
// operation true false null
const arr: EquipmentNode[] = [
{
equipmentName: '生产综合楼一楼消火栓1',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼一楼东走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼一楼消火栓2',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼一楼西走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼二楼消火栓1',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼二楼东走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼二楼消火栓2',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼二楼西走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼一楼消火栓1',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼一楼东走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼一楼消火栓2',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼一楼西走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼二楼消火栓1',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼二楼东走廊',
manufacturers: '宏达'
},
{
equipmentName: '生产综合楼二楼消火栓2',
equipmentModel: 'SN-65',
equipmentPlace: '生产综合楼二楼西走廊',
manufacturers: '宏达'
}
];
</script>
<style scoped>
.table-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.full-height-table {
flex: 1;
height: 100%;
}
.full-height-table :deep(.el-table__body-wrapper) {
flex: 1;
overflow-y: auto;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.operation-btn {
width: 60px;
min-width: 50px;
padding: 8px 12px;
height: 30px;
}
/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
font-size: 13px;
font-weight: bold;
}
/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
}
/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
</style>

@ -1,264 +0,0 @@
<template>
<div class="table-container">
<!-- 2号主变 -->
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">运行信息</h2>
<div class="table-wrapper" v-loading="arr.length === 0">
<el-table
:data="arr"
style="width: 100%"
class="full-height-table"
@cell-click="handleCellClick"
>
<el-table-column prop="equipmentName" label="设备名称" />
<el-table-column label="设备状态">
<template #default="{ row }">
<el-tag :type="row.equipmentState === 0 ? 'success' : 'warning'">
{{ row.equipmentState === 0 ? '正常' : '故障' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template #default="{ row }">
<el-tag type="primary">{{ row.currentState }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-tag v-if="row.operation == null || row.operation === ''" type="info"
>无操作</el-tag
>
<template v-else>
<el-button type="primary" size="small">开启</el-button>
<el-button type="primary" size="small">关闭</el-button>
</template>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, onUnmounted } from 'vue';
import emitter from '@/utils/emitter';
//
/// <reference path="../../../global.d.ts" />
function handleCellClick(obj: any) {
console.log('点击:', obj);
emitter.emit('binding-obj-facility-move', obj.id);
}
emitter.on('binding-data-update', () => {
console.log('@@binding-data-update');
dataInit();
});
const props = defineProps({
fontFamily: {
type: String,
default: '黑体'
},
fontSize: {
type: Number,
default: 12
},
testColor: {
type: String,
default: '#ffffff'
},
definitionItemJson: {
type: Object,
default: () => ({})
}
});
console.log('父传子itemjson:', props.definitionItemJson);
//
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {}
});
//
async function dataInit() {}
// onMounted
onMounted(async () => {
await dataInit();
});
onUnmounted(() => {
emitter.off('binding-data-update');
});
//node
interface EquipmentNode {
equipmentName: string; //
equipmentState: number; // 0 1
currentState: string; //
operation: boolean | null; // true false null
}
//
// equipmentState 0 1
// currentState 0 1 2 3 4 5 6 7
// operation true false null
const arr: EquipmentNode[] = [
{
equipmentName: '消防泵控制装置',
equipmentState: 0,
currentState: '运行',
operation: null
},
{
equipmentName: '消防泵主供电源供电',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '消防泵备用电源供电',
equipmentState: 0,
currentState: '开',
operation: true
},
{
equipmentName: '控制装置主供电源供电',
equipmentState: 0,
currentState: '开',
operation: true
},
{
equipmentName: '控制装置备用电源供电',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '深井泵',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '高压侧断路器',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '1号消防泵',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '2号消防泵',
equipmentState: 0,
currentState: '关',
operation: true
},
{
equipmentName: '消防水池水位',
equipmentState: 0,
currentState: '80%',
operation: null
},
{
equipmentName: '管网压力',
equipmentState: 0,
currentState: '0.4Mpa',
operation: null
}
];
</script>
<style scoped>
.table-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.full-height-table {
flex: 1;
height: 100%;
}
.full-height-table :deep(.el-table__body-wrapper) {
flex: 1;
overflow-y: auto;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.operation-btn {
width: 60px;
min-width: 50px;
padding: 8px 12px;
height: 30px;
}
/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
font-size: 13px;
font-weight: bold;
}
/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
}
/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
</style>

@ -1,378 +0,0 @@
<template>
<div class="table-container">
<!-- 2号主变 -->
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">运行信息</h2>
<div class="table-wrapper" v-loading="arr.length === 0">
<el-table
:data="arr"
style="width: 100%"
class="full-height-table"
@cell-click="handleCellClick"
>
<el-table-column prop="equipmentName" label="设备名称" />
<el-table-column label="设备状态">
<template #default="{ row }">
<el-tag :type="row.equipmentState === 0 ? 'success' : 'warning'">
{{ row.equipmentState === 0 ? '正常' : '故障' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template #default="{ row }">
<el-tag v-if="row.currentState === 0" type="info"></el-tag>
<el-tag v-else-if="row.currentState === 1" type="danger">报警</el-tag>
<el-tag v-else-if="row.currentState === 2" type="success">动作</el-tag>
<el-tag v-else-if="row.currentState === 3" type="danger">分位</el-tag>
<el-tag v-else-if="row.currentState === 4" type="danger">关闭</el-tag>
<el-tag v-else-if="row.currentState === 5" type="primary">开启</el-tag>
<el-tag v-else-if="row.currentState === 6" type="primary">运行</el-tag>
<el-tag v-else-if="row.currentState === 7" type="primary">正常</el-tag>
<el-tag v-else type="info">未知状态</el-tag>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-tag v-if="row.operation == null" type="info"></el-tag>
<el-button type="primary" class="operation-btn" v-else-if="row.operation">
屏蔽
</el-button>
<el-button type="primary" class="operation-btn" v-else-if="!row.operation">
取消屏蔽
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import type { TableColumnCtx } from 'element-plus';
import { ElMessage } from 'element-plus';
import { computed, onMounted, onUnmounted, ref, watch, reactive } from 'vue';
import { modelApi } from '@/utils/request';
import emitter from '@/utils/emitter';
const loading = ref(false);
//
/// <reference path="../../../global.d.ts" />
interface RecRuntimeData {
double: number;
node: {
name: string;
};
}
interface RecServiceType {
service: {
node: {
runtimes: Record<string, RecRuntimeData>;
};
};
}
interface ExtendedParentWindow extends Window {
Rec?: RecServiceType;
}
interface User {
id: string;
name: string;
amount1: string;
amount2: string;
amount3: number;
}
interface Equipment {
id: string; //ID
address?: string; //
name: string; //
eState: number; // 0 1
currentState: number; // 0 1 2
operation: boolean; // true false
}
interface FloorObj {
floorName: string; //
equipments: Equipment[];
}
// node
interface FloorNode {
roomId: string;
floorName: string;
eqpList: EquipmentNode[];
}
//node
// interface EquipmentNode {
// id: string; //ID
// name: string; //
// isBinding: boolean; //
// eState: number; // 0 1
// currentState: number; // 0 1 2
// operation: boolean; // true false
// }
function handleCellClick(obj: any) {
console.log('点击:', obj);
emitter.emit('binding-obj-facility-move', obj.id);
}
emitter.on('binding-data-update', () => {
console.log('@@binding-data-update');
dataInit();
});
const props = defineProps({
fontFamily: {
type: String,
default: '黑体'
},
fontSize: {
type: Number,
default: 12
},
testColor: {
type: String,
default: '#ffffff'
},
definitionItemJson: {
type: Object,
default: () => ({})
}
});
console.log('父传子itemjson:', props.definitionItemJson);
//
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {}
});
// const arr = ref<any[]>([]);
let targetDataTable: FloorNode[] = [];
let initArrs: any = {};
//
async function dataInit() {}
//
const tableDatas = computed(() => {
return targetDataTable.flatMap((floor) =>
floor.eqpList.map((equipment) => ({
...equipment,
floorName: floor.floorName, //
roomId: floor.roomId //
}))
);
});
// onMounted
onMounted(async () => {
await dataInit();
});
onUnmounted(() => {
emitter.off('binding-data-update');
});
//node
interface EquipmentNode {
equipmentName: string; //
equipmentState: number; // 0 1
currentState: number; // 0 1 2 3 4 5 6 7
operation: boolean | null; // true false null
}
//
// equipmentState 0 1
// currentState 0 1 2 3 4 5 6 7
// operation true false null
const arr: EquipmentNode[] = [
{
equipmentName: '火灾探测器1',
equipmentState: 0,
currentState: 1,
operation: true
},
{
equipmentName: '火灾探测器2',
equipmentState: 0,
currentState: 1,
operation: true
},
{
equipmentName: '火灾探测器3',
equipmentState: 1,
currentState: 0,
operation: false
},
{
equipmentName: '火灾探测器4',
equipmentState: 0,
currentState: 0,
operation: true
},
{
equipmentName: '重瓦斯保护',
equipmentState: 0,
currentState: 2,
operation: null
},
{
equipmentName: '压力缩放',
equipmentState: 0,
currentState: 2,
operation: null
},
{
equipmentName: '高压侧断路器',
equipmentState: 0,
currentState: 3,
operation: null
},
{
equipmentName: '中压侧断路器',
equipmentState: 0,
currentState: 3,
operation: null
},
{
equipmentName: '低压侧断路器',
equipmentState: 0,
currentState: 3,
operation: null
},
{
equipmentName: '断流阀',
equipmentState: 0,
currentState: 4,
operation: null
},
{
equipmentName: '排油阀',
equipmentState: 0,
currentState: 5,
operation: null
},
{
equipmentName: '注氮阀',
equipmentState: 0,
currentState: 5,
operation: null
},
{
equipmentName: '氮气瓶压力',
equipmentState: 0,
currentState: 7,
operation: null
},
{
equipmentName: '装置电源',
equipmentState: 0,
currentState: 6,
operation: null
}
];
interface SpanMethodProps {
row: any;
column: TableColumnCtx<User>;
rowIndex: number;
columnIndex: number;
}
//
const tableData = computed(() => {
return floorData.flatMap((floor) =>
floor.equipments.map((equipment) => ({
...equipment,
floorName: floor.floorName, //
//
address: equipment.address || floor.floorName
}))
);
});
</script>
<style scoped>
.table-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.full-height-table {
flex: 1;
height: 100%;
}
.full-height-table :deep(.el-table__body-wrapper) {
flex: 1;
overflow-y: auto;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
.operation-btn {
width: 60px;
min-width: 50px;
padding: 8px 12px;
height: 30px;
}
/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
font-size: 13px;
font-weight: bold;
}
/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
}
/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
</style>

@ -1,32 +0,0 @@
<template>
<!-- 四遥遥测 -->
<el-form :model="form" label-width="auto" style="max-width: 600px">
<el-form-item label="节点ID">
<el-input v-model="form.nodeId" />
</el-form-item>
<el-form-item label="值">
<el-input v-model="form.nodeValue" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">Send</el-button>
</el-form-item>
</el-form>
</template>
<script lang="ts" setup>
import { reactive } from 'vue';
// do not use same name with ref
const form = reactive({
nodeId: '',
nodeValue: ''
});
const onSubmit = () => {
console.log('submit!');
};
</script>
<style scoped></style>

@ -1,8 +1,5 @@
<template> <template>
<el-card <el-row :gutter="20" style="display: flex; align-items: center">
style="max-width: 100%; height: 100%; display: flex; flex-direction: column; overflow: hidden"
>
<el-row :gutter="20" style="flex-shrink: 0">
<el-col :span="24" class="centered-col"> <el-col :span="24" class="centered-col">
<el-text class="mx-1" size="large" style="font-size: 16px; margin-bottom: 15px" <el-text class="mx-1" size="large" style="font-size: 16px; margin-bottom: 15px"
>配置说明</el-text >配置说明</el-text
@ -10,13 +7,12 @@
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20" style="flex: 1; overflow: hidden"> <el-row :gutter="20">
<el-col :span="24" style="height: 100%"> <el-col :span="24" class="centered-col">
<el-scrollbar>
<el-table <el-table
:data="tableData" :data="tableData"
:header-cell-style="{ color: '#3b3b3b ' }" :header-cell-style="{ color: '#3b3b3b ' }"
:scrollbar-always-on="true" :style="{ height: '200px' }"
> >
<!-- 序号 --> <!-- 序号 -->
<el-table-column <el-table-column
@ -55,10 +51,8 @@
align="left" align="left"
/> />
</el-table> </el-table>
</el-scrollbar>
</el-col> </el-col>
</el-row> </el-row>
</el-card>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, watch, onMounted, computed } from 'vue'; import { ref, reactive, watch, onMounted, computed } from 'vue';
@ -173,12 +167,4 @@ let computedSize = computed({
justify-content: center; /* 水平居中 */ justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */ align-items: center; /* 垂直居中 */
} }
/* 确保滚动条只在 el-scrollbar 中显示 */
:deep(.el-card__body) {
overflow: hidden;
height: 100%;
display: flex;
flex-direction: column;
}
</style> </style>

@ -3,7 +3,6 @@
<h2 class="cardHead">基本信息</h2> <h2 class="cardHead">基本信息</h2>
<div class="cardBody"> <div class="cardBody">
<el-scrollbar>
<el-row :gutter="0" style="display: flex; align-items: center"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="8" :offset="4"> 名称 </el-col> <el-col :span="8" :offset="4"> 名称 </el-col>
<el-col :span="4"> <el-col :span="4">
@ -87,7 +86,6 @@
<el-tag type="primary">188*****00 </el-tag> <el-tag type="primary">188*****00 </el-tag>
</el-col> </el-col>
</el-row> </el-row>
</el-scrollbar>
</div> </div>
</el-card> </el-card>
@ -306,9 +304,8 @@ P:hover {
} }
.cardBody { .cardBody {
width: 100%; width: 100%;
margin: 0; margin: 0 0%;
padding: 0; padding: 0px 0%;
height: calc(100% - 40px); /* 减去标题高度 */ /* padding-bottom: 15px; */
overflow: hidden;
} }
</style> </style>

@ -1,143 +0,0 @@
<template>
<el-card class="card">
<h3 class="cardHead">2号主变排油注氮灭火</h3>
<div class="cardBody">
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
<el-col :span="12" class="full-width-col">
<el-tag type="danger" size="large" class="full-width-tag">火灾探测器1</el-tag>
</el-col>
<el-col :span="12" class="full-width-col">
<el-tag type="danger" size="large" class="full-width-tag">火灾探测器2</el-tag>
</el-col>
</el-row>
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
<el-col :span="12" class="full-width-col">
<el-tag type="warning" size="large" class="full-width-tag">火灾探测器3</el-tag>
</el-col>
<el-col :span="12" class="full-width-col">
<el-tag type="primary" size="large" class="full-width-tag">火灾探测器4</el-tag>
</el-col>
</el-row>
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
<el-col :span="12" class="full-width-col">
<el-tag type="danger" size="large" class="full-width-tag">注氮阀</el-tag>
</el-col>
<el-col :span="12" class="full-width-col">
<el-tag type="danger" size="large" class="full-width-tag">排油阀</el-tag>
</el-col>
</el-row>
<el-row :gutter="0" style="display: flex; align-items: center" class="row-spacing">
<el-col :span="12" class="full-width-col">
<el-tag type="danger" size="large" class="full-width-tag">断流阀</el-tag>
</el-col>
<el-col :span="12" class="full-width-col">
<el-tag type="primary" size="large" class="full-width-tag">氮气瓶</el-tag>
</el-col>
</el-row>
</div>
</el-card>
</template>
<script lang="ts" setup>
import { computed, ref, watch, onMounted } from 'vue';
const props = defineProps({
fontFamily: {
type: String,
default: 'Segoe UI'
},
fontSize: {
type: Number,
default: 14
},
testColor: {
type: String,
default: '#000000'
},
testBool: {
type: Boolean,
default: true
}
});
let computedSize = computed({
//
get() {
return props.fontSize + 'px';
}, //
set(val) {
console.log('有人修改了fullName', val);
}
});
</script>
<style scoped>
.row-spacing {
margin-bottom: 10px; /* 每行之间的间隔 */
}
.full-width-col {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}
.full-width-tag {
width: 85%; /* 填满父容器 */
text-align: center; /* 文字水平居中 */
display: flex; /* 使用 flexbox */
justify-content: center; /* 文字水平居中 */
align-items: center; /* 文字垂直居中 */
font-size: v-bind('computedSize');
}
/* 闪烁动画 */
.blinking-tag {
animation: blink 1s infinite; /* 1秒一次无限循环 */
}
@keyframes blink {
0%,
100% {
opacity: 1; /* 完全不透明 */
}
50% {
opacity: 0.3; /* 半透明 */
}
}
.card {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
/* max-width: 480px; */
color: v-bind('props.testColor');
font-family: v-bind('props.fontFamily');
/* font-family: 'Segoe UI'; */
font-size: v-bind('computedSize' - 1);
}
.cardHead {
margin: 0;
padding: 0px;
padding-bottom: 20px;
text-align: center;
color: #ffffff;
font-size: v-bind('computedSize' + 2);
}
.cardBody {
width: 100%;
margin: 0 0%;
padding: 0px 0%;
/* padding-bottom: 15px; */
}
</style>

@ -1,7 +1,67 @@
<template> <template>
<!-- <div style="display: flex; gap: 10px; align-items: center">
<el-popover
:width="300"
:visible="null"
popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;"
>
<template #reference>
<el-text
style="font-weight: bold; text-align: center; display: block"
type="primary"
color="rgb(236, 245, 255)"
>
{{ computedVal }}
</el-text>
</template>
<template #default>
<div class="demo-rich-conent" style="display: flex; gap: 2px; flex-direction: column">
<div class="demo-progress">
<el-progress
type="dashboard"
:width="100"
:percentage="percentage"
:color="colors"
:format="customFormat"
/>
</div>
<el-row :gutter="6">
<el-col :span="12" :xs="24" :sm="12" :md="6" class="elColInfo">
<el-statistic title="绑定ID" :value="null">
<template #suffix>
<el-tag size="default" type="primary">{{ moduleId }}</el-tag>
</template>
</el-statistic>
</el-col>
<el-col :span="12" :xs="24" :sm="12" :md="12" class="elColInfo">
<el-statistic title="节点名称" :value="null">
<template #suffix>
<el-tag size="default" type="success">{{ modeName }}</el-tag>
</template>
</el-statistic>
</el-col>
<el-col :span="12" :xs="24" :sm="12" :md="6" class="elColInfo">
<el-statistic title="类型" :value="null">
<template #suffix>
<el-tag size="default" type="primary">{{ moduleType }}</el-tag>
</template>
</el-statistic>
</el-col>
</el-row>
</div>
</template>
</el-popover>
<el-tag type="primary">{{ modeName }}</el-tag>
</div> -->
<el-row v-if="location === 'top'"> <el-row v-if="location === 'top'">
<el-col :span="24" class="flex-center"> <el-col :span="24" class="flex-center">
<el-tag v-if="showText" type="primary" size="small" style="opacity: 0.9"> <el-tag type="primary" size="small" style="opacity: 0.9">
<el-text type="primary" style="max-width: 65px" size="small" truncated> <el-text type="primary" style="max-width: 65px" size="small" truncated>
{{ modeName }} {{ modeName }}
</el-text> </el-text>
@ -11,7 +71,7 @@
<el-row justify="center"> <el-row justify="center">
<el-col :span="12" class="flex-center" v-if="location === 'left'"> <el-col :span="12" class="flex-center" v-if="location === 'left'">
<el-tag v-if="showText" type="primary" size="small" style="opacity: 0.9"> <el-tag type="primary" size="small" style="opacity: 0.9">
<el-text type="primary" style="max-width: 65px" size="small" truncated> <el-text type="primary" style="max-width: 65px" size="small" truncated>
{{ modeName }} {{ modeName }}
</el-text> </el-text>
@ -22,7 +82,7 @@
<div style="display: flex; gap: 10px; align-items: center"> <div style="display: flex; gap: 10px; align-items: center">
<el-popover <el-popover
:width="300" :width="300"
:disabled="!showInfo" :disabled="true"
popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;" popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;"
> >
<template #reference> <template #reference>
@ -75,7 +135,7 @@
</el-col> </el-col>
<el-col :span="12" class="flex-center" v-if="location === 'right'"> <el-col :span="12" class="flex-center" v-if="location === 'right'">
<el-tag v-if="showText" type="primary" size="small" style="opacity: 0.9"> <el-tag type="primary" size="small" style="opacity: 0.9">
<el-text type="primary" style="max-width: 65px" size="small" truncated> <el-text type="primary" style="max-width: 65px" size="small" truncated>
{{ modeName }} {{ modeName }}
</el-text> </el-text>
@ -85,7 +145,7 @@
<el-row v-if="location === 'bottom'"> <el-row v-if="location === 'bottom'">
<el-col :span="24" class="flex-center"> <el-col :span="24" class="flex-center">
<el-tag v-if="showText" type="primary" size="small" style="opacity: 0.9"> <el-tag type="primary" size="small" style="opacity: 0.9">
<el-text type="primary" style="max-width: 65px; opacity: 1" size="small" truncated> <el-text type="primary" style="max-width: 65px; opacity: 1" size="small" truncated>
{{ modeName }} {{ modeName }}
</el-text> </el-text>
@ -128,14 +188,6 @@ const props = defineProps({
location: { location: {
type: String, type: String,
default: 'bottom' default: 'bottom'
},
showInfo: {
type: Boolean,
default: false
},
showText: {
type: Boolean,
default: false
} }
}); });

@ -1,49 +1,47 @@
<template> <template>
<!-- <el-button @click="ccc">Default</el-button> -->
<el-card class="card"> <el-card class="card">
<el-scrollbar height="100%">
<h2 class="cardHead">运行信息</h2> <h2 class="cardHead">运行信息</h2>
<div class="cardBody" v-if="globalOverviewBool"> <div class="cardBody" v-if="globalOverviewBool">
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="9" :offset="4"> 设备状态 </el-col> <el-col :span="8" :offset="4"> 设备状态 </el-col>
<el-col :span="4"> <el-col :span="4">
<el-tag type="primary" v-if="isSwitch">/</el-tag> <el-tag type="primary">正常/中断</el-tag>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="9" :offset="4"> 温度 </el-col> <el-col :span="8" :offset="4"> 温度 </el-col>
<el-col :span="4"> <el-col :span="4">
<el-tag type="primary" v-if="isSwitch">23</el-tag> <el-tag type="primary">23</el-tag>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="9" :offset="4"> 湿度 </el-col> <el-col :span="8" :offset="4"> 湿度 </el-col>
<el-col :span="4"> <el-col :span="4">
<el-tag type="primary" v-if="isSwitch">45%RH</el-tag> <el-tag type="primary">45%RH</el-tag>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="9" :offset="4"> 风力 </el-col> <el-col :span="8" :offset="4"> 风力 </el-col>
<el-col :span="4"> <el-col :span="4">
<el-tag type="primary" v-if="isSwitch">5m/s</el-tag> <el-tag type="primary">三级5m/s</el-tag>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="9" :offset="4"> 风向 </el-col> <el-col :span="8" :offset="4"> 风向 </el-col>
<el-col :span="4"> <el-col :span="4">
<el-tag type="primary" v-if="isSwitch"></el-tag> <el-tag type="primary">东风</el-tag>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="9" :offset="4"> 雨量 </el-col> <el-col :span="8" :offset="4"> 雨量 </el-col>
<el-col :span="4"> <el-col :span="4">
<el-tag type="primary" v-if="isSwitch">20mm</el-tag> <el-tag type="primary">20mm</el-tag>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
@ -52,18 +50,18 @@
<el-row style="display: flex; align-items: center"> <el-row style="display: flex; align-items: center">
<el-col :span="24">火灾报警系统</el-col> <el-col :span="24">火灾报警系统</el-col>
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="9" :offset="1" <el-col :span="8" :offset="1"
>设备状态 >设备状态
<el-tag type="primary" v-if="isSwitch">/</el-tag> <el-tag type="primary">正常/故障</el-tag>
</el-col> </el-col>
<el-col :span="9" :offset="2" <el-col :span="8" :offset="2"
>通信状态 >通信状态
<el-tag type="primary" v-if="isSwitch">/</el-tag> <el-tag type="primary">正常/中断</el-tag>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="22" :offset="1" <el-col :span="22" :offset="1"
>火灾总告警 >火灾总告警
<!-- 带边框的蓝色圆 --> <!-- 带边框的蓝色圆 -->
@ -77,22 +75,22 @@
<el-col :span="24">2号主变灭火系统排油注氮灭火</el-col> <el-col :span="24">2号主变灭火系统排油注氮灭火</el-col>
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="7" :offset="1"> <el-col :span="7" :offset="1">
启动方式 启动方式
<el-tag type="primary" v-if="isSwitch">/</el-tag> <el-tag type="primary">自动/手动</el-tag>
</el-col> </el-col>
<el-col :span="7" :offset="1" <el-col :span="7" :offset="1"
>设备状态 >设备状态
<el-tag type="primary" v-if="isSwitch">/</el-tag> <el-tag type="primary">正常/故障</el-tag>
</el-col> </el-col>
<el-col :span="7" :offset="1" <el-col :span="7" :offset="1"
>通信状态 >通信状态
<el-tag type="primary" v-if="isSwitch">/</el-tag> <el-tag type="primary">正常/中断</el-tag>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="7" :offset="1" <el-col :span="7" :offset="1"
>火灾总告警 >火灾总告警
<div class="blue-circle redBordered"></div> <div class="blue-circle redBordered"></div>
@ -108,9 +106,7 @@
<div class="blue-circle greenBordered"></div> <div class="blue-circle greenBordered"></div>
</el-col> </el-col>
<el-col :span="7" :offset="1" style="display: flex; align-items: center"> <el-col :span="7" :offset="1" style="display: flex; align-items: center">
<el-text class="mx-1" type="primary" @click="dialogTableVisible = true" <el-text class="mx-1" type="primary" @click="dialogTableVisible = true">灭火动作</el-text>
>灭火动作</el-text
>
<!-- 带边框的蓝色圆 --> <!-- 带边框的蓝色圆 -->
<div class="blue-circle redBordered"></div> <div class="blue-circle redBordered"></div>
@ -118,7 +114,7 @@
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-top: 8px"> <el-row :gutter="0" style="display: flex; align-items: center; margin-top: 8px">
<el-col :span="7" :offset="1">灭火手动操作</el-col> <el-col :span="5" :offset="1">灭火手动操作</el-col>
<el-col :span="12"> <el-col :span="12">
<el-button type="primary" size="small">手动启动</el-button> <el-button type="primary" size="small">手动启动</el-button>
<el-button type="primary" size="small">紧急停止</el-button> <el-button type="primary" size="small">紧急停止</el-button>
@ -127,29 +123,28 @@
</div> </div>
<div class="cardBody" v-if="firePoliceBool"> <div class="cardBody" v-if="firePoliceBool">
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="9" :offset="4"> 设备状态 </el-col> <el-col :span="8" :offset="4"> 设备状态 </el-col>
<el-col :span="4"> <el-col :span="4">
<el-tag type="primary" v-if="isSwitch">/</el-tag> <el-tag type="primary">正常/故障</el-tag>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="9" :offset="4"> 通信状态 </el-col> <el-col :span="8" :offset="4"> 通信状态 </el-col>
<el-col :span="4"> <el-col :span="4">
<el-tag type="primary" v-if="isSwitch">/</el-tag> <el-tag type="primary">正常/中断</el-tag>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0" style="display: flex; align-items: center; margin-bottom: 2%"> <el-row :gutter="0" style="display: flex; align-items: center">
<el-col :span="9" :offset="4"> 电源状态</el-col> <el-col :span="8" :offset="4"> 电源状态</el-col>
<el-col :span="4"> <el-col :span="4">
<!-- 主供电源工作/备供电源工作/电源中断 --> <!-- 主供电源工作/备供电源工作/电源中断 -->
<el-tag type="primary" v-if="isSwitch"> </el-tag> <el-tag type="primary">主供电源工作</el-tag>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</el-scrollbar>
</el-card> </el-card>
<!-- :append-to-body="true" --> <!-- :append-to-body="true" -->
@ -183,7 +178,6 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ElButton } from 'element-plus';
import { computed, ref, watch, onMounted } from 'vue'; import { computed, ref, watch, onMounted } from 'vue';
let dialogTableVisible = ref(false); let dialogTableVisible = ref(false);
@ -208,26 +202,9 @@ const props = defineProps({
dataSource: { dataSource: {
type: String, type: String,
default: '--' default: '--'
},
isSwitch: {
type: Boolean,
default: true
},
testStr: {
type: String,
default: ''
},
definitionItemJson: {
type: Object as any,
default: () => ({})
} }
}); });
console.log('传递:', props.definitionItemJson);
function ccc() {
props.definitionItemJson.props.testStr = 'aaaaaa';
}
const activities = [ const activities = [
{ {
content: '灭火允许', content: '灭火允许',
@ -391,9 +368,8 @@ P:hover {
} }
.cardBody { .cardBody {
width: 100%; width: 100%;
height: 100%;
margin: 0 0%; margin: 0 0%;
padding: 0px 0%;
/* padding-bottom: 15px; */ /* padding-bottom: 15px; */
} }
</style> </style>

@ -1,5 +1,86 @@
<template> <template>
<!-- 四遥遥信 --> <!-- <div style="display: flex; gap: 10px; align-items: center">
<el-popover
:width="300"
popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;"
>
<template #reference>
<el-icon
:class="['iconStyle', isAalarm ? 'blink-animation' : '']"
:size="22"
:style="{ color: isBool ? 'rgb(146, 252, 40)' : 'rgb(252, 40, 40)' }"
>
<WarningFilled />
</el-icon>
</template>
<template #default>
<div class="demo-rich-conent" style="display: flex; gap: 20px; flex-direction: column">
<el-icon
class="iconStyle"
:size="60"
:style="{ color: isBool ? 'rgb(146, 252, 40)' : 'rgb(252, 40, 40)' }"
>
<WarningFilled />
</el-icon>
<el-row :gutter="6">
<el-col :span="12" :xs="24" :sm="12" :md="6" class="elColInfo">
<el-statistic title="绑定ID" :value="null">
<template #suffix>
<el-tag size="default" type="primary">{{ moduleId }}</el-tag>
</template>
</el-statistic>
</el-col>
<el-col :span="12" :xs="24" :sm="12" :md="12" class="elColInfo">
<el-statistic title="节点名称" :value="null">
<template #suffix>
<el-tag size="default" type="success">{{ modeName }}</el-tag>
</template>
</el-statistic>
</el-col>
<el-col :span="12" :xs="24" :sm="12" :md="6" class="elColInfo">
<el-statistic title="类型" :value="null">
<template #suffix>
<el-tag size="default" type="primary">遥信</el-tag>
</template>
</el-statistic>
</el-col>
</el-row>
<el-row :gutter="6">
<el-col :span="12" :xs="24" :sm="12" :md="6" class="elColInfo">
<el-statistic title="开关情况" :value="null">
<template #suffix>
<el-tag size="default" type="primary">{{ isBool }}</el-tag>
</template>
</el-statistic>
</el-col>
<el-col :span="12" :xs="24" :sm="12" :md="12" class="elColInfo">
<el-statistic title="告警" :value="null">
<template #suffix>
<el-tag size="default" type="primary">{{ isAalarm }}</el-tag>
</template>
</el-statistic>
</el-col>
<el-col :span="12" :xs="24" :sm="12" :md="6" class="elColInfo">
<el-statistic title="是否可告警" :value="null">
<template #suffix>
<el-tag size="default" type="primary">{{ isAlarmable }}</el-tag>
</template>
</el-statistic>
</el-col>
</el-row>
</div>
</template>
</el-popover>
<el-tag type="primary">{{ modeName }}</el-tag>
</div> -->
<!-- <button @click="console.log('data:', nodeByModelsStore.nodeMap)">点击</button> --> <!-- <button @click="console.log('data:', nodeByModelsStore.nodeMap)">点击</button> -->
<el-row v-if="location === 'top'"> <el-row v-if="location === 'top'">
<el-col :span="24" class="flex-center"> <el-col :span="24" class="flex-center">
@ -24,7 +105,7 @@
<div style="display: flex; gap: 10px; align-items: center"> <div style="display: flex; gap: 10px; align-items: center">
<el-popover <el-popover
:width="300" :width="300"
:disabled="showInfo" :disabled="false"
popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;" popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;"
> >
<!-- :style="{ color: isBool ? 'rgb(146, 252, 40)' : 'rgb(252, 40, 40)' }" --> <!-- :style="{ color: isBool ? 'rgb(146, 252, 40)' : 'rgb(252, 40, 40)' }" -->
@ -144,6 +225,8 @@ onUnmounted(() => {
emitter.off(props.definitionItemJson.id); emitter.off(props.definitionItemJson.id);
}); });
// const props = defineProps(['definitionItemJson']);
const props = defineProps({ const props = defineProps({
moduleType: { moduleType: {
type: String, type: String,
@ -157,10 +240,6 @@ const props = defineProps({
type: Object, type: Object,
default: () => ({}) default: () => ({})
}, },
showInfo: {
type: Boolean,
default: false
},
location: { location: {
type: String, type: String,
default: 'bottom' default: 'bottom'
@ -206,6 +285,24 @@ function loadingModuleById() {
} }
} }
// function loadingModuleById() {
// const globalData = (window as any).globalData as Map<string, any>;
// if (
// props.moduleId !== '' &&
// props.moduleId !== undefined &&
// props.moduleId !== '--' &&
// globalData?.has(props.moduleId)
// ) {
// let module = globalData.get(props.moduleId);
// if (module) {
// modeName.value = module.node.name;
// isBool.value = module.double == 1;
// isAalarm.value = module.alarm;
// isAlarmable.value = module.alarmable;
// }
// }
// }
// //
emitter.on(props.definitionItemJson.id, (value) => { emitter.on(props.definitionItemJson.id, (value) => {
console.log('触发事件', value); console.log('触发事件', value);

@ -46,6 +46,44 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
<!-- <div class="table-wrapper">
<el-table
:data="tableData"
border
:span-method="objectSpanMethod"
class="full-height-table"
style="width: 100%"
@cell-click="handleCellClick"
>
<el-table-column prop="floorName" label="楼层" />
<el-table-column prop="id" label="设备ID" />
<el-table-column prop="name" label="设备名称" />
<el-table-column label="设备状态">
<template #default="{ row }">
<el-tag :type="row.eState === 0 ? 'success' : 'warning'">
{{ row.eState === 0 ? '正常' : '故障' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template #default="{ row }">
<el-tag v-if="row.currentState === 0" type="success"></el-tag>
<el-tag v-else-if="row.currentState === 1" type="info">停止</el-tag>
<el-tag v-else type="error">报警</el-tag>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" class="operation-btn" v-if="row.operation">
屏蔽
</el-button>
<el-button type="primary" class="operation-btn" v-else> </el-button>
</template>
</el-table-column>
</el-table>
</div> -->
</el-card> </el-card>
</div> </div>
</template> </template>
@ -56,7 +94,6 @@ import { ElMessage } from 'element-plus';
import { computed, onMounted, onUnmounted, ref, watch, reactive } from 'vue'; import { computed, onMounted, onUnmounted, ref, watch, reactive } from 'vue';
import { modelApi } from '@/utils/request'; import { modelApi } from '@/utils/request';
import emitter from '@/utils/emitter'; import emitter from '@/utils/emitter';
import { type DataItem } from '@/components/mt-edit/store/types';
const loading = ref(false); const loading = ref(false);
@ -75,14 +112,9 @@ interface RecServiceType {
}; };
}; };
} }
// interface ExtendedParentWindow extends Window {
// Rec?: RecServiceType;
// }
interface ExtendedParentWindow extends Window { interface ExtendedParentWindow extends Window {
globalData: Map<string, DataItem> | Record<string, DataItem>; Rec?: RecServiceType;
} }
interface User { interface User {
id: string; id: string;
name: string; name: string;
@ -164,9 +196,8 @@ let targetDataTable: FloorNode[] = [];
let initArrs: any = {}; let initArrs: any = {};
// //
async function dataInit() { async function dataInit() {
// window globalData Map debugger;
const globalDataRaw = (window as unknown as ExtendedParentWindow).globalData; initArrs = (window.parent as ExtendedParentWindow).Rec?.service.node.runtimes;
// //
arr.value = []; arr.value = [];
targetDataTable = []; targetDataTable = [];
@ -184,27 +215,18 @@ async function dataInit() {
let eqpList: EquipmentNode[] = []; let eqpList: EquipmentNode[] = [];
floor.eqpList.forEach((eqp: any) => { floor.eqpList.forEach((eqp: any) => {
let currentState = 1; let currentState = 1;
// globalData 访
const getNodeData = (key: string) => {
if (globalDataRaw instanceof Map) {
return globalDataRaw.get(key);
} else {
return (globalDataRaw as Record<string, any>)[key];
}
};
// //
if (getNodeData(eqp.nodes[1])?.double != 1) currentState = 1; if (initArrs[eqp.nodes[1]].double != 1) currentState = 1;
else if (getNodeData(eqp.nodes[2])?.double == 1) currentState = 2; else if (initArrs[eqp.nodes[2]].double == 1) currentState = 2;
else if (getNodeData(eqp.nodes[1])?.double == 1) currentState = 0; else if (initArrs[eqp.nodes[1]].double == 1) currentState = 0;
let eqpNode: EquipmentNode = { let eqpNode: EquipmentNode = {
id: eqp.id, id: eqp.id,
name: getNodeData(eqp.nodes[0])?.node?.name || '', name: initArrs[eqp.nodes[0]].node.name || '',
eState: getNodeData(eqp.nodes[0])?.double || 0, eState: initArrs[eqp.nodes[0]].double || 0,
currentState: currentState, currentState: currentState,
isBinding: eqp.isBinding, isBinding: eqp.isBinding,
operation: getNodeData(eqp.nodes[3])?.double == 1 operation: initArrs[eqp.nodes[3]].double == 1
}; };
eqpList.push(eqpNode); eqpList.push(eqpNode);
}); });
@ -486,6 +508,38 @@ const objectSpanMethods = ({ row, columnIndex }: SpanMethodProps) => {
}; };
}; };
const objectSpanMethod = ({ row, columnIndex }: SpanMethodProps) => {
if (columnIndex === 0) {
//
const floor = floorData.find((f) => f.floorName === row.floorName);
if (floor) {
//
const firstEquipmentIndex = floor.equipments.findIndex((e) => e.id === row.id);
if (firstEquipmentIndex === 0) {
//
return {
rowspan: floor.equipments.length,
colspan: 1
};
} else {
//
return {
rowspan: 0,
colspan: 0
};
}
}
}
//
return {
rowspan: 1,
colspan: 1
};
};
// //
const tableData = computed(() => { const tableData = computed(() => {
return floorData.flatMap((floor) => return floorData.flatMap((floor) =>

@ -776,6 +776,7 @@ loader.load('/models/groundFloor/ground_floor08.gltf', (gltf: any) => {
moveArr.push(child as any); moveArr.push(child as any);
} else if (child.name.includes('smokeDetecto')) { } else if (child.name.includes('smokeDetecto')) {
console.log('@@aaa:', bindingArr);
// //
let smokePosition = child.position; let smokePosition = child.position;

@ -2,9 +2,10 @@
<div class="common-layout"> <div class="common-layout">
<el-container> <el-container>
<!-- 头部 --> <!-- 头部 -->
<!-- <el-header class="el-header">--> <!-- <el-header class="el-header">
<!-- <h2>220kV南河变电站辅助设备监控系统(全站总览)</h2>--> <h2>220kV南河变电站辅助设备监控系统(全站总览)</h2>
<!-- </el-header>--> </el-header> -->
<el-container> <el-container>
<!-- 左侧菜单 --> <!-- 左侧菜单 -->
<el-aside v-if="true" class="el-aside" :style="{ width: asideWidth }"> <el-aside v-if="true" class="el-aside" :style="{ width: asideWidth }">
@ -85,7 +86,7 @@ let initArr: any[] = [
{ id: 'testOverview', label: '智能锁控' }, { id: 'testOverview', label: '智能锁控' },
{ id: 'testOverview', label: '智能联动' } { id: 'testOverview', label: '智能联动' }
]; ];
// TODO pinia
const isCollapse = ref(false); const isCollapse = ref(false);
const asideWidth = ref('14%'); const asideWidth = ref('14%');

@ -10,7 +10,6 @@ import { createPinia } from 'pinia';
import 'element-plus/dist/index.css'; import 'element-plus/dist/index.css';
import router from './router/newIndex'; import router from './router/newIndex';
import '@/utils/globalUtils'; import '@/utils/globalUtils';
import { stompService } from '@/utils/stompService';
// 导入 Element Plus 语言包 // 导入 Element Plus 语言包
// import enLocale from 'element-plus/dist/locale/en.mjs'; // import enLocale from 'element-plus/dist/locale/en.mjs';
@ -75,11 +74,4 @@ app.component('my-input', MyInput);
app.component('my-button', MyButton); app.component('my-button', MyButton);
app.component('custom-demo', CustomDemo); app.component('custom-demo', CustomDemo);
app.component('pie-charts', PieCharts); app.component('pie-charts', PieCharts);
// 项目启动时自动连接 STOMP/MQTT
stompService.connect({
reconnectDelay: 5000 // 5 秒后重连
});
console.log('[Main] STOMP/MQTT 服务已启动,正在连接...');
app.mount('#app'); app.mount('#app');

@ -210,6 +210,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireControl/transformer', path: '/fireControl/transformer',
name: 'fireControlTransformer', name: 'fireControlTransformer',
component: () => import('@/views/edit/index.vue'),
meta: { meta: {
title: '变压器排油注氮灭火项目', title: '变压器排油注氮灭火项目',
hidden: false, hidden: false,
@ -221,7 +222,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireControl/transformer/index', path: '/fireControl/transformer/index',
name: 'fireControlTransformerIndex', name: 'fireControlTransformerIndex',
component: () => import('@/views/preview/fireControl/alarm/transformer/index.vue'), component: () => import('@/views/edit/index.vue'),
meta: { meta: {
title: '变压器排油注氮灭火', title: '变压器排油注氮灭火',
hidden: true, hidden: true,
@ -233,7 +234,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireFighting/transformer/host', path: '/fireFighting/transformer/host',
name: 'fireFightingTransformerHost', name: 'fireFightingTransformerHost',
component: () => import('@/views/preview/fireControl/alarm/transformer/host.vue'), component: () => import('@/views/edit/index.vue'),
meta: { meta: {
title: '主机', title: '主机',
hidden: false, hidden: false,
@ -245,8 +246,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireFighting/transformer/floor', path: '/fireFighting/transformer/floor',
name: 'fireFightingTransformerFloor', name: 'fireFightingTransformerFloor',
// // src\views\preview\fireControl\alarm\transformer\nitrogen.vue component: () => import('@/views/edit/index.vue'),
component: () => import('@/views/preview/fireControl/alarm/transformer/nitrogen.vue'),
meta: { meta: {
title: '2 号主变排油注氮灭火', title: '2 号主变排油注氮灭火',
hidden: false, hidden: false,
@ -260,7 +260,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireFighting/fireCock', path: '/fireFighting/fireCock',
name: 'fireFightingFireCock', name: 'fireFightingFireCock',
component: () => import('@/views/preview/fireControl/alarm/fireHydrant.vue'), component: () => import('@/views/edit/index.vue'),
meta: { meta: {
title: '消火栓系统', title: '消火栓系统',
hidden: false, hidden: false,
@ -272,7 +272,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireFighting/configuration', path: '/fireFighting/configuration',
name: 'fireFightingConfiguration', name: 'fireFightingConfiguration',
component: () => import('@/views/preview/fireControl/alarm/fireExtinguisher.vue'), component: () => import('@/views/edit/index.vue'),
meta: { meta: {
title: '灭火器配置', title: '灭火器配置',
hidden: false, hidden: false,
@ -284,8 +284,7 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
{ {
path: '/fireFighting/indicate', path: '/fireFighting/indicate',
name: 'fireFightingIndicator', name: 'fireFightingIndicator',
// F:\vue\workspace\maotu-webtopo\src\views\preview\fireControl\alarm\indicate.vue component: () => import('@/views/edit/index.vue'),
component: () => import('@/views/preview/fireControl/alarm/indicate.vue'),
meta: { meta: {
title: '消防应急照明及疏散指示系统', title: '消防应急照明及疏散指示系统',
hidden: false, hidden: false,
@ -812,33 +811,8 @@ export const constantRoutes: Readonly<RouteRecordRaw[]> = [
} }
} }
] ]
},
{
path: '/classify', //F:\vue\workspace\maotu-webtopo\src\views\preview\classify\index.vue
name: 'classify',
component: () => import('@/layout/view_index.vue'),
meta: {
title: '设备分类项目',
hidden: false,
treeHidden: false,
bottomHidden: false,
menuIcon: 'Operation'
},
children: [
{
path: '/classify/index',
name: 'classifyIndex',
component: () => import('@/views/preview/classify/index.vue'),
meta: {
title: '设备分类',
hidden: false,
treeHidden: false,
bottomHidden: false,
menuIcon: 'Setting'
} }
} ,
]
},
{ {
path: '/test', //F:\vue\workspace\maotu-webtopo\src\views\preview\systemInfo\index.vue path: '/test', //F:\vue\workspace\maotu-webtopo\src\views\preview\systemInfo\index.vue
name: 'test', name: 'test',

@ -1,135 +0,0 @@
/**
* Node
* STOMP
*/
import { stompService } from '@/utils/stompService';
interface NodeData {
id: string;
name: string;
status: string;
[key: string]: any;
}
interface NodeRuntime {
node: NodeData;
[key: string]: any;
}
class NodeService {
public runtimes: Record<string, NodeRuntime> = {};
constructor() {
// 注册服务
stompService.registerService('node', this);
}
/**
* STOMP
*/
mqttReady(): void {
console.log('[NodeService] STOMP 已就绪');
// 可以在这里请求初始化数据
}
/**
*
*/
onConnectionLost(): void {
console.log('[NodeService] STOMP 连接丢失');
}
/**
* Node
* @param value
*/
msgNodeInit(value: any): void {
console.log('[NodeService] 收到 Node 初始化数据:', value);
// 处理初始化逻辑
if (value && Array.isArray(value.nodes)) {
value.nodes.forEach((node: NodeData) => {
this.runtimes[node.id] = {
node,
lastUpdate: new Date()
};
});
}
}
/**
* Node
* @param value
*/
msgNode(value: any): void {
console.log('[NodeService] 收到 Node 更新:', value);
if (value && value.id) {
const runtime = this.runtimes[value.id];
if (runtime) {
// 更新现有节点
runtime.node = { ...runtime.node, ...value };
runtime.lastUpdate = new Date();
} else {
// 添加新节点
this.runtimes[value.id] = {
node: value,
lastUpdate: new Date()
};
}
// 触发更新事件(可以使用 mitt 或其他事件总线)
this.emitNodeUpdate(value.id);
}
}
/**
*
* @param nodeId ID
*/
getNode(nodeId: string): NodeData | null {
const runtime = this.runtimes[nodeId];
return runtime ? runtime.node : null;
}
/**
*
*/
getAllNodes(): NodeData[] {
return Object.values(this.runtimes).map((runtime) => runtime.node);
}
/**
*
* @param nodeId ID
* @param updates
*/
updateNode(nodeId: string, updates: Partial<NodeData>): void {
const runtime = this.runtimes[nodeId];
if (runtime) {
runtime.node = { ...runtime.node, ...updates };
runtime.lastUpdate = new Date();
// 发送更新到服务器
stompService.send('/app/web/write', 'nodeUpdate', {
id: nodeId,
updates
});
}
}
/**
*
* @param nodeId ID
*/
private emitNodeUpdate(nodeId: string): void {
// 这里可以使用 mitt 事件总线
// emitter.emit('node-update', nodeId);
console.log(`[NodeService] 节点 ${nodeId} 已更新`);
}
}
// 导出单例
export const nodeService = new NodeService();
export default nodeService;

@ -1,300 +0,0 @@
# MQTT 服务使用指南
## 简介
这是一个基于 `mqtt` 库封装的 MQTT 服务,提供了完整的连接、订阅、发布和消息处理功能。
## 主要功能
- ✅ 自动连接和重连
- ✅ 服务注册机制
- ✅ 消息自动分发
- ✅ TypeScript 类型支持
- ✅ 错误处理和日志记录
## 使用方法
### 1. 在 main.ts 中初始化
```typescript
import { mqttService } from './utils/mqttService';
// 应用启动时连接 MQTT
const app = createApp(App);
// 连接 MQTT 服务器
mqttService.connect({
// brokerUrl: 'ws://your-mqtt-broker:8083/mqtt', // 可选,默认使用当前域名
// username: 'your-username', // 可选
// password: 'your-password', // 可选
// clientId: 'your-client-id', // 可选,自动生成
reconnectPeriod: 5000 // 重连间隔,默认 5000ms
});
app.mount('#app');
```
### 2. 注册服务
```typescript
// 在您的组件或 store 中
import { mqttService } from '@/utils/mqttService';
// 注册您的服务
mqttService.registerService('node', {
// 当 MQTT 连接成功时会调用此方法
mqttReady() {
console.log('Node 服务已就绪');
},
// 处理 Node 初始化消息
msgNodeInit(data: any) {
console.log('收到 Node 初始化数据:', data);
},
// 处理 Node 更新消息
msgNode(data: any) {
console.log('收到 Node 更新:', data);
},
// 运行时的数据
runtimes: {}
});
// 注册其他服务
mqttService.registerService('channel', {
online(cid: string, isOnline: boolean) {
console.log(`通道 ${cid} 状态:`, isOnline);
}
});
mqttService.registerService('video', {
initVideo(data: any) {
console.log('初始化视频:', data);
},
playVideo(data: any) {
console.log('播放视频:', data);
}
});
```
### 3. 发送消息
```typescript
import { mqttService, MqttCmd } from '@/utils/mqttService';
// 发送控制命令
mqttService.send('/app/web/write', MqttCmd.Control, {
nodeId: 'node-001',
action: 'turnOn'
});
// 发送 Node 更新
mqttService.send('/app/web/write', MqttCmd.Node, {
node: {
id: 'node-001',
status: 'active'
}
});
```
### 4. 订阅主题
```typescript
import { mqttService } from '@/utils/mqttService';
// 订阅自定义主题
mqttService.subscribe('/topic/custom', (message) => {
console.log('收到自定义消息:', message);
});
// 取消订阅
mqttService.unsubscribe('/topic/custom');
```
### 5. 在 Vue 组件中使用
```vue
<template>
<div>
<el-button @click="sendCommand">发送命令</el-button>
<div>连接状态:{{ isConnected ? '已连接' : '未连接' }}</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { mqttService, MqttCmd } from '@/utils/mqttService';
const isConnected = ref(false);
// 注册服务
onMounted(() => {
mqttService.registerService('myComponent', {
mqttReady() {
console.log('组件服务已就绪');
isConnected.value = true;
},
onConnectionLost() {
isConnected.value = false;
}
});
});
// 发送命令
function sendCommand() {
mqttService.send('/app/web/write', MqttCmd.Control, {
command: 'test'
});
}
// 组件卸载时清理
onUnmounted(() => {
// 如果需要,可以在这里断开连接
// mqttService.disconnect();
});
</script>
```
## 消息命令类型
```typescript
export const MqttCmd = {
Channel: 'channel', // 通道状态
NodeInit: 'nodeInit', // Node 初始化
Node: 'node', // Node 更新
User: 'user', // 用户登录
Control: 'control', // 控制命令
VideoInit: 'videoInit', // 视频初始化
VideoCtl: 'videoCtl', // 视频控制
Lock: 'lock', // 锁控
Alarm: 'alarm', // 告警
Info: 'info', // 通知提示
SocketDebugger: 'socketDebugger' // 调试
};
```
## API 文档
### mqttService.connect(config?)
连接 MQTT 服务器
**参数:**
- `config?: MqttConfig` - 连接配置
- `brokerUrl?: string` - MQTT 服务器地址
- `username?: string` - 用户名
- `password?: string` - 密码
- `clientId?: string` - 客户端 ID
- `reconnectPeriod?: number` - 重连间隔(毫秒)
### mqttService.disconnect()
断开 MQTT 连接
### mqttService.send(topic, cmd, value)
发送消息
**参数:**
- `topic: string` - MQTT 主题
- `cmd: string` - 命令类型
- `value: any` - 消息内容
### mqttService.subscribe(topic, callback?)
订阅主题
**参数:**
- `topic: string` - 主题
- `callback?: (message: MqttMessage) => void` - 消息回调
### mqttService.unsubscribe(topic)
取消订阅
**参数:**
- `topic: string` - 主题
### mqttService.registerService(name, service)
注册服务
**参数:**
- `name: string` - 服务名称
- `service: any` - 服务对象
### mqttService.getClientStatus()
获取客户端状态
**返回:** `{ connected: boolean; client: MqttClient | null }`
## 注意事项
1. **连接时机**: 建议在应用启动时main.ts连接 MQTT
2. **服务注册**: 在组件的 `onMounted` 生命周期注册服务
3. **清理资源**: 在组件卸载时根据需要断开连接或取消订阅
4. **错误处理**: 服务已内置重连机制,无需手动处理
5. **类型安全**: 所有方法都有 TypeScript 类型支持
## 迁移指南
从旧的 ExtJS 版本迁移:
### 旧代码
```javascript
Rec.mqtt.connect();
Rec.service.node = { ... };
Rec.mqtt.send(cmd, value);
```
### 新代码
```typescript
import { mqttService } from '@/utils/mqttService';
mqttService.connect();
mqttService.registerService('node', { ... });
mqttService.send('/app/web/write', cmd, value);
```
## 示例项目结构
```
src/
├── utils/
│ └── mqttService.ts # MQTT 服务
├── services/
│ ├── nodeService.ts # Node 服务
│ ├── channelService.ts # 通道服务
│ └── videoService.ts # 视频服务
└── views/
└── YourComponent.vue # 使用 MQTT 的组件
```
## 故障排除
### 连接失败
- 检查 MQTT 服务器地址是否正确
- 检查网络连接
- 查看浏览器控制台日志
### 消息未收到
- 确认服务已注册
- 检查主题订阅是否正确
- 查看消息格式是否符合预期
### 重连问题
- 检查 `reconnectPeriod` 设置
- 查看服务器是否在线
- 检查认证信息是否正确

@ -1,309 +0,0 @@
# STOMP 服务使用指南
## 简介
这是一个基于 `@stomp/stompjs` 库封装的 STOMP 服务,提供了完整的连接、订阅、发布和消息处理功能。
**注意:** 您的项目使用的是 **STOMP over WebSocket** 协议,而不是 MQTT。
## 主要功能
- ✅ 自动连接和重连
- ✅ 服务注册机制
- ✅ 消息自动分发
- ✅ TypeScript 类型支持
- ✅ 错误处理和日志记录
## 使用方法
### 1. 在 main.ts 中初始化
```typescript
import { stompService } from './utils/stompService';
// 应用启动时连接 STOMP
const app = createApp(App);
// 连接 STOMP 服务器
stompService.connect({
// brokerUrl: 'ws://your-server:8080/stomp-endpoint', // 可选,默认使用当前域名
// username: 'your-username', // 可选
// password: 'your-password', // 可选
reconnectDelay: 5000 // 重连间隔,默认 5000ms
});
app.mount('#app');
```
### 2. 注册服务
```typescript
// 在您的组件或 store 中
import { stompService } from '@/utils/stompService';
// 注册您的服务
stompService.registerService('node', {
// 当 STOMP 连接成功时会调用此方法
mqttReady() {
console.log('Node 服务已就绪');
},
// 处理 Node 初始化消息
msgNodeInit(data: any) {
console.log('收到 Node 初始化数据:', data);
},
// 处理 Node 更新消息
msgNode(data: any) {
console.log('收到 Node 更新:', data);
},
// 运行时的数据
runtimes: {}
});
// 注册其他服务
stompService.registerService('channel', {
online(cid: string, isOnline: boolean) {
console.log(`通道 ${cid} 状态:`, isOnline);
}
});
stompService.registerService('video', {
initVideo(data: any) {
console.log('初始化视频:', data);
},
playVideo(data: any) {
console.log('播放视频:', data);
}
});
```
### 3. 发送消息
```typescript
import { stompService, MqttCmd } from '@/utils/stompService';
// 发送控制命令
stompService.send('/app/web/write', MqttCmd.Control, {
nodeId: 'node-001',
action: 'turnOn'
});
// 发送 Node 更新
stompService.send('/app/web/write', MqttCmd.Node, {
node: {
id: 'node-001',
status: 'active'
}
});
```
### 4. 订阅主题
```typescript
import { stompService } from '@/utils/stompService';
// 订阅自定义主题
stompService.subscribe('/topic/custom', (message) => {
console.log('收到自定义消息:', message);
});
// 取消订阅
stompService.unsubscribe('/topic/custom');
```
### 5. 在 Vue 组件中使用
```vue
<template>
<div>
<el-button @click="sendCommand">发送命令</el-button>
<div>连接状态:{{ isConnected ? '已连接' : '未连接' }}</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { stompService, MqttCmd } from '@/utils/stompService';
const isConnected = ref(false);
// 注册服务
onMounted(() => {
stompService.registerService('myComponent', {
mqttReady() {
console.log('组件服务已就绪');
isConnected.value = true;
},
onConnectionLost() {
isConnected.value = false;
}
});
});
// 发送命令
function sendCommand() {
stompService.send('/app/web/write', MqttCmd.Control, {
command: 'test'
});
}
// 组件卸载时清理
onUnmounted(() => {
// 如果需要,可以在这里断开连接
// stompService.disconnect();
});
</script>
```
## 消息命令类型
```typescript
export const MqttCmd = {
Channel: 'channel', // 通道状态
NodeInit: 'nodeInit', // Node 初始化
Node: 'node', // Node 更新
User: 'user', // 用户登录
Control: 'control', // 控制命令
VideoInit: 'videoInit', // 视频初始化
VideoCtl: 'videoCtl', // 视频控制
Lock: 'lock', // 锁控
Alarm: 'alarm', // 告警
Info: 'info', // 通知提示
SocketDebugger: 'socketDebugger' // 调试
};
```
## API 文档
### stompService.connect(config?)
连接 STOMP 服务器
**参数:**
- `config?: StompServiceConfig` - 连接配置
- `brokerUrl?: string` - STOMP 服务器地址
- `username?: string` - 用户名
- `password?: string` - 密码
- `reconnectDelay?: number` - 重连间隔(毫秒)
### stompService.disconnect()
断开 STOMP 连接
### stompService.send(destination, cmd, value)
发送消息
**参数:**
- `destination: string` - STOMP 目标地址
- `cmd: string` - 命令类型
- `value: any` - 消息内容
### stompService.subscribe(destination, callback?)
订阅主题
**参数:**
- `destination: string` - 目标地址
- `callback?: (message: StompMessage) => void` - 消息回调
### stompService.unsubscribe(destination)
取消订阅
**参数:**
- `destination: string` - 目标地址
### stompService.registerService(name, service)
注册服务
**参数:**
- `name: string` - 服务名称
- `service: any` - 服务对象
### stompService.getClientStatus()
获取客户端状态
**返回:** `{ connected: boolean; client: Client | null }`
## 注意事项
1. **连接时机**: 建议在应用启动时main.ts连接 STOMP
2. **服务注册**: 在组件的 `onMounted` 生命周期注册服务
3. **清理资源**: 组件卸载时根据需要断开连接或取消订阅
4. **错误处理**: 服务已内置重连机制,无需手动处理
5. **类型安全**: 所有方法都有 TypeScript 类型支持
## 迁移指南
从旧的 ExtJS 版本迁移:
### 旧代码
```javascript
Rec.mqtt.connect();
Rec.service.node = { ... };
Rec.mqtt.send(cmd, value);
```
### 新代码
```typescript
import { stompService } from '@/utils/stompService';
stompService.connect();
stompService.registerService('node', { ... });
stompService.send('/app/web/write', cmd, value);
```
## 示例项目结构
```
src/
├── utils/
│ └── stompService.ts # STOMP 服务
├── services/
│ ├── nodeService.ts # Node 服务
│ ├── channelService.ts # 通道服务
│ └── videoService.ts # 视频服务
└── views/
└── YourComponent.vue # 使用 STOMP 的组件
```
## 故障排除
### 连接失败
- 检查 STOMP 服务器地址是否正确
- 检查 WebSocket 是否可用(某些浏览器需要 HTTPS
- 查看浏览器控制台日志
### 消息未收到
- 确认服务已注册
- 检查主题订阅是否正确
- 查看消息格式是否符合预期
### 重连问题
- 检查 `reconnectDelay` 设置
- 查看服务器是否在线
- 检查认证信息是否正确
## 与 MQTT 的区别
STOMP 是一个简单的文本协议,基于 WebSocket
- 使用 `destination` 而不是 `topic`
- 使用 `send/publish` 发送消息
- 使用 `subscribe` 订阅消息
- 连接地址格式:`ws://host/stomp-endpoint`

@ -1,271 +0,0 @@
import { dayjs } from 'element-plus';
interface RecIn {
Node: {
InTypeIn: [number, string][];
TypeBase: [number, string][];
};
CONST: {
STR: {
EnumType: [number, string][];
};
YX: {
EnumType: [number, string][];
};
UserPage: [string, string][];
};
EnumTypeVal: [number, string][][];
EnumTypeValFun: Function[];
regex: any;
trans: (val: any, enumArr: [number, string][]) => string;
}
export const Rec: Partial<RecIn> = {};
Rec.Node = {} as RecIn['Node'];
Rec.CONST = {} as RecIn['CONST'];
Rec.CONST.STR = {} as RecIn['CONST']['STR'];
Rec.CONST.YX = {} as RecIn['CONST']['YX'];
Rec.trans = (index, type) => {
for (let i = 0; i < type.length; i++) {
if (type[i][0] == index) {
return type[i][1];
}
}
return '*未知*';
};
// 所有输入类型
Rec.Node.InTypeIn = [
[1, '遥信'],
[2, '遥测']
];
export const getIndex = (num: number) => {
switch (num) {
case 1:
return 100;
case 2:
return 0;
default:
return -1;
}
};
/**
*
* @param num Nodesig
* @returns
*/
export const getNodeStatus = (sig: number) => {
switch (sig) {
case -2000:
return '未初始化状态';
case 0:
return '正常';
case 1:
return '开启';
case 5:
return '联动关';
case 10:
return '高联动';
case -10:
return '低联动';
case 20:
return '高限告警';
case -20:
return '低限告警';
default:
return '未知状态';
}
};
/**
*
* @param num Nodesig
* @returns
*/
export const getNodeColor = (sig: number) => {
switch (sig) {
case -2000:
return 'info';
case 0:
case 1:
return 'primary';
case 5:
case 10:
case -10:
return 'warning';
case 20:
case -20:
return 'danger';
default:
return 'info';
}
};
// 四遥基本类型
Rec.Node.TypeBase = [
[1, '遥信'],
[2, '遥测'],
[3, '遥控'],
[4, '遥调']
];
// 定值转化的 类型
Rec.CONST.STR.EnumType = [
[0, '缺省'],
[1, '普通开关'],
[2, '数值'],
[3, '时间秒'],
[11, 'RY空调模式'],
[12, '空调温度'],
[13, '空调风速'],
[14, '国网空调模式'],
[21, 'KTC空调']
];
Rec.CONST.YX.EnumType = [
[0, '颜色'],
[1, '文字'],
[2, '颜色+文字']
];
Rec.EnumTypeVal = []; // 定值类型,用于编辑时的选择
Rec.EnumTypeValFun = []; // 转换函数,用于显示与控制
Rec.EnumTypeVal[100] = [
[0, 'green'],
[1, 'yellow'],
[2, 'red']
];
Rec.EnumTypeVal[101] = [
[0, '正常'],
[1, '异常'],
[2, '故障'],
[3, '报警'],
[4, '运行'],
[5, '关闭']
];
Rec.EnumTypeVal[102] = [
[0, '正常,green'],
[1, '异常,brown'],
[2, '故障,yellow'],
[3, '报警,red'],
[4, '运行,blue'],
[5, '关闭,purple']
];
// 缺省
Rec.EnumTypeVal[0] = [
[0, '关闭'],
[1, '开启']
];
Rec.EnumTypeValFun[0] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![index + 0]);
};
//Rec.EnumTypeValFun[etype](val,getIndex(btype));
// 遥控
Rec.EnumTypeVal[1] = [
[0, '关闭'],
[1, '开启']
];
Rec.EnumTypeValFun[1] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![index + 1]);
};
// 数值
Rec.EnumTypeVal[2] = [];
Rec.EnumTypeValFun[2] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![index + 2]);
};
// timestamp 转换成时间
Rec.EnumTypeValFun[3] = function (val: any) {
// Ext.Date.format(val * 1000, 'Y-m-d H:i:s')
dayjs.unix(val).format('YYYY-MM-DD HH:mm:ss');
};
// 国网空调模式
Rec.EnumTypeVal[14] = [
[4, '自动'],
[0, '制冷'],
[1, '制热'],
[3, '除湿'],
[2, '送风']
];
Rec.EnumTypeValFun[14] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![14]);
};
// RY空调模式
Rec.EnumTypeVal[11] = [
[0, '自动'],
[1, '制冷'],
[2, '制热'],
[3, '除湿'],
[4, '送风']
];
Rec.EnumTypeValFun[11] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![11]);
};
// 空调温度
Rec.EnumTypeVal[12] = [
[16, '16℃'],
[17, '17℃'],
[18, '18℃'],
[19, '19℃'],
[20, '20℃'],
[21, '21℃'],
[22, '22℃'],
[23, '23℃'],
[24, '24℃'],
[25, '25℃'],
[26, '26℃'],
[27, '27℃'],
[28, '28℃'],
[29, '29℃'],
[30, '30℃']
];
Rec.EnumTypeValFun[12] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![12]);
};
// 空调风速
Rec.EnumTypeVal[13] = [
[0, '自动'],
[1, '低'],
[2, '中'],
[3, '高']
];
Rec.EnumTypeValFun[13] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![13]);
};
// KTC 空调
Rec.EnumTypeVal[21] = [
[0, '关闭'],
[1, '制冷'],
[2, '制热']
];
Rec.EnumTypeValFun[21] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![21]);
};
//
Rec.EnumTypeValFun[21]();
// 用户的缺省界面
Rec.CONST.UserPage = [
['Admin', 'Admin'],
['User', 'User']
];
// 正则表达式
Rec.regex = {
// Modbus 配置的正则表达式
modbusCfg:
/^(?:25[0-4]|2[0-4]\d|1\d{2}|[1-9]\d|[1-9]):(?:[1-6]|10):(?:6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)(?::[2-9])?$/,
modbusParm: /^(?:\d+(?::\d+){0,2})?$/
};

@ -1,87 +0,0 @@
const EnumTypeVal: [number, string][][] = [];
const EnumTypeValFun: ((val: number) => string)[] = [];
/**
*
* @param index
* @param type
* @returns {string|*}
*/
const trans = function (index: number, type: any[]) {
for (let i = 0; i < type.length; i++) {
if (type[i][0] == index) {
return type[i][1];
}
}
return '*未知*';
};
const EnumType = [
[0, '缺省'],
[1, '普通开关'],
[2, '数值'],
[3, '时间秒'],
[11, 'RY空调模式'],
[12, '空调温度'],
[13, '空调风速'],
[14, '国网空调模式'],
[21, 'KTC空调']
];
// 缺省
EnumTypeVal[0] = [
[0, '关闭'],
[1, '开启']
];
EnumTypeValFun[0] = function (val: number) {
return trans(val, EnumTypeVal[0]);
};
// 遥控
EnumTypeVal[1] = [
[0, '关闭'],
[1, '开启']
];
EnumTypeValFun[1] = function (val) {
return trans(val, EnumTypeVal[1]);
};
// 数值
EnumTypeVal[2] = [];
EnumTypeValFun[2] = function (val) {
return val.toString();
};
// timestamp 转换成时间
EnumTypeValFun[3] = function (val) {
return format(val * 1000, 'Y-m-d H:i:s');
};
export { EnumTypeVal, EnumTypeValFun };
const format = function (date: Date, format: string) {
var formatFunctions = formatFunctions;
if (!Ext.isDate(date)) {
return '';
}
if (formatFunctions[format] == null) {
utilDate.createFormat(format);
}
return formatFunctions[format].call(date) + '';
};
const formatFunctions: { [key: string]: () => string } = {
MS: function () {
// UTC milliseconds since Unix epoch (MS-AJAX serialized date format (MRSF))
return '\\/Date(' + this.getTime() + ')\\/';
},
time: function () {
return this.getTime().toString();
},
timestamp: function () {
return format(this.getTime(), 'U');
}
};

@ -3,12 +3,13 @@ import { type DataItem } from '@/components/mt-edit/store/types';
import emitter from '@/utils/emitter'; import emitter from '@/utils/emitter';
import { useNodeByModelsStore } from '@/components/mt-edit/store/nodeByModels'; import { useNodeByModelsStore } from '@/components/mt-edit/store/nodeByModels';
// 扩展 Window 接口
declare global { declare global {
interface Window { interface Window {
vueGlobalFunction: (param: DataItem) => void; vueGlobalFunction: (param: any) => void;
// 添加其他全局函数
anotherGlobalFunction: (param: string) => string; anotherGlobalFunction: (param: string) => string;
// globalData: Map<string, DataItem> | Record<string, DataItem>; globalData: Map<string, DataItem> | Record<string, DataItem>;
globalData: Map<string, DataItem>;
globalNodeIdForModeId: Map<string, Array<string>>; globalNodeIdForModeId: Map<string, Array<string>>;
} }
} }
@ -30,16 +31,15 @@ function setModuleById(param: DataItem) {
// 定义全局函数 // 定义全局函数
function vueGlobalFunction(param: DataItem) { function vueGlobalFunction(param: DataItem) {
console.log('全局函数被调用:', param); console.log('全局函数被调用:', param);
debugger;
// 安全访问 globalData // 安全访问 globalData
const globalData = window.globalData; const globalData = window.globalData;
if (globalData instanceof Map) {
(globalData as Map<string, DataItem>).set(param.id.toString(), param); (globalData as Map<string, DataItem>).set(param.id.toString(), param);
} else {
// if (globalData instanceof Map) { (globalData as Record<string, DataItem>)[param.id.toString()] = param;
// (globalData as Map<string, DataItem>).set(param.id.toString(), param); }
// } else {
// (globalData as Record<string, DataItem>)[param.id.toString()] = param;
// }
// 延迟访问 store // 延迟访问 store
try { try {
@ -48,7 +48,7 @@ function vueGlobalFunction(param: DataItem) {
if (nodeByModelsStore.nodeMap.has(param.id.toString())) { if (nodeByModelsStore.nodeMap.has(param.id.toString())) {
const arr = nodeByModelsStore.nodeMap.get(param.id.toString()); const arr = nodeByModelsStore.nodeMap.get(param.id.toString());
arr?.forEach((nodeId) => { arr?.forEach((nodeId) => {
console.log('节点 ID:', nodeId); console.log('节点ID:', nodeId);
emitter.emit(nodeId, param.id); emitter.emit(nodeId, param.id);
}); });
} }
@ -85,22 +85,16 @@ async function getData() {
if (data && typeof data === 'object') { if (data && typeof data === 'object') {
// 判断当前 globalData 类型并相应处理 // 判断当前 globalData 类型并相应处理
const currentGlobalData = window.globalData; const currentGlobalData = window.globalData;
if (currentGlobalData instanceof Map) {
// 如果当前是 Map清空并重新设置
currentGlobalData.clear(); currentGlobalData.clear();
Object.entries(data).forEach(([key, value]) => { Object.entries(data).forEach(([key, value]) => {
currentGlobalData.set(key, value as DataItem); currentGlobalData.set(key, value as DataItem);
}); });
} else {
// if (currentGlobalData instanceof Map) { // 如果当前是对象,直接赋值
// // 如果当前是 Map清空并重新设置 window.globalData = data as Record<string, DataItem>;
// currentGlobalData.clear(); }
// Object.entries(data).forEach(([key, value]) => {
// currentGlobalData.set(key, value as DataItem);
// });
// } else {
// // 如果当前是对象,直接赋值
// window.globalData = data as Record<string, DataItem>;
// }
} }
console.log('全局数据已更新:', window.globalData); console.log('全局数据已更新:', window.globalData);
@ -116,10 +110,31 @@ if (typeof window !== 'undefined') {
} }
// 监听页面刷新/加载事件 // 监听页面刷新/加载事件
window.addEventListener('load', () => { // window.addEventListener('load', () => {
getData(); // getData();
}); // });
// 也可以直接挂载到全局对象 // 也可以直接挂载到全局对象
// (window as any).myGlobalFunction = myGlobalFunction; // (window as any).myGlobalFunction = myGlobalFunction;
(window as any).anotherGlobalFunction = anotherGlobalFunction; // (window as any).anotherGlobalFunction = anotherGlobalFunction;
// 接收父页面消息
window.addEventListener('message', function (event) {
if (event.data.type === 'SET_GLOBAL_DATA') {
// 接收父页面发送的数据
window.globalData = event.data.payload;
console.log('接收到父页面数据:', window.globalData);
}
});
// 通知父页面 Vue 已准备就绪
window.addEventListener('load', () => {
if (window.parent !== window) {
window.parent.postMessage(
{
type: 'VUE_APP_READY'
},
'*'
);
}
});

@ -21,92 +21,7 @@ export const buildApiUrl = (path: string) => {
}; };
export const modelApi = { export const modelApi = {
// http://localhost:8080/data/tree/changeNodeClass // http://localhost:8080/monitor/info
changeNodeClass_post(endJson: any): Promise<ApiResponse> {
return fetch(buildApiUrl('/data/tree/changeNodeClass'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: '*/*'
},
body: JSON.stringify(endJson)
}).then((response) => {
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
});
},
getNodeByCls_get(clsId: string): Promise<ApiResponse> {
return fetch(
buildApiUrl(`/data/tree/getNodeByCls?clsId=${clsId}`),
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
Accept: '*/*'
}
}).then((response) => {
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
});
},
deleteTreeNode_post(endJson: any): Promise<ApiResponse> {
return fetch(buildApiUrl('/data/tree/deleteTreeNode'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: '*/*'
},
body: JSON.stringify(endJson)
}).then((response) => {
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
});
},
changeTreeNode_post(endJson: any): Promise<ApiResponse> {
return fetch(buildApiUrl('/data/tree/changeTreeNode'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: '*/*'
},
body: JSON.stringify(endJson)
}).then((response) => {
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
});
},
addTreeNode_post(endJson: any): Promise<ApiResponse> {
return fetch(buildApiUrl('/data/tree/addTreeNode'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: '*/*'
},
body: JSON.stringify(endJson)
}).then((response) => {
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
});
},
allTree_get(): Promise<ApiResponse> {
return fetch(buildApiUrl('/data/tree/allTree'), {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Accept: '*/*'
}
}).then((response) => {
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
});
},
monitor_info_get(): Promise<ApiResponse> { monitor_info_get(): Promise<ApiResponse> {
return fetch(buildApiUrl('/monitor/info'), { return fetch(buildApiUrl('/monitor/info'), {
method: 'GET', method: 'GET',

@ -1,455 +0,0 @@
import { Client, Message, IFrame } from '@stomp/stompjs';
import type { StompConfig } from '@stomp/stompjs';
// 定义消息命令常量
export const MqttCmd = {
Channel: 1, // 通道消息
NodeInit: 2, // 节点初始化
Node: 3, // 节点消息
VideoInit: 4, // 视频初始化
VideoCtl: 5, // PTZ 控制
VideoPlay: 6, // 视频播放
Lock: 7, // 锁控消息
Control: 10, // 控制消息反馈
Alarm: 20, // 告警消息
Info: 100, // 通知
Error: 101, // 错误
DirVideo: 201, // 视频消息
DirLock: 202, // 锁控消息
DirLockWeb: 203, // 锁控 WEB 消息
User: 1000, // 用户登陆
SocketDebugger: 3001 // SocketDebugger 消息
};
// 定义消息接口
export interface StompMessage {
cmd: number;
value: any;
}
// 定义服务注册表
export interface ServiceRegistry {
[key: string]: any;
}
// STOMP 配置接口
export interface StompServiceConfig {
brokerUrl?: string;
username?: string;
password?: string;
reconnectDelay?: number;
}
class StompService {
private client: Client | null = null;
private isConnected: boolean = false;
private services: ServiceRegistry = {};
private config: StompServiceConfig = {};
/**
*
* @param name
* @param service
*/
public registerService(name: string, service: any): void {
this.services[name] = service;
console.log(`[STOMP] 服务已注册:${name}`);
}
/**
* STOMP
* @param config
*/
public connect(config: StompServiceConfig = {}): void {
if (this.client) {
console.warn('[STOMP] 客户端已存在,跳过连接');
return;
}
// 保存配置
this.config = config;
// 构建连接地址
const protocol = location.protocol === 'https:' ? 'wss://' : 'ws://';
// ${location.host} localhost:5173
const host = 'localhost:8080';
const brokerUrl = config.brokerUrl || `${protocol}${host}/stomp-endpoint`;
// STOMP 配置
const stompConfig: StompConfig = {
brokerURL: brokerUrl,
connectHeaders: {
login: config.username || '',
passcode: config.password || ''
},
debug: (str: string) => {}, // 关闭调试日志
reconnectDelay: config.reconnectDelay || 5000, // 重连延迟(毫秒)
// 连接成功回调
onConnect: (frame: IFrame) => {
this.onConnected(frame);
},
// 连接失败回调
onStompError: (frame: IFrame) => {
console.error('[STOMP] 服务器错误:', frame);
},
// WebSocket 关闭回调
onWebSocketClose: () => {
this.onConnectionLost();
},
// WebSocket 错误回调
onWebSocketError: (evt: Event) => {
console.error('[STOMP] WebSocket 错误:', evt);
this.handleConnectionError(evt);
}
};
try {
// 创建 STOMP 客户端
this.client = new Client(stompConfig);
// 激活连接
this.client.activate();
console.log('[STOMP] 正在连接至:', brokerUrl);
} catch (error) {
console.error('[STOMP] 连接失败:', error);
this.handleConnectionError(error);
}
}
/**
*
*/
public disconnect(): void {
if (this.client) {
this.client.deactivate();
this.client = null;
this.isConnected = false;
console.log('[STOMP] 已断开连接');
}
}
/**
*
* @param destination
* @param cmd
* @param value
*/
public send(destination: string, cmd: number, value: any): void {
if (!this.client || !this.isConnected) {
console.error('[STOMP] 客户端未连接,无法发送消息');
return;
}
const message: StompMessage = {
cmd,
value
};
try {
this.client.publish({
destination,
body: JSON.stringify(message)
});
// console.log(`[STOMP] 发送消息:${destination}`, message);
} catch (error) {
console.error('[STOMP] 发送消息失败:', error);
}
}
/**
*
* @param destination
* @param callback
*/
public subscribe(destination: string, callback?: (message: StompMessage) => void): void {
if (!this.client || !this.isConnected) {
console.error('[STOMP] 客户端未连接,无法订阅');
return;
}
try {
this.client.subscribe(destination, (message: Message) => {
this.onMessageArrived(message);
});
console.log(`[STOMP] 订阅成功:${destination}`);
// 如果有自定义回调,添加到内部消息处理
if (callback) {
this.services[`_custom_${destination}`] = { callback };
}
} catch (error) {
console.error('[STOMP] 订阅失败:', error);
}
}
/**
*
* @param destination
*/
public unsubscribe(destination: string): void {
if (!this.client) {
return;
}
try {
// STOMP 客户端会自动处理取消订阅
delete this.services[`_custom_${destination}`];
console.log(`[STOMP] 取消订阅:${destination}`);
} catch (error) {
console.error('[STOMP] 取消订阅失败:', error);
}
}
/**
*
* @param frame STOMP
*/
private onConnected(frame: IFrame): void {
this.isConnected = true;
console.log('[STOMP] 连接成功!');
// 订阅默认主题
this.subscribe('/topic/web/read');
// 通知所有服务 STOMP 已就绪
for (const serviceName in this.services) {
if (this.services[serviceName].mqttReady || this.services[serviceName].stompReady) {
const callback =
this.services[serviceName].mqttReady || this.services[serviceName].stompReady;
callback.call(this.services[serviceName]);
}
}
}
/**
*
*/
private onConnectionLost(): void {
this.isConnected = false;
console.log('[STOMP] 连接丢失!');
// 通知所有服务
for (const serviceName in this.services) {
if (this.services[serviceName].onConnectionLost) {
this.services[serviceName].onConnectionLost();
}
}
}
/**
*
* @param message STOMP
*/
private onMessageArrived(message: Message): void {
try {
const msgStr = message.body || '';
const msgObject: StompMessage = JSON.parse(msgStr);
// console.log('[STOMP] 收到消息:', message.destination, msgObject);
// 根据命令类型分发到不同的服务
this.dispatchMessage(msgObject);
// 处理自定义回调
const customService = this.services[`_custom_${message.destination}`];
if (customService && customService.callback) {
customService.callback(msgObject);
}
} catch (error) {
console.error('[STOMP] 消息解析失败:', error);
}
}
/**
*
* @param msgObject
*/
private dispatchMessage(msgObject: StompMessage): void {
switch (msgObject.cmd) {
case MqttCmd.Channel:
// 通道消息
if (this.services.channel) {
this.services.channel.online(msgObject.value.cid, msgObject.value.online);
}
break;
case MqttCmd.NodeInit:
// Node 初始化消息
if (this.services.node) {
this.services.node.msgNodeInit(msgObject.value);
}
break;
case MqttCmd.Node:
console.log('[STOMP] 收到 Node 更新消息:', msgObject.value);
window.vueGlobalFunction(msgObject.value);
// 单一 Node 更新消息
if (this.services.node) {
this.services.nod;
console.log('[STOMP] 收到 Node 更新消息:', msgObject.value);
}
break;
case MqttCmd.User:
// 用户登录消息 - 需要验证
const uid = this.getCookie('uid');
if (msgObject.value.uid !== uid) return;
const clientId = this.getCookie('client-id');
if (msgObject.value.clientid === clientId) return;
// 退出登录
window.location.href = window.location.origin + '/logout';
break;
case MqttCmd.Control:
// 控制返回
this.showToast(msgObject.value);
break;
case MqttCmd.VideoInit:
// 视频初始化
if (this.services.video) {
this.services.video.initVideo(msgObject.value);
}
break;
case MqttCmd.VideoCtl:
// 视频 PTZ 控制
if (this.services.video) {
this.services.video.playVideo(msgObject.value);
}
break;
case MqttCmd.Lock:
// 锁控消息
if (this.services.lock) {
this.services.lock.onMsg(msgObject.value);
}
break;
case MqttCmd.Alarm:
// 告警消息
if (this.services.node) {
if (!this.services.node.runtimes) {
this.services.node.runtimes = {};
}
this.services.node.runtimes[msgObject.value.node.id] = msgObject.value;
}
if (this.services.banner) {
this.services.banner.alarm(msgObject.value);
}
break;
case MqttCmd.Info:
// 通知和提示
this.showToast(msgObject.value);
break;
case MqttCmd.SocketDebugger:
if (this.services.SocketDebugger) {
this.services.SocketDebugger.onMsg(msgObject.value);
}
break;
default:
console.warn('[STOMP] 未知命令类型:', msgObject.cmd);
}
}
/**
*
* @param error
*/
private handleConnectionError(error: any): void {
console.error('[STOMP] 连接错误:', error);
// STOMP 客户端会自动重连,这里只需要通知服务
for (const serviceName in this.services) {
if (this.services[serviceName].onConnectionError) {
this.services[serviceName].onConnectionError(error);
}
}
}
/**
* UUID
*/
private generateUUID(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = (Math.random() * 16) | 0;
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
/**
* Cookie
*/
private getCookie(cname: string): string {
const name = cname + '=';
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i].trim();
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
/**
* Cookie
*/
private setCookie(cname: string, cvalue: string, exdays: number): void {
const d = new Date();
d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
const expires = 'expires=' + d.toUTCString();
document.cookie = cname + '=' + cvalue + '; ' + expires;
}
/**
* Cookie
*/
private clearCookie(name: string): void {
this.setCookie(name, '', -1);
}
/**
*
*/
private showToast(message: any): void {
console.log('[STOMP Toast]:', message);
// 如果使用了 Element Plus
try {
import('element-plus').then(({ ElMessage }) => {
ElMessage.info(typeof message === 'string' ? message : JSON.stringify(message));
});
} catch (e) {
// 如果没有 Element Plus使用 alert
alert(typeof message === 'string' ? message : JSON.stringify(message));
}
}
/**
*
*/
public getClientStatus(): { connected: boolean; client: Client | null } {
return {
connected: this.isConnected,
client: this.client
};
}
}
// 导出单例
export const stompService = new StompService();
// 默认导出
export default stompService;

@ -1,670 +0,0 @@
<template>
<div class="layout-container">
<el-row :gutter="10">
<el-col :span="6">
<el-card style="height: 100%">
<template #header>节点分区</template>
<el-row :gutter="10" style="margin-bottom: 2%">
<el-col :span="24">
<el-input
v-model="filterText"
style="width: 80%; height: 30px"
placeholder="Filter keyword"
/>
</el-col>
</el-row>
<el-row :gutter="10" style="margin-bottom: 4%">
<el-col :span="6">
<el-button type="primary" size="small" @click="dialogFormVisible = true"
>添加</el-button
>
</el-col>
<el-col :span="6">
<el-button type="primary" size="small" @click="getAllTree"></el-button>
</el-col>
</el-row>
<div style="height: 65vh">
<el-scrollbar height="100%">
<el-tree
ref="treeRef"
style="max-width: 100%; height: 100%"
class="filter-tree"
:data="treeData"
:props="defaultProps"
:filter-node-method="filterNode"
highlight-current
:expand-on-click-node="false"
@node-click="handleNodeClick"
>
<template #default="{ node, data }">
<div class="tree-node">
<span class="tree-node-label">{{ node.label }}</span>
<span class="tree-node-actions">
<el-button link type="primary" size="small" @click.stop="handleAdd(data)"
>添加</el-button
>
<el-button link type="primary" size="small" @click.stop="handleEdit(data)"
>编辑</el-button
>
<el-button link type="primary" size="small" @click.stop="handleDelete(data)"
>删除</el-button
>
</span>
</div>
</template>
</el-tree>
</el-scrollbar>
</div>
</el-card>
</el-col>
<el-col :span="11">
<el-card style="height: 100%" class="center-car">
<template #header>节点列表</template>
<el-input
v-model="centerSearch"
style="width: 60%; height: 25px; margin-bottom: 2%"
placeholder="节点名称"
/>
<el-tag type="primary" v-if="treeNodeId">{{ treeNodeName }}</el-tag>
<el-tag type="info" v-else></el-tag>
<el-table
ref="centerTableRef"
@selection-change="handleCenterSelectionChange"
:data="centerFilteredData"
style="width: 100%; height: 73vh"
row-key="modeId"
class="center-table"
>
<el-table-column type="selection" width="30" />
<el-table-column prop="modeId" label="遥 ID" width="70" />
<el-table-column prop="name" label="名称" />
<el-table-column prop="bType" label="类型" width="100">
<template #default="scope">
<el-tag type="primary" v-if="scope.row.bType === 1">{{ '' }}</el-tag>
<el-tag type="success" v-else-if="scope.row.bType === 2">{{ '遥测' }}</el-tag>
<el-tag type="info" v-else-if="scope.row.bType === 3">{{ '遥控' }}</el-tag>
<el-tag type="warning" v-else-if="scope.row.bType === 4">{{ '遥调' }}</el-tag>
<el-tag type="danger" v-else>{{ '' }}</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<!-- -->
<el-col :span="7">
<el-card style="height: 100%">
<template #header>所有节点</template>
<el-input
v-model="search"
style="width: 60%; height: 25px; margin-bottom: 2%"
placeholder="节点名称"
/>
<el-table
ref="rightTableRef"
@selection-change="handleSelectionChange"
:data="filteredData"
style="width: 100%; height: 73vh"
class="right-table"
>
<el-table-column type="selection" width="30" />
<el-table-column prop="modeId" label="遥ID" width="70" />
<el-table-column prop="name" label="名称" />
<el-table-column
v-if="inputTypeTagValue == undefined"
prop="bType"
label="类型筛选"
width="100"
:filters="[
{ text: '遥信', value: 1 },
{ text: '遥测', value: 2 },
{ text: '遥控', value: 3 },
{ text: '遥调', value: 4 },
{ text: '其他', value: 0 }
]"
:filter-method="filterTag"
filter-placement="bottom-end"
filter-confirm-button-text="确定"
filter-reset-button-text="重置"
>
<template #default="scope">
<el-tag type="primary" v-if="scope.row.bType === 1">{{ '' }}</el-tag>
<el-tag type="success" v-else-if="scope.row.bType === 2">{{ '遥测' }}</el-tag>
<el-tag type="info" v-else-if="scope.row.bType === 3">{{ '遥控' }}</el-tag>
<el-tag type="warning" v-else-if="scope.row.bType === 4">{{ '遥调' }}</el-tag>
<el-tag type="danger" v-else>{{ '' }}</el-tag>
</template>
</el-table-column>
<el-table-column v-if="inputTypeTagValue != undefined" label="类型">
<template #default="scope">
<el-tag type="primary" v-if="scope.row.bType === 1">{{ '' }}</el-tag>
<el-tag type="success" v-else-if="scope.row.bType === 2">{{ '遥测' }}</el-tag>
<el-tag type="info" v-else-if="scope.row.bType === 3">{{ '遥控' }}</el-tag>
<el-tag type="warning" v-else-if="scope.row.bType === 4">{{ '遥调' }}</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
</div>
<el-dialog v-model="dialogFormVisible" title="添加树节点" width="500">
<el-form :model="form" :rules="rules" ref="formRef">
<el-form-item label="子节点名" prop="label">
<el-input v-model="form.label" placeholder="请输入子节点名称" />
</el-form-item>
<el-form-item label="父节点">
<el-input-tag
v-model="form.parentIdLable"
disabled
placeholder="默认根节点"
:tag-type="'primary'"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="form.label = ''">重置</el-button>
<el-button type="primary" @click="handleConfirmAdd"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch, onMounted, reactive, computed, nextTick } from 'vue';
import { modelApi } from '@/utils/request';
import { ElMessage } from 'element-plus';
import type { FilterNodeMethodFunction, TreeInstance } from 'element-plus';
import { type DataItem } from '@/components/mt-edit/store/types';
import type { AnyColumns } from 'element-plus/es/components/table-v2/src/types.mjs';
import Sortable from 'sortablejs';
import { fa } from 'element-plus/es/locales.mjs';
interface Tree {
[key: string]: any;
}
interface GridDataItem {
modeId: string;
name: string;
bType: number;
}
interface ExtendedParentWindow {
globalData: Map<string, DataItem> | Record<string, DataItem>;
}
interface ExtendedWindow extends Window {
draggingItems?: GridDataItem[];
}
let dialogFormVisible = ref(false);
const filterText = ref('');
const treeRef = ref<TreeInstance>();
const formRef = ref(); //
let inputTypeTagValue = ref<string>();
const search = ref('');
const centerSearch = ref(''); //
const rightTableRef = ref(); //
const centerTableRef = ref(); //
const gridData = ref<GridDataItem[]>([]);
const centerData = ref<GridDataItem[]>([]); //
let treeNodeId = ref<string | null>(null);
let treeNodeName = ref<string | null>(null);
const filterTag = (value: number, row: any) => {
return row.bType === value;
};
const defaultProps = {
children: 'children',
label: 'label',
parentId: 'parentId'
};
const form = reactive({
nodeId: null,
label: '',
parentIdLable: [] as string[], // 使 el-input-tag
parentId: '' as string
});
//
const rules = {
label: [
{ required: true, message: '请输入子节点名称', trigger: 'blur' },
{ min: 1, max: 50, message: '长度在 1 到 50 个字符', trigger: 'blur' }
]
};
const multipleSelection = ref<GridDataItem[]>([]);
const handleSelectionChange = (val: GridDataItem[]) => {
multipleSelection.value = val;
console.log('右侧表格选中:', multipleSelection.value);
};
const centerSelection = ref<GridDataItem[]>([]);
const handleCenterSelectionChange = (val: GridDataItem[]) => {
centerSelection.value = val;
console.log('中间表格选中:', centerSelection.value);
};
//
const centerFilteredData = computed(() => {
if (!centerSearch.value) {
return centerData.value;
}
return centerData.value.filter((item) => {
return item.name.toLowerCase().includes(centerSearch.value.toLowerCase());
});
});
//
const filteredData = computed(() => {
if (!search.value) {
return gridData.value;
}
return gridData.value.filter((item) => {
return item.name.toLowerCase().includes(search.value.toLowerCase());
});
});
//
function assembleList() {
let code: number | undefined;
if (inputTypeTagValue.value !== undefined) code = getNameForNode(inputTypeTagValue.value);
gridData.value.splice(0, gridData.value.length);
let globalDataRaw = (window as unknown as ExtendedParentWindow).globalData;
if (!globalDataRaw) return;
// globalData Map
if (globalDataRaw instanceof Map) {
// Map
globalDataRaw.forEach((data, key) => {
if (code == undefined || code == data.bType) {
let modeId = key;
let name = data.node.name;
let bType = data.bType;
gridData.value.push({ modeId, name, bType });
}
});
} else {
//
for (const key in globalDataRaw) {
if (Object.prototype.hasOwnProperty.call(globalDataRaw, key)) {
const data = globalDataRaw[key];
if (data && (code == undefined || code == data.bType)) {
let modeId = key;
let name = data.node.name;
let bType = data.bType;
gridData.value.push({ modeId, name, bType });
}
}
}
}
}
function getNameForNode(nodeName: string): number {
switch (nodeName) {
case '遥信':
return 1;
case '遥测':
return 2;
case '遥控':
return 3;
case '遥调':
return 4;
default:
return 0;
}
}
watch(filterText, (val) => {
treeRef.value!.filter(val);
});
const filterNode: FilterNodeMethodFunction = (value: string, data: Tree) => {
if (!value) return true;
return data.label.includes(value);
};
//
const handleAdd = (data: Tree) => {
console.log('添加子节点:', data);
let tag = ' 父节点: ' + data.label;
form.parentIdLable = [tag]; //
form.parentId = data.id;
dialogFormVisible.value = true;
// addTreeNode(data.parentId, data.label);
};
const handleEdit = (data: Tree) => {
console.log('编辑节点:', data);
form.nodeId = data.id;
form.label = data.label;
dialogFormVisible.value = true;
};
//
const handleConfirmAdd = async () => {
if (!formRef.value) return;
await formRef.value.validate(async (valid: boolean) => {
if (!valid) return;
try {
// tag parentId
if (!form.nodeId) {
const parentId = form.parentId ? form.parentId : '0';
await addTreeNode(parentId, form.label);
} else {
await changeTreeNode(form.nodeId, form.label);
}
dialogFormVisible.value = false;
form.label = ''; //
form.parentId = '';
form.nodeId = null;
form.parentIdLable = [];
} catch (error) {
ElMessage.error('添加失败');
}
});
};
//
const handleDelete = (data: Tree) => {
deleteTreeNode(data.id);
};
async function getNodeByCls(nodeClassId: string) {
let response = await modelApi.getNodeByCls_get(nodeClassId);
if (response.code == 200 && response.data != null) {
centerData.value.splice(0, centerData.value.length);
let globalDataRaw = (window as unknown as ExtendedParentWindow).globalData as Map<
string,
DataItem
>;
response.data.forEach((item: any) => {
let dataItem = globalDataRaw.get(item.id.toString());
if (dataItem) {
let data: GridDataItem = {
modeId: dataItem.id.toString(),
name: dataItem.node.name,
bType: dataItem.bType
};
centerData.value.push(data);
}
});
}
}
const handleNodeClick = (data: Tree) => {
console.log('点击节点:', data);
treeNodeId.value = data.id;
treeNodeName.value = data.label;
getNodeByCls(data.id);
};
const treeData = ref<Tree[]>([]);
async function changeTreeNode(id: string, label: string) {
const response = await modelApi.changeTreeNode_post({ id, label });
if (response.code != 200 || response.data == null) {
ElMessage.error(response.message);
} else {
ElMessage.success('修改成功');
getAllTree();
}
}
async function deleteTreeNode(id: string) {
const response = await modelApi.deleteTreeNode_post({ id });
if (response.code != 200 || response.data == null) {
ElMessage.error(response.message);
} else {
ElMessage.success('删除成功');
getAllTree();
}
}
async function addTreeNode(parentId: string, label: string) {
const response = await modelApi.addTreeNode_post({ parentId, label });
if (response.code != 200 || response.data == null) {
ElMessage.error(response.message);
} else {
ElMessage.success('添加成功1');
getAllTree();
}
}
async function getAllTree() {
const response = await modelApi.allTree_get();
if (response.code != 200 || response.data == null) {
ElMessage.error(response.message);
} else {
treeData.value = response.data;
// ElMessage.success('');
}
}
async function changeNodeClass(nodeClassId: string, nodeIds: string[]) {
const response = await modelApi.changeNodeClass_post({ nodeClassId, nodeIds });
if (response.code != 200 || response.data == null) {
ElMessage.error(response.message);
} else {
getNodeByCls(nodeClassId);
ElMessage.success('操作成功');
}
}
onMounted(async () => {
assembleList();
getAllTree();
//
await nextTick();
initDraggable();
});
//
const initDraggable = () => {
// 使 class body
const rightTableBody = document.querySelector('.right-table .el-table__body-wrapper tbody');
const centerTableBody = document.querySelector('.center-table .el-table__body-wrapper tbody');
console.log('右侧表格 body:', rightTableBody);
console.log('中间表格 body:', centerTableBody);
if (!rightTableBody || !centerTableBody) {
console.error('未找到表格元素');
return;
}
//
Sortable.create(rightTableBody as HTMLElement, {
group: {
name: 'shared',
pull: 'clone', //
put: false //
},
animation: 150,
ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen',
dragClass: 'sortable-drag',
onEnd: (evt: any) => {
console.log('右侧表格拖拽结束', evt);
if (!treeNodeId.value || treeNodeId.value==''){
ElMessage.warning('请先选择树节点');
return;
}
// Sortable.js clone bug
// Sortable DOM
//
const { target, clone, item } = evt;
if (target && clone && item) {
//
target.insertBefore(item, clone);
//
target.removeChild(clone);
}
//
const isFromRightTable = evt.from === rightTableBody;
const isToCenterTable = evt.to === centerTableBody;
//
if (isFromRightTable && isToCenterTable) {
// 使使
const itemsToAdd =
multipleSelection.value.length > 0
? multipleSelection.value
: [gridData.value[evt.oldIndex]];
let addedCount = 0;
let nodeIds: string[] = [];
itemsToAdd.forEach((item) => {
if (!centerData.value.find((d) => d.modeId === item.modeId)) {
//
// centerData.value.push({ ...item });
nodeIds.push(item.modeId);
addedCount++;
}
});
if (addedCount > 0) {
// ID:
console.log('已添加的节点 ID:', nodeIds);
changeNodeClass(treeNodeId.value, nodeIds);
ElMessage.success(`已添加 ${addedCount} 项到节点列表`);
//
if (rightTableRef.value) {
rightTableRef.value.clearSelection();
}
} else {
ElMessage.info('所有选中项已存在');
}
}
}
});
//
Sortable.create(centerTableBody as HTMLElement, {
group: {
name: 'shared',
pull: false, //
put: true //
},
// animation: 150,
// ghostClass: 'sortable-ghost',
// chosenClass: 'sortable-chosen',
// dragClass: 'sortable-drag',
onAdd: (evt: any) => {
console.log('中间表格 onAdd', evt);
//
//
if (evt.from !== centerTableBody) {
// Sortable DOM
// Vue
const draggedElement = evt.item;
if (draggedElement && draggedElement.parentNode) {
draggedElement.parentNode.removeChild(draggedElement);
}
}
},
onEnd: (evt: any) => {
console.log('中间表格拖拽结束', evt);
if (evt.from === centerTableBody && evt.to !== centerTableBody) {
//
centerData.value.splice(evt.oldIndex, 1);
ElMessage.info('已移除');
}
}
});
};
</script>
<style scoped>
.layout-container {
width: 100%;
height: 100%;
overflow: hidden;
}
/* 修复 el-row gutter 导致的横向滚动条 */
:deep(.el-row) {
margin-left: 0 !important;
margin-right: 0 !important;
}
/* 树节点样式 */
.tree-node {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding-right: 8px;
}
.tree-node-label {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tree-node-actions {
display: flex;
gap: 4px;
opacity: 0;
transition: opacity 0.3s;
}
/* 鼠标悬停时显示操作按钮 */
.tree-node:hover .tree-node-actions {
opacity: 1;
}
/* 拖拽样式 */
.sortable-ghost {
opacity: 0.4;
background-color: #f5f7fa;
border: 2px dashed #409eff;
}
.sortable-chosen {
background-color: #ecf5ff;
cursor: grabbing !important;
}
.sortable-drag {
opacity: 0.8;
}
/* 表格行可拖拽样式 */
:deep(.right-table .el-table__row),
:deep(.center-car .el-table__row),
:deep(.center-table .el-table__row) {
cursor: grab;
}
:deep(.right-table .el-table__row:hover),
:deep(.center-car .el-table__row:hover),
:deep(.center-table .el-table__row:hover) {
/* background-color: #f5f7fa; */
}
</style>

@ -1,201 +0,0 @@
<template>
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { genExportJson, useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { objectDeepClone, randomString } from '@/components/mt-edit/utils/index';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
import type { IDoneJson } from '@/components/mt-edit/store/types';
const route = useRoute();
console.log('参数:', route.query.screen);
let drawerVisible = ref(false);
let fileNames: Array<{ id: string; name: string }> = reactive([]);
let radio = ref('-1');
//
let randomString1 = randomString();
//
function fileRead() {
fetch('/dataModes/index.json')
.then((response) => response.json())
.then((data) => {
fileNames = Object.assign(data);
})
.catch((error) => {
console.error('获取JSON文件错误', error);
});
}
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
//
function extractValFromProps(props: any) {
const result: Record<string, any> = {};
for (const key in props) {
if (props[key] && typeof props[key] === 'object' && 'val' in props[key]) {
result[key] = props[key].val;
}
}
return result;
}
//
function loadModeData() {
console.log('文件', route.query.screen);
console.log('xx:', globalStore.group_ids.get(route.query.screen as string));
if (globalStore.group_ids.get(route.query.screen as string)) {
let json: Array<IDoneJson> = objectDeepClone(
globalStore.group_ids.get(route.query.screen as string) || []
);
console.log('json1', json);
let endJson = {
canvasCfg: globalStore.canvasCfg,
gridCfg: globalStore.gridCfg,
json: json
};
console.log('endJson', endJson);
MtPreviewRef.value?.setImportJson(endJson);
}
}
function initLoad() {
let canvasCfg = globalStore.canvasCfg;
let gridCfg = globalStore.gridCfg;
// let json = globalStore.done_json;
let json: Array<any> = objectDeepClone(globalStore.done_json);
globalStore.done_json.forEach((item) => {
const extractedProps = extractValFromProps(item.props);
json.forEach((obj) => {
if (obj.id === item.id) {
obj.props = extractedProps;
}
});
});
let endJson = {
canvasCfg: canvasCfg,
gridCfg: gridCfg,
json: json
};
console.log('endJson', endJson);
MtPreviewRef.value?.setImportJson(endJson);
}
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
// globalStore.group_ids.set(route.query.screen as string, processedImportDoneJson);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onUnmounted(() => {
console.log('view卸载完毕');
});
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
//
function loadModel() {
console.log('选中:', radio.value, radio);
if (!radio.value || radio.value == '-1') {
ElMessage.warning('请先选择一个模型文件');
}
fileNames.forEach((item) => {
if (item.id == radio.value) {
fetch(`/dataModes/${item.name}`)
.then((response) => response.json())
.then((data) => {
console.log('文件内容:', data);
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(data);
globalStore.canvasCfg = canvasCfg;
globalStore.gridCfg = gridCfg;
globalStore.setGlobalStoreDoneJson(importDoneJson);
initLoad();
})
.catch((error) => {
ElMessage.error('获取文件错误:', error);
});
}
});
}
function test2() {
console.log('test3', globalStore);
}
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>

@ -1,202 +0,0 @@
<template>
<!-- <button @click="test2"></button> -->
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { genExportJson, useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { objectDeepClone, randomString } from '@/components/mt-edit/utils/index';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
import type { IDoneJson } from '@/components/mt-edit/store/types';
const route = useRoute();
console.log('参数:', route.query.screen);
let drawerVisible = ref(false);
let fileNames: Array<{ id: string; name: string }> = reactive([]);
let radio = ref('-1');
//
let randomString1 = randomString();
//
function fileRead() {
fetch('/dataModes/index.json')
.then((response) => response.json())
.then((data) => {
fileNames = Object.assign(data);
})
.catch((error) => {
console.error('获取JSON文件错误', error);
});
}
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
//
function extractValFromProps(props: any) {
const result: Record<string, any> = {};
for (const key in props) {
if (props[key] && typeof props[key] === 'object' && 'val' in props[key]) {
result[key] = props[key].val;
}
}
return result;
}
//
function loadModeData() {
console.log('文件', route.query.screen);
console.log('xx:', globalStore.group_ids.get(route.query.screen as string));
if (globalStore.group_ids.get(route.query.screen as string)) {
let json: Array<IDoneJson> = objectDeepClone(
globalStore.group_ids.get(route.query.screen as string) || []
);
console.log('json1', json);
let endJson = {
canvasCfg: globalStore.canvasCfg,
gridCfg: globalStore.gridCfg,
json: json
};
console.log('endJson', endJson);
MtPreviewRef.value?.setImportJson(endJson);
}
}
function initLoad() {
let canvasCfg = globalStore.canvasCfg;
let gridCfg = globalStore.gridCfg;
// let json = globalStore.done_json;
let json: Array<any> = objectDeepClone(globalStore.done_json);
globalStore.done_json.forEach((item) => {
const extractedProps = extractValFromProps(item.props);
json.forEach((obj) => {
if (obj.id === item.id) {
obj.props = extractedProps;
}
});
});
let endJson = {
canvasCfg: canvasCfg,
gridCfg: gridCfg,
json: json
};
console.log('endJson', endJson);
MtPreviewRef.value?.setImportJson(endJson);
}
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
// globalStore.group_ids.set(route.query.screen as string, processedImportDoneJson);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onUnmounted(() => {
console.log('view卸载完毕');
});
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
//
function loadModel() {
console.log('选中:', radio.value, radio);
if (!radio.value || radio.value == '-1') {
ElMessage.warning('请先选择一个模型文件');
}
fileNames.forEach((item) => {
if (item.id == radio.value) {
fetch(`/dataModes/${item.name}`)
.then((response) => response.json())
.then((data) => {
console.log('文件内容:', data);
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(data);
globalStore.canvasCfg = canvasCfg;
globalStore.gridCfg = gridCfg;
globalStore.setGlobalStoreDoneJson(importDoneJson);
initLoad();
})
.catch((error) => {
ElMessage.error('获取文件错误:', error);
});
}
});
}
function test2() {
console.log('test3', globalStore);
}
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>

@ -1,168 +0,0 @@
<template>
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { genExportJson, useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { objectDeepClone, randomString } from '@/components/mt-edit/utils/index';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
import type { IDoneJson } from '@/components/mt-edit/store/types';
const route = useRoute();
console.log('参数:', route.query.screen);
let drawerVisible = ref(false);
let fileNames: Array<{ id: string; name: string }> = reactive([]);
let radio = ref('-1');
//
let randomString1 = randomString();
//
function fileRead() {
fetch('/dataModes/index.json')
.then((response) => response.json())
.then((data) => {
fileNames = Object.assign(data);
})
.catch((error) => {
console.error('获取JSON文件错误', error);
});
}
//
function loadModeData() {
console.log('文件', route.query.screen);
console.log('xx:', globalStore.group_ids.get(route.query.screen as string));
if (globalStore.group_ids.get(route.query.screen as string)) {
let json: Array<IDoneJson> = objectDeepClone(
globalStore.group_ids.get(route.query.screen as string) || ([] as IDoneJson[])
);
console.log('json1', json);
let endJson = {
canvasCfg: globalStore.canvasCfg,
gridCfg: globalStore.gridCfg,
json: json
};
console.log('endJson', endJson);
MtPreviewRef.value?.setImportJson(endJson);
}
}
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
//
function extractValFromProps(props: any) {
const result: Record<string, any> = {};
for (const key in props) {
if (props[key] && typeof props[key] === 'object' && 'val' in props[key]) {
result[key] = props[key].val;
}
}
return result;
}
function initLoad() {
let canvasCfg = globalStore.canvasCfg;
let gridCfg = globalStore.gridCfg;
// let json = globalStore.done_json;
let json: Array<any> = objectDeepClone(globalStore.done_json);
globalStore.done_json.forEach((item) => {
const extractedProps = extractValFromProps(item.props);
json.forEach((obj) => {
if (obj.id === item.id) {
obj.props = extractedProps;
}
});
});
let endJson = {
canvasCfg: canvasCfg,
gridCfg: gridCfg,
json: json
};
MtPreviewRef.value?.setImportJson(endJson);
}
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = await response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
// globalStore.group_ids.set(route.query.screen as string, processedImportDoneJson);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onUnmounted(() => {
console.log('view卸载完毕');
});
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>

@ -1,91 +0,0 @@
<template>
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
const route = useRoute();
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
onUnmounted(() => {
console.log('view卸载完毕');
});
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = await response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
globalStore.group_ids.set(
route.query.screen as string,
processedImportDoneJson.map((item) => item.id)
);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>

@ -1,91 +0,0 @@
<template>
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
const route = useRoute();
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
onUnmounted(() => {
console.log('view卸载完毕');
});
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = await response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
globalStore.group_ids.set(
route.query.screen as string,
processedImportDoneJson.map((item) => item.id)
);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>

@ -1,93 +0,0 @@
<template>
<mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack"></mt-preview>
</template>
<!-- 2号主变 -->
<script setup lang="ts">
// keep-alive
defineOptions({
name: 'PreviewIndex'
});
import { MtPreview } from '@/export';
import { onMounted, ref, reactive, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { globalStore } from '@/components/mt-edit/store/global';
import { useExportJsonToDoneJson } from '@/components/mt-edit/composables';
import { useRoute } from 'vue-router';
import { modelApi } from '@/utils/request';
const route = useRoute();
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>();
const onEventCallBack = (type: string, item_id: string) => {
console.log(type, item_id);
if (type == 'test-dialog') {
ElMessage.success(`获取到了id:${item_id}`);
}
};
onUnmounted(() => {
console.log('view卸载完毕');
});
async function newLoadModel() {
let endJson = {
menuType: route.query.screen
};
try {
const response = await modelApi.model_getModelData_post(endJson);
if (response.code == 200) {
const result = await response.data;
const { canvasCfg, gridCfg, importDoneJson } = useExportJsonToDoneJson(result);
// importDoneJson props 使 reactive
const processedImportDoneJson = importDoneJson.map((item) => {
if (item.props) {
return {
...item,
props: reactive(item.props || {})
};
}
return {
...item,
props: reactive(item.props || {})
};
});
console.log('processedImportDoneJson:', processedImportDoneJson);
MtPreviewRef.value?.setNewImportJson({ canvasCfg, gridCfg, json: processedImportDoneJson });
if (globalStore.group_ids.has(route.query.screen as string)) {
globalStore.group_ids.delete(route.query.screen as string);
}
globalStore.group_ids.set(
route.query.screen as string,
processedImportDoneJson.map((item) => item.id)
);
ElMessage.success('数据模型加载成功');
} else {
ElMessage.error(`数据模型加载失败: ${response.code} - ${response.message}`);
}
} catch (error) {
console.error('请求错误:', error);
ElMessage.error('网络请求失败');
}
}
onMounted(() => {
console.log('view挂载完毕');
newLoadModel();
});
</script>
<style scoped>
.vertical-radio-group {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
</style>

@ -51,6 +51,7 @@ const onEventCallBack = (type: string, item_id: string) => {
// //
function extractValFromProps(props: any) { function extractValFromProps(props: any) {
const result: Record<string, any> = {}; const result: Record<string, any> = {};
for (const key in props) { for (const key in props) {
if (props[key] && typeof props[key] === 'object' && 'val' in props[key]) { if (props[key] && typeof props[key] === 'object' && 'val' in props[key]) {
result[key] = props[key].val; result[key] = props[key].val;

@ -0,0 +1 @@
.vertical-radio-group[data-v-67a3c190]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}

@ -0,0 +1 @@
import{d as q,aP as N,r as C,x as y,$ as R,Z as S,a as b,g as m,h as p,w as _,av as M,F as k,aw as F,O as r,I as d,as as v,o as J,b as L,q as x,t as D,A as T,X as U,i as $,Y as A,_ as O}from"./index-9847718b.js";import{u as E}from"./index-fd059ba6.js";import{M as G}from"./index-868f5209.js";const X={class:"drawer-footer"},Y=q({name:"PreviewIndex",__name:"floor",setup(Z){const g=N();console.log("参数:",g.query.screen);let u=C(!1),V=y([]),a=C("-1");U();const w=C(),h=(s,e)=>{console.log(s,e),s=="test-dialog"&&d.success(`获取到了id:${e}`)};function I(s){const e={};for(const o in s)s[o]&&typeof s[o]=="object"&&"val"in s[o]&&(e[o]=s[o].val);return e}function P(){var l;let s=r.canvasCfg,e=r.gridCfg,o=A(r.done_json);r.done_json.forEach(c=>{const n=I(c.props);o.forEach(i=>{i.id===c.id&&(i.props=n)})});let t={canvasCfg:s,gridCfg:e,json:o};console.log("endJson",t),(l=w.value)==null||l.setImportJson(t)}async function j(){var e;let s={menuType:g.query.screen};try{const o=await F.model_getModelData_post(s);if(o.code==200){const t=o.data,{canvasCfg:l,gridCfg:c,importDoneJson:n}=E(t),i=n.map(f=>f.props?{...f,props:y(f.props||{})}:{...f,props:y(f.props||{})});console.log("processedImportDoneJson:",i),(e=w.value)==null||e.setNewImportJson({canvasCfg:l,gridCfg:c,json:i}),r.group_ids.has(g.query.screen)&&r.group_ids.delete(g.query.screen),d.success("数据模型加载成功")}else d.error(`数据模型加载失败: ${o.code} - ${o.message}`)}catch(o){console.error("请求错误:",o),d.error("网络请求失败")}}R(()=>{console.log("view卸载完毕")}),S(()=>{console.log("view挂载完毕"),j()});function B(){console.log("选中:",a.value,a),(!a.value||a.value=="-1")&&d.warning("请先选择一个模型文件"),V.forEach(s=>{s.id==a.value&&fetch(`/dataModes/${s.name}`).then(e=>e.json()).then(e=>{console.log("文件内容:",e);const{canvasCfg:o,gridCfg:t,importDoneJson:l}=E(e);r.canvasCfg=o,r.gridCfg=t,r.setGlobalStoreDoneJson(l),P()}).catch(e=>{d.error("获取文件错误:",e)})})}return(s,e)=>{const o=v("el-radio"),t=v("el-radio-group"),l=v("el-button"),c=v("el-drawer");return J(),b(k,null,[m(p(G),{ref_key:"MtPreviewRef",ref:w,onOnEventCallBack:h},null,512),m(c,{modelValue:p(u),"onUpdate:modelValue":e[1]||(e[1]=n=>M(u)?u.value=n:u=n),modal:!1,title:"数据模型文件","modal-penetrable":""},{footer:_(()=>[L("div",X,[m(l,{onClick:B},{default:_(()=>[...e[2]||(e[2]=[x("加载模型11",-1)])]),_:1})])]),default:_(()=>[m(t,{class:"vertical-radio-group",modelValue:p(a),"onUpdate:modelValue":e[0]||(e[0]=n=>M(a)?a.value=n:a=n)},{default:_(()=>[x(D(p(u))+" ",1),(J(!0),b(k,null,T(p(V),n=>(J(),$(o,{key:n.id,label:n.id},{default:_(()=>[x(D(n.name),1)]),_:2},1032,["label"]))),128))]),_:1},8,["modelValue"])]),_:1},8,["modelValue"])],64)}}});const Q=O(Y,[["__scopeId","data-v-67a3c190"]]);export{Q as default};

@ -0,0 +1 @@
.vertical-radio-group[data-v-bdccb96b]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}

@ -0,0 +1 @@
import{d as m,aP as v,r as M,$ as b,Z as y,aw as w,x as p,O as c,I as a,i as J,h as x,o as k,_ as q}from"./index-9847718b.js";import{u as C}from"./index-fd059ba6.js";import{M as D}from"./index-868f5209.js";const I=m({name:"globalMessage",__name:"globalMessage",setup(h){const r=v();console.log("参数11",r.query.screen);const l=M(),u=(n,o)=>{console.log(n,o),n=="test-dialog"&&a.success(`获取到了id:${o}`)};b(()=>{console.log("view卸载完毕")}),y(()=>{d()});async function d(){var o;let n={menuType:r.query.screen};try{const s=await w.model_getModelData_post(n);if(s.code==200){const _=await s.data,{canvasCfg:g,gridCfg:i,importDoneJson:f}=C(_),t=f.map(e=>e.props?{...e,props:p(e.props||{})}:{...e,props:p(e.props||{})});console.log("processedImportDoneJson:",t),(o=l.value)==null||o.setNewImportJson({canvasCfg:g,gridCfg:i,json:t}),c.group_ids.has(r.query.screen)&&c.group_ids.delete(r.query.screen),c.group_ids.set(r.query.screen,t.map(e=>e.id)),a.success("数据模型加载成功")}else a.error(`数据模型加载失败: ${s.code} - ${s.message}`)}catch(s){console.error("请求错误:",s),a.error("网络请求失败")}}return(n,o)=>(k(),J(x(D),{ref_key:"MtPreviewRef",ref:l,onOnEventCallBack:u},null,512))}});const $=q(I,[["__scopeId","data-v-bdccb96b"]]);export{$ as default};

@ -0,0 +1 @@
import{d as g,aP as v,r as y,$ as w,Z as x,aw as M,x as l,O as c,I as a,i as h,h as E,o as J,_ as k}from"./index-9847718b.js";import{u as C}from"./index-fd059ba6.js";import{M as D}from"./index-868f5209.js";const I=g({__name:"homeExceptionFacility",setup(q){const n=v(),p=y(),d=(r,o)=>{console.log(r,o),r=="test-dialog"&&a.success(`获取到了id:${o}`)};w(()=>{console.log("view卸载完毕")}),x(()=>{i()});async function i(){var o;let r={menuType:n.query.screen};try{const s=await M.model_getModelData_post(r);if(s.code==200){const u=await s.data,{canvasCfg:_,gridCfg:f,importDoneJson:m}=C(u),t=m.map(e=>e.props?{...e,props:l(e.props||{})}:{...e,props:l(e.props||{})});console.log("processedImportDoneJson:",t),(o=p.value)==null||o.setNewImportJson({canvasCfg:_,gridCfg:f,json:t}),c.group_ids.has(n.query.screen)&&c.group_ids.delete(n.query.screen),c.group_ids.set(n.query.screen,t.map(e=>e.id)),a.success("数据模型加载成功")}else a.error(`数据模型加载失败: ${s.code} - ${s.message}`)}catch(s){console.error("请求错误:",s),a.error("网络请求失败")}}return(r,o)=>(J(),h(E(D),{ref_key:"MtPreviewRef",ref:p,onOnEventCallBack:d},null,512))}});const b=k(I,[["__scopeId","data-v-d872abad"]]);export{b as default};

@ -0,0 +1 @@
.vertical-radio-group[data-v-d872abad]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}

@ -0,0 +1 @@
import{d as g,aP as v,r as M,$ as w,Z as y,aw as h,x as u,O as c,I as a,i as J,h as x,o as O,_ as k}from"./index-9847718b.js";import{u as C}from"./index-fd059ba6.js";import{M as D}from"./index-868f5209.js";const I=g({name:"homeOverrunMessage",__name:"homeOverrunMessage",setup(q){const n=v(),p=M(),l=(r,o)=>{console.log(r,o),r=="test-dialog"&&a.success(`获取到了id:${o}`)};w(()=>{console.log("view卸载完毕")}),y(()=>{d()});async function d(){var o;let r={menuType:n.query.screen};try{const s=await h.model_getModelData_post(r);if(s.code==200){const _=await s.data,{canvasCfg:f,gridCfg:i,importDoneJson:m}=C(_),t=m.map(e=>e.props?{...e,props:u(e.props||{})}:{...e,props:u(e.props||{})});console.log("processedImportDoneJson:",t),(o=p.value)==null||o.setNewImportJson({canvasCfg:f,gridCfg:i,json:t}),c.group_ids.has(n.query.screen)&&c.group_ids.delete(n.query.screen),c.group_ids.set(n.query.screen,t.map(e=>e.id)),a.success("数据模型加载成功")}else a.error(`数据模型加载失败: ${s.code} - ${s.message}`)}catch(s){console.error("请求错误:",s),a.error("网络请求失败")}}return(r,o)=>(O(),J(x(D),{ref_key:"MtPreviewRef",ref:p,onOnEventCallBack:l},null,512))}});const $=k(I,[["__scopeId","data-v-436f0bc5"]]);export{$ as default};

@ -0,0 +1 @@
.vertical-radio-group[data-v-436f0bc5]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}

@ -0,0 +1 @@
import{d as B,aP as N,r as C,x as y,$ as R,Z as S,a as b,g as m,h as _,w as g,av as h,F as M,aw as F,O as a,I as i,as as v,o as J,b as L,q as x,t as k,A as T,X as U,i as $,Y as A,_ as O}from"./index-9847718b.js";import{u as D}from"./index-fd059ba6.js";import{M as G}from"./index-868f5209.js";const X={class:"drawer-footer"},Y=B({name:"PreviewIndex",__name:"host",setup(Z){const f=N();console.log("参数:",f.query.screen);let p=C(!1),V=y([]),r=C("-1");U();const w=C(),E=(s,e)=>{console.log(s,e),s=="test-dialog"&&i.success(`获取到了id:${e}`)};function I(s){const e={};for(const o in s)s[o]&&typeof s[o]=="object"&&"val"in s[o]&&(e[o]=s[o].val);return e}function P(){var l;let s=a.canvasCfg,e=a.gridCfg,o=A(a.done_json);a.done_json.forEach(c=>{const n=I(c.props);o.forEach(u=>{u.id===c.id&&(u.props=n)})});let t={canvasCfg:s,gridCfg:e,json:o};console.log("endJson",t),(l=w.value)==null||l.setImportJson(t)}async function j(){var e;let s={menuType:f.query.screen};try{const o=await F.model_getModelData_post(s);if(o.code==200){const t=o.data,{canvasCfg:l,gridCfg:c,importDoneJson:n}=D(t),u=n.map(d=>d.props?{...d,props:y(d.props||{})}:{...d,props:y(d.props||{})});console.log("processedImportDoneJson:",u),(e=w.value)==null||e.setNewImportJson({canvasCfg:l,gridCfg:c,json:u}),a.group_ids.has(f.query.screen)&&a.group_ids.delete(f.query.screen),a.group_ids.set(f.query.screen,u.map(d=>d.id)),i.success("数据模型加载成功")}else i.error(`数据模型加载失败: ${o.code} - ${o.message}`)}catch(o){console.error("请求错误:",o),i.error("网络请求失败")}}R(()=>{console.log("view卸载完毕")}),S(()=>{console.log("view挂载完毕"),j()});function q(){console.log("选中:",r.value,r),(!r.value||r.value=="-1")&&i.warning("请先选择一个模型文件"),V.forEach(s=>{s.id==r.value&&fetch(`/dataModes/${s.name}`).then(e=>e.json()).then(e=>{console.log("文件内容:",e);const{canvasCfg:o,gridCfg:t,importDoneJson:l}=D(e);a.canvasCfg=o,a.gridCfg=t,a.setGlobalStoreDoneJson(l),P()}).catch(e=>{i.error("获取文件错误:",e)})})}return(s,e)=>{const o=v("el-radio"),t=v("el-radio-group"),l=v("el-button"),c=v("el-drawer");return J(),b(M,null,[m(_(G),{ref_key:"MtPreviewRef",ref:w,onOnEventCallBack:E},null,512),m(c,{modelValue:_(p),"onUpdate:modelValue":e[1]||(e[1]=n=>h(p)?p.value=n:p=n),modal:!1,title:"数据模型文件","modal-penetrable":""},{footer:g(()=>[L("div",X,[m(l,{onClick:q},{default:g(()=>[...e[2]||(e[2]=[x("加载模型11",-1)])]),_:1})])]),default:g(()=>[m(t,{class:"vertical-radio-group",modelValue:_(r),"onUpdate:modelValue":e[0]||(e[0]=n=>h(r)?r.value=n:r=n)},{default:g(()=>[x(k(_(p))+" ",1),(J(!0),b(M,null,T(_(V),n=>(J(),$(o,{key:n.id,label:n.id},{default:g(()=>[x(k(n.name),1)]),_:2},1032,["label"]))),128))]),_:1},8,["modelValue"])]),_:1},8,["modelValue"])],64)}}});const Q=O(Y,[["__scopeId","data-v-d0f0d48f"]]);export{Q as default};

@ -0,0 +1 @@
.vertical-radio-group[data-v-d0f0d48f]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}

@ -0,0 +1 @@
import{d as D,r as p,x as N,$ as I,Z as O,a as M,q as u,t as v,h as i,b as j,g as f,w as c,av as C,F as y,O as s,Y as R,as as g,o as x,A as F,X as U,I as w,i as L,_ as T}from"./index-9847718b.js";import{u as $}from"./index-fd059ba6.js";import{M as q}from"./index-868f5209.js";const A={class:"drawer-footer"},G=D({name:"PreviewIndex",__name:"index",setup(X){let l=p(!1),m=N([]),a=p("-1"),E=U();function J(){fetch("/dataModes/index.json").then(o=>o.json()).then(o=>{m=Object.assign(o)}).catch(o=>{console.error("获取JSON文件错误",o)})}const b=p(),B=(o,e)=>{console.log(o,e),o=="test-dialog"&&w.success(`获取到了id:${e}`)};function P(o){const e={};for(const n in o)o[n]&&typeof o[n]=="object"&&"val"in o[n]&&(e[n]=o[n].val);return e}function k(){var d;let o=s.canvasCfg,e=s.gridCfg,n=R(s.done_json);s.done_json.forEach(_=>{const t=P(_.props);n.forEach(V=>{V.id===_.id&&(V.props=t)})});let r={canvasCfg:o,gridCfg:e,json:n};console.log("endJson",r),(d=b.value)==null||d.setImportJson(r)}I(()=>{console.log("view卸载完毕")}),O(()=>{console.log("view挂载完毕"),J(),k()});function S(){console.log("选中:",a.value,a),(!a.value||a.value=="-1")&&w.warning("请先选择一个模型文件"),m.forEach(o=>{o.id==a.value&&fetch(`/dataModes/${o.name}`).then(e=>e.json()).then(e=>{console.log("文件内容:",e);const{canvasCfg:n,gridCfg:r,importDoneJson:d}=$(e);s.canvasCfg=n,s.gridCfg=r,s.setGlobalStoreDoneJson(d),k()}).catch(e=>{w.error("获取文件错误:",e)})})}function h(){console.log("test3",s)}return(o,e)=>{const n=g("el-button"),r=g("el-radio"),d=g("el-radio-group"),_=g("el-drawer");return x(),M(y,null,[u(v(i(E))+" ",1),j("button",{onClick:h},"查看pina数据"),f(n,{type:"primary",onClick:e[0]||(e[0]=t=>C(l)?l.value=!0:l=!0)},{default:c(()=>[...e[3]||(e[3]=[u(" 数据文件222 ",-1)])]),_:1}),f(i(q),{ref_key:"MtPreviewRef",ref:b,onOnEventCallBack:B},null,512),f(_,{modelValue:i(l),"onUpdate:modelValue":e[2]||(e[2]=t=>C(l)?l.value=t:l=t),modal:!1,title:"数据模型文件","modal-penetrable":""},{footer:c(()=>[j("div",A,[f(n,{onClick:S},{default:c(()=>[...e[4]||(e[4]=[u("加载模型11",-1)])]),_:1})])]),default:c(()=>[f(d,{class:"vertical-radio-group",modelValue:i(a),"onUpdate:modelValue":e[1]||(e[1]=t=>C(a)?a.value=t:a=t)},{default:c(()=>[u(v(i(l))+" ",1),(x(!0),M(y,null,F(i(m),t=>(x(),L(r,{key:t.id,label:t.id},{default:c(()=>[u(v(t.name),1)]),_:2},1032,["label"]))),128))]),_:1},8,["modelValue"])]),_:1},8,["modelValue"])],64)}}});const H=T(G,[["__scopeId","data-v-d1648c7a"]]);export{H as default};

@ -0,0 +1 @@
.common-layout[data-v-635be2c1]{height:100vh;display:flex;align-items:center;justify-content:center}.layout-container[data-v-635be2c1]{width:100%;height:100vh;display:flex;flex-direction:column}.header-part[data-v-635be2c1]{height:18.75vh;background-color:#b3c0d1;display:flex;align-items:center;justify-content:center;font-size:36px;font-weight:700;color:#333}.main-part[data-v-635be2c1]{height:74.21875vh;background-color:#e9eef3;display:flex;align-items:center;justify-content:center;font-size:18px;color:#333}.footer-part[data-v-635be2c1]{height:7.03125vh;background-color:#d3dce6;padding:0!important;margin:0!important;color:#333;margin-top:0}.footer-part-col[data-v-635be2c1]{height:100%;background-color:#333;color:#606266;border:3px solid rgb(206,12,12);border-radius:4px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700}

@ -0,0 +1 @@
.vertical-radio-group[data-v-d1648c7a]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}

@ -0,0 +1 @@
import{d as q,aP as N,r as C,x,$ as R,Z as S,a as b,g as m,h as p,w as _,av as M,F as k,aw as F,O as r,I as c,as as v,o as y,b as L,q as J,t as D,A as T,X as U,i as $,Y as A,_ as O}from"./index-9847718b.js";import{u as E}from"./index-fd059ba6.js";import{M as G}from"./index-868f5209.js";const X={class:"drawer-footer"},Y=q({name:"PreviewIndex",__name:"index",setup(Z){const g=N();console.log("参数:",g.query.screen);let i=C(!1),V=x([]),a=C("-1");U();const w=C(),h=(n,e)=>{console.log(n,e),n=="test-dialog"&&c.success(`获取到了id:${e}`)};function I(n){const e={};for(const o in n)n[o]&&typeof n[o]=="object"&&"val"in n[o]&&(e[o]=n[o].val);return e}function P(){var l;let n=r.canvasCfg,e=r.gridCfg,o=A(r.done_json);r.done_json.forEach(d=>{const s=I(d.props);o.forEach(u=>{u.id===d.id&&(u.props=s)})});let t={canvasCfg:n,gridCfg:e,json:o};console.log("endJson",t),(l=w.value)==null||l.setImportJson(t)}async function j(){var e;let n={menuType:g.query.screen};try{const o=await F.model_getModelData_post(n);if(o.code==200){const t=await o.data,{canvasCfg:l,gridCfg:d,importDoneJson:s}=E(t),u=s.map(f=>f.props?{...f,props:x(f.props||{})}:{...f,props:x(f.props||{})});console.log("processedImportDoneJson:",u),(e=w.value)==null||e.setNewImportJson({canvasCfg:l,gridCfg:d,json:u}),r.group_ids.has(g.query.screen)&&r.group_ids.delete(g.query.screen),c.success("数据模型加载成功")}else c.error(`数据模型加载失败: ${o.code} - ${o.message}`)}catch(o){console.error("请求错误:",o),c.error("网络请求失败")}}R(()=>{console.log("view卸载完毕")}),S(()=>{console.log("view挂载完毕"),j()});function B(){console.log("选中:",a.value,a),(!a.value||a.value=="-1")&&c.warning("请先选择一个模型文件"),V.forEach(n=>{n.id==a.value&&fetch(`/dataModes/${n.name}`).then(e=>e.json()).then(e=>{console.log("文件内容:",e);const{canvasCfg:o,gridCfg:t,importDoneJson:l}=E(e);r.canvasCfg=o,r.gridCfg=t,r.setGlobalStoreDoneJson(l),P()}).catch(e=>{c.error("获取文件错误:",e)})})}return(n,e)=>{const o=v("el-radio"),t=v("el-radio-group"),l=v("el-button"),d=v("el-drawer");return y(),b(k,null,[m(p(G),{ref_key:"MtPreviewRef",ref:w,onOnEventCallBack:h},null,512),m(d,{modelValue:p(i),"onUpdate:modelValue":e[1]||(e[1]=s=>M(i)?i.value=s:i=s),modal:!1,title:"数据模型文件","modal-penetrable":""},{footer:_(()=>[L("div",X,[m(l,{onClick:B},{default:_(()=>[...e[2]||(e[2]=[J("加载模型11",-1)])]),_:1})])]),default:_(()=>[m(t,{class:"vertical-radio-group",modelValue:p(a),"onUpdate:modelValue":e[0]||(e[0]=s=>M(a)?a.value=s:a=s)},{default:_(()=>[J(D(p(i))+" ",1),(y(!0),b(k,null,T(p(V),s=>(y(),$(o,{key:s.id,label:s.id},{default:_(()=>[J(D(s.name),1)]),_:2},1032,["label"]))),128))]),_:1},8,["modelValue"])]),_:1},8,["modelValue"])],64)}}});const Q=O(Y,[["__scopeId","data-v-28d8a977"]]);export{Q as default};

@ -0,0 +1 @@
.vertical-radio-group[data-v-91993da2]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}

@ -0,0 +1 @@
import{d as J,Q as P,r as l,x as R,I as S,aY as j,aZ as V,Z as N,o as Z,a as T,g as i,w as Y,b as z,n as U,h as W,B as K,a_ as _,a$ as L,_ as Q}from"./index-9847718b.js";import{u as w,_ as q,a as F}from"./index-fd059ba6.js";const G={class:"mt-preview"},H=J({__name:"index",props:{exportJson:{},canZoom:{type:Boolean,default:!0},canDrag:{type:Boolean,default:!0},showPopover:{type:Boolean,default:!0}},emits:["onEventCallBack"],setup(h,{expose:C,emit:D}){P(e=>({bd32cc0c:`scale(${o.value.scale})`,v2fe7abe4:o.value.width+"px",v17da5d89:o.value.height+"px",v27bf1846:o.value.color,v87ebe69c:"url("+o.value.img+")"}));const r=h,I=D,f=l(),o=l({width:1920,height:1080,scale:1,color:"",img:"",guide:!0,adsorp:!0,adsorp_diff:3,transform_origin:{x:0,y:0},drag_offset:{x:0,y:0}}),c=l({enabled:!0,align:!0,size:10}),t=l([]),v=l(),g=l(),n=R({begin_left:0,begin_top:0,left:0,top:0}),M=({scrollLeft:e,scrollTop:a})=>{n.left=e,n.top=a},b=e=>{var a;r.canDrag&&((a=g.value)==null||a.onMouseDown(e))},x=()=>{n.begin_left=n.left,n.begin_top=n.top},B=(e,a)=>{var p,m;let s=n.begin_left-e,u=n.begin_top-a;(p=v.value)==null||p.setScrollLeft(s),(m=v.value)==null||m.setScrollTop(u)},y=()=>{},d=(e,a,s)=>_(e,a,s,t.value),A=e=>{e.forEach(a=>{_(a.id,a.key,a.val,t.value)})},E=(e,a,s)=>L(e,a,t.value),$=e=>{e.ctrlKey&&r.canZoom&&(e.preventDefault(),e.stopPropagation(),e.deltaY>0?o.value.scale=(o.value.scale*10-1)/10:e.deltaY<0&&(o.value.scale=(o.value.scale*10+1)/10))},k=(e,a,s)=>{setTimeout(()=>{d(e,a,s)},0)};return window.$mtElMessage=S,window.$mtElMessageBox=j,window.$setItemAttrByID=(e,a,s)=>k(e,a,s),window.$getItemAttrByID=E,window.$previewCompareVal=V,window.$mtEventCallBack=(e,a,...s)=>I("onEventCallBack",e,a,...s),N(()=>{if(r.exportJson){const{canvasCfg:e,gridCfg:a,importDoneJson:s}=w(r.exportJson);o.value=e,c.value=a,t.value=s,console.log("@@importDoneJson",s)}}),C({setItemAttrByID:d,setImportJson:e=>{const{canvasCfg:a,gridCfg:s,importDoneJson:u}=w(e);return o.value=a,c.value=s,t.value=e.json,t.value=u,!0},setItemAttrs:A,setNewImportJson:e=>(o.value=e.canvasCfg,c.value=e.gridCfg,t.value=e.json,!0)}),(e,a)=>(Z(),T("div",G,[i(W(K),{ref_key:"elScrollbarRef",ref:v,class:"w-1/1 h-1/1","max-height":o.value.height,onScroll:M},{default:Y(()=>[z("div",{ref_key:"canvasAreaRef",ref:f,class:U(`canvasArea ${r.canDrag?"cursor-grab":""} `),onMousedown:b,onWheel:$},[i(q,{"done-json":t.value,"canvas-cfg":o.value,"grid-cfg":c.value,"show-ghost-dom":!1,"canvas-dom":f.value,"global-lock":!1,"preivew-mode":!0,"show-popover":r.showPopover},null,8,["done-json","canvas-cfg","grid-cfg","canvas-dom","show-popover"])],34),i(F,{ref_key:"dragCanvasRef",ref:g,"scale-ratio":o.value.scale,onDragCanvasMouseDown:x,onDragCanvasMouseMove:B,onDragCanvasMouseUp:y},null,8,["scale-ratio"])]),_:1},8,["max-height"])]))}}),oe=Q(H,[["__scopeId","data-v-464d64c1"]]);export{oe as M};

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
import{_ as e,a as c,o as n}from"./index-9847718b.js";const o={};function r(t,a){return n(),c("h3",null,"测试页面")}const _=e(o,[["render",r]]);export{_ as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
.vertical-radio-group[data-v-28d8a977]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
import{d as v,aP as w,r as c,x as p,$ as x,Z as y,i as M,h as J,aw as I,O as l,I as a,o as k,X as q,_ as C}from"./index-9847718b.js";import{u as D}from"./index-fd059ba6.js";import{M as P}from"./index-868f5209.js";const h=v({name:"PreviewIndex",__name:"index",setup(B){const r=w();console.log("参数:",r.query.screen),c(!1),p([]),c("-1"),q();const d=c(),u=(n,o)=>{console.log(n,o),n=="test-dialog"&&a.success(`获取到了id:${o}`)};x(()=>{console.log("view卸载完毕")});async function i(){var o;let n={menuType:r.query.screen};try{const s=await I.model_getModelData_post(n);if(s.code==200){const _=await s.data,{canvasCfg:f,gridCfg:g,importDoneJson:m}=D(_),t=m.map(e=>e.props?{...e,props:p(e.props||{})}:{...e,props:p(e.props||{})});console.log("processedImportDoneJson:",t),(o=d.value)==null||o.setNewImportJson({canvasCfg:f,gridCfg:g,json:t}),l.group_ids.has(r.query.screen)&&l.group_ids.delete(r.query.screen),l.group_ids.set(r.query.screen,t.map(e=>e.id)),a.success("数据模型加载成功")}else a.error(`数据模型加载失败: ${s.code} - ${s.message}`)}catch(s){console.error("请求错误:",s),a.error("网络请求失败")}}return y(()=>{console.log("view挂载完毕"),i()}),(n,o)=>(k(),M(J(P),{ref_key:"MtPreviewRef",ref:d,onOnEventCallBack:u},null,512))}});const O=C(h,[["__scopeId","data-v-91993da2"]]);export{O as default};

@ -0,0 +1,16 @@
ace.define("ace/snippets/javascript.snippets",["require","exports","module"], function(require, exports, module){module.exports = "# Prototype\nsnippet proto\n\t${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) {\n\t\t${4:// body...}\n\t};\n# Function\nsnippet fun\n\tfunction ${1?:function_name}(${2:argument}) {\n\t\t${3:// body...}\n\t}\n# Anonymous Function\nregex /((=)\\s*|(:)\\s*|(\\()|\\b)/f/(\\))?/\nsnippet f\n\tfunction${M1?: ${1:functionName}}($2) {\n\t\t${0:$TM_SELECTED_TEXT}\n\t}${M2?;}${M3?,}${M4?)}\n# Immediate function\ntrigger \\(?f\\(\nendTrigger \\)?\nsnippet f(\n\t(function(${1}) {\n\t\t${0:${TM_SELECTED_TEXT:/* code */}}\n\t}(${1}));\n# if\nsnippet if\n\tif (${1:true}) {\n\t\t${0}\n\t}\n# if ... else\nsnippet ife\n\tif (${1:true}) {\n\t\t${2}\n\t} else {\n\t\t${0}\n\t}\n# tertiary conditional\nsnippet ter\n\t${1:/* condition */} ? ${2:a} : ${3:b}\n# switch\nsnippet switch\n\tswitch (${1:expression}) {\n\t\tcase '${3:case}':\n\t\t\t${4:// code}\n\t\t\tbreak;\n\t\t${5}\n\t\tdefault:\n\t\t\t${2:// code}\n\t}\n# case\nsnippet case\n\tcase '${1:case}':\n\t\t${2:// code}\n\t\tbreak;\n\t${3}\n\n# while (...) {...}\nsnippet wh\n\twhile (${1:/* condition */}) {\n\t\t${0:/* code */}\n\t}\n# try\nsnippet try\n\ttry {\n\t\t${0:/* code */}\n\t} catch (e) {}\n# do...while\nsnippet do\n\tdo {\n\t\t${2:/* code */}\n\t} while (${1:/* condition */});\n# Object Method\nsnippet :f\nregex /([,{[])|^\\s*/:f/\n\t${1:method_name}: function(${2:attribute}) {\n\t\t${0}\n\t}${3:,}\n# setTimeout function\nsnippet setTimeout\nregex /\\b/st|timeout|setTimeo?u?t?/\n\tsetTimeout(function() {${3:$TM_SELECTED_TEXT}}, ${1:10});\n# Get Elements\nsnippet gett\n\tgetElementsBy${1:TagName}('${2}')${3}\n# Get Element\nsnippet get\n\tgetElementBy${1:Id}('${2}')${3}\n# console.log (Firebug)\nsnippet cl\n\tconsole.log(${1});\n# return\nsnippet ret\n\treturn ${1:result}\n# for (property in object ) { ... }\nsnippet fori\n\tfor (var ${1:prop} in ${2:Things}) {\n\t\t${0:$2[$1]}\n\t}\n# hasOwnProperty\nsnippet has\n\thasOwnProperty(${1})\n# docstring\nsnippet /**\n\t/**\n\t * ${1:description}\n\t *\n\t */\nsnippet @par\nregex /^\\s*\\*\\s*/@(para?m?)?/\n\t@param {${1:type}} ${2:name} ${3:description}\nsnippet @ret\n\t@return {${1:type}} ${2:description}\n# JSON.parse\nsnippet jsonp\n\tJSON.parse(${1:jstr});\n# JSON.stringify\nsnippet jsons\n\tJSON.stringify(${1:object});\n# self-defining function\nsnippet sdf\n\tvar ${1:function_name} = function(${2:argument}) {\n\t\t${3:// initial code ...}\n\n\t\t$1 = function($2) {\n\t\t\t${4:// main code}\n\t\t};\n\t}\n# singleton\nsnippet sing\n\tfunction ${1:Singleton} (${2:argument}) {\n\t\t// the cached instance\n\t\tvar instance;\n\n\t\t// rewrite the constructor\n\t\t$1 = function $1($2) {\n\t\t\treturn instance;\n\t\t};\n\t\t\n\t\t// carry over the prototype properties\n\t\t$1.prototype = this;\n\n\t\t// the instance\n\t\tinstance = new $1();\n\n\t\t// reset the constructor pointer\n\t\tinstance.constructor = $1;\n\n\t\t${3:// code ...}\n\n\t\treturn instance;\n\t}\n# class\nsnippet class\nregex /^\\s*/clas{0,2}/\n\tvar ${1:class} = function(${20}) {\n\t\t$40$0\n\t};\n\t\n\t(function() {\n\t\t${60:this.prop = \"\"}\n\t}).call(${1:class}.prototype);\n\t\n\texports.${1:class} = ${1:class};\n# \nsnippet for-\n\tfor (var ${1:i} = ${2:Things}.length; ${1:i}--; ) {\n\t\t${0:${2:Things}[${1:i}];}\n\t}\n# for (...) {...}\nsnippet for\n\tfor (var ${1:i} = 0; $1 < ${2:Things}.length; $1++) {\n\t\t${3:$2[$1]}$0\n\t}\n# for (...) {...} (Improved Native For-Loop)\nsnippet forr\n\tfor (var ${1:i} = ${2:Things}.length - 1; $1 >= 0; $1--) {\n\t\t${3:$2[$1]}$0\n\t}\n\n\n#modules\nsnippet def\n\tdefine(function(require, exports, module) {\n\t\"use strict\";\n\tvar ${1/.*\\///} = require(\"${1}\");\n\t\n\t$TM_SELECTED_TEXT\n\t});\nsnippet req\nguard ^\\s*\n\tvar ${1/.*\\///} = require(\"${1}\");\n\t$0\nsnippet requ\nguard ^\\s*\n\tvar ${1/.*\\/(.)/\\u$1/} = require(\"${1}\").${1/.*\\/(.)/\\u$1/};\n\t$0\n";
});
ace.define("ace/snippets/javascript",["require","exports","module","ace/snippets/javascript.snippets"], function(require, exports, module){"use strict";
exports.snippetText = require("./javascript.snippets");
exports.scope = "javascript";
}); (function() {
ace.require(["ace/snippets/javascript"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

File diff suppressed because it is too large Load Diff

@ -0,0 +1,275 @@
ace.define("ace/mode/json_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(require, exports, module){"use strict";
var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var JsonHighlightRules = function () {
this.$rules = {
"start": [
{
token: "variable", // single line
regex: '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)'
}, {
token: "string", // single line
regex: '"',
next: "string"
}, {
token: "constant.numeric", // hex
regex: "0[xX][0-9a-fA-F]+\\b"
}, {
token: "constant.numeric", // float
regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token: "constant.language.boolean",
regex: "(?:true|false)\\b"
}, {
token: "text", // single quoted strings are not allowed
regex: "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token: "comment", // comments are not allowed, but who cares?
regex: "\\/\\/.*$"
}, {
token: "comment.start", // comments are not allowed, but who cares?
regex: "\\/\\*",
next: "comment"
}, {
token: "paren.lparen",
regex: "[[({]"
}, {
token: "paren.rparen",
regex: "[\\])}]"
}, {
token: "punctuation.operator",
regex: /[,]/
}, {
token: "text",
regex: "\\s+"
}
],
"string": [
{
token: "constant.language.escape",
regex: /\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|["\\\/bfnrt])/
}, {
token: "string",
regex: '"|$',
next: "start"
}, {
defaultToken: "string"
}
],
"comment": [
{
token: "comment.end", // comments are not allowed, but who cares?
regex: "\\*\\/",
next: "start"
}, {
defaultToken: "comment"
}
]
};
};
oop.inherits(JsonHighlightRules, TextHighlightRules);
exports.JsonHighlightRules = JsonHighlightRules;
});
ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"], function(require, exports, module){"use strict";
var Range = require("../range").Range;
var MatchingBraceOutdent = function () { };
(function () {
this.checkOutdent = function (line, input) {
if (!/^\s+$/.test(line))
return false;
return /^\s*\}/.test(input);
};
this.autoOutdent = function (doc, row) {
var line = doc.getLine(row);
var match = line.match(/^(\s*\})/);
if (!match)
return 0;
var column = match[1].length;
var openBracePos = doc.findMatchingBracket({ row: row, column: column });
if (!openBracePos || openBracePos.row == row)
return 0;
var indent = this.$getIndent(doc.getLine(openBracePos.row));
doc.replace(new Range(row, 0, row, column - 1), indent);
};
this.$getIndent = function (line) {
return line.match(/^\s*/)[0];
};
}).call(MatchingBraceOutdent.prototype);
exports.MatchingBraceOutdent = MatchingBraceOutdent;
});
ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"], function(require, exports, module){"use strict";
var oop = require("../../lib/oop");
var Range = require("../../range").Range;
var BaseFoldMode = require("./fold_mode").FoldMode;
var FoldMode = exports.FoldMode = function (commentRegex) {
if (commentRegex) {
this.foldingStartMarker = new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.start));
this.foldingStopMarker = new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.end));
}
};
oop.inherits(FoldMode, BaseFoldMode);
(function () {
this.foldingStartMarker = /([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/;
this.foldingStopMarker = /^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/;
this.singleLineBlockCommentRe = /^\s*(\/\*).*\*\/\s*$/;
this.tripleStarBlockCommentRe = /^\s*(\/\*\*\*).*\*\/\s*$/;
this.startRegionRe = /^\s*(\/\*|\/\/)#?region\b/;
this._getFoldWidgetBase = this.getFoldWidget;
this.getFoldWidget = function (session, foldStyle, row) {
var line = session.getLine(row);
if (this.singleLineBlockCommentRe.test(line)) {
if (!this.startRegionRe.test(line) && !this.tripleStarBlockCommentRe.test(line))
return "";
}
var fw = this._getFoldWidgetBase(session, foldStyle, row);
if (!fw && this.startRegionRe.test(line))
return "start"; // lineCommentRegionStart
return fw;
};
this.getFoldWidgetRange = function (session, foldStyle, row, forceMultiline) {
var line = session.getLine(row);
if (this.startRegionRe.test(line))
return this.getCommentRegionBlock(session, line, row);
var match = line.match(this.foldingStartMarker);
if (match) {
var i = match.index;
if (match[1])
return this.openingBracketBlock(session, match[1], row, i);
var range = session.getCommentFoldRange(row, i + match[0].length, 1);
if (range && !range.isMultiLine()) {
if (forceMultiline) {
range = this.getSectionRange(session, row);
}
else if (foldStyle != "all")
range = null;
}
return range;
}
if (foldStyle === "markbegin")
return;
var match = line.match(this.foldingStopMarker);
if (match) {
var i = match.index + match[0].length;
if (match[1])
return this.closingBracketBlock(session, match[1], row, i);
return session.getCommentFoldRange(row, i, -1);
}
};
this.getSectionRange = function (session, row) {
var line = session.getLine(row);
var startIndent = line.search(/\S/);
var startRow = row;
var startColumn = line.length;
row = row + 1;
var endRow = row;
var maxRow = session.getLength();
while (++row < maxRow) {
line = session.getLine(row);
var indent = line.search(/\S/);
if (indent === -1)
continue;
if (startIndent > indent)
break;
var subRange = this.getFoldWidgetRange(session, "all", row);
if (subRange) {
if (subRange.start.row <= startRow) {
break;
}
else if (subRange.isMultiLine()) {
row = subRange.end.row;
}
else if (startIndent == indent) {
break;
}
}
endRow = row;
}
return new Range(startRow, startColumn, endRow, session.getLine(endRow).length);
};
this.getCommentRegionBlock = function (session, line, row) {
var startColumn = line.search(/\s*$/);
var maxRow = session.getLength();
var startRow = row;
var re = /^\s*(?:\/\*|\/\/|--)#?(end)?region\b/;
var depth = 1;
while (++row < maxRow) {
line = session.getLine(row);
var m = re.exec(line);
if (!m)
continue;
if (m[1])
depth--;
else
depth++;
if (!depth)
break;
}
var endRow = row;
if (endRow > startRow) {
return new Range(startRow, startColumn, endRow, line.length);
}
};
}).call(FoldMode.prototype);
});
ace.define("ace/mode/json",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/json_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/folding/cstyle","ace/worker/worker_client"], function(require, exports, module){"use strict";
var oop = require("../lib/oop");
var TextMode = require("./text").Mode;
var HighlightRules = require("./json_highlight_rules").JsonHighlightRules;
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
var CStyleFoldMode = require("./folding/cstyle").FoldMode;
var WorkerClient = require("../worker/worker_client").WorkerClient;
var Mode = function () {
this.HighlightRules = HighlightRules;
this.$outdent = new MatchingBraceOutdent();
this.$behaviour = this.$defaultBehaviour;
this.foldingRules = new CStyleFoldMode();
};
oop.inherits(Mode, TextMode);
(function () {
this.lineCommentStart = "//";
this.blockComment = { start: "/*", end: "*/" };
this.getNextLineIndent = function (state, line, tab) {
var indent = this.$getIndent(line);
if (state == "start") {
var match = line.match(/^.*[\{\(\[]\s*$/);
if (match) {
indent += tab;
}
}
return indent;
};
this.checkOutdent = function (state, line, input) {
return this.$outdent.checkOutdent(line, input);
};
this.autoOutdent = function (state, doc, row) {
this.$outdent.autoOutdent(doc, row);
};
this.createWorker = function (session) {
var worker = new WorkerClient(["ace"], "ace/mode/json_worker", "JsonWorker");
worker.attachToDocument(session.getDocument());
worker.on("annotate", function (e) {
session.setAnnotations(e.data);
});
worker.on("terminate", function () {
session.clearAnnotations();
});
return worker;
};
this.$id = "ace/mode/json";
}).call(Mode.prototype);
exports.Mode = Mode;
}); (function() {
ace.require(["ace/mode/json"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

@ -0,0 +1 @@
.vertical-radio-group[data-v-cf8bfc69]{display:flex;flex-direction:column;gap:5px;align-items:flex-start}

@ -0,0 +1 @@
import{d as B,aP as N,r as C,x as y,$ as R,Z as S,aw as F,O as a,I as u,a as V,g as m,h as _,w as g,av as M,F as k,as as v,o as b,b as L,q as J,t as D,A as T,X as U,i as $,Y as A,_ as O}from"./index-9847718b.js";import{u as E}from"./index-fd059ba6.js";import{M as G}from"./index-868f5209.js";const X={class:"drawer-footer"},Y=B({name:"PreviewIndex111",__name:"overview",setup(Z){const f=N();console.log("参数11",f.query.screen);let p=C(!1),x=y([]),r=C("-1");U();const w=C(),h=(s,e)=>{console.log(s,e),s=="test-dialog"&&u.success(`获取到了id:${e}`)};function I(s){const e={};for(const o in s)s[o]&&typeof s[o]=="object"&&"val"in s[o]&&(e[o]=s[o].val);return e}function P(){var l;let s=a.canvasCfg,e=a.gridCfg,o=A(a.done_json);a.done_json.forEach(d=>{const n=I(d.props);o.forEach(i=>{i.id===d.id&&(i.props=n)})});let t={canvasCfg:s,gridCfg:e,json:o};console.log("endJson",t),(l=w.value)==null||l.setImportJson(t)}R(()=>{console.log("view卸载完毕")}),S(()=>{j()});async function j(){var e;let s={menuType:f.query.screen};try{const o=await F.model_getModelData_post(s);if(o.code==200){const t=await o.data,{canvasCfg:l,gridCfg:d,importDoneJson:n}=E(t),i=n.map(c=>c.props?{...c,props:y(c.props||{})}:{...c,props:y(c.props||{})});console.log("processedImportDoneJson:",i),(e=w.value)==null||e.setNewImportJson({canvasCfg:l,gridCfg:d,json:i}),a.group_ids.has(f.query.screen)&&a.group_ids.delete(f.query.screen),a.group_ids.set(f.query.screen,i.map(c=>c.id)),u.success("数据模型加载成功")}else u.error(`数据模型加载失败: ${o.code} - ${o.message}`)}catch(o){console.error("请求错误:",o),u.error("网络请求失败")}}function q(){console.log("选中:",r.value,r),(!r.value||r.value=="-1")&&u.warning("请先选择一个模型文件"),x.forEach(s=>{s.id==r.value&&fetch(`/dataModes/${s.name}`).then(e=>e.json()).then(e=>{console.log("文件内容:",e);const{canvasCfg:o,gridCfg:t,importDoneJson:l}=E(e);a.canvasCfg=o,a.gridCfg=t,a.setGlobalStoreDoneJson(l),P()}).catch(e=>{u.error("获取文件错误:",e)})})}return(s,e)=>{const o=v("el-radio"),t=v("el-radio-group"),l=v("el-button"),d=v("el-drawer");return b(),V(k,null,[m(_(G),{ref_key:"MtPreviewRef",ref:w,onOnEventCallBack:h},null,512),m(d,{modelValue:_(p),"onUpdate:modelValue":e[1]||(e[1]=n=>M(p)?p.value=n:p=n),modal:!1,title:"数据模型文件","modal-penetrable":""},{footer:g(()=>[L("div",X,[m(l,{onClick:q},{default:g(()=>[...e[2]||(e[2]=[J("加载模型",-1)])]),_:1})])]),default:g(()=>[m(t,{class:"vertical-radio-group",modelValue:_(r),"onUpdate:modelValue":e[0]||(e[0]=n=>M(r)?r.value=n:r=n)},{default:g(()=>[J(D(_(p))+" ",1),(b(!0),V(k,null,T(_(x),n=>(b(),$(o,{key:n.id,label:n.id},{default:g(()=>[J(D(n.name),1)]),_:2},1032,["label"]))),128))]),_:1},8,["modelValue"])]),_:1},8,["modelValue"])],64)}}});const Q=O(Y,[["__scopeId","data-v-cf8bfc69"]]);export{Q as default};

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

@ -0,0 +1,140 @@
{
"canvasCfg": {
"width": 1920,
"height": 1080,
"scale": 1,
"color": "",
"img": "",
"guide": true,
"adsorp": true,
"adsorp_diff": 5,
"transform_origin": {
"x": 0,
"y": 0
},
"drag_offset": {
"x": 0,
"y": 0
}
},
"gridCfg": {
"enabled": true,
"align": true,
"size": 10
},
"json": [
{
"id": "vue-my-regulator-iwEp1KifC7",
"title": "vue谣调",
"type": "vue",
"binfo": {
"left": 129.98797607421875,
"top": 70,
"width": 50,
"height": 50,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {
"moduleType": "遥测",
"moduleId": ""
},
"tag": "vue-my-regulator",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
},
{
"id": "vue-my-switch-info-XZmvJDTfd8",
"title": "vue遥控",
"type": "vue",
"binfo": {
"left": 240,
"top": 70,
"width": 50,
"height": 50,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {
"moduleType": "遥控",
"moduleId": ""
},
"tag": "vue-my-switch-info",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
},
{
"id": "vue-my-num-info-W1j7n1WBMs",
"title": "vue谣测",
"type": "vue",
"binfo": {
"left": 180,
"top": 70,
"width": 50,
"height": 50,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {
"moduleType": "遥测",
"moduleId": ""
},
"tag": "vue-my-num-info",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
},
{
"id": "vue-my-signal-info-VFdTsqHrqK",
"title": "vue遥信01",
"type": "vue",
"binfo": {
"left": 70,
"top": 140,
"width": 430,
"height": 210,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {},
"tag": "vue-my-signal-info",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
}
]
}

@ -0,0 +1,139 @@
{
"canvasCfg": {
"width": 1920,
"height": 1080,
"scale": 1,
"color": "",
"img": "",
"guide": true,
"adsorp": true,
"adsorp_diff": 5,
"transform_origin": {
"x": 0,
"y": 0
},
"drag_offset": {
"x": 0,
"y": 0
}
},
"gridCfg": {
"enabled": true,
"align": true,
"size": 10
},
"json": [
{
"id": "vue-my-regulator-iwEp1KifC7",
"title": "vue谣调",
"type": "vue",
"binfo": {
"left": 129.98797607421875,
"top": 70,
"width": 50,
"height": 50,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {
"moduleType": "遥测",
"moduleId": ""
},
"tag": "vue-my-regulator",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
},
{
"id": "vue-my-num-info-W1j7n1WBMs",
"title": "vue谣测",
"type": "vue",
"binfo": {
"left": 330,
"top": 380,
"width": 50,
"height": 50,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {
"moduleType": "遥测",
"moduleId": ""
},
"tag": "vue-my-num-info",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
},
{
"id": "vue-my-signal-info-VFdTsqHrqK",
"title": "vue遥信01",
"type": "vue",
"binfo": {
"left": 70,
"top": 140,
"width": 430,
"height": 210,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {},
"tag": "vue-my-signal-info",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
},
{
"id": "vue-my-img-DLxtEt9t9A",
"title": "vue图形组件",
"type": "vue",
"binfo": {
"left": 64.97598266601562,
"top": 370,
"width": 130,
"height": 100,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {
"maxWidth": ""
},
"tag": "vue-my-img",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
}
]
}

@ -0,0 +1,147 @@
{
"canvasCfg": {
"width": 1920,
"height": 1080,
"scale": 1,
"color": "",
"img": "",
"guide": true,
"adsorp": true,
"adsorp_diff": 5,
"transform_origin": {
"x": 0,
"y": 0
},
"drag_offset": {
"x": 0,
"y": 0
}
},
"gridCfg": {
"enabled": true,
"align": true,
"size": 10
},
"json": [
{
"id": "vue-my-signal-info-VFdTsqHrqK",
"title": "vue遥信01",
"type": "vue",
"binfo": {
"left": 50,
"top": 50,
"width": 430,
"height": 210,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {},
"tag": "vue-my-signal-info",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
},
{
"id": "vue-my-run-info-QOvDKecsyZ",
"title": "vue运行信息",
"type": "vue",
"binfo": {
"left": 500,
"top": 50,
"width": 240,
"height": 180,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {
"fontFamily": "Segoe UI",
"fontSize": 14,
"testColor": "#000000"
},
"tag": "vue-my-run-info",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
},
{
"id": "vue-my-multi-type-info-V5rhA1U1PF",
"title": "vue运行状态信息",
"type": "vue",
"binfo": {
"left": 490,
"top": 240,
"width": 270,
"height": 180,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {
"headline": "11111",
"fontFamily": "Segoe UI",
"fontSize": 14,
"dataSource": "ultraVires",
"testColor": "#000000"
},
"tag": "vue-my-multi-type-info",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
},
{
"id": "vue-my-multi-type-info-OMI6pUcsA9",
"title": "vue运行状态信息",
"type": "vue",
"binfo": {
"left": 110,
"top": 270,
"width": 310,
"height": 200,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {
"headline": "2222",
"fontFamily": "Segoe UI",
"fontSize": 14,
"dataSource": "ultraVires",
"testColor": "#000000"
},
"tag": "vue-my-multi-type-info",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
}
]
}

@ -0,0 +1,113 @@
{
"canvasCfg": {
"width": 1920,
"height": 1080,
"scale": 1,
"color": "",
"img": "",
"guide": true,
"adsorp": true,
"adsorp_diff": 5,
"transform_origin": {
"x": 0,
"y": 0
},
"drag_offset": {
"x": 0,
"y": 0
}
},
"gridCfg": {
"enabled": true,
"align": true,
"size": 10
},
"json": [
{
"id": "vue-my-signal-info-VFdTsqHrqK11111",
"title": "vue遥信01",
"type": "vue",
"binfo": {
"left": 50,
"top": 50,
"width": 430,
"height": 210,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {},
"tag": "vue-my-signal-info",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
},
{
"id": "vue-my-run-info-QOvDKecsyZ",
"title": "vue运行信息",
"type": "vue",
"binfo": {
"left": 500,
"top": 50,
"width": 240,
"height": 180,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {
"fontFamily": "Segoe UI",
"fontSize": 14,
"testColor": "#000000"
},
"tag": "vue-my-run-info",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
},
{
"id": "vue-my-tableOnly-a6n14qu2iO",
"title": "单一功能表单",
"type": "vue",
"binfo": {
"left": 40,
"top": 270,
"width": 620,
"height": 250,
"angle": 0
},
"resize": true,
"rotate": true,
"lock": false,
"active": false,
"hide": false,
"props": {
"fontFamily": "黑体",
"fontSize": 12,
"testColor": "#767676"
},
"tag": "vue-my-tableOnly",
"common_animations": {
"val": "",
"delay": "delay-0s",
"speed": "slow",
"repeat": "infinite"
},
"events": []
}
]
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save