新增能源報表
This commit is contained in:
parent
7f4d1e6e07
commit
cd0bfafa35
4
components.d.ts
vendored
4
components.d.ts
vendored
@ -13,6 +13,8 @@ declare module 'vue' {
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
|
||||
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
|
||||
ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
@ -23,8 +25,10 @@ declare module 'vue' {
|
||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||
EnergyBar: typeof import('./src/components/EnergyBar.vue')['default']
|
||||
EnergyLine: typeof import('./src/components/EnergyLine.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']
|
||||
PdfContent: typeof import('./src/components/PdfContent.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
}
|
||||
|
1280
package-lock.json
generated
1280
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,12 +14,14 @@
|
||||
"element-plus": "^2.9.6",
|
||||
"pinia": "^3.0.2",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0"
|
||||
"vue-router": "^4.5.0",
|
||||
"vue3-html2pdf": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.13.11",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"sass-embedded": "^1.87.0",
|
||||
"typescript": "~5.7.2",
|
||||
"unplugin-auto-import": "^19.1.1",
|
||||
"unplugin-vue-components": "^28.4.1",
|
||||
|
@ -170,6 +170,8 @@ watch(
|
||||
onMounted(async () => {
|
||||
// 等待數據加載
|
||||
await storeDemand.getElecDemandFromBaja();
|
||||
// 測試
|
||||
await storeDemand.getElecDatatTestBaja();
|
||||
// 初始化圖表
|
||||
chartInstance = echarts.init(demand_chart.value);
|
||||
chartInstance.setOption(chartOption.value);
|
||||
|
91
src/components/EnergyPie.vue
Normal file
91
src/components/EnergyPie.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, onUnmounted } from "vue";
|
||||
import * as echarts from "echarts";
|
||||
|
||||
const chartContainer = ref(null);
|
||||
let chartInstance = null;
|
||||
|
||||
const chartData = ref({
|
||||
series: [
|
||||
{
|
||||
name: "電表01",
|
||||
value: 2200,
|
||||
itemStyle: { color: "#5470c6" },
|
||||
},
|
||||
{
|
||||
name: "電表02",
|
||||
value: 3600,
|
||||
itemStyle: { color: "#91cc75" },
|
||||
},
|
||||
{
|
||||
name: "電表03",
|
||||
value: 1600,
|
||||
itemStyle: { color: "#fac858" },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const initChart = () => {
|
||||
chartInstance = echarts.init(chartContainer.value);
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: "{a} <br/>{b} : {c} ({d}%)", // 显示数据格式
|
||||
},
|
||||
legend: {
|
||||
orient: "vertical",
|
||||
left: "right",
|
||||
bottom: "0%",
|
||||
data: chartData.value.series.map((item) => item.name), // 添加图例
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "電表費用",
|
||||
type: "pie",
|
||||
radius: "70%", // 饼图大小
|
||||
center: ["50%", "50%"], // 饼图中心位置
|
||||
data: chartData.value.series,
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: "rgba(0, 0, 0, 0.5)",
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
chartInstance.setOption(option);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => chartData.value,
|
||||
(newChartData) => {
|
||||
if (chartInstance) {
|
||||
chartInstance.setOption({
|
||||
series: [
|
||||
{
|
||||
data: newChartData.series,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div ref="chartContainer" style="width: 100%; height: 250px"></div>
|
||||
</template>
|
@ -11,6 +11,7 @@
|
||||
<el-menu-item index="elecPricingSimple">住宅型</el-menu-item>
|
||||
<el-menu-item index="elecPricingStandard">標準型</el-menu-item>
|
||||
</el-sub-menu>
|
||||
<el-menu-item index="monthlyReport">能源報表</el-menu-item>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
@ -36,6 +37,10 @@ const handleSelect = (key: string, keyPath: string[]) => {
|
||||
router.push({ name: "ElecPricingStandard" });
|
||||
activeIndex.value = "elecPricingStandard";
|
||||
break;
|
||||
case "monthlyReport":
|
||||
router.push({ name: "monthlyReport" });
|
||||
activeIndex.value = "monthlyReport";
|
||||
break;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
221
src/components/PdfContent.vue
Normal file
221
src/components/PdfContent.vue
Normal file
@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-descriptions class="margin-top" title="報表資訊" :column="1" border>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">報表名稱</div>
|
||||
</template>
|
||||
智慧大樓電表月報表
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">報表期間</div>
|
||||
</template>
|
||||
2025/02/01 ~ 2025/02/29
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">編製日期</div>
|
||||
</template>
|
||||
2025/3/1
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">編製人員</div>
|
||||
</template>
|
||||
能源管理部
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-descriptions
|
||||
class="margin-top"
|
||||
title="單價(NTD/kWh)"
|
||||
:column="1"
|
||||
border
|
||||
>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">尖峰單價</div>
|
||||
</template>
|
||||
6
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">半尖峰單價</div>
|
||||
</template>
|
||||
4
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">離峰單價</div>
|
||||
</template>
|
||||
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>
|
||||
<td>電表01</td>
|
||||
<td>辦公室南區</td>
|
||||
<td>549</td>
|
||||
<td>51</td>
|
||||
<td>9.29</td>
|
||||
<td>600</td>
|
||||
<td>150</td>
|
||||
<td>200</td>
|
||||
<td>250</td>
|
||||
<td>900</td>
|
||||
<td>800</td>
|
||||
<td>500</td>
|
||||
<td>2200</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>電表02</td>
|
||||
<td>電梯機房</td>
|
||||
<td>969</td>
|
||||
<td>-69</td>
|
||||
<td>-7.12</td>
|
||||
<td>900</td>
|
||||
<td>300</td>
|
||||
<td>300</td>
|
||||
<td>300</td>
|
||||
<td>1800</td>
|
||||
<td>1200</td>
|
||||
<td>600</td>
|
||||
<td>3600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>電表03</td>
|
||||
<td>會議室</td>
|
||||
<td>489</td>
|
||||
<td>-39</td>
|
||||
<td>-7.98</td>
|
||||
<td>450</td>
|
||||
<td>100</td>
|
||||
<td>150</td>
|
||||
<td>200</td>
|
||||
<td>600</td>
|
||||
<td>600</td>
|
||||
<td>400</td>
|
||||
<td>1600</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="">各電表總費用佔比</h3>
|
||||
<EnergyPie />
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card style="border-radius: 8px; height: 100%">
|
||||
<h3 class="">各電表用電量比較(kWh)</h3>
|
||||
<EnergyBar :chartData="elecUsageData" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import EnergyPie from "../components/EnergyPie.vue";
|
||||
import EnergyBar from "../components/EnergyBar.vue";
|
||||
|
||||
const elecUsageData = ref({
|
||||
categories: ["電表01", "電表02", "電表03"],
|
||||
series: [
|
||||
{
|
||||
name: "尖峰用電",
|
||||
type: "bar",
|
||||
data: [150, 300, 100],
|
||||
itemStyle: { color: "#5470c6" },
|
||||
},
|
||||
{
|
||||
name: "半尖峰用電",
|
||||
type: "bar",
|
||||
data: [200, 300, 150],
|
||||
itemStyle: { color: "#91cc75" },
|
||||
},
|
||||
{
|
||||
name: "離峰用電",
|
||||
type: "bar",
|
||||
data: [250, 300, 200],
|
||||
itemStyle: { color: "#fac858" },
|
||||
},
|
||||
],
|
||||
});
|
||||
</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>
|
@ -22,6 +22,11 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: "ElecPricingStandard",
|
||||
component: () => import("../views/ElecPriceStd.vue"),
|
||||
},
|
||||
{
|
||||
path: "monthlyReport",
|
||||
name: "monthlyReport",
|
||||
component: () => import("../views/MonthlyReport.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -73,10 +73,7 @@ const useElecDemandStore = defineStore("elecDemand", () => {
|
||||
out: Number(newValue),
|
||||
};
|
||||
elecData.value = newElecData;
|
||||
console.log(
|
||||
`Niagara 用電需求 ${item.name} 更新:`,
|
||||
newValue
|
||||
);
|
||||
console.log(`Niagara 用電需求 ${item.name} 更新:`, newValue);
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
@ -109,7 +106,35 @@ const useElecDemandStore = defineStore("elecDemand", () => {
|
||||
console.log("所有訂閱已清除");
|
||||
};
|
||||
|
||||
return { getElecDemandFromBaja, elecData, clearAllSubscriber };
|
||||
// 測試
|
||||
const getElecDatatTestBaja = () => {
|
||||
// @ts-ignore
|
||||
window.require &&
|
||||
// @ts-ignore
|
||||
window.requirejs(["baja!"], (baja: any) => {
|
||||
console.log("進入 bajaSubscriber 準備執行 BQL 訂閱");
|
||||
baja.Ord.make(
|
||||
`local:|foxs:4918|history:/testStation_MJM/MGCB_KWH?period=timerange;start=2025-04-20T00:00:00.000+08:00;end=2025-04-21T00:00:00.000+08:00|bql:history:HistoryRollup.rollup(baja:RelTime '3600000')`
|
||||
).get({
|
||||
cursor: {
|
||||
before: () => {},
|
||||
each: (record: any) => {
|
||||
console.log("recordtest", record);
|
||||
},
|
||||
after: () => {},
|
||||
limit: -1,
|
||||
offset: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
getElecDemandFromBaja,
|
||||
elecData,
|
||||
clearAllSubscriber,
|
||||
getElecDatatTestBaja,
|
||||
};
|
||||
});
|
||||
|
||||
export default useElecDemandStore;
|
56
src/views/MonthlyReport.vue
Normal file
56
src/views/MonthlyReport.vue
Normal file
@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<div style="display: flex; justify-content: flex-end">
|
||||
<el-button type="primary" :icon="Printer" @click="generatePDF"
|
||||
>列印報表</el-button
|
||||
>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 顯示在畫面上的內容 -->
|
||||
<PdfContent />
|
||||
|
||||
<!-- 給 vue3-html2pdf 用的內容 -->
|
||||
<vue3-html2pdf
|
||||
ref="html2Pdf"
|
||||
:show-layout="false"
|
||||
:float-layout="true"
|
||||
:enable-download="true"
|
||||
:preview-modal="true"
|
||||
:filename="pdfFileName"
|
||||
:pdf-quality="2"
|
||||
:manual-pagination="false"
|
||||
:paginate-elements-by-height="1000"
|
||||
pdf-format="a4"
|
||||
pdf-orientation="landscape"
|
||||
pdf-content-width="1120px"
|
||||
>
|
||||
<template #pdf-content>
|
||||
<PdfContent />
|
||||
</template>
|
||||
</vue3-html2pdf>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import PdfContent from "../components/PdfContent.vue";
|
||||
import { Printer } from "@element-plus/icons-vue";
|
||||
import Vue3Html2pdf from "vue3-html2pdf";
|
||||
|
||||
// PDF 文件名稱
|
||||
const pdfFileName = ref("智慧大樓電表月報表");
|
||||
|
||||
// 引用 vue-html2pdf 實例
|
||||
const html2Pdf = ref<InstanceType<typeof Vue3Html2pdf> | null>(null);
|
||||
|
||||
// 觸發 PDF 生成和下載
|
||||
const generatePDF = async () => {
|
||||
if (html2Pdf.value) {
|
||||
await html2Pdf.value.generatePdf();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
6
src/vite-env.d.ts
vendored
6
src/vite-env.d.ts
vendored
@ -8,6 +8,12 @@ declare module "*.vue" {
|
||||
export default component;
|
||||
}
|
||||
|
||||
declare module "vue3-html2pdf" {
|
||||
import { DefineComponent } from "vue";
|
||||
const component: DefineComponent<{}, {}, any>;
|
||||
export default component;
|
||||
}
|
||||
|
||||
// 聲明環境變數 ( .env 檔案)
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_APP_TITLE: string;
|
||||
|
Loading…
Reference in New Issue
Block a user