加載效果 | 電價改成存進fallback

This commit is contained in:
huliang 2025-05-09 18:12:16 +08:00
parent 756cbd3b7a
commit c4f175d379
5 changed files with 312 additions and 270 deletions

3
components.d.ts vendored
View File

@ -36,4 +36,7 @@ declare module 'vue' {
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
} }
export interface ComponentCustomProperties {
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
} }

View File

@ -1,202 +1,206 @@
<template> <template>
<el-row :gutter="20"> <div v-loading="loading" element-loading-text="資料加載中...">
<el-col :span="7"> <el-row :gutter="20">
<el-descriptions class="margin-top" title="報表資訊" :column="1" border> <el-col :span="7">
<el-descriptions-item> <el-descriptions class="margin-top" title="報表資訊" :column="1" border>
<template #label> <el-descriptions-item>
<div class="cell-item">報表名稱</div> <template #label>
</template> <div class="cell-item">報表名稱</div>
{{ props.form?.name }} </template>
</el-descriptions-item> {{ props.form?.name }}
<el-descriptions-item> </el-descriptions-item>
<template #label> <el-descriptions-item>
<div class="cell-item">報表期間</div> <template #label>
</template> <div class="cell-item">報表期間</div>
{{ dayjs(props.form?.date).format("YYYY/MM") }} </template>
</el-descriptions-item> {{ dayjs(props.form?.date).format("YYYY/MM") }}
<el-descriptions-item> </el-descriptions-item>
<template #label> <el-descriptions-item>
<div class="cell-item">編製日期</div> <template #label>
</template> <div class="cell-item">編製日期</div>
{{ dayjs().format("YYYY/MM/DD") }} </template>
</el-descriptions-item> {{ dayjs().format("YYYY/MM/DD") }}
<el-descriptions-item> </el-descriptions-item>
<template #label> <el-descriptions-item>
<div class="cell-item">編製人員</div> <template #label>
</template> <div class="cell-item">編製人員</div>
{{ props.form?.staff }} </template>
</el-descriptions-item> {{ props.form?.staff }}
</el-descriptions> </el-descriptions-item>
</el-col> </el-descriptions>
<el-col :span="11"> </el-col>
<el-descriptions <el-col :span="11">
class="margin-top" <el-descriptions
:title="priceTitle" class="margin-top"
:column="2" :title="priceTitle"
border :column="2"
> border
<el-descriptions-item> >
<template #label> <el-descriptions-item>
<div class="cell-item">基本電費-三相</div> <template #label>
</template> <div class="cell-item">基本電費-三相</div>
{{ Three_Phase }} </template>
</el-descriptions-item> {{ Three_Phase }}
<el-descriptions-item v-if="isSummerMonth"> </el-descriptions-item>
<template #label> <el-descriptions-item v-if="isSummerMonth">
<div class="cell-item">基本電費-經常契約</div> <template #label>
</template> <div class="cell-item">基本電費-經常契約</div>
{{ Regular_Contract_Summer }} </template>
</el-descriptions-item> {{ Regular_Contract_Summer }}
<el-descriptions-item v-if="!isSummerMonth"> </el-descriptions-item>
<template #label> <el-descriptions-item v-if="!isSummerMonth">
<div class="cell-item">基本電費-經常契約</div> <template #label>
</template> <div class="cell-item">基本電費-經常契約</div>
{{ Regular_Contract_Non_Summer }} </template>
</el-descriptions-item> {{ Regular_Contract_Non_Summer }}
<el-descriptions-item v-if="isSummerMonth"> </el-descriptions-item>
<template #label> <el-descriptions-item v-if="isSummerMonth">
<div class="cell-item">流動電價-平日尖峰單價</div> <template #label>
</template> <div class="cell-item">流動電價-平日尖峰單價</div>
{{ Summer_Peak_Prices }} </template>
</el-descriptions-item> {{ Summer_Peak_Prices }}
<el-descriptions-item> </el-descriptions-item>
<template #label> <el-descriptions-item>
<div class="cell-item">流動電價-平日半尖峰單價</div> <template #label>
</template> <div class="cell-item">流動電價-平日半尖峰單價</div>
{{ </template>
isSummerMonth {{
? Summer_HalfPeak_Prices_Weekday isSummerMonth
: Non_Summer_HalfPeak_Prices_Weekday ? Summer_HalfPeak_Prices_Weekday
}} : Non_Summer_HalfPeak_Prices_Weekday
</el-descriptions-item> }}
<el-descriptions-item> </el-descriptions-item>
<template #label> <el-descriptions-item>
<div class="cell-item">流動電價-平日離峰單價</div> <template #label>
</template> <div class="cell-item">流動電價-平日離峰單價</div>
{{ </template>
isSummerMonth {{
? Summer_Off_Prices_Weekday isSummerMonth
: Non_Summer_Off_Prices_Weekday ? Summer_Off_Prices_Weekday
}} : Non_Summer_Off_Prices_Weekday
</el-descriptions-item> }}
<el-descriptions-item> </el-descriptions-item>
<template #label> <el-descriptions-item>
<div class="cell-item">流動電價-週六半尖峰單價</div> <template #label>
</template> <div class="cell-item">流動電價-週六半尖峰單價</div>
{{ </template>
isSummerMonth {{
? Summer_HalfPeak_Prices_Saturday isSummerMonth
: Non_Summer_HalfPeak_Prices_Saturday ? Summer_HalfPeak_Prices_Saturday
}} : Non_Summer_HalfPeak_Prices_Saturday
</el-descriptions-item> }}
<el-descriptions-item> </el-descriptions-item>
<template #label> <el-descriptions-item>
<div class="cell-item">流動電價-週六離峰單價</div> <template #label>
</template> <div class="cell-item">流動電價-週六離峰單價</div>
{{ </template>
isSummerMonth {{
? Summer_Off_Prices_Saturday isSummerMonth
: Non_Summer_Off_Prices_Saturday ? Summer_Off_Prices_Saturday
}} : Non_Summer_Off_Prices_Saturday
</el-descriptions-item> }}
<el-descriptions-item> </el-descriptions-item>
<template #label> <el-descriptions-item>
<div class="cell-item">流動電價-週日離峰單價</div> <template #label>
</template> <div class="cell-item">流動電價-週日離峰單價</div>
{{ isSummerMonth ? Summer_Off_Prices : Non_Summer_Off_Prices }} </template>
</el-descriptions-item> {{ isSummerMonth ? Summer_Off_Prices : Non_Summer_Off_Prices }}
</el-descriptions> </el-descriptions-item>
</el-col> <el-descriptions-item>
<el-col :span="6"> <template #label>
<el-descriptions class="margin-top" title="總計" :column="1" border> <div class="cell-item">契約容量</div>
<el-descriptions-item> </template>
<template #label> {{ ContractUse }}
<div class="cell-item">基本電費</div> </el-descriptions-item>
</template> </el-descriptions>
{{ totalStandCost.toFixed(2) }} </el-col>
</el-descriptions-item> <el-col :span="6">
<el-descriptions-item> <el-descriptions class="margin-top" title="總計" :column="1" border>
<template #label> <el-descriptions-item>
<div class="cell-item">流動電費</div> <template #label>
</template> <div class="cell-item">基本電費</div>
{{ totalFlowCost.toFixed(2) }} </template>
</el-descriptions-item> {{ totalStandCost.toFixed(2) }}
<el-descriptions-item> </el-descriptions-item>
<template #label> <el-descriptions-item>
<div class="cell-item">總費用</div> <template #label>
</template> <div class="cell-item">流動電費</div>
{{ totalCost.toFixed(2) }} </template>
</el-descriptions-item> {{ totalFlowCost.toFixed(2) }}
</el-descriptions> </el-descriptions-item>
</el-col> <el-descriptions-item>
</el-row> <template #label>
<el-row :gutter="20"> <div class="cell-item">總費用</div>
<el-col :span="24"> </template>
<table> {{ totalCost.toFixed(2) }}
<thead> </el-descriptions-item>
<tr> </el-descriptions>
<th colspan="2" class="bg-info">基本資料</th> </el-col>
<th colspan="3" class="bg-orange">前期比較</th> </el-row>
<th colspan="4" class="bg-green">用電量(kWh)</th> <el-row :gutter="20">
<th colspan="4" class="bg-yellow">費用(NTD)</th> <el-col :span="24">
</tr> <table>
<tr> <thead>
<th class="bg-info">電表編號</th> <tr>
<th class="bg-info">區域/用途</th> <th colspan="2" class="bg-info">基本資料</th>
<th class="bg-orange">上月用電量(kWh)</th> <th colspan="3" class="bg-orange">前期比較</th>
<th class="bg-orange">用電變化量(kWh)</th> <th colspan="4" class="bg-green">用電量(kWh)</th>
<th class="bg-orange">用電變化率(%)</th> <th colspan="4" class="bg-yellow">費用(NTD)</th>
<th class="bg-green">總用電量</th> </tr>
<th class="bg-green">尖峰用電</th> <tr>
<th class="bg-green">半尖峰用電</th> <th class="bg-info">電表編號</th>
<th class="bg-green">離峰用電</th> <th class="bg-info">區域/用途</th>
<th class="bg-yellow">尖峰費用</th> <th class="bg-orange">上月用電量(kWh)</th>
<th class="bg-yellow">半尖峰費用</th> <th class="bg-orange">用電變化量(kWh)</th>
<th class="bg-yellow">離峰費用</th> <th class="bg-orange">用電變化率(%)</th>
<th class="bg-yellow">小計</th> <th class="bg-green">總用電量</th>
</tr> <th class="bg-green">尖峰用電</th>
</thead> <th class="bg-green">半尖峰用電</th>
<tbody> <th class="bg-green">離峰用電</th>
<tr <th class="bg-yellow">尖峰費用</th>
v-for="meterData in formattedElecCostSummary" <th class="bg-yellow">半尖峰費用</th>
:key="meterData.name" <th class="bg-yellow">離峰費用</th>
> <th class="bg-yellow">小計</th>
<td>{{ meterData.name }}</td> </tr>
<td>{{ meterData.area }}</td> </thead>
<td>{{ meterData.lastMonthUsage.toFixed(2) }}</td> <tbody>
<td>{{ meterData.usageChange.toFixed(2) }}</td> <tr
<td>{{ meterData.usageChangeRate.toFixed(2) }}</td> v-for="meterData in formattedElecCostSummary"
<td>{{ meterData.totalUsage.toFixed(2) }}</td> :key="meterData.name"
<td>{{ meterData.peakUsage.toFixed(2) }}</td> >
<td>{{ meterData.halfPeakUsage.toFixed(2) }}</td> <td>{{ meterData.name }}</td>
<td>{{ meterData.offPeakUsage.toFixed(2) }}</td> <td>{{ meterData.area }}</td>
<td>{{ meterData.peakCost.toFixed(2) }}</td> <td>{{ meterData.lastMonthUsage.toFixed(2) }}</td>
<td>{{ meterData.halfPeakCost.toFixed(2) }}</td> <td>{{ meterData.usageChange.toFixed(2) }}</td>
<td>{{ meterData.offPeakCost.toFixed(2) }}</td> <td>{{ meterData.usageChangeRate.toFixed(2) }}</td>
<td>{{ meterData.totalCost.toFixed(2) }}</td> <td>{{ meterData.totalUsage.toFixed(2) }}</td>
</tr> <td>{{ meterData.peakUsage.toFixed(2) }}</td>
</tbody> <td>{{ meterData.halfPeakUsage.toFixed(2) }}</td>
</table> <td>{{ meterData.offPeakUsage.toFixed(2) }}</td>
</el-col> <td>{{ meterData.peakCost.toFixed(2) }}</td>
</el-row> <td>{{ meterData.halfPeakCost.toFixed(2) }}</td>
<el-row :gutter="20"> <td>{{ meterData.offPeakCost.toFixed(2) }}</td>
<el-col :span="12"> <td>{{ meterData.totalCost.toFixed(2) }}</td>
<el-card style="border-radius: 8px; height: 100%"> </tr>
<h3 class="">各電表用電量比較(kWh)</h3> </tbody>
<EnergyBar </table>
:chartData="elecUsageData" </el-col>
/> </el-row>
</el-card> <el-row :gutter="20">
</el-col> <el-col :span="12">
<el-col :span="12"> <el-card style="border-radius: 8px; height: 100%">
<el-card style="border-radius: 8px; height: 100%"> <h3 class="">各電表用電量比較(kWh)</h3>
<h3 class="">各電表總費用佔比</h3> <EnergyBar :chartData="elecUsageData" />
<EnergyPie </el-card>
:chartData="elecCostData" </el-col>
/> <el-col :span="12">
</el-card> <el-card style="border-radius: 8px; height: 100%">
</el-col> <h3 class="">各電表總費用佔比</h3>
</el-row> <EnergyPie :chartData="elecCostData" />
</el-card>
</el-col>
</el-row>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -205,6 +209,8 @@ import EnergyPie from "../components/EnergyPie.vue";
import EnergyBar from "../components/EnergyBar.vue"; import EnergyBar from "../components/EnergyBar.vue";
import useElecPriceStore from "../stores/useElecPriceStore"; import useElecPriceStore from "../stores/useElecPriceStore";
import useElecReportStore from "../stores/useElecReportStore"; import useElecReportStore from "../stores/useElecReportStore";
import useElecDemandStore from "../stores/useElecDemandStore";
import getRandomColor from "../utils/getRandomColor"; import getRandomColor from "../utils/getRandomColor";
import dayjs from "dayjs"; import dayjs from "dayjs";
@ -215,7 +221,22 @@ const props = defineProps({
}); });
const storeElecPrice = useElecPriceStore(); const storeElecPrice = useElecPriceStore();
const storeElecReport = useElecReportStore(); const storeElecReport = useElecReportStore();
const storeDemand = useElecDemandStore();
const elecPrices = storeElecPrice.elecData; const elecPrices = storeElecPrice.elecData;
const elecDemand = storeDemand.elecData;
const loading = computed(() => {
const summaryThisMonth = storeElecReport.elecCostSummary.thisMonth;
if (
!summaryThisMonth ||
Object.keys(summaryThisMonth).length === 0 ||
Object.values(summaryThisMonth).every((value) => value === undefined)
) {
return true;
}
return false;
});
const isSummerMonth = computed(() => { const isSummerMonth = computed(() => {
const month = dayjs(props.form?.date).month(); // month() 0-11 const month = dayjs(props.form?.date).month(); // month() 0-11
@ -336,10 +357,16 @@ const Non_Summer_Off_Prices_Saturday =
const Non_Summer_Off_Prices = const Non_Summer_Off_Prices =
elecPrices.find((item: any) => item.displayName === "流動週日離峰非夏月") elecPrices.find((item: any) => item.displayName === "流動週日離峰非夏月")
?.out || 0; ?.out || 0;
const ContractUse =
elecDemand.find((item: any) => item.name === "Engel")?.out || 0;
const elecUsageData = computed(() => { const elecUsageData = computed(() => {
const summaryThisMonth = storeElecReport.elecCostSummary.thisMonth; const summaryThisMonth = storeElecReport.elecCostSummary.thisMonth;
if (!summaryThisMonth) { if (
!summaryThisMonth ||
Object.keys(summaryThisMonth).length === 0 ||
Object.values(summaryThisMonth).every((value) => value === undefined)
) {
return { return {
categories: [], categories: [],
series: [], series: [],
@ -383,7 +410,11 @@ const elecUsageData = computed(() => {
}); });
const elecCostData = computed(() => { const elecCostData = computed(() => {
const summaryThisMonth = storeElecReport.elecCostSummary.thisMonth; const summaryThisMonth = storeElecReport.elecCostSummary.thisMonth;
if (!summaryThisMonth) { if (
!summaryThisMonth ||
Object.keys(summaryThisMonth).length === 0 ||
Object.values(summaryThisMonth).every((value) => value === undefined)
) {
return { series: [] }; return { series: [] };
} }

View File

@ -105,9 +105,9 @@ const useElecPriceStore = defineStore("elecPriceData", () => {
const updatePrice = async (slotPath: string, out: number) => { const updatePrice = async (slotPath: string, out: number) => {
const domain = window.location.origin; const domain = window.location.origin;
try { try {
console.log("updatePrice",`${domain}/obix/config/${slotPath}/in2/value`) console.log("updatePrice",`${domain}/obix/config/${slotPath}/fallback/value`)
const res = await axios.put( const res = await axios.put(
`${domain}/obix/config/${slotPath}/in2/value`, `${domain}/obix/config/${slotPath}/fallback/value`,
`<real name="in" val="${out}"/> `, `<real name="in" val="${out}"/> `,
{ {
headers: { "Content-Type": "text/xml" }, headers: { "Content-Type": "text/xml" },

View File

@ -4,8 +4,6 @@ import dayjs from "dayjs";
import type { ElecCostSummaryMap } from "../utils/types"; import type { ElecCostSummaryMap } from "../utils/types";
import { CalcuEleCost, CalcuEleStandCost } from "../utils/CalcuEleCost"; import { CalcuEleCost, CalcuEleStandCost } from "../utils/CalcuEleCost";
const useElecReportStore = defineStore("elecReportData", () => { const useElecReportStore = defineStore("elecReportData", () => {
const elecData = ref<any[]>([]); const elecData = ref<any[]>([]);
// @ts-ignore // @ts-ignore

View File

@ -1,67 +1,69 @@
<template> <template>
<el-row :gutter="20"> <div v-loading="loading" element-loading-text="資料加載中...">
<el-col :span="10"> <el-row :gutter="20">
<el-card style="border-radius: 8px"> <el-col :span="10">
<h3 class="">用電即時分佈 (kwh)</h3> <el-card style="border-radius: 8px">
<EnergySankey /> <h3 class="">用電即時分佈 (kwh)</h3>
</el-card> <EnergySankey />
</el-col> </el-card>
<el-col :span="14"> </el-col>
<h3 class="" style="margin-top: 15px">即時需量</h3> <el-col :span="14">
<EnergyLine /> <h3 class="" style="margin-top: 15px">即時需量</h3>
</el-col> <EnergyLine />
</el-row> </el-col>
<el-row :gutter="20"> </el-row>
<el-col :span="8"> <el-row :gutter="20">
<el-row style="padding-right: 15px"> <el-col :span="8">
<el-col :span="12" v-for="(item, index) in statisticData"> <el-row style="padding-right: 15px">
<el-card <el-col :span="12" v-for="(item, index) in statisticData">
style=" <el-card
width: 100%; style="
padding: 5px; width: 100%;
max-width: 480px; padding: 5px;
border-radius: 0; max-width: 480px;
" border-radius: 0;
:key="index" "
:class="{ 'bg-info': index == 0 || index == 3 || index == 4 }" :key="index"
shadow="hover" :class="{ 'bg-info': index == 0 || index == 3 || index == 4 }"
> shadow="hover"
<el-statistic >
:title="item.title" <el-statistic
:value="item.value" :title="item.title"
:suffix="item.unit" :value="item.value"
/> :suffix="item.unit"
</el-card> />
</el-col> </el-card>
</el-row> </el-col>
</el-col> </el-row>
<el-col :span="8"> </el-col>
<el-card style="border-radius: 8px; height: 100%"> <el-col :span="8">
<h3 class="">每月用電分析</h3> <el-card style="border-radius: 8px; height: 100%">
<EnergyBar :chartData="monthlyElectricityData" /> <h3 class="">每月用電分析</h3>
</el-card> <EnergyBar :chartData="monthlyElectricityData" />
</el-col> </el-card>
<el-col :span="8"> </el-col>
<el-card style="border-radius: 8px; height: 100%"> <el-col :span="8">
<h3 class="">每月碳排當量 (kgCO2e)</h3> <el-card style="border-radius: 8px; height: 100%">
<EnergyBar :chartData="monthlyCarbonData" /> <h3 class="">每月碳排當量 (kgCO2e)</h3>
</el-card> <EnergyBar :chartData="monthlyCarbonData" />
</el-col> </el-card>
</el-row> </el-col>
<el-row :gutter="20"> </el-row>
<el-col :span="8"> <el-row :gutter="20">
<el-card style="border-radius: 8px; height: 100%"> <el-col :span="8">
<h3 class="">每月計費度數 (kWh)</h3> <el-card style="border-radius: 8px; height: 100%">
<EnergyBar :chartData="monthlyBillingData" /> <h3 class="">每月計費度數 (kWh)</h3>
</el-card> <EnergyBar :chartData="monthlyBillingData" />
</el-col> </el-card>
<el-col :span="16"> </el-col>
<el-card style="border-radius: 8px"> <el-col :span="16">
<h3 class="">區間計費度數 {{ billingDateRange }}</h3> <el-card style="border-radius: 8px">
<EnergyBar :chartData="areaBillingData" /> <h3 class="">區間計費度數 {{ billingDateRange }}</h3>
</el-card> <EnergyBar :chartData="areaBillingData" />
</el-col> </el-card>
</el-row> </el-col>
</el-row>
</div>
</template> </template>
<script setup> <script setup>
@ -104,6 +106,14 @@ onUnmounted(() => {
storeElecTotal.stopTimer(); storeElecTotal.stopTimer();
}); });
const loading = computed(() => {
const summaryFlowCost = storeElecTotal.elecFlowCostSummary?.dailyResults;
if (!summaryFlowCost) {
return true;
}
return false;
});
const statisticData = computed(() => { const statisticData = computed(() => {
const currentMonth = dayjs().format("YYYY-MM"); const currentMonth = dayjs().format("YYYY-MM");
@ -187,12 +197,12 @@ const monthlyElectricityData = computed(() => {
dayjs().month(month).valueOf() dayjs().month(month).valueOf()
); );
const baseElecData = storeElecTotal.elecStandCostSummary.StandCost; const baseElecData = storeElecTotal.elecStandCostSummary.StandResults.map(item => item.StandCost);
const flowElecData = sortedCategories.map( const flowElecData = sortedCategories.map(
(month) => groupedData[month].totalCost (month) => groupedData[month].totalCost
); );
const totalElecData = sortedCategories.map((month, index) => { const totalElecData = sortedCategories.map((month, index) => {
return baseElecData + (flowElecData[index] || 0); return (baseElecData[index] || 0) + (flowElecData[index] || 0);
}); });
return { return {
@ -201,7 +211,7 @@ const monthlyElectricityData = computed(() => {
{ {
name: "基本電費", name: "基本電費",
type: "bar", type: "bar",
data: Array(sortedCategories.length).fill(baseElecData), data: baseElecData,
}, },
{ {
name: "流動電費", name: "流動電費",