@@ -10,7 +10,7 @@ Use this skill for the Shenzhen Natural Museum `frontend-miniapp` project. Treat
|
||||
The product has two first-class H5 businesses:
|
||||
|
||||
- `guide`: outdoor reference map, indoor 3D display, full-building/single-floor switching, POI search/focus, and POI/location preview. Real route planning requires verified `route_graph` and `nav_data`.
|
||||
- `explain`: exhibit/hall content, audio explanation, transcript/chapters/media metadata, search/filtering, player state, and optional linkage from an explain item to a guide location preview.
|
||||
- `explain`: hall catalog -> explain-object catalog -> detail, plus audio explanation, transcript/chapters/media metadata, search/filtering, player state, and optional linkage from an explain object to a guide location preview.
|
||||
|
||||
## Project Ground Truth
|
||||
|
||||
@@ -22,6 +22,9 @@ The product has two first-class H5 businesses:
|
||||
- Legacy demo data area: `src/assets/data`. Treat it as historical/demo-only unless the user explicitly asks to inspect or migrate it.
|
||||
- Current guide capability is indoor 3D display plus POI/location preview. Do not present it as certified real indoor navigation until `route_graph` and `nav_data` are available and verified.
|
||||
- Current explain capability must be described as content/audio explanation only when real media data is available. Do not invent working audio, transcript, or exhibit data from placeholders.
|
||||
- Current explain information architecture is `讲解 -> 展厅列表 -> 讲解对象列表 -> 讲解详情`. Do not insert a business-unit/outline list between a hall and its explain objects, and do not expose an "未分配单元" group.
|
||||
- Use `讲解对象` in user-facing H5 titles, cards, loading/empty/error states, and acceptance criteria. Treat backend `guide stop` / `STOP` / `stopId` and existing `ExplainGuideStop` names as integration or internal-domain terms; do not leak `讲解点` into new presentation copy or perform a broad internal rename without a scoped migration reason.
|
||||
- Treat `E:\MyWork\深圳国际艺术馆\智慧导览\smart-navigation-system\doc\miniapp_integration.md` as the authoritative explain API contract. Load halls from `/app-api/gis/guide/catalog/halls`, then page hall objects from `/app-api/gis/guide/catalog/halls/{hallId}/stops/page`; treat outline and non-paged hall-stop endpoints as migration compatibility only.
|
||||
|
||||
## Client Visual Design Standards
|
||||
|
||||
@@ -79,6 +82,7 @@ GuideMapShell / ThreeMap / ExplainList / AudioPlayer / Search / Cards
|
||||
```
|
||||
|
||||
- Keep guide and explain coupled through stable IDs and domain relationships such as `poiId`, `exhibitId`, `hallId`, and `floorId`, not through component internals.
|
||||
- Keep the explain presentation flow hall-based. Hall selection must navigate directly to a hall-scoped explain-object list; `outlineCount`, business-unit grouping, and legacy outline routes must not control the current UI hierarchy.
|
||||
- Keep Tencent/outdoor map logic separate from indoor Three.js/GLB rendering. Do not make Tencent Map branches depend on indoor model state, and do not let indoor 3D changes alter outdoor map behavior.
|
||||
- Keep `NAV_ROUTE_GRAPH_READY` false until real graph/nav data has been added, loaded, validated, and wired with smoke tests.
|
||||
- Do not claim "开始馆内导航", route planning, arrival guidance, turn-by-turn navigation, or positioning accuracy unless route graph/nav data and runtime behavior are verified.
|
||||
@@ -112,7 +116,7 @@ Guide data and explain data may share the same exhibit/hall/POI IDs, but their u
|
||||
|
||||
2. Scope changes tightly:
|
||||
- For guide work, start around `src/pages/index`, route/search/facility pages, `src/components/navigation`, `src/components/map`, `src/usecases/guideUseCase.ts`, and guide repositories/providers.
|
||||
- For explain work, start around `src/components/explain`, `src/components/audio`, exhibit/hall detail pages, top-tab routing, and the future content/explain repositories.
|
||||
- For explain work, start around `src/pages/explain`, `src/components/explain`, `src/components/audio`, exhibit/hall detail pages, top-tab routing, `ExplainRepository`, `explainUseCase`, and explain providers/adapters.
|
||||
- Do not touch legacy hall/exhibit/explain demo data unless the task is explicitly about migration, compatibility, or cleanup.
|
||||
|
||||
3. Protect the H5 boundary:
|
||||
@@ -134,6 +138,7 @@ Guide data and explain data may share the same exhibit/hall/POI IDs, but their u
|
||||
- Introduce content/explain/media repositories before migrating explain pages out of hardcoded arrays.
|
||||
- Do not duplicate parsed POI, floor, category, model path, explain media, transcript, or route readiness logic in page components.
|
||||
- Use contract-first data evolution. Static packages, future APIs, and CMS data should expose compatible `schemaVersion`/dataset metadata and preserve stable domain models.
|
||||
- Keep hall explain-object pagination behind the provider/repository/use-case boundary. Normalize `data.list` and `data.total`, preserve snowflake IDs as strings, and keep `pageNo`, `pageSize`, and `lang` out of presentation components except through a page/query view model.
|
||||
- Mark old demo compatibility explicitly when a temporary bridge is unavoidable.
|
||||
- If cleaning old mock data, first inventory references with `rg`, then split work into:
|
||||
- guide-critical stale data that blocks current work;
|
||||
@@ -248,6 +253,9 @@ Use this workflow when the user asks to connect the SGS Map SDK to the H5 guide
|
||||
## Explain And Media Standards
|
||||
|
||||
- Treat explain as a first-class content/media business, not as a decorative tab on the guide page.
|
||||
- Enforce the two-list flow: the explain entry shows halls; tapping a hall opens that hall's paged explain-object list; tapping an object opens detail. Do not create, retain, or route through a business-unit list for the current product flow.
|
||||
- Use the paged hall endpoint as the primary catalog path. Do not build the new list from `/outlines`, `/outlines/{outlineId}/stops`, or the non-paged `/halls/{hallId}/stops` compatibility endpoints.
|
||||
- Render catalog labels as `讲解对象` while preserving `STOP` and `stopId` for detail, playback, and text API requests. Use catalog `playTargetType` and `playTargetId` when available.
|
||||
- Use explain/content repositories for exhibits, halls, tracks, transcripts, chapters, cover images, audio URLs, duration, language, and availability.
|
||||
- Keep `ExplainList` focused on presentation, filtering controls, and emitted user actions. Do not keep long-lived mock exhibit arrays or search indexes in the component once repository data is available.
|
||||
- Keep `AudioPlayer` focused on playback, progress, seek, pause/resume, error, and teardown. Do not fetch content, infer exhibit data, or decide guide location behavior inside the player.
|
||||
@@ -282,6 +290,8 @@ Guide audit checklist:
|
||||
Explain audit checklist:
|
||||
|
||||
- Explain tab entry, list loading, filters, search drawer, hot/history keyword behavior.
|
||||
- Hall click navigates directly to a hall-scoped `讲解对象` list; no business-unit page, outline grouping, or "未分配单元" appears.
|
||||
- Explain-object pagination avoids duplicate rows across pages, stops at `total`, preserves string IDs, and exposes loading, empty, error/retry, and load-more failure states.
|
||||
- Exhibit/hall detail transitions, return paths, and top-tab preservation.
|
||||
- Audio play/pause/close, mini-player visibility, missing media fallback, playback state loss.
|
||||
- Transcript/chapter/language availability if data claims them.
|
||||
@@ -306,6 +316,7 @@ Check:
|
||||
- Fallback strategy: SDK unavailable, iframe load failure, API failure, or command timeout must show recovery/fallback states; do not silently leave a blank map.
|
||||
- API dependency: SDK mode should pair with API-backed guide repositories for floor/POI domain data; static package data should not be mixed into SDK runtime unless explicitly marked as a migration bridge.
|
||||
- Explain layer: `ExplainList` should render repository/view-model data and emit actions; `AudioPlayer` should own only playback runtime.
|
||||
- Explain routing: remove the legacy hall -> business unit -> stop dependency from current entry points, deep links, and back fallbacks. Object-list back returns to the hall list; detail back returns to the same hall/object-list context where feasible.
|
||||
- Data layer: static package and future API/CMS loading must stay behind providers/adapters/repositories/use cases; pages and presentation components must not own source-specific loading.
|
||||
- Repository layer: `MuseumContentRepository`, `GuideRepository`, `ExplainRepository`, and `MediaRepository` should hide providers/adapters from UI.
|
||||
- State layer: guide session, explain session, player state, search state, selected target, and route readiness should live in composables/stores/use cases when shared across pages.
|
||||
@@ -413,7 +424,7 @@ Use this module when the user asks to test the H5 app through browser automation
|
||||
- Home guide: outdoor map, indoor 3D switch, full-building/single-floor switch, primary guide CTA, search entry, recommended entrance flow.
|
||||
- Search: keyword entry or existing query, filters, result card click, result action click, browser/back navigation.
|
||||
- Facility/detail/route preview: choose target, view position, unavailable route state, return/reset/cancel.
|
||||
- Explain: tab switch, search drawer, hot/history keyword, result click, exhibit detail, audio play/pause/close, missing audio fallback.
|
||||
- Explain: tab switch, hall click -> paged explain-object list -> object detail -> back to the same list -> back to halls; also verify search, audio play/pause/close, missing audio fallback, direct-open behavior, and retry/load-more failure states.
|
||||
- Hall/exhibit detail: direct-open and in-flow-open behavior, visible back path, top-tab preservation, bottom action behavior.
|
||||
|
||||
3. Check closure risks:
|
||||
@@ -442,6 +453,7 @@ pnpm build:h5
|
||||
|
||||
- Treat lint warnings as debt even if the command exits successfully.
|
||||
- Add or run H5 smoke checks for top tabs, guide/explain tab switching, indoor 3D scene, full-building/single-floor control, search result click, route/detail preview, explain search, and audio play/pause/close when affected.
|
||||
- For explain hierarchy changes, add focused tests for hall -> object-list routing, paged repository/use-case loading, `讲解对象` copy, detail targets, deep links, and list/detail back behavior. Assert that current entry points do not navigate to a business-unit route.
|
||||
- For mobile risk, inspect small viewport behavior: overlays above canvas, no text/button overlap, no horizontal overflow, no accidental full-screen canvas capture, and no audio player overlap with critical controls.
|
||||
- If the user explicitly asks for mini-program/mp-weixin, add `pnpm build:mp-weixin` as an extra check for that task only.
|
||||
|
||||
@@ -449,6 +461,7 @@ pnpm build:h5
|
||||
|
||||
- `src/components/map/ThreeMap.vue` may still directly parse clean package manifest/floor/POI data. Treat this as transitional and flag it in architecture audits.
|
||||
- `src/components/explain/ExplainList.vue`, exhibit detail, and hall detail may still contain hardcoded or historical demo data. Treat these as migration targets for content/explain repositories.
|
||||
- `src/pages/explain/business-unit-list.vue`, business-unit routes, unit-stage UI, and `listGuideStopsByBusinessUnit` calls are legacy presentation debt for the current explain flow. Do not use them as the new hall entry path; retire or isolate them only within the requested implementation scope while preserving unrelated dirty work.
|
||||
- Audio fallback URLs such as `example.com` are not valid explain capability.
|
||||
- `src/pages/route/detail.vue` may still contain historical navigation states such as planning/navigating/arrived/location-error. Keep them blocked unless real graph data exists.
|
||||
- Runtime static JSON loading through `uni.request` must be verified on H5 for current work; verify mp-weixin only when explicitly requested.
|
||||
|
||||
@@ -10,7 +10,7 @@ Use this skill for the Shenzhen Natural Museum `frontend-miniapp` project. Treat
|
||||
The product has two first-class H5 businesses:
|
||||
|
||||
- `guide`: outdoor reference map, indoor 3D display, full-building/single-floor switching, POI search/focus, and POI/location preview. Real route planning requires verified `route_graph` and `nav_data`.
|
||||
- `explain`: exhibit/hall content, audio explanation, transcript/chapters/media metadata, search/filtering, player state, and optional linkage from an explain item to a guide location preview.
|
||||
- `explain`: hall catalog -> explain-object catalog -> detail, plus audio explanation, transcript/chapters/media metadata, search/filtering, player state, and optional linkage from an explain object to a guide location preview.
|
||||
|
||||
## Project Ground Truth
|
||||
|
||||
@@ -22,6 +22,9 @@ The product has two first-class H5 businesses:
|
||||
- Legacy demo data area: `src/assets/data`. Treat it as historical/demo-only unless the user explicitly asks to inspect or migrate it.
|
||||
- Current guide capability is indoor 3D display plus POI/location preview. Do not present it as certified real indoor navigation until `route_graph` and `nav_data` are available and verified.
|
||||
- Current explain capability must be described as content/audio explanation only when real media data is available. Do not invent working audio, transcript, or exhibit data from placeholders.
|
||||
- Current explain information architecture is `讲解 -> 展厅列表 -> 讲解对象列表 -> 讲解详情`. Do not insert a business-unit/outline list between a hall and its explain objects, and do not expose an "未分配单元" group.
|
||||
- Use `讲解对象` in user-facing H5 titles, cards, loading/empty/error states, and acceptance criteria. Treat backend `guide stop` / `STOP` / `stopId` and existing `ExplainGuideStop` names as integration or internal-domain terms; do not leak `讲解点` into new presentation copy or perform a broad internal rename without a scoped migration reason.
|
||||
- Treat `E:\MyWork\深圳国际艺术馆\智慧导览\smart-navigation-system\doc\miniapp_integration.md` as the authoritative explain API contract. Load halls from `/app-api/gis/guide/catalog/halls`, then page hall objects from `/app-api/gis/guide/catalog/halls/{hallId}/stops/page`; treat outline and non-paged hall-stop endpoints as migration compatibility only.
|
||||
|
||||
## Client Visual Design Standards
|
||||
|
||||
@@ -79,6 +82,7 @@ GuideMapShell / ThreeMap / ExplainList / AudioPlayer / Search / Cards
|
||||
```
|
||||
|
||||
- Keep guide and explain coupled through stable IDs and domain relationships such as `poiId`, `exhibitId`, `hallId`, and `floorId`, not through component internals.
|
||||
- Keep the explain presentation flow hall-based. Hall selection must navigate directly to a hall-scoped explain-object list; `outlineCount`, business-unit grouping, and legacy outline routes must not control the current UI hierarchy.
|
||||
- Keep Tencent/outdoor map logic separate from indoor Three.js/GLB rendering. Do not make Tencent Map branches depend on indoor model state, and do not let indoor 3D changes alter outdoor map behavior.
|
||||
- Keep `NAV_ROUTE_GRAPH_READY` false until real graph/nav data has been added, loaded, validated, and wired with smoke tests.
|
||||
- Do not claim "开始馆内导航", route planning, arrival guidance, turn-by-turn navigation, or positioning accuracy unless route graph/nav data and runtime behavior are verified.
|
||||
@@ -112,7 +116,7 @@ Guide data and explain data may share the same exhibit/hall/POI IDs, but their u
|
||||
|
||||
2. Scope changes tightly:
|
||||
- For guide work, start around `src/pages/index`, route/search/facility pages, `src/components/navigation`, `src/components/map`, `src/usecases/guideUseCase.ts`, and guide repositories/providers.
|
||||
- For explain work, start around `src/components/explain`, `src/components/audio`, exhibit/hall detail pages, top-tab routing, and the future content/explain repositories.
|
||||
- For explain work, start around `src/pages/explain`, `src/components/explain`, `src/components/audio`, exhibit/hall detail pages, top-tab routing, `ExplainRepository`, `explainUseCase`, and explain providers/adapters.
|
||||
- Do not touch legacy hall/exhibit/explain demo data unless the task is explicitly about migration, compatibility, or cleanup.
|
||||
|
||||
3. Protect the H5 boundary:
|
||||
@@ -134,6 +138,7 @@ Guide data and explain data may share the same exhibit/hall/POI IDs, but their u
|
||||
- Introduce content/explain/media repositories before migrating explain pages out of hardcoded arrays.
|
||||
- Do not duplicate parsed POI, floor, category, model path, explain media, transcript, or route readiness logic in page components.
|
||||
- Use contract-first data evolution. Static packages, future APIs, and CMS data should expose compatible `schemaVersion`/dataset metadata and preserve stable domain models.
|
||||
- Keep hall explain-object pagination behind the provider/repository/use-case boundary. Normalize `data.list` and `data.total`, preserve snowflake IDs as strings, and keep `pageNo`, `pageSize`, and `lang` out of presentation components except through a page/query view model.
|
||||
- Mark old demo compatibility explicitly when a temporary bridge is unavoidable.
|
||||
- If cleaning old mock data, first inventory references with `rg`, then split work into:
|
||||
- guide-critical stale data that blocks current work;
|
||||
@@ -248,6 +253,9 @@ Use this workflow when the user asks to connect the SGS Map SDK to the H5 guide
|
||||
## Explain And Media Standards
|
||||
|
||||
- Treat explain as a first-class content/media business, not as a decorative tab on the guide page.
|
||||
- Enforce the two-list flow: the explain entry shows halls; tapping a hall opens that hall's paged explain-object list; tapping an object opens detail. Do not create, retain, or route through a business-unit list for the current product flow.
|
||||
- Use the paged hall endpoint as the primary catalog path. Do not build the new list from `/outlines`, `/outlines/{outlineId}/stops`, or the non-paged `/halls/{hallId}/stops` compatibility endpoints.
|
||||
- Render catalog labels as `讲解对象` while preserving `STOP` and `stopId` for detail, playback, and text API requests. Use catalog `playTargetType` and `playTargetId` when available.
|
||||
- Use explain/content repositories for exhibits, halls, tracks, transcripts, chapters, cover images, audio URLs, duration, language, and availability.
|
||||
- Keep `ExplainList` focused on presentation, filtering controls, and emitted user actions. Do not keep long-lived mock exhibit arrays or search indexes in the component once repository data is available.
|
||||
- Keep `AudioPlayer` focused on playback, progress, seek, pause/resume, error, and teardown. Do not fetch content, infer exhibit data, or decide guide location behavior inside the player.
|
||||
@@ -282,6 +290,8 @@ Guide audit checklist:
|
||||
Explain audit checklist:
|
||||
|
||||
- Explain tab entry, list loading, filters, search drawer, hot/history keyword behavior.
|
||||
- Hall click navigates directly to a hall-scoped `讲解对象` list; no business-unit page, outline grouping, or "未分配单元" appears.
|
||||
- Explain-object pagination avoids duplicate rows across pages, stops at `total`, preserves string IDs, and exposes loading, empty, error/retry, and load-more failure states.
|
||||
- Exhibit/hall detail transitions, return paths, and top-tab preservation.
|
||||
- Audio play/pause/close, mini-player visibility, missing media fallback, playback state loss.
|
||||
- Transcript/chapter/language availability if data claims them.
|
||||
@@ -306,6 +316,7 @@ Check:
|
||||
- Fallback strategy: SDK unavailable, iframe load failure, API failure, or command timeout must show recovery/fallback states; do not silently leave a blank map.
|
||||
- API dependency: SDK mode should pair with API-backed guide repositories for floor/POI domain data; static package data should not be mixed into SDK runtime unless explicitly marked as a migration bridge.
|
||||
- Explain layer: `ExplainList` should render repository/view-model data and emit actions; `AudioPlayer` should own only playback runtime.
|
||||
- Explain routing: remove the legacy hall -> business unit -> stop dependency from current entry points, deep links, and back fallbacks. Object-list back returns to the hall list; detail back returns to the same hall/object-list context where feasible.
|
||||
- Data layer: static package and future API/CMS loading must stay behind providers/adapters/repositories/use cases; pages and presentation components must not own source-specific loading.
|
||||
- Repository layer: `MuseumContentRepository`, `GuideRepository`, `ExplainRepository`, and `MediaRepository` should hide providers/adapters from UI.
|
||||
- State layer: guide session, explain session, player state, search state, selected target, and route readiness should live in composables/stores/use cases when shared across pages.
|
||||
@@ -413,7 +424,7 @@ Use this module when the user asks to test the H5 app through browser automation
|
||||
- Home guide: outdoor map, indoor 3D switch, full-building/single-floor switch, primary guide CTA, search entry, recommended entrance flow.
|
||||
- Search: keyword entry or existing query, filters, result card click, result action click, browser/back navigation.
|
||||
- Facility/detail/route preview: choose target, view position, unavailable route state, return/reset/cancel.
|
||||
- Explain: tab switch, search drawer, hot/history keyword, result click, exhibit detail, audio play/pause/close, missing audio fallback.
|
||||
- Explain: tab switch, hall click -> paged explain-object list -> object detail -> back to the same list -> back to halls; also verify search, audio play/pause/close, missing audio fallback, direct-open behavior, and retry/load-more failure states.
|
||||
- Hall/exhibit detail: direct-open and in-flow-open behavior, visible back path, top-tab preservation, bottom action behavior.
|
||||
|
||||
3. Check closure risks:
|
||||
@@ -442,6 +453,7 @@ pnpm build:h5
|
||||
|
||||
- Treat lint warnings as debt even if the command exits successfully.
|
||||
- Add or run H5 smoke checks for top tabs, guide/explain tab switching, indoor 3D scene, full-building/single-floor control, search result click, route/detail preview, explain search, and audio play/pause/close when affected.
|
||||
- For explain hierarchy changes, add focused tests for hall -> object-list routing, paged repository/use-case loading, `讲解对象` copy, detail targets, deep links, and list/detail back behavior. Assert that current entry points do not navigate to a business-unit route.
|
||||
- For mobile risk, inspect small viewport behavior: overlays above canvas, no text/button overlap, no horizontal overflow, no accidental full-screen canvas capture, and no audio player overlap with critical controls.
|
||||
- If the user explicitly asks for mini-program/mp-weixin, add `pnpm build:mp-weixin` as an extra check for that task only.
|
||||
|
||||
@@ -449,6 +461,7 @@ pnpm build:h5
|
||||
|
||||
- `src/components/map/ThreeMap.vue` may still directly parse clean package manifest/floor/POI data. Treat this as transitional and flag it in architecture audits.
|
||||
- `src/components/explain/ExplainList.vue`, exhibit detail, and hall detail may still contain hardcoded or historical demo data. Treat these as migration targets for content/explain repositories.
|
||||
- `src/pages/explain/business-unit-list.vue`, business-unit routes, unit-stage UI, and `listGuideStopsByBusinessUnit` calls are legacy presentation debt for the current explain flow. Do not use them as the new hall entry path; retire or isolate them only within the requested implementation scope while preserving unrelated dirty work.
|
||||
- Audio fallback URLs such as `example.com` are not valid explain capability.
|
||||
- `src/pages/route/detail.vue` may still contain historical navigation states such as planning/navigating/arrived/location-error. Keep them blocked unless real graph data exists.
|
||||
- Runtime static JSON loading through `uni.request` must be verified on H5 for current work; verify mp-weixin only when explicitly requested.
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
VITE_APP_PUBLIC_BASE=/
|
||||
# 主开关:导览业务与讲解业务分离配置,避免互相切换。
|
||||
VITE_GUIDE_DATA_SOURCE_MODE=sdk
|
||||
VITE_EXPLAIN_CONTENT_SOURCE_MODE=static
|
||||
VITE_EXPLAIN_CONTENT_SOURCE_MODE=remote
|
||||
# 兼容旧变量:新代码优先读取上方显式主开关。
|
||||
VITE_DATA_SOURCE_MODE=sdk
|
||||
VITE_GUIDE_CONTENT_SOURCE_MODE=static
|
||||
VITE_GUIDE_CONTENT_SOURCE_MODE=remote
|
||||
VITE_EXPLAIN_ALLOW_STATIC_FALLBACK=false
|
||||
VITE_GUIDE_STATIC_DATA_BASE_URL=/static/guide-data
|
||||
VITE_API_BASE_URL=/app-api
|
||||
@@ -24,9 +24,9 @@ VITE_PUBLIC_SAME_ORIGIN_ASSET_HOST=
|
||||
VITE_PUBLIC_LEGACY_AUDIO_HOST=
|
||||
|
||||
# Vite 开发服务器代理目标,只由 vite.config.ts 读取。
|
||||
DEV_PROXY_APP_API_TARGET=http://localhost:3001
|
||||
DEV_PROXY_ENGINE_TARGET=http://localhost:3001
|
||||
DEV_PROXY_SDK_TARGET=http://localhost:3001
|
||||
DEV_PROXY_APP_API_TARGET=http://1.92.206.90:3001
|
||||
DEV_PROXY_ENGINE_TARGET=http://1.92.206.90:3001
|
||||
DEV_PROXY_SDK_TARGET=http://1.92.206.90:3001
|
||||
DEV_PROXY_MUSEUM_ASSETS_TARGET=http://1.92.206.90:9000
|
||||
DEV_PROXY_MINIO_TARGET=http://localhost:3001
|
||||
DEV_PROXY_AUDIO_TARGET=http://localhost:19000
|
||||
DEV_PROXY_MINIO_TARGET=http://1.92.206.90:3001
|
||||
DEV_PROXY_AUDIO_TARGET=http://1.92.206.90:19000
|
||||
|
||||
425
docs/CODEX_DUAL_MODEL_WORKFLOW.md
Normal file
425
docs/CODEX_DUAL_MODEL_WORKFLOW.md
Normal file
@@ -0,0 +1,425 @@
|
||||
# Codex 双模型审核与执行工作流
|
||||
|
||||
> 更新日期:2026-07-16
|
||||
> 适用项目:`frontend-miniapp` 及其他已登记到 Codex App 的本地项目
|
||||
> 工作模式:`gpt-5.6-sol / xhigh` 审核,`gpt-5.6-terra / medium` 执行
|
||||
> 文档版本:1.1(禁止子代理上下文分叉)
|
||||
|
||||
---
|
||||
|
||||
## 1. 文档目的
|
||||
|
||||
本说明用于处理需要先深入审核、再自动启动独立执行线程实施修复的开发任务。
|
||||
|
||||
推荐流程:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["整理真实需求"] --> B["手动创建 sol / xhigh 审核线程"]
|
||||
B --> C["源码审核与浏览器复现"]
|
||||
C --> D["生成实施级修复方案"]
|
||||
D --> E["自动创建 terra / medium 执行线程"]
|
||||
E --> F["修改、测试与浏览器验收"]
|
||||
F --> G["检查执行报告"]
|
||||
```
|
||||
|
||||
这种方式适合以下任务:
|
||||
|
||||
- 问题涉及多个页面、状态管理、异步流程或渲染器生命周期。
|
||||
- 需要先确认问题是否真实存在,不能直接按用户猜测修改。
|
||||
- 希望高推理模型负责根因分析,由成本和速度更平衡的模型负责实施。
|
||||
- 希望分析线程与修改线程职责分离,减少分析过程中误改文件的风险。
|
||||
|
||||
简单文案调整、单文件确定性修改或无需调查的小任务通常不需要使用该流程。
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前环境能力
|
||||
|
||||
本机当前已验证的 Codex App 能力:
|
||||
|
||||
- `codex_app__list_projects`:获取 Codex App 已登记项目及 `projectId`。
|
||||
- `codex_app__create_thread`:创建带初始提示词的新线程,并立即启动任务。
|
||||
- `codex_app__read_thread`:读取新线程状态,确认任务是否已接收和执行。
|
||||
- 创建线程时可以指定项目、运行环境、模型和推理强度。
|
||||
|
||||
### 2.1 必须区分的两类机制
|
||||
|
||||
| 机制 | 典型工具 | 是否用于本流程 | 原因 |
|
||||
| --- | --- | --- | --- |
|
||||
| 协作子代理 | `spawn_agent`、`fork_turns` | 禁止 | 需要分叉当前线程上下文,可能触发 Responses Lite 的上下文枚举兼容错误 |
|
||||
| 独立 Codex 线程 | `codex_app__create_thread` | 必须 | 使用完整、自包含的初始提示词启动独立项目会话,不依赖子代理上下文分叉 |
|
||||
| 历史线程分叉 | `codex_app__fork_thread` | 禁止 | 会复制线程历史,本流程不需要继承上下文,且不能替代明确的模型化执行线程 |
|
||||
|
||||
本流程中的“执行线程”始终指 `codex_app__create_thread` 创建的独立 Codex App 项目线程,不是 `spawn_agent` 创建的子代理。
|
||||
|
||||
已知错误:
|
||||
|
||||
```text
|
||||
X-OpenAI-Internal-Codex-Responses-Lite requires ***.context to be all_turns.
|
||||
```
|
||||
|
||||
该错误发生在子代理上下文分叉请求进入模型执行之前。即使公开参数传入 `fork_turns: "all"`,部分 Codex App/协作工具版本仍可能没有将其正确转换为内部要求的 `all_turns`。这不是项目源码、Git、目标业务模型或测试命令报错。
|
||||
|
||||
本流程的处理原则是彻底绕过该路径:
|
||||
|
||||
- 当前审核线程独立完成审核,不启动任何子代理。
|
||||
- 不设置或传递 `fork_turns`。
|
||||
- 不使用 `codex_app__fork_thread` 复制上下文。
|
||||
- 审核完成后只调用 `codex_app__create_thread`。
|
||||
- 将审核证据完整写入新线程的初始提示词,使执行线程不依赖父线程上下文。
|
||||
- `create_thread` 不可用或失败时如实报告阻塞,不得回退到 `spawn_agent`。
|
||||
|
||||
当前验证可用的组合:
|
||||
|
||||
| 阶段 | 模型 | 推理强度 | 创建方式 |
|
||||
| --- | --- | --- | --- |
|
||||
| 审核 | `gpt-5.6-sol` | `xhigh`(界面显示为“极高”) | 用户手动创建 |
|
||||
| 执行 | `gpt-5.6-terra` | `medium`(界面显示为“中”) | 审核线程自动创建 |
|
||||
|
||||
注意:模型 ID、推理档位和线程工具属于当前 Codex App 运行环境能力,升级 Codex 后应重新确认。在线 Codex 手册在本文编写时因 HTTP `403` 无法获取,因此上述能力以本机实际暴露的工具定义为准。
|
||||
|
||||
---
|
||||
|
||||
## 3. 提问前准备
|
||||
|
||||
每个新需求至少整理以下信息:
|
||||
|
||||
1. 项目绝对路径。
|
||||
2. 用户实际操作步骤。
|
||||
3. 当前实际结果。
|
||||
4. 预期正确结果。
|
||||
5. 已知影响范围。
|
||||
6. 不允许修改的内容或架构约束。
|
||||
7. 可以执行的测试和验收方式。
|
||||
|
||||
推荐使用以下需求结构:
|
||||
|
||||
```text
|
||||
业务场景:
|
||||
[用户在什么状态下执行什么操作]
|
||||
|
||||
复现步骤:
|
||||
1. [步骤一]
|
||||
2. [步骤二]
|
||||
3. [步骤三]
|
||||
|
||||
实际结果:
|
||||
[当前发生了什么]
|
||||
|
||||
预期结果:
|
||||
[正确行为是什么]
|
||||
|
||||
补充约束:
|
||||
[H5/小程序范围、性能、兼容性、禁止重构区域等]
|
||||
```
|
||||
|
||||
不要只写“功能有问题,请分析并修复”。缺少操作路径和预期结果时,审核模型可能只能根据源码猜测产品意图。
|
||||
|
||||
---
|
||||
|
||||
## 4. 标准操作步骤
|
||||
|
||||
### 4.1 创建审核线程
|
||||
|
||||
在 Codex App 中手动新建项目会话:
|
||||
|
||||
1. 选择目标项目。
|
||||
2. 模型选择 `gpt-5.6-sol`。
|
||||
3. 推理强度选择“极高”,对应 `xhigh`。
|
||||
4. 粘贴第 5 节的通用提示词。
|
||||
5. 替换其中的项目路径、需求、预期结果和约束。
|
||||
|
||||
### 4.2 审核线程职责
|
||||
|
||||
审核线程必须只进行以下工作:
|
||||
|
||||
- 检查工作区和项目规则。
|
||||
- 审核源码调用链和状态变化。
|
||||
- 对比正常路径与异常路径。
|
||||
- 通过 H5 浏览器或测试复现。
|
||||
- 判断问题是否真实存在。
|
||||
- 输出根因、文件位置、修复步骤、测试矩阵和验收标准。
|
||||
|
||||
审核线程不得修改、格式化、暂存、提交或回滚项目文件。
|
||||
|
||||
审核线程还必须遵守以下工具路由限制:
|
||||
|
||||
- 禁止调用 `spawn_agent` 或任何等价的协作子代理工具。
|
||||
- 禁止传递 `fork_turns`,无论其值是 `all`、`none` 还是其他值。
|
||||
- 禁止调用 `codex_app__fork_thread`。
|
||||
- 禁止为了并行审核创建专家子代理;所有审核由当前主线程完成。
|
||||
|
||||
### 4.3 自动创建执行线程
|
||||
|
||||
审核完成后,审核线程必须在当前回合结束前实际执行:
|
||||
|
||||
1. 调用 `codex_app__list_projects`。
|
||||
2. 使用项目绝对路径匹配正确的 `projectId`。
|
||||
3. 调用 `codex_app__create_thread`。
|
||||
4. 指定 `environment.type` 为 `local`。
|
||||
5. 指定模型为 `gpt-5.6-terra`。
|
||||
6. 指定推理强度为 `medium`。
|
||||
7. 将完整审核证据和修复方案放入新线程的初始提示词。
|
||||
8. 调用 `codex_app__read_thread` 检查一次启动状态。
|
||||
|
||||
本阶段只允许使用 `codex_app__list_projects`、`codex_app__create_thread` 和 `codex_app__read_thread` 完成交接。不得使用 `spawn_agent`、`fork_turns` 或 `fork_thread` 作为替代方案。
|
||||
|
||||
核心创建参数应符合:
|
||||
|
||||
```json
|
||||
{
|
||||
"target": {
|
||||
"type": "project",
|
||||
"projectId": "<通过 list_projects 解析出的真实 ID>",
|
||||
"environment": {
|
||||
"type": "local"
|
||||
}
|
||||
},
|
||||
"model": "gpt-5.6-terra",
|
||||
"thinking": "medium",
|
||||
"prompt": "<完整审核证据、修复方案、测试矩阵和验收标准>"
|
||||
}
|
||||
```
|
||||
|
||||
`codex_app__create_thread` 的初始提示词会启动新线程。不能只在回复中展示上述 JSON,也不能要求用户再手动复制修复方案。
|
||||
|
||||
### 4.4 执行线程职责
|
||||
|
||||
执行线程应:
|
||||
|
||||
- 直接按照审核结论实施,避免重新进行宽泛分析。
|
||||
- 保护用户已有未提交修改。
|
||||
- 优先修复共享状态、数据或架构边界,不使用页面级临时标志掩盖问题。
|
||||
- 增加与风险匹配的单元测试、集成测试和浏览器流程测试。
|
||||
- 执行项目要求的类型检查、lint、测试和构建命令。
|
||||
- 报告修改文件、验证结果和剩余风险。
|
||||
|
||||
### 4.5 验收交接
|
||||
|
||||
审核线程最终回复至少应提供:
|
||||
|
||||
- 审核结论和根因摘要。
|
||||
- 修复方案摘要。
|
||||
- 新执行线程 ID。
|
||||
- 执行模型和推理强度。
|
||||
- 新线程启动状态。
|
||||
- 创建失败时的真实错误。
|
||||
|
||||
执行线程最终回复至少应提供:
|
||||
|
||||
- 实际修改的文件。
|
||||
- 实施内容和关键设计决策。
|
||||
- 测试命令及结果。
|
||||
- 浏览器验证步骤及结果。
|
||||
- 未完成项和剩余风险。
|
||||
|
||||
---
|
||||
|
||||
## 5. 新需求通用提示词
|
||||
|
||||
将下面的内容粘贴到手动创建的 `gpt-5.6-sol / xhigh` 线程,并替换方括号内容。
|
||||
|
||||
```text
|
||||
这是一个新的开发任务,请按照“高模型审核 -> 新线程执行”的双阶段流程完成。
|
||||
|
||||
最高优先级工具路由约束:
|
||||
|
||||
1. 本任务禁止使用任何协作子代理或子 Agent。
|
||||
2. 禁止调用 spawn_agent、followup_task、send_message 或其他 collaboration 子代理工具。
|
||||
3. 禁止设置、传递或重试 fork_turns,包括 fork_turns="all"。
|
||||
4. 禁止调用 codex_app__fork_thread。
|
||||
5. 当前主线程必须独立完成全部审核,不得为了并行分析创建专家子代理。
|
||||
6. 审核完成后的执行任务,只能通过 codex_app__create_thread 创建独立 Codex App 项目线程。
|
||||
7. create_thread 不可用或调用失败时,必须如实报告阻塞;不得回退到 spawn_agent。
|
||||
8. 新执行线程必须获得完整、自包含的初始提示词,不能依赖父线程上下文继承。
|
||||
|
||||
项目目录:
|
||||
[项目绝对路径]
|
||||
|
||||
需求/问题:
|
||||
[真实业务场景、复现步骤和异常现象]
|
||||
|
||||
预期行为:
|
||||
[正确结果和验收标准]
|
||||
|
||||
补充约束:
|
||||
[不能修改的模块、运行端范围、数据来源、性能要求等]
|
||||
|
||||
第一阶段:当前线程只审核
|
||||
|
||||
1. 当前线程只进行源码审核、问题复现和修复方案设计,不修改文件。
|
||||
2. 先检查项目规则、AGENTS.md、相关 SKILL.md、架构文档和未提交修改。
|
||||
3. 不要直接接受我的根因判断,必须通过源码证据和实际运行验证问题是否存在。
|
||||
4. 对比正常路径和异常路径,追踪完整调用链、状态变化、异步请求和生命周期。
|
||||
5. 尽可能通过浏览器或项目测试复现;不能复现时标记为“仅源码风险”。
|
||||
6. 输出实施级方案,包括根因、文件/函数/行号、修改步骤、测试矩阵和验收标准。
|
||||
|
||||
第二阶段:强制创建并启动独立 Codex App 执行线程
|
||||
|
||||
用户明确授权你通过 codex_app__create_thread 创建和启动一个新的独立 Codex 项目线程执行修改。该线程不是协作子代理。
|
||||
|
||||
完成审核方案后,不得直接结束当前回合,必须:
|
||||
|
||||
1. 实际调用 codex_app__list_projects,解析上述项目的 projectId。
|
||||
2. 实际调用 codex_app__create_thread 创建新线程。
|
||||
3. 新线程必须使用 environment.type=local。
|
||||
4. 新线程模型必须使用 gpt-5.6-terra。
|
||||
5. 新线程推理强度必须使用 medium。
|
||||
6. 新线程初始提示词必须完整嵌入复现证据、根因、文件位置、修复步骤、测试矩阵和验收标准。
|
||||
7. 不能只输出线程创建参数或交接提示词,必须实际调用工具。
|
||||
8. 创建后使用 codex_app__read_thread 检查一次,确认新线程已经收到任务并开始执行。
|
||||
9. 不得重复创建多个执行线程。
|
||||
10. 不得调用 spawn_agent、fork_turns 或 codex_app__fork_thread;失败时不得切换到子代理方案。
|
||||
|
||||
执行线程必须:
|
||||
|
||||
1. 直接实施已经审核完成的方案,不重新开始宽泛分析。
|
||||
2. 保留用户已有未提交修改,不回滚无关变更。
|
||||
3. 修复真正的共享逻辑或架构边界,避免临时标志和数据特例。
|
||||
4. 增加与风险相匹配的测试。
|
||||
5. 运行项目规定的类型检查、lint、测试和构建命令。
|
||||
6. 对实际用户操作路径进行浏览器验证。
|
||||
7. 报告修改文件、测试结果、浏览器证据和剩余风险。
|
||||
|
||||
当前审核线程最终回复必须包含:
|
||||
|
||||
- 审核结论。
|
||||
- 根因和修复方案摘要。
|
||||
- 新执行线程 ID。
|
||||
- 执行模型和推理强度。
|
||||
- 新线程启动及首次状态检查结果。
|
||||
- 创建失败时的真实错误。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 本项目追加要求
|
||||
|
||||
在 `frontend-miniapp` 中使用该流程时,建议在提示词中继续加入:
|
||||
|
||||
```text
|
||||
开始前完整阅读并遵循:
|
||||
|
||||
- .agents/skills/shenzhen-natural-museum-dev/SKILL.md
|
||||
- 与本任务相关的 references 文档
|
||||
|
||||
默认只处理移动端 H5,不处理 mp-weixin,除非需求明确提出。
|
||||
|
||||
验证基线至少包括:
|
||||
|
||||
- pnpm type-check
|
||||
- pnpm lint
|
||||
- 相关单元测试
|
||||
- pnpm build:h5
|
||||
- 受影响用户路径的移动端浏览器验证
|
||||
```
|
||||
|
||||
涉及室内模型初始状态、楼层切换、POI 聚焦或详情返回时,还必须阅读:
|
||||
|
||||
```text
|
||||
.agents/skills/shenzhen-natural-museum-dev/references/guide-model-state-baseline.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 常见问题
|
||||
|
||||
### 7.1 出现 Responses Lite `context` / `all_turns` 错误
|
||||
|
||||
错误示例:
|
||||
|
||||
```text
|
||||
X-OpenAI-Internal-Codex-Responses-Lite requires ***.context to be all_turns.
|
||||
```
|
||||
|
||||
这表示流程错误地调用了 `spawn_agent` 或其他需要分叉上下文的协作工具。它不是项目代码故障,也不表示子代理已经开始执行。
|
||||
|
||||
处理步骤:
|
||||
|
||||
1. 停止重试 `spawn_agent`,不要继续传递 `fork_turns: "all"`。
|
||||
2. 由当前主线程直接完成剩余审核。
|
||||
3. 审核完成后使用 `codex_app__create_thread` 创建独立执行线程。
|
||||
4. 把审核结果完整写入 `create_thread.prompt`,不要依赖上下文继承。
|
||||
5. 如果仍然发生该错误,检查实际工具调用记录;正确的流程中不应出现 `spawn_agent` 或 `fork_turns`。
|
||||
6. 更新或重启 Codex App 后可重新验证子代理能力,但本工作流仍不需要子代理。
|
||||
|
||||
错误发生在模型执行前,因此通常不会修改项目文件或 Git 状态。仍应通过 `git status` 确认工作区没有其他线程产生的变化。
|
||||
|
||||
### 7.2 Codex 只输出了修复方案,没有创建线程
|
||||
|
||||
通常是提示词没有明确授予创建新线程的权限,或者只要求“生成交接提示词”。
|
||||
|
||||
必须明确写出:
|
||||
|
||||
```text
|
||||
用户明确授权你实际调用 codex_app__list_projects 和 codex_app__create_thread。
|
||||
不能只输出参数或建议,必须在当前回合结束前创建并启动线程。
|
||||
```
|
||||
|
||||
### 7.3 新线程没有拿到完整上下文
|
||||
|
||||
新线程不会可靠地自动获得父线程尚未完成的全部分析过程。审核线程必须把关键证据直接写入 `create_thread.prompt`,不能只写“按照父线程方案执行”。
|
||||
|
||||
### 7.4 创建到了错误项目
|
||||
|
||||
不要猜测 `projectId`。必须先调用 `list_projects`,再根据规范化后的项目绝对路径匹配。
|
||||
|
||||
### 7.5 执行线程模型或推理强度不正确
|
||||
|
||||
创建线程时显式设置:
|
||||
|
||||
```text
|
||||
model: gpt-5.6-terra
|
||||
thinking: medium
|
||||
```
|
||||
|
||||
如果 Codex App 升级后不再支持该组合,应以工具返回的可用模型和推理档位为准,并向用户说明差异。
|
||||
|
||||
### 7.6 执行线程覆盖了用户修改
|
||||
|
||||
提示词必须要求两个线程先检查工作区状态。审核线程保持只读;执行线程只能在任务范围内工作,不得回滚、覆盖或格式化无关改动。
|
||||
|
||||
### 7.7 为什么使用 local 而不是 worktree
|
||||
|
||||
`local` 让执行线程在已登记项目的当前工作目录中工作,可以看到用户现有未提交修改。使用它时必须避免多个修改线程同时编辑同一文件。
|
||||
|
||||
只有在明确需要隔离开发、并且已经决定从哪个 Git 状态开始时,才选择 `worktree`。
|
||||
|
||||
### 7.8 线程已经创建,是否等于开始执行
|
||||
|
||||
带初始 `prompt` 的 `codex_app__create_thread` 会创建并启动线程。仍应使用 `codex_app__read_thread` 检查一次,确认任务已被接收。不要高频轮询没有变化的线程状态。
|
||||
|
||||
---
|
||||
|
||||
## 8. 执行前检查清单
|
||||
|
||||
- [ ] 已提供项目绝对路径。
|
||||
- [ ] 已写清复现步骤、实际结果和预期结果。
|
||||
- [ ] 已填写任务范围与禁止修改项。
|
||||
- [ ] 手动审核线程为 `gpt-5.6-sol / xhigh`。
|
||||
- [ ] 提示词明确要求当前线程只审核、不修改。
|
||||
- [ ] 提示词明确禁止 `spawn_agent`、`fork_turns` 和 `codex_app__fork_thread`。
|
||||
- [ ] 当前审核由主线程独立完成,不创建专家子代理。
|
||||
- [ ] 提示词明确授权实际创建新线程。
|
||||
- [ ] 执行线程指定为 `gpt-5.6-terra / medium`。
|
||||
- [ ] 执行环境指定为 `local`。
|
||||
- [ ] 要求把完整审核证据嵌入新线程提示词。
|
||||
- [ ] 要求创建后读取一次线程状态。
|
||||
- [ ] 已定义测试命令和浏览器验收路径。
|
||||
- [ ] 已要求保护用户未提交修改。
|
||||
|
||||
---
|
||||
|
||||
## 9. 版本维护
|
||||
|
||||
Codex App 升级后,建议重新确认:
|
||||
|
||||
1. `codex_app__list_projects` 是否仍可用。
|
||||
2. `codex_app__create_thread` 的参数结构。
|
||||
3. `codex_app__read_thread` 的状态读取方式。
|
||||
4. `gpt-5.6-sol` 和 `gpt-5.6-terra` 是否仍可选。
|
||||
5. `xhigh` 和 `medium` 是否仍受对应模型支持。
|
||||
6. 工具调用记录中是否意外出现 `spawn_agent`、`fork_turns` 或 `fork_thread`。
|
||||
|
||||
如果能力发生变化,应先更新本文第 2 节和第 5 节提示词,再继续使用该工作流。
|
||||
232
docs/SGS_SDK_3D_RENDERING_COMPARISON_REPORT.md
Normal file
232
docs/SGS_SDK_3D_RENDERING_COMPARISON_REPORT.md
Normal file
@@ -0,0 +1,232 @@
|
||||
# SGS SDK 与当前 H5 三维渲染对照研究报告
|
||||
|
||||
> 版本:2026-07-18
|
||||
> 范围:`frontend-miniapp` 当前本地 ThreeMap 渲染器,与 `smart-navigation-system/sgs-frontend-map/sdk-engine` 的 SDK Engine。
|
||||
> 结论边界:本报告是参数、空间契约与验证方案研究,**不是**将当前 H5 迁移为 SDK iframe 的建议;不将外观首页和 SDK 单楼层 Demo 误判为应像素级一致的场景。
|
||||
|
||||
## 1. 执行摘要
|
||||
|
||||
当前 H5 应继续采用“本地 ThreeMap 渲染 + SGS REST 数据”的架构。`src/config/dataSource.ts:91-94` 中的 SDK 脚本和 Engine URL 只是配置能力;实际 SDK 数据路径是 `sgsSdkApiProvider` 的 `uni.request`,经 `GuideModelRepository` 转为本地模型资源供 Three.js 加载。既有的本地渲染和 SDK Engine 在背景、相机投影、DPR、渲染器、色调映射、阴影与三灯参数上已基本对齐,因此不建议进行无目标的颜色/灯光再调参。
|
||||
|
||||
当前最高优先级不是视觉参数,而是 Bundle 的模型变换契约缺失:SDK Engine 会尝试读取变换但静默回退单位矩阵,H5 类型、领域模型和仓储也只传递 URL。实时 Bundle 已确认不含变换字段;但尚未证明生产数据库中存在非单位变换。因此 P0 仅应完成真实激活模型的只读数据核验,不能先行扩展运行时代码。
|
||||
|
||||
SDK 与 H5 的相机、POI 密度与标签实现有刻意的产品策略差异。SDK 单楼层 AutoFit 与 H5 外观/楼层状态机不是相同视图;后续视觉验收必须固定同一楼层、同一模型、同一视口、同一 DPR 和同一 view mode。POI LOD 可做受控实验,但应保留 H5 的 WebGL 命中目标、DOM 标签和碰撞规避。
|
||||
|
||||
## 2. 证据口径
|
||||
|
||||
| 标签 | 含义 | 本报告用法 |
|
||||
| --- | --- | --- |
|
||||
| 源码事实 | 可定位到当前两仓源码的声明或执行路径 | 可以用于架构、参数和契约判断 |
|
||||
| 实时接口事实 | 2026-07-18 对已部署接口的实际响应 | 只说明当时、该地图/楼层的数据 |
|
||||
| 浏览器观察 | 指定服务、URL、视口下的实际运行结果 | 不能外推为所有发布物或设备 |
|
||||
| 尚未证明 | 当前证据不足以作出肯定结论 | 列为核验或回归项,不写作已修复 |
|
||||
|
||||
## 3. 两项目架构边界与数据链
|
||||
|
||||
| 维度 | 当前 H5 (`frontend-miniapp`) | SDK Engine / Web Demo | 判断 |
|
||||
| --- | --- | --- | --- |
|
||||
| 数据取得 | `sgsSdkApiProvider` 以 `uni.request` 请求 `/app-api/gis/sdk/*`(`src/data/providers/sgsSdkApiProvider.ts:381,458,489`) | Engine 读取 SDK API / Bundle | 数据可比,渲染运行时不同 |
|
||||
| 模型资源 | `GuideModelRepository` 取 `modelUrl` / `fallbackModelUrl`,生成本地 `GuideModelFloorAsset`(`src/repositories/GuideModelRepository.ts:364-378`) | Engine 直接消费 Bundle model | 都依赖 Bundle,但不可假设变换已传递 |
|
||||
| 渲染器 | 本地 Three.js `ThreeMap.vue` | SDK iframe 内 Engine | 不建议因本次研究替换 H5 渲染器 |
|
||||
| SDK URL 配置 | 存在 `sgsSdkScriptUrl`、`sgsMapEngineUrl` 和 timeout(`src/config/dataSource.ts:91-94`) | 发布 Demo 用相对 `../engine/` | 配置存在不等于当前 H5 走 iframe |
|
||||
| 页面能力 | H5 有自己的楼层基线、状态机、DOM 标签和 WebGL 命中目标 | 单楼层 AutoFit、HTML POI 层、可选服务端 LOD | 应比较契约/行为,不要求视觉像素等价 |
|
||||
|
||||
**源码事实。** 当前 H5 的领域类型 `GuideModelFloorAsset` 只含楼层、标签、顺序和 URL 类字段(`src/domain/guideModel.ts:24-31`);这与 REST 提供者 `SgsModelInfoPayload` 的字段集合一致(`src/data/providers/sgsSdkApiProvider.ts:194-202`)。本报告不建议跨仓抽取共享运行时包:两端发布、部署和生命周期边界不同,优先使用契约快照防漂移。
|
||||
|
||||
## 4. 三维基础渲染参数对照
|
||||
|
||||
| 项 | SDK Engine | 当前 H5 | 结论 |
|
||||
| --- | --- | --- | --- |
|
||||
| 场景背景 | `#ECEFF1` | `0xeceff1`,`ThreeMap.vue:106-108,1918-1920` | 一致 |
|
||||
| PerspectiveCamera | FOV 42、near 0.1、far 20000,`Viewport3D.tsx:509-558` | FOV 42、near 0.1、far 20000,`ThreeMap.vue:108-112,1923-1928` | 一致 |
|
||||
| Renderer | DPR cap 1.5、high-performance、antialias、alpha=false | 同值,`ThreeMap.vue:114-121,1931-1937` | 一致 |
|
||||
| 色调/曝光/阴影 | NoToneMapping、1.0、关闭阴影 | 同值,`ThreeMap.vue:119-121,1939-1941` | 一致 |
|
||||
| 半球灯 | `#fff/#b0bec5`、1.7 | 同值,`ThreeMap.vue:123-127,1968-1973` | 一致 |
|
||||
| 主光 | `[80,120,80]`、2.2 | 同值,`ThreeMap.vue:129-132,1975-1980` | 一致 |
|
||||
| 补光 | `[-60,70,-50]`、0.55 | 同值,`ThreeMap.vue:134-137,1982-1987` | 一致 |
|
||||
|
||||
**源码事实。** SDK 参数来源为 `sgs-frontend-map/sdk-engine/src/components/Viewport3D.tsx:509-558`,H5 参数集中在 `src/components/map/ThreeMap.vue:106-137,1918-1987`。因此基础色彩、灯光和 renderer 默认值不是当前主要根因;除非有受控的同场景截图证据,否则不应启动另一轮全局视觉调参。
|
||||
|
||||
## 5. 相机与视图策略
|
||||
|
||||
SDK AutoFit 以 `__model_root__` 的 `Box3`、模型尺寸和预设计算相机(`sdk-engine/src/components/AutoFitCamera.tsx:164-321`),常规距离约为 `fitDim * 1.2`,高度/目标依赖 preset。预设 `sdk-kiosk-landscape`、`sdk-mobile-portrait`、`default` 定义在 `sdk-engine/src/config/viewport-presets.ts:67-160`;竖屏会旋转约 90 度并设置 `minFitDimension=260`。
|
||||
|
||||
H5 则保存自己的参考外观相机和楼层基线:楼层基线从模型盒、屏幕偏移和相机方向计算(`ThreeMap.vue:3505-3554`),`setCameraView` / `fitCameraToObject` 根据 `overview` 或 `floor` 使用不同方向、距离与偏移(`ThreeMap.vue:3833-3921`),楼层恢复还会回放快照(`ThreeMap.vue:4245-4250`)。
|
||||
|
||||
**源码事实与验收结论。** H5 外观首页和 SDK 单楼层 Demo 是不同产品视图,不能要求像素级相同。视觉对照的前置条件是:相同 floorId、模型 URL/版本、视口尺寸、DPR、view mode、相机 preset/基线以及无 POI 焦点状态。此前宽屏初始化后缩窄的空白,固定 `430x720` 刷新未复现,故为“尚未证明的生产缺陷”;保留“相机快照污染”回归测试即可。
|
||||
|
||||
## 6. 模型变换契约
|
||||
|
||||
| 层级 | 现状 | 证据类型 | 风险 |
|
||||
| --- | --- | --- | --- |
|
||||
| SDK Engine | Bundle model 被 `any` 读取,尝试 `translationX/Y/Z`、`rotationX/Y/Z`、`scaleX/Y/Z`;缺失回退 `[0,0,0] / [0,0,0] / [1,1,1]` | 源码事实:`H5SdkEngine.tsx:5078-5099,5224-5239` | 非单位数据会被静默忽略 |
|
||||
| SDK Bundle VO | 只发布 URL、压缩/版本、节点数和大小 | 源码事实:`SdkModelInfoVO.java:15-36` | 外部契约未承载矩阵 |
|
||||
| H5 Provider / Domain / Repo | 同样只承载 URL 等字段 | 源码事实:`sgsSdkApiProvider.ts:194-202`、`guideModel.ts:24-31`、`GuideModelRepository.ts:364-378` | H5 也使用单位变换 |
|
||||
| 另一后端模型接口/DO | 存在变换字段 | 源码事实:`AppGisModelController.java:70-83`、`Map3dModelDO.java:57-87` | 数据能力与 SDK Bundle 契约脱节 |
|
||||
| L2 实时 Bundle | `floorId=2065808921578303490`,`code=0`、30 POI;model keys 仅 URL/压缩/版本/统计字段,所有变换字段缺失 | 实时接口事实(2026-07-18) | 只证明该 Bundle 未发布变换 |
|
||||
|
||||
**根因判断。** 如果数据库中存在非单位模型变换,当前 SDK 与 H5 都会静默按单位矩阵渲染,可能导致模型、POI、路线和点击坐标失配。**尚未证明:** 当前没有证据证明任一激活模型的数据库变换为非单位值;不可把该风险表述为已发生故障。
|
||||
|
||||
**P0 核验。** 在不改运行代码的前提下,通过只读 SQL 或管理接口枚举所有激活模型的平移、旋转、缩放;记录 modelId、floorId、版本和原始字段。只有发现非单位值,才进入 P2。
|
||||
|
||||
## 7. POI、标签与 LOD 策略
|
||||
|
||||
SDK 的 `PoiMarkerLayer` 是 HTML 标签,结合类型配置、遮挡检测与绝对相机距离阈值;非 kiosk 为 far=400、mid=150(`sdk-engine/src/components/layers/PoiMarkerLayer.tsx:771-855,1080-1086`)。服务端 LOD API 能力存在(`sdk-engine/src/api/sdk-api-loader.ts:524-533`),但 Engine real-preview 默认关闭,仅 URL 带 `enablePoiLabelLod=1/true` 才启用(`H5SdkEngine.tsx:1187-1225`);当前 Web Demo 未传该参数。
|
||||
|
||||
实时接口 `/app-api/gis/sdk/maps/1/poi-label-lod` 返回 9 层;总体为 far=22、mid=181、near=183、sourcePoiCount=183、clusterCount=24、singleCount=362,L2 为 far=3 / mid=26 / near=26(实时接口事实,2026-07-18)。这证明服务端可供实验,不证明当前 Engine Demo 已消费它。
|
||||
|
||||
H5 使用模型尺度归一化:点位阈值 `0.32/0.20`、标签阈值 `0.42/0.26`(`ThreeMap.vue:1260-1328`);点位数量 tight=5、balanced=9、full=无限,屏幕间距 `116/78/0`(`ThreeMap.vue:1300-1309,1425-1551`)。标记为 WebGL Sprite,另设命中 Sprite(`ThreeMap.vue:4805-4828,4880-4897`);DOM 标签带碰撞规避与 `ResizeObserver`(`ThreeMap.vue:4550-4591`)。
|
||||
|
||||
**建议。** 仅以 feature flag 引入服务端 LOD 作为候选数据源;保留 DOM 标签、碰撞规避及 WebGL 点击命中目标,失败时回退本地策略。不要直接用 SDK HTML POI 替换移动 H5 实现。
|
||||
|
||||
## 8. Web Demo 与运行证据
|
||||
|
||||
| 观察 | 证据类型 | 判断与后续动作 |
|
||||
| --- | --- | --- |
|
||||
| 发布 Demo `app.js:482-530` 从 scene/floorCode 读取参数、固定相对 `../engine/`,等待 `sdk.whenReady()` | 源码事实 | 宿主和 Engine 发布目录是关键依赖 |
|
||||
| 本地 5555 Demo 持续“连接中”,30 秒 `whenReady` 超时;iframe 指向 `5555/engine`;直开 `5556/engine` 成功 | 浏览器观察 | 优先查静态托管目录/发布版本不一致;不能归咎渲染器 |
|
||||
| 直开 SDK Engine:1280x720 Canvas 非空;L2 Bundle 约117ms、30 POI、Draco 约0.24MB、160节点;AutoFit 约262x133m、distance 314m、height 220m;发出 `ENGINE_READY` | 浏览器观察 | Engine 在该直接入口可运行 |
|
||||
| 曾出现一次 `webglcontextlost`,最终画面非空;`Viewport3D.tsx:531-539` 有恢复监听 | 浏览器观察 + 源码事实 | 仍需 context lost/restored 回归,不得视为已完全排除 |
|
||||
| 当前 H5 外观页正常;`430x720` 刷新后诊断 API 切到 1F:`activeView=floor`、单位变换误差0、7个 WebGL 点、2个 DOM 标签都在 Canvas 内 | 浏览器观察 | 证明此固定条件可用,非全部设备证明 |
|
||||
|
||||
## 9. 风险分级与分阶段实施方案
|
||||
|
||||
| 优先级 | 风险 / 目标 | 实施范围 | 退出条件 |
|
||||
| --- | --- | --- | --- |
|
||||
| P0 | Bundle 模型变换是否漏传 | 报告 + 所有激活模型的只读 SQL/管理接口核验;不改运行代码 | 有带版本的单位/非单位清单 |
|
||||
| P1 | 两仓参数与 Bundle schema 漂移 | 增加参数与 schema 契约快照/测试;不抽取跨仓共享 runtime 包 | 两仓变化能在 CI/本地契约检查中定位 |
|
||||
| P2 | 仅在 P0 发现非单位变换时,补齐变换契约 | `SdkModelInfoVO`、service mapper、SDK TS 类型、H5 provider/domain/repo/render matrix | 模型、POI、路线、点击坐标共用矩阵 |
|
||||
| P3 | 验证服务端 POI LOD 是否优于本地密度策略 | feature flag、候选数据源与对照记录;保持现有标签/命中目标 | 通过完整 LOD 验收,否则回退 |
|
||||
| P4 | Demo 宿主/Engine 版本闭环和 WebGL 韧性 | 统一静态发布目录与版本链;增加 context lost/restored 回归 | `whenReady` 与 `ENGINE_READY` 稳定闭环 |
|
||||
|
||||
P2 的最小正确实现不是“给模型加 transform”即可,而是定义同一 `M`:模型使用 `M`,POI 与路线使用同一正向投影,点击/射线结果用 `M^-1` 回到业务坐标。同步覆盖单位矩阵和非单位平移/旋转/缩放,禁止局部补偿。
|
||||
|
||||
## 10. 验收矩阵
|
||||
|
||||
| 验收主题 | 条件 | 必须记录 / 断言 | 失败处理 |
|
||||
| --- | --- | --- | --- |
|
||||
| Bundle 变换 | P0 全部激活模型 | 原始字段、floor/model/version、是否单位矩阵 | 未完成前禁止宣称 P2 必要 |
|
||||
| 变换契约(若 P2) | 单位与非单位矩阵 | 模型位置、POI 投影、路线点、点击反变换、同楼层视觉验证 | 任一失配阻断上线 |
|
||||
| 视觉对照 | 同楼层、同模型版本、同视口、同 view mode | 相机参数、DPR、截图及差异说明 | 不可用跨场景截图判定 |
|
||||
| LOD 实验 | L1/L2/EXTERIOR;390x844;DPR 1 与 3 | 可见标签数、重叠数、点击命中、帧时间 | 失败立即回退当前本地策略 |
|
||||
| Demo 发布 | Demo 与 Engine 同一发布目录/版本 | `whenReady` resolve、`ENGINE_READY`、楼层切换、30 POI、模型 Canvas 非空 | 调查宿主/资源/版本链 |
|
||||
| WebGL 恢复 | 主动或受控触发 context lost/restored | 日志、恢复后 Canvas、楼层、POI、交互状态 | 失败阻断 P4 闭环 |
|
||||
| H5 相机回归 | 固定刷新与宽屏后缩窄 | 外观/楼层快照、Canvas 非空、标签边界 | 标记相机快照污染并修复后复验 |
|
||||
|
||||
## 11. 实测与测试证据
|
||||
|
||||
- **测试事实:** 当前 H5 已执行 `tests/unit/poiDomLabels.spec.ts`、`GuideMapShell.spec.ts`、`GuideModelStateReset.spec.ts`,共 9/9 通过。
|
||||
- **测试事实:** SDK 相关测试 19/20 通过;`model-load-lifecycle.test.ts` 的唯一失败来自只匹配 LF 的正则读取 CRLF 文件。实际 remount key 代码存在,因此这是 Windows 跨平台测试脆弱性,不是生命周期实现缺失。
|
||||
- **证据边界:** 上述结果是既有审核提供的执行证据,本报告只整理记录,未在本次文档任务重跑测试或 build,避免写入 `output` / `dist`。
|
||||
|
||||
## 12. 明确不建议事项
|
||||
|
||||
1. 不因本报告将当前 H5 本地 ThreeMap 替换为 SDK iframe。
|
||||
2. 不在没有同场景证据时继续做全局颜色、灯光或 renderer 参数调参。
|
||||
3. 不把外观首页与 SDK 单楼层 AutoFit 作为像素级等价对象。
|
||||
4. 不在未核验数据库存在非单位变换前,盲目扩展 Bundle、SDK 或 H5 运行时代码。
|
||||
5. 不单独变换模型而遗漏 POI、路线和点击坐标,也不采用页面级坐标补丁。
|
||||
6. 不直接照搬 SDK HTML POI,替换 H5 的 DOM 碰撞标签和 WebGL 命中 Sprite。
|
||||
7. 不把 5555 Demo “连接中”直接归因为渲染器故障;先证明发布目录、Engine 版本和静态资源链一致。
|
||||
8. 不以单次 `webglcontextlost` 后画面恢复为 context-recovery 已验收。
|
||||
|
||||
## 13. 交接清单
|
||||
|
||||
后续执行者应先完成 P0 只读核验,再决定是否开启 P2;并在每个阶段把“源码事实、实时接口事实、浏览器观察、尚未证明”分列记录。任何变更前保留当前本地策略作为回退基线,特别是移动端 DOM 标签、WebGL 命中目标、楼层基线和相机快照状态机。
|
||||
|
||||
## 14. SDK Demo 业务功能与当前 H5 对比
|
||||
|
||||
### 14.1 范围、概念与运行边界
|
||||
|
||||
本节分析的 SDK Demo 是 `E:/MyWork/深圳国际艺术馆/智慧导览/smart-navigation-system/sgs-map-sdk-release/demo/`,主要证据为 `README.md`、`index.html`、`app.js`,以及 Engine 的 `sgs-frontend-map/sdk-engine/src/H5SdkEngine.tsx`。Demo README 明确其定位是“展示 SDK 能开发成什么效果,同时用于调试”,独立静态页不直接调用 `/app-api` 或 `/admin-api`,而是由 SDK iframe/Engine 连接远端地图服务(`demo/README.md:1-35`)。它不是当前博物馆移动 H5 的产品需求清单。
|
||||
|
||||
本节严格区分四个概念:
|
||||
|
||||
| 概念 | 判定依据 | 不能推导出的结论 |
|
||||
| --- | --- | --- |
|
||||
| Demo 展示入口 | `index.html` Tab/按钮和 `app.js` 处理函数存在 | 不代表发布链可用,也不代表适合移动端 |
|
||||
| SDK 已实现能力 | SDK 公开方法可调用,且 Engine 有对应命令/事件处理 | 不代表业务数据已发布或产品流程已设计 |
|
||||
| 后端接口能力 | Engine 调用的数据接口/Bundle 字段存在 | 不代表 Demo 或 H5 已做端到端错误恢复 |
|
||||
| 当前 H5 已产品化能力 | H5 页面/组件、Repository/provider 和用户流程共同存在 | 不以按钮文案、类型声明或历史 mock 单独认定 |
|
||||
|
||||
**浏览器观察(2026-07-18)。** URL 场景为本地 `5555` 发布 Demo,iframe 指向 `5555/engine` 时持续“连接中”,约 30 秒 `whenReady()` 超时;直接打开 `5556/engine` 则可获得非空 Canvas 和 `ENGINE_READY`。因此,Demo 的入口和源代码均已验证,但完整宿主链未闭环;本节不把 Demo 所列业务能力标记为“5555 发布版已实测成功”。具体发布链限制见第 8 节。
|
||||
|
||||
### 14.2 SDK Demo 功能清单
|
||||
|
||||
| 功能域 | Demo 触发入口 | SDK 方法 / 事件 | Engine / 数据接口证据 | 运行状态 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 初始化与状态 | URL `server/env/mapId/floorCode/token`,创建 `SGSMapSDK` | `whenReady()`、`on('ready')` | `app.js:479-535`;Engine 收到 `HELLO` 后发 `ENGINE_READY`,`H5SdkEngine.tsx:2521-2525` | 直接 Engine 已观察成功;5555 Demo 链未闭环 |
|
||||
| 事件/错误日志 | “事件”Tab | `ready`、`poiClick`、`floorChanged`、`error`、`loadError`、`routeTransfer`、模型/Bundle/路线/漫游事件 | `app.js:554-643` | 展示和诊断入口,不是访客业务 UI |
|
||||
| 地图/楼层/图层/视图 | 楼层浮栏、2D/3D、全局、Tab 切换 | `getManifest`、`changeFloor`、`setVisibleLayers`、`setViewMode`、`resetView`、`setRouteViewActive` | `app.js:172-315,655-704,718-795`;`CHANGE_FLOOR` 在 Engine 实现,`H5SdkEngine.tsx:2527-2546` | 方法存在;宿主发布链仍是前置风险 |
|
||||
| 空间查询与聚焦 | “空间”Tab:搜索、列表、详情 | `getSpaces()`、`highlightPolygon()` | `app.js:890-999,999-1068`;`GET_SPACES` 返回 Bundle spaces,`H5SdkEngine.tsx:4111-4145`;高亮设置空间与 fly-to,`3188-3218` | SDK/接口能力可确认;Demo 是否完整运行受 `whenReady` 限制 |
|
||||
| POI 查询、筛选、详情、聚焦 | “POI”Tab:类型 chip、搜索、列表 | `getFloorPois()`、`focusTo()`、`poiClick` | `app.js:1137-1288`;`GET_FLOOR_POIS`,`H5SdkEngine.tsx:4070-4104`;Canvas 点击上报并 fly-to,`4920-4938` | SDK/Engine 已实现;Demo 全链未闭环 |
|
||||
| 讲解点查询 | “讲解点”Tab:跨楼层扫描、搜索、详情 | `getGuideStops()`、`getGuideStopsByHall()` | `app.js:1289-1464`;`GET_GUIDE_STOPS` 返回 Bundle guideStops,`H5SdkEngine.tsx:4159-4176`,按展厅查询 `4178-4193` | 查询能力,不等于讲解内容产品流程 |
|
||||
| 同层/跨层路径 | “导航”Tab:起终点楼层/地点、无障碍、overview/handoff、推荐路线 | `getNavigablePlaces()`、`planRouteV2()`/`planRoute()`、`clearRoute()` | `app.js:803-825,1465-1777,1814-1986`;Engine `PLAN_ROUTE` 支持 displayMode 并激活跨层 viewer,`2785-2816` | SDK 实现存在;真实路网、起终点与发布 Demo 仍应单独验收 |
|
||||
| 路线分段/换层/漫游 | 路线结果分段按钮、漫游控制 | `routeTransfer`、`routeReady`、`startRoaming()`、暂停/停止 | `app.js:587-602,827-889`;Engine 有 `START_ROAMING` 命令(`H5SdkEngine.tsx:3243-3299`) | SDK 技术能力;不是 H5 当前可宣称的馆内导航 |
|
||||
| 推荐/精品动线 | “导航”推荐按钮及“动线”Tab | `getFeaturedRoutes()`、`getFeaturedRoute()`、`planFeaturedRoutePreview()`、`showFlowline()` | `app.js:1793-1986,2348-2563`;Engine `GET_FEATURED_ROUTES`,`4437-4471` | 可供后续产品评估,未证明当前博物馆数据已可用 |
|
||||
| 商户 POI | “商户”Tab:餐饮/商店/咖啡厅筛选 | `getBusinessPois()`、`focusTo()` | `index.html:177-193`;`app.js:2145-2245`;Engine `GET_BUSINESS_POIS`,`4378-4396` | 后端/SDK 可调用,不代表自然博物馆有商户业务需求 |
|
||||
| 诊断 | “诊断”Tab | `getDiagnostics()`、`getFloorDiagnostics()` | `index.html:161-175`;`app.js:1987-2144`;Engine `GET_DIAGNOSTICS`,`4300-4333` | 仅调试/运维能力,不应作为访客入口 |
|
||||
| 场景模式 | URL `scene=desktop/mobile/kiosk` | Engine 查询参数与 view preset | `demo/README.md:25-34`,`index.html:47-64`;SDK 预设见第 5 节 | 展示适配维度,不代表 H5 应复制 kiosk UI |
|
||||
|
||||
### 14.3 当前 H5 的实际业务路径
|
||||
|
||||
当前 H5 不使用 Demo iframe;仍是本地 ThreeMap 加 REST 数据(第 3 节)。其已可由源码证明的产品能力如下:
|
||||
|
||||
| 用户目标 | 真实 H5 路径与实现 | 证据 | 产品化判断 |
|
||||
| --- | --- | --- | --- |
|
||||
| 进入馆内/切换楼层/查看模型 | 首页 -> `GuideMapShell` -> `ThreeMap`,带外观/楼层/多层状态、楼层请求与失败状态 | `src/pages/index/index.vue:11-51,395-445`;`src/components/navigation/GuideMapShell.vue:12-26,136-165`;`src/components/map/ThreeMap.vue:27-43,444-452` | 已产品化 |
|
||||
| 搜索并定位 POI | 首页或搜索页 -> `PoiSearchPanel` 分类、关键词、楼层结果 -> 详情/聚焦请求 | `src/components/search/PoiSearchPanel.vue:3-203,263-324`;`src/pages/index/index.vue:157-179,1637-1709` | 已产品化;不同于 Demo 的单列表/类型 chip |
|
||||
| 地图 POI 点击、卡片和聚焦 | ThreeMap 发出 `poiClick`,H5 使用自己的渲染、命中和详情卡片状态 | `src/components/map/ThreeMap.vue:43-45,4805-4828,4880-4897`;DOM 标签见第 7 节 | 已产品化,采用 WebGL 命中 Sprite + DOM 标签而非 iframe HTML 图层 |
|
||||
| 小屏可读标签 | DOM 标签投影、碰撞规避、`ResizeObserver`,配合模型尺度和屏幕密度策略 | `ThreeMap.vue:1260-1328,1425-1551,4550-4591` | 已产品化,优于直接复制 Demo 标签层 |
|
||||
| 讲解浏览与详情 | `讲解 -> 展厅列表 -> 讲解对象列表 -> 讲解详情`;列表按展厅分页 | `src/utils/explainNavigation.ts:1-3`;`src/usecases/explainUseCase.ts:481-513`;`src/components/explain/ExplainGuideStopCatalog.vue:40-75` | 已产品化的内容 IA;不能退化成 Demo 按楼层查“讲解点” |
|
||||
| 音频讲解 | 讲解详情选择语言、播放/重试/进度;全局播放器具备 H5 audio lifecycle | `src/pages/exhibit/detail.vue:76-114,291-316`;`src/components/audio/AudioPlayer.vue:122-158,231-295` | 有源码能力;具体对象音频仍取决于真实内容数据 |
|
||||
| 位置预览而非导航承诺 | 路线 use case 先读取 readiness,不就绪返回“暂不提供正式室内导航” | `src/usecases/guideRouteUseCase.ts:43-76`;`src/pages/route/detail.vue:144-148,361-363,736-766` | 产品意图明确:不可将 Demo 路径规划视为当前 H5 缺陷 |
|
||||
| 来馆导航桥接 | H5 通过微信小程序宿主位置页传入经校验的目标 | `src/services/WechatMiniProgramBridgeService.ts:55-121` | 已实现桥接;保证结果是微信内置地图能力,不等同直接拉起任意第三方地图 |
|
||||
|
||||
### 14.4 完整业务功能矩阵
|
||||
|
||||
| 功能域 | SDK Demo 能力 | 当前 H5 能力 | 差异状态 | 差异根因 | 产品建议 | 源码证据 |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| 初始化、ready、错误日志 | `whenReady` + 12 类事件日志 | 本地模型加载/失败和诊断事件,无 SDK iframe ready | 不适用 | 渲染架构不同;Demo 还承担调试 | 保持 H5 本地生命周期;仅复用可观测性字段 | Demo `app.js:479-643`;H5 `ThreeMap.vue:451-452` |
|
||||
| Manifest/楼层切换 | Manifest、SDK changeFloor、重置视图 | Repository/Guide shell/ThreeMap 楼层状态、基线与预加载 | 部分覆盖 | H5 有自己的数据/相机契约 | 保持 H5;可对齐错误码和诊断快照 | Demo `655-795`;H5 `GuideMapShell.vue:136-165`、`ThreeMap.vue:3505-3554` |
|
||||
| 图层/2D-3D/场景 | Tab 驱动 `setVisibleLayers`、2D/3D、desktop/mobile/kiosk | overview/floor/multi、自动切换,非 Demo 场景模式 | 部分覆盖 | 产品体验不同 | 不接 kiosk;只在同场景评估必要的 view control | Demo `172-315`;H5 `ThreeMap.vue:90,3833-3921` |
|
||||
| 空间面查询/详情 | 搜索空间、`highlightPolygon` | 已有馆内 POI/展厅位置预览;未证明有独立空间面详情产品 | 部分覆盖 | H5 面向访客 POI,不是 GIS 空间管理 | P2,仅当“展厅/区域详情”有真实内容与模型锚点 | Demo `999-1136`;Engine `4111-4145`;H5 `GuideRepository.ts:115-153` |
|
||||
| POI 搜索/分类/详情/聚焦 | 当前楼层类型筛选、搜索、focus、点击事件 | 分类搜索、跨楼层结果、详情/定位、点击卡片 | 相同(流程不同) | H5 针对移动端任务流程深化 | 保持 H5;不迁移 iframe 列表实现 | Demo `1137-1288`;H5 `PoiSearchPanel.vue:3-203`、`index.vue:1637-1709` |
|
||||
| POI 标签与点击命中 | Engine HTML 标签、poiClick/fly-to | WebGL Sprite + hit target + DOM 碰撞标签 | 相同(实现不同) | H5 需移动端性能与命中稳定性 | 保持 H5;P3 才实验服务端 LOD | Engine `4920-4938`;H5 `ThreeMap.vue:4550-4591,4805-4897` |
|
||||
| 讲解点查询 | 按楼层扫描/搜索/详情 | 按展厅分页的讲解对象列表和详情 | 部分覆盖(H5 更产品化) | Demo 以 SDK 数据查询为主,H5 是内容 IA | 保持 H5 IA;可在后台按 hallId 补充关联,不改变用户导航 | Demo `1289-1464`;Engine `4159-4193`;H5 `explainUseCase.ts:481-513` |
|
||||
| 讲解内容/音频 | Demo 仅展示 guide stop 字段 | 讲解详情、语言、音频/图文状态、播放器 | 当前 H5 更高 | Demo 未形成内容播放流程 | 保持 H5,先补真实内容数据而非接 SDK UI | H5 `exhibit/detail.vue:76-114,291-316`、`AudioPlayer.vue:231-295` |
|
||||
| 同层/跨层路线 | 可选起终点、轮椅、overview/handoff、路线段、换层和漫游 | 有 readiness 门控的位置关系/预览;不把其称为正式导航 | 缺失(有意门控) | 路网/导航数据与真实运行未验收 | P0 数据核验后再评估,不能直接打开功能 | Demo `1465-1777,827-889`;H5 `guideRouteUseCase.ts:43-76` |
|
||||
| 推荐/精品动线 | 内置推荐和 featured-route 预览/展示 | 未证明有当前博物馆的路线产品数据 | 当前业务不需要/数据未证实 | Demo 是 SDK showcase,数据依赖待确认 | P2,先做内容/运营需求与路线数据评审 | Demo `1793-1986,2348-2563`;Engine `4437-4471` |
|
||||
| 商户 POI | 餐饮/商店/咖啡筛选 | H5 有通用服务/设施和搜索,但未证明商户运营域 | 不适用 | 自然博物馆当前产品域与商业体不同 | 不接入,除非业务明确新增餐饮/商店运营数据 | Demo `index.html:177-193`、`app.js:2145-2245` |
|
||||
| 诊断与事件面板 | 地图/楼层诊断、Event Log | 开发诊断、测试和控制台,不呈现访客面板 | 仅调试能力 | 受众不同,暴露技术细节会损害访客体验 | 不接入访客 H5;可做受权限保护的 QA 工具 | Demo `1987-2144,554-643`;Engine `4300-4333` |
|
||||
| 来馆/室外导航 | 未见宿主导航桥接 | 微信小程序宿主位置页桥接 | H5 独有 | H5 部署容器和用户任务不同 | 保持现状 | `WechatMiniProgramBridgeService.ts:86-121` |
|
||||
|
||||
### 14.5 建议接入、保持现状与不接入
|
||||
|
||||
| 决策 | 能力 | 优先级 | 前置条件与原因 |
|
||||
| --- | --- | --- | --- |
|
||||
| 建议接入 | 路网/可达性只读核验与契约快照 | P0 | 先验证每个激活楼层 `routePlanningReady`、节点/边、可导航地点、无障碍连接器和真实路径;没有数据不得开放导航。可复用 `SdkGuideRouteRepository` 的诊断逻辑(`src/repositories/SdkGuideRouteRepository.ts:92-155`),不接 iframe。 |
|
||||
| 建议接入 | Bundle/参数/路线 readiness 自动化契约检查 | P1 | 继承本报告第 9 节 P1;SDK Engine 的 `GET_NAVIGABLE_PLACES` / diagnostics 仅说明接口存在(`H5SdkEngine.tsx:4205-4238,4300-4333`),需要 H5 数据层的稳定契约。 |
|
||||
| 建议接入 | 受 feature flag 控制的服务端 POI LOD 对照 | P1 | 遵循第 7、10 节,保留 DOM 标签、碰撞与 WebGL 点击。只采集对比数据,不迁移 SDK HTML 标签层。 |
|
||||
| 建议接入 | 精品路线的产品/数据可行性探索 | P2 | 先取得博物馆运营定义、真实 routeId/waypoints、审核后图和无障碍规则;再在 H5 `GuideRouteRepository`/use case 后实现,不采用 Demo 硬编码推荐路线。 |
|
||||
| 建议接入 | 访客需要的展厅/区域空间详情 | P2 | 必须有空间-内容稳定 ID、模型面/锚点和有效详情数据;走 Repository/view model,不能把 `highlightPolygon` 当作完整产品。 |
|
||||
| 保持现状 | 本地 ThreeMap + REST、H5 搜索、卡片、相机基线、POI DOM/WebGL 混合策略 | P0 | 当前架构和移动体验已针对本项目;详见第 3、5、7 节。 |
|
||||
| 保持现状 | 展厅列表 -> 讲解对象列表 -> 讲解详情及音频路径 | P0 | 这是当前内容业务 IA;Demo 的按楼层 guide stop 查询不应改变此流程。 |
|
||||
| 不接入 | Demo iframe/Engine 的整体替换 | 不适用 | 发布 `whenReady` 链未闭环,且会破坏本地 ThreeMap 的相机、标签、点击和状态机契约。 |
|
||||
| 不接入 | 访客端诊断/事件日志、模型性能日志 | 不适用 | 仅调试/运维能力;需要时应做独立、受权限保护的 QA 面板。 |
|
||||
| 不接入 | kiosk/desktop 控制面与商户 POI 业务 | 不适用 | 设备和业务域不匹配;不能仅因 SDK Demo 展示而迁移。 |
|
||||
| 不接入 | 在路网未验收时的漫游、跨层 turn-by-turn、无障碍承诺 | 不适用 | 属于真实产品缺口但不应以 UI 模拟填补,必须先满足 P0 数据与现场验收。 |
|
||||
|
||||
### 14.6 后续实施边界、接口契约与验收
|
||||
|
||||
若通过 P0 证明路网和目标业务数据可用,实施边界必须保持如下分层,禁止页面直接调 SDK 或后端接口:
|
||||
|
||||
| 目标 | 文件边界 | 必要契约 | 测试与移动端验收 |
|
||||
| --- | --- | --- | --- |
|
||||
| 路线 readiness | `src/data/providers/sgsSdkApiProvider.ts` -> `src/repositories/SdkGuideRouteRepository.ts` -> `src/usecases/guideRouteUseCase.ts` -> `src/pages/route/detail.vue` / `src/pages/index/index.vue` | 楼层、route node/edge、navigable place、connector、wheelchair constraint、数据版本;失败必须给出不可用原因 | 单测覆盖无数据/部分楼层/全就绪;390x844 验证禁用、重试、返回位置预览,不显示“开始导航”承诺 |
|
||||
| 路线渲染(仅获批后) | `GuideRouteRepository` / `guideRouteUseCase` -> `GuideMapShell.vue` -> `ThreeMap.vue` | 同一模型矩阵 M 下的 route point、floorId、段类型、换层连接器、起终点;与第 6 节变换契约一并演进 | 单位/非单位矩阵、同层/跨层/无障碍路线、路线点/点击反变换;390x844、DPR 1/3 下分段切楼层与取消清理 |
|
||||
| 精品路线 | 新 Repository/provider/use case 与页面 view model,不在 `ThreeMap.vue` 硬编码路线 | routeId、name、waypoints、运营状态、无障碍规则、内容关联、版本 | 空/失效 waypoints、跨层、重复进入、关闭恢复;内容审核和运营验收后才暴露入口 |
|
||||
| 空间详情 | provider/adapter/repository -> `GuideMapShell` 或专用详情页 | `spaceId` 与 `hallId/poiId`、几何锚点、展示内容、有效状态 | 空间缺面/缺内容/锚点不匹配降级;不遮挡移动端控件 |
|
||||
| POI LOD 实验 | provider/adaptor 候选数据 -> `ThreeMap.vue` feature flag | server LOD 层、POI 稳定 ID、当前本地优先级和回退标志 | L1/L2/EXTERIOR、390x844、DPR 1/3,记录标签数/重叠/命中/帧时间;失败回退 |
|
||||
|
||||
所有实施都应补充:同一发布目录下的 SDK Demo `whenReady resolve`、`ENGINE_READY`、楼层切换、模型非空、30 POI 与 context lost/restored 验收,但这些是 SDK 发布物的独立回归项,不能作为把 iframe 引入当前 H5 的理由。
|
||||
@@ -67,8 +67,38 @@ const copyStaticFile = (fileName) => {
|
||||
console.log(`Copied ${fileName} to ${path.relative(projectRoot, targetFile)}`)
|
||||
}
|
||||
|
||||
const rewriteCopiedGuideDataUrls = () => {
|
||||
const guideDataDir = path.join(h5Root, 'static', 'guide-data')
|
||||
const replacements = [
|
||||
['http://1.92.206.90:9000/museum-assets', '/museum-assets'],
|
||||
['http://1.92.206.90:9000/tts-audio', '/tts-audio'],
|
||||
['https://guide.whaoyue.com/museum-assets', '/museum-assets'],
|
||||
['https://guide.whaoyue.com/tts-audio', '/tts-audio'],
|
||||
['https://guide.whaoyue.com/app-api', '/app-api'],
|
||||
['"sourceHost": "1.92.206.90:5237"', '"sourceHost": ""']
|
||||
]
|
||||
|
||||
for (const entry of fs.readdirSync(guideDataDir, { withFileTypes: true })) {
|
||||
if (!entry.isFile() || !entry.name.endsWith('.json')) continue
|
||||
|
||||
const filePath = path.join(guideDataDir, entry.name)
|
||||
let text = fs.readFileSync(filePath, 'utf8')
|
||||
const original = text
|
||||
|
||||
for (const [from, to] of replacements) {
|
||||
text = text.split(from).join(to)
|
||||
}
|
||||
|
||||
if (text !== original) {
|
||||
fs.writeFileSync(filePath, text, 'utf8')
|
||||
console.log(`Rewrote guide-data URLs in ${path.relative(projectRoot, filePath)}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copyStaticSubtree('nav-assets')
|
||||
copyStaticSubtree('guide-data')
|
||||
rewriteCopiedGuideDataUrls()
|
||||
copyStaticSubtree('guide')
|
||||
copyStaticSubtree('icons')
|
||||
// 讲解业务单元封面由 H5 运行时按 /static/explain/... 动态加载。
|
||||
|
||||
@@ -43,18 +43,20 @@ const h5JavaScriptCode = h5JavaScriptFiles
|
||||
.map((filePath) => readText(filePath))
|
||||
.join('\n')
|
||||
|
||||
for (const required of ['第三方导航', 'third-party-providers']) {
|
||||
assertContains(pageChunkCode, required, 'H5 首页 chunk')
|
||||
for (const required of [
|
||||
'第三方',
|
||||
'打开地图',
|
||||
'jweixin',
|
||||
'miniProgram',
|
||||
'/pages/open-location/index',
|
||||
'baidumap://',
|
||||
'iosamap://',
|
||||
'androidamap://'
|
||||
]) {
|
||||
assertContains(h5JavaScriptCode, required, 'H5 全量 JS')
|
||||
}
|
||||
|
||||
for (const forbidden of [
|
||||
'打开地图导航',
|
||||
'native-location',
|
||||
'jweixin',
|
||||
'wx.miniProgram',
|
||||
'宿主地图',
|
||||
'/pages/open-location/index'
|
||||
]) {
|
||||
for (const forbidden of ['native-location']) {
|
||||
assertNotContains(h5JavaScriptCode, forbidden, 'H5 全量 JS')
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user