全过程数据管理子系统

This commit is contained in:
王兴凯 2026-07-20 16:02:51 +08:00
parent 2f0bc9f67d
commit 0aa99bcde6
482 changed files with 138263 additions and 1273 deletions

View File

@ -0,0 +1,15 @@
# http://editorconfig.org
root = true
[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_style = space # 缩进风格tab | space
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
trim_trailing_whitespace = true # 去除行首的任意空白字符
insert_final_newline = true # 始终在文件末尾插入一个新行
[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off
trim_trailing_whitespace = false

View File

@ -0,0 +1,22 @@
## 开发环境
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
NODE_ENV='development'
VITE_APP_TITLE = '全过程数据管理子系统'
VITE_APP_PORT = 5000
VITE_APP_BASE_API = '/dev-api'
# 本地环境
VITE_APP_BASE_URL = 'http://localhost:8093'
# 测试环境
# VITE_APP_BASE_URL = 'http://172.16.21.142:8093'
# 汤伟
VITE_APP_BASE_URL = 'http://10.84.111.235:8093'
# 李林
# VITE_APP_BASE_URL = 'http://10.84.111.25:8093'
## 开发环境 附件服务地址
VITE_APP_ATTACHMENT_URL = 'https://211.99.26.225:12125'
# 地图服务地址
VITE_APP_MAP_URL = 'https://211.99.26.225:18085'
# ?menu=systemManageMenu&page=disposeManage

View File

@ -0,0 +1,14 @@
## 生产环境
NODE_ENV='production'
VITE_APP_TITLE = 'qgc-buji-web'
VITE_APP_PORT = 5000
VITE_APP_BASE_API = '/prod-api'
## 生产环境API地址
VITE_APP_BASE_URL = 'http://localhost:8093'
## 生产环境导入预览地址
VITE_APP_BASE_API_URL = 'https://211.99.26.225:12130/prod-api'
## 生产环境 附件服务地址
VITE_APP_ATTACHMENT_URL = 'https://211.99.26.225:12125'
# 地图服务地址
VITE_APP_MAP_URL = 'https://211.99.26.225:18085'

View File

@ -0,0 +1,6 @@
## 模拟环境
NODE_ENV='staging'
VITE_APP_TITLE = 'qgc-buji-web'
VITE_APP_PORT = 3000
VITE_APP_BASE_API = '/prod--api'

View File

@ -0,0 +1,16 @@
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
.eslintrc.js
prettier.config.js
src/assets

View File

@ -0,0 +1,33 @@
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
globals: {
defineProps: 'readonly',
defineEmits: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly',
DialogType: "readonly",
OptionType: "readonly",
},
parser: 'vue-eslint-parser',
extends: [
'eslint:recommended',
'plugin:vue/vue3-essential',
'plugin:@typescript-eslint/recommended'
],
parserOptions: {
ecmaVersion: 'latest',
parser: '@typescript-eslint/parser',
sourceType: 'module'
},
plugins: ['vue', '@typescript-eslint'],
rules: {
'vue/multi-word-component-names': 'off',
'@typescript-eslint/no-empty-function': 'off', // 关闭空方法检查
'@typescript-eslint/no-explicit-any': 'off', // 关闭any类型的警告
'vue/no-v-model-argument': 'off'
}
};

17
frontend-sjgl/.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
yarn.lock

View File

@ -0,0 +1,4 @@
{
"permissions": {},
"outputStyle": "Vibe"
}

5
frontend-sjgl/.npmrc Normal file
View File

@ -0,0 +1,5 @@
registry=https://registry.npmmirror.com
fetch-retries=5
strict-peer-dependencies=false
# 添加 Node.js 内存配置
node-options=--max-old-space-size=4096

View File

@ -0,0 +1,9 @@
/dist/*
.local
.output.js
/node_modules/**
**/*.svg
**/*.sh
/public/*

View File

@ -0,0 +1,36 @@
/**
* 代码格式化配置
*/
module.exports = {
// 指定每个缩进级别的空格数
tabWidth: 2,
// 使用制表符而不是空格缩进行
useTabs: false,
// 在语句末尾打印分号
semi: true,
// 使用单引号而不是双引号
singleQuote: true,
// 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>"
quoteProps: 'as-needed',
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>"默认none
trailingComma: 'none',
// 在对象文字中的括号之间打印空格
bracketSpacing: true,
// 在单独的箭头函数参数周围包括括号 always(x) => x \ avoidx => x
arrowParens: 'avoid',
// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
rangeStart: 0,
rangeEnd: Infinity,
// 指定要使用的解析器,不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 换行设置 always\never\preserve
proseWrap: 'never',
// 指定HTML文件的全局空格敏感度 css\strict\ignore
htmlWhitespaceSensitivity: 'css',
// Vue文件脚本和样式标签缩进
vueIndentScriptAndStyle: false,
// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>"
endOfLine: 'lf',
};

21
frontend-sjgl/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 有来开源组织
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,26 @@
module.exports = {
// 继承的规则
extends: ['@commitlint/config-conventional'],
// 定义规则类型
rules: {
// type 类型定义,表示 git 提交的 type 必须在以下类型范围内
'type-enum': [
2,
'always',
[
'feat', // 新功能 feature
'fix', // 修复 bug
'docs', // 文档注释
'style', // 代码格式(不影响代码运行的变动)
'refactor', // 重构(既不增加新功能也不是修复bug)
'perf', // 性能优化
'test', // 增加测试
'chore', // 构建过程或辅助工具的变动
'revert', // 回退
'build' // 打包
]
],
// subject 大小写不做校验
'subject-case': [0]
}
};

View File

@ -0,0 +1,479 @@
# 地图模块 3D Cesium 实施计划
## 1. 目标
在现有地图体系下补齐 `3D(Cesium)` 视图能力,使其尽量复用 `2D(OpenLayers)` 的业务编排结果,满足以下要求:
- 3D 默认进入中国视角,不再落到美国区域。
- 3D 初始化时显示过渡动画,再定位到中国。
- 3D 保留基础底图加载能力,但不提供底图切换面板。
- 3D 支持锚点展示。
- 3D 支持与 2D 一致的鼠标悬停 popup样式复用现有 popup。
- 3D 支持与 2D 一致的锚点点击行为,点击后打开同一套详情弹框逻辑。
- 菜单切换、图层树勾选、图例勾选后3D 锚点与 2D 一样联动变化。
- 3D 必须复用 `eng_point` 的层级显示规则,中型水电站仅在 `ENG_POINT_MEDIUM_VISIBLE_ZOOM = 7.5` 以上显示。
## 2. 2D 现状梳理
当前 `2D` 的能力并不是散落在页面里,而是已经形成了比较清晰的分层:
### 2.1 页面入口
- `src/components/gis/GisView.vue`
- 负责挂载地图容器、popup 容器、地图控制器、图例、图层树。
- 页面只调用 `mapOrchestrator.mountView()``handlePageChange()`,不直接拼地图业务。
### 2.2 地图编排层
- `src/modules/map/application/map-orchestrator.ts`
- 负责页面初始化、菜单切换、图层配置加载、图例配置加载、基地切换、缩放联动。
- 2D/3D 都应尽量复用这一层,避免在 Cesium 侧另起一套业务流程。
### 2.3 地图统一门面
- `src/components/gis/map.class.ts`
- 对外暴露统一接口,如:
- `addBaseDataLayer`
- `addInitDataLayer`
- `mdLayerTreeShowOrHidden`
- `setLegendPointVisible`
- `controlBaseLayerTreeShowAndHidden`
- `initPopupOverlay`
- `flyTopanto`
- 业务层只认这套接口,不应感知底层是 `OpenLayers` 还是 `Cesium`
### 2.4 2D 地图能力落点
- `src/components/gis/map.ol.ts`
- 已实现的关键能力:
- 默认中国视角初始化
- 基础底图加载与切换
- 点位图层注册和显隐
- 图例控制单类锚点显隐
- 鼠标 hover popup
- click 打开详情弹窗
- 基地裁切与底图遮罩
- 缩放/移动后的批量 popup 和标签刷新
### 2.5 2D 锚点与 popup 支撑
- `src/components/gis/ol/point-layer-manager.ts`
- 负责将点位数据转成地图要素、分层、索引、图例显隐。
- `src/components/gis/ol/popup-manager.ts`
- 负责 hover 命中、popup DOM 内容复用、批量 popup。
### 2.6 图层树和图例交互
- `src/components/mapController/LayerController.vue`
- 图层树勾选后走 `mapOrchestrator.applyLayerSelection()`
- `src/components/mapLegend/index.vue`
- 图例点击后走 `mapOrchestrator.toggleLegend()` / `toggleLegendBatch()`
- `src/store/modules/map.ts`
- 真正把缓存数据、图层状态、图例状态应用到地图实例
- 也就是说,`3D` 只要把统一接口补齐,就能直接接住现有业务流
### 2.7 2D 已有特殊业务规则
- 锚点点击逻辑已在 `src/components/gis/map.ol.ts` 实现:
- 命中锚点后,`ylfb` 走 `ylfbModalVisible`
- 其他锚点走 `modalVisible`
- 标题和参数都直接取当前锚点数据
- `eng_point` 的中型水电站显示阈值已在现有链路中实现:
- 阈值常量位于 `src/modules/map/application/map-orchestrator.ts`
- 过滤逻辑位于 `src/store/modules/map.ts``filterPointLayerDataForDisplay()`
- `3D` 不应重新发明一套规则,而应复用这套现有过滤结果
- 部分点位会随着缩放级别提升显示得更多,不是简单的“图层开/关”:
- `eng_point` 的中型电站要到 `ENG_POINT_MEDIUM_VISIBLE_ZOOM = 7.5` 以上才显示
- 水电开发页在缩放跨过 `12` 级时会自动补开一批动态图层
- `2D` 内部还存在点位密度阈值、近邻点展开、批量 popup 阈值等缩放联动规则
- `2D` 对锚点存在碰撞检测与密度控制,不是所有点始终全量显示:
- 图标和标签会分别经过碰撞计算
- 低缩放下会因为密度、碰撞、区域裁切、图例状态而隐藏部分点
- 高缩放下会逐步放开限制,显示更多锚点和标签
## 3. 3D 当前现状与缺口
### 3.1 已有内容
- `src/components/gis/map.cesium.ts`
- 当前只完成了最小化 `Cesium.Viewer` 初始化。
- 已有基础缩放、截图、`flyTopanto()` 雏形。
### 3.2 当前主要缺口
- `init()` 里虽然定义了 `flyToChina()`,但没有真正执行,也没有 `resolve(viewer)`,初始化流程不完整。
- 默认底图仍是 ArcGIS 全球影像,因此启动时容易落到美国默认视角。
- `addBaseDataLayer()` 为空,无法接住当前 `GISMap/customBaseLayer` 逻辑。
- `addInitDataLayer()` 为空,无法展示锚点。
- `mdLayerTreeShowOrHidden()` 为空,菜单切换时 3D 锚点不会同步显隐。
- `setLegendPointVisible()` 为空,图例勾选不会影响 3D 锚点。
- `initPopupOverlay()` 为空,无法复用 2D popup 容器。
- 缺少点击命中与详情弹框联动3D 当前无法做到“点击锚点与 2D 同行为”。
- `controlBaseLayerTreeShowAndHidden()` 为空3D 基础底图和叠加层无法受现有图层树控制。
- 尚未验证 `eng_point` 的缩放阈值规则在 3D 下是否能完全复用,存在实现时遗漏中型站点显隐的风险。
- 目前没有承接 `2D` 中“放大到具体层级显示更多锚点”的缩放联动显示机制。
- 目前没有承接 `2D` 中图标/标签的碰撞检测逻辑,后续若直接全量渲染,视觉效果会与 `2D` 明显不一致。
- 当前没有建立 `Cesium entity / datasource / imageryLayer` 的注册表,后续联动无从下手。
## 4. 实施原则
- 不重做业务编排,优先复用 `map-orchestrator.ts``src/store/modules/map.ts`
- 不额外引入一套 3D 专用图例和图层状态,仍以现有 store 为唯一运行态来源。
- 不单独复制 `eng_point` 的中型站显示规则,优先复用现有 `mapStore` 过滤结果。
- 不单独新建一套点击弹框协议,优先保持与 `map.ol.ts` 相同的命中后行为。
- 对“缩放越大显示越多锚点”这类规则,优先复用现有缩放阈值与显示门闩,不做拍脑袋的新规则。
- 对碰撞检测,优先与 `2D` 保持同方向行为:低缩放控量,高缩放放开,而不是 3D 全量堆点。
- 先做最小闭环,再逐步补能力:
- 第一步保证 3D 能正确初始化并定位中国。
- 第二步保证基础底图能显示。
- 第三步保证锚点能显示。
- 第四步保证 popup、图层树、图例联动打通。
- 3D 不做“基础地图切换 UI”但底层仍要支持 `customBaseLayer + addBaseDataLayer(..., true)` 这一逻辑。
## 5. 分步骤实施计划
### Step 1修正 3D 初始化并默认定位中国 ✅️
目标:
- 切到 3D 后稳定初始化 viewer。
- 首屏出现一个轻量加载动画。
- 初始化完成后飞到中国默认视角。
计划:
- 修复 `map.cesium.ts``init()`
- 保证初始化后一定 `resolve(this.viewer)`
- 执行 `flyToChina()`
- 补一个可控的启动过渡动画。
- 统一中国默认参数:
- 中心经纬度建议复用 `104.5, 36.5`
- 相机高度先按全国视角收口,后续再微调
- 如果切回 2D 再切到 3D仍然要能正确重建 viewer。
验收:
- 点击 `3D` 按钮后,不再出现美国默认视角。
- 首屏有加载过渡。
- 进入后稳定落在中国。
### Step 2展示 3D 基础底图 ✅️
目标:
- 3D 不显示空球。
- 保留“基础底图 + 3D 专用底图地址”能力。
- 不提供底图切换面板,但底层能吃现有配置。
计划:
- 在 `MapCesium` 内建立基础图层注册表。
- 实现 `addBaseDataLayer(layer, isShow)`
- 对 `customBaseLayer` 使用 `url_3d`
- 对 `BASEMAP-img`、`BASEMAP-white` 预留兼容能力
- **必须处理 `wmts` 类型图层**2D 通过 `WMTS` source 加载3D 使用 `Cesium.WebMapTileServiceImageryProvider`,从 URL 参数中提取 LAYER/TILEMATRIXSET
- **必须提供 `tileMatrixLabels`**Cesium 默认用纯数字作为 tileMatrix 参数值,但本系统 WMTS 服务器要求 `TileMatrixSet:zoom` 格式(如 `EPSG:3857_hbb_zrbhq_l13:4`)。需构建 `["TileMatrixSet:0", "TileMatrixSet:1", ...]` 传入 `tileMatrixLabels`
- 其他类型:`raster-dem`→XYZ、MapServer→ArcGIS、其余 →WMS
- **注意**:还存在一个 `key = "powerBaseStation"` 的基地底图图层,该图层**初始化时不加载**(已在 `IGNORED_BASE_LAYER_KEYS` 中忽略),但后续可通过图层树手动勾选显示。
- 实现 `controlBaseLayerTreeShowAndHidden()`
- 让图层树勾选能控制 3D 底图显隐
- 根据你的要求UI 层先不开放 `BaseLayerSwitcher` 的 3D 切换行为,只保留默认基础底图加载。
验收:
- 切到 3D 后可稳定看到基础底图。
- 图层初始化时 `addBaseDataLayer(this.baseLayerConfig, checked, true)` 的思路在 3D 可落地。
### Step 3打通 3D 锚点展示 ✅️
目标:
- 3D 能展示和 2D 同源的锚点数据。
- 菜单切换后3D 能跟随页面数据切换。
计划:
- 在 `MapCesium` 内建立点位图层注册结构,按 `layerKey -> entity[]` 管理。
- 实现 `addInitDataLayer(pointData, layerType)`
- 复用当前点位数据结构
- 解析 `lgtd/lttd/iconCode/titleName/stnm/anchoPointState/popupHtml`
- 复用现有图标资源路径
- Entity ID 使用 `${layerKey}:${item._id || `${iconType || 'point'}_${stcd}`}`,与 2D 对齐,确保同 stcd 不同 sttpMap 的点不被覆盖
- 确保 `eng_point` 仍按现有 `mapStore` 过滤后的数据展示,中型站点只在 `7.5` 以上层级出现
- 为后续缩放驱动的增量显示预留运行态字段(`_legendVisible`、`_regionVisible`、`_densityVisible`),不把所有点简单一次性硬渲染
- 实现 `mdLayerTreeShowOrHidden(layerType, checked)`
- 图层树控制整个点图层显隐
- 实现 `removePointLayer()` / `hasLayer()`
- 便于后续页面切换和重载
验收:
- 切到 3D 后当前页默认勾选图层的锚点能显示。
- 切换菜单后3D 锚点跟随变化。
- 取消勾选图层后,对应锚点消失。
- `eng_point` 在低于 `7.5` 时不显示中型水电站,高于 `7.5` 时正常显示。
### Step 4打通 3D 基地裁切jdPanelControlShowAndHidden ✅️
目标:
- 3D 点击基地面板后,与 2D 行为一致。
- 加载基地边界 GeoJSON只显示区域内锚点隐藏区域外锚点。
- 取消基地时恢复显示所有锚点。
计划:
- 在 `MapCesium` 中捕获 `hydropBase` 配置,与 2D 一样在 `addBaseDataLayer` 中记录。
- 实现 `jdPanelControlShowAndHidden(baseid, isAll)`
- `isAll=false`:清除 3D 球面遮罩实体、恢复所有锚点区域可见性、清除裁切状态。
- `isAll=true`:先隐藏所有锚点,异步加载基地边界 GeoJSON执行点在面判断后仅显示区域内锚点同时在球面绘制裁切边界多边形`applyRegionMask`),最后飞行到区域视野。
- 在 `createEntityPropertiesBag` 中新增 `_regionVisible` 属性,初始为 `true`
- 在 `applyPointVisibilityRefresh` 中跳过 `_regionVisible !== false` 的实体,确保裁切后碰撞检测不会把区域外锚点重新显示出来。
- 复用 `extractPolygonCoords` / `isPointInRing` 射线法判断逻辑(与 `region-mask-manager.ts` 一致)。
- 支持 `AbortController` 取消前一次未完成的请求,避免响应顺序错乱。
- `applyRegionMask` 将 GeoJSON 多边形转换为 Cesium `PolygonHierarchy`,在球面绘制半透明填充 + 可见边界的区域多边形,模拟 2D 底图 Canvas 裁切遮罩的视觉效果。
验收:
- 点击基地后3D 只显示该基地区域内的锚点,区域外锚点隐藏。
- 取消基地后,所有锚点恢复正常显示。
- 快速切换基地不会出现旧数据覆盖新数据的问题。
- 多次切换 2D/3D 后基地裁切行为正常。
### Step 5打通 3D popup 与 hover ✅️
目标:
- 3D 鼠标悬停时显示与 2D 一样的 popup。
- popup 样式复用现有 DOM 和样式,不再单独做一版。
计划:
- 实现 `initPopupOverlay(popupContainer)`
- 继续复用 `GisView.vue` 中现有 popup 容器
- 在 Cesium 中增加鼠标移动命中:
- 基于 `ScreenSpaceEventHandler`
- hover 到锚点时读取 entity 附带属性
- popup 内容生成逻辑复用 2D 现有字段:
- 优先使用 `popupHtml`
- 否则走通用字段渲染
- 处理离开锚点时隐藏 popup。
验收:
- 鼠标移入锚点出现 popup。
- 样式和 2D 保持一致。
- 移出后 popup 正常消失。
### Step 6补齐缩放驱动显示与碰撞检测
目标:
- 3D 在低缩放下控制锚点数量,避免全量堆叠。
- 3D 在放大到具体层级后,逐步显示更多锚点。
- 3D 的图标/标签显示效果尽量接近 2D不出现严重遮挡。
计划:
- 先承接现有明确可复用的缩放规则:
- `eng_point``7.5` 阈值
- 水电开发页的 `12` 级动态图层联动
- 再补 3D 侧的显示门闩:
- 低缩放下根据缩放级别、图层状态、图例状态控制 entity 显隐
- 高缩放下逐步放开限制,显示更多锚点
- 为 3D 补一版轻量碰撞控制:
- 至少先控制标签碰撞,避免名称完全叠在一起
- 如有必要,再补图标级碰撞或屏幕网格抽稀
- 明确与 2D 对齐的目标不是“算法完全一样”,而是“视觉行为一致”:
- 低缩放控量
- 高缩放增量显示
- 关键锚点不被完全淹没
验收:
- 3D 在全国视角下不会一次性挤满所有锚点。
- 放大到具体层级后会看到更多锚点逐步出现。
- 标签和锚点不会大面积重叠到不可读。
### Step 7打通 3D 锚点点击详情 ✅️
目标:
- 3D 点击锚点后,行为与 2D 一致。
- 继续复用现有详情弹框状态和参数结构。
计划:
- 在 Cesium 中增加点击命中:
- 基于 `ScreenSpaceEventHandler`
- 命中锚点后读取 entity 绑定的原始业务数据
- 复用 `2D` 当前点击行为:
- `sttpMap === 'ylfb'` 时打开 `ylfbModalVisible`
- 其他锚点打开 `modalVisible`
- `params`、`title` 赋值逻辑与 `map.ol.ts` 保持一致
- 避免 hover popup 与 click 弹框互相干扰。
验收:
- 点击 3D 锚点后可打开与 2D 一致的详情弹框。
- `ylfb` 和普通锚点分支行为一致。
- 点击空白区域不会误触发弹框。
### Step 8打通图例联动 ✅️
目标:
- 图例勾选后3D 只显示对应状态的锚点。
计划:
- 实现 `setLegendPointVisible(layerKey, anchoPointState, checked)`
- 复用 `anchoPointState` 作为图例匹配字段
- entity 级别维护显示状态
- 如果后续需要,也可补一个 3D 版本的图例索引表,避免每次全量遍历。
验收:
- 图例单项勾选/取消时3D 对应类别锚点同步显隐。
- 图例分组勾选/取消时3D 行为与 2D 保持一致。
### Step 9补足收口与稳定性 ✅️
目标:
- 让 3D 能稳定参与现有地图生命周期。
计划:
- 清理 Cesium 事件监听、viewer、entity、datasource避免重复切换内存泄漏。
- 检查 `switchView('2D' | '3D')` 前后 popup、底图、图层注册是否被正确重置。
- 检查 hover、click、图例、图层树、缩放阈值这几条联动链路在 3D 是否完全闭环。
- 视情况补最小诊断日志,确认菜单切换与图层联动没有漏项。
验收:
- 2D/3D 多次来回切换不报错。
- 菜单切换、图层切换、图例切换行为稳定。
## 6. 推荐落地顺序
按你的要求,建议严格按下面顺序推进:
1. 默认定位到中国 + 启动动画
2. 展示基础底图
3. 展示锚点 3.5. 补基地裁切jdPanelControlShowAndHidden
4. 补 hover popup
5. 补缩放驱动显示与碰撞检测
6. 补锚点点击详情
7. 补图层树联动
8. 补图例联动
9. 做切换稳定性收口
## 7. 预计修改文件
- `src/components/gis/map.cesium.ts`
- 3D 地图主体实现,主改动文件
- `src/components/gis/map.class.ts`
- 视情况补齐 2D/3D 切换后 popup 初始化和服务切换细节
- `src/components/gis/GisView.vue`
- 视情况控制 3D 下的底图切换器显示策略、加载态挂载位置
- `src/components/mapController/index.vue`
- 若需要补 3D 初始化后的交互控制
## 8. 当前建议
建议先只做 `Step 1`,也就是:
- 修正 Cesium 初始化完成逻辑
- 增加 3D 启动加载动画
- 默认飞到中国
这一步最小、最容易验证,也能先把“打开 3D 看起来不对”的核心问题解决掉。
## 9. 必须补齐的隐藏逻辑清单
下面这些逻辑不是表面接口能直接看出来的,但如果 `3D` 不补,最终效果就会和 `2D` 明显不一致。
### 9.1 图层与菜单切换 ✅️
- ✅ 菜单切换时,只隐藏旧页点图层,不隐藏底图。(编排器 `handlePageChange` 控制Cesium 被动接收数据)
- ✅ 图层树勾选前要先经过互斥规则归一化store 层 `updateLayerData` 处理Cesium 不感知)
- `rare_fish_point``fish_along_point` 互斥
- `stinfo/stinfo_video_point``stinfo_ai_video_point` 互斥
- `facilities``facilities_built` 两个分支互斥
- ✅ 点图层取消勾选时只隐藏,不删除缓存;重新勾选时优先从缓存恢复。`mdLayerTreeShowOrHidden` 设置 `_layerVisible` 标志,不删除 `pointLayerRegistry` 条目。
- ✅ **图层树勾选时按 `type` 字段走不同分支**(见 `updateLayerData`store 层处理):
- `type === 'pointMap'` → 走 `handlePointMapLayer` → 调用 `mdLayerTreeShowOrHidden`已实现L1624
- `type === 'GISMap'` → 走 `controlBaseLayerTreeShowAndHidden`已实现L1345
- 3D Cesium 已同时实现这两个方法。
### 9.2 图例与点内显隐 ✅️
- ✅ 图例控制的是图层内部锚点是否可见,不是图层本身是否可见。`setLegendPointVisible` 使用 `_legendVisible` 标志,与 `_layerVisible` 独立。
- ✅ 图层恢复显示时,图例要先整层全关,再按当前 checked 状态逐项恢复。支持 `anchoPointState=''` 全关 → 逐项 `(state, true)` 恢复两步模式L1764-1787
- ✅ 环保设施图例组当前是只展示不交互。编排器层面控制Cesium 不感知)
### 9.3 缩放驱动显示 ✅️
- ✅ `eng_point` 的中型水电站只在 `ENG_POINT_MEDIUM_VISIBLE_ZOOM = 7.5` 以上显示。store `filterPointLayerDataForDisplay` 在数据进入 Cesium 前过滤)
- ✅ 水电开发页缩放跨过 `12` 级时,会自动补开一批动态图层;缩回去时再自动收口。(编排器层面处理)
- ✅ `2D` 存在"缩放越大显示越多"的行为。碰撞检测中密度门控逐级放开。
- ✅ `2D` 还存在 hover、批量 popup、密度控制等缩放阈值
- hover 低于 ~zoom 4.5 不触发(`HOVER_POPUP_MAX_HEIGHT = 9_000_000`
- 高缩放进入批量 popup 模式(`BATCH_POPUP_MODE_ZOOM = 14.9`
- 点位随着缩放提升逐步放开密度限制(密度门控 + `DENSITY_ISOLATION_THRESHOLD`
- ✅ **图标动态缩放**`CallbackProperty` 实现 `billboard.scale`,公式 `clamp(0.7 + (zoom - 4.5) * 0.035, 0.4, 1.2)`L1522
- ✅ **字体动态大小**`CallbackProperty` 实现 `label.font`,钳位 `[10, 20]`L1535
- ✅ **文字在图标上方**`CallbackProperty` 实现 `label.pixelOffset`,负 Y 偏移L1549
- ✅ **Cesium 中必须使用 `CallbackProperty` 实现动态缩放**:已使用 3 个 `CallbackProperty`scale/font/offset`isConstant=false` 每帧重算。
### 9.4 锚点碰撞与控量 ✅️
- ✅ `2D` 中锚点是否可见,不只受图层开关控制,还受以下门闩共同影响:
- 图例可见性 `_legendVisible`
- 区域裁切可见性 `_regionVisible`
- 密度阈值(碰撞循环中 inline 计算,逐级放开)
- 图标碰撞结果 `_iconCollisionVisible`
- 标签碰撞结果 `_labelCollisionVisible`
- ✅ 低缩放下,为避免堆叠,部分锚点或标签会被主动隐藏。(`refreshPointLabelVisibility` 碰撞检测L2117-2455
- ✅ 高缩放下,会逐步放开图标/标签限制,显示更多内容。(密度门控 + 碰撞容差随 zoom 调整)
- ✅ 因此 `3D` 不能简单把所有 entity 永久全开。所有 entity 初始 `_iconCollisionVisible = _labelCollisionVisible = true`,碰撞检测运行后动态调整。
### 9.5 Popup 与点击 ✅️
- ✅ hover popup 不是全时开启的,有缩放门槛。相机高度 > `HOVER_POPUP_MAX_HEIGHT` 时不触发 hover。
- ✅ 点击和 hover 的命中对象是图标本体,不是任意文字区域。`ScreenSpaceEventHandler` 基于 `scene.pick` 命中 entity。
- ✅ `ylfb` 与普通锚点的点击详情弹框走不同业务分支。`sttpMap === 'ylfb'` 打开 `ylfbModalVisible`,其他走 `modalVisible`L366-375
### 9.6 基地与区域裁切 ✅️
- ✅ 基地切换不仅影响搜索候选,还会影响地图上的点位可见范围。`jdPanelControlShowAndHidden` 实现L1684-1748
- ✅ 区域裁切会直接把区域外点位隐藏,不是只改底图遮罩。`filterPointsByRegion` 设置 `_regionVisible = false`L1824-1848遮罩多边形 + 裁剪双重处理。
### 9.7 筛选器特殊逻辑 ✅️
- ✅ 装机容量筛选本质是批量切 `eng_point` 图例状态不是简单切图层。store 层处理Cesium 通过 `setLegendPointVisible` 响应)
- ✅ 鱼类分布模式会接管 `ylfb_point` 的数据、缓存、图例与显隐。store 层处理)
- ✅ 时间筛选当前只重载指定时间相关图层不是全量重载。store 层处理)
### 9.8 数据进入 addInitDataLayer 前的预处理 ✅️
- ✅ 所有点位数据在进入 `addInitDataLayer` 前会经过 `normalizePointLayerItems()` 过滤store 层 `map.ts` 执行Cesium 接收时已过滤)
- 没有 `iconCode``code !== 'colorLayer'` 的项会被抛弃
- `baseId == 'all'``anchoPointState` 结尾为 `_nbuilt` 的项会被抛弃
- ✅ `_id` 默认值生成规则store 层生成 `${sttpMap || iconType || 'point'}_${stcd}`
- ✅ **stcd+经纬度重复锚点处理**Cesium entity ID 使用 `${layerKey}:${item._id}`,与 2D 对齐,同 stcd 不同 sttpMap 的点不会互相覆盖。
### 9.9 图标渐进加载机制
- ❌ 2D 中图标不是一次性全加载完。有 `loading → loaded → error` 三种状态跟踪。
- ❌ 只有 `loaded` 状态的图标才参与样式渲染loader 失败的不渲染。
- ❌ 如果在图标加载过程中就触发了样式刷新,需要通过 `requestAnimationFrame` 回刷。
- ❌ 3D Cesium 中当前所有 entity 同步创建billboard `image` URL 直接赋值无渐进加载。Cesium 内部纹理加载无显式状态跟踪。
### 9.10 密度分档与近邻点元数据 ✅️
- ✅ 每个锚点的 `distance` 字段表示密度分档值(不是物理距离),值越大表示越稀疏。(已使用 `getEntityDensityValue``_rawData.distance` 读取L2460
- ✅ 不同 density 值对应不同的 `minZoom` 显示门槛。`getEntityDensityMinZoom` 映射 `nearby-point-rules.ts``densityDisplayRules`L2491
- ✅ 全量数据加载后store 会调用 `attachNearbyPointRuntimeMeta()` 给所有点打上 `_nearbyRule`、`_nearbyGroupId`、`_nearbyPriority` 等元数据。store 层处理Cesium 碰撞检测中读取)
- ✅ **孤立点例外规则**:如果一个点在当前视口内 ~56px 范围内没有同 layerKey 的其他可见点,它可以绕过密度门槛直接显示。`DENSITY_ISOLATION_THRESHOLD = 56` + `shouldBypassDensityGateForIsolatedEntity`L2506-2556

