diff --git a/components.d.ts b/components.d.ts index 99c46df..2c07aec 100644 --- a/components.d.ts +++ b/components.d.ts @@ -13,8 +13,12 @@ declare module 'vue' { ElCard: typeof import('element-plus/es')['ElCard'] ElCol: typeof import('element-plus/es')['ElCol'] ElContainer: typeof import('element-plus/es')['ElContainer'] + ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] + ElDialog: typeof import('element-plus/es')['ElDialog'] + ElForm: typeof import('element-plus/es')['ElForm'] + ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElHeader: typeof import('element-plus/es')['ElHeader'] ElInput: typeof import('element-plus/es')['ElInput'] ElMain: typeof import('element-plus/es')['ElMain'] @@ -24,6 +28,7 @@ declare module 'vue' { ElStatistic: typeof import('element-plus/es')['ElStatistic'] EnergyBar: typeof import('./src/components/EnergyBar.vue')['default'] EnergyLine: typeof import('./src/components/EnergyLine.vue')['default'] + EnergyModal: typeof import('./src/components/EnergyModal.vue')['default'] EnergyPie: typeof import('./src/components/EnergyPie.vue')['default'] EnergySankey: typeof import('./src/components/EnergySankey.vue')['default'] Navbar: typeof import('./src/components/Navbar.vue')['default'] diff --git a/src/components/EnergyModal.vue b/src/components/EnergyModal.vue new file mode 100644 index 0000000..9fdb692 --- /dev/null +++ b/src/components/EnergyModal.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/EnergyPie.vue b/src/components/EnergyPie.vue index a854b16..33981fe 100644 --- a/src/components/EnergyPie.vue +++ b/src/components/EnergyPie.vue @@ -1,30 +1,18 @@ diff --git a/src/stores/useElecPriceStore.ts b/src/stores/useElecPriceStore.ts index a362c19..8a0736d 100644 --- a/src/stores/useElecPriceStore.ts +++ b/src/stores/useElecPriceStore.ts @@ -1,6 +1,7 @@ import { ref } from "vue"; import { defineStore } from "pinia"; import type { NiagaraElecData } from "../utils/types"; +import axios from "axios"; const useElecPriceStore = defineStore("elecPriceData", () => { const elecData = ref([]); @@ -101,6 +102,30 @@ const useElecPriceStore = defineStore("elecPriceData", () => { }); }; + const updatePrice = async (slotPath: string, out: number) => { + const domain = window.location.origin; + try { + console.log("updatePrice",`${domain}/obix/config/${slotPath}/in2/value`) + const res = await axios.put( + `${domain}/obix/config/${slotPath}/in2/value`, + ` `, + { + headers: { "Content-Type": "text/xml" }, + } + ); + if (res.status === 200) { + console.log(`成功更新 ${slotPath} 為 ${out}`); + return true; + } else { + console.error(`更新 ${slotPath} 失敗,狀態碼: ${res.status}`); + return false; + } + } catch (error) { + console.error(`更新 ${slotPath} 出錯:`, error); + return false; + } + }; + const clearAllSubscriber = () => { subscribers.value.forEach((subscriber) => { subscriber.detach("changed"); @@ -112,6 +137,7 @@ const useElecPriceStore = defineStore("elecPriceData", () => { return { getElecDataFromBaja, + updatePrice, clearAllSubscriber, elecData, }; diff --git a/src/stores/useElecReportStore.ts b/src/stores/useElecReportStore.ts new file mode 100644 index 0000000..eb0224d --- /dev/null +++ b/src/stores/useElecReportStore.ts @@ -0,0 +1,202 @@ +import { ref } from "vue"; +import { defineStore } from "pinia"; +import dayjs from "dayjs"; +import type { ElecCostSummaryMap } from "../utils/types"; +import { CalcuEleCost, CalcuEleStandCost } from "../utils/CalcuEleCost"; + + + +const useElecReportStore = defineStore("elecReportData", () => { + const elecData = ref([]); + // @ts-ignore + let timerId = null; + + // 初始化為空物件,並定義類型 + const elecCostSummary = ref({ + thisMonth: {}, + lastMonth: {}, + }); + + // 儲存每個電表的 dataMap + const elecDataMaps = ref<{ + [id: string]: { + thisMonth: Map; + lastMonth: Map; + }; + }>({}); + + const startTime = ref(""); + const endTime = ref(""); + + // get data from baja + const getElecDataFromBaja = () => { + // @ts-ignore + window.require && + // @ts-ignore + window.requirejs(["baja!"], (baja: any) => { + console.log("進入 bajaSubscriber 準備執行用電度數 BQL 訂閱"); + + // 定義BQL 查詢 + const Total_kwhBql = `local:|foxs:4918|station:|neql:EMS:SubSys_kwh|bql:select slotPath,parent.displayName,displayName,NumericInterval.historyConfig.id,out`; + + // 執行各電表的 BQL 查詢 + fetchElecData(baja, Total_kwhBql); + }); + }; + + const fetchElecData = (baja: any, bql: string) => { + let eleclist: any[] = []; + 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, + area: record.get("out")?.get("value") ?? "", + }); + }, + after: () => { + const validElecList = eleclist.filter( + (item) => item.id !== undefined + ); + const menoElecList = eleclist.filter((item) => item.id == undefined); + const displayNameToAreaMap = new Map(); + menoElecList.forEach((item) => { + displayNameToAreaMap.set(item.displayName, item.area); + }); + validElecList.forEach((item) => { + const area = displayNameToAreaMap.get(item.displayName); + if (area) { + item.area = area; // 將 area 賦值給 validElecList 中的 item + } + }); + elecData.value = []; + elecData.value.push(...validElecList); + validElecList.forEach((item) => { + const id = item.id; + elecDataMaps.value[id] = { + thisMonth: new Map(), + lastMonth: new Map(), + }; + // 初始化每个 slotPath 的值为 undefined 或 null + elecCostSummary.value.thisMonth[id] = undefined; + elecCostSummary.value.lastMonth[id] = undefined; + getTimeToHistory(item, 'thisMonth'); // 獲取本月 + getTimeToHistory(item, 'lastMonth'); // 獲取上個月 + }); + }, + }, + }); + }; + + const getTimeToHistory = (item: any, month: 'thisMonth' | 'lastMonth') => { + const id = item.id; + let startTimeValue = startTime.value; + let endTimeValue = endTime.value; + + if (month === 'lastMonth') { + startTimeValue = dayjs(startTime.value).subtract(1, 'month').startOf('month').format("YYYY-MM-DDTHH:mm:ss.000+08:00"); + endTimeValue = dayjs(endTime.value).subtract(1, 'month').endOf('month').format("YYYY-MM-DDTHH:mm:ss.000+08:00"); + } + + const ordString = `local:|foxs:4918|history:${id}?period=timerange;start=${startTimeValue};end=${endTimeValue}|bql:history:HistoryRollup.rollup(baja:RelTime '3600000')`; //每小时一个rollup + console.log(ordString); + // @ts-ignore + window.require && + // @ts-ignore + window.requirejs(["baja!"], (baja: any) => { + // 使用對應電表的 dataMap + const dataMap = elecDataMaps.value[id][month]; + if (!dataMap) { + console.warn(`未找到電表 ${id} (${month}) 的 dataMap`); + return; + } + let lastTimestamp: string | null = null; + let lastValue: number | null = null; + baja.Ord.make(ordString).get({ + cursor: { + before: () => { + console.log(`開始訂閱 ${id} 的歷史資料`); + }, + each: (record: any) => { + const currentValue = record.get("min"); + const timestamp = record.get("timestamp").$cEncStr; + if ( + currentValue !== null && + currentValue !== 0 && + timestamp !== null + ) { + if ( + lastTimestamp !== null && + lastValue !== null && + lastValue !== 0 + ) { + const diff = currentValue - lastValue; + dataMap.set(lastTimestamp, diff); + } + lastValue = currentValue; + lastTimestamp = timestamp; + } + }, + after: () => { + const elecCost = CalcuEleCost(dataMap); + const eleceStandCost = CalcuEleStandCost(dataMap); + console.log(`⏱️ 電表 ${id} 每小時差值 map:`, dataMap); + if (item.slotPath) { + // 确保 slotPath 存在 + elecCostSummary.value[month][id] = { + ...elecCost, + standCost: eleceStandCost.StandCost, + name: item.displayName, + area: item.area, + }; + console.log( + `電表 ${item.displayName} 的電費計算結果 (${month}):`, + elecCostSummary.value[month][id] + ); + } else { + console.warn( + `電表 ${id} 的 slotPath 為空,無法儲存電費計算結果 (${month})` + ); + } + }, + limit: -1, + offset: 0, + }, + }); + }); + }; + + + // 定時更新資料的函數 + const updateHistoryData = () => { + console.log("重新獲取歷史資料"); + if (elecData.value && elecData.value.length > 0) { + elecCostSummary.value.thisMonth = {}; + elecCostSummary.value.lastMonth = {}; + + elecData.value.forEach((item) => { + const id = item.id; + elecDataMaps.value[id] = { + thisMonth: new Map(), + lastMonth: new Map(), + }; + getTimeToHistory(item, 'thisMonth'); + getTimeToHistory(item, 'lastMonth'); + }); + } + }; + + return { + getElecDataFromBaja, + elecData, + elecCostSummary, + startTime, + endTime, + updateHistoryData, + }; +}); + +export default useElecReportStore; diff --git a/src/stores/useElecTotalMeterStore.ts b/src/stores/useElecTotalMeterStore.ts index 5c20d7a..3624ef4 100644 --- a/src/stores/useElecTotalMeterStore.ts +++ b/src/stores/useElecTotalMeterStore.ts @@ -1,14 +1,19 @@ import { ref } from "vue"; import { defineStore } from "pinia"; import dayjs from "dayjs"; -import type { NiagaraElecData, ElecCostSummary } from "../utils/types"; -import { CalcuEleCost } from "../utils/CalcuEleCost"; +import type { + NiagaraElecData, + ElecCostSummary, + ElecStandCostSummary, +} from "../utils/types"; +import { CalcuEleCost, CalcuEleStandCost } from "../utils/CalcuEleCost"; const useElecStore = defineStore("elecData", () => { const elecData = ref([]); // @ts-ignore let timerId = null; - const elecCostSummary = ref(null); + const elecFlowCostSummary = ref(null); + const elecStandCostSummary = ref(null); // get data from baja const getElecDataFromBaja = () => { @@ -78,18 +83,27 @@ const useElecStore = defineStore("elecData", () => { each: (record: any) => { const currentValue = record.get("min"); const timestamp = record.get("timestamp").$cEncStr; - if (currentValue !== null && currentValue !== 0 && timestamp !== null) { - if (lastTimestamp !== null && lastValue !== null && lastValue !== 0) { + if ( + currentValue !== null && + currentValue !== 0 && + timestamp !== null + ) { + if ( + lastTimestamp !== null && + lastValue !== null && + lastValue !== 0 + ) { const diff = currentValue - lastValue; dataMap.set(lastTimestamp, diff); } lastValue = currentValue; lastTimestamp = timestamp; - } + } }, after: () => { console.log("⏱️ 每小時差值 map:", dataMap); - elecCostSummary.value = CalcuEleCost(dataMap); + elecFlowCostSummary.value = CalcuEleCost(dataMap); + elecStandCostSummary.value = CalcuEleStandCost(dataMap); }, limit: -1, offset: 0, @@ -129,7 +143,8 @@ const useElecStore = defineStore("elecData", () => { startTimer, stopTimer, elecData, - elecCostSummary, + elecFlowCostSummary, + elecStandCostSummary, }; }); diff --git a/src/utils/CalcuEleCost.ts b/src/utils/CalcuEleCost.ts index 70addc5..b16baa0 100644 --- a/src/utils/CalcuEleCost.ts +++ b/src/utils/CalcuEleCost.ts @@ -1,10 +1,18 @@ -import type { DailyResult, ElecCostSummary, DailyEntry } from "../utils/types"; +import type { + DailyResult, + ElecCostSummary, + DailyEntry, + StandEntry, + ElecStandCostSummary, + StandResult, +} from "../utils/types"; import useElecPriceStore from "../stores/useElecPriceStore"; -const storeElecPrice = useElecPriceStore(); +import useElecDemandStore from "../stores/useElecDemandStore"; -export const CalcuEleCost = ( - input: Map -): ElecCostSummary => { +const storeElecPrice = useElecPriceStore(); +const ContractUseValue = useElecDemandStore(); + +export const CalcuEleCost = (input: Map): ElecCostSummary => { const dailyData: Map = new Map(); let totalFlowCost = 0; // 總電價 let totalEleCost = 0; //總用電 @@ -17,13 +25,27 @@ export const CalcuEleCost = ( const dailyResults: DailyResult[] = []; const elecPrices = storeElecPrice.elecData; - const Summer_Off_Prices = elecPrices.find((item:any) => item.displayName === "流動週日離峰夏月")?.out || 0; - const Summer_HalfPeak_Prices_Saturday = elecPrices.find((item:any) => item.displayName === "流動週六半尖峰夏月")?.out || 0; - const Summer_HalfPeak_Prices_Weekday = elecPrices.find((item:any) => item.displayName === "流動平日半尖峰夏月")?.out || 0; - const Summer_Peak_Prices = elecPrices.find((item:any) => item.displayName === "流動平日尖峰夏月")?.out || 0; - const Non_Summer_Off_Prices = elecPrices.find((item:any) => item.displayName === "流動週日離峰非夏月")?.out || 0; - const Non_Summer_HalfPeak_Prices_Saturday = elecPrices.find((item:any) => item.displayName === "流動週六半尖峰非夏月")?.out || 0; - const Non_Summer_HalfPeak_Prices_Weekday = elecPrices.find((item:any) => item.displayName === "流動平日半尖峰非夏月")?.out || 0; + const Summer_Off_Prices = + elecPrices.find((item: any) => item.displayName === "流動週日離峰夏月") + ?.out || 0; + const Summer_HalfPeak_Prices_Saturday = + elecPrices.find((item: any) => item.displayName === "流動週六半尖峰夏月") + ?.out || 0; + const Summer_HalfPeak_Prices_Weekday = + elecPrices.find((item: any) => item.displayName === "流動平日半尖峰夏月") + ?.out || 0; + const Summer_Peak_Prices = + elecPrices.find((item: any) => item.displayName === "流動平日尖峰夏月") + ?.out || 0; + const Non_Summer_Off_Prices = + elecPrices.find((item: any) => item.displayName === "流動週日離峰非夏月") + ?.out || 0; + const Non_Summer_HalfPeak_Prices_Saturday = + elecPrices.find((item: any) => item.displayName === "流動週六半尖峰非夏月") + ?.out || 0; + const Non_Summer_HalfPeak_Prices_Weekday = + elecPrices.find((item: any) => item.displayName === "流動平日半尖峰非夏月") + ?.out || 0; // 1. 將輸入資料按日期分組 input.forEach((value, key) => { const dateStr = key.substring(0, 10); @@ -117,7 +139,6 @@ export const CalcuEleCost = ( dailyEleCost, dailyFlowCost, }); - } return { dailyResults, @@ -131,3 +152,72 @@ export const CalcuEleCost = ( total_peakCost, }; }; + +export const CalcuEleStandCost = ( + input: Map +): ElecStandCostSummary => { + const elecPrices = storeElecPrice.elecData; + const ContractUseData = ContractUseValue.elecData; + + const Three_Phase = + elecPrices.find((item: any) => item.displayName === "基本按戶三相")?.out || + 0; + const Summer_Regular_Use = + elecPrices.find((item: any) => item.displayName === "基本經常夏月")?.out || + 0; + const Non_Summer_Regular_Use = + elecPrices.find((item: any) => item.displayName === "基本經常非夏月") + ?.out || 0; + const ContractUse = + ContractUseData.find((item: any) => item.name === "Engel")?.out || 0; + + const monthMap = new Map(); // key: yyyy-MM + + // 將資料依據年月分組 + input.forEach((value, key) => { + const date = new Date(key); + const year = date.getFullYear(); + const month = date.getMonth() + 1; + const ymKey = `${year}-${month.toString().padStart(2, "0")}`; + + if (!monthMap.has(ymKey)) { + monthMap.set(ymKey, []); + } + monthMap.get(ymKey)?.push({ time: date, value }); + }); + + const StandResults: StandResult[] = []; + let totalStandCost = 0; + + for (const [ym, entries] of monthMap.entries()) { + if (!entries || entries.length === 0) continue; + + const sampleDate = entries[0].time; + const month = sampleDate.getMonth() + 1; + const isSummer = month >= 6 && month <= 9; + + let Phase = Three_Phase; + let Contract = isSummer ? Summer_Regular_Use : Non_Summer_Regular_Use; + + const StandCost = Phase + Contract * ContractUse; + + StandResults.push({ + Phase, + Contract, + ContractUse, + StandCost, + }); + + totalStandCost += StandCost; + console.log(`=== ${ym} ===`); + console.log(` 按戶類別: ${Phase.toFixed(2)}`); + console.log(` 契約類型: $${Contract.toFixed(2)}`); + console.log(` 契約度數: $${ContractUse.toFixed(2)}`); + console.log(` 基本電價: $${StandCost.toFixed(2)}`); + } + + return { + StandResults, + StandCost: totalStandCost, + }; +}; diff --git a/src/utils/getRandomColor.ts b/src/utils/getRandomColor.ts new file mode 100644 index 0000000..feeec0f --- /dev/null +++ b/src/utils/getRandomColor.ts @@ -0,0 +1,21 @@ +const predefinedColors = ["#5470c6", "#91cc75", "#fac858"]; +let colorIndex = 0; + +const getRandomColor = () => { + if (colorIndex < predefinedColors.length) { + return predefinedColors[colorIndex++]; + } else { + const letters = "0123456789ABCDEF"; + let color = "#"; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; + } +}; + +getRandomColor.resetIndex = () => { + colorIndex = 0; +}; + +export default getRandomColor; diff --git a/src/utils/types.ts b/src/utils/types.ts index 3d62def..4f5f714 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -3,14 +3,14 @@ export interface NiagaraElecData { slotPath: string; displayName: string; id: string; - out: number; + out: number; } export interface NiagaraElecDemandData { slotPath: string; displayName: string; name: string; - out: number; + out: number; } export interface DailyResult { @@ -18,9 +18,9 @@ export interface DailyResult { off: number; half: number; peak: number; - offcost:number; - halfcost:number; - peakcost:number; + offcost: number; + halfcost: number; + peakcost: number; dailyEleCost: number; dailyFlowCost: number; } @@ -35,9 +35,38 @@ export interface ElecCostSummary { total_OffCost: number; total_halfCost: number; total_peakCost: number; + standCost?:number; + name?: string; + area?: string; +} + +export interface ElecCostSummaryMap { + thisMonth: { + [slotPath: string]: ElecCostSummary | null | undefined; + }; + lastMonth: { + [slotPath: string]: ElecCostSummary | null | undefined; + }; } export interface DailyEntry { time: Date; value: number; +} + +export interface StandEntry { + time: Date; + value: number; +} + +export interface StandResult { + Phase : number ; + Contract : number ; + ContractUse : number; + StandCost :number ; +} + +export interface ElecStandCostSummary { + StandResults: StandResult[]; + StandCost :number ; } \ No newline at end of file diff --git a/src/views/EnergyChart.vue b/src/views/EnergyChart.vue index 63f4c36..0866531 100644 --- a/src/views/EnergyChart.vue +++ b/src/views/EnergyChart.vue @@ -73,11 +73,19 @@ import useElecTotalMeterStore from "../stores/useElecTotalMeterStore"; import dayjs from "dayjs"; const storeElecTotal = useElecTotalMeterStore(); +const billingDateRange = ref(""); watch( - () => storeElecTotal.elecCostSummary, + () => storeElecTotal.elecFlowCostSummary, (newElecData) => { - console.log("elecCostSummary", newElecData); + console.log("elecFlowCostSummary", newElecData); + }, + { deep: true } +); +watch( + () => storeElecTotal.elecStandCostSummary, + (newElecData) => { + console.log("elecStandCostSummary", newElecData); }, { deep: true } ); @@ -85,6 +93,11 @@ watch( onMounted(async () => { await storeElecTotal.getElecDataFromBaja(); storeElecTotal.startTimer(); + + // 區間計費時間區段 + billingDateRange.value = `${dayjs() + .startOf("month") + .format("YYYY/MM/DD")} - ${dayjs().format("YYYY/MM/DD")}`; }); onUnmounted(() => { @@ -97,8 +110,8 @@ const statisticData = computed(() => { let intervalFlowCost = 0; let intervalEleCost = 0; - if (storeElecTotal.elecCostSummary?.dailyResults) { - storeElecTotal.elecCostSummary.dailyResults.forEach((dailyResult) => { + if (storeElecTotal.elecFlowCostSummary?.dailyResults) { + storeElecTotal.elecFlowCostSummary.dailyResults.forEach((dailyResult) => { if (dailyResult.dateStr.startsWith(currentMonth)) { intervalFlowCost += dailyResult.dailyFlowCost; intervalEleCost += dailyResult.dailyEleCost; @@ -109,13 +122,13 @@ const statisticData = computed(() => { return [ { title: "今年電費累計", - value: storeElecTotal.elecCostSummary?.totalFlowCost || 0, + value: storeElecTotal.elecFlowCostSummary?.totalFlowCost || 0, unit: "元", }, { title: "區間電費", value: intervalFlowCost, unit: "元" }, { title: "今年碳排當量累計", - value: storeElecTotal.elecCostSummary?.totalEleCost * 0.424, + value: storeElecTotal.elecFlowCostSummary?.totalEleCost * 0.424, unit: "公斤 CO2e/度", }, { @@ -125,7 +138,7 @@ const statisticData = computed(() => { }, { title: "今年用電度數", - value: storeElecTotal.elecCostSummary?.totalEleCost || 0, + value: storeElecTotal.elecFlowCostSummary?.totalEleCost || 0, unit: "kWh", }, { title: "區間用電度數", value: intervalEleCost, unit: "kWh" }, @@ -162,22 +175,24 @@ function groupByMonth(dailyResults) { // 每月用電分析 const monthlyElectricityData = computed(() => { - if (!storeElecTotal.elecCostSummary?.dailyResults) { + if (!storeElecTotal.elecFlowCostSummary?.dailyResults) { return { categories: [], series: [] }; } - const groupedData = groupByMonth(storeElecTotal.elecCostSummary.dailyResults); + const groupedData = groupByMonth( + storeElecTotal.elecFlowCostSummary.dailyResults + ); const categories = Object.keys(groupedData); const sortedCategories = _.sortBy(categories, (month) => dayjs().month(month).valueOf() ); - const baseElecData = sortedCategories.map((month) => groupedData[month].offcost); + const baseElecData = storeElecTotal.elecStandCostSummary.StandCost; const flowElecData = sortedCategories.map( (month) => groupedData[month].totalCost ); - const totalElecData = sortedCategories.map((month, index) => { - return (baseElecData[index] || 0) + (flowElecData[index] || 0); + const totalElecData = sortedCategories.map((month, index) => { + return baseElecData + (flowElecData[index] || 0); }); return { @@ -186,7 +201,7 @@ const monthlyElectricityData = computed(() => { { name: "基本電費", type: "bar", - data: baseElecData, + data: Array(sortedCategories.length).fill(baseElecData), }, { name: "流動電費", @@ -194,7 +209,7 @@ const monthlyElectricityData = computed(() => { data: flowElecData, }, { - name: "總電量", + name: "總電費", type: "bar", data: totalElecData, }, @@ -204,11 +219,13 @@ const monthlyElectricityData = computed(() => { // 每月碳排當量 const monthlyCarbonData = computed(() => { - if (!storeElecTotal.elecCostSummary?.dailyResults) { + if (!storeElecTotal.elecFlowCostSummary?.dailyResults) { return { categories: [], series: [] }; } - const groupedData = groupByMonth(storeElecTotal.elecCostSummary.dailyResults); + const groupedData = groupByMonth( + storeElecTotal.elecFlowCostSummary.dailyResults + ); const categories = Object.keys(groupedData); const sortedCategories = _.sortBy(categories, (month) => dayjs().month(month).valueOf() @@ -232,76 +249,82 @@ const monthlyCarbonData = computed(() => { // 每月計費度數 (kWh) const monthlyBillingData = computed(() => { - if (!storeElecTotal.elecCostSummary?.dailyResults) { + if (!storeElecTotal.elecFlowCostSummary?.dailyResults) { return { categories: [], series: [] }; } - const billingData = groupByMonth(storeElecTotal.elecCostSummary.dailyResults); + const billingData = groupByMonth( + storeElecTotal.elecFlowCostSummary.dailyResults + ); const categories = Object.keys(billingData); - const sortedCategories = _.sortBy(categories, month => dayjs().month(month).valueOf()); + const sortedCategories = _.sortBy(categories, (month) => + dayjs().month(month).valueOf() + ); - const peakData = sortedCategories.map(date => billingData[date].peak); - const halfData = sortedCategories.map(date => billingData[date].half); - const offData = sortedCategories.map(date => billingData[date].off); + const peakData = sortedCategories.map((date) => billingData[date].peak); + const halfData = sortedCategories.map((date) => billingData[date].half); + const offData = sortedCategories.map((date) => billingData[date].off); return { categories: sortedCategories, series: [ { name: "尖峰", type: "bar", data: peakData }, { name: "半尖峰", type: "bar", data: halfData }, - { name: "離峰", type: "bar", data: offData } - ] + { name: "離峰", type: "bar", data: offData }, + ], }; }); -// 區間計費度數 -const billingDateRange = computed(() => { - const startOfMonth = dayjs().startOf('month').format('YYYY-MM-DD'); - const today = dayjs().format('YYYY-MM-DD'); - return `${startOfMonth} - ${today}`; -}); - const areaBillingData = computed(() => { - if (!storeElecTotal.elecCostSummary?.dailyResults) { + if (!storeElecTotal.elecFlowCostSummary?.dailyResults) { return { categories: [], series: [] }; } const today = dayjs(); - const currentMonth = today.format('YYYY-MM'); + const currentMonth = today.format("YYYY-MM"); const startDate = dayjs(`${currentMonth}-01`); // Get the first day of the current month const endDate = today; // Filter daily results within the specified date range - const areaResults = storeElecTotal.elecCostSummary.dailyResults.filter(result => { - const resultDate = dayjs(result.dateStr); - return resultDate.isSame(startDate, 'day') || (resultDate.isAfter(startDate, 'day') && resultDate.isBefore(endDate, 'day')) || resultDate.isSame(endDate, 'day'); - }); + const areaResults = storeElecTotal.elecFlowCostSummary.dailyResults.filter( + (result) => { + const resultDate = dayjs(result.dateStr); + return ( + resultDate.isSame(startDate, "day") || + (resultDate.isAfter(startDate, "day") && + resultDate.isBefore(endDate, "day")) || + resultDate.isSame(endDate, "day") + ); + } + ); // Transform the filtered data for billing const transformedData = {}; - areaResults.forEach(result => { - const date = dayjs(result.dateStr).format('MM-DD'); // Format the date for the category + areaResults.forEach((result) => { + const date = dayjs(result.dateStr).format("MM-DD"); // Format the date for the category transformedData[date] = { peak: result.peak, half: result.half, - off: result.off + off: result.off, }; }); const categories = Object.keys(transformedData); - const sortedCategories = _.sortBy(categories, date => dayjs(date, 'MM-DD').valueOf()); + const sortedCategories = _.sortBy(categories, (date) => + dayjs(date, "MM-DD").valueOf() + ); - const peakData = sortedCategories.map(date => transformedData[date].peak); - const halfData = sortedCategories.map(date => transformedData[date].half); - const offData = sortedCategories.map(date => transformedData[date].off); + const peakData = sortedCategories.map((date) => transformedData[date].peak); + const halfData = sortedCategories.map((date) => transformedData[date].half); + const offData = sortedCategories.map((date) => transformedData[date].off); return { categories: sortedCategories, series: [ { name: "尖峰", type: "bar", data: peakData }, { name: "半尖峰", type: "bar", data: halfData }, - { name: "離峰", type: "bar", data: offData } - ] + { name: "離峰", type: "bar", data: offData }, + ], }; }); diff --git a/src/views/EnergyPricing.vue b/src/views/EnergyPricing.vue index 1381746..f4ffe1d 100644 --- a/src/views/EnergyPricing.vue +++ b/src/views/EnergyPricing.vue @@ -311,7 +311,6 @@ import { ref, watch } from "vue"; import { Edit, CircleClose, CircleCheck } from "@element-plus/icons-vue"; import useElecPriceStore from "../stores/useElecPriceStore"; -import axios from "axios"; const storeElecPrice = useElecPriceStore(); @@ -360,30 +359,6 @@ const resetStand3Values = () => { } }; -const updatePrice = async (slotPath: string, out: number) => { - const domain = window.location.origin; - try { - console.log("updatePrice",`${domain}/obix/config/${slotPath}/in2/value`) - const res = await axios.put( - `${domain}/obix/config/${slotPath}/in2/value`, - ` `, - { - headers: { "Content-Type": "text/xml" }, - } - ); - if (res.status === 200) { - console.log(`成功更新 ${slotPath} 為 ${out}`); - return true; - } else { - console.error(`更新 ${slotPath} 失敗,狀態碼: ${res.status}`); - return false; - } - } catch (error) { - console.error(`更新 ${slotPath} 出錯:`, error); - return false; - } -}; - const confirmChanges = async () => { stand3isEditing.value = false; @@ -419,7 +394,7 @@ const confirmChanges = async () => { ? item.slotPath.slice(6) // 移除 "slot:/" : item.slotPath; // 如果没有前綴,則保持不變 // 更新 Niagara - const success = await updatePrice(slotPath, stand3Value.value[i]); + const success = await storeElecPrice.updatePrice(slotPath, stand3Value.value[i]); if (!success) { failedUpdates.push({ slotPath: item.slotPath, diff --git a/src/views/MonthlyReport.vue b/src/views/MonthlyReport.vue index 6eac371..87ec679 100644 --- a/src/views/MonthlyReport.vue +++ b/src/views/MonthlyReport.vue @@ -1,17 +1,52 @@ - +