WholeProcessPlatform/frontend/src/modules/dianzhanzhuantiMod/ZenZhiZhanYunXingPG/index.vue

623 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<SidePanelItem
title="增殖站运行及评估"
:select="stationSelect"
@update-values="onPanelChange"
>
<div class="zzzyx-wrapper">
<a-spin :spinning="loading" tip="加载中...">
<div v-if="hasData" class="step-card-wrapper">
<div
v-for="(item, index) in stepList"
:key="item.key"
class="step-card"
:class="{
'step-card--active': activeIndex === index,
'step-card--last': index === 4
}"
:style="{ zIndex: activeIndex === index ? 999 : 989 - index * 10 }"
@click="index === 4 ? undefined : setActiveIndex(index)"
>
<!-- 激活状态:展开子步骤 -->
<template v-if="activeIndex === index">
<div class="step-card__header">{{ item.title }}</div>
<div class="step-card__icon">
<img :src="fishStation2Svg" alt="" />
</div>
<div class="step-card__arrow">
<img :src="arrowDownLine2Svg" alt="" />
</div>
<div class="step-card__list">
<div
v-for="val in item.textList"
:key="val.key"
class="step-card__list-item"
:class="{
'is-disabled': val.disable,
'is-active': val.curNewSurFace
}"
:style="val.disable ? {} : { cursor: 'pointer' }"
@click="!val.disable && val.proTable?.length && detailModalRef?.open(val)"
>
{{ val.ctitle }}
</div>
</div>
<p class="step-card__step">STEP{{ index + 1 }}</p>
</template>
<!-- 折叠状态 -->
<template v-else>
<div class="step-card__fold-label">{{ item.title }}</div>
<p class="step-card__step">STEP{{ index + 1 }}</p>
</template>
</div>
</div>
<a-empty
v-if="!hasData && !loading"
description="暂无数据"
class="empty-center"
/>
</a-spin>
</div>
<!-- 详情弹窗子组件 -->
<ZenZhiZhanYunXingDetailModal
ref="detailModalRef"
:selected-stcd="selectedStcd"
/>
</SidePanelItem>
</template>
<script lang="ts" setup>
import { ref, computed, watch, inject } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import ZenZhiZhanYunXingDetailModal from './ZenZhiZhanYunXingDetailModal.vue';
import fishStation2Svg from '@/assets/icons/fishStation2.svg';
import arrowDownLine2Svg from '@/assets/icons/arrowDownLine2.svg';
import {
getHatcheryOperationData
} from '@/api/dianZhanZhuanTi';
import { msstbprptGetKendoList } from '@/api/zzfl';
import {
qinYuXinXi,
qinYuSiWanJiLu,
qinYuPeiYuFangShi,
qinYuPeiYuShuiWen,
qinYuPeiYuShuiZi,
qinYuPeiYuTouWei,
taoTaiQinYu,
yuLeiRenGo,
yuLeiShouJin,
yuleifuhua,
miaoZhongPeiYu,
miaoZhongJiLu,
yuBingFangZhi
} from '@/components/MapModal/components/NormalOperationData/proliferationColumns';
defineOptions({ name: 'ZenZhiZhanYunXingPG' });
// ==================== 注入电站上下文 ====================
const dianZhanStation = inject<any>('dianZhanStation', ref(null));
const apiId = computed(() => dianZhanStation.value?.stcd || '');
// ==================== 5个步骤的初始结构含 proTable 数据) ====================
const INIT_STEP_LIST = [
{
title: '亲鱼选配与培育',
key: '0',
textList: [
{
ctitle: '亲鱼选配',
key: '1-1',
disable: false,
curNewSurFace: '',
proTable: [
{
title: '亲鱼信息',
key: '1-1-1',
url: '/fb/bsmfr/GetKendoListCust',
columns: qinYuXinXi,
filter: [
{ type: 'select', name: 'ftp', label: '鱼类', options: [] },
{ type: 'input', name: 'signnum', label: '标记编号' }
]
},
{
title: '亲鱼死亡记录',
key: '1-1-2',
url: '/fb/bsdeathr/GetKendoListCust',
columns: qinYuSiWanJiLu,
filter: [
{ type: 'select', name: 'ftp', label: '鱼类', options: [] },
{ type: 'input', name: 'fpnum', label: '鱼池编号' },
{ type: 'input', name: 'signnum', label: '标记编号' }
]
}
]
},
{
ctitle: '亲鱼培育',
key: '1-2',
disable: false,
curNewSurFace: '',
proTable: [
{
title: '亲鱼培育方式',
key: '1-2-1',
url: '/fb/bsctmob/GetKendoListCust',
columns: qinYuPeiYuFangShi,
filter: [
{ type: 'select', name: 'ftp', label: '鱼类', options: [] },
{ type: 'input', name: 'fpnum', label: '鱼池编号' }
]
},
{
title: '亲鱼培育水温观测记录',
key: '1-2-2',
url: '/fb/fbbwtr/GetKendoListCust',
columns: qinYuPeiYuShuiWen,
filter: [
{ type: 'input', name: 'fpnum', label: '鱼池编号' }
]
},
{
title: '亲鱼培育水质监测记录',
key: '1-2-3',
url: '/fb/fbcwqr/GetKendoListCust',
columns: qinYuPeiYuShuiZi,
filter: [
{ type: 'input', name: 'fpnum', label: '鱼池编号' }
]
},
{
title: '亲鱼培育投喂记录',
key: '1-2-4',
url: '/fb/bsrfir/GetKendoListCust',
columns: qinYuPeiYuTouWei,
filter: [
{ type: 'input', name: 'fpnum', label: '鱼池编号' }
]
}
]
},
{
ctitle: '亲鱼补充与淘汰',
key: '1-3',
disable: false,
curNewSurFace: '',
proTable: [
{
title: '淘汰亲鱼信息',
key: '1-3-1',
url: '/fb/outfishr/GetKendoListCust',
columns: taoTaiQinYu,
filter: [
{ type: 'select', name: 'ftp', label: '鱼类', options: [] },
{ type: 'input', name: 'signno', label: '标记编号' }
]
}
]
}
]
},
{
title: '人工繁殖',
key: '1',
textList: [
{
ctitle: '亲本选择',
key: '2-1',
disable: true,
curNewSurFace: '',
proTable: []
},
{
ctitle: '人工催产',
key: '2-2',
disable: false,
curNewSurFace: '',
proTable: [
{
title: '鱼类人工催产记录',
key: '2-2-1',
url: '/fb/fishartinlr/GetKendoListCust',
columns: yuLeiRenGo,
filter: [
{ type: 'select', name: 'ftp', label: '鱼类', options: [] }
]
}
]
},
{
ctitle: '人工授精',
key: '2-3',
disable: true,
curNewSurFace: '',
proTable: []
},
{
ctitle: '孵化',
key: '2-4',
disable: false,
curNewSurFace: '',
proTable: [
{
title: '鱼类受精卵孵化过程记录',
key: '2-4-1',
url: '/fb/fishhatchrecr/GetKendoListCust',
columns: yuLeiShouJin,
filter: [
{ type: 'select', name: 'ftp', label: '鱼类', options: [] },
{ type: 'input', name: 'fishsrc', label: '亲鱼来源' }
]
},
{
title: '鱼类孵化过程巡查记录',
key: '2-4-2',
url: '/fb/fishhatchpror/GetKendoListCust',
columns: yuleifuhua,
filter: [
{ type: 'input', name: 'devno', label: '孵化设施编号' }
]
}
]
}
]
},
{
title: '鱼苗和鱼种的培育',
key: '2',
textList: [
{
ctitle: '鱼苗和鱼种的培育',
key: '3-1',
disable: false,
curNewSurFace: '',
proTable: [
{
title: '苗种培育水环境监测记录',
key: '3-1-1',
url: '/fb/scwemr/GetKendoListCust',
columns: miaoZhongPeiYu,
filter: [
{ type: 'input', name: 'fpnum', label: '鱼池编号' }
]
},
{
title: '苗种培育记录',
key: '3-1-2',
url: '/fb/fishbreedr/GetKendoListCust',
columns: miaoZhongJiLu,
filter: [
{ type: 'input', name: 'farmno', label: '鱼池编号' }
]
}
]
}
]
},
{
title: '鱼病防治',
key: '3',
textList: [
{
ctitle: '鱼病防治',
key: '4-1',
disable: false,
curNewSurFace: '',
proTable: [
{
title: '鱼病防治记录',
key: '4-1-1',
url: '/fb/fishdpacr/GetKendoListCust',
columns: yuBingFangZhi,
filter: [
{ type: 'input', name: 'fpnum', label: '鱼池编号' }
]
}
]
}
]
},
{
title: '放流',
key: '4',
textList: []
}
];
// ==================== 状态 ====================
const loading = ref(false);
const hasData = ref(false);
const stepList = ref<any[]>([]);
const activeIndex = ref(0);
const stationOptions = ref<
Array<{ value: string; label: string; stcd: string }>
>([]);
const selectedStation = ref<string>('');
const selectedStcd = ref<string>('');
// ==================== 弹窗子组件 ref ====================
const detailModalRef = ref();
// ==================== SidePanelItem 配置 ====================
const stationSelect = computed(() => ({
show: true,
value: selectedStation.value,
options: stationOptions.value,
width: '160px'
}));
// ==================== API方法 ====================
/** 拉取增殖站下拉列表 */
const fetchStationList = async (stcd: string) => {
if (!stcd) return;
try {
const params: any = {
filter: {
logic: 'and',
filters: [
{
field: 'rstcd',
operator: 'contains',
dataType: 'string',
value: stcd
},
{
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: 'FB'
}
]
},
select: [
'id',
'stcd',
'rstcd',
'ennm',
'stnm',
'sttpCode',
'lgtd',
'lttd',
'orderIndex'
]
};
const res = await msstbprptGetKendoList(params);
const data = res?.data?.data || [];
if (data.length > 0) {
const list = data.map((item: any) => ({
label: item.stnm,
value: item.stcd,
stcd: item.stcd
}));
stationOptions.value = list.map((item: any) => ({
value: item.value,
label: item.label,
stcd: item.stcd
}));
selectedStation.value = list[0].value;
selectedStcd.value = list[0].stcd;
} else {
stationOptions.value = [];
selectedStation.value = '';
selectedStcd.value = '';
}
} catch (e) {
console.error('获取增殖站列表失败', e);
}
};
/** 拉取各步骤运行状态 */
const fetchStepStatus = async (stcd: string) => {
if (!stcd) return;
loading.value = true;
try {
const params = {
filter: {
logic: 'and',
filters: [
{
field: 'stcd',
operator: 'eq',
dataType: 'string',
value: stcd
}
]
}
};
const stepRes = await getHatcheryOperationData(params);
const stepData = stepRes?.data?.data || [];
if (stepData.length > 0) {
hasData.value = true;
const newStepList = JSON.parse(JSON.stringify(INIT_STEP_LIST));
// 找最新步骤
stepData.forEach((item: any) => {
const { firstGrade, newest } = item;
if (newest) {
const idx = newStepList.findIndex((s: any) => s.title === firstGrade);
if (idx !== -1) activeIndex.value = idx;
}
});
// 填充各子步骤状态
newStepList.forEach((step: any) => {
step.textList.forEach((val: any) => {
let curNewSurFace = '';
stepData.forEach((dItem: any) => {
const { key, newSurface, value } = dItem;
if (val.ctitle === key) {
val.disable = value === '2';
curNewSurFace = newSurface;
}
});
val.curNewSurFace = curNewSurFace;
});
});
stepList.value = newStepList;
} else {
hasData.value = false;
}
} catch (e) {
console.error('获取增殖站运行状态失败', e);
hasData.value = false;
} finally {
loading.value = false;
}
};
// ==================== 事件处理 ====================
const onPanelChange = (data: any) => {
if (data.select) {
const option = stationOptions.value.find(
(item: any) => item.value === data.select
);
if (option) {
selectedStation.value = option.value;
selectedStcd.value = option.stcd;
fetchStepStatus(option.stcd);
}
}
};
const setActiveIndex = (index: number) => {
activeIndex.value = index;
};
// ==================== 监听 ====================
watch(apiId, newId => {
if (newId) {
fetchStationList(newId);
}
}, { immediate: true });
// 拉完下拉列表后自动拉步骤数据
watch(selectedStcd, newStcd => {
if (newStcd) {
fetchStepStatus(newStcd);
}
});
</script>
<style lang="scss" scoped>
.zzzyx-wrapper {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
:deep(.ant-spin-nested-loading) {
width: 100%;
height: 100%;
}
:deep(.ant-spin-container) {
width: 100%;
height: 100%;
}
}
/* .empty-center {
height: 100%;
} */
.step-card-wrapper {
display: flex;
height: 100%;
position: relative;
padding: 0px 10px;
align-items: center;
justify-content: space-between;
}
.step-card {
position: relative;
transition: all 0.3s ease;
background: #ffffff40;
border: 1px solid #ddd;
height: 100%;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
&:hover {
box-shadow: 3px 3px 3px 3px #2f6b9840;
}
}
.step-card--active {
background: #fff;
border: 0px solid #00000000;
display: block;
&:hover {
box-shadow: 3px 3px 3px 3px #2f6b9840;
}
}
.step-card__header {
font-size: 14px;
color: #000000d9;
margin-bottom: 2px;
width: 126px;
text-align: center;
}
.step-card__icon {
width: 100%;
display: flex;
justify-content: center;
margin: 3px 0px;
img {
width: 45px;
height: 45px;
}
}
.step-card__arrow {
width: 100%;
display: flex;
justify-content: center;
img {
width: 20px;
height: 8px;
}
}
.step-card__list {
display: flex;
flex-direction: column;
align-items: center;
margin: 4px 0;
}
.step-card__list-item {
font-size: 14px;
color: #000000d9;
white-space: nowrap;
}
.step-card__list-item.is-disabled {
color: #bbb;
cursor: default;
}
.step-card__step {
position: absolute;
left: -25px;
bottom: 4px;
font-size: 14px;
color: #999;
margin: 0;
}
.step-card__fold-label {
font-size: 14px;
color: #000000d9;
writing-mode: vertical-lr;
letter-spacing: 2px;
}
</style>