2026-07-01 18:23:41 +08:00
|
|
|
|
<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"
|
|
|
|
|
|
:date-arr="dateArr"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</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'
|
|
|
|
|
|
import { useMapViewStore } from '@/modules/map/stores/map-view.store';
|
2026-07-07 10:33:29 +08:00
|
|
|
|
import { useDraggable } from '@/utils/drag';
|
|
|
|
|
|
|
2026-07-01 18:23:41 +08:00
|
|
|
|
// 定义组件名(便于调试和递归)
|
|
|
|
|
|
defineOptions({
|
|
|
|
|
|
name: 'shengtaidabiaoMod'
|
|
|
|
|
|
});
|
|
|
|
|
|
const mode = ref('top');
|
|
|
|
|
|
const spinning = ref(false);
|
|
|
|
|
|
const chartRef = ref<HTMLElement | null>(null);
|
|
|
|
|
|
let chartInstance: echarts.ECharts | null = null;
|
|
|
|
|
|
const mapViewStore = useMapViewStore();
|
|
|
|
|
|
// 动态数据存储
|
|
|
|
|
|
let dateArr = ref<any[]>([]);
|
|
|
|
|
|
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;
|
|
|
|
|
|
};
|
2026-07-07 10:33:29 +08:00
|
|
|
|
|
2026-07-01 18:23:41 +08:00
|
|
|
|
// 加载数据
|
|
|
|
|
|
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 +
|
|
|
|
|
|
' <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;
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
// 设置弹框标题
|
|
|
|
|
|
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;
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
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 = (offsetYears = 0) => {
|
|
|
|
|
|
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}`;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let startDate: string;
|
|
|
|
|
|
let endDate: string;
|
|
|
|
|
|
let startDate1: string;
|
|
|
|
|
|
let endDate1: string;
|
|
|
|
|
|
|
|
|
|
|
|
// 如果 dateArr.value 有数据,使用数组中的日期
|
|
|
|
|
|
if (dateArr.value && dateArr.value.length === 2) {
|
|
|
|
|
|
|
|
|
|
|
|
const start = new Date(dateArr.value[0]);
|
|
|
|
|
|
const end = new Date(dateArr.value[1]);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果 offsetYears 不为 0,表示获取去年同期的时间
|
|
|
|
|
|
if (offsetYears !== 0) {
|
|
|
|
|
|
start.setFullYear(start.getFullYear() + offsetYears);
|
|
|
|
|
|
end.setFullYear(end.getFullYear() + offsetYears);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
startDate = `${formatDate(start)} 00:00:00`;
|
|
|
|
|
|
endDate = `${formatDate(end)} 23:59:59`;
|
|
|
|
|
|
// 提取日期部分(去除时间)
|
|
|
|
|
|
startDate1 = formatDate(start);
|
|
|
|
|
|
endDate1 = formatDate(end);
|
|
|
|
|
|
// debugger
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 否则使用默认的"一个月前到现在"
|
|
|
|
|
|
const now = new Date();
|
|
|
|
|
|
const oneMonthAgo = new Date(now);
|
|
|
|
|
|
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果 offsetYears 不为 0,表示获取去年同期的时间
|
|
|
|
|
|
if (offsetYears !== 0) {
|
|
|
|
|
|
now.setFullYear(now.getFullYear() + offsetYears);
|
|
|
|
|
|
oneMonthAgo.setFullYear(oneMonthAgo.getFullYear() + offsetYears);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
startDate = `${formatDate(oneMonthAgo)} 00:00:00`;
|
|
|
|
|
|
endDate = `${formatDate(now)} 23:59:59`;
|
|
|
|
|
|
startDate1 = formatDate(oneMonthAgo);
|
|
|
|
|
|
endDate1 = formatDate(now);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return { startDate, endDate, startDate1, endDate1 };
|
|
|
|
|
|
};
|
|
|
|
|
|
const getEcharts = async () => {
|
|
|
|
|
|
// 获取当前时间范围
|
|
|
|
|
|
const currentDateRange = getdate(0);
|
|
|
|
|
|
// 获取去年同期时间范围(往前推一年)
|
|
|
|
|
|
const lastYearDateRange = getdate(-1);
|
|
|
|
|
|
|
|
|
|
|
|
// 构建基础 filter(不包含时间)
|
|
|
|
|
|
const baseFilter = {
|
|
|
|
|
|
logic: 'and',
|
|
|
|
|
|
filters: [
|
|
|
|
|
|
mode.value == 'top'
|
|
|
|
|
|
? {
|
|
|
|
|
|
field: 'dtinEnv',
|
|
|
|
|
|
operator: 'in',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: [1, 2]
|
|
|
|
|
|
}
|
|
|
|
|
|
: {
|
|
|
|
|
|
field: 'type',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: 'DAY'
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 构建当前时间范围的 params
|
|
|
|
|
|
const currentParams = {
|
|
|
|
|
|
filter: {
|
|
|
|
|
|
...baseFilter,
|
|
|
|
|
|
filters: [
|
|
|
|
|
|
...baseFilter.filters,
|
|
|
|
|
|
{
|
|
|
|
|
|
field: 'tm',
|
|
|
|
|
|
operator: 'gte',
|
|
|
|
|
|
dataType: 'date',
|
|
|
|
|
|
value: currentDateRange.startDate
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
field: 'tm',
|
|
|
|
|
|
operator: 'lte',
|
|
|
|
|
|
dataType: 'date',
|
|
|
|
|
|
value: currentDateRange.endDate
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
group:
|
|
|
|
|
|
mode.value == 'top'
|
|
|
|
|
|
? [
|
|
|
|
|
|
{ dir: 'asc', field: 'basestepsort' },
|
|
|
|
|
|
{ dir: 'asc', field: 'baseId' },
|
|
|
|
|
|
{ dir: 'asc', field: 'baseName' }
|
|
|
|
|
|
]
|
|
|
|
|
|
: [{ dir: 'asc', field: 'qecPerformance' }]
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 构建去年同期时间范围的 params
|
|
|
|
|
|
const lastYearParams = {
|
|
|
|
|
|
filter: {
|
|
|
|
|
|
...baseFilter,
|
|
|
|
|
|
filters: [
|
|
|
|
|
|
...baseFilter.filters,
|
|
|
|
|
|
{
|
|
|
|
|
|
field: 'tm',
|
|
|
|
|
|
operator: 'gte',
|
|
|
|
|
|
dataType: 'date',
|
|
|
|
|
|
value: lastYearDateRange.startDate
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
field: 'tm',
|
|
|
|
|
|
operator: 'lte',
|
|
|
|
|
|
dataType: 'date',
|
|
|
|
|
|
value: lastYearDateRange.endDate
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
group: currentParams.group
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 并行请求两个 API
|
|
|
|
|
|
const [currentRes, lastYearRes]: [any, any] = await Promise.all([
|
|
|
|
|
|
eqqecRateCount(currentParams),
|
|
|
|
|
|
eqqecRateCount(lastYearParams)
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理当前数据
|
|
|
|
|
|
const currentApiData = (currentRes && currentRes.data && currentRes.data.data) ? currentRes.data.data : [];
|
|
|
|
|
|
// 处理去年同期数据
|
|
|
|
|
|
const lastYearApiData = (lastYearRes && lastYearRes.data && lastYearRes.data) ? lastYearRes.data.data : [];
|
|
|
|
|
|
|
|
|
|
|
|
// 根据 mode 提取不同的数据
|
|
|
|
|
|
if (mode.value === 'top') {
|
|
|
|
|
|
// 按基地模式:去重处理(避免 baseId 重复)
|
|
|
|
|
|
const uniqueMap = new Map();
|
|
|
|
|
|
currentApiData.forEach((item: any) => {
|
|
|
|
|
|
if (!uniqueMap.has(item.baseId)) {
|
|
|
|
|
|
uniqueMap.set(item.baseId, item);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const uniqueData = Array.from(uniqueMap.values());
|
|
|
|
|
|
|
|
|
|
|
|
// 建立去年同期的数据映射(按 baseId)
|
|
|
|
|
|
const lastYearMap = new Map();
|
|
|
|
|
|
lastYearApiData.forEach((item: any) => {
|
|
|
|
|
|
if (!lastYearMap.has(item.baseId)) {
|
|
|
|
|
|
lastYearMap.set(item.baseId, item.qecRate);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
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) => {
|
|
|
|
|
|
const lastYearRate = lastYearMap.get(item.baseId);
|
|
|
|
|
|
return lastYearRate != null ? Number(lastYearRate) : 0;
|
|
|
|
|
|
}),
|
|
|
|
|
|
baseIds: uniqueData.map((item: any) => item.baseId),
|
|
|
|
|
|
qecPerformances: []
|
|
|
|
|
|
};
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 按调节性能模式
|
|
|
|
|
|
|
|
|
|
|
|
// 建立去年同期的数据映射(按 qecPerformance)
|
|
|
|
|
|
const lastYearMap = new Map();
|
|
|
|
|
|
lastYearApiData.forEach((item: any) => {
|
|
|
|
|
|
if (!lastYearMap.has(item.qecPerformance)) {
|
|
|
|
|
|
lastYearMap.set(item.qecPerformance, item.qecRate);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
chartData.value = {
|
|
|
|
|
|
categories: currentApiData.map((item: any) => item.qecPerformanceName || ''),
|
|
|
|
|
|
currentData: currentApiData.map((item: any) =>
|
|
|
|
|
|
item.qecRate != null ? Number(item.qecRate) : 0
|
|
|
|
|
|
),
|
|
|
|
|
|
lastYearData: currentApiData.map((item: any) => {
|
|
|
|
|
|
const lastYearRate = lastYearMap.get(item.qecPerformance);
|
|
|
|
|
|
return lastYearRate != null ? Number(lastYearRate) : 0;
|
|
|
|
|
|
}),
|
|
|
|
|
|
baseIds: [],
|
|
|
|
|
|
qecPerformances: currentApiData.map((item: any) => item.qecPerformance || '')
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
} 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
|
|
|
|
|
};
|
|
|
|
|
|
// 页面加载时执行的逻辑
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
loadData();
|
|
|
|
|
|
getcont();
|
|
|
|
|
|
// 监听窗口大小变化
|
|
|
|
|
|
window.addEventListener('resize', () => {
|
|
|
|
|
|
chartInstance?.resize();
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => mapViewStore.searchTimeRange,
|
|
|
|
|
|
(newVal, oldVal) => {
|
|
|
|
|
|
console.log('时间范围变化:', oldVal, '->', newVal);
|
|
|
|
|
|
dateArr.value = newVal
|
|
|
|
|
|
// debugger
|
|
|
|
|
|
loadData();
|
|
|
|
|
|
// 处理你的逻辑
|
|
|
|
|
|
},
|
|
|
|
|
|
{ deep: true }
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 详情弹框相关
|
|
|
|
|
|
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();
|
|
|
|
|
|
});
|
2026-07-07 10:33:29 +08:00
|
|
|
|
useDraggable(huanbaoModalVisible, { boundary: true, resetOnOpen: true });
|
|
|
|
|
|
useDraggable(detailModalVisible, { boundary: true, resetOnOpen: true });
|
2026-07-01 18:23:41 +08:00
|
|
|
|
</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>
|