You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9.0 KiB
9.0 KiB
laic-frontend 目录对齐与地图壳设计
日期:2026-08-19
状态:已确认
参照仓:/Users/qingyuan/CodeProject/uav-edu-web
背景
laic-frontend(嘉谷低空智控平台)已是 Vue 3 + Vite + Pinia + Vue Router 的 SPA,但目录扁平、UI 以自研 prototype.css 为主,地图能力缺失。后续开发要以 uav-edu-web 的目录构成、代码风格与地图架构为准;开发环境底图使用天地图。
当前关键事实:
- 入口:
index.html→src/main.js→App.vue+layout/AppShell.vue - 视图:
src/views/*.vue(无XxxView/目录约定) - 状态:
src/store/{user,devices,ui}.js - HTTP:
src/api/request.js(Axios,/api代理到127.0.0.1:8080) jcWeb/为静态原型,非运行入口element-plus已声明但源码未使用
目标
本轮一次性完成(方案 A):
- 目录与命名对齐
uav-edu-web - 引入 TDesign(按需引入),重写主壳与登录页
- 挂上全局地图壳:开发环境天地图底图
- 修全量 import / 路由懒加载路径,保证
npm run build通过
非目标
- 业务页批量换成 TDesign 组件
- Monitor / 设备 / 航迹等业务图层实现
- 删除或改造
jcWeb/ - 引入 Mapbox 底图;生产环境底图 provider 切换定稿
- TypeScript、测试框架、细粒度权限
- 坐标系转换(GCJ-02 等);除非启动即发现阻塞再单开
方案选择
| 方案 | 内容 | 结论 |
|---|---|---|
| A 大爆炸一次性对齐 | 目录 + TDesign 壳 + Login + 天地图骨架同一轮 | 采用 |
| B 两阶段 | 先搬家,再壳与地图 | 否:中间态与目标不一致 |
| C 适配层 | 旧 AppShell 包一层 | 否:双壳并存,对照成本高 |
目录映射
目标树(相对 src/):
src/
├── main.js
├── App.vue
├── router/index.js
├── layout/
│ ├── MainContainer.vue # 取代 AppShell
│ ├── MapLayer.vue # 单例地图(开发天地图)
│ └── components/
│ ├── SideMenu.vue
│ └── TopBar.vue
├── views/
│ ├── LoginView/LoginView.vue
│ ├── MonitorView/MonitorView.vue
│ ├── DevicesView/DevicesView.vue
│ ├── DeviceDetailView/DeviceDetailView.vue
│ ├── ControlView/ControlView.vue
│ ├── TasksView/TasksView.vue
│ ├── ReplayView/ReplayView.vue
│ ├── MediaView/MediaView.vue
│ ├── AlarmsView/AlarmsView.vue
│ ├── AccountView/AccountView.vue
│ ├── UsersView/UsersView.vue
│ ├── FirmwaresView/FirmwaresView.vue
│ ├── SystemView/SystemView.vue
│ └── OperationLogsView/OperationLogsView.vue
├── stores/
│ ├── index.js # createPinia + re-export
│ └── modules/
│ ├── userStore.js
│ ├── devicesStore.js
│ └── uiStore.js
├── core/
│ └── mapHelper.js
├── config/
│ ├── map.js
│ └── urls.js # 可先骨架,后续从调用点抽全
├── utils/
│ ├── commonRefs.js
│ ├── http.js # 由 api/request.js 迁入
│ └── setupTDesign.js # 按需注册本轮用到的 TDesign 组件
├── components/ # 跨页组件(如 DockEditModal)保留
└── styles/ # prototype.css 暂留;壳层用 less module
文件搬迁对照:
| 现路径 | 新路径 |
|---|---|
src/views/Login.vue |
src/views/LoginView/LoginView.vue |
src/views/Monitor.vue |
src/views/MonitorView/MonitorView.vue |
src/views/Devices.vue |
src/views/DevicesView/DevicesView.vue |
src/views/DeviceDetail.vue |
src/views/DeviceDetailView/DeviceDetailView.vue |
src/views/Control.vue |
src/views/ControlView/ControlView.vue |
src/views/Tasks.vue |
src/views/TasksView/TasksView.vue |
src/views/Replay.vue |
src/views/ReplayView/ReplayView.vue |
src/views/Media.vue |
src/views/MediaView/MediaView.vue |
src/views/Alarms.vue |
src/views/AlarmsView/AlarmsView.vue |
src/views/Account.vue |
src/views/AccountView/AccountView.vue |
src/views/Users.vue |
src/views/UsersView/UsersView.vue |
src/views/Firmwares.vue |
src/views/FirmwaresView/FirmwaresView.vue |
src/views/System.vue |
src/views/SystemView/SystemView.vue |
src/views/OperationLogs.vue |
src/views/OperationLogsView/OperationLogsView.vue |
src/store/user.js |
src/stores/modules/userStore.js |
src/store/devices.js |
src/stores/modules/devicesStore.js |
src/store/ui.js |
src/stores/modules/uiStore.js |
src/api/request.js |
src/utils/http.js |
src/layout/AppShell.vue |
拆为 MainContainer.vue + SideMenu.vue + TopBar.vue |
不变:jcWeb/、public/、业务页功能逻辑(仅路径与必要 import)。
Vite:resolve.alias['@'] → src;envPrefix 含 APP_ / VITE_。
壳层与路由
App.vue:保留全局 SVG sprite / toast / confirm 能力(可逐步收敛);路由驱动:/login独立全屏,登录后子路由挂在MainContainer(保持现 laic 路由结构,不改为 edu 的 App 二选一挂载)MainContainer.vue:t-layout+SideMenu+TopBar;t-content内 常驻MapLayer+RouterView(对齐 edu:非登录页同一张地图)SideMenu/TopBar:TDesign 按需组件重写;菜单仍按admin/ 普通用户分流(行为对齐现AppShell)LoginView:TDesign 表单风格重写;对接现有/v1/auth/*行为不变- 路由懒加载全部改为
views/XxxView/XxxView.vue beforeEach:token 校验、meta.admin、meta.userOnly行为不变
TDesign:
- 依赖:
tdesign-vue-next、less(壳层 CSS Modules);样式按需方案在实施计划中二选一:unplugin-vue-components+unplugin-auto-import,或手写setupTDesign.js注册本轮组件 - 按需引入,禁止全量
app.use(TDesign) - 同步移除未使用的
element-plus、@element-plus/icons-vue依赖 - 本轮用到的最小集合预期:
Layout/Aside/Content/Header、Menu/MenuItem、Button、Input、Form/FormItem、Message(以实装为准,spec 约束「按需」而非插件选型)
地图骨架(开发环境天地图)
依赖本轮:maptalks(必要)。不为底图引入 mapbox-gl / maptalks.mapboxgl。
| 模块 | 职责 |
|---|---|
config/map.js |
center/zoom;APP_TIANDITU_TOKEN(或 VITE_);影像+注记图层 URL 模板 |
layout/MapLayer.vue |
maptalks.Map;baseLayer = 天地图 TileLayer / GroupTileLayer;commonRefs.setRef('map') + mapHelper.setMap;卸载销毁 |
core/mapHelper.js |
setMap/getMap;toggleMapMode({is2D,is3D}) 最小实现;replaceMapContainer/restoreMapContainer API 先留齐(弹窗复用后续用) |
utils/commonRefs.js |
setRef/getRef/removeRef |
.env.development |
APP_TIANDITU_TOKEN= 占位;无 token 时地图初始化明确报错/占位,不拖垮整站 SPA |
约定:
- 开发默认天地图;生产 provider 本轮不定稿
- 地图仅在
MainContainer挂载时初始化一次;路由切换不new Map - 业务页本轮不画设备/航迹;非透图页面可用不透明面板盖住地图
- 坐标:本轮按经纬度直接交给 maptalks;转换需求单开
代码风格对齐(本轮强制)
- SFC:
<script setup> - Pinia:
stores/modules/*Store.js,useXxxStore;stores/index.js统一导出 - HTTP:
utils/http.js保持现拦截器语义(Bearer、code===200解包、401 logout) - 样式:壳层 / Login 用 Less + CSS Modules(
lang="less" module="s");业务页可暂留prototype.css - 命名:视图
XxxView;storexxxStore.js;配置进config/
验收标准
- 目录与上表映射一致;旧
src/store/、src/api/、扁平src/views/*.vue、AppShell.vue已移除或不再被引用 @alias 可用;全仓无断裂 importnpm run build通过- 登录页为 TDesign 风格;登录后主壳为 TDesign 布局;角色菜单分流正确
- 登录后可见天地图底图(配置了有效 token 时)
- 无 token 时有明确错误/占位,应用其余路由仍可用
- 路由切换不重复初始化地图
- 鉴权与 API 行为与重构前一致(token / admin / userOnly / 401)
风险
- 壳层视觉相对原型跳变 → 接受;业务页暂留旧样式
- diff 大 → 实施计划按「搬家 → 壳 → 地图 → 验收」分步,映射表可追溯
- 天地图 token / 瓦片域名限制 → env 外置;失败降级不白屏
- TDesign 按需方案选型(插件 vs 手写注册)→ 实施计划中选定一种并写清
后续(本轮之后)
- Monitor 接全局地图 + 设备点位/聚合
- 业务页逐步 TDesign 化
config/urls.js抽全 API 常量- 弹窗复用地图(
replaceMapContainer)用于详情/回放 - 生产底图策略(天地图 / 其他)定稿