<script setup>
|
import {ref, onMounted, watch} from "vue";
|
import * as echarts from 'echarts/core';
|
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(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 setChartsRef = (el, index) => {
|
if (el) {
|
chartsRef.value[index] = el
|
charts[index] = 'charts' + index
|
}
|
}
|
|
// 获取图表配置
|
const getChartsOptions = (data, unit) => {
|
let xdata = [];
|
let Hdata = [];
|
let Adata = [];
|
let Ldata = [];
|
if (data) {
|
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: {
|
left: '4%',
|
right: '5%',
|
bottom: '3%',
|
containLabel: true
|
},
|
xAxis: {
|
type: 'category',
|
boundaryGap: false,
|
data: xdata,
|
axisLabel: {
|
color: '#fff',
|
fontSize: '1rem'
|
}
|
},
|
yAxis: {
|
type: 'value',
|
name: unit,
|
max: 40,
|
min: 0,
|
nameTextStyle: {
|
color: '#fff',
|
fontSize: '1rem'
|
},
|
axisLabel: {
|
color: '#fff',
|
fontSize: '1rem'
|
}
|
},
|
series: [
|
{
|
name: '最高水温',
|
data: Hdata,
|
type: 'line',
|
areaStyle: {
|
opacity: 0.8,
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
{
|
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;
|
showTime.value = ''
|
}
|
|
// 初始化图表
|
const initCharts = () => {
|
chartData.value.forEach((item, index) => {
|
if (chartsRef.value[index]) {
|
charts[index] = echarts.init(chartsRef.value[index])
|
const option = getChartsOptions(item, '℃')
|
charts[index].setOption(option)
|
}
|
})
|
}
|
|
// 全屏操作
|
const handleFullScreen = () => {
|
graphicRef.value.requestFullscreen()
|
}
|
|
// 一键导出
|
const handleExport = () => {
|
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 getTempMonitor = () => {
|
getTemperaturePointList().then(res => {
|
menuList.value = res.data
|
})
|
}
|
|
// 获取报表数据
|
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()
|
getChartData()
|
})
|
|
</script>
|
|
<template>
|
<div class="graphic">
|
<div class="graphic-menu">
|
<div class="menu-t">监测点列表</div>
|
<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>
|
</template>
|
<template v-else>
|
<el-sub-menu :index="item.id">
|
<template #title>
|
<span>{{ item.pointName }}</span>
|
</template>
|
<el-menu-item v-for="(child, cidx) in item.childrenList" :key="cidx" :index="child.id">
|
{{ child.pointName }}
|
</el-menu-item>
|
</el-sub-menu>
|
</template>
|
</template>
|
</el-menu>
|
</div>
|
<div class="graphic-info">
|
<div class="graphic-tool">
|
<div class="tool-l">
|
<div class="name">时间类型</div>
|
<el-button-group class="ml-4">
|
<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 === 1"
|
v-model="showTime"
|
type="date"
|
placeholder="选择时间"
|
style="width: 15rem"
|
@change="getTime"
|
/>
|
<el-date-picker
|
v-if="timeType === 2"
|
v-model="showTime"
|
type="week"
|
format="YYYY年 ww[周]"
|
placeholder="选择时间"
|
style="width: 15rem"
|
@change="getTime"
|
/>
|
<el-date-picker
|
v-if="timeType === 3"
|
v-model="showTime"
|
type="month"
|
placeholder="选择时间"
|
style="width: 15rem"
|
@change="getTime"
|
/>
|
<Quarter
|
v-if="timeType === 4"
|
placeholder="选择时间"
|
:default-value="showTime"
|
clearable
|
style="width: 15rem"
|
@change="getTime"
|
/>
|
<el-date-picker
|
v-if="timeType === 5"
|
v-model="showTime"
|
type="year"
|
placeholder="选择时间"
|
style="width: 15rem"
|
@change="getTime"
|
/>
|
<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">
|
<img src="@/assets/images/flow/fullscreen.png"/>
|
全屏
|
</div>
|
</div>
|
<div class="graphic-box" ref="graphicRef">
|
<div class="chartList">
|
<div class="chartItem" v-for="(item, index) in chartData">
|
<div class="charts" :ref="el => setChartsRef(el, index)"></div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<style scoped lang="scss">
|
.graphic {
|
height: 100%;
|
display: flex;
|
|
&-menu {
|
flex-shrink: 0;
|
width: 20%;
|
height: 100%;
|
padding: 10px 0;
|
background: linear-gradient(135deg, #91BDDB 0%, #9EC2DB 99%);
|
overflow-y: scroll;
|
|
&::-webkit-scrollbar {
|
display: none;
|
}
|
|
.menu-t {
|
height: 40px;
|
line-height: 40px;
|
padding-left: 20px;
|
font-size: 26px;
|
color: #fff;
|
background: url("@/assets/images/flow/monitor-title-bg.png") no-repeat;
|
background-size: 100% 100%;
|
}
|
|
.el-menu {
|
background-color: transparent;
|
border-right: none;
|
|
:deep(.el-menu) {
|
background-color: transparent;
|
}
|
|
:deep(.el-sub-menu__title:hover) {
|
background-color: rgba(0, 0, 0, 0.06);
|
}
|
|
:deep(.el-menu-item.is-active) {
|
color: #fff;
|
}
|
}
|
}
|
|
.graphic-info {
|
flex-shrink: 0;
|
width: 80%;
|
height: 100%;
|
|
.graphic-tool {
|
width: 100%;
|
height: 60px;
|
padding: 0 30px;
|
background: linear-gradient(90deg, #91BDDB 0%, #DADFE3 100%);
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
|
.tool-l {
|
display: flex;
|
align-items: center;
|
gap: 1rem;
|
|
.name {
|
font-size: 1.1rem;
|
}
|
}
|
|
.tool-r {
|
display: flex;
|
align-items: center;
|
|
img {
|
width: 25px;
|
margin-right: 10px;
|
}
|
}
|
}
|
|
.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: 100%;
|
min-height: 48%;
|
background: rgba(23, 108, 229, 0.3);
|
border: 1px solid #176CE5;
|
border-radius: 8px;
|
|
.charts {
|
height: 100%;
|
}
|
}
|
}
|
}
|
}
|
}
|
</style>
|