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

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.htmlsrc/main.jsApp.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):

  1. 目录与命名对齐 uav-edu-web
  2. 引入 TDesign(按需引入),重写主壳与登录页
  3. 挂上全局地图壳:开发环境天地图底图
  4. 修全量 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['@'] → srcenvPrefixAPP_ / VITE_

壳层与路由

  • App.vue:保留全局 SVG sprite / toast / confirm 能力(可逐步收敛);路由驱动:/login 独立全屏,登录后子路由挂在 MainContainer(保持现 laic 路由结构,不改为 edu 的 App 二选一挂载)
  • MainContainer.vuet-layout + SideMenu + TopBart-content常驻 MapLayer + RouterView(对齐 edu:非登录页同一张地图)
  • SideMenu / TopBar:TDesign 按需组件重写;菜单仍按 admin / 普通用户分流(行为对齐现 AppShell
  • LoginView:TDesign 表单风格重写;对接现有 /v1/auth/* 行为不变
  • 路由懒加载全部改为 views/XxxView/XxxView.vue
  • beforeEach:token 校验、meta.adminmeta.userOnly 行为不变

TDesign:

  • 依赖:tdesign-vue-nextless(壳层 CSS Modules);样式按需方案在实施计划中二选一:unplugin-vue-components + unplugin-auto-import,或手写 setupTDesign.js 注册本轮组件
  • 按需引入,禁止全量 app.use(TDesign)
  • 同步移除未使用的 element-plus@element-plus/icons-vue 依赖
  • 本轮用到的最小集合预期:Layout/Aside/Content/HeaderMenu/MenuItemButtonInputForm/FormItemMessage(以实装为准,spec 约束「按需」而非插件选型)

地图骨架(开发环境天地图)

依赖本轮:maptalks(必要)。为底图引入 mapbox-gl / maptalks.mapboxgl

模块 职责
config/map.js center/zoomAPP_TIANDITU_TOKEN(或 VITE_);影像+注记图层 URL 模板
layout/MapLayer.vue maptalks.MapbaseLayer = 天地图 TileLayer / GroupTileLayercommonRefs.setRef('map') + mapHelper.setMap;卸载销毁
core/mapHelper.js setMap/getMaptoggleMapMode({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.jsuseXxxStorestores/index.js 统一导出
  • HTTP:utils/http.js 保持现拦截器语义(Bearer、code===200 解包、401 logout)
  • 样式:壳层 / Login 用 Less + CSS Modules(lang="less" module="s");业务页可暂留 prototype.css
  • 命名:视图 XxxView;store xxxStore.js;配置进 config/

验收标准

  • 目录与上表映射一致;旧 src/store/src/api/、扁平 src/views/*.vueAppShell.vue 已移除或不再被引用
  • @ alias 可用;全仓无断裂 import
  • npm run build 通过
  • 登录页为 TDesign 风格;登录后主壳为 TDesign 布局;角色菜单分流正确
  • 登录后可见天地图底图(配置了有效 token 时)
  • 无 token 时有明确错误/占位,应用其余路由仍可用
  • 路由切换不重复初始化地图
  • 鉴权与 API 行为与重构前一致(token / admin / userOnly / 401)

风险

  1. 壳层视觉相对原型跳变 → 接受;业务页暂留旧样式
  2. diff 大 → 实施计划按「搬家 → 壳 → 地图 → 验收」分步,映射表可追溯
  3. 天地图 token / 瓦片域名限制 → env 外置;失败降级不白屏
  4. TDesign 按需方案选型(插件 vs 手写注册)→ 实施计划中选定一种并写清

后续(本轮之后)

  1. Monitor 接全局地图 + 设备点位/聚合
  2. 业务页逐步 TDesign 化
  3. config/urls.js 抽全 API 常量
  4. 弹窗复用地图(replaceMapContainer)用于详情/回放
  5. 生产底图策略(天地图 / 其他)定稿