数据集分区

dev_xq_0.0.1
谢庆 4 days ago
parent a63f3074c2
commit 05cff73389

93
package-lock.json generated

@ -26,18 +26,21 @@
"mqtt": "^5.15.0",
"pinia": "^3.0.4",
"sockjs-client": "^1.6.1",
"sortablejs": "^1.15.7",
"stats.js": "^0.17.0",
"three": "^0.182.0",
"vue": "^3.3.4",
"vue-echarts": "^6.6.5",
"vue-router": "^4.2.5",
"vue3-ace-editor": "^2.2.4"
"vue3-ace-editor": "^2.2.4",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.3.3",
"@tsconfig/node18": "^18.2.2",
"@types/jsdom": "^21.1.3",
"@types/node": "^18.18.5",
"@types/sortablejs": "^1.15.9",
"@types/three": "^0.182.0",
"@vitejs/plugin-vue": "^4.4.0",
"@vue/eslint-config-prettier": "^8.0.0",
@ -157,6 +160,7 @@
"integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.28.6",
"@babel/generator": "^7.28.6",
@ -1932,8 +1936,7 @@
"resolved": "https://registry.npmmirror.com/@rtsao/scc/-/scc-1.1.0.tgz",
"integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@rushstack/eslint-patch": {
"version": "1.15.0",
@ -2138,7 +2141,8 @@
"resolved": "https://registry.npmmirror.com/@types/chai/-/chai-4.3.20.tgz",
"integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==",
"dev": true,
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@types/chai-subset": {
"version": "1.3.6",
@ -2181,8 +2185,7 @@
"resolved": "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@types/lodash": {
"version": "4.17.23",
@ -2195,6 +2198,7 @@
"resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/lodash": "*"
}
@ -2230,6 +2234,13 @@
"dev": true,
"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": {
"version": "0.17.4",
"resolved": "https://registry.npmmirror.com/@types/stats.js/-/stats.js-0.17.4.tgz",
@ -2341,6 +2352,7 @@
"integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "6.21.0",
"@typescript-eslint/types": "6.21.0",
@ -3196,6 +3208,7 @@
"resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.26.tgz",
"integrity": "sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/reactivity": "3.5.26",
"@vue/shared": "3.5.26"
@ -3379,7 +3392,8 @@
"version": "1.43.5",
"resolved": "https://registry.npmmirror.com/ace-builds/-/ace-builds-1.43.5.tgz",
"integrity": "sha512-iH5FLBKdB7SVn9GR37UgA/tpQS8OTWIxWAuq3Ofaw+Qbc69FfPXsXd9jeW7KRG2xKpKMqBDnu0tHBrCWY5QI7A==",
"license": "BSD-3-Clause"
"license": "BSD-3-Clause",
"peer": true
},
"node_modules/acorn": {
"version": "8.15.0",
@ -3387,6 +3401,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@ -3593,7 +3608,6 @@
"integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
@ -3643,7 +3657,6 @@
"integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
@ -3666,7 +3679,6 @@
"integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
@ -3686,7 +3698,6 @@
"integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"call-bind": "^1.0.8",
"define-properties": "^1.2.1",
@ -4014,6 +4025,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@ -5126,6 +5138,7 @@
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.6.0.tgz",
"integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"tslib": "2.3.0",
"zrender": "5.6.1"
@ -5361,7 +5374,6 @@
"integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"hasown": "^2.0.2"
},
@ -5455,6 +5467,7 @@
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@ -5511,6 +5524,7 @@
"integrity": "sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"eslint-config-prettier": "bin/cli.js"
},
@ -5537,7 +5551,6 @@
"integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"debug": "^3.2.7",
"is-core-module": "^2.13.0",
@ -5550,7 +5563,6 @@
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"ms": "^2.1.1"
}
@ -5561,7 +5573,6 @@
"integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"debug": "^3.2.7"
},
@ -5580,7 +5591,6 @@
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"ms": "^2.1.1"
}
@ -5591,7 +5601,6 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9",
@ -5626,7 +5635,6 @@
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -5638,7 +5646,6 @@
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"ms": "^2.1.1"
}
@ -5649,7 +5656,6 @@
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"esutils": "^2.0.2"
},
@ -5663,7 +5669,6 @@
"integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==",
"dev": true,
"license": "ISC",
"peer": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -5677,7 +5682,6 @@
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"peer": true,
"bin": {
"semver": "bin/semver.js"
}
@ -5719,6 +5723,7 @@
"integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"globals": "^13.24.0",
@ -7715,6 +7720,7 @@
"integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"abab": "^2.0.6",
"cssstyle": "^3.0.0",
@ -7852,6 +7858,7 @@
"integrity": "sha512-UKgI3/KON4u6ngSsnDADsUERqhZknsVZbnuzlRZXLQCmfC/MDld42fTydUE9B+Mla1AL6SJ/Pp6SlEFi/AVGfw==",
"hasInstallScript": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"copy-anything": "^2.0.1",
"parse-node-version": "^1.0.1",
@ -7953,13 +7960,15 @@
"version": "4.17.21",
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lodash-es": {
"version": "4.17.22",
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.22.tgz",
"integrity": "sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lodash-unified": {
"version": "1.0.3",
@ -8797,7 +8806,6 @@
"integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
@ -8817,7 +8825,6 @@
"integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
@ -8856,7 +8863,6 @@
"integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
@ -9249,6 +9255,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@ -9366,6 +9373,7 @@
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@ -9857,6 +9865,7 @@
"integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"rollup": "dist/bin/rollup"
},
@ -10506,6 +10515,12 @@
"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": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
@ -10896,7 +10911,6 @@
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=4"
}
@ -11587,7 +11601,6 @@
"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/json5": "^0.0.29",
"json5": "^1.0.2",
@ -11601,7 +11614,6 @@
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"minimist": "^1.2.0"
},
@ -11764,6 +11776,7 @@
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@ -12074,6 +12087,7 @@
"integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.18.10",
"postcss": "^8.4.27",
@ -12337,6 +12351,7 @@
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.26.tgz",
"integrity": "sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.26",
"@vue/compiler-sfc": "3.5.26",
@ -12517,6 +12532,24 @@
"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": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",

