534 lines
17 KiB
Vue
534 lines
17 KiB
Vue
<template>
|
||
<div v-loading="loading" element-loading-text="資料加載中...">
|
||
<el-row :gutter="20">
|
||
<el-col :span="6">
|
||
<el-descriptions class="margin-top" title="報表資訊" :column="1" border>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">報表名稱</div>
|
||
</template>
|
||
{{ props.form?.name }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">報表期間</div>
|
||
</template>
|
||
{{ dayjs(props.form?.date).format("YYYY/MM") }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">編製日期</div>
|
||
</template>
|
||
{{ dayjs().format("YYYY/MM/DD") }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">編製人員</div>
|
||
</template>
|
||
{{ props.form?.staff }}
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
</el-col>
|
||
<el-col :span="13">
|
||
<el-descriptions
|
||
class="margin-top"
|
||
:title="priceTitle"
|
||
:column="2"
|
||
border
|
||
>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">基本電費-三相</div>
|
||
</template>
|
||
{{ Three_Phase }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">契約容量</div>
|
||
</template>
|
||
{{ ContractUse }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item v-if="isSummerMonth != 'non-summer'">
|
||
<template #label>
|
||
<div class="cell-item">
|
||
流動電價-平日尖峰單價
|
||
<!-- {{ isSummerMonth == "half-summer" ? "(夏月)" : "" }} -->
|
||
</div>
|
||
</template>
|
||
{{ Summer_Peak_Prices }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">
|
||
基本電費-經常契約
|
||
<!-- {{ isSummerMonth == "half-summer" ? "(夏月/非夏月)" : "" }} -->
|
||
</div>
|
||
</template>
|
||
{{
|
||
isSummerMonth === "summer"
|
||
? Regular_Contract_Summer
|
||
: isSummerMonth === "non-summer"
|
||
? Regular_Contract_Non_Summer
|
||
: `${Regular_Contract_Summer} / ${Regular_Contract_Non_Summer}`
|
||
}}
|
||
</el-descriptions-item>
|
||
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">
|
||
流動電價-平日半尖峰單價
|
||
<!-- {{ isSummerMonth == "half-summer" ? "(夏月/非夏月)" : "" }} -->
|
||
</div>
|
||
</template>
|
||
{{
|
||
isSummerMonth === "summer"
|
||
? Summer_HalfPeak_Prices_Weekday
|
||
: isSummerMonth === "non-summer"
|
||
? Non_Summer_HalfPeak_Prices_Weekday
|
||
: `${Summer_HalfPeak_Prices_Weekday} / ${Non_Summer_HalfPeak_Prices_Weekday}`
|
||
}}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">
|
||
流動電價-平日離峰單價
|
||
<!-- {{ isSummerMonth == "half-summer" ? "(夏月/非夏月)" : "" }} -->
|
||
</div>
|
||
</template>
|
||
{{
|
||
isSummerMonth === "summer"
|
||
? Summer_Off_Prices_Weekday
|
||
: isSummerMonth === "non-summer"
|
||
? Non_Summer_Off_Prices_Weekday
|
||
: `${Summer_Off_Prices_Weekday} / ${Non_Summer_Off_Prices_Weekday}`
|
||
}}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">
|
||
流動電價-週六半尖峰單價
|
||
<!-- {{ isSummerMonth == "half-summer" ? "(夏月/非夏月)" : "" }} -->
|
||
</div>
|
||
</template>
|
||
{{
|
||
isSummerMonth === "summer"
|
||
? Summer_HalfPeak_Prices_Saturday
|
||
: isSummerMonth === "non-summer"
|
||
? Non_Summer_HalfPeak_Prices_Saturday
|
||
: `${Summer_HalfPeak_Prices_Saturday} / ${Non_Summer_HalfPeak_Prices_Saturday}`
|
||
}}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">
|
||
流動電價-週六離峰單價
|
||
<!-- {{ isSummerMonth == "half-summer" ? "(夏月/非夏月)" : "" }} -->
|
||
</div>
|
||
</template>
|
||
{{
|
||
isSummerMonth === "summer"
|
||
? Summer_Off_Prices_Saturday
|
||
: isSummerMonth === "non-summer"
|
||
? Non_Summer_Off_Prices_Saturday
|
||
: `${Summer_Off_Prices_Saturday} / ${Non_Summer_Off_Prices_Saturday}`
|
||
}}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">
|
||
流動電價-週日離峰單價
|
||
<!-- {{ isSummerMonth == "half-summer" ? "(夏月/非夏月)" : "" }} -->
|
||
</div>
|
||
</template>
|
||
{{
|
||
isSummerMonth === "summer"
|
||
? Summer_Off_Prices
|
||
: isSummerMonth === "non-summer"
|
||
? Non_Summer_Off_Prices
|
||
: `${Summer_Off_Prices} / ${Non_Summer_Off_Prices}`
|
||
}}
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
</el-col>
|
||
<el-col :span="5">
|
||
<el-descriptions class="margin-top" title="總計" :column="1" border>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">基本電費</div>
|
||
</template>
|
||
{{ totalStandCost.toFixed(2) }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">流動電費</div>
|
||
</template>
|
||
{{ totalFlowCost.toFixed(2) }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item>
|
||
<template #label>
|
||
<div class="cell-item">總費用</div>
|
||
</template>
|
||
{{ totalCost.toFixed(2) }}
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="20">
|
||
<el-col :span="24">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th colspan="2" class="bg-info">基本資料</th>
|
||
<th colspan="3" class="bg-orange">前期比較</th>
|
||
<th colspan="4" class="bg-green">用電量(kWh)</th>
|
||
<th colspan="4" class="bg-yellow">費用(NTD)</th>
|
||
</tr>
|
||
<tr>
|
||
<th class="bg-info">電表編號</th>
|
||
<th class="bg-info">區域/用途</th>
|
||
<th class="bg-orange">上月用電量(kWh)</th>
|
||
<th class="bg-orange">用電變化量(kWh)</th>
|
||
<th class="bg-orange">用電變化率(%)</th>
|
||
<th class="bg-green">總用電量</th>
|
||
<th class="bg-green">尖峰用電</th>
|
||
<th class="bg-green">半尖峰用電</th>
|
||
<th class="bg-green">離峰用電</th>
|
||
<th class="bg-yellow">尖峰費用</th>
|
||
<th class="bg-yellow">半尖峰費用</th>
|
||
<th class="bg-yellow">離峰費用</th>
|
||
<th class="bg-yellow">小計</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr
|
||
v-for="meterData in formattedElecCostSummary"
|
||
:key="meterData.name"
|
||
>
|
||
<td>{{ meterData.name }}</td>
|
||
<td>{{ meterData.area }}</td>
|
||
<td>{{ meterData.lastMonthUsage.toFixed(2) }}</td>
|
||
<td>{{ meterData.usageChange.toFixed(2) }}</td>
|
||
<td>{{ meterData.usageChangeRate.toFixed(2) }}</td>
|
||
<td>{{ meterData.totalUsage.toFixed(2) }}</td>
|
||
<td>{{ meterData.peakUsage.toFixed(2) }}</td>
|
||
<td>{{ meterData.halfPeakUsage.toFixed(2) }}</td>
|
||
<td>{{ meterData.offPeakUsage.toFixed(2) }}</td>
|
||
<td>{{ meterData.peakCost.toFixed(2) }}</td>
|
||
<td>{{ meterData.halfPeakCost.toFixed(2) }}</td>
|
||
<td>{{ meterData.offPeakCost.toFixed(2) }}</td>
|
||
<td>{{ meterData.totalCost.toFixed(2) }}</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</el-col>
|
||
</el-row>
|
||
<el-row :gutter="20">
|
||
<el-col :span="12">
|
||
<el-card style="border-radius: 8px; height: 100%">
|
||
<h3 class="">各電表用電量比較(kWh)</h3>
|
||
<EnergyBar :chartData="elecUsageData" />
|
||
</el-card>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-card style="border-radius: 8px; height: 100%">
|
||
<h3 class="">各電表總費用佔比</h3>
|
||
<EnergyPie :chartData="elecCostData" />
|
||
</el-card>
|
||
</el-col>
|
||
<el-col :span="24">
|
||
<p style="margin: 0; padding-top: 15px; opacity: 0.8">
|
||
本系統所提供之時間電價計算結果,係以未超過契約容量為前提所進行之估算,僅供用電分析與管理參考之用。
|
||
</p>
|
||
</el-col>
|
||
</el-row>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { defineProps, computed } from "vue";
|
||
import EnergyPie from "../components/EnergyPie.vue";
|
||
import EnergyBar from "../components/EnergyBar.vue";
|
||
import useElecPriceStore from "../stores/useElecPriceStore";
|
||
import useElecReportStore from "../stores/useElecReportStore";
|
||
import useElecDemandStore from "../stores/useElecDemandStore";
|
||
|
||
import getRandomColor from "../utils/getRandomColor";
|
||
import dayjs from "dayjs";
|
||
|
||
const props = defineProps({
|
||
form: {
|
||
type: Object,
|
||
},
|
||
});
|
||
const storeElecPrice = useElecPriceStore();
|
||
const storeElecReport = useElecReportStore();
|
||
const storeDemand = useElecDemandStore();
|
||
|
||
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 date = dayjs(props.form?.date);
|
||
const month = date.month() + 1; // 代表一月到十二月
|
||
|
||
if (month > 5 && month < 10) {
|
||
return "summer";
|
||
} else if (month === 5 || month === 10) {
|
||
return "half-summer";
|
||
} else {
|
||
return "non-summer";
|
||
}
|
||
});
|
||
|
||
const priceTitle = computed(() => {
|
||
if (isSummerMonth.value === "summer") {
|
||
return "單價(NTD/kWh)-夏月";
|
||
} else if (isSummerMonth.value === "non-summer") {
|
||
return "單價(NTD/kWh)-非夏月";
|
||
} else {
|
||
return "單價(NTD/kWh)-夏月/非夏月";
|
||
}
|
||
});
|
||
|
||
const formattedElecCostSummary = computed(() => {
|
||
const summaryThisMonth = storeElecReport.elecCostSummary.thisMonth;
|
||
const summaryLastMonth = storeElecReport.elecCostSummary.lastMonth;
|
||
|
||
if (!summaryThisMonth) {
|
||
return [];
|
||
}
|
||
|
||
return Object.keys(summaryThisMonth).map((key) => {
|
||
const meterDataThisMonth = summaryThisMonth[key];
|
||
const meterDataLastMonth = summaryLastMonth?.[key]; // 使用可选链
|
||
|
||
const totalUsageThisMonth = meterDataThisMonth?.totalEleCost || 0;
|
||
const totalUsageLastMonth = meterDataLastMonth?.totalEleCost || 0;
|
||
|
||
const usageChange = totalUsageThisMonth - totalUsageLastMonth;
|
||
const usageChangeRate =
|
||
totalUsageLastMonth !== 0 ? (usageChange / totalUsageLastMonth) * 100 : 0; // 避免除以 0
|
||
|
||
return {
|
||
name: meterDataThisMonth?.name,
|
||
area: meterDataThisMonth?.area,
|
||
lastMonthUsage: totalUsageLastMonth,
|
||
usageChange: usageChange,
|
||
usageChangeRate: usageChangeRate,
|
||
totalUsage: totalUsageThisMonth,
|
||
peakUsage: meterDataThisMonth?.total_peak || 0,
|
||
halfPeakUsage: meterDataThisMonth?.total_half || 0,
|
||
offPeakUsage: meterDataThisMonth?.total_Off || 0,
|
||
peakCost: meterDataThisMonth?.total_peakCost || 0,
|
||
halfPeakCost: meterDataThisMonth?.total_halfCost || 0,
|
||
offPeakCost: meterDataThisMonth?.total_OffCost || 0,
|
||
totalCost: meterDataThisMonth?.totalFlowCost || 0,
|
||
};
|
||
});
|
||
});
|
||
|
||
// 基本電費
|
||
const totalStandCost = computed(() => {
|
||
if (!storeElecReport.elecCostSummary.thisMonth) {
|
||
return 0;
|
||
}
|
||
const elecCostSummaryArray = Object.values(
|
||
storeElecReport.elecCostSummary.thisMonth
|
||
);
|
||
if (elecCostSummaryArray.length === 0) {
|
||
return 0;
|
||
}
|
||
return elecCostSummaryArray[0]?.standCost || 0;
|
||
});
|
||
|
||
const totalFlowCost = computed(() => {
|
||
if (!storeElecReport.elecCostSummary.thisMonth) {
|
||
return 0;
|
||
}
|
||
let total = 0;
|
||
Object.keys(storeElecReport.elecCostSummary.thisMonth).forEach((key) => {
|
||
// @ts-ignore
|
||
total += storeElecReport.elecCostSummary.thisMonth[key]?.totalFlowCost || 0;
|
||
});
|
||
return total;
|
||
});
|
||
|
||
const totalCost = computed(() => {
|
||
return totalStandCost.value + totalFlowCost.value;
|
||
});
|
||
|
||
const Three_Phase =
|
||
elecPrices.find((item: any) => item.displayName === "基本按戶三相")?.out || 0;
|
||
|
||
// 夏月
|
||
const Regular_Contract_Summer =
|
||
elecPrices.find((item: any) => item.displayName === "基本經常夏月")?.out || 0;
|
||
const Summer_Peak_Prices =
|
||
elecPrices.find((item: any) => item.displayName === "流動平日尖峰夏月")
|
||
?.out || 0;
|
||
const Summer_HalfPeak_Prices_Weekday =
|
||
elecPrices.find((item: any) => item.displayName === "流動平日半尖峰夏月")
|
||
?.out || 0;
|
||
const Summer_Off_Prices_Weekday =
|
||
elecPrices.find((item: any) => item.displayName === "流動平日離峰夏月")
|
||
?.out || 0;
|
||
const Summer_HalfPeak_Prices_Saturday =
|
||
elecPrices.find((item: any) => item.displayName === "流動週六半尖峰夏月")
|
||
?.out || 0;
|
||
const Summer_Off_Prices_Saturday =
|
||
elecPrices.find((item: any) => item.displayName === "流動週六離峰夏月")
|
||
?.out || 0;
|
||
const Summer_Off_Prices =
|
||
elecPrices.find((item: any) => item.displayName === "流動週日離峰夏月")
|
||
?.out || 0;
|
||
// 非夏月
|
||
const Regular_Contract_Non_Summer =
|
||
elecPrices.find((item: any) => item.displayName === "基本經常非夏月")?.out ||
|
||
0;
|
||
const Non_Summer_HalfPeak_Prices_Weekday =
|
||
elecPrices.find((item: any) => item.displayName === "流動平日半尖峰非夏月")
|
||
?.out || 0;
|
||
const Non_Summer_Off_Prices_Weekday =
|
||
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_Off_Prices_Saturday =
|
||
elecPrices.find((item: any) => item.displayName === "流動週六離峰非夏月")
|
||
?.out || 0;
|
||
const Non_Summer_Off_Prices =
|
||
elecPrices.find((item: any) => item.displayName === "流動週日離峰非夏月")
|
||
?.out || 0;
|
||
const ContractUse =
|
||
elecDemand.find((item: any) => item.name === "Engel")?.out || 0;
|
||
|
||
const elecUsageData = computed(() => {
|
||
const summaryThisMonth = storeElecReport.elecCostSummary.thisMonth;
|
||
if (
|
||
!summaryThisMonth ||
|
||
Object.keys(summaryThisMonth).length === 0 ||
|
||
Object.values(summaryThisMonth).every((value) => value === undefined)
|
||
) {
|
||
return {
|
||
categories: [],
|
||
series: [],
|
||
};
|
||
}
|
||
|
||
const categories = Object.keys(summaryThisMonth);
|
||
const peakData = categories.map(
|
||
(key) => summaryThisMonth[key]?.total_peak || 0
|
||
);
|
||
const halfPeakData = categories.map(
|
||
(key) => summaryThisMonth[key]?.total_half || 0
|
||
);
|
||
const offPeakData = categories.map(
|
||
(key) => summaryThisMonth[key]?.total_Off || 0
|
||
);
|
||
|
||
return {
|
||
categories: categories.map((key) => summaryThisMonth[key]?.name || key),
|
||
series: [
|
||
{
|
||
name: "尖峰用電",
|
||
type: "bar",
|
||
data: peakData,
|
||
itemStyle: { color: "#5470c6" },
|
||
stack: "total",
|
||
},
|
||
{
|
||
name: "半尖峰用電",
|
||
type: "bar",
|
||
data: halfPeakData,
|
||
itemStyle: { color: "#91cc75" },
|
||
stack: "total",
|
||
},
|
||
{
|
||
name: "離峰用電",
|
||
type: "bar",
|
||
data: offPeakData,
|
||
itemStyle: { color: "#fac858" },
|
||
stack: "total",
|
||
},
|
||
],
|
||
};
|
||
});
|
||
const elecCostData = computed(() => {
|
||
const summaryThisMonth = storeElecReport.elecCostSummary.thisMonth;
|
||
if (
|
||
!summaryThisMonth ||
|
||
Object.keys(summaryThisMonth).length === 0 ||
|
||
Object.values(summaryThisMonth).every((value) => value === undefined)
|
||
) {
|
||
return { series: [] };
|
||
}
|
||
|
||
getRandomColor.resetIndex();
|
||
const series = Object.keys(summaryThisMonth).map((key) => {
|
||
const meterData = summaryThisMonth[key];
|
||
return {
|
||
name: meterData?.name || key,
|
||
value: meterData?.totalFlowCost.toFixed(2) || 0,
|
||
itemStyle: { color: getRandomColor() },
|
||
};
|
||
});
|
||
|
||
return { series };
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.el-row {
|
||
padding-top: 20px;
|
||
padding-right: 20px;
|
||
padding-left: 20px;
|
||
}
|
||
|
||
h3 {
|
||
margin: 0;
|
||
font-weight: 700;
|
||
font-size: 15px;
|
||
color: #141414;
|
||
}
|
||
|
||
th,
|
||
td {
|
||
border: 1px solid #ebeef5;
|
||
text-align: center;
|
||
padding: 8px 11px;
|
||
background: #fff;
|
||
color: #303133;
|
||
font-size: 12px;
|
||
text-wrap: nowrap;
|
||
}
|
||
|
||
.bg-info {
|
||
background: #add8e6;
|
||
}
|
||
|
||
.bg-orange {
|
||
background: #ffdab9;
|
||
}
|
||
|
||
.bg-green {
|
||
background: #90ee90;
|
||
}
|
||
|
||
.bg-yellow {
|
||
background: #ffd700;
|
||
}
|
||
</style>
|