343 lines
9.1 KiB
Vue
343 lines
9.1 KiB
Vue
|
|
<!-- SidePanelItem.vue -->
|
|||
|
|
<template>
|
|||
|
|
<SidePanelItem title="地表水水质达标率">
|
|||
|
|
<div class="body_item">
|
|||
|
|
<div class="tabs_all">
|
|||
|
|
<div :class="tabs == 1 ? 'zhong_tabs' : 'no_tabs'" @click="handleTabChange(1)">自建水质站</div>
|
|||
|
|
<div :class="tabs == 2 ? 'zhong_tabs' : 'no_tabs'" @click="handleTabChange(2)">国家水质站</div>
|
|||
|
|
</div>
|
|||
|
|
<div v-show="tabs == 1 || tabs == 2" class="tabs_body">
|
|||
|
|
<div ref="chartRef" class="chart-container"></div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
</SidePanelItem>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script lang="ts" setup>
|
|||
|
|
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
|||
|
|
import * as echarts from 'echarts';
|
|||
|
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
|||
|
|
|
|||
|
|
// 定义组件名(便于调试和递归)
|
|||
|
|
defineOptions({
|
|||
|
|
name: 'EnvironmentalQuality'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const tabs = ref(1);
|
|||
|
|
const chartRef = ref<HTMLElement | null>(null);
|
|||
|
|
let chartInstance: echarts.ECharts | null = null;
|
|||
|
|
|
|||
|
|
// 静态数据 - 自建水质站(第1页)
|
|||
|
|
const selfBuiltData = [
|
|||
|
|
{ name: '雅砻江\n干流', current: 99, lastYear: 100 },
|
|||
|
|
{ name: '大渡河\n干流', current: 99, lastYear: 100 },
|
|||
|
|
{ name: '黄河上游\n干流', current: 99, lastYear: 100 }
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 静态数据 - 国家水质站(第2页)
|
|||
|
|
const nationalData = [
|
|||
|
|
{ name: '长江\n干流', current: 98, lastYear: 99 },
|
|||
|
|
{ name: '珠江\n干流', current: 97, lastYear: 98 },
|
|||
|
|
{ name: '淮河\n干流', current: 96, lastYear: 97 }
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 根据tab获取对应数据
|
|||
|
|
const getCurrentData = () => {
|
|||
|
|
return tabs.value === 1 ? selfBuiltData : nationalData;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 处理tab切换
|
|||
|
|
const handleTabChange = (tab: number) => {
|
|||
|
|
tabs.value = tab;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 监听tabs变化,处理图表刷新
|
|||
|
|
watch(tabs, (newVal) => {
|
|||
|
|
if (newVal === 1 || newVal === 2) {
|
|||
|
|
nextTick(() => {
|
|||
|
|
setTimeout(() => {
|
|||
|
|
if (!chartInstance) {
|
|||
|
|
initChart();
|
|||
|
|
} else {
|
|||
|
|
// 更新图表数据
|
|||
|
|
updateChartData();
|
|||
|
|
}
|
|||
|
|
}, 50);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 初始化图表
|
|||
|
|
const initChart = () => {
|
|||
|
|
if (!chartRef.value) return;
|
|||
|
|
|
|||
|
|
chartInstance = echarts.init(chartRef.value);
|
|||
|
|
|
|||
|
|
const currentData = getCurrentData();
|
|||
|
|
|
|||
|
|
const option = {
|
|||
|
|
// 图例配置
|
|||
|
|
legend: {
|
|||
|
|
top: 10,
|
|||
|
|
itemWidth: 18,
|
|||
|
|
itemHeight: 12,
|
|||
|
|
itemGap: 20,
|
|||
|
|
icon: 'roundRect',
|
|||
|
|
data: [
|
|||
|
|
{ name: '2026-04 月度', itemStyle: { color: '#4A8BC2' } },
|
|||
|
|
{ name: '去年同期', itemStyle: { color: '#9B59B6' } }
|
|||
|
|
],
|
|||
|
|
textStyle: {
|
|||
|
|
fontSize: 12,
|
|||
|
|
color: '#333'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 提示框配置
|
|||
|
|
tooltip: {
|
|||
|
|
trigger: 'axis',
|
|||
|
|
axisPointer: {
|
|||
|
|
type: 'shadow',
|
|||
|
|
shadowStyle: {
|
|||
|
|
color: 'rgba(200, 200, 200, 0.2)'
|
|||
|
|
},
|
|||
|
|
label: {
|
|||
|
|
show: false
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
backgroundColor: '#fff',
|
|||
|
|
borderColor: '#e8e8e8',
|
|||
|
|
borderWidth: 1,
|
|||
|
|
padding: 12,
|
|||
|
|
textStyle: {
|
|||
|
|
color: '#333',
|
|||
|
|
fontSize: 12
|
|||
|
|
},
|
|||
|
|
formatter: (params: any) => {
|
|||
|
|
const name = params[0].name.replace('\n', '');
|
|||
|
|
let result = `<div style="font-weight: bold; margin-bottom: 8px;">${name}</div>`;
|
|||
|
|
params.forEach((item: any) => {
|
|||
|
|
result += `<div style="display: flex; align-items: center; margin-bottom: 4px;">
|
|||
|
|
<span style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background: ${item.color}; margin-right: 8px;"></span>
|
|||
|
|
<span>${item.seriesName}:</span>
|
|||
|
|
<span style="margin-left: auto; font-weight: bold;">${item.value} %</span>
|
|||
|
|
</div>`;
|
|||
|
|
});
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 网格配置
|
|||
|
|
grid: {
|
|||
|
|
left: 60,
|
|||
|
|
right: 10,
|
|||
|
|
top: 60,
|
|||
|
|
bottom: 50
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// X轴配置
|
|||
|
|
xAxis: {
|
|||
|
|
type: 'value',
|
|||
|
|
min: 0,
|
|||
|
|
max: 100,
|
|||
|
|
axisLine: {
|
|||
|
|
show: false
|
|||
|
|
},
|
|||
|
|
axisTick: {
|
|||
|
|
show: false
|
|||
|
|
},
|
|||
|
|
splitLine: {
|
|||
|
|
show: true,
|
|||
|
|
lineStyle: {
|
|||
|
|
color: '#e8e8e8',
|
|||
|
|
type: 'solid'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
axisLabel: {
|
|||
|
|
fontSize: 12,
|
|||
|
|
color: '#666'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// Y轴配置
|
|||
|
|
yAxis: {
|
|||
|
|
type: 'category',
|
|||
|
|
data: currentData.map(item => item.name),
|
|||
|
|
inverse: true,
|
|||
|
|
axisLine: {
|
|||
|
|
show: true,
|
|||
|
|
lineStyle: {
|
|||
|
|
color: '#333',
|
|||
|
|
width: 1
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
axisTick: {
|
|||
|
|
show: true,
|
|||
|
|
length: 4,
|
|||
|
|
lineStyle: {
|
|||
|
|
color: '#333',
|
|||
|
|
width: 1
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
axisLabel: {
|
|||
|
|
fontSize: 12,
|
|||
|
|
color: '#333',
|
|||
|
|
margin: 12
|
|||
|
|
},
|
|||
|
|
// 在Y轴底部添加"达标率(%)"标签
|
|||
|
|
name: '达标率(%)',
|
|||
|
|
nameLocation: 'end',
|
|||
|
|
nameGap: 20,
|
|||
|
|
nameTextStyle: {
|
|||
|
|
fontSize: 12,
|
|||
|
|
color: '#666',
|
|||
|
|
align: 'left'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 系列配置
|
|||
|
|
series: [
|
|||
|
|
{
|
|||
|
|
name: '2026-04 月度',
|
|||
|
|
type: 'bar',
|
|||
|
|
data: currentData.map(item => item.current),
|
|||
|
|
barWidth: 10,
|
|||
|
|
barGap: '20%',
|
|||
|
|
itemStyle: {
|
|||
|
|
color: '#4A8BC2',
|
|||
|
|
borderRadius: [0, 3, 3, 0]
|
|||
|
|
},
|
|||
|
|
markArea: {
|
|||
|
|
silent: true,
|
|||
|
|
itemStyle: {
|
|||
|
|
color: 'rgba(240, 245, 250, 0.5)'
|
|||
|
|
},
|
|||
|
|
data: [
|
|||
|
|
[{ yAxis: 1 }, { yAxis: 2 }]
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: '去年同期',
|
|||
|
|
type: 'bar',
|
|||
|
|
data: currentData.map(item => item.lastYear),
|
|||
|
|
barWidth: 10,
|
|||
|
|
barGap: '20%',
|
|||
|
|
itemStyle: {
|
|||
|
|
color: '#9B59B6',
|
|||
|
|
borderRadius: [0, 3, 3, 0]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
chartInstance.setOption(option);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 更新图表数据
|
|||
|
|
const updateChartData = () => {
|
|||
|
|
if (!chartInstance) return;
|
|||
|
|
|
|||
|
|
const currentData = getCurrentData();
|
|||
|
|
|
|||
|
|
chartInstance.setOption({
|
|||
|
|
yAxis: {
|
|||
|
|
data: currentData.map(item => item.name)
|
|||
|
|
},
|
|||
|
|
series: [
|
|||
|
|
{
|
|||
|
|
data: currentData.map(item => item.current)
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
data: currentData.map(item => item.lastYear)
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 强制重新计算尺寸
|
|||
|
|
chartInstance.resize();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 页面加载时执行
|
|||
|
|
onMounted(() => {
|
|||
|
|
// 延迟初始化,确保容器已渲染
|
|||
|
|
setTimeout(() => {
|
|||
|
|
initChart();
|
|||
|
|
}, 100);
|
|||
|
|
|
|||
|
|
// 监听窗口resize
|
|||
|
|
window.addEventListener('resize', () => {
|
|||
|
|
chartInstance?.resize();
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 组件卸载时清理
|
|||
|
|
onUnmounted(() => {
|
|||
|
|
chartInstance?.dispose();
|
|||
|
|
window.removeEventListener('resize', () => {
|
|||
|
|
chartInstance?.resize();
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="scss" scoped>
|
|||
|
|
.body_item {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 600px;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
|
|||
|
|
.tabs_all {
|
|||
|
|
width: 28px;
|
|||
|
|
height: 600px;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
border: 2px solid #2f6b98;
|
|||
|
|
border-radius: 5px;
|
|||
|
|
|
|||
|
|
.zhong_tabs {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 50%;
|
|||
|
|
background: #2f6b98;
|
|||
|
|
color: #fff;
|
|||
|
|
font-size: 14px;
|
|||
|
|
text-align: center;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
text-shadow: 0 0 .25px currentcolor;
|
|||
|
|
cursor: pointer;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.no_tabs {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 50%;
|
|||
|
|
font-size: 14px;
|
|||
|
|
text-align: center;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
cursor: pointer;
|
|||
|
|
}
|
|||
|
|
.no_tabs:hover {
|
|||
|
|
color: #40a9ff;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.tabs_body {
|
|||
|
|
width: 368px;
|
|||
|
|
height: 600px;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
|
|||
|
|
.chart-container {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|