View File

@ -0,0 +1,343 @@
# 地图模块-OpenLayers抽吸与碰撞分析
## 1. 背景
当前地图 2D 主引擎已经切换为 OpenLayers项目依赖版本为 `ol@^10.8.0`
本次关注的问题有两个:
- 点位“抽吸”逻辑不符合业务预期;
- 文字碰撞时把整个点位一起隐藏,而不是仅隐藏文字。
典型场景是两个相邻电站,例如“积石峡”和“公伯峡”:
- 可用代号 `1`、`2` 表示两个相邻点;
- 默认缩放下只展示 `1`
- 放大到某个层级后,`1` 隐藏,`2` 展示;
- 再继续放大后,`1` 和 `2` 都展示,但 `2` 需要“抽吸/拉开”显示,避免与 `1` 重叠;
- 如果只是文字发生碰撞,希望点图标保留,仅文字隐藏或延后显示。
本文件先整理当前代码现状和问题成因,不直接修改实现。
如果需要查看**当前已经落地的抽吸规则、默认参数和调参入口**,请同时参考:
- `docs/地图模块-抽吸规则与参数说明.md`
## 2. 当前代码结构
当前前端 GIS 运行链路如下:
1. `src/components/gis/GisView.vue`
2. `src/modules/map/application/map-orchestrator.ts`
3. `src/components/gis/map.class.ts`
4. `src/components/gis/map.ol.ts`
5. `src/components/gis/ol/point-layer-manager.ts`
6. `src/components/gis/ol/popup-manager.ts`
各层职责简述:
- `GisView.vue`
- 地图入口组件;
- 挂载地图容器、图例、筛选器、控制器;
- 通过 `mapOrchestrator.mountView()` 初始化地图;
- 菜单切换时通过 `handlePageChange()` 触发页面地图重载。
- `map.class.ts`
- 地图门面类;
- 当前 2D 实现实际绑定的是 `MapOl`
- 3D 实现才会切到 `MapCesium`
- `map.ol.ts`
- OpenLayers 主实现;
- 负责地图初始化、底图加载、点位样式、Popup、区域裁切、量算等
- 当前“点位渲染规则”和“碰撞相关逻辑”主要集中在这个文件。
- `point-layer-manager.ts`
- 负责点图层创建、Feature 灌入、按图层控制显隐;
- 点位图层统一使用 `VectorLayer + VectorSource`
- `popup-manager.ts`
- 管理 hover popup 和高缩放下的批量 popup
- 内部额外做了一套基于边界框的碰撞判断。
## 3. 当前点位渲染链路
### 3.1 点图层创建
`point-layer-manager.ts` 中的 `ensureLayer()` 会统一创建点图层:
- 图层类型为 `VectorLayer<VectorSource>`
- 图层上开启了 `declutter: true`
- 样式函数统一走 `map.ol.ts` 中的 `createPointStyle()`
也就是说,当前所有点位的“是否显示”和“图标/文字如何避让”,都收敛到 OpenLayers 的 declutter 机制和样式函数里。
### 3.2 点样式生成
`map.ol.ts``createPointStyle()` 当前做了这些事:
- 读取 `_iconUrl``_labelText`
- 如果图例不可见、区域不可见,则直接返回 `null`
- 如果 `distance` 不满足当前缩放级别要求,也直接返回 `null`
- 图标使用 `Icon`
- 文字使用 `Text`
- 图标和文字都设置了 `declutterMode: 'declutter'`
- 最终把图标和文字一起放进同一个 `Style` 返回。
这意味着:
- 点图标和文字不是两个独立的渲染对象;
- 它们在当前实现中属于同一个样式结果;
- 只要这组样式参与碰撞判定,图标和文字的命运就是绑定的。
### 3.3 当前已有的“抽稀”逻辑
当前项目中确实有一层“缩放越小,显示越少”的处理,但它不是精细的“抽吸”。
`map.ol.ts``shouldRenderFeatureByDistance()` 逻辑是:
- 小缩放下要求 `distance` 更大才允许显示;
- 缩放越大,允许显示的点逐渐增多;
- 本质上是基于后端数据字段 `distance` 做全局抽稀。
这个逻辑的特点是:
- 是全局阈值,不是成对点位或同组点位的专属规则;
- 只能决定“这个点显示还是不显示”;
- 不能表达“1 和 2 是近邻关系,并且在不同缩放阶段按业务优先级切换显示”。
### 3.4 当前批量 Popup 的碰撞检测
`popup-manager.ts` 在高缩放批量 popup 模式下,又额外做了一层碰撞判断:
- 先估算图标和文字合并后的锚点边界框;
- 如果边界框碰撞,则当前要素直接不参与 popup 渲染;
- 随后再判断 popup 矩形之间是否碰撞。
这说明当前“图标 + 文字”被视为一个整体,不仅体现在 OpenLayers 的 declutter 里,也体现在 popup 的辅助判断里。
## 4. 当前仓库里“抽吸”相关代码现状
仓库中确实存在历史上的“抽吸”实现,但不在当前 OpenLayers 主链路里。
相关文件:
- `src/utils/leaflet/leaflet.inflatable-markers-group.js`
- `src/components/gis/map.leaflet.ts`
现状判断:
- `leaflet.inflatable-markers-group.js` 是旧 Leaflet 时代的抽吸插件;
- 它内部有 `inflateAsManyAsPossible()`、`_zoomend()` 等典型抽吸逻辑;
- 但当前 `map.class.ts` 实际实例化的是 `new MapOl()`
- `map.leaflet.ts` 已经不在主运行路径上。
结论是:
- 当前页面上看到的点位行为,不是 Leaflet 抽吸插件在工作;
- 现在的显示结果主要来自 OpenLayers 的 `declutter`、当前样式函数和 `distance` 抽稀逻辑;
- 因此“已经有抽吸但是不太对”,更准确地说是“历史上有抽吸代码,但现在主链路没有真正使用那套机制”。
## 5. 问题分析
### 5.1 为什么当前实现做不到你要的分阶段抽吸
你描述的目标并不是简单“避让”,而是一个明确的分阶段显示策略:
1. 默认只显示 `1`
2. 缩放到阶段 A 时,隐藏 `1`,改为显示 `2`
3. 缩放到阶段 B 时,`1` 和 `2` 都显示;
4. 阶段 B 下,`2` 还要相对 `1` 做抽吸/偏移,避免完全重叠。
而当前代码缺少以下能力:
- 没有“近邻点关系”配置
- 代码里没有看到类似 `groupId`、`neighborIds`、`priority`、`displayLevel` 这样的结构;
- 系统不知道“积石峡”和“公伯峡”是一组特殊近邻点。
- 没有“分阶段显示规则”配置
- 当前只有全局的 `distance` 阈值判断;
- 没有按缩放阶段表达“谁替代谁显示、谁先隐藏、谁后展示”。
- 没有“抽吸偏移”计算
- 当前点要素坐标就是原始经纬度转换结果;
- 没有根据缩放级别和邻近关系生成偏移坐标;
- 也没有“展开后沿圆周/沿固定方向偏移”的逻辑。
- 当前 declutter 是被动避让,不是主动编排
- declutter 只会尽量避免重叠;
- 它不会理解业务上的“1 是主点、2 是附点”;
- 也不会自动实现“先 1后 2再两个都展示且 2 偏移”的规则。
所以当前看到的结果不稳定,本质原因不是某一个参数不对,而是“现有机制和目标能力不是一类问题”。
### 5.2 为什么文字碰撞会把整个点隐藏
这是当前实现里最关键的原因:
- 点图标和文字是在同一个 `Style` 里返回的;
- 图层开启了 `declutter: true`
- 图标和文字又都设置了 `declutterMode: 'declutter'`
在这种组织方式下,当前要素的碰撞判定是按“一个整体渲染单元”处理的,而不是“图标一套规则,文字一套规则”。
因此会出现下面的现象:
- 图标本身其实不冲突;
- 但文字边界框发生碰撞;
- 最终被隐藏的是整条样式结果;
- 用户视觉上就会觉得“明明只是字挤了,为什么点也没了”。
这和你现在观察到的问题是一致的。
### 5.3 为什么当前逻辑还会进一步放大这个问题
除了 OpenLayers 自身的 declutter 组织方式,代码里还有两层因素会继续放大问题:
- `shouldRenderFeatureByDistance()` 会先根据 `distance` 直接过滤点位;
- `popup-manager.ts` 在批量 popup 模式下,也把“图标 + 文字”当作合并边界框做碰撞模拟。
也就是说,当前系统对近邻点位的处理是:
- 先用全局 `distance` 规则筛掉一部分;
- 再用 OpenLayers declutter 继续过滤;
- 高缩放时 popup 层再做一轮碰撞跳过。
这三层叠加后,显示行为更偏向“谁先撞谁消失”,而不是“按业务规则分阶段展开”。
## 6. 结合你的案例做具体映射
如果以近邻点 `1`、`2` 为例,当前代码里实际上缺的是下面这些业务语义:
- `1``2` 属于同一近邻组;
- 组内有主次优先级;
- 在不同 zoom 区间内有不同展示策略;
- 在最大放大阶段需要给 `2` 一个偏移位;
- 偏移后图标和文字还要分别控制碰撞策略。
当前实现只能表达:
- 某个点在当前 zoom 下是否允许渲染;
- 某个点图例是否可见;
- 某个点是否被区域裁切隐藏;
- 某个点的图标和文字整体是否参与 declutter。
它并不能表达:
- “1 替代 2 展示”;
- “2 替代 1 展示”;
- “1 和 2 一起展示,但 2 抽吸展开”;
- “只隐藏文字,不隐藏图标”。
所以你现在遇到的问题是结构性问题,不是简单调一个 `declutter` 参数就能彻底解决。
## 7. 后续修改时建议优先动的层
如果下一步要真正改这块,建议优先从下面几层入手:
### 7.1 先补“近邻点显示规则”
建议不要直接把业务规则写死在样式函数里,而是先增加一层近邻点编排规则,例如:
- `groupId`
- `priority`
- `showZoomMin`
- `showZoomMax`
- `replaceAtZoom`
- `expandAtZoom`
- `expandOffset`
这样才能表达:
- 默认只显示主点;
- 中间层级切换成副点;
- 更大层级两个都显示;
- 副点在展示时做偏移。
### 7.2 抽吸不要依赖 declutter 自动完成
抽吸本质上是“主动布局”问题,不是“被动避让”问题。
建议后续把近邻点抽吸拆成单独逻辑:
- 先根据原始点数据识别近邻组;
- 再根据当前 zoom 产出“本次真正参与渲染的点集合”;
- 对需要展开的点,生成偏移后的渲染坐标;
- 最后再交给图层渲染。
这样会比直接指望 OpenLayers 的 declutter 更可控。
### 7.3 图标层和文字层要分开控制
要实现“文字碰撞时只隐藏文字,不隐藏点图标”,后续最重要的一点是把图标和文字的渲染职责拆开。
至少要做到下面二选一:
- 图标层和文字层拆成两个独立图层;
- 或者把图标与文字拆成可独立决策的渲染单元。
目标是:
- 图标优先保留;
- 文字单独避让;
- 文本碰撞时只压文字,不压图标。
如果仍然维持“同一个样式对象里同时放 image 和 text”的组织方式这个问题大概率还会持续存在。
### 7.4 Popup 碰撞策略也要和新规则同步
后续如果点位抽吸和文字单独避让改了,`popup-manager.ts` 里的边界框逻辑也要一起调整。
否则会出现:
- 图标已经正常显示;
- 文字也按新规则显示了;
- 但 popup 层仍然沿用旧的合并边界框;
- 最终又在 popup 阶段把结果打回去。
## 8. 建议的改造顺序
为了降低风险,建议后续改造按以下顺序推进:
1. 先梳理近邻点数据结构
- 确定近邻点如何分组;
- 确定主次优先级和缩放阈值从哪里来。
2. 再实现“显示决策层”
- 在真正生成 Style 之前,先决定哪些点应该显示;
- 哪些点应该隐藏;
- 哪些点需要偏移展开。
3. 然后拆分图标和文字碰撞
- 先保证点图标稳定显示;
- 再单独做文字避让。
4. 最后调整 popup 逻辑
- 保证 popup 的碰撞判定和最终可见点保持一致。
## 9. 涉及文件清单
本次分析重点涉及以下文件:
- `src/components/gis/GisView.vue`
- `src/components/gis/map.class.ts`
- `src/components/gis/map.ol.ts`
- `src/components/gis/ol/point-layer-manager.ts`
- `src/components/gis/ol/popup-manager.ts`
- `src/utils/leaflet/leaflet.inflatable-markers-group.js`
- `src/components/gis/map.leaflet.ts`
- `package.json`
## 10. 当前结论
当前地图问题可以归纳为两点:
1. 现在的 OpenLayers 主链路并没有真正使用旧 Leaflet 的抽吸机制;
2. 当前点图标和文字被作为一个整体参与 declutter所以文字碰撞时会连点一起隐藏。
所以后续如果要改,方向不应该只是“调避让参数”,而应该是:
- 增加近邻点分阶段显示规则;
- 增加主动抽吸/偏移布局;
- 把图标和文字拆成可独立控制的渲染单元;
- 同步修正 popup 的碰撞判断。
在这个基础上,再进入代码修改会更稳。

