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

545 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 馆内导览交互优化改进计划
## 文档信息
- **项目**:深圳自然博物馆智能导览应用
- **模块**:馆内 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<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. 针对不同建筑尺寸动态调整阈值:
```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
<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_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 |