WholeProcessPlatform/frontend/src/modules/shengTaiLiuLiangXieFangSheShiMod/xieFangFangShi/index.vue
2026-07-07 13:50:21 +08:00

383 lines
9.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- SidePanelItem.vue -->
<template>
<div class="xie-fang-fang-shi-container">
<SidePanelItem title="生态流量泄放方式">
<!-- Loading 状态 -->
<a-spin
v-if="loading"
:spinning="true"
style="
width: 100%;
height: 350px;
display: flex;
justify-content: center;
align-items: center;
"
/>
<!-- 空状态提示 -->
<a-empty
v-else-if="!loading && pieData.length === 0"
description="暂无数据"
style="
height: 350px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
text-indent: 0em;
"
/>
<!-- 图表容器 -->
<div v-else ref="chartRef" class="pie-chart"></div>
</SidePanelItem>
<!-- 详情弹框 -->
<a-modal
v-model:open="modalVisible"
:title="'生态流量泄放方式'"
width="80%"
@cancel="handleModalCancel"
>
<STLLXFFS
v-if="modalVisible"
:basicId="wbsCode"
:sttpCodekey="selectedData.sttpCode"
/>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import * as echarts from 'echarts';
import type { ECharts } from 'echarts';
import { msstbprptGetKendoList } from '@/api/stll';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import STLLXFFS from './TwoLayer/STLLXFFS.vue';
import { useDraggable } from '@/utils/drag';
// 定义组件名(便于调试和递归)
defineOptions({
name: 'xieFangFangShi'
});
const JidiSelectEventStore = useJidiSelectEventStore();
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: ECharts | null = null;
let wbsCode = ref('');
// Loading 状态
const loading = ref(false);
// 动态数据
const pieData = ref<any[]>([]);
const totalCount = ref(0);
const apiRawData = ref<any[]>([]); // 保存原始 API 数据
// 弹框状态
const modalVisible = ref(false);
const modalTitle = ref('');
const selectedData = ref<any>(null);
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
// 颜色配置(根据图片配色)
const colors = [
'#9556a4', // 基荷发电 - 紫色
'#30b7b9', // 泄洪设施 - 青绿色
'#4b79ab', // 生态机组 - 蓝色
'#dbb629', // 生态放流管 - 黄色
'#df91ab', // 生态放流闸 - 粉色
'#78c300', // 生态放流孔 - 浅绿色
'#7399c6' // 生态放流洞 - 浅蓝色
];
// 初始化图表
const initChart = () => {
if (!chartRef.value) return;
// 确保容器有正确的高度
if (chartRef.value.clientHeight === 0) {
// 如果容器高度为 0延迟初始化
setTimeout(() => {
initChart();
}, 100);
return;
}
chartInstance = echarts.init(chartRef.value);
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c}%'
},
series: [
{
name: '泄放设施',
type: 'pie',
radius: ['42%', '62%'], // 环形:内径 42%,外径 62%(进一步缩小)
center: ['50%', '50%'],
avoidLabelOverlap: true,
itemStyle: {
borderRadius: 0,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
position: 'outside',
alignTo: 'edge', // 标签对齐到边缘
margin: 8, // 标签与圆环的距离
formatter: (params: any) => {
return `{name|${params.name}}\n{value|${params.value}%}`;
},
rich: {
name: {
fontSize: 12,
color: '#666666', // 灰蓝色标签
lineHeight: 18,
fontFamily: 'Microsoft YaHei, sans-serif',
align: 'left' // 左对齐
},
value: {
fontSize: 12,
color: '#2f6b98', // 灰蓝色百分比
lineHeight: 18,
fontFamily: 'Microsoft YaHei, sans-serif',
align: 'center', // 左对齐
fontWeight: 'bold' // 百分比加粗
}
},
overflow: 'none', // 不省略,完整显示
padding: [0, 0]
},
labelLine: {
show: true,
length: 12,
length2: 12,
lineStyle: {
width: 1
}
},
emphasis: {
scale: false, // 禁用悬停放大
itemStyle: {
brightness: 1.2, // 鼠标悬停时颜色变亮 20%
shadowBlur: 0 // 禁用阴影
},
labelLine: {
show: true // 悬停时不显示引导线变化
}
},
data: pieData.value.map((item, index) => ({
...item,
itemStyle: { color: colors[index % colors.length] },
labelLine: {
lineStyle: {
color: colors[index % colors.length]
}
}
}))
}
],
// 中心文字
title: {
text: totalCount.value.toString(),
subtext: '泄放设施总数量\n(个)',
left: 'center',
top: 'center',
textStyle: {
color: '#2e86de',
fontSize: 30,
fontWeight: 'bold',
fontFamily: 'Arial'
},
subtextStyle: {
color: '#666',
fontSize: 12,
lineHeight: 16,
fontFamily: 'Microsoft YaHei, sans-serif'
}
}
};
chartInstance.setOption(option);
// 绑定点击事件
chartInstance.on('click', handleChartClick);
};
/**
* 图表点击事件
*/
const handleChartClick = (params: any) => {
// 获取点击的数据项
const clickedData = params.data;
if (clickedData) {
selectedData.value = {
name: clickedData.name,
value: clickedData.value,
sttpCode: clickedData.sttpCode,
count:
apiRawData.value.find(
(item: any) => item.sttpCode === clickedData.sttpCode
)?.count_sttpName || 0,
...apiRawData.value.find(
(item: any) => item.sttpCode === clickedData.sttpCode
) // 保留所有原始数据字段
};
modalTitle.value = `${clickedData.name} - 详细信息`;
modalVisible.value = true;
}
};
/**
* 弹框取消事件
*/
const handleModalCancel = () => {
modalVisible.value = false;
selectedData.value = null;
};
// 处理响应式
const handleResize = () => {
chartInstance?.resize();
};
// 页面加载时执行的逻辑
onMounted(() => {
// 使用 nextTick 确保 DOM 已经完全渲染
setTimeout(() => {
initChart();
// 初始化后再 resize 一次,确保尺寸正确
setTimeout(() => {
chartInstance?.resize();
}, 200);
}, 50);
window.addEventListener('resize', handleResize);
// 组件挂载时获取数据
if (wbsCode.value) {
getecharts();
}
});
// 组件卸载时清理
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
});
const getecharts = async () => {
loading.value = true;
let params = {
filter: {
logic: 'and',
filters: [
wbsCode.value != 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: wbsCode.value
}
: null,
{
field: 'sttp',
operator: 'contains',
dataType: 'string',
value: 'EQ_'
},
{
field: 'baseName',
operator: 'isnotnull',
dataType: 'string'
}
].filter(Boolean)
},
group: [
{
dir: 'desc',
field: 'sttpCode'
},
{
dir: 'desc',
field: 'sttpName'
}
],
groupResultFlat: 'true'
};
try {
let res = await msstbprptGetKendoList(params);
// 处理返回的数据结构
if (!res || !res.data || !res.data.data || !Array.isArray(res.data.data)) {
console.warn('未获取到有效的泄放设施数据:', res);
pieData.value = [];
totalCount.value = 0;
return;
}
const apiData = res.data.data;
// 保存原始数据
apiRawData.value = apiData;
// 计算总数
const total = apiData.reduce((sum: number, item: any) => {
return sum + (item.count_sttpName || 0);
}, 0);
totalCount.value = total;
// 映射数据结构,计算百分比(四舍五入保留两位小数)
pieData.value = apiData.map((item: any) => ({
name: item.sttpName,
value:
total > 0
? Number(((item.count_sttpName / total) * 100).toFixed(2))
: 0,
sttpCode: item.sttpCode // 添加 sttpCode 字段
}));
// 数据更新后重新渲染图表
setTimeout(() => {
initChart();
}, 100);
} catch (error) {
console.error('获取泄放设施数据失败:', error);
pieData.value = [];
totalCount.value = 0;
} finally {
loading.value = false;
}
};
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
console.log('流域切换:', newVal);
if (newVal?.wbsCode) {
wbsCode.value = newVal.wbsCode;
getecharts();
}
},
{ deep: true, immediate: true }
);
</script>
<style lang="scss" scoped>
.xie-fang-fang-shi-container {
width: 100%;
height: 100%;
}
.pie-chart {
width: 100%;
height: 350px;
}
</style>