12 KiB
12 KiB
实施路线图
规划时间:2026-04-14 目标:基于 ShopXO 的 VR 演唱会票务 MVP
一、整体时间估算
| 阶段 | 内容 | 人天 | 可并行 | 累计 |
|---|---|---|---|---|
| Phase 0 | 环境搭建 + 插件骨架 | 2天 | — | 2天 |
| Phase 1 | 数据库设计 + 迁移 | 2天 | ✅ Phase 0 | 2天 |
| Phase 2 | 场次管理 CRUD + API | 3天 | ✅ Phase 1 | 3天 |
| Phase 3 | 下单钩子 + 观演人收集 | 3天 | ✅ Phase 2 | 4天 |
| Phase 4 | 支付回调 + QR 票生成 | 2天 | ✅ Phase 3 | 5天 |
| Phase 5 | uni-app 票务页面 | 3天 | ✅ Phase 3 | 6天 |
| Phase 6 | B 端核销页 + API | 2天 | ✅ Phase 4 | 6天 |
| Phase 7 | 联调 + 测试 + 部署 | 3天 | 需串行 | 9天 |
预估:Agent 集群并行 1-2 周 MVP,3 周完整流程
二、Phase 0 — 环境搭建
目标
本地跑通 ShopXO + shopxo-uniapp 开发环境
任务
-
Docker 部署 ShopXO(参考
DEPLOYMENT.md)- PHP 8.0+ / MySQL 5.7+ / nginx
- 或使用虚拟主机安装包
-
安装 shopxo-uniapp
- HBuilderX 导入项目
- 配置
request_url和static_url - 本地 H5 预览验证
-
创建插件骨架
mkdir -p app/plugins/vr_ticket/ cp plugin.json app/plugins/vr_ticket/ mkdir -p app/plugins/vr_ticket/{service,view,Admin/Controller,Api/Controller} mkdir -p static/vr_ticket/ mkdir -p database/migrations/ -
在 ShopXO 后台安装插件
- 访问
/admin/plugins/index - 上传插件 zip 或手动放置到
app/plugins/vr_ticket/ - 点击安装
- 访问
验收
- ShopXO H5 前端正常访问
- shopxo-uniapp H5 预览正常
- 插件在后台可见
三、Phase 1 — 数据库设计
任务
创建插件迁移文件:
-- database/migrations/001_create_vr_events.sql
CREATE TABLE `vr_events` (
`id` int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`goods_id` int UNSIGNED NOT NULL COMMENT 'ShopXO商品ID',
`name` varchar(255) NOT NULL COMMENT '活动名称',
`venue` varchar(255) COMMENT '场馆',
`cover_image` varchar(255) COMMENT '封面图',
`status` tinyint DEFAULT 1 COMMENT '状态(0禁用, 1启用)',
`created_at` int UNSIGNED DEFAULT 0,
`updated_at` int UNSIGNED DEFAULT 0,
KEY `goods_id` (`goods_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- database/migrations/002_create_vr_sessions.sql
CREATE TABLE `vr_sessions` (
`id` int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`event_id` int UNSIGNED NOT NULL,
`session_time` datetime NOT NULL COMMENT '场次时间',
`total_stock` int UNSIGNED DEFAULT 0 COMMENT '总库存',
`available_stock` int UNSIGNED DEFAULT 0 COMMENT '可用库存',
`price` decimal(10,2) UNSIGNED DEFAULT 0 COMMENT '票价',
`status` tinyint DEFAULT 1,
`created_at` int UNSIGNED DEFAULT 0,
`updated_at` int UNSIGNED DEFAULT 0,
KEY `event_id` (`event_id`),
KEY `session_time` (`session_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- database/migrations/003_create_vr_tickets.sql
CREATE TABLE `vr_tickets` (
`id` int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`order_id` int UNSIGNED NOT NULL COMMENT '订单ID',
`order_no` char(60) NOT NULL,
`goods_id` int UNSIGNED NOT NULL,
`user_id` int UNSIGNED NOT NULL,
`event_id` int UNSIGNED NOT NULL,
`session_id` int UNSIGNED NOT NULL,
`ticket_code` char(36) NOT NULL COMMENT 'UUID票码',
`qr_data` text COMMENT '加密QR内容',
`seat_info` varchar(255) COMMENT '座位信息',
`real_name` varchar(60) COMMENT '观演人姓名',
`phone` char(15) COMMENT '手机号',
`verify_status` tinyint DEFAULT 0 COMMENT '0未核销, 1已核销',
`verify_time` int UNSIGNED DEFAULT 0,
`verifier_id` int UNSIGNED DEFAULT 0,
`issued_at` int UNSIGNED DEFAULT 0,
`created_at` int UNSIGNED DEFAULT 0,
`updated_at` int UNSIGNED DEFAULT 0,
UNIQUE KEY `ticket_code` (`ticket_code`),
KEY `order_id` (`order_id`),
KEY `user_id` (`user_id`),
KEY `verify_status` (`verify_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- database/migrations/004_create_vr_verifiers.sql
CREATE TABLE `vr_verifiers` (
`id` int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`user_id` int UNSIGNED NOT NULL COMMENT 'ShopXO用户ID',
`name` varchar(60) NOT NULL,
`status` tinyint DEFAULT 1,
`created_at` int UNSIGNED DEFAULT 0,
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- database/migrations/005_create_vr_verifications.sql
CREATE TABLE `vr_verifications` (
`id` int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`ticket_id` int UNSIGNED NOT NULL,
`ticket_code` char(36) NOT NULL,
`verifier_id` int UNSIGNED NOT NULL,
`verifier_name` varchar(60),
`event_id` int UNSIGNED,
`created_at` int UNSIGNED DEFAULT 0,
KEY `ticket_id` (`ticket_id`),
KEY `created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
AI 参与度
✅ 90% AI 可生成(妮可 agent 主导)
四、Phase 2 — 场次管理 CRUD
任务
-
管理端页面(后台)
Admin/Controller/EventController.php— 活动管理Admin/Controller/SessionController.php— 场次管理Admin/View/event_list.html— 活动列表Admin/View/session_edit.html— 场次编辑
-
C 端 API
Api/Controller/EventController.php— 活动详情Api/Controller/SessionController.php— 可用场次列表
API 设计
GET /?s=admin/vrticket/event/list
POST /?s=admin/vrticket/event/save
DELETE /?s=admin/vrticket/event/delete
GET /?s=admin/vrticket/session/list&event_id=8
POST /?s=admin/vrticket/session/save
DELETE /?s=admin/vrticket/session/delete
GET /?s=api/vrticket/event/detail&id=8
GET /?s=api/vrticket/session/available&goods_id=123
AI 参与度
✅ 85% AI 可生成(标准 CRUD,可套模板)
五、Phase 3 — 下单钩子 + 观演人收集
5.1 目标
在 ShopXO 下单流程中收集观演人信息
5.2 方案
利用 ShopXO 的「订单商品扩展表单」机制(ordergoodsform 插件的思路):
在 plugins_view_goods_detail_base_sku_top 注入观演人表单:
<!-- 观演人信息收集(票务商品专用)-->
<div id="vr-ticket-attendee-form" class="vr-form">
<view class="form-title">观演人信息</view>
<view v-for="(item, index) in attendeeList" :key="index">
<input type="text" placeholder="姓名" v-model="item.real_name" />
<input type="idcard" placeholder="身份证号(选填)" v-model="item.id_card" />
<input type="phone" placeholder="手机号" v-model="item.phone" />
</view>
<view class="add-btn" @tap="addAttendee">+ 添加观演人</view>
</div>
5.3 数据收集流程
- 用户在前端填写观演人信息
- 前端将观演人数据存入本地(
uni.setStorage) - 点击购买时,将观演人数据通过插件 API 暂存
- 插件在
plugins_service_buy_order_insert_begin钩子中将观演人数据写入vr_tickets表
5.4 钩子实现
// 插件 Service/TicketService.php
public static function OnBeforeOrderInsert(&$params, &$order_data) {
// 检查是否有票务商品
$items = $order_data['items'] ?? [];
foreach ($items as $item) {
if (self::IsTicketGoods($item['goods_id'])) {
// 收集观演人信息,生成票码
$attendees = self::CollectAttendees($item);
self::CreateTickets($order_data['order_id'], $item, $attendees);
}
}
}
AI 参与度
✅ 80% AI 可生成(逻辑稍复杂,需与 ShopXO 订单流程对接)
六、Phase 4 — 支付回调 + QR 票生成
6.1 目标
支付成功后自动发放 QR 电子票
6.2 触发点
ShopXO 支付成功 → plugins_service_buy_order_insert_success 钩子
6.3 任务
// 插件 Service/TicketService.php
public static function OnOrderPaid($order_id, $order_no) {
// 1. 查询该订单的所有票务商品
$tickets = self::GetPendingTickets($order_id);
foreach ($tickets as $ticket) {
// 2. 生成加密票码
$ticket_code = self::GenerateTicketCode(); // UUID v4
// 3. 加密 QR 内容
$qr_data = self::EncryptQrData([
'id' => $ticket['id'],
'code' => $ticket_code,
'event' => $ticket['event_id'],
'exp' => time() + 86400 * 30, // 30天有效期
]);
// 4. 更新数据库
Db::name('vr_tickets')
->where('id', $ticket['id'])
->update([
'ticket_code' => $ticket_code,
'qr_data' => $qr_data,
'issued_at' => time(),
]);
}
// 5. 发送通知(可选)
self::NotifyUser($order_id);
}
AI 参与度
✅ 90% AI 可生成(标准业务逻辑)
七、Phase 5 — uni-app 票务页面
7.1 任务
| 页面 | 文件 | 说明 |
|---|---|---|
| 选座 + 购票 | pages/ticket-buy/ticket-buy.vue |
参考 goods-detail.vue |
| 座位选择组件 | pages/ticket-buy/components/seat-selector.vue |
SVG/Canvas 座位图 |
| 观演人表单 | pages/ticket-buy/components/attendee-form.vue |
动态表单项 |
| 票夹 | pages/ticket-wallet/ticket-wallet.vue |
参考 user/order-list |
7.2 关键组件实现
座位选择器(最简单的 SVG 实现):
<template>
<view class="seat-map">
<svg viewBox="0 0 800 600" class="seat-svg">
<g v-for="seat in seats" :key="seat.id">
<rect
:x="seat.x"
:y="seat.y"
width="30"
height="30"
:fill="getSeatColor(seat.status)"
@tap="onSeatTap(seat)"
class="seat-rect"
/>
<text :x="seat.x + 15" :y="seat.y + 20" class="seat-label">
{{ seat.label }}
</text>
</g>
</svg>
<view class="seat-legend">
<view class="legend-item"><view class="dot available"></view>可选</view>
<view class="legend-item"><view class="dot selected"></view>已选</view>
<view class="legend-item"><view class="dot sold"></view>已售</view>
</view>
</view>
</template>
7.3 接入商品详情页
修改 pages/goods-detail/goods-detail.vue:
- 检测
goods.item_type === 'ticket' - 跳转到
pages/ticket-buy/ticket-buy?goods_id=xxx
或通过插件钩子注入选座 UI,覆盖原有的规格选择器。
AI 参与度
✅ 90% AI 可生成(标准 Vue 组件)
八、Phase 6 — B 端核销页
任务
-
插件 API:
Api/Controller/TicketController.phpverify()— 核销验证
-
uni-app 核销页:
- Fork
pages/plugins/realstore/check/check.vue - 改造成
pages/plugins/vr-ticket-verify/check/check.vue - 调整 API 路径和返回处理
- Fork
-
后台核销统计:
Admin/Controller/TicketController.phpAdmin/View/verification_list.html
AI 参与度
✅ 90% AI 可生成(核心逻辑已参考 realstore 完整实现)
九、Phase 7 — 联调 + 测试 + 部署
9.1 联调清单
- 活动创建 → 商品关联
- 场次库存 → 商品 SKU 映射
- 前端选座 → 后端扣库存
- 微信支付 → 回调 → QR 票生成
- 票夹显示 → QR 码展示
- B 端扫码 → 核销状态更新
- C 端状态实时刷新
9.2 测试用例
| 用例 | 预期 |
|---|---|
| 正常购票流程 | 支付成功 → 收到 QR 票 |
| 并发抢票 | 库存不超卖 |
| 核销同一张票两次 | 第二次报错「已核销」 |
| QR 码过期 | 核销时报「票已过期」 |
| 退款后票失效 | 票状态更新为已退款 |
9.3 部署
- PHP 虚拟主机:上传插件 zip → 后台安装
- shopxo-uniapp:HBuilderX 发行 → 微信审核
十、Agent 分工建议
| Agent | 负责任务 |
|---|---|
| 李狗蛋(MacBook Pro VM) | Phase 0 + Phase 2(场次 CRUD) |
| 妮可(Intel MacBook) | Phase 1(数据库迁移脚本) |
| 小老D(Proxmox Linux) | Phase 3 + Phase 6(钩子 + 核销) |
| 西莉娅(本地 Hub) | Phase 4(QR 生成)+ Phase 7(联调)+ 文档整合 |
十一、里程碑
| 里程碑 | 日期 | 交付物 |
|---|---|---|
| M1 | 第 1 周 | 插件跑通、数据库就绪 |
| M2 | 第 2 周 | 场次管理 + 购票流程 + QR 票发放 |
| M3 | 第 3 周 | B 端核销 + 票夹 + 联调测试 |
| M4 | 第 4 周 | 微信审核 + 正式上线 |