diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..c3ed821
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,4 @@
+VITE_API_BASEURL = "https://ibms-Empower-api.production.mjmtech.com.tw"
+VITE_FILE_API_BASEURL = "https://ibms-Empower.production.mjmtech.com.tw"
+VITE_MQTT_BASEURL = "wss://mqttwss.mjm-staging.developers-homelab.net"
+VITE_FORGE_BASEURL = "https://ibms-Empower.production.mjmtech.com.tw/dist"
\ No newline at end of file
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..c3ed821
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,4 @@
+VITE_API_BASEURL = "https://ibms-Empower-api.production.mjmtech.com.tw"
+VITE_FILE_API_BASEURL = "https://ibms-Empower.production.mjmtech.com.tw"
+VITE_MQTT_BASEURL = "wss://mqttwss.mjm-staging.developers-homelab.net"
+VITE_FORGE_BASEURL = "https://ibms-Empower.production.mjmtech.com.tw/dist"
\ No newline at end of file
diff --git a/.env.staging b/.env.staging
new file mode 100644
index 0000000..3a51cfe
--- /dev/null
+++ b/.env.staging
@@ -0,0 +1,3 @@
+VITE_API_BASEURL = "http://220.132.206.5:8008"
+VITE_FILE_API_BASEURL = "http://220.132.206.5:8085/file"
+VITE_FORGE_BASEURL = "http://localhost:5173"
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..b6565d2
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+* text=auto
+*.html text eol=lf
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/README.md b/README.md
index c35f2a3..da868fb 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,3 @@
-# 新創賦能
+# 智慧倉儲物流
Node version: 18
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..2b7c391
--- /dev/null
+++ b/index.html
@@ -0,0 +1,26 @@
+
+
+
+
+ */
+:root {
+ --primary: #6fdda8;
+ --vt-c-white: #ffffff;
+ --vt-c-white-soft: #f8f8f8;
+ --vt-c-white-mute: #f2f2f2;
+
+ --vt-c-black: #181818;
+ --vt-c-black-soft: #222222;
+ --vt-c-black-mute: #282828;
+
+ --vt-c-indigo: #2c3e50;
+
+ --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
+ --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
+ --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
+ --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
+
+ --vt-c-text-light-1: var(--vt-c-indigo);
+ --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
+ --vt-c-text-dark-1: var(--vt-c-white);
+ --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
+}
+
+/* semantic color variables for this project */
+:root {
+ --color-background: var(--vt-c-white);
+ --color-background-soft: var(--vt-c-white-soft);
+ --color-background-mute: var(--vt-c-white-mute);
+
+ --color-border: var(--vt-c-divider-light-2);
+ --color-border-hover: var(--vt-c-divider-light-1);
+
+ --color-heading: var(--vt-c-text-light-1);
+ --color-text: var(--vt-c-text-dark-1);
+
+ --section-gap: 160px;
+
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --color-background: var(--vt-c-black);
+ --color-background-soft: var(--vt-c-black-soft);
+ --color-background-mute: var(--vt-c-black-mute);
+
+ --color-border: var(--vt-c-divider-dark-2);
+ --color-border-hover: var(--vt-c-divider-dark-1);
+
+ --color-heading: var(--vt-c-text-dark-1);
+ --color-text: var(--vt-c-text-dark-2);
+ }
+}
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+ margin: 0;
+ font-weight: normal;
+}
+
+body {
+ min-height: 100vh;
+ color: var(--color-text);
+ background: var(--color-background);
+ transition:
+ color 0.5s,
+ background-color 0.5s;
+ line-height: 1.6;
+ font-family:
+ Inter,
+ -apple-system,
+ BlinkMacSystemFont,
+ 'Segoe UI',
+ Roboto,
+ Oxygen,
+ Ubuntu,
+ Cantarell,
+ 'Fira Sans',
+ 'Droid Sans',
+ 'Helvetica Neue',
+ sans-serif;
+ font-size: 15px;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+
+}
diff --git a/src/assets/btn.css b/src/assets/btn.css
new file mode 100644
index 0000000..9071e94
--- /dev/null
+++ b/src/assets/btn.css
@@ -0,0 +1,56 @@
+/**區域框**/
+.area-box {
+ /* width: 100%; */
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ color: #fff;
+}
+
+.area-box .item {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ color: #fff;
+ margin: 0;
+}
+
+.area-box .item button:last-child::after {
+ display: none;
+}
+
+.area-box .item button::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: -15px;
+ margin: auto;
+ display: block;
+ width: 15px;
+ height: 1px;
+ background-color: #a1ffd6;
+ z-index: -1;
+}
+
+.area-box .item button {
+ position: relative;
+ z-index: 1;
+ border-radius: 5px;
+ margin: 0 7px;
+ background-color: #021422;
+ padding: 0.5rem 0;
+ min-width: 65px;
+ color: #fff;
+ border: 1px solid #a1ffd6 !important;
+ text-align: center;
+ margin-bottom: 15px;
+ padding: 0 5px;
+}
+
+.area-box .item button.active {
+ background-color: #6fdda8;
+ text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.9);
+ box-shadow: 0px 0px 5px rgba(255, 255, 255, 0.8);
+}
diff --git a/src/assets/img/area-img-box-line-bottom.png b/src/assets/img/area-img-box-line-bottom.png
new file mode 100644
index 0000000..021264a
Binary files /dev/null and b/src/assets/img/area-img-box-line-bottom.png differ
diff --git a/src/assets/img/area-img-box-line-top.png b/src/assets/img/area-img-box-line-top.png
new file mode 100644
index 0000000..d27e7ec
Binary files /dev/null and b/src/assets/img/area-img-box-line-top.png differ
diff --git a/src/assets/img/background.jpg b/src/assets/img/background.jpg
new file mode 100644
index 0000000..873a2f9
Binary files /dev/null and b/src/assets/img/background.jpg differ
diff --git a/src/assets/img/chart-data-background01.svg b/src/assets/img/chart-data-background01.svg
new file mode 100644
index 0000000..5668311
--- /dev/null
+++ b/src/assets/img/chart-data-background01.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/chart-data-background02.svg b/src/assets/img/chart-data-background02.svg
new file mode 100644
index 0000000..4ccfade
--- /dev/null
+++ b/src/assets/img/chart-data-background02.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/chart-data-background03.svg b/src/assets/img/chart-data-background03.svg
new file mode 100644
index 0000000..32d1f69
--- /dev/null
+++ b/src/assets/img/chart-data-background03.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/chart-title01.svg b/src/assets/img/chart-title01.svg
new file mode 100644
index 0000000..8421061
--- /dev/null
+++ b/src/assets/img/chart-title01.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/chart-title02.svg b/src/assets/img/chart-title02.svg
new file mode 100644
index 0000000..b49dea2
--- /dev/null
+++ b/src/assets/img/chart-title02.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/chart-title03.svg b/src/assets/img/chart-title03.svg
new file mode 100644
index 0000000..b935ccf
--- /dev/null
+++ b/src/assets/img/chart-title03.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/chart-title04.svg b/src/assets/img/chart-title04.svg
new file mode 100644
index 0000000..afa5774
--- /dev/null
+++ b/src/assets/img/chart-title04.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/equipment-item-background.svg b/src/assets/img/equipment-item-background.svg
new file mode 100644
index 0000000..69359bd
--- /dev/null
+++ b/src/assets/img/equipment-item-background.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/equipment-item-background04.svg b/src/assets/img/equipment-item-background04.svg
new file mode 100644
index 0000000..64b7d0d
--- /dev/null
+++ b/src/assets/img/equipment-item-background04.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/equipment-item-background05.svg b/src/assets/img/equipment-item-background05.svg
new file mode 100644
index 0000000..67e6cbc
--- /dev/null
+++ b/src/assets/img/equipment-item-background05.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/equipment/replay01.svg b/src/assets/img/equipment/replay01.svg
new file mode 100644
index 0000000..639e6eb
--- /dev/null
+++ b/src/assets/img/equipment/replay01.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/equipment/replay02.svg b/src/assets/img/equipment/replay02.svg
new file mode 100644
index 0000000..62e067b
--- /dev/null
+++ b/src/assets/img/equipment/replay02.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/equipment/state-background.svg b/src/assets/img/equipment/state-background.svg
new file mode 100644
index 0000000..8334698
--- /dev/null
+++ b/src/assets/img/equipment/state-background.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/equipment/state-title.svg b/src/assets/img/equipment/state-title.svg
new file mode 100644
index 0000000..6202385
--- /dev/null
+++ b/src/assets/img/equipment/state-title.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/equipment/table-item-w.svg b/src/assets/img/equipment/table-item-w.svg
new file mode 100644
index 0000000..74bbc0c
--- /dev/null
+++ b/src/assets/img/equipment/table-item-w.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
diff --git a/src/assets/img/item-data-left-2.svg b/src/assets/img/item-data-left-2.svg
new file mode 100644
index 0000000..33018f6
--- /dev/null
+++ b/src/assets/img/item-data-left-2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/item-data-left.svg b/src/assets/img/item-data-left.svg
new file mode 100644
index 0000000..24d1b55
--- /dev/null
+++ b/src/assets/img/item-data-left.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/item-data-right-2.svg b/src/assets/img/item-data-right-2.svg
new file mode 100644
index 0000000..9025333
--- /dev/null
+++ b/src/assets/img/item-data-right-2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/item-data-right.svg b/src/assets/img/item-data-right.svg
new file mode 100644
index 0000000..927beac
--- /dev/null
+++ b/src/assets/img/item-data-right.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/logo.png b/src/assets/img/logo.png
new file mode 100644
index 0000000..08837f4
Binary files /dev/null and b/src/assets/img/logo.png differ
diff --git a/src/assets/img/logo.svg b/src/assets/img/logo.svg
new file mode 100644
index 0000000..2ce49b1
--- /dev/null
+++ b/src/assets/img/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/pagination/small-btn.svg b/src/assets/img/pagination/small-btn.svg
new file mode 100644
index 0000000..4aab060
--- /dev/null
+++ b/src/assets/img/pagination/small-btn.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/pagination/small-btn02.svg b/src/assets/img/pagination/small-btn02.svg
new file mode 100644
index 0000000..131fed5
--- /dev/null
+++ b/src/assets/img/pagination/small-btn02.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/src/assets/img/state-box-bottom.png b/src/assets/img/state-box-bottom.png
new file mode 100644
index 0000000..cf28ba9
Binary files /dev/null and b/src/assets/img/state-box-bottom.png differ
diff --git a/src/assets/img/state-box-top.png b/src/assets/img/state-box-top.png
new file mode 100644
index 0000000..0d78c94
Binary files /dev/null and b/src/assets/img/state-box-top.png differ
diff --git a/src/assets/img/state-title01.svg b/src/assets/img/state-title01.svg
new file mode 100644
index 0000000..d91ac0d
--- /dev/null
+++ b/src/assets/img/state-title01.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/state-title02.svg b/src/assets/img/state-title02.svg
new file mode 100644
index 0000000..93ae18b
--- /dev/null
+++ b/src/assets/img/state-title02.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/state-ul-background01.svg b/src/assets/img/state-ul-background01.svg
new file mode 100644
index 0000000..717aee9
--- /dev/null
+++ b/src/assets/img/state-ul-background01.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/state-ul-background02.svg b/src/assets/img/state-ul-background02.svg
new file mode 100644
index 0000000..b2fbadb
--- /dev/null
+++ b/src/assets/img/state-ul-background02.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/state-ul-text.svg b/src/assets/img/state-ul-text.svg
new file mode 100644
index 0000000..74a702b
--- /dev/null
+++ b/src/assets/img/state-ul-text.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/img/state-ul.svg b/src/assets/img/state-ul.svg
new file mode 100644
index 0000000..302c130
--- /dev/null
+++ b/src/assets/img/state-ul.svg
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/table/content-box-background01.svg b/src/assets/img/table/content-box-background01.svg
new file mode 100644
index 0000000..ac04bca
--- /dev/null
+++ b/src/assets/img/table/content-box-background01.svg
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/table/content-box-background02.svg b/src/assets/img/table/content-box-background02.svg
new file mode 100644
index 0000000..634a8e7
--- /dev/null
+++ b/src/assets/img/table/content-box-background02.svg
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/table/content-box-background03.svg b/src/assets/img/table/content-box-background03.svg
new file mode 100644
index 0000000..325068e
--- /dev/null
+++ b/src/assets/img/table/content-box-background03.svg
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/table/content-box-background04.svg b/src/assets/img/table/content-box-background04.svg
new file mode 100644
index 0000000..3034171
--- /dev/null
+++ b/src/assets/img/table/content-box-background04.svg
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/table/content-box-background05.svg b/src/assets/img/table/content-box-background05.svg
new file mode 100644
index 0000000..a99f849
--- /dev/null
+++ b/src/assets/img/table/content-box-background05.svg
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/table/large-btn.svg b/src/assets/img/table/large-btn.svg
new file mode 100644
index 0000000..60f7df9
--- /dev/null
+++ b/src/assets/img/table/large-btn.svg
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/table/large-btn02.svg b/src/assets/img/table/large-btn02.svg
new file mode 100644
index 0000000..4ac0476
--- /dev/null
+++ b/src/assets/img/table/large-btn02.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/table/small-btn.svg b/src/assets/img/table/small-btn.svg
new file mode 100644
index 0000000..4aab060
--- /dev/null
+++ b/src/assets/img/table/small-btn.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/img/table/small-btn02.svg b/src/assets/img/table/small-btn02.svg
new file mode 100644
index 0000000..131fed5
--- /dev/null
+++ b/src/assets/img/table/small-btn02.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/src/assets/img/text-position-line.svg b/src/assets/img/text-position-line.svg
new file mode 100644
index 0000000..cec0432
--- /dev/null
+++ b/src/assets/img/text-position-line.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/index.css b/src/assets/index.css
new file mode 100644
index 0000000..eda00dd
--- /dev/null
+++ b/src/assets/index.css
@@ -0,0 +1,81 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer components {
+ .arrow {
+ @apply relative triangle flex justify-center items-center text-lg;
+ box-shadow: inset 0px 6px 10px -10px rgba(255, 255, 255, 0.8),
+ inset 0px -6px 10px -10px rgba(255, 255, 255, 0.8);
+ }
+
+ .triangle {
+ @apply after:block after:absolute after:bottom-0 after:left-[100%]
+ after:border-t-[1rem] after:border-b-[1rem] after:border-l-[2rem]
+ after:border-t-transparent after:border-b-transparent after:z-50;
+ }
+ .triangle-dark {
+ @apply after:border-l-info;
+ }
+
+ .triangle-light {
+ @apply after:border-l-success;
+ }
+ .item button {
+ @apply hover:bg-active !important;
+ }
+ /* table */
+ .content-box-background {
+ background: linear-gradient(
+ 180deg,
+ rgba(127, 237, 193, 0.1),
+ rgba(0, 0, 0, 0),
+ rgba(127, 237, 193, 0.1)
+ );
+ }
+}
+
+@layer utilities {
+ .btn{
+ @apply whitespace-nowrap px-4 py-1;
+ text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.9);
+ box-shadow: 0px 0px 5px rgba(255, 255, 255, 0.8);
+ }
+
+ .btn-success {
+ @apply text-white border border-active bg-active hover:bg-[theme("colors.green.500")]
+ }
+
+ .btn-info {
+ @apply text-white border border-info bg-info hover:bg-[theme("colors.sky.400")]
+ }
+
+ .btn-outline-success {
+ @apply text-white border border-active hover:bg-active bg-transparent
+ }
+
+ .btn-outline-info {
+ @apply text-white border border-info hover:bg-info bg-transparent
+ }
+
+ .custom-border {
+ @apply border border-info rounded-md;
+ }
+
+ .btn-text-without-border {
+ @apply active:border-0 focus:border-0 focus-visible:border-0 active:outline-none focus:outline-none focus-visible:outline-none;
+ }
+
+ .btn-add {
+ @apply text-white border border-cyan-400 bg-cyan-400 hover:bg-[theme("colors.cyan.500")]
+ }
+
+ .btn-search {
+ @apply text-white border border-sky-400 bg-sky-400 hover:bg-[theme("colors.sky.500")]
+ }
+
+ .btn-export {
+ @apply text-white border border-emerald-400 bg-emerald-400 hover:bg-[theme("colors.emerald.500")]
+ }
+
+}
\ No newline at end of file
diff --git a/src/assets/logo.svg b/src/assets/logo.svg
new file mode 100644
index 0000000..b6cd190
--- /dev/null
+++ b/src/assets/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/main.css b/src/assets/main.css
new file mode 100644
index 0000000..563f00d
--- /dev/null
+++ b/src/assets/main.css
@@ -0,0 +1,29 @@
+@import "./base.css";
+
+#app {
+ overflow: hidden;
+ font-weight: normal;
+ background-color: theme("colors.body");
+ background-image: url("./img/background.jpg");
+ background-size: cover;
+ color: #fff;
+ min-height: 100dvh;
+}
+
+::-webkit-scrollbar {
+ width: 5px !important;
+ height: 8px !important;
+}
+
+/* Track */
+::-webkit-scrollbar-track {
+ box-shadow: inset 0 0 5px grey;
+ border-radius: 10px;
+}
+
+/* Handle */
+::-webkit-scrollbar-thumb {
+ background: theme("colors.info");
+ border-radius: 10px;
+ box-shadow: theme("boxShadow.custom");
+}
diff --git a/src/assets/pagination.css b/src/assets/pagination.css
new file mode 100644
index 0000000..e5369ab
--- /dev/null
+++ b/src/assets/pagination.css
@@ -0,0 +1,40 @@
+.page-box ul {
+ display: flex;
+ justify-content: flex-end;
+ flex-wrap: wrap;
+ font-size: 1rem;
+ color: #fff;
+ margin-bottom: 10px;
+}
+
+.page-box ul li {
+ padding: 10px;
+ white-space: nowrap;
+ cursor: pointer;
+}
+
+
+.page-box ul .ant-pagination-item {
+ background-image: url(./img/pagination/small-btn.svg);
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: contain;
+ padding: 10px 15px 10px 25px;
+ background-color: transparent;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: none;
+}
+
+.page-box ul .ant-pagination-item.ant-pagination-item-active {
+ background-image: url(./img/pagination/small-btn02.svg);
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: contain;
+ padding: 10px 15px 10px 25px;
+}
+
+.page-box .ant-pagination-item a {
+ color: #fff;
+}
diff --git a/src/assets/table.css b/src/assets/table.css
new file mode 100644
index 0000000..30adf55
--- /dev/null
+++ b/src/assets/table.css
@@ -0,0 +1,122 @@
+/**資料框**/
+.ant-table {
+ width: 100%;
+ margin-bottom: 1rem;
+ background-color: transparent !important;
+ color: white;
+}
+.ant-table::-webkit-scrollbar-thumb {
+ background-color: theme("colors.info") !important;
+}
+
+.ant-table th.ant-table-cell::before{
+ height: 100% !important;
+}
+
+.content-box {
+ border: 1px solid #35eded;
+ padding: 5px;
+ position: relative;
+ margin-bottom: 15px;
+ background-color: theme("colors.body");
+}
+
+.content-box table,
+.content-box table th {
+ border-radius: 0 !important;
+}
+
+.content-box .ant-table th.ant-table-cell,
+.content-box .ant-table td.ant-table-cell {
+ border-color: #fff !important;
+ color: #fff !important;
+ font-size: 1rem !important;
+ font-weight: 300 !important;
+ border-right: 1px solid #fff !important;
+ text-align: center !important;
+ padding: 0.5rem 0.75rem !important;
+ background-color: transparent !important;
+}
+
+.content-box .ant-table th.ant-table-cell.ant-table-cell-fix-left,
+.content-box .ant-table th.ant-table-cell.ant-table-cell-fix-right {
+ background-color: theme("colors.body") !important;
+ color: white;
+}
+
+.content-box .ant-table th.ant-table-cell {
+ border-bottom: 1px solid #e9e9e9 !important;
+}
+
+.content-box .ant-table tr td:last-child,
+.content-box .ant-table tr:first-child th:last-child {
+ border-right: 0 !important;
+}
+.content-box .ant-table tr:last-child td {
+ border-bottom: 0 !important;
+}
+
+/**資料框裝飾**/
+.content-box::before {
+ content: "" !important;
+ background: url(./img/table/content-box-background01.svg) center center !important;
+ position: absolute !important;
+ left: 4px !important;
+ top: 4px !important;
+ height: 20px !important;
+ width: 20px !important;
+ background-repeat: no-repeat !important;
+ z-index: 1 !important;
+}
+
+.content-box::after {
+ content: "" !important;
+ background: url(./img/table/content-box-background05.svg) center center !important;
+ position: absolute !important;
+ right: 4px !important;
+ bottom: 4px !important;
+ height: 20px !important;
+ width: 20px !important;
+ background-repeat: no-repeat !important;
+ z-index: 3 !important;
+}
+
+.content-box .page-box::before {
+ content: "" !important;
+ background: url(./img/table/content-box-background03.svg) center center !important;
+ position: absolute !important;
+ left: -1.2% !important;
+ bottom: -2px !important;
+ height: 56px !important;
+ width: 30px !important;
+ background-repeat: no-repeat !important;
+ z-index: 2 !important;
+}
+
+.content-box .page-box::after {
+ content: "" !important;
+ background: url(./img/table/content-box-background04.svg) center center !important;
+ position: absolute !important;
+ right: -27px !important;
+ bottom: -7px !important;
+ height: 65px !important;
+ width: 50px !important;
+ background-repeat: no-repeat !important;
+ z-index: 2 !important;
+}
+
+.content-box .content-decoration {
+ @apply px-2;
+}
+
+.content-box .content-decoration::before {
+ content: "" !important;
+ background: url(./img/table/content-box-background02.svg) center center !important;
+ position: absolute !important;
+ right: -10px !important;
+ top: -10px !important;
+ height: 30px !important;
+ width: 29px !important;
+ background-repeat: no-repeat !important;
+ z-index: 1 !important;
+}
diff --git a/src/components/Loading.vue b/src/components/Loading.vue
new file mode 100644
index 0000000..6ad4f0d
--- /dev/null
+++ b/src/components/Loading.vue
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
diff --git a/src/components/SvgIcon.vue b/src/components/SvgIcon.vue
new file mode 100644
index 0000000..ecf5446
--- /dev/null
+++ b/src/components/SvgIcon.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/alarm/AlarmCards.vue b/src/components/alarm/AlarmCards.vue
new file mode 100644
index 0000000..f675f44
--- /dev/null
+++ b/src/components/alarm/AlarmCards.vue
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t("alarm.notify") }}
+
+ {{ alarm.created_at }}
+
+
+
+
+
+
{{ $t("alarm.number") }}:{{ alarm.id }}
+
{{ $t("alert.alarmClass") }}:{{ alarm.factor }}
+
{{ $t("alarm.device_name") }}:{{ alarm.device_number }}
+
{{ $t("alert.device_point_name") }}:{{ alarm.points }}
+
{{ $t("alert.error_msg") }}:{{ alarm.reason }}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/alarm/AlarmDrawer.vue b/src/components/alarm/AlarmDrawer.vue
new file mode 100644
index 0000000..54438a9
--- /dev/null
+++ b/src/components/alarm/AlarmDrawer.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+ {{ $t("alarm.title") }}
+
+
+
+
+
+
+
diff --git a/src/components/chart/BarChart.vue b/src/components/chart/BarChart.vue
new file mode 100644
index 0000000..983732a
--- /dev/null
+++ b/src/components/chart/BarChart.vue
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
diff --git a/src/components/chart/EffectScatter.vue b/src/components/chart/EffectScatter.vue
new file mode 100644
index 0000000..9f122f1
--- /dev/null
+++ b/src/components/chart/EffectScatter.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
diff --git a/src/components/chart/GaugeChart.vue b/src/components/chart/GaugeChart.vue
new file mode 100644
index 0000000..da53127
--- /dev/null
+++ b/src/components/chart/GaugeChart.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
+
diff --git a/src/components/chart/LineChart.vue b/src/components/chart/LineChart.vue
new file mode 100644
index 0000000..da53127
--- /dev/null
+++ b/src/components/chart/LineChart.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
+
diff --git a/src/components/chart/SankeyChart.vue b/src/components/chart/SankeyChart.vue
new file mode 100644
index 0000000..557d51e
--- /dev/null
+++ b/src/components/chart/SankeyChart.vue
@@ -0,0 +1,31 @@
+
+
+
+
+
+
diff --git a/src/components/customUI/ButtonConnectedGroup.vue b/src/components/customUI/ButtonConnectedGroup.vue
new file mode 100644
index 0000000..67880cc
--- /dev/null
+++ b/src/components/customUI/ButtonConnectedGroup.vue
@@ -0,0 +1,52 @@
+
+
+
+
+ {
+ item.onClick ? item.onClick(e, item) : onclick(e, item);
+ }
+ "
+ >
+
+ {{ item.title }}
+
+
+
+
+
+
diff --git a/src/components/customUI/ButtonGroup.vue b/src/components/customUI/ButtonGroup.vue
new file mode 100644
index 0000000..5235a03
--- /dev/null
+++ b/src/components/customUI/ButtonGroup.vue
@@ -0,0 +1,53 @@
+
+
+
+
+ {
+ item.onClick ? item.onClick(e, item) : onclick(e, item);
+ }
+ "
+ >
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
diff --git a/src/components/customUI/Checkbox.vue b/src/components/customUI/Checkbox.vue
new file mode 100644
index 0000000..2f28bfc
--- /dev/null
+++ b/src/components/customUI/Checkbox.vue
@@ -0,0 +1,65 @@
+
+
+
+
+ {
+ onClick && onClick();
+ }
+ "
+ @change.stop.prevent="
+ (e) => {
+ console.log('@', e.target.value, e.target.checked);
+ onChange && onChange(e.target.value, e.target.checked);
+ }
+ "
+ />
+
+ {{ title }}
+
+
+
+
diff --git a/src/components/customUI/Collapse.vue b/src/components/customUI/Collapse.vue
new file mode 100644
index 0000000..2b9a911
--- /dev/null
+++ b/src/components/customUI/Collapse.vue
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+ {{ d.title }}
+
+
+
+
+
+
+
+
diff --git a/src/components/customUI/DateGroup.vue b/src/components/customUI/DateGroup.vue
new file mode 100644
index 0000000..91e2263
--- /dev/null
+++ b/src/components/customUI/DateGroup.vue
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/customUI/DraggableTable.vue b/src/components/customUI/DraggableTable.vue
new file mode 100644
index 0000000..965bca2
--- /dev/null
+++ b/src/components/customUI/DraggableTable.vue
@@ -0,0 +1,436 @@
+
+
+
+
+
+
+
+ {{ isDraggable ? "開始排序" : "完成排序" }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/customUI/Dropdown.vue b/src/components/customUI/Dropdown.vue
new file mode 100644
index 0000000..78f5453
--- /dev/null
+++ b/src/components/customUI/Dropdown.vue
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
diff --git a/src/components/customUI/FileSystemCollapse.vue b/src/components/customUI/FileSystemCollapse.vue
new file mode 100644
index 0000000..7b058b0
--- /dev/null
+++ b/src/components/customUI/FileSystemCollapse.vue
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+
diff --git a/src/components/customUI/Input.vue b/src/components/customUI/Input.vue
new file mode 100644
index 0000000..885cbe2
--- /dev/null
+++ b/src/components/customUI/Input.vue
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/customUI/InputNumber.vue b/src/components/customUI/InputNumber.vue
new file mode 100644
index 0000000..4bc9ea4
--- /dev/null
+++ b/src/components/customUI/InputNumber.vue
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/customUI/Menu.vue b/src/components/customUI/Menu.vue
new file mode 100644
index 0000000..054a6a3
--- /dev/null
+++ b/src/components/customUI/Menu.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+ menuCheck(item.id)"
+ />
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
diff --git a/src/components/customUI/Modal.vue b/src/components/customUI/Modal.vue
new file mode 100644
index 0000000..aa2d5a7
--- /dev/null
+++ b/src/components/customUI/Modal.vue
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/customUI/Pagination.vue b/src/components/customUI/Pagination.vue
new file mode 100644
index 0000000..d95ed64
--- /dev/null
+++ b/src/components/customUI/Pagination.vue
@@ -0,0 +1,200 @@
+
+
+
+
+
+ {
+ choosePage(currentPage - 1 > 0 ? currentPage - 1 : 1);
+ }
+ "
+ >
+
+
+
+
+ {
+ choosePage(page);
+ }
+ "
+ >
+
+
+
+
+
+ {{ dataSource.length }} {{ $t("table.in_otal") }}
+
+ {
+ choosePage(e.target.value);
+ }
+ "
+ />
+
+
+ {{ totalItems || dataSource.length }} {{ $t("table.in_otal") }}
+
+
+ {
+ choosePage(totalPage - index);
+ }
+ "
+ >
+
+
+
+
+ {
+ choosePage(
+ currentPage + 1 <= totalPage ? currentPage + 1 : totalPage
+ );
+ }
+ "
+ >
+
+
+
+
+
diff --git a/src/components/customUI/RadioGroup.vue b/src/components/customUI/RadioGroup.vue
new file mode 100644
index 0000000..f0ed74a
--- /dev/null
+++ b/src/components/customUI/RadioGroup.vue
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
diff --git a/src/components/customUI/SearchSelect.vue b/src/components/customUI/SearchSelect.vue
new file mode 100644
index 0000000..ae493eb
--- /dev/null
+++ b/src/components/customUI/SearchSelect.vue
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+ {} : (isOpen = !isOpen)"
+ >
+ {{ selectedOption ? selectedOption[Attribute] : "" }}
+
+
+
+
+
+
+
+ {{ option[Attribute] || option }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/customUI/Select.vue b/src/components/customUI/Select.vue
new file mode 100644
index 0000000..41166bc
--- /dev/null
+++ b/src/components/customUI/Select.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+ {
+ console.log(e.target.value);
+ props.onChange && props.onChange(e.target.value);
+ }
+ "
+ v-model="value[name]"
+ :required="required"
+ :readonly="readonly"
+ >
+
+
+ {{ option[Attribute] || option }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/customUI/Table.vue b/src/components/customUI/Table.vue
new file mode 100644
index 0000000..6914810
--- /dev/null
+++ b/src/components/customUI/Table.vue
@@ -0,0 +1,410 @@
+
+
+
+
+
+
+
diff --git a/src/components/customUI/Textarea.vue b/src/components/customUI/Textarea.vue
new file mode 100644
index 0000000..e14f010
--- /dev/null
+++ b/src/components/customUI/Textarea.vue
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/customUI/Toast.vue b/src/components/customUI/Toast.vue
new file mode 100644
index 0000000..cf312e9
--- /dev/null
+++ b/src/components/customUI/Toast.vue
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
{{ content }}
+
+ {{$t("button.cancel")}}
+ {{$t("button.confirm")}}
+
+
+
+
+
+
+
diff --git a/src/components/customUI/Upload.vue b/src/components/customUI/Upload.vue
new file mode 100644
index 0000000..37ff0a8
--- /dev/null
+++ b/src/components/customUI/Upload.vue
@@ -0,0 +1,307 @@
+
+
+
+
+ {}">
+
+
+
+
+
+
+
+
+ {
+ removeFile(file.key || file.id || file.lastModified);
+ }
+ "
+ >
+
+
+ createPreviewFileURL(file)"
+ >
+
+
revokeURL(file.src)"
+ alt=""
+ />
+
+
+ createPreviewFileURL(file)"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ (file.size / 1000).toFixed(1) }} KB
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t("upload.title") }}
+
{{ $t("upload.description") }}
+
+ {{ $t("upload.formats") }} : {{ props.formats }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/forge/Forge.vue b/src/components/forge/Forge.vue
new file mode 100644
index 0000000..e55b62d
--- /dev/null
+++ b/src/components/forge/Forge.vue
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
diff --git a/src/components/forge/ForgeForSystem.vue b/src/components/forge/ForgeForSystem.vue
new file mode 100644
index 0000000..4c9bb8a
--- /dev/null
+++ b/src/components/forge/ForgeForSystem.vue
@@ -0,0 +1,282 @@
+
+
+
+
+
+
+
+ {{ value }} {{
+ store.heatmapConfig?.unit }}
+
+
+
+
+
+
+
+
+ getCurrentInfoModalData(
+ e,
+ { left: e.clientX, top: e.clientY },
+ value
+ )
+ ">
+ {{ value.full_name }}
+ {{ value.alarmMsg }}
+ {{ value.show_value }}
+
+
+
+
+
+
diff --git a/src/components/forge/ForgeModal.vue b/src/components/forge/ForgeModal.vue
new file mode 100644
index 0000000..df4a248
--- /dev/null
+++ b/src/components/forge/ForgeModal.vue
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+ {{ modalContent?.full_name }}
+
+
changeOpenKey('leaf')"
+ >
+
+
+
changeOpenKey('desktop')"
+ >
+
+
+
changeOpenKey('cog')"
+ >
+
+
+
changeOpenKey('triangle')"
+ >
+
+
+
changeOpenKey('bars')"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/forge/ForgeModalContent.vue b/src/components/forge/ForgeModalContent.vue
new file mode 100644
index 0000000..b83816f
--- /dev/null
+++ b/src/components/forge/ForgeModalContent.vue
@@ -0,0 +1,223 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 設備編號
+
+ {{ modalContent?.device_number }}
+
+
+
+ 設備名稱
+
+ {{ modalContent?.full_name }}
+
+
+
+
+
+
+
+
+
+
冷媒: R-22
+
設備逸散率: 0.16
+
GWP: 1530
+
+
+
+
+
+
+
+
diff --git a/src/components/forge/index.vue b/src/components/forge/index.vue
new file mode 100644
index 0000000..a9f0e80
--- /dev/null
+++ b/src/components/forge/index.vue
@@ -0,0 +1,270 @@
+
+
+
+
+
+
+
+
diff --git a/src/components/navbar/Navbar.vue b/src/components/navbar/Navbar.vue
new file mode 100644
index 0000000..4a0c8e7
--- /dev/null
+++ b/src/components/navbar/Navbar.vue
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+ 新創賦能
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/navbar/NavbarBuilding.vue b/src/components/navbar/NavbarBuilding.vue
new file mode 100644
index 0000000..05238ac
--- /dev/null
+++ b/src/components/navbar/NavbarBuilding.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+ {{ store.selectedBuilding?.full_name }}
+
+
+
+
+ {{ bui.full_name }}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/navbar/NavbarItem.vue b/src/components/navbar/NavbarItem.vue
new file mode 100644
index 0000000..15e2d6c
--- /dev/null
+++ b/src/components/navbar/NavbarItem.vue
@@ -0,0 +1,218 @@
+
+
+
+
+
+
+
+ {
+ onClose();
+ closeDrawer();
+ }
+ "
+ >
+
+ {{ sub.full_name }}
+
+
+
+
+
+
+
diff --git a/src/components/navbar/NavbarLang.vue b/src/components/navbar/NavbarLang.vue
new file mode 100644
index 0000000..bff9147
--- /dev/null
+++ b/src/components/navbar/NavbarLang.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+ {{ $t("language") }}
+
+
+
+ 繁體中文
+
+
+ 简体中文
+
+
+ English
+
+
+
+
+
+
diff --git a/src/components/navbar/NavbarUser.vue b/src/components/navbar/NavbarUser.vue
new file mode 100644
index 0000000..5e31aeb
--- /dev/null
+++ b/src/components/navbar/NavbarUser.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+ {{ user || "webUser" }}
+
+
+
+
+
+
diff --git a/src/config/cn.json b/src/config/cn.json
new file mode 100644
index 0000000..afae1a9
--- /dev/null
+++ b/src/config/cn.json
@@ -0,0 +1,422 @@
+{
+ "language": "简体中文",
+ "home": "首页",
+ "sign_out": "登出",
+ "log_in": "登入",
+ "account": "帐号",
+ "password": "密码",
+ "table": {
+ "no_data": "表中数据为空",
+ "in_otal": "笔资料",
+ "skip_to": "跳至"
+ },
+ "upload": {
+ "title": "选择一个文件或拖放到这里",
+ "description": "档案不超过 10MB",
+ "formats": "档案格式"
+ },
+ "dashboard": {
+ "production_quantity": "生产量",
+ "today_production_rate": "今日生产完成率",
+ "yesterday_today": "昨天/今天",
+ "elec_consumption_comparison": "用电量比较",
+ "elec_consumption_comparison_trend": "用电量比较趋势",
+ "electricity_consumption": "用电量",
+ "today_electricity_consumption": "今日用电量",
+ "yesterday_electricity_consumption": "昨天用电量",
+ "this_last_week": "本周/上周",
+ "thisweek_electricity_consumption": "本周用电量",
+ "lastweek_electricity_consumption": "上周用电量",
+ "one_hour": "1小时",
+ "four_hour": "4小时",
+ "eight_hour": "8小时",
+ "energy_ranking": "能耗排行",
+ "last_30_days_energy_trend": "近30天能耗趋势",
+ "today_energy_consumption": "本日能耗",
+ "this_month_energy_consumption": "本月能耗",
+ "relative_energy_consumption": "环比能耗",
+ "daily_relative_change": "日环比",
+ "weekly_relative_change": "周环比",
+ "monthly_relative_change": "月环比",
+ "yearly_relative_change": "年环比",
+ "today": "今日",
+ "yesterday": "昨日",
+ "this_week": "本周",
+ "last_week": "上周",
+ "this_month": "本月",
+ "last_month": "上月",
+ "this_year": "今年",
+ "last_year": "去年",
+ "refrig_chart": "冷藏趨勢",
+ "indoor_chart": "室內",
+ "temperature": "温度",
+ "humidity": "湿度",
+ "no_data":"无数据",
+ "alerts_data": "异常资料"
+ },
+ "history": {
+ "title": "历史资料",
+ "building_name": "厂区",
+ "device_name": "设备名称",
+ "system_category": "系统类别",
+ "device_category": "设备类别",
+ "category": "类别",
+ "value": "数值",
+ "date": "记录时间",
+ "point": "点位",
+ "combinations": "常用组合",
+ "date_range": "日期区间",
+ "time_range": "时间区间",
+ "start_date": "起始日期",
+ "start_time": "起始时间",
+ "end_date": "结束日期",
+ "end_time": "结束时间"
+ },
+ "system": {
+ "status": "状态",
+ "details": "详细资料",
+ "attribute": "属性",
+ "value": "值"
+ },
+ "energy": {
+ "elec_consumption": "用电即时分布",
+ "total_elec": "总用电",
+ "green_elec": "绿电",
+ "immediate_demand": "即时需量",
+ "average_demand": "平均需量",
+ "real_time_Trend": "即时趋势",
+ "contract_capacity": "契约容量",
+ "alert_capacity": "警戒容量",
+ "reset_value": "复归值",
+ "edit_automatic_demand": "编辑自动需量",
+ "elec_bills": "今年电费累计(元)",
+ "interval_elec_charges": "区间电费(元)",
+ "year_carbon_emission": "今年碳排当量累计(公斤)",
+ "interval_carbon_emission": "区间碳排当量",
+ "year_elec_consumption": "今年用电度数(kWh)",
+ "interval_elec_consumption": "区间用电度数(kWh)",
+ "monthly_elec_consumption": "每月用电分析",
+ "daily_carbon_emission_and_reduction": "每日碳排当量 (kgCO2e)",
+ "monthly_bill_power": "每月计费度数 (kWh)",
+ "interval_bill_degree": "区间计费度数",
+ "peak": "尖峰",
+ "semi_peak": "半尖峰",
+ "off_peak": "离峰",
+ "var_elec_cost": "流动电费",
+ "fixed_elec_cost": "基本电费",
+ "total_elec_cost": "总电费",
+ "carbon_equivalent": "碳排当量",
+ "edit_carbon_emission": "编辑碳排放系数",
+ "carbon_emission_coefficient": "碳排放系数",
+ "electricity_classification": "用电分类",
+ "electricity_price": "电费每度单价",
+ "floor": "楼层",
+ "maximum": "最大值",
+ "maximum_time": "最大值时间",
+ "minimum": "最小值",
+ "minimum_time": "最小值时间",
+ "average_value": "平均值",
+ "start_value": "起始值(kWh)",
+ "end_value": "截止值(kWh)",
+ "difference": "差值(kWh)",
+ "power_consumption": "用电量(kWh)",
+ "ranking": "排名",
+ "subtotal": "小计",
+ "unit_price": "单价",
+ "total_amount": "金额总计",
+ "elec_price_list": "电价表",
+ "residential": "住宅型",
+ "standard": "标准型",
+ "simple_elec_price_two_stage": "简易型时间电价二段式",
+ "simple_elec_price_three_stage": "简易型时间电价三段式",
+ "classification": "分类",
+ "summer_months": "夏月",
+ "non_summer_months": "非夏月",
+ "time_outside_summer_months": "夏月以外的时间",
+ "basic_elec_charge": "基本电费",
+ "charged_per_household": "按户计收",
+ "per_household_month": "每户每月",
+ "mon_to_friday": "周一~周五",
+ "peak_hours": "尖峰时间",
+ "semi_peak_hours": "半尖峰时间",
+ "off_peak_hours": "离峰时间",
+ "price_per_kwh": "每度",
+ "all_day": "全日",
+ "sat_sun_off_peak_days": "周六、周日及离峰日",
+ "usage_over_2000kwh": "每月总度数超过2000度之部分",
+ "add": "加",
+ "standard_time_of_use_tariff_2_stage": "标准型时间电价二段式",
+ "standard_time_of_use_tariff_3_stage": "标准型时间电价三段式",
+ "single_phase": "单相",
+ "three_phase": "三相",
+ "frequent_contract": "经常契约",
+ "per_kw_per_month": "每瓩每月",
+ "non_summer_contract": "非夏日契约",
+ "saturday_semi_peak_contract": "周六半尖峰契约",
+ "off_peak_contract": "离峰契约",
+ "variable_electricity_charge": "流动电费",
+ "saturday": "周六",
+ "sunday_and_off_peak_days": "周日及离峰日",
+ "latest_elec_consumption": "最新用电度数",
+ "daily_elec": "每日用电度数",
+ "line_voltage": "线电压",
+ "electric_current": "电流",
+ "monthly_elec_bill": "每月电费分析"
+ },
+ "alarm": {
+ "title": "显示警告",
+ "notify": "异常通知",
+ "number": "异常ID",
+ "category": "异常类别",
+ "device_name": "设备名称",
+ "message": "异常讯息",
+ "confirm": "确认"
+ },
+ "alert": {
+ "query_title": "告警纪录查询",
+ "setting_title": "告警设定",
+ "offnormal": "未复归",
+ "normal": "已复归",
+ "unacked": "未确认",
+ "acked": "已确认",
+ "30days": "近30天",
+ "start_date": "起始日期",
+ "end_date": "结束日期",
+ "building_and_floor": "栋别-楼层",
+ "uuid": "异常ID",
+ "alarmClass": "告警条件",
+ "device_name": "设备名称",
+ "device_number": "设备编号",
+ "device_point_name": "点位名称",
+ "date": "发生日期",
+ "time": "发生时间",
+ "error_msg": "异常原因",
+ "ack_state": "Ack 确认",
+ "repair_order_number": "派工 / 维运单号",
+ "repair_order": "维修单",
+ "form_number": "表单编号",
+ "start_time": "预计开始时间",
+ "item": "项目",
+ "maintainance": "保养",
+ "repair": "维修",
+ "repair_item": "维修项目",
+ "repair_item_code": "维修项目代码(设备编号)",
+ "responsible_vendor": "负责厂商",
+ "status": "状态",
+ "not_completed": "未完成",
+ "completed": "已完成",
+ "worker_id": "工作人员编号",
+ "notice": "注意事项",
+ "result_description": "结果描述",
+ "upload_file": "上传文件",
+ "enable": "启用",
+ "not_enabled": "不启用",
+ "qualifications": "限定条件",
+ "upper_limit": "上限",
+ "lower_limit": "下限",
+ "delay": "持续秒数",
+ "highDelay": "上限持续秒数",
+ "lowDelay": "下限持续秒数",
+ "warning_method": "警示方式",
+ "warning_time": "警示时间",
+ "warning_value": "警示值",
+ "operation": "功能",
+ "alarm_settings": "异常设定",
+ "time_setting": "时间设定",
+ "yes": "是",
+ "no": "否",
+ "no_notify": "无通知",
+ "notify_name": "姓名",
+ "notify_phone": "手机号码",
+ "notify_email": "email",
+ "notify_items": "通知项目",
+ "notify_list": "通知名单",
+ "choose": "选择",
+ "day_time": "星期/时间",
+ "click_time_period": "请用滑鼠点击时间段",
+ "clear": "清空",
+ "sunday": "星期日",
+ "monday": "星期一",
+ "tuesday": "星期二",
+ "wednesday": "星期三",
+ "thursday": "星期四",
+ "friday": "星期五",
+ "saturday": "星期六",
+ "schedule_name": "时段名称",
+ "schedule_content": "时段内容",
+ "reorganization": "MQTT 告警重整"
+ },
+ "operation": {
+ "title": "运维管理",
+ "project": "项目",
+ "location": "位置",
+ "uuid": "异常ID",
+ "form_number": "表单编号",
+ "device_name": "设备名称",
+ "status": "狀態",
+ "staff": "处理人员",
+ "start_time": "预计开始时间",
+ "upload": "档案上传",
+ "finish_time": "完成时间",
+ "updated_time": "更新时间",
+ "operation": "功能",
+ "vendor": "厂商",
+ "contact_person": "联络人",
+ "phone": "电话",
+ "email": "email",
+ "created_at": "建立日期",
+ "maintenance": "保养",
+ "repair": "维修",
+ "company_info": "厂商资料",
+ "repair_item": "维修项目",
+ "repair_item_code": "维修项目代码(设备编号)",
+ "responsible_vendor": "负责厂商",
+ "not_completed": "未完成",
+ "completed": "已完成",
+ "worker_id": "工作人员编号",
+ "notice": "注意事项",
+ "result_description": "结果描述",
+ "upload_file": "上传文件",
+ "name": "姓名",
+ "city": "城市",
+ "address": "地址",
+ "tax_id_number": "统一编号",
+ "remark": "备注",
+ "date": "日期",
+ "time": "时间",
+ "serial": "单号",
+ "today": "今天",
+ "yesterday": "昨天",
+ "start_created_at": "起始日期",
+ "end_created_at": "结束日期",
+ "enter_text": "请输入文字",
+ "enter_serial": "请输入单号"
+ },
+ "graphManagement": {
+ "title": "图资管理",
+ "category": "图资类别",
+ "new_category": "新类别",
+ "index": "编号",
+ "oriOrgName": "档案",
+ "operation": "功能",
+ "folder_path": "资料夹路径",
+ "upload": "图资上传",
+ "staging_area": "删除暂存区",
+ "no_path": "无资料夹路径"
+ },
+ "assetManagement": {
+ "title": "资产管理",
+ "add_system_category": "新增系统类别",
+ "edit_system_category": "修改系统类别",
+ "add_device_category": "新增设备类别",
+ "edit_device_category": "修改设备类别",
+ "system_name": "名称",
+ "system_value": "代号",
+ "system_parent": "所属系統",
+ "device_number": "设备编号",
+ "device_name": "设备名称",
+ "asset_number": "资产编号",
+ "floor": "设备位置",
+ "add_floor": "新增楼层",
+ "add_floor_text": "须先上传楼层地图",
+ "device_coordinate": "图面标识",
+ "brand_and_modal": "品牌 / 型号",
+ "brand": "品牌",
+ "modal": "型号",
+ "company_and_contact": "厂商 / 联络人",
+ "company": "负责厂商",
+ "buying_date": "建置时间",
+ "oriFile": "档案上传",
+ "created_at": "建立时间",
+ "operation": "功能",
+ "device_list": "设备列表",
+ "edit_device": "编辑设备",
+ "add_device": "新增设备",
+ "operate_text": "显示名称",
+ "fill_text": "请由系统人员填写",
+ "equipment_point": "设备点位",
+ "point": "点位",
+ "add_sensor": "新增感测器",
+ "associated_device": "关联设备",
+ "choose": "选择",
+ "index": "编号",
+ "floor_plan": "平面图",
+ "department": "部门",
+ "department_name": "部门名称",
+ "building": "栋别"
+ },
+ "accountManagement": {
+ "account_title": "帐号管理",
+ "role_title": "角色管理",
+ "index": "编号",
+ "name": "姓名",
+ "account": "帐号",
+ "password": "密码",
+ "role": "角色",
+ "role_name": "角色名称",
+ "role_permissions": "角色权限",
+ "role_permissions_setting": "角色权限设定",
+ "permission_name": "权限名称",
+ "basic_permissions": "基础权限",
+ "production_permissions": "生产设定权限",
+ "email": "email",
+ "phone": "手机",
+ "created_at": "建立时间",
+ "operation": "功能",
+ "name_placeholder": "请输入使用者、帐号名称",
+ "role_placeholder": "请输入角色名称",
+ "change_password": "变更密码",
+ "choose": "选择"
+ },
+ "button": {
+ "add": "新增",
+ "cancel": "取消",
+ "query": "查询",
+ "search": "搜索",
+ "view": "查看",
+ "reset": "重置",
+ "export": "导出",
+ "enter_text": "输入文字后按下 Enter",
+ "required": "必填",
+ "submit": "确定",
+ "edit": "修改",
+ "delete": "删除",
+ "deselect_all": "取消全选",
+ "select_all": "全选",
+ "phone_format": "请输入正确电话号码格式",
+ "email_format": "请输入正确 Email 地址",
+ "password_format": "密码长度至少8码,必须包含英文及数字",
+ "start_time_placeholder": "请输入预计开始日期",
+ "finish_time_placeholder": "请输入完成日期",
+ "rename": "重新命名",
+ "download": "下载",
+ "confirm": "确认",
+ "restore": "复原",
+ "stop_edit": "停止修改",
+ "start_edit": "开始修改",
+ "convert": "轉換"
+ },
+ "msg": {
+ "sure_to_delete": "是否确认删除该项目?",
+ "sure_to_delete_permanent": "是否确认永久删除该项目?",
+ "delete_success": "删除成功",
+ "delete_failed": "删除失败",
+ "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": "系统点位名称",
+ "json_format_text": "请贴上 JSON 格式数据",
+ "json_click_text": "请在左侧输入JSON并点选转换按钮"
+ }
+}
diff --git a/src/config/tw.json b/src/config/tw.json
new file mode 100644
index 0000000..a53d1c6
--- /dev/null
+++ b/src/config/tw.json
@@ -0,0 +1,422 @@
+{
+ "language": "繁體中文",
+ "home": "首頁",
+ "sign_out": "登出",
+ "log_in": "登入",
+ "account": "帳號",
+ "password": "密碼",
+ "table": {
+ "no_data": "表中數據為空",
+ "in_otal": "筆資料",
+ "skip_to": "跳至"
+ },
+ "upload": {
+ "title": "選擇一個文件或拖放到這裡",
+ "description": "檔案不超過 10MB",
+ "formats": "檔案格式"
+ },
+ "dashboard": {
+ "production_quantity": "生產量",
+ "today_production_rate": "今日生產完成率",
+ "yesterday_today": "昨天/今天",
+ "elec_consumption_comparison": "用電量比較",
+ "elec_consumption_comparison_trend": "用電量比較趨勢",
+ "electricity_consumption": "用電量",
+ "today_electricity_consumption": "今日用電量",
+ "yesterday_electricity_consumption": "昨天用電量",
+ "this_last_week": "本週/上週",
+ "thisweek_electricity_consumption": "本周用電量",
+ "lastweek_electricity_consumption": "上週用電量",
+ "one_hour": "1小時",
+ "four_hour": "4小時",
+ "eight_hour": "8小時",
+ "energy_ranking": "能耗排行",
+ "last_30_days_energy_trend": "近30天能耗趨勢",
+ "today_energy_consumption": "本日能耗",
+ "this_month_energy_consumption": "本月能耗",
+ "relative_energy_consumption": "環比能耗",
+ "daily_relative_change": "日環比",
+ "weekly_relative_change": "周環比",
+ "monthly_relative_change": "月環比",
+ "yearly_relative_change": "年環比",
+ "today": "今日",
+ "yesterday": "昨日",
+ "this_week": "本周",
+ "last_week": "上周",
+ "this_month": "本月",
+ "last_month": "上月",
+ "this_year": "今年",
+ "last_year": "去年",
+ "refrig_chart": "冷藏",
+ "indoor_chart": "室內",
+ "temperature": "溫度",
+ "humidity": "濕度",
+ "no_data": "無資料",
+ "alerts_data": "異常資料"
+ },
+ "history": {
+ "title": "歷史資料",
+ "building_name": "廠區",
+ "device_name": "設備名稱",
+ "system_category": "系統類別",
+ "device_category": "設備類別",
+ "category": "類別",
+ "value": "數值",
+ "date": "記錄時間",
+ "point": "點位",
+ "combinations": "常用組合",
+ "date_range": "日期區間",
+ "time_range": "時間區間",
+ "start_date": "起始日期",
+ "start_time": "起始時間",
+ "end_date": "結束日期",
+ "end_time": "結束時間"
+ },
+ "system": {
+ "status": "狀態",
+ "details": "詳細資料",
+ "attribute": "屬性",
+ "value": "數值"
+ },
+ "energy": {
+ "elec_consumption": "用電即時分佈",
+ "total_elec": "總用電",
+ "green_elec": "綠電",
+ "immediate_demand": "即時需量",
+ "average_demand": "平均需量",
+ "real_time_Trend": "即時趨勢",
+ "contract_capacity": "契約容量",
+ "alert_capacity": "警戒容量",
+ "reset_value": "復歸值",
+ "edit_automatic_demand": "編輯自動需量",
+ "elec_bills": "今年電費累計(元)",
+ "interval_elec_charges": "區間電費(元)",
+ "year_carbon_emission": "今年碳排當量累計(公斤)",
+ "interval_carbon_emission": "區間碳排當量",
+ "year_elec_consumption": "今年用電度數(kWh)",
+ "interval_elec_consumption": "區間用電度數(kWh)",
+ "monthly_elec_consumption": "每月用電分析",
+ "daily_carbon_emission_and_reduction": "每日碳排當量 (kgCO2e)",
+ "monthly_bill_power": "每月計費度數 (kWh)",
+ "interval_bill_degree": "區間計費度數",
+ "peak": "尖峰",
+ "semi_peak": "半尖峰",
+ "off_peak": "離峰",
+ "var_elec_cost": "流動電費",
+ "fixed_elec_cost": "基本電費",
+ "total_elec_cost": "總電費",
+ "carbon_equivalent": "碳排當量",
+ "edit_carbon_emission": "編輯碳排放係數",
+ "carbon_emission_coefficient": "碳排放係數",
+ "electricity_classification": "用電分類",
+ "electricity_price": "電費每度單價",
+ "floor": "樓層",
+ "maximum": "最大值",
+ "maximum_time": "最大值時間",
+ "minimum": "最小值",
+ "minimum_time": "最小值時間",
+ "average_value": "平均值",
+ "start_value": "起始值(kWh)",
+ "end_value": "截止值(kWh)",
+ "difference": "差值(kWh)",
+ "power_consumption": "用電量(kWh)",
+ "ranking": "排名",
+ "subtotal": "小計",
+ "unit_price": "單價",
+ "total_amount": "金額總計",
+ "elec_price_list": "電價表",
+ "residential": "住宅型",
+ "standard": "標準型",
+ "simple_elec_price_two_stage": "簡易型時間電價二段式",
+ "simple_elec_price_three_stage": "簡易型時間電價三段式",
+ "classification": "分類",
+ "summer_months": "夏月",
+ "non_summer_months": "非夏月",
+ "time_outside_summer_months": "夏月以外的時間",
+ "basic_elec_charge": "基本電費",
+ "charged_per_household": "按戶計收",
+ "per_household_month": "每戶每月",
+ "mon_to_friday": "週一~週五",
+ "peak_hours": "尖峰時間",
+ "semi_peak_hours": "半尖峰時間",
+ "off_peak_hours": "離峰時間",
+ "price_per_kwh": "每度",
+ "all_day": "全日",
+ "sat_sun_off_peak_days": "週六、週日及離峰日",
+ "usage_over_2000kwh": "每月總度數超過2000度之部分",
+ "add": "加",
+ "standard_time_of_use_tariff_2_stage": "標準型時間電價二段式",
+ "standard_time_of_use_tariff_3_stage": "標準型時間電價三段式",
+ "single_phase": "單相",
+ "three_phase": "三相",
+ "frequent_contract": "經常契約",
+ "per_kw_per_month": "每瓩每月",
+ "non_summer_contract": "非夏日契約",
+ "saturday_semi_peak_contract": "週六半尖峰契約",
+ "off_peak_contract": "離峰契約",
+ "variable_electricity_charge": "流動電費",
+ "saturday": "週六",
+ "sunday_and_off_peak_days": "週日及離峰日",
+ "latest_elec_consumption": "最新用電度數",
+ "daily_elec": "每日用電度數",
+ "line_voltage": "線電壓",
+ "electric_current": "電流",
+ "monthly_elec_bill": "每月電費分析"
+ },
+ "alarm": {
+ "title": "顯示警告",
+ "notify": "異常通知",
+ "number": "異常ID",
+ "category": "異常類別",
+ "device_name": "設備名稱",
+ "message": "異常訊息",
+ "confirm": "確認"
+ },
+ "alert": {
+ "query_title": "告警紀錄查詢",
+ "setting_title": "告警設定",
+ "offnormal": "未復歸",
+ "normal": "已復歸",
+ "unacked": "未確認",
+ "acked": "已確認",
+ "30days": "近30天",
+ "start_date": "起始日期",
+ "end_date": "結束日期",
+ "building_and_floor": "棟別-樓層",
+ "uuid": "異常ID",
+ "alarmClass": "告警條件",
+ "device_name": "設備名稱",
+ "device_number": "設備編號",
+ "device_point_name": "點位名稱",
+ "date": "發生日期",
+ "time": "發生時間",
+ "error_msg": "異常原因",
+ "ack_state": "Ack 確認",
+ "repair_order_number": "派工 / 維運單號",
+ "repair_order": "維修單",
+ "form_number": "表單編號",
+ "start_time": "預計開始時間",
+ "item": "項目",
+ "maintainance": "保養",
+ "repair": "維修",
+ "repair_item": "維修項目",
+ "repair_item_code": "維修項目代碼(設備編號)",
+ "responsible_vendor": "負責廠商",
+ "status": "狀態",
+ "not_completed": "未完成",
+ "completed": "已完成",
+ "worker_id": "工作人員編號",
+ "notice": "注意事項",
+ "result_description": "結果描述",
+ "upload_file": "上傳檔案",
+ "enable": "啟用",
+ "not_enabled": "不啟用",
+ "qualifications": "限定條件",
+ "upper_limit": "上限",
+ "lower_limit": "下限",
+ "delay": "持續秒數",
+ "highDelay": "上限持續秒數",
+ "lowDelay": "下限持續秒數",
+ "warning_method": "警示方式",
+ "warning_time": "警示時間",
+ "warning_value": "警示值",
+ "operation": "功能",
+ "alarm_settings": "異常設定",
+ "time_setting": "時間設定",
+ "yes": "是",
+ "no": "否",
+ "no_notify": "無通知",
+ "notify_name": "姓名",
+ "notify_phone": "手機號碼",
+ "notify_email": "email",
+ "notify_items": "通知項目",
+ "notify_list": "通知名單",
+ "choose": "選擇",
+ "day_time": "星期/時間",
+ "click_time_period": "請用滑鼠點擊時間段",
+ "clear": "清空",
+ "sunday": "星期日",
+ "monday": "星期一",
+ "tuesday": "星期二",
+ "wednesday": "星期三",
+ "thursday": "星期四",
+ "friday": "星期五",
+ "saturday": "星期六",
+ "schedule_name": "時段名稱",
+ "schedule_content": "時段內容",
+ "reorganization": "MQTT 告警重整"
+ },
+ "operation": {
+ "title": "運維管理",
+ "project": "項目",
+ "location": "位置",
+ "uuid": "異常ID",
+ "form_number": "表單編號",
+ "device_name": "設備名稱",
+ "status": "狀態",
+ "staff": "處理人員",
+ "start_time": "預計開始時間",
+ "upload": "檔案上傳",
+ "finish_time": "完成時間",
+ "updated_time": "更新時間",
+ "operation": "功能",
+ "vendor": "廠商",
+ "contact_person": "聯絡人",
+ "phone": "電話",
+ "email": "email",
+ "created_at": "建立日期",
+ "maintenance": "保養",
+ "repair": "維修",
+ "company_info": "廠商資料",
+ "repair_item": "維修項目",
+ "repair_item_code": "維修項目代碼(設備編號)",
+ "responsible_vendor": "負責廠商",
+ "not_completed": "未完成",
+ "completed": "已完成",
+ "worker_id": "工作人員編號",
+ "notice": "注意事項",
+ "result_description": "結果描述",
+ "upload_file": "上傳檔案",
+ "name": "姓名",
+ "city": "城市",
+ "address": "地址",
+ "tax_id_number": "統一編號",
+ "remark": "備注",
+ "date": "日期",
+ "time": "時間",
+ "serial": "單號",
+ "today": "今天",
+ "yesterday": "昨天",
+ "start_created_at": "起始日期",
+ "end_created_at": "結束日期",
+ "enter_text": "請輸入文字",
+ "enter_serial": "請輸入單號"
+ },
+ "graphManagement": {
+ "title": "圖資管理",
+ "category": "圖資類別",
+ "new_category": "新類別",
+ "index": "編號",
+ "oriOrgName": "檔案",
+ "operation": "功能",
+ "folder_path": "資料夾路徑",
+ "upload": "圖資上傳",
+ "staging_area": "刪除暫存區",
+ "no_path": "無資料夾路徑"
+ },
+ "assetManagement": {
+ "title": "資產管理",
+ "add_system_category": "新增系統類別",
+ "edit_system_category": "修改系統類別",
+ "add_device_category": "新增設備類別",
+ "edit_device_category": "修改設備類別",
+ "system_name": "名稱",
+ "system_value": "代號",
+ "system_parent": "所屬系統",
+ "device_number": "設備編號",
+ "device_name": "設備名稱",
+ "asset_number": "資產編號",
+ "floor": "設備位置",
+ "add_floor": "新增樓層",
+ "add_floor_text": "須先上傳樓層地圖",
+ "device_coordinate": "圖面標識",
+ "brand_and_modal": "品牌 / 型號",
+ "brand": "品牌",
+ "modal": "型號",
+ "company_and_contact": "廠商 / 聯絡人",
+ "company": "負責廠商",
+ "buying_date": "購買日期",
+ "oriFile": "檔案上傳",
+ "created_at": "建立時間",
+ "operation": "功能",
+ "device_list": "設備列表",
+ "edit_device": "編輯設備",
+ "add_device": "新增設備",
+ "operate_text": "顯示名稱",
+ "fill_text": "請由系統人員填寫",
+ "equipment_point": "設備點位",
+ "point": "點位",
+ "add_sensor": "新增感測器",
+ "associated_device": "關聯設備",
+ "choose": "選擇",
+ "index": "編號",
+ "floor_plan": "平面圖",
+ "department": "部門",
+ "department_name": "部門名稱",
+ "building": "棟別"
+ },
+ "accountManagement": {
+ "account_title": "帳號管理",
+ "role_title": "角色管理",
+ "index": "編號",
+ "name": "姓名",
+ "account": "帳號",
+ "password": "密碼",
+ "role": "角色",
+ "role_name": "角色名稱",
+ "role_permissions": "角色權限",
+ "role_permissions_setting": "角色權限設定",
+ "permission_name": "權限名稱",
+ "basic_permissions": "基礎權限",
+ "production_permissions": "生產設定權限",
+ "email": "email",
+ "phone": "手機",
+ "created_at": "建立時間",
+ "operation": "功能",
+ "name_placeholder": "請輸入使用者、帳號名稱",
+ "role_placeholder": "請輸入角色名稱",
+ "change_password": "變更密碼",
+ "choose": "選擇"
+ },
+ "button": {
+ "add": "新增",
+ "cancel": "取消",
+ "query": "查詢",
+ "search": "搜尋",
+ "view": "查看",
+ "reset": "重置",
+ "export": "匯出",
+ "enter_text": "輸入文字後按下 Enter",
+ "required": "必填",
+ "submit": "確定",
+ "edit": "修改",
+ "delete": "刪除",
+ "deselect_all": "取消全選",
+ "select_all": "全選",
+ "phone_format": "請輸入正確電話號碼格式",
+ "email_format": "請輸入正確的 Email 地址",
+ "password_format": "密碼長度至少8碼,必須包含英文及數字",
+ "start_time_placeholder": "請輸入預計開始日期",
+ "finish_time_placeholder": "請輸入完成日期",
+ "rename": "重新命名",
+ "download": "下載",
+ "confirm": "確認",
+ "restore": "復原",
+ "stop_edit": "停止修改",
+ "start_edit": "開始修改",
+ "convert": "轉換"
+ },
+ "msg": {
+ "sure_to_delete": "是否確認刪除該項目?",
+ "sure_to_delete_permanent": "是否確認永久刪除該項目?",
+ "delete_success": "刪除成功",
+ "delete_failed": "刪除失敗",
+ "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": "系統點位名稱",
+ "json_format_text": "請貼上 JSON 格式數據",
+ "json_click_text": "請在左側輸入JSON並點選轉換按鈕"
+ }
+}
diff --git a/src/config/us.json b/src/config/us.json
new file mode 100644
index 0000000..99a19e9
--- /dev/null
+++ b/src/config/us.json
@@ -0,0 +1,422 @@
+{
+ "language": "English",
+ "home": "Home",
+ "sign_out": "Sign out",
+ "log_in": "Log in",
+ "account": "Account",
+ "password": "Password",
+ "table": {
+ "no_data": "No data",
+ "in_otal": "items in total",
+ "skip_to": "Skip to"
+ },
+ "upload": {
+ "title": "Select a file or drag and drop here",
+ "description": "File size cannot exceed 10MB",
+ "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",
+ "electricity_consumption": "electricity consumption",
+ "today_electricity_consumption": "Today’s electricity consumption",
+ "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",
+ "one_hour": "1 hour",
+ "four_hour": "4 hour",
+ "eight_hour": "8 hour",
+ "energy_ranking": "Energy consumption ranking",
+ "last_30_days_energy_trend": "Energy consumption trend for the past 30 days",
+ "today_energy_consumption": "Today",
+ "this_month_energy_consumption": "This month",
+ "relative_energy_consumption": "Energy consumption trend",
+ "daily_relative_change": "Daily",
+ "weekly_relative_change": "Weekly",
+ "monthly_relative_change": "Monthly",
+ "yearly_relative_change": "Yearly",
+ "today": "Today",
+ "yesterday": "Yesterday",
+ "this_week": "This week",
+ "last_week": "Last week",
+ "this_month": "This month",
+ "last_month": "Last month",
+ "this_year": "This year",
+ "last_year": "Last year",
+ "refrig_chart": "Refrigeration",
+ "indoor_chart": "Indoor",
+ "temperature": "Temp.",
+ "humidity": "Hum.",
+ "no_data":"No data",
+ "alerts_data": "Abnormal data"
+ },
+ "history": {
+ "title": "Historical Data",
+ "building_name": "Building",
+ "device_name": "Device Name",
+ "system_category": "System Category",
+ "device_category": "Device Category",
+ "category": "Category",
+ "value": "Value",
+ "date": "Record Time",
+ "point": "Character",
+ "combinations": "Common combinations",
+ "date_range": "Date Range",
+ "time_range": "Time interval",
+ "start_date": "Start date",
+ "start_time": "Start time",
+ "end_date": "End date",
+ "end_time": "End time"
+ },
+ "system": {
+ "status": "Status",
+ "details": "Details",
+ "attribute": "Attribute",
+ "value": "value"
+ },
+ "energy": {
+ "elec_consumption": "Real-time distribution of electricity consumption",
+ "total_elec": "Total electricity consumption",
+ "green_elec": "Green electricity",
+ "immediate_demand": "Immediate demand",
+ "average_demand": "Average demand",
+ "real_time_Trend": "Real-time Trend",
+ "contract_capacity": "Contract Capacity",
+ "alert_capacity": "Alert Capacity",
+ "reset_value": "Reset Value",
+ "edit_automatic_demand": "Edit automatic demand",
+ "elec_bills": "Total electricity bills this year (yuan)",
+ "interval_elec_charges": "Interval electricity charges (yuan)",
+ "year_carbon_emission": "Cumulative carbon emission equivalent this year (kg)",
+ "interval_carbon_emission": "Interval carbon emission equivalent",
+ "year_elec_consumption": "This year's electricity consumption (kWh)",
+ "interval_elec_consumption": "Interval electricity consumption (kWh)",
+ "monthly_elec_consumption": "Monthly electricity consumption analysis",
+ "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",
+ "semi_peak": "Semi-Peak",
+ "off_peak": "Off-Peak",
+ "var_elec_cost": "Var. Elec. Cost",
+ "fixed_elec_cost": "Fixed Elec. Cost",
+ "total_elec_cost": "Total Elec. Cost",
+ "carbon_equivalent": "Carbon Equivalent",
+ "edit_carbon_emission": "Edit carbon emission coefficient",
+ "carbon_emission_coefficient": "Carbon emission coefficient",
+ "electricity_classification": "Electricity Classification",
+ "electricity_price": "Electricity charge per unit price",
+ "floor": "Floor",
+ "maximum": "Maximum",
+ "maximum_time": "Maximum time",
+ "minimum": "Minimum value",
+ "minimum_time": "Minimum time",
+ "average_value": "Average value",
+ "start_value": "Start value (kWh)",
+ "end_value": "End value (kWh)",
+ "difference": "Difference (kWh)",
+ "power_consumption": "Power consumption (kWh)",
+ "ranking": "Ranking",
+ "subtotal": "Subtotal",
+ "unit_price": "Unit price",
+ "total_amount": "Total amount",
+ "elec_price_list": "Electricity Price List",
+ "residential": "Residential",
+ "standard": "Standard",
+ "simple_elec_price_two_stage": "Simple Time-of-Use Electricity Price (Two-Tier)",
+ "simple_elec_price_three_stage": "Simple Time-of-Use Electricity Price (Three-Tier)",
+ "classification": "Classification",
+ "summer_months": "Summer Months",
+ "non_summer_months": "Non-Summer Months",
+ "time_outside_summer_months": "Time Outside Summer Months",
+ "basic_elec_charge": "Basic Electricity Charge",
+ "charged_per_household": "Charged Per Household",
+ "per_household_month": "Per Household Per Month",
+ "mon_to_friday": "Monday to Friday",
+ "peak_hours": "Peak Hours",
+ "semi_peak_hours": "Semi-Peak Hours",
+ "off_peak_hours": "Off-Peak Hours",
+ "price_per_kwh": "Price Per kWh",
+ "all_day": "All Day",
+ "sat_sun_off_peak_days": "Saturday, Sunday, and Off-Peak Days",
+ "usage_over_2000kwh": "Usage Over 2000 kWh Per Month",
+ "add": "Add",
+ "standard_time_of_use_tariff_2_stage": "Standard Time-of-Use Tariff (Two-Tier)",
+ "standard_time_of_use_tariff_3_stage": "Standard Time-of-Use Tariff (Three-Tier)",
+ "single_phase": "Single Phase",
+ "three_phase": "Three Phase",
+ "frequent_contract": "Demand Charge",
+ "per_kw_per_month": "Per kW Per Month",
+ "non_summer_contract": "Non-Summer Demand Charge",
+ "saturday_semi_peak_contract": "Saturday Semi-Peak Demand Charge",
+ "off_peak_contract": "Off-Peak Demand Charge",
+ "variable_electricity_charge": "Variable Electricity Charge",
+ "saturday": "Saturday",
+ "sunday_and_off_peak_days": "Sunday and Off-Peak Days",
+ "latest_elec_consumption": "Latest electricity consumption",
+ "daily_elec": "Daily electricity consumption",
+ "line_voltage": "Line voltage",
+ "electric_current": "electric current",
+ "monthly_elec_bill": "Monthly electricity bill analysis"
+ },
+ "alarm": {
+ "title": "Warning",
+ "notify": "Notification",
+ "number": "ID",
+ "category": "Category",
+ "device_name": "Device name",
+ "message": "Message",
+ "confirm": "Confirm"
+ },
+ "alert": {
+ "query_title": "Alarm Record Query",
+ "setting_title": "Alarm Settings",
+ "offnormal": "Off Normal",
+ "normal": "Normal",
+ "unacked": "Unacked",
+ "acked": "Acked",
+ "30days": "Last 30 Days",
+ "start_date": "Start Date",
+ "end_date": "End Date",
+ "building_and_floor": "Building - Floor",
+ "uuid": "Exception ID",
+ "alarmClass": "Alarm Conditions",
+ "device_name": "Device Name",
+ "device_number": "Device Number",
+ "device_point_name": "Point Name",
+ "date": "Occurrence Date",
+ "time": "Occurrence Time",
+ "error_msg": "Abnormal Cause",
+ "ack_state": "Ack Confirm",
+ "repair_order_number": "Repair Order Number",
+ "repair_order": "Repair Order",
+ "form_number": "Form Number",
+ "start_time": "Estimated Start Time",
+ "item": "Item",
+ "maintainance": "Maintainance",
+ "repair": "Repair",
+ "repair_item": "Repair Item",
+ "repair_item_code": "Repair Item Code (Device Number)",
+ "responsible_vendor": "Responsible Vendor",
+ "status": "Status",
+ "not_completed": "Not Completed",
+ "completed": "Completed",
+ "worker_id": "Worker ID",
+ "notice": "Notice",
+ "result_description": "Result Description",
+ "upload_file": "Upload File",
+ "enable": "Enable",
+ "not_enabled": "Not Enabled",
+ "qualifications": "Qualifications",
+ "upper_limit": "Upper Limit",
+ "lower_limit": "Lower Limit",
+ "delay": "Duration (s)",
+ "highDelay": "Max Duration (s)",
+ "lowDelay": "Min Duration (s)",
+ "warning_method": "Warning Method",
+ "warning_time": "Warning Time",
+ "warning_value": "Warning Value",
+ "operation": "Function",
+ "alarm_settings": "Abnormal Alarm Settings",
+ "time_setting": "Time Setting",
+ "yes": "Yes",
+ "no": "No",
+ "no_notify": "No Notification",
+ "notify_name": "Name",
+ "notify_phone": "Phone Number",
+ "notify_email": "Email",
+ "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",
+ "sunday": "Sunday",
+ "monday": "Monday",
+ "tuesday": "Tuesday",
+ "wednesday": "Wednesday",
+ "thursday": "Thursday",
+ "friday": "Friday",
+ "saturday": "Saturday",
+ "schedule_name": "Time period name",
+ "schedule_content": "Time period content",
+ "reorganization": "MQTT Alarm Reorganization"
+ },
+ "operation": {
+ "title": "Operation And Maintenance Management",
+ "project": "Project",
+ "location": "Location",
+ "uuid": "Exception ID",
+ "form_number": "Form Number",
+ "device_name": "Device Name",
+ "status": "Status",
+ "staff": "Staff",
+ "start_time": "Estimated Start Time",
+ "upload": "File Upload",
+ "finish_time": "Completion Time",
+ "updated_time": "Update Time",
+ "operation": "Function",
+ "vendor": "Company",
+ "contact_person": "Contact Person",
+ "phone": "Phone",
+ "email": "Email",
+ "created_at": "Creation Date",
+ "maintenance": "Upkeep",
+ "repair": "Repair",
+ "company_info": "Company Info",
+ "repair_item": "Repair Item",
+ "repair_item_code": "Repair Item Code (Device Number)",
+ "responsible_vendor": "Responsible Vendor",
+ "not_completed": "Not Completed",
+ "completed": "Completed",
+ "worker_id": "Worker ID",
+ "notice": "Notice",
+ "result_description": "Result Description",
+ "upload_file": "Upload File",
+ "name": "Name",
+ "city": "City",
+ "address": "Address",
+ "tax_id_number": "Tax ID Number",
+ "remark": "Remark",
+ "date": "Date",
+ "time": "Time",
+ "serial": "Order Number",
+ "today": "Today",
+ "yesterday": "Yesterday",
+ "start_created_at": "Start Date",
+ "end_created_at": "End Date",
+ "enter_text": "Please enter text",
+ "enter_serial": "Please enter the order number"
+ },
+ "graphManagement": {
+ "title": "Data And Publication Management",
+ "category": "Category",
+ "new_category": "New Category",
+ "index": "Serial Number",
+ "oriOrgName": "File",
+ "operation": "Function",
+ "folder_path": "Folder Path",
+ "upload": "Upload",
+ "staging_area": "Staging Area",
+ "no_path": "No path"
+ },
+ "assetManagement": {
+ "title": "Asset Management",
+ "add_system_category": "Add system category",
+ "edit_system_category": "Edit system category",
+ "add_device_category": "Add device category",
+ "edit_device_category": "Edit device category",
+ "system_name": "Name",
+ "system_value": "Code",
+ "system_parent": "System category",
+ "device_number": "Device Number",
+ "device_name": "Device Name",
+ "asset_number": "Asset Number",
+ "floor": "Location",
+ "add_floor": "Add Floor",
+ "add_floor_text": "Floor map must be uploaded first",
+ "device_coordinate": "Coordinate",
+ "brand_and_modal": "Brand/Model",
+ "brand": "Brand",
+ "modal": "Model",
+ "company_and_contact": "Company/Contact Person",
+ "company": "Company",
+ "buying_date": "Purchase Time",
+ "oriFile": "File Upload",
+ "created_at": "Creation Time",
+ "operation": "Function",
+ "device_list": "Device List",
+ "edit_device": "Edit Device",
+ "add_device": "Add Device",
+ "operate_text": "Display name",
+ "fill_text": "Please fill it in by system personnel",
+ "equipment_point": "Equipment Point",
+ "point": "Point",
+ "add_sensor": "Add New Sensor",
+ "associated_device": "Associated Devices",
+ "choose": "Choose",
+ "index": "Serial Number",
+ "floor_plan": "Floor Plan",
+ "department": "Department",
+ "department_name": "Department Name",
+ "building": "Building"
+ },
+ "accountManagement": {
+ "account_title": "Account Management",
+ "role_title": "Role Management",
+ "index": "Serial Number",
+ "name": "Name",
+ "account": "Account",
+ "password": "Password",
+ "role": "Role",
+ "role_name": "Role Name",
+ "role_permissions": "Role Permissions",
+ "role_permissions_setting": "Role Permissions Settings",
+ "permission_name": "Permission Name",
+ "basic_permissions": "Basic Ppermissions",
+ "production_permissions": "Production Setting Permissions",
+ "email": "Email",
+ "phone": "Phone",
+ "created_at": "Created Time",
+ "operation": "Function",
+ "name_placeholder": "Please enter the user's name / account",
+ "role_placeholder": "Please enter the role's name",
+ "change_password": "Change Password",
+ "choose": "Choose"
+ },
+ "button": {
+ "add": "Add",
+ "cancel": "Cancel",
+ "query": "Query",
+ "search": "Search",
+ "view": "View",
+ "reset": "Reset",
+ "export": "Export",
+ "enter_text": "After entering text, press Enter",
+ "required": "Required",
+ "submit": "Submit",
+ "edit": "Edit",
+ "delete": "Delete",
+ "deselect_all": "Deselect All",
+ "select_all": "Select All",
+ "phone_format": "Please enter the correct phone number format",
+ "email_format": "Please enter correct email address",
+ "password_format": "The password must be at least 8 characters long and must contain English and numbers.",
+ "start_time_placeholder": "Please enter expected start date",
+ "finish_time_placeholder": "Please enter completion date",
+ "rename": "Rename",
+ "download": "Download",
+ "confirm": "Confirm",
+ "restore": "Restore",
+ "stop_edit": "Stop editing",
+ "start_edit": "Start editing",
+ "convert": "Convert"
+ },
+ "msg": {
+ "sure_to_delete": "Are you sure to delete this item?",
+ "sure_to_delete_permanent": "Are you sure you want to permanently delete this item?",
+ "delete_success": "Delete successfully",
+ "delete_failed": "Delete failed",
+ "mqtt_refresh": "MQTT reset successful"
+ },
+ "setting": {
+ "MQTT_parse": "MQTT Parse",
+ "schema": "Schema",
+ "point": "Point",
+ "description": "Description",
+ "IoT_point_name": "IoT Point Name",
+ "IoT_point_code": "IoT Point Code",
+ "number_of_decimal_places": "Number of Decimal Places",
+ "boolean_value": "Boolean Value",
+ "hide_point": "Point Display",
+ "schema_name": "Schema name",
+ "IoT_point_structure": "IoT Point Structure",
+ "system_point_name": "System Point Name",
+ "json_format_text": "Please paste JSON format data",
+ "json_click_text": "Please enter JSON on the left and click the conversion button"
+ }
+}
diff --git a/src/constant/CalculateTableColumn.js b/src/constant/CalculateTableColumn.js
new file mode 100644
index 0000000..5a81ee0
--- /dev/null
+++ b/src/constant/CalculateTableColumn.js
@@ -0,0 +1,127 @@
+const transformColumns = (columns) =>
+ columns.map((col) => ({
+ ...col,
+ dataIndex: col.key,
+ width: col.width ?? 120,
+ align: "center",
+ }));
+
+const MONTHCOLUMNS = transformColumns([
+ { title: "項目", key: "item", width: 190, fixed: true },
+ { title: "1月", key: "January" },
+ { title: "2月", key: "February" },
+ { title: "3月", key: "March" },
+ { title: "4月", key: "April" },
+ { title: "5月", key: "May" },
+ { title: "6月", key: "June" },
+ { title: "7月", key: "July" },
+ { title: "8月", key: "August" },
+ { title: "9月", key: "September" },
+ { title: "10月", key: "October" },
+ { title: "11月", key: "November" },
+ { title: "12月", key: "December" },
+]);
+
+const WORKHOURSROW = [
+ {
+ key: "Index",
+ item: "月份",
+ },
+ {
+ key: "WorkerNumber",
+ item: "員工數",
+ },
+ {
+ key: "WorkDay",
+ item: "每日每人平均工作時數",
+ },
+ {
+ key: "Scalar",
+ item: "總工時",
+ },
+ {
+ key: "OverTimeWorkerNumber",
+ item: "加班員工數",
+ },
+ {
+ key: "OverTimeAverageHourPerDay",
+ item: "每日每人平均加班時數",
+ },
+ {
+ key: "OverTimeWorkDay",
+ item: "月加班工作天數",
+ },
+ {
+ key: "OverTimeScalar",
+ item: "月合計加班時數",
+ },
+ { key: "TotalHours", item: "總工時", readonly: true },
+ { key: "KgCO2e", item: "KgCO2e", readonly: true },
+ { key: "Description", item: "描述/說明" },
+ {
+ item: "使用量佐證文件",
+ key: "ReferenceFileLink",
+ },
+];
+
+const ELECTRICROW = transformColumns([
+ {
+ key: "Index",
+ title: "月份",
+ },
+ {
+ key: "Peak",
+ title: "尖峰 / 峰",
+ },
+ {
+ key: "HalfPeak",
+ title: "半尖峰 / 平",
+ },
+ {
+ key: "SaturdayHalfPeak",
+ title: "週六半尖峰",
+ },
+ {
+ key: "OffPeak",
+ title: "離峰 / 谷",
+ },
+ {
+ key: "KgCO2e",
+ title: "碳排放 KgCO2e",
+ },
+ // {
+ // key: "Elecdeduct1",
+ // item: "電力扣除額1",
+ // },
+ // {
+ // key: "Elecdeduct2",
+ // item: "電力扣除額2",
+ // },
+ // {
+ // key: "Scalar",
+ // item: "總用電量",
+ // },
+ // { key: "Description", item: "描述/說明" },
+ // { key: "KgCO2e", item: "KgCO2e", readonly: true },
+ // {
+ // item: "使用量佐證文件",
+ // key: "ReferenceFileLink",
+ // },
+]);
+
+const REFRIGERANTCOLUMNS = transformColumns([
+ { title: "廠區 / 製程別", key: "ProcessName" },
+ { title: "負責單位", key: "ResponsibleUnit" },
+ { title: "設備名稱", key: "Name" },
+ { title: "型號", key: "ModelNumber" },
+ { title: "使用冷媒 / 製冷劑種類 ", key: "ParameterIDTitle" },
+ { title: "全廠台數", key: "TotalNumber" },
+ { title: "冷媒 / 製冷劑原始填充量(Kg) ", key: "Scalar" },
+ { title: "使用月數", key: "UsedMonth" },
+ { title: "設備類型(排放因子) ", key: "ParameterID2Title" },
+ { title: "GWP", key: "GWP" },
+ { title: "設備逸散率", key: "factor" },
+ { title: "KgCO2e", key: "KgCO2e" },
+]);
+
+export { MONTHCOLUMNS, WORKHOURSROW, ELECTRICROW, REFRIGERANTCOLUMNS };
diff --git a/src/constant/api_app.js b/src/constant/api_app.js
new file mode 100644
index 0000000..2744f29
--- /dev/null
+++ b/src/constant/api_app.js
@@ -0,0 +1,8 @@
+const BASEURL = import.meta.env.VITE_API_BASEURL;
+export const POST_LOGIN = `${BASEURL}/api/Login/`;
+export const GET_AUTHPAGE_API = `${BASEURL}/api/GetUsrFroList`;
+export const GET_SUBAUTHPAGE_API = `${BASEURL}/api/Device/GetMainSub`;
+export const GET_DEVICELIST_API = `${BASEURL}/api/Device/GetDeviceList`;
+export const GET_DEVICEIMME_API = `${BASEURL}/api/Energe/GetElecBySubSysTag`;
+
+
diff --git a/src/constant/api_forge.js b/src/constant/api_forge.js
new file mode 100644
index 0000000..9234002
--- /dev/null
+++ b/src/constant/api_forge.js
@@ -0,0 +1,4 @@
+const BASEURL = import.meta.env.VITE_API_BASEURL;
+export const GET_FORGETOKEN_API = `${BASEURL}/api/forge/oauth/token`;
+
+export const GET_FORGEURN_API = `${BASEURL}/api/Device/GetBuild`;
diff --git a/src/constant/authPage.js b/src/constant/authPage.js
new file mode 100644
index 0000000..956d94f
--- /dev/null
+++ b/src/constant/authPage.js
@@ -0,0 +1,70 @@
+export const AUTHPAGES = [
+ {
+ authCode: "PF0",
+ icon: "home",
+ navigate: "/dashboard",
+ },
+ {
+ authCode: "PF1",
+ icon: "tv",
+ navigate: "/system",
+ },
+ {
+ authCode: "PF2",
+ icon: "chart-pie",
+ pageName: "energyManagement",
+ navigate: "/energyManagement",
+ },
+ {
+ authCode: "PF3",
+ icon: "chart-area",
+ navigate: "/historyData",
+ },
+ {
+ authCode: "PF4",
+ icon: "chart-line",
+ navigate: "/historyData",
+ },
+ {
+ authCode: "PF5",
+ icon: "bell",
+ pageName: "alert",
+ navigate: "/alert",
+ },
+ {
+ authCode: "PF6",
+ icon: "server",
+ pageName: "operation",
+ navigate: "/operation",
+ },
+ {
+ authCode: "PF7",
+ icon: "image",
+ pageName: "graphManagement",
+ navigate: "/graphManagement",
+ },
+ {
+ authCode: "PF8",
+ icon: "user",
+ pageName: "accountManagement",
+ navigate: "/accountManagement",
+ },
+ {
+ authCode: "PF9",
+ icon: "database",
+ pageName: "AssetManagement",
+ navigate: "/assetManagement",
+ },
+ {
+ authCode: "PF10",
+ icon: "leaf",
+ pageName: "ProductSetting",
+ navigate: "/productSetting",
+ },
+ {
+ authCode: "PF11",
+ icon: "cog",
+ pageName: "Setting",
+ navigate: "/Setting",
+ },
+];
diff --git a/src/constant/calculateIcon.js b/src/constant/calculateIcon.js
new file mode 100644
index 0000000..b73e845
--- /dev/null
+++ b/src/constant/calculateIcon.js
@@ -0,0 +1,465 @@
+// import CapitalGood from "@ASSET/icon/CapitalGood.svg"; // 上游購買資本物品
+// import CapitalGoodHover from "@ASSET/icon/CapitalGood-h.svg";
+// import upstreamEnergyEmission from "@ASSET/icon/UpstreamEnergyEmission.svg"; // 與能源相關活動
+// import upstreamEnergyEmissionHover from "@ASSET/icon/UpstreamEnergyEmission-h.svg";
+// import Energy from "@ASSET/icon/Energy.svg"; // 外購能源排放
+// import EnergyHover from "@ASSET/icon/Energy-h.svg";
+// import Disposal from "@ASSET/icon/Disposal.svg"; // 上游廢棄
+// import DisposalHover from "@ASSET/icon/Disposal-h.svg";
+// import LeasedAsset from "@ASSET/icon/LeasedAsset.svg"; // 上游租賃資產
+// import LeasedAssetHover from "@ASSET/icon/LeasedAsset-h.svg";
+// import PurchasedGood from "@ASSET/icon/PurchasedGood.svg"; // 購買商品
+// import PurchasedGoodHover from "@ASSET/icon/PurchasedGood-h.svg";
+// import Consultant from "@ASSET/icon/Consultant.svg"; // 購買服務
+// import ConsultantHover from "@ASSET/icon/Consultant-h.svg";
+// import UpstreamTransport from "@ASSET/icon/UpstreamTransport.svg"; // 上游運輸及配送
+// import UpstreamTransportHover from "@ASSET/icon/UpstreamTransport-h.svg";
+// import BusinessTravel from "@ASSET/icon/BusinessTravel.svg"; // 商務旅行
+// import BusinessTravelHover from "@ASSET/icon/BusinessTravel-h.svg";
+// import Visitor from "@ASSET/icon/Visitor.svg"; // 訪客
+// import VisitorHover from "@ASSET/icon/Visitor-h.svg";
+// import Commuting from "@ASSET/icon/Commuting.svg"; // 員工通勤
+// import CommutingHover from "@ASSET/icon/Commuting-h.svg";
+
+// import StationaryCombustion from "@ASSET/icon/StationaryCombustion.svg"; // 固定源
+// import StationaryCombustionHover from "@ASSET/icon/StationaryCombustion-h.svg";
+// import MobileCombustion from "@ASSET/icon/MobileCombustion.svg"; // 移動源
+// import MobileCombustionHover from "@ASSET/icon/MobileCombustion-h.svg";
+// import DirectFugitiveEmission from "@ASSET/icon/DirectFugitiveEmission.svg"; // 逸散源
+// import DirectFugitiveEmissionHover from "@ASSET/icon/DirectFugitiveEmission-h.svg";
+// import DirectProcessEmission from "@ASSET/icon/DirectProcessEmission.svg"; // 製程
+// import DirectProcessEmissionHover from "@ASSET/icon/DirectProcessEmission-h.svg";
+// import Electricity from "@ASSET/icon/Electricity.svg"; // 用電量
+// import ElectricityHover from "@ASSET/icon/Electricity-h.svg";
+// import Steam from "@ASSET/icon/Steam.svg"; // 蒸氣
+// import SteamHover from "@ASSET/icon/Steam-h.svg";
+// import Refrigerant from "@ASSET/icon/Refrigerant.svg"; // 冷媒
+// import RefrigerantHover from "@ASSET/icon/Refrigerant-h.svg";
+// import OtherCompound from "@ASSET/icon/OtherCompound.svg"; // 其他關注類
+// import OtherCompoundHover from "@ASSET/icon/OtherCompound-h.svg";
+
+// import UseEmission from "@ASSET/icon/UseEmission.svg"; // 下游使用銷售產品
+// import UseEmissionHover from "@ASSET/icon/UseEmission-h.svg";
+// import DownstreamDisposal from "@ASSET/icon/DownstreamDisposal.svg"; // 下銷售產品廢棄處理
+// import DownstreamDisposalHover from "@ASSET/icon/DownstreamDisposal-h.svg";
+// import Investment from "@ASSET/icon/Investment.svg"; // 投資
+// import InvestmentHover from "@ASSET/icon/Investment-h.svg";
+
+// import Other from "@ASSET/icon/Other.svg"; // 投資
+// import OtherHover from "@ASSET/icon/Other-h.svg";
+
+// import WaterUsages from "@ASSET/icon/WaterUsages.png"; // 水
+// import WaterUsagesHover from "@ASSET/icon/WaterUsagesHover.png";
+
+import {
+ MONTHCOLUMNS,
+ WORKHOURSROW,
+ ELECTRICROW,
+ REFRIGERANTCOLUMNS,
+} from "./CalculateTableColumn";
+
+const alterSourceIcon = (sourceList) =>
+ sourceList.map(({ link, icon, hoverIcon, title, children = null }) => ({
+ icon,
+ hoverIcon,
+ title,
+ key: link,
+ link,
+ children,
+ }));
+
+const sourceIconListForUpstreamS3 = alterSourceIcon([
+ {
+ icon: "CapitalGood",
+ hoverIcon: "CapitalGood-h",
+ link: "capitalGood",
+ title: "購買資本物品 C4",
+ children: [
+ {
+ title: "購買資本物品 C4",
+ editType: "lifecycle",
+ link: "capitalGood",
+ },
+ ],
+ },
+ {
+ icon: "UpstreamEnergyEmission",
+ hoverIcon: "UpstreamEnergyEmission-h",
+ link: "upstreamEmissions",
+ title: "輸入能源上游排放 C4",
+ children: [
+ {
+ title: "輸入能源上游排放 C4",
+ editType: "lifecycle",
+ link: "upstreamEmissions",
+ },
+ ],
+ },
+ {
+ icon: "WaterUsages",
+ hoverIcon: "WaterUsages-h",
+ link: "waterUsage",
+ title: "用水(水資源管理) C4",
+ children: [
+ {
+ title: "用水(水資源管理) C4",
+ editType: "lifecycle",
+ link: "waterUsage",
+ },
+ ],
+ },
+ {
+ icon: "PurchasedGood",
+ hoverIcon: "PurchasedGood-h",
+ link: "purchasedGood",
+ title: "購買商品 C4",
+ children: [
+ {
+ title: "購買商品 C4",
+ editType: "lifecycle",
+ link: "purchasedGood",
+ },
+ ],
+ },
+ {
+ icon: "LeasedAsset",
+ hoverIcon: "LeasedAsset-h",
+ link: "leasedAsset",
+ title: "上游租賃資產 C4",
+ children: [
+ {
+ title: "上游租賃資產 C4",
+ editType: "lifecycle",
+ link: "leasedAsset",
+ },
+ ],
+ },
+ {
+ icon: "Consultant",
+ hoverIcon: "Consultant-h",
+ link: "consultant",
+ title: "顧問諮詢、清潔、維護等 C4",
+ children: [
+ {
+ title: "顧問諮詢、清潔、維護等 C4",
+ editType: "lifecycle",
+ link: "consultant",
+ },
+ ],
+ },
+]);
+
+const sourceIconListForBusinessS2UP = alterSourceIcon([
+ {
+ icon: "UpstreamTransport",
+ hoverIcon: "UpstreamTransport-h",
+ link: "upstreamTransport",
+ title: "上游運輸及配送 C3",
+ children: [
+ {
+ title: "上游運輸及配送 C3",
+ editType: "lifecycle",
+ link: "upstreamTransport",
+ },
+ ],
+ },
+]);
+
+const sourceIconListForBusinessS1 = alterSourceIcon([
+ {
+ icon: "MobileCombustion",
+ hoverIcon: "MobileCombustion-h",
+ link: "mobileCombustion",
+ title: "移動源 C1",
+ children: [
+ {
+ title: "移動源 C1",
+ editType: "yearlyDevice",
+ link: "mobileCombustion",
+ },
+ ],
+ },
+ {
+ icon: "StationaryCombustion",
+ hoverIcon: "StationaryCombustion-h",
+ link: "stationaryCombustion",
+ title: "固定燃燒源 C1",
+ children: [
+ {
+ title: "固定燃燒源 C1",
+ editType: "yearlyDevice",
+ link: "stationaryCombustion",
+ },
+ ],
+ },
+ {
+ icon: "DirectProcessEmission",
+ hoverIcon: "DirectProcessEmission-h",
+ link: "directProcessEmission",
+ title: "工業製程 C1",
+ children: [
+ {
+ title: "工業製程 C1",
+ editType: "yearlyDevice",
+ link: "directProcessEmission",
+ },
+ ],
+ },
+ {
+ icon: "DirectFugitiveEmission",
+ hoverIcon: "DirectFugitiveEmission-h",
+ link: "directFugitiveEmission",
+ title: "人為逸散 C1",
+ children: [
+ {
+ title: "冷媒設備 B.2.2.d",
+ editType: "nonYearlyDevice",
+ link: "refrigerant",
+ cols: REFRIGERANTCOLUMNS,
+ main_system_tag: "ME",
+ sub_system_tag: "M10",
+ },
+ {
+ title: "工時計算 B.2.2.d",
+ editType: "lifecycle",
+ link: "workHour",
+ rows: WORKHOURSROW,
+ cols: MONTHCOLUMNS,
+ data_api: "./mock/workhour.json",
+ },
+ {
+ title: "消防設備 B.2.2.d",
+ editType: "nonYearlyDevice",
+ link: "fireEquipment",
+ },
+ ],
+ },
+ {
+ icon: "OtherCompound",
+ hoverIcon: "OtherCompound-h",
+ link: "otherCompound",
+ title: "其他關注類物質 C1",
+ children: [
+ {
+ title: "其他關注類物質 C1",
+ editType: "nonYearlyDevice",
+ link: "otherCompound",
+ },
+ ],
+ },
+
+ {
+ icon: "Electricity",
+ hoverIcon: "Electricity-h",
+ link: "electricity",
+ title: "輸入電力 C2",
+ children: [
+ {
+ title: "一般用電 B.3.2.a",
+ editType: "month",
+ link: "plus",
+ rows: ELECTRICROW,
+ cols: MONTHCOLUMNS,
+ main_system_tag: "EE",
+ sub_system_tag: "E4",
+ data_api: "./mock/electricity.json",
+ },
+ // {
+ // title: "綠電 B.3.2.a",
+ // editType: "month",
+ // link: "minus",
+ // rows: ELECTRICROW,
+ // cols: MONTHCOLUMNS,
+ // },
+ ],
+ },
+ {
+ icon: "Steam",
+ hoverIcon: "Steam-h",
+ link: "steam",
+ title: "輸入蒸汽 C2",
+ children: [
+ {
+ title: "蒸氣加項 B.3.2.b",
+ editType: "month",
+ link: "plus",
+ },
+ {
+ title: "蒸氣減項 B.3.2.b",
+ editType: "month",
+ link: "minus",
+ },
+ ],
+ },
+ {
+ icon: "Visitor",
+ hoverIcon: "Visitor-h",
+ link: "visitor",
+ title: "客戶和訪客運輸 C3",
+ children: [
+ {
+ title: "客戶和訪客運輸 C3",
+ editType: "lifecycle",
+ link: "visitor",
+ },
+ ],
+ },
+ {
+ icon: "BusinessTravel",
+ hoverIcon: "BusinessTravel-h",
+ link: "businessTravel",
+ title: "員工差旅 C3",
+ children: [
+ {
+ title: "員工差旅 C3",
+ editType: "lifecycle",
+ link: "businessTravel",
+ },
+ ],
+ },
+ {
+ icon: "Commuting",
+ hoverIcon: "Commuting-h",
+ link: "commuting",
+ title: "員工通勤 C3",
+ children: [
+ {
+ title: "員工通勤 C3",
+ editType: "lifecycle",
+ link: "commuting",
+ },
+ ],
+ },
+ {
+ icon: "Disposal",
+ hoverIcon: "Disposal-h",
+ link: "disposal",
+ title: "營運產生之廢棄物 C4",
+ children: [
+ {
+ title: "營運產生之廢棄物 C4",
+ editType: "lifecycle",
+ link: "disposal",
+ },
+ ],
+ },
+]);
+
+const sourceIconListForBusinessS2Down = alterSourceIcon([
+ {
+ icon: "UpstreamTransport",
+ hoverIcon: "UpstreamTransport-h",
+ link: "downstreamTransport",
+ title: "下游運輸及配送 C3",
+ children: [
+ {
+ title: "下游運輸及配送 C3",
+ editType: "lifecycle",
+ link: "downstreamTransport",
+ },
+ ],
+ },
+ {
+ icon: "UpstreamTransport",
+ hoverIcon: "UpstreamTransport-h",
+ link: "disposalDownTransport",
+ title: "廢棄物運輸 C3",
+ children: [
+ {
+ title: "廢棄物運輸 C3",
+ editType: "lifecycle",
+ link: "disposalDownTransport",
+ },
+ ],
+ },
+]);
+
+const sourceIconListForDownstreamS3 = alterSourceIcon([
+ {
+ icon: "LeasedAsset",
+ hoverIcon: "LeasedAsset-h",
+ link: "downLeasedAsset",
+ title: "下游租賃資產 C5",
+ children: [
+ {
+ title: "下游租賃資產 C5",
+ editType: "lifecycle",
+ link: "downLeasedAsset",
+ },
+ ],
+ },
+ {
+ icon: "UseEmission",
+ hoverIcon: "UseEmission-h",
+ link: "useEmission",
+ title: "產品使用階段 C5",
+ children: [
+ {
+ title: "產品使用階段 C5",
+ editType: "lifecycle",
+ link: "useEmission",
+ },
+ ],
+ },
+ {
+ icon: "Investment",
+ hoverIcon: "Investment-h",
+ link: "investment",
+ title: "投資 C5",
+ children: [
+ {
+ title: "投資 C5",
+ editType: "lifecycle",
+ link: "investment",
+ },
+ ],
+ },
+ {
+ icon: "DownstreamDisposal",
+ hoverIcon: "DownstreamDisposal-h",
+ link: "downstreamDisposal",
+ title: "產品壽命終止階段 C5",
+ children: [
+ {
+ title: "產品壽命終止階段 C5",
+ editType: "lifecycle",
+ link: "downstreamDisposal",
+ },
+ ],
+ },
+]);
+
+const sourceIconListForOtherS3 = alterSourceIcon([
+ {
+ icon: "Other",
+ hoverIcon: "Other-h",
+ link: "other",
+ title: "其它間接排放 C6",
+ children: [
+ {
+ title: "其它間接排放 C6",
+ editType: "lifecycle",
+ link: "other",
+ },
+ ],
+ },
+]);
+
+const allSourceIconList = [
+ ...sourceIconListForUpstreamS3,
+ ...sourceIconListForBusinessS1,
+ ...sourceIconListForBusinessS2UP,
+ ...sourceIconListForBusinessS2Down,
+ ...sourceIconListForDownstreamS3,
+ ...sourceIconListForOtherS3,
+];
+
+export {
+ sourceIconListForUpstreamS3,
+ sourceIconListForBusinessS1,
+ sourceIconListForBusinessS2UP,
+ sourceIconListForBusinessS2Down,
+ sourceIconListForDownstreamS3,
+ sourceIconListForOtherS3,
+ allSourceIconList,
+};
diff --git a/src/constant/colors.js b/src/constant/colors.js
new file mode 100644
index 0000000..9665e09
--- /dev/null
+++ b/src/constant/colors.js
@@ -0,0 +1,32 @@
+export const COLOR = [
+ "#4cf3e9", // 亮藍
+ "#f5d54e", // 黃
+ "#63ed84", // 亮綠
+ "#9afed8", // 淺綠
+ "#e266fe", // 紫
+ "#e0e2e2", // 灰
+ "#500080", // 紫
+ "#115852", // 深綠
+ "#4B4E6C", // 灰
+ "#eb4c42", // 紅
+ "#007ba7", // 藍
+ "#da3287", // 粉紅
+ "#ccff00", // 綠
+ "#fff44f", // 黃
+];
+
+// 淺色
+export const CHART_COLOR = [
+ "#cb4154", // 紅
+ "#fad6a5", // 黃
+ "#ace1af", // 綠
+ "#9bddff", // 亮藍
+];
+
+// 深色
+export const SECOND_CHART_COLOR = [
+ "#cc0000", // 紅
+ "#ffb300", // 黃
+ "#00cc99", // 綠
+ "#4997d0", // 藍
+];
diff --git a/src/constant/index.js b/src/constant/index.js
new file mode 100644
index 0000000..5a01247
--- /dev/null
+++ b/src/constant/index.js
@@ -0,0 +1,45 @@
+import {
+ POST_LOGIN,
+ GET_AUTHPAGE_API,
+ GET_SUBAUTHPAGE_API,
+ GET_DEVICELIST_API,
+ GET_DEVICEIMME_API,
+} from "./api_app";
+import { GET_FORGETOKEN_API, GET_FORGEURN_API } from "./api_forge";
+import { AUTHPAGES } from "./authPage";
+import {
+ sourceIconListForUpstreamS3,
+ sourceIconListForBusinessS1,
+ sourceIconListForBusinessS2UP,
+ sourceIconListForBusinessS2Down,
+ sourceIconListForDownstreamS3,
+ sourceIconListForOtherS3,
+ allSourceIconList,
+} from "./calculateIcon";
+import { MONTHCOLUMNS } from "./CalculateTableColumn";
+import { COLOR, CHART_COLOR, SECOND_CHART_COLOR } from "./colors";
+
+export {
+ // api_app
+ POST_LOGIN,
+ GET_AUTHPAGE_API,
+ GET_SUBAUTHPAGE_API,
+ GET_DEVICELIST_API,
+ GET_DEVICEIMME_API,
+
+ //api_forge
+ GET_FORGETOKEN_API,
+ GET_FORGEURN_API,
+ AUTHPAGES,
+ sourceIconListForUpstreamS3,
+ sourceIconListForBusinessS1,
+ sourceIconListForBusinessS2UP,
+ sourceIconListForBusinessS2Down,
+ sourceIconListForDownstreamS3,
+ sourceIconListForOtherS3,
+ allSourceIconList,
+ MONTHCOLUMNS,
+ COLOR,
+ CHART_COLOR,
+ SECOND_CHART_COLOR,
+};
diff --git a/src/directives/draggable.js b/src/directives/draggable.js
new file mode 100644
index 0000000..726d156
--- /dev/null
+++ b/src/directives/draggable.js
@@ -0,0 +1,66 @@
+const moveModal = (elmnt) => {
+ console.log(elmnt);
+ var pos1 = 0,
+ pos2 = 0,
+ pos3 = 0,
+ pos4 = 0;
+ document.body.addEventListener("mousedown", dragMouseDown, {
+ passive: false,
+ });
+
+ function dragMouseDown(e) {
+ console.log("dragMouseDown", e);
+ e = e || window.event;
+ e.preventDefault();
+ // get the mouse cursor position at startup:
+ pos3 = e.clientX;
+ pos4 = e.clientY;
+ document.body.addEventListener("mouseup", closeDragElement, {
+ passive: false,
+ });
+ // call a function whenever the cursor moves:
+ document.body.addEventListener("mousemove", elementDrag, {
+ passive: false,
+ });
+ }
+
+ function elementDrag(e) {
+ e = e || window.event;
+ e.preventDefault();
+ // calculate the new cursor position:
+ pos1 = pos3 - e.clientX;
+ pos2 = pos4 - e.clientY;
+ pos3 = e.clientX;
+ pos4 = e.clientY;
+ // set the element's new position:
+ elmnt.style.top = elmnt.offsetTop - pos2 + "px";
+ elmnt.style.left = elmnt.offsetLeft - pos1 + "px";
+ }
+
+ function closeDragElement() {
+ // stop moving when mouse button is released:
+ document.body.removeEventListener("mouseup", closeDragElement);
+ document.body.removeEventListener("mousemove", elementDrag);
+ }
+};
+
+export const draggable = {
+ install(app) {
+ app.directive("draggable", {
+ mounted: (el, binding, vnode, prevVnode) => {
+ console.log("draggable", $(`#${el.id}`).draggable);
+ if (binding.value) {
+ if ($(`#${el.id}`).draggable) {
+ $(`#${el.id}`).draggable({
+ cursor: "move",
+ scroll: true,
+ container: ".app-container",
+ });
+ } else {
+ moveModal(el);
+ }
+ }
+ },
+ });
+ },
+};
diff --git a/src/directives/focusPlugin.js b/src/directives/focusPlugin.js
new file mode 100644
index 0000000..d917077
--- /dev/null
+++ b/src/directives/focusPlugin.js
@@ -0,0 +1,9 @@
+export const focusPlugin = {
+ install(app) {
+ app.directive("focus", {
+ mounted: (el, binding, vnode, prevVnode) => {
+ el.focus();
+ },
+ });
+ },
+};
diff --git a/src/fontawsomeIconRegister.js b/src/fontawsomeIconRegister.js
new file mode 100644
index 0000000..3758302
--- /dev/null
+++ b/src/fontawsomeIconRegister.js
@@ -0,0 +1,136 @@
+/* import the fontawesome core */
+import { library } from "@fortawesome/fontawesome-svg-core";
+
+/* import specific icons */
+import {
+ faHome,
+ faTv,
+ faChartArea,
+ faChartPie,
+ faChartLine,
+ faBell,
+ faServer,
+ faImage,
+ faUser,
+ faLeaf,
+ faDesktop,
+ faCog,
+ faExclamationTriangle,
+ faBars,
+ faTimes,
+ faAngleDown,
+ faUserCircle,
+ faCommentDots,
+ faCommentSlash,
+ faPlus,
+ faSearch,
+ faCaretRight,
+ faFolder,
+ faCloudUploadAlt,
+ faTrashAlt,
+ faChevronRight,
+ faChevronLeft,
+ faPencilAlt,
+ faSortUp,
+ faSortDown,
+ faFilter,
+ faFilePdf,
+ faFileExcel,
+ faFileWord,
+ faFilePowerpoint,
+ faFileArchive,
+ faFileAlt,
+ faDatabase,
+ faBuilding,
+ faVideo,
+ faFan,
+ faTemperatureHigh,
+ faLightbulb,
+ faBolt,
+ faChargingStation,
+ faTint,
+ faWater,
+ faCarBattery,
+ faFireExtinguisher,
+ faDoorOpen,
+ faCar,
+ faWind,
+ faEye,
+ faEyeSlash,
+ faGlobe,
+ faDownload,
+ faStream,
+ faSave,
+ faCrown,
+ faClock,
+ faCheckCircle
+} from "@fortawesome/free-solid-svg-icons";
+import { faCircle } from "@fortawesome/free-regular-svg-icons";
+
+/* add icons to the library */
+library.add(
+ faHome,
+ faTv,
+ faChartArea,
+ faChartPie,
+ faChartLine,
+ faBell,
+ faServer,
+ faImage,
+ faUser,
+ faLeaf,
+ faDesktop,
+ faCog,
+ faExclamationTriangle,
+ faBars,
+ faTimes,
+ faAngleDown,
+ faUserCircle,
+ faCommentDots,
+ faPlus,
+ faCommentSlash,
+ faSearch,
+ faCaretRight,
+ faFolder,
+ faCloudUploadAlt,
+ faTrashAlt,
+ faChevronRight,
+ faChevronLeft,
+ faPencilAlt,
+ faSortUp,
+ faSortDown,
+ faFilter,
+ faFilePdf,
+ faFileExcel,
+ faFileWord,
+ faFilePowerpoint,
+ faFileArchive,
+ faFileAlt,
+ faDatabase,
+ faBuilding,
+ faVideo,
+ faFan,
+ faTemperatureHigh,
+ faLightbulb,
+ faBolt,
+ faChargingStation,
+ faTint,
+ faWater,
+ faCarBattery,
+ faFireExtinguisher,
+ faDoorOpen,
+ faCar,
+ faWind,
+ faEye,
+ faEyeSlash,
+ faGlobe,
+ faDownload,
+ faStream,
+ faSave,
+ faCrown,
+ faClock,
+ faCheckCircle,
+ faCircle
+);
+
+export default library;
diff --git a/src/hooks/baja/useAlarmData.js b/src/hooks/baja/useAlarmData.js
new file mode 100644
index 0000000..8562df3
--- /dev/null
+++ b/src/hooks/baja/useAlarmData.js
@@ -0,0 +1,89 @@
+import { ref, onMounted, onUnmounted } from 'vue';
+import dayjs from 'dayjs';
+import { getAllDevice } from "@/apis/building";
+
+export default function useAlarmData() {
+ let timer = null;
+ const alarmData = ref([]);
+ const allDeviceList = ref([]);
+
+ const getFormateDate = (datetime, formatRule = 'YYYY-MM-DD HH:mm') => {
+ return dayjs(datetime).format(formatRule);
+ };
+
+ const getAlarmByBaja = (
+ startDate,
+ endDate,
+ isRecover,
+ isAck,
+ alarmClass,
+ callback
+ ) => {
+ window.require &&
+ window.requirejs(["baja!"], (baja) => {
+ let alarms = [];
+ // console.log("進入 bajaSubscriber 準備執行BQL訂閱");
+ const alarmClassQuery = alarmClass.map(ac => `alarmClass = '${ac}'`).join(' or ');
+ const ord = `local:|foxs:|alarm:|bql:select * where (${alarmClassQuery}) and timestamp.millis > ${startDate} and timestamp.millis < ${endDate} and sourceState = '${isRecover}' and ackState = '${isAck}' order by timestamp desc`;
+ baja.Ord.make(ord).get({
+ cursor: {
+ before: () => {
+ timer = null;
+ },
+ each: (record) => {
+ let alarmDisplayName = record.get("alarmData").get("sourceName");
+ alarmDisplayName = alarmDisplayName.replace(/\$2d/g, "_"); // 檢查並替換 $2d 為 _
+ const sourceTmp = alarmDisplayName.split("_");
+ const bfName = sourceTmp[1] + "-" + sourceTmp[4];
+ const sourceName = sourceTmp.slice(0, 8).join("_");
+ const sourceTmpFinal = sourceTmp[7] + "-" + sourceTmp[8];
+ if (!sourceTmpFinal.includes("undefined")) {
+ alarms.push({
+ building_tag: bfName,
+ uuid: record.get("uuid").$val,
+ timestamp_date: getFormateDate(record.get("timestamp").getJsDate(), "YYYY/MM/DD "),
+ timestamp_time: getFormateDate(record.get("timestamp").getJsDate(), "HH:mm:ss"),
+ alarmClass: record.get("alarmClass"),
+ device_number: sourceName,
+ full_name: allDeviceList.value.find((d) => sourceName === d.device_number)?.full_name,
+ msg: record.get("alarmData").get("msgText"),
+ sourceState: record.get("sourceState").getDisplayTag(),
+ normalTime: getFormateDate(record.get("normalTime").getJsDate()),
+ ackState: record.get("ackState").getDisplayTag(),
+ ackedTime: getFormateDate(record.get("ackTime").getJsDate()),
+ });
+ }
+ },
+ after: () => {
+ if (typeof callback === 'function') {
+ callback({ count: alarms.length, data: alarms });
+ }
+ },
+ limit: -1,
+ offset: 0,
+ },
+ });
+ });
+ };
+
+ const getDevice = async () => {
+ const res = await getAllDevice();
+ allDeviceList.value = res.data;
+ };
+
+ const stopFetching = () => {
+ if (timer) {
+ clearTimeout(timer);
+ }
+ };
+
+ onMounted(() => {
+ getDevice();
+ });
+
+ onUnmounted(() => {
+ stopFetching();
+ });
+
+ return { getAlarmByBaja, alarmData, stopFetching };
+}
diff --git a/src/hooks/baja/useRefrigerantHeatMap.js b/src/hooks/baja/useRefrigerantHeatMap.js
new file mode 100644
index 0000000..4a68ea9
--- /dev/null
+++ b/src/hooks/baja/useRefrigerantHeatMap.js
@@ -0,0 +1,150 @@
+import { ref, watch, markRaw } from "vue";
+
+export default function useRefrigerantTemp() {
+ const deviceList = ref([]);
+ const dataVizExtension = ref(null);
+
+ const getBasicData = (viewer, dataVizExtn, deviceArr) => {
+ dataVizExtension.value = markRaw(dataVizExtn);
+ const devices = deviceArr.map((d) => ({
+ ...d,
+ id: d.device_number, // An ID to identify this device
+ roomDbId: Number(d.room_dbid),
+ position: JSON.parse(d.device_coordinate_3d), // World coordinates of this device
+ sensorTypes: ["temperature"], // The types/properties this device exposes
+ temp: 10,
+ dbId: d.forge_dbid,
+ }));
+ deviceList.value = devices;
+ initHeatMap(viewer, dataVizExtn, devices);
+ };
+
+ const initHeatMap = async (viewer, dataVizExtn, deviceList) => {
+ const {
+ SurfaceShadingData,
+ SurfaceShadingPoint,
+ SurfaceShadingNode,
+ SurfaceShadingGroup,
+ } = Autodesk.DataVisualization.Core;
+ const shadingGroup = new SurfaceShadingGroup("iot-heatmap");
+ const rooms = new Map();
+
+ for (const { id, roomDbId, position, sensorTypes } of deviceList) {
+ if (!id || roomDbId == -1) {
+ continue;
+ }
+
+ if (!rooms.has(roomDbId)) {
+ const room = new SurfaceShadingNode(id, roomDbId);
+ shadingGroup.addChild(room);
+ rooms.set(roomDbId, room);
+ }
+ const room = rooms.get(roomDbId);
+ room.addPoint(new SurfaceShadingPoint(id, position, sensorTypes));
+ }
+
+ const shadingData = new SurfaceShadingData();
+ shadingData.addChild(shadingGroup);
+ shadingData.initialize(viewer.model);
+
+ await dataVizExtn.setupSurfaceShading(viewer.model, shadingData);
+ dataVizExtn.registerSurfaceShadingColors(
+ "temperature",
+ [0x0000ff, 0x00ff00, 0xffff00, 0xff0000]
+ );
+ dataVizExtn.renderSurfaceShading(
+ "iot-heatmap",
+ "temperature",
+ getSensorValue
+ );
+ };
+
+ // Function that provides sensor value in the range of [0.0, 1.0]
+ function getSensorValue(device, sensorType, pointData) {
+ const dev = deviceList.value.find(
+ ({ device_number }) => device_number === device.id
+ );
+ console.log(9, device, dev);
+
+ return (dev?.temp || 0) / 40;
+ }
+
+ function updateTemp() {
+ console.log(8, deviceList.value, dataVizExtension.value.updateSurfaceShading);
+ dataVizExtension.value.updateSurfaceShading(getSensorValue);
+
+
+ }
+
+ const transformDeviceNumber = (device_number) => {
+ return device_number.replaceAll("_", "/");
+ };
+
+ const subscribeDevice = (deviceList) => {
+ deviceList.forEach((d) => {
+ const ordPath = transformDeviceNumber(d.device_number);
+ getRealTempByBaja(ordPath);
+ });
+ };
+
+ const getRealTempByBaja = (ordPath) => {
+ window.require &&
+ window.requirejs(["baja!"], (baja) => {
+ console.log("進入 bajaSubscriber 準備執行BQL訂閱");
+ const sub = new baja.Subscriber();
+ function changeDeviceValue(temp) {
+ const device = deviceList.value.find(
+ ({ device_number }) =>
+ transformDeviceNumber(device_number) === ordPath
+ );
+ console.log(7, device, temp);
+ device.temp = Number(temp.replace(" °C", ""));
+ updateTemp();
+ }
+ sub.attach("changed", (prop) => {
+ if (prop && prop.$displayName === "Out") {
+ console.log(5, ordPath, prop);
+ if (prop.$getValue().getValueDisplay().includes(" °C")) {
+ changeDeviceValue(prop.$getValue().getValueDisplay());
+ }
+ }
+ });
+ sub.attach("subscribed", (prop) => {
+ if (prop && prop.$displayName === "Out") {
+ console.log(6, ordPath, prop);
+ if (prop.$getValue().getValueDisplay().includes(" °C")) {
+ changeDeviceValue(prop.$getValue().getValueDisplay());
+ }
+ }
+ });
+ // ord 為要訂閱的點位
+ // ord 為要訂閱的點位
+ baja.Ord.make(`local:|foxs:|station:|slot:/${ordPath}`)
+ .get()
+ .then((folder) => {
+ folder
+ .getSlots()
+ .is("control:NumericWritable")
+ .eachValue((point) => {
+ if (
+ point.getDisplayName() === "Temp" ||
+ point.getDisplayName() === "TEMP"
+ ) {
+ baja.Ord.make(
+ `local:|foxs:|station:|slot:/${ordPath}/${point.getDisplayName()}`
+ ).get({ subscriber: sub });
+ }
+ });
+ });
+ });
+ };
+
+ watch(deviceList, (newValue) => {
+ subscribeDevice(newValue);
+ });
+
+ return {
+ getBasicData,
+ updateTemp,
+ };
+}
diff --git a/src/hooks/baja/useSystemHeatmap.js b/src/hooks/baja/useSystemHeatmap.js
new file mode 100644
index 0000000..4d56f33
--- /dev/null
+++ b/src/hooks/baja/useSystemHeatmap.js
@@ -0,0 +1,123 @@
+// to deal with the temperature heatmap
+import { ref, watch, markRaw } from "vue";
+import useSearchParams from "@/hooks/useSearchParam";
+export default function useSystemHeatmap(updateHeatBarIsShow) {
+ const { searchParams } = useSearchParams();
+ // init heatmap
+ const forgeViewer = ref(null);
+ const dataVizExtension = ref(null);
+ const deviceList = ref([]);
+ const heatMaps = ref({});
+
+ const initHeatMap = async (viewer) => {
+ forgeViewer.value = markRaw(viewer);
+ const dataVizExtn = await viewer.loadExtension(
+ "Autodesk.DataVisualization"
+ );
+ dataVizExtension.value = markRaw(dataVizExtn);
+ };
+ const updateHeatMapData = (deviceArr) => {
+ deviceList.value = Object.values(deviceArr).map((d) => ({
+ ...d,
+ id: d.device_number, // An ID to identify this device
+ roomDbId: d.room_dbid,
+ position: d.device_coordinate_3d, // World coordinates of this device
+ sensorTypes: ["temperature"], // The types/properties this device exposes
+ temp: 10,
+ dbId: d.forge_dbid,
+ }));
+ };
+
+ //create the heatmap
+ function getSensorValue(device, sensorType, pointData) {
+ const dev = deviceList.value.find(
+ ({ device_number }) => device_number === device.id
+ );
+ console.log(9, device, dev);
+
+ return (dev?.temp || 0) / 40;
+ }
+
+ const updateTemp = (device_number, temp) => {
+ const subDevIndex = deviceList.value.findIndex(
+ (d) => d.device_number === device_number
+ );
+ deviceList.value[subDevIndex] = { ...deviceList.value[subDevIndex], temp };
+ dataVizExtension.value.updateSurfaceShading(getSensorValue);
+ };
+
+ const createHeatMap = async (heatMapName) => {
+ // let dataVizExtn = await viewer.loadExtension("Autodesk.DataVisualization");
+ // dataVizExtension.value = markRaw(dataVizExtn);
+
+ const {
+ SurfaceShadingData,
+ SurfaceShadingPoint,
+ SurfaceShadingNode,
+ SurfaceShadingGroup,
+ } = Autodesk.DataVisualization.Core;
+ const shadingGroup = new SurfaceShadingGroup(`iot_heatmap_${heatMapName}`);
+ const rooms = new Map();
+
+ for (const { id, roomDbId, position, sensorTypes } of deviceList.value) {
+ if (!id || roomDbId == -1 || !roomDbId) {
+ continue;
+ }
+
+ if (!rooms.has(roomDbId)) {
+ const room = new SurfaceShadingNode(id, roomDbId);
+ shadingGroup.addChild(room);
+ rooms.set(roomDbId, room);
+ }
+ const room = rooms.get(roomDbId);
+ room.addPoint(new SurfaceShadingPoint(id, position, sensorTypes));
+ }
+
+ const shadingData = new SurfaceShadingData();
+ shadingData.addChild(shadingGroup);
+ shadingData.initialize(forgeViewer.value?.model);
+
+ await dataVizExtension.value.setupSurfaceShading(
+ forgeViewer.value.model,
+ shadingData
+ );
+ dataVizExtension.value.registerSurfaceShadingColors(
+ "temperature",
+ [0x0000ff, 0x00ff00, 0xffff00, 0xff0000]
+ );
+ dataVizExtension.value.renderSurfaceShading(
+ `iot_heatmap_${heatMapName}`,
+ "temperature",
+ getSensorValue
+ );
+
+ console.log(dataVizExtension.value);
+ };
+
+ watch(deviceList, (newValue) => {
+ console.log("熱圖", newValue);
+ switch (parseInt(searchParams.value.option)) {
+ case 2:
+ createHeatMap("frozen");
+ updateHeatBarIsShow(true);
+ break;
+ case 3:
+ createHeatMap("gland");
+ updateHeatBarIsShow(true);
+ break;
+ case 4:
+ createHeatMap("packing");
+ break;
+ case 5:
+ createHeatMap("formula");
+ updateHeatBarIsShow(true);
+ break;
+ default:
+ dataVizExtension.value?.removeSurfaceShading();
+ updateHeatBarIsShow(false);
+ break;
+ }
+ });
+
+ return { updateHeatMapData, updateTemp, initHeatMap };
+}
diff --git a/src/hooks/baja/useSystemStatusByBaja.js b/src/hooks/baja/useSystemStatusByBaja.js
new file mode 100644
index 0000000..e8ba4cf
--- /dev/null
+++ b/src/hooks/baja/useSystemStatusByBaja.js
@@ -0,0 +1,388 @@
+import { onMounted, ref, computed, watch, markRaw, inject } from "vue";
+import { getDashboardDevice } from "@/apis/dashboard";
+import useSearchParams from "@/hooks/useSearchParam";
+import useSystemHeatmap from "./useSystemHeatmap";
+
+export default function useSystemStatusByBaja(updateHeatBarIsShow) {
+ const rawData = ref([]);
+ const forgeViewer = ref(null);
+ const urn = ref("");
+ const { searchParams } = useSearchParams();
+
+ const initialData = ref(null);
+
+ const updateInitialData = (data = false) => {
+ initialData.value = data;
+ };
+
+ const { updateHeatMapData, updateTemp, initHeatMap } =
+ useSystemHeatmap(updateHeatBarIsShow);
+
+ const updateForgeViewer = (viewer) => {
+ if (!viewer) {
+ forgeViewer.value = null;
+ return;
+ }
+ forgeViewer.value = markRaw(viewer);
+ initHeatMap(viewer);
+ };
+
+ const getSubPoint = (normal, close, error, sub_points) => {
+ let points = {
+ ...Object.fromEntries(sub_points.map((p) => [p, ""])),
+ };
+ if (normal) points[normal] = "";
+ if (close) points[close] = "";
+ if (error) points[error] = "";
+ return points;
+ };
+ const subscribeData = ref({});
+
+ watch(rawData, () => {
+ let sub_data = {};
+
+ rawData.value.forEach((d) => {
+ sub_data = {
+ ...sub_data,
+ ...Object.fromEntries(
+ d.device.map((dev) => [
+ dev.device_number,
+ {
+ ...dev,
+ labelText: d.labelText,
+ show_value: d.labelText,
+ device_normal_point_name: d.device_normal_point_name,
+ device_close_point_name: d.device_close_point_name,
+ device_error_point_name: d.device_error_point_name,
+ device_normal_point_value: d.device_normal_point_value,
+ device_close_point_value: d.device_close_point_value,
+ device_error_point_value: d.device_error_point_value,
+ device_normal_color: d.device_normal_color,
+ device_close_color: d.device_close_color,
+ device_error_color: d.device_error_color,
+ forge_dbid: parseInt(dev.forge_dbid),
+ device_coordinate_3d: dev.device_coordinate_3d
+ ? JSON.parse(dev.device_coordinate_3d)
+ : { x: 0, y: 0 },
+ points: getSubPoint(
+ d.device_normal_point_name,
+ d.device_close_point_name,
+ d.device_error_point_name,
+ d.points
+ ),
+ is_show: true,
+ currentColor: d.device_normal_color,
+ },
+ ])
+ ),
+ };
+ });
+ subscribeData.value = sub_data;
+ updateHeatMapData(sub_data);
+ updateSubscribeDataFromBaja(sub_data);
+ });
+
+ const visibleDbid = computed(() => {
+ let visible = [];
+
+ rawData.value.forEach((d) => {
+ visible = [
+ ...visible,
+ ...d.device.map((dev) => parseInt(dev.forge_dbid)),
+ ];
+ });
+
+ return visible;
+ });
+
+ const getDevice = async (option = 1) => {
+ const res = await getDashboardDevice({
+ option: parseInt(option),
+ });
+ rawData.value = res.data.map((d) => ({
+ ...d,
+ key: d.subSys,
+ }));
+ };
+
+ // subscribe from baja
+ const booleanPointFacets = ref({});
+ const updateFacets = (point, facets) => {
+ booleanPointFacets.value = {
+ ...booleanPointFacets,
+ [point]: facets,
+ };
+ };
+ const updateDeviceData = (device_number, point, value) => {
+ const correspondPoint = initialData.value.points.find(
+ ({ name }) => name === point
+ );
+ // console.log("sub 回傳值 ", typeof value)
+ const text = correspondPoint
+ ? correspondPoint.values.find(
+ ({ value: pValue }) => pValue === parseInt(value)
+ )?.text || ""
+ : value;
+
+ // console.log("sub", correspondPoint, device_number, point, value);
+ subscribeData.value[device_number].points[point] = text;
+ if (
+ point.toLowerCase() === "temp" &&
+ parseInt(searchParams.value.option) > 1
+ ) {
+ updateTemp(device_number, value);
+ }
+ if (point === subscribeData.value[device_number].device_error_point_name) {
+ subscribeData.value[device_number].currentColor =
+ value === subscribeData.value[device_number].device_error_point_value
+ ? subscribeData.value[device_number].device_error_color
+ : subscribeData.value[device_number].device_normal_color;
+ }
+
+ updateLabelText(device_number, point, text);
+ };
+
+ const transformDeviceNumber = (device_number) => {
+ return device_number.replaceAll("_", "/");
+ };
+
+ const updateLabelText = (key, point, value) => {
+ let text = subscribeData.value[key].labelText.replace(`%${point}`, value);
+ Object.keys(subscribeData.value[key].points)
+ .filter((p) => p !== point)
+ .forEach((p) => {
+ text = text.replace(`%${p}`, subscribeData.value[key].points[p]);
+ });
+ subscribeData.value[key].show_value = text;
+ };
+
+ const subComponents = ref(null);
+ const updateSubscribeDataFromBaja = (data) => {
+ for (let [key, value] of Object.entries(data)) {
+ window.require &&
+ window.requirejs(["baja!"], (baja) => {
+ console.log("進入 bajaSubscriber 準備執行BQL訂閱");
+
+ const ordPath = transformDeviceNumber(key);
+ baja.Ord.make(`local:|foxs:|station:|slot:/${ordPath}`)
+ .get()
+ .then((folder) => {
+ const batch = new baja.comm.Batch();
+
+ const sub = new baja.Subscriber();
+ sub.attach({
+ changed: function (prop, cx) {
+ if (prop.$getDisplayName() !== "Out") return;
+ if (
+ Object.hasOwn(
+ booleanPointFacets.value,
+ prop.$complex.$propInParent.$slotName
+ )
+ ) {
+ const facets =
+ booleanPointFacets.value[
+ prop.$complex.$propInParent.$slotName
+ ];
+
+ for (let [facetKey, facetValue] of Object.entries(facets)) {
+ if (facetValue === prop.$getValue().getValueDisplay()) {
+ updateDeviceData(
+ key,
+ prop.$complex.$propInParent.$slotName,
+ facetKey
+ );
+ }
+ }
+ } else {
+ updateDeviceData(
+ key,
+ prop.$complex.$propInParent.$slotName,
+ prop.$getValue().getValueDisplay()
+ );
+ }
+ },
+ });
+
+ folder
+ .getSlots()
+ .is("control:ControlPoint")
+ .eachValue((point) => {
+ if (
+ Object.keys(value.points).includes(point.getDisplayName())
+ ) {
+ baja.Ord.make(
+ `local:|foxs:|station:|slot:/${ordPath}/${point.getDisplayName()}`
+ )
+ .get()
+ .then((component) => {
+ if (
+ point.getType().getTypeSpec() ===
+ "control:BooleanWritable"
+ ) {
+ const facets = component.getFacets1().toObject();
+ updateFacets(point.getDisplayName(), facets);
+ for (let [facetKey, facetValue] of Object.entries(
+ facets
+ )) {
+ if (
+ facetValue ===
+ component.getOut().getValue().toString()
+ ) {
+ updateDeviceData(
+ key,
+ point.getDisplayName(),
+ facetKey
+ );
+ }
+ }
+ } else {
+ updateDeviceData(
+ key,
+ point.getDisplayName(),
+ component.getOut().getValue()
+ );
+ }
+
+ sub
+ .subscribe({
+ comps: component, // Can also just be an singular Component instance
+ batch, // if defined, any network calls will be batched into this object (optional)
+ })
+ .then(() => {
+ console.log("subscribed successfully");
+ subComponents.value = sub;
+ })
+ .catch(function (err) {
+ baja.error(
+ "some components failed to subscribe: " + err
+ );
+ });
+ });
+ }
+ });
+ });
+ });
+ }
+ };
+
+ const updateDbidPosition = (viewer, data) => {
+ if (!viewer) return;
+ if (!forgeViewer.value) forgeViewer.value = markRaw(viewer);
+ const tree = viewer.model.getData().instanceTree;
+ const fragList = viewer.model.getFragmentList();
+ for (let [key, value] of Object.entries(data)) {
+ const nodebBox = new window.THREE.Box3();
+
+ // for each fragId on the list, get the bounding box
+ tree.enumNodeFragments(
+ value.forge_dbid,
+ (fragId) => {
+ const fragbBox = new window.THREE.Box3();
+ fragList.getWorldBounds(fragId, fragbBox);
+ nodebBox.union(fragbBox); // create a unifed bounding box
+ },
+ true
+ );
+ subscribeData.value[key].device_coordinate_3d = viewer.worldToClient(
+ nodebBox.getCenter()
+ );
+ subscribeData.value[key].is_show = viewer.isNodeVisible(value.forge_dbid);
+ }
+ };
+
+ const fitToView = () => {
+ if(!searchParams.value.camera_position) return
+ const { x, y, z } = JSON.parse(searchParams.value.camera_position);
+ const newPosition = new THREE.Vector3(x, y, z); //!<<< 相机的新位置
+
+ const {
+ x: x1,
+ y: y1,
+ z: z1,
+ } = JSON.parse(searchParams.value.target_position); //!<<< 计算新焦点位置
+ const newTarget = new THREE.Vector3(x1, y1, z1); //!<<< 焦點的新位置
+
+ forgeViewer.value.navigation.getCamera().setView({
+ position: newPosition.clone(),
+ target: newTarget.clone(),
+ });
+ setTimeout(() => {
+ updateDbidPosition(forgeViewer.value, subscribeData.value);
+ }, 700);
+ };
+
+ const hideAllObjects = (instanceTree, filDbids = []) => {
+ const tree = instanceTree || forgeViewer.value.model?.getInstanceTree();
+ const allDbIdsStr = Object.keys(tree.nodeAccess.dbIdToIndex);
+ for (var i = 0; i < allDbIdsStr.length; i++) {
+ forgeViewer.value.hide(parseInt(allDbIdsStr[i]));
+ }
+
+ for (var i = 0; i < filDbids.length; i++) {
+ forgeViewer.value.show(parseInt(filDbids[i]));
+ }
+ fitToView();
+ forgeViewer.value.impl.invalidate(true);
+ };
+
+ const loadModel = (viewer, urn) => {
+ return new Promise(function (resolve, reject) {
+ async function onDocumentLoadSuccess(doc) {
+ viewer.setGroundShadow(false);
+ viewer.impl.renderer().setClearAlpha(0); //clear alpha channel
+ viewer.impl.glrenderer().setClearColor(0xffffff, 0); //set transparent background, color code does not matter
+ viewer.impl.invalidate(true); //trigger rendering
+
+ const documentNode = await viewer.loadDocumentNode(
+ doc,
+ doc.getRoot().getDefaultGeometry()
+ );
+
+ resolve(documentNode);
+ }
+ function onDocumentLoadFailure(code, message, errors) {
+ reject({ code, message, errors });
+ }
+ Autodesk.Viewing.Document.load(
+ "urn:" + urn,
+ onDocumentLoadSuccess,
+ onDocumentLoadFailure
+ );
+ });
+ };
+
+ const reloadModal = () => {};
+
+ watch(visibleDbid, (newValue) => {
+ forgeViewer.value &&
+ hideAllObjects(forgeViewer.value.model.getData().instanceTree, newValue);
+ });
+
+ watch(initialData, (newValue) => {
+ if (newValue) {
+ getDevice(searchParams.value.option);
+ }
+ });
+
+ watch(
+ searchParams,
+ (newValue) => {
+ getDevice(newValue.option);
+ },
+ {
+ deep: true,
+ }
+ );
+
+ return {
+ subscribeData,
+ visibleDbid,
+ updateDbidPosition,
+ hideAllObjects,
+ updateForgeViewer,
+ loadModel,
+ urn,
+ updateInitialData,
+ subComponents,
+ };
+}
diff --git a/src/hooks/forge/useForgeFloor.js b/src/hooks/forge/useForgeFloor.js
new file mode 100644
index 0000000..aa2f196
--- /dev/null
+++ b/src/hooks/forge/useForgeFloor.js
@@ -0,0 +1,115 @@
+import useSelectedFloor from "@/hooks/useSelectedFloor";
+import { watch, ref, inject } from "vue";
+import { useRoute } from "vue-router";
+import useSystemShowData from "@/hooks/useSystemShowData";
+
+function useForgeFloor() {
+ const route = useRoute();
+ const levelList = ref([]);
+ const { selectedFloor } = useSelectedFloor();
+ const { subscribeData } = inject("system_deviceList");
+
+ const forgeViewer = ref(null);
+ const dataVizExtn = ref(null);
+ const updateViewerFloor = (viewer, dataVisualization) => {
+ forgeViewer.value = viewer;
+ dataVizExtn.value = dataVisualization;
+ };
+
+ const findLevels = () => {
+ forgeViewer.value.model.search(
+ "layer",
+ (nodeIds) => {
+ let levels = [];
+ const tree = forgeViewer.value.model.getInstanceTree();
+ for (let i = 0; i < nodeIds.length; i++) {
+ const dbId = nodeIds[i];
+ const name = tree.getNodeName(dbId);
+ if (!name || name.includes("<沒有層級>")) continue;
+ levels.push({
+ guid: dbId,
+ name,
+ dbId,
+ extension: {
+ buildingStory: true,
+ structure: false,
+ computationHeight: 0,
+ groundPlane: false,
+ hasAssociatedViewPlans: false,
+ },
+ });
+ }
+ levels = levels.sort((a, b) => b.elevation - a.elevation);
+ console.log(levels);
+ levelList.value = levels;
+ },
+ (e) => {
+ console.log(e);
+ }
+ );
+ };
+
+ watch(forgeViewer, () => {
+ findLevels();
+ });
+
+ const hideDbIdFn = () => {
+ const tree = forgeViewer.value?.model.getInstanceTree();
+ const allDbIdsStr = Object.keys(tree.nodeAccess.dbIdToIndex);
+ for (var i = 0; i < allDbIdsStr.length; i++) {
+ forgeViewer.value.hide(parseInt(allDbIdsStr[i]));
+ }
+ };
+
+ const { flatSubData } = useSystemShowData();
+ const showDbIdFn = () => {
+ hideDbIdFn();
+ flatSubData.value.forEach((value, index) => {
+ forgeViewer.value.show(value.forge_dbid);
+ });
+
+ forgeViewer.value.impl.invalidate(true);
+ };
+
+ const showLevels = () => {
+ if (forgeViewer.value) {
+ const currentFloorName =
+ selectedFloor.value?.title?.replaceAll(/U/gi, "") || "";
+
+ const level = levelList.value.find(({ name }) =>
+ name.includes(currentFloorName)
+ );
+ console.log(currentFloorName, level);
+
+ if (!level) {
+ forgeViewer.value?.impl.toggleGhosting(true);
+ forgeViewer.value?.fitToView([forgeViewer.value.model.getRootId()]);
+ showDbIdFn();
+ } else {
+ showDbIdFn();
+ // forgeViewer.value.clearSelection();
+ // forgeViewer.value.model.setAllVisibility(0);
+ forgeViewer.value.impl.toggleGhosting(false);
+ // forgeViewer.value.impl.toggleGroundShadow(false);
+ forgeViewer.value.show(level.dbId);
+ forgeViewer.value.impl.invalidate(true);
+ forgeViewer.value.fitToView([level.dbId]);
+ }
+ }
+ };
+
+ watch(
+ () => route,
+ (newValue) => {
+ console.log(newValue);
+ newValue && showLevels();
+ },
+ {
+ deep: true,
+ }
+ );
+
+ return { findLevels, showLevels, updateViewerFloor };
+}
+
+export default useForgeFloor;
diff --git a/src/hooks/forge/useForgeHeatmap.js b/src/hooks/forge/useForgeHeatmap.js
new file mode 100644
index 0000000..7ae588c
--- /dev/null
+++ b/src/hooks/forge/useForgeHeatmap.js
@@ -0,0 +1,141 @@
+import { watch, inject, markRaw, ref, computed, onMounted } from "vue";
+import { useRoute } from "vue-router";
+import useHeatmapBarStore from "@/stores/useHeatmapBarStore";
+import useSystemShowData from "@/hooks/useSystemShowData";
+
+export default function useForgeHeatmap() {
+ const route = useRoute();
+ const { subscribeData, realtimeData } = inject("system_deviceList");
+
+ const store = useHeatmapBarStore();
+
+ const forgeViewer = ref(null);
+ const dataVizExtn = ref(null);
+ const updateViewExtension = (viewer, dataVisualization) => {
+ forgeViewer.value = viewer;
+ dataVizExtn.value = dataVisualization;
+ };
+
+ //create the heatmap
+ function getSensorValue(device, sensorType, pointData) {
+ const dev = realtimeData.value.find(
+ ({ device_number }) => device_number === device.id
+ );
+ if (dev) {
+ const [min, max] = store.heatmapConfig?.range;
+ const point = dev.data.find(({ point }) => point === route.query?.gas);
+ console.log(9, device, dev, point, (point?.value - min || 0) / max);
+
+ return Math.random();
+ }
+ return 0;
+ }
+
+ const { flatSubData } = useSystemShowData();
+
+ const data = computed(() =>
+ flatSubData.value?.map((d) => {
+ const pointsMap = d.points ? Object.fromEntries(d.points.map(({ point, value }) => [point, 0])) : {};
+ return {
+ ...d,
+ ...pointsMap,
+ };
+ })
+ );
+
+ watch(
+ () => realtimeData,
+ () => {
+ dataVizExtn.value &&
+ Object.keys(dataVizExtn.value?.surfaceShading)?.length &&
+ dataVizExtn.value.updateSurfaceShading(getSensorValue);
+ },
+ {
+ deep: true,
+ }
+ );
+
+ const createHeatMap = async () => {
+ if (route.query?.gas === "all" || !route.query?.gas || !dataVizExtn.value) return;
+ const heatMapName = `iot_heatmap_${route.query?.gas}`;
+ console.log("createHeatMap", heatMapName);
+ const {
+ SurfaceShadingData,
+ SurfaceShadingPoint,
+ SurfaceShadingNode,
+ SurfaceShadingGroup,
+ } = Autodesk.DataVisualization.Core;
+ const shadingGroup = new SurfaceShadingGroup(`${heatMapName}`);
+ const rooms = new Map();
+
+ const roomSet = new Set(data.value.filter(({ device_coordinate_3d }) => device_coordinate_3d).map(({ room_dbid }) => room_dbid));
+ // 每個room是一個node
+ [...roomSet].forEach((roomDbId) => {
+ if (!roomDbId) {
+ return;
+ }
+ const room = new SurfaceShadingNode(`room_${roomDbId}`, roomDbId);
+
+ //相同room內的設備
+ data.value
+ .filter(({ room_dbid }) => room_dbid === roomDbId)
+ .forEach(
+ ({
+ device_number: id,
+ device_coordinate_3d: position,
+ sensorTypes,
+ }) =>
+ room.addPoint(new SurfaceShadingPoint(id, position, sensorTypes))
+ );
+
+ shadingGroup.addChild(room);
+ });
+
+ // data.value.forEach(
+ // ({
+ // device_number: id,
+ // room_dbid: roomDbId,
+ // device_coordinate_3d: position,
+ // sensorTypes,
+ // }) => {
+ // if (!id || roomDbId == -1 || !roomDbId) {
+ // return;
+ // }
+ // if (!rooms.has(roomDbId)) {
+ // const room = new SurfaceShadingNode(id, roomDbId);
+ // shadingGroup.addChild(room);
+ // rooms.set(roomDbId, room);
+ // }
+ // const room = rooms.get(roomDbId);
+ // room.addPoint(new SurfaceShadingPoint(id, position, route.query.gas));
+ // }
+ // );
+ const shadingData = new SurfaceShadingData(`${heatMapName}`);
+ shadingData.addChild(shadingGroup);
+ shadingData.initialize(forgeViewer.value?.model);
+ await dataVizExtn.value.setupSurfaceShading(
+ forgeViewer.value.model,
+ shadingData
+ );
+ dataVizExtn.value.registerSurfaceShadingColors(
+ route.query?.gas,
+ store.heatmapConfig?.color
+ );
+ dataVizExtn.value.renderSurfaceShading(
+ heatMapName,
+ route.query?.gas,
+ getSensorValue
+ );
+ };
+
+ watch(
+ data,
+ (newValue, oldValue) => {
+ dataVizExtn.value?.removeSurfaceShading();
+ createHeatMap(route.query.gas);
+ },
+ { deep: true }
+ );
+
+ return { createHeatMap, updateViewExtension };
+}
diff --git a/src/hooks/forge/useForgeSprite.js b/src/hooks/forge/useForgeSprite.js
new file mode 100644
index 0000000..d0abad8
--- /dev/null
+++ b/src/hooks/forge/useForgeSprite.js
@@ -0,0 +1,222 @@
+import { watch, inject, markRaw, ref, computed, provide } from "vue";
+import useAlarmStore from "@/stores/useAlarmStore";
+import hexToRgb from "@/util/hexToRgb";
+import useSystemShowData from "@/hooks/useSystemShowData";
+import useForgeHeatmap from "./useForgeHeatmap";
+import useForgeFloor from "./useForgeFloor";
+
+export default function useForgeSprite() {
+ const { subscribeData } = inject("system_deviceList");
+ const { getCurrentInfoModalData, clearSelectedDeviceInfo, selected_dbid } =
+ inject("system_selectedDevice");
+ const forgeViewer = ref(null);
+ const dataVizExtn = ref(null);
+ let lastClickedDbId = null;
+
+ const { createHeatMap, updateViewExtension } = useForgeHeatmap();
+ const { updateViewerFloor } = useForgeFloor();
+
+ const setCameraPosition = (position, target) => {
+ // 使用 THREE.Vector3 定義位置與焦點
+ const newPosition = new THREE.Vector3(position.x, position.y, position.z);
+ const newTarget = new THREE.Vector3(target.x, target.y, target.z);
+
+ // 設定攝影機的新位置與焦點
+ forgeViewer.value.navigation.setView(newPosition, newTarget);
+
+ // 確保 Home 視角
+ forgeViewer.value.autocam.setCurrentViewAsHome(true);
+ };
+
+ const updateDataVisualization = async (viewer) => {
+ if (!forgeViewer.value) {
+ forgeViewer.value = markRaw(viewer);
+ }
+
+ const dataVisualization = await viewer.loadExtension(
+ "Autodesk.DataVisualization"
+ );
+ dataVizExtn.value = markRaw(dataVisualization);
+ updateViewExtension(markRaw(viewer), markRaw(dataVisualization));
+ updateViewerFloor(markRaw(viewer), markRaw(dataVisualization));
+ };
+
+ function onSpriteClicked(event) {
+ event.hasStopped = true;
+
+ if (event.type === Autodesk.DataVisualization.Core.MOUSE_CLICK_OUT) return;
+
+ const data = subscribeData.value.find(
+ (d) =>
+ d.spriteDbId === event.dbId || d.forge_dbid === event.dbIdArray?.[0]
+ );
+ console.log("onSpriteClicked", event.target);
+ console.log("onSpriteClicked", data);
+ // modalContent.value = data;
+ // debugger;
+ if (data) {
+ getCurrentInfoModalData(
+ event,
+ { left: event.target.startX, top: event.target.startY },
+ data
+ );
+ }
+ }
+
+ const { flatSubData } = useSystemShowData();
+
+ // 創建 sprites
+ const createSprites = async () => {
+ if (dataVizExtn.value) {
+ dataVizExtn.value.removeAllViewables();
+ const DataVizCore = Autodesk.DataVisualization.Core;
+ const viewableType = DataVizCore.ViewableType.SPRITE;
+ let spriteColor = new THREE.Color(0xffffff);
+ const BASEURL = import.meta.env.VITE_FORGE_BASEURL;
+ const spriteIconUrl = `${BASEURL}/hotspot.svg`;
+ const style = new DataVizCore.ViewableStyle(
+ viewableType,
+ spriteColor,
+ spriteIconUrl
+ );
+ const viewableData = new DataVizCore.ViewableData();
+ viewableData.spriteSize = 24; // Sprites as points of size 24 x 24 pixels
+ flatSubData.value?.forEach((d, index) => {
+ if (d.device_coordinate_3d) {
+ const position = d.device_coordinate_3d;
+ style.color = new THREE.Color(hexToRgb(d.device_normal_color));
+ const viewable = new DataVizCore.SpriteViewable(
+ position,
+ style,
+ d.spriteDbId
+ );
+ viewableData.addViewable(viewable);
+ }
+ });
+ // await viewableData.finish();
+ // dataVizExtn.value.addViewables(viewableData);
+ // console.log(dataVizExtn.value);
+ viewableData.finish().then(
+ () => {
+ dataVizExtn.value.addViewables(viewableData);
+ createHeatMap();
+ },
+ (error) => {
+ console.log(error);
+ }
+ );
+ }
+ };
+
+ watch(
+ () => flatSubData,
+ () => {
+ if (forgeViewer.value?.isLoadDone()) {
+ createSprites();
+ showSubSystemObjects();
+ }
+ },
+ {
+ deep: true,
+ }
+ );
+
+ watch(
+ () => selected_dbid,
+ () => {
+ if (forgeViewer.value?.isLoadDone()) {
+ cardfitToView(selected_dbid.value);
+ }
+ },
+ {
+ immediate: true,
+ deep: true,
+ }
+ );
+
+ const forgeClickListener = () => {
+ console.log("監聽forge");
+
+ forgeViewer.value.addEventListener(
+ Autodesk.DataVisualization.Core.MOUSE_CLICK,
+ onSpriteClicked
+ );
+ forgeViewer.value.addEventListener(
+ Autodesk.DataVisualization.Core.MOUSE_CLICK_OUT,
+ onSpriteClicked
+ );
+ };
+
+ const cardfitToView = async ([forge_dbid, spriteDbId]) => {
+ try {
+ // 相機調整
+ const nav = forgeViewer.value.navigation;
+ const camera = nav.getCamera();
+ forgeViewer.value.fitToView([forge_dbid], null, true);
+ const direction = new THREE.Vector3();
+ camera.getWorldDirection(direction);
+ const distanceBack = 30;
+ camera.position.add(direction.multiplyScalar(-distanceBack));
+ const target = nav.getTarget();
+ const fov = nav.getVerticalFov();
+ nav.setRequestTransition(true, camera.position, target, fov);
+
+ if (lastClickedDbId !== null && lastClickedDbId !== spriteDbId) {
+ dataVizExtn.value.invalidateViewables([lastClickedDbId], (viewable) => {
+ return {
+ scale: 1.0, // 恢復為 scale 1
+ };
+ });
+ }
+
+ dataVizExtn.value.invalidateViewables([spriteDbId], (viewable) => {
+ return {
+ scale: 2.0, // 設置為 scale 2
+ };
+ });
+
+ lastClickedDbId = spriteDbId;
+ } catch (error) {
+ console.error("Error in cardfitToView:", error);
+ }
+ };
+
+ const hideAllObjects = () => {
+ const tree = forgeViewer.value.model.getInstanceTree();
+ const allDbIdsStr = Object.keys(tree.nodeAccess.dbIdToIndex);
+ for (var i = 0; i < allDbIdsStr.length; i++) {
+ forgeViewer.value.hide(parseInt(allDbIdsStr[i]));
+ }
+ };
+
+ const showSubSystemObjects = () => {
+ hideAllObjects();
+ flatSubData.value.forEach((value, index) => {
+ forgeViewer.value.show(value.forge_dbid);
+ });
+
+ forgeViewer.value.impl.invalidate(true);
+ };
+
+ const clear = () => {
+ forgeViewer.value.removeEventListener(
+ Autodesk.DataVisualization.Core.MOUSE_CLICK,
+ onSpriteClicked
+ );
+ forgeViewer.value.removeEventListener(
+ Autodesk.DataVisualization.Core.MOUSE_CLICK_OUT,
+ onSpriteClicked
+ );
+ forgeViewer.value.tearDown();
+ };
+
+ return {
+ createSprites,
+ setCameraPosition,
+ updateDataVisualization,
+ showSubSystemObjects,
+ forgeClickListener,
+ clear,
+ cardfitToView,
+ };
+}
diff --git a/src/hooks/useActiveBtn.js b/src/hooks/useActiveBtn.js
new file mode 100644
index 0000000..9691ab2
--- /dev/null
+++ b/src/hooks/useActiveBtn.js
@@ -0,0 +1,41 @@
+import { computed } from "@vue/reactivity";
+import { ref } from "vue";
+export default function useActiveBtn(type = "single") {
+ // default buttons
+ const items = ref([]);
+
+ const setItems = (btnGroup) => {
+ items.value = btnGroup;
+ };
+
+ const selectedBtn = computed(() => {
+ if (type === "single") {
+ return items.value?.find((d) => {
+ return d.active
+ });
+ } else if (type === "multiple") {
+ return items.value?.filter(({ active }) => active);
+ }
+ });
+
+ // change active button
+ const changeActiveBtn = (item) => {
+ if (type === "single") {
+ // 先將全部變成false
+ const newItems = Object.assign(items.value).map((it) => ({
+ ...it,
+ active: item.key === it.key,
+ }));
+ items.value = newItems;
+ } else if (type === "multiple") {
+ // 先將全部變成false
+ const newItems = Object.assign(items.value).map((it) => ({
+ ...it,
+ active: item.key === it.key ? !item.active : it.active,
+ }));
+ items.value = newItems;
+ }
+ };
+
+ return { items, changeActiveBtn, setItems, selectedBtn };
+}
diff --git a/src/hooks/useDashboardOption.js b/src/hooks/useDashboardOption.js
new file mode 100644
index 0000000..ad2117a
--- /dev/null
+++ b/src/hooks/useDashboardOption.js
@@ -0,0 +1,20 @@
+import { inject, watch } from "vue";
+
+export default function useDashboardOption(
+ SetFn,
+ injectData = "dashboard_items"
+) {
+ const { initialData } = inject(injectData);
+
+ watch(initialData, (newValue) => {
+ const data = newValue.points[1].values.filter(({ value }) => value !== 0);
+ SetFn(
+ data.map(({ value, text }, index) => ({
+ title: text,
+ key: `option_${value}`,
+ active: index === 0,
+ typeOption: value,
+ }))
+ );
+ });
+}
diff --git a/src/hooks/useFormErrorMessage.js b/src/hooks/useFormErrorMessage.js
new file mode 100644
index 0000000..4d40f21
--- /dev/null
+++ b/src/hooks/useFormErrorMessage.js
@@ -0,0 +1,50 @@
+import { onMounted, ref } from "vue";
+
+export default function useFormErrorMessage(scheme) {
+ const formErrorMsg = ref({});
+
+ onMounted(() => {
+ // formErrorMsg.value = scheme
+ if (scheme) {
+ formErrorMsg.value = Object.fromEntries(
+ Object.keys(scheme.fields).map((f) => [f, ""])
+ );
+ }
+ });
+
+ const handleSubmit = (scheme, value) => {
+ return new Promise((resolve, reject) => {
+ scheme
+ .validate(value, {
+ abortEarly: false,
+ })
+ .then((res) => resolve(res))
+ .catch((err) => {
+ let errorMsg = Object.fromEntries(
+ err.inner.map((e) => [e.path, e.message])
+ );
+ formErrorMsg.value = errorMsg;
+ reject(errorMsg);
+ });
+ });
+ };
+
+ const handleErrorReset = () => {
+ // formErrorMsg.value = Object.fromEntries(
+ // Object.keys(scheme.fields).map((f) => [f, ""])
+ // );
+ let resetMsg = {};
+ for (let key in formErrorMsg.value) {
+ resetMsg[key] = "";
+ }
+ formErrorMsg.value = resetMsg;
+ };
+
+ const updateScheme = (scheme) => {
+ formErrorMsg.value = Object.fromEntries(
+ Object.keys(scheme.fields).map((f) => [f, ""])
+ );
+ };
+
+ return { formErrorMsg, handleSubmit, handleErrorReset, updateScheme };
+}
diff --git a/src/hooks/useGetCookie.js b/src/hooks/useGetCookie.js
new file mode 100644
index 0000000..6d150b0
--- /dev/null
+++ b/src/hooks/useGetCookie.js
@@ -0,0 +1,8 @@
+export default function getCookie(cookieName) {
+ let cookie = {};
+ document.cookie.split(";").forEach(function (el) {
+ let [key, value] = el.split("=");
+ cookie[key.trim()] = value;
+ });
+ return cookie[cookieName];
+}
diff --git a/src/hooks/useGetDevice.js b/src/hooks/useGetDevice.js
new file mode 100644
index 0000000..a717fe6
--- /dev/null
+++ b/src/hooks/useGetDevice.js
@@ -0,0 +1,31 @@
+import { ref, computed } from "vue";
+import instance from "@/util/request";
+import { GET_DEVICELIST_API } from "@/constant";
+
+export default function useGetDevice() {
+ const deviceList = ref(null);
+ //取得設備列表
+ const getDeviceList = async ({
+ building_tag,
+ main_system_tag,
+ sub_system_tag,
+ floor_tag,
+ }) => {
+ const res = await instance.post(GET_DEVICELIST_API, {
+ building_tag,
+ floor_tag,
+ sub_system_tag,
+ });
+
+ let devices = []
+ res.data.data.forEach(({device_list})=>{
+ devices = [...devices, ...device_list]
+ })
+ deviceList.value = devices;
+ };
+
+ return {
+ deviceList,
+ getDeviceList,
+ };
+}
diff --git a/src/hooks/useSearchParam.js b/src/hooks/useSearchParam.js
new file mode 100644
index 0000000..c971a02
--- /dev/null
+++ b/src/hooks/useSearchParam.js
@@ -0,0 +1,29 @@
+// 取得目前的params
+import { computed } from "vue";
+import { useRouter, useRoute } from "vue-router";
+
+export default function useSearchParam() {
+ const router = useRouter();
+ const route = useRoute();
+
+ const searchParams = computed(() => route.query);
+
+ // 排除null
+
+ const deleteNull = (query) => {
+ let newQuery = {};
+ for (let key in query) {
+ if (Array.isArray(query[key]) && query[key].length === 0) continue;
+ if (query[key]) {
+ newQuery[key] = query[key];
+ }
+ }
+ return newQuery;
+ };
+
+ const changeParams = (query) => {
+ router.push({ path: route.path, query: deleteNull(query) });
+ };
+
+ return { searchParams, changeParams };
+}
diff --git a/src/hooks/useSelectedFloor.js b/src/hooks/useSelectedFloor.js
new file mode 100644
index 0000000..986c62d
--- /dev/null
+++ b/src/hooks/useSelectedFloor.js
@@ -0,0 +1,17 @@
+import { useRoute } from "vue-router";
+import { computed, inject, ref, watch } from "vue";
+
+function useSelectedFloor() {
+ const { currentFloor } = inject("system_deviceList");
+ const route = useRoute();
+ const selectedFloor = computed(() =>
+ currentFloor.value?.find(({ key }) => key == route.params.floor_id)
+ );
+
+ return {
+ selectedFloor,
+ currentFloor,
+ };
+}
+
+export default useSelectedFloor;
diff --git a/src/hooks/useSystemShowData.js b/src/hooks/useSystemShowData.js
new file mode 100644
index 0000000..97f5457
--- /dev/null
+++ b/src/hooks/useSystemShowData.js
@@ -0,0 +1,27 @@
+import useSelectedFloor from "@/hooks/useSelectedFloor";
+import { computed, inject, watch } from "vue";
+
+function useSystemShowData() {
+ const { data } = inject("system_deviceList");
+ const { selectedFloor } = useSelectedFloor();
+
+ const showData = computed(() =>
+ selectedFloor.value?.key === "main"
+ ? data.value
+ : data.value.filter(
+ ({ floor_guid }) => floor_guid === selectedFloor.value?.key
+ ) || []
+ );
+
+ const flatSubData = computed(() => {
+ let items = [];
+ showData.value.forEach((device) => {
+ items = [...items, ...device.device_list];
+ });
+ return items;
+ });
+
+ return { showData, flatSubData };
+}
+
+export default useSystemShowData;
diff --git a/src/main.js b/src/main.js
new file mode 100644
index 0000000..9814296
--- /dev/null
+++ b/src/main.js
@@ -0,0 +1,60 @@
+import "./assets/index.css";
+import "./assets/main.css";
+// import "./assets/table.css";
+import "./assets/btn.css";
+import "./assets/pagination.css";
+
+import { createApp } from "vue";
+import { createI18n } from "vue-i18n";
+import tw from "./config/tw.json";
+import cn from "./config/cn.json";
+import us from "./config/us.json";
+import Antd from "ant-design-vue";
+import { createPinia } from "pinia";
+import App from "./App.vue";
+import router from "./router";
+import "virtual:svg-icons-register";
+// 引入项目中的全部全局组件
+import SvgIcon from "@/components/SvgIcon.vue";
+import library from "./fontawsomeIconRegister";
+import "flag-icons/css/flag-icons.min.css";
+
+/* import font awesome icon component */
+import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
+
+import { focusPlugin } from "@/directives/focusPlugin";
+import { draggable } from "@/directives/draggable";
+const messages = {
+ tw,
+ cn,
+ us,
+};
+
+const storedLanguage = localStorage.getItem("EmpowerLanguage") || "tw";
+
+const i18n = createI18n({
+ legacy: false,
+ locale: storedLanguage,
+ fallbackLocale: 'tw',
+ messages,
+});
+const app = createApp(App);
+app.use(createPinia());
+app.use(router);
+app.use(Antd);
+app.use(i18n);
+
+// 组装成一个对象
+const allGlobalComponents = { SvgIcon, FontAwesomeIcon };
+const globalComponent = {
+ install(app) {
+ // 循环注册所有的全局组件
+ Object.keys(allGlobalComponents).forEach((componentName) => {
+ app.component(componentName, allGlobalComponents[componentName]);
+ });
+ },
+};
+app.use(globalComponent);
+app.use(focusPlugin);
+app.use(draggable);
+app.mount("#app");
diff --git a/src/router/index-84b479b.js b/src/router/index-84b479b.js
new file mode 100644
index 0000000..01b98c5
Binary files /dev/null and b/src/router/index-84b479b.js differ
diff --git a/src/router/index.js b/src/router/index.js
new file mode 100644
index 0000000..49db595
--- /dev/null
+++ b/src/router/index.js
@@ -0,0 +1,116 @@
+import { createRouter, createWebHashHistory } from "vue-router";
+import useUserInfoStore from "@/stores/useUserInfoStore";
+import useGetCookie from "@/hooks/useGetCookie";
+import System from "@/views/system/System.vue";
+import SystemFloor from "@/views/system/SystemFloor.vue";
+
+const router = createRouter({
+ history: createWebHashHistory(import.meta.env.BASE_URL),
+ routes: [
+ {
+ path: "/login",
+ name: "login",
+ component: () => import("@/views/login/Login.vue"),
+ },
+ {
+ path: "/dashboard",
+ index: true,
+ name: "dashboard",
+ component: () => import("@/views/dashboard/Dashboard.vue"),
+ },
+ {
+ path: "/system/:main_system_id/:sub_system_id",
+ name: "system",
+ component: () => import("@/views/system/System.vue"),
+ children: [
+ {
+ path: ":floor_id",
+ name: "sub_system",
+ component: () => import("@/views/system/SystemMain.vue"),
+ },
+ ],
+ },
+ {
+ path: "/historyData",
+ name: "history",
+ component: () => import("@/views/history/History.vue"),
+ },
+ {
+ path: "/operation",
+ name: "operation",
+ component: () => import("@/views/operation/Operation.vue"),
+ },
+ {
+ path: "/graphManagement",
+ name: "graphManagement",
+ component: () => import("@/views/graphManagement/GraphManagement.vue"),
+ },
+ {
+ path: "/accountManagement",
+ name: "accountManagement",
+ component: () =>
+ import("@/views/accountManagement/AccountManagement.vue"),
+ },
+ {
+ path: "/assetManagement",
+ name: "assetManagement",
+ component: () => import("@/views/AssetManagement/AssetManagement.vue"),
+ },
+ {
+ path: "/alert",
+ name: "alert",
+ component: () => import("@/views/alert/AlertManagement.vue"),
+ },
+ {
+ path: "/energyManagement",
+ name: "energyManagement",
+ component: () => import("@/views/energyManagement/EnergyManagement.vue"),
+ },
+ {
+ path: "/setting/:main_system_id/:sub_system_id/:type",
+ name: "setting",
+ component: () => import("@/views/setting/SettingManagement.vue"),
+ },
+ {
+ path: "/mytestfile/mjm",
+ name: "mytestfile",
+ component: () => import("@/views/Test.vue"),
+ },
+ ],
+});
+
+router.beforeEach(async (to, from, next) => {
+ console.log("route", to, location, document.cookie);
+ // redirect to login page if not logged in and trying to access a restricted page
+ const publicPages = ["/login", "/"];
+ const authRequired = !publicPages.includes(to.path);
+ const auth = useUserInfoStore();
+ const token = useGetCookie("JWT-Authorization");
+ const user_name = useGetCookie("user_name");
+
+ if (to.path === "/logout") {
+ document.cookie = "JWT-Authorization=; Max-Age=0";
+ document.cookie = "user_name=; Max-Age=0";
+ auth.user.token = "";
+ auth.user.user_name = "";
+ localStorage.removeItem("EmpowerBuilding");
+ window.location.reload();
+ next({ path: "/login" });
+ }
+
+ if ((authRequired && !token) || to.path === "/") {
+ auth.user.token = "";
+ next({ path: "/login" });
+ } else if (!authRequired) {
+ document.cookie = "JWT-Authorization=; Max-Age=0";
+ document.cookie = "user_name=; Max-Age=0";
+ auth.user.token = "";
+ auth.user.user_name = "";
+ } else {
+ auth.user.token = token;
+ auth.user.user_name = user_name;
+ }
+ next();
+});
+
+export default router;
diff --git a/src/stores/useAlarmStore.js b/src/stores/useAlarmStore.js
new file mode 100644
index 0000000..7624b7d
--- /dev/null
+++ b/src/stores/useAlarmStore.js
@@ -0,0 +1,63 @@
+import { defineStore } from "pinia";
+import { onMounted, ref } from "vue";
+import dayjs from "dayjs";
+import { getAllDevice } from "@/apis/building";
+
+const useAlarmStore = defineStore("alarmData", () => {
+ let timer = null;
+ const alarmData = ref([]);
+ const allDeviceList = ref([]);
+
+ const getFormateDate = (datetime, format_rule = "YYYY-MM-DD HH:mm") => {
+ return dayjs(datetime).format(format_rule);
+ };
+ // get data from baja
+ const getAlarmDataFromBaja = () => {
+ const alarms = [];
+ const sampleDeviceNames = ["AA", "DeviceB", "DeviceC", "DeviceD"];
+ const sampleMsgs = [
+ "Over temperature",
+ "Power failure",
+ "Sensor malfunction",
+ "Connection lost",
+ ];
+
+ for (let i = 0; i < 3; i++) {
+ const timestamp = Date.now() - Math.floor(Math.random() * 100000000);
+
+ const device_number = `NTPC_F1_Dust_EM_U9F_NA_AD_AA${Math.floor(Math.random() * 5) + 1}`;
+
+ alarms.push({
+ uuid: `uuid-${i+1}`,
+ building_tag: "U9F",
+ timestamp_date: new Date(timestamp).toLocaleDateString("en-US"),
+ timestamp_time: new Date(timestamp).toLocaleTimeString("en-US"),
+ alarmClass: `Class ${Math.floor(Math.random() * 3) + 1}`,
+ device_number,
+ full_name: `AA${Math.floor(Math.random() * 5) + 1}`,
+ msg: sampleMsgs[Math.floor(Math.random() * sampleMsgs.length)],
+ sourceState: "offnormal",
+ normalTime: new Date(timestamp).toLocaleString("en-US"),
+ ackState: "Unacked",
+ ackedTime:
+ Math.random() > 0.5
+ ? new Date(timestamp).toLocaleString("en-US")
+ : null,
+ });
+ }
+
+ alarmData.value = alarms;
+ };
+
+ const getDevice = async () => {
+ const res = await getAllDevice();
+ allDeviceList.value = res.data;
+ };
+
+ onMounted(() => {
+ getDevice();
+ });
+
+ return { getAlarmDataFromBaja, alarmData };
+});
+export default useAlarmStore;
diff --git a/src/stores/useBuildingStore.js b/src/stores/useBuildingStore.js
new file mode 100644
index 0000000..40307a0
--- /dev/null
+++ b/src/stores/useBuildingStore.js
@@ -0,0 +1,129 @@
+import { defineStore } from "pinia";
+import { ref, computed, watch } from "vue";
+import { useRoute } from "vue-router";
+import { getBuildings, getAllSysSidebar } from "@/apis/building";
+import { getAssetFloorList, getDepartmentList } from "@/apis/asset";
+import { getSystemConfig } from "@/apis/system";
+
+const useBuildingStore = defineStore("buildingInfo", () => {
+ // 狀態定義
+ const buildings = ref([]);
+ const selectedBuilding = ref(null);
+ const floorList = ref([]);
+ const deptList = ref([]);
+ const mainSubSys = ref([]);
+ const sysConfig = ref([]);
+
+ // 計算屬性
+ const mainSys = computed(() =>
+ mainSubSys.value.map(({ main_system_tag, full_name }) => ({
+ main_system_tag,
+ full_name,
+ }))
+ );
+
+ const subSys = computed(() => {
+ let subPages = [];
+ mainSubSys.value.forEach(({ main_system_tag, history_Sub_systems }) => {
+ subPages = [
+ ...subPages,
+ ...history_Sub_systems.map((Sub) => ({
+ ...Sub,
+ main_system_tag,
+ key: Sub.sub_system_tag,
+ })),
+ ];
+ });
+ return subPages;
+ });
+
+ const route = useRoute();
+ const selectedSystem = computed(() => {
+ if (route.params.sub_system_id && subSys.value.length > 0) {
+ return subSys.value.find((s) => s.key === route.params.sub_system_id);
+ }
+ return null;
+ });
+
+ // 獲取所有建築物
+ const fetchBuildings = async () => {
+ const res = await getBuildings();
+ buildings.value = res.data;
+ if (res.data.length > 0 ) {
+ selectedBuilding.value = res.data[0]; // 預設選第一個建築
+ }else{
+ selectedBuilding.value = null; // 如果沒有建築物,則設為null
+ }
+ };
+
+ // 獲取樓層資料
+ const fetchFloorList = async (building_guid) => {
+ const res = await getAssetFloorList(building_guid);
+ floorList.value =
+ res.data[0]?.floors.map((d) => ({
+ ...d,
+ title: d.full_name,
+ key: d.floor_guid,
+ })) || [];
+ };
+
+ // 獲取部門資料
+ const fetchDepartmentList = async () => {
+ const res = await getDepartmentList();
+ deptList.value =
+ res.data.map((d) => ({
+ ...d,
+ title: d.name,
+ key: d.id,
+ })) || [];
+ };
+
+ // 取得大小類
+ const getSubMonitorPage = async (building_guid) => {
+ const res = await getAllSysSidebar(building_guid);
+ mainSubSys.value = res.data.history_Main_Systems;
+ };
+
+ // 取得系統設定
+ const getSysConfig = async (building_guid) => {
+ const res = await getSystemConfig(building_guid);
+ sysConfig.value = res.data;
+ };
+
+ // 當 selectedBuilding 改變時,更新 floorList 和 deptList 和 mainSubSys
+ watch(selectedBuilding, async (newBuilding) => {
+ if (newBuilding) {
+ localStorage.setItem("EmpowerBuilding", JSON.stringify(newBuilding));
+ await Promise.all([
+ fetchFloorList(newBuilding.building_guid),
+ fetchDepartmentList(),
+ getSubMonitorPage(newBuilding.building_guid),
+ getSysConfig(newBuilding.building_guid),
+ ]);
+ }
+ });
+
+ // 初始化資料
+ const initialize = async () => {
+ await fetchBuildings();
+ };
+
+ return {
+ buildings,
+ selectedBuilding,
+ floorList,
+ deptList,
+ mainSubSys,
+ mainSys,
+ subSys,
+ selectedSystem,
+ sysConfig,
+ fetchBuildings,
+ fetchFloorList,
+ fetchDepartmentList,
+ getSubMonitorPage,
+ initialize,
+ getSysConfig,
+ };
+});
+export default useBuildingStore;
diff --git a/src/stores/useForgeDbIdStore.js b/src/stores/useForgeDbIdStore.js
new file mode 100644
index 0000000..d2ace16
--- /dev/null
+++ b/src/stores/useForgeDbIdStore.js
@@ -0,0 +1,13 @@
+import { ref, computed } from 'vue'
+import { defineStore } from 'pinia'
+
+const useForgeDbIdStore = defineStore('dbId', () => {
+ const dbId = ref([])
+ function getDbIdStore(id) {
+ dbId.value = [id]
+ }
+
+ return { dbId, getDbIdStore }
+})
+
+export default useForgeDbIdStore
\ No newline at end of file
diff --git a/src/stores/useHeatmapBarStore.js b/src/stores/useHeatmapBarStore.js
new file mode 100644
index 0000000..6533620
--- /dev/null
+++ b/src/stores/useHeatmapBarStore.js
@@ -0,0 +1,31 @@
+import { defineStore } from "pinia";
+import axios from "axios";
+import { useRoute } from "vue-router";
+import { computed, ref, onMounted } from "vue";
+
+const useHeatmapBarStore = defineStore("heatmap", () => {
+ const route = useRoute();
+
+ const allHeatMaps = ref({});
+ const heatmapConfig = computed(() => allHeatMaps.value[route.query?.gas]);
+
+ const getConfig = async () => {
+ const api =
+ import.meta.env.MODE === "production"
+ ? "/dist/config.json"
+ : "/config.json";
+ const res = await axios.get(api);
+ console.log(res);
+ allHeatMaps.value = res.data.heatmap;
+ };
+
+ onMounted(() => {
+ getConfig();
+ });
+
+ const heat_bar_isShow = computed(() => Boolean(heatmapConfig.value));
+
+ return { heatmapConfig, heat_bar_isShow };
+});
+
+export default useHeatmapBarStore;
diff --git a/src/stores/useUserInfoStore.js b/src/stores/useUserInfoStore.js
new file mode 100644
index 0000000..b552ade
--- /dev/null
+++ b/src/stores/useUserInfoStore.js
@@ -0,0 +1,19 @@
+import { defineStore } from "pinia";
+import { ref } from "vue";
+
+const useUserInfoStore = defineStore("userInfo", () => {
+ const user = ref({
+ token: "",
+ expires: 0,
+ user_name:"",
+ });
+
+ const auth_page = ref([]);
+ const updateAuthPage = (data) => {
+ auth_page.value = data;
+ };
+
+ return { user, auth_page, updateAuthPage };
+});
+
+export default useUserInfoStore;
diff --git a/src/util/apiHandler.js b/src/util/apiHandler.js
new file mode 100644
index 0000000..788c2d3
--- /dev/null
+++ b/src/util/apiHandler.js
@@ -0,0 +1,11 @@
+const apihandler = (code, successData, errorData, cb = null) => {
+ return new Promise((resolve, reject) => {
+ if (code === "0000") {
+ cb && cb(successData);
+ resolve({ data: successData, isSuccess: true });
+ }
+ resolve({ ...errorData, isSuccess: false });
+ });
+};
+
+export default apihandler;
diff --git a/src/util/clearChart.js b/src/util/clearChart.js
new file mode 100644
index 0000000..b8998f7
--- /dev/null
+++ b/src/util/clearChart.js
@@ -0,0 +1,13 @@
+const clearChart = (chart) => {
+ chart.setOption({
+ legend: {
+ data: [],
+ },
+ series: chart.getOption().series.map((d) => ({
+ ...d,
+ data: [],
+ })),
+ });
+};
+
+export default clearChart;
diff --git a/src/util/downloadExcel.js b/src/util/downloadExcel.js
new file mode 100644
index 0000000..38c5025
--- /dev/null
+++ b/src/util/downloadExcel.js
@@ -0,0 +1,42 @@
+const BASEURL = import.meta.env.VITE_API_BASEURL;
+
+export default function downloadExcel(res) {
+ let disposition = res.headers.get("Content-Disposition");
+ let sDowName = "";
+ if (disposition) {
+ // 解析出名稱
+ sDowName = disposition.split(/filename\*=(?:utf-8'')?(.*)/gi)[1];
+ if (sDowName.toLowerCase().startsWith("utf-8''"))
+ sDowName = decodeURIComponent(sDowName.replace(/utf-8''/i, ""));
+ else sDowName = sDowName.replace(/['"]/g, "");
+ sDowName = decodeURIComponent(sDowName);
+ }
+
+ let blob = res.data;
+
+ if (window.navigator.msSaveOrOpenBlob) {
+ navigator.msSaveBlob(blob, sDowName);
+ } else {
+ const link = document.createElement("a");
+ link.href = URL.createObjectURL(blob);
+ link.download = sDowName;
+ document.body.appendChild(link);
+ link.click();
+ // 釋放內存
+ window.URL.revokeObjectURL(link.link);
+ document.body.removeChild(link);
+ }
+}
+
+export const downloadExcelByHref = async (url, filename) => {
+ const response = await fetch(url);
+ const blob = await response.blob();
+
+ const link = document.createElement("a");
+ link.href = URL.createObjectURL(blob);
+ link.setAttribute("download", filename);
+ // link.setAttribute("target", "_blank");
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+};
diff --git a/src/util/getModalPosition.js b/src/util/getModalPosition.js
new file mode 100644
index 0000000..fa12076
--- /dev/null
+++ b/src/util/getModalPosition.js
@@ -0,0 +1,18 @@
+export default function getModalPosition(viewer, dbid) {
+ const tree = viewer.model.getData().instanceTree;
+ const fragList = viewer.model.getFragmentList();
+ const nodebBox = new window.THREE.Box3();
+
+ // for each fragId on the list, get the bounding box
+ tree.enumNodeFragments(
+ dbid,
+ (fragId) => {
+ const fragbBox = new window.THREE.Box3();
+ fragList.getWorldBounds(fragId, fragbBox);
+ nodebBox.union(fragbBox); // create a unifed bounding box
+ },
+ true
+ );
+ const pos = viewer.worldToClient(nodebBox.center());
+ return { left: Math.floor(pos.x), top: Math.floor(pos.y) };
+}
diff --git a/src/util/hexToRgb.js b/src/util/hexToRgb.js
new file mode 100644
index 0000000..820f4fe
--- /dev/null
+++ b/src/util/hexToRgb.js
@@ -0,0 +1,12 @@
+//hex -> rgbsensor_circle
+export default function hexToRgb(hex) {
+ return (
+ "rgb(" +
+ parseInt("0x" + hex.slice(1, 3)) +
+ "," +
+ parseInt("0x" + hex.slice(3, 5)) +
+ "," +
+ parseInt("0x" + hex.slice(5, 7)) +
+ ")"
+ );
+}
diff --git a/src/util/request.js b/src/util/request.js
new file mode 100644
index 0000000..a3f31fa
--- /dev/null
+++ b/src/util/request.js
@@ -0,0 +1,123 @@
+import useGetCookie from "@/hooks/useGetCookie";
+import axios from "axios";
+const BASEURL = import.meta.env.VITE_API_BASEURL;
+
+const instance = axios.create({
+ baseURL: BASEURL,
+ timeout: -1,
+ headers: { Authorization: `Bearer ${useGetCookie("JWT-Authorization")}` },
+});
+
+// Add a request interceptor
+instance.interceptors.request.use(
+ function (config) {
+ // Do something before request is sent
+ const token = useGetCookie("JWT-Authorization");
+ // 取得 building_guid 並加到 headers
+ let buildingGuid = "";
+ try {
+ const cviBuilding = localStorage.getItem("EmpowerBuilding");
+ if (cviBuilding) {
+ const parsed = JSON.parse(cviBuilding);
+ buildingGuid = parsed.building_guid || "";
+ }
+ } catch (e) {
+ buildingGuid = "";
+ }
+ config.headers = {
+ Authorization: `Bearer ${token}`,
+ "X-Building-GUID": buildingGuid,
+ };
+ return config;
+ },
+ function (error) {
+ // Do something with request error
+ return Promise.reject(error);
+ }
+);
+
+// Add a response interceptor
+instance.interceptors.response.use(
+ function (response) {
+ // Any status code that lie within the range of 2xx cause this function to trigger
+ // Do something with response data
+ const { status, data, headers } = response;
+
+ return {
+ ...data,
+ };
+ },
+ function (error) {
+ // 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 = "/";
+ }
+ return Promise.reject(error);
+ }
+);
+
+export const fileInstance = axios.create({
+ baseURL: BASEURL,
+ timeout: -1,
+ headers: { Authorization: `Bearer ${useGetCookie("JWT-Authorization")}` },
+});
+
+// Add a request interceptor
+fileInstance.interceptors.request.use(
+ function (config) {
+ // Do something before request is sent
+ const token = useGetCookie("JWT-Authorization");
+ // 取得 building_guid 並加到 headers
+ let buildingGuid = "";
+ try {
+ const cviBuilding = localStorage.getItem("EmpowerBuilding");
+ if (cviBuilding) {
+ const parsed = JSON.parse(cviBuilding);
+ buildingGuid = parsed.building_guid || "";
+ }
+ } catch (e) {
+ buildingGuid = "";
+ }
+ config.headers = {
+ Authorization: `Bearer ${token}`,
+ "X-Building-GUID": buildingGuid,
+ };
+ return config;
+ },
+ function (error) {
+ // Do something with request error
+ return Promise.reject(error);
+ }
+);
+
+// Add a response interceptor
+fileInstance.interceptors.response.use(
+ async function (response) {
+ // Any status code that lie within the range of 2xx cause this function to trigger
+ // Do something with response data
+ const { status, data, headers } = response;
+
+ console.log("@@", status, data, headers);
+
+ let errorData = {};
+ if (headers["content-type"] === "application/json; charset=utf-8") {
+ const blob = new Blob([data]);
+ const blobText = await blob.text();
+ errorData = JSON.parse(blobText);
+ }
+
+ return headers["content-disposition"]
+ ? { data, code: "0000", headers }
+ : {
+ ...errorData,
+ };
+ },
+ function (error) {
+ // Any status codes that falls outside the range of 2xx cause this function to trigger
+ // Do something with response error
+ return Promise.reject(error);
+ }
+);
+
+export default instance;
diff --git a/src/util/showChartLoading.js b/src/util/showChartLoading.js
new file mode 100644
index 0000000..3499021
--- /dev/null
+++ b/src/util/showChartLoading.js
@@ -0,0 +1,9 @@
+const showChartLoading = (chart) => {
+ chart.showLoading({
+ text: "Loading...",
+ color: "#8ee894",
+ maskColor: "rgba(12, 21, 54, 0.7)",
+ });
+};
+
+export default showChartLoading;
diff --git a/src/views/AssetManagement/AssetManagement.vue b/src/views/AssetManagement/AssetManagement.vue
new file mode 100644
index 0000000..0bcda6b
--- /dev/null
+++ b/src/views/AssetManagement/AssetManagement.vue
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetMainList.vue b/src/views/AssetManagement/components/AssetMainList.vue
new file mode 100644
index 0000000..f0068c7
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetMainList.vue
@@ -0,0 +1,134 @@
+
+
+
+
+
+ {{ $t("history.system_category") }} :
+
+
+
+
+
+
+ {{ item.title }}
+
+ edit(item)"
+ >
+
+
+ deleteItem(item.id)"
+ >
+
+
+
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetMainListAddModal.vue b/src/views/AssetManagement/components/AssetMainListAddModal.vue
new file mode 100644
index 0000000..2fd6fa9
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetMainListAddModal.vue
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetSubList.vue b/src/views/AssetManagement/components/AssetSubList.vue
new file mode 100644
index 0000000..ae63968
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetSubList.vue
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+ {{ $t("history.device_category") }} :
+
+
+
+ {{ isEditMode ? t("button.stop_edit") : t("button.start_edit") }}
+
+
+
+
+ {{ item.title }}
+
+ openModal(item)"
+ >
+
+
+ deleteItem(item.id)"
+ >
+
+
+
+
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetSubListAddModal.vue b/src/views/AssetManagement/components/AssetSubListAddModal.vue
new file mode 100644
index 0000000..924cfa6
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetSubListAddModal.vue
@@ -0,0 +1,172 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetTable.vue b/src/views/AssetManagement/components/AssetTable.vue
new file mode 100644
index 0000000..a8d6cfc
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetTable.vue
@@ -0,0 +1,247 @@
+
+
+
+
+
{{ $t("assetManagement.device_list") }}
+
+
+
+
+
+ {{ record.company?.name }} /
+ {{ record.company?.contact_person }}
+
+
+ {{ record.brand }} / {{ record.device_model }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ edit(record.main_id)"
+ >
+ {{ $t("button.edit") }}
+
+ remove(record.main_id)"
+ >
+ {{ $t("button.delete") }}
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetTableAddModal.vue b/src/views/AssetManagement/components/AssetTableAddModal.vue
new file mode 100644
index 0000000..5a8f5bd
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetTableAddModal.vue
@@ -0,0 +1,158 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetTableModalLeft.vue b/src/views/AssetManagement/components/AssetTableModalLeft.vue
new file mode 100644
index 0000000..a41044b
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetTableModalLeft.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetTableModalLeftInfo.vue b/src/views/AssetManagement/components/AssetTableModalLeftInfo.vue
new file mode 100644
index 0000000..16fae59
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetTableModalLeftInfo.vue
@@ -0,0 +1,227 @@
+
+
+
+
+
+ {{ $t("assetManagement.device_name") }}
+
+ {{ formErrorMsg.full_name }}
+
+
+
+ {{ $t("assetManagement.department") }}
+
+
+
+ Tag_Name ({{ $t("assetManagement.fill_text") }})
+
+ {{ formErrorMsg.device_number }}
+
+
+
+ IoT
+
+
+
+
+ {{ $t("assetManagement.asset_number") }}
+
+ {{ formErrorMsg.asset_number }}
+
+
+ {{ $t("assetManagement.buying_date") }}
+
+ {{ formErrorMsg.buying_date }}
+
+
+
+ {{ $t("assetManagement.brand") }}
+
+ {{ formErrorMsg.brand }}
+
+
+ {{ $t("assetManagement.modal") }}
+
+ {{ formErrorMsg.device_model }}
+
+
+
+ {{ $t("assetManagement.company") }}
+
+
+
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetTableModalLeftInfoDept.vue b/src/views/AssetManagement/components/AssetTableModalLeftInfoDept.vue
new file mode 100644
index 0000000..093debb
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetTableModalLeftInfoDept.vue
@@ -0,0 +1,161 @@
+
+
+
+
+
+ {{ $t("assetManagement.department") }}
+
+
+ {{ $t("button.add") }}
+ {{ $t("button.edit") }}
+ {{ $t("button.delete") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetTableModalLeftInfoGraph.vue b/src/views/AssetManagement/components/AssetTableModalLeftInfoGraph.vue
new file mode 100644
index 0000000..90cacd2
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetTableModalLeftInfoGraph.vue
@@ -0,0 +1,173 @@
+
+
+
+
+
+ {{
+ $t("graphManagement.title")
+ }}
+
+ {{ $t("assetManagement.choose") }}
+
+
+
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetTableModalLeftInfoIoT.vue b/src/views/AssetManagement/components/AssetTableModalLeftInfoIoT.vue
new file mode 100644
index 0000000..2406460
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetTableModalLeftInfoIoT.vue
@@ -0,0 +1,290 @@
+
+
+
+
+
+
+
+ {{ $t("assetManagement.equipment_point") }}
+
+
+
+ {{ $t("assetManagement.add_sensor") }}
+
+
+
+
+ {{ index + 1 }}
+ deleteItem(record.device_number + record.points)
+ "
+ >
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetTableModalLeftInfoMQTT.vue b/src/views/AssetManagement/components/AssetTableModalLeftInfoMQTT.vue
new file mode 100644
index 0000000..e0258f7
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetTableModalLeftInfoMQTT.vue
@@ -0,0 +1,255 @@
+
+
+
+
+
+ MQTT Topic
+
+
+
+ Test
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dayjs(item.time).format("YYYY-MM-DD HH:mm:ss") }}
+
+
+
+
+ New
+
+
+
+
+
+
+ {{ key }}: {{ value }}
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
+
+
+ Auto close in
+ {{ countdown }}s
+
+
+
+ {{ t("button.cancel") }}
+
+
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetTableModalLeftModule.vue b/src/views/AssetManagement/components/AssetTableModalLeftModule.vue
new file mode 100644
index 0000000..effdead
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetTableModalLeftModule.vue
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/AssetManagement/components/AssetTableModalRight.vue b/src/views/AssetManagement/components/AssetTableModalRight.vue
new file mode 100644
index 0000000..4a1b472
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetTableModalRight.vue
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/AssetManagement/components/AssetTableModalRightInfo.vue b/src/views/AssetManagement/components/AssetTableModalRightInfo.vue
new file mode 100644
index 0000000..6689a75
--- /dev/null
+++ b/src/views/AssetManagement/components/AssetTableModalRightInfo.vue
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+
+ {{ $t("assetManagement.floor") }}
+
+
+ {{
+ $t("assetManagement.device_coordinate")
+ }}
+
+ {{ formErrorMsg.device_coordinate }}
+
+
+
+
+
+
{{ $t("assetManagement.add_floor_text") }}
+
+
+
+
+
diff --git a/src/views/Test.vue b/src/views/Test.vue
new file mode 100644
index 0000000..e4cff4b
--- /dev/null
+++ b/src/views/Test.vue
@@ -0,0 +1,27 @@
+
+
+
+
+ navigator.userAgent: {{ agent }}
+
+ isMobile: {{ currentInfoModalData }}
+
+
+
+
diff --git a/src/views/accountManagement/AccountManagement.vue b/src/views/accountManagement/AccountManagement.vue
new file mode 100644
index 0000000..b6df707
--- /dev/null
+++ b/src/views/accountManagement/AccountManagement.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/accountManagement/components/Account.vue b/src/views/accountManagement/components/Account.vue
new file mode 100644
index 0000000..dc97c4e
--- /dev/null
+++ b/src/views/accountManagement/components/Account.vue
@@ -0,0 +1,222 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/accountManagement/components/AccountModal.vue b/src/views/accountManagement/components/AccountModal.vue
new file mode 100644
index 0000000..95a7bb2
--- /dev/null
+++ b/src/views/accountManagement/components/AccountModal.vue
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/accountManagement/components/AccountPasswordModal.vue b/src/views/accountManagement/components/AccountPasswordModal.vue
new file mode 100644
index 0000000..b365198
--- /dev/null
+++ b/src/views/accountManagement/components/AccountPasswordModal.vue
@@ -0,0 +1,99 @@
+
+
+
+
+
+ {{ account.Name }}
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/accountManagement/components/Role.vue b/src/views/accountManagement/components/Role.vue
new file mode 100644
index 0000000..93299b8
--- /dev/null
+++ b/src/views/accountManagement/components/Role.vue
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
diff --git a/src/views/accountManagement/components/RoleAuthModal.vue b/src/views/accountManagement/components/RoleAuthModal.vue
new file mode 100644
index 0000000..6d03e45
--- /dev/null
+++ b/src/views/accountManagement/components/RoleAuthModal.vue
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/alert/AlertManagement.vue b/src/views/alert/AlertManagement.vue
new file mode 100644
index 0000000..910b477
--- /dev/null
+++ b/src/views/alert/AlertManagement.vue
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertQuery/AlertQuery.vue b/src/views/alert/components/AlertQuery/AlertQuery.vue
new file mode 100644
index 0000000..b10a832
--- /dev/null
+++ b/src/views/alert/components/AlertQuery/AlertQuery.vue
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertQuery/AlertSearch.vue b/src/views/alert/components/AlertQuery/AlertSearch.vue
new file mode 100644
index 0000000..661a409
--- /dev/null
+++ b/src/views/alert/components/AlertQuery/AlertSearch.vue
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+ {{ $t("button.search")}}
+
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertQuery/AlertSearchAckBtns.vue b/src/views/alert/components/AlertQuery/AlertSearchAckBtns.vue
new file mode 100644
index 0000000..42e9e96
--- /dev/null
+++ b/src/views/alert/components/AlertQuery/AlertSearchAckBtns.vue
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertQuery/AlertSearchNormalBtns.vue b/src/views/alert/components/AlertQuery/AlertSearchNormalBtns.vue
new file mode 100644
index 0000000..0af1067
--- /dev/null
+++ b/src/views/alert/components/AlertQuery/AlertSearchNormalBtns.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertQuery/AlertSearchTimeRange.vue b/src/views/alert/components/AlertQuery/AlertSearchTimeRange.vue
new file mode 100644
index 0000000..ce074d3
--- /dev/null
+++ b/src/views/alert/components/AlertQuery/AlertSearchTimeRange.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+ {{ $t("alert.30days") }}
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertQuery/AlertSearchTypesButton.vue b/src/views/alert/components/AlertQuery/AlertSearchTypesButton.vue
new file mode 100644
index 0000000..2b268d4
--- /dev/null
+++ b/src/views/alert/components/AlertQuery/AlertSearchTypesButton.vue
@@ -0,0 +1,87 @@
+
+
+
+
+
+ {{ $t("history.device_category") }} :
+
+
+ {{ checkedItem.length === store.subSys.length ? t("button.deselect_all") : t("button.select_all") }}
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertQuery/AlertTable.vue b/src/views/alert/components/AlertQuery/AlertTable.vue
new file mode 100644
index 0000000..abdc36f
--- /dev/null
+++ b/src/views/alert/components/AlertQuery/AlertTable.vue
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+ openModal(record)"
+ >
+ {{ record.formId }}
+
+ {{
+ $t("alert.repair_order_number")
+ }}
+
+
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertQuery/AlertTableModal.vue b/src/views/alert/components/AlertQuery/AlertTableModal.vue
new file mode 100644
index 0000000..49f5a58
--- /dev/null
+++ b/src/views/alert/components/AlertQuery/AlertTableModal.vue
@@ -0,0 +1,326 @@
+
+
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertSetting/AlertNoticesTable.vue b/src/views/alert/components/AlertSetting/AlertNoticesTable.vue
new file mode 100644
index 0000000..2bfdfd1
--- /dev/null
+++ b/src/views/alert/components/AlertSetting/AlertNoticesTable.vue
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertSetting/AlertNotifyTable.vue b/src/views/alert/components/AlertSetting/AlertNotifyTable.vue
new file mode 100644
index 0000000..4589752
--- /dev/null
+++ b/src/views/alert/components/AlertSetting/AlertNotifyTable.vue
@@ -0,0 +1,124 @@
+
+
+
+
+
{{ $t("alert.notify_list") }}
+
+
+
+
+
+ openModal(record)"
+ >
+ {{ $t("button.edit") }}
+
+ remove(record.id)"
+ >
+ {{ $t("button.delete") }}
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertSetting/AlertNotifyTableAddModal.vue b/src/views/alert/components/AlertSetting/AlertNotifyTableAddModal.vue
new file mode 100644
index 0000000..d02d03e
--- /dev/null
+++ b/src/views/alert/components/AlertSetting/AlertNotifyTableAddModal.vue
@@ -0,0 +1,159 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+ {{ $t("alert.notify_name") }}
+
+
+ {{ formErrorMsg.name }}
+
+
+
+
+ {{ $t("alert.notify_phone") }}
+
+
+ {{ formErrorMsg.phone }}
+
+
+
+
+ {{ $t("alert.notify_email") }}
+
+
+ {{ formErrorMsg.email }}
+
+
+
+
+
{{ $t("alert.notify_items") }}
+
+
+ {{ formErrorMsg.notices }}
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertSetting/AlertOutliersTable.vue b/src/views/alert/components/AlertSetting/AlertOutliersTable.vue
new file mode 100644
index 0000000..552c684
--- /dev/null
+++ b/src/views/alert/components/AlertSetting/AlertOutliersTable.vue
@@ -0,0 +1,257 @@
+
+
+
+
+
+
{{ $t("alert.alarm_settings") }}
+
+
+
+ {{ $t("alert.reorganization") }}
+
+
+
+
+
+ openModal(record)"
+ >
+ {{ $t("button.edit") }}
+
+ remove(record.id)"
+ >
+ {{ $t("button.delete") }}
+
+
+
+ {{ record.enable === 1 ? t("alert.yes") : t("alert.no") }}
+
+
+ {{ record.warning_method }}
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertSetting/AlertOutliersTableAddModal.vue b/src/views/alert/components/AlertSetting/AlertOutliersTableAddModal.vue
new file mode 100644
index 0000000..a92da1b
--- /dev/null
+++ b/src/views/alert/components/AlertSetting/AlertOutliersTableAddModal.vue
@@ -0,0 +1,274 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+ {{ $t("alert.device_name") }}
+
+ {{ formErrorMsg.device_number }}
+
+
+
+ {{ $t("alert.item") }}
+
+ {{ formErrorMsg.points }}
+
+
+
+ {{ $t("alert.qualifications") }}
+
+
+ {{ $t("alert.status") }}
+
+
+
+ {{ $t("alert.delay") }}
+
+
+
+
+
+ {{ $t("alert.upper_limit") }}(>=)
+
+
+ {{ $t("alert.lower_limit") }}(<=)
+
+
+
+
+ {{ $t("alert.highDelay") }}
+
+
+ {{ $t("alert.lowDelay") }}
+
+
+
+
+
+ {{ $t("alert.warning_value") }}
+
+
+
+
+
+ {{ $t("alert.warning_method") }}
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertSetting/AlertSetting.vue b/src/views/alert/components/AlertSetting/AlertSetting.vue
new file mode 100644
index 0000000..a1398d3
--- /dev/null
+++ b/src/views/alert/components/AlertSetting/AlertSetting.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertSetting/AlertSubList.vue b/src/views/alert/components/AlertSetting/AlertSubList.vue
new file mode 100644
index 0000000..3c3dc74
--- /dev/null
+++ b/src/views/alert/components/AlertSetting/AlertSubList.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/alert/components/AlertSetting/AlertTimeTable.vue b/src/views/alert/components/AlertSetting/AlertTimeTable.vue
new file mode 100644
index 0000000..eb440f1
--- /dev/null
+++ b/src/views/alert/components/AlertSetting/AlertTimeTable.vue
@@ -0,0 +1,110 @@
+
+
+
+
+
{{$t("alert.warning_time")}}
+
+
+
+
+
+
+
+
+ {{ weekDate[item.day] }}:
+
+ {{ time }}
+ ,
+
+
+
+
+
+
+ openModal(record)"
+ >
+ {{$("button.edit")}}
+
+ remove(record.id)"
+ >
+ {{$("button.delete")}}
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
diff --git a/src/views/alert/components/AlertSetting/AlertTimeTableAddModal.vue b/src/views/alert/components/AlertSetting/AlertTimeTableAddModal.vue
new file mode 100644
index 0000000..c68cf03
--- /dev/null
+++ b/src/views/alert/components/AlertSetting/AlertTimeTableAddModal.vue
@@ -0,0 +1,429 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+ {{ $t("alert.schedule_name") }}
+
+
+ {{ formErrorMsg.schedule_name }}
+
+
+
+ {{ $t("alert.schedule_content") }}
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/dashboard/Dashboard.vue b/src/views/dashboard/Dashboard.vue
new file mode 100644
index 0000000..1ef6a7c
--- /dev/null
+++ b/src/views/dashboard/Dashboard.vue
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardAlert.vue b/src/views/dashboard/components/DashboardAlert.vue
new file mode 100644
index 0000000..7a8d6f9
--- /dev/null
+++ b/src/views/dashboard/components/DashboardAlert.vue
@@ -0,0 +1,72 @@
+
+
+
+
+ {{ $t("dashboard.alerts_data") }} Top 5
+
+
+
+
+
+ {{ $t("operation.date") }}
+ {{ $t("operation.time") }}
+ {{ $t("operation.device_name") }}
+ {{ $t("operation.remark") }}
+
+
+
+
+ {{ alarm.year }}
+ {{ alarm.time }}
+ {{ alarm.device_number }}
+ {{ alarm.remark }}
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardEffectScatter.vue b/src/views/dashboard/components/DashboardEffectScatter.vue
new file mode 100644
index 0000000..1425032
--- /dev/null
+++ b/src/views/dashboard/components/DashboardEffectScatter.vue
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardEffectScatterModal.vue b/src/views/dashboard/components/DashboardEffectScatterModal.vue
new file mode 100644
index 0000000..b2b6278
--- /dev/null
+++ b/src/views/dashboard/components/DashboardEffectScatterModal.vue
@@ -0,0 +1,288 @@
+
+
+
+
+
+
+
{{ props.data?.full_name }}
+
+ changeOpenKey('desktop')"
+ >
+
+
+ changeOpenKey('image')"
+ >
+
+
+ changeOpenKey('cog')"
+ >
+
+
+ changeOpenKey('chart')"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 名稱
+ 點位
+ 數值
+
+
+
+
+ {{ point.full_name }}
+ {{ point.points }}
+ {{ point.value }}
+
+
+
+
+
+
+
+
+
+
+ 項目
+ 內容
+
+
+
+
+ 設備圖示
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 項目
+ 內容
+
+
+
+
+
+ {{ $t("assetManagement.device_number") }}
+
+ {{ props.data.device_number }}
+
+
+
+ {{ $t("assetManagement.device_name") }}
+
+ {{ props.data.full_name }}
+
+
+ {{ $t("assetManagement.floor") }}
+ {{ props.data.floor }}
+
+
+
+ {{ $t("assetManagement.device_coordinate") }}
+
+ {{ props.data.device_coordinate }}
+
+
+
+ {{ $t("assetManagement.brand_and_modal") }}
+ {{ props.data.brand }} / {{ props.data.device_model }}
+
+
+ {{ $t("assetManagement.company_and_contact") }}
+ {{ props.data.operation_name }} / {{ props.data.operation_contact_person }}
+
+
+ {{ $t("assetManagement.buying_date") }}
+ {{ props.data.buying_date }}
+
+
+ {{ $t("assetManagement.created_at") }}
+ {{ props.data.created_at }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardEffectScatterModalChart.vue b/src/views/dashboard/components/DashboardEffectScatterModalChart.vue
new file mode 100644
index 0000000..d496181
--- /dev/null
+++ b/src/views/dashboard/components/DashboardEffectScatterModalChart.vue
@@ -0,0 +1,227 @@
+
+
+
+
+
+ updateTimeRange(value)"
+ >
+
+ 搜尋
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardElectricity.vue b/src/views/dashboard/components/DashboardElectricity.vue
new file mode 100644
index 0000000..ee619f1
--- /dev/null
+++ b/src/views/dashboard/components/DashboardElectricity.vue
@@ -0,0 +1,177 @@
+
+
+
+
+
+ {{ $t("energy.immediate_demand") }}
+ {{
+ realTimeDemand.length > 0
+ ? realTimeDemand[realTimeDemand.length - 1].value / 1000
+ : "---"
+ }}
+ kw
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardElectricityModal.vue b/src/views/dashboard/components/DashboardElectricityModal.vue
new file mode 100644
index 0000000..b192795
--- /dev/null
+++ b/src/views/dashboard/components/DashboardElectricityModal.vue
@@ -0,0 +1,133 @@
+
+
+
+
+ {{ $t("button.edit") }}
+
+
+
+
+
+ {{ $t("energy.contract_capacity") }}
+
+
+ {{ formErrorMsg.contract }}
+
+
+
+
+ {{ $t("energy.alert_capacity") }}
+
+
+ {{ formErrorMsg.alert }}
+
+
+
+
+ {{ $t("energy.reset_value") }}
+
+
+ {{ formErrorMsg.reset }}
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardEmission.vue b/src/views/dashboard/components/DashboardEmission.vue
new file mode 100644
index 0000000..989f5b9
--- /dev/null
+++ b/src/views/dashboard/components/DashboardEmission.vue
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+ {{ $t("energy.daily_carbon_emission_and_reduction") }}
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardEmissionModal.vue b/src/views/dashboard/components/DashboardEmissionModal.vue
new file mode 100644
index 0000000..efea2d7
--- /dev/null
+++ b/src/views/dashboard/components/DashboardEmissionModal.vue
@@ -0,0 +1,110 @@
+
+
+
+
+ {{ $t("button.edit") }}
+
+
+
+
+
+ {{$t('energy.carbon_emission_coefficient')}}
+
+
+ {{ formErrorMsg.coefficient }}
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardFloorBar.vue b/src/views/dashboard/components/DashboardFloorBar.vue
new file mode 100644
index 0000000..b5d873d
--- /dev/null
+++ b/src/views/dashboard/components/DashboardFloorBar.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardHumidity.vue b/src/views/dashboard/components/DashboardHumidity.vue
new file mode 100644
index 0000000..b5b8ccb
--- /dev/null
+++ b/src/views/dashboard/components/DashboardHumidity.vue
@@ -0,0 +1,109 @@
+
+
+
+
+ {{ $t("dashboard.refrig_chart") }}
+
+
+
+
+
+ {{ $t("dashboard.no_data") }}
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardIndoor.vue b/src/views/dashboard/components/DashboardIndoor.vue
new file mode 100644
index 0000000..056aba2
--- /dev/null
+++ b/src/views/dashboard/components/DashboardIndoor.vue
@@ -0,0 +1,227 @@
+
+
+
+
+ {{ $t("dashboard.indoor_chart") }}
+
+
+
+
+
+ {{ $t("dashboard.no_data") }}
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardIndoorTemp.vue b/src/views/dashboard/components/DashboardIndoorTemp.vue
new file mode 100644
index 0000000..13e46eb
--- /dev/null
+++ b/src/views/dashboard/components/DashboardIndoorTemp.vue
@@ -0,0 +1,157 @@
+
+
+
+
+ {{ $t("dashboard.indoor_chart") }}
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardProduct.vue b/src/views/dashboard/components/DashboardProduct.vue
new file mode 100644
index 0000000..702e993
--- /dev/null
+++ b/src/views/dashboard/components/DashboardProduct.vue
@@ -0,0 +1,204 @@
+
+
+
+
+
+ {{ $t("dashboard.production_quantity") }}
+
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardProductComplete.vue b/src/views/dashboard/components/DashboardProductComplete.vue
new file mode 100644
index 0000000..97ad049
--- /dev/null
+++ b/src/views/dashboard/components/DashboardProductComplete.vue
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+ {{ $t("dashboard.today_production_rate") }} (%)
+
+
+ {{ $t("button.edit") }}
+
+
+
+
+
+
+
+
{{ pac }}
+
+
{{ percentage }} %
+
+
+
+ 尚未設定目標值
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardProductCompleteModal.vue b/src/views/dashboard/components/DashboardProductCompleteModal.vue
new file mode 100644
index 0000000..aa53491
--- /dev/null
+++ b/src/views/dashboard/components/DashboardProductCompleteModal.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+
+
+ 確定
+
+
+
+
+ 取消
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardProductCompleteModalRecord.vue b/src/views/dashboard/components/DashboardProductCompleteModalRecord.vue
new file mode 100644
index 0000000..8e14290
--- /dev/null
+++ b/src/views/dashboard/components/DashboardProductCompleteModalRecord.vue
@@ -0,0 +1,125 @@
+
+
+
+
+
+ 日期
+
+
+
+
+
+
+
+
+
{{ item.pac }} : {{ item.f2_value }}
+
+
+
+
+
{{ item.pac }} : {{ item.f3_value }}
+
+
+
+
+
{{ item.pac }} : {{ item.target }}
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardProductCompleteModalTarget.vue b/src/views/dashboard/components/DashboardProductCompleteModalTarget.vue
new file mode 100644
index 0000000..86d13a1
--- /dev/null
+++ b/src/views/dashboard/components/DashboardProductCompleteModalTarget.vue
@@ -0,0 +1,74 @@
+
+
+
+
+ 日期
+
+
+
+
+
+
包裝類型
+
+
+ {{ size }}
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardRefrig.vue b/src/views/dashboard/components/DashboardRefrig.vue
new file mode 100644
index 0000000..d9b8336
--- /dev/null
+++ b/src/views/dashboard/components/DashboardRefrig.vue
@@ -0,0 +1,229 @@
+
+
+
+
+ {{ $t("dashboard.refrig_chart") }}
+
+
+
+
+
+ {{ $t("dashboard.no_data") }}
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardRefrigTemp.vue b/src/views/dashboard/components/DashboardRefrigTemp.vue
new file mode 100644
index 0000000..0b9c84c
--- /dev/null
+++ b/src/views/dashboard/components/DashboardRefrigTemp.vue
@@ -0,0 +1,160 @@
+
+
+
+
+ {{ $t("dashboard.refrig_chart") }}
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardSysCard.vue b/src/views/dashboard/components/DashboardSysCard.vue
new file mode 100644
index 0000000..81d8a04
--- /dev/null
+++ b/src/views/dashboard/components/DashboardSysCard.vue
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+
{{ device[2]?.full_name }}
+
+
+
+
+ {{ $t("system.status") }}:
+ {{ device[2]?.state }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardTemp.vue b/src/views/dashboard/components/DashboardTemp.vue
new file mode 100644
index 0000000..1959ca5
--- /dev/null
+++ b/src/views/dashboard/components/DashboardTemp.vue
@@ -0,0 +1,198 @@
+
+
+
+
+ {{ $t("dashboard.indoor_chart") }}
+
+
+
+
+
+ {{ $t("dashboard.no_data") }}
+
+
+
+
+
diff --git a/src/views/dashboard/components/ForgeInfoModalChart.vue b/src/views/dashboard/components/ForgeInfoModalChart.vue
new file mode 100644
index 0000000..ac6bb72
--- /dev/null
+++ b/src/views/dashboard/components/ForgeInfoModalChart.vue
@@ -0,0 +1,219 @@
+
+
+
+
+
+ updateTimeRange(value)"
+ >
+
+ 搜尋
+
+
+
+
+
+
diff --git a/src/views/energyManagement/EnergyManagement.vue b/src/views/energyManagement/EnergyManagement.vue
new file mode 100644
index 0000000..16d57da
--- /dev/null
+++ b/src/views/energyManagement/EnergyManagement.vue
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/BillingDegreeChart.vue b/src/views/energyManagement/components/BillingDegreeChart.vue
new file mode 100644
index 0000000..c06650e
--- /dev/null
+++ b/src/views/energyManagement/components/BillingDegreeChart.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
+
{{ $t("energy.monthly_bill_power")}}
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/CurrentInformation.vue b/src/views/energyManagement/components/CurrentInformation.vue
new file mode 100644
index 0000000..25b13a4
--- /dev/null
+++ b/src/views/energyManagement/components/CurrentInformation.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+ {{ item.point }} (V)
+
+
+ {{ item.value }}
+
+
+ {{ lastUpdated }}
+
+
+
+
+
+
+
+ {{ item.point }} (A)
+
+
+ {{ item.value }}
+
+
+ {{ lastUpdated }}
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/ElectricityBillChart.vue b/src/views/energyManagement/components/ElectricityBillChart.vue
new file mode 100644
index 0000000..fc8397b
--- /dev/null
+++ b/src/views/energyManagement/components/ElectricityBillChart.vue
@@ -0,0 +1,101 @@
+
+
+
+
+
+
{{ $t("energy.monthly_elec_bill") }}
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyChart/BillingDegreeChart.vue b/src/views/energyManagement/components/EnergyChart/BillingDegreeChart.vue
new file mode 100644
index 0000000..f2f88ac
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyChart/BillingDegreeChart.vue
@@ -0,0 +1,132 @@
+
+
+
+
+
+ {{ $t("energy.monthly_bill_power") }}
+
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyChart/CarbonEmissionChart.vue b/src/views/energyManagement/components/EnergyChart/CarbonEmissionChart.vue
new file mode 100644
index 0000000..0b8d469
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyChart/CarbonEmissionChart.vue
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+ {{ $t("energy.daily_carbon_emission_and_reduction") }}
+
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyChart/CarbonEmissionModal.vue b/src/views/energyManagement/components/EnergyChart/CarbonEmissionModal.vue
new file mode 100644
index 0000000..30024c0
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyChart/CarbonEmissionModal.vue
@@ -0,0 +1,110 @@
+
+
+
+
+ {{ $t("button.edit") }}
+
+
+
+
+
+ {{$t('energy.carbon_emission_coefficient')}}
+
+
+ {{ formErrorMsg.coefficient }}
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyChart/ElecConsumption.vue b/src/views/energyManagement/components/EnergyChart/ElecConsumption.vue
new file mode 100644
index 0000000..460ee3e
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyChart/ElecConsumption.vue
@@ -0,0 +1,141 @@
+
+
+
+
+
+ {{ $t("energy.elec_consumption") }}
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyChart/EnergyChart.vue b/src/views/energyManagement/components/EnergyChart/EnergyChart.vue
new file mode 100644
index 0000000..26eb9a5
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyChart/EnergyChart.vue
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyChart/ImmediateDemandChart.vue b/src/views/energyManagement/components/EnergyChart/ImmediateDemandChart.vue
new file mode 100644
index 0000000..1d0be05
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyChart/ImmediateDemandChart.vue
@@ -0,0 +1,186 @@
+
+
+
+
+
+
+ {{ $t("energy.immediate_demand") }}
+ {{
+ realTimeDemand.length > 0
+ ? realTimeDemand[realTimeDemand.length - 1].value
+ : "---"
+ }}
+ kw
+
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyChart/ImmediateDemandModal.vue b/src/views/energyManagement/components/EnergyChart/ImmediateDemandModal.vue
new file mode 100644
index 0000000..bb20865
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyChart/ImmediateDemandModal.vue
@@ -0,0 +1,133 @@
+
+
+
+
+ {{ $t("button.edit") }}
+
+
+
+
+
+ {{ $t("energy.contract_capacity") }}
+
+
+ {{ formErrorMsg.contract }}
+
+
+
+
+ {{ $t("energy.alert_capacity") }}
+
+
+ {{ formErrorMsg.alert }}
+
+
+
+
+ {{ $t("energy.reset_value") }}
+
+
+ {{ formErrorMsg.reset }}
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyChart/IntervalBillChart.vue b/src/views/energyManagement/components/EnergyChart/IntervalBillChart.vue
new file mode 100644
index 0000000..ecfd31c
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyChart/IntervalBillChart.vue
@@ -0,0 +1,166 @@
+
+
+
+
+
+ {{ $t("energy.interval_bill_degree") }} {{ dateRange.min }} ~
+ {{ dateRange.max }}
+
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyChart/MonthlyElecBillChart.vue b/src/views/energyManagement/components/EnergyChart/MonthlyElecBillChart.vue
new file mode 100644
index 0000000..26d8956
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyChart/MonthlyElecBillChart.vue
@@ -0,0 +1,131 @@
+
+
+
+
+
+ {{ $t("energy.monthly_elec_consumption") }}
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyChart/UsageInformation.vue b/src/views/energyManagement/components/EnergyChart/UsageInformation.vue
new file mode 100644
index 0000000..4db0856
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyChart/UsageInformation.vue
@@ -0,0 +1,119 @@
+
+
+
+
+
+
{{ item.title }}
+
{{ item.time }}
+
{{ item.data }}
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyHistoryTable/EnergyActionButton.vue b/src/views/energyManagement/components/EnergyHistoryTable/EnergyActionButton.vue
new file mode 100644
index 0000000..7679bc5
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyHistoryTable/EnergyActionButton.vue
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyHistoryTable/EnergyDataCahrt.vue b/src/views/energyManagement/components/EnergyHistoryTable/EnergyDataCahrt.vue
new file mode 100644
index 0000000..edfaef3
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyHistoryTable/EnergyDataCahrt.vue
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyHistoryTable/EnergyDataTable.vue b/src/views/energyManagement/components/EnergyHistoryTable/EnergyDataTable.vue
new file mode 100644
index 0000000..9e1b7ac
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyHistoryTable/EnergyDataTable.vue
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyHistoryTable/EnergyHistoryTable.vue b/src/views/energyManagement/components/EnergyHistoryTable/EnergyHistoryTable.vue
new file mode 100644
index 0000000..aa7d750
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyHistoryTable/EnergyHistoryTable.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyHistoryTable/EnergySearch.vue b/src/views/energyManagement/components/EnergyHistoryTable/EnergySearch.vue
new file mode 100644
index 0000000..5d5fbe9
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyHistoryTable/EnergySearch.vue
@@ -0,0 +1,251 @@
+
+
+
+
+
+
+ {{ $t("assetManagement.department") }} :
+
+
+
+
+
+ {{ $t("energy.electricity_classification") }} :
+
+
+
+
+
+ {{ $t("history.system_category") }} :
+
+
+
+
+
+ {{ $t("history.device_category") }} :
+
+
+
+
+
+ {{ $t("history.point") }} :
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyHistoryTable/EnergySearchTime.vue b/src/views/energyManagement/components/EnergyHistoryTable/EnergySearchTime.vue
new file mode 100644
index 0000000..34f09e1
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyHistoryTable/EnergySearchTime.vue
@@ -0,0 +1,159 @@
+
+
+
+
+
+ {{ $t("history.date_range") }} :
+
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyHistoryTable/EnergySidebar.vue b/src/views/energyManagement/components/EnergyHistoryTable/EnergySidebar.vue
new file mode 100644
index 0000000..2d5bbbf
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyHistoryTable/EnergySidebar.vue
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyReport/EnergyReport.vue b/src/views/energyManagement/components/EnergyReport/EnergyReport.vue
new file mode 100644
index 0000000..ec8efda
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyReport/EnergyReport.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyReport/EnergyReportSearch.vue b/src/views/energyManagement/components/EnergyReport/EnergyReportSearch.vue
new file mode 100644
index 0000000..ce7b62f
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyReport/EnergyReportSearch.vue
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+ {{ $t("assetManagement.department") }} :
+
+
+
+
+
+ {{ $t("energy.floor") }} :
+
+
+
+
+
+ {{ $t("energy.electricity_classification") }} :
+
+
+
+
+
+
+ {{ $t("button.search") }}
+
+
+
+ {{ $t("button.export") }}
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyReport/EnergyReportTable.vue b/src/views/energyManagement/components/EnergyReport/EnergyReportTable.vue
new file mode 100644
index 0000000..eda12c3
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyReport/EnergyReportTable.vue
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/EnergyReport/EnergyReportTimeRange.vue b/src/views/energyManagement/components/EnergyReport/EnergyReportTimeRange.vue
new file mode 100644
index 0000000..cf6e7a0
--- /dev/null
+++ b/src/views/energyManagement/components/EnergyReport/EnergyReportTimeRange.vue
@@ -0,0 +1,129 @@
+
+
+
+
+ {{ $t("operation.date") }} :
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/energyManagement/components/ImmediateDemandChart.vue b/src/views/energyManagement/components/ImmediateDemandChart.vue
new file mode 100644
index 0000000..c2f6ac3
--- /dev/null
+++ b/src/views/energyManagement/components/ImmediateDemandChart.vue
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+ {{ $t("energy.latest_elec_consumption") }}
+ {{ todayUsage }} kWh
+
+
+
+
+
+
+
diff --git a/src/views/energyManagement/components/UsageInformation.vue b/src/views/energyManagement/components/UsageInformation.vue
new file mode 100644
index 0000000..3a5914c
--- /dev/null
+++ b/src/views/energyManagement/components/UsageInformation.vue
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+ {{ $t("energy.elec_bills") }}
+
+
+ {{ totalElecBills }}
+
+
+ {{ totalDate }}
+
+
+
+
+ {{ $t("energy.interval_elec_charges") }}
+
+
+ {{ IntervalElecBills }}
+
+
+ {{ IntervalDate }}
+
+
+
+
+
+
+
+
+ {{ $t("energy.year_elec_consumption") }}
+
+
+ {{ totalElecDegree }}
+
+
+ {{ totalDate }}
+
+
+
+
+ {{ $t("energy.interval_elec_consumption") }}
+
+
+ {{ IntervalElecDegree }}
+
+
+ {{ IntervalDate }}
+
+
+
+
+
+
diff --git a/src/views/graphManagement/GraphManagement.vue b/src/views/graphManagement/GraphManagement.vue
new file mode 100644
index 0000000..1e9074f
--- /dev/null
+++ b/src/views/graphManagement/GraphManagement.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
diff --git a/src/views/graphManagement/components/GraphModal.vue b/src/views/graphManagement/components/GraphModal.vue
new file mode 100644
index 0000000..f2c8cf8
--- /dev/null
+++ b/src/views/graphManagement/components/GraphModal.vue
@@ -0,0 +1,178 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+
{{ $t("graphManagement.category") }}
+
{{ current_dir?.remark }}
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/graphManagement/components/GraphSidebar.vue b/src/views/graphManagement/components/GraphSidebar.vue
new file mode 100644
index 0000000..6948398
--- /dev/null
+++ b/src/views/graphManagement/components/GraphSidebar.vue
@@ -0,0 +1,256 @@
+
+
+
+
+
+
+
diff --git a/src/views/graphManagement/components/GraphSidebarDropdown.vue b/src/views/graphManagement/components/GraphSidebarDropdown.vue
new file mode 100644
index 0000000..2bc32f9
--- /dev/null
+++ b/src/views/graphManagement/components/GraphSidebarDropdown.vue
@@ -0,0 +1,63 @@
+
+
+
+
+
+ {
+ add(!props.selectedItem?.key);
+ }
+ "
+ >
+ {{ $t("button.add") }}
+
+ {
+ edit(props.selectedItem.key);
+ }
+ "
+ >
+ {{ $t("button.rename") }}
+
+ {
+ remove();
+ }
+ "
+ >
+ {{ $t("button.delete") }}
+
+
+
+
+
+
diff --git a/src/views/graphManagement/components/GraphTable.vue b/src/views/graphManagement/components/GraphTable.vue
new file mode 100644
index 0000000..648a46e
--- /dev/null
+++ b/src/views/graphManagement/components/GraphTable.vue
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+
+ {{ searchParams.id < 0 ? $t("graphManagement.staging_area") : current_dir?.remark }}
+
+
+
+
+ {{ index + 1 }}
+
+
+ {{ record.oriOrgName }}
+
+
+
+ {{ getFolderPath(record.parentId) || $t("graphManagement.no_path") }}
+
+
+ downloadFile(record)"
+ v-if="searchParams.id > 0"
+ >
+ {{ $t("button.download") }}
+
+ {
+ updateEditRecord(record);
+ }
+ "
+ v-if="searchParams.id > 0"
+ >
+ {{ $t("button.edit") }}
+
+ {
+ delRecord(record.id, false, true);
+ }
+ "
+ v-else
+ >
+ {{ $t("button.restore") }}
+
+ delRecord(record.id, searchParams.id > 0 ? false : true)"
+ >
+ {{ $t("button.delete") }}
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
+
+
diff --git a/src/views/history/History.vue b/src/views/history/History.vue
new file mode 100644
index 0000000..705ca0c
--- /dev/null
+++ b/src/views/history/History.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
diff --git a/src/views/history/components/HistoryActionButton.vue b/src/views/history/components/HistoryActionButton.vue
new file mode 100644
index 0000000..a1c0e79
--- /dev/null
+++ b/src/views/history/components/HistoryActionButton.vue
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
diff --git a/src/views/history/components/HistoryDataCahrt.vue b/src/views/history/components/HistoryDataCahrt.vue
new file mode 100644
index 0000000..73ac973
--- /dev/null
+++ b/src/views/history/components/HistoryDataCahrt.vue
@@ -0,0 +1,186 @@
+
+
+
+
+
+
+
diff --git a/src/views/history/components/HistoryFavoriteOption.vue b/src/views/history/components/HistoryFavoriteOption.vue
new file mode 100644
index 0000000..b54c5a9
--- /dev/null
+++ b/src/views/history/components/HistoryFavoriteOption.vue
@@ -0,0 +1,205 @@
+
+
+
+
+
+
+ {{ $t("history.combinations") }}
+
+
+
+
+
+ changeToFavorite(record)"
+ >
+ {{ record.favorite_name }}
+
+
+ editItem(record.favorite_guid, record.favorite_name)
+ "
+ />
+ {
+ removeItem(record.favorite_guid);
+ }
+ "
+ />
+
+
+
+
+
+
+ {{ $t("button.add") }}
+
+
+ {{ $t("button.cancel") }}
+
+
+
+
+
+
+
+ addItem(!isAdding)"
+ >
+
+ {{ $t("button.add") }}
+
+ {
+ clearInput();
+ isAdding = false;
+ }
+ "
+ >
+ {{ $t("button.cancel") }}
+
+
+
+
+
+
+
diff --git a/src/views/history/components/HistorySearch.vue b/src/views/history/components/HistorySearch.vue
new file mode 100644
index 0000000..be12808
--- /dev/null
+++ b/src/views/history/components/HistorySearch.vue
@@ -0,0 +1,252 @@
+
+
+
+
+
+
+
+ {{ $t("assetManagement.department") }} :
+
+
+
+
+
+ {{ $t("history.system_category") }} :
+
+
+
+
+
+ {{ $t("history.device_category") }} :
+
+
+
+
+
+ {{ $t("history.point") }} :
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/history/components/HistorySearchTime.vue b/src/views/history/components/HistorySearchTime.vue
new file mode 100644
index 0000000..32a4662
--- /dev/null
+++ b/src/views/history/components/HistorySearchTime.vue
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/history/components/HistorySidebar.vue b/src/views/history/components/HistorySidebar.vue
new file mode 100644
index 0000000..3b5a11c
--- /dev/null
+++ b/src/views/history/components/HistorySidebar.vue
@@ -0,0 +1,295 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/history/components/HistoryTable.vue b/src/views/history/components/HistoryTable.vue
new file mode 100644
index 0000000..f236c28
--- /dev/null
+++ b/src/views/history/components/HistoryTable.vue
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
diff --git a/src/views/login/Login.vue b/src/views/login/Login.vue
new file mode 100644
index 0000000..70d1e22
--- /dev/null
+++ b/src/views/login/Login.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+ 新創賦能
+
+
+
+ {{
+ $t("account")
+ }}
+
+
+
+ {{ formErrorMsg.account }}
+
+
+
+
+ {{
+ $t("password")
+ }}
+
+
+
+
+ {{ formErrorMsg.password }}
+
+
+
+ {{ $t("log_in") }}
+
+
+
+
+
+
diff --git a/src/views/operation/Operation.vue b/src/views/operation/Operation.vue
new file mode 100644
index 0000000..6fe3022
--- /dev/null
+++ b/src/views/operation/Operation.vue
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/operation/components/OperationActionButton.vue b/src/views/operation/components/OperationActionButton.vue
new file mode 100644
index 0000000..a4d40dd
--- /dev/null
+++ b/src/views/operation/components/OperationActionButton.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+ openModal()">
+ {{ $t("button.add") }}
+
+
+
+
diff --git a/src/views/operation/components/OperationSearch.vue b/src/views/operation/components/OperationSearch.vue
new file mode 100644
index 0000000..fadc6b9
--- /dev/null
+++ b/src/views/operation/components/OperationSearch.vue
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/operation/components/OperationSearchSubSys.vue b/src/views/operation/components/OperationSearchSubSys.vue
new file mode 100644
index 0000000..9b24cf6
--- /dev/null
+++ b/src/views/operation/components/OperationSearchSubSys.vue
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+ {{ $t("history.system_category") }} :
+
+
+
+
+
+ {{ $t("history.device_category") }} :
+
+
+
+
+
+
+
diff --git a/src/views/operation/components/OperationSearchType.vue b/src/views/operation/components/OperationSearchType.vue
new file mode 100644
index 0000000..f8719bf
--- /dev/null
+++ b/src/views/operation/components/OperationSearchType.vue
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/operation/components/OperationTable.vue b/src/views/operation/components/OperationTable.vue
new file mode 100644
index 0000000..8037178
--- /dev/null
+++ b/src/views/operation/components/OperationTable.vue
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ changeData(record)"
+ >
+ {{ $t("button.edit") }}
+
+ deleteItem(record.id)"
+ >
+ {{ $t("button.delete") }}
+
+
+
+
+
diff --git a/src/views/operation/components/OperationTableModal.vue b/src/views/operation/components/OperationTableModal.vue
new file mode 100644
index 0000000..c33a7c6
--- /dev/null
+++ b/src/views/operation/components/OperationTableModal.vue
@@ -0,0 +1,452 @@
+
+
+
+
+
+
+
+
+ {{ $t("operation.project") }}
+
+
+ {{ $t("operation.form_number") }}
+
+
+ {{ $t("operation.start_time") }}
+
+ {{ maintainFormErrorMsg.start_time }}
+
+
+
+ {{ $t("operation.repair_item") }}
+
+ {{ maintainFormErrorMsg.fix_do }}
+
+
+
+ {{ $t("operation.repair_item_code") }}
+
+ {{ maintainFormErrorMsg.fix_do_code }}
+
+
+
+ {{
+ $t("operation.responsible_vendor")
+ }}
+
+ {{ maintainFormErrorMsg.fix_firm }}
+
+
+
+ {{ $t("operation.status") }}
+
+
+ {{ $t("operation.finish_time") }}
+
+ {{ maintainFormErrorMsg.finish_time }}
+
+
+
+ {{ $t("operation.worker_id") }}
+
+ {{ maintainFormErrorMsg.work_person_id }}
+
+
+
+ {{ $t("operation.notice") }}
+
+
+ {{ $t("operation.result_description") }}
+
+
+ {{ $t("operation.upload_file") }}
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/operation/constant/OperationTableColumns.js b/src/views/operation/constant/OperationTableColumns.js
new file mode 100644
index 0000000..bc2db76
--- /dev/null
+++ b/src/views/operation/constant/OperationTableColumns.js
@@ -0,0 +1,57 @@
+export const getFIX_COL = (t) => [
+ {
+ title: t("operation.project"),
+ key: "work_type_name",
+ },
+ // {
+ // title: t("operation.location"),
+ // key: "location",
+ // },
+ {
+ title: t("operation.uuid"),
+ key: "error_code",
+ },
+ {
+ title: t("operation.form_number"),
+ key: "formId",
+ },
+ {
+ title: t("operation.device_name"),
+ key: "device_name",
+ },
+ {
+ title: t("operation.status"),
+ key: "status_name",
+ filter: true,
+ },
+ {
+ title: t("operation.staff"),
+ key: "user_full_name",
+ filter: true,
+ },
+ {
+ title: t("operation.start_time"),
+ key: "start_time",
+ sort: true,
+ },
+ {
+ title: t("operation.upload"),
+ key: "lorf",
+ width: "15%",
+ },
+ {
+ title: t("operation.finish_time"),
+ key: "finish_time",
+ sort: true,
+ },
+ {
+ title: t("operation.updated_time"),
+ key: "updated_at",
+ sort: true,
+ },
+ {
+ title: t("operation.operation"),
+ key: "operation",
+ width: 200,
+ },
+];
diff --git a/src/views/setting/SettingManagement.vue b/src/views/setting/SettingManagement.vue
new file mode 100644
index 0000000..4555ff3
--- /dev/null
+++ b/src/views/setting/SettingManagement.vue
@@ -0,0 +1,51 @@
+
+
+
+
diff --git a/src/views/setting/components/Building.vue b/src/views/setting/components/Building.vue
new file mode 100644
index 0000000..4bd1968
--- /dev/null
+++ b/src/views/setting/components/Building.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
{{ $t("assetManagement.building") }}
+
+
+
+
+
+ {{ index + 1 }}
+
+ openModal(record)"
+ >
+ {{ $t("button.edit") }}
+
+ remove(record.building_guid)"
+ >
+ {{ $t("button.delete") }}
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/BuildingModal.vue b/src/views/setting/components/BuildingModal.vue
new file mode 100644
index 0000000..0885c59
--- /dev/null
+++ b/src/views/setting/components/BuildingModal.vue
@@ -0,0 +1,84 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+ {{
+ $t("assetManagement.building")
+ }}
+
+ {{ formErrorMsg.full_name }}
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/Demand.vue b/src/views/setting/components/Demand.vue
new file mode 100644
index 0000000..8453490
--- /dev/null
+++ b/src/views/setting/components/Demand.vue
@@ -0,0 +1,169 @@
+
+
+
+
+
電表
+
+ {{
+ $t("button.start_edit")
+ }}
+
+
+
+ {{ $t("button.confirm") }}
+
+
+ {{ $t("button.cancel") }}
+
+
+
+
+
+
+
+
+
+
+
+ Check(record.main_id)"
+ >
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/Dept.vue b/src/views/setting/components/Dept.vue
new file mode 100644
index 0000000..7569a3f
--- /dev/null
+++ b/src/views/setting/components/Dept.vue
@@ -0,0 +1,98 @@
+
+
+
+
+
{{ $t("assetManagement.department") }}
+
+
+
+
+ {{ index + 1 }}
+
+ openModal(record)"
+ >
+ {{ $t("button.edit") }}
+
+ remove(record.id)"
+ >
+ {{ $t("button.delete") }}
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/DeptModal.vue b/src/views/setting/components/DeptModal.vue
new file mode 100644
index 0000000..be9d1d3
--- /dev/null
+++ b/src/views/setting/components/DeptModal.vue
@@ -0,0 +1,86 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+ {{
+ $t("assetManagement.department_name")
+ }}
+
+ {{ formErrorMsg.name }}
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/ElecPriceManagement.vue b/src/views/setting/components/ElecPriceManagement.vue
new file mode 100644
index 0000000..648e00d
--- /dev/null
+++ b/src/views/setting/components/ElecPriceManagement.vue
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/setting/components/ElecPriceRes.vue b/src/views/setting/components/ElecPriceRes.vue
new file mode 100644
index 0000000..07b201a
--- /dev/null
+++ b/src/views/setting/components/ElecPriceRes.vue
@@ -0,0 +1,434 @@
+
+
+
+
+
{{ $t("energy.simple_elec_price_two_stage") }}
+
+ {{
+ $t("button.start_edit")
+ }}
+
+
+
+ {{ $t("button.confirm") }}
+
+
+ {{ $t("button.cancel") }}
+
+
+
+
+
+
+
+ {{ $t("energy.simple_elec_price_three_stage") }}
+
+
+ {{
+ $t("button.start_edit")
+ }}
+
+
+
+ {{ $t("button.confirm") }}
+
+
+ {{ $t("button.cancel") }}
+
+
+
+
+
+
+
diff --git a/src/views/setting/components/ElecPriceStd.vue b/src/views/setting/components/ElecPriceStd.vue
new file mode 100644
index 0000000..0d4791c
--- /dev/null
+++ b/src/views/setting/components/ElecPriceStd.vue
@@ -0,0 +1,729 @@
+
+
+
+
+
+ {{ $t("energy.standard_time_of_use_tariff_2_stage") }}
+
+
+ {{
+ $t("button.start_edit")
+ }}
+
+
+
+ {{ $t("button.confirm") }}
+
+
+ {{ $t("button.cancel") }}
+
+
+
+
+
+
+
+ {{ $t("energy.standard_time_of_use_tariff_3_stage") }}
+
+
+ {{
+ $t("button.start_edit")
+ }}
+
+
+
+ {{ $t("button.confirm") }}
+
+
+ {{ $t("button.cancel") }}
+
+
+
+
+
+
+
diff --git a/src/views/setting/components/ElecType.vue b/src/views/setting/components/ElecType.vue
new file mode 100644
index 0000000..5942a92
--- /dev/null
+++ b/src/views/setting/components/ElecType.vue
@@ -0,0 +1,105 @@
+
+
+
+
+
{{ $t("energy.electricity_classification") }}
+
+
+
+
+ {{ index + 1 }}
+
+ openModal(record)"
+ >
+ {{ $t("button.edit") }}
+
+ remove(record.id)"
+ >
+ {{ $t("button.delete") }}
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/ElecTypeModal.vue b/src/views/setting/components/ElecTypeModal.vue
new file mode 100644
index 0000000..0038d5c
--- /dev/null
+++ b/src/views/setting/components/ElecTypeModal.vue
@@ -0,0 +1,84 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+ {{
+ $t("energy.electricity_classification")
+ }}
+
+ {{ formErrorMsg.name }}
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/Floors.vue b/src/views/setting/components/Floors.vue
new file mode 100644
index 0000000..ee6a4b1
--- /dev/null
+++ b/src/views/setting/components/Floors.vue
@@ -0,0 +1,127 @@
+
+
+
+
+
{{ $t("energy.floor") }}
+
+
+
+
+ {{ index + 1 }}
+
+ openModal(record)"
+ >
+ {{ $t("button.edit") }}
+
+ remove(record.floor_guid)"
+ >
+ {{ $t("button.delete") }}
+
+
+
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/FloorsModal.vue b/src/views/setting/components/FloorsModal.vue
new file mode 100644
index 0000000..807709a
--- /dev/null
+++ b/src/views/setting/components/FloorsModal.vue
@@ -0,0 +1,112 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+ {{ $t("assetManagement.system_name") }}
+
+ {{ formErrorMsg.name }}
+
+
+ {{ $t("assetManagement.oriFile") }}
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/MQTTCheckboxTree.vue b/src/views/setting/components/MQTTCheckboxTree.vue
new file mode 100644
index 0000000..d260334
--- /dev/null
+++ b/src/views/setting/components/MQTTCheckboxTree.vue
@@ -0,0 +1,91 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/setting/components/MQTTList.vue b/src/views/setting/components/MQTTList.vue
new file mode 100644
index 0000000..3e103db
--- /dev/null
+++ b/src/views/setting/components/MQTTList.vue
@@ -0,0 +1,279 @@
+
+
+
+
+
+
+ {{ $t("history.system_category") }} :
+
+
+
+
+
+ {{ $t("history.device_category") }} :
+
+
+
+
+
{{ $t("setting.MQTT_parse") }} :
+
+
+
+
+
{{ $t("setting.point") }} :
+
+
+
+
+ {{ record.is_bool === 1 ? t("alert.yes") : t("alert.no") }}
+
+
+ {{ record.is_link === 1 ? t("alert.yes") : t("alert.no") }}
+
+
+ openModal(record)"
+ >
+ {{ $t("button.edit") }}
+
+ remove(record.id)"
+ >
+ {{ $t("button.delete") }}
+
+
+
+
+
+
+
+
diff --git a/src/views/setting/components/MQTTListAddModal.vue b/src/views/setting/components/MQTTListAddModal.vue
new file mode 100644
index 0000000..c88c45a
--- /dev/null
+++ b/src/views/setting/components/MQTTListAddModal.vue
@@ -0,0 +1,246 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+
+
+
+
+ {{ $t("button.convert")
+ }}
+
+
+ {{ $t("button.delete")
+ }}
+
+
+
+
+
+
+
+ {{ $t("setting.schema_name") }}:
+
+
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/PointList.vue b/src/views/setting/components/PointList.vue
new file mode 100644
index 0000000..f45e4db
--- /dev/null
+++ b/src/views/setting/components/PointList.vue
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+ {{ $t("history.system_category") }} :
+
+
+
+
+
+ {{ $t("history.device_category") }} :
+
+
+
+
+
+
+
+
+
diff --git a/src/views/setting/components/PointListAddModal.vue b/src/views/setting/components/PointListAddModal.vue
new file mode 100644
index 0000000..1ebb4eb
--- /dev/null
+++ b/src/views/setting/components/PointListAddModal.vue
@@ -0,0 +1,175 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+ {{ $t("setting.IoT_point_name") }}
+
+ {{ formErrorMsg.full_name }}
+
+
+ {{ $t("setting.IoT_point_code") }}
+
+ {{ formErrorMsg.points }}
+
+
+ {{
+ $t("setting.number_of_decimal_places")
+ }}
+
+
+ {{ $t("setting.boolean_value") }}
+
+
+
+ {{ $t("setting.hide_point") }}
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/Vendor.vue b/src/views/setting/components/Vendor.vue
new file mode 100644
index 0000000..cb087c4
--- /dev/null
+++ b/src/views/setting/components/Vendor.vue
@@ -0,0 +1,128 @@
+
+
+
+
+
{{ $t("assetManagement.company") }}
+
+
+
+
+ {{ index + 1 }}
+
+ openModal(record)"
+ >
+ {{ $t("button.edit") }}
+
+ remove(record.id)"
+ >
+ {{ $t("button.delete") }}
+
+
+
+ {{ record[column.key] }}
+
+
+
+
+
+
diff --git a/src/views/setting/components/VendorModal.vue b/src/views/setting/components/VendorModal.vue
new file mode 100644
index 0000000..8fff154
--- /dev/null
+++ b/src/views/setting/components/VendorModal.vue
@@ -0,0 +1,153 @@
+
+
+
+
+ {{ $t("button.add") }}
+
+
+
+
+
+ {{ $t("operation.name") }}
+
+ {{ formErrorMsg.name }}
+
+
+ {{ $t("operation.contact_person") }}
+
+ {{ formErrorMsg.contact_person }}
+
+
+ {{ $t("operation.phone") }}
+
+ {{ formErrorMsg.phone }}
+
+
+ {{ $t("operation.email") }}
+
+ {{ formErrorMsg.email }}
+
+
+ {{ $t("operation.city") }}
+
+ {{ formErrorMsg.city }}
+
+
+ {{ $t("operation.address") }}
+
+ {{ formErrorMsg.address }}
+
+
+ {{ $t("operation.tax_id_number") }}
+
+ {{ formErrorMsg.tax_id_number }}
+
+
+ {{ $t("operation.remark") }}
+
+ {{ formErrorMsg.remark }}
+
+
+
+
+
+
+ {{ $t("button.cancel") }}
+
+
+ {{ $t("button.submit") }}
+
+
+
+
+
+
diff --git a/src/views/system/System.vue b/src/views/system/System.vue
new file mode 100644
index 0000000..aa336fc
--- /dev/null
+++ b/src/views/system/System.vue
@@ -0,0 +1,303 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ statusList.device_normal_text }}
+
+
+
+ {{ statusList.device_close_text }}
+
+
+
+ {{ statusList.device_error_text }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/system/SystemFloor.vue b/src/views/system/SystemFloor.vue
new file mode 100644
index 0000000..452aee4
--- /dev/null
+++ b/src/views/system/SystemFloor.vue
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/system/SystemMain.vue b/src/views/system/SystemMain.vue
new file mode 100644
index 0000000..4c5cb6f
--- /dev/null
+++ b/src/views/system/SystemMain.vue
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/system/components/SystemCard.vue b/src/views/system/components/SystemCard.vue
new file mode 100644
index 0000000..feaa56d
--- /dev/null
+++ b/src/views/system/components/SystemCard.vue
@@ -0,0 +1,214 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ d.full_name }}
+
+
+
fitToView(device.forge_dbid, device.spriteDbId)"
+ >
+
+
+
+
+
{{ device.full_name }}
+
+
+
+
+ {{ $t("system.status") }}:
+ {{
+ device.full_name === "SmartSocket-AA001"
+ ? "Error"
+ : device.full_name === "SmartSocket-AA003" ||
+ device.full_name === "SmartSocket-AA004"
+ ? "Offline"
+ : device.device_status || 'Online'
+ }}
+
+
{
+ if (device.full_name === 'SmartSocket-AA001') {
+ openDialog();
+ } else {
+ getCurrentInfoModalData(
+ e,
+ { left: e.clientX, top: e.clientY },
+ device
+ );
+ }
+ }
+ "
+ >
+ {{ $t("system.details") }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/system/components/SystemDeptBar.vue b/src/views/system/components/SystemDeptBar.vue
new file mode 100644
index 0000000..2c9a06c
--- /dev/null
+++ b/src/views/system/components/SystemDeptBar.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/system/components/SystemFloorBar.vue b/src/views/system/components/SystemFloorBar.vue
new file mode 100644
index 0000000..2203a5e
--- /dev/null
+++ b/src/views/system/components/SystemFloorBar.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/system/components/SystemInfoModal.vue b/src/views/system/components/SystemInfoModal.vue
new file mode 100644
index 0000000..0917efe
--- /dev/null
+++ b/src/views/system/components/SystemInfoModal.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/system/components/SystemInfoModalChart.vue b/src/views/system/components/SystemInfoModalChart.vue
new file mode 100644
index 0000000..b0d74fe
--- /dev/null
+++ b/src/views/system/components/SystemInfoModalChart.vue
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+
+
+ {{ $t("button.search") }}
+
+
+
+
+
+
+ {{ $t("table.no_data") }}
+
+
+
+
+
diff --git a/src/views/system/components/SystemInfoModalCog.vue b/src/views/system/components/SystemInfoModalCog.vue
new file mode 100644
index 0000000..49ae667
--- /dev/null
+++ b/src/views/system/components/SystemInfoModalCog.vue
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+ {{ $t("assetManagement.device_number") }}
+ {{ tableData.device_number }}
+
+
+ {{ $t("assetManagement.device_name") }}
+ {{ tableData.full_name }}
+
+
+ {{ $t("assetManagement.floor") }}
+ {{ tableData.floor }}
+
+
+ {{ $t("assetManagement.device_coordinate") }}
+ {{ tableData.device_coordinate }}
+
+
+ {{ $t("assetManagement.brand_and_modal") }}
+ {{ tableData.brand }} / {{ tableData.device_model }}
+
+
+ {{ t("assetManagement.company_and_contact") }}
+
+ {{ tableData.company?.name }} /
+ {{ tableData.company?.contact_person }}
+
+
+
+ {{ t("assetManagement.buying_date") }}
+ {{ tableData.buying_date }}
+
+
+ {{ t("assetManagement.created_at") }}
+ {{ tableData.created_at }}
+
+
+
+
+
+
diff --git a/src/views/system/components/SystemInfoModalContent.vue b/src/views/system/components/SystemInfoModalContent.vue
new file mode 100644
index 0000000..1d2e7f6
--- /dev/null
+++ b/src/views/system/components/SystemInfoModalContent.vue
@@ -0,0 +1,63 @@
+
+
+
+
+
+
{{ data?.value?.full_name }}
+
+ changeOpenKey('desktop')">
+
+
+ changeOpenKey('image')">
+
+
+ changeOpenKey('cog')">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/system/components/SystemInfoModalDesktop.vue b/src/views/system/components/SystemInfoModalDesktop.vue
new file mode 100644
index 0000000..02cd2ea
--- /dev/null
+++ b/src/views/system/components/SystemInfoModalDesktop.vue
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+ {{ $t("operation.updated_time") }} : {{ group.time }}
+
+
+
+
+
+ {{ $t("system.attribute") }}
+
+
+ {{ $t("system.value") }}
+
+
+
+
+
+
+ {{ group.full_name }}
+
+
+ {{ group.value }}
+
+
+
+
+
+
+ {{$t("table.no_data")}}
+
+
+
diff --git a/src/views/system/components/SystemInfoModalImage.vue b/src/views/system/components/SystemInfoModalImage.vue
new file mode 100644
index 0000000..c8e6cab
--- /dev/null
+++ b/src/views/system/components/SystemInfoModalImage.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/system/components/SystemMode.vue b/src/views/system/components/SystemMode.vue
new file mode 100644
index 0000000..266acc4
--- /dev/null
+++ b/src/views/system/components/SystemMode.vue
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/system/components/SystemSubBar.vue b/src/views/system/components/SystemSubBar.vue
new file mode 100644
index 0000000..a5875b3
--- /dev/null
+++ b/src/views/system/components/SystemSubBar.vue
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/stats.html b/stats.html
new file mode 100644
index 0000000..a3c2d83
--- /dev/null
+++ b/stats.html
@@ -0,0 +1,4949 @@
+
+
+
+
+
+
+
+ Rollup Visualizer
+
+
+
+
+
+
+
+
+
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..95ba9d2
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,44 @@
+module.exports = {
+ content: [
+ "./src/**/*.{vue,js,ts}",
+ "./node_modules/vue-tailwind-datepicker/**/*.js",
+ ],
+ purge: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
+ darkMode: false,
+ theme: {
+ extend: {
+ backgroundImage: {
+ navbar:
+ "linear-gradient(to bottom,rgba(0, 15, 125, 0.9),rgba(0, 96, 255, 0.9))",
+ normal:
+ "linear-gradient(180deg,rgba(127, 237, 193, 0.1),rgba(0, 0, 0, 0),rgba(127, 237, 193, 0.1))",
+ },
+ colors: {
+ dark: "#111",
+ warning: "#ffe448",
+ "sub-warning": "#BEAC53",
+ info: "#35eded",
+ "dark-info": "#24272c",
+ "light-info": "#83e0ea",
+ success: "#8ee894",
+ "sub-success": "#808B68",
+ "success-content": "#8ee894",
+ body: "#02101B",
+ danger: "#722e3c",
+ active: "#6fdda8",
+ innerTable: "rgba(111, 221, 168, 0.1)",
+ error: "#ff033e",
+ },
+ boxShadow: {
+ custom: "0px 0px 10px 1px rgba(255, 255, 255, 0.8)",
+ },
+ },
+ },
+ variants: {
+ extend: {},
+ },
+ plugins: [require("daisyui")],
+ daisyui: {
+ themes: ["synthwave", "dracula"],
+ },
+};
diff --git a/vite.config.js b/vite.config.js
new file mode 100644
index 0000000..9f03cdd
--- /dev/null
+++ b/vite.config.js
@@ -0,0 +1,50 @@
+import { fileURLToPath, URL } from "node:url";
+import { defineConfig } from "vite";
+import vue from "@vitejs/plugin-vue";
+import Components from "unplugin-vue-components/vite";
+import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
+import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
+import path from "path";
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ base: process.env.NODE_ENV === "production" ? "./" : "/",
+ build: {
+ outDir: "./dist",
+ emptyOutDir: true,
+ },
+ server: {
+ proxy: {
+ "/upload": {
+ target: "https://ibms-empower2.production.mjmtech.com.tw",
+ changeOrigin: true,
+ secure: false,
+ },
+ },
+ },
+ plugins: [
+ vue(),
+ Components({
+ resolvers: [
+ AntDesignVueResolver({
+ importStyle: false, // css in js
+ }),
+ ],
+ }),
+ createSvgIconsPlugin({
+ iconDirs: [path.resolve(process.cwd(), "src/assets/icon")],
+ symbolId: "icon-[dir]-[name]",
+ }),
+ ],
+ css: {
+ preprocessorOptions: {
+ scss: {},
+ },
+ },
+ resolve: {
+ alias: {
+ "@": fileURLToPath(new URL("./src", import.meta.url)),
+ "@ASSET": fileURLToPath(new URL("./src/assets", import.meta.url)),
+ },
+ },
+});