系統監控: 2D圓點bug修正 | 能源管理: 日報表功能

This commit is contained in:
koko 2025-01-24 16:01:17 +08:00
parent 8e2b5e1e2c
commit 5b1ff9749d
7 changed files with 235 additions and 94 deletions

View File

@ -5,3 +5,5 @@ export const GET_TAI_POWER_API = `/api/Energe/GetTaipower`;
export const GET_SIDEBAR_API = `/api/Energe/GetEnergySideBar`;
export const GET_SEARCH_API = `/api/Energe/GetFilter`;
export const GET_REPORT_API = `/api/Energe/GetReport`;

View File

@ -4,6 +4,7 @@ import {
GET_TAI_POWER_API,
GET_SIDEBAR_API,
GET_SEARCH_API,
GET_REPORT_API,
} from "./api";
import instance from "@/util/request";
import apihandler from "@/util/apihandler";
@ -52,3 +53,26 @@ export const getEnergySearch = async (type) => {
code: res.code,
});
};
export const getReport = async ({
department,
elecType,
floor,
start_time,
end_time,
type,
}) => {
const res = await instance.post(GET_REPORT_API, {
department,
elecType,
floor,
start_time,
end_time,
type,
});
return apihandler(res.code, res.data, {
msg: res.msg,
code: res.code,
});
};

View File

