随机数据生成 田间监测
This commit is contained in:
		
							parent
							
								
									af11fa876b
								
							
						
					
					
						commit
						78255cea06
					
				| @ -1,6 +1,206 @@ | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted, watch } from 'vue'; | ||||
| import { ref, reactive, onMounted, watch, onBeforeUnmount } from 'vue'; | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| import * as echarts from 'echarts'; | ||||
| 
 | ||||
| // 图表 DOM 引用 | ||||
| const chartRef = ref(null); | ||||
| // ECharts 实例 | ||||
| let chartInstance = null; | ||||
| // 颜色列表 | ||||
| const colorList = ['#3685FE', '#FFD500', '#25BF82']; | ||||
| // x轴数据 | ||||
| const xData = ['1月', '2月', '3月', '4月', '5月', '6月']; | ||||
| 
 | ||||
| // 图表配置 | ||||
| const option = { | ||||
|   backgroundColor: '#fff', | ||||
|   title: { | ||||
|     text: '', | ||||
|     textStyle: { | ||||
|       fontSize: 12, | ||||
|       fontWeight: 400, | ||||
|     }, | ||||
|     left: 'center', | ||||
|     top: '5%', | ||||
|   }, | ||||
|   legend: { | ||||
|     icon: 'circle', | ||||
|     top: '0', | ||||
|     right: '5%', | ||||
|     itemWidth: 6, | ||||
|     itemGap: 20, | ||||
|     textStyle: { | ||||
|       color: '#556677', | ||||
|     }, | ||||
|   }, | ||||
|   tooltip: { | ||||
|     trigger: 'axis', | ||||
|     axisPointer: { | ||||
|       label: { | ||||
|         show: true, | ||||
|         backgroundColor: '#fff', | ||||
|         color: '#556677', | ||||
|         borderColor: 'rgba(0,0,0,0)', | ||||
|         shadowColor: 'rgba(0,0,0,0)', | ||||
|         shadowOffsetY: 0, | ||||
|       }, | ||||
|       lineStyle: { | ||||
|         width: 0, | ||||
|       }, | ||||
|     }, | ||||
|     backgroundColor: '#fff', | ||||
|     textStyle: { | ||||
|       color: '#5c6c7c', | ||||
|     }, | ||||
|     padding: [10, 10], | ||||
|     extraCssText: 'box-shadow: 1px 0 2px 0 rgba(163,163,163,0.5)', | ||||
|   }, | ||||
|   grid: { | ||||
|     top: '20%', | ||||
|   }, | ||||
|   xAxis: [ | ||||
|     { | ||||
|       type: 'category', | ||||
|       data: xData, | ||||
|       axisLine: { | ||||
|         lineStyle: { | ||||
|           color: 'rgba(107,107,107,0.37)', | ||||
|         }, | ||||
|       }, | ||||
|       axisTick: { | ||||
|         show: false, | ||||
|       }, | ||||
|       axisLabel: { | ||||
|         interval: 0, | ||||
|         textStyle: { | ||||
|           color: '#999', | ||||
|         }, | ||||
|         margin: 15, | ||||
|       }, | ||||
|       axisPointer: { | ||||
|         label: { | ||||
|           padding: [11, 5, 7], | ||||
|           backgroundColor: { | ||||
|             type: 'linear', | ||||
|             x: 0, | ||||
|             y: 0, | ||||
|             x2: 0, | ||||
|             y2: 1, | ||||
|             colorStops: [ | ||||
|               { | ||||
|                 offset: 0, | ||||
|                 color: '#fff', | ||||
|               }, | ||||
|               { | ||||
|                 offset: 0.9, | ||||
|                 color: '#fff', | ||||
|               }, | ||||
|               { | ||||
|                 offset: 0.9, | ||||
|                 color: '#33c0cd', | ||||
|               }, | ||||
|               { | ||||
|                 offset: 1, | ||||
|                 color: '#33c0cd', | ||||
|               }, | ||||
|             ], | ||||
|             global: false, | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|       boundaryGap: false, | ||||
|     }, | ||||
|   ], | ||||
|   yAxis: [ | ||||
|     { | ||||
|       type: 'value', | ||||
|       show: false, | ||||
|       axisTick: { | ||||
|         show: false, | ||||
|       }, | ||||
|       axisLine: { | ||||
|         show: true, | ||||
|         lineStyle: { | ||||
|           color: 'rgba(107,107,107,0.37)', | ||||
|         }, | ||||
|       }, | ||||
|       axisLabel: { | ||||
|         textStyle: { | ||||
|           color: '#999', | ||||
|         }, | ||||
|       }, | ||||
|       splitLine: { | ||||
|         show: false, | ||||
|       }, | ||||
|     }, | ||||
|   ], | ||||
|   series: [ | ||||
|     { | ||||
|       name: '茎秆高度', | ||||
|       type: 'line', | ||||
|       data: [10, 10, 30, 12, 15, 3], | ||||
|       symbolSize: 1, | ||||
|       symbol: 'circle', | ||||
|       smooth: true, | ||||
|       yAxisIndex: 0, | ||||
|       showSymbol: false, | ||||
|       lineStyle: { | ||||
|         width: 5, | ||||
|         color: '#3685FE', | ||||
|         shadowColor: 'rgba(158,135,255, 0.3)', | ||||
|         shadowBlur: 10, | ||||
|         shadowOffsetY: 20, | ||||
|       }, | ||||
|       itemStyle: { | ||||
|         color: colorList[0], | ||||
|         borderColor: colorList[0], | ||||
|       }, | ||||
|     }, | ||||
|     { | ||||
|       name: '叶片温度', | ||||
|       type: 'line', | ||||
|       data: [5, 12, 11, 14, 25, 16], | ||||
|       symbolSize: 1, | ||||
|       symbol: 'circle', | ||||
|       smooth: true, | ||||
|       yAxisIndex: 0, | ||||
|       showSymbol: false, | ||||
|       lineStyle: { | ||||
|         width: 5, | ||||
|         color: '#FFD500', | ||||
|         shadowColor: 'rgba(115,221,255, 0.3)', | ||||
|         shadowBlur: 10, | ||||
|         shadowOffsetY: 20, | ||||
|       }, | ||||
|       itemStyle: { | ||||
|         color: colorList[1], | ||||
|         borderColor: colorList[1], | ||||
|       }, | ||||
|     }, | ||||
|     { | ||||
|       name: '果实大小', | ||||
|       type: 'line', | ||||
|       data: [6, 14, 17, 25, 21, 10], | ||||
|       symbolSize: 1, | ||||
|       symbol: 'circle', | ||||
|       smooth: true, | ||||
|       yAxisIndex: 0, | ||||
|       showSymbol: false, | ||||
|       lineStyle: { | ||||
|         width: 5, | ||||
|         color: '#25BF82', | ||||
|         shadowColor: 'rgba(115,221,255, 0.3)', | ||||
|         shadowBlur: 10, | ||||
|         shadowOffsetY: 20, | ||||
|       }, | ||||
|       itemStyle: { | ||||
|         color: colorList[2], | ||||
|         borderColor: colorList[2], | ||||
|       }, | ||||
|     }, | ||||
|   ], | ||||
| }; | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   data: { | ||||
| @ -8,6 +208,11 @@ const props = defineProps({ | ||||
|     required: true, | ||||
|     default: () => [], | ||||
|   }, | ||||
|   chartsData: { | ||||
|     type: Array, | ||||
|     required: false, | ||||
|     default: () => [], | ||||
|   }, | ||||
|   title: { | ||||
|     type: String, | ||||
|     required: true, | ||||
| @ -20,11 +225,79 @@ const props = defineProps({ | ||||
|     type: Boolean, | ||||
|     default: false, | ||||
|   }, | ||||
|   showCharts: { | ||||
|     type: Boolean, | ||||
|     default: false, | ||||
|   }, | ||||
|   imageList: { | ||||
|     type: Array, | ||||
|     default: () => [], | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| /* --------------- methods --------------- */ | ||||
| // #region | ||||
| // 初始化图表 | ||||
| const initChart = () => { | ||||
|   if (chartRef.value) { | ||||
|     // 基于准备好的dom,初始化echarts实例 | ||||
|     chartInstance = echarts.init(chartRef.value); | ||||
|     // 绘制图表 | ||||
|     chartInstance.setOption(option); | ||||
|     // 自动显示最大值点的tooltip | ||||
|     // showMaxValueTooltip(); | ||||
|     // 响应式调整 | ||||
|     window.addEventListener('resize', resizeChart); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| const showMaxValueTooltip = () => { | ||||
|   if (!chartInstance) return; | ||||
| 
 | ||||
|   // 找出所有系列中的最大值点 | ||||
|   let maxValue = -Infinity; | ||||
|   let maxSeriesIndex = 0; | ||||
|   let maxDataIndex = 0; | ||||
| 
 | ||||
|   option.series.forEach((series, seriesIndex) => { | ||||
|     series.data.forEach((value, dataIndex) => { | ||||
|       if (value > maxValue) { | ||||
|         maxValue = value; | ||||
|         maxSeriesIndex = seriesIndex; | ||||
|         maxDataIndex = dataIndex; | ||||
|       } | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   // 延迟执行确保图表渲染完成 | ||||
|   setTimeout(() => { | ||||
|     chartInstance.dispatchAction({ | ||||
|       type: 'showTip', | ||||
|       seriesIndex: maxSeriesIndex, | ||||
|       dataIndex: maxDataIndex, | ||||
|     }); | ||||
|   }, 300); | ||||
| }; | ||||
| 
 | ||||
| // 组件挂载时初始化图表 | ||||
| onMounted(() => { | ||||
|   initChart(); | ||||
| }); | ||||
| // 组件卸载前销毁图表 | ||||
| onBeforeUnmount(() => { | ||||
|   if (chartInstance) { | ||||
|     window.removeEventListener('resize', resizeChart); | ||||
|     chartInstance.dispose(); | ||||
|     chartInstance = null; | ||||
|   } | ||||
| }); | ||||
| // 调整图表大小 | ||||
| const resizeChart = () => { | ||||
|   if (chartInstance) { | ||||
|     chartInstance.resize(); | ||||
|   } | ||||
| }; | ||||
| // #endregion | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
| @ -49,6 +322,9 @@ const props = defineProps({ | ||||
|           fit="cover" | ||||
|         /> | ||||
|       </div> | ||||
|       <div v-if="showCharts"> | ||||
|         <div ref="chartRef" style="width: 100%; height: 200px"></div> | ||||
|       </div> | ||||
|     </el-card> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted, onUnmounted } from 'vue'; | ||||
| import { ref, watch, onMounted, onUnmounted, computed } from 'vue'; | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| import { useRoute, useRouter } from 'vue-router'; | ||||
| import Hls from 'hls.js'; | ||||
| @ -27,9 +27,35 @@ const props = defineProps({ | ||||
|     type: Array, | ||||
|     required: true, | ||||
|     default: () => [], | ||||
|     validator: (items) => { | ||||
|       const validItems = items.filter((item) => item.icon === 'camera'); | ||||
|       return validItems.every((item) => { | ||||
|         return ( | ||||
|           typeof item === 'object' && | ||||
|           item !== null && | ||||
|           typeof item.id === 'number' && | ||||
|           typeof item.name === 'string' && | ||||
|           typeof item.icon === 'string' && | ||||
|           typeof item.detail === 'string' && | ||||
|           (!item.status || typeof item.status === 'number') | ||||
|         ); | ||||
|       }); | ||||
|     }, | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| const emit = defineEmits(['changeDevice']); | ||||
| // 显示天气详情弹窗 | ||||
| const showWeatherDetail = (data) => { | ||||
|   emit('changeDevice', { message: data }); | ||||
| }; | ||||
| 
 | ||||
| // 监听 currentDevice 的变化 | ||||
| watch(currentDevice, (newValue, oldValue) => { | ||||
|   showWeatherDetail(newValue); | ||||
|   // console.log(`count 从 ${oldValue} 变为 ${newValue}`); | ||||
| }); | ||||
| 
 | ||||
| onUnmounted(() => { | ||||
|   if (hls.value) { | ||||
|     hls.value.destroy(); | ||||
|  | ||||
| @ -6,43 +6,8 @@ | ||||
|           <devices :title="'田间监测设备'" :devices="devices"></devices> | ||||
|         </div> | ||||
|         <div style="display: flex; justify-content: space-between; margin-top: 10px"> | ||||
|           <stream :title="'田间监测实时监控'" :devices="devices" style="width: 60%; height: fit-content"></stream> | ||||
|           <el-card style="width: calc(40% - 20px); border-radius: 16px; padding: 10px"> | ||||
|             <div style="font-size: 16px; font-weight: bold; text-align: left">作物生长状态</div> | ||||
|             <div class="plantStatus"> | ||||
|               <div class="leftKey">作物名称:</div> | ||||
|               <div class="rightValue">橙子</div> | ||||
|             </div> | ||||
|             <div class="plantStatus"> | ||||
|               <div class="leftKey">生长状态:</div> | ||||
|               <div class="rightValue">成熟期</div> | ||||
|             </div> | ||||
|             <div class="plantStatus"> | ||||
|               <div class="leftKey">植株形态:</div> | ||||
|               <div class="rightValue">果木型</div> | ||||
|             </div> | ||||
|             <div class="plantStatus"> | ||||
|               <div class="leftKey">叶片形态:</div> | ||||
|               <div class="rightValue">阔叶型</div> | ||||
|             </div> | ||||
|             <div class="plantStatus"> | ||||
|               <div class="leftKey">生长态势:</div> | ||||
|               <div class="rightValue">良好</div> | ||||
|             </div> | ||||
|             <div class="plantStatus"> | ||||
|               <div class="leftKey">田间有机质含量:</div> | ||||
|               <div class="rightValue">橙子</div> | ||||
|             </div> | ||||
|             <div class="plantStatus"> | ||||
|               <div class="leftKey">田间有机质含量:</div> | ||||
|               <div class="rightValue">16%</div> | ||||
|             </div> | ||||
|             <div class="plantStatus"> | ||||
|               <div class="leftKey">生长趋势图</div> | ||||
|               <div class="rightValue"> </div> | ||||
|             </div> | ||||
|             <div ref="chartRef1" style="width: 100%; height: 200px"></div> | ||||
|           </el-card> | ||||
|           <stream :title="'田间监测实时监控'" :devices="devices" style="width: 60%; height: fit-content" @change-device="changeDevice"></stream> | ||||
|           <data-display style="width: calc(40% - 20px)" title="作物生长状态" show-charts :data="textData"></data-display> | ||||
|         </div> | ||||
|       </template> | ||||
|     </common> | ||||
| @ -55,29 +20,62 @@ import Common from '../components/common.vue'; | ||||
| import Devices from '@/views/smartFarm/components/devices.vue'; | ||||
| import Stream from '@/views/smartFarm/components/stream.vue'; | ||||
| import * as echarts from 'echarts'; | ||||
| import Mock from 'mockjs'; | ||||
| import DataDisplay from '@/views/smartFarm/components/dataDisplay.vue'; | ||||
| /* --------------- data --------------- */ | ||||
| // #region | ||||
| // 图表 DOM 引用 | ||||
| const chartRef1 = ref(null); | ||||
| // ECharts 实例 | ||||
| let chartInstance = null; | ||||
| // 颜色列表 | ||||
| const colorList = ['#3685FE', '#FFD500', '#25BF82']; | ||||
| // x轴数据 | ||||
| const xData = ['1月', '2月', '3月', '4月', '5月', '6月']; | ||||
| 
 | ||||
| const textData = ref([ | ||||
|   { | ||||
|     title: '作物名称', //左侧文本 | ||||
|     status: '1', //  0:不正常 1:正常 | ||||
|     statusText: '橙子', //左侧文本 | ||||
|   }, | ||||
|   { | ||||
|     title: '生长状态', | ||||
|     status: '1', | ||||
|     statusText: '成熟期', | ||||
|   }, | ||||
|   { | ||||
|     title: '植株形态', | ||||
|     status: '1', | ||||
|     statusText: '果木型', | ||||
|   }, | ||||
|   { | ||||
|     title: '叶片形态', | ||||
|     status: '1', | ||||
|     statusText: '阔叶型', | ||||
|   }, | ||||
|   { | ||||
|     title: '生长态势', | ||||
|     status: '1', | ||||
|     statusText: '良好', | ||||
|   }, | ||||
|   { | ||||
|     title: '田间有机质含量', | ||||
|     status: '1', | ||||
|     statusText: '16%', | ||||
|   }, | ||||
|   { | ||||
|     title: '生长趋势图', | ||||
|     status: '1', | ||||
|     statusText: '', | ||||
|   }, | ||||
| ]); | ||||
| 
 | ||||
| const devices = ref([ | ||||
|   { | ||||
|     name: 'A-001', | ||||
|     icon: 'camera', | ||||
|     detail: 'A区-监控设备9', | ||||
|     status: '0', | ||||
|     status: '1', | ||||
|     id: 0, | ||||
|   }, | ||||
|   { | ||||
|     name: 'A-002', | ||||
|     icon: 'camera', | ||||
|     detail: 'A区-监控设备66', | ||||
|     status: '0', | ||||
|     status: '1', | ||||
|     id: 1, | ||||
|   }, | ||||
|   { | ||||
| @ -123,258 +121,118 @@ const devices = ref([ | ||||
|     id: 7, | ||||
|   }, | ||||
| ]); | ||||
| // 图表配置 | ||||
| const option = { | ||||
|   backgroundColor: '#fff', | ||||
|   title: { | ||||
|     text: '', | ||||
|     textStyle: { | ||||
|       fontSize: 12, | ||||
|       fontWeight: 400, | ||||
|     }, | ||||
|     left: 'center', | ||||
|     top: '5%', | ||||
|   }, | ||||
|   legend: { | ||||
|     icon: 'circle', | ||||
|     top: '0', | ||||
|     right: '5%', | ||||
|     itemWidth: 6, | ||||
|     itemGap: 20, | ||||
|     textStyle: { | ||||
|       color: '#556677', | ||||
|     }, | ||||
|   }, | ||||
|   tooltip: { | ||||
|     trigger: 'axis', | ||||
|     axisPointer: { | ||||
|       label: { | ||||
|         show: true, | ||||
|         backgroundColor: '#fff', | ||||
|         color: '#556677', | ||||
|         borderColor: 'rgba(0,0,0,0)', | ||||
|         shadowColor: 'rgba(0,0,0,0)', | ||||
|         shadowOffsetY: 0, | ||||
|       }, | ||||
|       lineStyle: { | ||||
|         width: 0, | ||||
|       }, | ||||
|     }, | ||||
|     backgroundColor: '#fff', | ||||
|     textStyle: { | ||||
|       color: '#5c6c7c', | ||||
|     }, | ||||
|     padding: [10, 10], | ||||
|     extraCssText: 'box-shadow: 1px 0 2px 0 rgba(163,163,163,0.5)', | ||||
|   }, | ||||
|   grid: { | ||||
|     top: '20%', | ||||
|   }, | ||||
|   xAxis: [ | ||||
|     { | ||||
|       type: 'category', | ||||
|       data: xData, | ||||
|       axisLine: { | ||||
|         lineStyle: { | ||||
|           color: 'rgba(107,107,107,0.37)', | ||||
|         }, | ||||
|       }, | ||||
|       axisTick: { | ||||
|         show: false, | ||||
|       }, | ||||
|       axisLabel: { | ||||
|         interval: 0, | ||||
|         textStyle: { | ||||
|           color: '#999', | ||||
|         }, | ||||
|         margin: 15, | ||||
|       }, | ||||
|       axisPointer: { | ||||
|         label: { | ||||
|           padding: [11, 5, 7], | ||||
|           backgroundColor: { | ||||
|             type: 'linear', | ||||
|             x: 0, | ||||
|             y: 0, | ||||
|             x2: 0, | ||||
|             y2: 1, | ||||
|             colorStops: [ | ||||
|               { | ||||
|                 offset: 0, | ||||
|                 color: '#fff', | ||||
|               }, | ||||
|               { | ||||
|                 offset: 0.9, | ||||
|                 color: '#fff', | ||||
|               }, | ||||
|               { | ||||
|                 offset: 0.9, | ||||
|                 color: '#33c0cd', | ||||
|               }, | ||||
|               { | ||||
|                 offset: 1, | ||||
|                 color: '#33c0cd', | ||||
|               }, | ||||
|             ], | ||||
|             global: false, | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|       boundaryGap: false, | ||||
|     }, | ||||
|   ], | ||||
|   yAxis: [ | ||||
|     { | ||||
|       type: 'value', | ||||
|       show: false, | ||||
|       axisTick: { | ||||
|         show: false, | ||||
|       }, | ||||
|       axisLine: { | ||||
|         show: true, | ||||
|         lineStyle: { | ||||
|           color: 'rgba(107,107,107,0.37)', | ||||
|         }, | ||||
|       }, | ||||
|       axisLabel: { | ||||
|         textStyle: { | ||||
|           color: '#999', | ||||
|         }, | ||||
|       }, | ||||
|       splitLine: { | ||||
|         show: false, | ||||
|       }, | ||||
|     }, | ||||
|   ], | ||||
|   series: [ | ||||
|     { | ||||
|       name: '茎秆高度', | ||||
|       type: 'line', | ||||
|       data: [10, 10, 30, 12, 15, 3], | ||||
|       symbolSize: 1, | ||||
|       symbol: 'circle', | ||||
|       smooth: true, | ||||
|       yAxisIndex: 0, | ||||
|       showSymbol: false, | ||||
|       lineStyle: { | ||||
|         width: 5, | ||||
|         color: '#3685FE', | ||||
|         shadowColor: 'rgba(158,135,255, 0.3)', | ||||
|         shadowBlur: 10, | ||||
|         shadowOffsetY: 20, | ||||
|       }, | ||||
|       itemStyle: { | ||||
|         color: colorList[0], | ||||
|         borderColor: colorList[0], | ||||
|       }, | ||||
|     }, | ||||
|     { | ||||
|       name: '叶片温度', | ||||
|       type: 'line', | ||||
|       data: [5, 12, 11, 14, 25, 16], | ||||
|       symbolSize: 1, | ||||
|       symbol: 'circle', | ||||
|       smooth: true, | ||||
|       yAxisIndex: 0, | ||||
|       showSymbol: false, | ||||
|       lineStyle: { | ||||
|         width: 5, | ||||
|         color: '#FFD500', | ||||
|         shadowColor: 'rgba(115,221,255, 0.3)', | ||||
|         shadowBlur: 10, | ||||
|         shadowOffsetY: 20, | ||||
|       }, | ||||
|       itemStyle: { | ||||
|         color: colorList[1], | ||||
|         borderColor: colorList[1], | ||||
|       }, | ||||
|     }, | ||||
|     { | ||||
|       name: '果实大小', | ||||
|       type: 'line', | ||||
|       data: [6, 14, 17, 25, 21, 10], | ||||
|       symbolSize: 1, | ||||
|       symbol: 'circle', | ||||
|       smooth: true, | ||||
|       yAxisIndex: 0, | ||||
|       showSymbol: false, | ||||
|       lineStyle: { | ||||
|         width: 5, | ||||
|         color: '#25BF82', | ||||
|         shadowColor: 'rgba(115,221,255, 0.3)', | ||||
|         shadowBlur: 10, | ||||
|         shadowOffsetY: 20, | ||||
|       }, | ||||
|       itemStyle: { | ||||
|         color: colorList[2], | ||||
|         borderColor: colorList[2], | ||||
|       }, | ||||
|     }, | ||||
|   ], | ||||
| }; | ||||
| 
 | ||||
| // #endregion | ||||
| /* --------------- methods --------------- */ | ||||
| // #region | ||||
| // 初始化图表 | ||||
| const initChart = () => { | ||||
|   if (chartRef1.value) { | ||||
|     // 基于准备好的dom,初始化echarts实例 | ||||
|     chartInstance = echarts.init(chartRef1.value); | ||||
|     // 绘制图表 | ||||
|     chartInstance.setOption(option); | ||||
|     // 自动显示最大值点的tooltip | ||||
|     // showMaxValueTooltip(); | ||||
|     // 响应式调整 | ||||
|     window.addEventListener('resize', resizeChart); | ||||
|   } | ||||
| const changeDevice = (params) => { | ||||
|   console.log(params); | ||||
|   textData.value = generateCropReport(); | ||||
| }; | ||||
| 
 | ||||
| const showMaxValueTooltip = () => { | ||||
|   if (!chartInstance) return; | ||||
| 
 | ||||
|   // 找出所有系列中的最大值点 | ||||
|   let maxValue = -Infinity; | ||||
|   let maxSeriesIndex = 0; | ||||
|   let maxDataIndex = 0; | ||||
| 
 | ||||
|   option.series.forEach((series, seriesIndex) => { | ||||
|     series.data.forEach((value, dataIndex) => { | ||||
|       if (value > maxValue) { | ||||
|         maxValue = value; | ||||
|         maxSeriesIndex = seriesIndex; | ||||
|         maxDataIndex = dataIndex; | ||||
|       } | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   // 延迟执行确保图表渲染完成 | ||||
|   setTimeout(() => { | ||||
|     chartInstance.dispatchAction({ | ||||
|       type: 'showTip', | ||||
|       seriesIndex: maxSeriesIndex, | ||||
|       dataIndex: maxDataIndex, | ||||
|     }); | ||||
|   }, 300); | ||||
| // 生成模拟数据 | ||||
| // 农业知识库 | ||||
| const AGRICULTURE_KNOWLEDGE = { | ||||
|   crops: ['橙子', '蓝莓', '水稻', '番茄', '小麦', '苹果', '葡萄'], | ||||
|   plantTypes: { | ||||
|     橙子: '乔木型', | ||||
|     蓝莓: '灌木型', | ||||
|     水稻: '禾本型', | ||||
|     番茄: '藤本型', | ||||
|     小麦: '草本型', | ||||
|     苹果: '乔木型', | ||||
|     葡萄: '藤本型', | ||||
|   }, | ||||
|   leafTypes: { | ||||
|     橙子: '革质叶', | ||||
|     蓝莓: '卵形叶', | ||||
|     水稻: '线形叶', | ||||
|     番茄: '羽状叶', | ||||
|     小麦: '披针叶', | ||||
|     苹果: '椭圆形叶', | ||||
|     葡萄: '掌状叶', | ||||
|   }, | ||||
|   growthStages: { | ||||
|     橙子: ['幼苗期', '生长期', '开花期', '结果期'], | ||||
|     蓝莓: ['萌芽期', '开花期', '果实膨大期', '成熟期'], | ||||
|     水稻: ['分蘖期', '拔节期', '抽穗期', '灌浆期'], | ||||
|     番茄: ['育苗期', '定植期', '开花坐果期', '采收期'], | ||||
|     小麦: ['出苗期', '越冬期', '返青期', '成熟期'], | ||||
|     苹果: ['花芽期', '展叶期', '果实发育期', '成熟期'], | ||||
|     葡萄: ['萌芽期', '新梢生长期', '果实生长期', '成熟期'], | ||||
|   }, | ||||
|   organicMatterRange: { | ||||
|     橙子: [12, 20], | ||||
|     蓝莓: [8, 15], | ||||
|     水稻: [15, 25], | ||||
|     番茄: [10, 18], | ||||
|     小麦: [18, 30], | ||||
|     苹果: [10, 22], | ||||
|     葡萄: [12, 18], | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| // 组件挂载时初始化图表 | ||||
| onMounted(() => { | ||||
|   initChart(); | ||||
| // 生成单组作物数据 | ||||
| function generateCropReport() { | ||||
|   const crop = Mock.Random.pick(AGRICULTURE_KNOWLEDGE.crops); | ||||
|   const isHealthy = Mock.Random.integer(0, 10) > 1; // 80%概率健康 | ||||
|   const growthStage = Mock.Random.pick(AGRICULTURE_KNOWLEDGE.growthStages[crop]); | ||||
| 
 | ||||
|   // 异常数据生成 | ||||
|   const abnormalTexts = { | ||||
|     growth: ['发育迟缓', '生长停滞', '提前成熟'], | ||||
|     leaf: ['枯黄', '卷曲', '病斑'], | ||||
|     status: ['欠佳', '受阻', '严重滞后'], | ||||
|     organic: ['过低', '严重不足', '失衡'], | ||||
|   }; | ||||
| 
 | ||||
|   return [ | ||||
|     { | ||||
|       title: '作物名称', | ||||
|       status: isHealthy ? 1 : 0, | ||||
|       statusText: crop, | ||||
|     }, | ||||
|     { | ||||
|       title: '生长状态', | ||||
|       status: isHealthy ? 1 : 0, | ||||
|       statusText: isHealthy ? growthStage : `${Mock.Random.pick(abnormalTexts.growth)}${growthStage}`, | ||||
|     }, | ||||
|     { | ||||
|       title: '植株形态', | ||||
|       status: isHealthy ? 1 : 0, | ||||
|       statusText: AGRICULTURE_KNOWLEDGE.plantTypes[crop], | ||||
|     }, | ||||
|     { | ||||
|       title: '叶片形态', | ||||
|       status: isHealthy ? 1 : 0, | ||||
|       statusText: isHealthy | ||||
|         ? AGRICULTURE_KNOWLEDGE.leafTypes[crop] | ||||
|         : `${Mock.Random.pick(abnormalTexts.leaf)}${AGRICULTURE_KNOWLEDGE.leafTypes[crop]}`, | ||||
|     }, | ||||
|     { | ||||
|       title: '生长态势', | ||||
|       status: isHealthy ? 1 : 0, | ||||
|       statusText: isHealthy ? '良好' : Mock.Random.pick(abnormalTexts.status), | ||||
|     }, | ||||
|     { | ||||
|       title: '田间有机质含量', | ||||
|       status: isHealthy ? 1 : 0, | ||||
|       statusText: isHealthy | ||||
|         ? `${Mock.Random.integer(...AGRICULTURE_KNOWLEDGE.organicMatterRange[crop])}%` | ||||
|         : `${Mock.Random.integer(3, 8)}% (${Mock.Random.pick(abnormalTexts.organic)})`, | ||||
|     }, | ||||
|     { | ||||
|       title: '生长趋势图', | ||||
|       status: isHealthy ? 1 : 0, | ||||
|       statusText: '', | ||||
|     }, | ||||
|   ]; | ||||
| } | ||||
| 
 | ||||
| // 生成7组不同作物数据 | ||||
| const cropMonitoringData = Mock.mock({ | ||||
|   'data|7': [generateCropReport], | ||||
| }); | ||||
| // 组件卸载前销毁图表 | ||||
| onBeforeUnmount(() => { | ||||
|   if (chartInstance) { | ||||
|     window.removeEventListener('resize', resizeChart); | ||||
|     chartInstance.dispose(); | ||||
|     chartInstance = null; | ||||
|   } | ||||
| }); | ||||
| // 调整图表大小 | ||||
| const resizeChart = () => { | ||||
|   if (chartInstance) { | ||||
|     chartInstance.resize(); | ||||
|   } | ||||
| }; | ||||
| // #endregion | ||||
| </script> | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user