@ -47,18 +47,21 @@
"mqtt": "^5.15.0",
"pinia": "^3.0.4",
"sockjs-client": "^1.6.1",
"sortablejs": "^1.15.7",
"stats.js": "^0.17.0",
"three": "^0.182.0",
"vue": "^3.3.4",
"vue-echarts": "^6.6.5",
"vue-router": "^4.2.5",
"vue3-ace-editor": "^2.2.4"
"vue3-ace-editor": "^2.2.4",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.3.3",
"@tsconfig/node18": "^18.2.2",
"@types/jsdom": "^21.1.3",
"@types/node": "^18.18.5",
"@types/sortablejs": "^1.15.9",
"@types/three": "^0.182.0",
"@vitejs/plugin-vue": "^4.4.0",
"@vue/eslint-config-prettier": "^8.0.0",

@ -60,8 +60,10 @@ import VueTableFireHydrant from '@/components/vue-components/vue-table-fire-hydr
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';
// F:\vue\workspace\maotu-webtopo\src\components\vue-components\vue-illumination-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';
@ -116,6 +118,8 @@ instance?.appContext.app.component('vue-my-table-fire-hydrant-info', VueTableFir
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-guage-line-chart', VueGuageLineChart);
@ -344,6 +348,44 @@ 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',
title: 'vue遥调',
@ -361,6 +403,19 @@ leftAsideStore.registerConfig('vue四遥组件', [
title: '绑定ID'
}
}
},
{
id: 'vue-my-test-controller',
title: '测试组件',
type: 'vue',
thumbnail: '/svgs/regulator.svg',
props: {
moduleId: {
type: 'inputSelectId',
val: '--',
title: '绑定ID'
}
}
}
]);

