Browse Source

docs: add laic-frontend structure alignment design

Align directory layout, TDesign shell/login, and Tianditu map skeleton
with uav-edu-web conventions for the next implementation pass.
main
xiaosi 1 month ago
parent
commit
8b57184791
  1. 190
      docs/superpowers/specs/2026-08-19-laic-frontend-structure-align-design.md

190
docs/superpowers/specs/2026-08-19-laic-frontend-structure-align-design.md

@ -0,0 +1,190 @@
# 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):
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/`):
```text
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`;store `xxxStore.js`;配置进 `config/`
## 验收标准
- [ ] 目录与上表映射一致;旧 `src/store/`、`src/api/`、扁平 `src/views/*.vue`、`AppShell.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. 生产底图策略(天地图 / 其他)定稿
Loading…
Cancel
Save