383 lines
10 KiB
Vue
383 lines
10 KiB
Vue
<template>
|
||
<div class="trends-container">
|
||
<!-- 月度能耗图表区域 -->
|
||
<el-row class="chart-group">
|
||
<el-col :span="24">
|
||
<div class="chart-header">
|
||
<h3>月度能耗趋势</h3>
|
||
<div class="chart-type-btn-group">
|
||
<el-button :type="monthChartType === 'bar' ? 'primary' : 'default'" @click="toggleMonthChartType('bar')"
|
||
:disabled="!hasMonthData">
|
||
柱状图
|
||
</el-button>
|
||
<el-button :type="monthChartType === 'line' ? 'primary' : 'default'" @click="toggleMonthChartType('line')"
|
||
:disabled="!hasMonthData">
|
||
折线图
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
<div class="chart-wrapper">
|
||
<div ref="monthChart" class="chart-container"></div>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<!-- 日度能耗图表区域 -->
|
||
<el-row class="chart-group">
|
||
<el-col :span="24">
|
||
<div class="chart-header">
|
||
<h3>日度能耗趋势</h3>
|
||
<div class="chart-type-btn-group">
|
||
<el-button :type="dayChartType === 'bar' ? 'primary' : 'default'" @click="toggleDayChartType('bar')"
|
||
:disabled="!hasDayData">
|
||
柱状图
|
||
</el-button>
|
||
<el-button :type="dayChartType === 'line' ? 'primary' : 'default'" @click="toggleDayChartType('line')"
|
||
:disabled="!hasDayData">
|
||
折线图
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
<div class="chart-wrapper">
|
||
<div ref="dayChart" class="chart-container"></div>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import * as echarts from 'echarts'
|
||
import { getRecentEnergySummary } from '@/api/ems/dashboard/timer'
|
||
|
||
export default {
|
||
name: 'RecentTrends',
|
||
data() {
|
||
return {
|
||
monthData: [], // 原始月度数据
|
||
dayData: [], // 原始日度数据
|
||
completedMonthData: [], // 补全后的月度数据
|
||
completedDayData: [], // 补全后的日度数据
|
||
monthChartType: 'bar',
|
||
dayChartType: 'bar',
|
||
monthChart: null,
|
||
dayChart: null,
|
||
hasMonthData: false, // 标记是否有月度数据
|
||
hasDayData: false // 标记是否有日度数据
|
||
}
|
||
},
|
||
props: {
|
||
unit: {
|
||
type: String,
|
||
required: true
|
||
},
|
||
energyName: {
|
||
type: String,
|
||
required: true
|
||
},
|
||
energyType: {
|
||
type: String,
|
||
required: true
|
||
},
|
||
locationId: {
|
||
type: String,
|
||
required: false
|
||
},
|
||
deviceId: {
|
||
type: String,
|
||
required: false
|
||
}
|
||
},
|
||
mounted() {
|
||
const dayChartDOM = this.$refs.dayChart
|
||
console.log(dayChartDOM, this.$refs)
|
||
if (!dayChartDOM) return
|
||
this.dayChart = echarts.init(dayChartDOM)
|
||
|
||
const monthChartDOM = this.$refs.monthChart
|
||
if (!monthChartDOM) return
|
||
this.monthChart = echarts.init(monthChartDOM)
|
||
this.fetchMonthData()
|
||
this.fetchDayData()
|
||
window.addEventListener('resize', this.handleWindowResize)
|
||
},
|
||
beforeDestroy() {
|
||
this.destroyCharts()
|
||
window.removeEventListener('resize', this.handleWindowResize)
|
||
},
|
||
methods: {
|
||
// 销毁图表实例
|
||
destroyCharts() {
|
||
if (this.monthChart) {
|
||
this.monthChart.dispose()
|
||
this.monthChart = null
|
||
}
|
||
if (this.dayChart) {
|
||
this.dayChart.dispose()
|
||
this.dayChart = null
|
||
}
|
||
},
|
||
|
||
// 数据请求
|
||
fetchMonthData() {
|
||
const year = new Date().getFullYear()
|
||
getRecentEnergySummary({ year, energyType: this.energyType, locationId: this.locationId, deviceId: this.deviceId })
|
||
.then(res => {
|
||
this.monthData = res.data || []
|
||
console.log(this.monthData)
|
||
// 检查是否有有效数据
|
||
this.hasMonthData = Array.isArray(this.monthData) && this.monthData.length > 0
|
||
|
||
this.completedMonthData = this.completeMonthData(this.monthData)
|
||
this.initMonthChart()
|
||
})
|
||
},
|
||
|
||
fetchDayData() {
|
||
const date = new Date()
|
||
const month = date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, '0')
|
||
getRecentEnergySummary({ month, energyType: this.energyType, locationId: this.locationId, deviceId: this.deviceId })
|
||
.then(res => {
|
||
this.dayData = res.data || []
|
||
console.log(this.dayData)
|
||
|
||
this.completedDayData = this.completeDayData(this.dayData)
|
||
this.initDayChart()
|
||
})
|
||
},
|
||
|
||
// 补全月度数据 - 固定显示12个月份(一整年)
|
||
completeMonthData(data) {
|
||
this.hasMonthData = Array.isArray(this.monthData) && this.monthData.length > 0
|
||
if (!this.hasMonthData) {
|
||
const result = []
|
||
for (let i = 0; i < 12; i++) {
|
||
result.push({ month: i + 1, totalConsumption: 0 })
|
||
}
|
||
return result
|
||
}
|
||
|
||
const result = []
|
||
|
||
for (let i = 0; i < 12; i++) {
|
||
// 查找data中month{year}-{month}中{month}为i+1的数据
|
||
const item = data.find(item => item.month?.split('-')[1].padStart(2, '0') == i + 1)
|
||
console.log(item, i + 1, data)
|
||
if (item) {
|
||
result.push(item)
|
||
} else {
|
||
result.push({ month: i + 1, totalConsumption: 0 })
|
||
}
|
||
}
|
||
|
||
return result
|
||
},
|
||
|
||
// 补全日度数据 - 按照当月实际天数补齐
|
||
completeDayData(data) {
|
||
this.hasDayData = Array.isArray(this.dayData) && this.dayData.length > 0
|
||
|
||
// 本月天数
|
||
const today = new Date()
|
||
const dayCount = new Date(today.getFullYear(), today.getMonth() + 1, 0).getDate()
|
||
if (!this.hasDayData) {
|
||
const result = []
|
||
for (let i = 0; i < dayCount; i++) {
|
||
result.push({ day: i + 1, totalConsumption: 0 })
|
||
}
|
||
return result
|
||
}
|
||
|
||
// 补全数据
|
||
const result = []
|
||
for (let i = 0; i < dayCount; i++) {
|
||
const item = data.find(item => item.day?.split('-')[2].padStart(2, '0') == i + 1)
|
||
if (item) {
|
||
result.push(item)
|
||
} else {
|
||
result.push({ day: i + 1, totalConsumption: 0 })
|
||
}
|
||
}
|
||
|
||
return result;
|
||
},
|
||
|
||
// 初始化月度图表
|
||
initMonthChart() {
|
||
if (!this.hasMonthData) return
|
||
|
||
console.log(this.completedMonthData)
|
||
const xData = this.completedMonthData.map(item => item.month)
|
||
const yData = this.completedMonthData.map(item => item.totalConsumption)
|
||
|
||
const option = {
|
||
tooltip: {
|
||
trigger: 'axis',
|
||
formatter: '{b}: {c} ' + this.unit
|
||
},
|
||
grid: {
|
||
left: '3%',
|
||
right: '4%',
|
||
bottom: '3%',
|
||
containLabel: true
|
||
},
|
||
xAxis: {
|
||
type: 'category',
|
||
data: xData,
|
||
axisLabel: {
|
||
rotate: 15
|
||
}
|
||
},
|
||
yAxis: {
|
||
type: 'value',
|
||
name: '能耗 (' + this.unit + ')',
|
||
min: 0
|
||
},
|
||
series: [
|
||
{
|
||
name: '总能耗',
|
||
type: this.monthChartType,
|
||
data: yData,
|
||
itemStyle: {
|
||
color: this.monthChartType === 'bar' ? '#409EFF' : '#67C23A'
|
||
},
|
||
markPoint: {
|
||
data: [
|
||
{ type: 'max', name: '最大值', itemStyle: { color: '#F56C6C' } },
|
||
{ type: 'min', name: '最小值', itemStyle: { color: '#909399' } }
|
||
],
|
||
label: {
|
||
formatter: '{b}: {c} ' + this.unit
|
||
}
|
||
},
|
||
smooth: this.monthChartType === 'line'
|
||
}
|
||
]
|
||
}
|
||
console.log(option)
|
||
this.monthChart.setOption(option)
|
||
},
|
||
|
||
// 初始化日度图表
|
||
initDayChart() {
|
||
if (!this.hasDayData) return
|
||
|
||
const xData = this.completedDayData.map(item => item.day)
|
||
const yData = this.completedDayData.map(item => item.totalConsumption)
|
||
|
||
const option = {
|
||
tooltip: {
|
||
trigger: 'axis',
|
||
formatter: '{b}: {c} ' + this.unit
|
||
},
|
||
grid: {
|
||
left: '3%',
|
||
right: '4%',
|
||
bottom: '3%',
|
||
containLabel: true
|
||
},
|
||
xAxis: {
|
||
type: 'category',
|
||
data: xData,
|
||
axisLabel: {
|
||
rotate: 15
|
||
}
|
||
},
|
||
yAxis: {
|
||
type: 'value',
|
||
name: '能耗 (' + this.unit + ')',
|
||
min: 0
|
||
},
|
||
series: [
|
||
{
|
||
name: '总能耗',
|
||
type: this.dayChartType,
|
||
data: yData,
|
||
itemStyle: {
|
||
color: this.dayChartType === 'bar' ? '#409EFF' : '#67C23A'
|
||
},
|
||
markPoint: {
|
||
data: [
|
||
{ type: 'max', name: '最大值', itemStyle: { color: '#F56C6C' } },
|
||
{ type: 'min', name: '最小值', itemStyle: { color: '#909399' } }
|
||
],
|
||
label: {
|
||
formatter: '{b}: {c} ' + this.unit
|
||
}
|
||
},
|
||
smooth: this.dayChartType === 'line'
|
||
}
|
||
]
|
||
}
|
||
|
||
this.dayChart.setOption(option)
|
||
},
|
||
|
||
// 切换图表类型
|
||
toggleMonthChartType(type) {
|
||
this.monthChartType = type
|
||
this.initMonthChart()
|
||
},
|
||
toggleDayChartType(type) {
|
||
this.dayChartType = type
|
||
this.initDayChart()
|
||
},
|
||
|
||
// 窗口大小调整
|
||
handleWindowResize() {
|
||
if (this.monthChart) this.monthChart.resize()
|
||
if (this.dayChart) this.dayChart.resize()
|
||
},
|
||
|
||
// 对外暴露的刷新方法
|
||
refresh() {
|
||
this.fetchMonthData()
|
||
this.fetchDayData()
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.trends-container {
|
||
padding: 20px;
|
||
}
|
||
|
||
.chart-group {
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.chart-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.chart-type-btn-group button {
|
||
margin-left: 10px;
|
||
}
|
||
|
||
.chart-wrapper {
|
||
width: 100%;
|
||
height: 300px;
|
||
border: 1px solid #eee;
|
||
border-radius: 4px;
|
||
position: relative;
|
||
}
|
||
|
||
.chart-container {
|
||
width: 100%;
|
||
height: 100%;
|
||
padding: 10px;
|
||
}
|
||
|
||
.no-data {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
</style>
|