|
@@ -37,6 +37,8 @@ import type {
|
|
CoolingHistoryDataResult,
|
|
CoolingHistoryDataResult,
|
|
CoolingRealTimeDataResult,
|
|
CoolingRealTimeDataResult,
|
|
CoolingStatisticsResult,
|
|
CoolingStatisticsResult,
|
|
|
|
+ DevGroupTabCompProps,
|
|
|
|
+ RangeValue,
|
|
} from '@/types';
|
|
} from '@/types';
|
|
|
|
|
|
use([
|
|
use([
|
|
@@ -63,9 +65,11 @@ type EChartsOption = ComposeOption<
|
|
| PieSeriesOption
|
|
| PieSeriesOption
|
|
>;
|
|
>;
|
|
|
|
|
|
|
|
+const props = defineProps<DevGroupTabCompProps>();
|
|
|
|
+
|
|
const deviceTypes = [DeviceType.冷水主机, DeviceType.冷却塔, DeviceType.冷却泵, DeviceType.冷冻泵];
|
|
const deviceTypes = [DeviceType.冷水主机, DeviceType.冷却塔, DeviceType.冷却泵, DeviceType.冷冻泵];
|
|
|
|
|
|
-const { handleRequest } = useRequest();
|
|
|
|
|
|
+const { isLoading, handleRequest } = useRequest();
|
|
const coolingRTDResult = ref<CoolingRealTimeDataResult>();
|
|
const coolingRTDResult = ref<CoolingRealTimeDataResult>();
|
|
let coolingRTDTimer: number | undefined;
|
|
let coolingRTDTimer: number | undefined;
|
|
|
|
|
|
@@ -76,7 +80,7 @@ const getCoolingRTDResult = () => {
|
|
const now = dayjs();
|
|
const now = dayjs();
|
|
|
|
|
|
coolingRTDResult.value = await getCoolingRealTimeData({
|
|
coolingRTDResult.value = await getCoolingRealTimeData({
|
|
- deviceGroupId: 7,
|
|
|
|
|
|
+ deviceGroupId: props.deviceGroupId,
|
|
startTime: now.startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
|
startTime: now.startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
|
endTime: now.endOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
|
endTime: now.endOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
|
});
|
|
});
|
|
@@ -85,15 +89,19 @@ const getCoolingRTDResult = () => {
|
|
coolingRTDTimer = window.setTimeout(getCoolingRTDResult, 3600 * 1000);
|
|
coolingRTDTimer = window.setTimeout(getCoolingRTDResult, 3600 * 1000);
|
|
};
|
|
};
|
|
|
|
|
|
-const { handleRequest: handleCoolingHisDataRequest } = useRequest();
|
|
|
|
|
|
+const { isLoading: isCoolingHisDataLoading, handleRequest: handleCoolingHisDataRequest } = useRequest();
|
|
const { visible, showView } = useViewVisible();
|
|
const { visible, showView } = useViewVisible();
|
|
-const coolingHisResult = ref<CoolingHistoryDataResult[]>([]);
|
|
|
|
|
|
+const coolingHisResult = ref<CoolingHistoryDataResult>();
|
|
|
|
+let coolingHisTimeRange: Dayjs[] = [];
|
|
|
|
+
|
|
|
|
+const handleCoolingHisTimeChange = (range: RangeValue) => {
|
|
|
|
+ coolingHisTimeRange = range;
|
|
|
|
+ getCoolingHisData();
|
|
|
|
+};
|
|
|
|
|
|
watch(visible, () => {
|
|
watch(visible, () => {
|
|
- if (visible.value) {
|
|
|
|
- getCoolingHisData();
|
|
|
|
- } else {
|
|
|
|
- coolingHisResult.value = [];
|
|
|
|
|
|
+ if (!visible.value) {
|
|
|
|
+ coolingHisResult.value = undefined;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
@@ -105,10 +113,10 @@ const viewCoolingHisData = (energyCard: CoolingEnergyCardItem) => {
|
|
const getCoolingHisData = () => {
|
|
const getCoolingHisData = () => {
|
|
handleCoolingHisDataRequest(async () => {
|
|
handleCoolingHisDataRequest(async () => {
|
|
coolingHisResult.value = await getCoolingHistoryData({
|
|
coolingHisResult.value = await getCoolingHistoryData({
|
|
- deviceGroupId: 7,
|
|
|
|
|
|
+ deviceGroupId: props.deviceGroupId,
|
|
deviceTypes,
|
|
deviceTypes,
|
|
- startTime: '2025-04-01 00:00:00',
|
|
|
|
- endTime: '2025-05-01 23:00:00',
|
|
|
|
|
|
+ startTime: coolingHisTimeRange[0].format('YYYY-MM-DD HH:mm:ss'),
|
|
|
|
+ endTime: coolingHisTimeRange[1].format('YYYY-MM-DD HH:mm:ss'),
|
|
type: selectedEnergyCard.value?.type as CoolingDataType,
|
|
type: selectedEnergyCard.value?.type as CoolingDataType,
|
|
});
|
|
});
|
|
});
|
|
});
|
|
@@ -116,17 +124,19 @@ const getCoolingHisData = () => {
|
|
|
|
|
|
const coolingHisDataOption = computed<EChartsOption>(() => {
|
|
const coolingHisDataOption = computed<EChartsOption>(() => {
|
|
const unitText = selectedEnergyCard.value?.unit ?? '-';
|
|
const unitText = selectedEnergyCard.value?.unit ?? '-';
|
|
- const legendData = coolingHisResult.value.map((device) => device.deviceTypeName);
|
|
|
|
|
|
+ const timeScaleType = coolingHisResult.value?.timeScale;
|
|
|
|
+ const historyData = coolingHisResult.value?.data || [];
|
|
|
|
+ const legendData = historyData.map((device) => device.deviceTypeName);
|
|
|
|
|
|
const allTimesSet = new Set<string>();
|
|
const allTimesSet = new Set<string>();
|
|
|
|
|
|
- coolingHisResult.value.forEach((device) => {
|
|
|
|
|
|
+ historyData.forEach((device) => {
|
|
device.data.forEach((point) => allTimesSet.add(point.time));
|
|
device.data.forEach((point) => allTimesSet.add(point.time));
|
|
});
|
|
});
|
|
|
|
|
|
const times: string[] = Array.from(allTimesSet).sort(timeSorter);
|
|
const times: string[] = Array.from(allTimesSet).sort(timeSorter);
|
|
|
|
|
|
- const seriesData = coolingHisResult.value.map<LineSeriesOption>((device) => {
|
|
|
|
|
|
+ const seriesData = historyData.map<LineSeriesOption>((device) => {
|
|
const valueKey = Object.keys(device.data[0] ?? {}).find((key) => key !== 'time');
|
|
const valueKey = Object.keys(device.data[0] ?? {}).find((key) => key !== 'time');
|
|
const timeMap: Record<string, string | number> = {};
|
|
const timeMap: Record<string, string | number> = {};
|
|
|
|
|
|
@@ -163,7 +173,7 @@ const coolingHisDataOption = computed<EChartsOption>(() => {
|
|
formatter(params) {
|
|
formatter(params) {
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const tempParms = params as any[];
|
|
const tempParms = params as any[];
|
|
- const time = dayjs(tempParms[0].axisValue).format('MM-DD HH:mm');
|
|
|
|
|
|
+ const time = formatTimeByScale(tempParms[0].axisValue, timeScaleType);
|
|
|
|
|
|
let tableHtml = '<table class="echarts-tooltip-electricity">';
|
|
let tableHtml = '<table class="echarts-tooltip-electricity">';
|
|
tableHtml += `<tr><th>${time}</th></tr>`;
|
|
tableHtml += `<tr><th>${time}</th></tr>`;
|
|
@@ -201,7 +211,7 @@ const coolingHisDataOption = computed<EChartsOption>(() => {
|
|
color: '#999',
|
|
color: '#999',
|
|
fontSize: 10,
|
|
fontSize: 10,
|
|
formatter(value) {
|
|
formatter(value) {
|
|
- return dayjs(value).format('MM-DD HH:mm');
|
|
|
|
|
|
+ return formatTimeByScale(value, timeScaleType);
|
|
},
|
|
},
|
|
},
|
|
},
|
|
axisTick: {
|
|
axisTick: {
|
|
@@ -236,22 +246,28 @@ const coolingHisDataOption = computed<EChartsOption>(() => {
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
getCoolingRTDResult();
|
|
getCoolingRTDResult();
|
|
- getEnergyConsumeResult();
|
|
|
|
});
|
|
});
|
|
|
|
|
|
onUnmounted(() => {
|
|
onUnmounted(() => {
|
|
clearTimeout(coolingRTDTimer);
|
|
clearTimeout(coolingRTDTimer);
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+const { isLoading: isEfficiencyLoading, handleRequest: handleEfficiencyRequest } = useRequest();
|
|
const energyEfficiencyResult = ref<CoolingStatisticsResult>();
|
|
const energyEfficiencyResult = ref<CoolingStatisticsResult>();
|
|
|
|
+let efficiencyTimeRange: Dayjs[] = [];
|
|
|
|
|
|
-const getEnergyConsumeResult = () => {
|
|
|
|
- handleRequest(async () => {
|
|
|
|
|
|
+const handleEfficiencyTimeChange = (range: RangeValue) => {
|
|
|
|
+ efficiencyTimeRange = range;
|
|
|
|
+ getEnergyEfficiencyResult();
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const getEnergyEfficiencyResult = () => {
|
|
|
|
+ handleEfficiencyRequest(async () => {
|
|
energyEfficiencyResult.value = await getCoolingDataStatistics({
|
|
energyEfficiencyResult.value = await getCoolingDataStatistics({
|
|
- deviceGroupId: 7,
|
|
|
|
|
|
+ deviceGroupId: props.deviceGroupId,
|
|
deviceTypes,
|
|
deviceTypes,
|
|
- startTime: '2025-04-16 00:00:00',
|
|
|
|
- endTime: '2025-04-16 23:00:00',
|
|
|
|
|
|
+ startTime: efficiencyTimeRange[0].format('YYYY-MM-DD HH:mm:ss'),
|
|
|
|
+ endTime: efficiencyTimeRange[1].format('YYYY-MM-DD HH:mm:ss'),
|
|
});
|
|
});
|
|
|
|
|
|
energyEfficiencyResult.value.hisQueryVos.forEach((item) => {
|
|
energyEfficiencyResult.value.hisQueryVos.forEach((item) => {
|
|
@@ -900,90 +916,95 @@ const lineOption = computed<EChartsOption>(() => {
|
|
const exportData = async () => {
|
|
const exportData = async () => {
|
|
const fileName = t('energyAnalysis.energyEfficiencyAnalysis') + ' - ' + dayjs().format('YYYYMMDDHHmmss');
|
|
const fileName = t('energyAnalysis.energyEfficiencyAnalysis') + ' - ' + dayjs().format('YYYYMMDDHHmmss');
|
|
const file = await downloadCoolingHisData({
|
|
const file = await downloadCoolingHisData({
|
|
- deviceGroupId: 7,
|
|
|
|
|
|
+ deviceGroupId: props.deviceGroupId,
|
|
deviceTypes,
|
|
deviceTypes,
|
|
- startTime: '2025-04-01 00:00:00',
|
|
|
|
- endTime: '2025-05-01 23:00:00',
|
|
|
|
|
|
+ startTime: efficiencyTimeRange[0].format('YYYY-MM-DD HH:mm:ss'),
|
|
|
|
+ endTime: efficiencyTimeRange[1].format('YYYY-MM-DD HH:mm:ss'),
|
|
});
|
|
});
|
|
|
|
|
|
downloadBlob(file, fileName);
|
|
downloadBlob(file, fileName);
|
|
};
|
|
};
|
|
-
|
|
|
|
-const handleTimeChange = (range: [Dayjs, Dayjs]) => {
|
|
|
|
- console.log(range[0].format('YYYY-MM-DD HH:mm:ss'), range[1].format('YYYY-MM-DD HH:mm:ss'));
|
|
|
|
-};
|
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<template>
|
|
<template>
|
|
- <ACard :title="$t('energyAnalysis.realTimeValue')" :bordered="false">
|
|
|
|
- <ARow class="energy-card-list" :gutter="[24, 24]">
|
|
|
|
- <ACol v-for="(item, index) in energyCardList" :key="index" :xs="24" :sm="24" :md="12" :lg="12" :xl="6" :xxl="6">
|
|
|
|
- <div
|
|
|
|
- class="energy-card-container"
|
|
|
|
- :style="{
|
|
|
|
- backgroundColor: item.bgColor,
|
|
|
|
- }"
|
|
|
|
- @click="viewCoolingHisData(item)"
|
|
|
|
- >
|
|
|
|
- <img class="energy-card-icon" :src="item.icon" />
|
|
|
|
- <div>
|
|
|
|
- <div class="energy-card-title">
|
|
|
|
- <span class="energy-card-value">{{ item.value }}</span>
|
|
|
|
- <span class="energy-card-unit">{{ item.unit }}</span>
|
|
|
|
|
|
+ <ASpin :spinning="isLoading">
|
|
|
|
+ <ACard class="real-time-card" :title="$t('energyAnalysis.realTimeValue')" :bordered="false">
|
|
|
|
+ <ARow class="energy-card-list" :gutter="[24, 24]">
|
|
|
|
+ <ACol v-for="(item, index) in energyCardList" :key="index" :xs="24" :sm="24" :md="12" :lg="12" :xl="6" :xxl="6">
|
|
|
|
+ <div
|
|
|
|
+ class="energy-card-container"
|
|
|
|
+ :style="{
|
|
|
|
+ backgroundColor: item.bgColor,
|
|
|
|
+ }"
|
|
|
|
+ @click="viewCoolingHisData(item)"
|
|
|
|
+ >
|
|
|
|
+ <img class="energy-card-icon" :src="item.icon" />
|
|
|
|
+ <div>
|
|
|
|
+ <div class="energy-card-title">
|
|
|
|
+ <span class="energy-card-value">{{ item.value }}</span>
|
|
|
|
+ <span class="energy-card-unit">{{ item.unit }}</span>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="energy-card-description">{{ item.description }}</div>
|
|
</div>
|
|
</div>
|
|
- <div class="energy-card-description">{{ item.description }}</div>
|
|
|
|
</div>
|
|
</div>
|
|
- </div>
|
|
|
|
- </ACol>
|
|
|
|
- </ARow>
|
|
|
|
- </ACard>
|
|
|
|
- <ACard :title="$t('energyAnalysis.coolingStationEfficiency')" :bordered="false">
|
|
|
|
- <template #extra>
|
|
|
|
- <TimeRangeSelect @change="handleTimeChange" />
|
|
|
|
- <AButton class="export-button" @click="exportData">{{ $t('common.export') }}</AButton>
|
|
|
|
- </template>
|
|
|
|
- <div class="chart-container">
|
|
|
|
- <div class="chart-wrapper chart-pie">
|
|
|
|
- <div class="chart-pie-title">{{ $t('energyAnalysis.subItemEnergyEfficiency') }}</div>
|
|
|
|
- <VChart class="chart" :option="gaugeOption" autoresize />
|
|
|
|
- <!-- <div class="chart-pie-level">
|
|
|
|
|
|
+ </ACol>
|
|
|
|
+ </ARow>
|
|
|
|
+ </ACard>
|
|
|
|
+ </ASpin>
|
|
|
|
+ <ASpin :spinning="isEfficiencyLoading">
|
|
|
|
+ <ACard :title="$t('energyAnalysis.coolingStationEfficiency')" :bordered="false">
|
|
|
|
+ <template #extra>
|
|
|
|
+ <TimeRangeSelect @change="handleEfficiencyTimeChange" />
|
|
|
|
+ <AButton class="export-button" @click="exportData">{{ $t('common.export') }}</AButton>
|
|
|
|
+ </template>
|
|
|
|
+ <div class="chart-container">
|
|
|
|
+ <div class="chart-wrapper chart-pie">
|
|
|
|
+ <div class="chart-pie-title">{{ $t('energyAnalysis.subItemEnergyEfficiency') }}</div>
|
|
|
|
+ <VChart class="chart" :option="gaugeOption" autoresize />
|
|
|
|
+ <!-- <div class="chart-pie-level">
|
|
<span>中等</span>
|
|
<span>中等</span>
|
|
</div> -->
|
|
</div> -->
|
|
- <ARow class="sub-efficiency-container" :gutter="[24, 8]">
|
|
|
|
- <ACol v-for="(item, index) in subItemEfficiency" :key="index" :span="12">
|
|
|
|
- <div class="sub-efficiency-item">
|
|
|
|
- <div :style="{ backgroundColor: item.color }"></div>
|
|
|
|
- <span>{{ item.label }}: {{ item.value }}</span>
|
|
|
|
- </div>
|
|
|
|
- </ACol>
|
|
|
|
- </ARow>
|
|
|
|
- </div>
|
|
|
|
- <div class="chart-wrapper chart-line">
|
|
|
|
- <VChart class="chart" :option="energyEfficiencyLineOption" autoresize />
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </ACard>
|
|
|
|
- <ACard :title="$t('energyAnalysis.coolingPricePerUnit')" :bordered="false">
|
|
|
|
- <div class="chart-container">
|
|
|
|
- <div class="chart-wrapper chart-pie">
|
|
|
|
- <div class="chart-pie-title">
|
|
|
|
- {{ $t('energyAnalysis.cumulativeCoolingCapacity') }}(GJ):
|
|
|
|
- {{ energyEfficiencyResult?.totalCoolingData ?? '-' }}
|
|
|
|
|
|
+ <ARow class="sub-efficiency-container" :gutter="[24, 8]">
|
|
|
|
+ <ACol v-for="(item, index) in subItemEfficiency" :key="index" :span="12">
|
|
|
|
+ <div class="sub-efficiency-item">
|
|
|
|
+ <div :style="{ backgroundColor: item.color }"></div>
|
|
|
|
+ <span>{{ item.label }}: {{ item.value }}</span>
|
|
|
|
+ </div>
|
|
|
|
+ </ACol>
|
|
|
|
+ </ARow>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="chart-wrapper chart-line">
|
|
|
|
+ <VChart class="chart" :option="energyEfficiencyLineOption" autoresize />
|
|
</div>
|
|
</div>
|
|
- <VChart class="chart" :option="pieOption" autoresize />
|
|
|
|
</div>
|
|
</div>
|
|
- <div class="chart-wrapper chart-line">
|
|
|
|
- <VChart class="chart" :option="lineOption" autoresize />
|
|
|
|
|
|
+ </ACard>
|
|
|
|
+ <ACard :title="$t('energyAnalysis.coolingPricePerUnit')" :bordered="false">
|
|
|
|
+ <div class="chart-container">
|
|
|
|
+ <div class="chart-wrapper chart-pie">
|
|
|
|
+ <div class="chart-pie-title">
|
|
|
|
+ {{ $t('energyAnalysis.cumulativeCoolingCapacity') }}(GJ):
|
|
|
|
+ {{ energyEfficiencyResult?.totalCoolingData ?? '-' }}
|
|
|
|
+ </div>
|
|
|
|
+ <VChart class="chart" :option="pieOption" autoresize />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="chart-wrapper chart-line">
|
|
|
|
+ <VChart class="chart" :option="lineOption" autoresize />
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
- </div>
|
|
|
|
- </ACard>
|
|
|
|
- <AModal v-model:open="visible" :title="$t('deviceWorkStatus.viewData')" :width="920" :footer="null">
|
|
|
|
- <TimeRangeSelect class="cooling-history-select" is-last />
|
|
|
|
|
|
+ </ACard>
|
|
|
|
+ </ASpin>
|
|
|
|
+ <AModal v-model:open="visible" :title="$t('deviceWorkStatus.viewData')" :width="920" :footer="null" destroy-on-close>
|
|
|
|
+ <ASpin class="center-loading" :spinning="isCoolingHisDataLoading" />
|
|
|
|
+ <TimeRangeSelect class="cooling-history-select" @change="handleCoolingHisTimeChange" />
|
|
<VChart class="cooling-history-chart" :option="coolingHisDataOption" autoresize />
|
|
<VChart class="cooling-history-chart" :option="coolingHisDataOption" autoresize />
|
|
</AModal>
|
|
</AModal>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
|
|
+.real-time-card {
|
|
|
|
+ margin-bottom: 16px;
|
|
|
|
+}
|
|
|
|
+
|
|
.energy-card-container {
|
|
.energy-card-container {
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
}
|
|
}
|