This commit is contained in:
likaikai 2025-06-04 13:25:40 +08:00
parent 99512771ab
commit 6971ad77f6
21 changed files with 1630 additions and 382 deletions

400
package-lock.json generated
View File

@ -21,6 +21,7 @@
"js-beautify": "1.14.11",
"js-cookie": "3.0.5",
"jsencrypt": "3.3.2",
"mqtt": "^5.13.0",
"nprogress": "0.2.0",
"pinia": "2.1.7",
"splitpanes": "3.1.5",
@ -85,6 +86,14 @@
"node": ">=6.0.0"
}
},
"node_modules/@babel/runtime": {
"version": "7.27.4",
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.27.4.tgz",
"integrity": "sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/types": {
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz",
@ -1013,12 +1022,19 @@
"version": "22.13.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.17.tgz",
"integrity": "sha512-nAJuQXoyPj04uLgu+obZcSmsfOenUg6DxPKogeUy6yNCFwWaj5sBF8/G/pNo8EtBJjAfSVgfIlugR/BCOleO+g==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
}
},
"node_modules/@types/readable-stream": {
"version": "4.0.20",
"resolved": "https://registry.npmmirror.com/@types/readable-stream/-/readable-stream-4.0.20.tgz",
"integrity": "sha512-eLgbR5KwUh8+6pngBDxS32MymdCsCHnGtwHTrC0GDorbc7NbcnkZAWptDLgZiRk9VRas+B6TyRgPDucq4zRs8g==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/svgo": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/@types/svgo/-/svgo-2.6.4.tgz",
@ -1327,6 +1343,17 @@
"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==",
"dependencies": {
"event-target-shim": "^5.0.0"
},
"engines": {
"node": ">=6.5"
}
},
"node_modules/acorn": {
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
@ -1567,6 +1594,25 @@
"node": ">=0.10.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"
}
]
},
"node_modules/big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@ -1590,6 +1636,32 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/bl": {
"version": "6.1.0",
"resolved": "https://registry.npmmirror.com/bl/-/bl-6.1.0.tgz",
"integrity": "sha512-ClDyJGQkc8ZtzdAAbAwBmhMSpwN/sC9HA8jxdYm6nVUbCfZbe2mgza4qh7AuEYyEPB/c4Kznf9s66bnsKMQDjw==",
"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==",
"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": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@ -1626,6 +1698,34 @@
"node": ">=8"
}
},
"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"
}
],
"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=="
},
"node_modules/cache-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
@ -1872,6 +1972,11 @@
"node": ">=14"
}
},
"node_modules/commist": {
"version": "3.2.0",
"resolved": "https://registry.npmmirror.com/commist/-/commist-3.2.0.tgz",
"integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw=="
},
"node_modules/component-emitter": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
@ -1882,6 +1987,20 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"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"
],
"dependencies": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.0.2",
"typedarray": "^0.0.6"
}
},
"node_modules/confbox": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
@ -2133,7 +2252,6 @@
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@ -2700,12 +2818,28 @@
"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==",
"engines": {
"node": ">=6"
}
},
"node_modules/eventemitter3": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==",
"license": "MIT"
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmmirror.com/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/expand-brackets": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
@ -2838,6 +2972,23 @@
"node": ">=8.6.0"
}
},
"node_modules/fast-unique-numbers": {
"version": "8.0.13",
"resolved": "https://registry.npmmirror.com/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz",
"integrity": "sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==",
"dependencies": {
"@babel/runtime": "^7.23.8",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=16.1.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=="
},
"node_modules/fastq": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
@ -3394,6 +3545,11 @@
"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=="
},
"node_modules/htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
@ -3416,6 +3572,25 @@
"dev": true,
"license": "BSD-2-Clause"
},
"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"
}
]
},
"node_modules/image-size": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
@ -3440,7 +3615,6 @@
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true,
"license": "ISC"
},
"node_modules/ini": {
@ -3464,6 +3638,18 @@
"node": ">= 0.4"
}
},
"node_modules/ip-address": {
"version": "9.0.5",
"resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-9.0.5.tgz",
"integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
"dependencies": {
"jsbn": "1.1.0",
"sprintf-js": "^1.1.3"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/is-accessor-descriptor": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz",
@ -4039,6 +4225,15 @@
"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==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/js-sdsl"
}
},
"node_modules/js-tokens": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
@ -4046,6 +4241,11 @@
"dev": true,
"license": "MIT"
},
"node_modules/jsbn": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/jsbn/-/jsbn-1.1.0.tgz",
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
},
"node_modules/jsencrypt": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/jsencrypt/-/jsencrypt-3.3.2.tgz",
@ -4293,7 +4493,6 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@ -4348,11 +4547,64 @@
"ufo": "^1.5.4"
}
},
"node_modules/mqtt": {
"version": "5.13.0",
"resolved": "https://registry.npmmirror.com/mqtt/-/mqtt-5.13.0.tgz",
"integrity": "sha512-pR+z+ChxFl3n8AKLQbTONVOOg/jl4KiKQRBAi78tjd6PksOWvl1nl9L8ZHOZ3MiavZfrUOjok2ddwc1VymGWRg==",
"dependencies": {
"commist": "^3.2.0",
"concat-stream": "^2.0.0",
"debug": "^4.4.0",
"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.3",
"split2": "^4.2.0",
"worker-timers": "^7.1.8",
"ws": "^8.18.0"
},
"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==",
"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==",
"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/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
@ -4507,6 +4759,15 @@
"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==",
"dependencies": {
"debug": "^4.3.1",
"js-sdsl": "4.3.0"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@ -4958,6 +5219,19 @@
"posthtml-render": "^1.0.6"
}
},
"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==",
"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=="
},
"node_modules/proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@ -5071,7 +5345,6 @@
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
@ -5228,6 +5501,11 @@
"node": ">=0.10.0"
}
},
"node_modules/rfdc": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz",
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="
},
"node_modules/rollup": {
"version": "4.38.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.38.0.tgz",
@ -5323,7 +5601,6 @@
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true,
"funding": [
{
"type": "github",
@ -5607,6 +5884,15 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"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==",
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
}
},
"node_modules/snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@ -5732,6 +6018,19 @@
"node": ">=0.10.0"
}
},
"node_modules/socks": {
"version": "2.8.4",
"resolved": "https://registry.npmmirror.com/socks/-/socks-2.8.4.tgz",
"integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==",
"dependencies": {
"ip-address": "^9.0.5",
"smart-buffer": "^4.2.0"
},
"engines": {
"node": ">= 10.0.0",
"npm": ">= 3.0.0"
}
},
"node_modules/sortablejs": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
@ -5828,6 +6127,14 @@
"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==",
"engines": {
"node": ">= 10.x"
}
},
"node_modules/splitpanes": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/splitpanes/-/splitpanes-3.1.5.tgz",
@ -5837,6 +6144,11 @@
"url": "https://github.com/sponsors/antoniandre"
}
},
"node_modules/sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.1.3.tgz",
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
},
"node_modules/stable": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
@ -5900,7 +6212,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dev": true,
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.2.0"
@ -6587,6 +6898,11 @@
"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=="
},
"node_modules/typedarray.prototype.slice": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.5.tgz",
@ -6652,7 +6968,6 @@
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"dev": true,
"license": "MIT"
},
"node_modules/unimport": {
@ -6938,7 +7253,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true,
"license": "MIT"
},
"node_modules/vary": {
@ -7304,6 +7618,52 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/worker-timers": {
"version": "7.1.8",
"resolved": "https://registry.npmmirror.com/worker-timers/-/worker-timers-7.1.8.tgz",
"integrity": "sha512-R54psRKYVLuzff7c1OTFcq/4Hue5Vlz4bFtNEIarpSiCYhpifHU3aIQI29S84o1j87ePCYqbmEJPqwBTf+3sfw==",
"dependencies": {
"@babel/runtime": "^7.24.5",
"tslib": "^2.6.2",
"worker-timers-broker": "^6.1.8",
"worker-timers-worker": "^7.0.71"
}
},
"node_modules/worker-timers-broker": {
"version": "6.1.8",
"resolved": "https://registry.npmmirror.com/worker-timers-broker/-/worker-timers-broker-6.1.8.tgz",
"integrity": "sha512-FUCJu9jlK3A8WqLTKXM9E6kAmI/dR1vAJ8dHYLMisLNB/n3GuaFIjJ7pn16ZcD1zCOf7P6H62lWIEBi+yz/zQQ==",
"dependencies": {
"@babel/runtime": "^7.24.5",
"fast-unique-numbers": "^8.0.13",
"tslib": "^2.6.2",
"worker-timers-worker": "^7.0.71"
}
},
"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=="
},
"node_modules/worker-timers-worker": {
"version": "7.0.71",
"resolved": "https://registry.npmmirror.com/worker-timers-worker/-/worker-timers-worker-7.0.71.tgz",
"integrity": "sha512-ks/5YKwZsto1c2vmljroppOKCivB/ma97g9y77MAAz2TBBjPPgpoOiS1qYQKIgvGTr2QYPT3XhJWIB6Rj2MVPQ==",
"dependencies": {
"@babel/runtime": "^7.24.5",
"tslib": "^2.6.2"
}
},
"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=="
},
"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=="
},
"node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
@ -7392,6 +7752,26 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/ws": {
"version": "8.18.2",
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.18.2.tgz",
"integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/zrender": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.0.tgz",

View File

@ -28,6 +28,7 @@
"js-beautify": "1.14.11",
"js-cookie": "3.0.5",
"jsencrypt": "3.3.2",
"mqtt": "^5.13.0",
"nprogress": "0.2.0",
"pinia": "2.1.7",
"splitpanes": "3.1.5",

View File

