312 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
		
		
			
		
	
	
			312 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
|  | <template> | |||
|  |     <div class="chart-container"> | |||
|  |         <!-- 图表标题和时间范围选择器 --> | |||
|  |         <div class="chart-header"> | |||
|  |             <h2>功率与效率趋势</h2> | |||
|  |             <div class="chart-actions"> | |||
|  |                 <button @click="timeRange = 'day'" :class="{ active: timeRange === 'day' }">今日</button> | |||
|  |                 <button @click="timeRange = 'week'" :class="{ active: timeRange === 'week' }">本周</button> | |||
|  |                 <button @click="timeRange = 'month'" :class="{ active: timeRange === 'month' }">本月</button> | |||
|  |             </div> | |||
|  |         </div> | |||
|  |         <!-- 图表内容区域 --> | |||
|  |         <div ref="chartRef" class="chart-content"></div> | |||
|  |     </div> | |||
|  | </template> | |||
|  | 
 | |||
|  | <script setup> | |||
|  | import { ref, onMounted, watch } from 'vue'; | |||
|  | import * as echarts from 'echarts'; | |||
|  | 
 | |||
|  | // 图表DOM引用
 | |||
|  | const chartRef = ref(null); | |||
|  | // 时间范围状态
 | |||
|  | const timeRange = ref('day'); | |||
|  | // 图表实例
 | |||
|  | let chartInstance = null; | |||
|  | 
 | |||
|  | // 定义颜色常量
 | |||
|  | const POWER_COLOR = 'rgba(42, 130, 228, 1)'; | |||
|  | const EFFICIENCY_COLOR = 'rgba(67, 207, 124, 1)'; | |||
|  | 
 | |||
|  | // 生成指定范围内的随机数(用于模拟数据)
 | |||
|  | const getRandomValue = (min, max) => { | |||
|  |     return Math.floor(Math.random() * (max - min + 1)) + min; | |||
|  | }; | |||
|  | 
 | |||
|  | // 生成指定范围内的随机浮点数(用于效率数据)
 | |||
|  | const getRandomFloat = (min, max, decimalPlaces = 1) => { | |||
|  |     const value = Math.random() * (max - min) + min; | |||
|  |     return parseFloat(value.toFixed(decimalPlaces)); | |||
|  | }; | |||
|  | 
 | |||
|  | // 获取当前月份的天数
 | |||
|  | const getDaysInCurrentMonth = () => { | |||
|  |     const now = new Date(); | |||
|  |     const year = now.getFullYear(); | |||
|  |     const month = now.getMonth() + 1; // 月份从0开始,所以+1
 | |||
|  |     return new Date(year, month, 0).getDate(); | |||
|  | }; | |||
|  | 
 | |||
|  | // 根据时间范围返回对应的数据
 | |||
|  | const getChartData = () => { | |||
|  |     if (timeRange.value === 'day') { | |||
|  |         return { | |||
|  |             xAxis: ['00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00'], | |||
|  |             powerData: [320, 380, 350, 420, 580, 630, 550, 480], | |||
|  |             efficiencyData: [85.2, 86.5, 87.1, 88.3, 89.5, 89.2, 88.7, 88.1] | |||
|  |         }; | |||
|  |     } else if (timeRange.value === 'week') { | |||
|  |         return { | |||
|  |             xAxis: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], | |||
|  |             powerData: [4200, 4800, 5100, 4900, 5300, 3800, 3200], | |||
|  |             efficiencyData: [86.2, 87.5, 88.1, 87.8, 89.0, 88.5, 87.9] | |||
|  |         }; | |||
|  |     } else { | |||
|  |         // 本月数据 - 按天显示
 | |||
|  |         const daysInMonth = getDaysInCurrentMonth(); | |||
|  |         const xAxis = []; | |||
|  |         const powerData = []; | |||
|  |         const efficiencyData = []; | |||
|  | 
 | |||
|  |         // 生成每天的数据
 | |||
|  |         for (let i = 1; i <= daysInMonth; i++) { | |||
|  |             xAxis.push(`${i}日`); | |||
|  |             // 生成合理范围内的功率数据(10000-25000之间)
 | |||
|  |             powerData.push(getRandomValue(10000, 25000)); | |||
|  |             // 生成合理范围内的效率数据(85-90之间,保留1位小数)
 | |||
|  |             efficiencyData.push(getRandomFloat(85, 90)); | |||
|  |         } | |||
|  | 
 | |||
|  |         return { | |||
|  |             xAxis, | |||
|  |             powerData, | |||
|  |             efficiencyData | |||
|  |         }; | |||
|  |     } | |||
|  | }; | |||
|  | 
 | |||
