1159 lines
33 KiB
Markdown
1159 lines
33 KiB
Markdown
|
|
# 地图模块现状与改造方案
|
|||
|
|
|
|||
|
|
## 1. 文档目的
|
|||
|
|
|
|||
|
|
本文档用于完整梳理当前地图模块的技术实现、业务能力、数据流转、关键规则、已知问题与性能瓶颈,并给出可分阶段落地的重构方案。目标是:
|
|||
|
|
|
|||
|
|
- 让地图模块职责边界清晰,便于后续新增功能;
|
|||
|
|
- 降低组件、Store、地图引擎之间的耦合;
|
|||
|
|
- 优化基础图层、锚点、图例、筛选、基地裁切等功能的响应速度;
|
|||
|
|
- 为后续 2D/3D 扩展、复杂专题图层、更多筛选维度、更多交互能力预留稳定结构。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 当前模块范围
|
|||
|
|
|
|||
|
|
当前地图模块覆盖以下业务能力:
|
|||
|
|
|
|||
|
|
- 地图初始化与 2D/3D 切换;
|
|||
|
|
- GeoServer 基础底图、叠加图层、区域矢量图层加载;
|
|||
|
|
- Java 后端锚点数据请求、缓存、渲染;
|
|||
|
|
- 右侧图层树勾选控制图层显示与隐藏;
|
|||
|
|
- 左侧图例基于图层选中结果动态生成;
|
|||
|
|
- 图例项点击控制锚点显隐;
|
|||
|
|
- 基地选择后底图裁切与区域外锚点隐藏;
|
|||
|
|
- 地图悬停 Popup、点击详情弹窗;
|
|||
|
|
- 搜索、时间筛选、容量筛选、基地筛选;
|
|||
|
|
- 某些业务图层的互斥显示与特殊联动;
|
|||
|
|
- 局部专题菜单下的缩放级别联动动态图层。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 当前技术实现概览
|
|||
|
|
|
|||
|
|
## 3.1 技术栈
|
|||
|
|
|
|||
|
|
- 地图引擎:OpenLayers 作为 2D 主引擎,Cesium 作为 3D 引擎入口;
|
|||
|
|
- 状态管理:Pinia;
|
|||
|
|
- UI 框架:Vue 3 + `script setup` + Ant Design Vue;
|
|||
|
|
- 数据来源:
|
|||
|
|
- GeoServer:基础底图、WMTS、XYZ、GeoJSON 边界;
|
|||
|
|
- Java 后端接口:图层配置、图例配置、锚点数据;
|
|||
|
|
- 业务配置:
|
|||
|
|
- 图层配置与图例配置来自后端;
|
|||
|
|
- 锚点接口映射规则由 `src/store/modules/GisUrlList.ts` 维护。
|
|||
|
|
|
|||
|
|
## 3.2 核心文件职责
|
|||
|
|
|
|||
|
|
- `src/components/gis/GisView.vue`
|
|||
|
|
|
|||
|
|
- 地图容器入口;
|
|||
|
|
- 地图初始化;
|
|||
|
|
- 拉取图层配置与图例配置;
|
|||
|
|
- 监听菜单切换、基地切换、缩放联动;
|
|||
|
|
- 挂载 `MapLegend`、`MapFilter`、`MapController`、`BaseLayerSwitcher`。
|
|||
|
|
|
|||
|
|
- `src/components/gis/map.class.ts`
|
|||
|
|
|
|||
|
|
- 地图能力门面类;
|
|||
|
|
- 对外屏蔽 OpenLayers / Cesium 差异;
|
|||
|
|
- 当前主要起到转发作用。
|
|||
|
|
|
|||
|
|
- `src/components/gis/map.ol.ts`
|
|||
|
|
|
|||
|
|
- OpenLayers 主实现;
|
|||
|
|
- 负责底图、锚点图层、Popup、图层显隐、区域裁切、量算、定位等;
|
|||
|
|
- 当前承担了过多业务规则与渲染控制逻辑。
|
|||
|
|
|
|||
|
|
- `src/store/modules/map.ts`
|
|||
|
|
|
|||
|
|
- 地图图层树、图例、锚点、缓存的核心 Store;
|
|||
|
|
- 负责图层选中状态、图例选中状态、锚点请求、缓存、图例联动、图层联动;
|
|||
|
|
- 当前是业务与渲染耦合最重的文件之一。
|
|||
|
|
|
|||
|
|
- `src/components/mapController/LayerController.vue`
|
|||
|
|
|
|||
|
|
- 图层树 UI;
|
|||
|
|
- 负责初始基础图层加载;
|
|||
|
|
- 勾选事件直接调用 Store 更新图层与图例状态;
|
|||
|
|
- 包含多个互斥业务规则。
|
|||
|
|
|
|||
|
|
- `src/components/mapLegend/index.vue`
|
|||
|
|
|
|||
|
|
- 图例展示;
|
|||
|
|
- 基于当前选中图层动态显示;
|
|||
|
|
- 图例点击后直接驱动地图锚点显隐。
|
|||
|
|
|
|||
|
|
- `src/components/mapFilter/index.vue`
|
|||
|
|
|
|||
|
|
- 搜索、基地筛选、容量筛选、时间筛选;
|
|||
|
|
- 直接依赖 `mapStore` 和地图实例;
|
|||
|
|
- 部分筛选逻辑通过直接修改图例和锚点实现。
|
|||
|
|
|
|||
|
|
- `src/components/BaseLayerSwitcher/index.vue`
|
|||
|
|
|
|||
|
|
- 底图模式切换器;
|
|||
|
|
- 切换矢量 / 地形 / 影像底图。
|
|||
|
|
|
|||
|
|
- `src/components/gis/gisUtils.ts`
|
|||
|
|
|
|||
|
|
- 图层结构拍平;
|
|||
|
|
- 基础图层 URL 处理;
|
|||
|
|
- 图例数据转对象;
|
|||
|
|
- 若干地图布局相关工具。
|
|||
|
|
|
|||
|
|
- `src/api/map.ts`
|
|||
|
|
- 拉取地图配置和图例配置。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 当前业务能力与逻辑链路
|
|||
|
|
|
|||
|
|
## 4.1 初始化流程
|
|||
|
|
|
|||
|
|
当前初始化主要发生在 `GisView.vue`:
|
|||
|
|
|
|||
|
|
1. 调用 `MapClass.init()` 初始化 OpenLayers;
|
|||
|
|
2. 调用 `initPopupOverlay()` 挂载悬停 Popup;
|
|||
|
|
3. 调用 `fetchMapConfigs()` 并行请求:
|
|||
|
|
- 地图图层配置;
|
|||
|
|
- 全量图例配置;
|
|||
|
|
- 当前页面图例配置;
|
|||
|
|
4. `mapStore.setLegendData()` 初始化图例原始数据与映射;
|
|||
|
|
5. `mapStore.setLayerData()` 初始化图层树和选中图层 key;
|
|||
|
|
6. `mapStore.loadAllLayerData()` 递归加载所有有 URL 的图层数据;
|
|||
|
|
7. `loadLayerData()` 将锚点数据写入缓存并直接调用 `mapClass.addInitDataLayer()` 预创建锚点图层;
|
|||
|
|
8. 全部锚点加载完成后,再调用 `updateLayerData()` 统一控制初始显示状态;
|
|||
|
|
9. 图例根据当前选中的图层动态生成并展示。
|
|||
|
|
|
|||
|
|
### 现状特点
|
|||
|
|
|
|||
|
|
- 当前是“初始化阶段一次性预加载大多数锚点图层,再通过显隐控制”的策略;
|
|||
|
|
- 图例显示被设计为“锚点完成后再显示”;
|
|||
|
|
- 地图实例、Store、UI 组件三方互相直接调用。
|
|||
|
|
|
|||
|
|
## 4.2 基础图层加载与切换
|
|||
|
|
|
|||
|
|
基础底图主要由 `LayerController.vue` 和 `map.ol.ts` 协同完成:
|
|||
|
|
|
|||
|
|
- `LayerController.vue` 中监听图层树配置;
|
|||
|
|
- 对类型为 `GISMap` 的节点解析 `paramJson`,通过 `getMapConfig()` 补齐 GeoServer 地址;
|
|||
|
|
- 调用 `mapClass.addBaseDataLayer()` 初始化基础图层;
|
|||
|
|
- 同时调用 `controlBaseLayerTreeShowAndHidden()` 控制显隐;
|
|||
|
|
- `BaseLayerSwitcher` 再通过 `baseLayerSwitcher()` 在矢量 / 地形 / 影像底图之间切换。
|
|||
|
|
|
|||
|
|
当前基础图层类型主要包括:
|
|||
|
|
|
|||
|
|
- WMTS:GeoServer WMTS 瓦片;
|
|||
|
|
- XYZ:例如 DEM 或其他切片图层;
|
|||
|
|
- vector:部分矢量底图或区域配置。
|
|||
|
|
|
|||
|
|
### 自然保护区图层特点
|
|||
|
|
|
|||
|
|
- 属于叠加在底图之上的 GIS 图层;
|
|||
|
|
- 显隐仍通过基础图层控制逻辑处理;
|
|||
|
|
- 与区域裁切场景存在较强耦合。
|
|||
|
|
|
|||
|
|
## 4.3 图层树勾选控制
|
|||
|
|
|
|||
|
|
右侧图层树由 `LayerController.vue` 驱动:
|
|||
|
|
|
|||
|
|
- 树节点勾选结果通过 `broadcast()` 调用 `mapStore.updateLayerData()`;
|
|||
|
|
- 图层树中包含多种特殊规则:
|
|||
|
|
- 视频监控站与 AI 视频监控站互斥;
|
|||
|
|
- 环保设施和环保设施在建互斥;
|
|||
|
|
- 珍稀鱼类与沿程鱼类互斥;
|
|||
|
|
- 初始选中状态通过递归遍历图层树生成。
|
|||
|
|
|
|||
|
|
### 现状问题
|
|||
|
|
|
|||
|
|
- 互斥逻辑分散在 UI 组件和 Store 两处;
|
|||
|
|
- “图层树状态”与“地图真实状态”并非单向流;
|
|||
|
|
- 图层节点既承担展示,又携带业务配置与运行态字段。
|
|||
|
|
|
|||
|
|
## 4.4 锚点数据加载
|
|||
|
|
|
|||
|
|
锚点数据由 `mapStore.loadAllLayerData()` 和 `loadLayerData()` 负责:
|
|||
|
|
|
|||
|
|
- 遍历图层树中全部带 URL 的图层;
|
|||
|
|
- 使用 `GisUrlList.ts` 将图层 key / title / url 映射成真实请求地址、筛选条件、排序规则;
|
|||
|
|
- 请求 Java 接口;
|
|||
|
|
- 将返回记录补充:
|
|||
|
|
- `iconCode`
|
|||
|
|
- `code`
|
|||
|
|
- `_id`
|
|||
|
|
- `tm`
|
|||
|
|
- 然后缓存到:
|
|||
|
|
- `pointDataCache[layerKey]`
|
|||
|
|
- `layer.data`
|
|||
|
|
- 合并后的 `pointData`
|
|||
|
|
- 若地图上还不存在该图层,则直接调用 `mapClass.addInitDataLayer()` 创建 `VectorLayer`。
|
|||
|
|
|
|||
|
|
### 当前锚点渲染方式
|
|||
|
|
|
|||
|
|
- 每个 `pointMap` 图层对应一个 `VectorLayer`;
|
|||
|
|
- 每个点被转为 `Feature<Point>`;
|
|||
|
|
- Feature 上维护多个运行态字段:
|
|||
|
|
- `_iconUrl`
|
|||
|
|
- `_labelText`
|
|||
|
|
- `_legendVisible`
|
|||
|
|
- `_regionVisible`
|
|||
|
|
- `_layerKey`
|
|||
|
|
- 样式函数 `createPointStyle()` 在渲染时综合判断:
|
|||
|
|
- 图例是否显示;
|
|||
|
|
- 是否在基地区域内;
|
|||
|
|
- 当前缩放级别;
|
|||
|
|
- 点之间距离阈值;
|
|||
|
|
- 是否悬停。
|
|||
|
|
|
|||
|
|
## 4.5 图例动态生成与点击联动
|
|||
|
|
|
|||
|
|
图例数据来源于两部分:
|
|||
|
|
|
|||
|
|
- `legendDataOriginal`:后端返回的全量图例;
|
|||
|
|
- `legendDataSelected`:根据当前选中的图层动态筛选后的图例结构。
|
|||
|
|
|
|||
|
|
当前机制:
|
|||
|
|
|
|||
|
|
1. 初始化时拉取全部图例;
|
|||
|
|
2. 通过 `layerCode` 与图层树选中结果建立关联;
|
|||
|
|
3. `mapStore.updateLayerData()` 重新计算当前选中的图例树;
|
|||
|
|
4. `MapLegend` 监听 `legendDataSelected` 进行展示;
|
|||
|
|
5. 点击图例项后:
|
|||
|
|
- 更新 Store 中图例 checked 状态;
|
|||
|
|
- 若是锚点图层,则调用 `mapClass.setLegendPointVisible()`;
|
|||
|
|
- 若是 GIS 图层,则调用 `controlBaseLayerTreeShowAndHidden()`。
|
|||
|
|
|
|||
|
|
### 环保设施特殊逻辑
|
|||
|
|
|
|||
|
|
- 勾选 `fp_point`、`eq_point`、`fb_point`、`vp_point`、`va_point`、`sg_point`、`dw_point` 中任意图层时,图例自动补充“环保设施”分组;
|
|||
|
|
- 全部取消时自动移除该图例分组。
|
|||
|
|
|
|||
|
|
## 4.6 筛选与搜索
|
|||
|
|
|
|||
|
|
`MapFilter` 负责以下功能:
|
|||
|
|
|
|||
|
|
- 装机容量筛选;
|
|||
|
|
- 锚点关键字搜索;
|
|||
|
|
- 时间筛选;
|
|||
|
|
- 基地筛选;
|
|||
|
|
- 个别专题下的鱼类分布筛选。
|
|||
|
|
|
|||
|
|
当前实现方式:
|
|||
|
|
|
|||
|
|
- 搜索下拉列表从 `pointData` 里计算;
|
|||
|
|
- 只展示当前已选中图层中的锚点;
|
|||
|
|
- 容量筛选直接修改图例状态,并调用 `map.mdLayerShowOrHidden()` 控制 feature 显隐;
|
|||
|
|
- 时间筛选通过 `mapStore.updateSearchTimeRange()` 清缓存、删图层、重新请求;
|
|||
|
|
- 基地切换通过监听 `JidiSelectEventStore.selectedItem` 联动地图区域裁切。
|
|||
|
|
|
|||
|
|
## 4.7 基地选择与区域裁切
|
|||
|
|
|
|||
|
|
基地逻辑入口在 `GisView.vue` 监听器中:
|
|||
|
|
|
|||
|
|
- 当基地变化时,调用 `mapClass.jdPanelControlShowAndHidden()`;
|
|||
|
|
- `map.ol.ts` 内会:
|
|||
|
|
- 更新当前 `BASEID`;
|
|||
|
|
- 请求基地 GeoJSON 边界;
|
|||
|
|
- 隐藏所有锚点;
|
|||
|
|
- 通过射线法判断锚点是否在区域内;
|
|||
|
|
- 标记 `_regionVisible`;
|
|||
|
|
- 调整视角;
|
|||
|
|
- 对底图应用遮罩。
|
|||
|
|
|
|||
|
|
### 该能力的业务效果
|
|||
|
|
|
|||
|
|
- 只显示当前基地区域内的锚点;
|
|||
|
|
- 底图裁切到当前基地范围;
|
|||
|
|
- 全选时取消遮罩并显示全部锚点。
|
|||
|
|
|
|||
|
|
## 4.8 Popup 与点击详情
|
|||
|
|
|
|||
|
|
当前交互如下:
|
|||
|
|
|
|||
|
|
- `pointermove` 时调用 `detectFeatureAtPixel()` 检查命中点要素;
|
|||
|
|
- 若命中图标区域,则:
|
|||
|
|
- 更新鼠标指针;
|
|||
|
|
- 更新 `hoveredFeatureId`;
|
|||
|
|
- 调用 `showPopup()` 展示悬停浮窗;
|
|||
|
|
- 重绘所有点图层;
|
|||
|
|
- `click` 命中点要素时,打开详情弹窗并将 feature 属性写入 `modelStore`。
|
|||
|
|
|
|||
|
|
### 当前特点
|
|||
|
|
|
|||
|
|
- Popup 内容由 `popupHtml` 或 `generatePopupHtml(props)` 生成;
|
|||
|
|
- 命中检测采用逐像素回调加距离二次判断;
|
|||
|
|
- 所有点图层在 hover 状态切换时都会 `layer.changed()`。
|
|||
|
|
|
|||
|
|
## 4.9 菜单与缩放级别联动
|
|||
|
|
|
|||
|
|
在水电开发状况菜单下:
|
|||
|
|
|
|||
|
|
- 地图缩放级别大于等于 12 时自动添加一组动态图层;
|
|||
|
|
- 缩回 12 以下时自动移除;
|
|||
|
|
- 菜单切换时会根据当前层级重新判断是否添加。
|
|||
|
|
|
|||
|
|
当前动态图层 key 包括:
|
|||
|
|
|
|||
|
|
- `dw_point`
|
|||
|
|
- `stinfo_video_point`
|
|||
|
|
- `stinfo_gjllz_point`
|
|||
|
|
- `wt_point`
|
|||
|
|
- `wq_ownWq_point`
|
|||
|
|
- `wq_countryWq_point`
|
|||
|
|
- `fp_point`
|
|||
|
|
- `eq_point`
|
|||
|
|
- `fb_point`
|
|||
|
|
- `vp_point`
|
|||
|
|
- `va_point`
|
|||
|
|
- `sg_point`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 当前数据流与调用关系
|
|||
|
|
|
|||
|
|
当前主数据流可概括为:
|
|||
|
|
|
|||
|
|
1. `GisView.vue` 拉取配置;
|
|||
|
|
2. `mapStore` 保存图层树、图例、缓存;
|
|||
|
|
3. `LayerController.vue` / `MapLegend.vue` / `MapFilter.vue` 直接操作 `mapStore`;
|
|||
|
|
4. `mapStore` 又直接调用 `mapClass`;
|
|||
|
|
5. `mapClass` 继续转发到 `map.ol.ts`;
|
|||
|
|
6. `map.ol.ts` 内部维护图层注册表和 Feature 运行态;
|
|||
|
|
7. 地图状态变化后,组件又通过监听 Store 再次更新 UI。
|
|||
|
|
|
|||
|
|
### 现有结构本质
|
|||
|
|
|
|||
|
|
当前是“多入口、多方向写状态”的结构:
|
|||
|
|
|
|||
|
|
- 组件可以改 Store;
|
|||
|
|
- 组件可以直接调地图;
|
|||
|
|
- Store 可以直接调地图;
|
|||
|
|
- 地图内部又维护一套运行态;
|
|||
|
|
- 图例、图层树、地图显隐存在多份状态镜像。
|
|||
|
|
|
|||
|
|
这会导致:
|
|||
|
|
|
|||
|
|
- 状态同步成本高;
|
|||
|
|
- 某些场景下容易出现 UI 勾选状态与实际地图状态不一致;
|
|||
|
|
- 新增规则时只能继续在现有逻辑上叠加 `if/else`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 当前存在的主要问题
|
|||
|
|
|
|||
|
|
## 6.1 架构层面问题
|
|||
|
|
|
|||
|
|
### 1. UI、业务编排、地图渲染耦合过深
|
|||
|
|
|
|||
|
|
- `LayerController.vue`、`MapLegend.vue`、`MapFilter.vue` 都直接调 Store 和地图实例;
|
|||
|
|
- `map.ts` 同时负责:
|
|||
|
|
- 请求;
|
|||
|
|
- 缓存;
|
|||
|
|
- 图例结构整理;
|
|||
|
|
- 图层勾选;
|
|||
|
|
- 地图显隐;
|
|||
|
|
- 业务互斥;
|
|||
|
|
- `map.ol.ts` 同时负责:
|
|||
|
|
- OpenLayers 适配;
|
|||
|
|
- 业务过滤;
|
|||
|
|
- 区域裁切;
|
|||
|
|
- 弹窗;
|
|||
|
|
- 图例控制;
|
|||
|
|
- 锚点显示策略。
|
|||
|
|
|
|||
|
|
### 2. 缺乏清晰的单向数据流
|
|||
|
|
|
|||
|
|
- 图层树 checked、图例 checked、Feature `_legendVisible`、Layer visible 都是状态源;
|
|||
|
|
- 任何一个点修改后都可能触发联动,难以推断最终状态;
|
|||
|
|
- 某些流程依赖顺序正确才能表现正常。
|
|||
|
|
|
|||
|
|
### 3. 业务规则分散
|
|||
|
|
|
|||
|
|
- 互斥规则分散在 `LayerController.vue` 和 `map.ts`;
|
|||
|
|
- 环保设施图例补充逻辑在 `map.ts`;
|
|||
|
|
- 装机容量筛选逻辑在 `MapFilter.vue`;
|
|||
|
|
- 基地区域过滤逻辑在 `map.ol.ts`;
|
|||
|
|
- 这些规则没有统一归口,新增业务会继续扩大分散度。
|
|||
|
|
|
|||
|
|
## 6.2 性能问题
|
|||
|
|
|
|||
|
|
### 1. 初始化阶段预加载过重
|
|||
|
|
|
|||
|
|
- `loadAllLayerData()` 会递归处理大量图层;
|
|||
|
|
- 即使图层未勾选,也会提前请求并建图层;
|
|||
|
|
- 页面首次进入时网络压力和首屏渲染压力较大。
|
|||
|
|
|
|||
|
|
### 2. 递归遍历频繁
|
|||
|
|
|
|||
|
|
- 图层树查找 `findLayerByKey()` 多次递归;
|
|||
|
|
- 图例生成 `getlegendData()` 递归;
|
|||
|
|
- `updateLayerData()` 每次变化都要递归更新 checked 状态;
|
|||
|
|
- 搜索项计算 `anchorPointOptions` 也会递归收集图层 key。
|
|||
|
|
|
|||
|
|
### 3. 锚点显隐是全量 feature 遍历
|
|||
|
|
|
|||
|
|
- 图例点击时逐个遍历 feature;
|
|||
|
|
- 基地裁切时逐个 feature 做点在面内判断;
|
|||
|
|
- hover 时所有点图层重绘;
|
|||
|
|
- 缩放变化会重复执行样式计算。
|
|||
|
|
|
|||
|
|
### 4. 底图切换会 remove / add 图层
|
|||
|
|
|
|||
|
|
- `baseLayerSwitcher()` 每次切换都移除旧底图再新增;
|
|||
|
|
- 对 WMTS / XYZ 来说会造成重复创建图层对象和重复请求开销。
|
|||
|
|
|
|||
|
|
## 6.3 一致性与可靠性问题
|
|||
|
|
|
|||
|
|
### 1. 存在明显临时代码与未收敛逻辑
|
|||
|
|
|
|||
|
|
- `GisView.vue` 中 `fetchMapConfigs()` 里对图层做了 `splice(0, 2)` 临时截断;
|
|||
|
|
- 日志仍显示“临时限制”,说明线上逻辑可能仍处于测试状态。
|
|||
|
|
|
|||
|
|
### 2. 存在未定义引用
|
|||
|
|
|
|||
|
|
- `GisView.vue` 切换地图后调用 `fetchPointData()`,但项目中未找到定义;
|
|||
|
|
- `map.ts` 中使用了 `wq_lineTime`、`wt_lineTime`,但项目中未找到定义。
|
|||
|
|
|
|||
|
|
### 3. 请求去重逻辑未真正落地
|
|||
|
|
|
|||
|
|
- `map.ts` 中生成了 `requestIdentifier`,但未实际用于请求去重;
|
|||
|
|
- `requestParamsCopy` 也未参与有效逻辑。
|
|||
|
|
|
|||
|
|
### 4. 图层状态与渲染状态容易失同步
|
|||
|
|
|
|||
|
|
- `layer.checked`、`checkedLayerKeys`、图例 checked、Feature 可见状态是多份数据;
|
|||
|
|
- 其中任意一份被跳过更新,就可能出现视觉不一致。
|
|||
|
|
|
|||
|
|
### 5. 部分代码存在明显遗留痕迹
|
|||
|
|
|
|||
|
|
- `addInitDataLayer()` 中存在无意义语句 `3;`;
|
|||
|
|
- 有重复日志;
|
|||
|
|
- 有注释掉的大量旧逻辑;
|
|||
|
|
- 说明代码迁移过程中缺乏结构性收口。
|
|||
|
|
|
|||
|
|
## 6.4 可维护性问题
|
|||
|
|
|
|||
|
|
### 1. Store 过大
|
|||
|
|
|
|||
|
|
- `map.ts` 既是数据仓库,又是调度器,又是业务规则中心;
|
|||
|
|
- 后续新增图层类型、筛选类型、专题逻辑时,文件会持续膨胀。
|
|||
|
|
|
|||
|
|
### 2. MapOl 职责过多
|
|||
|
|
|
|||
|
|
- 当前 `map.ol.ts` 既是 OpenLayers 适配器,又是图层经理、锚点经理、Popup 经理、区域裁切经理;
|
|||
|
|
- 单文件理解和修改成本已经偏高。
|
|||
|
|
|
|||
|
|
### 3. 缺少规范化类型系统
|
|||
|
|
|
|||
|
|
- 大量 `any`;
|
|||
|
|
- 图层配置、图例配置、锚点数据、请求映射结构都没有稳定类型;
|
|||
|
|
- 特殊图层规则依赖字符串常量散落在各处。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 改造目标
|
|||
|
|
|
|||
|
|
本次改造建议达成以下目标:
|
|||
|
|
|
|||
|
|
### 7.1 结构目标
|
|||
|
|
|
|||
|
|
- 建立清晰的四层结构:视图层、应用编排层、领域状态层、地图渲染层;
|
|||
|
|
- 收拢业务规则,不再散落到多个 UI 组件和地图引擎实现中;
|
|||
|
|
- 建立稳定的数据模型与类型定义。
|
|||
|
|
|
|||
|
|
### 7.2 性能目标
|
|||
|
|
|
|||
|
|
- 首屏只加载必要图层;
|
|||
|
|
- 选中图层优先加载,未选中图层延后或懒加载;(待考虑)
|
|||
|
|
- 图例切换、基地切换、搜索筛选尽量使用索引和差量更新;
|
|||
|
|
- 减少重复递归、重复建图层、重复样式重算。
|
|||
|
|
|
|||
|
|
### 7.3 维护目标
|
|||
|
|
|
|||
|
|
- 新增图层类型、专题规则、图例规则时有固定扩展点;
|
|||
|
|
- 2D/3D 共享统一业务层,底层只替换渲染适配器;
|
|||
|
|
- 可以较容易增加埋点、日志、调试工具和单元测试。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 目标架构设计
|
|||
|
|
|
|||
|
|
建议将地图模块拆分为四层:
|
|||
|
|
|
|||
|
|
## 8.1 视图层
|
|||
|
|
|
|||
|
|
只负责展示和用户交互,不直接编写复杂业务逻辑。
|
|||
|
|
|
|||
|
|
建议保留的组件:
|
|||
|
|
|
|||
|
|
- `GisView.vue`
|
|||
|
|
- `LayerController.vue`
|
|||
|
|
- `MapLegend.vue`
|
|||
|
|
- `MapFilter.vue`
|
|||
|
|
- `BaseLayerSwitcher.vue`
|
|||
|
|
|
|||
|
|
视图层职责:
|
|||
|
|
|
|||
|
|
- 展示树、图例、筛选项、底图切换器;
|
|||
|
|
- 分发用户动作;
|
|||
|
|
- 订阅 Store 派生结果;
|
|||
|
|
- 不直接调用 `map.ol.ts` 里的业务方法。
|
|||
|
|
|
|||
|
|
## 8.2 应用编排层
|
|||
|
|
|
|||
|
|
新增地图编排层,建议命名为:
|
|||
|
|
|
|||
|
|
- `src/modules/map/application/map-orchestrator.ts`
|
|||
|
|
- 或 `src/components/gis/core/orchestrator.ts`
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 承接 UI 动作;
|
|||
|
|
- 统一处理“图层勾选、图例勾选、基地切换、时间筛选、搜索定位、底图切换”等命令;
|
|||
|
|
- 控制加载顺序;
|
|||
|
|
- 根据状态差异驱动地图渲染层;
|
|||
|
|
- 管理互斥规则和特殊规则。
|
|||
|
|
|
|||
|
|
### 推荐模式
|
|||
|
|
|
|||
|
|
所有 UI 动作统一转换成 Command:
|
|||
|
|
|
|||
|
|
- `toggleLayer(layerKey)`
|
|||
|
|
- `toggleLegend(layerKey, legendKey)`
|
|||
|
|
- `switchBaseMap(baseMapKey)`
|
|||
|
|
- `changeBaseRegion(baseId)`
|
|||
|
|
- `changeTimeRange(range)`
|
|||
|
|
- `focusPoint(pointId)`
|
|||
|
|
|
|||
|
|
## 8.3 领域状态层
|
|||
|
|
|
|||
|
|
保留 Pinia,但将当前大 Store 拆分为多个职责明确的 Store / Service:
|
|||
|
|
|
|||
|
|
- `mapConfigStore`
|
|||
|
|
|
|||
|
|
- 保存图层树、图例原始配置、页面配置;
|
|||
|
|
|
|||
|
|
- `mapViewStateStore`
|
|||
|
|
|
|||
|
|
- 保存当前选中图层、选中图例、当前底图、当前基地、当前时间范围、当前缩放级别;
|
|||
|
|
|
|||
|
|
- `mapDataStore`
|
|||
|
|
|
|||
|
|
- 保存锚点缓存、请求状态、加载状态、错误状态;
|
|||
|
|
|
|||
|
|
- `mapRuleEngine`
|
|||
|
|
- 保存互斥规则、派生规则、特殊专题规则。
|
|||
|
|
|
|||
|
|
## 8.4 地图渲染层
|
|||
|
|
|
|||
|
|
保留 `MapClass` 作为统一门面,但将 `MapOl` 拆分成多个 Manager:
|
|||
|
|
|
|||
|
|
- `ol-map-adapter.ts`
|
|||
|
|
|
|||
|
|
- 只负责地图实例生命周期;
|
|||
|
|
|
|||
|
|
- `ol-base-layer-manager.ts`
|
|||
|
|
|
|||
|
|
- 负责 WMTS / XYZ / GeoJSON / 底图切换;
|
|||
|
|
|
|||
|
|
- `ol-point-layer-manager.ts`
|
|||
|
|
|
|||
|
|
- 负责锚点图层创建、更新、索引、显隐;
|
|||
|
|
|
|||
|
|
- `ol-popup-manager.ts`
|
|||
|
|
|
|||
|
|
- 负责 hover / click / popup;
|
|||
|
|
|
|||
|
|
- `ol-region-mask-manager.ts`
|
|||
|
|
|
|||
|
|
- 负责基地裁切、遮罩、点在面内过滤;
|
|||
|
|
|
|||
|
|
- `ol-interaction-manager.ts`
|
|||
|
|
- 负责缩放监听、量算、定位等。
|
|||
|
|
|
|||
|
|
这样做后,`MapOl` 只保留聚合职责,不再直接承载全部细节。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. 详细改造方案
|
|||
|
|
|
|||
|
|
## 9.1 统一领域模型
|
|||
|
|
|
|||
|
|
首先建立类型定义,避免继续依赖 `any`。
|
|||
|
|
|
|||
|
|
建议新增:
|
|||
|
|
|
|||
|
|
- `types/map-layer.ts`
|
|||
|
|
- `types/map-legend.ts`
|
|||
|
|
- `types/map-point.ts`
|
|||
|
|
- `types/map-rule.ts`
|
|||
|
|
|
|||
|
|
### 图层类型建议
|
|||
|
|
|
|||
|
|
- `BaseMapLayer`
|
|||
|
|
- `OverlayLayer`
|
|||
|
|
- `PointLayer`
|
|||
|
|
- `RegionMaskLayer`
|
|||
|
|
- `DynamicLayer`
|
|||
|
|
|
|||
|
|
### 图层运行态建议(待考虑)
|
|||
|
|
|
|||
|
|
将运行态从后端配置中剥离,不再直接把运行态写回原始配置:
|
|||
|
|
|
|||
|
|
- `config`: 后端返回配置,只读;
|
|||
|
|
- `runtime`:
|
|||
|
|
- `visible`
|
|||
|
|
- `loaded`
|
|||
|
|
- `loading`
|
|||
|
|
- `error`
|
|||
|
|
- `featureCount`
|
|||
|
|
- `lastRequestKey`
|
|||
|
|
- `lastUpdatedAt`
|
|||
|
|
|
|||
|
|
## 9.2 统一图层树、图例、地图显隐状态源
|
|||
|
|
|
|||
|
|
建议明确一个唯一状态源:
|
|||
|
|
|
|||
|
|
- 图层是否勾选:只认 `selectedLayerKeys`;
|
|||
|
|
- 图例是否勾选:只认 `selectedLegendKeys`;
|
|||
|
|
- 地图渲染层不再存业务真相,只接收派生后的可见性差量。
|
|||
|
|
|
|||
|
|
### 派生关系建议
|
|||
|
|
|
|||
|
|
- `selectedLayerKeys` -> 派生当前显示的图例组;
|
|||
|
|
- `selectedLayerKeys + selectedLegendKeys + currentBaseId` -> 派生 Feature 可见性;
|
|||
|
|
- `selectedBaseMapKey` -> 派生当前底图组合;
|
|||
|
|
- `timeRange + filterConditions` -> 派生图层请求签名。
|
|||
|
|
|
|||
|
|
## 9.3 建立图层索引与图例索引
|
|||
|
|
|
|||
|
|
为提升速度,初始化配置后立即建立索引:
|
|||
|
|
|
|||
|
|
- `layerByKey`
|
|||
|
|
- `legendByNameEn`
|
|||
|
|
- `legendByLayerCode`
|
|||
|
|
- `childrenByParentKey`
|
|||
|
|
- `layerDescendantsByKey`
|
|||
|
|
- `featureIndexByLayerAndLegendKey`
|
|||
|
|
|
|||
|
|
### 优化收益
|
|||
|
|
|
|||
|
|
- 避免每次 `findLayerByKey()` 递归;
|
|||
|
|
- 图例切换时直接定位对应图层和对应 feature 集合;
|
|||
|
|
- 图层树勾选联动时只处理差异节点。
|
|||
|
|
|
|||
|
|
## 9.4 抽离请求解析器
|
|||
|
|
|
|||
|
|
当前 `GisUrlList.ts` 的匹配逻辑散落在 `loadLayerData()` 中,建议拆出:
|
|||
|
|
|
|||
|
|
- `map-layer-request-resolver.ts`
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 根据 `layer.key` / `layer.title` / `layer.url` 解析真实请求;
|
|||
|
|
- 生成标准请求结构:
|
|||
|
|
- `url`
|
|||
|
|
- `method`
|
|||
|
|
- `filter`
|
|||
|
|
- `sort`
|
|||
|
|
- `cacheKey`
|
|||
|
|
|
|||
|
|
### 进一步建议
|
|||
|
|
|
|||
|
|
- 在应用启动时将 `GisUrlList.ts` 预编译成多索引字典;
|
|||
|
|
- 不要在每次 `loadLayerData()` 内重新构建 `urlListDict`;
|
|||
|
|
- 请求签名应真正参与去重和缓存。
|
|||
|
|
|
|||
|
|
## 9.5 重新设计锚点加载策略(待考虑)
|
|||
|
|
|
|||
|
|
建议从“全量预加载”改为“分层加载”:
|
|||
|
|
|
|||
|
|
### 第一阶段
|
|||
|
|
|
|||
|
|
- 首屏只加载默认勾选图层;
|
|||
|
|
- 图例也只基于已加载的默认勾选图层生成;
|
|||
|
|
|
|||
|
|
### 第二阶段(待考虑)
|
|||
|
|
|
|||
|
|
- 对常用图层做后台低优先级预取;
|
|||
|
|
- 非常规图层在首次勾选时再加载;
|
|||
|
|
|
|||
|
|
### 第三阶段(待考虑)
|
|||
|
|
|
|||
|
|
- 对时间敏感或高频筛选图层使用缓存失效策略:
|
|||
|
|
- `cacheKey = layerKey + requestSignature`
|
|||
|
|
- 基于时间范围、基地、专题条件生成。
|
|||
|
|
|
|||
|
|
### 配套措施(待考虑)
|
|||
|
|
|
|||
|
|
- 增加并发控制,例如同时最多 4 到 6 个接口请求;
|
|||
|
|
- 增加可取消请求,避免菜单切换时旧请求回写新页面;
|
|||
|
|
- 记录每个图层单独 loading 和 error 状态。
|
|||
|
|
|
|||
|
|
## 9.6 重构点图层渲染管理
|
|||
|
|
|
|||
|
|
建议将点图层改造成“图层级管理 + 索引级更新”模式。
|
|||
|
|
|
|||
|
|
### 当前问题
|
|||
|
|
|
|||
|
|
- 图例点击靠遍历全量 feature;
|
|||
|
|
- 基地裁切靠遍历全量 feature;
|
|||
|
|
- hover 时所有点图层都重绘。
|
|||
|
|
|
|||
|
|
### 改造建议
|
|||
|
|
|
|||
|
|
在 `PointLayerManager` 中维护以下索引:
|
|||
|
|
|
|||
|
|
- `featuresByLayerKey`
|
|||
|
|
- `featuresByLegendKey`
|
|||
|
|
- `featuresByBaseId`
|
|||
|
|
- `featureById`
|
|||
|
|
|
|||
|
|
### 改造后的显隐策略
|
|||
|
|
|
|||
|
|
- 图例点击时,只处理该图例对应 feature 集合;
|
|||
|
|
- 基地切换时,优先按 `baseId` 做粗筛,再对边界交叉区域做点在面内判断;
|
|||
|
|
- 图层勾选时只切换对应 `VectorLayer.visible`;
|
|||
|
|
- 非必要不重新 `addFeatures()`。
|
|||
|
|
|
|||
|
|
### 样式策略建议
|
|||
|
|
|
|||
|
|
- 保留 style function,但减少在 style function 内做复杂业务判断;
|
|||
|
|
- 将 `_legendVisible`、`_regionVisible`、`_layerVisible` 预先计算为单个 `renderVisible` 标记;
|
|||
|
|
- 样式函数只做:
|
|||
|
|
- 是否可见;
|
|||
|
|
- 当前缩放级别;
|
|||
|
|
- 当前 hover 状态;
|
|||
|
|
- 图标与文本样式计算。
|
|||
|
|
|
|||
|
|
## 9.7 底图与叠加层管理重构(待考虑)
|
|||
|
|
|
|||
|
|
建议明确区分三类图层:
|
|||
|
|
|
|||
|
|
- 主底图:矢量 / 地形 / 影像三选一;
|
|||
|
|
- 基础叠加层:自然保护区、行政边界等可附加;
|
|||
|
|
- 专题锚点层:水电工程、生态流量、水质站、视频站等。
|
|||
|
|
|
|||
|
|
### 当前问题
|
|||
|
|
|
|||
|
|
- 底图切换会 remove / add `customBaseLayer`;
|
|||
|
|
- 主底图和叠加底图概念混杂;
|
|||
|
|
- `controlBaseLayerTreeShowAndHidden()` 实际控制的不全是底图。
|
|||
|
|
|
|||
|
|
### 改造建议
|
|||
|
|
|
|||
|
|
- 维护 `currentBaseMapKey`;
|
|||
|
|
- 主底图预创建,切换时只改 visible;
|
|||
|
|
- 叠加层作为独立 overlay 管理;
|
|||
|
|
- 自然保护区等图层明确归类为 overlay,不与主底图复用同一逻辑。
|
|||
|
|
|
|||
|
|
## 9.8 图例模块重构
|
|||
|
|
|
|||
|
|
建议把“图例结构”和“图例选中态”彻底分离:
|
|||
|
|
|
|||
|
|
- `legendSchema`: 后端原始图例树;
|
|||
|
|
- `legendVisibleTree`: 根据当前图层选择派生;
|
|||
|
|
- `legendCheckedSet`: 当前选中的图例 key 集。
|
|||
|
|
|
|||
|
|
### 这样做的好处
|
|||
|
|
|
|||
|
|
- 后端原始图例树不再被运行态污染;
|
|||
|
|
- 图例点击只更新 `legendCheckedSet`;
|
|||
|
|
- 图层变化只重算当前显示哪些图例,不直接修改原始结构;
|
|||
|
|
- 更容易实现“重置图例”、“记忆用户图例偏好”。
|
|||
|
|
|
|||
|
|
## 9.9 基地裁切与区域过滤重构
|
|||
|
|
|
|||
|
|
建议将基地逻辑完全收口到 `RegionMaskManager`。
|
|||
|
|
|
|||
|
|
### 改造重点
|
|||
|
|
|
|||
|
|
- 缓存基地 GeoJSON;
|
|||
|
|
- 一次解析边界,多次复用;
|
|||
|
|
- 对点位先按 `baseId` 粗筛,再按 polygon 精筛;
|
|||
|
|
- 避免每次基地切换都重新请求已缓存边界;
|
|||
|
|
- 底图遮罩和锚点区域过滤使用同一份区域上下文。
|
|||
|
|
|
|||
|
|
### 进一步优化
|
|||
|
|
|
|||
|
|
- 若后端能返回基地与锚点的归属关系,可优先直接按 `baseId` 过滤;
|
|||
|
|
- 点在面内判断只作为兜底校验;
|
|||
|
|
- 对非常大的多边形可预处理 bbox,先做 bbox 命中,再做射线法。 -
|
|||
|
|
- 有一个 baseID 来传值 直接请求接口数据加载
|
|||
|
|
- const url = this.hydropBaseConfig.geojson_url + `&cql_filter=BASEID='${this.BASEID}'`; console.log('正在请求裁切数据:', url);
|
|||
|
|
|
|||
|
|
// 等待数据加载
|
|||
|
|
const geoJsonData = await this.loadGeoJsonData(url);
|
|||
|
|
|
|||
|
|
## 9.10 Popup 与交互重构
|
|||
|
|
|
|||
|
|
建议将 Popup 逻辑从 `MapOl` 中抽离:
|
|||
|
|
|
|||
|
|
- `PopupManager` 负责:
|
|||
|
|
- hover 命中检测;
|
|||
|
|
- popup 位置;
|
|||
|
|
- popup 内容渲染;
|
|||
|
|
- click 详情回调;
|
|||
|
|
|
|||
|
|
### 优化方向
|
|||
|
|
|
|||
|
|
- 命中检测尽量只针对当前可见的点图层;
|
|||
|
|
- 对 hover 更新增加最小移动阈值;
|
|||
|
|
- 只重绘当前命中 feature 所在图层,而不是所有点图层;
|
|||
|
|
- Popup 内容生成应支持模板注册,不直接在地图层拼接业务 HTML。
|
|||
|
|
|
|||
|
|
## 9.11 业务规则引擎化
|
|||
|
|
|
|||
|
|
建议把分散的特殊规则抽到统一规则层。
|
|||
|
|
|
|||
|
|
### 当前应纳入规则引擎的规则
|
|||
|
|
|
|||
|
|
- 视频监控站与 AI 视频监控站互斥;
|
|||
|
|
- 环保设施与环保设施在建互斥;
|
|||
|
|
- 珍稀鱼类与沿程鱼类互斥;
|
|||
|
|
- 环保设施图例自动补充;
|
|||
|
|
- 水电开发状况菜单的缩放级别动态图层;
|
|||
|
|
- 水质断面多接口拼接;
|
|||
|
|
- 生态流量三级数据结构处理。
|
|||
|
|
|
|||
|
|
### 建议实现方式
|
|||
|
|
|
|||
|
|
定义规则接口:
|
|||
|
|
|
|||
|
|
```ts
|
|||
|
|
interface MapBusinessRule {
|
|||
|
|
id: string;
|
|||
|
|
when(context: RuleContext): boolean;
|
|||
|
|
apply(context: RuleContext): RulePatch;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
这样新增业务时只加规则文件,不再继续往组件和 Store 塞判断。
|
|||
|
|
|
|||
|
|
## 9.12 组件层改造建议
|
|||
|
|
|
|||
|
|
### `GisView.vue`
|
|||
|
|
|
|||
|
|
- 只保留地图容器、初始化、模块挂载;
|
|||
|
|
- 配置请求交给 `mapOrchestrator.initialize(pageKey)`;
|
|||
|
|
- 菜单切换、基地切换也只发送命令。
|
|||
|
|
|
|||
|
|
### `LayerController.vue`
|
|||
|
|
|
|||
|
|
- 只处理树控件展示与事件抛出;
|
|||
|
|
- 互斥逻辑不要写在组件中;
|
|||
|
|
- 初始底图加载不要放在组件 watch 里,改到编排层统一处理。
|
|||
|
|
|
|||
|
|
### `MapLegend.vue`
|
|||
|
|
|
|||
|
|
- 只负责展示图例树和发出切换事件;
|
|||
|
|
- 不直接调用 `mapClass`。
|
|||
|
|
|
|||
|
|
### `MapFilter.vue`
|
|||
|
|
|
|||
|
|
- 搜索、容量、时间、基地变化全部改为发送标准命令;
|
|||
|
|
- 过滤后的锚点候选列表由 Store 派生,不在组件里自行拼装业务逻辑。
|
|||
|
|
|
|||
|
|
### `BaseLayerSwitcher.vue`
|
|||
|
|
|
|||
|
|
- 只负责切换主底图;
|
|||
|
|
- 不关心图层树中 `customBaseLayer` 的内部结构。
|
|||
|
|
|
|||
|
|
## 9.13 日志、监控与调试能力(待考虑)
|
|||
|
|
|
|||
|
|
建议补充以下调试能力:
|
|||
|
|
|
|||
|
|
- 图层加载耗时;
|
|||
|
|
- 单图层接口耗时;
|
|||
|
|
- 首屏加载耗时;
|
|||
|
|
- 当前可见图层列表;
|
|||
|
|
- 当前可见锚点数量;
|
|||
|
|
- 当前选中图例数量;
|
|||
|
|
- 当前缓存命中率;
|
|||
|
|
- 当前基地裁切耗时。
|
|||
|
|
|
|||
|
|
可以在开发模式下提供一个简易的地图调试面板,便于排查性能与状态同步问题。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. 分阶段落地方案
|
|||
|
|
|
|||
|
|
建议采用“四阶段渐进式改造”,避免一次性大改导致风险过高。
|
|||
|
|
|
|||
|
|
## 第 1 阶段:收口现状与止血
|
|||
|
|
|
|||
|
|
目标:不改变功能表现,先把明显风险收口。
|
|||
|
|
|
|||
|
|
建议内容:
|
|||
|
|
|
|||
|
|
- 去掉测试遗留逻辑,如 `splice(0, 2)`;
|
|||
|
|
- 修复未定义方法和未定义变量;
|
|||
|
|
- 清理重复日志、无效代码、注释垃圾;
|
|||
|
|
- 补充类型定义;
|
|||
|
|
- 建立 `layerByKey`、`legendByNameEn` 等基础索引;
|
|||
|
|
- 将互斥规则从组件内搬到 Store 或规则层统一处理;
|
|||
|
|
- 实现真实请求去重和请求取消。
|
|||
|
|
|
|||
|
|
## 第 2 阶段:拆 Store 与编排层
|
|||
|
|
|
|||
|
|
目标:建立单向数据流。
|
|||
|
|
|
|||
|
|
建议内容:
|
|||
|
|
|
|||
|
|
- 新增 `mapOrchestrator`;
|
|||
|
|
- 拆 `map.ts` 为配置、状态、数据三个模块;
|
|||
|
|
- UI 组件只发送命令;
|
|||
|
|
- 图例派生、图层派生、筛选派生全部收口到编排层。
|
|||
|
|
|
|||
|
|
## 第 3 阶段:拆地图渲染层
|
|||
|
|
|
|||
|
|
目标:把 `MapOl` 大文件拆开。
|
|||
|
|
|
|||
|
|
建议内容:
|
|||
|
|
|
|||
|
|
- 抽 `BaseLayerManager`;
|
|||
|
|
- 抽 `PointLayerManager`;
|
|||
|
|
- 抽 `PopupManager`;
|
|||
|
|
- 抽 `RegionMaskManager`;
|
|||
|
|
- 明确地图引擎层只负责“渲染执行”,不处理业务真相。
|
|||
|
|
|
|||
|
|
## 第 4 阶段:性能强化与能力扩展
|
|||
|
|
|
|||
|
|
目标:让模块适合长期迭代。
|
|||
|
|
|
|||
|
|
建议内容:
|
|||
|
|
|
|||
|
|
- 实现懒加载与后台预取;
|
|||
|
|
- feature 索引化;
|
|||
|
|
- 地图交互性能优化;
|
|||
|
|
- 支持规则插件化;
|
|||
|
|
- 补充测试与性能指标看板;
|
|||
|
|
- 为 3D 共用业务层做适配。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. 推荐目录结构
|
|||
|
|
|
|||
|
|
建议重构后目录大致如下:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
src/
|
|||
|
|
modules/
|
|||
|
|
map/
|
|||
|
|
application/
|
|||
|
|
map-orchestrator.ts
|
|||
|
|
map-commands.ts
|
|||
|
|
map-rule-engine.ts
|
|||
|
|
domain/
|
|||
|
|
types/
|
|||
|
|
map-layer.ts
|
|||
|
|
map-legend.ts
|
|||
|
|
map-point.ts
|
|||
|
|
map-filter.ts
|
|||
|
|
services/
|
|||
|
|
layer-request-resolver.ts
|
|||
|
|
legend-deriver.ts
|
|||
|
|
layer-deriver.ts
|
|||
|
|
infrastructure/
|
|||
|
|
stores/
|
|||
|
|
map-config.store.ts
|
|||
|
|
map-view-state.store.ts
|
|||
|
|
map-data.store.ts
|
|||
|
|
repositories/
|
|||
|
|
map-config.repository.ts
|
|||
|
|
map-point.repository.ts
|
|||
|
|
render/
|
|||
|
|
map.class.ts
|
|||
|
|
ol/
|
|||
|
|
ol-map-adapter.ts
|
|||
|
|
ol-base-layer-manager.ts
|
|||
|
|
ol-point-layer-manager.ts
|
|||
|
|
ol-popup-manager.ts
|
|||
|
|
ol-region-mask-manager.ts
|
|||
|
|
ol-interaction-manager.ts
|
|||
|
|
components/
|
|||
|
|
gis/
|
|||
|
|
GisView.vue
|
|||
|
|
mapController/
|
|||
|
|
LayerController.vue
|
|||
|
|
mapLegend/
|
|||
|
|
index.vue
|
|||
|
|
mapFilter/
|
|||
|
|
index.vue
|
|||
|
|
BaseLayerSwitcher/
|
|||
|
|
index.vue
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 12. 重点业务的改造策略
|
|||
|
|
|
|||
|
|
## 12.1 基础图层
|
|||
|
|
|
|||
|
|
策略:
|
|||
|
|
|
|||
|
|
- 单独定义主底图与叠加图层;
|
|||
|
|
- 预创建主底图;
|
|||
|
|
- 切换时仅改 visible;
|
|||
|
|
- `customBaseLayer` 不再作为特殊魔法 key 到处透传。
|
|||
|
|
|
|||
|
|
## 12.2 水电工程锚点
|
|||
|
|
|
|||
|
|
策略:
|
|||
|
|
|
|||
|
|
- 作为标准 `PointLayer` 处理;
|
|||
|
|
- 保留当前图标、标签、距离阈值、Popup 规则;
|
|||
|
|
- 在 `PointLayerManager` 中建立 feature 索引。
|
|||
|
|
|
|||
|
|
## 12.3 生态流量三级数据
|
|||
|
|
|
|||
|
|
策略:
|
|||
|
|
|
|||
|
|
- 在领域层定义树结构转换器;
|
|||
|
|
- Store 不直接关心层级深浅;
|
|||
|
|
- 图层树组件只拿已经标准化后的树。
|
|||
|
|
|
|||
|
|
## 12.4 水质监测断面三接口拼接
|
|||
|
|
|
|||
|
|
策略:
|
|||
|
|
|
|||
|
|
- 不在 UI 或 Store 中散写拼接逻辑;
|
|||
|
|
- 建立专题数据聚合器,例如 `water-quality-point-aggregator.ts`;
|
|||
|
|
- 对外输出统一的 `PointLayerData`。
|
|||
|
|
|
|||
|
|
## 12.5 视频监控站与 AI 视频监控站互斥
|
|||
|
|
|
|||
|
|
策略:
|
|||
|
|
|
|||
|
|
- 写成标准业务规则;
|
|||
|
|
- 由规则引擎统一裁剪勾选结果;
|
|||
|
|
- UI 不再内嵌业务互斥判断。
|
|||
|
|
|
|||
|
|
## 12.6 自然保护区与区域底图
|
|||
|
|
|
|||
|
|
策略:
|
|||
|
|
|
|||
|
|
- 统一归类为 `OverlayLayer`;
|
|||
|
|
- 与主底图切换分离;
|
|||
|
|
- 与基地裁切共享区域上下文。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 13. 测试与验收建议
|
|||
|
|
|
|||
|
|
## 13.1 功能验收清单
|
|||
|
|
|
|||
|
|
- 页面首次进入,默认勾选图层正确显示;
|
|||
|
|
- 图层树勾选与取消勾选,地图表现与图例表现一致;
|
|||
|
|
- 图例点击后,仅影响对应锚点;
|
|||
|
|
- 基地切换后,区域外锚点正确隐藏;
|
|||
|
|
- 底图切换不影响锚点和图例状态;
|
|||
|
|
- 时间筛选后相关图层正确重载;
|
|||
|
|
- 视频监控站与 AI 视频监控站互斥稳定;
|
|||
|
|
- 菜单切换后图层、图例、筛选项正确重置;
|
|||
|
|
- 悬停 Popup 与点击详情正常。
|
|||
|
|
|
|||
|
|
## 13.2 性能验收指标
|
|||
|
|
|
|||
|
|
建议至少跟踪:
|
|||
|
|
|
|||
|
|
- 首屏地图可交互时间;
|
|||
|
|
- 默认勾选图层加载总耗时;
|
|||
|
|
- 单图层首次加载耗时;
|
|||
|
|
- 图层勾选后锚点出现时间;
|
|||
|
|
- 图例点击后的显隐响应时间;
|
|||
|
|
- 基地切换后的裁切完成时间;
|
|||
|
|
- 缓存命中率;
|
|||
|
|
- 页面切换时旧请求是否被取消。
|
|||
|
|
|
|||
|
|
## 13.3 自动化测试建议
|
|||
|
|
|
|||
|
|
建议补充三类测试:
|
|||
|
|
|
|||
|
|
- 单元测试:
|
|||
|
|
|
|||
|
|
- 图例派生;
|
|||
|
|
- 图层互斥规则;
|
|||
|
|
- 请求解析器;
|
|||
|
|
- 缓存 key 生成;
|
|||
|
|
|
|||
|
|
- 集成测试:
|
|||
|
|
|
|||
|
|
- 图层勾选 -> 图例变化 -> 地图显隐;
|
|||
|
|
- 基地切换 -> 区域裁切 -> 搜索列表更新;
|
|||
|
|
|
|||
|
|
- 端到端测试:
|
|||
|
|
- 地图初始化;
|
|||
|
|
- 图层切换;
|
|||
|
|
- 图例切换;
|
|||
|
|
- 筛选联动;
|
|||
|
|
- Popup 和详情弹窗。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 14. 优先级最高的首批改造项
|
|||
|
|
|
|||
|
|
如果本轮改造只做最有价值的一批,建议优先按以下顺序处理:
|
|||
|
|
|
|||
|
|
1. 修复明显问题:
|
|||
|
|
|
|||
|
|
- 去掉 `splice(0, 2)`;
|
|||
|
|
- 修复 `fetchPointData()` 未定义;
|
|||
|
|
- 修复 `wq_lineTime` / `wt_lineTime` 未定义;
|
|||
|
|
- 清理无效代码与重复日志。
|
|||
|
|
|
|||
|
|
2. 建立统一状态源:
|
|||
|
|
|
|||
|
|
- `selectedLayerKeys`
|
|||
|
|
- `selectedLegendKeys`
|
|||
|
|
- `currentBaseId`
|
|||
|
|
- `currentBaseMapKey`
|
|||
|
|
|
|||
|
|
3. 抽离请求解析器和规则引擎:
|
|||
|
|
|
|||
|
|
- URL 映射规则统一;
|
|||
|
|
- 互斥规则统一;
|
|||
|
|
- 特殊图例补充规则统一。
|
|||
|
|
|
|||
|
|
4. 拆 `map.ts`:
|
|||
|
|
|
|||
|
|
- 配置状态;
|
|||
|
|
- 运行状态;
|
|||
|
|
- 数据缓存;
|
|||
|
|
- 行为编排。
|
|||
|
|
|
|||
|
|
5. 拆 `map.ol.ts`:
|
|||
|
|
- 底图管理;
|
|||
|
|
- 锚点管理;
|
|||
|
|
- Popup 管理;
|
|||
|
|
- 区域裁切管理。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 15. 改造后的预期收益
|
|||
|
|
|
|||
|
|
完成改造后,地图模块应达到以下效果:
|
|||
|
|
|
|||
|
|
- 新增图层和专题能力时,不需要修改多个组件和多个文件;
|
|||
|
|
- 图层树、图例、地图显隐的状态不再互相打架;
|
|||
|
|
- 首屏加载更快,图层切换更轻;
|
|||
|
|
- 地图代码从“堆逻辑”变成“可扩展的稳定结构”;
|
|||
|
|
- 后续增加 3D 共用逻辑、专题聚合图层、更多筛选条件时,改造成本明显下降。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 16. 结论
|
|||
|
|
|
|||
|
|
当前地图模块功能已经较完整,但代码结构处于“功能可用、结构偏重、规则分散、性能隐患较多”的阶段。继续在现有结构上叠加新需求,后续维护成本会快速上升。
|
|||
|
|
|
|||
|
|
建议本次改造不要只做局部优化,而应围绕以下核心原则整体推进:
|
|||
|
|
|
|||
|
|
- 单向数据流;
|
|||
|
|
- 业务规则收口;
|
|||
|
|
- 渲染层职责下沉;
|
|||
|
|
- 类型与索引先行;
|
|||
|
|
- 先止血,再拆层,再提速。
|
|||
|
|
|
|||
|
|
按照本文档的分阶段方案推进,可以在不一次性推翻现有功能的前提下,逐步完成地图模块的结构升级。
|