@ -11,6 +11,9 @@
<script setup>
import usePermissionStore from '@/store/modules/permission'
import { useAppStore } from '@/store/modules/app';
const appStore = useAppStore();
const { proxy } = getCurrentInstance();
const route = useRoute()
const router = useRouter()
@ -18,6 +21,7 @@ const permissionStore = usePermissionStore()
const levelList = ref([])
function getBreadcrumb() {
console.log(route.path,'===luy')
// only show routes with meta.title
let matched = []
const pathNum = findPathNum(route.path)
@ -34,7 +38,7 @@ function getBreadcrumb() {
}
//
if (!isDashboard(matched[0])) {
matched = [{ path: "/index", meta: { title: "首页" } }].concat(matched)
matched = [{ path: "/index", meta: { title: proxy.$t('dashboard.dashboard') } }].concat(matched)
}
levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
}
@ -80,6 +84,12 @@ watchEffect(() => {
}
getBreadcrumb()
})
watch(
() => appStore.language,
() => {
getBreadcrumb()
}
)
getBreadcrumb()
</script>

View File

@ -16,7 +16,7 @@
<!-- 顶部菜单超出数量折叠 -->
<el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
<template #title>更多菜单</template>
<template #title>{{ proxy.$t('common.moreMenu') }}</template>
<template v-for="(item, index) in topMenus">
<el-menu-item
:index="item.path"
@ -38,7 +38,7 @@ import { isHttp } from '@/utils/validate'
import {useAppStore} from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
const { proxy } = getCurrentInstance();
//
const visibleNumber = ref(null);
// index

View File

