diff --git a/index.html b/index.html
index d3ee532..166a1b3 100644
--- a/index.html
+++ b/index.html
@@ -5,6 +5,11 @@
EMS
+
+
diff --git a/package-lock.json b/package-lock.json
index 8e62c85..5703962 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,8 +8,10 @@
"name": "ems_front",
"version": "0.0.0",
"dependencies": {
+ "dayjs": "^1.11.13",
"echarts": "^5.6.0",
"element-plus": "^2.9.6",
+ "pinia": "^3.0.2",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
},
@@ -969,6 +971,28 @@
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"license": "MIT"
},
+ "node_modules/@vue/devtools-kit": {
+ "version": "7.7.5",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.5.tgz",
+ "integrity": "sha512-S9VAVJYVAe4RPx2JZb9ZTEi0lqTySz2CBeF0wHT5D3dkTLnT9yMMGegKNl4b2EIELwLSkcI9bl2qp0/jW+upqA==",
+ "dependencies": {
+ "@vue/devtools-shared": "^7.7.5",
+ "birpc": "^2.3.0",
+ "hookable": "^5.5.3",
+ "mitt": "^3.0.1",
+ "perfect-debounce": "^1.0.0",
+ "speakingurl": "^14.0.1",
+ "superjson": "^2.2.2"
+ }
+ },
+ "node_modules/@vue/devtools-shared": {
+ "version": "7.7.5",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.5.tgz",
+ "integrity": "sha512-QBjG72RfpM0DKtpns2RZOxBltO226kOAls9e4Lri6YxS2gWTgL0H+wj1R2K76lxxIeOrqo4+2Ty6RQnzv+WSTQ==",
+ "dependencies": {
+ "rfdc": "^1.4.1"
+ }
+ },
"node_modules/@vue/language-core": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.8.tgz",
@@ -1224,6 +1248,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/birpc": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.3.0.tgz",
+ "integrity": "sha512-ijbtkn/F3Pvzb6jHypHRyve2QApOCZDR25D/VnkY2G/lBNcXCTsnsCxgY4k4PkVB7zfwzYbY3O9Lcqe3xufS5g==",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
@@ -1279,6 +1311,20 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/copy-anything": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
+ "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
+ "dependencies": {
+ "is-what": "^4.1.8"
+ },
+ "engines": {
+ "node": ">=12.13"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mesqueeb"
+ }
+ },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -1288,8 +1334,7 @@
"node_modules/dayjs": {
"version": "1.11.13",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
- "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
- "license": "MIT"
+ "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
},
"node_modules/de-indent": {
"version": "1.0.2",
@@ -1503,6 +1548,11 @@
"he": "bin/he"
}
},
+ "node_modules/hookable": {
+ "version": "5.5.3",
+ "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
+ "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="
+ },
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -1549,6 +1599,17 @@
"node": ">=0.12.0"
}
},
+ "node_modules/is-what": {
+ "version": "4.1.16",
+ "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
+ "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
+ "engines": {
+ "node": ">=12.13"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mesqueeb"
+ }
+ },
"node_modules/js-tokens": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
@@ -1628,6 +1689,11 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/mitt": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
+ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
+ },
"node_modules/mlly": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz",
@@ -1722,6 +1788,11 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/perfect-debounce": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
+ "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -1741,6 +1812,34 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pinia": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.2.tgz",
+ "integrity": "sha512-sH2JK3wNY809JOeiiURUR0wehJ9/gd9qFN2Y828jCbxEzKEmEt0pzCXwqiSTfuRsK9vQsOflSdnbdBOGrhtn+g==",
+ "dependencies": {
+ "@vue/devtools-api": "^7.7.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.4.4",
+ "vue": "^2.7.0 || ^3.5.11"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/pinia/node_modules/@vue/devtools-api": {
+ "version": "7.7.5",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.5.tgz",
+ "integrity": "sha512-HYV3tJGARROq5nlVMJh5KKHk7GU8Au3IrrmNNqr978m0edxgpHgYPDoNUGrvEgIbObz09SQezFR3A1EVmB5WZg==",
+ "dependencies": {
+ "@vue/devtools-kit": "^7.7.5"
+ }
+ },
"node_modules/pkg-types": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz",
@@ -1824,6 +1923,11 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/rfdc": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
+ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="
+ },
"node_modules/rollup": {
"version": "4.36.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.36.0.tgz",
@@ -1879,6 +1983,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/speakingurl": {
+ "version": "14.0.1",
+ "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
+ "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/strip-literal": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz",
@@ -1892,6 +2004,17 @@
"url": "https://github.com/sponsors/antfu"
}
},
+ "node_modules/superjson": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz",
+ "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==",
+ "dependencies": {
+ "copy-anything": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/tinyglobby": {
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz",
diff --git a/package.json b/package.json
index 17aadd8..97b09ff 100644
--- a/package.json
+++ b/package.json
@@ -9,8 +9,10 @@
"preview": "vite preview"
},
"dependencies": {
+ "dayjs": "^1.11.13",
"echarts": "^5.6.0",
"element-plus": "^2.9.6",
+ "pinia": "^3.0.2",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
},
diff --git a/src/components/EnergyLine.vue b/src/components/EnergyLine.vue
index 058d616..4cc7eea 100644
--- a/src/components/EnergyLine.vue
+++ b/src/components/EnergyLine.vue
@@ -1,7 +1,9 @@
diff --git a/src/components/EnergySankey.vue b/src/components/EnergySankey.vue
index 0012265..472c690 100644
--- a/src/components/EnergySankey.vue
+++ b/src/components/EnergySankey.vue
@@ -1,16 +1,36 @@
diff --git a/src/main.ts b/src/main.ts
index 466ad5c..f1f0e32 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,8 +1,11 @@
-import { createApp } from 'vue'
-import './reset.css'
-import App from './App.vue'
-import router from './router'
+import { createApp } from "vue";
+import "./reset.css";
+import { createPinia } from "pinia";
+import App from "./App.vue";
+import router from "./router";
-const app = createApp(App)
-app.use(router)
-app.mount('#app')
+const pinia = createPinia();
+const app = createApp(App);
+app.use(pinia);
+app.use(router);
+app.mount("#app");
diff --git a/src/stores/useElecDemandStore.ts b/src/stores/useElecDemandStore.ts
new file mode 100644
index 0000000..ceca673
--- /dev/null
+++ b/src/stores/useElecDemandStore.ts
@@ -0,0 +1,44 @@
+import { ref } from "vue";
+import { defineStore } from "pinia";
+// import dayjs from "dayjs";
+import type { NiagaraElecData } from "../utils/types";
+
+const useElecStore = defineStore("elecData", () => {
+ const elecData = ref([]);
+
+ // get data from baja
+ const getElecDataFromBaja = () => {
+ // @ts-ignore
+ window.require &&
+ // @ts-ignore
+ window.requirejs(["baja!"], (baja: any) => {
+ console.log("進入 bajaSubscriber 準備執行 BQL 訂閱");
+ let eleclist: NiagaraElecData[] = [];
+ baja.Ord.make(
+ `local:|foxs:4912|station:|neql:EMS:kw|bql:select slotPath,parent.displayName,name`
+ ).get({
+ cursor: {
+ before: () => {
+ },
+ each: (record: any) => {
+ console.log("record", record);
+ // eleclist.push({
+ // slotPath: record.get("slotPath"),
+ // displayName: record.get("parent$2edisplayName"),
+ // id: record.get("NumericInterval$2ehistoryConfig$2eid").$cEncStr,
+ // out: record.get("out").get("value"),
+ // });
+ },
+ after: () => {
+ elecData.value = eleclist;
+ console.log("Niagara 用電:", elecData.value);
+ },
+ },
+ });
+ });
+ };
+
+ return { getElecDataFromBaja, elecData };
+});
+
+export default useElecStore;
diff --git a/src/stores/useElecDistStore.ts b/src/stores/useElecDistStore.ts
new file mode 100644
index 0000000..a01ce76
--- /dev/null
+++ b/src/stores/useElecDistStore.ts
@@ -0,0 +1,127 @@
+import { ref } from "vue";
+import { defineStore } from "pinia";
+import dayjs from "dayjs";
+import type { NiagaraElecData } from "../utils/types";
+
+const useElecStore = defineStore("elecData", () => {
+ const elecData = ref([]);
+ // @ts-ignore
+ let timerId = null;
+ // get data from baja
+ const getElecDataFromBaja = () => {
+ // @ts-ignore
+ window.require &&
+ // @ts-ignore
+ window.requirejs(["baja!"], (baja: any) => {
+ console.log("進入 bajaSubscriber 準備執行 BQL 訂閱");
+
+ // 定義BQL 查詢
+ const subSysKwhBql = `local:|foxs:4918|station:|neql:EMS:SubSys_kwh|bql:select slotPath,parent.displayName,displayName,NumericInterval.historyConfig.id`;
+
+ // 執行各電表的 BQL 查詢
+ fetchElecData(baja, subSysKwhBql);
+ });
+ };
+
+ const fetchElecData = (baja: any, bql: string) => {
+ let eleclist: NiagaraElecData[] = [];
+ baja.Ord.make(bql).get({
+ cursor: {
+ before: () => {},
+ each: (record: any) => {
+ eleclist.push({
+ slotPath: record.get("slotPath"),
+ displayName: record.get("parent$2edisplayName"),
+ id: record.get("NumericInterval$2ehistoryConfig$2eid").$cEncStr,
+ out: 0,
+ });
+ },
+ after: () => {
+ const validElecList = eleclist.filter(
+ (item) => item.id !== undefined
+ );
+ elecData.value = [...elecData.value, ...validElecList];
+ validElecList.forEach((item) => {
+ subscribeToHistory(item);
+ });
+ },
+ },
+ });
+ };
+
+ const subscribeToHistory = (item: NiagaraElecData) => {
+ const startTime = dayjs()
+ .subtract(2, "hour")
+ .format("YYYY-MM-DDTHH:mm:ss.000+08:00"); // 現在時間前2個小時
+ const endTime = dayjs().format("YYYY-MM-DDTHH:mm:ss.000+08:00"); // 現在的時間
+ const id = item.id;
+ console.log(
+ `local:|foxs:4918|history:${id}?period=timerange;start=${startTime};end=${endTime}|bql:history:HistoryRollup.rollup(baja:RelTime '3600000')`
+ );
+ const ordString = `local:|foxs:4918|history:${id}?period=timerange;start=${startTime};end=${endTime}|bql:history:HistoryRollup.rollup(baja:RelTime '3600000')`;
+ // @ts-ignore
+ window.require &&
+ // @ts-ignore
+ window.requirejs(["baja!"], (baja: any) => {
+ console.log("進入 bajaSubscriber 準備執行 BQL 訂閱");
+ let historyData: number[] = [];
+ baja.Ord.make(ordString).get({
+ cursor: {
+ before: () => {
+ console.log(`開始訂閱 ${id} 的歷史資料`);
+ },
+ each: (record: any) => {
+ let currentValue = record.get("min");
+ historyData.push(currentValue);
+ },
+ after: () => {
+ const diff = historyData[historyData.length - 1] - historyData[0];
+ console.log(
+ `收到 ${id} 的歷史資料: 最後一筆減第一筆的值為:`,
+ diff
+ );
+
+ elecData.value = elecData.value.map((elec) => {
+ if (elec.id === id) {
+ console.log(`更新 ${id} 的 out 值為:`, diff);
+ return { ...elec, out: diff };
+ }
+ return elec;
+ });
+ },
+ },
+ });
+ });
+ };
+
+ // 定時更新資料的函數
+ const updateHistoryData = () => {
+ console.log("定時器觸發,重新獲取歷史資料");
+ if (elecData.value && elecData.value.length > 0) {
+ elecData.value.forEach((item) => {
+ subscribeToHistory(item);
+ });
+ }
+ };
+
+ // 啟動定時器
+ const startTimer = () => {
+ timerId = setInterval(() => {
+ updateHistoryData();
+ }, 60 * 1000); // 每小時執行一次
+ };
+
+ // 停止定時器
+ const stopTimer = () => {
+ // @ts-ignore
+ if (timerId) {
+ clearInterval(timerId);
+ timerId = null;
+ console.log("計時器已停止");
+ }
+ };
+
+ return { getElecDataFromBaja, startTimer, stopTimer, elecData };
+});
+
+export default useElecStore;
diff --git a/src/stores/useElecStore copy.ts b/src/stores/useElecStore copy.ts
new file mode 100644
index 0000000..050796b
--- /dev/null
+++ b/src/stores/useElecStore copy.ts
@@ -0,0 +1,59 @@
+import { ref } from "vue";
+import { defineStore } from "pinia";
+// import dayjs from "dayjs";
+import type { NiagaraElecData } from "../utils/types";
+
+const useElecStore = defineStore("elecData", () => {
+ // @ts-ignore
+ let timer = null;
+ const elecData = ref([]);
+
+ // get data from baja
+ const getElecDataFromBaja = () => {
+ // @ts-ignore
+ window.require &&
+ // @ts-ignore
+ window.requirejs(["baja!"], (baja: any) => {
+ console.log("進入 bajaSubscriber 準備執行 BQL 訂閱");
+ let eleclist: NiagaraElecData[] = [];
+ baja.Ord.make(
+ `local:|foxs:4912|station:|neql:EMS:SubSys_kwh|bql:select slotPath,parent.displayName,name,out`
+ ).get({
+ cursor: {
+ before: () => {
+ timer = null;
+ },
+ each: (record: any) => {
+ console.log("record", record);
+ eleclist.push({
+ slotPath: record.get("slotPath"),
+ displayName: record.get("parent$2edisplayName"),
+ id: record.get("NumericInterval$2ehistoryConfig$2eid").$cEncStr,
+ out: record.get("out").get("value"),
+ });
+ },
+ after: () => {
+ elecData.value = eleclist;
+ console.log("Niagara 用電:", elecData.value);
+ timer = setTimeout(() => {
+ getElecDataFromBaja();
+ }, 30000);
+ },
+ },
+ });
+ });
+ };
+
+ const clearElecDataFromBaja = () => {
+ // @ts-ignore
+ if (timer) {
+ clearTimeout(timer);
+ timer = null;
+ console.log("Timeout 已清除");
+ }
+ };
+
+ return { getElecDataFromBaja, clearElecDataFromBaja, elecData };
+});
+
+export default useElecStore;
diff --git a/src/utils/types.ts b/src/utils/types.ts
new file mode 100644
index 0000000..f1cf055
--- /dev/null
+++ b/src/utils/types.ts
@@ -0,0 +1,7 @@
+// Niagara 用電數據類型定義
+export interface NiagaraElecData {
+ slotPath: string;
+ displayName: string;
+ id: string;
+ out: number;
+}
\ No newline at end of file
diff --git a/src/views/EnergyChart.vue b/src/views/EnergyChart.vue
index 09c7eb5..3f2ed58 100644
--- a/src/views/EnergyChart.vue
+++ b/src/views/EnergyChart.vue
@@ -2,7 +2,7 @@
- 用電即時分佈
+ 用電即時分佈 (kwh)
@@ -65,7 +65,7 @@