# VR票务详情页面 UniApp 移植规划文档

> 创建时间：2026-05-13  
> 状态：**Phase 3 导航优化完成（防闪烁/缓存预检查）**

---

## 📌 背景与目标

### 背景
- 后端 VR Ticket 插件 (`vr_ticket`) 已实现票务商品详情页模板 `ticket_detail.html`
- 前端参考项目 [show-start](file:///Users/bigemon/WorkSpace/vr-shopxo-uniapp/references/show-start/src/App.vue) 提供了高质量的 UI 设计
- 需要将参考项目的 UI 移植到 UniApp 环境中，并整合票务商品的4维选择逻辑

### 用户需求
1. **保持 show-start 的 popup 交互模式** 作为购票弹窗基础
2. **点击"立即购票"按钮** 后弹出购票弹窗
3. 弹窗内容包含：场次选择、场馆/演播室/分区选择、"选座"按钮
4. **选座功能**：独立的全屏遮罩座位选择器，选完后返回已选座位 tags

---

## 📋 数据结构规范（Phase 2 核心）

### VR 票务扩展字段
从后端 API 返回的商品扩展数据中，票务商品会包含以下关键字段：

```typescript
interface VRTicketGoods {
  id: number;
  title: string;
  images: string[];
  is_vr_ticket: 1;  // 票务商品标识
  
  // VR 票务扩展数据（来自 vr_config 或 extension_data）
  vr_config?: {
    // 场次规格列表（从 goods_spec_data 解析）
    spec_list?: Array<{
      spec_name: string;    // 场次名称，如 "2026-06-01 14:00"
      price: number;    // 价格
      inventory: number; // 库存
    }>;
    
    // 座位规格映射（从 seat_spec_map 解析）
    seat_spec_map?: Record<string, {
      spec: Array<{ type: string; value: string }>;  // 4维规格
      price: number;
      inventory: number;
      section: { name: string; color: string };
    }>;
    
    // 座位模板（座位图数据）
    seat_template?: {
      venue: { name: string; address: string; location: { lng: string; lat: string } };
      rooms: Array<{
        id: string;
        name: string;
        map: string[];  // 座位矩阵，如 ["AAAAA", "AAB__AA"]
        sections: Array<{ char: string; name: string; price: number; color: string }>;
      }>;
    };
  };
}
```

### 4维规格体系
票务商品的选座流程采用 **4维规格级联选择**：

| 维度 | 字段名 | 说明 | 示例 |
|------|--------|------|------|
| 1 | `$vr-场次` | 演出场次/时间 | "2026-06-01 14:00" |
| 2 | `$vr-场馆` | 演出场馆 | "北京凯迪拉克中心" |
| 3 | `$vr-演播室` | 室内演出厅 | "主要展厅" |
| 4 | `$vr-分区` | 座位分区 | "VIP区"、"普通区" |

**选择级联逻辑**：选择场次 → 筛选可用场馆 → 选择场馆 → 筛选可用演播室 → 选择演播室 → 筛选可用分区 → 选择分区 → 加载座位图

---

## 📐 UI/UX 设计概览

### 页面结构
```
┌─────────────────────────────────────┐
│  Header Banner (海报 + 标题 + 收藏) │
├─────────────────────────────────────┤
│  Location Card (最近场馆)           │
├─────────────────────────────────────┤
│  Service Tags (服务说明)            │
├─────────────────────────────────────┤
│  演出详情 Section                   │
├─────────────────────────────────────┤
│  购票须知 Section                   │
├─────────────────────────────────────┤
│  观演须知 Section                   │
├─────────────────────────────────────┤
│  Bottom Bar (客服 + 立即购票)       │  ← Fixed 底部
└─────────────────────────────────────┘
```

### 购票弹窗 Popup 交互（核心功能区）
```
┌─────────────────────────────────────┐
│  [场次选择 - 横向卡片滚动]          │  ← vr-session-grid
├─────────────────────────────────────┤
│  [选择场馆]                       │  ← vr-booking-block
├─────────────────────────────────────┤
│  [选择演播室] → [选择分区]        │  ← 级联选择
├─────────────────────────────────────┤
│  [选座] 按钮 ← 打开座位选择器     │
│                                     │
│  未选座时：尚未选择 [立刻选座]  │
│  已选座时：                      │
│    ┌─────┐ ┌─────┐ ┌─────┐    │
│    │ A1  │ │ A2  │ │ A3  │    │  ← 已选座位 tags
│    └─────┘ └─────┘ └─────┘    │
│    【重新选座】                  │
├─────────────────────────────────────┤
│     合计: ¥888  [确认购票]       │  ← 底部购买栏
└─────────────────────────────────────┘
```

### 座位选择器（全屏遮罩）
```
┌─────────────────────────────────────┐
│  ← 返回  选择座位 [已完成 3 座]    │
├─────────────────────────────────────┤
│  🎵  舞  台                    │  ← 舞台指示
├─────────────────────────────────────┤
│  A  ■ ■ ■ ■ ■                 │  ← 座位行（A排）
│  B  ■ ■ ■ ■ ■ ■ ■           │  ← 可用座位：■ 点击选中
│  C  ■ _ _ ■ ■ ■             │  ← 过道：_ 
│  D  ■ ■ ■ ■ ■             │  ← 已售：灰色
├─────────────────────────────────────┤
│  图例: [VIP] [普通] [已售]        │
└─────────────────────────────────────┘
```

### 座位状态定义
- **可用座位**：可点击选择，带分区颜色
- **已选座位**：高亮边框，数字标识
- **已售座位**：灰色，不可点击
- **过道/空位**：占位符，不渲染

---

## 🔄 阶段进展记录

### Phase 1: 基础 UI 移植 ✅ 已完成
- [x] 在 `pages.json` 中注册新页面路由
- [x] 创建 `pages/goods-vr-ticket/` 目录
- [x] 搬运 `App.vue` 内容到 `goods-vr-ticket.vue`
- [x] 适配 UniApp 语法（scrollable、navigation 等）
- [x] 替换内联 SVG → iconfont 组件（兼容��信小程序）
- [x] 添加 popup 容器左右留白（padding: 16px）
- [x] 修复 popup-content 溢出问题（overflow-x, word-break）

### Phase 2: 购票弹窗与4维选择（已完成）
- [x] 购票弹窗基础结构（当前 popupType='buy'）
- [x] 接入商品 Tree API 数据（vr_config 已废弃，使用 Tree API）
- [x] 场次选择器实现（级联选择）
- [x] 场馆选择器实现
- [x] 演播室/分区级联选择
- [x] 座位选择器组件开发
- [x] 已选座位 UI 展示
- [x] 底部总价计算

### Phase 3: 完整购票流程（开发中）
- [ ] 观演人信息表单（每座必填）
- [ ] 订单提交 API 集成
- [ ] 跳转支付流程

### Phase 4: 优化与测试
- [ ] 滚动穿透处理（catchtouchmove）
- [ ] 真机/小程序测试
- [ ] 性能优化

---

## 📝 待办事项

### ✅ 已完成
- [x] 在 `pages.json` 中注册新页面路由
- [x] 创建 `pages/goods-vr-ticket/` 目录
- [x] 搬运 `App.vue` 内容到 `goods-vr-ticket.vue`
- [x] 适配 UniApp 语法（scrollable、navigation 等）
- [x] 替换内联 SVG → iconfont 组件（兼容微信小程序）
- [x] 添加 popup 容器左右留白（padding: 16px）
- [x] 修复 popup-content 溢出问题（overflow-x, word-break）
- [x] 购票弹窗基础框架（popupType='buy' 判断）

### ⏳ 后续待办
- [x] 在 `goods-detail.vue` 中添加跳转判断逻辑
- [x] 解析商品数据中的 vr_config 等扩展字段 (已改为使用 Tree API)
- [x] 实现场次选择器（级联卡片）
- [x] 实现场馆选择器（场次筛选后可用）
- [x] 实现演播室→分区级联选择
- [x] 实现选座按钮与座位选择器（全屏遮罩）
- [x] 实现已选座位 tags 展示
- [x] 实现重新选座功能
- [ ] 连接后端 BuyService API 获取动态票务数据
- [x] 实现底部购买栏联动（已选座数、总价）
- [x] 添加 popup 滚动事件处理（:catchtouchmove）
- [ ] 观演人信息表单（姓名/手机/身份证）
- [ ] 订单提交入口
- [ ] 测试页面在真机/小程序环境运行

---

## 🔌 API 接口规范

### 商品详情接口（扩展字段）
请求商品详情时，后端返回 `vr_config` 扩展数据：

```javascript
// GET /api/goods/detail?id=xxx
{
  "code": 0,
  "data": {
    "id": 100,
    "title": "王一浩「To U」巡演北京收官站",
    "images": "[\"xxx.jpg\"]",
    "is_vr_ticket": 1,
    // VR 票务扩展
    "vr_config": {
      "goods_spec_data": [
        { "spec_name": "2026-06-01 14:00", "price": 580, "inventory": 100 },
        { "spec_name": "2026-06-01 20:00", "price": 680, "inventory": 50 }
      ],
      "seat_spec_map": {
        "room_001_A_1": {
          "spec": [
            { "type": "$vr-场次", "value": "2026-06-01 14:00" },
            { "type": "$vr-场馆", "value": "北京凯迪拉克中心" },
            { "type": "$vr-演播室", "value": "主要展厅" },
            { "type": "$vr-分区", "value": "VIP区" }
          ],
          "price": 580,
          "inventory": 1,
          "section": { "name": "VIP区", "color": "#ff4d4f" }
        }
      },
      "vr_seat_template": {
        "venue": { "name": "北京凯迪拉克中心", "address": "...", "location": { "lng": "116.4", "lat": "39.9" } },
        "rooms": [...]
      }
    }
  }
}
```

### 订单提交接口
```javascript
// POST /api/buy/add
{
  "goods_data": [
    {
      "goods_id": 100,
      "spec": [...],        // 4维规格数组
      "stock": 1,
      "order_base": {
        "extension_data": {
          "attendee": {
            "real_name": "张三",
            "phone": "13800138000",
            "id_card": "110101199001011234"
          }
        }
      }
    }
  ],
  "buy_type": "goods",
  "address_id": "0",
  "site_model": "2"
}
```

---

## 🛠️ 技术实现要点

### 1. 4维规格筛选逻辑
参考 `ticket_detail.html` 中的 `filterSeats` 方法：

```javascript
// 根据当前选择的4维过滤可用座位
filterSeats: function() {
  var matchSession = this.currentSession != null;
  var matchVenue = this.currentVenue != null;
  var matchRoom = this.currentRoom != null;
  var matchSection = this.currentSection != null;
  
  // 遍历所有座位，检查是否满足当前选择条件
  for (var i = 0; i < seatInfo.spec.length; i++) {
    if (seatInfo.spec[i].type === '$vr-场次' && seatInfo.spec[i].value === this.currentSession) {
      matchSession = true;
    }
    // ... 同理其他维度
  }
}
```

### 2. 座位状态管理
- `selectedSeats[]`：已选座位数组
- `soldSeats{}`：已售座位映射
- 切换场次时清空已选座位

### 3. 级联选择
- 选择「场次」后 → 重置「场馆/演播室/分区」，重新计算可选场馆
- 选择「场馆」后 → 筛选出��场馆下的演播室
- 选择「演播室」后 → 筛选出该演播室下的分区，显示分区选择器

### 4. 座位渲染
座位图使用字符矩阵渲染：
- `A`/`B`/...：座位字符
- `_`：过道/空位

---

## 📦 文件结构

```
pages/goods-vr-ticket/
├── goods-vr-ticket.vue        # 主页面（已移植 Phase 1）
├── goods-vr-ticket.css      # 独立样式（可选）
└── components/
    ├── vr-session-select/   # 场次选择器组件
    ├── vr-venue-select/   # 场馆选择器组件
    ├── vr-seat-selector/   # 座位选择器（全屏遮罩）
    └── vr-attendee-form/   # 观演人表单
```

---

## 🔗 相关参考

| 文件 | 说明 |
|------|------|
| [references/show-start/src/App.vue](file:///Users/bigemon/WorkSpace/vr-shopxo-uniapp/references/show-start/src/App.vue) | 源 UI 参考（Vue 2） |
| [pages/goods-detail/goods-detail.vue](file:///Users/bigemon/WorkSpace/vr-shopxo-uniapp/pages/goods-detail/goods-detail.vue) | 商品详情页（跳转入口） |
| [vr_ticket/ticket_detail.html](file:///Users/bigemon/WorkSpace/vr-shopxo-plugin/shopxo/app/plugins/vr_ticket/view/goods/ticket_detail.html) | 后端票务模板参考（4维选择+座位图） |
| [pages.json](file:///Users/bigemon/WorkSpace/vr-shopxo-uniapp/pages.json) | 页面路由配置 |

---

## 🎯 关键文件

| 文件 | 状态 | 说明 |
|------|------|------|
| pages/goods-vr-ticket/goods-vr-ticket.vue | ✅ 已移植 | 主页面（Phase 1 完成） |
| pages/goods-detail/goods-detail.vue | ⏳ 待修改 | 添加 is_vr_ticket 跳转判断 |
| components/iconfont/iconfont.vue | ✅ 已加固 | iconfont 组件 |

---

> ⚠️ **注意**：当前 Phase 2 正在开发中，核心为 4维规格选择器 + 座位选择器。Phase 3 将实现观演人表单和订单提交。座时：尚未选择 [立刻选座]      │
│  已选座时：                         │
│    [A区-2排-3号] [A区-2排-4号]      │
│    【重新选座】                     │
├─────────────────────────────────────┤
│         [确认购票]                 │
└─────────────────────────────────────┘

点击[选座] → 打开座位选择器（全屏遮罩）
```

---

## 🗂️ 文件结构（Phase 1 完成后）

```
pages/goods-vr-ticket/
├── goods-vr-ticket.vue        # 主页面（移植自 App.vue）
└── goods-vr-ticket.css        # 独立样式文件（可选）
```

---

## 📝 待办事项

### ✅ 已完成
- [x] 在 `pages.json` 中注册新页面路由
- [x] 创建 `pages/goods-vr-ticket/` 目录
- [x] 搬运 `App.vue` 内容到 `goods-vr-ticket.vue`
- [x] 适配 UniApp 语法（scrollable、navigation 等）
- [x] 替换内联 SVG → iconfont 组件（兼容微信小程序）
- [x] 添加 popup 容器左右留白（padding: 16px）
- [x] 修复 popup-content 溢出问题（overflow-x, word-break）

### ⏳ 后续待办
- [ ] 在 `goods-detail.vue` 中添加跳转判断逻辑
- [ ] 对 商品数据里的vr_config 等数据进行解析，
- [ ] 实现购票弹窗 Popup 交互，移植老的4 维规格选择到新的购票弹窗 Popup 中。
- [ ] 实现购票弹窗内的选座逻辑
- [ ] 连接后端 BuyService API（动态票务数据）
- [ ] 优化 popup 滚动事件处理（:catchtouchmove）
- [ ] 测试页面在真机/小程序环境运行

---

## 🔄 阶段进展记录

### 2026-05-13 样式迁移完成
- ✅ 移除 inline SVG，改用 iconfont 组件
- ✅ map-icon 容器添加边框
- ✅ venue-popup-info 添加地址图标（icon-location）
- ✅ popup-container 添加 padding: 0 16px
- ✅ popup-content 修复溢出（word-break, box-sizing）

### 2026-05-14 导航优化完成
- ✅ goods-detail.vue 添加白色遮罩（初始覆盖，200ms后渐变消失）
- ✅ 添加缓存预检查（快速判断VR票务，无需等待API）
- ✅ goods-vr-ticket.vue 加载遮罩 + pageShow 显示控制
- ✅ 修复返回导航：智能判断页面栈，无历史则跳转首页
- ✅ goods-detail 使用 redirectTo 替代 navigateTo，避免循环

### 关键文件
| 文件 | 状态 |
|------|------|
| pages/goods-vr-ticket/goods-vr-ticket.vue | ✅ 已移植 |
| pages/goods-vr-ticket/goods-vr-ticket.css | ✅ 已移植 |
| pages/goods-vr-ticket/components/ticket-header/index.vue | ✅ 已移植 |
| pages/goods-vr-ticket/components/venue-card/index.vue | ✅ 已移植 |
| pages/goods-vr-ticket/components/ticket-popup/index.vue | ✅ 已移植 |
| components/iconfont/iconfont.vue | ✅ 已加固尺寸 |
| pages/goods-detail/goods-detail.vue | ✅ 已加固导航 |

---

## 🔗 相关参考

| 文件 | 说明 |
|------|------|
| [references/show-start/src/App.vue](file:///Users/bigemon/WorkSpace/vr-shopxo-uniapp/references/show-start/src/App.vue) | 源 UI 参考（Vue 2） |
| [pages/goods-detail/goods-detail.vue](file:///Users/bigemon/WorkSpace/vr-shopxo-uniapp/pages/goods-detail/goods-detail.vue) | 商品详情页（跳转入口） |
| [vr_ticket/ticket_detail.html](file:///Users/bigemon/WorkSpace/vr-shopxo-plugin/shopxo/app/plugins/vr_ticket/view/goods/ticket_detail.html) | 后端票务模板参考 |
| [pages.json](file:///Users/bigemon/WorkSpace/vr-shopxo-uniapp/pages.json) | 页面路由配置 |

---

> ⚠️ **注意**：当前为 Phase 1 规划，仅实现初步移植和测试环境搭建。后续 Phase 2-4 将逐步实现座位选择器、4维规格选择、完整购票流程等高级功能。
