From 8b57184791a1a8e87d32f4e9e8098142e489652b Mon Sep 17 00:00:00 2001 From: xiaosi <2652281683@qq.com> Date: Wed, 19 Aug 2026 16:58:52 +0800 Subject: [PATCH] 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. --- ...19-laic-frontend-structure-align-design.md | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 docs/superpowers/specs/2026-08-19-laic-frontend-structure-align-design.md diff --git a/docs/superpowers/specs/2026-08-19-laic-frontend-structure-align-design.md b/docs/superpowers/specs/2026-08-19-laic-frontend-structure-align-design.md new file mode 100644 index 0000000..da880a5 --- /dev/null +++ b/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:`