2026-06-26 17:52:57 +08:00
|
|
|
|
<!-- 沿程鱼类变化情况 -->
|
2026-05-12 08:47:27 +08:00
|
|
|
|
<template>
|
2026-06-26 17:52:57 +08:00
|
|
|
|
<SidePanelItem
|
|
|
|
|
|
title="沿程鱼类变化情况"
|
|
|
|
|
|
:moreSelect="moreSelect"
|
|
|
|
|
|
:select="select"
|
|
|
|
|
|
@update-values="handlePanelChange"
|
|
|
|
|
|
>
|
|
|
|
|
|
<a-spin :spinning="dataLoading" tip="加载中...">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-show="chartData.length > 0 && select.options.length > 0"
|
|
|
|
|
|
ref="chartRef"
|
|
|
|
|
|
class="chart-container"
|
|
|
|
|
|
></div>
|
|
|
|
|
|
<a-empty
|
|
|
|
|
|
v-show="
|
|
|
|
|
|
!dataLoading &&
|
|
|
|
|
|
(chartData.length === 0 || select.options.length === 0)
|
|
|
|
|
|
"
|
|
|
|
|
|
:description="select.options.length === 0 ? '暂无数据' : '暂无数据'"
|
|
|
|
|
|
class="empty-placeholder"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-spin>
|
|
|
|
|
|
</SidePanelItem>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 沿程鱼类变化详情弹框 -->
|
|
|
|
|
|
<a-modal
|
|
|
|
|
|
v-model:open="modalVisible"
|
|
|
|
|
|
title="沿程鱼类变化"
|
|
|
|
|
|
width="1536px"
|
|
|
|
|
|
:footer="null"
|
|
|
|
|
|
@cancel="handleModalClose"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Yanchengyulei
|
2026-07-01 18:23:41 +08:00
|
|
|
|
v-if="modalVisible && JidiSelectEventStore.jidiData.length > 0"
|
2026-06-26 17:52:57 +08:00
|
|
|
|
:tm="modalYear"
|
2026-07-15 18:24:05 +08:00
|
|
|
|
:dataDimensionVal="moreSelect.value.value"
|
2026-06-26 17:52:57 +08:00
|
|
|
|
:hbrvcd="modalHbrvcd"
|
|
|
|
|
|
:jdList="JidiSelectEventStore.jidiData"
|
|
|
|
|
|
:stateName="modalStateName"
|
|
|
|
|
|
:sectionName="modalSectionName"
|
|
|
|
|
|
:stcd="modalStcd"
|
|
|
|
|
|
:ly="true"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-modal>
|
2026-05-12 08:47:27 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
2026-06-26 17:52:57 +08:00
|
|
|
|
import { ref, watch, onMounted, onUnmounted, nextTick } from 'vue';
|
2026-05-12 08:47:27 +08:00
|
|
|
|
import * as echarts from 'echarts';
|
|
|
|
|
|
import type { EChartsOption } from 'echarts';
|
|
|
|
|
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
2026-06-26 17:52:57 +08:00
|
|
|
|
import Yanchengyulei from './TwoLayers/Yanchengyulei.vue';
|
|
|
|
|
|
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
|
2026-07-15 18:24:05 +08:00
|
|
|
|
import { getDftYear, fishChanges2 } from '@/api/stdc';
|
2026-06-26 17:52:57 +08:00
|
|
|
|
import moment from 'moment';
|
2026-07-07 10:33:29 +08:00
|
|
|
|
import { useDraggable } from '@/utils/drag';
|
2026-05-12 08:47:27 +08:00
|
|
|
|
|
|
|
|
|
|
defineOptions({
|
2026-06-26 17:52:57 +08:00
|
|
|
|
name: 'alongFishMod'
|
2026-05-12 08:47:27 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-06-26 17:52:57 +08:00
|
|
|
|
// ==================== Store ====================
|
|
|
|
|
|
const JidiSelectEventStore = useJidiSelectEventStore();
|
2026-05-12 08:47:27 +08:00
|
|
|
|
|
2026-06-26 17:52:57 +08:00
|
|
|
|
// ==================== 基础状态 ====================
|
|
|
|
|
|
/** 图表数据加载状态 */
|
|
|
|
|
|
const dataLoading = ref(false);
|
|
|
|
|
|
/** 初始化标志位:初始化期间不响应控件变化触发数据请求 */
|
|
|
|
|
|
const isInitializing = ref(false);
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 选择器状态 ====================
|
|
|
|
|
|
/** 流域树形选择器配置 */
|
|
|
|
|
|
const moreSelect = ref({
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
value: undefined as string | undefined,
|
|
|
|
|
|
options: [] as any[]
|
2026-05-12 08:47:27 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-06-26 17:52:57 +08:00
|
|
|
|
/** 年份选择器配置 */
|
|
|
|
|
|
const select = ref({
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
value: undefined as string | undefined,
|
|
|
|
|
|
options: [] as any[],
|
|
|
|
|
|
picker: undefined,
|
|
|
|
|
|
format: undefined,
|
|
|
|
|
|
width: '120px'
|
2026-05-12 08:47:27 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-06-26 17:52:57 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 按流域分组的年份数据
|
|
|
|
|
|
* 结构:{ "wbsCode1": [{label:'2023', value:'2023'}], "wbsCode2": [...] }
|
|
|
|
|
|
* 用于流域切换时快速更新年份下拉选项
|
|
|
|
|
|
*/
|
|
|
|
|
|
const yearOptions = ref<Record<string, any[]>>({});
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 图表状态 ====================
|
|
|
|
|
|
const chartRef = ref<HTMLDivElement>();
|
|
|
|
|
|
let chartInstance: any = null;
|
|
|
|
|
|
/** 图表原始数据,由 API 返回 */
|
|
|
|
|
|
const chartData = ref<any[]>([]);
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 弹框状态 ====================
|
|
|
|
|
|
const modalVisible = ref(false);
|
|
|
|
|
|
const modalYear = ref('');
|
|
|
|
|
|
const modalHbrvcd = ref('');
|
|
|
|
|
|
const modalStateName = ref('');
|
|
|
|
|
|
const modalSectionName = ref('');
|
|
|
|
|
|
const modalStcd = ref('');
|
2026-07-07 10:33:29 +08:00
|
|
|
|
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
|
2026-06-26 17:52:57 +08:00
|
|
|
|
// ==================== 图表相关 ====================
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 初始化 ECharts 实例
|
|
|
|
|
|
* 在 onMounted 中调用,绑定点击事件用于打开详情弹框
|
|
|
|
|
|
*/
|
2026-05-12 08:47:27 +08:00
|
|
|
|
const initChart = () => {
|
2026-06-26 17:52:57 +08:00
|
|
|
|
if (!chartRef.value) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (chartInstance) {
|
|
|
|
|
|
chartInstance.dispose();
|
|
|
|
|
|
}
|
2026-05-12 08:47:27 +08:00
|
|
|
|
|
2026-06-26 17:52:57 +08:00
|
|
|
|
chartInstance = echarts.init(chartRef.value);
|
|
|
|
|
|
|
|
|
|
|
|
// 点击柱子弹出详情
|
|
|
|
|
|
chartInstance.on('click', (params: any) => {
|
|
|
|
|
|
if (params.componentType === 'series') {
|
|
|
|
|
|
openDetail(params);
|
2026-05-12 08:47:27 +08:00
|
|
|
|
}
|
2026-06-26 17:52:57 +08:00
|
|
|
|
});
|
2026-05-12 08:47:27 +08:00
|
|
|
|
|
2026-06-26 17:52:57 +08:00
|
|
|
|
updateChart();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 根据 chartData 更新图表配置
|
|
|
|
|
|
* 将 API 返回的 detail 对象(key: 1=外来鱼类, 2=本土受威胁, 3=本土无危)
|
|
|
|
|
|
* 转换为 ECharts 堆叠柱状图数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
const updateChart = () => {
|
|
|
|
|
|
if (!chartInstance) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 按 sort 字段排序
|
|
|
|
|
|
const sortedData = [...chartData.value].sort(
|
|
|
|
|
|
(a, b) => (a.sort || 0) - (b.sort || 0)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const waimaiData: number[] = [];
|
|
|
|
|
|
const bentuThreatData: number[] = [];
|
|
|
|
|
|
const bentuSafeData: number[] = [];
|
|
|
|
|
|
const xAxisData: string[] = [];
|
|
|
|
|
|
|
|
|
|
|
|
sortedData.forEach((item: any) => {
|
|
|
|
|
|
xAxisData.push(item.stnm || '');
|
|
|
|
|
|
waimaiData.push(item.detail?.['1'] || 0);
|
|
|
|
|
|
bentuThreatData.push(item.detail?.['2'] || 0);
|
|
|
|
|
|
bentuSafeData.push(item.detail?.['3'] || 0);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const option: EChartsOption = {
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
axisPointer: { type: 'shadow' },
|
|
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
|
|
|
|
borderColor: 'transparent',
|
|
|
|
|
|
textStyle: { color: '#ffffff' }
|
|
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
|
|
|
|
|
top: 30,
|
|
|
|
|
|
left: '2%',
|
|
|
|
|
|
right: '4%',
|
|
|
|
|
|
bottom: 30,
|
|
|
|
|
|
containLabel: true
|
|
|
|
|
|
},
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
bottom: 0,
|
|
|
|
|
|
itemWidth: 10,
|
|
|
|
|
|
itemHeight: 10
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
type: 'value',
|
|
|
|
|
|
minInterval: 1,
|
|
|
|
|
|
name: '种',
|
|
|
|
|
|
axisLine: { lineStyle: { color: '#e0e0e0' } },
|
|
|
|
|
|
axisLabel: { color: '#666' },
|
|
|
|
|
|
splitLine: { lineStyle: { color: '#e0e0e0', type: 'solid' } }
|
|
|
|
|
|
},
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
type: 'category',
|
|
|
|
|
|
axisTick: { show: false },
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
interval: 0,
|
|
|
|
|
|
rotate: 0,
|
|
|
|
|
|
color: '#666',
|
|
|
|
|
|
rich: {
|
|
|
|
|
|
a: { height: 24, align: 'center' },
|
|
|
|
|
|
b: { height: 30, align: 'center' }
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
name: '数量(个)',
|
|
|
|
|
|
data: xAxisData
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '外来鱼类',
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
stack: 'stack',
|
|
|
|
|
|
data: waimaiData,
|
|
|
|
|
|
label: { show: false }
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '本土受威胁鱼类',
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
stack: 'stack',
|
|
|
|
|
|
data: bentuThreatData,
|
|
|
|
|
|
label: { show: false }
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '本土无危鱼类',
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
stack: 'stack',
|
|
|
|
|
|
data: bentuSafeData,
|
|
|
|
|
|
label: { show: false }
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
barWidth: 15,
|
|
|
|
|
|
color: ['#4B79AB', '#78C300', '#9556A4']
|
|
|
|
|
|
};
|
2026-05-12 08:47:27 +08:00
|
|
|
|
|
2026-06-26 17:52:57 +08:00
|
|
|
|
chartInstance.setOption(option);
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
chartInstance.resize();
|
|
|
|
|
|
});
|
2026-05-12 08:47:27 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-26 17:52:57 +08:00
|
|
|
|
/** 窗口大小变化时自适应 */
|
2026-05-12 08:47:27 +08:00
|
|
|
|
const handleResize = () => {
|
2026-06-26 17:52:57 +08:00
|
|
|
|
if (chartInstance) {
|
|
|
|
|
|
chartInstance.resize();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 数据获取 ====================
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取年份选项数据
|
|
|
|
|
|
* 调用 getDftYear API,按基地/流域分组返回可用年份
|
|
|
|
|
|
* 初始化时调用,为每个流域缓存其对应的年份列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
const getYearData = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const filter: any = {};
|
2026-07-15 18:24:05 +08:00
|
|
|
|
if (moreSelect.value.value) {
|
|
|
|
|
|
filter.baseId = moreSelect.value.value;
|
2026-06-26 17:52:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
filter,
|
|
|
|
|
|
group: [{ dir: 'des', field: 'yr' }]
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const res = await getDftYear(params);
|
|
|
|
|
|
const data = res?.data?.data?.[0] || {};
|
|
|
|
|
|
|
|
|
|
|
|
if (Object.keys(data).length > 0) {
|
|
|
|
|
|
const objYear: Record<string, any[]> = {};
|
|
|
|
|
|
const allYears: any[] = [];
|
|
|
|
|
|
|
|
|
|
|
|
Object.keys(data).forEach(key => {
|
|
|
|
|
|
objYear[key] = data[key].map((item: any) => ({
|
|
|
|
|
|
label: String(item),
|
|
|
|
|
|
value: String(item)
|
|
|
|
|
|
}));
|
|
|
|
|
|
allYears.push(...data[key]);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
yearOptions.value = objYear;
|
|
|
|
|
|
|
|
|
|
|
|
// 去重排序(降序),取最新年份作为默认值
|
|
|
|
|
|
const uniqueYears = [...new Set(allYears)].sort(
|
|
|
|
|
|
(a: any, b: any) => Number(b) - Number(a)
|
|
|
|
|
|
);
|
|
|
|
|
|
const latestYear = uniqueYears[0];
|
|
|
|
|
|
|
2026-07-15 18:24:05 +08:00
|
|
|
|
// 取第一个有数据的流域
|
2026-06-26 17:52:57 +08:00
|
|
|
|
const firstWbsCode = Object.keys(data)[0];
|
|
|
|
|
|
select.value.options = objYear[firstWbsCode] || [];
|
|
|
|
|
|
select.value.value = latestYear
|
|
|
|
|
|
? String(latestYear)
|
|
|
|
|
|
: moment().format('YYYY');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
yearOptions.value = {};
|
|
|
|
|
|
select.value.options = [];
|
|
|
|
|
|
select.value.value = moment().format('YYYY');
|
2026-05-12 08:47:27 +08:00
|
|
|
|
}
|
2026-06-26 17:52:57 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取年份数据失败:', error);
|
|
|
|
|
|
select.value.options = [];
|
|
|
|
|
|
select.value.value = moment().format('YYYY');
|
|
|
|
|
|
}
|
2026-05-12 08:47:27 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-26 17:52:57 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 根据选中的流域代码更新年份下拉选项
|
|
|
|
|
|
* 从 yearOptions 缓存中查找对应流域的年份列表并更新 select.options
|
|
|
|
|
|
* @param wbsCode 流域代码
|
|
|
|
|
|
*/
|
|
|
|
|
|
const updateYearOptionsByBase = async (wbsCode: string) => {
|
|
|
|
|
|
const options = yearOptions.value[wbsCode];
|
|
|
|
|
|
if (options) {
|
|
|
|
|
|
select.value.options = options;
|
|
|
|
|
|
await nextTick();
|
|
|
|
|
|
// 默认选中最新年份(数组第一项)
|
|
|
|
|
|
select.value.value = options[0]?.value || '';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
select.value.options = [];
|
|
|
|
|
|
await nextTick();
|
|
|
|
|
|
select.value.value = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2026-05-12 08:47:27 +08:00
|
|
|
|
|
2026-06-26 17:52:57 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 获取流域树形选择器数据 + 年份数据 + 图表数据
|
|
|
|
|
|
* 在基地变化时调用,是整个模块数据加载的入口
|
|
|
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取图表数据
|
|
|
|
|
|
* 根据当前选中的流域(hbrvcd)、年份(yr)、基地(baseId)调用 fishChanges2 API
|
|
|
|
|
|
*/
|
|
|
|
|
|
const getChartData = async () => {
|
|
|
|
|
|
if (!select.value.value) return;
|
|
|
|
|
|
|
|
|
|
|
|
dataLoading.value = true;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
filter: {
|
|
|
|
|
|
logic: 'and',
|
|
|
|
|
|
filters: [
|
2026-07-15 18:24:05 +08:00
|
|
|
|
{
|
|
|
|
|
|
field: 'baseId',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: moreSelect.value.value
|
|
|
|
|
|
},
|
2026-06-26 17:52:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
field: 'yr',
|
|
|
|
|
|
operator: 'eq',
|
|
|
|
|
|
dataType: 'string',
|
|
|
|
|
|
value: moment(select.value.value).format('YYYY')
|
2026-07-15 18:24:05 +08:00
|
|
|
|
}
|
2026-06-26 17:52:57 +08:00
|
|
|
|
].filter(Boolean)
|
|
|
|
|
|
},
|
|
|
|
|
|
group: [
|
|
|
|
|
|
{ dir: 'des', field: 'stnm' },
|
|
|
|
|
|
{ dir: 'des', field: 'stcd' },
|
|
|
|
|
|
{ dir: 'des', field: 'ty' }
|
|
|
|
|
|
],
|
|
|
|
|
|
groupResultFlat: 'true'
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const res = await fishChanges2(params);
|
|
|
|
|
|
chartData.value = res?.data?.data || [];
|
2026-05-12 08:47:27 +08:00
|
|
|
|
nextTick(() => {
|
2026-06-26 17:52:57 +08:00
|
|
|
|
updateChart();
|
2026-05-12 08:47:27 +08:00
|
|
|
|
});
|
2026-06-26 17:52:57 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取图表数据失败:', error);
|
|
|
|
|
|
chartData.value = [];
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
updateChart();
|
|
|
|
|
|
});
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
dataLoading.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 弹框相关 ====================
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 打开详情弹框
|
|
|
|
|
|
* 点击图表柱子时触发,传递当前选中的年份、流域、站点名称等参数
|
|
|
|
|
|
*/
|
|
|
|
|
|
const openDetail = (params: any) => {
|
2026-07-01 18:23:41 +08:00
|
|
|
|
|
2026-06-26 17:52:57 +08:00
|
|
|
|
// 从 chartData 中查找对应站点的 stcd
|
|
|
|
|
|
const found = chartData.value.find((el: any) => el.stnm === params.name);
|
|
|
|
|
|
modalYear.value = select.value.value;
|
|
|
|
|
|
modalHbrvcd.value = moreSelect.value.value || '';
|
2026-07-01 18:23:41 +08:00
|
|
|
|
modalStateName.value = params.seriesName || '';
|
2026-06-26 17:52:57 +08:00
|
|
|
|
modalSectionName.value = params.name || '';
|
|
|
|
|
|
modalStcd.value = found?.stcd || '';
|
|
|
|
|
|
modalVisible.value = true;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 关闭详情弹框 */
|
|
|
|
|
|
const handleModalClose = () => {
|
|
|
|
|
|
modalVisible.value = false;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 事件处理 ====================
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 处理侧边面板控件变化(流域或年份选择改变时触发)
|
|
|
|
|
|
* SidePanelItem 内部通过 watch 监听用户操作后 emit 此事件
|
|
|
|
|
|
* @param data 包含 { select, moreSelect, ... } 的变更值
|
|
|
|
|
|
*/
|
|
|
|
|
|
const handlePanelChange = async (data: any) => {
|
|
|
|
|
|
// 初始化期间不响应控件变化
|
|
|
|
|
|
if (isInitializing.value) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 流域选择变化:更新年份选项 + 请求图表数据
|
|
|
|
|
|
if (
|
|
|
|
|
|
data.moreSelect !== undefined &&
|
|
|
|
|
|
data.moreSelect !== moreSelect.value.value
|
|
|
|
|
|
) {
|
|
|
|
|
|
moreSelect.value.value = data.moreSelect;
|
|
|
|
|
|
await updateYearOptionsByBase(data.moreSelect);
|
|
|
|
|
|
await getChartData();
|
|
|
|
|
|
return; // 已用新年份请求数据,避免年份变化再次触发请求
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 年份选择变化:直接请求图表数据
|
|
|
|
|
|
if (data.select !== undefined && data.select !== select.value.value) {
|
|
|
|
|
|
select.value.value = data.select;
|
|
|
|
|
|
await getChartData();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== Watch 监听 ====================
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 监听基地变化
|
|
|
|
|
|
* 当用户在顶部切换基地时,重新加载流域列表、年份和图表数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => JidiSelectEventStore.selectedItem,
|
|
|
|
|
|
async newVal => {
|
|
|
|
|
|
if (newVal && newVal.wbsCode) {
|
2026-07-15 18:24:05 +08:00
|
|
|
|
if (newVal.wbsCode === 'all') {
|
|
|
|
|
|
moreSelect.value.value = moreSelect.value.options[0]?.value;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
moreSelect.value.value = newVal.wbsCode;
|
|
|
|
|
|
}
|
|
|
|
|
|
await getYearData();
|
|
|
|
|
|
if (moreSelect.value.value) {
|
|
|
|
|
|
await updateYearOptionsByBase(moreSelect.value.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
await getChartData();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{ deep: true, immediate: true }
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 监听 JidiSelectEventStore.jidiData 变化,同步 moreSelect 下拉框选项
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => JidiSelectEventStore.jidiData,
|
|
|
|
|
|
newVal => {
|
|
|
|
|
|
const filtered = newVal.filter(item => item.wbsCode !== 'all');
|
|
|
|
|
|
moreSelect.value.options = filtered.map(item => ({
|
|
|
|
|
|
value: item.wbsCode,
|
|
|
|
|
|
title: item.wbsName
|
|
|
|
|
|
}));
|
|
|
|
|
|
if (!moreSelect.value.value && filtered.length > 0) {
|
|
|
|
|
|
moreSelect.value.value = filtered[0].wbsCode;
|
2026-06-26 17:52:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{ deep: true, immediate: true }
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 生命周期钩子 ====================
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
initChart();
|
|
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
|
|
|
|
}, 50);
|
|
|
|
|
|
});
|
2026-05-12 08:47:27 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
2026-06-26 17:52:57 +08:00
|
|
|
|
window.removeEventListener('resize', handleResize);
|
|
|
|
|
|
|
|
|
|
|
|
if (chartInstance) {
|
|
|
|
|
|
chartInstance.dispose();
|
|
|
|
|
|
chartInstance = null;
|
|
|
|
|
|
}
|
2026-05-12 08:47:27 +08:00
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.chart-container {
|
2026-06-26 17:52:57 +08:00
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 231px;
|
|
|
|
|
|
min-height: 231px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.empty-placeholder {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
min-height: 231px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-empty-description) {
|
|
|
|
|
|
text-indent: 0em !important;
|
2026-05-12 08:47:27 +08:00
|
|
|
|
}
|
2026-06-26 17:52:57 +08:00
|
|
|
|
</style>
|