View File

@ -0,0 +1,316 @@
# 地图模块-抽吸规则与参数说明
## 1. 文档目的
本文档用于记录当前地图点位“抽吸”功能的现行实现、默认参数、分层级显示规则和后续调参方式。
本文件描述的是**当前已经落地并验证通过**的规则,适合作为后续维护和继续调参的依据。
相关文档:
- `docs/地图模块-详细说明.md`:地图整体架构说明
- `docs/地图模块-OpenLayers抽吸与碰撞分析.md`:问题成因与改造分析
## 2. 当前实现范围
当前抽吸逻辑运行在 OpenLayers 主链路中,核心文件如下:
1. `src/modules/map/domain/nearby-point-rules.ts`
2. `src/store/modules/map.ts`
3. `src/components/gis/map.ol.ts`
4. `src/components/gis/ol/point-layer-manager.ts`
各文件职责:
- `nearby-point-rules.ts`
- 近邻点规则入口
- 自动识别配置入口
- 近邻点运行时元数据挂载
- `map.ts`
- 点位数据加载完成后,统一触发近邻点分组和元数据写回
- `map.ol.ts`
- 决定某个点在当前缩放级别是否显示
- 决定文字是否允许显示
- 承担图标与文字的手工碰撞控制
- `point-layer-manager.ts`
- 负责展开阶段的几何偏移
- 负责把同组点位按扇形/环形布局散开
## 3. 当前抽吸规则
### 3.1 近邻点自动识别
当前采用自动识别近邻点,不再靠固定站名手工枚举。
识别原则:
- 只在同一 `layerKey` 内做近邻识别
- 按点位空间距离自动聚组
- 满足最小组大小后,才认为是近邻组
- 组内自动生成显示优先级 `priority`
这样做的目的:
- 避免跨图层混组
- 避免后续新增点位还要手工补名字
- 让抽吸能力可以覆盖整批业务点
### 3.2 分层级显示规则
当前显示规则以 `replaceAtZoom``expandAtZoom` 为核心:
1. `zoom < replaceAtZoom`
- 只显示组内主点
- 即 `priority = 1`
2. `replaceAtZoom <= zoom < expandAtZoom`
- 显示组内前两个点
- 即 `priority <= 2`
- 当前这样设计是为了避免主点在放大过程中突然消失
3. `zoom >= expandAtZoom`
- 同组点全部显示
- 同时进入展开布局阶段
补充规则:
- 如果某个点配置了 `showZoomMin``showZoomMax`,则先受这两个值约束
- 没有进入近邻组的点,不受抽吸规则影响
### 3.3 文字显示规则
当前文字显示必须依赖点位显示。
也就是说:
- 点不显示,文字一定不显示
- 点显示后,文字还要继续通过碰撞判断才会显示
当前文字碰撞规则:
- 文字要避让已保留的图标占位盒
- 文字要避让已保留的其他文字
- 图标与文字不再分别交给 OpenLayers 的 `declutter` 自动处理
- 当前走的是项目内的手工碰撞控制
## 4. 当前默认参数
当前默认参数集中维护在:
- `src/modules/map/domain/nearby-point-rules.ts`
当前采用统一配置对象:
```ts
type NearbyPointConfig = {
autoRule: NearbyPointAutoRule;
layoutRule: NearbyPointLayoutRule;
densityDisplayRules: NearbyPointDensityDisplayRule[];
};
```
其中:
- `autoRule`:控制近邻点自动识别、缩放切换和基础展开半径
- `layoutRule`:控制展开阶段的单圈容量、扇形角度和外圈间距
- `densityDisplayRules`:控制 `distance` 密度分档在不同缩放级别的基础显示资格
### 4.1 自动识别与缩放阶段参数
当前值如下:
| 参数 | 当前值 | 作用 |
|---|---:|---|
| `distanceThresholdMeters` | `9000` | 近邻点自动识别距离阈值 |
| `replaceAtZoom` | `10.5` | 进入“主点 + 次点”阶段的缩放级别 |
| `expandAtZoom` | `12.2` | 进入“全部显示并展开”阶段的缩放级别 |
| `expandOffsetPx` | `48` | 第一圈展开的基础偏移半径 |
| `angleStepDeg` | `55` | 默认角度步长参考值 |
| `minGroupSize` | `2` | 最小成组数量 |
### 4.2 展开布局参数
当前值如下:
| 参数 | 当前值 | 作用 |
|---|---:|---|
| `ringSize` | `5` | 单圈最多容纳的次点数量 |
| `fanAngleForTwoDeg` | `110` | 单圈剩余 `2` 个点时的扇形总角度 |
| `fanAngleForFourDeg` | `150` | 单圈剩余 `3``4` 个点时的扇形总角度 |
| `fanAngleForManyDeg` | `180` | 单圈剩余 `5` 个及以上点时的扇形总角度 |
| `ringGapPx` | `22` | 外圈最小增量半径 |
| `ringGapFactor` | `0.85` | 外圈相对基础半径的增量系数 |
### 4.3 密度分档显示参数
这里的 `distance` 不是物理距离,而是点位密度分档值。
数值越大表示越稀疏,越早参与显示候选;数值越小表示越密集,需要更高缩放级别才参与显示。
当前值如下:
| `minDensityValue` | `minZoom` | 作用 |
|---:|---:|---|
| `1500000` | `0` | 很稀疏的点,从小缩放级别就可参与显示 |
| `800000` | `6.1` | 稍密集的点,从中低缩放开始参与显示 |
| `400000` | `8.1` | 中密度点,需要进一步放大 |
| `50000` | `10.6` | 高密度点,需要较高缩放级别 |
| `0` | `12.2` | 极密集点,只有更高缩放才进入候选 |
## 5. 当前展开布局
展开阶段由 `point-layer-manager.ts` 控制。
### 5.1 布局特点
当前布局不是简单把点随机散开,而是按以下方式处理:
- 主点保留原位置
- 同组其他点围绕主点展开
- 展开方向优先偏下方
- 单圈数量由 `ringSize` 控制
- 点数较多时进入第二圈
- 第二圈半径按 `ringGapPx``ringGapFactor` 继续增大,避免继续叠在一起
### 5.2 为什么优先向下展开
当前优先向下展开,主要是为了:
- 尽量给上方文字留空间
- 降低文字压住上方点的概率
- 让地图上的抽吸形态更稳定
## 6. 当前实现的几个关键约束
### 6.1 不使用淡入淡出动画
目前已移除点和文字的淡入淡出动画。
原因:
- 抽吸状态切换和动画叠加时,容易让点和文字出现闪烁
- 会干扰对“当前到底该不该显示”的判断
当前阶段优先保证:
- 显示规则稳定
- 点和文字状态一致
- 放大缩小时不出现明显错位
### 6.2 不再依赖 OL 的自动 declutter 决定图标命运
当前图标和文字都设置为 `declutterMode: 'none'`,由项目内逻辑统一控制。
这样做的原因:
- 避免图标和文字落在两套碰撞体系里
- 避免出现“文字先出来、点没出来”
- 避免文字压住其他点却仍然显示
## 7. 常见现象与调参建议
### 7.1 成组太少
表现:
- 相近点仍然容易互相盖住
- 进入展开前看起来还是压在一起
优先调整:
- 增大 `distanceThresholdMeters`
### 7.2 成组太多
表现:
- 距离并不算近的点也被当成一组
- 放大后过早进入抽吸关系
优先调整:
- 减小 `distanceThresholdMeters`
### 7.3 展开太晚
表现:
- 放大到较深层级前仍然挤在一起
优先调整:
- 减小 `expandAtZoom`
### 7.4 展开太早
表现:
- 中等缩放时地图上就出现较明显散开效果
优先调整:
- 增大 `expandAtZoom`
### 7.5 展开后间距不够
表现:
- 虽然已经展开,但图标还是比较挤
优先调整:
- 增大 `expandOffsetPx`
- 或增大 `ringGapPx`
- 或增大 `ringGapFactor`
### 7.6 单圈散开角度不合适
表现:
- 次点虽然已经展开,但仍然集中在一侧
- 或者扇形过大,展开形态显得太散
优先调整:
- 调整 `fanAngleForTwoDeg`
- 调整 `fanAngleForFourDeg`
- 调整 `fanAngleForManyDeg`
### 7.7 主点在放大过程中突然消失
当前已经通过 `replaceAtZoom <= zoom < expandAtZoom` 阶段显示 `priority <= 2` 进行修正。
如果后续又出现类似现象,优先检查:
- `map.ol.ts``shouldRenderNearbyFeature()` 的阶段逻辑
- 是否误改成只显示 `priority = 2`
### 7.8 明明周围看起来空,文字还是不显示
优先检查:
- 图标碰撞盒是否过大
- 文字碰撞盒是否过于保守
- 候选集是否发生重复统计
相关代码主要在:
- `src/components/gis/map.ol.ts`
## 8. 后续维护建议
建议后续继续保持以下约定:
1. 抽吸参数继续统一放在 `nearby-point-rules.ts`
2. 显示决策继续集中在 `map.ol.ts`
3. 几何偏移继续集中在 `point-layer-manager.ts`
4. 后续调参优先改 `DEFAULT_NEARBY_POINT_CONFIG`,不要直接把数值散落回业务代码
5. 如果继续加动画,必须放在抽吸状态机完全稳定之后
6. 如果继续优化 popup也要同步遵循“点先于文字”的显示原则
## 9. 当前结论
当前这版抽吸实现已经形成了比较稳定的主线:
- 自动识别近邻点
- 统一缩放阶段显示规则
- 展开阶段几何偏移
- 文字依赖点显示
- 文字避让图标与文字
后续如果继续调优,建议先从参数层开始,不要先动主逻辑结构。

View File

