更新 SGS 地图 SDK 并补充数据层接入手册
This commit is contained in:
568
docs/Data/SGS_SDK_DATA_LAYER_INTEGRATION_GUIDE.md
Normal file
568
docs/Data/SGS_SDK_DATA_LAYER_INTEGRATION_GUIDE.md
Normal file
@@ -0,0 +1,568 @@
|
||||
# SGS Map SDK 数据层接入操作手册
|
||||
|
||||
创建日期:2026-06-25
|
||||
适用项目:`frontend-miniapp` H5 导览业务
|
||||
目标:通过后端 SGS Map SDK 数据接口接入真实楼层、POI、空间面和导航目的地数据,同时保持展示层只消费领域模型。
|
||||
|
||||
## 1. 接入原则
|
||||
|
||||
SGS Map SDK 接入分为两条边界:
|
||||
|
||||
| 边界 | 职责 | 允许接触 SDK/后端字段的位置 | 禁止事项 |
|
||||
| --- | --- | --- | --- |
|
||||
| 数据层 | 拉取楼层、POI、空间面、导航目的地、诊断信息,并转换为 `MuseumFloor`、`MuseumPoi`、`GuideLocationPreview` 等领域模型 | `src/data/providers`、`src/data/adapters`、`src/repositories` | 页面和组件直接请求 `/app-api/gis/sdk/*` |
|
||||
| 渲染层 | 加载 SGS H5 地图基座、管理 iframe/SDK 生命周期、执行切楼层和聚焦命令 | `src/services/sgs`、`src/components/map/SgsMapRenderer.vue` | 把后端数据解析逻辑写进 `SgsMapRenderer.vue` |
|
||||
|
||||
展示层必须只通过以下入口拿数据:
|
||||
|
||||
- `src/usecases/guideUseCase.ts`
|
||||
- `src/repositories/GuideRepository.ts` 暴露的 `GuideRepository` 合同
|
||||
- `src/domain/museum.ts` 中的领域模型
|
||||
|
||||
展示层禁止直接依赖:
|
||||
|
||||
- `SGSMapSDK`
|
||||
- `/app-api/gis/sdk/*` 响应结构
|
||||
- `floorCode`、`typeName`、`position.x/y/z` 等后端原始字段
|
||||
- `manifest.poiCount`、`manifest.spaceCount` 等不可靠摘要字段
|
||||
|
||||
## 2. 当前服务地址
|
||||
|
||||
部署信息:
|
||||
|
||||
| 服务 | 地址 | 当前验证结果 |
|
||||
| --- | --- | --- |
|
||||
| 后端直连 | `http://1.92.206.90:48080/yudao-server/app-api` | 当前开发机访问超时,需服务端排查防火墙/安全组/监听地址 |
|
||||
| 前端代理 | `http://1.92.206.90:3001/app-api` | 可访问,返回后端 `CommonResult code=0` |
|
||||
| H5 SDK 基座 | `http://1.92.206.90:3001/h5-sdk` | 可访问 |
|
||||
| SDK 脚本 | `http://1.92.206.90:3001/sdk/sgs-map-sdk.min.js` | 可访问 |
|
||||
|
||||
本项目推荐环境变量:
|
||||
|
||||
```env
|
||||
VITE_DATA_SOURCE_MODE=sdk
|
||||
VITE_API_BASE_URL=/app-api
|
||||
VITE_SGS_SDK_SCRIPT_URL=/sdk/sgs-map-sdk.min.js
|
||||
VITE_SGS_H5_ENGINE_URL=/h5-sdk
|
||||
VITE_SGS_SDK_ORIGIN=http://1.92.206.90:3001
|
||||
VITE_SGS_SDK_TIMEOUT_MS=10000
|
||||
```
|
||||
|
||||
本地直连联调时可临时使用:
|
||||
|
||||
```env
|
||||
VITE_API_BASE_URL=http://1.92.206.90:3001/app-api
|
||||
VITE_SGS_H5_ENGINE_URL=http://1.92.206.90:3001/h5-sdk
|
||||
VITE_SGS_SDK_SCRIPT_URL=http://1.92.206.90:3001/sdk/sgs-map-sdk.min.js
|
||||
VITE_SGS_SDK_ORIGIN=http://1.92.206.90:3001
|
||||
```
|
||||
|
||||
不要在页面或组件里读取这些环境变量。统一通过 `src/config/dataSource.ts` 暴露配置。
|
||||
|
||||
## 3. 后端接口清单
|
||||
|
||||
SDK 数据接口走 App API 通道,控制器为:
|
||||
|
||||
- `smart-navigation-system/yudao-module-gis/src/main/java/cn/iocoder/yudao/module/gis/controller/app/spatial/SdkMapController.java`
|
||||
- 请求前缀:`/app-api/gis/sdk`
|
||||
|
||||
必接接口:
|
||||
|
||||
| 用途 | 方法 | 路径 | 数据层使用方式 |
|
||||
| --- | --- | --- | --- |
|
||||
| 地图 Manifest | GET | `/gis/sdk/maps/{mapId}/manifest` | 只用于楼层列表、版本、能力声明;不要信任 `poiCount/spaceCount` |
|
||||
| 楼层完整包 | GET | `/gis/sdk/floors/{floorId}/bundle` | 单层详情、模型信息、POI、空间面、路网摘要 |
|
||||
| 楼层 POI | GET | `/gis/sdk/floors/{floorId}/pois` | POI 主数据 |
|
||||
| 楼层空间面 | GET | `/gis/sdk/floors/{floorId}/spaces` | 展厅/空间/服务空间 |
|
||||
| 可导航目的地 | GET | `/gis/sdk/floors/{floorId}/navigable-places` | 起终点候选和空间门点 |
|
||||
| 地图诊断 | GET | `/gis/sdk/maps/{mapId}/diagnostics` | QA、健康检查、路网就绪判断 |
|
||||
| 楼层诊断 | GET | `/gis/sdk/floors/{floorId}/diagnostics` | 单层数据完整性与路网就绪 |
|
||||
|
||||
后端原始 App 口径,可用于交叉核验:
|
||||
|
||||
| 用途 | 方法 | 路径 |
|
||||
| --- | --- | --- |
|
||||
| 楼层主表 | GET | `/gis/floor/list` |
|
||||
| 原始 POI | GET | `/gis/poi/list-by-floor?floorId={floorId}` |
|
||||
| C 端精简 POI | GET | `/gis/sgs-poi/list-by-floor?floorId={floorId}` |
|
||||
|
||||
当前已知数据风险:
|
||||
|
||||
- `manifest.floors[].poiCount` 当前全部为 `0`,实际后端 POI 为 `162`。
|
||||
- `manifest.floors[].spaceCount` 当前与实际空间面数量不一致。
|
||||
- `L-1` 有 POI 和路网,但 `navigable-places=0`。
|
||||
- `EXTERIOR` 路网节点和边为 `0`,不能用于路径规划。
|
||||
- 逐层 `guide-stops` 合计为 `0`,地图 diagnostics 中 `guideStopCount=1`,聚合口径不一致。
|
||||
- SDK POI 当前全部 `status=INACTIVE`,`anchorNodeName`、`description`、`iconUrl` 为空。数据层不要因为 `INACTIVE` 自动丢弃全部 POI,除非后端明确状态语义。
|
||||
|
||||
## 4. 推荐落地文件
|
||||
|
||||
只新增或修改数据边界文件,展示层不动。
|
||||
|
||||
```text
|
||||
src/config/dataSource.ts
|
||||
继续作为 mode/api/sdk/url 配置唯一入口
|
||||
|
||||
src/data/providers/sgsSdkApiProvider.ts
|
||||
新增:负责请求 /app-api/gis/sdk/*
|
||||
|
||||
src/data/adapters/sgsSdkGuideAdapter.ts
|
||||
新增:负责 SDK 响应 -> MuseumFloor/MuseumPoi/GuideLocationPreview/GuideRouteReadiness
|
||||
|
||||
src/repositories/GuideRepository.ts
|
||||
增加 ApiGuideRepository 或 SgsSdkGuideRepository
|
||||
保持 GuideRepository interface 不变
|
||||
|
||||
src/repositories/createGuideRepository.ts
|
||||
可选新增:根据 dataSourceConfig.mode 选择 StaticGuideRepository 或 SgsSdkGuideRepository
|
||||
|
||||
src/usecases/guideUseCase.ts
|
||||
原则上不改业务方法,只替换 repository 注入来源
|
||||
```
|
||||
|
||||
不要把以下逻辑写进组件:
|
||||
|
||||
```text
|
||||
src/pages/**
|
||||
src/components/navigation/**
|
||||
src/components/search/**
|
||||
src/components/map/SgsMapRenderer.vue
|
||||
```
|
||||
|
||||
`SgsMapRenderer.vue` 只负责 SDK iframe/渲染生命周期。它可以接收领域模型里来的 `floorId`、`poiId`、`positionGltf`,但不能自己请求 POI 列表或解析后端字段。
|
||||
|
||||
## 5. Provider 实现要求
|
||||
|
||||
`sgsSdkApiProvider.ts` 只做网络请求和 CommonResult 解包,不做领域转换。
|
||||
|
||||
建议接口:
|
||||
|
||||
```ts
|
||||
export interface SgsSdkApiProvider {
|
||||
getManifest(mapId?: string): Promise<SgsSdkManifestPayload>
|
||||
getMapDiagnostics(mapId?: string): Promise<SgsMapDiagnosticsPayload>
|
||||
getFloorDiagnostics(floorId: string): Promise<SgsFloorDiagnosticsPayload>
|
||||
getFloorBundle(floorId: string): Promise<SgsFloorBundlePayload>
|
||||
getFloorPois(floorId: string): Promise<SgsPoiPayload[]>
|
||||
getFloorSpaces(floorId: string): Promise<SgsSpacePayload[]>
|
||||
getNavigablePlaces(floorId: string): Promise<SgsNavigablePlacePayload[]>
|
||||
}
|
||||
```
|
||||
|
||||
请求实现规则:
|
||||
|
||||
- 使用 `dataSourceConfig.apiBaseUrl` 作为基地址。
|
||||
- H5 下可继续用 `uni.request`,不要在组件中使用 `fetch`。
|
||||
- 统一处理 `{ code, data, msg }`,`code !== 0` 必须抛出带路径的错误。
|
||||
- 请求超时和网络错误要带 endpoint 信息,方便 QA 判断是后端还是代理问题。
|
||||
- 可以在 Provider 内做短生命周期缓存,避免每次搜索重复拉全量 POI。
|
||||
- Provider 返回类型命名使用 `Payload` 后缀,提醒调用者这是后端形状,不是领域模型。
|
||||
|
||||
示例骨架:
|
||||
|
||||
```ts
|
||||
import { dataSourceConfig } from '@/config/dataSource'
|
||||
|
||||
const normalizeBaseUrl = (baseUrl: string) => baseUrl.replace(/\/+$/, '')
|
||||
|
||||
const requestJson = <T>(path: string): Promise<T> => new Promise((resolve, reject) => {
|
||||
const baseUrl = normalizeBaseUrl(dataSourceConfig.apiBaseUrl || '/app-api')
|
||||
|
||||
uni.request({
|
||||
url: `${baseUrl}${path}`,
|
||||
method: 'GET',
|
||||
success: (response) => {
|
||||
const statusCode = Number(response.statusCode || 0)
|
||||
if (statusCode < 200 || statusCode >= 300) {
|
||||
reject(new Error(`SGS 后端接口请求失败: ${statusCode} ${path}`))
|
||||
return
|
||||
}
|
||||
|
||||
const body = typeof response.data === 'string'
|
||||
? JSON.parse(response.data)
|
||||
: response.data
|
||||
|
||||
if (!body || body.code !== 0) {
|
||||
reject(new Error(`SGS 后端接口业务失败: ${path} code=${body?.code} msg=${body?.msg || ''}`))
|
||||
return
|
||||
}
|
||||
|
||||
resolve(body.data as T)
|
||||
},
|
||||
fail: (error) => reject(new Error(`SGS 后端接口网络失败: ${path} ${JSON.stringify(error)}`))
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## 6. Adapter 映射规则
|
||||
|
||||
`sgsSdkGuideAdapter.ts` 是阻断展示层污染的关键。所有后端字段都在这里转换。
|
||||
|
||||
### 6.1 楼层映射
|
||||
|
||||
后端字段:
|
||||
|
||||
```ts
|
||||
{
|
||||
floorId: '2065808921272119298',
|
||||
floorCode: 'L1',
|
||||
floorName: '1.0层',
|
||||
sortOrder: 10
|
||||
}
|
||||
```
|
||||
|
||||
领域模型:
|
||||
|
||||
```ts
|
||||
MuseumFloor {
|
||||
id: floorId,
|
||||
label: readableFloorLabel(floorCode, floorName),
|
||||
order: sortOrder
|
||||
}
|
||||
```
|
||||
|
||||
建议显示标签:
|
||||
|
||||
| 后端 floorCode | 领域 label |
|
||||
| --- | --- |
|
||||
| `EXTERIOR` | `室外` |
|
||||
| `L-2` | `B2` |
|
||||
| `L-1` | `B1` |
|
||||
| `L1` | `1F` |
|
||||
| `L1.5` | `1.5F` |
|
||||
| `L2` | `2F` |
|
||||
|
||||
`normalizeFloorId(labelOrId)` 必须同时支持:
|
||||
|
||||
- 后端长 ID,例如 `2065808921272119298`
|
||||
- 后端 `floorCode`,例如 `L1`
|
||||
- 前端显示标签,例如 `1F`
|
||||
|
||||
### 6.2 POI 映射
|
||||
|
||||
后端字段:
|
||||
|
||||
```ts
|
||||
{
|
||||
id: '5576',
|
||||
name: '服务台',
|
||||
type: 'service_desk',
|
||||
typeName: '服务台',
|
||||
floorId: '2065808921272119298',
|
||||
floorCode: 'L1',
|
||||
position: { x: -59.617386, y: 0.658652, z: 16.816816 },
|
||||
status: 'INACTIVE',
|
||||
anchorNodeName: null,
|
||||
description: null,
|
||||
iconUrl: null
|
||||
}
|
||||
```
|
||||
|
||||
领域模型:
|
||||
|
||||
```ts
|
||||
MuseumPoi {
|
||||
id: String(id),
|
||||
name,
|
||||
floorId: String(floorId),
|
||||
floorLabel,
|
||||
primaryCategory: mapSgsPoiCategory(type, typeName),
|
||||
categories: [primaryCategory],
|
||||
positionGltf: [position.x, position.y, position.z],
|
||||
sourceConfidence: 'backend-sgs-sdk',
|
||||
navigationReadiness,
|
||||
accessible
|
||||
}
|
||||
```
|
||||
|
||||
坐标规则:
|
||||
|
||||
- 后端 SDK 文档声明坐标系为 `GLB_METER`。
|
||||
- `position.x/y/z` 进入领域层统一保存为 `positionGltf: [x, y, z]`。
|
||||
- 不要在展示层重排坐标轴。
|
||||
- 如果某个接口只返回 `x/y/z` 平铺字段,也在 Adapter 内统一转为 `positionGltf`。
|
||||
|
||||
类型映射建议:
|
||||
|
||||
| SGS type | 领域分类 id | label | accessible |
|
||||
| --- | --- | --- | --- |
|
||||
| `toilet` | `basic_service_facility` | `卫生间` | false |
|
||||
| `accessible_toilet` | `accessibility_special_service` | `无障碍卫生间` | true |
|
||||
| `elevator` | `transport_circulation` | `电梯` | true |
|
||||
| `stairs` | `transport_circulation` | `楼梯` | false |
|
||||
| `escalator` | `transport_circulation` | `扶梯` | false |
|
||||
| `entrance_exit` | `transport_circulation` | `出入口` | false |
|
||||
| `service_desk` | `basic_service_facility` | `服务台` | false |
|
||||
| `mother_baby_room` | `basic_service_facility` | `母婴室` | true |
|
||||
| `locker` | `basic_service_facility` | `存包处` | false |
|
||||
| `rental_service` | `basic_service_facility` | `租赁服务` | true |
|
||||
| `ticket_office` | `basic_service_facility` | `售票处` | false |
|
||||
|
||||
不要让组件判断 `type === 'toilet'`。组件只看领域层的 `primaryCategory`、`accessible`、`floorLabel`。
|
||||
|
||||
### 6.3 导航目的地映射
|
||||
|
||||
`navigable-places` 不等同于 POI,它可能是空间门点。
|
||||
|
||||
建议在数据层使用独立内部类型,例如:
|
||||
|
||||
```ts
|
||||
interface SgsNavigablePlaceDomain {
|
||||
id: string
|
||||
name: string
|
||||
floorId: string
|
||||
floorLabel: string
|
||||
category: 'poi' | 'door' | 'space' | 'guide'
|
||||
positionGltf: [number, number, number]
|
||||
ownerName?: string
|
||||
}
|
||||
```
|
||||
|
||||
当前 `GuideRepository` 合同没有暴露导航目的地列表。如果近期只做位置预览,可暂时只把 POI 映射到 `MuseumPoi`。如果要启用真实路线选择,再扩展 `GuideRouteRepository` 或新增 route use case,避免把导航目的地塞进 POI 列表污染搜索。
|
||||
|
||||
### 6.4 路线就绪映射
|
||||
|
||||
`GuideRepository.getRouteReadiness()` 应基于 diagnostics,而不是静态常量。
|
||||
|
||||
建议规则:
|
||||
|
||||
```text
|
||||
mapDiagnostics.status === 'OK'
|
||||
且所有室内可导航楼层 routePlanningReady=true
|
||||
且 routeNodeCount > 0
|
||||
且 routeEdgeCount > 0
|
||||
且关键楼层 navigablePlaceCount > 0
|
||||
=> ready=true
|
||||
|
||||
否则 ready=false,并把 warnings / requiredData 写入 GuideRouteReadiness
|
||||
```
|
||||
|
||||
当前线上数据必须返回 `ready=false` 或“实验性路线预览”,因为:
|
||||
|
||||
- `EXTERIOR` 路径规划未就绪。
|
||||
- `L-1` 无可导航目的地。
|
||||
- guideStop 聚合口径不一致。
|
||||
|
||||
## 7. Repository 接入方式
|
||||
|
||||
保持现有 `GuideRepository` interface 不变:
|
||||
|
||||
```ts
|
||||
export interface GuideRepository {
|
||||
getAssetBaseUrl(): string
|
||||
getFloors(): Promise<MuseumFloor[]>
|
||||
normalizeFloorId(labelOrId: string): string
|
||||
listPois(): Promise<MuseumPoi[]>
|
||||
getPoiById(id: string): Promise<MuseumPoi | null>
|
||||
searchPois(keyword?: string): Promise<MuseumPoi[]>
|
||||
getLocationPreview(poiId: string): Promise<GuideLocationPreview | null>
|
||||
getRouteReadiness(): Promise<GuideRouteReadiness>
|
||||
}
|
||||
```
|
||||
|
||||
新增 `SgsSdkGuideRepository`:
|
||||
|
||||
```ts
|
||||
export class SgsSdkGuideRepository implements GuideRepository {
|
||||
private floorsCache: MuseumFloor[] | null = null
|
||||
private poiCache: MuseumPoi[] | null = null
|
||||
|
||||
constructor(private readonly provider: SgsSdkApiProvider = defaultSgsSdkApiProvider) {}
|
||||
|
||||
getAssetBaseUrl() {
|
||||
return ''
|
||||
}
|
||||
|
||||
async getFloors() {
|
||||
if (this.floorsCache) return this.floorsCache
|
||||
const manifest = await this.provider.getManifest('1')
|
||||
this.floorsCache = manifest.floors
|
||||
.map(toMuseumFloor)
|
||||
.sort((a, b) => a.order - b.order)
|
||||
return this.floorsCache
|
||||
}
|
||||
|
||||
async listPois() {
|
||||
if (this.poiCache) return this.poiCache
|
||||
const manifest = await this.provider.getManifest('1')
|
||||
const poisByFloor = await Promise.all(
|
||||
manifest.floors.map((floor) => this.provider.getFloorPois(String(floor.floorId)))
|
||||
)
|
||||
this.poiCache = poisByFloor.flat().map((poi) => toMuseumPoiFromSgs(poi, manifest.floors))
|
||||
return this.poiCache
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Repository 规则:
|
||||
|
||||
- `listPois()` 可以跨楼层聚合,但只返回领域模型。
|
||||
- `getPoiById()` 从 `listPois()` 缓存查找,避免重复请求。
|
||||
- `searchPois()` 使用 `MuseumPoi` 字段构建搜索文本,不能搜索后端 raw JSON。
|
||||
- `getLocationPreview()` 只返回 `GuideLocationPreview`。
|
||||
- `getRouteReadiness()` 只返回 `GuideRouteReadiness`,不要把 diagnostics 原样传给 UI。
|
||||
|
||||
## 8. 模式切换
|
||||
|
||||
当前 `src/config/dataSource.ts` 已有:
|
||||
|
||||
```ts
|
||||
export type DataSourceMode = 'static' | 'api' | 'sdk'
|
||||
export const isSgsSdkMode = () => dataSourceConfig.mode === 'sdk'
|
||||
```
|
||||
|
||||
推荐新增仓库工厂:
|
||||
|
||||
```ts
|
||||
import { dataSourceConfig } from '@/config/dataSource'
|
||||
import { StaticGuideRepository } from '@/repositories/GuideRepository'
|
||||
import { SgsSdkGuideRepository } from '@/repositories/SgsSdkGuideRepository'
|
||||
|
||||
export const createGuideRepository = () => {
|
||||
if (dataSourceConfig.mode === 'sdk' || dataSourceConfig.mode === 'api') {
|
||||
return new SgsSdkGuideRepository()
|
||||
}
|
||||
|
||||
return new StaticGuideRepository()
|
||||
}
|
||||
```
|
||||
|
||||
然后 `guideUseCase.ts` 只依赖工厂返回的 `GuideRepository`,页面不用知道当前是 static/api/sdk。
|
||||
|
||||
推荐模式语义:
|
||||
|
||||
| mode | 数据来源 | 渲染器 |
|
||||
| --- | --- | --- |
|
||||
| `static` | 本地 clean nav-assets | `ThreeMap` |
|
||||
| `api` | 后端 SGS App API | 仍可用 `ThreeMap` 或本地渲染 |
|
||||
| `sdk` | 后端 SGS App API | `SgsMapRenderer` |
|
||||
|
||||
不要把 `sdk` 理解成“页面直接调用 `SGSMapSDK.getFloorPois()`”。数据仍从 Repository 进来,SDK 只做地图渲染和交互命令。
|
||||
|
||||
## 9. 展示层改造边界
|
||||
|
||||
允许展示层做的事:
|
||||
|
||||
- 调用 `guideUseCase.getFloors()`
|
||||
- 调用 `guideUseCase.searchPois(keyword)`
|
||||
- 调用 `guideUseCase.getPoiById(id)`
|
||||
- 传 `GuideLocationPreview.positionGltf` 给地图聚焦
|
||||
- 通过 `GuideMapShell` 选择 `ThreeMap` 或 `SgsMapRenderer`
|
||||
|
||||
禁止展示层做的事:
|
||||
|
||||
```ts
|
||||
// 禁止:页面直接请求后端
|
||||
uni.request({ url: '/app-api/gis/sdk/floors/xxx/pois' })
|
||||
|
||||
// 禁止:组件直接判断后端字段
|
||||
if (poi.type === 'accessible_toilet') { ... }
|
||||
|
||||
// 禁止:组件直接拼后端楼层 ID 显示
|
||||
text = `${raw.floorCode}-${raw.floorName}`
|
||||
|
||||
// 禁止:SgsMapRenderer 拉取 POI 列表
|
||||
await service.getFloorPois(floorId)
|
||||
```
|
||||
|
||||
如果组件需要新增展示信息,先判断是否属于领域模型:
|
||||
|
||||
- 属于稳定导览语义:加到 `src/domain/museum.ts`。
|
||||
- 属于后端传输字段:留在 Provider/Adapter,禁止穿透。
|
||||
- 属于 SDK 渲染命令结果:放到 `src/services/sgs/SgsMapEventAdapter.ts` 转成 UI 事件。
|
||||
|
||||
## 10. 推荐实施步骤
|
||||
|
||||
1. 新增 `src/data/providers/sgsSdkApiProvider.ts`。
|
||||
2. 新增 `src/data/adapters/sgsSdkGuideAdapter.ts`。
|
||||
3. 新增 `SgsSdkGuideRepository`,实现现有 `GuideRepository` interface。
|
||||
4. 新增仓库工厂,根据 `dataSourceConfig.mode` 选择 static 或 SGS 后端数据。
|
||||
5. 让 `guideUseCase` 使用仓库工厂,不改页面调用方式。
|
||||
6. 在 `sdk` 模式下让 `GuideMapShell` 继续选择 `SgsMapRenderer`,但 POI/楼层数据仍来自 `GuideUseCase`。
|
||||
7. 增加数据健康检查脚本或开发命令,校验楼层、POI、空间面、导航目的地计数。
|
||||
8. 通过 H5 浏览器检查搜索、楼层切换、POI 聚焦、位置预览。
|
||||
|
||||
## 11. 验收检查清单
|
||||
|
||||
数据接口检查:
|
||||
|
||||
```powershell
|
||||
$base = "http://1.92.206.90:3001/app-api"
|
||||
Invoke-RestMethod "$base/gis/floor/list"
|
||||
Invoke-RestMethod "$base/gis/sdk/maps/1/manifest"
|
||||
Invoke-RestMethod "$base/gis/sdk/maps/1/diagnostics"
|
||||
Invoke-RestMethod "$base/gis/sdk/floors/2065808921272119298/pois"
|
||||
Invoke-RestMethod "$base/gis/sdk/floors/2065808921272119298/navigable-places"
|
||||
```
|
||||
|
||||
必须满足:
|
||||
|
||||
- `/gis/floor/list` 与 SDK manifest 楼层 ID 一致。
|
||||
- `/gis/poi/list-by-floor` 与 `/gis/sdk/floors/{id}/pois` POI ID 一致。
|
||||
- POI 无重复 ID。
|
||||
- POI 无缺失 `id/name/type/floorId/position`。
|
||||
- POI `floorId` 与请求楼层一致。
|
||||
- 空间面无缺失 `id/name/type/floorId/boundaryWkt`。
|
||||
- `GuideRepository.listPois()` 只返回 `MuseumPoi[]`。
|
||||
- 页面源码中不能出现 `/app-api/gis/sdk`。
|
||||
- 页面源码中不能出现 `SGSMapSDK`。
|
||||
|
||||
代码扫描:
|
||||
|
||||
```powershell
|
||||
rg -n "/app-api/gis/sdk|SGSMapSDK|getFloorPois|getManifest|getNavigablePlaces" src/pages src/components
|
||||
```
|
||||
|
||||
预期:
|
||||
|
||||
- `src/components/map/SgsMapRenderer.vue` 可以出现 SDK 渲染相关服务调用。
|
||||
- 其它页面和组件不应直接出现后端 SDK 数据接口或 SDK 全局对象。
|
||||
|
||||
构建验证:
|
||||
|
||||
```powershell
|
||||
pnpm type-check
|
||||
pnpm lint
|
||||
pnpm build:h5
|
||||
```
|
||||
|
||||
浏览器验证:
|
||||
|
||||
- `static` 模式仍可加载本地 3D/POI。
|
||||
- `api` 模式能展示后端楼层和 POI,渲染器不变。
|
||||
- `sdk` 模式能加载 SGS 地图基座,楼层切换与 POI 聚焦可用。
|
||||
- SDK 失败时有错误态,不出现空白地图。
|
||||
- 顶部 tabs、搜索、楼层控件、详情卡片不被 iframe/canvas 遮挡。
|
||||
|
||||
## 12. 上线前阻断项
|
||||
|
||||
以下问题未解决前,不建议对用户宣称“正式室内导航”:
|
||||
|
||||
- `L-1` 无可导航目的地。
|
||||
- `EXTERIOR` 路网未就绪。
|
||||
- `manifest` 计数与实际明细不一致。
|
||||
- `guideStopCount` 聚合口径不一致。
|
||||
- POI 全部 `status=INACTIVE` 的业务语义未确认。
|
||||
|
||||
用户文案应保持为:
|
||||
|
||||
- `位置预览`
|
||||
- `查看三维位置`
|
||||
- `路线预览`
|
||||
- `导航数据准备中`
|
||||
|
||||
不要使用:
|
||||
|
||||
- `开始馆内导航`
|
||||
- `实时导航`
|
||||
- `到达引导`
|
||||
- `精准路径规划`
|
||||
|
||||
## 13. 维护约定
|
||||
|
||||
- 后端接口字段变化先改 Provider Payload 类型。
|
||||
- 领域含义变化再改 Adapter。
|
||||
- UI 需要新信息时先扩展领域模型,再通过 Repository 暴露。
|
||||
- 不要为了一个页面临时把 raw SDK 字段传透到组件。
|
||||
- 每次更新 SDK 后,重新跑楼层/POI/空间面/导航目的地完整性检查。
|
||||
- 每次启用真实路线能力前,重新审核 `GuideRouteReadiness`,保持不夸大导航能力。
|
||||
Reference in New Issue
Block a user