資產管理: 部門、IOT、MQTT欄位 | 系統監控: 系統小卡詳細內容 TABLE不分頁、顯示即時資料、NO Data改成0 | 運維管理: 維運、保養修正搜尋功能、廠商資料隱藏搜尋
This commit is contained in:
parent
d19c7fd240
commit
9e5ff1544c
@ -1,3 +1,4 @@
|
||||
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
||||
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
|
||||
VITE_MQTT_BASEURL = "ws://192.168.0.217:8083/mqtt"
|
||||
VITE_FORGE_BASEURL = "https://cgems.cvilux-group.com:8088/dist"
|
@ -1,3 +1,4 @@
|
||||
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
||||
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
|
||||
VITE_MQTT_BASEURL = "wss://192.168.0.217:8084/mqtt"
|
||||
VITE_FORGE_BASEURL = "https://cgems.cvilux-group.com:8088/dist"
|
435
package-lock.json
generated
435
package-lock.json
generated
@ -22,12 +22,14 @@
|
||||
"echarts": "^5.4.3",
|
||||
"flag-icons": "^7.2.3",
|
||||
"jquery-ui": "^1.14.1",
|
||||
"mqtt": "^5.10.3",
|
||||
"pinia": "^2.1.7",
|
||||
"requirejs": "^2.3.6",
|
||||
"tailwind-merge": "^2.2.1",
|
||||
"vue": "^3.3.4",
|
||||
"vue-i18n": "^10.0.4",
|
||||
"vue-router": "^4.2.5",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"yup": "^1.4.0",
|
||||
"yup-phone-lite": "^2.0.1"
|
||||
},
|
||||
@ -102,9 +104,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
|
||||
"integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
|
||||
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
@ -764,11 +767,26 @@
|
||||
"version": "20.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz",
|
||||
"integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/readable-stream": {
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.18.tgz",
|
||||
"integrity": "sha512-21jK/1j+Wg+7jVw1xnSwy/2Q1VgVjWuFssbYGTREPUBeZ+rqVFl2udq0IkxzPC0ZhOzVceUbyIACFZKLqKEBlA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"safe-buffer": "~5.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/readable-stream/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/svgo": {
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/svgo/-/svgo-2.6.4.tgz",
|
||||
@ -778,6 +796,15 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.5.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz",
|
||||
"integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitejs/plugin-vue": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.5.0.tgz",
|
||||
@ -1087,6 +1114,18 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.5"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.11.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
|
||||
@ -1370,6 +1409,26 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/big.js": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
|
||||
@ -1388,6 +1447,34 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "6.0.16",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-6.0.16.tgz",
|
||||
"integrity": "sha512-V/kz+z2Mx5/6qDfRCilmrukUXcXuCoXKg3/3hDvzKKoSUx8CJKudfIoT29XZc3UE9xBvxs5qictiHdprwtteEg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/readable-stream": "^4.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bl/node_modules/readable-stream": {
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
|
||||
"integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"abort-controller": "^3.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"events": "^3.3.0",
|
||||
"process": "^0.11.10",
|
||||
"string_decoder": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bluebird": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||
@ -1454,12 +1541,34 @@
|
||||
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
|
||||
},
|
||||
"node_modules/cache-base": {
|
||||
"version": "1.0.1",
|
||||
@ -1684,6 +1793,12 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/commist": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz",
|
||||
"integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/component-emitter": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
|
||||
@ -1704,6 +1819,21 @@
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/concat-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
|
||||
"engines": [
|
||||
"node >= 6.0"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.0.2",
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/copy-descriptor": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
|
||||
@ -1926,7 +2056,6 @@
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
@ -2213,12 +2342,19 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/events": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.8.x"
|
||||
}
|
||||
@ -2354,6 +2490,25 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/fast-unique-numbers": {
|
||||
"version": "8.0.13",
|
||||
"resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz",
|
||||
"integrity": "sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==",
|
||||
"license": "MIT",
|
||||
"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.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/fastparse": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
|
||||
@ -2665,6 +2820,12 @@
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/help-me": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
|
||||
"integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
||||
@ -2679,6 +2840,26 @@
|
||||
"readable-stream": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/image-size": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
|
||||
@ -2710,8 +2891,7 @@
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/is-accessor-descriptor": {
|
||||
"version": "1.0.1",
|
||||
@ -2906,6 +3086,16 @@
|
||||
"integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/js-sdsl": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
|
||||
"integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/js-sdsl"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@ -3035,6 +3225,12 @@
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.5",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
|
||||
@ -3149,7 +3345,6 @@
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@ -3200,11 +3395,69 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mqtt": {
|
||||
"version": "5.10.3",
|
||||
"resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.10.3.tgz",
|
||||
"integrity": "sha512-hA/6YrUS4fywhBGCjH/XXUuLeueJiPqruVVWjK2A24Ma4KcWfZ/x8x07aoesBV+HXDWBC08tbT4IWfSXNW0Jtw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/readable-stream": "^4.0.5",
|
||||
"@types/ws": "^8.5.9",
|
||||
"commist": "^3.2.0",
|
||||
"concat-stream": "^2.0.0",
|
||||
"debug": "^4.3.4",
|
||||
"help-me": "^5.0.0",
|
||||
"lru-cache": "^10.0.1",
|
||||
"minimist": "^1.2.8",
|
||||
"mqtt-packet": "^9.0.1",
|
||||
"number-allocator": "^1.0.14",
|
||||
"readable-stream": "^4.4.2",
|
||||
"reinterval": "^1.1.0",
|
||||
"rfdc": "^1.3.0",
|
||||
"split2": "^4.2.0",
|
||||
"worker-timers": "^7.1.4",
|
||||
"ws": "^8.17.1"
|
||||
},
|
||||
"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.1",
|
||||
"resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.1.tgz",
|
||||
"integrity": "sha512-koZF1V/X2RZUI6uD9wN5OK1JxxcG1ofAR4H3LjCw1FkeKzruZQ26aAA6v2m1lZyWONZIR5wMMJFrZJDRNzbiQw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bl": "^6.0.8",
|
||||
"debug": "^4.3.4",
|
||||
"process-nextick-args": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/mqtt/node_modules/readable-stream": {
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
|
||||
"integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"abort-controller": "^3.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"events": "^3.3.0",
|
||||
"process": "^0.11.10",
|
||||
"string_decoder": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
@ -3371,6 +3624,16 @@
|
||||
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/number-allocator": {
|
||||
"version": "1.0.14",
|
||||
"resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz",
|
||||
"integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.1",
|
||||
"js-sdsl": "4.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
@ -3822,6 +4085,21 @@
|
||||
"posthtml-render": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/process": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/property-expr": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
|
||||
@ -3898,7 +4176,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,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
@ -3984,6 +4261,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/reinterval": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz",
|
||||
"integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/repeat-element": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
|
||||
@ -4062,6 +4345,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rfdc": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
||||
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "3.29.4",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
|
||||
@ -4105,7 +4394,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",
|
||||
@ -4377,6 +4665,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sortablejs": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
|
||||
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
@ -4484,6 +4778,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/split2": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
|
||||
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">= 10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/stable": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
|
||||
@ -4542,7 +4845,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,
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
@ -5119,11 +5421,16 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
||||
},
|
||||
"node_modules/union-value": {
|
||||
"version": "1.0.1",
|
||||
@ -5338,8 +5645,7 @@
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
@ -5492,6 +5798,18 @@
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vuedraggable": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/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/warning": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||
@ -5577,12 +5895,85 @@
|
||||
"integrity": "sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/worker-timers": {
|
||||
"version": "7.1.8",
|
||||
"resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.8.tgz",
|
||||
"integrity": "sha512-R54psRKYVLuzff7c1OTFcq/4Hue5Vlz4bFtNEIarpSiCYhpifHU3aIQI29S84o1j87ePCYqbmEJPqwBTf+3sfw==",
|
||||
"license": "MIT",
|
||||
"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.npmjs.org/worker-timers-broker/-/worker-timers-broker-6.1.8.tgz",
|
||||
"integrity": "sha512-FUCJu9jlK3A8WqLTKXM9E6kAmI/dR1vAJ8dHYLMisLNB/n3GuaFIjJ7pn16ZcD1zCOf7P6H62lWIEBi+yz/zQQ==",
|
||||
"license": "MIT",
|
||||
"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.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/worker-timers-worker": {
|
||||
"version": "7.0.71",
|
||||
"resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-7.0.71.tgz",
|
||||
"integrity": "sha512-ks/5YKwZsto1c2vmljroppOKCivB/ma97g9y77MAAz2TBBjPPgpoOiS1qYQKIgvGTr2QYPT3XhJWIB6Rj2MVPQ==",
|
||||
"license": "MIT",
|
||||
"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.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/worker-timers/node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
||||
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
|
||||
"license": "MIT",
|
||||
"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/yaml": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz",
|
||||
|
@ -23,12 +23,14 @@
|
||||
"echarts": "^5.4.3",
|
||||
"flag-icons": "^7.2.3",
|
||||
"jquery-ui": "^1.14.1",
|
||||
"mqtt": "^5.10.3",
|
||||
"pinia": "^2.1.7",
|
||||
"requirejs": "^2.3.6",
|
||||
"tailwind-merge": "^2.2.1",
|
||||
"vue": "^3.3.4",
|
||||
"vue-i18n": "^10.0.4",
|
||||
"vue-router": "^4.2.5",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"yup": "^1.4.0",
|
||||
"yup-phone-lite": "^2.0.1"
|
||||
},
|
||||
|
@ -18,3 +18,9 @@ export const DELETE_ASSET_FLOOR_API = `/AssetManage/DeleteFloor`;
|
||||
|
||||
export const GET_ASSET_IOT_LIST_API = `/AssetManage/GetIOTList`;
|
||||
export const GET_ASSET_SUB_POINT_API = `/AssetManage/GetSubPoint`;
|
||||
|
||||
export const GET_ASSET_IOT_SCHEMA_API = `/AssetManage/GetResponseSchema`;
|
||||
|
||||
export const GET_ASSET_DEPARTMENT_API = `/AssetManage/GetDepartment`;
|
||||
export const POST_ASSET_DEPARTMENT_API = `/AssetManage/SaveDepartment`;
|
||||
export const DELETE_ASSET_DEPARTMENT_API = `/AssetManage/DeleteDepartment`;
|
||||
|
@ -14,6 +14,10 @@ import {
|
||||
DELETE_ASSET_ITEM_API,
|
||||
POST_ASSET_SINGLE_API,
|
||||
GET_ASSET_SUB_POINT_API,
|
||||
GET_ASSET_IOT_SCHEMA_API,
|
||||
GET_ASSET_DEPARTMENT_API,
|
||||
POST_ASSET_DEPARTMENT_API,
|
||||
DELETE_ASSET_DEPARTMENT_API,
|
||||
} from "./api";
|
||||
import instance from "@/util/request";
|
||||
import apihandler from "@/util/apihandler";
|
||||
@ -124,16 +128,15 @@ export const postAssetSingle = async (data) => {
|
||||
});
|
||||
} else {
|
||||
value.forEach((element, index) => {
|
||||
formData.append(`sub_device[${index}].device_number`, element.device_number);
|
||||
formData.append(
|
||||
`sub_device[${index}].device_number`,
|
||||
element.device_number
|
||||
);
|
||||
formData.append(`sub_device[${index}].points`, element.points);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (key === "device_number" && value === "") {
|
||||
formData.append(key, "0");
|
||||
} else {
|
||||
formData.append(key, value);
|
||||
}
|
||||
formData.append(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,3 +202,42 @@ export const getAssetSubPoint = async (sub_system_tag) => {
|
||||
code: res.code,
|
||||
});
|
||||
};
|
||||
|
||||
export const getIOTSchema = async (sub_system_tag, points) => {
|
||||
const res = await instance.post(GET_ASSET_IOT_SCHEMA_API, {});
|
||||
|
||||
return apihandler(res.code, res.data, {
|
||||
msg: res.msg,
|
||||
code: res.code,
|
||||
});
|
||||
};
|
||||
|
||||
export const getDepartmentList = async () => {
|
||||
const res = await instance.post(GET_ASSET_DEPARTMENT_API, {});
|
||||
|
||||
return apihandler(res.code, res.data, {
|
||||
msg: res.msg,
|
||||
code: res.code,
|
||||
});
|
||||
};
|
||||
|
||||
export const postDepartmentList = async ({ name, id }) => {
|
||||
const res = await instance.post(POST_ASSET_DEPARTMENT_API, {
|
||||
name,
|
||||
id,
|
||||
});
|
||||
|
||||
return apihandler(res.code, res.data, {
|
||||
msg: res.msg,
|
||||
code: res.code,
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteDepartmentItem = async (id) => {
|
||||
const res = await instance.post(DELETE_ASSET_DEPARTMENT_API, { id });
|
||||
|
||||
return apihandler(res.code, res.data, {
|
||||
msg: res.msg,
|
||||
code: res.code,
|
||||
});
|
||||
};
|
||||
|
436
src/components/customUI/DraggableTable.vue
Normal file
436
src/components/customUI/DraggableTable.vue
Normal file
@ -0,0 +1,436 @@
|
||||
<script setup>
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { computed, defineProps, provide, ref, watch } from "vue";
|
||||
import Pagination from "@/components/customUI/Pagination.vue";
|
||||
import Checkbox from "@/components/customUI/Checkbox.vue";
|
||||
import draggable from "vuedraggable";
|
||||
import dayjs from "dayjs";
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n();
|
||||
/*
|
||||
column={
|
||||
title,key,class, width, filter:Boolean, sort:Boolean
|
||||
}
|
||||
*/
|
||||
const props = defineProps({
|
||||
columns: Array,
|
||||
dataSource: Array,
|
||||
rowKey: String,
|
||||
withStyle: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
withDraggable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
pagination: { type: Boolean, default: true } || {
|
||||
pageSize: Number,
|
||||
totalPages: Number,
|
||||
totalItems: Number,
|
||||
},
|
||||
loading: Boolean,
|
||||
});
|
||||
|
||||
const currentDataSource = ref([]);
|
||||
const dataSourceStorage = ref([]);
|
||||
const isDraggable = ref(props.withDraggable);
|
||||
|
||||
watch(
|
||||
() => props.dataSource,
|
||||
(newValue) => {
|
||||
dataSourceStorage.value = newValue;
|
||||
filterItems.value = Object.fromEntries(
|
||||
props.columns.map((c, i) => [
|
||||
c.key,
|
||||
[...new Set(newValue.map((d) => d[c.key]))].map((name) => ({
|
||||
name,
|
||||
selected: false,
|
||||
})),
|
||||
])
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const updateDataSource = (data) => {
|
||||
console.log("update", data);
|
||||
currentDataSource.value = data;
|
||||
};
|
||||
provide("current_table_data", {
|
||||
updateDataSource,
|
||||
});
|
||||
|
||||
const sortRule = ref({});
|
||||
const filterColumn = ref({});
|
||||
const filterItems = ref({});
|
||||
const selectedFilterItem = ref({});
|
||||
|
||||
const toggleFilterModal = (key) => {
|
||||
let newFilter = Object.assign(filterColumn.value);
|
||||
|
||||
for (let oKey in newFilter) {
|
||||
newFilter[oKey] = key === oKey && !newFilter[key];
|
||||
}
|
||||
|
||||
filterColumn.value = newFilter;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.columns,
|
||||
(newValue) => {
|
||||
sortRule.value = Object.fromEntries(newValue.map((c) => [c.key, 0]));
|
||||
filterColumn.value = Object.fromEntries(
|
||||
newValue.map((c, i) => [c.key, false])
|
||||
);
|
||||
selectedFilterItem.value = Object.fromEntries(
|
||||
newValue.map((c, i) => [c.key, []])
|
||||
);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
0:取消
|
||||
1:ascending
|
||||
2:descending
|
||||
*/
|
||||
const toggleSortRule = (key) => {
|
||||
let newSort = Object.assign(sortRule.value);
|
||||
|
||||
for (let oKey in newSort) {
|
||||
newSort[oKey] = key === oKey ? newSort[key] : 0;
|
||||
}
|
||||
|
||||
sortRule.value = newSort;
|
||||
};
|
||||
|
||||
const sort = (column) => {
|
||||
toggleSortRule(column);
|
||||
const cantSort = ["object", "boolean"];
|
||||
console.log(props.dataSource?.[0][column]);
|
||||
if (cantSort.includes(typeof props.dataSource?.[0][column])) return;
|
||||
// 小->大
|
||||
const newArray = Object.assign(props.dataSource, []).sort((a, b) => {
|
||||
// if (column === "timestamp") {
|
||||
// return dayjs(a[column]).valueOf() - dayjs(b[column]).valueOf();
|
||||
// }
|
||||
if (typeof a[column] === "number") return a[column] - b[column];
|
||||
else if (typeof a[column] === "string") {
|
||||
console.log(a[column], b[column], a[column].localeCompare(b[column]));
|
||||
return a[column].localeCompare(b[column]);
|
||||
}
|
||||
// return parseInt(a[column]) - parseInt(b[column]);
|
||||
});
|
||||
if (sortRule.value[column] === 0) {
|
||||
sortRule.value[column] = 1;
|
||||
dataSourceStorage.value = newArray;
|
||||
} else if (sortRule.value[column] === 1) {
|
||||
sortRule.value[column] = 2;
|
||||
dataSourceStorage.value = newArray.reverse();
|
||||
} else if (sortRule.value[column] === 2) {
|
||||
sortRule.value[column] = 0;
|
||||
dataSourceStorage.value = props.dataSource;
|
||||
}
|
||||
};
|
||||
const form = ref(null);
|
||||
|
||||
const onFilter = (key, reset = false) => {
|
||||
const formData = new FormData(form.value);
|
||||
reset && formData.delete(key);
|
||||
for (let [name, value] of formData) {
|
||||
console.log(name, value);
|
||||
}
|
||||
selectedFilterItem.value[key] = formData.getAll(key);
|
||||
toggleFilterModal(key);
|
||||
};
|
||||
|
||||
watch(
|
||||
selectedFilterItem,
|
||||
(newVal) => {
|
||||
let newData = Object.assign(props.dataSource);
|
||||
for (let key in newVal) {
|
||||
if (newVal[key].length > 0) {
|
||||
newData = newData.filter((d) => newVal[key].includes(d[key]));
|
||||
}
|
||||
}
|
||||
dataSourceStorage.value = newData;
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="withStyle ? 'content-box' : 'py-5'">
|
||||
<div class="content-decoration">
|
||||
<button
|
||||
v-if="withDraggable"
|
||||
class="btn btn-sm mb-2"
|
||||
@click.stop.prevent="isDraggable = !isDraggable"
|
||||
>
|
||||
<font-awesome-icon :icon="['fas', 'stream']" />
|
||||
{{ isDraggable ? "開始排序" : "完成排序" }}
|
||||
</button>
|
||||
<slot name="beforeTable"></slot>
|
||||
<form ref="form" class="overflow-x-auto">
|
||||
<table
|
||||
:class="
|
||||
twMerge(
|
||||
withStyle ? 'table' : 'table border',
|
||||
currentDataSource.length === 0 ? 'h-28' : ''
|
||||
)
|
||||
"
|
||||
>
|
||||
<!-- head -->
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
v-for="column in columns"
|
||||
:key="column.key"
|
||||
:class="`${column.class ? column.class : ''}`"
|
||||
:style="{
|
||||
width: `${
|
||||
column.width
|
||||
? typeof column.width === 'string'
|
||||
? column.width
|
||||
: column.width + 'px'
|
||||
: 'auto'
|
||||
}`,
|
||||
}"
|
||||
>
|
||||
<span class="flex justify-center">
|
||||
{{ column.title }}
|
||||
<div
|
||||
v-if="column.sort"
|
||||
class="flex flex-col justify-center w-3 mx-2 relative"
|
||||
@click="() => sort(column.key)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'sort-up']"
|
||||
:class="
|
||||
twMerge(
|
||||
'absolute top-0',
|
||||
sortRule[column.key] === 1 ? 'text-success' : ''
|
||||
)
|
||||
"
|
||||
size="lg"
|
||||
/>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'sort-down']"
|
||||
:class="
|
||||
twMerge(
|
||||
'absolute bottom-1',
|
||||
sortRule[column.key] === 2 ? 'text-success' : ''
|
||||
)
|
||||
"
|
||||
size="lg"
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-2 relative" v-if="column.filter">
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'filter']"
|
||||
:class="
|
||||
twMerge(
|
||||
filterColumn[column.key] ||
|
||||
selectedFilterItem[column.key].length > 0
|
||||
? 'text-success'
|
||||
: ''
|
||||
)
|
||||
"
|
||||
@click="() => toggleFilterModal(column.key)"
|
||||
/>
|
||||
<div
|
||||
class="absolute top-full -left-1/2 z-50"
|
||||
v-if="filterColumn[column.key]"
|
||||
>
|
||||
<div class="card min-w-max bg-body shadow-xl px-10 py-5">
|
||||
<Checkbox
|
||||
v-for="item in filterItems[column.key]"
|
||||
:title="item.name"
|
||||
:value="item.name"
|
||||
:key="item.name"
|
||||
:name="column.key"
|
||||
:checked="
|
||||
selectedFilterItem[column.key].includes(item.name)
|
||||
"
|
||||
className="justify-start"
|
||||
/>
|
||||
<div class="card-actions mt-4 justify-end">
|
||||
<input
|
||||
type="reset"
|
||||
class="btn btn-sm text-white btn-error"
|
||||
:value="t('button.reset')"
|
||||
@click="() => onFilter(column.key, true)"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-sm btn-success"
|
||||
@click.stop.prevent="() => onFilter(column.key)"
|
||||
>
|
||||
{{ $t("button.submit") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-if="isDraggable">
|
||||
<tr v-if="loading">
|
||||
<td :colspan="columns.length">
|
||||
<Loading />
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-else-if="currentDataSource.length == 0">
|
||||
<td :colspan="columns.length">{{ $t("table.no_data") }}</td>
|
||||
</tr>
|
||||
<template v-else :sort="sortRule">
|
||||
<tr
|
||||
v-for="(data, index) in currentDataSource"
|
||||
:key="data.key || data[rowKey]"
|
||||
>
|
||||
<template
|
||||
v-for="column in columns"
|
||||
:key="`${data.key || data[rowKey]}_${column.key}`"
|
||||
>
|
||||
<td
|
||||
:class="column.class"
|
||||
:style="{
|
||||
width: `${
|
||||
column.width
|
||||
? typeof column.width === 'string'
|
||||
? column.width
|
||||
: column.width + 'px'
|
||||
: 'auto'
|
||||
}`,
|
||||
}"
|
||||
>
|
||||
<slot
|
||||
name="bodyCell"
|
||||
v-bind="{ record: data, column, index }"
|
||||
>
|
||||
{{ data[column.key] }}</slot
|
||||
>
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
<draggable
|
||||
tag="tbody"
|
||||
:list="dataSourceStorage"
|
||||
item-key="rowKey"
|
||||
v-else
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<tr :key="element[rowKey] || element.key" >
|
||||
<template
|
||||
v-for="column in columns"
|
||||
:key="`${element[rowKey] || element.key}_${column.key}`"
|
||||
>
|
||||
<td
|
||||
:class="column.class"
|
||||
:style="{
|
||||
width: `
|
||||
${
|
||||
column.width
|
||||
? typeof column.width === 'string'
|
||||
? column.width
|
||||
: column.width + 'px'
|
||||
: 'auto'
|
||||
}`,
|
||||
}"
|
||||
>
|
||||
<slot
|
||||
name="bodyCell"
|
||||
v-bind="{ record: element, column, index }"
|
||||
>
|
||||
{{ element[column.key] }}</slot
|
||||
>
|
||||
</td>
|
||||
</template>
|
||||
</tr>
|
||||
</template>
|
||||
</draggable>
|
||||
</table>
|
||||
</form>
|
||||
<slot name="afterTable"></slot>
|
||||
<Pagination
|
||||
:class="twMerge(!isDraggable ? 'hidden' : 'flex')"
|
||||
:pagination="pagination"
|
||||
:dataSource="dataSourceStorage"
|
||||
:sort="sortRule"
|
||||
/>
|
||||
</div>
|
||||
<div class="content-decoration2"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="css" scoped>
|
||||
/**資料框**/
|
||||
.content-box {
|
||||
@apply border border-info p-1 relative mb-4 bg-transparent;
|
||||
}
|
||||
|
||||
.content-box .table {
|
||||
@apply rounded-none;
|
||||
}
|
||||
|
||||
.table th {
|
||||
@apply bg-cyan-600 bg-opacity-30 border-r border-b border-white text-lg font-semibold text-white text-center px-2 py-3;
|
||||
}
|
||||
|
||||
.table td {
|
||||
@apply border-r border-b border-white text-lg font-semibold text-white text-center px-2 py-3;
|
||||
}
|
||||
|
||||
.table tr td:last-child,
|
||||
.table tr:first-child th:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
/* .table tr:last-child td {
|
||||
border-bottom: v-bind("withStyle ? '0px': '1px'");
|
||||
} */
|
||||
|
||||
/**資料框裝飾**/
|
||||
.content-box::before {
|
||||
@apply absolute top-1 left-1 h-5 w-5 bg-no-repeat z-10 bg-[url('../../assets/img/table/content-box-background01.svg')] bg-center;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.content-box::after {
|
||||
@apply absolute bottom-1 right-1 h-5 w-5 bg-no-repeat z-10 bg-[url('../../assets/img/table/content-box-background05.svg')] bg-center;
|
||||
content: "";
|
||||
}
|
||||
.content-box .content-decoration {
|
||||
@apply bg-normal px-8 py-4;
|
||||
}
|
||||
|
||||
/* .content-box .content-decoration::before {
|
||||
@apply absolute -top-3 -right-[10px] h-8 w-8 bg-no-repeat z-10 bg-[url('../../assets/img/table/content-box-background02.svg')] bg-center;
|
||||
content: "";
|
||||
} */
|
||||
|
||||
.content-box .content-decoration2::before {
|
||||
@apply absolute -bottom-1 -left-8 h-14 w-14 bg-no-repeat z-10 bg-[url('../../assets/img/table/content-box-background03.svg')] bg-center;
|
||||
content: "";
|
||||
}
|
||||
|
||||
/* .content-box .content-decoration2::after {
|
||||
content: "";
|
||||
background: url(../../assets/img/table/content-box-background04.svg) center
|
||||
center;
|
||||
position: absolute;
|
||||
right: -27px;
|
||||
bottom: -7px;
|
||||
height: 65px;
|
||||
width: 50px;
|
||||
background-repeat: no-repeat;
|
||||
z-index: 2;
|
||||
} */
|
||||
</style>
|
@ -30,6 +30,10 @@ const props = defineProps({
|
||||
const currentDataSource = ref([]);
|
||||
const dataSourceStorage = ref([]);
|
||||
|
||||
const tableDataSource = computed(() =>
|
||||
props.pagination ? currentDataSource.value : dataSourceStorage.value
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.dataSource,
|
||||
(newValue) => {
|
||||
@ -271,12 +275,12 @@ watch(
|
||||
<Loading />
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-else-if="currentDataSource.length == 0">
|
||||
<tr v-else-if="tableDataSource.length == 0">
|
||||
<td :colspan="columns.length">{{ $t("table.no_data") }}</td>
|
||||
</tr>
|
||||
<template v-else :sort="sortRule">
|
||||
<tr
|
||||
v-for="(data, index) in currentDataSource"
|
||||
v-for="(data, index) in tableDataSource"
|
||||
:key="data.key || data[rowKey]"
|
||||
>
|
||||
<template
|
||||
@ -310,6 +314,7 @@ watch(
|
||||
</form>
|
||||
<slot name="afterTable"></slot>
|
||||
<Pagination
|
||||
v-if="pagination"
|
||||
:pagination="pagination"
|
||||
:dataSource="dataSourceStorage"
|
||||
:sort="sortRule"
|
||||
|
@ -24,7 +24,10 @@
|
||||
"yesterday_electricity_consumption": "昨天用电量",
|
||||
"this_last_week": "本周/上周",
|
||||
"thisweek_electricity_consumption": "本周用电量",
|
||||
"lastweek_electricity_consumption": "上周用电量"
|
||||
"lastweek_electricity_consumption": "上周用电量",
|
||||
"one_hour": "1小时",
|
||||
"four_hour": "4小时",
|
||||
"eight_hour": "8小时"
|
||||
},
|
||||
"history": {
|
||||
"title": "历史资料",
|
||||
@ -170,7 +173,7 @@
|
||||
"phone": "电话",
|
||||
"email": "email",
|
||||
"created_at": "建立日期",
|
||||
"maintainance": "保养",
|
||||
"maintenance": "保养",
|
||||
"repair": "维修",
|
||||
"company_info": "厂商资料",
|
||||
"repair_item": "维修项目",
|
||||
@ -244,7 +247,9 @@
|
||||
"associated_device": "关联设备",
|
||||
"choose": "选择",
|
||||
"index": "编号",
|
||||
"floor_plan": "平面图"
|
||||
"floor_plan": "平面图",
|
||||
"department": "部门",
|
||||
"department_name": "部门名称"
|
||||
},
|
||||
"accountManagement": {
|
||||
"account_title": "帐号管理",
|
||||
|
@ -24,7 +24,10 @@
|
||||
"yesterday_electricity_consumption": "昨天用電量",
|
||||
"this_last_week": "本週/上週",
|
||||
"thisweek_electricity_consumption": "本周用電量",
|
||||
"lastweek_electricity_consumption": "上週用電量"
|
||||
"lastweek_electricity_consumption": "上週用電量",
|
||||
"one_hour": "1小時",
|
||||
"four_hour": "4小時",
|
||||
"eight_hour": "8小時"
|
||||
},
|
||||
"history": {
|
||||
"title": "歷史資料",
|
||||
@ -170,7 +173,7 @@
|
||||
"phone": "電話",
|
||||
"email": "email",
|
||||
"created_at": "建立日期",
|
||||
"maintainance": "保養",
|
||||
"maintenance": "保養",
|
||||
"repair": "維修",
|
||||
"company_info": "廠商資料",
|
||||
"repair_item": "維修項目",
|
||||
@ -244,7 +247,9 @@
|
||||
"associated_device": "關聯設備",
|
||||
"choose": "選擇",
|
||||
"index": "編號",
|
||||
"floor_plan": "平面圖"
|
||||
"floor_plan": "平面圖",
|
||||
"department": "部門",
|
||||
"department_name": "部門名稱"
|
||||
},
|
||||
"accountManagement": {
|
||||
"account_title": "帳號管理",
|
||||
|
@ -42,7 +42,10 @@
|
||||
"yesterday_electricity_consumption": "Yesterday’s electricity consumption",
|
||||
"this_last_week": "This Week's / Last Week's",
|
||||
"thisweek_electricity_consumption": "This week’s electricity consumption",
|
||||
"lastweek_electricity_consumption": "Last week’s electricity consumption"
|
||||
"lastweek_electricity_consumption": "Last week’s electricity consumption",
|
||||
"one_hour": "1 hour",
|
||||
"four_hour": "4 hour",
|
||||
"eight_hour": "8 hour"
|
||||
},
|
||||
"system": {
|
||||
"status": "Status",
|
||||
@ -147,9 +150,9 @@
|
||||
"notify_items": "Notification Items",
|
||||
"notify_list": "Notification List",
|
||||
"choose": "Choose",
|
||||
"day_time":"Week/Time",
|
||||
"click_time_period":"Please click the time period with your mouse",
|
||||
"clear":"Clear"
|
||||
"day_time": "Week/Time",
|
||||
"click_time_period": "Please click the time period with your mouse",
|
||||
"clear": "Clear"
|
||||
},
|
||||
"operation": {
|
||||
"title": "Operation And Maintenance Management",
|
||||
@ -244,7 +247,9 @@
|
||||
"associated_device": "Associated Devices",
|
||||
"choose": "Choose",
|
||||
"index": "Serial Number",
|
||||
"floor_plan": "Floor Plan"
|
||||
"floor_plan": "Floor Plan",
|
||||
"department": "Department",
|
||||
"department_name": "Department Name"
|
||||
},
|
||||
"accountManagement": {
|
||||
"account_title": "Account Management",
|
||||
|
@ -58,7 +58,8 @@ import {
|
||||
faEye,
|
||||
faEyeSlash,
|
||||
faGlobe,
|
||||
faDownload
|
||||
faDownload,
|
||||
faStream
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
/* add icons to the library */
|
||||
@ -118,7 +119,8 @@ library.add(
|
||||
faEye,
|
||||
faEyeSlash,
|
||||
faGlobe,
|
||||
faDownload
|
||||
faDownload,
|
||||
faStream
|
||||
);
|
||||
|
||||
export default library;
|
||||
|
@ -39,7 +39,7 @@ instance.interceptors.response.use(
|
||||
// Any status codes that falls outside the range of 2xx cause this function to trigger
|
||||
// Do something with response error
|
||||
if (error.response && error.response.status === 401) {
|
||||
window.location.href = "/logout";
|
||||
window.location.href = "/";
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ const closeModal = () => {
|
||||
>
|
||||
<template #modalContent>
|
||||
<form ref="form" class="grid grid-cols-5 gap-5">
|
||||
<div class="grid grid-cols-2 col-span-2">
|
||||
<div class="grid grid-cols-2 col-span-2 items-end">
|
||||
<AssetTableModalLeft :current_component_key="current_component_key" />
|
||||
</div>
|
||||
<div class="col-span-3">
|
||||
|
@ -3,10 +3,12 @@ import { ref, inject, onBeforeMount, onMounted, watch } from "vue";
|
||||
import * as yup from "yup";
|
||||
import "yup-phone-lite";
|
||||
import AssetTableModalLeftInfoIoT from "./AssetTableModalLeftInfoIoT.vue";
|
||||
import AssetTableModalLeftInfoDept from "./AssetTableModalLeftInfoDept.vue";
|
||||
import AssetTableModalLeftInfoGraph from "./AssetTableModalLeftInfoGraph.vue";
|
||||
import AssetTableModalLeftInfoMQTT from "./AssetTableModalLeftInfoMQTT.vue";
|
||||
import { getOperationCompanyList } from "@/apis/operation";
|
||||
import { getIOTSchema } from "@/apis/asset";
|
||||
import useSearchParam from "@/hooks/useSearchParam";
|
||||
import OperationTableModal from "@/views/operation/components/OperationTableModal.vue";
|
||||
import dayjs from "dayjs";
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n();
|
||||
@ -28,6 +30,15 @@ let schema = {
|
||||
.number()
|
||||
.transform((value) => (Number.isNaN(value) ? null : value))
|
||||
.nullable(true),
|
||||
response_schema_id: yup
|
||||
.number()
|
||||
.transform((value) => (Number.isNaN(value) ? null : value))
|
||||
.nullable(true),
|
||||
department_id: yup
|
||||
.number()
|
||||
.transform((value) => (Number.isNaN(value) ? null : value))
|
||||
.nullable(true),
|
||||
topic: yup.string().nullable(true),
|
||||
asset_number: yup.string().nullable(true),
|
||||
sub_device: yup.array().nullable(true),
|
||||
oriFile: yup.array().nullable(true),
|
||||
@ -41,7 +52,10 @@ onBeforeMount(() => {
|
||||
brand: "",
|
||||
device_model: "",
|
||||
operation_id: 0,
|
||||
response_schema_id: 0,
|
||||
department_id: 0,
|
||||
asset_number: "",
|
||||
topic: "",
|
||||
sub_device: [],
|
||||
oriFile: [],
|
||||
buying_date: "",
|
||||
@ -80,28 +94,25 @@ watch(formState, (newValue) => {
|
||||
}
|
||||
});
|
||||
|
||||
const updateFileList = (files) => {
|
||||
formState.value = { ...formState.value, oriFile: files };
|
||||
};
|
||||
|
||||
const companyOptions = ref([]);
|
||||
const iotSchemaOptions = ref([]);
|
||||
const getCompany = async () => {
|
||||
const res = await getOperationCompanyList();
|
||||
companyOptions.value = res.data.map((d) => ({ ...d, key: d.id }));
|
||||
};
|
||||
const getIOTSchemaOptions = async () => {
|
||||
const res = await getIOTSchema();
|
||||
iotSchemaOptions.value = res.data.map((d) => ({ ...d, key: d.id }));
|
||||
};
|
||||
onMounted(() => {
|
||||
getCompany();
|
||||
getIOTSchemaOptions();
|
||||
});
|
||||
|
||||
const openCompanyAddModal = () => {
|
||||
changeParams({ ...searchParams.value, work_type: 3 }); // 開啟company Add modal
|
||||
operation_action_item.showModal();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- information -->
|
||||
<Input :value="formState" width="270" name="full_name">
|
||||
<Input :value="formState" width="290" name="full_name">
|
||||
<template #topLeft>{{ $t("assetManagement.device_name") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
@ -109,15 +120,8 @@ const openCompanyAddModal = () => {
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<Input :value="formState" width="270" name="operate_text">
|
||||
<template #topLeft>Mac</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.operate_text }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<Input :value="formState" width="270" name="device_number">
|
||||
<AssetTableModalLeftInfoDept />
|
||||
<Input :value="formState" width="290" name="device_number">
|
||||
<template #topLeft
|
||||
>Tag_Name ({{ $t("assetManagement.fill_text") }})</template
|
||||
>
|
||||
@ -127,28 +131,19 @@ const openCompanyAddModal = () => {
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<!-- <Input :value="formState" width="270" name="floor_guid">
|
||||
<template #topLeft>設備位置(樓層 / 區域)</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.floor_guid }}
|
||||
</span></template
|
||||
></Input
|
||||
> -->
|
||||
<Input
|
||||
:value="formState"
|
||||
width="270"
|
||||
name="device_coordinate"
|
||||
:disabled="true"
|
||||
>
|
||||
<template #topLeft>{{ $t("assetManagement.device_coordinate") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.device_coordinate }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<Input :value="formState" width="270" name="asset_number">
|
||||
<div class="flex items-center w-72">
|
||||
<Select
|
||||
:value="formState"
|
||||
selectClass="border-info focus-within:border-info"
|
||||
name="response_schema_id"
|
||||
Attribute="name"
|
||||
:options="iotSchemaOptions"
|
||||
:required="true"
|
||||
>
|
||||
<template #topLeft>IoT</template>
|
||||
</Select>
|
||||
</div>
|
||||
<Input :value="formState" width="290" name="asset_number">
|
||||
<template #topLeft>{{ $t("assetManagement.asset_number") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
@ -156,7 +151,7 @@ const openCompanyAddModal = () => {
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<DateGroup :items="buying_date" width="270" :withLine="false">
|
||||
<DateGroup :items="buying_date" width="290" :withLine="false">
|
||||
<template #topLeft>{{ $t("assetManagement.buying_date") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
@ -164,7 +159,7 @@ const openCompanyAddModal = () => {
|
||||
</span></template
|
||||
>
|
||||
</DateGroup>
|
||||
<Input :value="formState" width="270" name="brand">
|
||||
<Input :value="formState" width="290" name="brand">
|
||||
<template #topLeft>{{ $t("assetManagement.brand") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
@ -172,7 +167,7 @@ const openCompanyAddModal = () => {
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<Input :value="formState" width="270" name="device_model">
|
||||
<Input :value="formState" width="290" name="device_model">
|
||||
<template #topLeft>{{ $t("assetManagement.modal") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
@ -180,7 +175,7 @@ const openCompanyAddModal = () => {
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<div class="flex items-center col-span-2">
|
||||
<div class="flex items-center w-72">
|
||||
<Select
|
||||
:value="formState"
|
||||
selectClass="border-info focus-within:border-info"
|
||||
@ -191,27 +186,9 @@ const openCompanyAddModal = () => {
|
||||
>
|
||||
<template #topLeft>{{ $t("assetManagement.company") }}</template>
|
||||
</Select>
|
||||
<OperationTableModal type="asset" />
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-add ml-2 mt-7"
|
||||
@click="openCompanyAddModal"
|
||||
>
|
||||
<font-awesome-icon :icon="['fas', 'plus']" />
|
||||
{{ $t("button.add") }}
|
||||
</button>
|
||||
</div>
|
||||
<AssetTableModalLeftInfoMQTT />
|
||||
<AssetTableModalLeftInfoGraph />
|
||||
<!-- <Upload
|
||||
name="oriFile"
|
||||
:fileList="formState.oriFile"
|
||||
:getFileList="updateFileList"
|
||||
:multiple="true"
|
||||
class="col-span-2"
|
||||
:baseUrl="FILE_BASEURL"
|
||||
>
|
||||
<template #topLeft>{{ $t("assetManagement.oriFile") }}</template>
|
||||
</Upload> -->
|
||||
<AssetTableModalLeftInfoIoT />
|
||||
</template>
|
||||
|
||||
|
@ -0,0 +1,161 @@
|
||||
<script setup>
|
||||
import { onMounted, ref, inject, onBeforeMount, watch, computed } from "vue";
|
||||
import {
|
||||
getDepartmentList,
|
||||
postDepartmentList,
|
||||
deleteDepartmentItem,
|
||||
} from "@/apis/asset";
|
||||
import useFormErrorMessage from "@/hooks/useFormErrorMessage";
|
||||
import * as yup from "yup";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const { openToast, cancelToastOpen } = inject("app_toast");
|
||||
const { formState } = inject("asset_table_modal_form");
|
||||
|
||||
const selectedOption = ref("add");
|
||||
|
||||
const DeptFormState = ref({ id: 0, name: "" });
|
||||
const departmentList = ref([]);
|
||||
|
||||
const getDepartment = async () => {
|
||||
const res = await getDepartmentList();
|
||||
departmentList.value = res.data.map((d) => ({ ...d, key: d.id }));
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getDepartment();
|
||||
});
|
||||
|
||||
// modal
|
||||
const openModal = () => {
|
||||
if (selectedOption.value === "add") {
|
||||
DeptFormState.value = {
|
||||
id: 0,
|
||||
name: "",
|
||||
};
|
||||
} else if (selectedOption.value === "edit") {
|
||||
const dept = departmentList.value.find(
|
||||
(d) => d.id === formState.value.department_id
|
||||
);
|
||||
if (dept) {
|
||||
DeptFormState.value = {
|
||||
id: dept.id,
|
||||
name: dept.name,
|
||||
};
|
||||
}
|
||||
}
|
||||
asset_add_dept.showModal();
|
||||
};
|
||||
|
||||
const form = ref(null);
|
||||
|
||||
const deptScheme = yup.object({
|
||||
name: yup.string().required(t("button.required")),
|
||||
});
|
||||
|
||||
const { formErrorMsg, handleSubmit, handleErrorReset, updateScheme } =
|
||||
useFormErrorMessage(deptScheme);
|
||||
const onOk = async () => {
|
||||
const value = await handleSubmit(deptScheme, DeptFormState.value);
|
||||
|
||||
const res = await postDepartmentList(value);
|
||||
if (res.isSuccess) {
|
||||
getDepartment();
|
||||
onCancel();
|
||||
}
|
||||
};
|
||||
|
||||
const onDelete = async () => {
|
||||
openToast(
|
||||
"warning",
|
||||
t("msg.sure_to_delete"),
|
||||
"#asset_add_table_item",
|
||||
async () => {
|
||||
await cancelToastOpen();
|
||||
const res = await deleteDepartmentItem(formState.value.department_id);
|
||||
if (res.isSuccess) {
|
||||
getDepartment();
|
||||
openToast("success", t("msg.delete_success"), "#asset_add_table_item");
|
||||
} else {
|
||||
openToast("error", res.msg, "#asset_add_table_item");
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const onCancel = () => {
|
||||
DeptFormState.value = {
|
||||
id: 0,
|
||||
name: "",
|
||||
};
|
||||
asset_add_dept.close();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div className="join w-72 mb-4">
|
||||
<Select
|
||||
:value="formState"
|
||||
selectClass="border-info focus-within:border-info rounded-r-none"
|
||||
name="department_id"
|
||||
Attribute="name"
|
||||
:options="departmentList"
|
||||
:isBottomLabelExist="false"
|
||||
>
|
||||
<template #topLeft>{{ $t("assetManagement.department") }}</template>
|
||||
</Select>
|
||||
<select
|
||||
v-model="selectedOption"
|
||||
className="select border-info focus-within:border-info join-item mt-11"
|
||||
>
|
||||
<option value="add" selected>{{ $t("button.add") }}</option>
|
||||
<option value="edit">{{ $t("button.edit") }}</option>
|
||||
<option value="delete">{{ $t("button.delete") }}</option>
|
||||
</select>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-success join-item mt-11"
|
||||
@click="selectedOption === 'delete' ? onDelete() : openModal()"
|
||||
:aria-label="$t('button.submit')"
|
||||
>
|
||||
{{ $t("button.submit") }}
|
||||
</button>
|
||||
</div>
|
||||
<Modal
|
||||
id="asset_add_dept"
|
||||
:title="t('assetManagement.department')"
|
||||
:onCancel="onCancel"
|
||||
width="400"
|
||||
>
|
||||
<template #modalContent>
|
||||
<form ref="form">
|
||||
<Input :value="DeptFormState" width="270" name="name">
|
||||
<template #topLeft>{{
|
||||
$t("assetManagement.department_name")
|
||||
}}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.name }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
</form>
|
||||
</template>
|
||||
<template #modalAction>
|
||||
<button
|
||||
type="reset"
|
||||
class="btn btn-outline-success mr-2"
|
||||
@click.prevent="onCancel"
|
||||
>
|
||||
{{ $t("button.cancel") }}
|
||||
</button>
|
||||
<button type="submit" class="btn btn-outline-success" @click="onOk">
|
||||
{{ $t("button.submit") }}
|
||||
</button>
|
||||
</template></Modal
|
||||
>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
@ -0,0 +1,134 @@
|
||||
<script setup>
|
||||
import { onMounted, ref, inject, watch, computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import mqtt from "mqtt";
|
||||
|
||||
const { t } = useI18n();
|
||||
const { openToast, cancelToastOpen } = inject("app_toast");
|
||||
const { formState } = inject(
|
||||
"asset_table_modal_form"
|
||||
);
|
||||
const BASEURL = import.meta.env.VITE_MQTT_BASEURL;
|
||||
// MQTT相關
|
||||
const mqttClient = ref(null); // MQTT客戶端
|
||||
const receivedMessages = ref([]); // 儲存接收到的訊息
|
||||
const countdown = ref(60); // 倒計時初始為 60 秒
|
||||
let timer = null; // 記錄計時器
|
||||
|
||||
const openModal = () => {
|
||||
if (!mqttClient.value) {
|
||||
connectMqtt();
|
||||
}
|
||||
mqtt_test.showModal();
|
||||
startCountdown(); // 開始倒計時
|
||||
};
|
||||
|
||||
const connectMqtt = () => {
|
||||
const topic = formState.value.topic || ""; // 取得主題
|
||||
const mqttHost = `${BASEURL}`;
|
||||
const protocol = import.meta.env.MODE === "production" ? "wss" : "ws"; // 根據伺服器配置,需要設置為 "ws" 或 "wss"
|
||||
mqttClient.value = mqtt.connect(mqttHost, {
|
||||
protocol,
|
||||
reconnectPeriod: 1000, // 每秒嘗試重新連線
|
||||
});
|
||||
|
||||
mqttClient.value.on("connect", () => {
|
||||
console.log("MQTT 已連接");
|
||||
if (topic) {
|
||||
mqttClient.value.subscribe(topic, (err) => {
|
||||
if (!err) {
|
||||
console.log(`已訂閱主題: ${topic}`);
|
||||
} else {
|
||||
console.error("訂閱失敗: ", err);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
mqttClient.value.on("message", (topic, message) => {
|
||||
// 儲存接收到的訊息
|
||||
receivedMessages.value.push({ topic, message: message.toString() });
|
||||
clearInterval(timer); // 收到訊息後清除倒計時
|
||||
});
|
||||
|
||||
mqttClient.value.on("error", (err) => {
|
||||
console.error("MQTT 連線錯誤: ", err);
|
||||
});
|
||||
};
|
||||
|
||||
const startCountdown = () => {
|
||||
if (timer) return; // 防止重複啟動計時器
|
||||
timer = setInterval(() => {
|
||||
if (countdown.value > 0) {
|
||||
countdown.value--;
|
||||
} else {
|
||||
onCancel(); // 1分鐘後如果沒有收到訊息則觸發 onCancel
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const onCancel = () => {
|
||||
receivedMessages.value = [];
|
||||
mqtt_test.close();
|
||||
|
||||
// 斷開 MQTT 連線
|
||||
if (mqttClient.value) {
|
||||
mqttClient.value.end();
|
||||
mqttClient.value = null;
|
||||
}
|
||||
|
||||
// 重置倒計時
|
||||
if (timer) {
|
||||
clearInterval(timer);
|
||||
timer = null; // 清除計時器引用
|
||||
}
|
||||
countdown.value = 60;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex w-72">
|
||||
<Input :value="formState" name="topic" >
|
||||
<template #topLeft>MQTT Topic</template>
|
||||
</Input>
|
||||
<button type="button" class="btn btn-add mt-11 ms-1" @click="openModal">
|
||||
<font-awesome-icon :icon="['fas', 'cog']" />
|
||||
Test
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Modal id="mqtt_test" title="MQTT Topic" :onCancel="onCancel" width="400">
|
||||
<template #modalContent>
|
||||
<!-- 顯示接收到的訊息 -->
|
||||
<div v-if="receivedMessages.length > 0" class="overflow-y-auto h-96">
|
||||
<ul>
|
||||
<li
|
||||
v-for="(message, index) in receivedMessages"
|
||||
:key="index"
|
||||
class="bg-base-200 rounded-md text-wrap shadow shadow-slate-400 p-4 my-2 me-2"
|
||||
>
|
||||
<strong class=" text-base block text-info mb-2">{{ message.topic }} :</strong>
|
||||
<p class=" text-sm break-words">{{ message.message }}</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- 顯示 loading 和倒計時 -->
|
||||
<p v-else class="text-center mt-20">
|
||||
<Loading />
|
||||
<br />
|
||||
<span class="text-base">{{ countdown }} seconds</span>
|
||||
</p>
|
||||
</template>
|
||||
<template #modalAction>
|
||||
<button
|
||||
type="reset"
|
||||
class="btn btn-outline-success mr-2"
|
||||
@click.prevent="onCancel"
|
||||
>
|
||||
{{ t("button.cancel") }}
|
||||
</button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
@ -74,10 +74,10 @@ const defaultOption = (map, data = []) => {
|
||||
watch(currentFloor, (newValue) => {
|
||||
if (newValue?.floor_map_name) {
|
||||
const coordinates = totalCoordinates.value[newValue.floor_guid] || [];
|
||||
if (coordinates.length === 0 || coordinates.every(coord => coord === "")) return;
|
||||
const parsedCoordinates = coordinates.map((coord) => {
|
||||
return JSON.parse(coord);
|
||||
});
|
||||
|
||||
asset_floor_chart.value.updateSvg(
|
||||
{
|
||||
full_name: newValue?.floor_map_name,
|
||||
@ -209,8 +209,8 @@ const onCancel = () => {
|
||||
<template>
|
||||
<!-- 平面圖 -->
|
||||
|
||||
<div class="flex items-center justify-between mb-5">
|
||||
<div className="join">
|
||||
<div class="flex gap-4 mb-5">
|
||||
<div className="join w-80 mb-4">
|
||||
<Select
|
||||
:value="formState"
|
||||
selectClass="border-info focus-within:border-info rounded-r-none"
|
||||
@ -238,6 +238,19 @@ const onCancel = () => {
|
||||
{{ $t("button.submit") }}
|
||||
</button>
|
||||
</div>
|
||||
<Input
|
||||
:value="formState"
|
||||
width="270"
|
||||
name="device_coordinate"
|
||||
:disabled="true"
|
||||
>
|
||||
<template #topLeft>{{ $t("assetManagement.device_coordinate") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.device_coordinate }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<EffectScatter
|
||||
|
@ -89,7 +89,7 @@ const getAllOptions = async () => {
|
||||
};
|
||||
|
||||
const updateDataSource = (data) => {
|
||||
dataSource.value = data.map((d) => ({ ...d, key: d.uuid }));
|
||||
dataSource.value = (data || []).map((d) => ({ ...d, key: d.uuid }));
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
|
@ -19,7 +19,7 @@ const store = useBuildingStore();
|
||||
|
||||
const dataSource = ref([]);
|
||||
const updateDataSource = (data) => {
|
||||
dataSource.value = data.map((d) => ({
|
||||
dataSource.value = (data || []).map((d) => ({
|
||||
...d,
|
||||
key: d.id,
|
||||
start_time: d?.start_time ? dayjs(d?.start_time).format("YYYY-MM-DD") : "",
|
||||
|
@ -81,7 +81,7 @@ watch(
|
||||
:items="submitBtns"
|
||||
:withLine="false"
|
||||
:withBtnClass="true"
|
||||
class="ml-5 mr-8 xl:mr-10"
|
||||
v-if="selectedWorkType?.work_type !== 3"
|
||||
/>
|
||||
|
||||
<button class="btn btn-add" @click.stop.prevent="() => openModal()">
|
||||
|
@ -135,7 +135,8 @@ watch(
|
||||
"
|
||||
/>
|
||||
|
||||
<OperationSearchType :selected="selectedSearchType" />
|
||||
<OperationSearchType :selected="selectedSearchType"
|
||||
v-if="selectedWorkType?.work_type !== 3" />
|
||||
<OperationActionButton :selectedWorkType="selectedWorkType" />
|
||||
</div>
|
||||
</form>
|
||||
|
@ -116,7 +116,7 @@ watch(
|
||||
} else if (newSearchParams.search_type === "serial") {
|
||||
changeParams({
|
||||
...searchParams.value,
|
||||
serial_number: newSerialNumber.value,
|
||||
serial_number: newSerialNumber,
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -151,7 +151,7 @@ watch(
|
||||
name="serial_number"
|
||||
:class="twMerge(searchParams?.work_type === '3' ? '' : 'mr-3')"
|
||||
:placeholder="searchParams?.work_type === '3' ? $t('operation.enter_text') : $t('operation.enter_serial')"
|
||||
:value="serial_number"
|
||||
:value="searchParams"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
@ -530,7 +530,7 @@ watch(
|
||||
class="my-2"
|
||||
name="email"
|
||||
>
|
||||
<template #topLeft>>{{ $t("operation.email") }}</template>
|
||||
<template #topLeft>{{ $t("operation.email") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ companyFormErrorMsg.email }}
|
||||
|
@ -206,6 +206,9 @@ const getCurrentInfoModalData = async (e, position, value) => {
|
||||
: "",
|
||||
};
|
||||
}
|
||||
|
||||
const immediateRes = await getSystemRealTime([value.device_number]);
|
||||
realtimeData.value = immediateRes.data;
|
||||
}
|
||||
const mobile = isMobile(e);
|
||||
selectedDevice.value = {
|
||||
|
194
src/views/system/components/SystemInfoModalChart.vue
Normal file
194
src/views/system/components/SystemInfoModalChart.vue
Normal file
@ -0,0 +1,194 @@
|
||||
<script setup>
|
||||
import { inject, onMounted, onUnmounted, ref, nextTick, watch } from "vue";
|
||||
import { getHistoryData } from "@/apis/history";
|
||||
import LineChart from "@/components/chart/LineChart.vue";
|
||||
import { SECOND_CHART_COLOR } from "@/constant";
|
||||
import dayjs from "dayjs";
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n();
|
||||
|
||||
const { selectedDevice: data } = inject("system_selectedDevice");
|
||||
const pointsList = ref([]);
|
||||
const timeList = ref([
|
||||
{ value: 1, name: t("dashboard.one_hour") },
|
||||
{ value: 4, name: t("dashboard.four_hour") },
|
||||
{ value: 8, name: t("dashboard.eight_hour") },
|
||||
]);
|
||||
const chartData = ref([]);
|
||||
const forge_chart = ref(null);
|
||||
const loading = ref(false);
|
||||
|
||||
// 預設圖表選項
|
||||
const defaultChartOption = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
},
|
||||
legend: {
|
||||
data: [],
|
||||
textStyle: {
|
||||
color: "#ffffff",
|
||||
fontSize: 16,
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: "25%",
|
||||
left: "0%",
|
||||
right: "0%",
|
||||
bottom: "0%",
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
splitLine: { show: false },
|
||||
axisLabel: {
|
||||
color: "#ffffff",
|
||||
formatter: (value) => dayjs(value).format("HH:mm"), // 格式化為時間
|
||||
},
|
||||
data: [],
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
splitLine: { show: false },
|
||||
axisLabel: { color: "#ffffff" },
|
||||
},
|
||||
series: [],
|
||||
};
|
||||
|
||||
const formState = ref({
|
||||
Cumulant: 1,
|
||||
Type: 2,
|
||||
Points: [],
|
||||
Start_date: dayjs().format("YYYY-MM-DD"),
|
||||
Start_time: dayjs().format("HH:00"),
|
||||
End_date: dayjs().format("YYYY-MM-DD"),
|
||||
End_time: dayjs().format("HH:00"),
|
||||
Device_list: [],
|
||||
});
|
||||
|
||||
const updateTimeRange = (hours) => {
|
||||
const now = dayjs();
|
||||
const startTime = now.subtract(hours, "hour");
|
||||
formState.value.Start_date = startTime.format("YYYY-MM-DD");
|
||||
formState.value.Start_time = startTime.format("HH:00");
|
||||
formState.value.End_date = now.format("YYYY-MM-DD");
|
||||
formState.value.End_time = now.format("HH:00");
|
||||
};
|
||||
|
||||
const onSearch = async () => {
|
||||
loading.value = true;
|
||||
const res = await getHistoryData(formState.value);
|
||||
if (res.isSuccess) {
|
||||
if (res.data.items.length > 0) {
|
||||
chartData.value = res.data.items
|
||||
.map((d) => ({
|
||||
timestamp: d.timestamp,
|
||||
value: parseFloat(d.value),
|
||||
}))
|
||||
.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp));
|
||||
|
||||
// 更新圖表
|
||||
await nextTick();
|
||||
if (forge_chart.value?.chart) {
|
||||
forge_chart.value.chart.setOption({
|
||||
xAxis: {
|
||||
data: chartData.value.map((d) => d.timestamp),
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: data?.value?.value.full_name,
|
||||
type: "line",
|
||||
data: chartData.value.map((d) => d.value),
|
||||
showSymbol: false,
|
||||
itemStyle: {
|
||||
color: SECOND_CHART_COLOR[0], // 使用預設顏色
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
} else {
|
||||
chartData.value = [];
|
||||
if (forge_chart.value?.chart) {
|
||||
forge_chart.value.chart.clear(); // 清空圖表
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error("API Error:", res.msg);
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
console.log("Initial data:", data?.value?.value);
|
||||
if (data?.value?.value.device_number) {
|
||||
formState.value.Device_list = [data?.value?.value.device_number];
|
||||
}
|
||||
if (data?.value?.value.points) {
|
||||
pointsList.value = data?.value?.value?.points.map((item) => ({
|
||||
name: item.full_name,
|
||||
value: item.points,
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
formState.value = {};
|
||||
chartData.value = [];
|
||||
});
|
||||
|
||||
watch(
|
||||
() => formState.value.Points,
|
||||
(newPoints) => {
|
||||
if (newPoints.includes("Total")) {
|
||||
formState.value.Cumulant = 2;
|
||||
} else {
|
||||
formState.value.Cumulant = 1;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center gap-4">
|
||||
<Select
|
||||
:value="formState"
|
||||
class=""
|
||||
selectClass="border-info focus-within:border-info"
|
||||
name="Points"
|
||||
Attribute="name"
|
||||
:options="pointsList"
|
||||
></Select>
|
||||
<Select
|
||||
:value="formState"
|
||||
class=""
|
||||
selectClass="border-info focus-within:border-info"
|
||||
name="time"
|
||||
Attribute="name"
|
||||
:options="timeList"
|
||||
:onChange="updateTimeRange"
|
||||
></Select>
|
||||
<button class="btn btn-search" @click.stop.prevent="onSearch">
|
||||
<font-awesome-icon :icon="['fas', 'search']" />
|
||||
{{ $t("button.search") }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="min-h-[300px] relative">
|
||||
<span
|
||||
v-if="loading"
|
||||
className="loading loading-spinner loading-lg text-info absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-20"
|
||||
></span>
|
||||
<LineChart
|
||||
v-if="chartData.length > 0"
|
||||
id="forge_chart"
|
||||
class="min-h-[300px] max-h-fit"
|
||||
:option="defaultChartOption"
|
||||
ref="forge_chart"
|
||||
/>
|
||||
<p class="text-center text-xl" v-if="!loading && chartData.length === 0">
|
||||
{{ $t("table.no_data") }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
@ -3,9 +3,9 @@ import { defineProps, inject, ref, watch } from "vue";
|
||||
import SystemInfoModalDesktop from "./SystemInfoModalDesktop.vue";
|
||||
import SystemInfoModalCog from "./SystemInfoModalCog.vue";
|
||||
import SystemInfoModalImage from "./SystemInfoModalImage.vue";
|
||||
import SystemInfoModalChart from "./SystemInfoModalChart.vue";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
|
||||
const { selectedDevice: data, clearSelectedDeviceInfo } = inject("system_selectedDevice")
|
||||
|
||||
|
||||
@ -13,7 +13,8 @@ const currentTab = ref("desktop");
|
||||
const tabs = {
|
||||
desktop: SystemInfoModalDesktop,
|
||||
cog: SystemInfoModalCog,
|
||||
image: SystemInfoModalImage
|
||||
image: SystemInfoModalImage,
|
||||
// chart: SystemInfoModalChart,
|
||||
};
|
||||
|
||||
const changeOpenKey = (key) => {
|
||||
@ -44,28 +45,10 @@ const onCancel = () => {
|
||||
<font-awesome-icon :icon="['fas', 'cog']" size="lg"
|
||||
:class="twMerge(currentTab === 'cog' ? 'text-success' : 'text-[#a5abb1]')" />
|
||||
</Button>
|
||||
<!-- <Button
|
||||
type="link"
|
||||
class="btn-link btn-text-without-border px-2"
|
||||
@click="() => changeOpenKey('triangle')"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'exclamation-triangle']"
|
||||
size="lg"
|
||||
class="text-[#a5abb1]"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
type="link"
|
||||
class="btn-link btn-text-without-border px-2"
|
||||
@click="() => changeOpenKey('bars')"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'bars']"
|
||||
size="lg"
|
||||
class="text-[#a5abb1]"
|
||||
/>
|
||||
</Button>-->
|
||||
<!-- <Button type="link" class="btn-link btn-text-without-border px-2" @click="() => changeOpenKey('chart')">
|
||||
<font-awesome-icon :icon="['fas', 'chart-line']" size="lg"
|
||||
:class="twMerge(currentTab === 'chart' ? 'text-success' : 'text-[#a5abb1]')" />
|
||||
</Button> -->
|
||||
<Button type="link" class="btn-link btn-text-without-border px-2" @click="onCancel">
|
||||
<font-awesome-icon :icon="['fas', 'times']" size="lg" class="text-[#a5abb1]" />
|
||||
</Button>
|
||||
|
@ -11,14 +11,16 @@ const data = computed(() => {
|
||||
|
||||
return selectedDevice.value?.value?.points?.map((d) => ({
|
||||
...d,
|
||||
value: selectedDeviceRealtime?.value?.find(({ point }) => point === d.points)?.value || "No Data"
|
||||
value: selectedDeviceRealtime?.value?.find(({ point }) => point === d.points)?.value || 0
|
||||
})) || []
|
||||
});
|
||||
|
||||
watch(selectedDeviceRealtime, (newValue) => {
|
||||
watch(selectedDeviceRealtime, (newValue,oldValue) => {
|
||||
if (newValue) {
|
||||
loading.value = false;
|
||||
updatedTime.value = dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss");
|
||||
}else{
|
||||
loading.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
@ -40,6 +42,7 @@ const columns = [{
|
||||
:columns="columns"
|
||||
:dataSource="data || []"
|
||||
:withStyle="false"
|
||||
:pagination="false"
|
||||
>
|
||||
</Table>
|
||||
</template>
|
||||
|
Loading…
Reference in New Issue
Block a user