1 files added
1 files modified
| | |
| | | component: () => import('@/views/charts/index'), |
| | | meta: { title: '监测因子趋势', icon: 'example' } |
| | | } |
| | | const radar = { |
| | | path: 'charts/radar', |
| | | name: 'radar', |
| | | component: () => import('@/views/radar/index'), |
| | | meta: { title: '雷达趋势', icon: 'example' } |
| | | } |
| | | |
| | | const contrast = { |
| | | path: 'charts/contrast', |
| | |
| | | const ruleMapping = { |
| | | wind: wind, |
| | | car: car, |
| | | radar: radar, |
| | | UAV: UAV, |
| | | tend: tend, |
| | | contrast: contrast, |
| New file |
| | |
| | | <template> |
| | | <div |
| | | id="chartTableContent" |
| | | style="width: 100%; height: 100%" |
| | | > |
| | | <div class="topSelect"> |
| | | |
| | | <el-input-number |
| | | v-model="high1" |
| | | :min="0" |
| | | :max="15000" |
| | | label="最低高度" |
| | | style="width: 130px; margin-left: 10px" |
| | | controls-position="right" |
| | | ></el-input-number> |
| | | <el-input-number |
| | | v-model="high2" |
| | | :min="0" |
| | | :max="15000" |
| | | label="最高高度" |
| | | style="width: 130px; margin-left: 10px" |
| | | controls-position="right" |
| | | ></el-input-number> |
| | | <component |
| | | :is="dataType" |
| | | ref="picker" |
| | | style="padding-left: 0; margin-left: 20px; width: 160px" |
| | | class="select11" |
| | | @sendPickerChild="showPickerChild" |
| | | |
| | | /> |
| | | <!--查询按钮--> |
| | | <el-button |
| | | class="btn1" |
| | | @click="selectData" |
| | | > |
| | | 查询 |
| | | </el-button> |
| | | </div> |
| | | <div class="pm-profile"> |
| | | <h2 >PM2.5 / PM10 垂直剖面动态演化图</h2> |
| | | <div ref="chart" class="chart-container"></div> |
| | | <div class="controls"> |
| | | <p>底部时间轴可拖拽,自动播放</p> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import * as echarts from 'echarts' |
| | | import HourPicker from '@/components/Form/HourPicker1' |
| | | export default { |
| | | name: 'PMProfile', |
| | | components: { |
| | | HourPicker |
| | | }, |
| | | props: { |
| | | chartData: { |
| | | type: Object, |
| | | default: null |
| | | } |
| | | }, |
| | | data() { |
| | | |
| | | return { |
| | | chart: null, |
| | | dataType: 'HourPicker', |
| | | defaultData: {}, |
| | | newData: [], |
| | | high1: 100, |
| | | high2: 3000, |
| | | timeList: null, |
| | | currentTimeIdx: 0 |
| | | }; |
| | | }, |
| | | watch: { |
| | | select1 (nv, ov) { |
| | | this.unit = 'FiveMinute' |
| | | } |
| | | }, |
| | | computed: { |
| | | chartDataResolved() { |
| | | return this.chartData || this.defaultData; |
| | | } |
| | | }, |
| | | mounted() { |
| | | const now = new Date(); |
| | | const startTime = new Date(now.getTime() - 20 * 60 * 1000); |
| | | const fmt = (d) => { |
| | | const Y = d.getFullYear(); |
| | | const M = String(d.getMonth() + 1).padStart(2, '0'); |
| | | const D = String(d.getDate()).padStart(2, '0'); |
| | | const h = String(d.getHours()).padStart(2, '0'); |
| | | const m = String(d.getMinutes()).padStart(2, '0'); |
| | | const s = String(d.getSeconds()).padStart(2, '0'); |
| | | return `${Y}-${M}-${D} ${h}:${m}:${s}`; |
| | | }; |
| | | const defaultVal = [fmt(startTime), fmt(now)]; |
| | | this.$refs.picker.value1 = defaultVal; |
| | | this.$nextTick(() => this.selectData()); |
| | | }, |
| | | beforeDestroy() { |
| | | if (this.chart) { |
| | | this.chart.dispose(); |
| | | this.chart = null; |
| | | } |
| | | }, |
| | | |
| | | methods: { |
| | | initChart() { |
| | | const DATA = this.chartDataResolved; |
| | | const chartEl = this.$refs.chart; |
| | | if (!chartEl) return; |
| | | |
| | | const chartLib = this.$echarts || echarts; |
| | | if (!chartLib || !chartLib.init) return; |
| | | |
| | | if (this.chart) { |
| | | this.chart.dispose(); |
| | | this.chart = null; |
| | | } |
| | | this.chart = chartLib.init(chartEl); |
| | | if (!DATA || !DATA.time||!DATA.time.length) { |
| | | this.chart.setOption({ |
| | | graphic: { |
| | | type: 'text', |
| | | left: 'center', |
| | | top: 'center', |
| | | style: { |
| | | text: '未查询到数据', |
| | | fontSize: 18, |
| | | fill: '#909399' |
| | | } |
| | | } |
| | | }); |
| | | return; |
| | | } |
| | | this.timeList = DATA.time; |
| | | this.currentTimeIdx = 0; |
| | | this.chart.setOption({ |
| | | baseOption: { |
| | | timeline: { |
| | | axisType: 'category', |
| | | autoPlay: true, |
| | | playInterval: 1000, |
| | | data: DATA.time, |
| | | label: { |
| | | formatter: function (s) { return s.slice(0, 5); } |
| | | }, |
| | | checkpointStyle: { borderColor: '#fff', borderWidth: 2 }, |
| | | controlStyle: { showNextBtn: true, showPrevBtn: true } |
| | | }, |
| | | title: { text: '', left: 'center', top: 0 }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | formatter: (params) => { |
| | | const time = this.timeList ? this.timeList[this.currentTimeIdx] : ''; |
| | | var res = '时间: ' + time + '<br>'; |
| | | params.forEach(function (p) { |
| | | res += '<span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:' + p.color + ';margin-right:4px"></span> ' |
| | | + p.seriesName + ': ' + p.value[0] + ' μg/m³ @ ' + p.value[1] + 'm<br>'; |
| | | }); |
| | | return res; |
| | | } |
| | | }, |
| | | legend: { data: ['PM2.5', 'PM10'], top: 35 }, |
| | | grid: { top: 60, bottom: 100, left: 50, right: 50 }, |
| | | xAxis: { type: 'value', name: '浓度 (μg/m³)', position: 'top', splitLine: { show: true } }, |
| | | //yAxis: { type: 'value', name: '高度 (m)', splitLine: { show: true } }, |
| | | yAxis: { type: 'value', name: '高度 (m)', min: this.high1, max: this.high2, splitLine: { show: true } }, |
| | | series: [ |
| | | { |
| | | name: 'PM2.5', type: 'line', smooth: true, symbol: 'circle', symbolSize: 6, |
| | | lineStyle: { width: 3, color: '#ef4444' }, itemStyle: { color: '#ef4444' }, |
| | | areaStyle: { color: 'rgba(239,68,68,0.2)' }, data: [] |
| | | }, |
| | | { |
| | | name: 'PM10', type: 'line', smooth: true, symbol: 'circle', symbolSize: 6, |
| | | lineStyle: { width: 3, color: '#3b82f6' }, itemStyle: { color: '#3b82f6' }, |
| | | areaStyle: { color: 'rgba(59,130,246,0.2)' }, data: [] |
| | | } |
| | | ] |
| | | }, |
| | | options: DATA.time.map(function (time, idx) { |
| | | return { |
| | | title: { text: '当前时间: ' + time }, |
| | | series: [ |
| | | { data: DATA.pm25[idx] }, |
| | | { data: DATA.pm10[idx] } |
| | | ] |
| | | }; |
| | | }) |
| | | }); |
| | | |
| | | this.chart.on('timelinechanged', (params) => { |
| | | this.currentTimeIdx = params.currentIndex; |
| | | }); |
| | | }, |
| | | selectData () { |
| | | |
| | | this.$request({ |
| | | url: '/historyRadar/list', |
| | | method: 'post', |
| | | data: { |
| | | startTime: this.newData[0], |
| | | endTime: this.newData[1], |
| | | high1: this.high1, |
| | | high2: this.high2 |
| | | } |
| | | }) |
| | | .then((res) => { |
| | | |
| | | this.defaultData = res.data |
| | | this.$nextTick(() => this.initChart()); |
| | | }).catch((err) => { |
| | | |
| | | }) |
| | | }, |
| | | showPickerChild (data) { |
| | | this.newData = data |
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .pm-profile { |
| | | width: 100%; |
| | | background: #fff; |
| | | padding: 20px; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); |
| | | } |
| | | .pm-profile h2 { |
| | | text-align: center; |
| | | color: #303133; |
| | | margin: 0 0 20px 0; |
| | | font-size: 20px; |
| | | } |
| | | .chart-container { |
| | | width: 100%; |
| | | height: 600px; |
| | | } |
| | | .controls { |
| | | text-align: center; |
| | | margin-top: 10px; |
| | | color: #909399; |
| | | font-size: 14px; |
| | | } |
| | | .controls p { |
| | | margin: 0; |
| | | } |
| | | .topSelect { |
| | | display: flex; |
| | | margin-bottom: 20px; |
| | | padding: 20px 15px 0 15px; |
| | | } |
| | | .select11 { |
| | | width: 20% !important; |
| | | } |
| | | </style> |