@ -0,0 +1,621 @@
# 地图模块-详细说明
## 1. 文档目的
本文档用于说明当前地图模块的真实运行结构、初始化时序、图层与图例联动、点位渲染规则、筛选与缩放行为,以及近期已经落地的关键约束。
本文档描述的是“当前可运行版本”的现状,不展开抽吸参数细节与专项问题分析。相关补充文档如下:
- `docs/地图模块-抽吸规则与参数说明.md`
- `docs/地图模块-OpenLayers抽吸与碰撞分析.md`
## 2. 当前技术栈
- 前端框架Vue 3 + TypeScript + Ant Design Vue
- 状态管理Pinia
- 2D 地图引擎OpenLayers 10.8.0
- 3D 地图引擎Cesium
- 地图服务GeoServer / WMTS / XYZ
- 运行模式:后台配置驱动 + 前台运行时编排
说明:
- 当前 2D 主链路已经完全围绕 OpenLayers 组织。
- 项目中仍保留 Leaflet 相关依赖和旧代码,但不是当前主执行路径。
## 3. 模块分层
当前地图模块可以按 6 层理解:
1. 页面入口层
2. 应用编排层
3. 地图能力门面层
4. 地图引擎执行层
5. Store 运行态层
6. 前台交互组件层
对应核心文件如下:
- 页面入口层
- `src/components/gis/GisView.vue`
- 应用编排层
- `src/modules/map/application/map-orchestrator.ts`
- 地图能力门面层
- `src/components/gis/map.class.ts`
- 地图引擎执行层
- `src/components/gis/map.ol.ts`
- `src/components/gis/map.cesium.ts`
- `src/components/gis/ol/point-layer-manager.ts`
- `src/components/gis/ol/popup-manager.ts`
- Store 运行态层
- `src/store/modules/map.ts`
- `src/modules/map/stores/map-config.store.ts`
- `src/modules/map/stores/map-data.store.ts`
- `src/modules/map/stores/map-view.store.ts`
- 前台交互组件层
- `src/components/mapLegend/index.vue`
- `src/components/mapFilter/index.vue`
- `src/components/mapController/index.vue`
- `src/components/mapController/LayerController.vue`
- `src/components/BaseLayerSwitcher/index.vue`
## 4. 整体原则
当前地图模块遵循以下几个运行原则:
### 4.1 地图容器全局常驻
地图由 `GisView.vue` 常驻挂载,不会随着菜单切换被销毁重建。页面切换本质上是:
- 重新计算 `pageKey`
- 重新加载该页图层配置和图例配置
- 用新的运行态覆盖旧页面显示内容
### 4.2 配置驱动
前端不把全部图层和图例硬编码死,而是依赖后端返回的:
- 图层树配置
- 图例配置
- 页面级图例配置
- 各业务点位接口数据
### 4.3 运行态绝对优先
初始化默认值只在第一次派生时生效;一旦进入运行态,后续图层勾选、图例勾选、筛选器切换,都必须以当前用户操作后的状态为准,不能在加载完成后回退到默认状态。
## 5. 页面入口层
### 5.1 `GisView.vue`
`GisView.vue` 的职责主要是:
- 提供地图容器 `#mapContainer`
- 提供 popup 挂载容器
- 挂载图例、筛选器、控制器、底图切换器
- 根据路由计算 `pageKey`
- 在挂载时调用 `mapOrchestrator.mountView()`
- 在页面切换时交给编排器重载页面
当前页面层已经不再直接承载复杂业务逻辑,复杂链路都收敛到了编排器和 Store。
## 6. 应用编排层
### 6.1 `map-orchestrator.ts` 的职责
`map-orchestrator.ts` 是当前地图业务的总调度中心,主要负责:
- 初始化地图壳与 popup
- 加载页面图层配置和图例配置
- 初始化 GIS 基础图层
- 触发点位图层加载
- 管理缩放监听和基地切换监听
- 处理图层树勾选
- 处理图例勾选
- 处理时间筛选、容量筛选、搜索定位
- 处理水电开发菜单下的缩放联动图层
### 6.2 页面初始化链路
当前初始化顺序如下:
1. `GisView.vue` 调用 `mapOrchestrator.mountView()`
2. `MapClass.init()` 初始化地图实例
3. 页面级 popup 容器挂到地图实例
4. 绑定缩放监听和基地监听
5. 并行请求图层树配置与图例配置
6. 图例接口先返回时,立即生成图例运行态
7. 图层树接口返回后,生成默认勾选图层并初始化 GIS 基础图层
8. 再按图层配置批量加载点位数据
这里有两个当前已落地的关键时序调整:
- 图例转圈只跟图例接口绑定,不再等待所有锚点接口完成。
- 筛选器数据会随着已加载图层逐步出现,不再必须等全量点位接口结束。
### 6.3 页面切换
页面切换时地图不销毁,只重载当前页面的:
- 图层树配置
- 图例配置
- 点位数据
- 当前页面的默认运行态
如果仍处于同一个 `pageKey` 且用户之前修改过勾选态,会尽量复用当前运行态,而不是重新回放默认勾选。
### 6.4 缩放联动
当前编排层主要有两类缩放联动:
- `eng_point` 缩放联动
- 大型电站始终允许显示
- 中型电站仅在 `zoom > 7.5` 时进入显示候选
- 水电开发菜单动态图层联动
- `HYDRO_DYNAMIC_LAYER_KEYS` 在缩放跨越阈值时参与加载与显隐编排
## 7. 地图能力门面层
### 7.1 `map.class.ts`
`MapClass` 是地图能力统一门面,屏蔽 2D / 3D 引擎差异,对外暴露统一方法。
当前常用能力包括:
- `init()`
- `initPopupOverlay()`
- `addBaseDataLayer()`
- `addInitDataLayer()`
- `mdLayerTreeShowOrHidden()`
- `controlBaseLayerTreeShowAndHidden()`
- `setLegendPointVisible()`
- `hasLayer()`
- `hasBaseLayer()`
- `removePointLayer()`
- `flyTopanto()`
- `switchView()`
当前业务主执行层仍然是 `MapOl`
## 8. 地图引擎执行层
### 8.1 OpenLayers 主执行层
`map.ol.ts` 负责 OpenLayers 地图的实际渲染与交互,是当前 2D 地图主执行文件。
当前承担的核心能力包括:
- 地图实例初始化
- 底图与 GIS 图层管理
- 点位图层渲染
- 图标与文字样式生成
- hover popup 与批量 popup
- 基地范围裁切
- 高缩放交互
- 测量、截图、飞行定位等基础地图能力
### 8.2 Cesium 执行层
`map.cesium.ts` 目前更多是保留 3D 入口和部分基础能力,复杂业务点位与碰撞规则并未与 OpenLayers 完全对齐。
结论上,当前真实业务规则仍然以 OpenLayers 链路为准。
## 9. Store 分层
### 9.1 `map-config.store.ts`
负责配置态数据:
- 图层树配置
- 图层配置索引
- 全量原始图例配置
- 图例索引
- 页面级图例配置
- 配置接口加载状态
当前这里拆分出了两个加载态:
- `configLoading`
- `legendLoading`
其中 `legendLoading` 单独控制图例转圈。
### 9.2 `map-data.store.ts`
负责数据态:
- `pointData`
- `pointDataCache`
- `layerLoadState`
- 地图整体 `loading`
这里的关键设计是:
- 每个点图层有独立缓存
- `pointData` 是由缓存合并出来的运行态数据
- 单个图层命中缓存或接口返回后,就会立即回填 `pointData`
因此当前搜索筛选下拉已经支持“渐进可用”,不再只能等全部接口结束。
### 9.3 `map-view.store.ts`
负责视图运行态:
- 当前勾选图层 `checkedLayerKeys`
- 图例勾选状态 `legendCheckedState`
- 搜索时间范围
- 当前基地
- 当前缩放级别
### 9.4 `src/store/modules/map.ts`
这是当前地图运行逻辑最重的 Store负责串联配置、缓存和地图实例。
主要职责包括:
- 生成图例运行态
- 批量加载点位数据
- 控制图层显隐
- 控制图例显隐
- 管理请求缓存与并发加载
- 刷新点图层显示数据
- 处理 `eng_point` 的显示过滤
- 在全量点位准备完成后挂载近邻点元数据
## 10. 图层分类
当前地图里的图层大体可以分成三类:
### 10.1 `GISMap`
这类图层对应 GIS 基础图层或专题底图,由 `addBaseDataLayer()` 加载到 `layerRegistry`
当前已补充的规则:
- 勾选 `GISMap` 时,不能只做显示/隐藏。
- 如果地图实例中不存在该图层,需要先重新加载,再显示。
### 10.2 点位图层
这类图层由接口返回锚点数据,最终进入 `PointLayerManager` 维护的 `VectorLayer`
### 10.3 其他专题图层
例如梯级流域、区域裁切辅助层等,这些更多由 `map.ol.ts` 单独控制。
## 11. 图层数据加载机制
### 11.1 配置与数据分离
当前初始化时,配置加载与点位数据加载是两条链:
- 图层树配置决定有哪些层、哪些默认勾选
- 图例配置决定图例结构和图例项元数据
- 点位数据接口决定地图上实际锚点内容
### 11.2 加载顺序
`loadAllLayerData()` 的主要逻辑是:
1. 先收集所有带 URL 的图层
2. 把默认勾选图层作为高优先级任务
3. 收集完成后全量并发加载,不再按 4 个一组分批发起
4. 每个图层完成后立即写入缓存
5. 每个图层命中缓存或返回成功后,立即增量更新 `pointData`
6. 全部图层结束后,再统一:
- 回填每层原始数据
- 挂载近邻点运行时元数据
- 刷新各图层显示数据
- 用最新运行态收尾
### 11.3 初始化阶段的图例绝对性
当前已修复一个关键问题:
- 图例虽然可能在界面上还在 loading
- 但只要图例配置已经返回,默认隐藏的图例项在点位首批入图时就必须生效
也就是说,现在不会再出现:
- loading 过程中先显示默认隐藏点
- loading 结束后才消失
## 12. 图例机制
### 12.1 图例来源
图例运行态由以下数据共同决定:
- 原始全量图例配置
- 当前页面图例配置
- 当前已勾选图层
- 当前图例勾选状态
### 12.2 图例派生
图例最终显示的是 `legendDataSelected`,而不是全量图例。
派生逻辑核心原则如下:
- 只有当前勾选图层对应的图例项才进入页面图例
- 图例勾选状态是运行态绝对值
- 环保设施分组有单独规则
### 12.3 图例加载时机
当前图例面板的 loading 只跟图例接口绑定:
- 图例接口返回后立即停转
- 图例内容在图层默认勾选同步后立即派生
- 不再等待所有锚点接口完成
## 13. 筛选器机制
### 13.1 `MapFilter` 的职责
筛选器当前包含以下能力:
- 时间范围筛选
- 装机容量筛选
- 搜索定位
- 个别页面的专题筛选项
### 13.2 搜索下拉来源
搜索下拉使用 `mapDataStore.pointData` 作为数据源。
当前行为已经调整为:
- 某个图层一旦命中缓存,筛选器即可出现该图层点位
- 某个图层接口一旦返回成功,筛选器也会立即出现该图层点位
因此筛选器当前是“渐进展示”,而不是“全量完成后一次性展示”。
### 13.3 装机容量筛选
装机容量筛选针对 `eng_point` 图层,当前规则如下:
- `all`
- 恢复大型与中型图例
- `large_eng_built`
- 只保留 `large_eng_` 前缀相关图例
- 地图上只显示大型电站点位
- `mid_eng_built`
- 只保留 `mid_eng_` 前缀相关图例
- 地图上只显示中型电站点位
当前容量切换不再只是影响筛选器本地下拉,而是会同步驱动:
- 图例运行态
- `eng_point` 点位显示
## 14. `eng_point` 专项规则
`eng_point` 是当前地图模块中的特殊图层,存在独立显示规则。
### 14.1 缩放规则
在数据入图阶段就生效:
- 大型电站始终允许显示
- 中型电站仅在 `zoom > 7.5` 时允许进入显示候选
这不是单纯的图例控制,而是点位入图时的过滤逻辑。
### 14.2 图例规则
点位入图之后,仍然必须再经过图例运行态控制:
- 允许入图,不等于最终可见
- 只要图例勾选为隐藏,该类点位就必须隐藏
### 14.3 容量筛选规则
装机容量下拉会进一步批量控制 `eng_point` 的图例项,使图例与点位同步切换。
## 15. 点位显示裁决链
当前点位最终是否显示,至少会经过以下几层判断:
1. 图层是否勾选
2. 图例是否勾选
3. 基地范围是否允许
4. `eng_point` 缩放过滤是否通过
5. `distance` 密度分档是否通过
6. 近邻点显示阶段是否通过
7. 图标是否已加载完成
8. 当前缩放下是否进入碰撞控制
这几层不是互斥关系,而是叠加裁决。
## 16. 点位渲染与样式
### 16.1 基础样式
当前点位渲染包括:
- 图标
- 文字标签
- 标签换行与截断
- 缩放相关的图标与文字样式变化
### 16.2 图标加载约束
当前已经补充图标加载状态缓存:
- 图标未加载完成时,不显示该点
- 图标未加载完成时,文字也不先显示
- 图标未加载完成时,不参与碰撞候选
这样可以避免“文字先出来、图标还是空的”的问题。
## 17. 抽吸、密度与碰撞
### 17.1 专项文档
抽吸与密度分档的详细参数请查看:
- `docs/地图模块-抽吸规则与参数说明.md`
### 17.2 当前裁决顺序
当前点位显示顺序可以理解为:
1. 密度分档
2. 近邻抽吸
3. 图标碰撞
4. 文字碰撞
补充约束:
- 只有满足可见性条件的点,才能进入碰撞候选集
- 被图例或缩放过滤掉的点,不能再去占用碰撞资格
- 视图内无近邻的孤立点允许局部放行
### 17.3 高缩放特例
当前在高缩放层级 `zoom >= 15` 时,行为与中低缩放不同:
- 只处理视口内点位
- 点与文字不再做碰撞淘汰
- 视口内符合基础显示条件的点和文字全部显示
- 同时进入批量 popup 模式
这条规则的目标是:
- 保证深度放大后信息完整可见
- 避免高缩放下还因为碰撞把点或文字压掉
## 18. Popup 机制
### 18.1 两类 popup
当前 popup 分成两类:
- hover popup
- batch popup
### 18.2 hover popup
鼠标悬停时由 `pointermove` 驱动,只在非 batch popup 模式下显示。
### 18.3 batch popup
`zoom >= 15` 时进入批量 popup 模式:
- 只基于当前视口内点位
- 拖动地图时持续刷新
- 但通过 `requestAnimationFrame` 做节流
- `moveend` 后立即再做一次强制刷新
当前这样做是为了兼顾两件事:
- 保留“拖动时 popup 跟着更新”的原交互
- 避免拖动过程中每个事件都重建整批 DOM
### 18.4 惯性平移已关闭
当前地图拖动已经关闭 OpenLayers 默认惯性平移:
- 普通拖动仍然保留
- 松手后不再继续滑动一小段
这样可以减少高缩放 popup 场景下“松手还轻微位移”的观感问题。
## 19. 基地与区域过滤
基地切换是当前地图模块的关键能力之一,主要影响:
- 地图裁切范围
- 当前基地相关点位的可见性
- 部分专题图层显示
整体过程通常是:
1. 外部基地选择源变化
2. 编排器接收到基地 ID
3. 地图实例切换基地范围
4. 点位更新 `_regionVisible`
5. 样式函数按区域可见性决定是否显示
## 20. 典型交互链路
### 20.1 图层树勾选
1. `LayerController` 触发勾选变化
2. 编排器归一化图层 key
3. `map.ts` 更新运行态图层勾选
4. 地图实例更新图层显隐
5. 图例重新派生
补充:
- `GISMap` 勾选时,如果地图里没有该图层,会先补载,再显示
### 20.2 图例勾选
1. 图例组件触发点击
2. 编排器转发图例切换
3. `map.ts` 更新图例运行态
4. 对应点位立即更新显隐
5. 图例树同步更新灰态
### 20.3 筛选器操作
1. 用户切换时间、容量、搜索等条件
2. 编排器接收命令
3. 视情况更新视图运行态或重载数据
4. 地图实例与图例运行态同步刷新
### 20.4 缩放操作
1. OpenLayers 视图触发 `change:resolution`
2. 编排器更新当前缩放级别
3. 处理 `eng_point` 阈值联动
4. 水电开发菜单下处理动态图层联动
5. `map.ol.ts` 处理高缩放 popup 与点位显示策略
## 21. 当前重点文件清单
- `src/components/gis/GisView.vue`
- `src/components/gis/map.class.ts`
- `src/components/gis/map.ol.ts`
- `src/components/gis/map.cesium.ts`
- `src/components/gis/gisUtils.ts`
- `src/components/gis/mapurlManage.ts`
- `src/components/gis/ol/point-layer-manager.ts`
- `src/components/gis/ol/popup-manager.ts`
- `src/modules/map/application/map-orchestrator.ts`
- `src/modules/map/stores/map-config.store.ts`
- `src/modules/map/stores/map-data.store.ts`
- `src/modules/map/stores/map-view.store.ts`
- `src/store/modules/map.ts`
- `src/components/mapLegend/index.vue`
- `src/components/mapFilter/index.vue`
- `src/components/mapController/index.vue`
- `src/components/mapController/LayerController.vue`
- `src/components/BaseLayerSwitcher/index.vue`
## 22. 当前结论
当前地图模块已经形成比较清晰的主干结构:
- `GisView` 负责挂载与页面入口
- `map-orchestrator` 负责业务编排
- `MapClass` 负责能力门面
- `MapOl` 负责 2D 主执行
- `map.ts + 三个拆分 store` 共同维护配置、数据与视图运行态
- 图层树、图例、筛选器、popup、高缩放规则都已经围绕这条主干收口
相较旧版说明,当前最重要的现状变化有 8 点:
1. 图例 loading 已与锚点全量加载解耦
2. 筛选器数据已支持渐进展示
3. 初始化阶段默认隐藏图例项会立即生效
4. 运行态勾选不会在 loading 完成后被默认值覆盖
5. `eng_point` 有独立的缩放与容量规则
6. 高缩放下视口内点和文字全部显示,不再做碰撞淘汰
7. batch popup 保留拖动跟随,但增加了节流
8. 地图拖动惯性已关闭
后续如果继续扩展地图功能,建议仍然优先沿着“编排层 + Store 分层 + OpenLayers 执行层”这条主干扩展,不要再把复杂业务回填到页面组件里。

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,380 @@
# 地图模块重构实施清单
## 1. 使用说明
本文档是地图模块重构的执行清单,只保留当前已经明确、可以直接落地的实施项。
以下内容暂不纳入本清单:
- 仍需进一步讨论的方案;
- 依赖后端配合后才能确定的优化项;
- 暂未确定收益与改造成本的预研项;
- 调试面板、埋点体系、长期性能平台化建设等扩展项。
执行原则:
- 先止血,再拆层,再提速;
- 每一步都要保证现有业务可用;
- 每个阶段结束后都要做功能回归;
- 不在同一阶段同时改动 UI、Store、地图渲染层的大块逻辑。
---
## 2. 本轮重构目标
本轮只完成以下确定目标:
- 收口当前明显缺陷和遗留代码;
- 建立基础类型和索引;
- 将分散在组件中的核心业务规则收口;
- 拆分地图 Store建立更清晰的数据职责
- 抽离统一编排层;
- 拆分 `map.ol.ts` 的核心管理职责;
- 保证图层树、图例、锚点显隐链路更清晰;
- 为后续继续重构预留稳定结构。
---
## 3. 阶段一:现状收口与问题修复
## 3.1 清理明显遗留问题
- [ ] 删除 `map.ol.ts` 中无意义代码和重复日志
- [ ] 清理大段失效注释,保留必要说明
- [ ] 统一地图相关文件中的临时 `console.log`
涉及文件:
- `src/components/gis/map.ol.ts`
验收标准:
- 页面可正常编译;
- 首次进入地图页面不报错;
- 控制台不再出现未定义函数或变量错误;
- 默认图层、图例、锚点仍可正常显示。
## 3.2 补充基础类型定义
- [ ] 新增地图图层类型定义
- [ ] 新增图例结构类型定义
- [ ] 新增锚点数据类型定义
- [ ] 新增筛选参数类型定义
- [ ] 为 `map.ts`、`map.class.ts`、`map.ol.ts` 替换第一批高频 `any`
建议新增文件:
- `src/modules/map/types/map-layer.ts`
- `src/modules/map/types/map-legend.ts`
- `src/modules/map/types/map-point.ts`
- `src/modules/map/types/map-filter.ts`
验收标准:
- 核心地图模块类型边界可读;
- 新增类型后不影响现有运行;
- `map.ts`、`map.ol.ts` 中关键方法参数不再全部使用 `any`
## 3.3 建立基础索引
- [x] 建立 `layerByKey` 索引
- [x] 建立 `legendByNameEn` 索引
- [x] 建立 `legendByLayerCode` 索引
- [x] 将 `findLayerByKey()` 的高频调用逐步替换为索引访问
- [x] 将图例派生中的重复递归改为“初始化索引 + 增量查询”
优先改造位置:
- `src/store/modules/map.ts`
验收标准:
- 图层查找和图例查找不再完全依赖全量递归;
- 图层勾选、图例切换后响应速度不下降;
- 功能表现与现状一致。
---
## 4. 阶段二:规则收口
## 4.1 收口互斥规则
- [x] 将图层互斥逻辑从 `LayerController.vue` 中移出
- [x] 将视频监控站与 AI 视频监控站互斥统一到规则函数
- [x] 将环保设施与环保设施在建互斥统一到规则函数
- [x] 将珍稀鱼类与沿程鱼类互斥统一到规则函数
- [x] 保证互斥规则只有一个入口执行
建议新增文件:
- `src/modules/map/domain/map-layer-rules.ts`
涉及文件:
- `src/components/mapController/LayerController.vue`
- `src/store/modules/map.ts`
验收标准:
- 图层树勾选时互斥结果稳定;
- 不再同时在组件和 Store 两处维护同一套互斥规则;
- 勾选结果、图例结果、地图显示结果保持一致。
## 4.2 收口图例派生规则
- [x] 将“图层选中后生成图例”逻辑提炼为独立函数
- [x] 将“环保设施图例自动补充”逻辑提炼为独立规则
- [x] 分离图例原始结构与图例选中状态
- [x] 保证 `legendDataOriginal` 不再被运行态逻辑污染
建议新增文件:
- `src/modules/map/domain/legend-deriver.ts`
涉及文件:
- `src/store/modules/map.ts`
- `src/components/mapLegend/index.vue`
验收标准:
- 图例显示仍按当前选中图层正确联动;
- 图例点击后锚点显隐正确;
- 图例原始结构与运行时状态职责更清晰。
---
## 5. 阶段三:拆分 Store
## 5.1 拆分配置状态
- [ ] 抽离图层树配置状态
- [ ] 抽离图例原始配置状态
- [ ] 抽离页面地图配置加载逻辑
建议新增文件:
- `src/modules/map/stores/map-config.store.ts`
当前迁移来源:
- `src/store/modules/map.ts`
- `src/api/map.ts`
## 5.2 拆分运行状态
- [ ] 抽离当前选中图层 key
- [ ] 抽离当前选中图例 key
- [ ] 抽离当前基地、时间范围、缩放级别等运行态
- [ ] 统一“当前地图状态”的唯一来源
建议新增文件:
- `src/modules/map/stores/map-view.store.ts`
## 5.3 拆分数据缓存
- [ ] 抽离锚点缓存
- [ ] 抽离图层加载状态
- [ ] 抽离锚点合并数据 `pointData`
- [ ] 为每个图层维护独立 `loading / loaded / error`
建议新增文件:
- `src/modules/map/stores/map-data.store.ts`
验收标准:
- 原 `map.ts` 体积明显下降;
- 配置、运行态、数据缓存职责分离;
- 现有组件仍可通过兼容方式读取数据;
- 默认图层、图例、锚点加载不受影响。
---
## 6. 阶段四:建立统一编排层
## 6.1 新增地图编排器
- [x] 新增地图模块统一编排入口
- [x] 将地图初始化流程迁移到编排器
- [x] 将图层勾选、图例勾选、基地切换、时间筛选、搜索定位改为统一命令
- [x] 收口 `GisView.vue` 中的配置加载与监听联动逻辑
建议新增文件:
- `src/modules/map/application/map-orchestrator.ts`
## 6.2 统一入口命令
- [x] 定义 `initialize(pageKey)`
- [x] 定义 `toggleLayer(layerKey)`
- [x] 定义 `toggleLegend(layerKey, legendKey)`
- [x] 定义 `changeBaseId(baseId)`
- [x] 定义 `changeTimeRange(range)`
- [x] 定义 `focusPoint(pointId)`
涉及文件:
- `src/components/gis/GisView.vue`
- `src/components/mapController/LayerController.vue`
- `src/components/mapLegend/index.vue`
- `src/components/mapFilter/index.vue`
验收标准:
- 地图相关 UI 组件不再直接拼复杂业务逻辑;
- 组件交互都通过统一入口触发;
- 图层树、图例、筛选的联动链路更容易追踪。
---
## 7. 阶段五:拆分 OpenLayers 渲染层
## 7.1 拆分点图层管理
- [ ] 从 `map.ol.ts` 中抽离锚点图层创建逻辑
- [ ] 从 `map.ol.ts` 中抽离锚点显隐逻辑
- [ ] 从 `map.ol.ts` 中抽离图例控制锚点逻辑
- [ ] 在点图层管理模块中维护图层注册表
建议新增文件:
- `src/components/gis/ol/point-layer-manager.ts`
当前迁移来源:
- `src/components/gis/map.ol.ts`
## 7.2 拆分 Popup 管理
- [ ] 抽离 `initPopupOverlay()`
- [ ] 抽离 `detectFeatureAtPixel()`
- [ ] 抽离 `showPopup()`
- [ ] 收口 hover 和 click 交互逻辑
建议新增文件:
- `src/components/gis/ol/popup-manager.ts`
## 7.3 拆分区域过滤管理
- [x] 抽离基地切换后的区域裁切逻辑
- [x] 抽离点在面内判断逻辑
- [x] 抽离区域外锚点显隐逻辑
- [x] 抽离遮罩应用与清理逻辑
建议新增文件:
- `src/components/gis/ol/region-mask-manager.ts`
验收标准:
- `map.ol.ts` 文件长度和职责明显收缩;
- 点图层、Popup、基地裁切三类逻辑各自独立
- 现有地图交互行为不变。
---
## 8. 阶段六:组件瘦身
## 8.1 `GisView.vue`
- [x] 仅保留地图容器、地图初始化调用、组件挂载
- [x] 移除配置请求和复杂 watch 编排逻辑
- [x] 只通过编排器触发初始化和页面切换
## 8.2 `LayerController.vue`
- [x] 只保留树渲染与勾选事件
- [x] 移除互斥规则
- [x] 移除基础图层初始化编排逻辑
## 8.3 `MapLegend.vue`
- [x] 只保留图例渲染与点击事件分发
- [x] 不直接调用地图实例
## 8.4 `MapFilter.vue`
- [x] 只保留表单与用户输入
- [x] 搜索、容量、时间、基地变化全部通过编排器分发
- [x] 不直接修改图例运行态和锚点显隐
验收标准:
- 组件文件职责单一;
- UI 组件中不再出现大段业务逻辑;
- 地图相关行为主要集中在编排层和 Store。
---
## 9. 阶段七:性能优化
## 9.1 请求与缓存优化
- [x] 将 `GisUrlList.ts` 预编译为索引字典,而不是每次请求时重建
- [x] 实现真实请求去重
- [x] 增加请求取消能力,避免菜单切换时旧请求回写
- [x] 对图层加载增加并发控制
- [x] 将缓存 key 与图层 key、筛选条件绑定
## 9.2 锚点显示优化
- [x] 图例切换时只处理目标图例对应的锚点集合
- [x] 图层切换时优先切换图层可见性,不重复加点
- [x] 减少 hover 时全量点图层重绘
- [x] 减少样式函数中的业务判断复杂度
验收标准:
- 首屏加载时长不高于当前;
- 图层勾选、图例勾选、基地切换响应速度优于当前;
- 菜单快速切换时不出现旧数据回写。
---
## 10. 回归测试清单
每完成一个阶段,至少回归以下功能:
- [x] 地图初始化正常
- [x] 默认基础图层正常显示
- [x] 图层树勾选与取消勾选正常
- [x] 图例随图层选中动态显示
- [x] 图例点击能正确控制锚点显隐
- [x] 基地切换后区域裁切和锚点过滤正常
- [x] 锚点 hover Popup 正常
- [x] 锚点点击详情弹窗正常
- [x] 时间筛选、容量筛选、搜索定位正常
- [x] 视频监控站与 AI 视频监控站互斥正常
- [x] 菜单切换后地图数据不串页
---
## 11. 实施顺序建议
推荐严格按以下顺序执行:
1. 阶段一:现状收口与问题修复
2. 阶段二:规则收口
3. 阶段三:拆分 Store
4. 阶段四:建立统一编排层
5. 阶段五:拆分 OpenLayers 渲染层
6. 阶段六:组件瘦身
7. 阶段七:性能优化
不建议直接跳到渲染层拆分或性能优化,否则会在旧结构上重复返工。
---
## 12. 本轮交付标准
当本清单全部完成后,应达到以下结果:
- 地图模块核心职责划分清晰;
- 图层树、图例、锚点、筛选、基地切换链路可追踪;
- 关键规则不再散落在多个组件里;
- `map.ts``map.ol.ts` 体积明显下降;
- 新增地图业务时有明确扩展点;
- 后续继续做底图体系优化、长期性能建设时不需要再推翻本轮结构。

