vr-shopxo-uniapp/docs/vr-ticket-integration-plan.md

17 KiB
Raw Blame History

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

创建时间2026-05-13
状态:Phase 3 导航优化完成(防闪烁/缓存预检查)


📌 背景与目标

背景

  • 后端 VR Ticket 插件 (vr_ticket) 已实现票务商品详情页模板 ticket_detail.html
  • 前端参考项目 show-start 提供了高质量的 UI 设计
  • 需要将参考项目的 UI 移植到 UniApp 环境中并整合票务商品的4维选择逻辑

用户需求

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

📋 数据结构规范Phase 2 核心)

VR 票务扩展字段

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

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 移植 已完成

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

Phase 2: 购票弹窗与4维选择已完成

  • 购票弹窗基础结构(当前 popupType='buy'
  • 接入商品 Tree API 数据vr_config 已废弃,使用 Tree API
  • 场次选择器实现(级联选择)
  • 场馆选择器实现
  • 演播室/分区级联选择
  • 座位选择器组件开发
  • 已选座位 UI 展示
  • 底部总价计算

Phase 3: 完整购票流程(开发中)

  • 观演人信息表单(每座必填)
  • 订单提交 API 集成
  • 跳转支付流程

Phase 4: 优化与测试

  • 滚动穿透处理catchtouchmove
  • 真机/小程序测试
  • 性能优化

📝 待办事项

已完成

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

后续待办

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

🔌 API 接口规范

商品详情接口(扩展字段)

请求商品详情时,后端返回 vr_config 扩展数据:

// 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": [...]
      }
    }
  }
}

订单提交接口

// 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 方法:

// 根据当前选择的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. 级联选择

  • 选择「场次」后 → 重置「场馆/演播室/分区」,重新计算可选场馆
  • 选择「场馆」后 → 筛选出<E98089><E587BA>场馆下的演播室
  • 选择「演播室」后 → 筛选出该演播室下的分区,显示分区选择器

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 源 UI 参考Vue 2
pages/goods-detail/goods-detail.vue 商品详情页(跳转入口)
vr_ticket/ticket_detail.html 后端票务模板参考4维选择+座位图)
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维规格选择、完整购票流程等高级功能。