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

681 lines
18 KiB
Vue
Raw Normal View History

<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';
import { useDraggable } from '@/utils/drag';
// 定义组件名(便于调试和递归)
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;
};
// 加载数据
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;
//
// 设置弹框标题
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();
});
useDraggable(huanbaoModalVisible, { boundary: true, resetOnOpen: true });
useDraggable(detailModalVisible, { boundary: true, resetOnOpen: true });
</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>