442 lines
10 KiB
Vue
442 lines
10 KiB
Vue
<script setup lang="ts">
|
|
import {
|
|
ref,
|
|
reactive,
|
|
watch,
|
|
onMounted,
|
|
onBeforeUnmount,
|
|
nextTick
|
|
} from 'vue';
|
|
import * as echarts from 'echarts';
|
|
import type { ECharts } from 'echarts';
|
|
import { getFishtKendoList, getCompareBar } from '@/api/stdc';
|
|
import BasicTable from '@/components/BasicTable/index.vue';
|
|
|
|
const props = defineProps<{
|
|
currentItem: any;
|
|
}>();
|
|
|
|
// ==================== 搜索状态 ====================
|
|
const weLis = ref<any[]>([]);
|
|
const pcList = ref<any[]>([]);
|
|
const searchParam = reactive({
|
|
dcpc: '',
|
|
dcpcCompare: '',
|
|
stcd: ''
|
|
});
|
|
|
|
// ==================== 图表状态 ====================
|
|
const chartRef = ref<HTMLElement | null>(null);
|
|
let chartInstance: ECharts | null = null;
|
|
const chartList = ref<any[]>([]);
|
|
const chartLoading = ref(true);
|
|
|
|
// ==================== 表格状态 ====================
|
|
const tabLoading = ref(false);
|
|
const tableRef = ref();
|
|
const column = ref([
|
|
{
|
|
key: 'ftp',
|
|
title: '鱼种类',
|
|
dataIndex: 'ftp',
|
|
fixed: 'left' as const,
|
|
width: 150,
|
|
ellipsis: true
|
|
},
|
|
{
|
|
key: 'genus',
|
|
title: '科属',
|
|
dataIndex: 'genus',
|
|
fixed: 'left' as const,
|
|
width: 150,
|
|
ellipsis: true
|
|
},
|
|
{
|
|
key: 'fcnt',
|
|
title: '第一批次',
|
|
dataIndex: 'fcnt',
|
|
width: 150,
|
|
ellipsis: true
|
|
},
|
|
{
|
|
key: 'fcnt2',
|
|
title: '对比批次',
|
|
dataIndex: 'fcnt2',
|
|
width: 150,
|
|
ellipsis: true
|
|
}
|
|
]);
|
|
|
|
// ==================== 构建表格过滤条件 ====================
|
|
const buildTableFilter = () => {
|
|
const filters: any[] = [];
|
|
if (searchParam.stcd) {
|
|
filters.push({ field: 'stcd', operator: 'eq', value: searchParam.stcd });
|
|
}
|
|
if (searchParam.dcpc) {
|
|
filters.push({ field: 'dcpc', operator: 'eq', value: searchParam.dcpc });
|
|
}
|
|
if (searchParam.dcpcCompare) {
|
|
filters.push({
|
|
field: 'dcpc2',
|
|
operator: 'eq',
|
|
value: searchParam.dcpcCompare
|
|
});
|
|
}
|
|
|
|
// 动态更新列标题
|
|
column.value[2].title = searchParam.dcpc || '第一批次';
|
|
column.value[3].title = searchParam.dcpcCompare || '对比批次';
|
|
|
|
return {
|
|
logic: 'and',
|
|
filters
|
|
};
|
|
};
|
|
|
|
// ==================== 获取断面和批次列表 ====================
|
|
const fetchPcData = async () => {
|
|
const baseid = props.currentItem?.wbsCode || props.currentItem?.baseid;
|
|
const params = {
|
|
filter: {
|
|
filters:
|
|
baseid === 'all'
|
|
? []
|
|
: [
|
|
{
|
|
field: 'baseId',
|
|
operator: 'eq',
|
|
value: baseid
|
|
}
|
|
]
|
|
},
|
|
group: [
|
|
{ dir: 'asc', field: 'stcd' },
|
|
{ dir: 'asc', field: 'stnm' },
|
|
{ dir: 'asc', field: 'dcpc' }
|
|
]
|
|
};
|
|
|
|
const res = await getFishtKendoList(params);
|
|
if (res?.data?.data?.length) {
|
|
const options: any[] = [];
|
|
res.data.data.forEach((el: any) => {
|
|
if (el?.items?.[0]?.items?.length > 1) {
|
|
options.push({
|
|
label: el?.items?.[0]?.key,
|
|
value: el?.key,
|
|
dcpc: el?.items?.[0]?.items?.map((item: any) => ({
|
|
label: item.key,
|
|
value: item.key
|
|
}))
|
|
});
|
|
}
|
|
});
|
|
|
|
weLis.value = options;
|
|
pcList.value = options?.[0]?.dcpc ?? [];
|
|
|
|
searchParam.stcd = options[0]?.value || '';
|
|
searchParam.dcpc = options[0]?.dcpc?.[0]?.value || '';
|
|
searchParam.dcpcCompare = options[0]?.dcpc?.[1]?.value || '';
|
|
|
|
tabLoading.value = true;
|
|
} else {
|
|
weLis.value = [];
|
|
pcList.value = [];
|
|
tabLoading.value = true;
|
|
}
|
|
};
|
|
|
|
// ==================== 断面切换 ====================
|
|
const handleStcdChange = (stcd: string) => {
|
|
if (!stcd) return;
|
|
const found = weLis.value.find((el: any) => el.value === stcd);
|
|
if (found) {
|
|
pcList.value = found.dcpc;
|
|
searchParam.stcd = found.value;
|
|
searchParam.dcpc = found.dcpc?.[0]?.value || '';
|
|
searchParam.dcpcCompare = found.dcpc?.[1]?.value || '';
|
|
}
|
|
};
|
|
|
|
// ==================== 获取图表数据 ====================
|
|
const fetchChartData = async () => {
|
|
chartLoading.value = true;
|
|
try {
|
|
const params = {
|
|
filter: {
|
|
logic: 'and',
|
|
filters: [
|
|
{
|
|
field: 'stcd',
|
|
operator: 'eq',
|
|
dataType: 'string',
|
|
value: searchParam.stcd
|
|
},
|
|
{
|
|
field: 'dcpc',
|
|
operator: 'eq',
|
|
dataType: 'string',
|
|
value: searchParam.dcpc
|
|
},
|
|
{
|
|
field: 'dcpc2',
|
|
operator: 'eq',
|
|
dataType: 'string',
|
|
value: searchParam.dcpcCompare
|
|
}
|
|
]
|
|
}
|
|
};
|
|
const res: any = await getCompareBar(params);
|
|
// debugger
|
|
if (res?.data?.data?.[0]?.dataSource) {
|
|
chartList.value = res.data.data[0].dataSource;
|
|
} else {
|
|
chartList.value = [];
|
|
}
|
|
} catch (error) {
|
|
console.error('获取图表数据失败:', error);
|
|
chartList.value = [];
|
|
} finally {
|
|
chartLoading.value = false;
|
|
}
|
|
};
|
|
|
|
// ==================== 初始化图表 ====================
|
|
const initChart = () => {
|
|
if (!chartRef.value) return;
|
|
|
|
if (!chartInstance) {
|
|
chartInstance = echarts.init(chartRef.value);
|
|
}
|
|
|
|
if (!chartList.value || chartList.value.length < 1) {
|
|
chartInstance.setOption({
|
|
title: { text: '', subtext: '' },
|
|
tooltip: { trigger: 'axis' },
|
|
xAxis: { type: 'category', data: [] },
|
|
yAxis: { type: 'value' },
|
|
series: []
|
|
});
|
|
return;
|
|
}
|
|
|
|
const option = {
|
|
title: { text: '', subtext: '' },
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
axisPointer: { type: 'shadow' }
|
|
},
|
|
legend: {
|
|
data: [searchParam.dcpc, searchParam.dcpcCompare],
|
|
left: 'center',
|
|
show: true,
|
|
itemWidth: 12,
|
|
itemHeight: 8,
|
|
textStyle: { fontSize: 14 }
|
|
},
|
|
grid: {
|
|
top: '20%',
|
|
left: '5%',
|
|
right: 0,
|
|
bottom: 0,
|
|
containLabel: true
|
|
},
|
|
xAxis: {
|
|
type: 'category',
|
|
axisLabel: { rotate: 45 },
|
|
axisTick: { show: false },
|
|
data: chartList.value.map((e: any) => e.ftp)
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
name: '数量(尾)'
|
|
},
|
|
series: [
|
|
{
|
|
name: searchParam.dcpc,
|
|
type: 'bar',
|
|
barWidth: 5,
|
|
stack: 'dcpc',
|
|
data: chartList.value.map((e: any) => e.fcnt)
|
|
},
|
|
{
|
|
name: searchParam.dcpcCompare,
|
|
type: 'bar',
|
|
barWidth: 5,
|
|
stack: 'dcpcCompare',
|
|
data: chartList.value.map((e: any) => e.fcnt2)
|
|
}
|
|
]
|
|
};
|
|
|
|
chartInstance.setOption(option, true);
|
|
};
|
|
|
|
// ==================== 表格数据转换 ====================
|
|
const customTransform = (res: any) => {
|
|
return {
|
|
records: res?.data?.data?.[0].dataSource || [],
|
|
total: res?.data?.total || 0
|
|
};
|
|
};
|
|
|
|
// ==================== 刷新表格 ====================
|
|
const refreshTable = () => {
|
|
const filter = buildTableFilter();
|
|
tableRef.value?.getList(filter);
|
|
};
|
|
|
|
// ==================== 查询按钮 ====================
|
|
const handleSearch = () => {
|
|
fetchChartData();
|
|
nextTick(() => {
|
|
initChart();
|
|
refreshTable();
|
|
});
|
|
};
|
|
|
|
// ==================== 监听批次变化自动刷新图表 ====================
|
|
watch(
|
|
() => [searchParam.dcpc, searchParam.dcpcCompare],
|
|
() => {
|
|
fetchChartData();
|
|
nextTick(() => {
|
|
initChart();
|
|
});
|
|
}
|
|
);
|
|
|
|
// ==================== 监听图表数据变化 ====================
|
|
watch(
|
|
() => chartList.value,
|
|
() => {
|
|
nextTick(() => {
|
|
initChart();
|
|
});
|
|
}
|
|
);
|
|
|
|
// ==================== 窗口resize ====================
|
|
const handleResize = () => {
|
|
chartInstance?.resize();
|
|
};
|
|
|
|
// ==================== 生命周期 ====================
|
|
onMounted(async () => {
|
|
await fetchPcData();
|
|
await nextTick();
|
|
fetchChartData();
|
|
await nextTick();
|
|
initChart();
|
|
await nextTick();
|
|
refreshTable();
|
|
window.addEventListener('resize', handleResize);
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
window.removeEventListener('resize', handleResize);
|
|
chartInstance?.dispose();
|
|
chartInstance = null;
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="ssstdcdb-page">
|
|
<!-- 搜索表单 -->
|
|
<div class="search-form">
|
|
<a-form-item label="调查断面">
|
|
<a-select
|
|
v-model:value="searchParam.stcd"
|
|
placeholder="请选择调查断面"
|
|
style="width: 200px; margin-right: 12px"
|
|
:options="weLis"
|
|
@change="handleStcdChange"
|
|
/>
|
|
</a-form-item>
|
|
<a-form-item label="调查批次">
|
|
<a-select
|
|
v-model:value="searchParam.dcpc"
|
|
placeholder="请选择调查批次"
|
|
style="width: 200px; margin-right: 12px"
|
|
:options="pcList"
|
|
/>
|
|
</a-form-item>
|
|
<a-form-item label="对比批次">
|
|
<a-select
|
|
v-model:value="searchParam.dcpcCompare"
|
|
placeholder="请选择对比批次"
|
|
style="width: 200px; margin-right: 12px"
|
|
:options="pcList"
|
|
/>
|
|
</a-form-item>
|
|
<a-button type="primary" @click="handleSearch">查询</a-button>
|
|
</div>
|
|
|
|
<!-- 图表 + 表格 -->
|
|
<div class="content-area">
|
|
<!-- 图表 -->
|
|
<div class="chart-section">
|
|
<a-spin :spinning="chartLoading">
|
|
<div ref="chartRef" class="chart-container" style="height: 500px"></div>
|
|
<a-empty
|
|
v-if="!chartLoading && chartList.length === 0"
|
|
class="chart-empty"
|
|
description="暂无数据"
|
|
/>
|
|
</a-spin>
|
|
</div>
|
|
|
|
<!-- 表格 -->
|
|
|
|
<BasicTable
|
|
ref="tableRef"
|
|
:columns="column"
|
|
:scroll-y="400"
|
|
:scroll-x="300"
|
|
:list-url="tabLoading ? getCompareBar : undefined"
|
|
:search-params="{ sort: [] }"
|
|
:transform-data="customTransform"
|
|
/>
|
|
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.ssstdcdb-page {
|
|
// padding: 16px;
|
|
|
|
.search-form {
|
|
padding: 16px 0;
|
|
display: flex;
|
|
}
|
|
|
|
.content-area {
|
|
display: flex;
|
|
gap: 16px;
|
|
|
|
.chart-section {
|
|
width: 40%;
|
|
height: 500px;
|
|
position: relative;
|
|
}
|
|
|
|
.chart-empty {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
z-index: 1;
|
|
}
|
|
|
|
.table-section {
|
|
width: 60%;
|
|
height: 500px;
|
|
}
|
|
}
|
|
}
|
|
</style>
|