Browse Source
Break the approved design into tasks: tooling, path moves, TDesign shell/login, and Tianditu MapLayer skeleton.main
1 changed files with 564 additions and 0 deletions
@ -0,0 +1,564 @@ |
|||||
|
# laic-frontend 目录对齐与地图壳 Implementation Plan |
||||
|
|
||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. |
||||
|
|
||||
|
**Goal:** 将 `laic-frontend` 目录/命名对齐 `uav-edu-web`,按需接入 TDesign 并重写主壳+登录,挂上开发环境天地图全局地图壳;业务页只搬家与修路径,功能不变。 |
||||
|
|
||||
|
**Architecture:** 一次大爆炸:先搭 Vite/`@`/依赖与空目录骨架 → 搬迁 views/stores/http 并修全量 import → 用 TDesign 重写 `MainContainer`/`SideMenu`/`TopBar`/`LoginView` → 以 `maptalks` + 天地图 `TileLayer`/`GroupTileLayer` 实现常驻 `MapLayer`。地图单例经 `commonRefs` + `mapHelper` 暴露;路由结构保持「`/login` 独立 + 登录后 `MainContainer` 子路由」。 |
||||
|
|
||||
|
**Tech Stack:** Vue 3、Vite 5、Pinia、Vue Router 4、Axios、tdesign-vue-next(按需)、less、maptalks、天地图瓦片 |
||||
|
|
||||
|
**Spec:** `docs/superpowers/specs/2026-08-19-laic-frontend-structure-align-design.md` |
||||
|
|
||||
|
## Global Constraints |
||||
|
|
||||
|
- 开发环境底图:**天地图**;不引入 Mapbox / `maptalks.mapboxgl` |
||||
|
- TDesign:**按需引入**,禁止 `app.use(TDesign)` 全量 |
||||
|
- 移除未使用依赖:`element-plus`、`@element-plus/icons-vue` |
||||
|
- 鉴权 meta(`admin` / `userOnly`)、HTTP 拦截器语义、业务页功能本轮不变 |
||||
|
- `jcWeb/`、`public/` 不动 |
||||
|
- store 文件迁到 `stores/modules/*Store.js`;`devices` 导出符号保持现有 `useDeviceStore`(避免无谓全局改名) |
||||
|
- 每完成一个 Task:`npm run build` 必须通过(Task 1 可在装依赖后先 build 旧树) |
||||
|
|
||||
|
## File Map |
||||
|
|
||||
|
| 文件 | 职责 | |
||||
|
|------|------| |
||||
|
| `vite.config.js` | `@` alias、`envPrefix`、代理保留、TDesign 按需插件 | |
||||
|
| `package.json` | 增删依赖 | |
||||
|
| `.env.development` | `APP_TIANDITU_TOKEN` 等 | |
||||
|
| `src/utils/http.js` | 原 `api/request.js` | |
||||
|
| `src/utils/commonRefs.js` | 地图等异步单例引用 | |
||||
|
| `src/utils/setupTDesign.js` | 仅当不用 unplugin 时的手写注册;优先 unplugin 则可省略 | |
||||
|
| `src/stores/index.js` | createPinia + re-export | |
||||
|
| `src/stores/modules/{user,devices,ui}Store.js` | 原 store | |
||||
|
| `src/config/map.js` | 天地图 token / 图层模板 / center/zoom | |
||||
|
| `src/config/urls.js` | API 常量骨架(本轮可先空或少量) | |
||||
|
| `src/core/mapHelper.js` | setMap/getMap/toggleMapMode/replace|restore | |
||||
|
| `src/layout/MainContainer.vue` | TDesign 壳 + MapLayer + RouterView | |
||||
|
| `src/layout/MapLayer.vue` | maptalks + 天地图底图 | |
||||
|
| `src/layout/components/SideMenu.vue` | 角色菜单 | |
||||
|
| `src/layout/components/TopBar.vue` | 顶栏(移动菜单/标题区) | |
||||
|
| `src/views/*View/*View.vue` | 原 views 搬迁;Login 重写 | |
||||
|
| `src/router/index.js` | 懒加载路径 + MainContainer | |
||||
|
| `src/main.js` / `src/App.vue` | 启动与全局 toast/confirm | |
||||
|
|
||||
|
本仓库无 lint/test scripts;验收以 `npm run build` + 手工 `npm run dev` 为主。 |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
### Task 1: 依赖、Vite 与环境骨架 |
||||
|
|
||||
|
**Files:** |
||||
|
- Modify: `package.json` |
||||
|
- Modify: `vite.config.js` |
||||
|
- Create: `.env.development` |
||||
|
- Create: `src/config/map.js`(可先最小导出) |
||||
|
- Create: `src/config/urls.js`(空骨架即可) |
||||
|
|
||||
|
**Interfaces:** |
||||
|
- Produces: `@` → `src`;`import.meta.env.APP_TIANDITU_TOKEN`;TDesign 按需解析能力 |
||||
|
|
||||
|
- [ ] **Step 1: 安装/移除依赖** |
||||
|
|
||||
|
```bash |
||||
|
npm uninstall element-plus @element-plus/icons-vue |
||||
|
npm install tdesign-vue-next maptalks less |
||||
|
npm install -D unplugin-vue-components unplugin-auto-import |
||||
|
``` |
||||
|
|
||||
|
- [ ] **Step 2: 改 `vite.config.js`** |
||||
|
|
||||
|
要求: |
||||
|
|
||||
|
```js |
||||
|
import { fileURLToPath, URL } from 'node:url' |
||||
|
import { defineConfig } from 'vite' |
||||
|
import vue from '@vitejs/plugin-vue' |
||||
|
import AutoImport from 'unplugin-auto-import/vite' |
||||
|
import Components from 'unplugin-vue-components/vite' |
||||
|
import { TDesignResolver } from 'unplugin-vue-components/resolvers' |
||||
|
|
||||
|
export default defineConfig({ |
||||
|
plugins: [ |
||||
|
vue(), |
||||
|
AutoImport({ |
||||
|
resolvers: [TDesignResolver({ library: 'vue-next' })], |
||||
|
}), |
||||
|
Components({ |
||||
|
resolvers: [TDesignResolver({ library: 'vue-next' })], |
||||
|
}), |
||||
|
], |
||||
|
resolve: { |
||||
|
alias: { |
||||
|
'@': fileURLToPath(new URL('./src', import.meta.url)), |
||||
|
}, |
||||
|
}, |
||||
|
envPrefix: ['APP_', 'VITE_'], |
||||
|
server: { |
||||
|
host: '0.0.0.0', |
||||
|
port: 5173, |
||||
|
proxy: { |
||||
|
'/api': { |
||||
|
target: 'http://127.0.0.1:8080', |
||||
|
changeOrigin: true, |
||||
|
rewrite: (p) => p.replace(/^\/api/, ''), |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}) |
||||
|
``` |
||||
|
|
||||
|
若 `TDesignResolver` 从 `unplugin-vue-components/resolvers` 导出不可用,改从 `tdesign-vue-next/es` 官方文档当前推荐路径引入,并在本 Task commit message 注明实际路径。 |
||||
|
|
||||
|
- [ ] **Step 3: 写 `.env.development`** |
||||
|
|
||||
|
```env |
||||
|
APP_TIANDITU_TOKEN= |
||||
|
APP_MAP_CENTER_LNG=106.62341584179686 |
||||
|
APP_MAP_CENTER_LAT=26.657826154258505 |
||||
|
APP_MAP_ZOOM=5 |
||||
|
``` |
||||
|
|
||||
|
- [ ] **Step 4: 写 `src/config/map.js` 最小版** |
||||
|
|
||||
|
```js |
||||
|
const token = import.meta.env.APP_TIANDITU_TOKEN || import.meta.env.VITE_TIANDITU_TOKEN || '' |
||||
|
|
||||
|
export default { |
||||
|
token, |
||||
|
center: [ |
||||
|
Number(import.meta.env.APP_MAP_CENTER_LNG) || 106.62341584179686, |
||||
|
Number(import.meta.env.APP_MAP_CENTER_LAT) || 26.657826154258505, |
||||
|
], |
||||
|
zoom: Number(import.meta.env.APP_MAP_ZOOM) || 5, |
||||
|
} |
||||
|
|
||||
|
/** 天地图影像 + 注记(WGS84 lk 系列) */ |
||||
|
export function createTiandituLayerOptions(tk) { |
||||
|
return { |
||||
|
img: { |
||||
|
urlTemplate: `https://t{s}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${tk}`, |
||||
|
subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], |
||||
|
}, |
||||
|
cia: { |
||||
|
urlTemplate: `https://t{s}.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${tk}`, |
||||
|
subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], |
||||
|
}, |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
- [ ] **Step 5: 写 `src/config/urls.js` 骨架** |
||||
|
|
||||
|
```js |
||||
|
export const BASE_URL = '/api' |
||||
|
// 后续从调用点抽全;本轮允许仅占位 |
||||
|
``` |
||||
|
|
||||
|
- [ ] **Step 6: Build 冒烟** |
||||
|
|
||||
|
Run: `npm run build` |
||||
|
|
||||
|
Expected: 成功(此时目录尚未搬迁,旧代码仍可编过) |
||||
|
|
||||
|
- [ ] **Step 7: Commit** |
||||
|
|
||||
|
```bash |
||||
|
git add package.json package-lock.json vite.config.js .env.development src/config/map.js src/config/urls.js |
||||
|
git commit -m "chore: add TDesign/maptalks tooling and map config skeleton" |
||||
|
``` |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
### Task 2: 搬迁 stores / http / views 并修 import |
||||
|
|
||||
|
**Files:** |
||||
|
- Create: `src/stores/index.js` |
||||
|
- Move: `src/store/*.js` → `src/stores/modules/{user,devices,ui}Store.js` |
||||
|
- Move: `src/api/request.js` → `src/utils/http.js` |
||||
|
- Move: 每个 `src/views/Foo.vue` → `src/views/FooView/FooView.vue`(对照 spec 映射表) |
||||
|
- Modify: 所有引用上述路径的文件(router、views、components、App.vue、http 自身) |
||||
|
- Delete: 空的 `src/store/`、`src/api/` 与旧扁平 views |
||||
|
|
||||
|
**Interfaces:** |
||||
|
- Produces: `useUserStore` / `useDeviceStore` / `useUiStore` 从 `@/stores` 或 `@/stores/modules/*` 可导入 |
||||
|
- Produces: `import request from '@/utils/http'`(或 default export 名保持 `request`) |
||||
|
- Consumes: 无行为变更 |
||||
|
|
||||
|
- [ ] **Step 1: 建 `stores` 并搬家** |
||||
|
|
||||
|
```bash |
||||
|
mkdir -p src/stores/modules |
||||
|
git mv src/store/user.js src/stores/modules/userStore.js |
||||
|
git mv src/store/devices.js src/stores/modules/devicesStore.js |
||||
|
git mv src/store/ui.js src/stores/modules/uiStore.js |
||||
|
``` |
||||
|
|
||||
|
`devicesStore.js` 内 `import request from '@/utils/http'`(可先相对路径,Step 3 统一)。 |
||||
|
|
||||
|
写 `src/stores/index.js`: |
||||
|
|
||||
|
```js |
||||
|
import { createPinia } from 'pinia' |
||||
|
|
||||
|
export * from './modules/userStore' |
||||
|
export * from './modules/devicesStore' |
||||
|
export * from './modules/uiStore' |
||||
|
|
||||
|
export function setupStore(app) { |
||||
|
app.use(createPinia()) |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
- [ ] **Step 2: 迁 http** |
||||
|
|
||||
|
```bash |
||||
|
mkdir -p src/utils |
||||
|
git mv src/api/request.js src/utils/http.js |
||||
|
``` |
||||
|
|
||||
|
更新 `http.js` 内 store/router import 为 `@/stores/modules/userStore` 等;default export 保持不变。 |
||||
|
|
||||
|
- [ ] **Step 3: 迁全部 views** |
||||
|
|
||||
|
按 spec 表逐个 `git mv`,例如: |
||||
|
|
||||
|
```bash |
||||
|
mkdir -p src/views/LoginView && git mv src/views/Login.vue src/views/LoginView/LoginView.vue |
||||
|
# …其余 13 个同样处理 |
||||
|
``` |
||||
|
|
||||
|
完整列表见 spec「文件搬迁对照」。 |
||||
|
|
||||
|
- [ ] **Step 4: 全仓改 import / 路由懒加载** |
||||
|
|
||||
|
必须替换: |
||||
|
|
||||
|
- `../store/user` → `@/stores/modules/userStore`(或 `@/stores`) |
||||
|
- `../store/devices` → `@/stores/modules/devicesStore` |
||||
|
- `../store/ui` → `@/stores/modules/uiStore` |
||||
|
- `../api/request` / `./api/request` → `@/utils/http` |
||||
|
- `App.vue` 中 `./store/ui` → `@/stores/modules/uiStore` |
||||
|
- `router/index.js` 中所有 `import('../views/Xxx.vue')` → `import('../views/XxxView/XxxView.vue')` |
||||
|
- 组件相对路径:`DockEditModal` 等按新位置修正 |
||||
|
|
||||
|
`main.js` 改为: |
||||
|
|
||||
|
```js |
||||
|
import { createApp } from 'vue' |
||||
|
import App from './App.vue' |
||||
|
import router from './router' |
||||
|
import { setupStore } from './stores' |
||||
|
import './styles/prototype.css' |
||||
|
|
||||
|
const app = createApp(App) |
||||
|
setupStore(app) |
||||
|
app.use(router) |
||||
|
app.mount('#app') |
||||
|
``` |
||||
|
|
||||
|
- [ ] **Step 5: 删除空目录确认** |
||||
|
|
||||
|
确认无残留:`src/store/`、`src/api/`、扁平 `src/views/*.vue`。 |
||||
|
|
||||
|
- [ ] **Step 6: Build** |
||||
|
|
||||
|
Run: `npm run build` |
||||
|
|
||||
|
Expected: 成功;若失败,修断链 import 直至通过。 |
||||
|
|
||||
|
- [ ] **Step 7: Commit** |
||||
|
|
||||
|
```bash |
||||
|
git add -A src |
||||
|
git commit -m "refactor: align stores/views/http paths with uav-edu-web layout" |
||||
|
``` |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
### Task 3: TDesign 主壳(MainContainer / SideMenu / TopBar) |
||||
|
|
||||
|
**Files:** |
||||
|
- Create: `src/layout/MainContainer.vue` |
||||
|
- Create: `src/layout/components/SideMenu.vue` |
||||
|
- Create: `src/layout/components/TopBar.vue` |
||||
|
- Modify: `src/router/index.js`(`AppShell` → `MainContainer`) |
||||
|
- Delete: `src/layout/AppShell.vue` |
||||
|
- Modify: 壳层样式(Less CSS Modules) |
||||
|
|
||||
|
**Interfaces:** |
||||
|
- Produces: 登录后壳层菜单分流与现 AppShell 一致(见下方菜单契约) |
||||
|
- Consumes: `useUserStore` / `useUiStore` / router names |
||||
|
|
||||
|
**菜单契约(行为对齐 AppShell):** |
||||
|
|
||||
|
- 公共:实时监控 `monitor`、设备管理 `devices` |
||||
|
- 非 admin:任务管理(plans/records/routes)、媒体中心(live/videos)、告警 `alarms`、账户 `account` |
||||
|
- admin:用户 `users`、固件 `firmwares`、系统 `system` |
||||
|
- 底栏:用户名首字母、退出(走 `ui.confirm` + `userStore.logout`) |
||||
|
|
||||
|
- [ ] **Step 1: 实现 `SideMenu.vue`** |
||||
|
|
||||
|
用 `t-menu`(或等价按需组件)实现上述契约;子路由 query(`view=plans|records|routes|live|videos`)保持与旧壳一致。样式:`lang="less" module="s"`。 |
||||
|
|
||||
|
- [ ] **Step 2: 实现 `TopBar.vue`** |
||||
|
|
||||
|
最小:移动端打开侧栏按钮、可选当前页标题。不要阻塞主流程。 |
||||
|
|
||||
|
- [ ] **Step 3: 实现 `MainContainer.vue`** |
||||
|
|
||||
|
结构: |
||||
|
|
||||
|
```vue |
||||
|
<template> |
||||
|
<t-layout :class="s.root"> |
||||
|
<t-aside :class="s.aside"> |
||||
|
<SideMenu /> |
||||
|
</t-aside> |
||||
|
<t-layout> |
||||
|
<t-header :class="s.header"> |
||||
|
<TopBar /> |
||||
|
</t-header> |
||||
|
<t-content :class="s.content"> |
||||
|
<!-- MapLayer 在 Task 5 接入;本 Task 先留注释或空 slot --> |
||||
|
<router-view /> |
||||
|
</t-content> |
||||
|
</t-layout> |
||||
|
</t-layout> |
||||
|
</template> |
||||
|
``` |
||||
|
|
||||
|
本 Task **可以先不挂 MapLayer**(Task 5 再挂),但文件位置与 class 预留 content 相对定位(`position: relative; height: 100%`)。 |
||||
|
|
||||
|
- [ ] **Step 4: 改路由** |
||||
|
|
||||
|
```js |
||||
|
import MainContainer from '@/layout/MainContainer.vue' |
||||
|
// path: '/' component: MainContainer |
||||
|
``` |
||||
|
|
||||
|
删除对 `AppShell` 的引用与文件。 |
||||
|
|
||||
|
- [ ] **Step 5: Build + 手工点菜单** |
||||
|
|
||||
|
Run: `npm run build` |
||||
|
Run: `npm run dev` → 登录后点 admin/非 admin 菜单各 1~2 项 |
||||
|
|
||||
|
Expected: 路由跳转正确;无全量 TDesign CSS 误引入导致的明显全局污染以外的构建错误。 |
||||
|
|
||||
|
- [ ] **Step 6: Commit** |
||||
|
|
||||
|
```bash |
||||
|
git add src/layout src/router/index.js |
||||
|
git commit -m "feat: replace AppShell with TDesign MainContainer shell" |
||||
|
``` |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
### Task 4: LoginView 改 TDesign |
||||
|
|
||||
|
**Files:** |
||||
|
- Modify: `src/views/LoginView/LoginView.vue` |
||||
|
|
||||
|
**Interfaces:** |
||||
|
- Consumes: `@/utils/http`、`useUserStore`、`useUiStore`、现有 `/v1/auth/*` 调用 |
||||
|
- Produces: 同功能登录/注册/找回;UI 为 TDesign 表单 |
||||
|
|
||||
|
- [ ] **Step 1: 用 t-form / t-input / t-button 重写登录主面板** |
||||
|
|
||||
|
保留: |
||||
|
|
||||
|
- 密码登录(对接原 `submitLogin`) |
||||
|
- 短信登录 UI(若原逻辑未接通后端,保持「前端未开放/同等行为」) |
||||
|
- 注册、找回密码流程与校验文案 |
||||
|
|
||||
|
可用左右分栏:左侧品牌区可暂留简化视觉;右侧 TDesign 表单。 |
||||
|
|
||||
|
- [ ] **Step 2: 去掉对旧 login 专用 DOM class 的强依赖(壳层)** |
||||
|
|
||||
|
Login 全屏,不进 MainContainer;确认无地图闪现。 |
||||
|
|
||||
|
- [ ] **Step 3: Build + 手工登录/失败提示** |
||||
|
|
||||
|
Run: `npm run build` |
||||
|
Expected: 登录成功进 `/monitor`;401/错误 toast 仍可用。 |
||||
|
|
||||
|
- [ ] **Step 4: Commit** |
||||
|
|
||||
|
```bash |
||||
|
git add src/views/LoginView/LoginView.vue |
||||
|
git commit -m "feat: rewrite LoginView with on-demand TDesign" |
||||
|
``` |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
### Task 5: 地图骨架(commonRefs / mapHelper / MapLayer / 天地图) |
||||
|
|
||||
|
**Files:** |
||||
|
- Create: `src/utils/commonRefs.js` |
||||
|
- Create: `src/core/mapHelper.js` |
||||
|
- Create: `src/layout/MapLayer.vue` |
||||
|
- Modify: `src/layout/MainContainer.vue`(挂载 MapLayer) |
||||
|
- Modify: `src/config/map.js`(若 Task 1 需补 GroupTileLayer 工厂) |
||||
|
|
||||
|
**Interfaces:** |
||||
|
- Produces: `commonRefs.getRef('map')` → `Promise<maptalks.Map>` |
||||
|
- Produces: `mapHelper.setMap/getMap/toggleMapMode/replaceMapContainer/restoreMapContainer` |
||||
|
- Consumes: `config/map.js` token 与图层模板 |
||||
|
|
||||
|
- [ ] **Step 1: 实现 `commonRefs.js`** |
||||
|
|
||||
|
对齐 edu 语义:`setRef` / `getRef`(Promise) / `removeRef` / `clearPendingList`。可用精简版,但 `getRef` 必须支持「地图尚未 init 时等待」。 |
||||
|
|
||||
|
- [ ] **Step 2: 实现 `mapHelper.js` 最小集** |
||||
|
|
||||
|
```js |
||||
|
class MapHelper { |
||||
|
_map = null |
||||
|
_originParent = null |
||||
|
_savedView = null |
||||
|
|
||||
|
setMap(map) { this._map = map } |
||||
|
getMap() { return this._map } |
||||
|
|
||||
|
toggleMapMode({ is2D = false, is3D = false } = {}) { |
||||
|
if (!this._map) return |
||||
|
if (is2D) { |
||||
|
this._map.setPitch(0) |
||||
|
this._map.setBearing(0) |
||||
|
// 按 maptalks API 关闭/限制拖倾若有 |
||||
|
} else if (is3D) { |
||||
|
this._map.setPitch(45) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
replaceMapContainer(newParent) { |
||||
|
if (!this._map || !newParent) return |
||||
|
const el = this._map.getContainer() |
||||
|
this._originParent = el.parentNode |
||||
|
this._savedView = { |
||||
|
center: this._map.getCenter(), |
||||
|
zoom: this._map.getZoom(), |
||||
|
pitch: this._map.getPitch(), |
||||
|
bearing: this._map.getBearing(), |
||||
|
} |
||||
|
newParent.appendChild(el) |
||||
|
this._map.resize?.() || this._map.checkSize?.() |
||||
|
} |
||||
|
|
||||
|
restoreMapContainer() { |
||||
|
if (!this._map || !this._originParent) return |
||||
|
const el = this._map.getContainer() |
||||
|
this._originParent.appendChild(el) |
||||
|
if (this._savedView) { |
||||
|
this._map.setCenter(this._savedView.center) |
||||
|
this._map.setZoom(this._savedView.zoom) |
||||
|
this._map.setPitch(this._savedView.pitch) |
||||
|
this._map.setBearing(this._savedView.bearing) |
||||
|
} |
||||
|
this._map.resize?.() || this._map.checkSize?.() |
||||
|
this._originParent = null |
||||
|
this._savedView = null |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default new MapHelper() |
||||
|
``` |
||||
|
|
||||
|
按实际 maptalks 版本校正 `resize/checkSize` 方法名。 |
||||
|
|
||||
|
- [ ] **Step 3: 实现 `MapLayer.vue`** |
||||
|
|
||||
|
要点: |
||||
|
|
||||
|
```js |
||||
|
import * as maptalks from 'maptalks' |
||||
|
import mapConfig, { createTiandituLayerOptions } from '@/config/map' |
||||
|
import commonRefs from '@/utils/commonRefs' |
||||
|
import mapHelper from '@/core/mapHelper' |
||||
|
import 'maptalks/dist/maptalks.css' |
||||
|
|
||||
|
function initMap() { |
||||
|
const tk = mapConfig.token |
||||
|
if (!tk) { |
||||
|
console.error('[MapLayer] 缺少 APP_TIANDITU_TOKEN,跳过地图初始化') |
||||
|
return |
||||
|
} |
||||
|
const layers = createTiandituLayerOptions(tk) |
||||
|
const baseLayer = new maptalks.GroupTileLayer('tianditu-base', [ |
||||
|
new maptalks.TileLayer('tdt-img', layers.img), |
||||
|
new maptalks.TileLayer('tdt-cia', layers.cia), |
||||
|
]) |
||||
|
const map = new maptalks.Map('map', { |
||||
|
center: mapConfig.center, |
||||
|
zoom: mapConfig.zoom, |
||||
|
minZoom: 3, |
||||
|
attribution: false, |
||||
|
baseLayer, |
||||
|
}) |
||||
|
commonRefs.setRef('map', map) |
||||
|
mapHelper.setMap(map) |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
`onUnmounted`:`map.remove()`、`commonRefs.removeRef('map')`、`mapHelper.setMap(null)`。 |
||||
|
|
||||
|
模板:`<div id="map" :class="s.root" />`,绝对定位铺满 content。 |
||||
|
|
||||
|
- [ ] **Step 4: 挂到 MainContainer** |
||||
|
|
||||
|
`t-content` 内顺序:`MapLayer` 在下,`RouterView` 在上(业务层可盖住地图)。给 content 设 `position: relative; overflow: hidden; height: ...`。 |
||||
|
|
||||
|
- [ ] **Step 5: 配置 token 后手工验收** |
||||
|
|
||||
|
在 `.env.development` 填入有效天地图 key(若无 key:确认控制台错误且 SPA 其余路由可用)。 |
||||
|
|
||||
|
Run: `npm run build` |
||||
|
Run: `npm run dev` → 登录后应见影像底图;切换 `/devices` 再回 `/monitor` **不**重新 `new Map`(可用 console 打点或 performance 观察,MapLayer 仅随 MainContainer 生命周期)。 |
||||
|
|
||||
|
- [ ] **Step 6: Commit** |
||||
|
|
||||
|
```bash |
||||
|
git add src/utils/commonRefs.js src/core/mapHelper.js src/layout/MapLayer.vue src/layout/MainContainer.vue src/config/map.js .env.development |
||||
|
git commit -m "feat: add Tianditu MapLayer skeleton with mapHelper/commonRefs" |
||||
|
``` |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
### Task 6: 收尾验收与清理 |
||||
|
|
||||
|
**Files:** |
||||
|
- Modify: 任何残留旧路径、未用文件 |
||||
|
- Optional: `README.md` 补一句 dev 启动与 `APP_TIANDITU_TOKEN`(仅当仓库已有 README 或用户要求;当前无 README 则**不要**新建,除非用户点名) |
||||
|
|
||||
|
- [ ] **Step 1: 全局搜旧路径** |
||||
|
|
||||
|
确认无命中:`src/store/`、`api/request`、`AppShell`、`views/Monitor.vue`(扁平)、`element-plus`。 |
||||
|
|
||||
|
- [ ] **Step 2: 对照 spec 验收清单** |
||||
|
|
||||
|
逐条勾选 spec「验收标准」。 |
||||
|
|
||||
|
- [ ] **Step 3: 最终 build** |
||||
|
|
||||
|
Run: `npm run build` |
||||
|
Expected: 通过。 |
||||
|
|
||||
|
- [ ] **Step 4: Commit(若有清理)** |
||||
|
|
||||
|
```bash |
||||
|
git add -A |
||||
|
git commit -m "chore: finalize structure alignment cleanup" |
||||
|
``` |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## 执行方式 |
||||
|
|
||||
|
计划写完后请用户选择: |
||||
|
|
||||
|
1. **本会话直接按 Task 执行**(executing-plans) |
||||
|
2. **新会话 / 子代理按 Task 推进**(subagent-driven-development) |
||||
|
|
||||
|
未完成 Task 1~6 前,不要开始业务图层或批量 TDesign 化业务页。 |
||||
Loading…
Reference in new issue