15
frontend-sjgl/index.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="qgc-buji-web" />
<meta name="keywords" content="qgc-buji-web" />
<title>全过程数据管理子系统</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@ -0,0 +1,97 @@
{
"name": "qgc-buji-web",
"version": "1.2.0",
"scripts": {
"dev": "vite serve --mode development",
"build": "vite build --mode production",
"build:mvn": "vite build --mode production",
"serve": "vite preview",
"lint": "eslint src/**/*.{ts,js,vue} --fix",
"prettier": "prettier --write ."
},
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
"@element-plus/icons-vue": "^2.0.10",
"@turf/turf": "^7.3.5",
"@types/js-cookie": "^3.0.2",
"@univerjs-pro/exchange-client": "0.15.0",
"@univerjs/core": "0.14.0",
"@univerjs/preset-sheets-core": "^0.14.0",
"@univerjs/presets": "^0.14.0",
"@vueuse/core": "^9.1.1",
"@wangeditor/editor": "^5.0.0",
"@wangeditor/editor-for-vue": "^5.1.10",
"ant-design-vue": "latest",
"antdv-draggable-modal": "^1.1.6",
"axios": "^1.2.0",
"better-scroll": "^2.4.2",
"cesium": "^1.141.0",
"dayjs": "^1.11.20",
"default-passive-events": "^2.0.0",
"dom-to-image": "^2.6.0",
"echarts": "^5.2.2",
"element-plus": "^2.2.27",
"esri-leaflet": "^3.0.19",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
"js-base64": "^3.7.5",
"js-cookie": "^3.0.1",
"jsencrypt": "^3.3.2",
"jszip": "^3.10.1",
"leaflet": "^1.9.4",
"lodash": "^4.18.1",
"moment": "^2.30.1",
"nprogress": "^0.2.0",
"ol": "^10.8.0",
"path-browserify": "^1.0.1",
"path-to-regexp": "^6.2.0",
"pdfjs-dist": "^6.0.227",
"pinia": "^2.0.12",
"react": "18",
"react-dom": "18",
"screenfull": "^6.0.0",
"sortablejs": "^1.14.0",
"video.js": "^8.23.7",
"videojs-contrib-hls": "^5.15.0",
"vue": "^3.2.40",
"vue-ant-modal-enhance": "^1.2.2",
"vue-i18n": "^9.1.9",
"vue-router": "^4.1.6",
"vuedraggable": "^2.24.3",
"wujie": "^1.0.24",
"wujie-vue3": "^1.0.24",
"xlsx": "^0.18.5",
"xlsx-js-style": "^1.2.0"
},
"devDependencies": {
"@commitlint/cli": "^16.2.3",
"@commitlint/config-conventional": "^16.2.1",
"@types/dom-to-image": "^2.6.7",
"@types/lodash": "^4.17.24",
"@types/node": "^16.11.7",
"@types/nprogress": "^0.2.0",
"@types/path-browserify": "^1.0.0",
"@typescript-eslint/eslint-plugin": "^5.19.0",
"@typescript-eslint/parser": "^5.19.0",
"@vitejs/plugin-vue": "^4.0.0",
"autoprefixer": "^10.4.13",
"eslint": "^8.14.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.6.0",
"fast-glob": "^3.2.11",
"husky": "^7.0.4",
"postcss": "^8.4.20",
"prettier": "^2.6.2",
"sass": "^1.53.0",
"tailwindcss": "^3.2.4",
"typescript": "latest",
"vite": "^4.0.3",
"vite-plugin-cesium": "^1.2.22",
"vite-plugin-svg-icons": "^2.0.1",
"vue-tsc": "latest"
},
"repository": "https://gitee.com/youlaiorg/vue3-element-admin.git",
"author": "有来开源组织",
"license": "MIT"
}

13865
frontend-sjgl/pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

1
frontend-sjgl/readme.md Normal file
View File

@ -0,0 +1 @@
这里放置前端项目的readme文件

19
frontend-sjgl/src/App.vue Normal file
View File

@ -0,0 +1,19 @@
<script setup lang="ts">
import { ElConfigProvider } from 'element-plus';
import { useAppStore, usetTheme } from '@/store/modules/app';
import locale from 'ant-design-vue/es/locale/zh_CN';
const appStore = useAppStore();
</script>
<template>
<!--
1.地图抽吸
2.地图文字和点显示
-->
<el-config-provider :locale="appStore.locale" :size="appStore.size">
<a-config-provider :theme="usetTheme" :locale="locale">
<router-view />
</a-config-provider>
</el-config-provider>
</template>

View File

@ -0,0 +1,310 @@
import request from '@/utils/request';
// 基础信息 集团/公司
export function getCompanyList(data) {
return request({
url: '/env/hycd/selectForDropdown',
method: 'get',
params: data
});
}
// 基础信息 表格
export function getPowerTableList(data) {
return request({
url: '/env/engInfo/vmsstbprpt/GetKendoList',
method: 'post',
data
});
}
// 基础信息 编辑
export function updatePowerInfo(data) {
return request({
url: '/env/engInfo/update',
method: 'post',
data
});
}
// 基础信息 删除
export function deletePowerInfo(data) {
return request({
url: '/env/engInfo/delete',
method: 'post',
data
});
}
// 鱼类基础信息 科
export function getFishResourceList(data) {
return request({
url: '/fpr/fishDic/GetKendoList',
method: 'post',
data
});
}
// 鱼类基础信息 表格
export function getFishResourceZYList(data) {
return request({
url: '/fpr/fishDic/zy/GetKendoList',
method: 'post',
data
});
}
// 批复文件
export function getApprovalStatusList(data) {
return request({
url: '/eng/base/eiaapproval/GetKendoList',
method: 'post',
data
});
}
// 生态流量运行数据 - 小时
export function getFlowDataList(data) {
return request({
url: '/eq/data/GetKendoListCust',
method: 'post',
data
});
}
// 生态流量运行数据 - 日
export function getFlowDataDayList(data) {
return request({
url: '/eq/data/day/GetKendoListCust',
method: 'post',
data
});
}
// 生态流量运行数据 - 月
export function getFlowDataMonthList(data) {
return request({
url: '/eq/data/drtp/GetKendoListCust',
method: 'post',
data
});
}
// 水质监测数据 - 断面
export function getWaterDataSectionList(data) {
return request({
url: '/wq/msstbprpt/GetKendoList',
method: 'post',
data
});
}
// 水质监测数据 - 小时
export function getWaterDataList(data) {
return request({
url: '/wq/data/GetKendoListCust',
method: 'post',
data
});
}
// 水质监测数据 - 日
export function getWaterDataDayList(data) {
return request({
url: '/wq/data/day/GetKendoListCust',
method: 'post',
data
});
}
// 水质监测数据 - 月
export function getWaterDataMonthList(data) {
return request({
url: '/wq/data/drtp/GetKendoListCust',
method: 'post',
data
});
}
// 水质监测数据 编辑
export function updateWaterDataInfo(data) {
return request({
url: '/wq/updateWqRsData',
method: 'post',
data
});
}
// 水质监测数据 删除
export function deleteWaterDataInfo(data) {
return request({
url: '/wq/removeKendoByIds',
method: 'post',
data
});
}
// 垂向 - 列表
export function getVerticalList(data) {
return request({
url: '/wt/cxDetail/GetKendoListCust',
method: 'post',
data
});
}
// 垂向 - 编辑
export function updateVerticalInfo(data) {
return request({
url: '/wt/cxDetail/updateWtvtRData',
method: 'post',
data
});
}
// 垂向 - 删除
export function deleteVerticalInfo(data) {
return request({
url: '/wt/cxDetail/removeKendoByIds',
method: 'post',
data
});
}
// 表层水温 - 断面
export function getSurfaceTempSectionList(data) {
return request({
url: '/wt/msstbprpt/GetKendoList',
method: 'post',
data
});
}
// 表层水温 - 小时
export function getSurfaceTempList(data) {
return request({
url: '/wt/alongDetail/GetKendoListCust',
method: 'post',
data
});
}
// 表层水温 - 日
export function getSurfaceTempDayList(data) {
return request({
url: '/wt/alongDetail/day/GetKendoListCust',
method: 'post',
data
});
}
// 表层水温 - 月
export function getSurfaceTempMonthList(data) {
return request({
url: '/wt/alongDetail/drtp/GetKendoListCust',
method: 'post',
data
});
}
// 表层水温 - 编辑
export function updateSurfaceTempInfo(data) {
return request({
url: '/wt/alongDetail/updateWtrvRData',
method: 'post',
data
});
}
// 表层水温 - 删除
export function deleteSurfaceTempInfo(data) {
return request({
url: '/wt/alongDetail/drtp/removeKendoByIds',
method: 'post',
data
});
}
// 表层水温 - 数据分析 - 断面
export function getSurfaceTempAnalysisList(data) {
return request({
url: '/wt/msstbprpt/eng/GetKendoList',
method: 'post',
data
});
}
// 表层水温 - 数据分析 - excel
export function getSurfaceTempAnalysisExcel(data) {
return request({
url: '/wt/wtrvAmend/dayAmend/GetKendoListCust',
method: 'post',
data
});
}
// 表层水温 - 数据分析 - 保存
export function saveSurfaceTempAnalysisExcel(data) {
return request({
url: '/wt/wtrvAmend/dayAmend/saveAmendData',
method: 'post',
data
});
}
// 过鱼设施名称 - 断面
export function getFishReleaseMonitorSectionList(data) {
return request({
url: '/fp/msstbprpt/GetKendoList',
method: 'post',
data
});
}
// 过鱼监测数据
export function getFishReleaseMonitorList(data) {
return request({
url: '/fp/query/qgc/GetKendoListCust',
method: 'post',
data
});
}
// 鱼类 放鱼
export function getFishReleaseList(data) {
return request({
url: '/fb/fishrun/qgc/GetKendoListCust',
method: 'post',
data
});
}
// 流量站 - 断面
export function getFlowStationSectionList(data) {
return request({
url: '/zq/msstbprpt/GetKendoList',
method: 'post',
data
});
}
// 流量站 - 小时
export function getFlowStationList(data) {
return request({
url: '/zq/river/GetKendoListCust',
method: 'post',
data
});
}
// 流量站 - 日
export function getFlowStationDayList(data) {
return request({
url: '/zq/river/day/GetKendoListCust',
method: 'post',
data
});
}
// 流量站 - 月
export function getFlowStationMonthList(data) {
return request({
url: '/zq/river/drtp/GetKendoListCust',
method: 'post',
data
});
}
// 流量站 - 编辑
export function updateFlowStationInfo(data) {
return request({
url: '/zq/river/updateRiverRData',
method: 'post',
data
});
}
// 流量站 - 删除
export function deleteFlowStationInfo(data) {
return request({
url: '/zq/river/removeKendoByIds',
method: 'post',
data
});
}

