feat: 图表

This commit is contained in:
砂糖
2025-09-30 10:01:16 +08:00
parent 6c483ad6f5
commit 8b31f9bf84
13 changed files with 1287 additions and 142 deletions

View File

@@ -1,9 +1,12 @@
<template>
<el-row>
<el-col :span="4">
<el-select v-model="energyType" placeholder="请选择能源类型">
<el-option v-for="item in energyTypeList" :key="item.energyTypeId" :label="item.name" :value="item.energyTypeId" />
</el-select>
<div style="padding: 10px;">
<el-select v-model="energyType" placeholder="请选择能源类型" @change="refresh">
<el-option v-for="item in energyTypeList" :key="item.energyTypeId" :label="item.name" :value="item.energyTypeId" />
</el-select>
</div>
<!-- 区域选择默认展开最高高度为60%的屏幕尺寸 -->
<el-tree @node-click="handleNodeClick" :data="locationList" :props="defaultProps" :default-expand-all="true" :style="{ height: 'calc(50vh - 50px)' }"></el-tree>
@@ -17,19 +20,21 @@
</div>
</el-col>
<el-col :span="20">
<el-tabs v-model="activeTab">
<el-tab-pane label="环比概况" name="1">
</el-tab-pane>
<el-col :span="20" v-if="showRight">
<el-tabs v-model="activeTab" type="card">
<el-tab-pane label="环比概况" name="1"></el-tab-pane>
<el-tab-pane label="近期趋势" name="2"></el-tab-pane>
<el-tab-pane label="同比分析" name="3"></el-tab-pane>
<el-tab-pane label="环比分析" name="4"></el-tab-pane>
</el-tabs>
<Overview v-if="activeTab === '1'" />
<RecentTrend v-if="activeTab === '2'" />
<YearToYear v-if="activeTab === '3'" />
<MonthToMonth v-if="activeTab === '4'" />
<Overview ref="overview" v-if="activeTab === '1'" :unit="energyUnit" :energyName="energyName" :energyType="energyType" :locationId="locationId" :deviceId="deviceId" />
<RecentTrend ref="recentTrend" v-if="activeTab === '2'" :unit="energyUnit" :energyName="energyName" :energyType="energyType" :locationId="locationId" :deviceId="deviceId" />
<YearToYear ref="yearToYear" v-if="activeTab === '3'" :unit="energyUnit" :energyName="energyName" :energyType="energyType" :locationId="locationId" :deviceId="deviceId" />
<MonthToMonth ref="monthToMonth" v-if="activeTab === '4'" :unit="energyUnit" :energyName="energyName" :energyType="energyType" :locationId="locationId" :deviceId="deviceId" />
</el-col>
<el-col :span="20" v-else>
<el-empty description="请选择能源类型和区域"></el-empty>
</el-col>
</el-row>
</template>
@@ -39,10 +44,9 @@ import { listEnergyType } from "@/api/ems/energyType";
import { listLocation } from "@/api/ems/location";
import Overview from "./panels/Overview.vue";
import RecentTrend from "./panels/RecentTrend.vue";
import YearToYear from "./panels/YearToYear.vue";
import RecentTrend from "./panels/RecentTrends.vue";
import YearToYear from "./panels/YearOnYear.vue";
import MonthToMonth from "./panels/MonthToMonth.vue";
import Overview from "./panels/Overview.vue";
export default {
name: "Dashboard",
@@ -57,6 +61,7 @@ export default {
energyTypeList: [],
energyType: '',
locationId: '',
deviceId: '',
locationList: [
],
defaultProps: {
@@ -70,11 +75,16 @@ export default {
this.getEnergyTypeList();
this.getLocationList();
},
watch: {
// 当选择的区域变化时重新获取设备列表
locationId: {
computed: {
showRight() {
return this.energyType && (this.deviceId || this.locationId);
},
energyUnit() {
return this.energyTypeList.find(item => item.energyTypeId === this.energyType)?.unit;
},
energyName() {
return this.energyTypeList.find(item => item.energyTypeId === this.energyType)?.name;
}
},
methods: {
getEnergyTypeList() {
@@ -84,13 +94,27 @@ export default {
},
getLocationList() {
listLocation().then(response => {
const data = { locationId: undefined, name: '顶级节点', children: [] };
data.children = this.handleTree(response.data, "locationId", "parentId");
this.locationList.push(data);
this.locationList = this.handleTree(response.data, "locationId", "parentId");
});
},
handleNodeClick(data) {
this.locationId = data.locationId;
this.deviceId = undefined;
this.refresh();
},
refresh() {
if (this.$refs.overview) {
this.$refs.overview.refresh();
}
if (this.$refs.recentTrend) {
this.$refs.recentTrend.refresh();
}
if (this.$refs.yearToYear) {
this.$refs.yearToYear.refresh();
}
if (this.$refs.monthToMonth) {
this.$refs.monthToMonth.refresh();
}
}
}
}

View File

@@ -0,0 +1,239 @@
<template>
<div class="energy-analysis-container">
<!-- 年份选择与查询按钮区域 -->
<div class="query-section">
<el-input
v-model="year"
placeholder="请输入年份"
style="width: 200px; margin-right: 10px;"
/>
<el-button type="primary" @click="handleQuery">查询</el-button>
</div>
<!-- 图表区域含图例图表类型切换刷新 -->
<div class="chart-section">
<el-row :gutter="10" align="middle" style="margin-bottom: 10px;">
<!-- 图例 -->
<el-col>
<div class="legend-item">
<span class="legend-dot" style="background-color: #409EFF;"></span>
<span>本期</span>
</div>
<div class="legend-item">
<span class="legend-dot" style="background-color: #C084FC;"></span>
<span>同期</span>
</div>
</el-col>
<!-- 图表类型切换 + 刷新 -->
<el-col :offset="18">
<el-button-group>
<el-button type="text" @click="chartType = 'bar'">柱状图</el-button>
<el-button type="text" @click="chartType = 'line'">折线图</el-button>
</el-button-group>
<el-button icon="el-icon-refresh" type="text" @click="handleRefresh">刷新</el-button>
</el-col>
</el-row>
<!-- ECharts 容器 -->
<div ref="chartRef" class="echarts-box" />
</div>
<!-- 同比分析表格 -->
<div class="table-section">
<el-table :data="tableData" border style="width: 100%">
<el-table-column prop="periodTime" label="本期时间" />
<el-table-column prop="currentEnergy" label="本期能耗(Nm3)" />
<el-table-column prop="samePeriodEnergy" label="同比能耗(Nm3)" />
<el-table-column prop="yearOnYear" label="同比(%)" />
</el-table>
</div>
</div>
</template>
<script>
import echarts from 'echarts'
export default {
name: 'MonthToMonthAnalysis',
props: {
energyType: {
type: String,
default: ''
},
locationId: {
type: String,
default: ''
},
deviceId: {
type: String,
default: ''
},
unit: {
type: String,
default: ''
},
energyName: {
type: String,
default: ''
}
},
data() {
return {
year: '2025',
chartType: 'bar',
tableData: [
{ periodTime: '1月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' },
{ periodTime: '2月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' },
{ periodTime: '3月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' },
{ periodTime: '4月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' },
{ periodTime: '5月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' },
{ periodTime: '6月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' },
{ periodTime: '7月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' },
{ periodTime: '8月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' },
{ periodTime: '9月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' },
{ periodTime: '10月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' },
{ periodTime: '11月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' },
{ periodTime: '12月', currentEnergy: '--', samePeriodEnergy: '--', yearOnYear: '--' }
],
chartInstance: null
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (this.chartInstance) {
this.chartInstance.dispose()
}
},
watch: {
chartType: {
handler(newVal) {
this.drawChart()
},
immediate: true
}
},
methods: {
// 初始化图表
initChart() {
this.chartInstance = echarts.init(this.$refs.chartRef)
this.drawChart()
// 监听窗口大小变化,调整图表尺寸
window.addEventListener('resize', this.handleResize)
},
// 绘制图表
drawChart() {
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
},
yAxis: {
type: 'value'
},
series: [
{
name: '本期',
type: this.chartType,
data: [120, 132, 101, 134, 90, 230, 210, 120, 132, 101, 134, 90],
itemStyle: {
color: '#409EFF'
}
},
{
name: '同期',
type: this.chartType,
data: [90, 110, 120, 110, 120, 140, 130, 90, 110, 120, 110, 120],
itemStyle: {
color: '#C084FC'
}
}
]
}
this.chartInstance.setOption(option)
},
// 处理查询
handleQuery() {
// 实际项目中这里会调用接口获取数据
console.log('查询年份:', this.year)
// 模拟数据加载
this.tableData = this.tableData.map(item => ({
...item,
currentEnergy: Math.floor(Math.random() * 1000) + '',
samePeriodEnergy: Math.floor(Math.random() * 1000) + '',
yearOnYear: (Math.random() * 20 - 10).toFixed(2) + ''
}))
this.drawChart()
},
// 刷新图表
handleRefresh() {
this.drawChart()
},
// 处理窗口大小变化
handleResize() {
if (this.chartInstance) {
this.chartInstance.resize()
}
}
}
}
</script>
<style scoped>
.energy-analysis-container {
padding: 20px;
background-color: #fff;
border-radius: 4px;
}
.query-section {
margin-bottom: 20px;
display: flex;
align-items: center;
}
.chart-section {
margin-bottom: 20px;
}
.echarts-box {
width: 100%;
height: 400px;
border: 1px solid #e6e6e6;
border-radius: 4px;
}
.legend-item {
display: inline-block;
margin-right: 20px;
vertical-align: middle;
}
.legend-dot {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 5px;
}
.table-section {
margin-top: 20px;
}
</style>

View File

@@ -0,0 +1,320 @@
<template>
<div>
<!-- 今日 vs 昨日 -->
<div class="trend-row">
<div class="data-card">
<div class="data-value">{{ data.today }}</div>
<div class="data-label">今日</div>
</div>
<div class="data-card">
<div class="data-value">{{ data.yesterday }}</div>
<div class="data-label">昨日</div>
</div>
<div class="trend-card" :class="todayTrendClass">
<div class="trend-indicator">
<i class="fas" :class="todayTrendIcon"></i>
</div>
<div class="trend-percent">{{ todayPercent }}</div>
<div class="trend-diff">{{ todayDiff }}</div>
</div>
</div>
<!-- 本月 vs 上月 -->
<div class="trend-row">
<div class="data-card">
<div class="data-value">{{ data.currentMonth }}</div>
<div class="data-label">本月</div>
</div>
<div class="data-card">
<div class="data-value">{{ data.lastMonth }}</div>
<div class="data-label">上月</div>
</div>
<div class="trend-card" :class="monthTrendClass">
<div class="trend-indicator">
<i class="fas" :class="monthTrendIcon"></i>
</div>
<div class="trend-percent">{{ monthPercent }}</div>
<div class="trend-diff">{{ monthDiff }}</div>
</div>
</div>
<!-- 本年 vs 去年 -->
<div class="trend-row">
<div class="data-card">
<div class="data-value">{{ data.currentYear }}</div>
<div class="data-label">本年</div>
</div>
<div class="data-card">
<div class="data-value">{{ data.lastYear }}</div>
<div class="data-label">去年</div>
</div>
<div class="trend-card" :class="yearTrendClass">
<div class="trend-indicator">
<i class="fas" :class="yearTrendIcon"></i>
</div>
<div class="trend-percent">{{ yearPercent }}</div>
<div class="trend-diff">{{ yearDiff }}</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "TrendComparison",
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
}
},
data() {
return {
data: {} // 存储模拟数据
};
},
created() {
// 组件创建时获取模拟数据
this.data = this.fetchMockData();
},
methods: {
/**
* 模拟API请求生成六个数值
* 生成规则:
* - 今日随机100-500之间的数值
* - 昨日基于今日数值上下浮动20%
* - 本月随机5000-20000之间的数值
* - 上月基于本月数值上下浮动30%
* - 本年随机100000-500000之间的数值
* - 去年基于本年数值上下浮动40%
*/
fetchMockData() {
// 生成今日数据
const today = parseFloat((Math.random() * 400 + 100).toFixed(2));
// 昨日数据今日数据的80%-120%之间
const yesterday = parseFloat((today * (0.8 + Math.random() * 0.4)).toFixed(2));
// 本月数据
const currentMonth = parseFloat((Math.random() * 15000 + 5000).toFixed(2));
// 上月数据本月数据的70%-130%之间
const lastMonth = parseFloat((currentMonth * (0.7 + Math.random() * 0.6)).toFixed(2));
// 本年数据
const currentYear = parseFloat((Math.random() * 400000 + 100000).toFixed(2));
// 去年数据本年数据的60%-140%之间
const lastYear = parseFloat((currentYear * (0.6 + Math.random() * 0.8)).toFixed(2));
return {
today,
yesterday,
currentMonth,
lastMonth,
currentYear,
lastYear
};
},
/**
* 格式化数值显示,添加千位分隔符
* @param {Number} num 要格式化的数值
* @returns {String} 格式化后的字符串
*/
formatNumber(num) {
return num.toLocaleString('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
},
// 对外暴露的刷新方法
refresh() {
this.data = this.fetchMockData();
}
},
computed: {
// ---- 今日 vs 昨日 计算 ----
todayDiff() {
const diff = this.data.today - this.data.yesterday;
return diff >= 0
? `+${this.formatNumber(diff)}`
: `${this.formatNumber(diff)}`;
},
todayPercent() {
if (this.data.yesterday === 0) return "0.00%";
const percent = ((this.data.today - this.data.yesterday) / this.data.yesterday) * 100;
return percent >= 0
? `+${percent.toFixed(2)}%`
: `${percent.toFixed(2)}%`;
},
todayTrendClass() {
return this.data.today > this.data.yesterday ? "trend-up" : "trend-down";
},
todayTrendIcon() {
return this.data.today > this.data.yesterday ? "fa-arrow-up" : "fa-arrow-down";
},
// ---- 本月 vs 上月 计算 ----
monthDiff() {
const diff = this.data.currentMonth - this.data.lastMonth;
return diff >= 0
? `+${this.formatNumber(diff)}`
: `${this.formatNumber(diff)}`;
},
monthPercent() {
if (this.data.lastMonth === 0) return "0.00%";
const percent = ((this.data.currentMonth - this.data.lastMonth) / this.data.lastMonth) * 100;
return percent >= 0
? `+${percent.toFixed(2)}%`
: `${percent.toFixed(2)}%`;
},
monthTrendClass() {
return this.data.currentMonth > this.data.lastMonth ? "trend-up" : "trend-down";
},
monthTrendIcon() {
return this.data.currentMonth > this.data.lastMonth ? "fa-arrow-up" : "fa-arrow-down";
},
// ---- 本年 vs 去年 计算 ----
yearDiff() {
const diff = this.data.currentYear - this.data.lastYear;
return diff >= 0
? `+${this.formatNumber(diff)}`
: `${this.formatNumber(diff)}`;
},
yearPercent() {
if (this.data.lastYear === 0) return "0.00%";
const percent = ((this.data.currentYear - this.data.lastYear) / this.data.lastYear) * 100;
return percent >= 0
? `+${percent.toFixed(2)}%`
: `${percent.toFixed(2)}%`;
},
yearTrendClass() {
return this.data.currentYear > this.data.lastYear ? "trend-up" : "trend-down";
},
yearTrendIcon() {
return this.data.currentYear > this.data.lastYear ? "fa-arrow-up" : "fa-arrow-down";
}
}
};
</script>
<style scoped>
.trend-container {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 800px;
margin: 20px auto;
padding: 20px;
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.trend-title {
color: #333333;
font-size: 18px;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #f0f0f0;
}
.trend-row {
display: flex;
margin-bottom: 15px;
border-radius: 8px;
overflow: hidden;
transition: transform 0.2s;
}
.trend-row:hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1);
}
.data-card, .trend-card {
padding: 15px;
text-align: center;
}
.data-card {
flex: 1;
background-color: #f9fafb;
border-right: 1px solid #f0f0f0;
}
.trend-card {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 15px;
}
.data-value {
font-size: 22px;
font-weight: 600;
color: #111827;
margin-bottom: 5px;
}
.data-label {
font-size: 14px;
color: #6b7280;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.trend-indicator {
margin-bottom: 5px;
font-size: 16px;
}
.trend-percent {
font-size: 20px;
font-weight: 600;
margin-bottom: 3px;
}
.trend-diff {
font-size: 14px;
color: #4b5563;
}
/* 趋势样式 */
.trend-up {
background-color: rgba(16, 185, 129, 0.05);
}
.trend-up .trend-percent,
.trend-up .trend-indicator {
color: #10b981; /* 绿色表示上升 */
}
.trend-down {
background-color: rgba(239, 68, 68, 0.05);
}
.trend-down .trend-percent,
.trend-down .trend-indicator {
color: #ef4444; /* 红色表示下降 */
}
</style>

View File

@@ -0,0 +1,382 @@
<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>

View File

@@ -0,0 +1,5 @@
<template>
<div>
同比分析
</div>
</template>