import { defineStore, storeToRefs } from 'pinia'; import { ref } from 'vue'; import dayjs from 'dayjs'; import { MapClass } from '@/components/gis/map.class'; import { getMapConfig } from '@/components/gis/gisUtils'; import { applyLayerMutualExclusionRules } from '@/modules/map/domain/map-layer-rules'; import { applyEnvFacilityLegendRule, buildLegendCheckedState, buildLegendTree } from '@/modules/map/domain/legend-deriver'; import { attachNearbyPointRuntimeMeta } from '@/modules/map/domain/nearby-point-rules'; import { useMapConfigStore } from '@/modules/map/stores/map-config.store'; import { useMapDataStore } from '@/modules/map/stores/map-data.store'; import { useMapViewStore } from '@/modules/map/stores/map-view.store'; import request from '@/utils/request'; import { urlList } from '@/utils/GisUrlList'; const mapClass = MapClass.getInstance(); const DEFAULT_LAYER_REQUEST_CONCURRENCY = 4; const ENG_POINT_LAYER_KEY = 'eng_point'; const ENG_POINT_MEDIUM_VISIBLE_ZOOM = 7.5; const ENG_POINT_LARGE_STATES = [ 'large_eng_built', 'large_eng_ubuilt', 'large_eng_nbuilt' ]; const ENG_POINT_MEDIUM_STATES = [ 'mid_eng_built', 'mid_eng_ubuilt', 'mid_eng_nbuilt' ]; const normalizeCachePayload = (value: any): any => { if (Array.isArray(value)) { return value.map(item => normalizeCachePayload(item)); } if (value && typeof value === 'object') { return Object.keys(value) .sort() .reduce>((acc, key) => { acc[key] = normalizeCachePayload(value[key]); return acc; }, {}); } return value; }; const buildUrlListIndex = (items: any[] = []) => { const index: Record = {}; items.forEach(item => { [item.url, item.title, item.keyType].forEach(key => { if (!key) return; if (!index[key]) { index[key] = []; } index[key].push(item); }); }); return index; }; const urlListIndex = buildUrlListIndex(urlList); const isCanceledRequestError = (error: unknown) => { const message = error instanceof Error ? error.message : String(error || ''); return ( message.includes('canceled') || message.includes('aborted') || message.includes('AbortError') ); }; export const useMapStore = defineStore('map', () => { const mapConfigStore = useMapConfigStore(); const mapDataStore = useMapDataStore(); const mapViewStore = useMapViewStore(); const { getLayerConfigByKey, getLegendConfigByLayerCode, getLegendConfigByNameEn } = mapConfigStore; const { getPointLayerData, hasPointLayerData, hasValidPointLayerCache } = mapDataStore; const { layerConfigTree: layerData, legendConfigOriginal: legendDataOriginal, pageLegendConfig } = storeToRefs(mapConfigStore); const { checkedLayerKeys, legendCheckedState, searchTimeRange } = storeToRefs(mapViewStore); const { pointData, pointDataCache, layerLoadState, loading } = storeToRefs(mapDataStore); // 图例数据(经过筛选和排序的) const legendData = ref([]); // 选中的图例数据 const legendDataSelected = ref([]); const inFlightRequestMap = new Map< string, { promise: Promise; controller: AbortController; layerKey: string; sessionId: number; } >(); const activeLayerRequestKeyMap = new Map(); let loadSessionSeed = 0; const normalizeLegendNameEn = mapConfigStore.normalizeLegendNameEn; const filterPointLayerDataForDisplay = ( layerKey: string, sourceData: any[] = [], currentZoom: number = mapViewStore.currentZoomLevel ): any[] => { if (layerKey !== ENG_POINT_LAYER_KEY || !Array.isArray(sourceData)) { return sourceData; } const allowMedium = currentZoom > ENG_POINT_MEDIUM_VISIBLE_ZOOM; return sourceData.filter((item: any) => { const state = String(item?.anchoPointState || ''); if (ENG_POINT_LARGE_STATES.includes(state)) { return true; } if (ENG_POINT_MEDIUM_STATES.includes(state)) { return allowMedium; } return true; }); }; const refreshPointLayerDisplayData = (layerKey: string) => { if (!layerKey) return; const layerItem = findLayerByKey(layerData.value, layerKey); const rawData = layerItem?.data || getPointLayerData(layerKey); const displayData = filterPointLayerDataForDisplay(layerKey, rawData); const shouldRestoreVisible = layerItem?.checked === 1 || checkedLayerKeys.value.includes(layerKey); mapClass.addInitDataLayer(displayData, layerKey); if (!shouldRestoreVisible) { mapClass.mdLayerTreeShowOrHidden(layerKey, false); return; } restoreLayerLegendVisibility(layerKey); mapClass.mdLayerTreeShowOrHidden(layerKey, true); }; const getLegendItemsByLayerCode = (layerCode: string): any[] => { return getLegendConfigByLayerCode(layerCode); }; const getLegendChecked = (nameEn?: string): number => { const normalizedNameEn = normalizeLegendNameEn(nameEn); if (!normalizedNameEn) return 0; return mapViewStore.getLegendChecked(normalizedNameEn); }; const restoreLayerLegendVisibility = (layerKey: string): boolean => { const layerLegendItems = getLegendItemsByLayerCode(layerKey); if ( legendDataOriginal.value.length === 0 || layerLegendItems.length === 0 ) { return false; } mapClass.setLegendPointVisible(layerKey, '', false); layerLegendItems.forEach((legendItem: any) => { if (getLegendChecked(legendItem.nameEn) === 1) { applyLegendItemVisibility(legendItem, 1); } }); return true; }; const buildRuntimeLegendTree = ( items: any[] = [], selectedLayerCodes?: Set ): any[] => { return buildLegendTree({ items, selectedLayerCodes, getLegendChecked, normalizeLegendNameEn }); }; const deriveSelectedLegendData = (layerKeys: string[]): any[] => { const selectedLayerCodes = new Set( layerKeys.filter( key => key && key !== '-' && key !== 'customBaseLayer' && key !== 'powerBaseStation' ) ); let derivedLegend = buildRuntimeLegendTree( legendDataOriginal.value, selectedLayerCodes ); derivedLegend = applyEnvFacilityLegendRule( derivedLegend, Array.from(selectedLayerCodes), legendDataOriginal.value, items => buildRuntimeLegendTree(items) ); return sortByOrderIndex(derivedLegend); }; const rebuildLegendRuntimeData = ( layerKeys: string[] = checkedLayerKeys.value ) => { legendData.value = sortByOrderIndex( buildRuntimeLegendTree(legendDataOriginal.value) ); legendDataSelected.value = deriveSelectedLegendData(layerKeys); }; const getLayerBranchKeys = (rootKey: string): string[] => { const rootLayer = getLayerConfigByKey(rootKey); if (!rootLayer) return []; const branchKeys: string[] = []; const walk = (node: any) => { if (node?.key) { branchKeys.push(node.key); } if (node?.children?.length > 0) { node.children.forEach((child: any) => walk(child)); } }; walk(rootLayer); return branchKeys; }; const normalizeCheckedLayerKeys = ( rawKeys: string[] = [], triggerKey?: string, isChecked?: boolean ): string[] => { return applyLayerMutualExclusionRules({ rawKeys, previousKeys: checkedLayerKeys.value, triggerKey, checked: isChecked, getLayerBranchKeys }); }; const getRuntimeCheckedLayerKeys = (): string[] => { return normalizeCheckedLayerKeys(mapViewStore.getCheckedLayerKeys()); }; const syncPointDataForFilter = () => { mapDataStore.rebuildPointDataFromCache(); }; const ensureGISLayerConfig = (layerItem: any) => { if (!layerItem) return null; if (!layerItem.config && layerItem.paramJson) { try { const jsonObj = JSON.parse(layerItem.paramJson); layerItem.config = getMapConfig(jsonObj); } catch { layerItem.config = null; } } if (!layerItem.config) { return null; } if (layerItem.config.key !== layerItem.key) { layerItem.config = { ...layerItem.config, key: layerItem.key }; } return layerItem.config; }; /** * 设置图层数据 */ const setLayerData = (data: any[]) => { mapConfigStore.setLayerConfigTree(data); const nextCheckedLayerKeys = mapConfigStore.extractCheckedLayerKeys(data); mapViewStore.setCheckedLayerKeys(nextCheckedLayerKeys); rebuildLegendRuntimeData(nextCheckedLayerKeys); }; /** * 按照 orderIndex 排序图例数据(递归) */ const sortByOrderIndex = (items: any[]): any[] => { return items .map(item => { if (item.childrenList && item.childrenList.length > 0) { return { ...item, childrenList: sortByOrderIndex(item.childrenList) }; } return item; }) .sort((a, b) => (a.orderIndex || 0) - (b.orderIndex || 0)); }; /** * 启动新的图层加载会话,并取消上一轮仍在进行中的旧请求,避免菜单切换后旧数据回写。 */ const startLoadSession = () => { loadSessionSeed += 1; const currentSessionId = loadSessionSeed; inFlightRequestMap.forEach(entry => { if (entry.sessionId !== currentSessionId) { entry.controller.abort(); mapDataStore.clearLayerLoadState(entry.layerKey); } }); return currentSessionId; }; /** * 判断当前请求是否仍属于最新加载会话,避免旧请求结果回写到最新页面。 */ const isCurrentLoadSession = (sessionId: number) => { return loadSessionSeed === sessionId; }; /** * 按固定并发数执行图层加载任务,避免瞬时请求过多,同时让单个失败不影响其他任务。 */ const runLayerLoadQueue = async ( tasks: Array<() => Promise>, concurrency: number = DEFAULT_LAYER_REQUEST_CONCURRENCY ) => { const results: PromiseSettledResult[] = []; const safeConcurrency = Math.max(1, concurrency); for (let i = 0; i < tasks.length; i += safeConcurrency) { const batch = tasks.slice(i, i + safeConcurrency).map(task => task()); const batchResults = await Promise.allSettled(batch); results.push(...batchResults); } return results; }; /** * 设置图例数据(过滤掉 name == '地图' 的项,ifShow == 0 时不显示) * @param data - 全部图例数据 * @param selectedData - 当前页面选中的图例数据(用于标记选中状态) */ const setLegendData = (data: any[], selectedData: any[] = []) => { mapConfigStore.setLegendConfigOriginal(data); mapConfigStore.setPageLegendConfig(selectedData); mapViewStore.setLegendCheckedState( buildLegendCheckedState(legendDataOriginal.value, normalizeLegendNameEn) ); rebuildLegendRuntimeData(checkedLayerKeys.value); }; /** * 设置选中的图例数据(在图层加载完成后调用) */ const setSelectedLegendData = () => { rebuildLegendRuntimeData(checkedLayerKeys.value); }; /** * 设置描点数据 */ const setPointData = (data: any[]) => { mapDataStore.setPointData(data); }; /** * 图例数据转对象 */ const legendData2Obj = (data: any[]): Record => { const _tempData: Record = {}; const f = (_data: any[]) => { _data.forEach(item => { if (item?.childrenList && item.childrenList?.length > 0) { f(item.childrenList); } else { const normalizedNameEn = normalizeLegendNameEn(item.nameEn); if (normalizedNameEn) { _tempData[normalizedNameEn] = item; } } }); }; f(data); return _tempData; }; /** * 处理单个 pointMap 图层的显示/隐藏 * 数据已在初始化时通过 loadLayerData 加载并存入 layer.data */ const handlePointMapLayer = async (layer: any, isChecked: boolean) => { const { key } = layer; // 如果没有勾选,隐藏图层 if (!isChecked) { if (mapClass.hasLayer(key)) { mapClass.mdLayerTreeShowOrHidden(key, false); } if (mapDataStore.getPointLayerCache(key)) { mapDataStore.setPointLayerCacheChecked(key, false); } if (layer) { layer.checked = 0; } return; } // 使用初始化时已加载的数据(存入 layer.data) const cachedData = layer?.data || getPointLayerData(key); if (cachedData && cachedData.length > 0) { layer.checked = 1; const displayData = filterPointLayerDataForDisplay(key, cachedData); if (!mapClass.hasLayer(key)) { mapClass.addInitDataLayer(displayData, key); } else { mapClass.addInitDataLayer(displayData, key); } restoreLayerLegendVisibility(key); if (mapDataStore.getPointLayerCache(key)) { mapDataStore.setPointLayerCacheChecked(key, true); } } else { console.warn(`图层 ${key} 没有缓存数据`); } }; /** * 更新图层数据(联动图例和描点) * @param checkKeys - 选中的图层 key 列表 * @param isInit - 是否是初始化阶段(初始化时遍历所有图层) */ const updateLayerData = async (checkKeys: string[], isInit = false) => { checkKeys = normalizeCheckedLayerKeys(checkKeys); mapViewStore.setCheckedLayerKeys(checkKeys); // 收集变化的图层 key(新增选中 / 取消选中) const newlyChecked: string[] = []; const newlyUnchecked: string[] = []; // 更新图层的 checked 状态,并记录变化 const updateCheckedStatus = (items: any[]) => { items.forEach(item => { if (item.key) { const wasChecked = item.checked === 1; const isChecked = checkKeys.includes(item.key); item.checked = isChecked ? 1 : 0; if (wasChecked !== isChecked) { if (isChecked) { newlyChecked.push(item.key); } else { newlyUnchecked.push(item.key); } } } if (item.children && item.children.length > 0) { updateCheckedStatus(item.children); } }); }; updateCheckedStatus(layerData.value); rebuildLegendRuntimeData(checkKeys); // 控制锚点显示隐藏:初始化时处理全部,否则只处理变化的图层 const keysToProcess = isInit ? getAllLayerKeys(layerData.value) : [...newlyChecked, ...newlyUnchecked]; for (const key of keysToProcess) { const layerItem = findLayerByKey(layerData.value, key); if (layerItem && layerItem.type === 'pointMap' && layerItem.url) { const shouldBeVisible = checkKeys.includes(key); await handlePointMapLayer(layerItem, shouldBeVisible); if (shouldBeVisible) { restoreLayerLegendVisibility(key); mapClass.mdLayerTreeShowOrHidden(key, true); } } else if (layerItem && layerItem.type === 'GISMap') { // 处理 GISMap 类型的图层:勾选时若地图实例中不存在,则先重新加载再控制显隐。 if (key && key !== '-' && key !== 'powerBaseStation') { const shouldBeVisible = checkKeys.includes(key); const layerConfig = ensureGISLayerConfig(layerItem); if ( shouldBeVisible && layerConfig && !mapClass.hasBaseLayer(layerItem.key) ) { mapClass.addBaseDataLayer(layerConfig, true); } mapClass.controlBaseLayerTreeShowAndHidden( key, layerItem.key, shouldBeVisible ); } } } }; /** * 加载所有包含URL的图层数据 * @param items 图层数据 * @param checkedKeys 选中的图层 keys(用于优先加载) */ const loadAllLayerData = async (items: any[], checkedKeys: string[] = []) => { mapDataStore.setLoading(true); const currentSessionId = startLoadSession(); const checkedTasks: Array<() => Promise> = []; const uncheckedTasks: Array<() => Promise> = []; const processedKeys = new Set(); const processItems = (itemList: any[]) => { itemList.forEach(item => { if ( (item.type === 'pointMap' || item.url) && item.key && item.url && !processedKeys.has(item.key) ) { processedKeys.add(item.key); const task = () => loadLayerData(item, currentSessionId); if (checkedKeys.includes(item.key)) { checkedTasks.push(task); } else { uncheckedTasks.push(task); } } if (item.children && item.children.length > 0) { processItems(item.children); } }); }; processItems(items); try { const checkedResults = await runLayerLoadQueue(checkedTasks); const uncheckedResults = await runLayerLoadQueue(uncheckedTasks); const failedResults = [...checkedResults, ...uncheckedResults].filter( result => result.status === 'rejected' ); if (failedResults.length > 0) { console.warn( '部分图层数据加载失败,但不会阻断其他图层:', failedResults ); } if (!isCurrentLoadSession(currentSessionId)) { return; } // 确保所有图层的数据都已经缓存到 pointDataCache 和 layer.data const allLayerKeys = getAllLayerKeys(items); for (const key of allLayerKeys) { const layer = findLayerByKey(items, key); if (layer && hasPointLayerData(key)) { layer.data = getPointLayerData(key); } } const allPointData = mapDataStore.rebuildPointDataFromCache(allLayerKeys); attachNearbyPointRuntimeMeta(allPointData); const runtimeCheckedKeys = getRuntimeCheckedLayerKeys(); // 备注:近邻点元数据需要基于全量点位统一识别,识别完成后同步刷新各图层 Feature。 for (const key of allLayerKeys) { const layer = findLayerByKey(items, key); if (!layer || !hasPointLayerData(key)) { continue; } const layerPoints = getPointLayerData(key); const displayData = filterPointLayerDataForDisplay(key, layerPoints); const cacheChecked = mapDataStore.getPointLayerCache(key)?.checked; const shouldRestoreVisible = typeof cacheChecked === 'boolean' ? cacheChecked : layer.checked === 1 || runtimeCheckedKeys.includes(key); layer.data = layerPoints; mapClass.addInitDataLayer(displayData, key); if (shouldRestoreVisible) { restoreLayerLegendVisibility(key); } mapClass.mdLayerTreeShowOrHidden(key, shouldRestoreVisible); } // 设置选中的图例数据(确保图例在所有锚点加载完成后才显示) setSelectedLegendData(); // 备注:初始化 loading 期间用户可能已经手动改过图层勾选,这里必须以最新运行态收尾, // 不能再回放 load 启动瞬间的默认 checked 快照。 await updateLayerData(runtimeCheckedKeys, true); } finally { mapDataStore.setLoading(false); } }; /** * 根据 key 查找图层 */ const findLayerByKey = (items: any[], key: string): any | null => { void items; if (!key) return null; return getLayerConfigByKey(key) || null; }; /** * 获取所有图层 keys */ const getAllLayerKeys = (data: any[]): string[] => { const keys: string[] = []; const f = (arr: any[] = []) => { arr.forEach((item: any) => { if (item.key) { keys.push(item.key); } if (item.children && item.children.length > 0) { f(item.children); } }); }; f(data); return keys; }; const getRuntimeLegendNames = ( layerKey: string, nameEn: string ): string[] => { void layerKey; const normalizedNameEn = normalizeLegendNameEn(nameEn); if (!normalizedNameEn) { return []; } if (normalizedNameEn.includes('alarm_range_')) { return [`large_eng_built_${normalizedNameEn}`]; } return [normalizedNameEn]; }; const syncLegendCheckedInTree = ( items: any[], nameEn: string, checked: number ) => { items.forEach((item: any) => { if (item.nameEn === nameEn) { item.checked = checked; } if (item.childrenList && item.childrenList.length > 0) { syncLegendCheckedInTree(item.childrenList, nameEn, checked); } }); }; const applyLegendItemVisibility = (legendItem: any, checked: number) => { if (!legendItem?.nameEn || !legendItem?.layerCode) { return; } const layerKey = legendItem.layerCode; const layerItem = getLayerConfigByKey(layerKey); const shouldBeVisible = checked === 1; const runtimeLegendNames = getRuntimeLegendNames( layerKey, legendItem.nameEn ); if (layerItem?.type === 'GISMap') { mapClass.controlBaseLayerTreeShowAndHidden( layerKey, layerItem.config?.id || layerKey, shouldBeVisible ); return; } runtimeLegendNames.forEach(runtimeLegendName => { mapClass.setLegendPointVisible( layerKey, runtimeLegendName, shouldBeVisible ); }); }; /** * 更新图例选中状态 */ const updateLegendChecked = (nameEn: string, checked: number) => { const normalizedNameEn = normalizeLegendNameEn(nameEn); const legendItem = getLegendConfigByNameEn(normalizedNameEn); if (!legendItem) { return; } mapViewStore.setLegendChecked(normalizedNameEn, checked); syncLegendCheckedInTree(legendData.value, normalizedNameEn, checked); syncLegendCheckedInTree( legendDataSelected.value, normalizedNameEn, checked ); rebuildLegendRuntimeData(checkedLayerKeys.value); applyLegendItemVisibility(legendItem, checked); }; const updateLegendCheckedBatch = (nameEns: string[], checked: number) => { const nextState = { ...legendCheckedState.value }; const changedLegendItems: any[] = []; nameEns.forEach(nameEn => { const normalizedNameEn = normalizeLegendNameEn(nameEn); const legendItem = getLegendConfigByNameEn(normalizedNameEn); if (!legendItem) return; nextState[normalizedNameEn] = checked; changedLegendItems.push(legendItem); }); mapViewStore.setLegendCheckedState(nextState); rebuildLegendRuntimeData(checkedLayerKeys.value); changedLegendItems.forEach(legendItem => applyLegendItemVisibility(legendItem, checked) ); }; /** /** * 生成请求标识符,用于避免重复请求 */ const getRequestIdentifier = (url: string, params: any): string => { const paramString = JSON.stringify(normalizeCachePayload(params)); return `${url}?${encodeURIComponent(paramString)}`; }; /** * 加载单个图层数据 */ const loadLayerData = async ( layer: any, sessionId: number = loadSessionSeed ) => { const { key, url, params = {}, paramJson } = layer; // 没有URL,跳过 if (!url) { return []; } // 参考 React 版本:使用 urlList 匹配图层配置 let requestUrl = url; let requestParams: any = params; let requestOrders: any = null; // 根据图层的 key(keyType)、title、url 查找匹配的 urlList 项 const layerKey = layer?.key || ''; const layerTitle = layer?.title || ''; const matchedList = urlListIndex[layerKey] || urlListIndex[layerTitle] || urlListIndex[url]; if (matchedList && matchedList.length > 0) { let matchedItem: any = null; if (key == 'va_built_point ' || key == 'vp_built_point') { matchedList.forEach(item => { if (item.title === layerTitle) { matchedItem = item; } }); } else { matchedItem = matchedList[0]; } requestUrl = matchedItem.url; // 转换 params 为 filter 格式 if (matchedItem.params) { const filtersArray: any[] = []; for (const key in matchedItem.params) { const value = matchedItem.params[key]; if (Array.isArray(value)) { // 处理数组格式: { field: 'sttpCode', operator: 'eq', value: 'WQ' } value.forEach((filter: any) => { filtersArray.push({ ...filter, dataType: filter.dataType || 'string' }); }); } else { // 处理简单格式: sttpCode: 'VP' filtersArray.push({ field: key, operator: 'eq', dataType: 'string', value: value }); } } requestParams = { logic: 'and', filters: filtersArray }; } let voidSttp = 'all'; const ylfbKeys = ['ylfb_point']; // 需要时间搜索的图层key const timeRangeLayerKeys = ['ef_point']; // 需要时间搜索的图层key const spjkz = ['stinfo_video_point']; const lineTimeLayerKeys = [ 'wt_rive_gradient_line', 'wq_rive_gradient_line' ]; // 需要时间搜索的图层key let yearTime = dayjs().subtract(1, 'years'); // 鱼类分布年份 if (timeRangeLayerKeys.includes(layerKey)) { requestParams.filters.push({ field: 'tm', operator: 'gte', dataType: 'date', value: dayjs(searchTimeRange.value[0]).format('YYYY-MM-DD HH:mm:ss') }); requestParams.filters.push({ field: 'tm', operator: 'lte', dataType: 'date', value: dayjs(searchTimeRange.value[1]).format('YYYY-MM-DD 23:59:59') }); } if (spjkz.includes(layerKey)) { if (voidSttp !== 'all') { requestParams.filters.push({ field: 'sttp', operator: 'in', value: voidSttp == 'VD_EQ,VD_EQS' ? ['VD_EQ', 'VD_EQS'] : [voidSttp] }); } } if (ylfbKeys.includes(layerKey)) { if (yearTime) { requestParams.filters.push({ field: 'startTime', operator: 'eq', dataType: 'date', value: dayjs(yearTime).startOf('year').format('YYYY-MM-DD 00:00:00') }); requestParams.filters.push({ field: 'endTime', operator: 'eq', dataType: 'date', value: dayjs(yearTime).endOf('year').format('YYYY-MM-DD 23:59:59') }); } } // 转换 orders 格式:从 JSON 字符串转换为数组格式 if (matchedItem.orders) { try { const ordersObj = JSON.parse(matchedItem.orders); const ordersArray = Object.entries(ordersObj).map(([field, dir]) => ({ field, dir })); requestOrders = ordersArray; } catch (e) { console.error('解析 orders 失败:', e); } } } // 如果没有匹配到 urlList,尝试解析 paramJson if (!Object.keys(requestParams).length && paramJson) { try { const jsonObj = JSON.parse(paramJson); if (jsonObj.params) { requestParams = jsonObj.params; } } catch (e) { console.error('解析 paramJson 失败:', e); } } const requestData: any = { filter: requestParams }; if (requestOrders) { requestData.sort = requestOrders; } const requestIdentifier = getRequestIdentifier(requestUrl, { layerKey: key, requestData }); if (hasValidPointLayerCache(key, requestIdentifier)) { layer.data = getPointLayerData(key); layer.checked = 0; syncPointDataForFilter(); if (!mapClass.hasLayer(key)) { mapClass.addInitDataLayer( filterPointLayerDataForDisplay(key, getPointLayerData(key)), key ); mapClass.mdLayerTreeShowOrHidden(key, false); } return layer.data; } const previousRequestKey = activeLayerRequestKeyMap.get(key); if (previousRequestKey && previousRequestKey !== requestIdentifier) { const previousRequest = inFlightRequestMap.get(previousRequestKey); previousRequest?.controller.abort(); mapDataStore.clearLayerLoadState(key); inFlightRequestMap.delete(previousRequestKey); } const existingRequest = inFlightRequestMap.get(requestIdentifier); if (existingRequest) { return existingRequest.promise; } mapDataStore.setLayerLoading(key); const controller = new AbortController(); activeLayerRequestKeyMap.set(key, requestIdentifier); const requestPromise = (async () => { try { const response = await request({ url: '/api' + requestUrl, method: 'post', data: requestData, signal: controller.signal }); const resData = response?.data || response?.data?.data || []; if ( controller.signal.aborted || !isCurrentLoadSession(sessionId) || activeLayerRequestKeyMap.get(key) !== requestIdentifier ) { return []; } let list: any[] = []; if (resData) { if (Array.isArray(resData)) { list = resData; } else if (Array.isArray(resData.data)) { list = resData.data; } else if (resData.data && Array.isArray(resData.data.data)) { list = resData.data.data; } else if ( resData.data && resData.data.data && Array.isArray(resData.data.data.data) ) { list = resData.data.data.data; } } list.forEach((item: any) => { const iconType = item.anchoPointState; const legendConfig = getLegendConfigByNameEn(iconType); item.iconCode = legendConfig?.icon || ''; item.code = legendConfig?.code || ''; item.tm = item.sttpMap === 'WQ_ALARM' ? item?.warnDataList?.[0]?.tm : item?.tm; item._id = item.sttpMap + '_' + item.stcd; }); list = list.filter( (l: any) => (l.iconCode || l.code == 'colorLayer') && !(l?.baseId == 'all' && l?.anchoPointState?.endsWith('_nbuilt')) ); const isLayerChecked = layer.checked === 1; mapDataStore.setPointLayerCache(key, { checked: isLayerChecked, data: list, cacheKey: requestIdentifier }); syncPointDataForFilter(); layer.data = list; if (list.length > 0) { const displayData = filterPointLayerDataForDisplay(key, list); mapClass.addInitDataLayer(displayData, key); if (isLayerChecked) { restoreLayerLegendVisibility(key); } mapClass.mdLayerTreeShowOrHidden(key, isLayerChecked); } mapDataStore.setLayerLoaded(key); return list; } catch (error) { if ( controller.signal.aborted || isCanceledRequestError(error) || !isCurrentLoadSession(sessionId) || activeLayerRequestKeyMap.get(key) !== requestIdentifier ) { return []; } console.error(`加载描点数据失败 [${key}]:`, error); mapDataStore.setLayerLoadError(key, error); throw error; } finally { const activeRequest = inFlightRequestMap.get(requestIdentifier); if (activeRequest?.controller === controller) { inFlightRequestMap.delete(requestIdentifier); } if (activeLayerRequestKeyMap.get(key) === requestIdentifier) { activeLayerRequestKeyMap.delete(key); } } })(); inFlightRequestMap.set(requestIdentifier, { promise: requestPromise, controller, layerKey: key, sessionId }); return requestPromise; }; /** * 获取选中的图层 key */ const getCheckedKeys = (): string[] => { return mapViewStore.getCheckedLayerKeys(); }; /** * 根据当前搜索时间范围重新加载描点数据 */ const reloadBySearchTimeRange = async () => { mapDataStore.setLoading(true); const currentSessionId = startLoadSession(); // 只处理和 searchTimeRange 相关的图层 const timeRangeLayerKeys = ['ef_point']; try { for (const key of timeRangeLayerKeys) { // 如果描点图层存在于地图中,先删除旧图层 mapClass.removePointLayer(key); // 清空缓存 if (mapDataStore.getPointLayerCache(key)) { mapDataStore.removePointLayerCache(key); mapDataStore.clearLayerLoadState(key); } } // 重新加载需要时间搜索的图层数据 if (layerData.value.length > 0) { const currentCheckedKeys = getCheckedKeys(); for (const key of timeRangeLayerKeys) { const layerItem = findLayerByKey(layerData.value, key); if (layerItem && currentCheckedKeys.includes(key)) { await loadLayerData(layerItem, currentSessionId); } } if (!isCurrentLoadSession(currentSessionId)) { return; } const allPointData = mapDataStore.rebuildPointDataFromCache(); // 更新地图锚点显示 await updateLayerData(currentCheckedKeys, false); } } finally { mapDataStore.setLoading(false); } }; /** * 更新搜索时间范围并重新加载描点数据 */ const updateSearchTimeRange = async (newRange: [any, any]) => { mapViewStore.setSearchTimeRange(newRange); await reloadBySearchTimeRange(); }; return { layerData, setLayerData, loadAllLayerData, loadLayerData, setSelectedLegendData, legendData, setLegendData, legendDataSelected, pointData, setPointData, checkedLayerKeys, updateLayerData, updateLegendChecked, updateLegendCheckedBatch, getCheckedKeys, legendData2Obj, loading, pointDataCache, layerLoadState, findLayerByKey, getLegendItemsByLayerCode, getLayerBranchKeys, normalizeCheckedLayerKeys, refreshPointLayerDisplayData, searchTimeRange, reloadBySearchTimeRange, updateSearchTimeRange }; });