fix: 首頁與歷史資料頁圖表顯示優化
首頁: 1. 室內/冷藏與溫度/濕度位置互換 2. 碳排圖表改為顯示「每日」資料 3. 平面圖點擊 icons 顯示彈跳視窗 歷史資料頁: 1. 調整折線圖 X 軸過密的顯示問題
This commit is contained in:
parent
995cd77bef
commit
2e15353384
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
* text=auto
|
||||
*.html text eol=lf
|
341
package-lock.json
generated
341
package-lock.json
generated
@ -40,6 +40,7 @@
|
||||
"autoprefixer": "^10.4.16",
|
||||
"daisyui": "^4.4.17",
|
||||
"postcss": "^8.4.31",
|
||||
"rollup-plugin-visualizer": "^6.0.3",
|
||||
"sass": "^1.69.5",
|
||||
"sass-loader": "^13.3.2",
|
||||
"tailwindcss": "^3.3.5",
|
||||
@ -1815,6 +1816,44 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/clone": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||
@ -1837,6 +1876,26 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
@ -2159,6 +2218,16 @@
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/define-lazy-prop": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
||||
"integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/define-property": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
|
||||
@ -2282,6 +2351,13 @@
|
||||
"integrity": "sha512-KD6CWjf1BnQG+NsXuyiTDDT1eV13sKuYsOUioXkQweYTQIbgHkXPry9K7M+7cKtYHnSUPitVaLrXYB1jTkkYrw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/emojis-list": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
|
||||
@ -2763,6 +2839,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-value": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
|
||||
@ -3119,6 +3205,22 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-docker": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
|
||||
"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"is-docker": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extendable": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
|
||||
@ -3137,6 +3239,16 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
@ -3190,6 +3302,19 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-wsl": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
|
||||
"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-docker": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
@ -4002,6 +4127,24 @@
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/open": {
|
||||
"version": "8.4.2",
|
||||
"resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
|
||||
"integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"define-lazy-prop": "^2.0.0",
|
||||
"is-docker": "^2.1.1",
|
||||
"is-wsl": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/optimist": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||
@ -4629,6 +4772,16 @@
|
||||
"node": ">= 0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/requirejs": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
|
||||
@ -4711,6 +4864,60 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup-plugin-visualizer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.3.tgz",
|
||||
"integrity": "sha512-ZU41GwrkDcCpVoffviuM9Clwjy5fcUxlz0oMoTXTYsK+tcIFzbdacnrr2n8TXcHxbGKKXtOdjxM2HUS4HjkwIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"open": "^8.0.0",
|
||||
"picomatch": "^4.0.2",
|
||||
"source-map": "^0.7.4",
|
||||
"yargs": "^17.5.1"
|
||||
},
|
||||
"bin": {
|
||||
"rollup-plugin-visualizer": "dist/bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rolldown": "1.x || ^1.0.0-beta",
|
||||
"rollup": "2.x || 3.x || 4.x"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rolldown": {
|
||||
"optional": true
|
||||
},
|
||||
"rollup": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/rollup-plugin-visualizer/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup-plugin-visualizer/node_modules/source-map": {
|
||||
"version": "0.7.6",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
|
||||
"integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
@ -5224,6 +5431,44 @@
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
@ -6384,6 +6629,63 @@
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
@ -6411,6 +6713,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz",
|
||||
@ -6420,6 +6732,35 @@
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yup": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz",
|
||||
|
@ -41,6 +41,7 @@
|
||||
"autoprefixer": "^10.4.16",
|
||||
"daisyui": "^4.4.17",
|
||||
"postcss": "^8.4.31",
|
||||
"rollup-plugin-visualizer": "^6.0.3",
|
||||
"sass": "^1.69.5",
|
||||
"sass-loader": "^13.3.2",
|
||||
"tailwindcss": "^3.3.5",
|
||||
|
@ -16,6 +16,8 @@
|
||||
"formats": "档案格式"
|
||||
},
|
||||
"dashboard": {
|
||||
"production_quantity": "生产量",
|
||||
"today_production_rate": "今日生产完成率",
|
||||
"yesterday_today": "昨天/今天",
|
||||
"elec_consumption_comparison": "用电量比较",
|
||||
"elec_consumption_comparison_trend": "用电量比较趋势",
|
||||
@ -45,8 +47,10 @@
|
||||
"last_month": "上月",
|
||||
"this_year": "今年",
|
||||
"last_year": "去年",
|
||||
"refrig_temp": "冷藏温度",
|
||||
"indoor_temp": "室内温度",
|
||||
"refrig_chart": "冷藏趨勢",
|
||||
"indoor_chart": "室內趨勢",
|
||||
"temperature": "温度",
|
||||
"humidity": "湿度",
|
||||
"alerts_data": "异常资料"
|
||||
},
|
||||
"history": {
|
||||
@ -91,7 +95,7 @@
|
||||
"year_elec_consumption": "今年用电度数(kWh)",
|
||||
"interval_elec_consumption": "区间用电度数(kWh)",
|
||||
"monthly_elec_consumption": "每月用电分析",
|
||||
"monthly_carbon_emission_and_reduction": "每月碳排当量 (kgCO2e)",
|
||||
"daily_carbon_emission_and_reduction": "每日碳排当量 (kgCO2e)",
|
||||
"monthly_bill_power": "每月计费度数 (kWh)",
|
||||
"interval_bill_degree": "区间计费度数",
|
||||
"peak": "尖峰",
|
||||
|
@ -16,6 +16,8 @@
|
||||
"formats": "檔案格式"
|
||||
},
|
||||
"dashboard": {
|
||||
"production_quantity": "生產量",
|
||||
"today_production_rate": "今日生產完成率",
|
||||
"yesterday_today": "昨天/今天",
|
||||
"elec_consumption_comparison": "用電量比較",
|
||||
"elec_consumption_comparison_trend": "用電量比較趨勢",
|
||||
@ -45,9 +47,11 @@
|
||||
"last_month": "上月",
|
||||
"this_year": "今年",
|
||||
"last_year": "去年",
|
||||
"refrig_temp":"冷藏溫度",
|
||||
"indoor_temp":"室內溫度",
|
||||
"alerts_data":"異常資料"
|
||||
"refrig_chart": "冷藏趨勢",
|
||||
"indoor_chart": "室內趨勢",
|
||||
"temperature": "溫度",
|
||||
"humidity": "濕度",
|
||||
"alerts_data": "異常資料"
|
||||
},
|
||||
"history": {
|
||||
"title": "歷史資料",
|
||||
@ -91,7 +95,7 @@
|
||||
"year_elec_consumption": "今年用電度數(kWh)",
|
||||
"interval_elec_consumption": "區間用電度數(kWh)",
|
||||
"monthly_elec_consumption": "每月用電分析",
|
||||
"monthly_carbon_emission_and_reduction": "每月碳排當量 (kgCO2e)",
|
||||
"daily_carbon_emission_and_reduction": "每日碳排當量 (kgCO2e)",
|
||||
"monthly_bill_power": "每月計費度數 (kWh)",
|
||||
"interval_bill_degree": "區間計費度數",
|
||||
"peak": "尖峰",
|
||||
@ -155,8 +159,8 @@
|
||||
"latest_elec_consumption": "最新用電度數",
|
||||
"daily_elec": "每日用電度數",
|
||||
"line_voltage": "線電壓",
|
||||
"electric_current" : "電流",
|
||||
"monthly_elec_bill":"每月電費分析"
|
||||
"electric_current": "電流",
|
||||
"monthly_elec_bill": "每月電費分析"
|
||||
},
|
||||
"alarm": {
|
||||
"title": "顯示警告",
|
||||
@ -182,7 +186,7 @@
|
||||
"alarmClass": "告警條件",
|
||||
"device_name": "設備名稱",
|
||||
"device_number": "設備編號",
|
||||
"device_point_name":"點位名稱",
|
||||
"device_point_name": "點位名稱",
|
||||
"date": "發生日期",
|
||||
"time": "發生時間",
|
||||
"error_msg": "異常原因",
|
||||
@ -389,28 +393,28 @@
|
||||
"restore": "復原",
|
||||
"stop_edit": "停止修改",
|
||||
"start_edit": "開始修改",
|
||||
"convert":"轉換"
|
||||
"convert": "轉換"
|
||||
},
|
||||
"msg": {
|
||||
"sure_to_delete": "是否確認刪除該項目?",
|
||||
"sure_to_delete_permanent": "是否確認永久刪除該項目?",
|
||||
"delete_success": "刪除成功",
|
||||
"delete_failed": "刪除失敗",
|
||||
"mqtt_refresh":"重新設定成功"
|
||||
"mqtt_refresh": "重新設定成功"
|
||||
},
|
||||
"setting": {
|
||||
"MQTT_parse": "MQTT 解析",
|
||||
"schema":"架構",
|
||||
"point":"點位",
|
||||
"description":"描述",
|
||||
"IoT_point_name":"IoT 點位名稱",
|
||||
"IoT_point_code":"IoT 點位代號",
|
||||
"number_of_decimal_places":"小數位數",
|
||||
"boolean_value":"布林值",
|
||||
"hide_point":"點位顯示",
|
||||
"schema_name":"架構名稱",
|
||||
"IoT_point_structure" :"IoT點位結構",
|
||||
"system_point_name":"系統點位名稱",
|
||||
"schema": "架構",
|
||||
"point": "點位",
|
||||
"description": "描述",
|
||||
"IoT_point_name": "IoT 點位名稱",
|
||||
"IoT_point_code": "IoT 點位代號",
|
||||
"number_of_decimal_places": "小數位數",
|
||||
"boolean_value": "布林值",
|
||||
"hide_point": "點位顯示",
|
||||
"schema_name": "架構名稱",
|
||||
"IoT_point_structure": "IoT點位結構",
|
||||
"system_point_name": "系統點位名稱",
|
||||
"json_format_text": "請貼上 JSON 格式數據",
|
||||
"json_click_text": "請在左側輸入JSON並點選轉換按鈕"
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
"formats": "File formats"
|
||||
},
|
||||
"dashboard": {
|
||||
"production_quantity": "Production Quantity",
|
||||
"today_production_rate": "Today's Production Completion Rate",
|
||||
"yesterday_today": "Yesterday / Today's",
|
||||
"elec_consumption_comparison": "Electricity Consumption Comparison",
|
||||
"elec_consumption_comparison_trend": "Electricity Consumption Comparison Trend",
|
||||
@ -45,8 +47,10 @@
|
||||
"last_month": "Last month",
|
||||
"this_year": "This year",
|
||||
"last_year": "Last year",
|
||||
"refrig_temp": "Refrigeration temperature",
|
||||
"indoor_temp": "Indoor temperature",
|
||||
"refrig_chart": "Refrigeration chart",
|
||||
"indoor_chart": "Indoor chart",
|
||||
"temperature": "Temp.",
|
||||
"humidity": "Hum.",
|
||||
"alerts_data": "Abnormal data"
|
||||
},
|
||||
"history": {
|
||||
@ -91,7 +95,7 @@
|
||||
"year_elec_consumption": "This year's electricity consumption (kWh)",
|
||||
"interval_elec_consumption": "Interval electricity consumption (kWh)",
|
||||
"monthly_elec_consumption": "Monthly electricity consumption analysis",
|
||||
"monthly_carbon_emission_and_reduction": "Monthly carbon emission equivalent (kgCO2e)",
|
||||
"daily_carbon_emission_and_reduction": "Daily carbon emission equivalent (kgCO2e)",
|
||||
"monthly_bill_power": "Monthly billing power (kWh)",
|
||||
"interval_bill_degree": "Interval billing degree",
|
||||
"peak": "Peak",
|
||||
|
@ -1,93 +1,80 @@
|
||||
import { createRouter, createWebHashHistory } from "vue-router";
|
||||
import Dashboard from "@/views/dashboard/Dashboard.vue";
|
||||
import History from "@/views/history/History.vue";
|
||||
import Operation from "@/views/operation/Operation.vue";
|
||||
import GraphManagement from "@/views/graphManagement/GraphManagement.vue";
|
||||
import AccountManagement from "@/views/accountManagement/AccountManagement.vue";
|
||||
import AssetManagement from "@/views/AssetManagement/AssetManagement.vue";
|
||||
import AlertManagement from "@/views/alert/AlertManagement.vue";
|
||||
import EnergyManagement from "@/views/energyManagement/EnergyManagement.vue";
|
||||
import SettingManagement from "@/views/setting/SettingManagement.vue";
|
||||
import Login from "@/views/login/Login.vue";
|
||||
import useUserInfoStore from "@/stores/useUserInfoStore";
|
||||
import useGetCookie from "@/hooks/useGetCookie";
|
||||
import System from "@/views/system/System.vue";
|
||||
import SystemFloor from "@/views/system/SystemFloor.vue";
|
||||
|
||||
import Test from "@/views/Test.vue";
|
||||
import SystemMain from "@/views/system/SystemMain.vue";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(import.meta.env.BASE_URL),
|
||||
// linkActiveClass: "is-active",
|
||||
routes: [
|
||||
{
|
||||
path: "/login",
|
||||
name: "login",
|
||||
component: Login,
|
||||
component: () => import("@/views/login/Login.vue"),
|
||||
},
|
||||
{
|
||||
path: "/dashboard",
|
||||
index: true,
|
||||
name: "dashboard",
|
||||
component: Dashboard,
|
||||
component: () => import("@/views/dashboard/Dashboard.vue"),
|
||||
},
|
||||
{
|
||||
path: "/system/:main_system_id/:sub_system_id",
|
||||
name: "system",
|
||||
component: System,
|
||||
component: () => import("@/views/system/System.vue"),
|
||||
children: [
|
||||
{
|
||||
path: ":floor_id",
|
||||
name: "sub_system",
|
||||
component: SystemMain,
|
||||
component: () => import("@/views/system/SystemMain.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/historyData",
|
||||
name: "history",
|
||||
component: History,
|
||||
component: () => import("@/views/history/History.vue"),
|
||||
},
|
||||
{
|
||||
path: "/operation",
|
||||
name: "operation",
|
||||
component: Operation,
|
||||
component: () => import("@/views/operation/Operation.vue"),
|
||||
},
|
||||
{
|
||||
path: "/graphManagement",
|
||||
name: "graphManagement",
|
||||
component: GraphManagement,
|
||||
component: () => import("@/views/graphManagement/GraphManagement.vue"),
|
||||
},
|
||||
{
|
||||
path: "/accountManagement",
|
||||
name: "accountManagement",
|
||||
component: AccountManagement,
|
||||
component: () =>
|
||||
import("@/views/accountManagement/AccountManagement.vue"),
|
||||
},
|
||||
{
|
||||
path: "/assetManagement",
|
||||
name: "assetManagement",
|
||||
component: AssetManagement,
|
||||
component: () => import("@/views/AssetManagement/AssetManagement.vue"),
|
||||
},
|
||||
{
|
||||
path: "/alert",
|
||||
name: "alert",
|
||||
component: AlertManagement,
|
||||
component: () => import("@/views/alert/AlertManagement.vue"),
|
||||
},
|
||||
{
|
||||
path: "/energyManagement",
|
||||
name: "energyManagement",
|
||||
component: EnergyManagement,
|
||||
component: () => import("@/views/energyManagement/EnergyManagement.vue"),
|
||||
},
|
||||
{
|
||||
path: "/setting/:main_system_id/:sub_system_id/:type",
|
||||
name: "setting",
|
||||
component: SettingManagement,
|
||||
component: () => import("@/views/setting/SettingManagement.vue"),
|
||||
},
|
||||
{
|
||||
path: "/mytestfile/mjm",
|
||||
name: "mytestfile",
|
||||
component: Test,
|
||||
component: () => import("@/views/Test.vue"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -8,6 +8,7 @@ import useBuildingStore from "@/stores/useBuildingStore";
|
||||
const store = useBuildingStore();
|
||||
const { t, locale } = useI18n();
|
||||
const taipower_data = ref([]);
|
||||
const elecUseDayData = ref([]);
|
||||
const carbonValue = ref(null);
|
||||
const carbonData = ref(null);
|
||||
const search_data = computed(() => {
|
||||
@ -75,7 +76,7 @@ const getData = async (value) => {
|
||||
const res = await getTaipower(value);
|
||||
if (res.isSuccess) {
|
||||
taipower_data.value = res.data
|
||||
? res.data.sort((a, b) => a.month.localeCompare(b.month))
|
||||
? res.data.sort((a, b) => a.day.localeCompare(b.month))
|
||||
: [];
|
||||
}
|
||||
};
|
||||
@ -107,6 +108,7 @@ watch(
|
||||
JSON.stringify(newValue) !== JSON.stringify(oldValue)
|
||||
) {
|
||||
getData(newValue);
|
||||
getElecUseDayData(newValue);
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -119,12 +121,12 @@ watch(
|
||||
watch(
|
||||
taipower_data,
|
||||
() => {
|
||||
// 提取月份和碳排放數據
|
||||
const months = taipower_data.value.map((item) => item.month);
|
||||
// 依照每日顯示
|
||||
const days = taipower_data.value.map((item) => item.day);
|
||||
const carbonTotal = taipower_data.value.map((item) => item.carbon);
|
||||
|
||||
// 更新圖表的 xAxis 和 series
|
||||
defaultChartOption.value.xAxis.data = months;
|
||||
// 更新圖表資料
|
||||
defaultChartOption.value.xAxis.data = days;
|
||||
defaultChartOption.value.series[0].data = carbonTotal;
|
||||
},
|
||||
{ deep: true }
|
||||
@ -144,7 +146,7 @@ onMounted(() => {
|
||||
<div class="mb-3 relative">
|
||||
<h3 class="font-bold text-xl text-center">
|
||||
<span class="text-info">
|
||||
{{ $t("energy.monthly_carbon_emission_and_reduction") }}
|
||||
{{ $t("energy.daily_carbon_emission_and_reduction") }}
|
||||
</span>
|
||||
</h3>
|
||||
<DashboardEmissionModal :carbonData="carbonData" :getData="getCarbonData" />
|
||||
|
@ -2,12 +2,14 @@
|
||||
import LineChart from "@/components/chart/LineChart.vue";
|
||||
import { SECOND_CHART_COLOR } from "@/constant";
|
||||
import dayjs from "dayjs";
|
||||
import { ref, watch, onUnmounted } from "vue";
|
||||
import { ref, watch, onMounted, onUnmounted, computed } from "vue";
|
||||
import useActiveBtn from "@/hooks/useActiveBtn";
|
||||
import { getDashboardTemp } from "@/apis/dashboard";
|
||||
import useSearchParams from "@/hooks/useSearchParam";
|
||||
import useBuildingStore from "@/stores/useBuildingStore";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const { searchParams } = useSearchParams();
|
||||
const buildingStore = useBuildingStore();
|
||||
const intervalType = "immediateTemp";
|
||||
@ -17,6 +19,9 @@ const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
|
||||
|
||||
const data = ref([]);
|
||||
const other_real_temp_chart = ref(null);
|
||||
const currentOptionType = ref(1); // 1: 溫度, 2: 濕度
|
||||
const noData = ref(false);
|
||||
|
||||
const defaultChartOption = ref({
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
@ -36,72 +41,50 @@ const defaultChartOption = ref({
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
// type: 'time',
|
||||
type: "category",
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#ffffff",
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLabel: { color: "#ffffff" },
|
||||
data: [],
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#ffffff",
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLabel: { color: "#ffffff" },
|
||||
},
|
||||
series: [],
|
||||
});
|
||||
|
||||
const getData = async (tempOption) => {
|
||||
const getData = async () => {
|
||||
const res = await getDashboardTemp({
|
||||
building_guid: buildingStore.selectedBuilding.building_guid,
|
||||
tempOption, // 1:室溫 2:冷藏
|
||||
timeInterval: 1, // 時間間隔=>1.4.8
|
||||
option: 2, // 2:濕度
|
||||
tempOption: 2, // 參數 tempOption 1:室溫 2:冷藏
|
||||
timeInterval: 1,
|
||||
option: currentOptionType.value, // 參數 option:1:溫度 2:濕度
|
||||
});
|
||||
|
||||
if (res.isSuccess) {
|
||||
if (tempOption === 1) {
|
||||
console.log("室內溼度資料:", res.data["室溫"]);
|
||||
data.value = res.data["室溫"] || [];
|
||||
} else {
|
||||
console.log("冷藏溼度資料:", res.data["冷藏溫度"]);
|
||||
data.value = res.data["冷藏溫度"] || [];
|
||||
}
|
||||
const key = "冷藏溫度";
|
||||
const label = currentOptionType.value === 1 ? "溫度" : "濕度";
|
||||
console.log(`冷藏${label}資料:`, res.data[key]);
|
||||
data.value = res.data[key] || [];
|
||||
noData.value = !data.value || data.value.length === 0;
|
||||
} else {
|
||||
noData.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
// 監聽建築物選擇變化
|
||||
const buttonItems = computed(() => [
|
||||
{ key: 1, title: t("dashboard.temperature"), active: true },
|
||||
{ key: 2, title: t("dashboard.humidity"), active: false },
|
||||
]);
|
||||
|
||||
// 當語言改變時,重新設定項目
|
||||
watch(
|
||||
() => buildingStore.sysConfig,
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
// 根據 sysConfig 設定動態生成按鈕
|
||||
const itemsArr = buildingStore.sysConfig?.humiture_options
|
||||
? Object.entries(buildingStore.sysConfig.humiture_options).map(
|
||||
([key, title], index) => ({
|
||||
key: Number(key),
|
||||
title,
|
||||
active: index === 0,
|
||||
})
|
||||
)
|
||||
: [];
|
||||
setItems(itemsArr);
|
||||
} else {
|
||||
// 清除定時器
|
||||
if (timeoutTimer.value) {
|
||||
clearInterval(timeoutTimer.value);
|
||||
}
|
||||
}
|
||||
() => locale.value,
|
||||
() => {
|
||||
setItems(buttonItems.value);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
@ -111,18 +94,15 @@ watch(
|
||||
clearInterval(timeoutTimer.value);
|
||||
}
|
||||
|
||||
if (newValue?.key) {
|
||||
getData(newValue.key);
|
||||
// 重新設置定時器
|
||||
if (newValue?.key === 1 || newValue?.key === 2) {
|
||||
currentOptionType.value = newValue.key;
|
||||
getData();
|
||||
timeoutTimer.value = setInterval(() => {
|
||||
getData(newValue.key);
|
||||
getData();
|
||||
}, 60 * 1000);
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
@ -170,7 +150,6 @@ watch(
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
// 清除定時器
|
||||
if (timeoutTimer.value) {
|
||||
clearInterval(timeoutTimer.value);
|
||||
}
|
||||
@ -178,18 +157,23 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h3 class="text-info text-xl text-center">濕度趨勢</h3>
|
||||
<h3 class="text-info text-xl text-center">
|
||||
{{ $t("dashboard.refrig_chart") }}
|
||||
</h3>
|
||||
<div className="my-3 w-full flex justify-center relative">
|
||||
<ButtonConnectedGroup
|
||||
:items="items"
|
||||
:onclick="
|
||||
(e, item) => {
|
||||
changeActiveBtn(item);
|
||||
}
|
||||
"
|
||||
:onclick="(e, item) => changeActiveBtn(item)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="noData"
|
||||
class="text-center text-white text-lg min-h-[260px] flex items-center justify-center"
|
||||
>
|
||||
無資料
|
||||
</div>
|
||||
<LineChart
|
||||
v-else
|
||||
id="dashboard_other_real_temp"
|
||||
class="min-h-[260px] max-h-fit"
|
||||
:option="defaultChartOption"
|
||||
|
@ -55,7 +55,7 @@ const defaultChartOption = ref({
|
||||
});
|
||||
|
||||
const timeoutTimer = ref("");
|
||||
const indoor_temp_chart = ref(null);
|
||||
const indoor_chart = ref(null);
|
||||
const data = ref([]);
|
||||
|
||||
const getData = async (timeInterval) => {
|
||||
@ -75,7 +75,7 @@ watch(
|
||||
data,
|
||||
(newValue) => {
|
||||
newValue.length > 0 &&
|
||||
indoor_temp_chart.value.chart.setOption({
|
||||
indoor_chart.value.chart.setOption({
|
||||
legend: {
|
||||
data: newValue.map(({ full_name }) => full_name),
|
||||
},
|
||||
@ -143,14 +143,14 @@ onUnmounted(() => {
|
||||
|
||||
<template>
|
||||
<h3 class="text-info font-bold text-xl text-center mb-3 relative">
|
||||
<span>{{ $t("dashboard.indoor_temp") }}</span>
|
||||
<span>{{ $t("dashboard.indoor_chart") }}</span>
|
||||
</h3>
|
||||
|
||||
<LineChart
|
||||
id="dashboard_indoor_temp"
|
||||
id="dashboard_indoor_chart"
|
||||
class="min-h-[300px] max-h-fit"
|
||||
:option="defaultChartOption"
|
||||
ref="indoor_temp_chart"
|
||||
ref="indoor_chart"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
@ -120,7 +120,9 @@ onMounted(() => {
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<h3 class="text-info text-xl text-center mb-3">生產量</h3>
|
||||
<h3 class="text-info text-xl text-center mb-3">
|
||||
{{ $t("dashboard.production_quantity") }}
|
||||
</h3>
|
||||
<div class="w-full grid grid-cols-3">
|
||||
<div>
|
||||
<GaugeChart
|
||||
|
@ -44,15 +44,17 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DashboardProductCompleteModal/>
|
||||
<DashboardProductCompleteModal />
|
||||
<div class="mb-3 relative">
|
||||
<h3 class="text-info text-xl text-center">今日生產完成率 %</h3>
|
||||
<h3 class="text-info text-xl text-center">
|
||||
{{ $t("dashboard.today_production_rate") }} (%)
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-xs btn-success absolute top-0 right-0"
|
||||
@click.stop="openModal"
|
||||
>
|
||||
設定
|
||||
{{ $t("button.edit") }}
|
||||
</button>
|
||||
</div>
|
||||
<div className="my-3 w-full flex justify-center relative">
|
||||
|
@ -146,7 +146,7 @@ onUnmounted(() => {
|
||||
|
||||
<template>
|
||||
<h3 class="text-info font-bold text-xl text-center mb-3 relative">
|
||||
<span>{{ $t("dashboard.refrig_temp") }}</span>
|
||||
<span>{{ $t("dashboard.refrig_chart") }}</span>
|
||||
</h3>
|
||||
|
||||
<LineChart
|
||||
|
@ -2,12 +2,14 @@
|
||||
import LineChart from "@/components/chart/LineChart.vue";
|
||||
import { SECOND_CHART_COLOR } from "@/constant";
|
||||
import dayjs from "dayjs";
|
||||
import { ref, watch, onUnmounted } from "vue";
|
||||
import { ref, watch, onMounted, onUnmounted, computed } from "vue";
|
||||
import useActiveBtn from "@/hooks/useActiveBtn";
|
||||
import { getDashboardTemp } from "@/apis/dashboard";
|
||||
import useSearchParams from "@/hooks/useSearchParam";
|
||||
import useBuildingStore from "@/stores/useBuildingStore";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const { searchParams } = useSearchParams();
|
||||
const buildingStore = useBuildingStore();
|
||||
const intervalType = "immediateTemp";
|
||||
@ -17,6 +19,9 @@ const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
|
||||
|
||||
const data = ref([]);
|
||||
const other_real_temp_chart = ref(null);
|
||||
const currentOptionType = ref(1); // 1: 溫度, 2: 濕度
|
||||
const noData = ref(false);
|
||||
|
||||
const defaultChartOption = ref({
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
@ -36,24 +41,15 @@ const defaultChartOption = ref({
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
// type: 'time',
|
||||
type: "category",
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#ffffff",
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLabel: { color: "#ffffff" },
|
||||
data: [],
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#ffffff",
|
||||
},
|
||||
splitLine: { show: false },
|
||||
axisLabel: { color: "#ffffff" },
|
||||
},
|
||||
series: [],
|
||||
});
|
||||
@ -61,47 +57,33 @@ const defaultChartOption = ref({
|
||||
const getData = async (tempOption) => {
|
||||
const res = await getDashboardTemp({
|
||||
building_guid: buildingStore.selectedBuilding.building_guid,
|
||||
tempOption, // 1:室溫 2:冷藏
|
||||
timeInterval: 1, // 時間間隔=>1.4.8
|
||||
option: 1, // 1:即時溫度
|
||||
tempOption, // 參數 tempOption 1:室溫 2:冷藏
|
||||
timeInterval: 1,
|
||||
option: currentOptionType.value, // 參數 option:1:溫度 2:濕度
|
||||
});
|
||||
|
||||
if (res.isSuccess) {
|
||||
if (tempOption === 1) {
|
||||
console.log("室內溫度資料:", res.data["室溫"]);
|
||||
data.value = res.data["室溫"] || [];
|
||||
} else {
|
||||
console.log("冷藏溫度資料:", res.data["冷藏溫度"]);
|
||||
data.value = res.data["冷藏溫度"] || [];
|
||||
}
|
||||
const key = "室溫";
|
||||
const label = currentOptionType.value === 1 ? "溫度" : "濕度";
|
||||
// console.log(`室內${label}資料:`, res.data[key]);
|
||||
data.value = res.data[key] || [];
|
||||
noData.value = !data.value || data.value.length === 0;
|
||||
} else {
|
||||
noData.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
// 監聽建築物選擇變化
|
||||
const buttonItems = computed(() => [
|
||||
{ key: 1, title: t("dashboard.temperature"), active: true },
|
||||
{ key: 2, title: t("dashboard.humidity"), active: false },
|
||||
]);
|
||||
|
||||
watch(
|
||||
() => buildingStore.sysConfig,
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
// 根據 sysConfig 設定動態生成按鈕
|
||||
const itemsArr = buildingStore.sysConfig?.humiture_options
|
||||
? Object.entries(buildingStore.sysConfig.humiture_options).map(
|
||||
([key, title], index) => ({
|
||||
key: Number(key),
|
||||
title,
|
||||
active: index === 0,
|
||||
})
|
||||
)
|
||||
: [];
|
||||
setItems(itemsArr);
|
||||
} else {
|
||||
// 清除定時器
|
||||
if (timeoutTimer.value) {
|
||||
clearInterval(timeoutTimer.value);
|
||||
}
|
||||
}
|
||||
() => locale.value,
|
||||
() => {
|
||||
setItems(buttonItems.value);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
@ -111,18 +93,15 @@ watch(
|
||||
clearInterval(timeoutTimer.value);
|
||||
}
|
||||
|
||||
if (newValue?.key) {
|
||||
getData(newValue.key);
|
||||
// 重新設置定時器
|
||||
if (newValue?.key === 1 || newValue?.key === 2) {
|
||||
currentOptionType.value = newValue.key; // 1:溫度, 2:濕度
|
||||
getData(1); // tempOption 固定為 1
|
||||
timeoutTimer.value = setInterval(() => {
|
||||
getData(newValue.key);
|
||||
getData(1);
|
||||
}, 60 * 1000);
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
@ -170,7 +149,6 @@ watch(
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
// 清除定時器
|
||||
if (timeoutTimer.value) {
|
||||
clearInterval(timeoutTimer.value);
|
||||
}
|
||||
@ -178,17 +156,21 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h3 class="text-info text-xl text-center">溫度趨勢</h3>
|
||||
<h3 class="text-info text-xl text-center">
|
||||
{{ $t("dashboard.indoor_chart") }}
|
||||
</h3>
|
||||
<div className="my-3 w-full flex justify-center relative">
|
||||
<ButtonConnectedGroup
|
||||
:items="items"
|
||||
:onclick="
|
||||
(e, item) => {
|
||||
changeActiveBtn(item);
|
||||
}
|
||||
"
|
||||
:onclick="(e, item) => changeActiveBtn(item)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="noData"
|
||||
class="text-center text-white text-lg min-h-[260px] flex items-center justify-center"
|
||||
>
|
||||
無資料
|
||||
</div>
|
||||
<LineChart
|
||||
id="dashboard_other_real_temp"
|
||||
class="min-h-[260px] max-h-fit"
|
||||
|
@ -109,7 +109,7 @@ onMounted(() => {
|
||||
<div class="bg-slate-800 p-3">
|
||||
<div class="flex items-center">
|
||||
<div class="text-white mb-3 text-base">
|
||||
{{ $t("energy.monthly_carbon_emission_and_reduction") }}
|
||||
{{ $t("energy.daily_carbon_emission_and_reduction") }}
|
||||
</div>
|
||||
<CarbonEmissionModal
|
||||
:carbonData="carbonData"
|
||||
|
@ -3,7 +3,7 @@ import HistorySidebar from "./components/HistorySidebar.vue";
|
||||
import HistorySearch from "./components/HistorySearch.vue";
|
||||
import HistoryTable from "./components/HistoryTable.vue";
|
||||
import dayjs from "dayjs";
|
||||
import { ref, provide } from "vue";
|
||||
import { ref, provide, watch } from "vue";
|
||||
|
||||
const tableData = ref([]);
|
||||
const loading = ref(false);
|
||||
@ -21,6 +21,10 @@ provide("history_table_data", {
|
||||
loading,
|
||||
updateLoading,
|
||||
});
|
||||
|
||||
watch(tableData, (newVal) => {
|
||||
console.log("🔍 提供端 tableData 改變:", newVal);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -11,7 +11,6 @@ const { t } = useI18n();
|
||||
const { tableData } = inject("history_table_data");
|
||||
const history_chart = ref(null);
|
||||
|
||||
// 預設圖表選項
|
||||
const defaultChartOption = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
@ -51,7 +50,7 @@ const defaultChartOption = {
|
||||
formatter: (value) =>
|
||||
searchParams.value.Type == 2
|
||||
? dayjs(value).format("HH:mm")
|
||||
: dayjs(value).format("MM-DD"), // 格式化為時間
|
||||
: dayjs(value).format("MM-DD"),
|
||||
},
|
||||
data: [],
|
||||
},
|
||||
@ -59,15 +58,12 @@ const defaultChartOption = {
|
||||
type: "value",
|
||||
splitLine: { show: false },
|
||||
axisLabel: { color: "#ffffff" },
|
||||
// interval: 100, //Y 軸的刻度間隔
|
||||
min: "dataMin",
|
||||
max: "dataMax",
|
||||
// splitArea: { show: false },
|
||||
max: "dataMax",
|
||||
},
|
||||
series: [],
|
||||
};
|
||||
|
||||
// 格式化數據
|
||||
const formatChartData = (data) => {
|
||||
return data.reduce((acc, item) => {
|
||||
const seriesKey = `${item.device_name || ""}_${item.item_name || ""}`;
|
||||
@ -86,19 +82,33 @@ const formatChartData = (data) => {
|
||||
}, {});
|
||||
};
|
||||
|
||||
// 監聽 tableData,更新圖表
|
||||
watch(
|
||||
tableData,
|
||||
(newData) => {
|
||||
if (newData?.length > 0) {
|
||||
const formattedData = formatChartData(newData);
|
||||
|
||||
const xDataRaw = formattedData[Object.keys(formattedData)[0]].timestamps;
|
||||
const totalPoints = xDataRaw.length;
|
||||
const tickCount = 30;
|
||||
const interval = Math.max(1, Math.floor(totalPoints / (tickCount - 1)));
|
||||
const sampledTime = xDataRaw.filter((_, idx) => idx % interval === 0);
|
||||
if (sampledTime[sampledTime.length - 1] !== xDataRaw[totalPoints - 1]) {
|
||||
sampledTime.push(xDataRaw[totalPoints - 1]);
|
||||
}
|
||||
|
||||
const series = Object.keys(formattedData).map((seriesKey, index) => {
|
||||
const { maxValue, minValue, averageValue } = formattedData[seriesKey];
|
||||
const { timestamps, values, maxValue, minValue, averageValue } =
|
||||
formattedData[seriesKey];
|
||||
|
||||
const timeToValue = Object.fromEntries(
|
||||
timestamps.map((t, i) => [t, values[i]])
|
||||
);
|
||||
|
||||
return {
|
||||
name: seriesKey,
|
||||
type: "line",
|
||||
data: formattedData[seriesKey].values,
|
||||
data: sampledTime.map((t) => timeToValue[t] ?? null),
|
||||
showSymbol: false,
|
||||
itemStyle: {
|
||||
color: SECOND_CHART_COLOR[index % SECOND_CHART_COLOR.length],
|
||||
@ -127,7 +137,6 @@ watch(
|
||||
};
|
||||
});
|
||||
|
||||
// 更新圖表
|
||||
history_chart.value?.chart.setOption(
|
||||
{
|
||||
...defaultChartOption,
|
||||
@ -137,10 +146,7 @@ watch(
|
||||
},
|
||||
xAxis: {
|
||||
...defaultChartOption.xAxis,
|
||||
data:
|
||||
Object.keys(formattedData).length > 0
|
||||
? formattedData[Object.keys(formattedData)[0]].timestamps
|
||||
: [],
|
||||
data: sampledTime,
|
||||
},
|
||||
series,
|
||||
},
|
||||
@ -161,4 +167,4 @@ watch(
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped></style>
|
4949
stats.html
Normal file
4949
stats.html
Normal file
File diff suppressed because one or more lines are too long
@ -4,7 +4,7 @@ module.exports = {
|
||||
"./node_modules/vue-tailwind-datepicker/**/*.js",
|
||||
],
|
||||
purge: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
|
||||
darkMode: false, // or 'media' or 'class'
|
||||
darkMode: false,
|
||||
theme: {
|
||||
extend: {
|
||||
backgroundImage: {
|
||||
|
Loading…
Reference in New Issue
Block a user