@ -8,7 +8,7 @@ import {
getAssetFloorList,
getElecTypeList,
} from "@/apis/asset";
import { getAccountUserList } from "@/apis/account";
import { getReport } from "@/apis/energy";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const route = useRoute();
@ -78,7 +78,7 @@ const getFloor = async () => {
const onSearch = async () => {
loading.value = true;
const res = await getAccountUserList(formState.value);
const res = await getReport(formState.value);
tableData.value = res.data;
loading.value = false;
};
@ -114,7 +114,7 @@ watch(
watch(
() => route.params.type,
(newVal) => {
formState.value.type = newVal;
formState.value.type = Number(newVal);
},
{ immediate: true }
);

View File

@ -1,33 +1,91 @@
<script setup>
import Table from "@/components/customUI/Table.vue";
import { inject, computed } from "vue";
import { inject, computed, ref } from "vue";
import { useI18n } from "vue-i18n";
import dayjs from "dayjs";
const { t } = useI18n();
const { tableData, loading } = inject("energy_table_data");
const columns = computed(() => [
//
const defaultColumns = ref([
{
title: t("history.building_name"),
key: "building_name",
title: t("assetManagement.department"),
key: "department_name",
},
{
title: t("energy.floor"),
key: "building_name",
key: "floor_name",
},
{
title: t("energy.electricity_classification"),
key: "elecType",
},
{
title: t("history.device_name"),
key: "device_name",
filter: true,
},
{
]);
//
const columns = computed(() => {
if (!tableData.value || tableData.value.length === 0) {
return [...defaultColumns.value, {
title: t("energy.subtotal"),
key: "subtotal",
}];
}
]);
//
const dynamicColumns = [...defaultColumns.value];
// data
const firstDataItem = tableData.value[0];
if (firstDataItem && firstDataItem.data) {
// data
firstDataItem.data.forEach((item, index) => {
// 使 dayjs format
const formattedTime = dayjs(item.time).format("MM-DD");
dynamicColumns.push({
title: formattedTime,
key: `data[${index}].value`,
});
});
}
dynamicColumns.push({
title: t("energy.subtotal"),
key: "subtotal",
});
return dynamicColumns;
});
// 調 subtotal
const dataSource = computed(() => {
if(!tableData.value || tableData.value.length === 0) return [];
return tableData.value.map(item => {
let subtotalValue = 0;
if(item.data && item.data.length > 0) {
item.data.forEach((dataItem) => {
subtotalValue += parseFloat(dataItem.value || 0);
});
}
return {
...item,
subtotal: subtotalValue.toFixed(2)
}
})
})
</script>
<template>
<Table :columns="columns" :dataSource="tableData" :loading="loading"></Table>
<Table :columns="columns" :dataSource="dataSource" :loading="loading"></Table>
</template>
<style lang="scss" scoped></style>

View File

@ -157,12 +157,17 @@ const updateCurrentFloor = (floor) => {
const realtimeData = ref([])
const timeId = ref(null)
const getAllDeviceRealtime = () => {
timeId.value = setInterval(async () => {
const res = await getSystemRealTime(subscribeData.value.map(d => d.device_number))
console.log(res.data)
realtimeData.value = res.data
}, 10000)
const getAllDeviceRealtime = async () => {
//
const fetchData = async () => {
const res = await getSystemRealTime(subscribeData.value.map(d => d.device_number));
console.log(res.data);
realtimeData.value = res.data;
};
await fetchData(); //
// 10
timeId.value = setInterval(fetchData, 10000);
}
watch(subscribeData, (newValue) => {
@ -207,8 +212,6 @@ const getCurrentInfoModalData = async (e, position, value) => {
};
}
const immediateRes = await getSystemRealTime([value.device_number]);
realtimeData.value = immediateRes.data;
}
const mobile = isMobile(e);
selectedDevice.value = {

View File

@ -1,14 +1,16 @@
<script setup>
import { useRoute } from 'vue-router';
import { useRoute } from "vue-router";
import EffectScatter from "@/components/chart/EffectScatter.vue";
import { computed, inject, ref, watch } from 'vue';
import { twMerge } from 'tailwind-merge';
import useSelectedFloor from "@/hooks/useSelectedFloor"
import { computed, inject, ref, watch } from "vue";
import { twMerge } from "tailwind-merge";
import useSelectedFloor from "@/hooks/useSelectedFloor";
const route = useRoute()
const route = useRoute();
const { currentFloor, subscribeData } = inject("system_deviceList")
const { getCurrentInfoModalData } = inject("system_selectedDevice")
const { currentFloor, subscribeData } = inject("system_deviceList");
const { getCurrentInfoModalData, selected_dbid } = inject(
"system_selectedDevice"
);
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const asset_floor_chart = ref(null);
@ -19,7 +21,7 @@ const sameOption = {
encode: {
tooltip: 2,
},
}
};
const defaultOption = (map, data = []) => {
return {
animation: false,
@ -36,7 +38,7 @@ const defaultOption = (map, data = []) => {
...sameOption,
symbolSize: 10,
itemStyle: {
color: data?.[0]?.[3]?.device_normal_color || "#009100",
color: data?.[0]?.[2]?.device_normal_color || "#009100",
},
data,
},
@ -44,85 +46,141 @@ const defaultOption = (map, data = []) => {
...sameOption,
symbolSize: 20,
itemStyle: {
color: data?.[0]?.[3]?.device_normal_color || "#009100",
color: data?.[0]?.[2]?.device_normal_color || "#009100",
},
data: [],
}
},
],
}
};
};
const { selectedFloor } = useSelectedFloor()
const { selectedFloor } = useSelectedFloor();
const allData = ref([])
const allData = ref([]);
const selectedData = ref([]);
watch(
[selectedFloor, () => asset_floor_chart],
([newValue, newChart], [oldValue]) => {
if (
newValue &&
newChart.value &&
oldValue?.key !== newValue.key &&
newValue.map_url
) {
selectedData.value =
subscribeData.value
?.filter(
(d) => d.device_coordinate && d.floor_guid === route.params.floor_id
)
.map((d) => [...d.device_coordinate.slice(1, -1).split(","), d]) ||
[];
watch([selectedFloor, () => asset_floor_chart,], ([newValue, newChart], [oldValue]) => {
if (newValue && newChart.value && oldValue?.key !== newValue.key && newValue.map_url) {
asset_floor_chart.value.updateSvg(
{
full_name: newValue?.title,
path: `${FILE_BASEURL}/${newValue.map_url}`,
},
defaultOption(newValue?.title, subscribeData.value?.filter(d => d.device_coordinate && d.floor_guid === route.params.floor_id).map(d => [...d.device_coordinate.split(","), d]) || [])
defaultOption(newValue?.title, selectedData.value)
);
newChart.value.chart.on("click", function (params) {
console.log(params, params.data[2])
getCurrentInfoModalData(params.event, {
left: params.event.offsetX
, top: params.event.offsetY
}, params.data[2])
let values = [...subscribeData.value].map(d => ({ ...d, is2DActive: d.forge_dbid === params.data[2].forge_dbid }))
subscribeData.value = values;
const selected = allData.value.filter((d => d[2].device_number === params.data[2].device_number))
const unSelected = allData.value.filter((d => d[2].device_number !== params.data[2].device_number))
newChart.value.chart.setOption({
series: [
{ data: unSelected }, {
data: selected,
}
]
})
getCurrentInfoModalData(
params.event,
{
left: params.event.offsetX,
top: params.event.offsetY,
},
params.data[2]
);
selected_dbid.value[0] = params.data[2].forge_dbid;
});
}
}, {
},
{
immediate: true,
deep: true,
})
}
);
watch(subscribeData, (newData) => {
let values = newData?.filter(d => d.device_coordinate && d.floor_guid === route.params.floor_id).map(d => [...d.device_coordinate.split(","), d])
watch(
subscribeData,
(newData) => {
let values = newData
?.filter(
(d) => d.device_coordinate && d.floor_guid === route.params.floor_id
)
.map((d) => [...d.device_coordinate.slice(1, -1).split(","), d]);
allData.value = values;
if (selectedFloor.value && asset_floor_chart.value && asset_floor_chart.value.chart) {
const selected = allData.value.filter((d => d[2].is2DActive))
const unSelected = allData.value.filter((d => !d[2].is2DActive))
selectedData.value = newData
?.filter((d) => d.device_coordinate)
.map((d) => [...d.device_coordinate.slice(1, -1).split(","), d]);
if (
selectedFloor.value &&
asset_floor_chart.value &&
asset_floor_chart.value.chart
) {
const selected = allData.value.filter((d) => d[2].is2DActive);
const unSelected = allData.value.filter((d) => !d[2].is2DActive);
asset_floor_chart.value.chart.setOption({
series: [
{ data: unSelected }, {
{ data: unSelected },
{
data: selected,
},
],
});
}
]
})
console.log(asset_floor_chart.value.chart.getOption())
}
}, {
immediate: true,
},
{
deep: true,
})
}
);
watch(
selected_dbid,
(newSelectedDbid) => {
if (
asset_floor_chart.value &&
asset_floor_chart.value.chart &&
allData.value
) {
selectedData.value = selectedData.value.map((item) => {
if (item[2].forge_dbid === newSelectedDbid[0]) {
return [...item.slice(0, 2), { ...item[2], is2DActive: true }];
}
return [...item.slice(0, 2), { ...item[2], is2DActive: false }];
});
const selected = selectedData.value.filter((d) => d[2].is2DActive);
const unSelected = selectedData.value.filter((d) => !d[2].is2DActive);
console.log("allData.value", allData.value, selected, unSelected);
asset_floor_chart.value.chart.setOption({
series: [
{ data: unSelected },
{
data: selected,
},
],
});
}
},
{
deep: true,
}
);
</script>
<template>
<!-- <Loading class="absolute" /> -->
<EffectScatter id="system_floor_chart" ref="asset_floor_chart" class="min-h-full bg-white" />
<EffectScatter
id="system_floor_chart"
ref="asset_floor_chart"
class="min-h-full bg-white"
/>
<!-- <div class="text-lg" v-if="!currentFloor?.key">尚未上傳樓層平面圖</div> -->
</template>
<style lang='scss' scoped></style>
<style lang="scss" scoped></style>

View File

@ -10,10 +10,6 @@ const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const fitToView = (forge_dbid, spriteDbId) => {
selected_dbid.value = [forge_dbid, spriteDbId];
console.log(subscribeData.value)
let allData = [...subscribeData.value].map(d => ({ ...d, is2DActive: d.forge_dbid === forge_dbid }))
subscribeData.value = allData;
};
</script>