| | |
| | | <script setup> |
| | | import {ref, reactive, onMounted} from "vue"; |
| | | import {ref, onMounted, watch} from "vue"; |
| | | import * as echarts from 'echarts/core'; |
| | | import html2canvas from "html2canvas"; |
| | | import {getTemperaturePointList} from '@/api/screen/index.js' |
| | | import Quarter from "@/components/Quarter"; |
| | | import moment from "moment"; |
| | | import { getGraphicData } from '@/api/screen/graphic/index.js' |
| | | |
| | | |
| | | const menuList = ref([]) |
| | | const timeType = ref('date') |
| | | const timeRange = ref() |
| | | const timeType = ref(1) //时间类型 1日 2周 3月 4季 5年 |
| | | const showTime = ref(moment().format('YYYY-MM-DD')); //展示时间 |
| | | const timeValue = ref(moment().format('YYYY-MM-DD')) //处理后得时间 |
| | | const searchVal = ref() |
| | | const graphicRef = ref(null) |
| | | const chartsRef = ref([]) //动态生成图表ref |
| | | const chartData = ref([]) |
| | | let charts = [] |
| | | |
| | | // 动态设置ref |
| | |
| | | } |
| | | } |
| | | |
| | | const data = [ |
| | | [ {name: '一月', value: 22}, {name: '二月', value: 38}, {name: '三月', value: 31}, ], |
| | | [ {name: '一月', value: 22}, {name: '二月', value: 38}, {name: '三月', value: 31}, ], |
| | | [ {name: '一月', value: 22}, {name: '二月', value: 38}, {name: '三月', value: 31}, ], |
| | | [ {name: '一月', value: 22}, {name: '二月', value: 38}, {name: '三月', value: 31}, ], |
| | | [ {name: '一月', value: 22}, {name: '二月', value: 38}, {name: '三月', value: 31}, ], |
| | | [ {name: '一月', value: 22}, {name: '二月', value: 38}, {name: '三月', value: 31}, ], |
| | | ] |
| | | |
| | | // 获取图表配置 |
| | | const getChartsOptions = (data, unit, maxData, minData=0) => { |
| | | const getChartsOptions = (data, unit) => { |
| | | let xdata = []; |
| | | let sdata = []; |
| | | let Hdata = []; |
| | | let Adata = []; |
| | | let Ldata = []; |
| | | if(data) { |
| | | data.forEach(item => { |
| | | xdata.push(item.name) |
| | | sdata.push(item.value); |
| | | data.dataVOList.forEach(item => { |
| | | xdata.push(item.dataTime) |
| | | Hdata.push(item.maxValue); |
| | | Adata.push(item.avgValue); |
| | | Ldata.push(item.minValue); |
| | | }) |
| | | } |
| | | return { |
| | | title: { |
| | | text: data.pointName, |
| | | left: '3%', |
| | | textStyle: { |
| | | color: '#fff', |
| | | } |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | }, |
| | | color: ['#D4B3E3FF', '#00DDFFFF', '#ABFA97FF'], |
| | | legend: { |
| | | top: 0, |
| | | data: ['最高水温', '平均水温', '最低水温'], |
| | | textStyle: { |
| | | color: '#fff' |
| | | } |
| | | }, |
| | | grid: { |
| | | top: 50, |
| | | left: 50, |
| | | right: 50, |
| | | bottom: 40 |
| | | left: '4%', |
| | | right: '5%', |
| | | bottom: '3%', |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | |
| | | yAxis: { |
| | | type: 'value', |
| | | name: unit, |
| | | max: 40, |
| | | min: 0, |
| | | nameTextStyle: { |
| | | color: '#fff', |
| | | fontSize: '1rem' |
| | |
| | | }, |
| | | series: [ |
| | | { |
| | | data: sdata, |
| | | name: '最高水温', |
| | | data: Hdata, |
| | | type: 'line', |
| | | areaStyle: {}, |
| | | } |
| | | ], |
| | | visualMap: [ |
| | | areaStyle: { |
| | | opacity: 0.8, |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | type: 'piecewise', |
| | | show: false, |
| | | dimension: 1, |
| | | seriesIndex: 0, |
| | | pieces: [ |
| | | {max: minData, color: 'red'}, |
| | | { min: maxData, color: 'red'} |
| | | ], |
| | | outOfRange: { // 在选中范围外 的视觉元素,这里设置在正常范围内的图形颜色 |
| | | color: '#8EE5FA' |
| | | offset: 0, |
| | | color: 'rgb(212,179,227)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(212,179,227,0)' |
| | | } |
| | | ]) |
| | | }, |
| | | }, |
| | | { |
| | | name: '平均水温', |
| | | data: Adata, |
| | | type: 'line', |
| | | areaStyle: { |
| | | opacity: 0.8, |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: 'rgb(0, 221, 255)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(0,221,255,0)' |
| | | } |
| | | ], |
| | | ]) |
| | | }, |
| | | }, |
| | | { |
| | | name: '最低水温', |
| | | data: Ldata, |
| | | type: 'line', |
| | | areaStyle: { |
| | | opacity: 0.8, |
| | | color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
| | | { |
| | | offset: 0, |
| | | color: 'rgb(171,250,151)' |
| | | }, |
| | | { |
| | | offset: 1, |
| | | color: 'rgba(171,250,151,0)' |
| | | } |
| | | ]) |
| | | }, |
| | | } |
| | | ] |
| | | } |
| | | } |
| | | |
| | | // 选择时间类型 |
| | | const changeType = (type) => { |
| | | timeType.value = type; |
| | | timeRange.value = '' |
| | | showTime.value = '' |
| | | } |
| | | |
| | | // 初始化图表 |
| | | const initCharts = () => { |
| | | data.forEach((item, index) => { |
| | | chartData.value.forEach((item, index) => { |
| | | if(chartsRef.value[index]) { |
| | | charts[index] = echarts.init(chartsRef.value[index]) |
| | | const option = getChartsOptions(item, '℃', 35) |
| | | const option = getChartsOptions(item, '℃') |
| | | charts[index].setOption(option) |
| | | } |
| | | }) |
| | |
| | | |
| | | // 一键导出 |
| | | const handleExport = () => { |
| | | chartsRef.value?.forEach((item, index) => { |
| | | html2canvas(item, { |
| | | scale: 2, // 提高渲染质量 |
| | | useCORS: true, // 如果需要跨域资源 |
| | | allowTaint: true, // 如果需要处理跨域图片 |
| | | backgroundColor: 'rgba(23, 108, 229, 0.3)' //背景色 |
| | | }).then(canvas => { |
| | | const link = document.createElement("a"); |
| | | link.href = canvas.toDataURL("image/png"); |
| | | link.download = `图表分析${index}.png`; |
| | | link.click() |
| | | charts?.forEach((chart, index) => { |
| | | const imgData = chart.getDataURL({ |
| | | type: 'png', // 也可以是 'jpeg' |
| | | pixelRatio: 2, // 提高导出图片的分辨率 |
| | | backgroundColor: 'rgba(23, 108, 229, 0.3)' |
| | | }); |
| | | |
| | | // 创建下载链接 |
| | | const link = document.createElement('a'); |
| | | link.href = imgData; |
| | | link.download = `chart_${index + 1}.png`; |
| | | link.click(); |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 获取时间 |
| | | const getTime = (value) => { |
| | | const momentValue = moment(value) |
| | | const time = momentValue.format('YYYY-MM-DD') |
| | | let data = '' |
| | | switch (timeType.value) { |
| | | case 1: |
| | | data = '' |
| | | break; |
| | | case 2: |
| | | data = momentValue.add(1, 'week').format('YYYY-MM-DD') |
| | | break; |
| | | case 3: |
| | | data = momentValue.add(1, 'month').format('YYYY-MM-DD') |
| | | break; |
| | | case 4: |
| | | data = momentValue.add(1, 'quarter').format('YYYY-MM-DD') |
| | | break; |
| | | case 5: |
| | | data = momentValue.add(1, 'year').format('YYYY-MM-DD') |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | if(data) { |
| | | timeValue.value = time + '~' + data |
| | | } else { |
| | | timeValue.value = time |
| | | } |
| | | } |
| | | |
| | | // 获取水温监控点菜单 |
| | |
| | | }) |
| | | } |
| | | |
| | | // 获取时间 |
| | | const getTime = (value) => { |
| | | const time = moment(value).format('YYYY-MM-DD') |
| | | console.log(time) |
| | | // 获取报表数据 |
| | | const getChartData = (point = '') => { |
| | | const data = { |
| | | type: timeType.value, |
| | | pointId: point, |
| | | pointName: searchVal.value, |
| | | dataTime: timeValue.value, |
| | | } |
| | | getGraphicData(data).then(async res => { |
| | | chartData.value = res.data |
| | | await nextTick() |
| | | initCharts() |
| | | }) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getTempMonitor() |
| | | initCharts() |
| | | getChartData() |
| | | }) |
| | | |
| | | </script> |
| | |
| | | <div class="graphic"> |
| | | <div class="graphic-menu"> |
| | | <div class="menu-t">监测点列表</div> |
| | | <el-menu class="el-menu"> |
| | | <el-menu class="el-menu" @select="getChartData"> |
| | | <template v-for="(item, index) in menuList" :key="index+1"> |
| | | <template v-if="item?.childrenList?.length === 0"> |
| | | <el-menu-item :index="item.id">{{ item.pointName }}</el-menu-item> |
| | |
| | | <div class="tool-l"> |
| | | <div class="name">类型</div> |
| | | <el-button-group class="ml-4"> |
| | | <el-button :type="timeType === 'date' ? 'primary' : ''" @click="changeType('date')">日</el-button> |
| | | <el-button :type="timeType === 'week' ? 'primary' : ''" @click="changeType('week')">周</el-button> |
| | | <el-button :type="timeType === 'month' ? 'primary' : ''" @click="changeType('month')">月</el-button> |
| | | <el-button :type="timeType === 'quarter' ? 'primary' : ''" @click="changeType('quarter')">季</el-button> |
| | | <el-button :type="timeType === 'year' ? 'primary' : ''" @click="changeType('year')">年</el-button> |
| | | <el-button :type="timeType === 1 ? 'primary' : ''" @click="changeType(1)">日 |
| | | </el-button> |
| | | <el-button :type="timeType === 2 ? 'primary' : ''" @click="changeType(2)">周 |
| | | </el-button> |
| | | <el-button :type="timeType === 3 ? 'primary' : ''" @click="changeType(3)">月 |
| | | </el-button> |
| | | <el-button :type="timeType === 4 ? 'primary' : ''" @click="changeType(4)">季 |
| | | </el-button> |
| | | <el-button :type="timeType === 5 ? 'primary' : ''" @click="changeType(5)">年 |
| | | </el-button> |
| | | </el-button-group> |
| | | <el-date-picker |
| | | v-if="timeType === 'date'" |
| | | v-model="timeRange" |
| | | v-if="timeType === 1" |
| | | v-model="showTime" |
| | | type="date" |
| | | placeholder="选择时间" |
| | | style="width: 15rem" |
| | | @change="getTime" |
| | | /> |
| | | <el-date-picker |
| | | v-if="timeType === 'week'" |
| | | v-model="timeRange" |
| | | v-if="timeType === 2" |
| | | v-model="showTime" |
| | | type="week" |
| | | format="YYYY年 ww[周]" |
| | | placeholder="选择时间" |
| | |
| | | @change="getTime" |
| | | /> |
| | | <el-date-picker |
| | | v-if="timeType === 'month'" |
| | | v-model="timeRange" |
| | | v-if="timeType === 3" |
| | | v-model="showTime" |
| | | type="month" |
| | | placeholder="选择时间" |
| | | style="width: 15rem" |
| | | @change="getTime" |
| | | /> |
| | | <Quarter |
| | | v-if="timeType === 'quarter'" |
| | | v-if="timeType === 4" |
| | | placeholder="选择时间" |
| | | :default-value="timeRange" |
| | | :default-value="showTime" |
| | | clearable |
| | | style="width: 15rem" |
| | | @change="getTime" |
| | | /> |
| | | <el-date-picker |
| | | v-if="timeType === 'year'" |
| | | v-model="timeRange" |
| | | v-if="timeType === 5" |
| | | v-model="showTime" |
| | | type="year" |
| | | placeholder="选择时间" |
| | | style="width: 15rem" |
| | | @change="getTime" |
| | | /> |
| | | <el-input v-model="searchVal" style="width: 15rem" placeholder="请输入监测点名称" /> |
| | | <el-button><el-icon><Search /></el-icon>搜索</el-button> |
| | | <el-input v-model="searchVal" style="width: 15rem" clearable placeholder="请输入监测点名称"/> |
| | | <el-button @click="() => getChartData()"> |
| | | <el-icon> |
| | | <Search/> |
| | | </el-icon> |
| | | 搜索 |
| | | </el-button> |
| | | <el-button type="success" @click="handleExport">一键导出</el-button> |
| | | </div> |
| | | <div class="tool-r" @click="handleFullScreen"> |
| | |
| | | </div> |
| | | <div class="graphic-box" ref="graphicRef"> |
| | | <div class="chartList"> |
| | | <div class="chartItem" v-for="(item, index) in data"> |
| | | <div class="chartItem" v-for="(item, index) in chartData"> |
| | | <div class="charts" :ref="el => setChartsRef(el, index)"></div> |
| | | <div class="name">标题</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | .graphic { |
| | | height: 100%; |
| | | display: flex; |
| | | |
| | | &-menu { |
| | | flex-shrink: 0; |
| | | width: 20%; |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | .graphic-info { |
| | | flex-shrink: 0; |
| | | width: 80%; |
| | | height: 100%; |
| | | |
| | | .graphic-tool { |
| | | width: 100%; |
| | | height: 60px; |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | .graphic-box{ |
| | | height: calc(100% - 60px); |
| | | padding: 10px 30px; |
| | | background: linear-gradient(180deg, #91BDDB 0%, rgba(102, 102, 102, 0.5) 100%); |
| | | |
| | | .chartList{ |
| | | height: 100%; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 20px; |
| | | |
| | | .chartItem{ |
| | | width: 32%; |
| | | height: 48%; |
| | | width: 100%; |
| | | min-height: 48%; |
| | | background: rgba(23,108,229,0.3); |
| | | border: 1px solid #176CE5; |
| | | border-radius: 8px; |
| | | |
| | | .charts{ |
| | | height: 90%; |
| | | } |
| | | .name{ |
| | | height: 10%; |
| | | text-align: center; |
| | | font-size: 20px; |
| | | color: #fff; |
| | | height: 100%; |
| | | } |
| | | } |
| | | } |