首頁與能源管理語言包 | 設備管理的2d位置debug | 設備管理的圖資與iot先隱藏

This commit is contained in:
koko 2025-07-18 18:04:26 +08:00
parent bc51a9db1f
commit 6e346af685
21 changed files with 200 additions and 100 deletions

View File

@ -9,7 +9,7 @@ const props = defineProps({
type: String, type: String,
default: "", default: "",
}, },
value: String, value: Object || String,
isTopLabelExist: { isTopLabelExist: {
type: Boolean, type: Boolean,
default: true, default: true,

View File

@ -21,7 +21,7 @@ const route = useRoute();
const authPages = ref([]); // API authPages const authPages = ref([]); // API authPages
const menu_array = ref([]); const menu_array = ref([]);
const isDrawerOpen = ref(false); const isDrawerOpen = ref(false);
const iniFroList = async () => { const iniFroList = async () => {
try { try {
@ -69,7 +69,12 @@ watch(locale, () => {
<template> <template>
<header class="navbar w-full relative z-50 p-0"> <header class="navbar w-full relative z-50 p-0">
<input id="nav-drawer" type="checkbox" class="drawer-toggle" v-model="isDrawerOpen" /> <input
id="nav-drawer"
type="checkbox"
class="drawer-toggle"
v-model="isDrawerOpen"
/>
<!-- Navbar --> <!-- Navbar -->
<div class="navbar bg-base-300 w-full justify-between"> <div class="navbar bg-base-300 w-full justify-between">
<div class="flex-none lg:hidden"> <div class="flex-none lg:hidden">
@ -101,18 +106,16 @@ watch(locale, () => {
<img src="/logo.svg" alt="logo" class="w-6 lg:w-8 me-1" /> <img src="/logo.svg" alt="logo" class="w-6 lg:w-8 me-1" />
新創賦能 新創賦能
</router-link> </router-link>
<NavbarBuilding class="hidden lg:block ms-8" />
</div> </div>
<div class="hidden flex-1 lg:block"> <div class="hidden flex-1 lg:block">
<div class="flex items-center justify-around"> <NavbarItem
<NavbarBuilding /> :authPages="authPages"
<NavbarItem :menu_array="menu_array"
:authPages="authPages" @show-drawer="getSubMonitorPage"
:menu_array="menu_array" @getSubPage="getSubPage"
@show-drawer="getSubMonitorPage" @close-drawer="closeDrawer"
@getSubPage="getSubPage" />
@close-drawer="closeDrawer"
/>
</div>
</div> </div>
<ul class="left-menu flex-none"> <ul class="left-menu flex-none">
<li> <li>
@ -142,7 +145,7 @@ watch(locale, () => {
:menu_array="menu_array" :menu_array="menu_array"
@show-drawer="getSubMonitorPage" @show-drawer="getSubMonitorPage"
@getSubPage="getSubPage" @getSubPage="getSubPage"
@close-drawer="closeDrawer" @close-drawer="closeDrawer"
/> />
</div> </div>
</div> </div>

View File

@ -44,7 +44,10 @@
"this_month": "本月", "this_month": "本月",
"last_month": "上月", "last_month": "上月",
"this_year": "今年", "this_year": "今年",
"last_year": "去年" "last_year": "去年",
"refrig_temp": "冷藏温度",
"indoor_temp": "室内温度",
"alerts_data": "异常资料"
}, },
"history": { "history": {
"title": "历史资料", "title": "历史资料",
@ -148,7 +151,12 @@
"off_peak_contract": "离峰契约", "off_peak_contract": "离峰契约",
"variable_electricity_charge": "流动电费", "variable_electricity_charge": "流动电费",
"saturday": "周六", "saturday": "周六",
"sunday_and_off_peak_days": "周日及离峰日" "sunday_and_off_peak_days": "周日及离峰日",
"latest_elec_consumption": "最新用电度数",
"daily_elec": "每日用电度数",
"line_voltage": "线电压",
"electric_current": "电流",
"monthly_elec_bill": "每月电费分析"
}, },
"alarm": { "alarm": {
"title": "显示警告", "title": "显示警告",
@ -174,7 +182,7 @@
"alarmClass": "告警条件", "alarmClass": "告警条件",
"device_name": "设备名称", "device_name": "设备名称",
"device_number": "设备编号", "device_number": "设备编号",
"device_point_name":"点位名称", "device_point_name": "点位名称",
"date": "发生日期", "date": "发生日期",
"time": "发生时间", "time": "发生时间",
"error_msg": "异常原因", "error_msg": "异常原因",
@ -270,6 +278,7 @@
"tax_id_number": "统一编号", "tax_id_number": "统一编号",
"remark": "备注", "remark": "备注",
"date": "日期", "date": "日期",
"time": "时间",
"serial": "单号", "serial": "单号",
"today": "今天", "today": "今天",
"yesterday": "昨天", "yesterday": "昨天",
@ -387,7 +396,7 @@
"sure_to_delete_permanent": "是否确认永久删除该项目?", "sure_to_delete_permanent": "是否确认永久删除该项目?",
"delete_success": "删除成功", "delete_success": "删除成功",
"delete_failed": "删除失败", "delete_failed": "删除失败",
"mqtt_refresh":"重新设定成功" "mqtt_refresh": "重新设定成功"
}, },
"setting": { "setting": {
"MQTT_parse": "MQTT 解析", "MQTT_parse": "MQTT 解析",

View File

@ -44,7 +44,10 @@
"this_month": "本月", "this_month": "本月",
"last_month": "上月", "last_month": "上月",
"this_year": "今年", "this_year": "今年",
"last_year": "去年" "last_year": "去年",
"refrig_temp":"冷藏溫度",
"indoor_temp":"室內溫度",
"alerts_data":"異常資料"
}, },
"history": { "history": {
"title": "歷史資料", "title": "歷史資料",
@ -148,7 +151,12 @@
"off_peak_contract": "離峰契約", "off_peak_contract": "離峰契約",
"variable_electricity_charge": "流動電費", "variable_electricity_charge": "流動電費",
"saturday": "週六", "saturday": "週六",
"sunday_and_off_peak_days": "週日及離峰日" "sunday_and_off_peak_days": "週日及離峰日",
"latest_elec_consumption": "最新用電度數",
"daily_elec": "每日用電度數",
"line_voltage": "線電壓",
"electric_current" : "電流",
"monthly_elec_bill":"每月電費分析"
}, },
"alarm": { "alarm": {
"title": "顯示警告", "title": "顯示警告",
@ -270,6 +278,7 @@
"tax_id_number": "統一編號", "tax_id_number": "統一編號",
"remark": "備注", "remark": "備注",
"date": "日期", "date": "日期",
"time": "時間",
"serial": "單號", "serial": "單號",
"today": "今天", "today": "今天",
"yesterday": "昨天", "yesterday": "昨天",

View File

@ -44,7 +44,10 @@
"this_month": "This month", "this_month": "This month",
"last_month": "Last month", "last_month": "Last month",
"this_year": "This year", "this_year": "This year",
"last_year": "Last year" "last_year": "Last year",
"refrig_temp": "Refrigeration temperature",
"indoor_temp": "Indoor temperature",
"alerts_data": "Abnormal data"
}, },
"history": { "history": {
"title": "Historical Data", "title": "Historical Data",
@ -148,7 +151,12 @@
"off_peak_contract": "Off-Peak Demand Charge", "off_peak_contract": "Off-Peak Demand Charge",
"variable_electricity_charge": "Variable Electricity Charge", "variable_electricity_charge": "Variable Electricity Charge",
"saturday": "Saturday", "saturday": "Saturday",
"sunday_and_off_peak_days": "Sunday and Off-Peak Days" "sunday_and_off_peak_days": "Sunday and Off-Peak Days",
"latest_elec_consumption": "Latest electricity consumption",
"daily_elec": "Daily electricity consumption",
"line_voltage": "Line voltage",
"electric_current": "electric current",
"monthly_elec_bill": "Monthly electricity bill analysis"
}, },
"alarm": { "alarm": {
"title": "Warning", "title": "Warning",
@ -174,7 +182,7 @@
"alarmClass": "Alarm Conditions", "alarmClass": "Alarm Conditions",
"device_name": "Device Name", "device_name": "Device Name",
"device_number": "Device Number", "device_number": "Device Number",
"device_point_name":"Point Name", "device_point_name": "Point Name",
"date": "Occurrence Date", "date": "Occurrence Date",
"time": "Occurrence Time", "time": "Occurrence Time",
"error_msg": "Abnormal Cause", "error_msg": "Abnormal Cause",
@ -270,6 +278,7 @@
"tax_id_number": "Tax ID Number", "tax_id_number": "Tax ID Number",
"remark": "Remark", "remark": "Remark",
"date": "Date", "date": "Date",
"time": "Time",
"serial": "Order Number", "serial": "Order Number",
"today": "Today", "today": "Today",
"yesterday": "Yesterday", "yesterday": "Yesterday",
@ -387,7 +396,7 @@
"sure_to_delete_permanent": "Are you sure you want to permanently delete this item?", "sure_to_delete_permanent": "Are you sure you want to permanently delete this item?",
"delete_success": "Delete successfully", "delete_success": "Delete successfully",
"delete_failed": "Delete failed", "delete_failed": "Delete failed",
"mqtt_refresh":"MQTT reset successful" "mqtt_refresh": "MQTT reset successful"
}, },
"setting": { "setting": {
"MQTT_parse": "MQTT Parse", "MQTT_parse": "MQTT Parse",

View File

@ -75,7 +75,7 @@ const router = createRouter({
component: AlertManagement, component: AlertManagement,
}, },
{ {
path: "/energyManagement/:main_system_id/:sub_system_id/:type", path: "/energyManagement",
name: "energyManagement", name: "energyManagement",
component: EnergyManagement, component: EnergyManagement,
}, },

View File

@ -76,11 +76,11 @@ const onOk = async () => {
formData.append("Device_image", props.formState.Device_image); formData.append("Device_image", props.formState.Device_image);
} }
const res = await postAssetSubList(formData); // const res = await postAssetSubList(formData);
if (res.isSuccess) { // if (res.isSuccess) {
props.getData(parseInt(searchParams.value.mainSys_id)); // props.getData(parseInt(searchParams.value.mainSys_id));
onCancel(); // onCancel();
} // }
}; };
</script> </script>

View File

@ -209,8 +209,8 @@ watch(
</Select> </Select>
</div> </div>
<AssetTableModalLeftInfoMQTT /> <AssetTableModalLeftInfoMQTT />
<AssetTableModalLeftInfoGraph /> <!-- <AssetTableModalLeftInfoGraph /> -->
<AssetTableModalLeftInfoIoT /> <!-- <AssetTableModalLeftInfoIoT /> -->
</template> </template>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -34,14 +34,25 @@ const defaultOption = (map, data = []) => {
// //
const formattedData = data.map((coordinate) => { const formattedData = data.map((coordinate) => {
const coordString = JSON.stringify(coordinate); const coordString = JSON.stringify(coordinate);
// device_coordinate
let isSelected = false;
if (formState.value.device_coordinate) {
try {
const deviceCoord = JSON.parse(formState.value.device_coordinate);
//
isSelected = coordinate.length === deviceCoord.length &&
coordinate.every((val, index) => Math.abs(val - deviceCoord[index]) < 0.001);
} catch (e) {
console.warn('解析 device_coordinate 失敗:', e);
}
}
return { return {
name: coordString, name: coordString,
value: coordinate, value: coordinate,
itemStyle: { itemStyle: {
color: color: isSelected ? "#0000FF" : "#b02a02",
coordString === formState.value.device_coordinate
? "#0000FF"
: "#b02a02",
}, },
}; };
}); });

View File

@ -2,7 +2,9 @@
import dayjs from "dayjs"; import dayjs from "dayjs";
import { computed, ref, onMounted } from "vue"; import { computed, ref, onMounted } from "vue";
import { faker } from "@faker-js/faker"; // faker.js import { faker } from "@faker-js/faker"; // faker.js
import { useI18n } from "vue-i18n";
const { t } = useI18n();
// //
const fakeAlarmData = ref([]); const fakeAlarmData = ref([]);
@ -36,15 +38,15 @@ const alarms = computed(() =>
</script> </script>
<template> <template>
<h3 class="text-info font-bold text-xl text-center">異常資料 Top 5</h3> <h3 class="text-info text-xl text-center">{{$t("dashboard.alerts_data")}} Top 5</h3>
<div class="overflow-x-auto"> <div class="overflow-x-auto">
<table class="table"> <table class="table">
<thead> <thead>
<tr class="border-b-2 border-info text-base"> <tr class="border-b-2 border-info text-base">
<th>日期</th> <th>{{$t("operation.date")}}</th>
<th>時間</th> <th>{{$t("operation.time")}}</th>
<th>設備名稱</th> <th>{{$t("operation.device_name")}}</th>
<th>備註</th> <th>{{$t("operation.remark")}}</th>
</tr> </tr>
</thead> </thead>
<tbody class="text-base"> <tbody class="text-base">

View File

@ -4,7 +4,9 @@ import EffectScatter from "@/components/chart/EffectScatter.vue";
import useSearchParam from "@/hooks/useSearchParam"; import useSearchParam from "@/hooks/useSearchParam";
import { computed, inject, ref, watch } from "vue"; import { computed, inject, ref, watch } from "vue";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const { searchParams, changeParams } = useSearchParam(); const { searchParams, changeParams } = useSearchParam();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
@ -28,9 +30,9 @@ const defaultOption = (map, data = []) => {
formatter: function (params) { formatter: function (params) {
return params.data[2]?.full_name return params.data[2]?.full_name
? ` ? `
<div class="p-2 w-24"> <div class="p-2 w-auto min-w-24">
<div class="text-lg">${params.data[2].full_name}</div> <div class="text-lg">${params.data[2].full_name}</div>
<div class="text-sm text-gray-500">狀態: ${ <div class="text-sm text-gray-500">${t("operation.status")} : ${
params.data[2].state || "" params.data[2].state || ""
}</div>` }</div>`
: ""; : "";
@ -99,6 +101,7 @@ watch(
[searchParams, () => asset_floor_chart.value, () => props.data], [searchParams, () => asset_floor_chart.value, () => props.data],
([newValue, newChart, newData], [oldValue]) => { ([newValue, newChart, newData], [oldValue]) => {
if (newValue.floor_id && newChart && Object.keys(newData || {}).length > 0) { if (newValue.floor_id && newChart && Object.keys(newData || {}).length > 0) {
console.log("Updating chart with new data", newValue, newChart, newData);
newChart.updateSvg( newChart.updateSvg(
{ {
full_name: newValue.floor_id, full_name: newValue.floor_id,

View File

@ -81,7 +81,7 @@ const onCancel = () => {
id="immediate_demand_add_item" id="immediate_demand_add_item"
:title="t('energy.edit_automatic_demand')" :title="t('energy.edit_automatic_demand')"
:onCancel="closeModal" :onCancel="closeModal"
width="400" :width="400"
> >
<template #modalContent> <template #modalContent>
<form ref="form" class="mt-5 flex flex-col items-center"> <form ref="form" class="mt-5 flex flex-col items-center">

View File

@ -74,7 +74,7 @@ const closeModal = () => {
id="carbon_emission_item" id="carbon_emission_item"
:title="t('energy.edit_carbon_emission')" :title="t('energy.edit_carbon_emission')"
:onCancel="closeModal" :onCancel="closeModal"
width="400" :width="400"
> >
<template #modalContent> <template #modalContent>
<form ref="form" class="mt-5 flex flex-col items-center"> <form ref="form" class="mt-5 flex flex-col items-center">

View File

@ -6,7 +6,9 @@ import { ref, inject, onMounted, onUnmounted, watch } from "vue";
import { getDashboardTemp } from "@/apis/dashboard"; import { getDashboardTemp } from "@/apis/dashboard";
import useSearchParams from "@/hooks/useSearchParam"; import useSearchParams from "@/hooks/useSearchParam";
import useBuildingStore from "@/stores/useBuildingStore"; import useBuildingStore from "@/stores/useBuildingStore";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const { searchParams } = useSearchParams(); const { searchParams } = useSearchParams();
const buildingStore = useBuildingStore(); const buildingStore = useBuildingStore();
const intervalType = "indoor"; const intervalType = "indoor";
@ -38,7 +40,6 @@ const defaultChartOption = ref({
axisLabel: { axisLabel: {
color: "#ffffff", color: "#ffffff",
}, },
data: [], data: [],
}, },
yAxis: { yAxis: {
@ -49,14 +50,14 @@ const defaultChartOption = ref({
axisLabel: { axisLabel: {
color: "#ffffff", color: "#ffffff",
}, },
// min/max ECharts
}, },
series: [], series: [],
}); });
const timeoutTimer = ref("");
const indoor_temp_chart = ref(null); const indoor_temp_chart = ref(null);
const data = ref([]); const data = ref([]);
const getData = async (timeInterval) => { const getData = async (timeInterval) => {
const res = await getDashboardTemp({ const res = await getDashboardTemp({
building_guid: buildingStore.selectedBuilding.building_guid, building_guid: buildingStore.selectedBuilding.building_guid,
@ -64,16 +65,15 @@ const getData = async (timeInterval) => {
tempOption: 1, // 1 2: tempOption: 1, // 1 2:
}); });
if (res.isSuccess) { if (res.isSuccess) {
console.log('室內溫度資料:', res.data['室溫']); console.log("室內溫度資料:", res.data["室溫"]);
data.value = res.data['室溫']; data.value = res.data["室溫"];
} }
}; };
watch( watch(
data, data,
(newValue) => { (newValue) => {
newValue.length > 0 && newValue.length > 0 &&
indoor_temp_chart.value.chart.setOption({ indoor_temp_chart.value.chart.setOption({
legend: { legend: {
@ -82,6 +82,22 @@ watch(
xAxis: { xAxis: {
data: newValue[0]?.data.map(({ time }) => time), // 使 time data: newValue[0]?.data.map(({ time }) => time), // 使 time
}, },
yAxis: {
min: Math.floor(
Math.min(
...newValue[0]?.data
.filter((data) => data.value !== null)
.map(({ value }) => value)
)
),
max: Math.ceil(
Math.max(
...newValue[0]?.data
.filter((data) => data.value !== null)
.map(({ value }) => value)
)
),
},
series: newValue.map(({ full_name, data }, index) => ({ series: newValue.map(({ full_name, data }, index) => ({
name: full_name, name: full_name,
type: "line", type: "line",
@ -111,9 +127,11 @@ watch(
clearInterval(timeoutTimer.value); clearInterval(timeoutTimer.value);
} }
} }
},
{
immediate: true,
} }
); );
const timeoutTimer = ref("");
onUnmounted(() => { onUnmounted(() => {
// //
@ -125,7 +143,7 @@ onUnmounted(() => {
<template> <template>
<h3 class="text-info font-bold text-xl text-center mb-3 relative"> <h3 class="text-info font-bold text-xl text-center mb-3 relative">
<span>室內溫度</span> <span>{{ $t("dashboard.indoor_temp") }}</span>
</h3> </h3>
<LineChart <LineChart

View File

@ -6,7 +6,10 @@ import { ref, inject, onMounted, onUnmounted, watch } from "vue";
import { getDashboardTemp } from "@/apis/dashboard"; import { getDashboardTemp } from "@/apis/dashboard";
import useSearchParams from "@/hooks/useSearchParam"; import useSearchParams from "@/hooks/useSearchParam";
import useBuildingStore from "@/stores/useBuildingStore"; import useBuildingStore from "@/stores/useBuildingStore";
import { useI18n } from "vue-i18n";
import { max, min } from "date-fns";
const { t } = useI18n();
const { searchParams } = useSearchParams(); const { searchParams } = useSearchParams();
const buildingStore = useBuildingStore(); const buildingStore = useBuildingStore();
@ -53,8 +56,8 @@ const defaultChartOption = ref({
series: [], series: [],
}); });
const timeoutTimer = ref("");
const frozen_temp_chart = ref(null); const frozen_temp_chart = ref(null);
const data = ref([]); const data = ref([]);
const getData = async (timeInterval) => { const getData = async (timeInterval) => {
const res = await getDashboardTemp({ const res = await getDashboardTemp({
@ -63,9 +66,9 @@ const getData = async (timeInterval) => {
tempOption: 2, // 1 2: tempOption: 2, // 1 2:
}); });
if (res.isSuccess) { if (res.isSuccess) {
console.log('冷藏溫度資料:', res.data['冷藏溫度']); console.log("冷藏溫度資料:", res.data["冷藏溫度"]);
data.value = res.data['冷藏溫度']; data.value = res.data["冷藏溫度"];
} }
}; };
@ -80,6 +83,24 @@ watch(
xAxis: { xAxis: {
data: newValue[0]?.data.map(({ time }) => time), // 使 time data: newValue[0]?.data.map(({ time }) => time), // 使 time
}, },
yAxis: {
min:
Math.floor(
Math.min(
...newValue[0]?.data
.filter((data) => data.value !== null)
.map(({ value }) => value)
)
),
max:
Math.ceil(
Math.max(
...newValue[0]?.data
.filter((data) => data.value !== null)
.map(({ value }) => value)
)
),
},
series: newValue.map(({ full_name, data }, index) => ({ series: newValue.map(({ full_name, data }, index) => ({
name: full_name, name: full_name,
type: "line", type: "line",
@ -109,9 +130,11 @@ watch(
clearInterval(timeoutTimer.value); clearInterval(timeoutTimer.value);
} }
} }
},
{
immediate: true,
} }
); );
const timeoutTimer = ref("");
onUnmounted(() => { onUnmounted(() => {
// //
@ -123,7 +146,7 @@ onUnmounted(() => {
<template> <template>
<h3 class="text-info font-bold text-xl text-center mb-3 relative"> <h3 class="text-info font-bold text-xl text-center mb-3 relative">
<span>冷藏溫度</span> <span>{{ $t("dashboard.refrig_temp") }}</span>
</h3> </h3>
<LineChart <LineChart

View File

@ -51,15 +51,15 @@ provide("energy_data", { realTime_data, elecMonth_data, elecDay_data });
</script> </script>
<template> <template>
<div class="grid gap-4 grid-cols-5 h-[47%] mb-4"> <div class="grid gap-4 md:grid-cols-5 grid-cols-1 h-[47%] my-4">
<div class="col-span-3"> <div class="md:col-span-3 col-span-1">
<ImmediateDemandChart /> <ImmediateDemandChart />
</div> </div>
<div class="col-span-2"> <div class="md:col-span-2 col-span-1">
<CurrentInformation /> <CurrentInformation />
</div> </div>
</div> </div>
<div class="grid gap-4 grid-cols-3 h-[47%]"> <div class="grid gap-4 md:grid-cols-3 grid-cols-1 h-[47%]">
<div class="col-span-1"> <div class="col-span-1">
<UsageInformation /> <UsageInformation />
</div> </div>

View File

@ -1,6 +1,9 @@
<script setup> <script setup>
import BarChart from "@/components/chart/BarChart.vue"; import BarChart from "@/components/chart/BarChart.vue";
import { ref, watch, inject } from "vue"; import { ref, watch, inject } from "vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const { elecMonth_data } = inject("energy_data"); const { elecMonth_data } = inject("energy_data");
const defaultChartOption = ref({ const defaultChartOption = ref({
@ -11,7 +14,7 @@ const defaultChartOption = ref({
}, },
}, },
legend: { legend: {
data: ["尖峰", "半尖峰", "離峰度數"], data: [t("energy.peak"), t("energy.semi_peak"), t("energy.off_peak")],
textStyle: { textStyle: {
color: "#ffffff", color: "#ffffff",
fontSize: 16, fontSize: 16,
@ -35,41 +38,41 @@ const defaultChartOption = ref({
}, },
yAxis: { yAxis: {
type: "value", type: "value",
max:15, // max: 15,
axisLabel: { axisLabel: {
color: "#ffffff", color: "#ffffff",
}, },
}, },
series: [ series: [
{ {
name: "尖峰", name: t("energy.peak"),
type: "bar", type: "bar",
stack: "total", stack: "total",
data: [], data: [],
itemStyle: { itemStyle: {
color: "#3c50e0", color: "#3c50e0",
}, },
barWidth: '20px', // barWidth: "20px",
}, },
{ {
name: "半尖峰", name: t("energy.semi_peak"),
type: "bar", type: "bar",
stack: "total", stack: "total",
data: [], data: [],
itemStyle: { itemStyle: {
color: "#6577f3", color: "#6577f3",
}, },
barWidth: '20px', // barWidth: "20px",
}, },
{ {
name: "離峰度數", name: t("energy.off_peak"),
type: "bar", type: "bar",
stack: "total", stack: "total",
data: [], data: [],
itemStyle: { itemStyle: {
color: "#8fd0ef", color: "#8fd0ef",
}, },
barWidth: '20px', // barWidth: "20px",
}, },
], ],
}); });
@ -96,10 +99,10 @@ watch(
class="card bg-normal w-full h-full border border-cyan-300/50 rounded-md" class="card bg-normal w-full h-full border border-cyan-300/50 rounded-md"
> >
<div class="card-body"> <div class="card-body">
<h2 class="card-title">每月計費度數 (kWh)</h2> <h2 class="card-title">{{ $t("energy.monthly_bill_power")}}</h2>
<BarChart <BarChart
id="billing_degree_chart" id="billing_degree_chart"
class="h-full w-full" class="min-h-[250px] max-h-fit"
:option="defaultChartOption" :option="defaultChartOption"
ref="degree_chart" ref="degree_chart"
/> />
@ -107,4 +110,5 @@ watch(
</div> </div>
</template> </template>
<style lang="scss" scoped></style> <style lang="scss" scoped>
</style>

View File

@ -1,17 +1,20 @@
<script setup> <script setup>
import { ref, watch, inject } from "vue"; import { ref, watch, inject } from "vue";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const { realTime_data } = inject("energy_data"); const { realTime_data } = inject("energy_data");
const voltage = ref([ const voltage = ref([
{ point: "線電壓 V12", value: 0 }, { point: `${t("energy.line_voltage")} V12`, value: 0 },
{ point: "線電壓 V23", value: 0 }, { point: `${t("energy.line_voltage")} V23`, value: 0 },
{ point: "線電壓 V31", value: 0 }, { point: `${t("energy.line_voltage")} V31`, value: 0 },
]); ]);
const current = ref([ const current = ref([
{ point: "電流 1", value: 0 }, { point: `${t("energy.electric_current")} 1`, value: 0 },
{ point: "電流 2", value: 0 }, { point: `${t("energy.electric_current")} 2`, value: 0 },
{ point: "電流 3", value: 0 }, { point: `${t("energy.electric_current")} 3`, value: 0 },
]); ]);
const lastUpdated = ref(""); const lastUpdated = ref("");

View File

@ -1,6 +1,9 @@
<script setup> <script setup>
import BarChart from "@/components/chart/BarChart.vue"; import BarChart from "@/components/chart/BarChart.vue";
import { ref, onMounted, inject, watch } from "vue"; import { ref, onMounted, inject, watch } from "vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const { elecMonth_data } = inject("energy_data"); const { elecMonth_data } = inject("energy_data");
const defaultChartOption = ref({ const defaultChartOption = ref({
tooltip: { tooltip: {
@ -10,7 +13,7 @@ const defaultChartOption = ref({
}, },
}, },
legend: { legend: {
data: ["基本電費", "流動電費"], data: [t("energy.fixed_elec_cost"), t("energy.var_elec_cost")],
textStyle: { textStyle: {
color: "#ffffff", color: "#ffffff",
fontSize: 16, fontSize: 16,
@ -34,7 +37,7 @@ const defaultChartOption = ref({
}, },
yAxis: { yAxis: {
type: "value", type: "value",
max: 500, // max: 500,
min: 0, min: 0,
axisLabel: { axisLabel: {
color: "#ffffff", color: "#ffffff",
@ -42,24 +45,24 @@ const defaultChartOption = ref({
}, },
series: [ series: [
{ {
name: "基本電費", name: t("energy.fixed_elec_cost"),
type: "bar", type: "bar",
stack: "total", stack: "total",
data: [], data: [],
itemStyle: { itemStyle: {
color: "#37c640", color: "#37c640",
}, },
barWidth: '20px', // barWidth: "20px",
}, },
{ {
name: "流動電費", name: t("energy.var_elec_cost"),
type: "bar", type: "bar",
stack: "total", stack: "total",
data: [], data: [],
itemStyle: { itemStyle: {
color: "#8ee894", color: "#8ee894",
}, },
barWidth: '20px', // barWidth: "20px",
}, },
], ],
}); });
@ -69,8 +72,8 @@ watch(
(newData) => { (newData) => {
const times = newData.map((item) => item.time); const times = newData.map((item) => item.time);
const costBase = newData.map((item) => item.costBase); const costBase = newData.map((item) => item.costBase);
const costDemand = newData.map( const costDemand = newData.map((item) =>
(item) => (item.costPeak + item.costHalfPeak + item.costOffPeak).toFixed(2) (item.costPeak + item.costHalfPeak + item.costOffPeak).toFixed(2)
); );
defaultChartOption.value.xAxis.data = times; defaultChartOption.value.xAxis.data = times;
@ -86,10 +89,10 @@ watch(
class="card bg-normal w-full h-full border border-cyan-300/50 rounded-md" class="card bg-normal w-full h-full border border-cyan-300/50 rounded-md"
> >
<div class="card-body"> <div class="card-body">
<h2 class="card-title">每月電費分析</h2> <h2 class="card-title">{{ $t("energy.monthly_elec_bill") }}</h2>
<BarChart <BarChart
id="electricity_bill_chart" id="electricity_bill_chart"
class="h-full w-full" class="min-h-[250px] max-h-fit"
:option="defaultChartOption" :option="defaultChartOption"
ref="bill_chart" ref="bill_chart"
/> />

View File

@ -1,6 +1,9 @@
<script setup> <script setup>
import LineChart from "@/components/chart/LineChart.vue"; import LineChart from "@/components/chart/LineChart.vue";
import { ref, onMounted, watch, inject } from "vue"; import { ref, onMounted, watch, inject } from "vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const { elecDay_data } = inject("energy_data"); const { elecDay_data } = inject("energy_data");
const todayUsage = ref(0); const todayUsage = ref(0);
const demand_chart = ref(null); const demand_chart = ref(null);
@ -9,7 +12,7 @@ const defaultChartOption = ref({
trigger: "axis", trigger: "axis",
}, },
legend: { legend: {
data: ["每日用電度數"], data: [t("energy.daily_elec")],
textStyle: { textStyle: {
color: "#ffffff", color: "#ffffff",
fontSize: 16, fontSize: 16,
@ -45,7 +48,7 @@ const defaultChartOption = ref({
}, },
series: [ series: [
{ {
name: "每日用電度數", name: t("energy.daily_elec"),
type: "line", type: "line",
data: [], data: [],
smooth: true, smooth: true,
@ -95,12 +98,12 @@ watch(
> >
<div class="card-body"> <div class="card-body">
<h2 class="card-title"> <h2 class="card-title">
最新用電度數 {{$t("energy.latest_elec_consumption")}}
<p>{{ todayUsage }} kWh</p> <p>{{ todayUsage }} kWh</p>
</h2> </h2>
<LineChart <LineChart
id="immediate_demand_chart" id="immediate_demand_chart"
class="h-full w-full" class="min-h-[250px] max-h-fit w-full"
:option="defaultChartOption" :option="defaultChartOption"
ref="demand_chart" ref="demand_chart"
/> />
@ -115,7 +118,7 @@ watch(
} }
.bg-normal::before { .bg-normal::before {
@apply absolute -top-3 -right-[10px] h-8 w-8 bg-no-repeat z-10 bg-[url('@/assets/img/table/content-box-background02.svg')] bg-center; @apply absolute -top-[9px] -left-[11px] -rotate-90 h-8 w-8 bg-no-repeat z-10 bg-[url('@/assets/img/table/content-box-background02.svg')] bg-center;
content: ""; content: "";
} }
</style> </style>

View File

@ -65,7 +65,7 @@ watch(
<!-- 電壓資訊 --> <!-- 電壓資訊 -->
<div class="stat place-items-start"> <div class="stat place-items-start">
<div class="stat-title text-gray-200 3xl:text-[2rem]"> <div class="stat-title text-gray-200 3xl:text-[2rem]">
今年電費總計 () {{ $t("energy.elec_bills") }}
</div> </div>
<div class="stat-value text-success text-5xl 3xl:text-[6rem]"> <div class="stat-value text-success text-5xl 3xl:text-[6rem]">
{{ totalElecBills }} {{ totalElecBills }}
@ -76,7 +76,7 @@ watch(
</div> </div>
<div class="stat place-items-start"> <div class="stat place-items-start">
<div class="stat-title text-gray-200 3xl:text-[2rem]"> <div class="stat-title text-gray-200 3xl:text-[2rem]">
區間電費總計 () {{ $t("energy.interval_elec_charges") }}
</div> </div>
<div class="stat-value text-success text-5xl 3xl:text-[6rem]"> <div class="stat-value text-success text-5xl 3xl:text-[6rem]">
{{ IntervalElecBills }} {{ IntervalElecBills }}
@ -93,7 +93,7 @@ watch(
<!-- 電流資訊 --> <!-- 電流資訊 -->
<div class="stat place-items-start"> <div class="stat place-items-start">
<div class="stat-title text-gray-200 3xl:text-[2rem]"> <div class="stat-title text-gray-200 3xl:text-[2rem]">
今年用電度數 (kWh) {{ $t("energy.year_elec_consumption") }}
</div> </div>
<div class="stat-value text-success text-5xl 3xl:text-[6rem]"> <div class="stat-value text-success text-5xl 3xl:text-[6rem]">
{{ totalElecDegree }} {{ totalElecDegree }}
@ -104,7 +104,7 @@ watch(
</div> </div>
<div class="stat place-items-start"> <div class="stat place-items-start">
<div class="stat-title text-gray-200 3xl:text-[2rem]"> <div class="stat-title text-gray-200 3xl:text-[2rem]">
區間用電度數 (kWh) {{ $t("energy.interval_elec_consumption") }}
</div> </div>
<div class="stat-value text-success text-5xl 3xl:text-[6rem]"> <div class="stat-value text-success text-5xl 3xl:text-[6rem]">
{{ IntervalElecDegree }} {{ IntervalElecDegree }}