WholeProcessPlatform/frontend/src/modules/EnvironmentalQuality/index.vue

343 lines
9.1 KiB
Vue
Raw Normal View History

2026-04-24 17:46:41 +08:00
<!-- 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>