# 馆内导览交互优化改进计划 ## 文档信息 - **项目**:深圳自然博物馆智能导览应用 - **模块**:馆内 3D 导览交互 - **创建时间**:2026-06-12 - **状态**:待评审 --- ## 背景 当前馆内导览采用**显式"全馆/楼层"手动切换**模式,用户需要点击按钮在"建筑外观"和"楼层内部"之间切换。这个模式功能完整,但与基于缩放距离的自动切换模式相比,交互直觉性较弱。 **现有模式**: - 进入馆内 3D → 加载建筑外观 - 用户手动点击"楼层"按钮 → 楼层控件出现 → 选择楼层 → 加载楼层内部 - 用户缩放只改变视角距离,不触发模型切换 **目标模式**: - 进入馆内 3D → 加载建筑外观 - 用户放大到一定距离 → **自动切换**到楼层内部 - 用户缩小到一定距离 → **自动切换**回建筑外观 - 保留手动控制入口作为兜底 --- ## 改进目标 1. **增加基于缩放距离的自动视角切换**,提升交互直觉性。 2. **保留手动切换入口**,避免误触和性能抖动。 3. **优化楼层控件可见性**,缩短操作路径。 4. **为未来多层展示预留架构空间**(不在本次实施)。 --- ## 改进任务分解 ### Phase 1:基础自动切换能力(核心) **目标**:实现基于缩放距离的建筑外观 ↔ 楼层内部自动切换。 #### Task 1.1:在 ThreeMap 组件实现距离监听与自动切换逻辑 **优先级**:P0 **预估工作量**:2-3 天 **风险**:中等(需要调优阈值和滞回参数) **实现要点**: 1. 监听 `OrbitControls` 的 `change` 事件,而不是每帧检查: ```typescript controls.addEventListener('change', () => { throttledCheckAutoSwitch() }) ``` 2. 实现双阈值滞回机制,避免反复切换: ```typescript const autoSwitchConfig = { thresholdLowFactor: 1.0, // 放大到建筑尺寸 1.0 倍时切换到楼层 thresholdHighFactor: 1.3, // 缩小到建筑尺寸 1.3 倍时切换回全馆 cooldownMs: 2000, // 切换后冷却 2 秒 enableAuto: true // 可配置开关 } ``` 3. 增加加载锁和冷却时间: ```typescript let isAutoSwitchLocked = false let lastAutoSwitchTime = 0 const checkAutoSwitch = () => { if (!autoSwitchConfig.enableAuto) return if (isAutoSwitchLocked) return const now = Date.now() if (now - lastAutoSwitchTime < autoSwitchConfig.cooldownMs) return const distance = controls.getDistance() // ... 判断阈值并切换 } ``` 4. 切换时触发事件通知上层: ```typescript emit('auto-switch', { from: 'overview', to: 'floor', trigger: 'zoom-in', distance: number }) ``` **验证标准**: - 在建筑外观缩放到近距离,自动切换到默认楼层(L1)。 - 在楼层内部缩放到远距离,自动切换回建筑外观。 - 快速缩放不会触发多次加载。 - 切换过程有 loading 状态提示。 **文件修改**: - `src/components/map/ThreeMap.vue`:增加自动切换逻辑 - `src/domain/guideModel.ts`:增加自动切换配置类型定义 --- #### Task 1.2:调整首页和 GuideMapShell 配合自动切换 **优先级**:P0 **预估工作量**:1 天 **依赖**:Task 1.1 **实现要点**: 1. 监听 `ThreeMap` 的 `auto-switch` 事件,同步 `indoorView` 状态: ```typescript const handleAutoSwitch = (event: { from: string; to: string }) => { if (event.to === 'floor') { indoorView.value = 'floor' } else { indoorView.value = 'overview' } } ``` 2. 更新状态标签文案: - 自动切换时显示"馆内楼层(自动)"或"馆内全馆(自动)" - 手动切换时显示"馆内楼层"或"馆内全馆" 3. 楼层控件可见性调整: - 改为 `:show-floor="is3DMode"`,在全馆模式也显示楼层控件 - 全馆模式下点击楼层,先切换到楼层视图,再加载对应楼层 **验证标准**: - 自动切换后,顶部状态标签正确更新。 - 全馆模式下可以直接点击楼层控件选择楼层。 **文件修改**: - `src/pages/index/index.vue`:监听自动切换事件 - `src/components/navigation/GuideMapShell.vue`:调整楼层控件可见性 --- #### Task 1.3:保留"全馆/楼层"手动切换作为兜底 **优先级**:P1 **预估工作量**:0.5 天 **依赖**:Task 1.1, 1.2 **实现要点**: 1. 保留现有"全馆/楼层"切换按钮,但调整定位: - 不再是主交互入口,而是手动控制和兜底入口。 - 样式可以调整为更轻量(例如图标按钮,而不是双按钮切换组)。 2. 手动切换时临时禁用自动切换(例如 10 秒): ```typescript const handleManualSwitch = (view: 'overview' | 'floor') => { // 临时禁用自动切换 threeMapRef.value?.disableAutoSwitchTemporarily?.(10000) // 执行手动切换 if (view === 'overview') { void threeMapRef.value?.showOverview?.() } else { void threeMapRef.value?.switchFloor?.(activeFloorId.value) } indoorView.value = view } ``` 3. 增加设置入口,允许用户永久禁用自动切换(可选)。 **验证标准**: - 手动切换后,10 秒内不会因缩放触发自动切换。 - 手动切换按钮始终可用。 **文件修改**: - `src/components/map/ThreeMap.vue`:增加临时禁用自动切换方法 - `src/components/navigation/GuideMapShell.vue`:调整切换按钮样式和行为 --- ### Phase 2:交互细节优化(增强) **目标**:优化自动切换的用户体验细节。 #### Task 2.1:增加视觉过渡和状态提示 **优先级**:P1 **预估工作量**:1 天 **依赖**:Task 1.1 **实现要点**: 1. 自动切换时增加淡入淡出过渡: ```typescript const transitionSwitch = async (loadFn: () => Promise) => { // 淡出当前模型 if (activeModel) { await fadeOut(activeModel, 300) } // 加载新模型 await loadFn() // 淡入新模型 if (activeModel) { await fadeIn(activeModel, 300) } } ``` 2. 切换时显示提示文案: - "正在切换到楼层视图..." - "正在切换到完整建筑..." 3. 首次自动切换时显示引导提示(Toast): - "已自动切换到楼层内部,您也可以手动控制视图" - 提示只显示一次,存储到本地缓存 **验证标准**: - 切换过程视觉流畅,无突兀感。 - 首次自动切换有引导提示。 **文件修改**: - `src/components/map/ThreeMap.vue`:增加过渡动画 - `src/pages/index/index.vue`:增加首次引导提示 --- #### Task 2.2:优化阈值和参数 **优先级**:P2 **预估工作量**:1-2 天(需要实测调优) **依赖**:Task 1.1 **实现要点**: 1. 在真实设备(手机、平板)上测试不同阈值的效果: - 建筑尺寸的 0.8x / 1.0x / 1.2x - 冷却时间 1s / 2s / 3s 2. 针对不同建筑尺寸动态调整阈值: ```typescript const calculateThresholds = (modelSize: THREE.Vector3) => { const maxDim = Math.max(modelSize.x, modelSize.y, modelSize.z, 1) // 大建筑用较大倍数,小建筑用较小倍数 const sizeFactor = maxDim > 100 ? 1.2 : 1.0 return { low: maxDim * sizeFactor * 0.9, high: maxDim * sizeFactor * 1.1 } } ``` 3. 记录切换频率和用户行为,优化参数。 **验证标准**: - 移动端测试无误触。 - 切换时机符合用户预期。 - 不会频繁切换导致加载抖动。 **文件修改**: - `src/components/map/ThreeMap.vue`:优化阈值计算 --- ### Phase 3:多层展示支持(未来) **目标**:支持单层/多层显示模式切换,适配跨层路线展示。 **前置条件**: - `route_graph` 和 `nav_data` 已接入 - 跨层路线规划能力已实现 #### Task 3.1:扩展 ViewMode 类型和多层加载逻辑 **优先级**:P3(依赖路线能力) **预估工作量**:3-4 天 **实现要点**: 1. 扩展 `ViewMode` 类型: ```typescript type ViewMode = 'overview' | 'single-floor' | 'multi-floor' ``` 2. 实现 `loadMultiFloor` 方法: ```typescript const loadMultiFloor = async (floorIds: string[]) => { activeView.value = 'multi-floor' clearSceneData() const verticalSpacing = 10 // 楼层间距 for (const [index, floorId] of floorIds.entries()) { const floor = floorIndex.value.find(f => f.floorId === floorId) if (!floor) continue const gltf = await loadModel(floorModelUrl(floor), `加载 ${floor.label}`) const model = gltf.scene model.position.y = index * verticalSpacing prepareModel(model) scene.add(model) } fitCameraToMultiFloor(floorIds) } ``` 3. 注意性能优化: - 多层模型总面数可能很大,需要监控帧率 - 考虑 LOD(细节层次)或简化模型 **验证标准**: - 可以同时加载并显示多个楼层。 - 楼层保持合理的垂直间距。 - 帧率在可接受范围(>30fps)。 **文件修改**: - `src/components/map/ThreeMap.vue`:增加多层加载逻辑 - `src/domain/guideModel.ts`:扩展 ViewMode 类型 --- #### Task 3.2:增加"单层/多层"切换控件 **优先级**:P3 **预估工作量**:1 天 **依赖**:Task 3.1 **实现要点**: 1. 在 `GuideMapShell` 增加切换控件: ```vue 单层 多层 ``` 2. 多层模式下显示楼层选择器,支持多选: - 用户可以勾选要同时显示的楼层(例如 B2、B1、1F) - 默认显示当前楼层的上下各一层 **验证标准**: - 切换到多层模式,可以选择要显示的楼层。 - 多层模式下可以看到跨层路线完整路径。 **文件修改**: - `src/components/navigation/GuideMapShell.vue`:增加多层切换控件 - `src/pages/index/index.vue`:增加多层模式状态管理 --- ## 实施优先级 ### 必须实施(Phase 1) 这些任务实现核心的自动切换能力,显著提升交互直觉性。 - Task 1.1:实现距离监听与自动切换逻辑 - Task 1.2:调整首页和 GuideMapShell 配合自动切换 - Task 1.3:保留手动切换作为兜底 **预估总工作量**:3.5-4.5 天 --- ### 建议实施(Phase 2) 这些任务优化用户体验细节,提升产品完成度。 - Task 2.1:增加视觉过渡和状态提示 - Task 2.2:优化阈值和参数 **预估总工作量**:2-3 天 --- ### 未来实施(Phase 3) 这些任务依赖跨层路线能力,优先级较低。 - Task 3.1:扩展 ViewMode 和多层加载逻辑 - Task 3.2:增加"单层/多层"切换控件 **预估总工作量**:4-5 天 **前置条件**:`route_graph` 和 `nav_data` 接入完成 --- ## 技术风险与应对 ### 风险 1:自动切换触发频繁,导致加载抖动 **影响**:用户体验差,可能导致卡顿。 **应对措施**: - 使用双阈值滞回机制(低阈值 1.0x,高阈值 1.3x) - 增加冷却时间(2 秒内不重复触发) - 增加加载锁(切换期间锁定,不响应新的切换请求) - 监听 `controls.change` 事件而不是每帧检查,减少计算频率 --- ### 风险 2:移动端误触缩放,导致意外切换 **影响**:用户可能在查看建筑外观时误触放大,意外切换到楼层。 **应对措施**: - 手动切换后临时禁用自动切换(10 秒) - 提供设置项,允许用户永久禁用自动切换 - 优化阈值,避免轻微缩放就触发 - 首次自动切换时显示引导提示,告知用户可以手动控制 --- ### 风险 3:多层模式性能问题 **影响**:同时加载多个楼层可能导致内存占用过高、帧率下降。 **应对措施**: - 限制最多同时显示 3-4 层 - 考虑使用 LOD(细节层次),远处楼层使用简化模型 - 监控帧率,低于阈值时提示用户减少显示楼层 - 多层模式下禁用部分高级渲染特性(例如阴影) --- ## 质量保证 ### 单元测试 - `ThreeMap.vue` 的距离计算和阈值判断逻辑 - 自动切换状态机测试(overview → floor → overview) - 加载锁和冷却时间逻辑测试 ### 集成测试 - 完整的用户流程:进入馆内 → 缩放 → 自动切换 → 手动切换 → 楼层切换 - 自动切换与手动切换的交互测试 - 多层模式与单层模式切换测试 ### 移动端测试 - 在真实移动设备(iOS/Android)测试缩放手势 - 测试误触场景 - 测试弱网环境下的加载体验 ### 性能测试 - 监控切换过程的内存占用 - 监控多层模式的帧率 - 测试大建筑和小建筑的阈值适配性 --- ## 验收标准 ### Phase 1 验收标准 - [ ] 用户在建筑外观放大到一定距离,自动切换到默认楼层(L1) - [ ] 用户在楼层内部缩小到一定距离,自动切换回建筑外观 - [ ] 快速缩放不会触发多次加载 - [ ] 手动切换后 10 秒内不会自动切换 - [ ] 全馆模式下可以直接点击楼层控件选择楼层 - [ ] 移动端测试无明显误触 ### Phase 2 验收标准 - [ ] 切换过程有视觉过渡,无突兀感 - [ ] 首次自动切换有引导提示 - [ ] 切换时有 loading 状态提示 - [ ] 阈值在真实设备上测试符合预期 ### Phase 3 验收标准 - [ ] 可以切换到多层模式,同时显示多个楼层 - [ ] 多层模式帧率 >30fps - [ ] 多层模式下可以看到跨层路线完整路径 --- ## 附录:配置项设计 ### ThreeMap 组件新增 Props ```typescript interface ThreeMapProps { // ... 现有 props // 自动切换配置 autoSwitch?: boolean // 是否启用自动切换,默认 true autoSwitchThresholdLow?: number // 下阈值倍数,默认 1.0 autoSwitchThresholdHigh?: number // 上阈值倍数,默认 1.3 autoSwitchCooldown?: number // 冷却时间(毫秒),默认 2000 // 多层模式配置(Phase 3) enableMultiFloor?: boolean // 是否启用多层模式,默认 false multiFloorVerticalSpacing?: number // 楼层间距(米),默认 10 } ``` ### 新增 Events ```typescript // ThreeMap emit 的新事件 emit('auto-switch', { from: 'overview' | 'floor', to: 'overview' | 'floor', trigger: 'zoom-in' | 'zoom-out', distance: number }) emit('auto-switch-blocked', { reason: 'loading-locked' | 'cooldown' | 'disabled' }) ``` --- ## 参考资料 - OrbitControls 文档:https://threejs.org/docs/#examples/en/controls/OrbitControls - Three.js 性能优化最佳实践:https://threejs.org/manual/#en/optimize-lots-of-objects - 馆内导览产品参考:机场导览 App、商场导览 App、博物馆 3D 导览 --- ## 变更记录 | 日期 | 版本 | 变更内容 | 作者 | |------|------|---------|------| | 2026-06-12 | v1.0 | 初始版本 | Claude |