800 lines
42 KiB
Markdown
800 lines
42 KiB
Markdown
# frontend-miniapp 数据层全面审计报告
|
||
|
||
审计日期:2026-05-28
|
||
审计分支:`analysis/ux-ui-audit-2026-05-28`
|
||
审计对象:`museum-guide-v4.0/frontend-miniapp`
|
||
审计范围:Mock 数据、类型定义、数据加载、搜索/地图/详情页硬编码数据、静态资源、3D/馆内 POI 数据、数据治理与性能策略。
|
||
|
||
## 执行摘要
|
||
|
||
当前 `frontend-miniapp` 的数据层处于“多套 Mock 数据并存”的原型状态,不能直接作为深圳自然博物馆导览的数据基础。最高风险集中在三类:业务定位数据错配、数据源不统一、资源与关联关系不可验证。
|
||
|
||
| 优先级 | 关键风险 | 影响 | 建议 |
|
||
| --- | --- | --- | --- |
|
||
| P0 | 核心 JSON 仍是“深圳国际艺术馆/世界名画”内容,而产品标识是“深圳自然博物馆” | 搜索、详情、路线、讲解内容与真实馆方定位冲突 | 立即建立自然博物馆数据字典和迁移清单,冻结旧艺术馆 Mock 数据新增 |
|
||
| P0 | 列表、详情、地图、搜索各自硬编码不同实体与 ID | 用户从搜索/地图进入详情会看到不一致内容,甚至找不到对应数据 | 建立单一数据源,所有页面按 `entityId` 查询同一仓库 |
|
||
| P0 | 15 个图片/音频 URL 指向不存在资源,另有 `https://example.com/audio.mp3` 占位 | 展品图、展厅图、语音讲解失败,影响核心导览体验 | 建立资源清单校验,缺失资源上线前阻断 |
|
||
| P1 | 类型定义与真实 POI/地图数据不匹配 | TypeScript 无法保护 3D 坐标、入口/展厅/设施枚举,后续扩展易破 | 扩展 `Position`、`POI`、`FacilityType`、多语言与状态字段 |
|
||
| P1 | 无数据版本、校验、缓存、错误分级 | 数据异常会静默返回空数组,难以监控和降级 | 引入 schema 校验、数据版本元信息和错误态 UI |
|
||
|
||
建议采用两步治理:先用 1 周完成“数据源收敛和阻断性校验”,再用 2 到 4 周完成自然博物馆正式数据迁移、地图 POI 绑定、资源治理与多语言模型。
|
||
|
||
## 审计方法
|
||
|
||
本次审计使用静态扫描和结构化脚本校验,未修改业务代码。
|
||
|
||
| 方法 | 覆盖内容 | 证据来源 |
|
||
| --- | --- | --- |
|
||
| JSON 结构扫描 | 展品、展厅、设施、路线、楼层、馆内 POI 数量与字段 | `src/assets/data/*.json`、`static/data/f1-indoor-pois.json` |
|
||
| 引用完整性校验 | 展品到展厅、楼层到展厅/设施、路线到站点 | Node 脚本读取 JSON 后交叉比对 |
|
||
| 静态资源存在性校验 | 图片、音频、展厅图是否存在于 `static/` | 文件系统校验 |
|
||
| 硬编码扫描 | 页面、组件、地图、搜索中的本地数组和占位 URL | `rg` 搜索 |
|
||
| 类型与数据流审查 | TypeScript 接口、数据加载、搜索工具、服务层 | `src/types/index.ts`、`src/utils/dataLoader.ts`、`src/utils/search.ts`、`src/services/map/Map3DManager.ts` |
|
||
|
||
## 数据资产盘点
|
||
|
||
| 数据源 | 数量 | 现状判断 | 主要问题 |
|
||
| --- | ---: | --- | --- |
|
||
| `src/assets/data/exhibits.json` | 5 | 艺术馆展品 Mock | 全部是世界名画,不是自然博物馆展品;图片/音频缺失 |
|
||
| `src/assets/data/halls.json` | 5 | 艺术馆展厅 Mock | 展厅主题为文艺复兴、印象派、现代艺术;展品数量与实际 JSON 不一致 |
|
||
| `src/assets/data/facilities.json` | 8 | 基础设施/模型坐标混合数据 | 点位坐标来自 `f1-floor.glb` 提取,应保留;但实体名称、类型、描述仍与真实 1F POI 和自然博物馆语义不一致 |
|
||
| `src/assets/data/routes.json` | 3 | 艺术馆路线 Mock | 路线名称、站点均围绕艺术作品;不适配自然博物馆参观动线 |
|
||
| `src/assets/data/floors.json` | 4 | 楼层索引 | `B1` 引用不存在设施,且无展厅 |
|
||
| `static/data/f1-indoor-pois.json` | 67 | 真实 1F 馆内点位基准 | 其它设施、展厅、搜索、地图详情数据未以它为准,存在大面积冲突 |
|
||
| `static/models/*.glb` | 2 | 真实 1F 3D 模型资产 | `f1-indoor.glb`、`f1-floor.glb` 均为自然博物馆 1F 真实模型;需补模型清单、坐标系与部署目录策略 |
|
||
| `static/icons/*.svg` | 8 | 地图图标 | 可用,但 POI 类型枚举与图标映射未统一 |
|
||
|
||
当前数据流可以概括为:
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A["assets/data/*.json<br/>艺术馆核心 Mock"] --> B["dataLoader.ts"]
|
||
B --> C["部分列表/工具函数"]
|
||
D["pages/detail.vue<br/>硬编码详情"] --> E["详情页展示"]
|
||
F["SearchPanel / ExplainList<br/>自然博物馆硬编码 Mock"] --> G["搜索/讲解抽屉"]
|
||
H["TencentMap / ThreeMap<br/>硬编码地图点"] --> I["地图弹层"]
|
||
J["static/data/f1-indoor-pois.json<br/>67 个馆内 POI"] -.未统一接入.-> I
|
||
```
|
||
|
||
## 1. 数据完整性审计
|
||
|
||
### 1.1 Mock 数据覆盖度
|
||
|
||
| 实体 | 当前覆盖 | 与真实自然博物馆导览的差距 | 严重性 |
|
||
| --- | --- | --- | --- |
|
||
| 展品 | 5 个艺术作品 | 缺少标本、化石、矿物、动植物、年代、分类、馆藏编号、展陈状态、讲解文本层级 | P0 |
|
||
| 展厅 | 5 个艺术主题展厅 | 缺少自然史展厅分区、楼层分布、入口/出口、展厅开放状态、人流/容量 | P0 |
|
||
| 设施 | 8 个基础设施 | 馆内 POI 有 58 个设施,但未与设施表合并;缺少服务台、母婴室、寄存、无障碍、楼梯等正式类型 | P1 |
|
||
| 路线 | 3 条艺术馆路线 | 缺少亲子、研学、无障碍、快速参观、自然史主题路线 | P0 |
|
||
| 楼层 | 4 层索引 | 只有简单数组引用,无真实地图区域、楼层坐标系、模型版本、开放状态 | P1 |
|
||
| POI | F1 有 67 个模型点 | 只覆盖 `1F`,未绑定展品/展厅/路线/设施详情 | P1 |
|
||
|
||
### 1.2 必填字段缺失与占位符
|
||
|
||
结构字段层面,展品、展厅、设施、路线大多包含基础字段,但业务必填字段明显不足:没有馆藏编号、自然史分类、状态、更新时间、版权、资源元信息、语种、坐标系。
|
||
|
||
静态校验结果:
|
||
|
||
```text
|
||
COUNTS
|
||
exhibits: 5
|
||
halls: 5
|
||
facilities: 8
|
||
routes: 3
|
||
floors: 4
|
||
pois: 67
|
||
|
||
MISSING REQUIRED
|
||
exhibits: none
|
||
halls: none
|
||
facilities: none
|
||
routes: none
|
||
floors: floor_b1:halls
|
||
```
|
||
|
||
虽然基础字段未大量为空,但资源字段失效非常严重:
|
||
|
||
```text
|
||
exhibit_1.image -> /static/exhibits/mona-lisa.jpg missing
|
||
exhibit_1.audioUrl -> /static/audio/exhibit-1.mp3 missing
|
||
exhibit_2.image -> /static/exhibits/last-supper.jpg missing
|
||
exhibit_2.audioUrl -> /static/audio/exhibit-2.mp3 missing
|
||
exhibit_3.image -> /static/exhibits/starry-night.jpg missing
|
||
exhibit_3.audioUrl -> /static/audio/exhibit-3.mp3 missing
|
||
exhibit_4.image -> /static/exhibits/sunflowers.jpg missing
|
||
exhibit_4.audioUrl -> /static/audio/exhibit-4.mp3 missing
|
||
exhibit_5.image -> /static/exhibits/david.jpg missing
|
||
exhibit_5.audioUrl -> /static/audio/exhibit-5.mp3 missing
|
||
hall_1.image -> /static/halls/hall-1.jpg missing
|
||
hall_2.image -> /static/halls/hall-2.jpg missing
|
||
hall_3.image -> /static/halls/hall-3.jpg missing
|
||
hall_4.image -> /static/halls/hall-4.jpg missing
|
||
hall_5.image -> /static/halls/hall-5.jpg missing
|
||
```
|
||
|
||
页面中还存在音频占位 URL:
|
||
|
||
```text
|
||
frontend-miniapp/src/pages/index/index.vue:306
|
||
audioUrl: exhibit.audioUrl || 'https://example.com/audio.mp3'
|
||
|
||
frontend-miniapp/src/pages/index/index.vue:355
|
||
audioUrl: exhibit.audioUrl || 'https://example.com/audio.mp3'
|
||
```
|
||
|
||
### 1.3 数据一致性
|
||
|
||
展厅统计与实际展品数量完全不一致:
|
||
|
||
| 展厅 | `halls.json` 标称展品数 | `exhibits.json` 实际归属数 | 差异 |
|
||
| --- | ---: | ---: | ---: |
|
||
| `hall_1` | 25 | 3 | -22 |
|
||
| `hall_2` | 18 | 2 | -16 |
|
||
| `hall_3` | 30 | 0 | -30 |
|
||
| `hall_4` | 22 | 0 | -22 |
|
||
| `hall_5` | 15 | 0 | -15 |
|
||
|
||
同一逻辑实体在不同模块中出现了多套 ID 和名称:
|
||
|
||
| 模块 | 示例 | 问题 |
|
||
| --- | --- | --- |
|
||
| 核心 JSON | `exhibit_1`:`蒙娜丽莎` | 艺术馆实体 |
|
||
| 搜索页 | `id: '1', name: '蒙娜丽莎'` | ID 不是 `exhibit_1`,进入详情时无法保证匹配 |
|
||
| 搜索面板 | `id: '1', name: '霸王龙化石骨架'` | 同一 ID `1` 在另一模块代表自然博物馆展品 |
|
||
| 讲解抽屉 | `id: '1', name: '银杏化石'` | 同一 ID `1` 又代表第三个实体 |
|
||
| 地图首页 | `exhibit-1`:`恐龙化石展区` | ID 命名与核心 JSON 不一致 |
|
||
| 3D 地图 | `exhibit-1`:`恐龙化石展区` | 与 `exhibit_1` 不一致,且未绑定详情数据 |
|
||
|
||
硬编码证据截图:
|
||
|
||
```text
|
||
frontend-miniapp/src/pages/search/index.vue:101
|
||
{ id: '1', name: '蒙娜丽莎', artist: '达芬奇', hall: '1号展厅', hasAudio: true }
|
||
|
||
frontend-miniapp/src/components/search/SearchPanel.vue:143
|
||
{ id: '1', name: '霸王龙化石骨架', desc: '恐龙厅 · 2F', type: 'exhibit' }
|
||
|
||
frontend-miniapp/src/components/explain/ExplainList.vue:293
|
||
{ id: '1', name: '银杏化石', hall: '演化厅 B1', hasAudio: true, audioUrl: '' }
|
||
|
||
frontend-miniapp/src/pages/index/index.vue:164
|
||
'exhibit-1': { id: 'exhibit-1', name: '恐龙化石展区', subtitle: '中生代恐龙化石展示', type: 'exhibit', floor: '2F' }
|
||
```
|
||
|
||
### 1.4 关联关系完整性
|
||
|
||
路线站点都能在艺术馆展品表中找到,但楼层到设施存在断链:
|
||
|
||
```text
|
||
BROKEN REFERENCES
|
||
floor floor_b1 facility parking_b1
|
||
floor floor_b1 facility storage_b1
|
||
```
|
||
|
||
更大的关联问题是 `static/data/f1-indoor-pois.json` 与核心实体完全脱钩。该文件已确认为真实 1F 设施点位基准,包含 67 个 POI,类型分布为:
|
||
|
||
```text
|
||
POI TYPES
|
||
{ hall: 6, facility: 58, entrance: 3 }
|
||
POI floors: 1F
|
||
```
|
||
|
||
这些 POI 的 `id` 形如 `poi_0`,没有 `entityId` 指向 `hall_1`、`facility_*` 或路线站点,无法支撑“点击地图点打开统一详情”“按路线高亮真实点位”等核心导览能力。
|
||
|
||
### 1.5 数据时效性
|
||
|
||
当前数据没有以下字段,无法判断是否过期:
|
||
|
||
| 缺失能力 | 影响 |
|
||
| --- | --- |
|
||
| `status` / `visibility` | 无法区分开放、临时关闭、下架、维护中 |
|
||
| `validFrom` / `validTo` | 无法表达临展、活动、设施维修周期 |
|
||
| `updatedAt` / `sourceVersion` | 无法追踪数据来源和更新批次 |
|
||
| `reviewedBy` / `reviewedAt` | 无法形成馆方内容审核闭环 |
|
||
|
||
因此“已下架展品、已关闭设施”目前无法自动识别,只能依赖人工回归。
|
||
|
||
## 2. 数据结构与类型规范性
|
||
|
||
### 2.1 TypeScript 类型定义
|
||
|
||
`src/types/index.ts` 更像早期 Mock 类型,无法覆盖现有地图和真实业务数据。
|
||
|
||
| 类型 | 当前定义 | 发现的问题 | 严重性 |
|
||
| --- | --- | --- | --- |
|
||
| `Position` | `{ x, y }` | 2D 坐标,不支持馆内 POI 的 `{ x, y, z }`,也不支持腾讯地图的 `{ latitude, longitude }` | P1 |
|
||
| `Facility.type` | `restroom/cafe/shop/exit/elevator/info` | 不包含 `entrance`、`hall`、`stairs`、`mother_baby`、`accessible_restroom`、`service_desk` 等真实 POI 类型 | P1 |
|
||
| `POIMarker.type` | `exhibit/hall/facility/location` | 不包含 `entrance`,与 `ThreeMap`、`f1-indoor-pois.json` 不一致 | P1 |
|
||
| `Exhibit` | 艺术品字段 `artist/year/material/size` | 自然博物馆需要 `taxonomy`、`period`、`specimenType`、`collectionNo`、`scientificName`、`ageRange` 等字段 | P0 |
|
||
| 全部实体 | 无多语言、无状态、无版本 | 无法支撑中英文切换、数据审核、增量更新和下线 | P1 |
|
||
|
||
建议新增分层模型:
|
||
|
||
```ts
|
||
type LocaleText = { zhCN: string; enUS?: string }
|
||
|
||
type Coordinate =
|
||
| { system: 'indoor_3d'; floorId: string; x: number; y: number; z: number }
|
||
| { system: 'indoor_2d'; floorId: string; x: number; y: number }
|
||
| { system: 'wgs84' | 'gcj02'; latitude: number; longitude: number }
|
||
|
||
type EntityStatus = 'draft' | 'published' | 'hidden' | 'closed' | 'maintenance'
|
||
```
|
||
|
||
### 2.2 API 响应格式
|
||
|
||
`src/services/` 下只有 `map/Map3DManager.ts`,没有业务 API service。数据加载集中在 `src/utils/dataLoader.ts`,但返回值未声明类型,错误时统一返回空数组:
|
||
|
||
```ts
|
||
export const loadExhibits = async () => {
|
||
try {
|
||
const data = await import('@/assets/data/exhibits.json')
|
||
return data.default || data
|
||
} catch (error) {
|
||
console.error('加载展品数据失败:', error)
|
||
return []
|
||
}
|
||
}
|
||
```
|
||
|
||
风险:
|
||
|
||
| 问题 | 影响 |
|
||
| --- | --- |
|
||
| 无 `Promise<Exhibit[]>` 等返回类型 | 调用方无法获得类型保护 |
|
||
| 使用 `any` 查找 | ID 类型、字段缺失、空数据不会被编译期发现 |
|
||
| 异常统一变成 `[]` | 加载失败、数据为空、校验失败三种状态无法区分 |
|
||
| 无响应 envelope | 后续接 API 时缺少 `version`、`updatedAt`、`source`、`errors`、`pagination` 规范 |
|
||
|
||
建议定义统一响应:
|
||
|
||
```ts
|
||
interface DataResult<T> {
|
||
ok: boolean
|
||
data: T
|
||
version: string
|
||
updatedAt: string
|
||
source: 'mock' | 'cms' | 'cache'
|
||
errors?: DataError[]
|
||
}
|
||
```
|
||
|
||
### 2.3 枚举值规范
|
||
|
||
枚举值目前分散在类型、地图、组件、数据文件中:
|
||
|
||
| 位置 | 枚举/类别 | 问题 |
|
||
| --- | --- | --- |
|
||
| `types/index.ts` | `Facility.type` | 只覆盖 6 种旧设施 |
|
||
| `components/area/AreaSelector.vue` | `storage`、`accessible` 等 | UI 类别未进入类型系统 |
|
||
| `static/data/f1-indoor-pois.json` | `hall/facility/entrance` | 与 `POIMarker.type` 不一致 |
|
||
| `ThreeMap.vue` | `entrance/exhibit/facility/hall` | 局部定义,与全局类型重复 |
|
||
| `TencentMap.vue` | marker 图标路径 | 通过硬编码绑定,不受枚举约束 |
|
||
|
||
建议将枚举集中到 `src/types/enums.ts` 或 `src/domain/guideSchema.ts`,并由数据校验脚本复用。
|
||
|
||
### 2.4 数据转换逻辑
|
||
|
||
当前没有明确的 adapter/transformer。结果是 2D JSON、3D POI、腾讯地图经纬度、页面详情对象各自拥有不同字段形态。
|
||
|
||
建议新增三层转换:
|
||
|
||
| 层级 | 职责 |
|
||
| --- | --- |
|
||
| Raw Schema | 接收 CMS/JSON 原始字段,严格校验 |
|
||
| Domain Model | 统一实体、坐标、资源、状态、多语言 |
|
||
| View Model | 为卡片、地图弹层、路线列表、搜索结果生成轻量字段 |
|
||
|
||
## 3. 业务数据合理性
|
||
|
||
### 3.1 内容与项目定位不符
|
||
|
||
项目描述与页面标题已经使用“深圳自然博物馆”,但核心数据仍是艺术馆:
|
||
|
||
| 位置 | 当前内容 | 业务判断 |
|
||
| --- | --- | --- |
|
||
| `manifest.json` | `深圳自然博物馆智能导览应用` | 项目定位明确为自然博物馆 |
|
||
| `exhibits.json` | `蒙娜丽莎`、`最后的晚餐`、`星空`、`向日葵`、`大卫像` | 与自然博物馆定位冲突 |
|
||
| `halls.json` | 文艺复兴、印象派、现代艺术 | 与自然史展陈冲突 |
|
||
| `routes.json` | 经典艺术之旅、印象派精选 | 与自然博物馆导览路线冲突 |
|
||
| `SearchPanel.vue` / `ExplainList.vue` | 恐龙、化石、银杏、矿石 | 内容方向正确,但与核心 JSON 脱节 |
|
||
|
||
这是 P0 风险,因为它会直接导致“产品名是自然博物馆,但内容是艺术馆”的体验断裂。
|
||
|
||
### 3.2 数量级合理性
|
||
|
||
真实自然博物馆导览通常需要覆盖更多实体:
|
||
|
||
| 数据类型 | 当前数量 | 建议 MVP 数量 | 建议正式版数量 |
|
||
| --- | ---: | ---: | ---: |
|
||
| 展品/标本 | 5 | 30 到 60 | 200+ |
|
||
| 展厅/展区 | 5 | 8 到 12 | 按真实楼层和展陈分区完整覆盖 |
|
||
| 设施 | 8 | 30 到 60 | 与馆内 POI 全量绑定 |
|
||
| 路线 | 3 | 5 到 8 | 支持人群、时长、无障碍、拥堵策略 |
|
||
| 馆内 POI | 67,仅 1F | 每层 50+ | 全楼层、全关键节点 |
|
||
|
||
当前数量只适合演示 UI,无法支撑真实导览。
|
||
|
||
### 3.3 地理坐标准确性
|
||
|
||
坐标系统存在三套并行:
|
||
|
||
| 坐标来源 | 字段 | 问题 |
|
||
| --- | --- | --- |
|
||
| 核心 JSON | `position: { x, y }` | 未声明坐标系、楼层、比例尺和原点 |
|
||
| 3D POI | `{ x, y, z }` | 未进入 `types/index.ts`,未绑定实体 |
|
||
| 腾讯地图 | `{ latitude, longitude }` | 硬编码在组件内,未与馆内 POI 建立转换关系 |
|
||
|
||
`TencentMap.vue` 里的建筑轮廓和 `ThreeMap.vue` 的中心点均硬编码为深圳自然博物馆附近坐标,但无法验证这些点与 GLB 模型、馆内 POI、楼层图是否同源。
|
||
|
||
### 3.4 多语言数据
|
||
|
||
当前核心实体没有英文名、英文说明、拼音、别名、检索关键词,也没有语言切换后的字段 fallback。
|
||
|
||
建议每个可展示字段采用 `LocaleText`,搜索索引包括:
|
||
|
||
| 字段 | 用途 |
|
||
| --- | --- |
|
||
| `name.zhCN` / `name.enUS` | 中英文展示 |
|
||
| `aliases.zhCN[]` / `aliases.enUS[]` | 同义词、简称、俗名 |
|
||
| `scientificName` | 自然史学名 |
|
||
| `keywords[]` | 搜索、推荐、路线匹配 |
|
||
| `audio.zhCN` / `audio.enUS` | 多语言讲解 |
|
||
|
||
## 4. 数据管理与维护性
|
||
|
||
### 4.1 数据源管理
|
||
|
||
当前数据分散在至少 11 类位置:
|
||
|
||
| 数据位置 | 数据类型 | 风险 |
|
||
| --- | --- | --- |
|
||
| `src/assets/data/*.json` | 核心 Mock | 内容过旧,艺术馆化 |
|
||
| `static/data/f1-indoor-pois.json` | 3D 模型 POI | 未接入业务实体 |
|
||
| `pages/search/index.vue` | 搜索页本地数组 | 与核心 JSON ID 不一致 |
|
||
| `components/search/SearchPanel.vue` | 搜索弹层本地数组 | 自然博物馆 Mock,与核心 JSON 不一致 |
|
||
| `components/explain/ExplainList.vue` | 讲解列表本地数组 | 音频字段为空,ID 冲突 |
|
||
| `pages/index/index.vue` | 地图详情 `markerDataMap` | 自然博物馆硬编码,与 POI/JSON 不一致 |
|
||
| `components/map/ThreeMap.vue` | `defaultPOIs` | 默认值会被空数组 props 覆盖,且 ID 不统一 |
|
||
| `components/map/TencentMap.vue` | 经纬度 markers | 地图数据不可配置 |
|
||
| `pages/exhibit/detail.vue` | 展品详情默认对象 | 不按 ID 加载真实数据 |
|
||
| `pages/hall/detail.vue` | 展厅详情默认对象 | 不按 ID 加载真实数据 |
|
||
| `pages/facility/detail.vue` | 设施详情默认对象 | 不按 ID 加载真实数据 |
|
||
|
||
建议将所有页面改为读取同一份 domain store:
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
A["CMS / Mock JSON"] --> B["schema validation"]
|
||
B --> C["domain repository"]
|
||
C --> D["search index"]
|
||
C --> E["map POI view model"]
|
||
C --> F["detail pages"]
|
||
C --> G["route engine"]
|
||
C --> H["offline cache"]
|
||
```
|
||
|
||
### 4.2 数据更新机制
|
||
|
||
当前没有发现以下机制:
|
||
|
||
| 机制 | 当前状态 | 建议 |
|
||
| --- | --- | --- |
|
||
| 数据版本控制 | 无 `version` 文件 | 新增 `data-manifest.json` |
|
||
| 增量更新 | 无 | 按实体类型和 `updatedAt` 增量拉取 |
|
||
| 本地缓存 | 未见 `uni.setStorage`/`uni.getStorage` 数据缓存 | 小程序端缓存核心 JSON 和搜索索引 |
|
||
| 灰度发布 | 无 | 支持 `draft/published` 与版本回滚 |
|
||
| 数据来源追踪 | 无 | 每条记录保留 `sourceId`、`sourceUpdatedAt` |
|
||
|
||
### 4.3 数据校验
|
||
|
||
建议建立 `scripts/audit-data.ts`,在 CI 或提交前执行:
|
||
|
||
| 校验类型 | 规则 |
|
||
| --- | --- |
|
||
| Schema 校验 | 必填字段、枚举、坐标类型、资源字段 |
|
||
| 引用校验 | 展品到展厅、路线到站点、POI 到实体、楼层到设施 |
|
||
| 资源校验 | 图片/音频/模型路径存在,远程 URL 可访问或有降级 |
|
||
| 业务校验 | 开放时间格式、路线时长总和、展厅展品数可计算 |
|
||
| 多语言校验 | 中文必填,英文按上线策略设阈值 |
|
||
| 审核状态校验 | 非 `published` 数据不得进入正式包 |
|
||
|
||
### 4.4 错误处理
|
||
|
||
当前 `dataLoader.ts` 在异常时返回空数组,页面无法知道错误原因。建议改为:
|
||
|
||
| 异常类型 | 降级方式 |
|
||
| --- | --- |
|
||
| JSON 加载失败 | 展示“数据暂不可用”,上报错误码 |
|
||
| Schema 校验失败 | 阻止使用该批数据,回退到上一个缓存版本 |
|
||
| 资源缺失 | 展示占位图,隐藏播放按钮,上报资源 ID |
|
||
| 关联断链 | 从路线/地图中隐藏该站点,保留错误日志 |
|
||
| 多语言缺失 | 回退中文,并记录缺失翻译 |
|
||
|
||
## 5. 性能与优化
|
||
|
||
### 5.1 数据体积与加载策略
|
||
|
||
当前 JSON 体积不大;`static/models/` 下模型已确认为自然博物馆 1F 真实 3D 模型资产,不应按普通占位资源处理。但模型资产仍需要元数据和部署治理:
|
||
|
||
| 资源 | 路径 | 大小 |
|
||
| --- | --- | ---: |
|
||
| 馆内模型 | `static/models/f1-indoor.glb` | 1,562,816 bytes |
|
||
| 楼层模型 | `static/models/f1-floor.glb` | 95,720 bytes;`facilities.json` 点位坐标来源 |
|
||
| 部署副本 | `public/models/f1-indoor.glb`、`public/models/f1-floor.glb` | 与 `static/models` 同大小;如果两端都会打包,需要明确去重或按端分发 |
|
||
|
||
风险:
|
||
|
||
| 问题 | 影响 |
|
||
| --- | --- |
|
||
| `public/models` 和 `static/models` 同时存在 | 若二者同时进入同一端包体,会造成重复;若分别服务 web/小程序,需要 manifest 标注用途 |
|
||
| 图片/音频 URL 缺失 | 无法验证真实媒体体积和懒加载策略 |
|
||
| 3D 模型与 POI 分离加载 | 需要版本锁定,否则 POI 坐标与模型不匹配 |
|
||
|
||
建议:
|
||
|
||
| 优先级 | 建议 |
|
||
| --- | --- |
|
||
| P1 | 明确模型部署目录策略:同一端只保留一份,跨端复用则在 manifest 中声明 |
|
||
| P1 | 模型按楼层拆包并懒加载,非当前楼层不加载 |
|
||
| P1 | 图片提供缩略图、详情图、原图三级资源 |
|
||
| P2 | 音频使用按需加载,播放前预取下一站讲解 |
|
||
|
||
### 5.2 请求与预加载
|
||
|
||
当前没有真实请求层,数据通过动态 import 加载;页面和组件中重复本地数组导致“无请求但重复数据维护”。未来接 API 时建议:
|
||
|
||
| 场景 | 策略 |
|
||
| --- | --- |
|
||
| 首页启动 | 加载 `data-manifest`、楼层、轻量 POI、热门展品 |
|
||
| 搜索打开 | 延迟构建或读取本地搜索索引 |
|
||
| 进入详情 | 按 `entityId` 读取详情,缺资源时显示降级态 |
|
||
| 开始路线 | 预加载路线站点、当前位置楼层 POI、下一站音频元信息 |
|
||
|
||
### 5.3 本地存储与离线可用性
|
||
|
||
导览类小程序对弱网很敏感,应支持基础离线:
|
||
|
||
| 数据 | 离线等级 |
|
||
| --- | --- |
|
||
| 楼层、展厅、设施、核心 POI | 必须离线可用 |
|
||
| 展品详情、路线 | 建议离线可用 |
|
||
| 图片缩略图 | 建议缓存最近访问和路线相关资源 |
|
||
| 音频 | 可选缓存,需考虑版权与包体 |
|
||
| 3D 模型 | 按楼层缓存,版本变更后更新 |
|
||
|
||
## 数据问题清单
|
||
|
||
### P0 阻塞性问题
|
||
|
||
| ID | 问题 | 证据 | 影响 | 修复建议 |
|
||
| --- | --- | --- | --- | --- |
|
||
| D-P0-01 | 核心数据仍是艺术馆内容 | `exhibits.json` 为 `蒙娜丽莎` 等世界名画 | 产品定位与内容冲突 | 建立自然博物馆实体数据集并替换核心 JSON |
|
||
| D-P0-02 | 多套硬编码实体互相冲突 | 同一 `id: '1'` 分别代表蒙娜丽莎、霸王龙、银杏化石 | 搜索、讲解、详情跳转不可信 | 收敛到统一 `entityId`,禁止页面本地 Mock |
|
||
| D-P0-03 | 资源 URL 大量失效 | 5 张展品图、5 个音频、5 张展厅图缺失 | 图片/音频核心体验失败 | 上线前加入资源存在性校验 |
|
||
| D-P0-04 | 详情页未按 ID 加载 | `exhibit/detail.vue`、`hall/detail.vue` 等使用默认对象 | 用户点击任意实体都可能看到同一详情 | 详情页接入 repository `findById` |
|
||
| D-P0-05 | 路线仍为艺术馆路线 | `routes.json` 为经典艺术之旅等 | 参观规划完全不适配自然博物馆 | 重建路线数据模型和正式路线 |
|
||
|
||
### P1 重要问题
|
||
|
||
| ID | 问题 | 证据 | 影响 | 修复建议 |
|
||
| --- | --- | --- | --- | --- |
|
||
| D-P1-01 | 楼层引用断链 | `floor_b1` 引用 `parking_b1`、`storage_b1` | 楼层设施展示不完整 | 补齐设施或删除无效引用 |
|
||
| D-P1-02 | 展厅 `exhibitCount` 与实际数量不一致 | `hall_1` 标称 25,实际 3 | 统计误导用户 | 改为派生计算或校验阻断 |
|
||
| D-P1-03 | 3D POI 未绑定实体 | 67 个 `poi_*` 无 `entityId` | 地图无法打开统一详情 | 增加 `entityType/entityId` |
|
||
| D-P1-04 | 类型定义不支持 3D/经纬度坐标 | `Position` 只有 `{x,y}` | 地图类型保护失效 | 定义统一 `Coordinate` union |
|
||
| D-P1-05 | 设施枚举不完整 | 真实 POI 含入口、母婴室、服务台等 | UI 图标和筛选无法统一 | 建立设施类型字典 |
|
||
| D-P1-06 | 无数据版本与缓存策略 | 未见 manifest 和 storage 机制 | 无法增量更新、离线弱 | 新增 `data-manifest` 和本地缓存 |
|
||
| D-P1-07 | 错误处理吞掉原因 | `dataLoader` 异常返回 `[]` | 无法区分空数据和加载失败 | 返回 `DataResult<T>` |
|
||
| D-P1-08 | 多语言字段缺失 | 核心 JSON 无英文/别名/学名 | 国际访客和英文搜索不可用 | 引入 `LocaleText` 与搜索索引 |
|
||
|
||
### P2 优化项
|
||
|
||
| ID | 问题 | 证据 | 影响 | 修复建议 |
|
||
| --- | --- | --- | --- | --- |
|
||
| D-P2-01 | 模型部署目录未说明 | `static/models` 与 `public/models` 同名同大小 | 可能包体重复,也可能是跨端分发但缺少说明 | 建立模型 manifest,明确每个端使用哪个路径 |
|
||
| D-P2-02 | 搜索工具未统一使用 | 页面自建数组,`utils/search.ts` 被绕开 | 搜索规则重复 | 搜索统一走 index service |
|
||
| D-P2-03 | 缺少资源元数据 | 图片/音频只有 URL | 版权、尺寸、时长不可控 | 建立 `Asset` 模型 |
|
||
| D-P2-04 | 缺少数据生成文档 | 无数据字典和维护手册 | 后续运营难维护 | 建立数据治理规范 |
|
||
|
||
## 数据迁移方案:从艺术馆到深圳自然博物馆
|
||
|
||
### 阶段 0:冻结与基线,1 到 2 天
|
||
|
||
目标:防止旧 Mock 继续扩散。
|
||
|
||
| 任务 | 产出 |
|
||
| --- | --- |
|
||
| 标记艺术馆数据为 legacy | `legacy-art-gallery` 数据目录或删除计划 |
|
||
| 建立数据审计脚本 | 可输出数量、断链、资源缺失 |
|
||
| 定义自然博物馆实体清单 | 展厅、展品、设施、路线、POI、资源字段 |
|
||
| 统一 ID 规范 | `exhibit_dino_trex_001`、`hall_dinosaur_2f`、`facility_restroom_1f_east` |
|
||
|
||
### 阶段 1:核心模型重建,3 到 5 天
|
||
|
||
目标:让所有页面可以读同一套自然博物馆数据。
|
||
|
||
| 任务 | 产出 |
|
||
| --- | --- |
|
||
| 重写 TypeScript domain 类型 | `Exhibit` 从艺术品模型改为自然史模型 |
|
||
| 新增 `Coordinate`、`Asset`、`LocaleText`、`EntityStatus` | 支撑地图、资源、多语言、上下线 |
|
||
| 建立 mock data v1 | 至少 30 个展品、8 个展厅、30 个设施、5 条路线 |
|
||
| 改造 `dataLoader` | 返回 typed `DataResult<T>`,支持校验错误 |
|
||
| 改造详情页 | 按 URL `id` 从 repository 查询 |
|
||
|
||
### 阶段 2:地图与路线绑定,5 到 8 天
|
||
|
||
目标:地图、POI、路线、详情形成闭环。
|
||
|
||
| 任务 | 产出 |
|
||
| --- | --- |
|
||
| 为 67 个 F1 POI 增加 `entityType/entityId` | 点击 POI 打开统一详情 |
|
||
| 建立楼层坐标系元信息 | `origin`、`scale`、`rotation`、`modelVersion` |
|
||
| 把 `TencentMap`/`ThreeMap` 的硬编码 marker 迁出组件 | 地图 view model |
|
||
| 路线站点绑定 POI | 路线可在 2D/3D 地图高亮 |
|
||
| 增加无障碍/亲子/研学路线 | 覆盖典型人群 |
|
||
|
||
### 阶段 3:资源、多语言与离线,5 到 10 天
|
||
|
||
目标:接近可运营数据质量。
|
||
|
||
| 任务 | 产出 |
|
||
| --- | --- |
|
||
| 建立图片、音频资源清单 | 路径、尺寸、时长、版权、语言 |
|
||
| 替换占位 URL 和缺失资源 | 所有核心展品可展示/播放 |
|
||
| 建立中英文内容字段 | 英文名、学名、英文简介、英文音频 |
|
||
| 生成搜索索引 | 支持中文、英文、别名、学名 |
|
||
| 增加本地缓存和版本更新 | 弱网可用,支持增量更新 |
|
||
|
||
### 阶段 4:CMS/API 接入,2 到 4 周
|
||
|
||
目标:从静态 Mock 过渡到可维护的馆方内容系统。
|
||
|
||
| 任务 | 产出 |
|
||
| --- | --- |
|
||
| 定义 API response envelope | `version/source/updatedAt/errors` |
|
||
| 接入 CMS 或后台服务 | 馆方可维护内容 |
|
||
| 增加审核流 | draft 到 published |
|
||
| 增加数据监控 | 资源失效、断链、翻译缺失告警 |
|
||
| 建立回滚机制 | 数据版本可回退 |
|
||
|
||
## 数据治理建议
|
||
|
||
### 数据目录建议
|
||
|
||
```text
|
||
src/domain/
|
||
guideTypes.ts
|
||
guideEnums.ts
|
||
guideRepository.ts
|
||
guideAdapters.ts
|
||
|
||
src/assets/data/
|
||
data-manifest.json
|
||
museum/
|
||
exhibits.json
|
||
halls.json
|
||
facilities.json
|
||
floors.json
|
||
routes.json
|
||
pois.json
|
||
assets.json
|
||
|
||
scripts/
|
||
audit-data.ts
|
||
build-search-index.ts
|
||
```
|
||
|
||
### 数据质量门禁
|
||
|
||
| 门禁 | 触发时机 | 阻断规则 |
|
||
| --- | --- | --- |
|
||
| 本地审计 | 提交前 | P0 不允许提交 |
|
||
| CI 审计 | PR/合并前 | P0/P1 必须有处理或豁免 |
|
||
| 资源审计 | 打包前 | 核心图片/音频缺失阻断 |
|
||
| 内容审计 | 发布前 | 未审核、未发布数据不能进正式包 |
|
||
| 多语言审计 | 英文版发布前 | 英文关键字段缺失阻断 |
|
||
|
||
### 数据字典建议
|
||
|
||
每个实体至少包含:
|
||
|
||
| 字段组 | 必填内容 |
|
||
| --- | --- |
|
||
| 标识 | `id`、`type`、`status`、`version` |
|
||
| 展示 | `name`、`summary`、`description`、`keywords` |
|
||
| 位置 | `floorId`、`hallId`、`coordinates[]`、`poiIds[]` |
|
||
| 资源 | `coverImage`、`gallery[]`、`audio[]`、`modelAssetId` |
|
||
| 运营 | `validFrom`、`validTo`、`updatedAt`、`reviewedAt` |
|
||
| 多语言 | `zhCN` 必填,`enUS` 按上线范围要求 |
|
||
|
||
## 预估修复工作量
|
||
|
||
| 工作包 | 角色 | 预估工时 | 优先级 |
|
||
| --- | --- | ---: | --- |
|
||
| 数据审计脚本与 CI 门禁 | 前端/工具链 | 1 到 2 人日 | P0 |
|
||
| 自然博物馆数据模型重建 | 前端 + 内容策划 | 2 到 3 人日 | P0 |
|
||
| 核心 Mock 数据迁移 v1 | 内容策划 + 前端 | 3 到 5 人日 | P0 |
|
||
| 详情页/搜索/地图统一接 repository | 前端 | 4 到 6 人日 | P0 |
|
||
| POI 与实体绑定 | 前端 + 3D/地图 | 3 到 5 人日 | P1 |
|
||
| 资源清单与缺失资源替换 | 内容/设计/前端 | 3 到 6 人日 | P1 |
|
||
| 多语言字段与搜索索引 | 前端 + 翻译/内容 | 4 到 8 人日 | P1 |
|
||
| 离线缓存与增量更新 | 前端 | 4 到 7 人日 | P1 |
|
||
| CMS/API 接入 | 后端 + 前端 | 10 到 20 人日 | P1 |
|
||
|
||
建议最小可交付排期:
|
||
|
||
| 周期 | 目标 | 验收标准 |
|
||
| --- | --- | --- |
|
||
| 短期,1 周内 | 解决 P0 | 核心数据为自然博物馆;搜索/详情/地图 ID 统一;资源缺失校验可运行 |
|
||
| 中期,2 到 4 周 | 解决主要 P1 | POI 绑定、路线可用、缓存和版本机制上线 |
|
||
| 长期,1 到 2 个月 | 数据治理闭环 | CMS/API、审核流、多语言、监控和回滚机制可用 |
|
||
|
||
## 下一步行动清单
|
||
|
||
1. 建立 `scripts/audit-data.ts`,把本报告中的数量、断链、资源缺失、统计不一致变成可重复命令。
|
||
2. 先删除或隔离旧艺术馆 Mock 数据,防止新页面继续引用。
|
||
3. 制定深圳自然博物馆首批 MVP 数据清单:8 个展厅、30 个展品、30 个设施、5 条路线、F1 全量 POI 绑定。
|
||
4. 改造 `dataLoader` 为 typed repository,详情页、搜索、地图统一从 repository 读取。
|
||
5. 在发布流程中加入 P0 数据门禁:资源缺失、引用断链、实体冲突、非自然博物馆内容不得进入正式包。
|
||
|
||
## 补充审计:以真实 F1 点位为基准
|
||
|
||
补充前提:`static/data/f1-indoor-pois.json` 是真实 1 楼设施点位信息。因此它不应被视为普通 Mock,而应作为校验 1F 设施、展厅、入口、地图点击、搜索和筛选数据的基准。
|
||
|
||
### 基准数据摘要
|
||
|
||
| 指标 | 结果 |
|
||
| --- | --- |
|
||
| POI 总数 | 67 |
|
||
| 类型分布 | `facility: 58`、`hall: 6`、`entrance: 3` |
|
||
| 楼层分布 | 全部为 `1F` |
|
||
| 坐标范围 | `x: -106.59 到 150.26`,`y: 0 到 0`,`z: -37.73 到 79.06` |
|
||
| 重复坐标 | 无 |
|
||
| 加载路径 | `Map3DManager` 会从 `/static/models/f1-indoor.glb` 推断并加载 `/static/data/f1-indoor-pois.json` |
|
||
|
||
真实 1F 点位包含的代表性设施和区域:
|
||
|
||
```text
|
||
展厅/场馆:展厅人类厅、巨幕影院、动感多维影院、自然剧场、球幕影院、展厅
|
||
入口/服务:售票处、售票机、服务台
|
||
设施:女卫、男卫、无障碍卫生间、楼梯、电梯、扶梯、存包处、轮椅及儿童车租车处、贵宾接待区、贵宾卫生间、茶水间、母婴间
|
||
```
|
||
|
||
### 真实 F1 点位反查出的新增问题
|
||
|
||
| 严重性 | 问题 | 证据 | 影响 | 建议 |
|
||
| --- | --- | --- | --- | --- |
|
||
| P0 | `facilities.json` 的 1F 设施与真实点位完全不匹配 | 1F 设施只有 `洗手间`、`艺术咖啡厅`、`艺术品商店`、`主出口`,真实 POI 中均无这些同名点位 | 设施列表、设施详情、楼层设施入口都会展示不存在或不准确的设施 | 以 `f1-indoor-pois.json` 生成 1F 设施实例,旧艺术馆设施迁入 legacy |
|
||
| P0 | `halls.json` 的 1F 展厅与真实点位完全不匹配 | 1F 展厅为 `1号展厅`、`2号展厅`;真实 POI 展厅为 `展厅人类厅`、`巨幕影院`、`动感多维影院`、`自然剧场`、`球幕影院`、`展厅` | 地图点位点击与展厅详情无法对应,展厅统计不可用 | 建立真实 1F 展厅/场馆实体,并用 `poiId` 绑定 |
|
||
| P0 | 3D 点击逻辑会忽略大部分真实设施点位 | `handlePOIClick` 只处理 `exhibit` 和 `hall`;真实 POI 中 58/67 为 `facility` | 用户点击厕所、电梯、楼梯、母婴间、售票处等核心服务点位不会弹出详情 | 点击逻辑必须支持 `facility` 和 `entrance`,并进入统一设施详情/导航 |
|
||
| P1 | 真实 POI 与 `markerDataMap` 无法映射 | 真实 ID 为 `poi_0` 到 `poi_66`;首页映射使用 `0`、`1`、`hall-1`、`exhibit-1` | POI 点击只能走临时 fallback,无法获得图片、说明、导航策略、收藏状态 | 用 `poiId` 或 `entityId` 建立真实映射,删除手写 `markerDataMap` |
|
||
| P1 | `floors.json` 的 1F 设施引用严重不足 | `floor_1f.facilities` 只引用 3 个设施,真实 1F 有 58 个 facility POI 和 3 个 entrance POI | 楼层筛选和设施面板无法覆盖真实服务点 | `floor_1f` 应引用真实 POI 或引用从 POI 派生的 facility instances |
|
||
| P1 | 设施类型粒度不足 | 真实 POI 全部压成 `facility/entrance/hall`,具体类别藏在中文 label 中 | 搜索、筛选、图标、无障碍路线无法可靠判断类别 | 增加 `category/subtype`,如 `restroom_female`、`elevator`、`stairs`、`ticket_office`、`nursing_room` |
|
||
| P1 | UI 筛选分类与真实标签没有规范映射 | `AreaSelector` 有 `卫生间/电梯/楼梯/停车场/母婴室/服务中心/寄存处/饮水处/影院`,真实标签是 `女卫001`、`电梯020`、`楼梯.001`、`存包处`、`茶水间` 等 | 用户选择分类后很难精确筛出真实点位 | 建立 label 归一化和分类映射表,区分展示名与检索名 |
|
||
| P1 | 搜索数据未覆盖真实 1F 设施 | 搜索 Mock 只有 `洗手间`、`咖啡厅`、`服务中心`、`纪念品商店` 等 | 搜索不到真实存在的售票机、服务台、母婴间、轮椅及儿童车租车处、贵宾卫生间等 | 搜索索引从真实 POI 和设施实体生成 |
|
||
| P1 | 存在两套 POI 坐标模型 | 真实 POI 为 `{x,y,z}`;`ThreeMap.vue` props/default POI 为 `{latitude,longitude}` | 组件接口同名但数据形态不同,后续接入容易错用 | 将馆内 3D POI 与馆外经纬度 POI 拆成不同类型 |
|
||
| P2 | 真实 POI label 带模型导出痕迹 | `电梯001`、`楼梯.001`、`无障碍卫生间.001` | 直接展示会显得粗糙,也不利于搜索同义词 | 保留原始 label,同时新增 `displayName`、`instanceNo`、`normalizedName` |
|
||
| P2 | `entrance` 类型语义混杂 | `售票处`、`售票机`、`服务台` 被标为 `entrance` | 类型名称无法表达真实服务属性 | 原始类型可保留,业务层补充 `category: ticket/service` |
|
||
|
||
### 与真实 F1 点位冲突的关键文件
|
||
|
||
| 文件 | 冲突点 | 处理建议 |
|
||
| --- | --- | --- |
|
||
| `src/assets/data/facilities.json` | 1F 设施与真实 POI 无同名匹配 | 用真实 POI 重建 1F facilities |
|
||
| `src/assets/data/halls.json` | 1F 展厅名称和数量与真实 POI 冲突 | 重建 halls,并绑定 `poi_0/poi_51` 到 `poi_55` |
|
||
| `src/assets/data/floors.json` | 1F 只引用 3 个旧设施 | 从真实 POI 派生楼层设施索引 |
|
||
| `src/pages/index/index.vue` | `markerDataMap` 不认识 `poi_*`,点击设施被忽略 | 改为根据 `poiId/entityId` 查询 repository |
|
||
| `src/components/map/ThreeMap.vue` | 默认 POI 使用经纬度,和真实馆内 `{x,y,z}` POI 混用 | 拆分 `IndoorPOI` 与 `OutdoorMarker` |
|
||
| `src/types/index.ts` | `Position` 只有 `{x,y}`,`POIMarker` 不含 `entrance` | 扩展坐标和 POI 类型 |
|
||
| `src/components/search/SearchPanel.vue` | 搜索 Mock 未来自真实 POI | 搜索索引从 `pois + entities` 生成 |
|
||
| `src/components/area/AreaSelector.vue` | 分类只停留在 UI 文案,没有连接真实 POI subtype | 建立设施分类字典和 label 归一化规则 |
|
||
|
||
### 建议的数据归一化模型
|
||
|
||
真实 POI 文件可以继续作为原始点位数据,但业务层需要派生规范实体:
|
||
|
||
```ts
|
||
interface RawIndoorPOI {
|
||
id: string
|
||
label: string
|
||
x: number
|
||
y: number
|
||
z: number
|
||
type: 'hall' | 'facility' | 'entrance'
|
||
floor: '1F'
|
||
}
|
||
|
||
interface FacilityInstance {
|
||
id: string
|
||
poiId: string
|
||
floorId: string
|
||
displayName: string
|
||
normalizedName: string
|
||
category: 'restroom' | 'elevator' | 'stairs' | 'escalator' | 'ticket' | 'service' | 'storage' | 'nursing' | 'theater' | 'vip' | 'water' | 'entrance'
|
||
accessibility?: string[]
|
||
coordinate: { system: 'indoor_3d'; modelId: 'f1-indoor'; x: number; y: number; z: number }
|
||
}
|
||
```
|
||
|
||
### 更新后的优先修复顺序
|
||
|
||
1. P0:让 3D POI 点击支持 `facility` 和 `entrance`,否则真实 1F 点位 61 个服务类点位无法交互。
|
||
2. P0:用真实 POI 重建 1F `facilities` 和 `halls`,移除艺术馆设施/展厅对 1F 的覆盖。
|
||
3. P1:建立 `poiId -> entityId` 映射,让地图、搜索、详情、路线共享同一实体。
|
||
4. P1:新增设施分类字典,把 `女卫001`、`男卫002`、`电梯020`、`楼梯.001` 等归一到可筛选类别。
|
||
5. P1:让 `floor_1f` 从真实 POI 派生设施和展厅索引,避免手工维护数量不一致。
|
||
6. P2:保留原始 label 作为 `sourceLabel`,增加面向用户的 `displayName`,避免模型导出编号直接暴露。
|
||
|
||
## 补充审计:真实模型与 `f1-floor.glb` 坐标来源
|
||
|
||
补充前提:`frontend-miniapp/static/models/` 下的模型是自然博物馆 1F 真实 3D 模型;`facilities.json` 中的点位坐标来自 `frontend-miniapp/static/models/f1-floor.glb` 提取,目的是为后续 web 端页面与模型交互准备数据。
|
||
|
||
因此,对模型和坐标的审计结论需要修正为:模型资产和部分坐标来源可信,不能简单当作 Mock 删除;真正的问题是缺少模型元数据、坐标系说明、实体语义绑定和跨端资源治理。
|
||
|
||
### 修正后的判断
|
||
|
||
| 数据/资产 | 可信部分 | 仍存在的问题 |
|
||
| --- | --- | --- |
|
||
| `static/models/f1-indoor.glb` | 真实 1F 馆内 3D 模型 | 缺少 `modelId`、hash、版本、来源、坐标系、比例尺、与 POI 文件的绑定说明 |
|
||
| `static/models/f1-floor.glb` | 真实 1F 楼层模型,且是 `facilities.json.position` 的提取来源 | `facilities.json` 未记录 `sourceModel`、提取工具、提取时间、坐标原点、单位、投影规则 |
|
||
| `static/data/f1-indoor-pois.json` | 真实 1F POI 点位,使用 `{x,y,z}` 模型空间坐标 | 未绑定业务实体,label 仍是模型导出名称,需要业务归一化 |
|
||
| `src/assets/data/facilities.json` | `position` 字段有真实模型来源 | 设施名称、类型、描述仍是旧艺术馆语义;坐标字段只有 `{x,y}`,无法判断与 `f1-indoor-pois.json` 的 `{x,y,z}` 如何互转 |
|
||
| `public/models/*.glb` | 可能用于 web 端静态访问 | 与 `static/models/*.glb` 同名同大小,需说明是否为跨端副本,避免构建重复打包 |
|
||
|
||
### 新增数据风险
|
||
|
||
| 严重性 | 问题 | 影响 | 建议 |
|
||
| --- | --- | --- | --- |
|
||
| P0 | 坐标来源真实,但业务实体语义不真实 | 后续 web 与模型交互可能点位能落到模型上,但弹出的名称、类别、详情仍是错的 | 将 `facilities.json` 拆为“模型点位层”和“业务设施层”,用 `poiId/entityId` 连接 |
|
||
| P1 | 缺少模型 manifest | 无法保证 `f1-floor.glb`、`f1-indoor.glb`、POI JSON、设施坐标来自同一版本 | 新增 `static/models/model-manifest.json` 或 `src/assets/data/model-manifest.json` |
|
||
| P1 | 缺少坐标系/变换元数据 | `facilities.json.position {x,y}` 与 `f1-indoor-pois {x,y,z}` 可能来自不同模型或投影空间,未来 web 交互容易错位 | 为每组坐标声明 `sourceModel`、`coordinateSystem`、`unit`、`origin`、`scale`、`axisMapping` |
|
||
| P1 | `Map3DManager` 运行时加载 `f1-indoor-pois.json`,但 `facilities.json` 坐标来自 `f1-floor.glb` | 运行态点位和业务设施点位可能使用两套坐标基准 | 明确 `f1-floor` 与 `f1-indoor` 的关系,建立统一转换或只让业务层引用同一基准 |
|
||
| P2 | 模型部署目录策略不明确 | web 端和小程序端可能各自引用不同路径,造成缓存、版本和包体问题 | 约定 web 用 `public/models` 或 `static/models` 之一,并通过 manifest 管理 |
|
||
|
||
### 建议新增模型清单
|
||
|
||
```json
|
||
{
|
||
"models": [
|
||
{
|
||
"id": "f1-indoor",
|
||
"path": "/static/models/f1-indoor.glb",
|
||
"purpose": "runtime-3d-indoor-map",
|
||
"floor": "1F",
|
||
"version": "2026-05-28",
|
||
"hash": "<sha256>",
|
||
"poiDataset": "/static/data/f1-indoor-pois.json",
|
||
"coordinateSystem": {
|
||
"type": "model_world_3d",
|
||
"unit": "model_unit",
|
||
"scaleInMap3DManager": 0.3
|
||
}
|
||
},
|
||
{
|
||
"id": "f1-floor",
|
||
"path": "/static/models/f1-floor.glb",
|
||
"purpose": "floor-point-extraction",
|
||
"floor": "1F",
|
||
"version": "2026-05-28",
|
||
"derivedDatasets": [
|
||
"src/assets/data/facilities.json"
|
||
],
|
||
"coordinateSystem": {
|
||
"type": "model_floor_projection",
|
||
"unit": "model_unit",
|
||
"axisMapping": "to-be-documented"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 修正后的下一步
|
||
|
||
1. 保留 `static/models/f1-indoor.glb`、`static/models/f1-floor.glb` 作为真实资产,不再按占位资源处理。
|
||
2. 为 `facilities.json.position` 增加来源字段,例如 `sourceModel: "f1-floor"`、`sourceCoordinateSystem: "model_floor_projection"`。
|
||
3. 把 `facilities.json` 中的业务字段与模型坐标分离:坐标可来自模型,设施名称/类型/描述需按真实自然博物馆内容重建。
|
||
4. 建立 `f1-floor` 坐标与 `f1-indoor` POI 坐标的关系说明,否则 web 端点击、3D 高亮和导航路径会有错位风险。
|
||
5. 明确 `public/models` 和 `static/models` 的分工;如果 `public/models` 是 web 端专用副本,应写入 README/manifest,而不是简单删除。
|