Files
frontend-miniapp/docs/室内导览交互优化改进计划.md
lyf 8fed715235
Some checks failed
CI / verify (push) Has been cancelled
chore: sync latest project updates
2026-07-03 14:42:38 +08:00

15 KiB
Raw Blame History

馆内导览交互优化改进计划

文档信息

  • 项目:深圳自然博物馆智能导览应用
  • 模块:馆内 3D 导览交互
  • 创建时间2026-06-12
  • 状态:待评审

背景

当前馆内导览采用显式"全馆/楼层"手动切换模式,用户需要点击按钮在"建筑外观"和"楼层内部"之间切换。这个模式功能完整,但与基于缩放距离的自动切换模式相比,交互直觉性较弱。

现有模式

  • 进入馆内 3D → 加载建筑外观
  • 用户手动点击"楼层"按钮 → 楼层控件出现 → 选择楼层 → 加载楼层内部
  • 用户缩放只改变视角距离,不触发模型切换

目标模式

  • 进入馆内 3D → 加载建筑外观
  • 用户放大到一定距离 → 自动切换到楼层内部
  • 用户缩小到一定距离 → 自动切换回建筑外观
  • 保留手动控制入口作为兜底

改进目标

  1. 增加基于缩放距离的自动视角切换,提升交互直觉性。
  2. 保留手动切换入口,避免误触和性能抖动。
  3. 优化楼层控件可见性,缩短操作路径。
  4. 为未来多层展示预留架构空间(不在本次实施)。

改进任务分解

Phase 1基础自动切换能力核心

目标:实现基于缩放距离的建筑外观 ↔ 楼层内部自动切换。

Task 1.1:在 ThreeMap 组件实现距离监听与自动切换逻辑

优先级P0
预估工作量2-3 天
风险:中等(需要调优阈值和滞回参数)

实现要点

  1. 监听 OrbitControlschange 事件,而不是每帧检查:

    controls.addEventListener('change', () => {
      throttledCheckAutoSwitch()
    })
    
  2. 实现双阈值滞回机制,避免反复切换:

    const autoSwitchConfig = {
      thresholdLowFactor: 1.0,   // 放大到建筑尺寸 1.0 倍时切换到楼层
      thresholdHighFactor: 1.3,  // 缩小到建筑尺寸 1.3 倍时切换回全馆
      cooldownMs: 2000,          // 切换后冷却 2 秒
      enableAuto: true           // 可配置开关
    }
    
  3. 增加加载锁和冷却时间:

    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. 切换时触发事件通知上层:

    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. 监听 ThreeMapauto-switch 事件,同步 indoorView 状态:

    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 秒):

    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. 自动切换时增加淡入淡出过渡:

    const transitionSwitch = async (loadFn: () => Promise<void>) => {
      // 淡出当前模型
      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. 针对不同建筑尺寸动态调整阈值:

    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_graphnav_data 已接入
  • 跨层路线规划能力已实现

Task 3.1:扩展 ViewMode 类型和多层加载逻辑

优先级P3依赖路线能力
预估工作量3-4 天

实现要点

  1. 扩展 ViewMode 类型:

    type ViewMode = 'overview' | 'single-floor' | 'multi-floor'
    
  2. 实现 loadMultiFloor 方法:

    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 增加切换控件:

    <view v-if="mapType === 'indoor' && indoorView === 'floor'" class="floor-display-mode">
      <view class="mode-item" :class="{ active: floorDisplayMode === 'single' }">
        <text>单层</text>
      </view>
      <view class="mode-item" :class="{ active: floorDisplayMode === 'multi' }">
        <text>多层</text>
      </view>
    </view>
    
  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_graphnav_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

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

// 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'
})

参考资料


变更记录

日期 版本 变更内容 作者
2026-06-12 v1.0 初始版本 Claude