View File

@ -0,0 +1,175 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { LoginData, TokenResult, VerifyCode } from './types';
export function getAccessToken() {
return request({
url: '/register/accessToken',
method: 'get'
});
}
/**
*
* @param data {LoginForm}
* @returns
*/
export function loginApi(data: LoginData): AxiosPromise<TokenResult> {
return request({
url: '/user/login',
method: 'post',
params: data
});
}
/**
*
*/
export function logoutApi() {
return request({
url: '/user/logout',
method: 'post'
});
}
/**
*
*/
export function getCaptcha(): AxiosPromise<VerifyCode> {
return request({
url: '/user/code?t=' + new Date().getTime().toString(),
method: 'get'
});
}
/**
*
*/
export function registerUser(data: any): AxiosPromise<any> {
return request({
url: '/sms/register',
method: 'post',
data
});
}
/**
*
* @param companyId ID(),
*/
export function getBasinList(): AxiosPromise<any[]> {
return request({
url: '/register/dropdown/rvcd',
method: 'get',
headers: {
'register-token': localStorage.getItem('register-token') || ''
}
// params: baseid ? { baseid } : {}
});
}
/**
* (,)
*/
export function getGroupList(): AxiosPromise<any[]> {
return request({
url: '/register/dropdown/hycd',
method: 'get',
params: { lx: 1 },
headers: {
'register-token': localStorage.getItem('register-token') || ''
}
});
}
/**
*
*/
export function getCompanyList(): AxiosPromise<any[]> {
return request({
url: '/register/dropdown/hycd',
method: 'get',
params: { lx: 2 },
headers: {
'register-token': localStorage.getItem('register-token') || ''
}
});
}
/**
*
*/
export function getStationList(params: any): AxiosPromise<any[]> {
return request({
url: '/register/dropdown/engInfo',
method: 'post',
data: params,
headers: {
'register-token': localStorage.getItem('register-token') || ''
}
});
}
/**
*
* @param phone
* @param type 1- 2-
*/
export function sendSmsCode(phone: string, type = 1): AxiosPromise<any> {
return request({
url: '/sms/sendCode',
method: 'post',
data: { phone, type }
});
}
/**
*
* @param phone
* @param code
* @param type 1- 2-
*/
export function verifySmsCode(
phone: string,
code: string,
type = 1
): AxiosPromise<any> {
return request({
url: '/sms/verifyCode',
method: 'post',
data: { phone, code, type }
});
}
/**
*
* @param phone
* @param code
*/
export function smsLoginApi(
phone: string,
code: string
): AxiosPromise<TokenResult> {
return request({
url: '/sms/login',
method: 'post',
data: { phone, code }
});
}
/**
*
* @param phone
* @param code
* @param password
*/
export function resetPassword(
phone: string,
code: string,
password: string
): AxiosPromise<any> {
return request({
url: '/sms/resetPassword',
method: 'post',
data: { phone, code, password }
});
}

View File

@ -0,0 +1,34 @@
/**
*
*/
export interface LoginData {
username: string;
password: string;
code: string;
uuid: string;
/**
* Code
*/
//verifyCode: string;
/**
* Code服务端缓存key(UUID)
*/
// verifyCodeKey: string;
}
/**
* Token响应类型
*/
export interface TokenResult {
token: string;
refreshToken: string;
expires: number;
}
/**
*
*/
export interface VerifyCode {
verifyCodeImg: string;
verifyCodeKey: string;
}

View File

@ -0,0 +1,9 @@
import request from '@/utils/request';
//修改密码
export function updatePassword(params:any) {
return request({
url: '/user/updatePassword',
method: 'post',
data: params
});
}

View File

@ -0,0 +1,139 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { DeptForm, DeptQuery, Dept } from './types';
//获取组织架构
export function getTreelist(queryParams:any) {
return request({
url: '/system/organization/getOrgTree',
method: 'POST',
params: queryParams
});
}
//新增企业或部门
export function addTreelist(queryParams:any) {
return request({
url: '/system/organization/addOrg',
method: 'POST',
data: queryParams
});
}
// 修改企业部门
export function updataTreelist(queryParams:any) {
return request({
url: '/system/organization/updateById',
method: 'POST',
data: queryParams
});
}
//删除企业
export function delTreelist(queryParams:any) {
return request({
url: '/system/organization/deleteById',
method: 'POST',
params: queryParams
});
}
//获取部门信息
export function gettableData(queryParams:any) {
return request({
url: '/system/organization/getOrganizationById',
method: 'POST',
params: queryParams
});
}
//部门是否有效
export function deptIsVaild(queryParams:any) {
return request({
url: '/system/organization/setIsValid',
method: 'POST',
params: queryParams
});
}
//修改部门信息
export function reviseDepartment(queryParams:any) {
return request({
url: '/system/organization/updateById',
method: 'POST',
data: queryParams
});
}
/**
*
*
* @param queryParams
*/
export function listDepartments(queryParams?: DeptQuery): AxiosPromise<Dept[]> {
return request({
url: '/api/v1/dept',
method: 'get',
params: queryParams
});
}
/**
*
*/
export function listDeptOptions(): AxiosPromise<Dept[]> {
return request({
url: '/api/v1/dept/options',
method: 'get'
});
}
/**
*
*
* @param id
*/
export function getDeptForm(id: string): AxiosPromise<DeptForm> {
return request({
url: '/api/v1/dept/' + id + '/form',
method: 'get'
});
}
/**
*
*
* @param data
*/
export function addDept(data: DeptForm) {
return request({
url: '/api/v1/dept',
method: 'post',
data: data
});
}
/**
*
*
* @param id
* @param data
*/
export function updateDept(id: string, data: DeptForm) {
return request({
url: '/api/v1/dept/' + id,
method: 'put',
data: data
});
}
/**
*
*
* @param ids
*/
export function deleteDept(ids: string) {
return request({
url: '/api/v1/dept/' + ids,
method: 'delete'
});
}

View File

@ -0,0 +1,34 @@
/**
*
*/
export interface DeptQuery {
keywords: string | undefined;
status: number | undefined;
}
/**
*
*/
export interface Dept {
id: string;
name: string;
parentId: string;
treePath: string;
sort: number;
status: number;
leader?: string;
mobile?: string;
email?: string;
children: Dept[];
}
/**
*
*/
export interface DeptForm {
id?: string;
parentId: string;
name: string;
sort: number;
status: number;
}

View File

@ -0,0 +1,250 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import {
DictQuery,
DictPageResult,
DictTypeForm,
DictItemQuery,
DictItemPageResult,
DictItemForm
} from './types';
// 查询字典
export function getTreelist(params:any) {
return request({
url: '/system/dictionary/dictList',
method: 'get',
params: params
});
}
// 新增字典
export function addDict(params:any) {
return request({
url: '/system/dictionary/addDict',
method: 'post',
data: params
});
}
// 修改字典
export function updateDict(params:any) {
return request({
url: '/system/dictionary/updateDict',
method: 'post',
data: params
});
}
// 删除字典
export function deleteById(params:any) {
return request({
url: '/system/dictionary/deleteById',
method: 'post',
params: params
});
}
// 字典排序
export function changeDictOrder(params:any) {
return request({
url: '/system/dictionary/changeDictOrder',
method: 'post',
params: params
});
}
// 查询字典项
export function getDictItemById(params:any) {
return request({
url: '/system/dictionaryItems/page',
method: 'get',
params: params
});
}
// 新增字典项
export function addDictionaryItem(params:any) {
return request({
url: '/system/dictionaryItems/addDictionaryItem',
method: 'post',
data: params
});
}
// 修改字典项
export function updateDictionaryItem(params:any) {
return request({
url: '/system/dictionaryItems/updateDictionaryItem',
method: 'post',
data: params
});
}
// 删除字典项
export function deleteDictItemById(params:any) {
return request({
url: '/system/dictionaryItems/deleteDictItemById',
method: 'post',
params: params
});
}
// 批量删除字典项
export function deleteDictItemByIds(params:any) {
return request({
url: '/system/dictionaryItems/deleteDictItemByIds',
method: 'post',
params: params
});
}
// 字典项排序
export function changeItemOrder(params:any) {
return request({
url: '/system/dictionaryItems/changeItemOrder',
method: 'post',
params: params
});
}
//根据字典编号查询字典项列表
export function getDictItemsByCode(params:any) {
return request({
url: '/system/dictionary/getDictItemsByCode',
method: 'get',
params: params
});
}
/**
*
*
* @param queryParams
*/
export function listDictTypePages(
queryParams: DictQuery
): AxiosPromise<DictPageResult> {
return request({
url: '/api/v1/dict/types/pages',
method: 'get',
params: queryParams
});
}
/**
*
*
* @param id
*/
export function getDictTypeForm(id: number): AxiosPromise<DictTypeForm> {
return request({
url: '/api/v1/dict/types/' + id + '/form',
method: 'get'
});
}
/**
*
*
* @param data
*/
export function addDictType(data: DictTypeForm) {
return request({
url: '/api/v1/dict/types',
method: 'post',
data: data
});
}
/**
*
*
* @param id
* @param data
*/
export function updateDictType(id: number, data: DictTypeForm) {
return request({
url: '/api/v1/dict/types/' + id,
method: 'put',
data: data
});
}
/**
*
*/
export function deleteDictTypes(ids: string) {
return request({
url: '/api/v1/dict/types/' + ids,
method: 'delete'
});
}
/**
*
*
* @param typeCode
*/
export function getDictionaries(typeCode: string): AxiosPromise<any[]> {
return request({
url: '/api/v1/dict/types/' + typeCode + '/items',
method: 'get'
});
}
/**
*
*/
export function listDictItemPages(
queryParams: DictItemQuery
): AxiosPromise<DictItemPageResult> {
return request({
url: '/api/v1/dict/items/pages',
method: 'get',
params: queryParams
});
}
/**
*
*
* @param id
*/
export function getDictItemData(id: number): AxiosPromise<DictItemForm> {
return request({
url: '/api/v1/dict/items/' + id + '/form',
method: 'get'
});
}
/**
*
*
* @param data
*/
export function saveDictItem(data: DictItemForm) {
return request({
url: '/api/v1/dict/items',
method: 'post',
data: data
});
}
/**
*
*
* @param id
* @param data
*/
export function updateDictItem(id: number, data: DictItemForm) {
return request({
url: '/api/v1/dict/items/' + id,
method: 'put',
data: data
});
}
/**
*
*
* @param ids ID(,)
*/
export function deleteDictItems(ids: string) {
return request({
url: '/api/v1/dict/items/' + ids,
method: 'delete'
});
}

View File

@ -0,0 +1,92 @@
/**
*
*/
export interface DictQuery extends PageQuery {
/**
*
*/
name?: string;
}
interface PageResult<T> {
total: number;
list: T[];
}
/**
*
*/
export interface Dict {
id: number;
code: string;
name: string;
status: number;
remark: string;
}
/**
*
*/
export type DictPageResult = PageResult<Dict[]>;
/**
*
*/
export interface DictTypeForm {
id: number | undefined;
name: string;
code: string;
status: number;
remark: string;
}
interface PageQuery {
pageIndex: number;
pageSize: number;
}
/**
*
*/
export interface DictItemQuery extends PageQuery {
/**
*
*/
name?: string;
/**
*
*/
typeCode?: string;
}
/**
*
*/
export interface DictItem {
id: number;
name: string;
value: string;
typeCode: string;
sort: number;
status: number;
defaulted: number;
remark?: string;
}
/**
*
*/
export type DictItemPageResult = PageResult<DictItem[]>;
/**
*
*/
export interface DictItemForm {
id?: number;
typeCode?: string;
typeName?: string;
name: string;
code: string;
value: string;
status: number;
sort: number;
remark: string;
}

View File

@ -0,0 +1,138 @@
import request from '@/utils/request';
// 分页查询过鱼数据
export function getFishDraftPage(data: any) {
return request({
url: '/data/fishDraft/page',
method: 'post',
data
});
}
//新增过鱼数据
export function addFishDraft(queryParams: any) {
return request({
url: '/data/fishDraft/saveDraft',
method: 'post',
data: queryParams
});
}
//修改过鱼数据
export function editFishDraft(queryParams: any) {
return request({
url: '/data/fishDraft/updateDraft',
method: 'post',
data: queryParams
});
}
//删除 过鱼数据
export function delFishDraft(data: any) {
return request({
url: '/data/fishDraft/batchRemoveDraft',
method: 'post',
data
});
}
//提交过鱼数据
export function submitFishDraft(data: any) {
return request({
url: '/data/fishDraft/submitDrafts',
method: 'post',
data
});
}
//提交全部过鱼数据
export function batchApproveAll() {
return request({
url: '/data/fishDraft/submitDraftsAll',
method: 'post'
});
}
//审批过鱼数据
export function successFishDraft(data: any) {
return request({
url: '/data/fishDraft/batchApprove',
method: 'post',
data
});
}
//驳回过鱼数据
export function rejectFishDraft(data: any) {
return request({
url: '/data/fishDraft/reject',
method: 'post',
data
});
}
// 导入zip
export function importFishZip(data: FormData) {
return request({
url: '/data/fishDraft/importZip',
method: 'post',
data,
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 1000 * 60 * 5 // 5分钟
});
}
// 取消导入任务
export function cancelImportTask(data: any) {
return request({
url: '/data/fishDraft/cancelImport',
method: 'post',
data
});
}
//检测用户导入状态
export function checkImportStatus() {
return request({
url: '/data/fishDraft/checkImportStatus',
method: 'get'
});
}
// 查询用户导入结果
export function getLastImportResult() {
return request({
url: '/data/fishDraft/getLastImportResult',
method: 'get'
});
}
export function deleteFile(params: any) {
return request({
url: '/data/fishDraft/deleteFile',
method: 'get',
params
});
}
// 批量保存草稿
export function batchSaveDraft(data: any) {
return request({
url: '/data/fishDraft/batchSaveDraft',
method: 'post',
data
});
}
// 批量删除 审批已驳回的
export function batchRemoveDraft(data: any) {
return request({
url: '/data/approvalMain/batchDelete',
method: 'post',
data
});
}
// 过鱼倒数统计
export function statistics(data: any) {
return request({
url: '/data/fishDraft/statistics',
method: 'post',
data
});
}
// 催促
export function batchUrgeContent(data: any) {
return request({
url: '/sms/batchUrgeContent',
method: 'post',
data
});
}

View File

@ -0,0 +1,61 @@
import request from '@/utils/request';
// 获取图例列表
export function getModuleMapLegendList(params?: { moduleId?: string }) {
const url = params?.moduleId
? `/mapLegend/getModuleMapLegendList?moduleId=${params.moduleId}`
: '/mapLegend/getModuleMapLegendList';
return request({
url,
method: 'get'
});
}
// 获取地图配置列表
export function getMapList(data: any) {
return request({
url: '/mapmodule/getMapData',
method: 'post',
data
});
}
// 获取梯级流域地图
export function getQgcRvcd(data: any) {
return request({
url: '/eng/base/rsvrcscdb/getQgcRvcd',
method: 'post',
data
});
}
// 获取梯级流域下拉框列表
export function getRvcdList(data: any) {
return request({
url: '/eng/base/rsvrcscdb/rvcd',
method: 'post',
data
});
}
// 获取梯级流域下拉框图表数据
export function getKendoList(data: any) {
return request({
url: '/eng/base/rsvrcscdb/GetKendoList',
method: 'post',
data
});
}
// 鱼类分布查询 - 站点查询
export function getFishPointList(data: any) {
return request({
url: '/wte/we/fishPoint/qgc/GetKendoListCust',
method: 'post',
data
});
}
// 鱼类分布查询 -鱼查询
export function getFishList(data: any) {
return request({
url: '/wte/we/fishList/GetKendoListCust',
method: 'post',
data
});
}

View File