@ -11,8 +11,10 @@
<!-- 连接控制 -->
<div class="control-section">
<el-button type="primary" @click="connect" :disabled="isConnected">连接</el-button>
<el-button type="danger" @click="disconnect" :disabled="!isConnected">断开</el-button>
<el-tag :type="isConnected ? 'success' : 'danger'" size="large">
{{ isConnected ? 'MQTT 已连接' : 'MQTT 未连接' }}
</el-tag>
<el-button type="primary" @click="reconnect" :disabled="isConnected">重新连接</el-button>
</div>
<!-- 消息发送 -->
@ -119,17 +121,14 @@ const clearLogs = () => {
};
// STOMP
const connect = () => {
const reconnect = () => {
stompService.disconnect();
setTimeout(() => {
stompService.connect({
reconnectDelay: 5000
});
ElMessage.info('正在连接 STOMP...');
};
//
const disconnect = () => {
stompService.disconnect();
ElMessage.info('已断开 STOMP 连接');
ElMessage.info('正在重新连接 MQTT...');
}, 1000);
};
//
@ -151,17 +150,17 @@ const sendMessage = () => {
//
onMounted(() => {
//
stompService.registerService('demoComponent', {
mqttReady() {
console.log('[Demo] STOMP 已就绪');
console.log('[Demo] MQTT 已就绪');
isConnected.value = true;
ElMessage.success('STOMP 连接成功');
},
onConnectionLost() {
console.log('[Demo] STOMP 连接丢失');
console.log('[Demo] MQTT 连接丢失');
isConnected.value = false;
ElMessage.warning('STOMP 连接已断开,正在重连...');
ElMessage.warning('MQTT 连接已断开,正在重连...');
}
});
@ -187,8 +186,8 @@ onMounted(() => {
//
onUnmounted(() => {
//
// stompService.disconnect();
// MQTT
console.log('[Demo] 组件卸载');
});
</script>

@ -116,6 +116,24 @@
height="80%"
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-column type="index" label="序号" />
<el-table-column prop="modeId" label="遥ID" />
@ -186,6 +204,7 @@ import {
ElColorPicker,
ElIcon,
ElButton,
ElMessage,
type UploadFile
} from 'element-plus';
import { Search } from '@element-plus/icons-vue';
@ -245,16 +264,22 @@ function setInputTagVal() {
const item = selectItemPropsSettingProps.propsInfo[key];
if (item.type === 'inputTypeTag') {
inputTypeTagValue.value = item.val;
console.log('inputTypeTagValue:', inputTypeTagValue.value);
break;
}
}
}
let attrItem: any;
const dialogTableVisible = ref(false);
function handleIconClick(obj: any) {
assembleList();
async function handleIconClick(obj: any) {
console.log('inputTypeTagValue11:', inputTypeTagValue.value);
console.log('handleIconClick:', obj);
attrItem = obj;
dialogTableVisible.value = true;
await getAllTree(); //
assembleList();
dialogTableVisible.value = true; //
}
let attrImg: any;
@ -274,6 +299,22 @@ function bindingImg(obj: any) {
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) {
console.log('绑定', modelIds.value);
dialogTableVisible.value = false;
@ -320,20 +361,36 @@ const filterTag = (value: number, row: any) => {
//
const filteredData = computed(() => {
debugger;
if (!search.value) {
return gridData;
return gridData.value;
}
return gridData.filter((item) => {
return gridData.value.filter((item) => {
return item.name.toLowerCase().includes(search.value.toLowerCase());
});
});
//
function assembleList() {
// debugger;
debugger;
let code: number | undefined;
setInputTagVal();
// globalDataRaw
gridData.value.splice(0, gridData.value.length);
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;
@ -350,7 +407,7 @@ function assembleList() {
let modeId = key;
let name = data.node.name;
let bType = data.bType;
gridData.push({ modeId, name, bType });
gridData.value.push({ modeId, name, bType });
}
});
} else {
@ -362,7 +419,7 @@ function assembleList() {
let modeId = key;
let name = data.node.name;
let bType = data.bType;
gridData.push({ modeId, name, bType });
gridData.value.push({ modeId, name, bType });
}
}
}
@ -375,7 +432,73 @@ interface GridDataItem {
bType: number;
}
const gridData: GridDataItem[] = [];
const gridData = ref<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>
<style lang="less" scoped>

@ -27,9 +27,7 @@ const props = defineProps({
default: 'bottom'
}
});
const getSting = (data: any) => {
};
const getSting = (data: any) => {};
function getModuleById(moduleId: string) {
const globalData = (window as any).globalData;
if (!globalData || moduleId == undefined || moduleId == '' || props.moduleId == '--') {

@ -0,0 +1,289 @@
<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>

@ -0,0 +1,32 @@
<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>

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

@ -813,6 +813,32 @@ 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
name: 'test',

@ -2,57 +2,110 @@ import { dayjs } from 'element-plus';
interface RecIn {
Node: {
InTypeIn: [number, string][],
TypeBase: [number, string][],
},
InTypeIn: [number, string][];
TypeBase: [number, string][];
};
CONST: {
STR: {
EnumType: [number, string][]
},
EnumType: [number, string][];
};
YX: {
EnumType: [number, string][]
},
UserPage:[string, string][]
},
EnumTypeVal: [number, string][][],
EnumTypeValFun: Function[],
regex: any,
trans: (val: any, enumArr: [number, string][])=> string
EnumType: [number, string][];
};
UserPage: [string, string][];
};
EnumTypeVal: [number, string][][];
EnumTypeValFun: Function[];
regex: any;
trans: (val: any, enumArr: [number, string][]) => string;
}
const Rec: Partial<RecIn>={};
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 "*未知*";
return '*未知*';
};
// 所有输入类型
Rec.Node.InTypeIn = [
[1, '遥信'],
[2, '遥测']
];
const getIndex=(num:number)=>{
switch (num)
{
export const getIndex = (num: number) => {
switch (num) {
case 1:
return 100
return 100;
case 2:
return 0
return 0;
default:
return -1
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, '遥调'],
[4, '遥调']
];
// 定值转化的 类型
@ -70,23 +123,32 @@ Rec.CONST.STR.EnumType = [
Rec.CONST.YX.EnumType = [
[0, '颜色'],
[1, '文字'],
[2, '颜色+文字'],
]
[2, '颜色+文字']
];
Rec.EnumTypeVal = []; // 定值类型,用于编辑时的选择
Rec.EnumTypeValFun = []; // 转换函数,用于显示与控制
Rec.EnumTypeVal[100] = [
[0, '绿色'],
[1, '黄色'],
[2, '红色'],
[0, 'green'],
[1, 'yellow'],
[2, 'red']
];
Rec.EnumTypeVal[101] = [
[0, '开启'],
[1, '关闭'],
[2, ''],
[0, '正常'],
[1, '异常'],
[2, '故障'],
[3, '报警'],
[4, '运行'],
[5, '关闭']
];
Rec.EnumTypeVal[102] = [
[0, '正常,green'],
[1, '异常,brown'],
[2, '故障,yellow'],
[3, '报警,red'],
[4, '运行,blue'],
[5, '关闭,purple']
];
// 缺省
Rec.EnumTypeVal[0] = [
@ -95,9 +157,9 @@ Rec.EnumTypeVal[0] = [
];
Rec.EnumTypeValFun[0] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![index+0])
}
//Rec.EnumTypeValFun[0](val,getIndex(btype));
return Rec.trans!(val, Rec.EnumTypeVal![index + 0]);
};
//Rec.EnumTypeValFun[etype](val,getIndex(btype));
// 遥控
Rec.EnumTypeVal[1] = [
@ -106,20 +168,20 @@ Rec.EnumTypeVal[1] = [
];
Rec.EnumTypeValFun[1] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![index+1])
}
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')
}
dayjs.unix(val).format('YYYY-MM-DD HH:mm:ss');
};
// 国网空调模式
Rec.EnumTypeVal[14] = [
@ -130,9 +192,9 @@ Rec.EnumTypeVal[14] = [
[2, '送风']
];
Rec.EnumTypeValFun[14] = function (val:any) {
return Rec.trans!(val, Rec.EnumTypeVal![14])
}
Rec.EnumTypeValFun[14] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![14]);
};
// RY空调模式
Rec.EnumTypeVal[11] = [
@ -143,9 +205,9 @@ Rec.EnumTypeVal[11] = [
[4, '送风']
];
Rec.EnumTypeValFun[11] = function (val:any) {
return Rec.trans!(val, Rec.EnumTypeVal![11])
}
Rec.EnumTypeValFun[11] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![11]);
};
// 空调温度
Rec.EnumTypeVal[12] = [
@ -166,9 +228,9 @@ Rec.EnumTypeVal[12] = [
[30, '30℃']
];
Rec.EnumTypeValFun[12] = function (val:any) {
return Rec.trans!(val, Rec.EnumTypeVal![12])
}
Rec.EnumTypeValFun[12] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![12]);
};
// 空调风速
Rec.EnumTypeVal[13] = [
@ -178,9 +240,9 @@ Rec.EnumTypeVal[13] = [
[3, '高']
];
Rec.EnumTypeValFun[13] = function (val:any) {
return Rec.trans!(val, Rec.EnumTypeVal![13])
}
Rec.EnumTypeValFun[13] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![13]);
};
// KTC 空调
Rec.EnumTypeVal[21] = [
@ -189,22 +251,21 @@ Rec.EnumTypeVal[21] = [
[2, '制热']
];
Rec.EnumTypeValFun[21] = function (val:any) {
return Rec.trans!(val, Rec.EnumTypeVal![21])
}
Rec.EnumTypeValFun[21] = function (val: any, index: number) {
return Rec.trans!(val, Rec.EnumTypeVal![21]);
};
//
Rec.EnumTypeValFun[21]()
Rec.EnumTypeValFun[21]();
// 用户的缺省界面
Rec.CONST.UserPage = [
['Admin', 'Admin'],
['User', 'User'],
]
['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])?$/,
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})?$/
}
export default Rec;
};

