<template>
|
<div class="app-container">
|
<!-- 搜索区域 -->
|
<div class="search_form">
|
<el-form :model="searchForm"
|
:inline="true">
|
<el-form-item label="统计维度:">
|
<el-radio-group v-model="statisticsType"
|
@change="handleTypeChange">
|
<el-radio-button label="day">按日统计</el-radio-button>
|
<el-radio-button label="month">按月统计</el-radio-button>
|
<el-radio-button label="year">按年统计</el-radio-button>
|
</el-radio-group>
|
</el-form-item>
|
<!-- <el-form-item label="能耗类型:">
|
<el-select v-model="searchForm.energyType"
|
placeholder="全部"
|
clearable
|
style="width: 120px;"
|
@change="handleQuery">
|
<el-option label="全部"
|
value="全部" />
|
<el-option label="水"
|
value="水" />
|
<el-option label="电"
|
value="电" />
|
<el-option label="蒸汽"
|
value="蒸汽" />
|
</el-select>
|
</el-form-item> -->
|
<el-form-item label="时间范围:">
|
<el-date-picker v-if="statisticsType === 'day'"
|
v-model="searchForm.dateRange"
|
type="daterange"
|
range-separator="至"
|
start-placeholder="开始日期"
|
end-placeholder="结束日期"
|
value-format="YYYY-MM-DD"
|
style="width: 240px;"
|
@change="handleQuery" />
|
<el-date-picker v-else-if="statisticsType === 'month'"
|
v-model="searchForm.monthRange"
|
type="monthrange"
|
range-separator="至"
|
start-placeholder="开始月份"
|
end-placeholder="结束月份"
|
value-format="YYYY-MM"
|
style="width: 240px;"
|
@change="handleQuery" />
|
<el-select v-else
|
v-model="searchForm.year"
|
placeholder="选择年份"
|
style="width: 140px;"
|
@change="handleQuery">
|
<el-option v-for="year in yearOptions"
|
:key="year"
|
:label="year + '年'"
|
:value="year" />
|
</el-select>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary"
|
@click="handleQuery">查询</el-button>
|
<el-button @click="handleReset">重置</el-button>
|
</el-form-item>
|
</el-form>
|
<div>
|
<el-button type="success"
|
@click="handleExport">导出报表</el-button>
|
</div>
|
</div>
|
<!-- 图表区域 -->
|
<div class="chart-section">
|
<h2 class="section-header">
|
<el-icon class="header-icon">
|
<TrendCharts />
|
</el-icon>
|
能耗单耗趋势
|
</h2>
|
<div class="chart-card">
|
<div ref="consumptionChart"
|
class="chart-content"></div>
|
</div>
|
</div>
|
<!-- 数据表格 -->
|
<div class="table-section">
|
<h2 class="section-header">
|
<el-icon class="header-icon">
|
<List />
|
</el-icon>
|
能耗单耗数据
|
</h2>
|
<el-table :data="tableValue"
|
v-loading="tableLoading"
|
border>
|
<el-table-column prop="meterReadingDate"
|
label="日期"
|
align="center" />
|
<!-- <el-table-column prop="type"
|
label="类型"
|
align="center"
|
width="100">
|
<template #default="scope">
|
<el-tag :type="scope.row.type === '生产' ? 'primary' : 'success'">
|
{{ scope.row.type }}
|
</el-tag>
|
</template>
|
</el-table-column> -->
|
<el-table-column prop="energyTyep"
|
label="能耗类型"
|
align="center">
|
<template #default="scope">
|
<el-tag :type="getEnergyTypeType(scope.row.type)">
|
{{ scope.row.type }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column prop="consumption"
|
label="用量"
|
align="right" />
|
<el-table-column prop="cost"
|
label="成本"
|
align="right">
|
<template #default="scope">
|
<span class="data-value">¥{{ scope.row.cost }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="unitConsumption"
|
label="单耗"
|
align="right">
|
<template #default="scope">
|
<span class="data-value">{{ scope.row.unitConsumption }}</span>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted, nextTick } from "vue";
|
import { ElMessage } from "element-plus";
|
import { TrendCharts, List } from "@element-plus/icons-vue";
|
import * as echarts from "echarts";
|
import { energyConsumptionDetailStatistics } from "@/api/energyManagement/energyType";
|
|
// 统计维度
|
const statisticsType = ref("day");
|
|
// 搜索表单
|
const searchForm = reactive({
|
energyType: "",
|
dateRange: null,
|
monthRange: null,
|
year: new Date().getFullYear(),
|
});
|
|
// 生成年份选项(最近7年)
|
const yearOptions = [];
|
const currentYear = new Date().getFullYear();
|
for (let i = currentYear - 6; i <= currentYear; i++) {
|
yearOptions.push(i);
|
}
|
|
// 处理统计维度变化
|
const handleTypeChange = () => {
|
// 重置时间选择
|
if (statisticsType.value === "day") {
|
// 设置默认日期范围为最近30天
|
const end = new Date();
|
const start = new Date();
|
start.setDate(start.getDate() - 29);
|
searchForm.dateRange = [
|
`${start.getFullYear()}-${String(start.getMonth() + 1).padStart(
|
2,
|
"0"
|
)}-${String(start.getDate()).padStart(2, "0")}`,
|
`${end.getFullYear()}-${String(end.getMonth() + 1).padStart(
|
2,
|
"0"
|
)}-${String(end.getDate()).padStart(2, "0")}`,
|
];
|
} else if (statisticsType.value === "month") {
|
// 设置默认月份范围为最近6个月
|
const end = new Date();
|
const start = new Date();
|
start.setMonth(start.getMonth() - 5);
|
searchForm.monthRange = [
|
`${start.getFullYear()}-${String(start.getMonth() + 1).padStart(2, "0")}`,
|
`${end.getFullYear()}-${String(end.getMonth() + 1).padStart(2, "0")}`,
|
];
|
} else {
|
searchForm.year = currentYear;
|
}
|
handleQuery();
|
};
|
|
// 表格数据
|
const tableData = ref([]);
|
const tableLoading = ref(false);
|
|
// 图表引用
|
const consumptionChart = ref(null);
|
let consumptionChartInstance = null;
|
|
// 获取能耗类型标签类型
|
const getEnergyTypeType = type => {
|
const typeMap = {
|
水: "primary",
|
电: "warning",
|
蒸汽: "success",
|
};
|
return typeMap[type] || "info";
|
};
|
|
// 初始化图表
|
const initChart = () => {
|
nextTick(() => {
|
if (consumptionChart.value) {
|
consumptionChartInstance = echarts.init(consumptionChart.value);
|
updateChart();
|
}
|
});
|
};
|
|
// 更新图表
|
const updateChart = () => {
|
const data = tableData.value;
|
let xAxisData = [];
|
|
// 根据统计维度准备数据
|
if (statisticsType.value === "year") {
|
// 年度模式:12个月
|
xAxisData = [
|
"1月",
|
"2月",
|
"3月",
|
"4月",
|
"5月",
|
"6月",
|
"7月",
|
"8月",
|
"9月",
|
"10月",
|
"11月",
|
"12月",
|
];
|
} else if (statisticsType.value === "month") {
|
// 月度模式:根据选择的月份范围
|
if (searchForm.monthRange && searchForm.monthRange.length === 2) {
|
const startMonth = searchForm.monthRange[0];
|
const endMonth = searchForm.monthRange[1];
|
const [startYear, startMonthNum] = startMonth.split("-");
|
const [endYear, endMonthNum] = endMonth.split("-");
|
|
xAxisData = [];
|
let currentYear = parseInt(startYear);
|
let currentMonth = parseInt(startMonthNum);
|
const endYearInt = parseInt(endYear);
|
const endMonthInt = parseInt(endMonthNum);
|
|
while (
|
currentYear < endYearInt ||
|
(currentYear === endYearInt && currentMonth <= endMonthInt)
|
) {
|
xAxisData.push(
|
`${currentYear}-${String(currentMonth).padStart(2, "0")}`
|
);
|
currentMonth++;
|
if (currentMonth > 12) {
|
currentMonth = 1;
|
currentYear++;
|
}
|
}
|
} else {
|
// 默认显示最近6个月
|
xAxisData = [];
|
const end = new Date();
|
for (let i = 5; i >= 0; i--) {
|
const date = new Date();
|
date.setMonth(date.getMonth() - i);
|
xAxisData.push(
|
`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(
|
2,
|
"0"
|
)}`
|
);
|
}
|
}
|
} else {
|
// 按日统计:根据选择的日期范围
|
if (searchForm.dateRange && searchForm.dateRange.length === 2) {
|
const startDate = searchForm.dateRange[0];
|
const endDate = searchForm.dateRange[1];
|
|
xAxisData = [];
|
let currentDate = new Date(startDate);
|
const end = new Date(endDate);
|
|
while (currentDate <= end) {
|
xAxisData.push(
|
`${currentDate.getFullYear()}-${String(
|
currentDate.getMonth() + 1
|
).padStart(2, "0")}-${String(currentDate.getDate()).padStart(2, "0")}`
|
);
|
currentDate.setDate(currentDate.getDate() + 1);
|
}
|
} else {
|
// 默认显示最近30天
|
xAxisData = [];
|
const end = new Date();
|
for (let i = 29; i >= 0; i--) {
|
const date = new Date();
|
date.setDate(date.getDate() - i);
|
xAxisData.push(
|
`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(
|
2,
|
"0"
|
)}-${String(date.getDate()).padStart(2, "0")}`
|
);
|
}
|
}
|
}
|
|
// 提取所有唯一的meterReadingDate并排序
|
const allDates = [...new Set(data.map(item => item.meterReadingDate))].sort(
|
(a, b) => {
|
return new Date(a) - new Date(b);
|
}
|
);
|
// 使用实际的meterReadingDate作为横轴数据
|
xAxisData = allDates;
|
|
const option = {
|
tooltip: {
|
trigger: "axis",
|
backgroundColor: "rgba(255, 255, 255, 0.95)",
|
borderColor: "#409EFF",
|
borderWidth: 1,
|
textStyle: { color: "#303133" },
|
},
|
legend: {
|
data: ["单耗"],
|
top: 0,
|
right: 10,
|
textStyle: { color: "#606266" },
|
},
|
grid: {
|
left: "3%",
|
right: "4%",
|
bottom: "10%",
|
top: "15%",
|
containLabel: true,
|
},
|
xAxis: {
|
type: "category",
|
data: xAxisData,
|
axisLabel: {
|
color: "#606266",
|
rotate: statisticsType.value === "month" ? 45 : 0,
|
},
|
axisLine: { lineStyle: { color: "#ebeef5" } },
|
splitLine: { show: false },
|
},
|
yAxis: {
|
type: "value",
|
name: "单耗",
|
nameTextStyle: { color: "#606266" },
|
axisLabel: { color: "#606266" },
|
axisLine: { show: false },
|
splitLine: { lineStyle: { color: "#f0f2f5" } },
|
},
|
series: {
|
name: "单耗",
|
type: "line",
|
data: data.map(item => item.totalCost),
|
smooth: true,
|
symbol: "circle",
|
symbolSize: 8,
|
lineStyle: {
|
width: 3,
|
},
|
itemStyle: {
|
color: "#409EFF",
|
},
|
},
|
};
|
|
consumptionChartInstance.setOption(option);
|
};
|
const tableValue = ref([]);
|
|
// 查询
|
const handleQuery = () => {
|
tableLoading.value = true;
|
|
const params = {
|
type: "",
|
state:
|
statisticsType.value === "year"
|
? "年"
|
: statisticsType.value === "month"
|
? "月"
|
: "日",
|
};
|
|
if (searchForm.energyType && searchForm.energyType !== "全部") {
|
params.type = searchForm.energyType;
|
}
|
|
if (statisticsType.value === "year") {
|
params.startDate = searchForm.year + "-01-01";
|
params.endDate = searchForm.year + "-12-31";
|
// 计算天数
|
const start = new Date(params.startDate);
|
const end = new Date(params.endDate);
|
params.days = Math.ceil((end - start) / (1000 * 60 * 60 * 24)) + 1;
|
} else if (statisticsType.value === "month" && searchForm.monthRange) {
|
const [startMonth, endMonth] = searchForm.monthRange;
|
const [startYearStr, startMonthStr] = startMonth.split("-");
|
const [endYearStr, endMonthStr] = endMonth.split("-");
|
|
params.startDate = `${startYearStr}-${startMonthStr}-01`;
|
|
const endYear = Number(endYearStr);
|
const endMonthNum = Number(endMonthStr);
|
const lastDay = new Date(endYear, endMonthNum, 0).getDate();
|
params.endDate = `${endYearStr}-${endMonthStr}-${String(lastDay).padStart(
|
2,
|
"0"
|
)}`;
|
|
// 计算天数
|
const start = new Date(params.startDate);
|
const end = new Date(params.endDate);
|
params.days = Math.ceil((end - start) / (1000 * 60 * 60 * 24)) + 1;
|
} else if (statisticsType.value === "day" && searchForm.dateRange) {
|
params.startDate = searchForm.dateRange[0];
|
params.endDate = searchForm.dateRange[1];
|
// 计算天数
|
const start = new Date(params.startDate);
|
const end = new Date(params.endDate);
|
params.days = Math.ceil((end - start) / (1000 * 60 * 60 * 24)) + 1;
|
}
|
|
energyConsumptionDetailStatistics(params)
|
.then(res => {
|
if (res.code === 200) {
|
const data = res.data;
|
tableData.value = data.energyCostDtos || [];
|
tableValue.value = [];
|
tableData.value.forEach(item => {
|
tableValue.value.push({
|
meterReadingDate: item.meterReadingDate,
|
consumption: item.waterConsumption,
|
cost: item.waterCost,
|
type: "水",
|
});
|
tableValue.value.push({
|
consumption: item.electricityConsumption,
|
cost: item.electricityCost,
|
meterReadingDate: item.meterReadingDate,
|
type: "电",
|
});
|
tableValue.value.push({
|
consumption: item.gasConsumption,
|
cost: item.gasCost,
|
meterReadingDate: item.meterReadingDate,
|
type: "蒸汽",
|
});
|
});
|
updateChart();
|
} else {
|
ElMessage.error(res.message || "获取数据失败");
|
tableData.value = [];
|
}
|
})
|
.catch(err => {
|
console.error("获取数据异常:", err);
|
ElMessage.error("系统异常,获取数据失败");
|
tableData.value = [];
|
})
|
.finally(() => {
|
tableLoading.value = false;
|
});
|
};
|
|
// 重置
|
const handleReset = () => {
|
// 重置搜索表单
|
searchForm.energyType = "";
|
if (statisticsType.value === "day") {
|
// 设置默认日期范围为最近30天
|
const end = new Date();
|
const start = new Date();
|
start.setDate(start.getDate() - 29);
|
searchForm.dateRange = [
|
`${start.getFullYear()}-${String(start.getMonth() + 1).padStart(
|
2,
|
"0"
|
)}-${String(start.getDate()).padStart(2, "0")}`,
|
`${end.getFullYear()}-${String(end.getMonth() + 1).padStart(
|
2,
|
"0"
|
)}-${String(end.getDate()).padStart(2, "0")}`,
|
];
|
} else if (statisticsType.value === "month") {
|
// 设置默认月份范围为最近6个月
|
const end = new Date();
|
const start = new Date();
|
start.setMonth(start.getMonth() - 5);
|
searchForm.monthRange = [
|
`${start.getFullYear()}-${String(start.getMonth() + 1).padStart(2, "0")}`,
|
`${end.getFullYear()}-${String(end.getMonth() + 1).padStart(2, "0")}`,
|
];
|
} else {
|
searchForm.year = new Date().getFullYear();
|
}
|
handleQuery();
|
};
|
|
// 导出
|
const handleExport = () => {
|
ElMessage.success("报表导出成功");
|
};
|
|
// 窗口大小变化时重新渲染图表
|
const handleResize = () => {
|
consumptionChartInstance && consumptionChartInstance.resize();
|
};
|
|
onMounted(() => {
|
// 初始化时间范围
|
if (statisticsType.value === "day") {
|
// 设置默认日期范围为最近30天
|
const end = new Date();
|
const start = new Date();
|
start.setDate(start.getDate() - 29);
|
searchForm.dateRange = [
|
`${start.getFullYear()}-${String(start.getMonth() + 1).padStart(
|
2,
|
"0"
|
)}-${String(start.getDate()).padStart(2, "0")}`,
|
`${end.getFullYear()}-${String(end.getMonth() + 1).padStart(
|
2,
|
"0"
|
)}-${String(end.getDate()).padStart(2, "0")}`,
|
];
|
} else if (statisticsType.value === "month") {
|
// 设置默认月份范围为最近6个月
|
const end = new Date();
|
const start = new Date();
|
start.setMonth(start.getMonth() - 5);
|
searchForm.monthRange = [
|
`${start.getFullYear()}-${String(start.getMonth() + 1).padStart(2, "0")}`,
|
`${end.getFullYear()}-${String(end.getMonth() + 1).padStart(2, "0")}`,
|
];
|
}
|
handleQuery();
|
initChart();
|
window.addEventListener("resize", handleResize);
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.app-container {
|
padding: 20px;
|
}
|
|
.search_form {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 20px;
|
padding: 15px;
|
background-color: #f5f7fa;
|
border-radius: 8px;
|
}
|
|
.chart-section {
|
margin-bottom: 30px;
|
}
|
|
.table-section {
|
margin-bottom: 20px;
|
}
|
|
.section-header {
|
display: flex;
|
align-items: center;
|
font-size: 18px;
|
font-weight: bold;
|
color: #303133;
|
margin-bottom: 15px;
|
padding-left: 10px;
|
border-left: 3px solid #409eff;
|
|
.header-icon {
|
margin-right: 8px;
|
color: #409eff;
|
}
|
}
|
|
.chart-card {
|
background: #fff;
|
border-radius: 4px;
|
border: 1px solid #ebeef5;
|
padding: 20px;
|
|
.chart-content {
|
height: 400px;
|
}
|
}
|
|
.data-value {
|
font-weight: bold;
|
color: #409eff;
|
}
|
</style>
|