# 导览集成指南

本文档面向**接入众趣 zqsdk 的开发者**，说明如何在自己的项目中实现「导览」功能。导览即按预设场景顺序自动漫游并讲解，你的项目需要：在初始化时判断是否支持导览、监听进度与暂停事件、在用户操作时调用开始/暂停/跳转方法，并实现导览入口与场景列表 UI。

---

## 一、功能简介与前置条件

### 1.1 什么是导览

导览是 SDK 提供的**自动漫游**能力：按后台配置的「场景」（如客厅、主卧、厨房等）顺序依次飞行并停留。你的项目需要：

- 在 `init_UI` 中根据模型数据判断**当前模型是否支持导览**；
- **监听 SDK 事件**以更新当前场景索引与播放状态；
- **调用 SDK 方法**实现开始、暂停、跳转到指定场景；
- 提供**导览入口、场景列表、播放/暂停与进度**等 UI（样式可完全自定义）。

### 1.2 展示效果
![导览展示效果](../../screenshot/scene-tour/导览.png)

### 1.3 前置条件

- 已接入众趣 zqsdk，并在 `zqsdk.init` 的 `complete` 回调中拿到 `window.housePlay`（或等价实例）。
- 模型在众趣后台已配置导览场景；支持导览的模型会在初始化时提供 `heroLocations`。
- 导览与讲房**互不排斥**：同一模型可同时具备导览和讲房，需分别根据 `heroLocations` 与 `vr_speak_data` 判断。

---

## 二、集成步骤概览

| 步骤 | 内容 |
|------|------|
| 1 | 在 `init_UI` 中根据 `heroLocations` 判断是否支持导览，并初始化你的「导览场景列表」 |
| 2 | 在 housePlay 上注册 `stopTour`、`updateTour`，将播放状态与当前场景索引同步到你的状态 |
| 3 | 在用户操作时调用 `play()` / `pause()` / `gotoScenebyId(index)` |
| 4 | 实现导览入口、场景列表、播放/暂停按钮等 UI |

以下按步骤展开。

---

## 三、第一步：判断模型是否支持导览

**时机**：在 `housePlay.on('init_UI', ...)` 回调中执行。

**做法**：从 `housePlay.model.heroLocations` 读取场景数组。若存在且长度大于 0，则当前模型支持导览。建议过滤掉「总述」或仅作脚本用的项（例如 `script === 1` 或 `name === '总述'`），只保留需要展示给用户的场景。

```javascript
housePlay.on('init_UI', function(model) {
  let heroLocations = model.heroLocations
  if (!heroLocations || !heroLocations.length) return

  let list = []
  for (let i = 0; i < heroLocations.length; i++) {
    let scene = heroLocations[i]
    // 过滤总述、脚本项等，按业务需要调整
    if (!scene || !scene.name || scene.name === '总述' || scene.script === 1) continue
    list.push({ name: scene.name, index: i })
  }

  if (list.length) {
    yourApp.setTourAvailable(true)
    yourApp.initSceneList(list)
  }
})
```

**场景项建议**：每条保留 `name`（展示用）和 `index`（传给 `gotoScenebyId` 的 id），与 SDK 文档中的「目标导览 index」一致。

---

## 四、第二步：准备导览状态

建议在你自己项目中维护至少以下状态（名称可自定）：

| 状态 | 含义 | 建议更新方式 |
|------|------|----------------|
| 导览是否可用 | 当前模型是否有导览数据 | 仅在 `init_UI` 中根据 `heroLocations` 设置 |
| 导览场景列表 | 展示用名称 + index | `init_UI` 中初始化 |
| 当前场景索引 | 正在播放到的场景 index | 由 `updateTour` 的 `destinationItem` 或用户点击场景时更新 |
| 是否正在播放导览 | 与 SDK 实际状态一致 | **仅由 `stopTour` 回调更新为 false**；用户点击「开始」时先调 SDK，再由事件回写 |

---

## 五、第三步：注册 SDK 事件并同步到你的状态

在 housePlay 可用后注册以下导览事件，并**仅在这些回调中**更新「是否正在播放」「当前场景索引」。

```javascript
// 导览暂停（用户点击暂停或 SDK 结束导览时触发）
housePlay.on('stopTour', function() {
  yourApp.setTourPlaying(false)
})

// 导览进度更新：当前播放到的场景 index
housePlay.on('updateTour', function(describe) {
  if (describe && typeof describe.destinationItem === 'number') {
    yourApp.setCurrentSceneIndex(describe.destinationItem)
  }
})
```