|  | // 初始化图表
 | |||
|  | const initChart = () => { | |||
|  |     if (chartRef.value && !chartInstance) { | |||
|  |         chartInstance = echarts.init(chartRef.value); | |||
|  |     } | |||
|  | 
 | |||
|  |     const data = getChartData(); | |||
|  | 
 | |||
|  |     const option = { | |||
|  |         tooltip: { | |||
|  |             trigger: 'axis', | |||
|  |             axisPointer: { type: 'cross' } | |||
|  |         }, | |||
|  |         legend: { | |||
|  |             data: ['总功率(kW)', '平均效率(%)'], | |||
|  |             top: 0 | |||
|  |         }, | |||
|  |         grid: { | |||
|  |             left: '3%', | |||
|  |             right: '4%', | |||
|  |             bottom: '3%', | |||
|  |             containLabel: true | |||
|  |         }, | |||
|  |         xAxis: { | |||
|  |             type: 'category', | |||
|  |             boundaryGap: false, | |||
|  |             data: data.xAxis, | |||
|  |             // 当月天数较多时,优化X轴标签显示
 | |||
|  |             axisLabel: { | |||
|  |                 interval: timeRange.value === 'month' ? 'auto' : 0, | |||
|  |                 rotate: timeRange.value === 'month' ? 45 : 0 | |||
|  |             } | |||
|  |         }, | |||
|  |         yAxis: [ | |||
|  |             { | |||
|  |                 type: 'value', | |||
|  |                 name: '总功率(kW)', | |||
|  |                 axisLabel: { | |||
|  |                     formatter: '{value}' | |||
|  |                 } | |||
|  |             }, | |||
|  |             { | |||
|  |                 type: 'value', | |||
|  |                 name: '平均效率(%)', | |||
|  |                 min: 80, | |||
|  |                 max: 95, | |||
|  |                 axisLabel: { | |||
|  |                     formatter: '{value}%' | |||
|  |                 } | |||
|  |             } | |||
|  |         ], | |||
|  |         series: [ | |||
|  |             { | |||
|  |                 name: '总功率(kW)', | |||
|  |                 type: 'line', | |||
|  |                 data: data.powerData, | |||
|  |                 smooth: true, | |||
|  |                 lineStyle: { | |||
|  |                     width: 3, | |||
|  |                     color: POWER_COLOR | |||
|  |                 }, | |||
|  |                 symbol: 'circle', | |||
|  |                 symbolSize: 8, | |||
|  |                 itemStyle: { | |||
|  |                     color: POWER_COLOR | |||
|  |                 }, | |||
|  |                 markPoint: { | |||
|  |                     data: [ | |||
|  |                         { type: 'max', name: '最大值' }, | |||
|  |                         { type: 'min', name: '最小值' } | |||
|  |                     ], | |||
|  |                     itemStyle: { | |||
|  |                         color: POWER_COLOR | |||
|  |                     } | |||
|  |                 } | |||
|  |             }, | |||
|  |             { | |||
|  |                 name: '平均效率(%)', | |||
|  |                 type: 'line', | |||
|  |                 yAxisIndex: 1, | |||
|  |                 data: data.efficiencyData, | |||
|  |                 smooth: true, | |||
|  |                 lineStyle: { | |||
|  |                     width: 3, | |||
|  |                     type: 'dashed', | |||
|  |                     color: EFFICIENCY_COLOR | |||
|  |                 }, | |||
|  |                 symbol: 'diamond', | |||
|  |                 symbolSize: 8, | |||
|  |                 itemStyle: { | |||
|  |                     color: EFFICIENCY_COLOR | |||
|  |                 }, | |||
|  |                 markPoint: { | |||
|  |                     data: [ | |||
|  |                         { type: 'max', name: '最大值' }, | |||
|  |                         { type: 'min', name: '最小值' } | |||
|  |                     ], | |||
|  |                     itemStyle: { | |||
|  |                         color: EFFICIENCY_COLOR | |||
|  |                     } | |||
|  |                 } | |||
|  |             } | |||
|  |         ] | |||
|  |     }; | |||
|  | 
 | |||
|  |     chartInstance.setOption(option); | |||
|  | }; | |||
|  | 
 | |||