@ -0,0 +1,544 @@
import request from '@/utils/request';
export function getStcdDetail(url: string, stcd: string) {
return request({
url: url,
method: 'get',
params: { stcd }
});
}
// 公共接口 - post
export function queryPostUrlList(url: string, data: any) {
return request({
url: url,
method: 'post',
data
});
}
// 公共接口 - 获取预览地址
export function getIdUrl(params: any) {
return request({
url: import.meta.env.VITE_APP_ATTACHMENT_URL + '/get',
method: 'get',
params
});
}
export function postIdUrl(data: any) {
return request({
url: import.meta.env.VITE_APP_ATTACHMENT_URL + '/get',
method: 'post',
data,
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
}
});
}
// 查询站点建设状态
export function getBuildState(data: any) {
return request({
url: '/wt/vmsstbprpt/GetKendoList',
method: 'post',
data: {
filter: data.filter,
select: ['bldsttCcode', 'engIwtCode', 'engDwtCode']
}
});
}
// 查询鱼类栖息地监测数据类型可用性
export function getFishTab(stcd: string) {
return request({
url: `/wte/we/wer/getWeDefaultData`,
method: 'get',
params: { stcd }
});
}
// 检查水质站是否启用 AI 预测功能
export function checkAnalysisShow(data: any) {
return request({
url: '/overview/vmsstbprpt/GetKendoList',
method: 'post',
data
});
}
// 查询站点的关联子站点 (垂向水温、AI 识别)
export function getStInfoByStcd(params: any) {
return request({
url: '/eng/base/msstbprpt/getStInfoByStcd',
method: 'get',
params
});
}
// 检查电站是否有专题配置数据
export function checkPowerStationTopic(data: any) {
return request({
url: '/api/wmp-sys-server/sys/psbmodulelbb/GetKendoList',
method: 'post',
data
});
}
// 全景影像
export function getPanoramaList(data: any) {
return request({
url: '/eq/msstbprpt/GetKendoList',
method: 'post',
data
});
}
// 实时视频
export function getVideoList(data: any) {
return request({
url: '/vd/msstbprpt/GetKendoList',
method: 'post',
data
});
}
// 录像视频 - 时间查询
export function getNoLiveVideoYear(data: any) {
return request({
url: '/vd/GetKendoListCust',
method: 'post',
data
});
}
// 录像视频
export function getNoLiveVideoList(data: any) {
return request({
url: '/vd/runData/GetKendoListCust',
method: 'post',
data
});
}
// 实时视频单个查询
export function getVideoDetail(data: any) {
return request({
url: '/vd/GetKendoListCust',
method: 'post',
data
});
}
// 实时视频 回放
export function getVideoPlayDetail(data: any) {
return request({
url: '/vd/runData/GetKendoListCust',
method: 'post',
data
});
}
// 监测数据 - 电站
export function getMonitorData(data: any) {
return request({
url: '/eq/data/GetKendoListCust',
method: 'post',
data
});
}
// 监测数据 水温查询 栖息地
export function getMonitorDataWt(data: any) {
return request({
url: '/wt/msstbprpt/GetKendoList',
method: 'post',
data
});
}
export function getMonitorDataWq(data: any) {
return request({
url: '/wq/msstbprpt/GetKendoList',
method: 'post',
data
});
}
export function getMonitorDataZq(data: any) {
return request({
url: '/zq/msstbprpt/GetKendoList',
method: 'post',
data
});
}
// 监测数据 - 水温
export function getMonitorDataWaterTemp(data: any) {
return request({
url: '/wt/alongDetail/qgc/GetKendoListCust',
method: 'post',
data
});
}
// 监测数据 - 水温 - 查询显示 综合/等温
export function getMonitorDataWaterTempPowerStation(params: any) {
return request({
url: '/wt/wtrv/getIoWtrvFlag',
method: 'get',
params
});
}
// 监测数据 - 水温 - 、综合分析导出数据
export function exportMonitorDataWaterTempPowerStation(params: any) {
return request({
url: '/wt/alongDetail/qgc/GetKendoListCust',
method: 'post',
params,
responseType: 'blob'
});
}
// 监测数据 - 水温 - 查询是否显示 等温水深
export function getMonitorDataWaterTempPowerStation2(params: any) {
return request({
url: '/wt/alongDetail/qgc/stcdCheck2',
method: 'get',
params
});
}
// 监测数据 - 垂向水温
export function getMonitorDataWaterTempVertical(data: any) {
return request({
url: '/wt/cxDetail/GetKendoListCust',
method: 'post',
data
});
}
// 监测数据 - 水质 判断是否显示综合分析
export function getMonitorDataWaterQuality(data: any) {
return request({
url: '/wq/vmsstbprpt/GetKendoList',
method: 'post',
data
});
}
// 监测数据 - 水质 - 获取水质参数
export function getMonitorDataWaterQualityDetail(data: any) {
return request({
url: '/wq/stbprp/GetStbprpYsByStcd',
method: 'get',
params: data
});
}
// 监测数据 - 水质 - 获取水质数据
export function getMonitorDataWaterQualityList(data: any) {
return request({
url: '/wq/data/noAuth/GetKendoListCust',
method: 'post',
data
});
}
// 生态流量 - 限制范围查询 - 日
export function getMonitorDataWaterTempVerticalDay(data: any) {
return request({
url: '/eq/interval/qgc/day/GetKendoListCust',
method: 'post',
data
});
}
// 生态流量 - 限制范围查询 - 小时
export function getMonitorDataWaterTempVerticalHour(data: any) {
return request({
url: '/eq/interval/qgc/hour/GetKendoListCust',
method: 'post',
data
});
}
// 生态流量 - 查询限制和来源
export function getEngLimit(data: any) {
return request({
url: '/eq/data/getEngLimit',
method: 'post',
data
});
}
// 生态流量 - 列表 - 日
export function getMonitorDataWaterTempVerticalDayList(data: any) {
return request({
url: '/eq/data/day/GetKendoListCust',
method: 'post',
data
});
}
// 生态流量 - 列表 - 小时
export function getMonitorDataWaterTempVerticalHourList(data: any) {
return request({
url: '/eq/data/GetKendoListCust',
method: 'post',
data
});
}
// 在线监测数据
export function getMonitorDataOnline(data: any) {
return request({
url: '/fp/fpssTable/qgc/GetKendoListCust',
method: 'post',
data
});
}
// 没接
export function getMonitorDataFpq(data: any) {
return request({
url: '/fp/msstbprpt/GetKendoList',
method: 'post',
data
});
}
// 运行状态
export function getRunState(data: any) {
return request({
url: '/fp/query/qgc/sdfpssr/GetKendoListCust',
method: 'post',
data
});
}
export function getRunStateSecondPlan(data: any) {
return request({
url: '/fp/run/secondPlan/qgc/GetKendoListCust',
method: 'post',
data
});
}
// 综合分析
export function getFishZHFX(data: any) {
return request({
url: 'fp/run/fish/select',
method: 'post',
data
});
}
export function getRunStateAnalysis(data: any) {
return request({
url: '/fp/run/analysis/GetKendoListCust',
method: 'post',
data
});
}
// ai运行识别
export function getAIYXSB(data: any) {
return request({
url: '/fp/msstbprpt/getStInfoByStcd',
method: 'get',
params: data
});
}
// ai运行识别 视频/表格
export function getAIComList(data: any) {
return request({
url: '/warn/ai/com/GetKendoListCust',
method: 'post',
data
});
}
// ai运行识别 日历
export function getAIComCalendar(data: any) {
return request({
url: '/warn/ai/com/qgc/aiRecord/GetKendoListCust',
method: 'post',
data
});
}
// ai运行 日历点击
export function getAIComCalendarClick(data: any) {
return request({
url: '/warn/ai/com/qgc/aiFile/GetKendoListCust',
method: 'post',
data
});
}
// 鱼类增殖站 - 运行数据 -获取年
export function getFishProgressionYear(data: any) {
return request({
url: '/fb/fbrdmr/getFbRelatedYrByStcd',
method: 'get',
params: data
});
}
//鱼类增殖站 - 运行数据 -获取鱼
export function getFishProgressionFish(data: any) {
return request({
url: '/fp/fishDic/stcd/GetKendoList',
method: 'post',
data
});
}
// 过程图 - 亲鱼
export function getProcessDiagramParentFish(data: any) {
return request({
url: '/fb/bsmfr/fish/GetKendoListCust',
method: 'post',
data
});
}
// 过程图 - 产卵/孵化
export function getProcessDiagramHatch(data: any, type: 1 | 2) {
return request({
url: `/fb/fishhatchrecr/fish/GetKendoListCust?type=${type}`,
method: 'post',
data
});
}
// 过程图 - 鱼苗
export function getProcessDiagramFishFry(data: any) {
return request({
url: '/fb/fishbreedr/fish/GetKendoListCust',
method: 'post',
data
});
}
//增值放流情况 获取年
export function getNormalAddedSituationYear(data: any) {
return request({
url: '/fb/msfbrdm/fbFlData/GetKendoListCust',
method: 'post',
data
});
}
//增值放流情况 列表
export function getNormalAddedSituation(data: any) {
return request({
url: '/fb/msfbrdm/qgc/GetKendoListCust',
method: 'post',
data
});
}
// 科研情况
export function getNormalResearchSituation(data: any) {
return request({
url: '/fb/base/researchb/GetKendoList',
method: 'post',
data
});
}
// 珍稀植物园 - 运行数据 没接
export function getNormalDataMonitoring2Year(data: any) {
return request({
url: '/vap/vpr/year/GetKendoListCust',
method: 'post',
data
});
}
// 珍稀植物园 - 运行数据 列表
export function getNormalDataMonitoring2List(data: any) {
return request({
url: '/vap/vpr/basinVpIntDetail',
method: 'post',
data
});
}
// 珍稀动物园 - 监测数据 时间
export function getNormal2Year(data: any) {
return request({
url: '/vap/var/year/GetKendoListCust',
method: 'post',
data
});
}
// 珍稀动物园 - 监测数据 列表 没接
export function getNormal2List(data: any) {
return request({
url: '/vap/var/GetKendoListCust',
method: 'post',
data
});
}
// 水生生态调查断面 - 监测数据 年份 没接
export function getEcologyYear(data: any) {
return request({
url: '/wte/we/wer/getWeYr',
method: 'get',
params: data
});
}
// 水生生态调查断面 - 监测数据 调查批次
export function getEcologyBatch(data: any) {
return request({
url: '/wte/we/fisht/GetKendoListCust',
method: 'post',
data
});
}
// 水生生态调查断面 - 监测数据 调查鱼类列表
export function getEcologyList(data: any) {
return request({
url: '/wte/we/fisht/qgc/GetKendoListCust',
method: 'post',
data
});
}
// 水生生态调查断面 - 监测数据 水温列表 没接
export function getEcologyList1(data: any) {
return request({
url: '/wte/we/wewtr/GetKendoListCust',
method: 'post',
data
});
}
// 水生生态调查断面 - 监测数据 水质列表 没接
export function getEcologyList2(data: any) {
return request({
url: '/wte/we/wewqr/GetKendoListCust',
method: 'post',
data
});
}
// 水生生态调查断面 - 监测数据 流速列表 没接
export function getEcologyList3(data: any) {
return request({
url: '/wte/we/fvR/GetKendoListCust',
method: 'post',
data
});
}
// 野生动物检测 -现场录像 - 年份
export function getLiveFootageYear(data: any) {
return request({
url: '/wte/wva/default/GetKendoListCust',
method: 'post',
data
});
}
// 野生动物检测 -现场录像
export function getLiveFootageList(data: any) {
return request({
url: '/wte/wva/GetKendoListCust',
method: 'post',
data
});
}
// 鱼类分布明细 - 年 没接
export function getFishDistributionYear(data: any) {
return request({
url: '/wte/we/wer/getWeYr',
method: 'get',
params: data
});
}
// 鱼类分布明细 - 列表
export function getFishDistributionList(data: any) {
return request({
url: '/wte/we/fisht/qgc/GetKendoListCust',
method: 'post',
data
});
}
// 生态流量泄放设施 - 监测数据 年份 没接
export function getFlowDischargeYear(data: any) {
return request({
url: '/eq/operat/default/year',
method: 'post',
data
});
}
export function getFlowDischargeList(code: string, data: any) {
return request({
url: `/env/engInfo/stbprpData/GetKendoListCust?tbCode=${code}`,
method: 'post',
data
});
}

View File

@ -0,0 +1,159 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { MenuQuery, Menu, Resource, MenuForm } from './types';
//获取菜单表格
export function getdata(queryParams:any) {
return request({
url: '/system/menu/getMenuButtonTree',
method: 'post',
params: queryParams
});
}
//新增目录
export function addmenu(queryParams:any) {
return request({
url: '/system/menu/addMenu',
method: 'post',
data: queryParams
});
}
//修改目录
export function editmenu(queryParams:any) {
return request({
url: '/system/menu/updateById',
method: 'post',
data: queryParams
});
}
//删除
export function deltmenu(queryParams:any) {
return request({
url: '/system/menu/deleteById',
method: 'post',
params: queryParams
});
}
//排序
export function moveOrderno(params:any) {
return request({
url: '/system/menu/changeMenuOrder',
method: 'post',
params: params
});
}
//上传图标之前获取ID
//上传单个图标
export function uploadIcon (data:any) {
return request({
headers: {
'Content-Type': 'multipart/form-data'
},
url: '/system/menu/uploadIcon',
method: 'POST',
data
});
}
//删除单个图标
export function moveIcon(params:any) {
return request({
url: '/system/menu/deleteIcon',
method: 'post',
params: params
});
}
/**
*
*/
export function listRoutes() {
return request({
url: 'system/menu/treeRoutes',
method: 'get',
});
}
/**
*
*
* @param queryParams
*/
export function listMenus(queryParams: MenuQuery): AxiosPromise<Menu[]> {
return request({
url: '/api/v1/menus',
method: 'get',
params: queryParams
});
}
/**
*
*/
export function listMenuOptions(): AxiosPromise<Menu[]> {
return request({
url: '/api/v1/menus/options',
method: 'get'
});
}
/**
* (+)
*/
export function listResources(): AxiosPromise<Resource[]> {
return request({
url: '/api/v1/menus/resources',
method: 'get'
});
}
/**
*
* @param id
*/
export function getMenuDetail(id: string): AxiosPromise<MenuForm> {
return request({
url: '/api/v1/menus/' + id,
method: 'get'
});
}
/**
*
*
* @param data
*/
export function addMenu(data: MenuForm) {
return request({
url: '/api/v1/menus',
method: 'post',
data: data
});
}
/**
*
*
* @param id
* @param data
*/
export function updateMenu(id: string, data: MenuForm) {
return request({
url: '/api/v1/menus/' + id,
method: 'put',
data: data
});
}
/**
*
*
* @param ids ID(,)
*/
export function deleteMenus(ids: string) {
return request({
url: '/api/v1/menus/' + ids,
method: 'delete'
});
}

View File

@ -0,0 +1,105 @@
/**
*
*/
export interface MenuQuery {
keywords?: string;
}
/**
*
*/
export interface Menu {
id?: number;
parentId: number;
type?: string | 'CATEGORY' | 'MENU' | 'EXTLINK';
createTime: string;
updateTime: string;
name: string;
icon: string;
component: string;
sort: number;
visible: number;
children: Menu[];
}
/**
*
*/
export interface MenuForm {
/**
* ID
*/
id?: string;
/**
* ID
*/
parentId: string;
/**
*
*/
name: string;
/**
* (1:;0:;)
*/
visible: number;
icon?: string;
/**
*
*/
sort: number;
/**
*
*/
component?: string;
/**
*
*/
path: string;
/**
*
*/
redirect?: string;
/**
*
*/
type: string;
/**
*
*/
perm?: string;
}
/**
* (+)
*/
export interface Resource {
/**
*
*/
value: string;
/**
*
*/
label: string;
/**
*
*/
children: Resource[];
}
/**
*
*/
export interface Permission {
/**
*
*/
value: string;
/**
*
*/
label: string;
}

View File

@ -0,0 +1,18 @@
import request from '@/utils/request';
//获取所有角色
export function getLogList(params:any){
return request({
url: '/system/log/getLogList' ,
method: 'post',
params: params
});
}
export function exportExcel(queryParams: any) {
return request({
url: '/system/log/exportExcel',
method: 'get',
params: queryParams,
responseType: 'arraybuffer'
});
}

View File

@ -0,0 +1,196 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { RoleQuery, RoleForm } from './types';
//获取所有角色
export function listRolePages(queryParams:any){
return request({
url: '/system/role/list' ,
method: 'post',
params:queryParams
});
}
//角色是否有效
export function isvaildTo(queryParams:any){
return request({
url: '/system/role/setIsvaild' ,
method: 'post',
params:queryParams
});
}
//新增角色
export function addDept(queryParams:any){
return request({
url:'/system/role/addRole' ,
method: 'post',
data: queryParams
});
}
//更新角色信息
export function renewDept (queryParams:any){
return request({
url:'/system/role/updateById' ,
method: 'post',
data: queryParams
});
}
//单个删除角色
export function deleDept (queryParams:any){
return request({
url:'/system/role/deleteById' ,
method: 'post',
params: queryParams
});
}
//获取分配权限
export function assignmentPer (queryParams:any){
return request({
url:'/system/menu/permissionAssignment' ,
method: 'post',
params: queryParams
});
}
//发出分配权限
export function setMenuById (queryParams:any){
return request({
url:'/system/role/setMenuById' ,
method: 'post',
params: queryParams
});
}
////获取组织范围
export function setOrgscope (queryParams:any){
return request({
url:'/system/organization/getOrgScopeTree' ,
method: 'post',
params: queryParams
});
}
//修改组织范围
export function postOrgscope (queryParams:any){
return request({
url:'/system/role/setOrgscope' ,
method: 'post',
params: queryParams
});
}
//删除角色
// export function delDept(queryParams:any){
// return request({
// url:'/system/role/addRole' ,
// method: 'post',
// data: queryParams
// });
// }
/**
*
*
* @param queryParam
*/
// export function listRolePages(
// queryParams?: RoleQuery
// ): AxiosPromise<RolePageResult> {
// return request({
// url: '/system/role/list',
// method: 'post',
// params: queryParams
// });
// }
/**
*
*
* @param queryParams
*/
export function listRoleOptions(
queryParams?: RoleQuery
): AxiosPromise<any[]> {
return request({
url: '/api/v1/roles/options',
method: 'get',
params: queryParams
});
}
/**
* ID集合
*
* @param queryParams
*/
export function getRoleMenuIds(roleId: string): AxiosPromise<number[]> {
return request({
url: '/api/v1/roles/' + roleId + '/menuIds',
method: 'get'
});
}
/**
*
*
* @param queryParams
*/
export function updateRoleMenus(
roleId: string,
data: number[]
): AxiosPromise<any> {
return request({
url: '/api/v1/roles/' + roleId + '/menus',
method: 'put',
data: data
});
}
/**
*
*
* @param id
*/
export function getRoleDetail(id: number): AxiosPromise<RoleForm> {
return request({
url: '/api/v1/roles/' + id,
method: 'get'
});
}
/**
*
*
* @param data
*/
export function addRole(data: RoleForm) {
return request({
url: '/api/v1/roles',
method: 'post',
data: data
});
}
/**
*
*
* @param id
* @param data
*/
export function updateRole(id: number, data: RoleForm) {
return request({
url: '/api/v1/roles/' + id,
method: 'put',
data: data
});
}
/**
* (,)
*
* @param ids
*/
export function deleteRoles(ids: string) {
return request({
url: '/api/v1/roles/' + ids,
method: 'delete'
});
}

View File

@ -0,0 +1,47 @@
/**
*
*/
interface PageQuery {
pageIndex: number;
pageSize: number;
}
export interface RoleQuery extends PageQuery {
keywords?: string;
}
interface PageResult<T> {
total: number;
list: T[];
}
/**
*
*/
export interface Role {
id: string;
name: string;
code: string;
sort: number;
status: number;
deleted: number;
menuIds?: any;
permissionIds?: any;
}
/**
*
*/
export type RolePageResult = PageResult<Role[]>;
/**
*
*/
export interface RoleForm {
id?: number;
name: string;
code: string;
sort: number;
status: number;
/**
*
*/
dataScope: number;
}

View File

@ -0,0 +1,132 @@
import request from '@/utils/request';
//水电基地数据获取
export function wbsbGetKendoList(data: any) {
return request({
url: '/env/hydrobase/wbsb/GetKendoList',
method: 'post',
data
});
}
// 基地下拉列表
export function getBaseDropdown(data: any) {
return request({
url: '/env/hydrobase/dropdown',
method: 'get',
data
});
}
// 流域下拉列表
export function getSelectForDropdown(data: any) {
return request({
// url: '/env/rvcd/selectForDropdown',
url: '/env/rvcd/selectRvcdDropdown',
method: 'get',
data
});
}
// 所在河段下拉列表
export function getRvcdDropdown(params: any) {
return request({
url: '/env/rvcd/selectForDropdown',
method: 'get',
params: params
});
}
//电站下拉列表
export function getEngInfoDropdown(data: any) {
return request({
url: '/env/engInfo/dropdown',
method: 'post',
data
});
}
// 根据河段获取电站
export function getByRvcd(data: any) {
return request({
url: '/env/engInfo/getByRvcd',
method: 'get',
params:data
});
}
// 根据id获取电站信息
export function getEngInfoById(params: any) {
return request({
url: '/env/engInfo/getById',
method: 'get',
params
});
}
// 所在位置下拉列表
export function getAddvcdDropdown(data: any) {
return request({
url: '/env/addvcd/selectForDropdown',
method: 'post',
data
});
}
// 重新验证并更新行数据
export function revalidateAndUpdateRow(data: any) {
return request({
url: '/data/fishDraft/revalidateAndUpdateRow',
method: 'post',
data
});
}
// 删除 行数据
export function deleteRowById(data: any) {
return request({
url: '/data/fishDraft/deleteRowById',
method: 'post',
data
});
}
//过鱼设施下拉列表
export function getFpssDropdown(params: any) {
return request({
url: '/env/fpss/dropdown',
method: 'get',
params
});
}
//鱼类名称下拉列表
export function getFishDictoryDropdown() {
return request({
url: '/env/fishDictory/listByName',
method: 'get'
});
}
// 类似鱼类名称下拉列表
export function getSimilarFishDictoryDropdown(params: any) {
return request({
url: '/env/fishDictory/similar',
method: 'get',
params
});
}
// 上传文件
export function uploadFile(data: any) {
return request({
url: import.meta.env.VITE_APP_ATTACHMENT_URL + '/upload',
method: 'post',
data,
headers: { 'Content-Type': 'multipart/form-data' }
});
}
// 所在位置下拉列表
export function getAddvcdDropdownByRvcd(data: any = {}) {
return request({
url: '/base/msalongb/noAuth/GetKendoList',
method: 'post',
data
});
}
//沿程配置下拉列表
export function noAuthGetKendoPage(data: any = {}) {
return request({
url: '/base/msalongb/noAuth/GetKendoPage',
method: 'post',
data
});
}

