WholeProcessPlatform/frontend/src/modules/shengtaidabiaoTwoMod/index.vue
2026-06-16 17:39:51 +08:00

592 lines
15 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.

<template>
<div>
<SidePanelItem title="生态流量达标情况" :click-action="{ show: true }">
<!-- 使用插槽自定义点击提示的内容 -->
<!-- 1时间2026-05-11 2026-06-11
-->
<template #click-action-content>
<div v-if="titleData.cnt" style="max-width: 300px; line-height: 1.6">
<p>
1、时间{{ getdate().startDate1 }} 至 {{ getdate().endDate1 }}
</p>
<p>
2、范围接入过生态流量数据的电站<span
style="color: #5989ad; cursor: pointer"
@click.stop="handleStationClick()"
>
({{ titleData.cnt }}) </span
>
</p>
<p>3、达标判定按环评批复或报告中对生态流量限值有明确要求的评判。</p>
</div>
</template>
<div class="body_topOne">
<a-radio-group v-model:value="mode" @change="getEcharts()">
<a-radio-button value="top">按基地</a-radio-button>
<a-radio-button value="left">按调节性能</a-radio-button>
</a-radio-group>
</div>
<a-spin :spinning="spinning">
<div ref="chartRef" class="chart-container"></div>
</a-spin>
</SidePanelItem>
</div>
<!-- 环保自动监测工作开展情况弹框 -->
<a-modal
v-model:open="huanbaoModalVisible"
:title="'环保自动监测工作开展情况'"
width="1536px"
:footer="null"
>
<ModalYkzhbzdjcgz v-if="huanbaoModalVisible" :titleData="titleData" />
</a-modal>
<!-- 生态流量达标率详情弹框 -->
<a-modal
v-model:open="detailModalVisible"
:title="detailModalTitle"
width="1536px"
:footer="null"
>
<STLLXFFS
v-if="detailModalVisible"
:type="mode"
:basicId="detailData[0]?.baseId"
:qecPerformance=detailData[0].qecPerformance
/>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, onMounted, watch } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import * as echarts from 'echarts';
import { eqqecRateCount, evnmAutoMonitorGetKendoListCust } from '@/api/stll';
import ModalYkzhbzdjcgz from '../shengtaidabiaoMod/TwoLayer/ModalYkzhbzdjcgz.vue';
import STLLXFFS from './TwoLayer/STLLXFFS.vue'
// 定义组件名(便于调试和递归)
defineOptions({
name: 'shengtaidabiaoMod'
});
const mode = ref('top');
const spinning = ref(false);
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
// 动态数据存储
const chartData = ref<{
categories: string[];
currentData: number[];
lastYearData: number[];
baseIds: (string | number)[];
qecPerformances: (string | number)[];
}>({
categories: [],
currentData: [],
lastYearData: [],
baseIds: [],
qecPerformances: []
});
const huanbaoModalVisible = ref(false);
// 处理电站数量点击事件
const handleStationClick = () => {
huanbaoModalVisible.value = true;
};
// 加载数据
const loadData = async () => {
spinning.value = true;
try {
// 先获取数据
await getEcharts();
// 确保 DOM 已渲染后初始化图表
setTimeout(() => {
initChart();
spinning.value = false;
}, 50);
} catch (error) {
console.error('数据加载失败:', error);
spinning.value = false;
}
};
// 初始化图表
const initChart = () => {
if (!chartRef.value) {
console.error('图表容器未渲染');
return;
}
// 检查容器尺寸
const containerHeight = chartRef.value.offsetHeight;
if (!containerHeight || containerHeight === 0) {
console.warn('容器高度为 0延迟重试');
setTimeout(() => initChart(), 50);
return;
}
// 如果实例存在,先销毁
if (chartInstance) {
chartInstance.dispose();
}
chartInstance = echarts.init(chartRef.value);
// 使用动态数据
const data = chartData.value;
const isHorizontal = mode.value === 'top';
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params: any) {
let result = params[0].name + '<br/>';
params.forEach((param: any) => {
const percentage = param.value.toFixed(2) + '%';
result +=
param.marker +
param.seriesName +
'&nbsp;&nbsp;<b>' +
percentage +
'</b><br/>';
});
return result;
}
},
legend: {
data: ['当前', '去年同期']
},
grid: { left: 10, right: 10, bottom: 20, top: 40, containLabel: true },
dataZoom: [
{
type: 'inside',
// 横向柱形图(mode='top'): X轴是数值轴需要缩放
// 竖向柱状图(mode='left'): X轴是分类轴不需要缩放Y轴是数值轴也不需要内部缩放
[isHorizontal ? 'xAxisIndex' : 'xAxisIndex']: 0,
filterMode: 'empty',
zoomOnMouseWheel: true,
moveOnMouseMove: false,
moveOnMouseWheel: true,
start: 0,
end: 100,
minValueSpan: 0,
maxValueSpan: isHorizontal ? 20 : 5
}
],
xAxis: isHorizontal
? {
type: 'value',
min: 80,
max: 100,
splitLine: {
show: true,
lineStyle: {
color: '#E8E8E8',
type: 'solid'
}
},
axisLabel: {
color: '#666',
formatter: '{value}'
}
}
: {
type: 'category',
data: data.categories,
axisLabel: {
color: '#666',
fontSize: 12,
interval: 0,
rotate: 0,
margin: 10
},
axisLine: {
show: true,
lineStyle: {
color: '#666'
}
},
axisTick: {
show: true,
lineStyle: {
color: '#666'
}
},
splitLine: {
show: false
}
},
yAxis: isHorizontal
? {
type: 'category',
data: data.categories,
inverse: true,
axisLabel: {
color: '#666',
fontSize: 12,
interval: 0,
rotate: 45,
margin: 10
},
axisLine: {
show: true,
lineStyle: {
color: '#666'
}
},
axisTick: {
show: true,
lineStyle: {
color: '#666'
}
},
splitLine: {
show: false
}
}
: {
type: 'value',
min: 0,
max: 100,
splitLine: {
show: true,
lineStyle: {
color: '#E8E8E8',
type: 'solid'
}
},
axisLabel: {
color: '#666',
formatter: '{value}'
}
},
series: [
{
name: '当前',
type: 'bar',
data: data.currentData,
itemStyle: {
color: '#5470C6'
},
barWidth: isHorizontal ? 8 : 8
// barGap: '30%'
},
{
name: '去年同期',
type: 'bar',
data: data.lastYearData,
itemStyle: {
color: '#91CC75'
},
barWidth: isHorizontal ? 8 : 8
// barGap: '30%'
}
]
};
chartInstance.setOption(option);
// 添加点击事件
chartInstance.off('click');
chartInstance.on('click', (params: any) => {
handleChartClick(params);
});
// 强制重绘,确保尺寸正确
setTimeout(() => {
chartInstance?.resize();
}, 0);
};
// 处理图表点击事件
const handleChartClick = (params: any) => {
const categoryName = params.name;
const currentIndex = params.dataIndex;
// debugger
// 设置弹框标题
detailModalTitle.value =
mode.value === 'top'
? `生态流量达标率(按基地统计) `
: `生态流量达标率(按调节性能统计)`;
// 获取当前点击项的详细数据
const baseId = mode.value === 'top' ? chartData.value.baseIds[currentIndex] : undefined;
const qecPerformance = mode.value === 'left' ? chartData.value.qecPerformances[currentIndex] : undefined;
// debugger
const currentItem = {
baseId: baseId,
baseName: mode.value === 'top' ? categoryName :'',
qecPerformance: qecPerformance,
qecPerformanceName: mode.value === 'left' ? categoryName : '',
qecRate: chartData.value.currentData[currentIndex],
beforeQecRate: chartData.value.lastYearData[currentIndex]
};
detailData.value = [currentItem];
detailModalVisible.value = true;
};
const getdate = () => {
const now = new Date();
const oneMonthAgo = new Date(now);
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
// 格式化日期为 YYYY-MM-DD
const formatDate = (date: Date) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
const startDate = `${formatDate(oneMonthAgo)} 00:00:00`;
const endDate = `${formatDate(now)} 23:59:59`;
const startDate1 = `${formatDate(oneMonthAgo)}`;
const endDate1 = `${formatDate(now)}`;
return { startDate, endDate, startDate1, endDate1 };
};
const getEcharts = async () => {
let params = {
filter: {
logic: 'and',
filters: [
mode.value == 'top'
? {
field: 'dtinEnv',
operator: 'in',
dataType: 'string',
value: [1, 2]
}
: {
field: 'type',
operator: 'eq',
dataType: 'string',
value: 'DAY'
},
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: getdate().startDate
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: getdate().endDate
}
]
},
group:
mode.value == 'top'
? [
{
dir: 'asc',
field: 'basestepsort'
},
{
dir: 'asc',
field: 'baseId'
},
{
dir: 'asc',
field: 'baseName'
}
]
: [
{
dir: 'asc',
field: 'qecPerformance'
}
]
};
try {
const res: any = await eqqecRateCount(params);
// 处理返回数据
if (res && res.success && res.data && res.data.data) {
const apiData = res.data.data;
// 根据 mode 提取不同的数据
if (mode.value === 'top') {
// 按基地模式:去重处理(避免 baseId 重复)
const uniqueMap = new Map();
apiData.forEach((item: any) => {
if (!uniqueMap.has(item.baseId)) {
uniqueMap.set(item.baseId, item);
}
});
const uniqueData = Array.from(uniqueMap.values());
chartData.value = {
categories: uniqueData.map((item: any) => item.baseName || ''),
currentData: uniqueData.map((item: any) =>
item.qecRate != null ? Number(item.qecRate) : 0
),
lastYearData: uniqueData.map((item: any) =>
item.beforeQecRate != null ? Number(item.beforeQecRate) : 0
),
baseIds: uniqueData.map((item: any) => item.baseId),
qecPerformances: []
};
} else {
// 按调节性能模式
chartData.value = {
categories: apiData.map((item: any) => item.qecPerformanceName || ''),
currentData: apiData.map((item: any) =>
item.qecRate != null ? Number(item.qecRate) : 0
),
lastYearData: apiData.map((item: any) =>
item.beforeQecRate != null ? Number(item.beforeQecRate) : 0
),
baseIds: [],
qecPerformances: apiData.map((item: any) => item.qecPerformance || '')
};
}
} else {
console.warn('API 返回数据格式异常');
// 使用空数据
chartData.value = {
categories: [],
currentData: [],
lastYearData: [],
baseIds: [],
qecPerformances: []
};
}
} catch (error) {
console.error('API 调用失败:', error);
// 发生错误时使用空数据
chartData.value = {
categories: [],
currentData: [],
lastYearData: [],
baseIds: [],
qecPerformances: []
};
}
};
//统计电站范围:接入过生态流量数据的电站
const titleData: any = ref({ cnt: 0 });
const getcont = async () => {
let params = {
filter: {
logic: 'and',
filters: [
{
field: 'showIds',
operator: 'in',
value: ['7']
}
]
}
};
let res = await evnmAutoMonitorGetKendoListCust(params);
// [
// {
// "cnt": 452,
// "orderInx": 7,
// "orderInxName": "生态流量",
// "sttpFullPath": "ENG",
// "sttpCode": "ENG",
// "sttpName": "生态流量"
// }
// ]
let list = res?.data?.data[0];
if (list) {
titleData.value = list;
}
// debugger
};
// 页面加载时执行的逻辑
onMounted(() => {
loadData();
getcont();
// 监听窗口大小变化
window.addEventListener('resize', () => {
chartInstance?.resize();
});
});
// 详情弹框相关
const detailModalVisible = ref(false);
const detailModalTitle = ref('');
const detailData = ref<any[]>([]);
const detailColumns = ref([
{
title: mode.value === 'top' ? '基地名称' : '调节性能',
dataIndex: mode.value === 'top' ? 'baseName' : 'qecPerformanceName',
key: mode.value === 'top' ? 'baseName' : 'qecPerformanceName',
width: 150,
fixed: 'left'
},
{
title: '当前达标率',
dataIndex: 'qecRate',
key: 'qecRate',
width: 120,
align: 'right'
},
{
title: '去年同期达标率',
dataIndex: 'beforeQecRate',
key: 'beforeQecRate',
width: 150,
align: 'right'
}
]);
// 监听 mode 变化
watch(mode, () => {
loadData();
});
</script>
<style lang="scss" scoped>
.body_topOne {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
.title_text {
font-size: 16px;
}
}
.ant-radio-group {
.ant-radio-button-wrapper-checked {
border: 1px solid #2f6b98 !important;
background-color: #2f6b98 !important;
color: #fff !important;
}
.ant-radio-button-wrapper {
border: 2px solid #2f6b98 !important;
}
.ant-radio-button-wrapper-checked :before {
background-color: #2f6b98 !important;
}
}
.chart-container {
width: 100%;
height: 449px;
// padding: 10px;
}
.detail-content {
padding: 16px 0;
}
</style>