WholeProcessPlatform/frontend/src/modules/fishSurvey/FishChangeTu/index.vue

316 lines
7.2 KiB
Vue
Raw Normal View History

2026-06-18 09:29:15 +08:00
<template>
<SidePanelItem
title="鱼类变化情况"
:datetimePicker="datetimePicker"
@update-values="handlePanelChange"
>
2026-07-07 13:50:21 +08:00
<a-spin :spinning="loading" style="width: 100%">
<div
ref="chartContainer"
class="chart-container"
v-show="sourceData.length > 0"
></div>
<a-empty
v-show="sourceData.length === 0"
description="暂无数据"
class="empty-container"
/>
2026-06-18 09:29:15 +08:00
</a-spin>
</SidePanelItem>
</template>
<script lang="ts" setup>
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue';
import * as echarts from 'echarts';
2026-06-24 11:26:19 +08:00
import type { ECharts } from 'echarts';
2026-06-18 09:29:15 +08:00
import type { EChartsOption } from 'echarts';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { sdFprdRGetFtpChangeInfo } from '@/api/yldc';
2026-06-24 11:26:19 +08:00
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
2026-06-18 09:29:15 +08:00
defineOptions({
name: 'FishChangeTu'
});
const JidiSelectEventStore = useJidiSelectEventStore();
// const BASE_ID = '07';
// 日期选择器配置
const datetimePicker = ref({
show: true,
value: `${new Date().getFullYear()}`,
format: 'YYYY',
picker: 'year' as const,
options: []
});
// 数据状态
const sourceData = ref<
Array<{
year: number;
month: number;
ftpCount: number;
fishCount: number;
}>
>([]);
const loading = ref(false);
// 图表实例
const chartContainer = ref<HTMLDivElement | null>(null);
2026-06-24 11:26:19 +08:00
let chartInstance: ECharts | null = null;
2026-06-18 09:29:15 +08:00
// 生成从1月到当前月份的月份列表
function getMonthsUntilNow(year: number) {
const now = new Date();
const currentYear = now.getFullYear();
const currentMonth = now.getMonth() + 1;
const months: Array<{ name: string; value: number }> = [];
const maxMonth = year >= currentYear ? currentMonth : 12;
for (let i = 1; i <= maxMonth; i++) {
months.push({
name: i + '月',
value: i
});
}
return months;
}
// 处理图表数据
const fishData = computed(() => {
const dates = getMonthsUntilNow(parseInt(datetimePicker.value.value));
if (sourceData.value.length > 0) {
const speciesCount = dates.map(item => {
const info = sourceData.value.find(v => v.month === item.value);
return info ? Number(info.ftpCount) : 0;
});
const fishCount = dates.map(item => {
const info = sourceData.value.find(v => v.month === item.value);
return info ? Number(info.fishCount) : 0;
});
return {
dates: dates.map(item => item.name),
speciesCount,
fishCount
};
}
return {
dates: dates.map(item => item.name),
speciesCount: [],
fishCount: []
};
});
// 图表配置
const option = computed<EChartsOption>(() => {
const data = fishData.value;
const baseFontSize = 12;
// 动态计算Y轴范围
const speciesMax = Math.max(...data.speciesCount, 1);
const fishMax = Math.max(...data.fishCount, 1);
return {
yAxisSplit: 5,
tooltip: {
trigger: 'axis',
axisPointer: { type: 'cross' },
backgroundColor: 'rgba(50,50,50,0.9)',
textStyle: { fontSize: baseFontSize, color: '#fff' }
},
legend: {
data: ['种类', '总数'],
top: 0,
textStyle: { fontSize: baseFontSize }
},
grid: {
2026-06-24 11:26:19 +08:00
left: 50,
right: 60,
top: 45,
bottom: 40
2026-06-18 09:29:15 +08:00
},
xAxis: {
type: 'category',
data: data.dates,
axisLine: { lineStyle: { color: '#ccc' } },
splitLine: { show: true },
axisLabel: {
color: '#666',
fontSize: baseFontSize,
rotate: 0,
interval: 0
}
},
yAxis: [
{
type: 'value',
name: '种类',
nameTextStyle: { fontSize: baseFontSize },
min: 0,
max: Math.ceil(speciesMax * 1.2),
axisLine: { lineStyle: { color: '#165DFF' } },
axisLabel: {
color: '#666',
fontSize: baseFontSize,
formatter: (value: number) => Math.floor(value).toString()
},
splitLine: { lineStyle: { color: '#eee' } }
},
{
type: 'value',
name: '总数',
nameTextStyle: { fontSize: baseFontSize },
min: 0,
max: Math.ceil(fishMax * 1.2),
axisLine: { lineStyle: { color: '#36CFC9' } },
axisLabel: {
color: '#666',
fontSize: baseFontSize,
formatter: (value: number) => Math.floor(value).toString()
}
}
],
series: [
{
name: '种类',
type: 'line',
data: data.speciesCount,
yAxisIndex: 0,
color: '#165DFF',
smooth: true,
symbol: 'circle',
symbolSize: 8,
label: {
show: true,
position: 'top',
fontSize: baseFontSize - 2
}
},
{
name: '总数',
type: 'line',
data: data.fishCount,
yAxisIndex: 1,
color: '#36CFC9',
smooth: true,
symbol: 'circle',
symbolSize: 8,
label: {
show: true,
position: 'top',
fontSize: baseFontSize - 2
}
}
]
};
});
// 获取数据
const getData = async () => {
try {
loading.value = true;
const year = datetimePicker.value.value;
const res = await sdFprdRGetFtpChangeInfo({
baseId: baseid.value,
year
});
if (res && (res as any).data) {
sourceData.value = (res as any).data;
} else {
sourceData.value = [];
}
} catch (error) {
console.error('获取鱼类变化数据失败:', error);
sourceData.value = [];
} finally {
loading.value = false;
}
2026-06-24 11:26:19 +08:00
nextTick(() => {
if (sourceData.value.length > 0) {
initChart();
}
});
2026-06-18 09:29:15 +08:00
};
// 初始化图表
const initChart = () => {
if (!chartContainer.value) return;
if (chartInstance) {
chartInstance.dispose();
}
chartInstance = echarts.init(chartContainer.value);
chartInstance.setOption(option.value, true);
};
// 更新图表
const updateChart = () => {
if (chartInstance) {
chartInstance.setOption(option.value, true);
chartInstance.resize();
}
};
// 处理面板变化
const handlePanelChange = (data: any) => {
if (data.datetime) {
datetimePicker.value.value = data.datetime;
getData();
}
};
// 窗口大小变化时重新调整图表
const handleResize = () => {
2026-06-24 11:26:19 +08:00
chartInstance?.resize();
2026-06-18 09:29:15 +08:00
};
let baseid = ref('');
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
}
},
{ deep: true, immediate: true }
);
2026-06-24 11:26:19 +08:00
2026-06-18 09:29:15 +08:00
onMounted(() => {
2026-06-24 11:26:19 +08:00
nextTick(() => {
// 延时确保容器尺寸已完全渲染
setTimeout(() => {
if (chartContainer.value) {
chartInstance = echarts.init(chartContainer.value);
chartInstance.setOption(option.value);
}
// 监听窗口大小变化
window.addEventListener('resize', handleResize);
}, 50);
});
2026-06-18 09:29:15 +08:00
getData();
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
2026-06-24 11:26:19 +08:00
chartInstance?.dispose();
chartInstance = null;
2026-06-18 09:29:15 +08:00
});
</script>
<style lang="scss" scoped>
.chart-container {
width: 100%;
height: 200px;
2026-06-24 11:26:19 +08:00
min-height: 200px;
}
.empty-container {
display: flex;
2026-07-07 13:50:21 +08:00
flex-direction: column;
2026-06-24 11:26:19 +08:00
justify-content: center;
align-items: center;
height: 200px;
2026-07-07 13:50:21 +08:00
p{
text-indent:0px !important;
}
2026-06-18 09:29:15 +08:00
}
</style>