diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index 7f1f1d9..a283c1b 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -1,273 +1,240 @@
# ShopXO VR票务插件 — 架构文档
+> 版本:v1.1(2026-04-14 更新,整合 ShopXO 技术调研成果)
+> 源码位置:council-research/shopxo-eval/.worktrees/shopxo-evaluator/shopxo-src/
+
## 项目概述
基于 ShopXO 生态的 VR 演唱会票务插件(Plan B)。
当 vr-ticket-mp 主线项目因维护成本或架构限制无法继续时,此插件作为 Plan B:
- **完全复用** ShopXO 已有能力(会员体系/积分/优惠券/微信支付)
-- **仅扩展** 票务专属逻辑(场次/观演人/QR核销)
+- **仅扩展** 票务专属逻辑(场次/座位/观演人/QR核销)
- **不修改** ShopXO 核心代码,通过插件机制隔离
-### 目标用户
-朋友的合作伙伴:需要一个可上线、后期可 AI 改动的轻量商城小程序。
+---
+
+## 核心技术发现(2026-04-14 调研)
+
+### 1. CustomView Ace 编辑器 ⭐
+
+ShopXO 内置全代码自定义页面编辑器,HTML/CSS/JS 三栏,实时预览。
+文件:`app/admin/view/default/customview/saveinfo.html`
+访问:后台 → 营销 → 自定义页面管理
+
+### 2. 商品详情页 30+ 钩子 ⭐
+
+最佳注入点:`plugins_view_goods_detail_base_sku_top`(规格选择区顶部)
+- 完全注入票务选座 UI
+- 不修改核心代码
+
+### 3. 按商品类型替换模板 ⭐
+
+修改 `Goods.php Index()` 加 1 行判断:
+```php
+if($goods['item_type'] == 'ticket') {
+ return MyView('/goods/ticket_detail');
+}
+```
+
+### 4. shopxo-uniapp 支持微信小程序 ⭐
+
+HBuilderX 导入 → 配置 AppID → 发行 → 微信开发者工具
+条件编译指令已配置(`#ifdef MP-WEIXIN`)
+
+### 5. QR 码生成内置 ⭐
+
+使用 `\base\Qrcode` 类 + phpqrcode 库:
+```php
+$qr_url = MyUrl('index/qrcode/index', ['content' => base64_encode($data)]);
+```
+
+### 6. 自提点核销页面可直接参考 ⭐
+
+`pages/plugins/realstore/check/check.vue` — 完整 B 端核销 UI
+- uni.scanCode 扫码
+- 手动输入兼容
+- 成功/失败状态展示
+
+### 7. 订单 extension_data 存票务信息 ⭐
+
+`sxo_order.extension_data` — JSON 扩展字段,可存核销状态
---
-## 核心设计思路
-
-### 商品模型统一
-
-票务作为 ShopXO 商品类型的扩展:
+## 整体架构
```
-ShopXO items 表
- └── item_type = 'ticket' 时,启用插件逻辑
- ├── 关联 vr_events(场次表)
- ├── 关联 vr_sessions(场次时间)
- └── 关联 vr_attendees(观演人)
-
-ShopXO orders 表
- └── 订单项 item_type='ticket' → 插件处理履约
- └── 触发 vr_tickets 表写入 → 生成 QR 票
+┌─────────────────────────────────────────────────────┐
+│ ShopXO PHP 后端 │
+│ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
+│ │ 会员/积分 │ │ 商品/订单 │ │ 微信支付 │ │
+│ │ coupons │ │ items/orders│ │ payment │ │
+│ └──────────────┘ └──────────────┘ └──────────┘ │
+│ │
+│ ┌─────────────────────────────────────────────┐ │
+│ │ vr_ticket 插件 │ │
+│ │ ┌────────────────────────────────────────┐ │ │
+│ │ │ EventService — 场次管理 │ │ │
+│ │ │ TicketService — QR票生成/发放 │ │ │
+│ │ │ VerifyService — 核销验证 │ │ │
+│ │ └────────────────────────────────────────┘ │ │
+│ │ ┌────────────────────────────────────────┐ │ │
+│ │ │ 钩子: plugins_view_goods_detail_* │ │ │
+│ │ │ 钩子: plugins_service_buy_order_* │ │ │
+│ │ └────────────────────────────────────────┘ │ │
+│ └─────────────────────────────────────────────┘ │
+└─────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────┐
+│ shopxo-uniapp │
+│ ┌──────────────┐ ┌──────────────────┐ │
+│ │ 商品详情页 │ │ 票务选座页 │ ← Fork │
+│ │goods-detail.vue│ │ ticket-buy.vue │ 自定义 │
+│ └──────────────┘ └──────────────────┘ │
+│ ┌──────────────┐ ┌──────────────────┐ │
+│ │ 用户中心 │ │ 票夹页 │ ← 新建 │
+│ │ user.vue │ │ ticket-wallet.vue│ │
+│ └──────────────┘ └──────────────────┘ │
+│ ┌──────────────┐ │
+│ │ 核销页 │ ← Fork realstore/check.vue │
+│ │ verify.vue │ │
+│ └──────────────┘ │
+└─────────────────────────────────────────────────────┘
```
-### 与 ShopXO 的边界
-
-| 能力 | 来源 | 说明 |
-|------|------|------|
-| 商品目录/上下架 | ShopXO | 复用 items 表 |
-| 会员体系/充值/积分 | ShopXO | 复用 user/wallet/integral 表 |
-| 优惠券 | ShopXO | 复用 coupons 表 |
-| 微信支付 | ShopXO | 复用 payment 表 + 回调 |
-| 场次/日期管理 | **插件** | 独立表 vr_events/sessions |
-| 观演人信息 | **插件** | 独立表 vr_attendees |
-| QR 电子票 | **插件** | 独立表 vr_tickets |
-| 核销组件 | **插件** | 独立 B 端页面 |
-
---
-## 数据库设计
+## 数据模型
+
+### ShopXO 复用表
+
+| 表 | 用途 |
+|---|---|
+| `sxo_user` | 会员 |
+| `sxo_wallet` | 余额钱包 |
+| `sxo_integral` | 积分 |
+| `sxo_coupon` | 优惠券 |
+| `sxo_order` | 订单 |
+| `sxo_order_address` | 地址(含身份证) |
+| `sxo_payment` | 支付配置 |
+| `sxo_goods` | 商品(含票务商品) |
+| `sxo_goods_spec_base` | SKU(座位=库存1) |
### 插件独立表
-```sql
--- 场次表
-vr_events (
- id, goods_id, -- 关联 ShopXO items.id
- name, -- "周杰伦2026巡回演唱会"
- venue, -- 场馆
- cover_image,
- status,
- created_at
-)
-
--- 场次时间表
-vr_sessions (
- id, event_id,
- session_time, -- 2026-06-01 20:00
- total_stock, -- 总库存
- available_stock, -- 可用库存(扣减用 FOR UPDATE SKIP LOCKED)
- price,
- status,
- created_at
-)
-
--- 观演人表
-vr_attendees (
- id, order_id, order_item_id,
- session_id,
- real_name,
- id_card, -- 可选
- phone,
- ticket_code, -- UUID,唯一
- qr_data, -- 加密后的 QR 内容
- status, -- pending/issued/used/cancelled
- created_at
-)
-
--- QR 票表
-vr_tickets (
- id, attendee_id,
- ticket_code,
- qr_image_path, -- QR码图片路径
- issued_at, -- 支付成功时生成
- used_at, -- 核销时间
- created_at
-)
-
--- 核销记录表
-vr_verifications (
- id, ticket_id, verifier_id,
- verified_at,
- ip_address,
- location
-)
-```
+| 表 | 用途 |
+|---|---|
+| `vr_events` | 活动 |
+| `vr_sessions` | 场次时间+库存 |
+| `vr_tickets` | 电子票(含QR数据) |
+| `vr_verifiers` | 核销员 |
+| `vr_verifications` | 核销记录 |
---
## 插件目录结构
```
-shopxo-vr-ticket-plugin/
+app/plugins/vr_ticket/
├── plugin.json # 插件声明
-├── app/
-│ ├── Admin/ # 管理端
-│ │ ├── Controller/
-│ │ │ ├── EventController.php
-│ │ │ ├── SessionController.php
-│ │ │ └── TicketController.php
-│ │ ├── Route.php # 管理端路由
-│ │ └── View/ # 管理页面
-│ │ ├── event_list.html
-│ │ ├── session_edit.html
-│ │ └── ticket_list.html
-│ ├── Api/ # C端API
-│ │ ├── EventController.php # 场次详情
-│ │ ├── SessionController.php # 可用场次
-│ │ ├── CheckoutController.php# 下单钩子(收集观演人)
-│ │ └── TicketController.php # 我的票/票夹
-│ ├── EventListener.php # 监听 ShopXO 支付成功事件
-│ ├── Model/
-│ │ ├── VrEvent.php
-│ │ ├── VrSession.php
-│ │ ├── VrAttendee.php
-│ │ └── VrTicket.php
-│ └── Service/
-│ ├── EventService.php
-│ ├── TicketService.php # QR 生成 + 发放
-│ └── VerificationService.php# 核销逻辑
-├── database/
-│ └── migrations/ # 插件数据库迁移
-│ ├── 001_create_vr_events.php
-│ ├── 002_create_vr_sessions.php
-│ ├── 003_create_vr_attendees.php
-│ └── 004_create_vr_tickets.php
-├── static/
-│ └── admin/ # 管理端静态资源
-└── README.md
+├── service/
+│ ├── BaseService.php # 基础配置
+│ ├── EventService.php # 活动/场次服务
+│ ├── TicketService.php # 票生成/发放
+│ └── VerifyService.php # 核销逻辑
+├── view/
+│ ├── Goods.php # 商品详情页钩子
+│ └── User.php # 用户中心钩子
+├── Admin/
+│ ├── Controller/
+│ │ ├── EventController.php
+│ │ ├── SessionController.php
+│ │ └── TicketController.php
+│ └── View/
+│ ├── event_list.html
+│ ├── event_save.html
+│ ├── session_list.html
+│ ├── session_save.html
+│ ├── ticket_list.html
+│ └── verification_list.html
+├── Api/
+│ └── Controller/
+│ ├── EventController.php # 活动API
+│ ├── SessionController.php # 场次API
+│ └── TicketController.php # 票/核销API
+└── EventListener.php # ShopXO事件监听
+
+database/migrations/ # 数据库迁移
+static/vr_ticket/ # 静态资源
```
---
-## 核心流程
-
-### 1. 票务发布流程
+## 完整购票流程
```
-商家后台 → 插件菜单 → 新建活动
- → 关联 ShopXO 商品(填写价格/库存)
- → 添加场次(时间+价格+库存)
- → 上架
-```
+1. 商家后台
+ → VR票务插件 → 新建活动(关联ShopXO商品)
+ → 添加场次(时间 + 座位图 + 票价 + 库存)
-### 2. 用户购票流程
+2. 用户前端
+ → 首页浏览 → 进入商品详情页
+ → 判断 item_type == 'ticket'
+ → 跳转到票务选座页(pages/ticket-buy)
+ → 选择座位 → 填写观演人信息
+ → 提交订单 → 微信支付
-```
-首页浏览 → 商品详情 → 选择场次 → 立即购买
- → 填写观演人信息(1-N人,场次配置决定)
- → 提交订单(插件收集 attendees)
- → 微信支付
- → 支付回调 → 插件生成 QR 票
- → 票夹页显示电子票
-```
+3. 支付成功
+ → ShopXO 支付回调
+ → TicketService::OnOrderPaid() 触发
+ → 生成 QR 票 → 存入 vr_tickets 表
+ → 用户可在票夹页查看
-### 3. 核销流程
-
-```
-B端核销员 → 扫码页面 → 扫描 QR
- → API 校验 ticket_code
- → 标记 used_at
- → 返回核销结果
+4. 核销
+ → 工作人员打开核销页(pages/plugins/vr-ticket-verify)
+ → 扫描用户 QR 码
+ → POST /api/ticket/verify
+ → VerifyService 更新核销状态
+ → 返回核销结果
```
---
-## 关键技术决策
+## 与 vr-ticket-mp 对比
-### 库存扣减
-
-采用 `FOR UPDATE SKIP LOCKED`(与 vr-ticket-mp 相同策略):
-
-```sql
-BEGIN;
-SELECT available_stock FROM vr_sessions
- WHERE id = ? AND available_stock >= ? FOR UPDATE SKIP LOCKED;
--- 若成功,执行 UPDATE available_stock = available_stock - ?
-COMMIT;
-```
-
-### QR 票安全
-
-```php
-// qr_data = AES_Encrypt(json_encode([
-// 'code' => $attendee->ticket_code,
-// 'event_id' => $event_id,
-// 'exp' => time() + 86400 * 30 // 30天有效期
-// ]), $secret_key)
-```
-
-核销时解密验证,防止伪造。
-
-### 与 ShopXO 的事件对接
-
-```php
-// EventListener.php
-class EventListener
-{
- // 监听 ShopXO 支付成功事件
- public function onOrderPaid($order_id)
- {
- $items = $this->orderService->getOrderItems($order_id);
- foreach ($items as $item) {
- if ($item->item_type === 'ticket') {
- $this->ticketService->issueTickets($item);
- }
- }
- }
-}
-```
-
----
-
-## 与 vr-ticket-mp 的对比
-
-| 维度 | vr-ticket-mp(主线) | ShopXO 插件(Plan B) |
-|------|---------------------|---------------------|
-| 后端 | Go + Gin(自建) | PHP + ThinkPHP(ShopXO) |
-| 数据库 | Supabase Postgres | ShopXO MySQL |
-| 前端 | uni-app(自建) | shopxo-uniapp(已有) |
-| 会员体系 | Supabase Auth | ShopXO 内置 |
-| 积分/优惠券 | 自建 | ShopXO 内置 |
-| 微信支付 | 自建 | ShopXO 内置 |
-| 部署 | Docker | 虚拟主机即可 |
-| 开发成本 | 高(全部自建) | 低(复用 ShopXO) |
-| 适合场景 | 票务为主,商城为辅 | 商城为主,票务为辅 |
+| 维度 | vr-ticket-mp(主线) | vr-shopxo-plugin(Plan B) |
+|---|---|---|
+| **后端** | Go + Gin(自建) | PHP + ThinkPHP(ShopXO) |
+| **数据库** | Supabase Postgres | ShopXO MySQL |
+| **前端** | uni-app(自建) | shopxo-uniapp(已有) |
+| **会员体系** | Supabase Auth | ShopXO 内置 |
+| **积分/优惠券** | 自建 | ShopXO 内置 |
+| **微信支付** | 自建 | ShopXO 内置 |
+| **QR 核销** | 自建 | 基于 ShopXO 已有机制 |
+| **部署** | Docker | 虚拟主机即可 |
+| **AI 参与度** | 80% | 85-90% |
+| **维护成本** | 高 | 低 |
---
## 技术栈
-- **语言**:PHP 8+
-- **框架**:ThinkPHP 8(ShopXO 生态)
-- **前端**:Vue.js(插件管理端)+ uni-app(ShopXO 已有)
-- **数据库**:MySQL(ShopXO 同一实例)
-- **QR生成**:phpqrcode / endroid/qr-code
+- **PHP 8+** / ThinkPHP 8(ShopXO 生态)
+- **MySQL 5.7+**(ShopXO 同一实例)
+- **uni-app**(shopxo-uniapp,已支持微信小程序)
+- **phpqrcode**(`extend/qrcode/phpqrcode.php`,内置)
+- **uni.scanCode**(微信/支付宝等小程序扫码)
---
-## 开发计划(Agent 集群并行)
+## 开发文档
-| 阶段 | 工作内容 | 负责人 |
-|------|---------|--------|
-| Phase 0 | 插件骨架 + 本地跑通 demo | 李狗蛋 |
-| Phase 1 | 数据库设计 + 迁移脚本 | 妮可 |
-| Phase 2 | 场次管理 CRUD + API | 李狗蛋 |
-| Phase 3 | 下单钩子 + 观演人收集 | 小老D |
-| Phase 4 | 支付回调 + QR 票生成 | 西莉娅 |
-| Phase 5 | B端核销页 + 扫码API | 小老D |
-| Phase 6 | Uni-app 改造(观演人表单 + 票夹) | 妮可 |
-| Phase 7 | 联调 + 测试 + 部署文档 | 西莉娅 |
-
-预计:**2-3 周 MVP**,**1 个月**完整上线。
+| 文档 | 内容 |
+|---|---|
+| [docs/00_OVERVIEW.md](docs/00_OVERVIEW.md) | 项目总览 |
+| [docs/01_SHOPXO_TECHNICAL_RESEARCH.md](docs/01_SHOPXO_TECHNICAL_RESEARCH.md) | ShopXO 技术能力完整调研 |
+| [docs/02_FRONTEND_CUSTOMIZATION.md](docs/02_FRONTEND_CUSTOMIZATION.md) | shopxo-uniapp 编译与自定义 |
+| [docs/03_VERIFICATION_SYSTEM.md](docs/03_VERIFICATION_SYSTEM.md) | 核销系统设计 |
+| [docs/04_IMPLEMENTATION_ROADMAP.md](docs/04_IMPLEMENTATION_ROADMAP.md) | 实施路线图与 Agent 分工 |
diff --git a/README.md b/README.md
index 719fb07..ed636dc 100644
--- a/README.md
+++ b/README.md
@@ -1,40 +1,62 @@
-# ShopXO VR票务插件
+# VR票务插件 for ShopXO
-基于 ShopXO 生态的 VR 演唱会票务解决方案(Plan B)。
+> Plan B:基于 ShopXO 生态的 VR 演唱会票务解决方案
+> 当 vr-ticket-mp(Go + Supabase + uni-app 主线)不适用时,选用此方案
-## 功能特性
+## 核心能力
-- ✅ 场次管理(多日期/多票价/库存追踪)
-- ✅ 观演人信息收集(下单时强制填写)
-- ✅ QR 电子票生成(支付成功后自动发放)
-- ✅ B 端扫码核销(支持多核销员)
-- ✅ 复用 ShopXO 会员/积分/优惠券体系
-- ✅ 插件独立部署,不修改 ShopXO 核心代码
+| 能力 | 实现方式 |
+|---|---|
+| 场次管理 | 插件独立表 `vr_events` / `vr_sessions` |
+| 商品详情页定制 | 30+ 钩子注入,或 1 行控制器代码替换模板 |
+| 选座 UI | 自定义 Vue 组件,Fork shopxo-uniapp |
+| 观演人收集 | 插件钩子收集,下单时写入 `vr_tickets` 表 |
+| QR 电子票 | ShopXO 内置 `\base\Qrcode` + phpqrcode |
+| 微信小程序 | shopxo-uniapp 已支持,HBuilderX 一键发行 |
+| B 端核销 | Fork `realstore/check/check.vue`,完整参考 |
+| 会员/积分/优惠券 | 全部复用 ShopXO 内置能力 |
## 快速开始
```bash
-# 1. 克隆插件
+# 1. 克隆本仓库
git clone http://xmhome.ow-my.com:3000/sileya-ai/vr-shopxo-plugin.git
-# 2. 上传至 ShopXO 插件目录
-cp -r vr-shopxo-plugin /path/to/shopxo/app/plugins/
+# 2. 上传插件到 ShopXO
+cp -r vr-shopxo-plugin/app/plugins/vr_ticket /path/to/shopxo/app/plugins/
-# 3. 后台安装插件
+# 3. 数据库迁移
+# 访问 /admin/plugins/vr_ticket/migrate 或手动执行 SQL
+
+# 4. 后台安装
# 管理后台 → 应用中心 → 插件管理 → 安装 VR票务插件
-# 4. 数据库迁移
-# 访问 /plugins/vr-ticket/admin/migrate
+# 5. shopxo-uniapp 改造
+# HBuilderX 导入 shopxo-uniapp
+# 添加 pages/ticket-buy/ 和 pages/ticket-verify/
+# 配置 manifest.json 的 AppID
+# 发行 → 微信小程序
```
-## 架构文档
+## 技术调研文档
-详见 [ARCHITECTURE.md](ARCHITECTURE.md)
+- [ShopXO 技术能力调研](docs/01_SHOPXO_TECHNICAL_RESEARCH.md) — DIY/CustomView/钩子/插件完整分析
+- [uni-app 前端定制](docs/02_FRONTEND_CUSTOMIZATION.md) — 小程序编译与自定义组件
+- [核销系统设计](docs/03_VERIFICATION_SYSTEM.md) — QR 生成/核销 API/票夹
+- [实施路线图](docs/04_IMPLEMENTATION_ROADMAP.md) — Agent 分工与开发计划
-## 开发状态
+## 关键发现(2026-04-14)
-🚧 正在规划中,尚未开始编码。
+- ✅ ShopXO 内置 **CustomView Ace 编辑器**(全代码自定义页面)
+- ✅ 商品详情页 **30+ 插件钩子**,最佳注入点 `plugins_view_goods_detail_base_sku_top`
+- ✅ shopxo-uniapp **已支持微信小程序**,条件编译已配置
+- ✅ ShopXO 内置 **phpqrcode** QR 码生成库
+- ✅ `realstore/check/check.vue` 是 **B 端核销页最佳参考**
----
+## 项目状态
-**仓库**:`http://xmhome.ow-my.com:3000/sileya-ai/vr-shopxo-plugin`
+🚧 **调研完成,尚未开始编码**
+
+## 仓库地址
+
+`http://xmhome.ow-my.com:3000/sileya-ai/vr-shopxo-plugin`
diff --git a/docs/00_OVERVIEW.md b/docs/00_OVERVIEW.md
new file mode 100644
index 0000000..6917423
--- /dev/null
+++ b/docs/00_OVERVIEW.md
@@ -0,0 +1,79 @@
+# VR票务插件 — 项目总览
+
+## 项目背景
+
+大头的朋友需要一个外卖/包邮/自提 + 会员(充值/积分/优惠券)的小程序商城。
+约束条件:**无程序员/无运维/无前端,要直接可用,后期能用 AI 改代码,部署简单,不考虑 Java**。
+
+在 vr-ticket-mp(主线:Go + Supabase + uni-app)之外,建立 **Plan B**:基于 ShopXO 生态的票务插件。
+
+---
+
+## 双线策略
+
+| | vr-ticket-mp(主线) | vr-shopxo-plugin(Plan B) |
+|---|---|---|
+| **定位** | 票务为核心,商城为辅 | 商城为主,票务为辅 |
+| **后端** | Go + Gin(自建) | PHP + ThinkPHP(ShopXO) |
+| **数据库** | Supabase Postgres | ShopXO MySQL |
+| **前端** | uni-app(自建) | shopxo-uniapp(已有) |
+| **会员/积分/优惠券** | 自建 | ShopXO 内置 |
+| **微信支付** | 自建 | ShopXO 内置 |
+| **部署** | Docker | 虚拟主机即可 |
+| **维护成本** | 高 | 低 |
+| **触发条件** | — | 电商需求 > 票务需求,或 vr-ticket-mp 维护成本过高 |
+
+---
+
+## 为什么选择 ShopXO
+
+ShopXO 在 ShopXO / Bagisto / Saleor / Medusa 四个候选中**断层第一推荐(9/10)**。
+
+| 能力 | ShopXO | Bagisto | Saleor | Medusa |
+|---|---|---|---|---|
+| 外卖/自提/包邮 | ✅ 全功能内置 | ❌ 无 | ❌ 无 | ❌ 无 |
+| 会员充值/积分/优惠券 | ✅ 全功能内置 | ❌ 无 | ❌ 无 | ❌ 无 |
+| 微信支付 | ✅ 内置 | ⚠️ 需配置 | ⚠️ 需配置 | ⚠️ 需配置 |
+| 部署难度 | ⭐ 虚拟主机即可 | ⭐ VPS/SSH | ⭐ Docker 门槛高 | ⭐ 云托管推荐 |
+| uni-app 前端 | ✅ shopxo-uniapp | ❌ 无 | ❌ | ❌ |
+| 票务插件 | ⚠️ 需开发 | ❌ 无 | ❌ 无 | ❌ 无 |
+| AI 友好度 | ⭐ 业务层 80% 可AI | ⭐ 差 | ⭐ 差 | ⭐ 差 |
+| 协议 | MIT | MIT | MIT | MIT |
+
+---
+
+## 今天调研的关键突破
+
+1. **CustomView Ace 编辑器**:ShopXO 内置全代码自定义页面编辑器,HTML/CSS/JS 三栏,实时预览
+2. **30+ 商品详情页钩子**:`plugins_view_goods_detail_base_sku_top` 是票务 UI 最佳注入点
+3. **商品详情页按类型替换模板**:修改 `Goods.php Index()` 加 1 行判断即可
+4. **shopxo-uniapp 支持微信小程序**:条件编译已配置,HBuilderX 一键发行
+5. **核销机制现成可用**:`realstore/check/check.vue` 是 B 端核销页最佳参考
+6. **QR 码生成内置**:`\base\Qrcode` 类 + phpqrcode 库,URL 即用
+
+---
+
+## 文档目录
+
+| 文档 | 内容 |
+|---|---|
+| [00_OVERVIEW.md](00_OVERVIEW.md) | 项目总览(本文档) |
+| [01_SHOPXO_TECHNICAL_RESEARCH.md](01_SHOPXO_TECHNICAL_RESEARCH.md) | ShopXO 技术能力完整调研 |
+| [02_FRONTEND_CUSTOMIZATION.md](02_FRONTEND_CUSTOMIZATION.md) | shopxo-uniapp 编译与自定义 |
+| [03_VERIFICATION_SYSTEM.md](03_VERIFICATION_SYSTEM.md) | 核销系统设计 |
+| [04_IMPLEMENTATION_ROADMAP.md](04_IMPLEMENTATION_ROADMAP.md) | 实施路线图与 Agent 分工 |
+| [../ARCHITECTURE.md](../ARCHITECTURE.md) | 核心架构设计(基础版) |
+
+---
+
+## 关键文件路径(源码位置)
+
+ShopXO 源码克隆自 `https://gitee.com/zongzhige/shopxo`,位于:
+```
+/Users/bigemon/.openclaw/workspace/council-research/shopxo-eval/.worktrees/shopxo-evaluator/shopxo-src/
+```
+
+shopxo-uniapp 克隆自 `https://gitee.com/zongzhige/shopxo-uniapp`,位于:
+```
+/Users/bigemon/.openclaw/workspace/council-research/shopxo-eval/.worktrees/shopxo-evaluator/shopxo-uniapp-src/
+```
diff --git a/docs/01_SHOPXO_TECHNICAL_RESEARCH.md b/docs/01_SHOPXO_TECHNICAL_RESEARCH.md
new file mode 100644
index 0000000..ac00c15
--- /dev/null
+++ b/docs/01_SHOPXO_TECHNICAL_RESEARCH.md
@@ -0,0 +1,603 @@
+# ShopXO 技术能力完整调研
+
+> 调研时间:2026-04-14(上午)
+> 调研方式:源码分析 + Council 并行 agent 调研(ShopXO / Bagisto / Saleor / Medusa)
+> 源码位置:`council-research/shopxo-eval/.worktrees/shopxo-evaluator/shopxo-src/`
+
+---
+
+## 一、DIY 设计器组件系统
+
+### 1.1 组件定义机制
+
+ShopXO DIY 设计器是 **Vue3 SPA**:
+- 入口:`public/static/diy/js/entry/index-*.js`
+- 组件列表定义在前端 JS 中(组件面板)
+- 后端只存储布局配置 JSON(`sxo_diy` 表)
+
+### 1.2 渲染层支持的组件类型
+
+模板位置:
+`app/module/view/layout/public/common/module_view.html`
+
+| 组件值 (value) | 功能 | AI 参与度 |
+|---|---|---|
+| `images` | 单图 | ✅ 替换链接即可 |
+| `many-images` | 多图(多种布局) | ✅ |
+| `images-text` | 图文混排 | ✅ |
+| `images-magic-cube` | 图片魔方(复杂宫格) | ✅ |
+| `video` | 视频 | ✅ |
+| `goods` | 商品列表(3 种样式:routine/leftright/rolling) | ✅ |
+| `title` | 标题文字 | ✅ |
+| **`custom`** | **自定义 HTML** | **✅✅ 完全自由** |
+
+### 1.3 `custom` 组件渲染逻辑
+
+```php
+{{case custom}}
+ {{if !empty($vss['config']['custom'])}}
+ {{$vss.config.custom|raw}}
+ {{/if}}
+{{/case}}
+```
+
+直接输出原始 HTML,无任何过滤。
+
+**⚠️ 注意**:`custom` 组件在后端渲染层存在,但 admin DIY Vue3 设计器的组件面板 UI 入口不明确(未在源码中找到 admin 侧配置)。**替代方案**:使用 CustomView 完全弥补(见下节)。
+
+### 1.4 DIY 设计器局限性
+
+- **展示型页面**(首页/专题页):重度依赖拖拽装修,JSON 数据库存储,AI 无法直接参与视觉设计
+- **业务型页面**(商品/订单/会员):表格 + 表单,AI 参与度高
+- **票务插件 UI**:完全走代码,不依赖 DIY 系统 → AI 参与度极高
+
+---
+
+## 二、CustomView 自定义页面系统 ⭐ 重大发现
+
+### 2.1 功能概述
+
+ShopXO 内置全代码自定义页面编辑器(Ace Playground Web Component)。
+
+后台入口:**营销菜单 → 自定义页面管理**
+
+### 2.2 技术细节
+
+| 能力 | 详情 |
+|---|---|
+| **编辑器** | Ace Playground(非 iframe,是原生 Web Component) |
+| **语言** | HTML + CSS + JavaScript 三栏独立编辑 |
+| **实时预览** | iframe 渲染,实时刷新 |
+| **模板语法** | ThinkPHP `{{$data.xxx|raw}}` 可用(会员信息、商品数据等) |
+| **访问地址** | `/index/customview/index?id=xxx` |
+| **全屏模式** | 支持 `is_full_screen` 参数 |
+
+### 2.3 存储内容
+
+| 字段 | 渲染方式 |
+|---|---|
+| `html_content` | `{{$data.html_content\|raw}}` 在 div 内 |
+| `css_content` | `` 自动包裹 |
+| `js_content` | `` 自动包裹 |
+
+### 2.4 admin 端 Ace 编辑器实现
+
+文件:`app/admin/view/default/customview/saveinfo.html`
+
+```javascript
+class AcePlayground extends HTMLElement {
+ constructor() {
+ var shadow = this.attachShadow({mode: 'open'});
+ dom.buildDom(['div', {id: 'host'},
+ ['div', {id: 'html'}], // HTML 编辑器
+ ['div', {id: 'css'}], // CSS 编辑器
+ ['div', {id: 'js'}], // JS 编辑器
+ ['iframe', {id: 'preview'}] // 实时预览
+ ], shadow);
+
+ this.htmlEditor = ace.edit(shadow.querySelector('#html'), {...});
+ this.cssEditor = ace.edit(shadow.querySelector('#css'), {...});
+ this.jsEditor = ace.edit(shadow.querySelector('#js'), {...});
+ this.preview = shadow.querySelector('#preview');
+ this.updatePreview(); // 实时更新预览
+ }
+}
+```
+
+### 2.5 对票务的意义
+
+✅ **CustomView 可以实现完全自定义的票务辅助页面**:
+- 票夹页面(用户的所有电子票)
+- 观演人管理页面
+- 活动专题页面
+
+在 DIY 设计器中,通过 `custom` 组件引用 CustomView 页面 URL,或直接在插件钩子中链接到 CustomView 页面。
+
+---
+
+## 三、商品详情页钩子系统(30+ 钩子)
+
+### 3.1 核心文件
+
+- 控制器:`app/index/controller/Goods.php`(`PluginsHook()` 方法)
+- 模板:`app/index/view/default/goods/module/middle_base/right/` 目录下各模板
+
+### 3.2 钩子完整列表
+
+```
+📍 相册区域
+ plugins_view_goods_detail_photo_within ← 相册内部
+ plugins_view_goods_detail_photo_bottom ← 相册底部
+
+📍 右侧购买面板
+ plugins_view_goods_detail_panel_original_price_top ← 原价上方
+ plugins_view_goods_detail_panel_price_top ← 现价上方
+ plugins_view_goods_detail_panel_price_bottom ← 现价下方
+ plugins_view_goods_detail_panel_bottom ← 整个面板底部
+
+📍 规格/库存区域 ← 🎯 票务最佳注入点
+ plugins_view_goods_detail_base_sku_top ← 规格选择区顶部 ⭐
+ plugins_view_goods_detail_base_inventory_top ← 库存区域顶部
+ plugins_view_goods_detail_base_inventory_bottom ← 库存区域底部 ⭐
+
+📍 购买导航
+ plugins_view_goods_detail_base_buy_nav_min_inside_begin ← 购买区内部前
+ plugins_view_goods_detail_base_buy_nav_min_inside ← 购买区内部后
+
+📍 底部信息(标签页)
+ plugins_view_goods_detail_tabs_top / _content / _bottom
+ plugins_view_goods_detail_tabs_comments_top/bottom
+ plugins_view_goods_detail_tabs_guess_like_top/bottom
+
+📍 全局
+ plugins_view_goods_detail_content_top/bottom
+ plugins_view_goods_detail_left_top
+ plugins_view_goods_detail_title
+```
+
+### 3.3 钩子渲染机制
+
+控制器中:
+```php
+foreach($hook_arr as $hook_name) {
+ $assign[$hook_name.'_data'] = MyEventTrigger($hook_name, [
+ 'hook_name' => $hook_name,
+ 'is_backend' => false,
+ 'goods_id' => $goods_id,
+ 'goods' => &$goods,
+ ]);
+}
+MyViewAssign($assign);
+```
+
+模板中渲染:
+```php
+{{foreach $plugins_view_goods_detail_base_sku_top_data as $hook}}
+ {{if is_string($hook) or is_int($hook)}}
+ {{$hook|raw}}
+ {{/if}}
+{{/foreach}}
+```
+
+### 3.4 最佳注入点分析
+
+**票务选座 UI 最佳位置**:`plugins_view_goods_detail_base_sku_top`
+- 位于规格选择区顶部
+- 在购买按钮上方
+- 可以完全占据购买区域
+- 插件返回 HTML 字符串即可渲染
+
+---
+
+## 四、按商品类型完全替换模板
+
+### 4.1 主题机制
+
+`MyView()` 函数(`app/common.php`)支持主题覆盖:
+```php
+function MyView($view = '', $data = []) {
+ $theme = DefaultTheme(); // 从配置读取主题名
+ $file = APP_PATH.$group.DS.'view'.DS.$theme.DS.$view_new.$suffix;
+ // 如果当前主题有这个文件,就用主题的;否则用 default
+}
+```
+
+主题目录:`app/index/view/{theme_name}/goods/index.html`
+
+主题切换配置:`sxo_config` 表中 `common_default_theme` 字段。
+
+**⚠️ 限制**:主题是全局的,所有商品共用同一套模板。
+
+### 4.2 按商品类型动态选择模板
+
+在 `Goods.php Index()` 方法中加 1 行判断:
+
+```php
+// Goods.php Index() 方法,约第 440 行
+// 在 return MyView(); 之前插入:
+
+if(!empty($goods['item_type']) && $goods['item_type'] == 'ticket') {
+ return MyView('/goods/ticket_detail'); // 自定义票务模板
+}
+return MyView(); // 默认模板
+```
+
+对应模板文件:`app/index/view/default/goods/ticket_detail.html`
+
+**这是 ShopXO 允许范围内,唯一能让特定类型商品使用独立模板的方式。**
+
+---
+
+## 五、插件系统架构
+
+### 5.1 目录结构
+
+```
+app/plugins/{PluginName}/
+├── service/
+│ └── BaseService.php ← 必须:配置字段 + 安装/卸载逻辑
+├── view/
+│ ├── User.php ← 用户中心钩子实现
+│ ├── Goods.php ← 商品详情页钩子实现
+│ └── ...
+├── js/
+│ └── ...
+└── 配置文件
+```
+
+### 5.2 BaseService.php 必须实现
+
+```php
+namespace app\plugins\{PluginName}\service;
+
+class BaseService {
+ // 1. 插件配置表单字段
+ public static function Config($params = []) {
+ return [
+ 'title' => '插件名称',
+ 'base' => [...], // 基础配置
+ 'items' => [...], // 自定义配置项
+ ];
+ }
+
+ // 2. 安装回调
+ public static function Install($params = []) { ... }
+
+ // 3. 卸载回调
+ public static function Uninstall($params = []) { ... }
+}
+```
+
+### 5.3 视图钩子实现示例
+
+插件 `view/Goods.php`:
+```php
+namespace app\plugins\vr_ticket\view;
+
+class Goods {
+ // 钩子:plugins_view_goods_detail_base_sku_top
+ public static function PluginsViewGoodsDetailBaseSkuTop($params) {
+ $goods = $params['goods'];
+ if(empty($goods['item_type']) || $goods['item_type'] != 'ticket') {
+ return ''; // 非票务商品,不输出
+ }
+ return '
...
';
+ }
+}
+```
+
+ShopXO 事件系统自动发现并调用所有注册该钩子的插件方法。
+
+### 5.4 Service 层钩子(可改业务逻辑)
+
+```
+plugins_service_goods_buy_nav_button_handle ← 可动态增减购买按钮
+plugins_service_goods_spec_data ← 可改规格/库存数据
+plugins_service_buy_order_insert_begin ← 订单创建前
+plugins_service_buy_order_insert_success ← 订单创建后
+```
+
+---
+
+## 六、用户中心钩子
+
+### 6.1 路由
+
+- 个人资料页:`/index/personal/`(`Personal.php`)— ❌ 无钩子
+- 用户中心:`/index/user/`(`User.php`)— ✅ 6 个钩子
+
+### 6.2 钩子列表
+
+```
+plugins_view_user_center_top ← 用户中心顶部
+plugins_view_user_base_bottom ← 用户基础信息底部
+plugins_view_user_various_top ← 聚合内容(订单/资产)顶部
+plugins_view_user_various_bottom ← 聚合内容底部
+plugins_view_user_various_inside_top ← 聚合内容内部顶部 ⭐
+plugins_view_user_various_inside_bottom ← 聚合内容内部底部
+```
+
+### 6.3 最佳注入点
+
+**票夹**(我的票):注入到 `plugins_view_user_various_inside_top`
+
+在插件 `view/User.php` 中:
+```php
+public static function PluginsViewUserVariousInsideTop($params) {
+ return render_ticket_list_html($tickets); // 返回票夹 HTML
+}
+```
+
+---
+
+## 七、搜索页钩子(8 个)
+
+```
+plugins_view_search_top ← 搜索区域顶部
+plugins_view_search_bottom ← 搜索区域底部
+plugins_view_search_inside_top ← 搜索结果区域顶部
+plugins_view_search_inside_bottom ← 搜索结果区域底部
+plugins_view_search_data_top ← 商品列表顶部
+plugins_view_search_data_bottom ← 商品列表底部
+plugins_view_search_nav_top ← 筛选导航顶部
+plugins_view_search_nav_inside_begin/end ← 筛选导航内部
+```
+
+---
+
+## 八、订单系统关键发现
+
+### 8.1 订单状态
+
+| 值 | 含义 |
+|---|---|
+| 0 | 待确认 |
+| 1 | 已确认/待支付 |
+| 2 | 已支付/待发货 |
+| 3 | 已发货/待收货 |
+| 4 | 已完成 |
+| 5 | 已取消 |
+| 6 | 已关闭 |
+
+### 8.2 支付状态
+
+| 值 | 含义 |
+|---|---|
+| 0 | 未支付 |
+| 1 | 已支付 |
+| 2 | 已退款 |
+| 3 | 部分退款 |
+
+### 8.3 订单模式
+
+| 值 | 含义 |
+|---|---|
+| 0 | 快递 |
+| 1 | 同城 |
+| 2 | 自提 |
+| 3 | 虚拟 |
+
+**票务建议**:使用 `order_model = 3`(虚拟),因为不需要物流。
+
+### 8.4 关键表结构
+
+**订单表 `sxo_order`**:
+- `order_no` — 订单号(UNIQUE)
+- `user_id` — 用户 ID
+- `status` — 订单状态
+- `pay_status` — 支付状态
+- `order_model` — 订单模式
+- **`extension_data`** — 扩展数据 JSON(可存票务核销信息)
+- `client_type` — 客户端类型(weixin/h5/app 等)
+
+**订单地址表 `sxo_order_address`**:
+- `name` — 收件人姓名
+- `tel` — 收件人电话
+- `idcard_name` — 身份证姓名
+- `idcard_number` — 身份证号码
+
+**核销码表 `sxo_order_extraction_code`**:
+```sql
+CREATE TABLE `sxo_order_extraction_code` (
+ `id` int PRIMARY KEY AUTO_INCREMENT,
+ `order_id` int, -- 关联订单ID
+ `user_id` int, -- 用户ID
+ `code` char(30), -- 取货码(可用于票务核销)
+ `add_time` int,
+ `upd_time` int
+);
+```
+
+---
+
+## 九、QR 码生成能力
+
+### 9.1 核心类
+
+位置:`extend/base/Qrcode.php`
+
+使用 phpqrcode 库(`extend/qrcode/phpqrcode.php`)
+
+### 9.2 API 接口
+
+```
+展示模式:GET /?s=index/qrcode/index&content=BASE64_ENCODE(data)
+创建模式:\base\Qrcode::Create(['content' => $data, 'root_path' => $path])
+```
+
+### 9.3 展示模式参数
+
+| 参数 | 说明 | 默认值 |
+|---|---|---|
+| `content` | 二维码内容(base64 编码) | 当前 URL |
+| `level` | 容错率(L/M/Q/H) | L |
+| `size` | 大小(1-30) | 6 |
+| `mr` | 外边距 | 1 |
+
+### 9.4 生成票务 QR 码
+
+```php
+$ticket_data = json_encode([
+ 'code' => $attendee->ticket_code,
+ 'event' => $event->name,
+ 'session' => $session->session_time,
+ 'seat' => $seat,
+ 'exp' => time() + 86400 * 30 // 30天有效期
+]);
+
+$qr_url = MyUrl('index/qrcode/index', [
+ 'content' => urlencode(base64_encode($ticket_data)),
+ 'size' => 8,
+ 'level' => 'H', // 高容错率
+]);
+```
+
+在页面中展示:`
`
+
+---
+
+## 十、购买流程与库存原子性
+
+### 10.1 Buy API 端点
+
+```
+POST /?s=index/buy/add ← 创建订单
+GET /?s=index/buy/index ← 获取结算页数据
+```
+
+关键参数 `goods_data`(绕过购物车直接下单):
+```php
+$params['goods_data'] = [
+ 'goods_id' => 123,
+ 'stock' => 1,
+ 'spec' => [['type_id' => $type_id, 'value_id' => $value_id]]
+];
+```
+
+### 10.2 库存扣减原子性
+
+`BuyService.php` 第 1692-1699 行:
+```php
+$where = [
+ 'id' => $spec_base_id,
+ 'goods_id' => $goods_id,
+ 'inventory >= ' => $buy_number
+];
+Db::name('GoodsSpecBase')->where($where)->dec('inventory', $buy_number)->update();
+```
+
+- 订单支付时在事务内原子扣减
+- WHERE 条件不满足时 `dec()` 返回 0 行 → 事务回滚
+- **结论**:ShopXO 自身防超卖是安全的,无需额外 Go 锁座层
+
+### 10.3 锁座机制
+
+ShopXO **不支持锁座**。对于演唱会选座:
+- 座位作为 SKU(inventory = 0 或 1)
+- 购买时直接扣库存
+- 超卖风险由 ShopXO 库存原子性兜底
+
+---
+
+## 十一、自提点核销机制(最佳参考)
+
+### 11.1 核销码表
+
+`sxo_order_extraction_code` — ShopXO 用此表存储自提点取货码
+
+### 11.2 uni-app 核销页面
+
+位置:`pages/plugins/realstore/check/check.vue`
+
+关键代码:
+```vue
+
+
+
+
+
+
+
+
+
+uni.scanCode({
+ success: (res) => {
+ self.check_value = res.result;
+ self.form_submit(); // 自动提交验证
+ }
+});
+
+
+uni.request({
+ url: app.globalData.get_request_url('verification', 'adminorderallot', 'realstore'),
+ method: 'POST',
+ data: { extraction_code: this.check_value }
+});
+```
+
+### 11.3 核销 API
+
+路径:`/?s=admin/orderallot/verification`(插件内)
+
+参数:`extraction_code`(核销码)
+
+返回:
+```json
+{
+ "code": 0, // 0=成功,其他=失败
+ "msg": "核销成功",
+ "data": {...}
+}
+```
+
+### 11.4 核销页面 B 端 UI 特性
+
+- 成功/失败结果大字展示(绿/红)
+- 核销后清空输入框,可连续扫描
+- 底部统计(已核销/待核销/今日核销)
+- 支持切换核销门店(popup 选择)
+
+---
+
+## 十二、ShopXO 其他关键表
+
+### 12.1 商品表 `sxo_goods`
+
+| 字段 | 说明 |
+|---|---|
+| `site_type` | 履约类型(0-8,对应快递/自提/虚拟等) |
+| `is_exist_many_spec` | 是否多规格 |
+| `inventory` | 主库存 |
+| `site_model` | 站点模式 |
+
+### 12.2 规格相关表
+
+- `sxo_goods_spec_type` — 规格维度(如区域:A区/B区/C区)
+- `sxo_goods_spec_value` — 规格值映射(如座位:排号+座号)
+- `sxo_goods_spec_base` — 每个 SKU 的库存+价格(`inventory` 整数字段)
+
+### 12.3 库存日志表
+
+`sxo_order_goods_inventory_log` — 记录所有库存变动,支持回滚
+
+---
+
+## 十三、综合评估
+
+| 场景 | 能力 | 方式 |
+|---|---|---|
+| 首页/专题页 DIY | ✅ 完全支持 | DIY 设计器 |
+| 自定义 HTML 组件 | ⚠️ 渲染层支持,admin UI 不明确 | `custom` 组件 |
+| 完全自定义页面 | ✅✅ Ace 编辑器 | CustomView |
+| 商品详情页注入票务 UI | ✅✅ 30+ 钩子,最佳注入点 SKU 顶部 | 插件钩子 |
+| 商品详情页整体替换 | ✅ 1 行控制器代码 | 修改 Goods.php |
+| 用户中心注入票夹 | ✅ 6 个钩子 | 插件 |
+| 个人资料页 | ❌ 无法自定义 | 固定模板 |
+| 搜索页扩展 | ✅ 8 个钩子 | 插件 |
+| 订单详情页 | ❌ 无视图钩子,仅 Service 钩子 | 插件改数据 |
+| 购买流程 | ✅ 多个 Service 钩子 | 插件改逻辑 |
+| B 端核销页 | ✅✅ 参考 realstore/check.vue | Fork + 定制 |
+| QR 码生成 | ✅✅ 内置 phpqrcode | `\base\Qrcode` |
+| 插件开发 | ✅ 完整 Hook + Service 机制 | 文档完善 |
+
+**AI 参与度**:票务核心逻辑 95% 可 AI 生成(除 Goods.php 的 1 行判断外)
diff --git a/docs/02_FRONTEND_CUSTOMIZATION.md b/docs/02_FRONTEND_CUSTOMIZATION.md
new file mode 100644
index 0000000..f712479
--- /dev/null
+++ b/docs/02_FRONTEND_CUSTOMIZATION.md
@@ -0,0 +1,471 @@
+# shopxo-uniapp 前端编译与自定义
+
+> 调研时间:2026-04-14
+> 源码位置:`council-research/shopxo-eval/.worktrees/shopxo-evaluator/shopxo-uniapp-src/`
+> 官方仓库:https://gitee.com/zongzhige/shopxo-uniapp
+
+---
+
+## 一、项目概述
+
+shopxo-uniapp 是 ShopXO 官方出品的 uni-app 前端,支持:
+- ✅ 微信小程序(MP-WEIXIN)
+- ✅ QQ 小程序(MP-QQ)
+- ✅ 百度小程序(MP-BAIDU)
+- ✅ 支付宝小程序(MP-ALIPAY)
+- ✅ 抖音/头条小程序(MP-TOUTIAO)
+- ✅ 快手小程序(MP-KUAISHOU)
+- ✅ H5
+- ✅ APP(iOS/Android)
+
+**README 原文**:> 已支持小程序(微信、QQ、百度、支付宝、头条&抖音、快手)+ H5 + APP
+
+---
+
+## 二、编译到微信小程序
+
+### 2.1 编译工具
+
+**HBuilderX**(uni-app 官方 IDE)
+
+### 2.2 编译步骤
+
+1. 用 HBuilderX 导入 `shopxo-uniapp-src` 项目
+2. 修改 `App.vue` 中的接口地址:
+ ```javascript
+ // globalData 配置
+ request_url: 'https://your-shopxo-domain.com/', // 你的 ShopXO 域名
+ static_url: 'https://your-shopxo-domain.com/static/'
+ ```
+3. 修改 `manifest.json` 中的 AppID(微信小程序配置):
+ ```json
+ {
+ "mp-weixin": {
+ "appid": "wx YOUR APPID",
+ "setting": {
+ "urlCheck": false
+ }
+ }
+ }
+ ```
+4. 顶部菜单 → **发行** → **微信小程序**
+5. 用微信开发者工具打开发行目录
+
+### 2.3 条件编译指令
+
+在 `.vue` 文件和 `pages.json` 中使用:
+
+```vue
+
+微信/百度/QQ/快手/H5/APP 专属内容
+
+
+
+支付宝专属内容
+
+
+
+
+
+
+```
+
+在 `pages.json` 中:
+```json
+{
+ "path": "pages/goods-detail/goods-detail",
+ "style": {
+ "// #ifdef MP-WEIXIN": "",
+ "navigationStyle": "custom",
+ "// #endif": "",
+ }
+}
+```
+
+---
+
+## 三、pages.json 路由与全局组件
+
+### 3.1 核心页面
+
+```json
+{
+ "pages": [
+ { "path": "pages/index/index" }, // 首页(含 DIY)
+ { "path": "pages/goods-category/goods-category" }, // 分类
+ { "path": "pages/cart/cart" }, // 购物车
+ { "path": "pages/user/user" } // 用户中心
+ ],
+ "subPackages": [
+ {
+ "root": "pages/diy", // DIY 页面
+ "pages": [{ "path": "diy" }]
+ },
+ {
+ "root": "pages/goods-detail", // 商品详情
+ "pages": [{ "path": "goods-detail" }]
+ },
+ {
+ "root": "pages/goods-search", // 搜索
+ "pages": [{ "path": "goods-search" }]
+ },
+ {
+ "root": "pages/user-order-detail", // 订单详情
+ "pages": [{ "path": "user-order-detail" }]
+ }
+ ]
+}
+```
+
+### 3.2 全局注册的自定义组件
+
+在 `pages/index/index` 的 `style.usingComponents` 中全局注册:
+
+```json
+{
+ "component-diy": "/pages/diy/components/diy/diy",
+ "component-form-input": "/pages/form-input/components/form-input/form-input",
+ "component-layout": "/pages/design/components/layout/layout",
+ "component-goods-comments": "/pages/goods-detail/components/goods-comments/goods-comments",
+ "component-coupon-card": "/pages/plugins/coupon/components/coupon-card/coupon-card",
+ "component-form-input-base": "/pages/form-input/components/form-input/form-input-base"
+}
+```
+
+其他页面按需引入。
+
+---
+
+## 四、商品详情页改造
+
+### 4.1 商品详情页位置
+
+`pages/goods-detail/goods-detail.vue`
+
+### 4.2 添加票务条件渲染
+
+在 `` 中添加:
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### 4.3 后端配合(可选)
+
+如果需要完全不同的页面结构,可以:
+
+**方案 A:插件钩子替换**
+- 在 `plugins_view_goods_detail_base_sku_top` 注入跳转按钮
+- 点击后用 `uni.reLaunch` 跳转到 `pages/ticket-buy/ticket-buy`
+
+**方案 B:修改 Goods.php 控制器(1 行)**
+```php
+// app/index/controller/Goods.php Index() 方法
+if($goods['item_type'] == 'ticket') {
+ return MyView('/goods/ticket_detail'); // 自定义模板
+}
+return MyView();
+```
+
+**推荐方案 A**(通过插件机制,不修改核心代码)。
+
+---
+
+## 五、新建票务专属页面
+
+### 5.1 在 pages.json 中添加路由
+
+```json
+{
+ "subPackages": [
+ {
+ "root": "pages/ticket-buy",
+ "pages": [
+ {
+ "path": "ticket-buy",
+ "style": {
+ "navigationBarTitleText": "选择座位",
+ "navigationStyle": "custom"
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/ticket-verify",
+ "pages": [
+ {
+ "path": "ticket-verify",
+ "style": {
+ "navigationBarTitleText": "票务核销",
+ "enablePullDownRefresh": false
+ }
+ }
+ ]
+ },
+ {
+ "root": "pages/ticket-wallet",
+ "pages": [
+ {
+ "path": "ticket-wallet",
+ "style": {
+ "navigationBarTitleText": "我的票夹"
+ }
+ }
+ ]
+ }
+ ]
+}
+```
+
+### 5.2 页面目录结构
+
+```
+pages/ticket-buy/
+├── ticket-buy.vue # 选座 + 购票主流程
+└── components/
+ ├── seat-selector.vue # 座位选择器
+ ├── attendee-form.vue # 观演人表单
+ └── purchase-bar.vue # 购买栏
+
+pages/ticket-wallet/
+├── ticket-wallet.vue # 票夹主页面
+└── components/
+ └── ticket-card.vue # 电子票卡片(含 QR 码)
+
+pages/ticket-verify/
+└── ticket-verify.vue # B 端核销页面(参考 realstore/check.vue)
+```
+
+---
+
+## 六、uni.scanCode 扫码能力
+
+### 6.1 基础用法
+
+```javascript
+// 扫码
+uni.scanCode({
+ onlyFromCamera: true, // 只允许相机扫码
+ success: (res) => {
+ console.log('扫码结果:', res.result);
+ // res.result: 扫码内容
+ // res.scanType: 二维码类型(QR_CODE 等)
+ },
+ fail: (err) => {
+ console.error('扫码失败', err);
+ }
+});
+```
+
+### 6.2 在 H5 平台的处理
+
+```vue
+
+
+
+
+
+
+
+ 请输入核销码
+
+
+```
+
+### 6.3 参考实现
+
+ShopXO 的 `realstore/check/check.vue` 已完整实现:
+- 扫码触发 → 自动提交验证
+- 手动输入兼容
+- 成功/失败状态显示
+- 连续扫描(核销后清空输入框)
+
+---
+
+## 七、QR 码展示
+
+### 7.1 后端生成 QR 码图片 URL
+
+```javascript
+// 生成票务 QR 码 URL
+function getTicketQrUrl(ticketId) {
+ const baseUrl = app.globalData.request_url;
+ const ticketData = JSON.stringify({
+ id: ticketId,
+ exp: Date.now() + 30 * 86400 * 1000 // 30天有效期
+ });
+ const encoded = encodeURIComponent(
+ uni.base64ToString(
+ uni.stringToBase64(ticketData)
+ )
+ );
+ return `${baseUrl}?s=index/qrcode/index&content=${encoded}&size=8&level=H`;
+}
+```
+
+### 7.2 在页面中展示
+
+```vue
+
+
+
+ {{ ticket.code }}
+
+
+```
+
+---
+
+## 八、manifest.json 关键配置
+
+### 8.1 多端配置
+
+```json
+{
+ "name": "ShopXO",
+ "appid": "__UNI__50E3C11",
+ "description": "ShopXO开源商城...",
+ "transformPx": false,
+ "app-plus": {
+ "usingComponents": true,
+ "nvueCompiler": "uni-app",
+ "distribute": {
+ "android": { ... },
+ "ios": { ... },
+ "mp-weixin": {
+ "appid": "wx YOUR APPID",
+ "setting": {
+ "urlCheck": false,
+ "es6": true,
+ "minified": true
+ },
+ "usingComponents": true
+ }
+ }
+ }
+}
+```
+
+### 8.2 权限配置(微信小程序)
+
+```json
+"mp-weixin": {
+ "permission": {
+ "scope.userLocation": {
+ "desc": "用于场馆定位"
+ }
+ }
+}
+```
+
+---
+
+## 九、自定义组件注册
+
+### 9.1 全局注册(所有页面可用)
+
+在 `pages/index/index.vue` 的 `style.usingComponents` 中添加:
+
+```json
+"component-ticket-seat": "/pages/ticket-buy/components/seat-selector/seat-selector",
+"component-ticket-card": "/pages/ticket-wallet/components/ticket-card/ticket-card",
+"component-attendee-form": "/pages/ticket-buy/components/attendee-form/attendee-form"
+```
+
+### 9.2 页面级注册
+
+在单个页面的 `pages.json` 中:
+```json
+{
+ "path": "pages/ticket-wallet/ticket-wallet",
+ "style": {
+ "usingComponents": {
+ "component-ticket-card": "/pages/ticket-wallet/components/ticket-card/ticket-card"
+ }
+ }
+}
+```
+
+---
+
+## 十、ShopXO API 调用
+
+### 10.1 请求封装
+
+ShopXO uni-app 使用全局封装的请求方法:
+
+```javascript
+uni.request({
+ url: app.globalData.get_request_url('action', 'controller', 'module'),
+ method: 'POST',
+ data: { ... },
+ success: (res) => {
+ if (res.data.code == 0) {
+ // 成功
+ } else {
+ // 失败
+ }
+ }
+});
+```
+
+### 10.2 插件 API 路径
+
+对于插件的 API:
+```javascript
+// 格式:get_request_url(action, controller, plugins_name)
+const url = app.globalData.get_request_url(
+ 'verify', // action
+ 'adminverify', // controller
+ 'vrticket' // 插件名(apps 目录下的目录名)
+);
+```
+
+### 10.3 鉴权
+
+请求自动带上登录态:
+```javascript
+// 已在全局封装,每次请求自动附加:
+// Header: Authorization / Token
+// 或者通过 Session/Cookie
+```
diff --git a/docs/03_VERIFICATION_SYSTEM.md b/docs/03_VERIFICATION_SYSTEM.md
new file mode 100644
index 0000000..6bf6f1d
--- /dev/null
+++ b/docs/03_VERIFICATION_SYSTEM.md
@@ -0,0 +1,544 @@
+# 核销系统设计
+
+> 调研时间:2026-04-14
+> 关键参考:`realstore/check/check.vue`(自提点核销页)、`sxo_order_extraction_code` 表
+
+---
+
+## 一、系统概述
+
+核销系统解决:用户持电子票 QR 码 → 工作人员验证 → 标记已入场。
+
+### 1.1 核销模式
+
+| 模式 | 说明 | 适用场景 |
+|---|---|---|
+| **扫码核销** | B 端扫用户 QR 码 | 演唱会入口、活动签到 |
+| **手动输入** | B 端输入票码 | 网络不稳定场景 |
+| **双重核销** | 用户扫码 + B 端扫码 | 高安全要求 |
+
+### 1.2 核销粒度
+
+| 粒度 | 说明 | 实现难度 |
+|---|---|---|
+| 按订单 | 一个订单一个码 | ⭐ 最简单 |
+| 按座位 | 每个座位一个码 | ⭐⭐ 推荐 |
+
+**推荐**:按座位核销(每人一个 QR 码),与演唱会场景完全匹配。
+
+---
+
+## 二、QR 票生成
+
+### 2.1 触发时机
+
+**支付成功回调时**(`plugins_service_buy_order_insert_success` 钩子)
+
+### 2.2 QR 码内容设计
+
+```json
+{
+ "id": 12345, // vr_attendees.id
+ "code": "UUID-v4", // ticket_code,唯一标识
+ "event_id": 8,
+ "session_id": 15,
+ "seat": "A区-3排-15座",
+ "exp": 1735689600 // 过期时间(时间戳)
+}
+```
+
+### 2.3 加密方式
+
+不加密(明文 QR):
+- 优点:调试方便,可人工识别
+- 缺点:可伪造
+- 适用:低安全要求、内部活动
+
+**加密 QR**(推荐):
+```php
+$qr_data = json_encode([...]);
+$encrypted = base64_encode(
+ openssl_encrypt($qr_data, 'AES-256-CBC', $secret_key, OPENSSL_RAW_DATA, $iv)
+);
+```
+
+核销时解密验证:
+```php
+$decrypted = openssl_decrypt(
+ base64_decode($encrypted), 'AES-256-CBC',
+ $secret_key, OPENSSL_RAW_DATA, $iv
+);
+```
+
+### 2.4 QR 码生成
+
+使用 ShopXO 内置 `\base\Qrcode` 类:
+
+```php
+// 生成展示用 QR 码 URL
+$ticket_code = $attendee->ticket_code;
+$qr_url = MyUrl('index/qrcode/index', [
+ 'content' => urlencode(base64_encode($ticket_code)),
+ 'size' => 8,
+ 'level' => 'H', // 高容错率,扫码成功率高
+ 'mr' => 2,
+]);
+
+// 生成文件(用于发送邮件/消息)
+$qr_path = (new \base\Qrcode())->Create([
+ 'content' => $ticket_code,
+ 'path' => 'static/upload/tickets/' . date('Y/md') . '/',
+ 'filename' => $ticket_code . '.png',
+ 'level' => 'H',
+ 'size' => 10,
+ 'mr' => 2,
+]);
+```
+
+---
+
+## 三、数据存储
+
+### 3.1 扩展方案 vs 独立表
+
+**方案 A:用 `sxo_order.extension_data`**
+
+```json
+{
+ "item_type": "ticket",
+ "event_id": 8,
+ "session_id": 15,
+ "tickets": [
+ {
+ "attendee_id": 101,
+ "ticket_code": "uuid-xxx",
+ "seat": "A区-3排-15座",
+ "verify_status": 0,
+ "verify_time": null
+ },
+ {
+ "attendee_id": 102,
+ "ticket_code": "uuid-yyy",
+ "seat": "A区-3排-16座",
+ "verify_status": 0,
+ "verify_time": null
+ }
+ ]
+}
+```
+
+优点:无需新建表,查询方便
+缺点:JSON 更新需要整体替换
+
+**方案 B:新建 `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 COMMENT '订单号',
+ `goods_id` int UNSIGNED NOT NULL COMMENT '商品ID',
+ `user_id` int UNSIGNED NOT NULL COMMENT '用户ID',
+ `event_id` int UNSIGNED NOT NULL COMMENT '活动ID',
+ `session_id` int UNSIGNED NOT NULL COMMENT '场次ID',
+ `ticket_code` char(36) NOT NULL COMMENT '票码(UUID)',
+ `qr_data` text COMMENT '加密QR内容',
+ `seat_info` varchar(255) COMMENT '座位信息',
+ `real_name` varchar(60) COMMENT '观演人姓名',
+ `id_card` char(20) COMMENT '身份证号',
+ `phone` char(15) COMMENT '手机号',
+ `verify_status` tinyint DEFAULT 0 COMMENT '核销状态(0未核销, 1已核销)',
+ `verify_time` int UNSIGNED DEFAULT 0 COMMENT '核销时间',
+ `verifier_id` int UNSIGNED DEFAULT 0 COMMENT '核销员ID',
+ `issued_at` int UNSIGNED DEFAULT 0 COMMENT '发放时间',
+ `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 `event_id` (`event_id`),
+ KEY `session_id` (`session_id`),
+ KEY `verify_status` (`verify_status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='VR电子票表';
+```
+
+### 3.2 核销记录表
+
+```sql
+CREATE TABLE `vr_verifications` (
+ `id` int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+ `ticket_id` int UNSIGNED NOT NULL COMMENT '票ID',
+ `ticket_code` char(36) NOT NULL COMMENT '票码',
+ `verifier_id` int UNSIGNED NOT NULL COMMENT '核销员ID',
+ `verifier_name` varchar(60) COMMENT '核销员名称',
+ `event_id` int UNSIGNED COMMENT '活动ID',
+ `session_id` int UNSIGNED COMMENT '场次ID',
+ `ip_address` varchar(45) COMMENT '核销IP',
+ `location` varchar(255) COMMENT '核销地点备注',
+ `created_at` int UNSIGNED DEFAULT 0,
+ KEY `ticket_id` (`ticket_id`),
+ KEY `verifier_id` (`verifier_id`),
+ KEY `created_at` (`created_at`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='核销记录表';
+```
+
+### 3.3 核销员表
+
+```sql
+CREATE TABLE `vr_verifiers` (
+ `id` int UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+ `user_id` int UNSIGNED NOT NULL COMMENT '关联用户ID(ShopXO user.id)',
+ `name` varchar(60) NOT NULL COMMENT '核销员名称',
+ `mobile` char(15) COMMENT '手机号',
+ `event_ids` varchar(255) COMMENT '可核销的活动ID列表(逗号分隔)',
+ `status` tinyint DEFAULT 1 COMMENT '状态(0禁用, 1启用)',
+ `created_at` int UNSIGNED DEFAULT 0,
+ KEY `user_id` (`user_id`),
+ KEY `status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='核销员表';
+```
+
+---
+
+## 四、B 端核销页面
+
+### 4.1 参考实现
+
+**直接 fork** `pages/plugins/realstore/check/check.vue`
+
+### 4.2 页面 UI 设计
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 核销成功
+
+ 活动:{{ result.event_name }}
+ 场次:{{ result.session_time }}
+ 座位:{{ result.seat_info }}
+ 观演人:{{ result.real_name }}
+
+
+
+
+
+
+ 核销失败
+ {{ error_msg }}
+
+
+
+
+
+
+
+ 今日核销
+ {{ stats.today }}
+
+
+ 待核销
+ {{ stats.pending }}
+
+
+ 已核销
+ {{ stats.verified }}
+
+
+
+
+
+```
+
+### 4.3 API 调用
+
+```javascript
+verify_submit() {
+ if (!this.check_value) return;
+
+ uni.showLoading({ title: '核销中...' });
+ this.verify_loading = true;
+
+ uni.request({
+ url: app.globalData.get_request_url('verify', 'ticket', 'vrticket'),
+ method: 'POST',
+ data: {
+ ticket_code: this.check_value,
+ event_id: this.current_event?.id || 0,
+ },
+ success: (res) => {
+ uni.hideLoading();
+ if (res.data.code == 0) {
+ this.result_type = 'success';
+ this.result = res.data.data;
+ this.stats.today++;
+ this.stats.pending--;
+ } else {
+ this.result_type = 'error';
+ this.error_msg = res.data.msg;
+ }
+ // 清空输入框,支持连续扫描
+ this.check_value = '';
+ },
+ fail: () => {
+ uni.hideLoading();
+ this.result_type = 'error';
+ this.error_msg = '网络错误,请重试';
+ },
+ complete: () => {
+ this.verify_loading = false;
+ }
+ });
+}
+```
+
+---
+
+## 五、后端核销 API
+
+### 5.1 接口定义
+
+```
+POST /?s=admin/vrticket/verify
+Content-Type: application/json
+
+{
+ "ticket_code": "uuid-xxx", // 票码
+ "event_id": 8 // 活动ID(可选)
+}
+```
+
+### 5.2 返回格式
+
+**成功**:
+```json
+{
+ "code": 0,
+ "msg": "核销成功",
+ "data": {
+ "ticket_id": 101,
+ "ticket_code": "uuid-xxx",
+ "event_name": "周杰伦2026巡回演唱会",
+ "session_time": "2026-06-01 20:00",
+ "seat_info": "A区-3排-15座",
+ "real_name": "张三",
+ "verify_time": 1745328000
+ }
+}
+```
+
+**失败**:
+```json
+{
+ "code": -1,
+ "msg": "该票已核销"
+}
+```
+
+### 5.3 核销逻辑实现
+
+```php
+// app/plugins/vr_ticket/service/TicketService.php
+
+public static function VerifyTicket($ticket_code, $verifier_id, $event_id = 0)
+{
+ // 1. 查询票
+ $ticket = Db::name('vr_tickets')
+ ->where('ticket_code', $ticket_code)
+ ->find();
+ if (!$ticket) {
+ return DataReturn('票码不存在', -1);
+ }
+
+ // 2. 检查活动匹配
+ if ($event_id > 0 && $ticket['event_id'] != $event_id) {
+ return DataReturn('该票不属于当前活动', -1);
+ }
+
+ // 3. 检查是否已核销
+ if ($ticket['verify_status'] == 1) {
+ return DataReturn('该票已核销(' . date('Y-m-d H:i', $ticket['verify_time']) . ')', -1);
+ }
+
+ // 4. 解密验证(如果加密了)
+ if (!empty($ticket['qr_data'])) {
+ $decrypted = openssl_decrypt(
+ base64_decode($ticket['qr_data']),
+ 'AES-256-CBC',
+ MyC('vrticket_secret_key'),
+ OPENSSL_RAW_DATA,
+ substr(md5($ticket['ticket_code']), 0, 16)
+ );
+ $qr_content = json_decode($decrypted, true);
+
+ // 检查过期
+ if (!empty($qr_content['exp']) && $qr_content['exp'] < time()) {
+ return DataReturn('票已过期', -1);
+ }
+ }
+
+ // 5. 执行核销(事务)
+ Db::startTrans();
+ try {
+ // 更新票状态
+ Db::name('vr_tickets')->where('id', $ticket['id'])->update([
+ 'verify_status' => 1,
+ 'verify_time' => time(),
+ 'verifier_id' => $verifier_id,
+ 'updated_at' => time(),
+ ]);
+
+ // 写入核销记录
+ Db::name('vr_verifications')->insert([
+ 'ticket_id' => $ticket['id'],
+ 'ticket_code' => $ticket_code,
+ 'verifier_id' => $verifier_id,
+ 'verifier_name' => self::GetVerifierName($verifier_id),
+ 'event_id' => $ticket['event_id'],
+ 'session_id' => $ticket['session_id'],
+ 'created_at' => time(),
+ ]);
+
+ Db::commit();
+ } catch (\Exception $e) {
+ Db::rollback();
+ return DataReturn('核销失败:' . $e->getMessage(), -1);
+ }
+
+ // 6. 返回票信息
+ $ticket['verify_status'] = 1;
+ $ticket['verify_time'] = time();
+ return DataReturn('核销成功', 0, self::FormatTicketInfo($ticket));
+}
+```
+
+---
+
+## 六、C 端票夹(用户查看已购票)
+
+### 6.1 页面入口
+
+通过用户中心钩子注入:`plugins_view_user_various_inside_top`
+
+### 6.2 页面内容
+
+显示用户所有已支付订单中的票务商品,每张票一行:
+
+```
+┌─────────────────────────────────────┐
+│ 🎵 周杰伦2026巡回演唱会 │
+│ 📅 2026-06-01 20:00 │
+│ 📍 国家体育馆 │
+│ 💺 A区-3排-15座 │
+│ │
+│ ┌─────────┐ 状态: │
+│ │ QR CODE │ ✅ 已核销 / ⏳ 待使用 │
+│ └─────────┘ │
+└─────────────────────────────────────┘
+```
+
+### 6.3 核销状态实时更新(可选)
+
+如果需要实时更新核销状态:
+- 方案 A(推荐):用户进入票夹时刷新状态
+- 方案 B:WebSocket 推送(ShopXO 无内置 WebSocket)
+- 方案 C:页面可见时通过 `onShow` 刷新
+
+---
+
+## 七、部署形态
+
+### 7.1 B 端核销页面部署
+
+| 形态 | 说明 | 推荐度 |
+|---|---|---|
+| **uni-app B 端插件页** | `pages/plugins/vr-ticket-verify/` | ✅ 最佳 |
+| **ShopXO H5 管理后台** | `/admin/ticket-verify/` | ⚠️ 个人小程序无法内嵌 |
+| **独立微信小程序** | 单独注册 B 端小程序 | ⚠️ 需额外资质 |
+
+### 7.2 个人主体小程序限制
+
+- ❌ 禁止 web-view(无法内嵌 H5)
+- ✅ 可以新建另一个小程序(独立 AppID)
+- ✅ 可以用 `uni.scanCode` 做纯小程序核销页
+
+### 7.3 推荐方案
+
+**演唱会现场**:用 ShopXO 的 uni-app 新建 `vr-ticket-verify` 插件页面。工作人员用自己的微信账号(授权为核销员)登录 ShopXO 小程序,访问核销页面。
+
+**部署**:
+1. 把 `vr-ticket-verify` 作为 ShopXO uni-app 的插件发布
+2. 工作人员在小程序中访问该页面
+3. 手机对着票 QR 码扫描
+
+---
+
+## 八、核销统计
+
+### 8.1 实时统计 API
+
+```
+GET /?s=admin/vrticket/stats&event_id=8
+```
+
+返回:
+```json
+{
+ "code": 0,
+ "data": {
+ "total_tickets": 500,
+ "verified": 320,
+ "pending": 180,
+ "today": 45
+ }
+}
+```
+
+### 8.2 核销大屏
+
+可在演唱会入口放置一个大屏电视,显示实时核销进度:
+- 总票数 / 已核销数 / 待核销数
+- 每分钟核销速度
+- 最近核销记录滚动列表
+
+实现方式:轮询 stats API + 数字动画(CountUp.js)
diff --git a/docs/04_IMPLEMENTATION_ROADMAP.md b/docs/04_IMPLEMENTATION_ROADMAP.md
new file mode 100644
index 0000000..7263353
--- /dev/null
+++ b/docs/04_IMPLEMENTATION_ROADMAP.md
@@ -0,0 +1,421 @@
+# 实施路线图
+
+> 规划时间: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 开发环境
+
+### 任务
+
+1. **Docker 部署 ShopXO**(参考 `DEPLOYMENT.md`)
+ - PHP 8.0+ / MySQL 5.7+ / nginx
+ - 或使用虚拟主机安装包
+
+2. **安装 shopxo-uniapp**
+ - HBuilderX 导入项目
+ - 配置 `request_url` 和 `static_url`
+ - 本地 H5 预览验证
+
+3. **创建插件骨架**
+ ```bash
+ 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/
+ ```
+
+4. **在 ShopXO 后台安装插件**
+ - 访问 `/admin/plugins/index`
+ - 上传插件 zip 或手动放置到 `app/plugins/vr_ticket/`
+ - 点击安装
+
+### 验收
+
+- ShopXO H5 前端正常访问
+- shopxo-uniapp H5 预览正常
+- 插件在后台可见
+
+---
+
+## 三、Phase 1 — 数据库设计
+
+### 任务
+
+创建插件迁移文件:
+
+```sql
+-- 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
+
+### 任务
+
+1. **管理端页面**(后台)
+ - `Admin/Controller/EventController.php` — 活动管理
+ - `Admin/Controller/SessionController.php` — 场次管理
+ - `Admin/View/event_list.html` — 活动列表
+ - `Admin/View/session_edit.html` — 场次编辑
+
+2. **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` 注入观演人表单:
+
+```html
+
+
+ 观演人信息
+
+
+
+
+
+ + 添加观演人
+
+```
+
+### 5.3 数据收集流程
+
+1. 用户在前端填写观演人信息
+2. 前端将观演人数据存入本地(`uni.setStorage`)
+3. 点击购买时,将观演人数据通过插件 API 暂存
+4. 插件在 `plugins_service_buy_order_insert_begin` 钩子中将观演人数据写入 `vr_tickets` 表
+
+### 5.4 钩子实现
+
+```php
+// 插件 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 任务
+
+```php
+// 插件 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 实现):
+```vue
+
+
+
+
+ 可选
+ 已选
+ 已售
+
+
+
+```
+
+### 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 端核销页
+
+### 任务
+
+1. **插件 API**:`Api/Controller/TicketController.php`
+ - `verify()` — 核销验证
+
+2. **uni-app 核销页**:
+ - Fork `pages/plugins/realstore/check/check.vue`
+ - 改造成 `pages/plugins/vr-ticket-verify/check/check.vue`
+ - 调整 API 路径和返回处理
+
+3. **后台核销统计**:
+ - `Admin/Controller/TicketController.php`
+ - `Admin/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 周 | 微信审核 + 正式上线 |