|  | // 响应窗口大小变化
 | |||
|  | const handleResize = () => { | |||
|  |     if (chartInstance) { | |||
|  |         chartInstance.resize(); | |||
|  |     } | |||
|  | }; | |||
|  | 
 | |||
|  | // 生命周期钩子
 | |||
|  | onMounted(() => { | |||
|  |     initChart(); | |||
|  |     window.addEventListener('resize', handleResize); | |||
|  | 
 | |||
|  |     // 清理函数
 | |||
|  |     return () => { | |||
|  |         window.removeEventListener('resize', handleResize); | |||
|  |         if (chartInstance) { | |||
|  |             chartInstance.dispose(); | |||
|  |             chartInstance = null; | |||
|  |         } | |||
|  |     }; | |||
|  | }); | |||
|  | 
 | |||
|  | // 监听时间范围变化,更新图表
 | |||
|  | watch(timeRange, () => { | |||
|  |     initChart(); | |||
|  | }); | |||
|  | </script> | |||
|  | 
 | |||
|  | <style scoped> | |||
|  | .chart-container { | |||
|  |     background-color: #fff; | |||
|  |     border-radius: 8px; | |||
|  |     box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); | |||
|  |     overflow: hidden; | |||
|  |     height: 400px; | |||
|  |     width: 100%; | |||
|  | } | |||
|  | 
 | |||
|  | .chart-header { | |||
|  |     display: flex; | |||
|  |     justify-content: space-between; | |||
|  |     align-items: center; | |||
|  |     padding: 15px 20px; | |||
|  |     border-bottom: 1px solid #f0f0f0; | |||
|  | } | |||
|  | 
 | |||
|  | .chart-header h2 { | |||
|  |     font-size: 16px; | |||
|  |     font-weight: 600; | |||
|  |     color: #333; | |||
|  |     margin: 0; | |||
|  | } | |||
|  | 
 | |||
|  | .chart-actions button { | |||
|  |     background: none; | |||
|  |     border: 1px solid #e0e0e0; | |||
|  |     padding: 5px 12px; | |||
|  |     border-radius: 4px; | |||
|  |     margin-left: 8px; | |||
|  |     cursor: pointer; | |||
|  |     font-size: 12px; | |||
|  |     transition: all 0.2s ease; | |||
|  | } | |||
|  | 
 | |||
|  | .chart-actions button.active { | |||
|  |     background-color: #1890ff; | |||
|  |     color: white; | |||
|  |     border-color: #1890ff; | |||
|  | } | |||
|  | 
 | |||
|  | .chart-content { | |||
|  |     width: 100%; | |||
|  |     height: calc(100% - 54px); | |||
|  |     padding: 10px; | |||
|  | } | |||
|  | 
 | |||
|  | @media (max-width: 768px) { | |||
|  |     .chart-container { | |||
|  |         height: 350px; | |||
|  |     } | |||
|  | } | |||
|  | 
 | |||
|  | @media (max-width: 480px) { | |||
|  |     .chart-container { | |||
|  |         height: 300px; | |||
|  |     } | |||
|  | 
 | |||
|  |     .chart-header { | |||
|  |         flex-direction: column; | |||
|  |         align-items: flex-start; | |||
|  |         gap: 10px; | |||
|  |     } | |||
|  | 
 | |||
|  |     .chart-actions { | |||
|  |         width: 100%; | |||
|  |         display: flex; | |||
|  |         justify-content: space-between; | |||
|  |     } | |||
|  | 
 | |||
|  |     .chart-actions button { | |||
|  |         margin: 0; | |||
|  |         flex: 1; | |||
|  |         margin-right: 5px; | |||
|  |     } | |||
|  | 
 | |||
|  |     .chart-actions button:last-child { | |||
|  |         margin-right: 0; | |||
|  |     } | |||
|  | } | |||
|  | 
 | |||
|  | .model { | |||
|  |     padding: 20px; | |||
|  |     background-color: rgba(242, 248, 252, 1); | |||
|  | } | |||
|  | </style> |