WholeProcessPlatform/frontend/src/components/MapModal/index.vue
2026-06-24 11:26:19 +08:00

1003 lines
32 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
<a-modal
:open="visible"
:title="title + ' ' + '详情信息'"
width="80vw"
:footer="null"
:closable="true"
@cancel="handleClose"
:destroyOnClose="true"
class="map-modal"
>
<!-- 问题
1.基础信息图片展示是什么逻辑
2. 电站专题展示逻辑
3. 实时视频回放 少接口
4. 预警提示 少接口
5. 生态流量 达标率查询不对()
6. 鱼类适应性繁殖同期对比NAN ()
7. 出库水温 综合分析 导出没做
8. 栖息地-流量监测 没有水位视频和流量视频 字段没数据
9. 栖息地 水温水质流量没有数据没法测
10.鱼类增殖站 - 运行数据 要添加字典
11.珍惜植物园 - 种植要求字段不知道
12.水生调查断面 - 监测数据 不知道电导率 性腺发育期早期资源量和种类
13.水电告警情况 生态流量 不知道字段 接口传参有问题
14. 地图抽吸 碰撞检测 放大到具体层级锚点抽吸了但是popup弹框还在显示;
15.运行情况 计划开始运行时间 接口没接
-->
<div v-if="modelStore.showStcdSelector" class="stcd-selector-wrapper">
<a-select
v-model:value="modelStore.params.stcd"
placeholder="请选择测站"
style="width: 240px; margin-bottom: 12px"
:options="modelStore.stcdOptions"
show-search
:filter-option="filterOption"
@change="handleStcdChange"
>
</a-select>
</div>
<!-- 加载状态提示 -->
<div v-if="isLoading" class="loading-container">
<a-spin tip="加载中..." />
</div>
<!-- Tabs 区域 - 等待加载完成后显示 -->
<a-tabs v-else :active-key="currentActiveKey" @change="onTabChange">
<a-tab-pane v-for="tab in tabsConfig" :key="tab.key" :tab="tab.name">
</a-tab-pane>
<template #rightExtra v-if="anchor.sttp == 'ENG' || anchor.sttp == 'eng'">
<a-tooltip :title="!hasPowerStatData ? '该电站无专题配置' : ''">
<a-button
type="primary"
:disabled="!hasPowerStatData"
@click="gotoEngTopic"
>
<i class="icon iconfont icon-topic mr-[5px]"></i>
电站专题
</a-button></a-tooltip
>
</template>
</a-tabs>
<!-- 内容区域 - 使用动态组件 + keep-alive 实现按需加载和缓存 -->
<keep-alive>
<div v-if="!isLoading" class="content">
<div class="content-wrapper" v-show="isQxdMode(currentActiveKey)">
测站
<a-select
v-model:value="currentQxdSelectedStcd"
:options="qxdStationOptions"
style="width: 200px; margin-bottom: 12px"
placeholder="请选择站点"
@change="handleQxdStationChange"
/>
</div>
<!-- 基本信息 -->
<BasicInfo
v-show="currentActiveKey === 'basicInfo'"
:url="getTabUrl('basicInfo')"
:is-active="currentActiveKey === 'basicInfo'"
/>
<!-- 实时视频 -->
<VideoInfo
v-show="currentActiveKey === 'videoInfo'"
:is-active="currentActiveKey === 'videoInfo'"
/>
<!-- 录像视频 -->
<NoLiveVideo
v-show="currentActiveKey === 'noLiveVideo'"
:is-active="currentActiveKey === 'noLiveVideo'"
/>
<!-- 全景影像 -->
<PanoramaInfo
v-show="currentActiveKey === 'panoramaInfo'"
:url="getTabUrl('panoramaInfo')"
:is-active="currentActiveKey === 'panoramaInfo'"
/>
<!-- 监测数据 - 电站运行过程线 -->
<MonitorInfo
v-show="currentActiveKey === 'monitorInfo'"
:is-active="currentActiveKey === 'monitorInfo'"
/>
<!-- 监测数据 - 水温 -->
<WaterTemperature
v-show="currentActiveKey === 'WaterTemperature'"
:is-active="currentActiveKey === 'WaterTemperature'"
:code="getTabCode('WaterTemperature')"
:stcd="
getTabCode('WaterTemperature') == 'qxd.tabs.jcsj'
? qxdSelectedStcd
: ''
"
:wt-config="modelStore.wtConfig"
/>
<!-- 监测数据 - 垂向水温 -->
<VerticalWaterTemperature
v-show="currentActiveKey === 'VerticalWaterTemperature'"
:is-active="currentActiveKey === 'VerticalWaterTemperature'"
:stcd="modelStore.verticalWaterStcd || modelStore.params.stcd"
/>
<!-- 监测数据 - 水质 -->
<WaterQuality
v-show="currentActiveKey === 'WaterQuality'"
:is-active="currentActiveKey === 'WaterQuality'"
:code="getTabCode('WaterQuality')"
:stcd="
getTabCode('WaterQuality') == 'qxd.tabs.szjc'
? qxdSelectedStcdWq
: ''
"
:wq-show="modelStore.wqShow"
/>
<!-- 监测数据 - 水电站告警情况 -->
<DZGJ
v-show="currentActiveKey === 'DZGJ'"
:is-active="currentActiveKey === 'DZGJ'"
:tabs-items="getTabChildren('DZGJ')"
/>
<!-- 生态流量泄放设施 - 监测数据 -->
<FlowDischarge
v-show="currentActiveKey === 'flowDischarge'"
:is-active="currentActiveKey === 'flowDischarge'"
/>
<!-- 流量监测 -->
<FlowMeasure
v-show="currentActiveKey === 'FlowMeasure'"
:is-active="currentActiveKey === 'FlowMeasure'"
:url="getTabUrl('FlowMeasure')"
:code="getTabCode('FlowMeasure')"
:stcd="
getTabCode('FlowMeasure') == 'qxd.tabs.lcjs'
? qxdSelectedStcdZq
: ''
"
/>
<!-- 在线监测数据 -->
<FishFacilityMonitorData
v-show="currentActiveKey === 'FishFacilityMonitorData'"
:is-active="currentActiveKey === 'FishFacilityMonitorData'"
/>
<!-- 运行情况 -->
<FishFacilityRunState
v-show="currentActiveKey === 'FishFacilityRunState'"
:is-active="currentActiveKey === 'FishFacilityRunState'"
/>
<!-- 综合分析 -->
<FishZHFX
v-show="currentActiveKey === 'FishZHFX'"
:is-active="currentActiveKey === 'FishZHFX'"
/>
<!-- 建设情况 -->
<FishFacilityBuildState
v-show="currentActiveKey === 'FishFacilityBuildState'"
:is-active="currentActiveKey === 'FishFacilityBuildState'"
:url="getTabUrl('FishFacilityBuildState')"
/>
<!-- AI运行识别 -->
<AIYXSB
v-show="currentActiveKey === 'AIYXSB'"
:is-active="currentActiveKey === 'AIYXSB'"
/>
<!-- 预警提示 -->
<EarlyWarningAlert
v-show="currentActiveKey === 'tableTabs'"
:tabs-items="getTabChildren('tableTabs')"
:is-active="currentActiveKey === 'tableTabs'"
/>
<!-- 生态流量 -->
<EcologicalFlow
v-show="currentActiveKey === 'EcologicalFlow'"
:is-active="currentActiveKey === 'EcologicalFlow'"
/>
<!-- 鱼类繁殖适宜性分析 -->
<WaterTemperatureRep
v-show="currentActiveKey === 'WaterTemperatureRep'"
:is-active="currentActiveKey === 'WaterTemperatureRep'"
/>
<!-- 鱼类增殖站 - 运行数据 -->
<NormalOperationData
v-show="currentActiveKey === 'NormalOperationData'"
:is-active="currentActiveKey === 'NormalOperationData'"
/>
<!-- 过程图 -->
<ProcessDiagram
v-show="currentActiveKey === 'ProcessDiagram'"
:is-active="currentActiveKey === 'ProcessDiagram'"
/>
<!-- 增殖放流情况 -->
<NormalAddedSituation
v-show="currentActiveKey === 'NormalAddedSituation'"
:is-active="currentActiveKey === 'NormalAddedSituation'"
/>
<!-- 科研情况 -->
<NormalResearchSituation
v-show="currentActiveKey === 'NormalResearchSituation'"
:is-active="currentActiveKey === 'NormalResearchSituation'"
/>
<!-- 珍稀植物园 - 运行数据 -->
<NormalDataMonitoring2
v-show="currentActiveKey === 'NormalDataMonitoring2'"
:is-active="currentActiveKey === 'NormalDataMonitoring2'"
/>
<!-- 动物救助站 - 监测数据 -->
<Normal
v-show="currentActiveKey === 'Normal'"
:is-active="currentActiveKey === 'Normal'"
/>
<!-- 水生生态调查断面 - 监测数据 -->
<Ecology
v-show="currentActiveKey === 'Ecology'"
:is-active="currentActiveKey === 'Ecology'"
/>
<!-- 野生动物检测 -现场录像 -->
<liveFootage
v-show="currentActiveKey === 'liveFootage'"
:is-active="currentActiveKey === 'liveFootage'"
/>
<!-- 野生动物检测 -现场照片 -->
<onSitePhoto
v-show="currentActiveKey === 'onSitePhoto'"
:is-active="currentActiveKey === 'onSitePhoto'"
/>
<!-- 查看报告 -->
<Attachment
v-show="currentActiveKey === 'attachment'"
:is-active="currentActiveKey === 'attachment'"
tabKey="attachment"
:show-download="false"
:url="getTabUrl('attachment')"
/>
<!-- 批复文件 -->
<Attachment
v-show="currentActiveKey === 'approval'"
:is-active="currentActiveKey === 'approval'"
tabKey="approval"
:show-download="true"
:url="getTabUrl('approval')"
/>
</div>
</keep-alive>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, watch, reactive, computed } from 'vue';
// 导入预定义的 Tab 内容组件
import BasicInfo from './components/BasicInfo.vue'; // 基本信息
import VideoInfo from './components/videoInfo.vue'; // 实时视频
import NoLiveVideo from './components/NoLiveVideo.vue'; // 录像视频
import PanoramaInfo from './components/PanoramaInfo.vue'; // 全景影像
import MonitorInfo from './components/MonitorInfo.vue'; // 电站运行过程线
import WaterTemperature from './components/WaterTemperature.vue'; // 水温
import VerticalWaterTemperature from './components/VerticalWaterTemperature.vue'; // 垂向水温
import WaterQuality from './components/WaterQuality.vue'; // 水质
import AIYXSB from './components/AIYXSB/index.vue'; // AI运行识别
import EarlyWarningAlert from './components/EarlyWarningAlert.vue'; // 预警提示
import FlowMeasure from './components/FlowMeasure.vue'; // 流量监测
import FishFacilityMonitorData from './components/FishFacilityMonitorData.vue'; // 在线监测数据
import FishFacilityRunState from './components/FishFacilityRunState.vue'; // 运行情况
import FlowDischarge from './components/FlowDischarge.vue'; // 生态流量泄放设施 - 监测数据
import FishFacilityBuildState from './components/FishFacilityBuildState.vue'; // 建设情况
// 鱼类增殖站
import NormalOperationData from './components/NormalOperationData/index.vue'; // 运行数据
import ProcessDiagram from './components/ProcessDiagram.vue'; // 过程图
import NormalAddedSituation from './components/NormalAddedSituation.vue'; // 增值放流情况
import NormalResearchSituation from './components/NormalResearchSituation.vue'; // 科研情况
// 珍惜植物园
import NormalDataMonitoring2 from './components/NormalDataMonitoring2.vue'; // 运行数据
// 野生动物检测 -现场录像
import liveFootage from './components/liveFootage.vue'; // 现场录像
import onSitePhoto from './components/onSitePhoto.vue'; // 现场照片
/// 动物救助站
import Normal from './components/Normal.vue'; // 监测数据
// 水生生态调查断面
import Ecology from './components/Ecology.vue'; // 监测数据
// 水电站告警情况
import DZGJ from './components/DZGJ.vue'; // 水电站告警情况
import FishZHFX from './components/FishZHFX.vue'; // 鱼类繁殖适宜性分析
import EcologicalFlow from './components/EcologicalFlow.vue'; // 生态流量
import Attachment from './components/Attachment.vue'; // 查看报告/批复文件
import WaterTemperatureRep from './components/WaterTemperatureRep.vue'; // 水温对比数据
import { useModelStore } from '@/store/modules/model';
import { handleTabs } from './setting.config';
import {
getMonitorDataWt,
getMonitorDataWq,
getMonitorDataZq,
getBuildState,
getFishTab,
checkAnalysisShow,
getStInfoByStcd,
getVideoList,
getMonitorDataWaterTempPowerStation,
getMonitorDataWaterTempPowerStation2,
checkPowerStationTopic
} from '@/api/mapModal';
// import { useRouter } from 'vue-router';
const modelStore = useModelStore();
const tabsConfig = ref([]);
// 加载状态:等待所有验证完成后再显示 tabs
const isLoading = ref(true);
// ==================== 电站专题相关 ====================
// 电站专题配置数据状态
const hasPowerStatData = ref(false);
// 电站专题 URL 参数(仅 hbb
const hbbSearchParams = '?menu=dianZhanZhuanTi&page=dianZhanZhuanTi';
// 判断当前是否在电站专题页面
const isPowerStatPage = computed(() => {
return window.location.search === hbbSearchParams;
});
// 判断是否为局级页面(根据当前路由判断)
const isJiangJu = computed(() => {
// TODO: 根据实际路由判断逻辑修改
return false;
});
// const router = useRouter();
/**
* 查询电站是否有专题配置数据
*/
const checkPowerStationTopicData = async (stcd: string) => {
try {
const res = await checkPowerStationTopic({
filter: {
logic: 'and',
filters: [
{
field: 'stcd',
operator: 'eq',
dataType: 'string',
value: stcd
},
{
field: 'bclData',
operator: 'contains',
dataType: 'string',
value: 'image/png'
}
]
}
});
hasPowerStatData.value = res?.data?.data && res?.data?.data?.length > 0;
} catch (error) {
console.error('查询电站专题配置失败:', error);
hasPowerStatData.value = false;
}
};
/**
* 跳转到电站专题页面
*/
const gotoEngTopic = () => {
// TODO: 等待电站专题页面创建后,取消注释以下代码
/*
const url = `/qgc-biz-home/${hbbSearchParams}`;
const menu = {
id: 'dianZhanZhuanTi',
url,
name: '电站专题'
};
// 缓存当前电站 stcd跳转后页面会读取
localStorage.setItem('modalSelectedEngTopic', JSON.stringify({ stcd: modelStore.params.stcd }));
// 关闭弹窗
handleClose();
// 使用 Vue Router 跳转
// router.push(url);
*/
console.log('电站专题跳转(暂未实现):', modelStore.params.stcd);
};
// 环境判断变量(与 React 版本对齐)
const app = 'hbb'; // 模拟 React 中的 Session.getAppCode()
const env = 'hbb'; // 模拟 React 中的 window.__env__
const isLCJ = env?.startsWith('lcj');
const sttpList = ['ENG', 'WT', 'WQ', 'FP', 'FB', 'VP', 'DW', 'EQ', 'VA'];
// ==================== 异步 Tab 过滤逻辑 ====================
// 功能8: 鱼类栖息地数据类型检查 (React: isLCJ && sttpCode === 'WE')
const checkFishTab = async (stcd: string) => {
try {
const res = await getFishTab(stcd);
const data = res?.data || res;
if (data && data.length > 0) {
modelStore.fishTabInfo = data[0];
// 根据 hasWt/hasWq/hasFv 过滤 FlowMeasure 的子 Tab
const flowTab = tabsConfig.value.find(
(item: any) => item.key === 'FlowMeasure'
);
if (flowTab && flowTab.tabs) {
flowTab.tabs = flowTab.tabs.filter((tab: any) => {
if (tab.name === '水温(℃)' && !data[0].hasWt) return false;
if (tab.name === '水质' && !data[0].hasWq) return false;
if (tab.name === '流速(m/s)' && !data[0].hasFv) return false;
return true;
});
}
}
} catch (error) {
console.error('鱼类数据检查失败:', error);
}
};
// 功能9: 水质 AI 预测功能检查 (React: (app === "hbb" || baseId === "07" || "02") && sttpCode === 'WQ'/'WQFB'/'wq')
const checkAnalysisAvailability = async (stcd: string) => {
try {
const filter = {
filter: {
logic: 'and',
filters: [
{ field: 'stcd', operator: 'eq', value: stcd },
{ field: 'mway', operator: 'eq', value: '2' },
{ field: 'dtinType', operator: 'eq', value: '0' },
{
logic: 'or',
filters: [
{ field: 'engLctn3Code', operator: 'isnotnull' },
{ field: 'engLctn1Code', operator: 'isnotnull' }
]
}
]
}
};
const res = await checkAnalysisShow(filter);
modelStore.wqShow = !!res?.data;
} catch (error) {
console.error('水质 AI 预测检查失败:', error);
modelStore.wqShow = false;
}
};
// 功能10: 水温站特殊处理 (React: (app === "hbb" || baseId === "07" || "02") && sttpCode === 'WT'/'wt')
const checkWaterTempConfig = async (stcd: string) => {
try {
const [configRes, dwRes, buildRes] = await Promise.all([
getMonitorDataWaterTempPowerStation({ stcd }),
getMonitorDataWaterTempPowerStation2({ stcd }),
getBuildState({
filter: {
logic: 'and',
filters: [{ field: 'stcd', operator: 'eq', value: stcd }]
}
})
]);
modelStore.wtConfig = {
ioWtrv: configRes?.data?.ioWtrv,
hasRstcdWtvt: dwRes?.data
};
// 检查出入库水温对比
const buildData = buildRes?.data?.[0];
if (!buildData?.engIwtCode && !buildData?.engDwtCode) {
tabsConfig.value = tabsConfig.value.filter(
(item: any) => item.name !== '出入库水温对比'
);
}
} catch (error) {
console.error('水温配置检查失败:', error);
}
};
// 功能11: 电站建设状态过滤 (React: sttp == "ENG" && eqtp != "QEC")
const checkBuildState = async (stcd: string) => {
try {
const res = await getBuildState({
filter: {
logic: 'and',
filters: [{ field: 'stcd', operator: 'eq', value: stcd }]
}
});
const buid = res?.data?.[0]?.bldsttCcode;
// 0 未建 1 在建 2 已建
const zj = ['基础信息', '实时视频', '全景影像', '查看报告'];
const wj = ['基础信息', '查看报告'];
if (res?.data?.length > 0) {
const zJTabData = tabsConfig.value?.filter((item: any) =>
zj.includes(item.name)
);
const wJTabData = tabsConfig.value?.filter((item: any) =>
wj.includes(item.name)
);
tabsConfig.value =
buid == 1 ? zJTabData : buid == 0 ? wJTabData : tabsConfig.value;
}
} catch (error) {
console.error('建设状态检查失败:', error);
}
};
// QGC 完整 Tab 过滤逻辑(与 React setQGCTabList 对齐)
const setQGCTabList = async (_tabs: any, stcd: string) => {
let tabs = [..._tabs];
try {
// 1. 电站建设状态过滤
if (modelStore.params.sttp == 'ENG' && modelStore.params.eqtp != 'QEC') {
const res = await getBuildState({
filter: {
logic: 'and',
filters: [{ field: 'stcd', operator: 'eq', value: stcd }]
}
});
const buid = res?.data?.[0]?.bldsttCcode;
const zj = ['基础信息', '实时视频', '全景影像', '查看报告'];
const wj = ['基础信息', '查看报告'];
if (res?.data?.length > 0) {
const zJTabData = tabs?.filter((item: any) => zj.includes(item.name));
const wJTabData = tabs?.filter((item: any) => wj.includes(item.name));
tabs = buid == 1 ? zJTabData : buid == 0 ? wJTabData : tabs;
}
}
// 2. 垂向水温 & AI 识别检查(对所有类型执行,与 React 一致)
const res4 = await getStInfoByStcd({ stcd });
let newTabs = [...tabs];
// debugger
if (res4 && res4.data && res4.data.relList) {
const relList = res4.data.relList;
const jianCei = relList.find((item: any) => item.sttpCode === 'WTVT');
const aiShiBie = relList.filter((item: any) =>
item?.sttpCode?.startsWith('AI')
);
if (!jianCei) {
newTabs = newTabs.filter(
item => item.type !== 'VerticalWaterTemperature'
);
} else {
modelStore.verticalWaterStcd = jianCei.stcd;
}
if (!aiShiBie.length) {
newTabs = newTabs.filter(item => item.type !== 'AIYXSB');
} else {
modelStore.aiSites = aiShiBie;
}
}
// 3. 视频存在性检查
let params = {
filter: {
logic: 'and',
filters: [
{
field: 'sttpCode',
operator: 'startswith',
value: 'VD_'
},
{
logic: 'or',
filters: [
{
field: 'rstcd',
operator: 'eq',
dataType: 'string',
value: stcd
},
{
field: 'stcd',
operator: 'eq',
dataType: 'string',
value: stcd
},
{
field: 'fhstcd',
operator: 'eq',
dataType: 'string',
value: stcd
},
{
field: 'stCode',
operator: 'eq',
dataType: 'string',
value: stcd
}
]
}
]
},
select: ['stcd', 'stnm', 'sttpCode', 'sttpName', 'playWay', 'url'],
sort: [
{
field: 'stnm',
dir: 'asc'
}
]
};
const res2 = await getVideoList(params);
console.log('', modelStore.params.sttp);
//
if (
res2?.data?.data?.length > 0 ||
res2?.data?.records?.length > 0 ||
modelStore.params.sttp == 'WQ'
) {
tabsConfig.value = newTabs;
} else {
tabsConfig.value = newTabs.filter((item: any) => item.type != 'video');
}
} catch (error) {
console.error('QGC Tab 过滤失败:', error);
}
};
// 综合过滤函数(与 React useEffect 逻辑对齐)
const applyTabFilters = async (params: any) => {
isLoading.value = true; // 开始加载
try {
const sttpCode = params?.sttp;
const stcd = params?.stcd;
const eqtp = params?.eqtp;
const baseId = modelStore.baseId;
if (!stcd) return;
// 按照 React 的分支逻辑执行(注意运算符优先级)
if (isLCJ && sttpCode === 'VP') {
// LCJ 珍稀植物园视频检查
const res = await getVideoList({
filter: {
logic: 'and',
filters: [{ field: 'stcd', operator: 'eq', value: stcd }]
}
});
if (!res?.data?.data?.length && !res?.data?.records?.length) {
tabsConfig.value = tabsConfig.value.filter(
item => item.name != '实时视频'
);
}
} else if (isLCJ && sttpCode === 'WE') {
// LCJ 鱼类栖息地数据类型检查
await checkFishTab(stcd);
} else if (
( sttpCode === 'WQ') ||
sttpCode === 'WQFB' ||
sttpCode === 'wq'
) {
// 水质 AI 预测检查React 逻辑WQ 需要条件WQFB/wq 无条件)
await checkAnalysisAvailability(stcd);
} else if (
( sttpCode === 'WT') ||
sttpCode === 'wt'
) {
// 水温站特殊处理React 逻辑WT 需要条件wt 无条件)
await checkWaterTempConfig(stcd);
} else if (
sttpList.includes(sttpCode?.toUpperCase()) ||
sttpCode?.startsWith('FP_') ||
sttpCode?.includes('DW')
) {
// QGC 完整 Tab 过滤包含建设状态、垂向水温、AI识别、视频检查
await setQGCTabList(tabsConfig.value, stcd);
}
} catch (error) {
console.error('Tab 过滤逻辑执行失败:', error);
} finally {
isLoading.value = false; // 无论成功失败都停止加载
}
};
// ==================== qxd 栖息地模式相关 ====================
// qxd模式配置映射
const qxdConfigMap: Record<
string,
{
sttpCode: string;
apiFn: (data: any) => Promise<any>;
selectProp: string;
}
> = {
'qxd.tabs.jcsj': {
// 水温
sttpCode: 'WTRV',
apiFn: getMonitorDataWt,
selectProp: 'qxdSelectedStcd'
},
'qxd.tabs.szjc': {
// 水质
sttpCode: 'WQ',
apiFn: getMonitorDataWq,
selectProp: 'qxdSelectedStcdWq'
},
'qxd.tabs.lcjs': {
// 流量监测
sttpCode: 'ZQ',
apiFn: getMonitorDataZq,
selectProp: 'qxdSelectedStcdZq'
}
};
// 各模式的站点选项和选中值
const qxdStationOptions = ref<{ label: string; value: string }[]>([]);
const qxdSelectedStcd = ref<string>('');
const qxdSelectedStcdWq = ref<string>('');
const qxdSelectedStcdZq = ref<string>('');
const qxdLoadedCodes = ref<Set<string>>(new Set());
// 获取当前tab对应的qxd配置
const getCurrentQxdConfig = (tabKey: string) => {
const code = getTabCode(tabKey);
return code && qxdConfigMap[code] ? qxdConfigMap[code] : null;
};
// 获取选中的stcd
const getQxdSelectedStcd = (tabKey: string) => {
const config = getCurrentQxdConfig(tabKey);
if (!config) return '';
switch (config.selectProp) {
case 'qxdSelectedStcd':
return qxdSelectedStcd.value;
case 'qxdSelectedStcdWq':
return qxdSelectedStcdWq.value;
case 'qxdSelectedStcdZq':
return qxdSelectedStcdZq.value;
default:
return '';
}
};
// 设置选中的stcd
const setQxdSelectedStcd = (tabKey: string, value: string) => {
const config = getCurrentQxdConfig(tabKey);
if (!config) return;
switch (config.selectProp) {
case 'qxdSelectedStcd':
qxdSelectedStcd.value = value;
break;
case 'qxdSelectedStcdWq':
qxdSelectedStcdWq.value = value;
break;
case 'qxdSelectedStcdZq':
qxdSelectedStcdZq.value = value;
break;
}
};
// 加载栖息地站点列表
const loadQxdStationList = async (tabKey: string) => {
const code = getTabCode(tabKey);
if (!code || !qxdConfigMap[code]) return;
if (qxdLoadedCodes.value.has(code)) return;
const config = qxdConfigMap[code];
try {
const params = {
filter: {
logic: 'and',
filters: [
{
field: 'fhstcd',
operator: 'eq',
dataType: 'string',
value: modelStore.params.stcd
},
{
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: config.sttpCode
}
]
},
select: ['stcd', 'stnm']
};
const res = await config.apiFn(params);
const stations = res?.data?.data || res?.data?.records || [];
if (stations.length > 0) {
qxdStationOptions.value = stations.map((item: any) => ({
label: item.stnm,
value: item.stcd
}));
setQxdSelectedStcd(tabKey, stations[0].stcd);
}
qxdLoadedCodes.value.add(code);
} catch (error) {
console.error(`获取站点列表失败(${code}):`, error);
}
};
// 获取当前激活tab对应的选中stcd (支持v-model双向绑定)
const currentQxdSelectedStcd = computed({
get: () => getQxdSelectedStcd(currentActiveKey.value),
set: (val: string) => setQxdSelectedStcd(currentActiveKey.value, val)
});
// 判断是否是qxd模式
const isQxdMode = (tabKey: string) => {
const code = getTabCode(tabKey);
return code && qxdConfigMap[code] ? true : false;
};
// 处理栖息地站点切换
const handleQxdStationChange = () => {
// 站点切换后,子组件会通过 watch stcd 自动刷新
};
// import MapView from './components/MapView.vue';
// import SurroundingInfo from './components/SurroundingInfo.vue';
// 定义 Tab 配置项接口
interface TabItem {
key: string;
title: string;
url: string;
}
// 获取 Tab 配置项的 URL
const getTabUrl = (key: string) => {
const tab = tabsConfig.value.find((item: any) => item.key === key);
return tab?.url || '';
};
// 获取 Tab 配置项的子 Tab
const getTabChildren = (key: string) => {
console.log(tabsConfig.value);
const tab = tabsConfig.value.find((item: any) => item.key === key);
return tab?.tabs || [];
};
// 获取 Tab 配置项的 code
const getTabCode = (key: string) => {
const tab = tabsConfig.value.find((item: any) => item.key === key);
return tab?.code || '';
};
// 定义 Props
const props = defineProps<{
visible: boolean;
title?: string;
activeKey?: string; // 外部控制的当前激活 tab
data?: any; // 可选:传递给内部组件的数据
}>();
// 定义 Emits
// 添加 'update:activeKey' 以支持 v-model:active-key
const emit = defineEmits<{
(e: 'update:visible', value: boolean): void;
(e: 'change', key: string): void;
}>();
// 内部维护的 activeKey
const currentActiveKey = ref<string>('');
const anchor = ref<any>('');
// 监听外部传入的 activeKey 变化,同步到内部状态
watch(
() => props.activeKey,
newVal => {
if (newVal && newVal !== currentActiveKey.value) {
currentActiveKey.value = newVal;
}
},
{ immediate: true }
);
watch(
() => modelStore.params,
async newVal => {
if (!newVal || Object.keys(newVal).length === 0) return;
console.log(newVal);
anchor.value = newVal;
let params = newVal;
if (['VD', 'WTRV', 'ZQ', 'WQ'].includes(params?.sttpCode)) {
params.sttp = params.sttpCode;
} else if (['ENG_ALARM'].includes(params?.sttpMap)) {
params.sttp = params.sttpMap;
}
tabsConfig.value = handleTabs({ ...params });
let value = tabsConfig.value.find((item: any) => item.default);
currentActiveKey.value = value?.key;
// 电站类型时,查询电站专题配置数据
if (params?.sttp?.toUpperCase() === 'ENG') {
checkPowerStationTopicData(params.stcd);
}
// 应用异步 Tab 过滤(非阻塞式)
applyTabFilters(params);
},
{ deep: true, immediate: true }
);
// 监听 tab 切换,如果是 qxd 模式,加载站点列表
watch(
() => currentActiveKey.value,
activeKey => {
const code = getTabCode(activeKey);
if (code && qxdConfigMap[code]) {
loadQxdStationList(activeKey);
}
},
{ immediate: true }
);
// 监听内部 tab 切换
const onTabChange = (key: string) => {
currentActiveKey.value = key;
// 通知父组件更新 activeKey (支持 v-model)
// 通知父组件发生了切换事件 (用于业务逻辑,如加载数据)
emit('change', key);
};
// 关闭弹窗
const handleClose = () => {
emit('update:visible', false);
modelStore.params = {
sttp: 'eng',
stcd: '',
date: '',
show: true,
enfc: '0',
eqtp: '',
baseId: '',
sttpCode: '',
sttpMap: ''
};
// 清理状态,避免影响下次打开
modelStore.showStcdSelector = false;
modelStore.stcdOptions = [];
// 清理qxd模式状态
qxdStationOptions.value = [];
qxdSelectedStcd.value = '';
qxdSelectedStcdWq.value = '';
qxdSelectedStcdZq.value = '';
qxdLoadedCodes.value = new Set();
// 清理电站专题状态
hasPowerStatData.value = false;
modelStore.verticalWaterStcd = '';
modelStore.aiSites = [];
modelStore.wtConfig = {};
modelStore.filter = {
stllgzlx: '', // 生态流量 - 规则类型
stllTmType: '', // 生态流量 - 时间类型
tm: '',
rangeTm: []
};
modelStore.wqShow = false;
modelStore.fishTabInfo = null;
};
// 为了方便模板中使用,将 props.data 暴露给模板
const modalData = ref(props.data);
watch(
() => props.data,
newVal => {
modalData.value = newVal;
}
);
// 搜索过滤函数
const filterOption = (input: string, option: any) => {
return option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
// 处理测站切换
const handleStcdChange = (newStcd: string) => {
console.log('【测站切换】', newStcd);
// 由于 BasicInfo.vue 监听了 stcd 变化,这里只需更新 store
// 如果需要刷新所有 tab 的数据,可以在这里触发事件
};
</script>
<style lang="scss" scoped>
.map-modal {
.content {
min-height: 600px;
}
.loading-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 400px;
}
}
</style>