@ -81,6 +81,7 @@ export default {
logout: 'Logout'
},
maintenance: {
maintenanceManagement: 'Maintenance Management',
deviceName: 'Device Name',
deviceCode: 'Device Code',
deviceModel: 'Device Model',
@ -95,6 +96,7 @@ export default {
},
// 客户管理
customer: {
customerManagement: 'Customer Management',
customerName: 'Customer Name',
customerCode: 'Customer Code',
customerType: 'Customer Type',
@ -119,6 +121,7 @@ export default {
},
// 部门管理
department: {
departmentManagement: 'Department Management',
departmentName: 'Department Name',
inputDepartmentName: 'Please enter department name',
addDepartment: 'Add Department',
@ -129,6 +132,7 @@ export default {
},
// 岗位管理
position: {
positionManagement: 'Position Management',
positionName:'Position Name',
inputPositionName:'Please enter position name',
addPosition:'Add Position',
@ -137,6 +141,7 @@ export default {
},
// 设备
equipment: {
deviceManagement:'Device Management',
deviceName:'Device Name',
inputDeviceName:'Please enter device name',
deviceCode:'Device Code',
@ -177,6 +182,7 @@ export default {
},
// 首页
dashboard: {
dashboard:'Dashboard',
deviceCount:'Device Count',
customerCount:'Customer Count',
maintenanceCount:'Maintenance Count',
@ -241,5 +247,15 @@ export default {
userNameValid:'User nickname cannot be empty',
emailValid:'Email address cannot be empty',
phoneValid:'Phone number cannot be empty',
oldPassword: 'Old Password',
newPassword: 'New Password',
confirmPassword: 'Confirm Password',
oldPasswordValid: 'Old password cannot be empty',
newPasswordValid: 'New password cannot be empty',
confirmPasswordValid: 'Confirm password cannot be empty',
inputOldPassword: 'Please enter old password',
inputNewPassword: 'Please enter new password',
passwordNotEqual:'The two passwords do not match',
moreMenu:'More Menu',
}
}

View File

@ -86,6 +86,7 @@ export default {
},
//维保管理
maintenance: {
maintenanceManagement:'维保管理',
deviceName:'设备名称',
deviceCode:'设备编码',
deviceModel:'设备型号',
@ -100,6 +101,7 @@ export default {
},
// 客户管理
customer: {
customerManagement:'客户管理',
customerName:'客户名称',
customerCode:'客户编码',
customerAddress:'客户地址',
@ -124,6 +126,7 @@ export default {
},
// 部门管理
department: {
departmentManagement:'部门管理',
departmentName:'部门名称',
inputDepartmentName:'请输入部门名称',
addDepartment:'新建部门',
@ -134,6 +137,7 @@ export default {
},
// 岗位管理
position: {
positionManagement:'岗位管理',
positionName:'岗位名称',
inputPositionName:'请输入岗位名称',
addPosition:'新建岗位',
@ -142,6 +146,7 @@ export default {
},
// 设备
equipment: {
deviceManagement:'设备管理',
deviceName: '设备名称',
inputDeviceName: '请输入设备名称',
deviceCode: '设备编码',
@ -182,6 +187,7 @@ export default {
},
// 首页
dashboard: {
dashboard:'首页',
deviceCount:'设备数量',
customerCount:'客户数量',
maintenanceCount:'用户数量',
@ -248,5 +254,15 @@ export default {
userNameValid:'用户昵称不能为空',
emailValid:'邮箱地址不能为空',
phoneValid:'手机号不能为空',
oldPassword: '旧密码',
newPassword: '新密码',
confirmPassword: '确认密码',
oldPasswordValid: '旧密码不能为空',
newPasswordValid: '新密码不能为空',
confirmPasswordValid: '确认密码不能为空',
inputOldPassword: '请输入旧密码',
inputNewPassword: '请输入新密码',
passwordNotEqual: '两次输入的密码不一致',
moreMenu: '更多菜单',
}
};

View File

@ -1,7 +1,6 @@
import { createWebHistory, createRouter } from 'vue-router'
/* Layout */
import Layout from '@/layout'
/**
* Note: 路由配置项
*

View File

@ -4,6 +4,7 @@ import { getRouters } from '@/api/menu'
import Layout from '@/layout/index'
import ParentView from '@/components/ParentView'
import InnerLink from '@/layout/components/InnerLink'
import i18n from '@/lang/index'
// 匹配views里面所有的.vue文件
const modules = import.meta.glob('./../../views/**/*.vue')

89
src/utils/mqttClient.js Normal file
View File

@ -0,0 +1,89 @@
import mqtt from 'mqtt'
import { ref } from 'vue'
export const useMqtt = () => {
const client = ref(null)
const connected = ref(false)
const messageData = ref({})
const messageCallbacks = ref({}) // 新增:存储消息回调函数
const pendingSubscriptions = ref([]) // 存储待订阅的主题
const connect = (url, options = {}) => {
client.value = mqtt.connect(url, {
...options,
reconnectPeriod: 1000,
connectTimeout: 30 * 1000,
clean: true
})
client.value.on('connect', () => {
console.log('MQTT 连接成功')
connected.value = true
// 连接成功后,订阅所有待订阅的主题
pendingSubscriptions.value.forEach(topic => {
client.value.subscribe(topic, (err) => {
if (!err) {
const data = messageData.value[topic]
}
})
})
})
client.value.on('message', (topic, message) => {
// console.log('收到消息:', topic, JSON.parse(message.toString()))
messageData.value[topic] = message.toString()
// 执行对应主题的回调函数
if (messageCallbacks.value[topic]) {
messageCallbacks.value[topic](JSON.parse(message.toString()))
}
})
}
const subscribe = (topic, callback) => {
// 存储回调函数
if (callback) {
messageCallbacks.value[topic] = callback
}
if (!connected.value) {
pendingSubscriptions.value.push(topic)
return
}
if (client.value) {
client.value.subscribe(topic, (err) => {
if (!err) {
console.log(topic, '订阅主题')
}
})
}
}
const getTopicData = (topic) => {
return messageData.value[topic]
}
const publish = (topic, message) => {
if (client.value && connected.value) {
client.value.publish(topic, message)
}
}
const disconnect = () => {
if (client.value) {
client.value.end()
connected.value = false
}
}
return {
connected,
messageData,
getTopicData,
connect,
subscribe,
publish,
disconnect
}
}

View File

@ -0,0 +1,110 @@
<template>
<el-dialog title="添加监测数据" v-model="dialogVisible" width="500px">
<el-form :model="form" label-width="100px">
<el-form-item label="数据项" required>
<el-cascader
v-model="form.dataType"
:options="options"
:props="{ expandTrigger: 'hover' }"
placeholder="请选择数据项"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { ref } from 'vue'
const dialogVisible = ref(false)
const form = ref({
dataType: []
})
const options = [
{
value: 'conductorDiameter',
label: '导体直径',
children: [
{
value: 'conductorDiameterX',
label: '导体直径X'
},
{
value: 'conductorDiameterY',
label: '导体直径Y'
},
{
value: 'conductorDiameterOval',
label: '导体直径椭圆度'
}
]
},
{
value: 'hotOuterDiameter',
label: '热外径'
},
{
value: 'coldOuterDiameter',
label: '冷外径'
},
{
value: 'totalThickness',
label: '总厚度'
},
{
value: 'innerShieldThickness',
label: '内屏层厚度'
},
{
value: 'insulationThickness',
label: '绝缘层厚度'
},
{
value: 'outerShieldThickness',
label: '外屏层厚度'
},
{
value: 'productionInfo',
label: '生产线信息'
}
]
//
const showDialog = () => {
dialogVisible.value = true
form.value.dataType = []
}
//
const handleConfirm = () => {
if (!form.value.dataType || form.value.dataType.length === 0) {
ElMessage.warning('请选择数据项')
return
}
emit('confirm', form.value.dataType[form.value.dataType.length - 1])
dialogVisible.value = false
}
//
const emit = defineEmits(['confirm'])
//
defineExpose({
showDialog
})
</script>
<style scoped>
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
</style>

View File

@ -1,156 +1,452 @@
<template>
<div class="circle-chart">
<div ref="chartRef" style="width: 400px; height: 400px;"></div>
<canvas ref="canvasRef" width="500" height="400"></canvas>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue'
import * as echarts from 'echarts'
import { ref, onMounted, watch } from 'vue'
const props = defineProps({
innerData: {
type: Array,
default: () => [0.68, 0.85, 1.07, 1.18, 1.13, 0.97, 0.67, 0.98]
},
middleData: {
type: Array,
default: () => [9.52, 9.95, 10.53, 11.04, 11.34, 11.15, 9.66, 10.40]
selectedLayer: {
type: String,
default: ''
},
outerData: {
type: Array,
default: () => [1.15, 1.19, 1.21, 1.17, 1.05, 0.96, 1.06, 0.79]
default: () => [1.15, 0.67, 5.2, 0.85, 1.07, 1.18, 1.1, 0.97]
},
errorRange: {
middleData: {
type: Array,
default: () => [180, 225] //
default: () => [9.52, 9.66, 9.5, 9.95, 10.53, 11.04, 1.4, 11.15]
},
innerData: {
type: Array,
default: () => [0.79, 0.97, 0.6, 0.85, 1.07, 1.18, 1.2, 0.96]
},
//
eccentricity: {
type: Number,
default: 0.08 // 8%
},
nominalValue: {
type: Number,
default: 0.06 // 6%
}
})
const chartRef = ref(null)
let chart = null
const canvasRef = ref(null)
let ctx = null
const initChart = () => {
if (chart) {
chart.dispose()
}
const drawCircles = () => {
const canvas = canvasRef.value
ctx = canvas.getContext('2d')
const centerX = canvas.width / 2
const centerY = canvas.height / 2
//
ctx.clearRect(0, 0, canvas.width, canvas.height)
// //
const radii = [30,50,90,100]
//
const angles = [0, 45, 90, 135, 180, 225, 270, 315]
nextTick(() => {
chart = echarts.init(chartRef.value)
const option = {
color: ['#67F9D8', '#FFE434', '#56A3F1', '#FF917C'],
legend: {
show: false
},
radar: [
{
indicator: [
{ text: `${props.outerData[0]}\n${props.middleData[0]}\n${props.innerData[0]}`, max: 100 },
{ text: `${props.outerData[1]}\n${props.middleData[1]}\n${props.innerData[1]}`, max: 100 },
{ text: `${props.outerData[2]}\n${props.middleData[2]}\n${props.innerData[2]}`, max: 100 },
{ text: `${props.outerData[3]}\n${props.middleData[3]}\n${props.innerData[3]}`, max: 100 },
{ text: `${props.outerData[4]}\n${props.middleData[4]}\n${props.innerData[4]}`, max: 100 },
{ text: `${props.outerData[5]}\n${props.middleData[5]}\n${props.innerData[5]}`, max: 100 },
{ text: `${props.outerData[6]}\n${props.middleData[6]}\n${props.innerData[6]}`, max: 100 },
{ text: `${props.outerData[7]}\n${props.middleData[7]}\n${props.innerData[7]}`, max: 100 }
],
center: ['50%', '50%'], //
radius: '60%', //
startAngle: 90,
splitNumber: 1, //
shape: 'circle',
axisName: {
show: true,
color: '#333',
fontSize: 12,
rich: {
value: {
lineHeight: 20,
align: 'center'
}
}
},
splitArea: {
show: false
},
axisLine: {
lineStyle: {
color: '#999'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#999',
type: 'dashed'
},
formatter: function(params) {
// 45°135°225°315°线
const angles = [45, 135, 225, 315]
return angles.includes(params.value) ? params.value : ''
}
}
}
],
series: [
{
type: 'radar',
data: [
{
value: [80, 70, 90, 85, 75, 88, 82, 78],
symbol: 'none', //
lineStyle: {
color: '#1890ff',
width: 2
},
areaStyle: {
color: 'rgba(24, 144, 255, 0.2)'
},
smooth: true, // 线
smoothMonotone: 'cw', //
emphasis: {
focus: 'series'
}
}
]
}
]
// //
for (let i = 0; i < 3; i++) {
ctx.beginPath()
ctx.arc(centerX, centerY, radii[i], 0, 2 * Math.PI)
ctx.arc(centerX, centerY, radii[i + 1], 0, 2 * Math.PI, true)
ctx.closePath()
//
let fillColor = '#F5F7FA' //
if (props.selectedLayer === 'inner' && i === 0) {
fillColor = '#1D4389' //
} else if (props.selectedLayer === 'middle' && i === 1) {
fillColor = '#1D4389' //
} else if (props.selectedLayer === 'outer' && i === 2) {
fillColor = '#1D4389' //
}
chart.setOption(option)
ctx.fillStyle = fillColor
ctx.fill()
}
// // //
ctx.beginPath()
ctx.arc(centerX, centerY, radii[0], 0, 2 * Math.PI)
ctx.arc(centerX, centerY, radii[1], 0, 2 * Math.PI, true)
ctx.closePath()
ctx.fillStyle = props.selectedLayer === 'inner' ? '#1D4389' : '#F5F7FA'
ctx.fill()
//
// console.log(centerX, centerY, radii[0], radii[1], radii[2])
// angles.forEach((angle, index) => {
// console.log(angle,'angle')
// const radian = angle * Math.PI / 180
// console.log(radian,'radian')
// const actualRadius = radii[1] + props.innerData[index]
// console.log(actualRadius,'actualRadius')
// ctx.beginPath()
// ctx.arc(centerX, centerY, actualRadius, angle * Math.PI / 180, ((angle + 45) % 360) * Math.PI / 180)
// ctx.arc(centerX, centerY, radii[2], ((angle + 45) % 360) * Math.PI / 180, angle * Math.PI / 180, true)
// ctx.closePath()
// ctx.fillStyle = props.selectedLayer === 'middle' ? '#1D4389' : '#F5F7FA'
// ctx.fill()
// })
// middleData
// angles.forEach((angle, index) => {
// const radian = angle * Math.PI / 180
// const actualRadius = radii[2] + props.middleData[index]
//
// ctx.beginPath()
// ctx.arc(centerX, centerY, actualRadius, angle * Math.PI / 180, ((angle + 45) % 360) * Math.PI / 180)
// ctx.arc(centerX, centerY, radii[3], ((angle + 45) % 360) * Math.PI / 180, angle * Math.PI / 180, true)
// ctx.closePath()
// ctx.fillStyle = props.selectedLayer === 'outer' ? '#1D4389' : '#F5F7FA'
// ctx.fill()
// })
// outerData
// angles.forEach((angle, index) => {
// const radian = angle * Math.PI / 180
// const actualRadius = radii[3] + props.outerData[index]
//
// ctx.beginPath()
// ctx.arc(centerX, centerY, actualRadius, angle * Math.PI / 180, ((angle + 45) % 360) * Math.PI / 180)
// ctx.strokeStyle = '#666'
// ctx.lineWidth = 1
// ctx.stroke()
// })
//
for (let i = 0; i < radii.length - 1; i++) {
ctx.beginPath()
ctx.arc(centerX, centerY, radii[i], 0, 2 * Math.PI)
ctx.strokeStyle = '#666'
ctx.lineWidth = 1
ctx.stroke()
}
// 线
ctx.beginPath()
// 135315线
ctx.moveTo(
centerX - radii[3] * Math.cos(Math.PI * 135 / 180),
centerY + radii[3] * Math.sin(Math.PI * 135 / 180)
)
ctx.lineTo(
centerX + radii[3] * Math.cos(Math.PI * 135 / 180),
centerY - radii[3] * Math.sin(Math.PI * 135 / 180)
)
// 45225线
ctx.moveTo(
centerX - radii[3] * Math.cos(Math.PI * 45 / 180),
centerY - radii[3] * Math.sin(Math.PI * 45 / 180)
)
ctx.lineTo(
centerX + radii[3] * Math.cos(Math.PI * 45 / 180),
centerY + radii[3] * Math.sin(Math.PI * 45 / 180)
)
ctx.strokeStyle = '#999'
ctx.lineWidth = 1
ctx.stroke()
//
angles.forEach((angle, index) => {
const radian = (angle - 90) * Math.PI / 180
//
ctx.font = `${props.selectedLayer === 'inner' ? 'bold 14px' : '12px'} Arial`
ctx.fillStyle = '#333'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
const x1 = centerX + (radii[3] + 20) * Math.cos(radian)
const y1 = centerY + (radii[3] + 20) * Math.sin(radian)
ctx.fillText(props.outerData[index].toString(), x1, y1)
//
ctx.font = `${props.selectedLayer === 'middle' ? 'bold 14px' : '12px'} Arial`
const x2 = centerX + (radii[3] + 40) * Math.cos(radian)
const y2 = centerY + (radii[3] + 40) * Math.sin(radian)
ctx.fillText(props.middleData[index].toString(), x2, y2)
//
ctx.font = `${props.selectedLayer === 'outer' ? 'bold 14px' : '12px'} Arial`
const x3 = centerX + (radii[3] + 60) * Math.cos(radian)
const y3 = centerY + (radii[3] + 60) * Math.sin(radian)
ctx.fillText(props.innerData[index].toString(), x3, y3)
})
}
//
// watch([() => props.innerData, () => props.middleData, () => props.outerData], () => {
// initChart()
// }, { deep: true })
//
const refresh = () => {
initChart()
}
//
watch(
() => props.selectedLayer,
() => {
drawCircles()
}
)
onMounted(() => {
initChart()
window.addEventListener('resize', () => chart?.resize())
})
onUnmounted(() => {
window.removeEventListener('resize', () => chart?.resize())
chart?.dispose()
drawCircles()
})
//
defineExpose({
refresh
refresh: drawCircles
})
</script>
<style scoped lang="scss">
<style scoped>
.circle-chart {
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
background: #fff;
border-radius: 4px;
}
</style>
</style>
<!--<template>-->
<!-- <div class="circle-chart">-->
<!-- <div ref="chartRef" style="width: 400px; height: 400px;"></div>-->
<!-- </div>-->
<!--</template>-->
<!--<script setup>-->
<!--import { ref, onMounted, onUnmounted, watch } from 'vue'-->
<!--import * as echarts from 'echarts'-->
<!--const props = defineProps({-->
<!-- innerData: {-->
<!-- type: Array,-->
<!-- default: () => [0.68, 0.85, 1.07, 1.18, 1.13, 0.97, 0.67, 0.98]-->
<!-- },-->
<!-- middleData: {-->
<!-- type: Array,-->
<!-- default: () => [9.52, 9.95, 10.53, 11.04, 11.34, 11.15, 9.66, 10.40]-->
<!-- },-->
<!-- outerData: {-->
<!-- type: Array,-->
<!-- default: () => [1.15, 1.19, 1.21, 1.17, 1.05, 0.96, 1.06, 0.79]-->
<!-- },-->
<!-- errorRange: {-->
<!-- type: Array,-->
<!-- default: () => [180, 225] // -->
<!-- }-->
<!--})-->
<!--const chartRef = ref(null)-->
<!--let chart = null-->
<!--const initChart = () => {-->
<!-- if (chart) {-->
<!-- chart.dispose()-->
<!-- }-->
<!-- nextTick(() => {-->
<!-- chart = echarts.init(chartRef.value)-->
<!-- const option = {-->
<!-- // color: ['#67F9D8', '#FFE434', '#56A3F1', '#FF917C'],-->
<!-- legend: {-->
<!-- show: false-->
<!-- },-->
<!-- radar: [-->
<!-- {-->
<!-- indicator: [-->
<!-- { text: `${props.outerData[0]}\n${props.middleData[0]}\n${props.innerData[0]}`, max: 100 },-->
<!-- { text: `${props.outerData[1]}\n${props.middleData[1]}\n${props.innerData[1]}`, max: 100 },-->
<!-- { text: `${props.outerData[2]}\n${props.middleData[2]}\n${props.innerData[2]}`, max: 100 },-->
<!-- { text: `${props.outerData[3]}\n${props.middleData[3]}\n${props.innerData[3]}`, max: 100 },-->
<!-- { text: `${props.outerData[4]}\n${props.middleData[4]}\n${props.innerData[4]}`, max: 100 },-->
<!-- { text: `${props.outerData[5]}\n${props.middleData[5]}\n${props.innerData[5]}`, max: 100 },-->
<!-- { text: `${props.outerData[6]}\n${props.middleData[6]}\n${props.innerData[6]}`, max: 100 },-->
<!-- { text: `${props.outerData[7]}\n${props.middleData[7]}\n${props.innerData[7]}`, max: 100 }-->
<!-- ],-->
<!-- center: ['50%', '50%'], // -->
<!-- radius: '60%', // -->
<!-- startAngle: 90,-->
<!-- splitNumber: 1, // -->
<!-- shape: 'circle',-->
<!-- axisName: {-->
<!-- show: true,-->
<!-- color: '#333',-->
<!-- fontSize: 12,-->
<!-- rich: {-->
<!-- value: {-->
<!-- lineHeight: 20,-->
<!-- align: 'center'-->
<!-- }-->
<!-- }-->
<!-- },-->
<!-- splitArea: {-->
<!-- areaStyle: {-->
<!-- color: '#F5F7FA',-->
<!-- shadowColor: 'rgba(0, 0, 0, 0.2)',-->
<!-- shadowBlur: 10-->
<!-- }-->
<!-- },-->
<!-- axisLine: {-->
<!-- lineStyle: {-->
<!-- color: '#999'-->
<!-- }-->
<!-- },-->
<!-- splitLine: {-->
<!-- show: true,-->
<!-- lineStyle: [{-->
<!-- color: '#999',-->
<!-- type: 'dashed'-->
<!-- },{color:'transparent'},{-->
<!-- color: '#999',-->
<!-- type: 'dashed'-->
<!-- }],-->
<!-- formatter: function(params) {-->
<!-- // 45°135°225°315°线-->
<!-- const angles = [45, 135, 225, 315]-->
<!-- return angles.includes(params.value) ? params.value : ''-->
<!-- }-->
<!-- }-->
<!-- }-->
<!-- ],-->
<!-- // series: [-->
<!-- // {-->
<!-- // type: 'radar',-->
<!-- // data: [-->
<!-- // {-->
<!-- // value: Array(8).fill(30),-->
<!-- // symbol: 'none',-->
<!-- // lineStyle: {-->
<!-- // color: 'transparent',-->
<!-- // width: 0-->
<!-- // },-->
<!-- // areaStyle: {-->
<!-- // color: '#1D4389'-->
<!-- // },-->
<!-- // smooth: true,-->
<!-- // smoothMonotone: 'cw'-->
<!-- // }-->
<!-- // ]-->
<!-- // },-->
<!-- // {-->
<!-- // type: 'radar',-->
<!-- // data: [-->
<!-- // {-->
<!-- // value: [50,50,50,50,50,50,50,50,50],-->
<!-- // symbol: 'none',-->
<!-- // lineStyle: {-->
<!-- // color: 'transparent',-->
<!-- // width: 0-->
<!-- // },-->
<!-- // areaStyle: {-->
<!-- // color: '#1D4389',-->
<!-- // },-->
<!-- // smooth: true,-->
<!-- // smoothMonotone: 'cw'-->
<!-- // },-->
<!-- // {-->
<!-- // value: Array(8).fill(40), // -->
<!-- // symbol: 'none',-->
<!-- // lineStyle: {-->
<!-- // color: 'transparent'-->
<!-- // },-->
<!-- // areaStyle: {-->
<!-- // color: 'transparent'-->
<!-- // }-->
<!-- // },-->
<!-- // {-->
<!-- // value: Array(8).fill(30), // -->
<!-- // symbol: 'none',-->
<!-- // lineStyle: {-->
<!-- // color: 'transparent'-->
<!-- // },-->
<!-- // areaStyle: {-->
<!-- // color: '#F5F7FA'-->
<!-- // }-->
<!-- // }-->
<!-- // ]-->
<!-- // }-->
<!-- // ]-->
<!-- series: [-->
<!-- {-->
<!-- type: 'radar',-->
<!-- data: [-->
<!-- {-->
<!-- value: Array(8).fill(30), // -->
<!-- symbol: 'none',-->
<!-- lineStyle: {-->
<!-- color: 'transparent',-->
<!-- width: 0-->
<!-- },-->
<!-- areaStyle: {-->
<!-- color: '#1D4389',-->
<!-- opacity: 1-->
<!-- },-->
<!-- smooth: true,-->
<!-- smoothMonotone: 'cw'-->
<!-- }-->
<!-- ]-->
<!-- },-->
<!-- {-->
<!-- type: 'radar',-->
<!-- data: [-->
<!-- {-->
<!-- value: props.middleData.map(val => Math.min(val * 7, 70)), // -->
<!-- symbol: 'none',-->
<!-- lineStyle: {-->
<!-- color: 'transparent',-->
<!-- width: 0-->
<!-- },-->
<!-- areaStyle: {-->
<!-- color: 'red',-->
<!-- opacity: 0.3-->
<!-- },-->
<!-- smooth: true,-->
<!-- smoothMonotone: 'cw'-->
<!-- },-->
<!-- {-->
<!-- value: Array(8).fill(30), // -->
<!-- symbol: 'none',-->
<!-- lineStyle: {-->
<!-- color: 'transparent'-->
<!-- },-->
<!-- areaStyle: {-->
<!-- color: '#F5F7FA',-->
<!-- opacity: 1-->
<!-- }-->
<!-- }-->
<!-- ]-->
<!-- }-->
<!-- ]-->
<!-- }-->
<!-- chart.setOption(option)-->
<!-- })-->
<!--}-->
<!--// -->
<!--// watch([() => props.innerData, () => props.middleData, () => props.outerData], () => {-->
<!--// initChart()-->
<!--// }, { deep: true })-->
<!--// -->
<!--const refresh = () => {-->
<!-- initChart()-->
<!--}-->
<!--onMounted(() => {-->
<!-- initChart()-->
<!-- window.addEventListener('resize', () => chart?.resize())-->
<!--})-->
<!--onUnmounted(() => {-->
<!-- window.removeEventListener('resize', () => chart?.resize())-->
<!-- chart?.dispose()-->
<!--})-->
<!--defineExpose({-->
<!-- refresh-->
<!--})-->
<!--</script>-->
<!--<style scoped lang="scss">-->
<!--.circle-chart {-->
<!-- display: flex;-->
<!-- justify-content: center;-->
<!-- align-items: center;-->
<!-- padding: 20px;-->
<!-- background: #fff;-->
<!-- border-radius: 4px;-->
<!--}-->
<!--</style>-->

View File

@ -8,13 +8,13 @@
</div>
<div class="action-buttons">
<div class="button-group">
<el-button
type="primary"
link
@click="handleShowImage()"
>
{{proxy.$t('equipment.imagePage')}}
</el-button>
<!-- <el-button-->
<!-- type="primary"-->
<!-- link-->
<!-- @click="handleShowImage()"-->
<!-- >-->
<!-- {{proxy.$t('equipment.imagePage')}}-->
<!-- </el-button>-->
<el-button
:type="mode === 'fast' ? 'primary' : ''"
@click="handleModeChange('fast')"
@ -24,6 +24,7 @@
</el-button>
<el-button
plain
:type="xRayStatus ? 'danger' : 'success'"
@click="handleXRayToggle"
>
@ -49,7 +50,7 @@
</div>
</div>
<div class="chart-container">
<div class="chart-box chart-box-left">
<div class="chart-box">
<el-tabs
v-model="activeName"
type="card"
@ -62,7 +63,7 @@
<div class="eccentricity-card" v-for="(item, index) in cardList" :key="index">
<div class="card-header">
<span class="title">{{item.title}}</span>
<el-icon class="close-icon"><Close /></el-icon>
<el-icon class="close-icon" @click="deleteCard(index)"><Close /></el-icon>
</div>
<div class="card-content">
@ -109,17 +110,20 @@
</div>
</div>
</div>
<div class="eccentricity-card" @click="openDialog">
<el-icon><Plus></Plus></el-icon>
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="数据组2" name="second">数据组2</el-tab-pane>
<el-tab-pane label="数据组3" name="third">数据组3</el-tab-pane>
</el-tabs>
<div class="btn">
<el-button type="primary">{{proxy.$t('button.add')}}</el-button>
</div>
</div>
<div class="chart-box chart-box-right">
</div>
<div class="chart-container">
<div class="chart-box">
<el-tabs
v-model="activeTwoName"
type="card"
@ -128,23 +132,30 @@
>
<el-tab-pane :label="proxy.$t('equipment.sketch')" name="first">
<div class="detection-section">
<CircleDetectionChart
:inner-data="innerLayerData"
:middle-data="middleLayerData"
:outer-data="outerLayerData"
/>
<el-radio-group v-model="selectedLayer" class="layer-select">
<el-radio label="outer">外屏蔽层</el-radio>
<el-radio label="middle">绝缘层</el-radio>
<el-radio label="inner">内屏蔽层</el-radio>
</el-radio-group>
<!-- <CircleDetectionChart-->
<!-- :inner-data="innerLayerData"-->
<!-- :middle-data="middleLayerData"-->
<!-- :outer-data="outerLayerData"-->
<!-- />-->
<CircleDetectionChart :selected-layer="selectedLayer" />
<!-- <CircleDetectionChart :eccentricity="0.08" :thickness="20" />-->
<div class="history-content">
<div>左边指南针</div>
<div class="history-right">
<div>
<el-button v-if="showHistory" type="primary" @click="showHistoryDialog">选择历史数据</el-button>
<el-switch
v-model="showHistory"
size="large"
style="margin-left: 6px"
:inactive-text="proxy.$t('equipment.historyData')"
/>
</div>
<div>
<el-button v-if="showHistory" type="primary" @click="showHistoryDialog">选择历史数据</el-button>
<el-switch
v-model="showHistory"
size="large"
style="margin-left: 6px"
:inactive-text="proxy.$t('equipment.historyData')"
/>
</div>
<div class="scanItem">扫描时间2025/01/07 04:34:8</div>
<div class="scanItem">2025-01-07_04_30_34_866_direction_1_device2.json</div>
</div>
@ -165,7 +176,7 @@
</div>
</div>
<div class="chart-container" style="margin-top: 14px">
<div class="chart-box chart-bottom-left">
<div class="chart-box">
<el-tabs
v-model="activeThreeName"
type="card"
@ -231,49 +242,49 @@
</el-tab-pane>
</el-tabs>
</div>
<div class="chart-box chart-bottom-right">
<div class="header">
<div>
<span>{{proxy.$t('equipment.imagePage')}}</span>
<span class="time">{{ currentTime }}</span>
</div>
<el-divider/>
</div>
<div class="imagePage-container">
<div class="imagePage-left">
<DataTable :table-data="tableData" />
</div>
<div class="charts">
<div class="controls">
<el-button-group>
<el-button type="primary" plain class="switch-btn" @click="handleImagePagePrev"><el-icon><ArrowLeft /></el-icon></el-button>
<el-button type="primary" plain class="switch-btn switch" @click="handleImagePageNext"><el-icon><ArrowRight /></el-icon></el-button>
<el-button type="primary" plain class="switch-btn switch" @click="handleRefresh"><el-icon><Refresh /></el-icon></el-button>
</el-button-group>
</div>
<div v-if="showImagePageRed">
<CurveChart ref="bowlCurvePageRef" :title="chartTitle.left" :color="colorRed"/>
<CurveChart ref="bowlCurvePageRef" :title="chartTitle.right" :color="colorRed"/>
</div>
<div v-if="showImagePageGreen">
<CurveChart ref="bowlCurvePageRef" :title="chartTitle.left" :color="colorGreen"/>
<CurveChart ref="bowlCurvePageRef" :title="chartTitle.right" :color="colorGreen"/>
</div>
<div v-if="showImagePageRedGreen">
<DualChannelChart
title="扫描臂1"
ref="dualChart1PageRef"
:chart-data="arm1ChartData"
/>
<DualChannelChart
title="扫描臂2"
ref="dualChart2PageRef"
:chart-data="arm2ChartData"
/>
</div>
</div>
</div>
</div>
<!-- <div class="chart-box chart-bottom-right">-->
<!-- <div class="header">-->
<!-- <div>-->
<!-- <span>{{proxy.$t('equipment.imagePage')}}</span>-->
<!-- <span class="time">{{ currentTime }}</span>-->
<!-- </div>-->
<!-- <el-divider/>-->
<!-- </div>-->
<!-- <div class="imagePage-container">-->
<!-- <div class="imagePage-left">-->
<!-- <DataTable :table-data="tableData" />-->
<!-- </div>-->
<!-- <div class="charts">-->
<!-- <div class="controls">-->
<!-- <el-button-group>-->
<!-- <el-button type="primary" plain class="switch-btn" @click="handleImagePagePrev"><el-icon><ArrowLeft /></el-icon></el-button>-->
<!-- <el-button type="primary" plain class="switch-btn switch" @click="handleImagePageNext"><el-icon><ArrowRight /></el-icon></el-button>-->
<!-- <el-button type="primary" plain class="switch-btn switch" @click="handleRefresh"><el-icon><Refresh /></el-icon></el-button>-->
<!-- </el-button-group>-->
<!-- </div>-->
<!-- <div v-if="showImagePageRed">-->
<!-- <CurveChart ref="bowlCurvePageRef" :title="chartTitle.left" :color="colorRed"/>-->
<!-- <CurveChart ref="bowlCurvePageRef" :title="chartTitle.right" :color="colorRed"/>-->
<!-- </div>-->
<!-- <div v-if="showImagePageGreen">-->
<!-- <CurveChart ref="bowlCurvePageRef" :title="chartTitle.left" :color="colorGreen"/>-->
<!-- <CurveChart ref="bowlCurvePageRef" :title="chartTitle.right" :color="colorGreen"/>-->
<!-- </div>-->
<!-- <div v-if="showImagePageRedGreen">-->
<!-- <DualChannelChart-->
<!-- title="扫描臂1"-->
<!-- ref="dualChart1PageRef"-->
<!-- :chart-data="arm1ChartData"-->
<!-- />-->
<!-- <DualChannelChart-->
<!-- title="扫描臂2"-->
<!-- ref="dualChart2PageRef"-->
<!-- :chart-data="arm2ChartData"-->
<!-- />-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
<!-- 历史数据弹框-->
<HistoryDataDialog
@ -281,23 +292,41 @@
@confirm="handleHistoryConfirm"
@cancel="handleHistoryCancel"
/>
<!-- 添加数据弹框-->
<AddMonitorData ref="addMonitorRef" @confirm="handleDataConfirm" />
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { Close, ArrowLeft, ArrowRight, Timer, Refresh } from '@element-plus/icons-vue'
import {getDeviceDetailApi} from "@/api/equipment/index.js";
import {Close, ArrowLeft, ArrowRight, Timer, Refresh, Plus} from '@element-plus/icons-vue'
import TemperatureChart from './common/TemperatureChart.vue'
import RealtimeChart from './common/RealtimeChart.vue';
import DeviceStatus from './common/DeviceStatus.vue';
import DeviceSetting from './common/DeviceSetting.vue';
import DataTable from './common/DataTable.vue';
import DualChannelChart from './common/DualChannelChart.vue';
import CurveChart from './common/CurveChart.vue';
import CircleDetectionChart from "./common/CircleDetectionChart.vue";
import HistoryDataDialog from './common/HistoryDataDialog.vue';
import {ElMessageBox} from "element-plus";
import {ElMessageBox, ElMessage} from "element-plus";
import { useMqtt } from '@/utils/mqttClient.js';
import {useRoute} from 'vue-router';
import AddMonitorData from './common/AddMonitorData.vue'
const {
connected,
messageData,
connect,
subscribe,
disconnect,
publish
} = useMqtt()
const deviceInfo = ref(null)
const deviceData = ref(null)
const { proxy } = getCurrentInstance();
const route = useRoute()
const deviceId = ref(null)
const selectedLayer = ref('outer')
const toleranceList = ['15%', '20%', '25%']
const showRed = ref(true)
const showGreen = ref(false)
@ -328,14 +357,14 @@ const chartTitle = ref({
left: '扫描臂1 曲线',
right: '扫描臂2 曲线'
})
const cardList = [
const cardList = ref([
{ title: '外屏层偏心度' },
{ title: '内屏层偏心度' },
{ title: '绝缘层偏心度' },
{ title: '外屏层厚度' },
{ title: '内屏层厚度' },
{ title: '绝缘层厚度' }
]
// { title: '' }
])
const warningList = ref([
{ title: '设备1离线', status: 'offline' },
{ title: '设备2离线', status: 'offline' },
@ -386,6 +415,7 @@ const deviceStatus = ref({
currentSet: '1800'
}
})
const addMonitorRef = ref(null)
//
const tableData = ref([
{ name: '射线电源反馈电压[V]', arm1: '15', arm2: '0' },
@ -403,47 +433,45 @@ const arm2ChartData = ref({
a: Array.from({ length: 100 }, () => Math.random() * 9000),
b: Array.from({ length: 100 }, () => Math.random() * 9000)
})
//
const handleImagePageNext = () => {
if (showImagePageRedGreen.value) {
showImagePageRedGreen.value = false
showImagePageRed.value = true
showImagePageGreen.value = false
} else if (showImagePageRed.value) {
showImagePageRedGreen.value = false
showImagePageRed.value = false
showImagePageGreen.value = true
} else if (showImagePageGreen.value) {
showImagePageRedGreen.value = true
showImagePageRed.value = false
showImagePageGreen.value = false
}
//
const openDialog = () => {
addMonitorRef.value.showDialog()
}
const handleDataConfirm = (dataType) => {
console.log('选择的数据项:', dataType)
//
}
// mqtt
const mqttConnect = () => {
connect('ws://123.57.81.127:8085/mqtt', { // /mqtt
clientId: 'vue-client-' + Math.random().toString(16).substring(2, 8),
username: 'cepianyi',
password: 'cpy123',
protocol: 'ws',
protocolVersion: 4,
keepalive: 60,
reconnectPeriod: 1000,
connectTimeout: 30 * 1000,
path: '/mqtt'// WebSocket
})
}
const handleImagePagePrev = () => {
if (showImagePageRedGreen.value) {
showImagePageRedGreen.value = false
showImagePageRed.value = false
showImagePageGreen.value = true
} else if (showImagePageGreen.value) {
showImagePageRedGreen.value = false
showImagePageRed.value = true
showImagePageGreen.value = false
} else if (showImagePageRed.value) {
showImagePageRedGreen.value = true
showImagePageRed.value = false
showImagePageGreen.value = false
}
}
const handleRefresh = () => {
//
if (showImagePageRedGreen.value) {
dualChart1PageRef.value?.refresh()
dualChart2PageRef.value?.refresh()
} else {
bowlCurvePageRef.value?.refresh()
}
const deleteCard = (index) => {
ElMessageBox.confirm(
'确认删除该卡片吗?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
cardList.value.splice(index, 1)
ElMessage.success('删除成功')
}).catch(() => {
//
})
}
//
const showHistoryDialog = () => {
@ -542,11 +570,6 @@ const handleSettingUpdate = ({ key, value }) => {
const handleDataUpdate = (data) => {
console.log('数据更新:', data)
}
//
const handleShowImage = () => {
// router.push({ path: '/image-page' })
// ElMessage.success('')
}
//
const handleModeChange = (newMode) => {
mode.value = newMode
@ -574,9 +597,26 @@ const handleGenerateReport = () => {
//
const handleDeviceShare = () => {
}
//
const getDeviceDetail = async () => {
try {
const response = await getDeviceDetailApi(deviceId.value)
console.log('设备信息:', deviceInfo.value)
} catch (error) {
console.error('获取设备信息失败:', error)
}
}
onMounted(() => {
if(route.query.id) {
deviceId.value= route.query.id;
mqttConnect()
}
generateData()
})
onBeforeUnmount(() => {
disconnect()
})
</script>
<style scoped lang="scss">
@ -629,6 +669,7 @@ onMounted(() => {
gap: 20px;
.chart-box {
flex:1;
position: relative;
padding: 14px;
background: #fff;
@ -640,12 +681,6 @@ onMounted(() => {
right: 14px;
}
}
.chart-box-left {
width:60%;
}
.chart-box-right {
flex: 1;
}
}
}
.action-buttons {

View File

@ -88,9 +88,6 @@
</template>
</el-table-column>
<el-table-column :label="proxy.$t('equipment.serviceStatus')" align="center" prop="serviceStatus" width="100">
<template #default="scope">
{{statusFormat(scope.row.serviceStatus)}}
</template>
</el-table-column>
<el-table-column :label="proxy.$t('customer.createBy')" align="center" prop="createBy" width="160" />
<el-table-column :label="proxy.$t('customer.createTime')" align="center" prop="createTime" width="200" />
@ -111,44 +108,31 @@
type="primary"
@click="handleGo(scope.row)"
>{{ proxy.$t('button.viewDetails') }}</el-button>
<!-- <el-dropdown @command="handleCommand">-->
<!-- <el-button type="primary" link>-->
<!-- 更多<el-icon class="el-icon&#45;&#45;right"><CaretBottom /></el-icon>-->
<!-- </el-button>-->
<!-- <template #dropdown>-->
<!-- <el-dropdown-menu>-->
<!-- <el-dropdown-item :command="{ type: 'stop', row }"-->
<!-- :disabled="row.status === 0">停止服务</el-dropdown-item>-->
<!-- <el-dropdown-item :command="{ type: 'restart', row }"-->
<!-- :disabled="row.status === 0">重启服务</el-dropdown-item>-->
<!-- <el-dropdown-item :command="{ type: 'start', row }"-->
<!-- :disabled="row.status === 1">启动服务</el-dropdown-item>-->
<!-- </el-dropdown-menu>-->
<!-- </template>-->
<!-- </el-dropdown>-->
<!-- <el-dropdown placement="bottom">-->
<!-- <el-button-->
<!-- link-->
<!-- type="primary"-->
<!-- >更多</el-button>-->
<!-- <template #dropdown>-->
<!-- <el-dropdown-menu>-->
<!-- <el-dropdown-item>停止服务</el-dropdown-item>-->
<!-- <el-dropdown-item>重启服务</el-dropdown-item>-->
<!-- <el-dropdown-item>启动服务</el-dropdown-item>-->
<!-- </el-dropdown-menu>-->
<!-- </template>-->
<!-- </el-dropdown>-->
<!-- <el-button-->
<!-- link-->
<!-- type="primary"-->
<!-- @click="handleShare(scope.row)"-->
<!-- >分享</el-button>-->
<el-dropdown @command="handleCommand">
<el-button type="primary" link>
更多<el-icon class="el-icon--right"><CaretBottom /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :command="{ type: 'stop', row: scope.row }"
:disabled="scope.row.status === 0">停止服务</el-dropdown-item>
<el-dropdown-item :command="{ type: 'restart', row: scope.row }"
:disabled="scope.row.status === 0">重启服务</el-dropdown-item>
<el-dropdown-item :command="{ type: 'start', row: scope.row }"
:disabled="scope.row.status === 1">启动服务</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-button
link
type="primary"
@click="handleEmqx(scope.row)"
>{{proxy.$t('equipment.viewAuth')}}</el-button>
@click="handleShare(scope.row)"
>分享</el-button>
<!-- <el-button-->
<!-- link-->
<!-- type="primary"-->
<!-- @click="handleEmqx(scope.row)"-->
<!-- >{{proxy.$t('equipment.viewAuth')}}</el-button>-->
</template>
</el-table-column>
</el-table>
@ -199,7 +183,7 @@
</template>
</el-dialog>
<!--查看鉴权-->
<EmqDialog ref="emqDialogRef" :form-data="emqFormData" ></EmqDialog>
<!-- <EmqDialog ref="emqDialogRef" :form-data="emqFormData" ></EmqDialog>-->
<!--分享-->
<ShareDialog ref="shareDialogRef" :form-data="shareDialogRef"></ShareDialog>
</div>
@ -224,6 +208,15 @@ import {getDicts} from "@/api/system/dict/data.js";
import { useI18n } from 'vue-i18n';
import {deleteDepartmentPostApi, getCustomerListApi} from "@/api/customer/index.js";
import EmqDialog from './common/EmqDialog.vue'
import { useMqtt } from '@/utils/mqttClient.js';
const {
connected,
messageData,
connect,
subscribe,
disconnect,
publish
} = useMqtt()
const emqDialogRef = ref()
const emqFormData = ref({})
const router = useRouter()
@ -286,49 +279,50 @@ const getStatus = async() => {
ElMessage.error(res.msg)
}
}
// const handleCommand = async ({ type, row }) => {
// const actionMap = {
// stop: {
// title: '',
// // api: stopDeviceApi,
// successMsg: ''
// },
// restart: {
// title: '',
// // api: restartDeviceApi,
// successMsg: ''
// },
// start: {
// title: '',
// // api: startDeviceApi,
// successMsg: ''
// }
// }
//
// const action = actionMap[type]
//
// try {
// await ElMessageBox.confirm(
// `${action.title}?`,
// '',
// {
// confirmButtonText: '',
// cancelButtonText: '',
// type: 'warning'
// }
// )
//
// const res = await action.api(row.id)
// if (res.code === 200) {
// ElMessage.success(action.successMsg)
// getList() //
// } else {
// ElMessage.error(res.msg)
// }
// } catch {
// //
// }
// }
//
const handleCommand = async ({ type, row }) => {
const actionMap = {
stop: {
title: '停止服务',
command: 'stop',
successMsg: '停止成功'
},
restart: {
title: '重启服务',
command: 'restart',
successMsg: '重启成功'
},
start: {
title: '启动服务',
command: 'start',
successMsg: '启动成功'
}
}
const action = actionMap[type]
try {
await ElMessageBox.confirm(
`是否确认${action.title}?`,
'警告',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
//
publish(`v1/cpycal/${row.deviceCode}/control`, JSON.stringify({
command: action.command
}))
} catch (error) {
console.error('操作失败:', error)
ElMessage.error('操作失败')
}
}
//
const exportDevice = async() => {
proxy?.download(
@ -351,6 +345,20 @@ const getList = async() => {
if(res.code === 200) {
deviceList.value = res.rows || []
total.value = res.total
if (deviceList.value.length > 0) {
deviceList.value.map(item => {
subscribe(`v1/cpycal/${item.deviceCode}/status`, (message) => {
console.log('Received message:', message)
const index = deviceList.value.findIndex(device => device.deviceCode === item.deviceCode)
if (index !== -1) {
deviceList.value[index] = {
...deviceList.value[index],
serviceStatus: message.running ? '在线' : '离线'
}
}
})
})
}
}
loading.value = false
}
@ -480,8 +488,21 @@ watch(
},
{ immediate: true }
)
onMounted(() => {
// mqtt
const mqttConnect = () => {
connect('ws://123.57.81.127:8085/mqtt', { // /mqtt
clientId: 'vue-client-' + Math.random().toString(16).substring(2, 8),
username: 'cepianyi',
password: 'cpy123',
protocol: 'ws',
protocolVersion: 4,
keepalive: 60,
reconnectPeriod: 1000,
connectTimeout: 30 * 1000,
path: '/mqtt'// WebSocket
})
}
onMounted(async() => {
// 使
if (route.query.id) {
queryParams.customerId = route.query.id
@ -489,10 +510,11 @@ onMounted(() => {
if (route.query.id) {
queryParams.customerId = Number(route.query.id)
}
getList()
getCustomerList()
getUserSelect()
getStatus()
await mqttConnect()
await getList()
await getCustomerList()
await getUserSelect()
await getStatus()
})
</script>

View File

@ -129,6 +129,7 @@ onMounted(() => {
getMaintainSummary()
getMaintainAnalysis()
})
</script>
<style scoped lang="scss">
@ -159,7 +160,7 @@ onMounted(() => {
align-items: center;
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
.img-icon {
border:1px dashed #ccc;
//border:1px dashed #ccc;
margin-right: 10px;
}
.number {

View File

@ -54,8 +54,8 @@
<el-table-column :label="proxy.$t('maintenance.maintenanceType')" align="center" prop="maintenanceTypeName" />
<el-table-column :label="proxy.$t('common.comments')" align="center" prop="comments" />
<el-table-column :label="proxy.$t('maintenance.maintenanceUser')" align="center" prop="maintenanceUser" />
<el-table-column :label="proxy.$t('maintenance.maintenanceDate')" align="center" prop="maintenanceDate" width="100" />
<el-table-column :label="proxy.$t('maintenance.createTime')" align="center" prop="createTime" width="160" />
<el-table-column :label="proxy.$t('maintenance.maintenanceDate')" align="center" prop="maintenanceDate" width="160" />
<el-table-column :label="proxy.$t('customer.createTime')" align="center" prop="createTime" width="160" />
<el-table-column :label="proxy.$t('common.action')" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button

View File

@ -85,7 +85,7 @@
<!-- 添加或修改菜单对话框 -->
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
<el-form ref="menuRef" :model="form" :rules="rules" label-width="100px">
<el-form ref="menuRef" :model="form" :rules="rules" label-width="120px">
<el-row>
<el-col :span="24">
<el-form-item label="上级菜单">
@ -138,10 +138,15 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="菜单名称" prop="menuName">
<el-form-item label="中文菜单名称" prop="menuName">
<el-input v-model="form.menuName" placeholder="请输入菜单名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="英文菜单名称" prop="menuNameEn">
<el-input v-model="form.menuNameEn" placeholder="请输入菜单名称" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item prop="routeName">
<template #label>
@ -314,6 +319,7 @@ const data = reactive({
},
rules: {
menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
menuNameEn: [{ required: true, message: "菜单英文名称不能为空", trigger: "blur" }],
orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
},
@ -352,6 +358,7 @@ function reset() {
menuId: undefined,
parentId: 0,
menuName: undefined,
menuNameEn:undefined,
icon: undefined,
menuType: "M",
orderNum: undefined,

View File

@ -215,7 +215,7 @@
<script setup name="User">
import { getToken } from "@/utils/auth";
import useAppStore from '@/store/modules/app'
import {useAppStore} from '@/store/modules/app'
import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect } from "@/api/system/user";
import { Splitpanes, Pane } from "splitpanes"
import "splitpanes/dist/splitpanes.css"

View File

@ -1,17 +1,18 @@
<template>
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
<el-form-item label="旧密码" prop="oldPassword">
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
<el-form ref="pwdRef" :model="user" :rules="rules" :label-width="appStore.language === 'zh_CN' ? '100px' : '160px'"
label-position="right">
<el-form-item :label="proxy.$t('common.oldPassword')" prop="oldPassword">
<el-input v-model="user.oldPassword" :placeholder="proxy.$t('common.inputOldPassword')" type="password" show-password />
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
<el-form-item :label="proxy.$t('common.newPassword')" prop="newPassword">
<el-input v-model="user.newPassword" :placeholder="proxy.$t('common.inputNewPassword')" type="password" show-password />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password/>
<el-form-item :label="proxy.$t('common.confirmPassword')" prop="confirmPassword">
<el-input v-model="user.confirmPassword" :placeholder="proxy.$t('common.inputNewPassword')" type="password" show-password/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">保存</el-button>
<el-button type="danger" @click="close">关闭</el-button>
<el-button type="primary" @click="submit">{{proxy.$t('button.save')}}</el-button>
<el-button type="danger" @click="close">{{proxy.$t('button.cancel')}}</el-button>
</el-form-item>
</el-form>
</template>
@ -19,6 +20,8 @@
<script setup>
import { updateUserPwd } from "@/api/system/user";
import { useAppStore } from '@/store/modules/app';
const appStore = useAppStore();
const { proxy } = getCurrentInstance();
const user = reactive({
@ -29,16 +32,16 @@ const user = reactive({
const equalToPassword = (rule, value, callback) => {
if (user.newPassword !== value) {
callback(new Error("两次输入的密码不一致"));
callback(new Error(proxy.$t('common.passwordNotEqual')));
} else {
callback();
}
};
const rules = ref({
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
oldPassword: [{ required: true, message: proxy.$t('common.oldPasswordValid'), trigger: "blur" }],
newPassword: [{ required: true, message: proxy.$t('common.newPasswordValid'), trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
confirmPassword: [{ required: true, message: proxy.$t('common.confirmPasswordValid'), trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
});
/** 提交按钮 */
@ -57,3 +60,8 @@ function close() {
proxy.$tab.closePage();
};
</script>
<style lang="scss" scoped>
:deep(.el-form-item__label) {
justify-content: flex-end;
}
</style>

View File

@ -1,5 +1,7 @@
<template>
<el-form ref="userRef" :model="form" :rules="rules" label-width="80px">
<el-form ref="userRef" :model="form" :rules="rules"
:label-width="appStore.language === 'zh_CN' ? '80px' : '140px'"
label-position="right">
<el-form-item :label="proxy.$t('equipment.nickName')" prop="nickName">
<el-input v-model="form.nickName" maxlength="30" />
</el-form-item>
@ -24,14 +26,16 @@
<script setup>
import { updateUserProfile } from "@/api/system/user";
import { useAppStore } from '@/store/modules/app';
const appStore = useAppStore();
const { proxy } = getCurrentInstance();
const props = defineProps({
user: {
type: Object
}
});
const { proxy } = getCurrentInstance();
const form = ref({});
const rules = ref({
@ -65,3 +69,8 @@ watch(() => props.user, user => {
}
},{ immediate: true });
</script>
<style scoped>
:deep(.el-form-item__label) {
justify-content: flex-end;
}
</style>

View File

@ -30,11 +30,11 @@ export default defineConfig(({ mode, command }) => {
open: true,
proxy: {
[env.VITE_APP_BASE_API]: {
target: 'http://124.236.46.74:8104',
// target: 'http://192.168.0.22:8111/',
// target: 'http://124.236.46.74:8104',
target: 'http://192.168.0.109:8081/',
changeOrigin: true,
// rewrite: (p) => p.replace(/^\/dev-api/, '')
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '/api')
rewrite: (p) => p.replace(/^\/dev-api/, '')
// rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '/api')
}
}
},

260
yarn.lock
View File

@ -24,6 +24,11 @@
dependencies:
"@babel/types" "^7.27.0"
"@babel/runtime@^7.23.8", "@babel/runtime@^7.24.5":
version "7.27.4"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.27.4.tgz"
integrity sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==
"@babel/types@^7.27.0":
version "7.27.0"
resolved "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz"
@ -184,6 +189,13 @@
dependencies:
undici-types "~6.20.0"
"@types/readable-stream@^4.0.0":
version "4.0.20"
resolved "https://registry.npmmirror.com/@types/readable-stream/-/readable-stream-4.0.20.tgz"
integrity sha512-eLgbR5KwUh8+6pngBDxS32MymdCsCHnGtwHTrC0GDorbc7NbcnkZAWptDLgZiRk9VRas+B6TyRgPDucq4zRs8g==
dependencies:
"@types/node" "*"
"@types/svgo@^2.6.1":
version "2.6.4"
resolved "https://registry.npmjs.org/@types/svgo/-/svgo-2.6.4.tgz"
@ -395,6 +407,13 @@ abbrev@^2.0.0:
resolved "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz"
integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==
abort-controller@^3.0.0:
version "3.0.0"
resolved "https://registry.npmmirror.com/abort-controller/-/abort-controller-3.0.0.tgz"
integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
dependencies:
event-target-shim "^5.0.0"
acorn@^8.14.0:
version "8.14.1"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz"
@ -540,6 +559,11 @@ base@^0.11.1:
mixin-deep "^1.2.0"
pascalcase "^0.1.1"
base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz"
@ -550,6 +574,16 @@ binary-extensions@^2.0.0:
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz"
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
bl@^6.0.8:
version "6.1.0"
resolved "https://registry.npmmirror.com/bl/-/bl-6.1.0.tgz"
integrity sha512-ClDyJGQkc8ZtzdAAbAwBmhMSpwN/sC9HA8jxdYm6nVUbCfZbe2mgza4qh7AuEYyEPB/c4Kznf9s66bnsKMQDjw==
dependencies:
"@types/readable-stream" "^4.0.0"
buffer "^6.0.3"
inherits "^2.0.4"
readable-stream "^4.2.0"
bluebird@^3.5.0:
version "3.7.2"
resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz"
@ -590,6 +624,19 @@ braces@^3.0.3, braces@~3.0.2:
dependencies:
fill-range "^7.1.1"
buffer-from@^1.0.0:
version "1.1.2"
resolved "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
buffer@^6.0.3:
version "6.0.3"
resolved "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz"
integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
dependencies:
base64-js "^1.3.1"
ieee754 "^1.2.1"
cache-base@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz"
@ -726,11 +773,26 @@ commander@^7.2.0:
resolved "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz"
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
commist@^3.2.0:
version "3.2.0"
resolved "https://registry.npmmirror.com/commist/-/commist-3.2.0.tgz"
integrity sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==
component-emitter@^1.2.1:
version "1.3.1"
resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz"
integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==
concat-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/concat-stream/-/concat-stream-2.0.0.tgz"
integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==
dependencies:
buffer-from "^1.0.0"
inherits "^2.0.3"
readable-stream "^3.0.2"
typedarray "^0.0.6"
confbox@^0.1.8:
version "0.1.8"
resolved "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz"
@ -853,7 +915,7 @@ debug@^2.3.3:
dependencies:
ms "2.0.0"
debug@^4.3.3:
debug@^4.3.1, debug@^4.3.3, debug@^4.3.4, debug@^4.4.0:
version "4.4.0"
resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz"
integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
@ -1227,11 +1289,21 @@ etag@^1.8.1:
resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz"
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
event-target-shim@^5.0.0:
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==
eventemitter3@^2.0.3:
version "2.0.3"
resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz"
integrity sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==
events@^3.3.0:
version "3.3.0"
resolved "https://registry.npmmirror.com/events/-/events-3.3.0.tgz"
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
expand-brackets@^2.1.4:
version "2.1.4"
resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz"
@ -1313,6 +1385,14 @@ fast-glob@^3.3.2, fast-glob@^3.3.3:
merge2 "^1.3.0"
micromatch "^4.0.8"
fast-unique-numbers@^8.0.13:
version "8.0.13"
resolved "https://registry.npmmirror.com/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz"
integrity sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==
dependencies:
"@babel/runtime" "^7.23.8"
tslib "^2.6.2"
fastq@^1.6.0:
version "1.19.1"
resolved "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz"
@ -1593,6 +1673,11 @@ he@^1.1.1:
resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
help-me@^5.0.0:
version "5.0.0"
resolved "https://registry.npmmirror.com/help-me/-/help-me-5.0.0.tgz"
integrity sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==
htmlparser2@^3.8.3:
version "3.10.1"
resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz"
@ -1605,6 +1690,11 @@ htmlparser2@^3.8.3:
inherits "^2.0.1"
readable-stream "^3.1.1"
ieee754@^1.2.1:
version "1.2.1"
resolved "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
image-size@^0.5.1:
version "0.5.5"
resolved "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz"
@ -1615,7 +1705,7 @@ immutable@^4.0.0:
resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz"
integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==
inherits@^2.0.1, inherits@^2.0.3:
inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -1634,6 +1724,14 @@ internal-slot@^1.1.0:
hasown "^2.0.2"
side-channel "^1.1.0"
ip-address@^9.0.5:
version "9.0.5"
resolved "https://registry.npmmirror.com/ip-address/-/ip-address-9.0.5.tgz"
integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==
dependencies:
jsbn "1.1.0"
sprintf-js "^1.1.3"
is-accessor-descriptor@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz"
@ -1963,11 +2061,21 @@ js-cookie@3.0.5:
resolved "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz"
integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==
js-sdsl@4.3.0:
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==
js-tokens@^9.0.1:
version "9.0.1"
resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz"
integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==
jsbn@1.1.0:
version "1.1.0"
resolved "https://registry.npmmirror.com/jsbn/-/jsbn-1.1.0.tgz"
integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==
jsencrypt@3.3.2:
version "3.3.2"
resolved "https://registry.npmjs.org/jsencrypt/-/jsencrypt-3.3.2.tgz"
@ -2078,7 +2186,7 @@ lodash@*, lodash@^4.17.21:
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
lru-cache@^10.2.0:
lru-cache@^10.2.0, lru-cache@^10.4.3:
version "10.4.3"
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz"
integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
@ -2189,7 +2297,7 @@ minimatch@9.0.1:
dependencies:
brace-expansion "^2.0.1"
minimist@^1.2.0:
minimist@^1.2.0, minimist@^1.2.8:
version "1.2.8"
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
@ -2217,6 +2325,35 @@ mlly@^1.7.3, mlly@^1.7.4:
pkg-types "^1.3.0"
ufo "^1.5.4"
mqtt-packet@^9.0.2:
version "9.0.2"
resolved "https://registry.npmmirror.com/mqtt-packet/-/mqtt-packet-9.0.2.tgz"
integrity sha512-MvIY0B8/qjq7bKxdN1eD+nrljoeaai+qjLJgfRn3TiMuz0pamsIWY2bFODPZMSNmabsLANXsLl4EMoWvlaTZWA==
dependencies:
bl "^6.0.8"
debug "^4.3.4"
process-nextick-args "^2.0.1"
mqtt@^5.13.0:
version "5.13.0"
resolved "https://registry.npmmirror.com/mqtt/-/mqtt-5.13.0.tgz"
integrity sha512-pR+z+ChxFl3n8AKLQbTONVOOg/jl4KiKQRBAi78tjd6PksOWvl1nl9L8ZHOZ3MiavZfrUOjok2ddwc1VymGWRg==
dependencies:
commist "^3.2.0"
concat-stream "^2.0.0"
debug "^4.4.0"
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.3"
split2 "^4.2.0"
worker-timers "^7.1.8"
ws "^8.18.0"
ms@^2.1.3:
version "2.1.3"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
@ -2278,6 +2415,14 @@ nth-check@^2.0.1:
dependencies:
boolbase "^1.0.0"
number-allocator@^1.0.14:
version "1.0.14"
resolved "https://registry.npmmirror.com/number-allocator/-/number-allocator-1.0.14.tgz"
integrity sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==
dependencies:
debug "^4.3.1"
js-sdsl "4.3.0"
object-assign@^4, object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
@ -2496,6 +2641,16 @@ posthtml@^0.9.2:
posthtml-parser "^0.2.0"
posthtml-render "^1.0.5"
process-nextick-args@^2.0.1:
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==
process@^0.11.10:
version "0.11.10"
resolved "https://registry.npmmirror.com/process/-/process-0.11.10.tgz"
integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
proto-list@~1.2.1:
version "1.2.4"
resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz"
@ -2554,7 +2709,7 @@ quill@^1.3.7:
parchment "^1.1.4"
quill-delta "^3.6.2"
readable-stream@^3.1.1:
readable-stream@^3.0.2, readable-stream@^3.1.1:
version "3.6.2"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz"
integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
@ -2563,6 +2718,28 @@ readable-stream@^3.1.1:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
readable-stream@^4.2.0:
version "4.7.0"
resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-4.7.0.tgz"
integrity sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==
dependencies:
abort-controller "^3.0.0"
buffer "^6.0.3"
events "^3.3.0"
process "^0.11.10"
string_decoder "^1.3.0"
readable-stream@^4.7.0:
version "4.7.0"
resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-4.7.0.tgz"
integrity sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==
dependencies:
abort-controller "^3.0.0"
buffer "^6.0.3"
events "^3.3.0"
process "^0.11.10"
string_decoder "^1.3.0"
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz"
@ -2629,6 +2806,11 @@ reusify@^1.0.4:
resolved "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz"
integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==
rfdc@^1.4.1:
version "1.4.1"
resolved "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz"
integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==
rollup@^1.20.0||^2.0.0||^3.0.0||^4.0.0, rollup@^4.13.0:
version "4.38.0"
resolved "https://registry.npmjs.org/rollup/-/rollup-4.38.0.tgz"
@ -2827,6 +3009,11 @@ signal-exit@^4.0.1:
resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz"
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
smart-buffer@^4.2.0:
version "4.2.0"
resolved "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
snapdragon-node@^2.0.1:
version "2.1.1"
resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz"
@ -2857,6 +3044,14 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
socks@^2.8.3:
version "2.8.4"
resolved "https://registry.npmmirror.com/socks/-/socks-2.8.4.tgz"
integrity sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==
dependencies:
ip-address "^9.0.5"
smart-buffer "^4.2.0"
sortablejs@1.14.0:
version "1.14.0"
resolved "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz"
@ -2905,11 +3100,21 @@ split-string@^3.0.1, split-string@^3.0.2:
dependencies:
extend-shallow "^3.0.0"
split2@^4.2.0:
version "4.2.0"
resolved "https://registry.npmmirror.com/split2/-/split2-4.2.0.tgz"
integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
splitpanes@3.1.5:
version "3.1.5"
resolved "https://registry.npmjs.org/splitpanes/-/splitpanes-3.1.5.tgz"
integrity sha512-r3Mq2ITFQ5a2VXLOy4/Sb2Ptp7OfEO8YIbhVJqJXoFc9hc5nTXXkCvtVDjIGbvC0vdE7tse+xTM9BMjsszP6bw==
sprintf-js@^1.1.3:
version "1.1.3"
resolved "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.1.3.tgz"
integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==
stable@^0.1.8:
version "0.1.8"
resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz"
@ -2928,7 +3133,7 @@ strict-uri-encode@^1.0.0:
resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz"
integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==
string_decoder@^1.1.1:
string_decoder@^1.1.1, string_decoder@^1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz"
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
@ -3126,6 +3331,11 @@ traverse@^0.6.6:
typedarray.prototype.slice "^1.0.5"
which-typed-array "^1.1.18"
tslib@^2.6.2:
version "2.8.1"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
tslib@2.3.0:
version "2.3.0"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz"
@ -3190,6 +3400,11 @@ typedarray.prototype.slice@^1.0.5:
typed-array-buffer "^1.0.3"
typed-array-byte-offset "^1.0.4"
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz"
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
typescript@*, typescript@^5.8.3, typescript@>=4.4.4:
version "5.8.3"
resolved "https://registry.npmmirror.com/typescript/-/typescript-5.8.3.tgz"
@ -3469,6 +3684,34 @@ which@^2.0.1:
dependencies:
isexe "^2.0.0"
worker-timers-broker@^6.1.8:
version "6.1.8"
resolved "https://registry.npmmirror.com/worker-timers-broker/-/worker-timers-broker-6.1.8.tgz"
integrity sha512-FUCJu9jlK3A8WqLTKXM9E6kAmI/dR1vAJ8dHYLMisLNB/n3GuaFIjJ7pn16ZcD1zCOf7P6H62lWIEBi+yz/zQQ==
dependencies:
"@babel/runtime" "^7.24.5"
fast-unique-numbers "^8.0.13"
tslib "^2.6.2"
worker-timers-worker "^7.0.71"
worker-timers-worker@^7.0.71:
version "7.0.71"
resolved "https://registry.npmmirror.com/worker-timers-worker/-/worker-timers-worker-7.0.71.tgz"
integrity sha512-ks/5YKwZsto1c2vmljroppOKCivB/ma97g9y77MAAz2TBBjPPgpoOiS1qYQKIgvGTr2QYPT3XhJWIB6Rj2MVPQ==
dependencies:
"@babel/runtime" "^7.24.5"
tslib "^2.6.2"
worker-timers@^7.1.8:
version "7.1.8"
resolved "https://registry.npmmirror.com/worker-timers/-/worker-timers-7.1.8.tgz"
integrity sha512-R54psRKYVLuzff7c1OTFcq/4Hue5Vlz4bFtNEIarpSiCYhpifHU3aIQI29S84o1j87ePCYqbmEJPqwBTf+3sfw==
dependencies:
"@babel/runtime" "^7.24.5"
tslib "^2.6.2"
worker-timers-broker "^6.1.8"
worker-timers-worker "^7.0.71"
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
@ -3487,6 +3730,11 @@ wrap-ansi@^8.1.0:
string-width "^5.0.1"
strip-ansi "^7.0.1"
ws@^8.18.0:
version "8.18.2"
resolved "https://registry.npmmirror.com/ws/-/ws-8.18.2.tgz"
integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==
zrender@5.6.0:
version "5.6.0"
resolved "https://registry.npmjs.org/zrender/-/zrender-5.6.0.tgz"