Browse Source
Align directory layout, TDesign shell/login, and Tianditu map skeleton with uav-edu-web conventions for the next implementation pass.main
1 changed files with 190 additions and 0 deletions
@ -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…
Reference in new issue