View File

@ -0,0 +1,45 @@
import request from '@/utils/request';
export function queryPageList(queryParams:any){
return request({
url: '/data/approvalMain/queryPageList' ,
method: 'post',
data:queryParams
});
}
// 查询审批操作日志列表
export function getApprovalLogList(params: any) {
return request({
url: '/data/approvalLog/queryPageList',
method: 'post',
data: params
});
}
// 查询审批变更记录列表
export function getApprovalChangeLogList(params: any) {
return request({
url: '/data/approvalChangeLog/queryPageList',
method: 'post',
data: params
});
}
// 批量审批
export function batchApproveByApprovalId(data: any) {
return request({
url: '/data/fishDraft/batchApproveByApprovalId',
method: 'post',
data
});
}
// 批量驳回
export function batchReject(data: { approvalIds: string[], rejectReason: string }) {
return request({
url: '/data/fishDraft/batchReject',
method: 'post',
data
});
}

View File

@ -0,0 +1,25 @@
import request from '@/utils/request';
// 顶部tabs
export function baseMsstbprpt(data: any) {
return request({
url: '/vd/msstbprpt/GetKendoList',
method: 'post',
data
});
}
// 实时视频
export function envVdTreeGetKendoListCust(data: any) {
return request({
url: '/vd/tree/GetKendoListCust',
method: 'post',
data
});
}
// 录像
export function envVdRunDataGetKendoList(data: any) {
return request({
url: '/vd/runData/GetKendoListCust',
method: 'post',
data
});
}

View File

@ -0,0 +1,154 @@
import request from '@/utils/request';
export function getKendoListCust(data: any) {
return request({
url: '/wt/alongList/qgc/GetKendoListCust',
method: 'post',
data
});
}
//获取水温下拉框
export function wbsbGetKendoList(data: any) {
return request({
url: '/wt/wbsb/GetKendoList',
method: 'post',
data
});
}
/**
*
* @param data
* @returns Promise
*/
export function getChuiXiangShuiWenTreeStcd(data: any) {
return request({
url: '/wt/sdrvwts/default/treeStcd',
method: 'post',
data,
});
}
/**
*
* @param data { filter, sort }
* @returns Promise
*/
export function getCxswList(data: any) {
return request({
url: '/wt/dzCxList/GetKendoListCust',
method: 'post',
data
});
}
//获取出入库水温下拉选则树
export function getVmsstbprpt(data: any) {
return request({
url: '/eq/vmsstbprpt/GetKendoList',
method: 'post',
data
});
}
//出入库水温图表数据
//
export function inOutOneGetKendoListCust(data: any) {
return request({
url: '/wt/inOutOne/GetKendoListCust',
method: 'post',
data
});
}
//水温监测工作开展情况
export function baseEvnmAutoMonitorGetKendoListCust(data: any) {
return request({
url: '/wt/evnmAutoMonitor/GetKendoListCust',
method: 'post',
data
});
}
////水温监测工作开展情况弹框
export function vmsstbprptGetKendoList(data: any) {
return request({
url: '/wt/vmsstbprpt/GetKendoList',
method: 'post',
data
});
}
//出入库水温打开弹框api/wmp-env-server/sw/inOutOne/details
export function inOutOneDetails(data: any) {
return request({
url: '/wt/inOutOne/details',
method: 'post',
data
});
}
//鱼类适宜性分析 - select
export function infoGetKendoListCust(data: any) {
return request({
url: '/wt/wtrv/fish/info/GetKendoListCust',
method: 'post',
data
});
}
//鱼类适宜性分析-图表和table
export function fishGetKendoListCust(data: any) {
return request({
url: '/wt/wtrv/fish/GetKendoListCust',
method: 'post',
data
});
}
//月平均水温历史对比
export function avgMonGetKendoListCust(data: any) {
return request({
url: '/wt/monthList/avgMon/GetKendoListCust',
method: 'post',
data
});
}
//水温年内分布
export function yearListGetKendoListCust(data: any) {
return request({
url: '/wt/yearList/GetKendoListCust',
method: 'post',
data
});
}
//设施类型介绍
export function sttpbGetKendoList(data: any) {
return request({
url: '/wt/sttpb/GetKendoList',
method: 'post',
data
});
}
//设施类型及接入情况
export function dwInfoGetKendoListCust(data: any) {
return request({
url: '/wt/dwInfo/GetKendoListCust',
method: 'post',
data
});
}
//月均水温对比,图表,表格
export function DetGetKendoListCust(data: any) {
return request({
url: '/wt/monthDetail/Det/GetKendoListCust',
method: 'post',
data
});
}
//水温年内分布
export function yearDetailGetKendoListCust(data: any) {
return request({
url: '/wt/yearDetail/GetKendoListCust',
method: 'post',
data
});
}
//获取建设状态
export function dictgetRemoteDictValue(data: any) {
return request({
url: '/wt/usm/v1/dict/getRemoteDictValue',
method: 'get',
params: data
});
}

View File

@ -0,0 +1,26 @@
import request from '@/utils/request';
// 获取所有倾斜摄影
export function warnruleGetKendoList(data: any) {
return request({
url: '/api/wmp-sys-server/sys/warn/rule/GetKendoList',
method: 'post',
data: data
});
}
//预警类型下拉框 //水质等级下拉框
export function dictGetRemoteDictValue(data: any) {
return request({
url: '/api/dec-modules-usm-springcloud-starter/usm/v1/dict/getRemoteDictValue',
method: 'get',
params: data
});
}
//新增修改获取相关输入数据
export function ruleysList(data: any) {
return request({
url: '/api/wmp-sys-server/sys/warn/rule/ysList',
method: 'post',
data: data
});
}

View File

@ -0,0 +1,50 @@
import request from '@/utils/request';
// 飞行路径
export function threedroambGetKendoListCust(data: any) {
return request({
url: '/threedroamb/GetKendoListCust',
method: 'post',
data: data
});
}
export function threedroambsave(data: any) {
return request({
url: '/threedroamb/save',
method: 'post',
data: data
});
}
export function threedroambdelete(data: any) {
return request({
url: '/threedroamb/delete',
method: 'get',
params: data
});
}
//根据id查询弹窗
export function threedroambGetKendoById(data: any) {
return request({
url: '/threedroamb/getThreedRoamDetails',
method: 'get',
params: data
});
}
// 导入接口
export function threedroambimport(data: FormData) {
return request({
url: '/threedroamb/import',
method: 'post',
data: data,
headers: { 'Content-Type': 'multipart/form-data' }
});
}
// 导出模板
export function threedroambexport(data: any) {
return request({
url: '/threedroamb/export',
method: 'post',
data: data,
responseType: 'blob'
});
}

View File

@ -0,0 +1,59 @@
import request from '@/utils/request';
// 获取所有沿程配置数据
export function getAllConfigTree(data: any) {
return request({
url: '/base/msalongb/GetKendoList',
method: 'post',
data: data
});
}
// 保存沿程配置
export function saveBaseWbsb(data: any) {
return request({
url: '/base/msalongb/save',
method: 'post',
data: data
});
}
// 删除沿程配置
export function deleteBaseWbsb(data: any) {
return request({
url: '/base/msalongb/delete',
method: 'post',
data
});
}
// 保存沿程配置子节点
export function saveBaseWbsbChild(data: any) {
return request({
url: '/base/msalongb/save',
method: 'post',
data: data
});
}
// 查询子节点
export function getChildConfigTree(data: any) {
return request({
url: '/base/msalongdetb/GetKendoList',
method: 'post',
data: data
});
}
// 保存子节点
export function saveBaseWbsbChildDetail(data: any) {
return request({
url: '/base/msalongdetb/save',
method: 'post',
data: data
});
}
//站点类型下拉框
export function sttpGetKendoList(data: any) {
return request({
url: '/base/msalongb/sttp/GetKendoList',
method: 'post',
data: data
});
}

View File

@ -0,0 +1,26 @@
import request from '@/utils/request';
// 获取所有地图 图层树
export function getAllMapLayerTree(data: any) {
return request({
url: '/mapLayer/getAllMapLayerTree',
method: 'post',
data: data
});
}
// 保存地图 图层
export function saveMapLayer(data: any) {
return request({
url: '/mapLayer/save',
method: 'post',
data: data
});
}
// 删除地图 图层
export function deleteMapLayer(data: any) {
return request({
url: '/mapLayer/delete',
method: 'post',
data: data
});
}

View File

@ -0,0 +1,60 @@
import request from '@/utils/request';
// 获取所有地图 图例树
export function getAllMapLegendTree(data: any) {
return request({
url: '/mapLegend/GetKendoList',
method: 'post',
data: data
});
}
// 选中配置 列表
export function getAllMapLegendModuleTree(data: any) {
return request({
url: '/mapmodule/GetKendoList',
method: 'post',
data: data
});
}
// 选中配置 新增
export function saveMapLegendModule(data: any) {
return request({
url: '/mapmodule/save',
method: 'post',
data: data
});
}
// 选中配置 删除
export function deleteMapLegendModule(data: any) {
return request({
url: '/mapmodule/delete',
method: 'post',
data: data
});
}
// 保存地图 图例
export function saveMapLegend(data: any) {
return request({
url: '/mapLegend/save',
method: 'post',
data: data
});
}
// 删除地图 图例
export function deleteMapLegend(data: any) {
return request({
url: '/mapLegend/delete',
method: 'post',
data: data
});
}
// 获取所有地图 图例树
export function getAllMapLegendParentIdTree(data: any) {
return request({
url: '/mapLegend/getAllMapLegendTree',
method: 'get',
params: data
});
}

View File

@ -0,0 +1,34 @@
import request from '@/utils/request';
// 获取倾斜摄影 列表
export function getListTiltPhotoTree(data: any) {
return request({
url: '/sys/oblique/GetKendoListCust',
method: 'post',
data: data
});
}
// 获取所有倾斜摄影
export function getAllTiltPhotoTree(data: any) {
return request({
url: '/overview/vmsstbprpt/GetKendoList',
method: 'post',
data: data
});
}
// 保存倾斜摄影
export function saveTiltPhoto(data: any) {
return request({
url: '/sys/oblique/addOrUpdate',
method: 'post',
data: data
});
}
// 删除倾斜摄影
export function deleteTiltPhoto(data: any) {
return request({
url: '/sys/oblique/delete',
method: 'get',
params: data
});
}

View File

@ -0,0 +1,100 @@
import request from '@/utils/request';
// 获取列表
export function getPushConfigList(data: any) {
return request({
url: '/system/pushConfig/getPushConfigList',
method: 'post',
data
});
}
//新增推送配置
export function addPushConfig(data: any) {
return request({
url: '/system/pushConfig/addPushConfig',
method: 'post',
data
});
}
//修改新增配置
export function deletePushConfig(data: any) {
return request({
url: '/system/pushConfig/deletePushConfig',
method: 'post',
data
});
}
//删除新增配置
export function updatePushConfig(data: any) {
return request({
url: '/system/pushConfig/updatePushConfig',
method: 'post',
data
});
}
//推送目标配置 --用户
export function queryUsersList(data: any) {
return request({
url: '/system/pushConfig/queryUsersList',
method: 'get',
params:data
});
}
//推送目标配置 -- 角色
export function queryRolesList(data: any) {
return request({
url: '/system/pushConfig/queryRolesList',
method: 'get',
params:data
});
}
//查询推送目标
export function getPushTargets(data: any) {
return request({
url: '/system/pushConfig/getPushTargets',
method: 'get',
params:data
});
}
//新增推送目标
export function savePushTargets(data: any) {
return request({
url: '/system/pushConfig/savePushTargets',
method: 'post',
data
});
}
//短信提醒状态修改
export function setPushConfigSmsSwitch(data: any) {
return request({
url: '/system/pushConfig/setPushConfigSmsSwitch',
method: 'post',
params:data
});
}
//获取推送历史列表
export function postPushHistoryList(data: any) {
return request({
url: '/system/pushConfig/postPushHistoryList',
method: 'post',
data
});
}
//推送情况
export function getPushHistoryDetailList(data: any) {
return request({
url: '/system/pushConfig/getPushHistoryDetailList',
method: 'post',
data
});
}
//s数量
export function getPushHistoryDetailById(data: any) {
return request({
url: '/system/pushConfig/getPushHistoryDetailById',
method: 'get',
params:data
});
}

View File

@ -0,0 +1,279 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { UserForm, UserInfo, UserPageResult, UserQuery } from './types';
//获取企业树 数据
export function getTreelist(queryParams:any) {
return request({
url: '/system/organization/getOrgTree',
method: 'POST',
params: queryParams
});
}
//获取用户列表信息
export function gettableData(queryParams:any) {
return request({
url: '/system/user/queryUsers',
method: 'get',
params: queryParams
});
}
// 审核用户列表
export function queryPendingAuditUsers(queryParams:any) {
return request({
url: '/system/user/queryPendingAuditUsers',
method: 'get',
params: queryParams
});
}
//用户-禁用,启用
export function DataStatus (queryParams:any) {
return request({
url: '/system/user/setStatus',
method: 'POST',
params: queryParams
});
}
//删除用户
export function deltableData (queryParams:any) {
return request({
url: '/system/user/deleteById',
method: 'POST',
params: queryParams
});
}
//批量删除
export function delChoise (queryParams:any) {
return request({
url: '/system/user/deleteUserByIds',
method: 'POST',
params: queryParams
});
}
//获取角色
export function getRole (queryParams:any) {
return request({
url: '/system/role/list',
method: 'POST',
params: queryParams
});
}
//新建用户
export function addUsers (queryParams:any,roleids:any) {
return request({
url: '/system/user/addUser?'+'roleids='+roleids,
method: 'POST',
data: queryParams,
});
}
//更改用户
export function updataUser (queryParams:any,roleids:any) {
return request({
url: '/system/user/updateUser?'+'roleids='+roleids,
method: 'POST',
data: queryParams,
});
}
//更改用户
export function updatePersonalInfo (queryParams:any) {
return request({
url: '/user/updatePersonalInfo',
method: 'POST',
data: queryParams,
});
}
//更改头像
export function updateAvatar (data:any) {
return request({
headers: {
'Content-Type': 'multipart/form-data'
},
url: '/system/user/updateAvatar',
method: 'POST',
data
});
}
//重置密码
export function setpass (queryParams:any) {
return request({
url: '/system/user/resetPassword',
method: 'POST',
params: queryParams,
});
}
export function updatePassword (queryParams:any) {
return request({
url: '/user/updatePassword',
method: 'GET',
params: queryParams,
});
}
//获取过鱼设施权限树
export function getFishtree(queryParams:any) {
return request({
url: '/env/tree/rvcdEng',
method: 'get',
params: queryParams
});
}
//保存权限
export function saveFishqvan(queryParams:any) {
return request({
url: '/data/userDataScope/batchAdd',
method: 'post',
data: queryParams
});
}
//查询用户有效权限
export function getuserdata(queryParams:any) {
return request({
url: '/data/userDataScope/getValidPermissions',
method: 'get',
params: queryParams
});
}
// 审计用户(审批通过/驳回)
export function auditUser(data: any) {
return request({
url: '/system/user/auditUser',
method: 'post',
data
});
}
/**
*
*/
export function getUserInfo(): AxiosPromise<UserInfo> {
return request({
url: '/user/me',
method: 'get'
});
}
/**
*
*
* @param queryParams
*/
export function listUserPages(
queryParams: UserQuery
): AxiosPromise<UserPageResult> {
return request({
url: '/api/v1/users/pages',
method: 'get',
params: queryParams
});
}
/**
*
*
* @param userId
*/
export function getUserForm(userId: number): AxiosPromise<UserForm> {
return request({
url: '/api/v1/users/' + userId + '/form',
method: 'get'
});
}
/**
*
*
* @param data
*/
export function addUser(data: any) {
return request({
url: '/api/v1/users',
method: 'post',
data: data
});
}
/**
*
*
* @param id
* @param data
*/
export function updateUser(id: number, data: UserForm) {
return request({
url: '/api/v1/users/' + id,
method: 'put',
data: data
});
}
/**
*
*
* @param id
* @param status
*/
export function updateUserStatus(id: number, status: number) {
return request({
url: '/api/v1/users/' + id + '/status',
method: 'patch',
params: { status: status }
});
}
/**
*
*
* @param id
* @param password
*/
export function updateUserPassword(id: number, password: string) {
return request({
url: '/api/v1/users/' + id + '/password',
method: 'patch',
params: { password: password }
});
}
/**
*
*
* @param ids
*/
export function deleteUsers(ids: string) {
return request({
url: '/api/v1/users/' + ids,
method: 'delete'
});
}
/**
*
*
* @returns
*/
export function downloadTemplate() {
return request({
url: '/api/v1/users/template',
method: 'get',
responseType: 'arraybuffer'
});
}
/**
*
*
* @param queryParams
* @returns
*/
export function exportUser(queryParams: UserQuery) {
return request({
url: '/api/v1/users/_export',
method: 'get',
params: queryParams,
responseType: 'arraybuffer'
});
}

View File

@ -0,0 +1,75 @@
/**
*
*/
export interface UserInfo {
permissions: string[];
userInfo: any;
nickname: string;
avatar: string;
roles: string[];
perms: string[];
}
/**
*
*/
export interface PageQuery {
keywords: string;
status: number;
deptId: number;
}
export interface UserQuery extends PageQuery {
keywords: string;
status: number;
deptId: number;
}
/**
*
*/
export interface UserType {
id: string;
username: string;
nickname: string;
mobile: string;
gender: number;
avatar: string;
email: string;
status: number;
deptName: string;
roleNames: string;
createTime: string;
}
interface PageResult<T> {
total: number;
list: T[];
}
/**
*
*/
export type UserPageResult = PageResult<any[]>;
/**
*
*/
export interface UserForm {
id: number | undefined;
deptId: number;
username: string;
nickname: string;
password: string;
mobile: string;
email: string;
gender: number;
status: number;
remark: string;
roleIds: number[];
}
/**
*
*/
export interface UserImportData {
deptId: number;
roleIds: number[];
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Some files were not shown because too many files have changed in this diff Show More