@ -13,7 +13,7 @@ const trans = function (index: number, type: any[]) {
return type[i][1];
}
}
return "*未知*";
return '*未知*';
};
const EnumType = [
@ -34,8 +34,8 @@ EnumTypeVal[0] = [
[1, '开启']
];
EnumTypeValFun[0] = function (val: number) {
return trans(val, EnumTypeVal[0])
}
return trans(val, EnumTypeVal[0]);
};
// 遥控
EnumTypeVal[1] = [
@ -43,24 +43,21 @@ EnumTypeVal[1] = [
[1, '开启']
];
EnumTypeValFun[1] = function (val) {
return trans(val, EnumTypeVal[1])
}
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')
}
return format(val * 1000, 'Y-m-d H:i:s');
};
export {EnumTypeVal,EnumTypeValFun}
export { EnumTypeVal, EnumTypeValFun };
const format = function (date: Date, format: string) {
var formatFunctions = formatFunctions;
@ -74,17 +71,17 @@ const format = function(date: Date, format: string) {
}
return formatFunctions[format].call(date) + '';
}
};
const formatFunctions: { [key: string]: () => string } = {
"MS": function() {
MS: function () {
// UTC milliseconds since Unix epoch (MS-AJAX serialized date format (MRSF))
return '\\/Date(' + this.getTime() + ')\\/';
},
"time": function() {
time: function () {
return this.getTime().toString();
},
"timestamp": function() {
timestamp: function () {
return format(this.getTime(), 'U');
}
}
};

@ -85,7 +85,6 @@ async function getData() {
if (data && typeof data === 'object') {
// 判断当前 globalData 类型并相应处理
const currentGlobalData = window.globalData;
debugger;
currentGlobalData.clear();
Object.entries(data).forEach(([key, value]) => {

@ -21,7 +21,92 @@ export const buildApiUrl = (path: string) => {
};
export const modelApi = {
// http://localhost:8080/monitor/info
// http://localhost:8080/data/tree/changeNodeClass
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> {
return fetch(buildApiUrl('/monitor/info'), {
method: 'GET',

@ -287,7 +287,9 @@ class StompService {
break;
case MqttCmd.Node:
debugger;
console.log('[STOMP] 收到 Node 更新消息:', msgObject.value);
window.vueGlobalFunction(msgObject.value);
// 单一 Node 更新消息
if (this.services.node) {
this.services.nod;

@ -0,0 +1,670 @@
<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>
Loading…
Cancel
Save