注意：**不要**在用户点击「开始导览」时仅本地把「是否正在播放」设为 true；应先调 `housePlay.play()`，由 `updateTour` 等反馈进度，`stopTour` 时再设为 false，以保证与 SDK 一致。

---

## 六、第四步：在用户操作时调用 SDK 方法

SDK 提供三个与导览相关的方法（均在 `housePlay` 上调用）：

| 方法 | 说明 | 调用时机建议 |
|------|------|--------------|
| `housePlay.play()` | 开始导览 | 用户点击「开始导览」或控制条上的「播放」 |
| `housePlay.pause()` | 暂停导览 | 用户点击「暂停」 |
| `housePlay.gotoScenebyId(index)` | 跳转到指定场景 | 用户点击场景列表某一项时 |

**推荐交互逻辑**：

- **用户点击「导览」入口**：展示导览面板/场景列表；若直接开始播放则调用 `housePlay.play()`。
- **用户点击「播放」**：调用 `housePlay.play()`。
- **用户点击「暂停」**：调用 `housePlay.pause()`；播放状态由 `stopTour` 回写为 false。
- **用户点击某场景**：先 `yourApp.setCurrentSceneIndex(index)`（可选，用于高亮），再调用 `housePlay.gotoScenebyId(index)`；若当前在播放，SDK 会跳转到该场景并继续；若未播放，仅跳转不自动播放（以 SDK 实际行为为准）。

---

## 七、第五步：实现导览 UI

UI 完全由你自定义，建议具备：

1. **导览入口**  
   显示条件：SDK 已就绪且当前模型有 `heroLocations`（即「导览可用」为 true），且未在讲房等独占模式下。点击后展示导览面板或直接开始播放。

2. **导览面板/列表**  
   - 场景列表：根据 `sceneList` 渲染，每项显示 `name`，点击时调用 `gotoScenebyId(item.index)`。  
   - 播放/暂停按钮：对应 `housePlay.play()` / `housePlay.pause()`。  
   - 当前播放到的场景：用 `currentSceneIndex` 高亮或标记。

3. **与讲房的关系**  
   若同一页面同时有导览和讲房，建议在讲房面板打开时隐藏导览入口（或反之），避免两个自动播放能力同时开启造成混淆。

---

## 八、API 速查表

### 8.1 方法（housePlay）

| 方法 | 说明 |
|------|------|
| `housePlay.play()` | 开始导览 |
| `housePlay.pause()` | 暂停导览 |
| `housePlay.gotoScenebyId(index)` | 跳转到指定导览场景；index 为场景在 heroLocations 中的索引 |

### 8.2 事件（housePlay.on）

| 事件 | 回调参数 | 说明 |
|------|----------|------|
| `stopTour` | 无 | 导览暂停或结束，应将「是否正在播放」设为 false |
| `updateTour` | `describe` | `describe.destinationItem` 为当前播放到的场景 index |

### 8.3 判断导览是否可用

- 在 `init_UI` 中读取 `housePlay.model.heroLocations`，存在且过滤后长度大于 0 即表示支持导览。

---

## 九、常见问题与注意事项

1. **播放状态以 stopTour 为准**  
   仅在 `stopTour` 回调中将「是否正在播放」设为 false，避免与 SDK 不同步。

2. **方法名与兼容性**  
   部分环境可能暴露为 `play` / `pause` / `gotoScenebyId`，调用前可用 `housePlay.play != null` 等方式做存在性判断。

3. **setPlaySpeed**  
   SDK 文档中另有 `setPlaySpeed(number)` 设置导览倍速，建议不做设置，以免影响体验。

4. **与讲房独立**  
   导览与讲房可同时存在于同一模型，分别用 `heroLocations` 和 `vr_speak_data` 判断即可；UI 上可同时展示两个入口，或根据产品需求互斥显示。

---

以上完成即可在你自己的项目中实现导览功能。若需参考本仓库实现，可参阅 `src/stores/scene.ts`、`src/stores/vr.ts` 中的 init_UI 导览初始化与 stopTour/updateTour 注册，以及 `src/modules/pc/NestScenePanel.vue`。
