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

592 lines
15 KiB
Vue
Raw Normal View History

<template>
2026-06-12 16:59:35 +08:00
<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">
2026-06-16 17:39:51 +08:00
<p>
1时间{{ getdate().startDate1 }} {{ getdate().endDate1 }}
</p>
2026-06-12 16:59:35 +08:00
<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>
2026-06-16 17:39:51 +08:00
<!-- 生态流量达标率详情弹框 -->
<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';
2026-06-12 16:59:35 +08:00
import { eqqecRateCount, evnmAutoMonitorGetKendoListCust } from '@/api/stll';
import ModalYkzhbzdjcgz from '../shengtaidabiaoMod/TwoLayer/ModalYkzhbzdjcgz.vue';
2026-06-16 17:39:51 +08:00
import STLLXFFS from './TwoLayer/STLLXFFS.vue'
// 定义组件名(便于调试和递归)
defineOptions({
2026-06-12 16:59:35 +08:00
name: 'shengtaidabiaoMod'
});
const mode = ref('top');
2026-06-12 16:59:35 +08:00
const spinning = ref(false);
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
2026-06-12 16:59:35 +08:00
// 动态数据存储
const chartData = ref<{
categories: string[];
currentData: number[];
lastYearData: number[];
2026-06-16 17:39:51 +08:00
baseIds: (string | number)[];
qecPerformances: (string | number)[];
2026-06-12 16:59:35 +08:00
}>({
categories: [],
currentData: [],
2026-06-16 17:39:51 +08:00
lastYearData: [],
baseIds: [],
qecPerformances: []
2026-06-12 16:59:35 +08:00
});
const huanbaoModalVisible = ref(false);
// 处理电站数量点击事件
const handleStationClick = () => {
huanbaoModalVisible.value = true;
};
// 加载数据
2026-06-12 16:59:35 +08:00
const loadData = async () => {
spinning.value = true;
try {
// 先获取数据
await getEcharts();
// 确保 DOM 已渲染后初始化图表
setTimeout(() => {
2026-06-12 16:59:35 +08:00
initChart();
spinning.value = false;
}, 50);
2026-06-12 16:59:35 +08:00
} catch (error) {
console.error('数据加载失败:', error);
spinning.value = false;
}
};
// 初始化图表
const initChart = () => {
2026-06-12 16:59:35 +08:00
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'
}
2026-06-12 16:59:35 +08:00
},
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
}
},
2026-06-12 16:59:35 +08:00
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'
}
2026-06-12 16:59:35 +08:00
},
axisTick: {
show: true,
lineStyle: {
color: '#666'
}
2026-06-12 16:59:35 +08:00
},
splitLine: {
show: false
}
}
: {
type: 'value',
min: 0,
max: 100,
splitLine: {
show: true,
lineStyle: {
color: '#E8E8E8',
type: 'solid'
}
2026-06-12 16:59:35 +08:00
},
axisLabel: {
color: '#666',
formatter: '{value}'
}
},
2026-06-12 16:59:35 +08:00
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);
2026-06-16 17:39:51 +08:00
// 添加点击事件
chartInstance.off('click');
chartInstance.on('click', (params: any) => {
handleChartClick(params);
});
2026-06-12 16:59:35 +08:00
// 强制重绘,确保尺寸正确
setTimeout(() => {
chartInstance?.resize();
}, 0);
};
2026-06-16 17:39:51 +08:00
// 处理图表点击事件
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;
};
2026-06-12 16:59:35 +08:00
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]
}
2026-06-12 16:59:35 +08:00
: {
field: 'type',
operator: 'eq',
dataType: 'string',
value: 'DAY'
},
2026-06-12 16:59:35 +08:00
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: getdate().startDate
},
2026-06-12 16:59:35 +08:00
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: getdate().endDate
}
]
},
group:
mode.value == 'top'
? [
{
dir: 'asc',
field: 'basestepsort'
},
{
2026-06-12 16:59:35 +08:00
dir: 'asc',
field: 'baseId'
},
{
2026-06-12 16:59:35 +08:00
dir: 'asc',
field: 'baseName'
}
2026-06-12 16:59:35 +08:00
]
: [
{
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
2026-06-16 17:39:51 +08:00
),
baseIds: uniqueData.map((item: any) => item.baseId),
qecPerformances: []
2026-06-12 16:59:35 +08:00
};
} 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
2026-06-16 17:39:51 +08:00
),
baseIds: [],
qecPerformances: apiData.map((item: any) => item.qecPerformance || '')
2026-06-12 16:59:35 +08:00
};
}
} else {
console.warn('API 返回数据格式异常');
// 使用空数据
chartData.value = {
categories: [],
currentData: [],
2026-06-16 17:39:51 +08:00
lastYearData: [],
baseIds: [],
qecPerformances: []
2026-06-12 16:59:35 +08:00
};
}
} catch (error) {
console.error('API 调用失败:', error);
// 发生错误时使用空数据
chartData.value = {
categories: [],
currentData: [],
2026-06-16 17:39:51 +08:00
lastYearData: [],
baseIds: [],
qecPerformances: []
};
2026-06-12 16:59:35 +08:00
}
};
//统计电站范围:接入过生态流量数据的电站
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(() => {
2026-06-12 16:59:35 +08:00
loadData();
getcont();
// 监听窗口大小变化
window.addEventListener('resize', () => {
chartInstance?.resize();
});
});
2026-06-16 17:39:51 +08:00
// 详情弹框相关
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, () => {
2026-06-12 16:59:35 +08:00
loadData();
});
</script>
<style lang="scss" scoped>
2026-04-20 09:13:35 +08:00
.body_topOne {
2026-06-12 16:59:35 +08:00
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
2026-04-20 09:13:35 +08:00
2026-06-12 16:59:35 +08:00
.title_text {
font-size: 16px;
}
2026-04-20 09:13:35 +08:00
}
.ant-radio-group {
2026-06-12 16:59:35 +08:00
.ant-radio-button-wrapper-checked {
border: 1px solid #2f6b98 !important;
background-color: #2f6b98 !important;
color: #fff !important;
}
2026-06-12 16:59:35 +08:00
.ant-radio-button-wrapper {
border: 2px solid #2f6b98 !important;
}
2026-04-20 09:13:35 +08:00
2026-06-12 16:59:35 +08:00
.ant-radio-button-wrapper-checked :before {
background-color: #2f6b98 !important;
}
}
.chart-container {
2026-06-12 16:59:35 +08:00
width: 100%;
height: 449px;
// padding: 10px;
}
2026-06-16 17:39:51 +08:00
.detail-content {
padding: 16px 0;
}
</style>