# Agent 任务卡 — vr-shopxo-plugin

> 每次派 agent 任务前，先读本文件和 `DEVELOPMENT_GUIDELINES.md`。
> 每次任务以一个小目标为限，做完汇报，不要一次塞太多。

---

## 当前项目状态

**分支**: `feat/phase4-ticket-wallet`
**主分支**: `main`（干净，无 ShopXO 核心修改）
**已验证可用**: Docker 环境 + ShopXO 后台

**已完成的文件（可直接引用/继续开发）：**
- `service/WalletService.php` — 票夹查询 + QR JWT 签名 + 短码编码（HMAC-XOR）
- `service/TicketService.php` — 发票/核销逻辑
- `view/goods/ticket_card.html` — 票卡 UI 片段
- `view/goods/ticket_wallet.html` — C端票夹整页
- `service/AuditService.php` — 核销审计日志
- `database/migrations/001_vr_tables.sql` — 表结构（tickets/verifiers/verifications/audit_log）
- `tests/phase4_1_feistel_test.php` — 单元测试（HMAC-XOR + QR 签名）

**Phase 4 待完成（优先级从高到低）：**

| # | 任务 | 难度 | 约束 |
|---|------|------|------|
| 1 | **C端票夹 API** + 挂载到 ShopXO 用户中心 | 中 | 改动在插件内，ShopXO 核心不动 |
| 2 | **B端核销 API** `/?s=api/vr_ticket/verify` | 低 | 已有 AuditService，只需写 API 控制器 |
| 3 | **B端核销页面** admin 侧边栏入口 + 核销操作页 | 中 | 复用 ShopXO Layui 风格 |
| 4 | **出票链路闭环** `order.paid` 事件 → `issueTicket()` | 中 | 参考 Phase 4 Plan §5 |
| 5 | **Migration 002** `002_ticket_wallet.sql` | 低 | 无需存 short_code（实时编码），检查 001 是否完整 |

---

## 任务卡 1：C端票夹 API + 前端挂载

**目标**：用户访问票夹页 `/?s=user/wallet` 时展示 vr_ticket 票。

### Step 1 — API 端点

文件：`shopxo/app/plugins/vr_ticket/api/Ticket.php`

参考 Phase 4 Plan §3.3，新增两个方法：

```php
// GET /?s=api/vr_ticket/tickets
// 返回：当前用户所有票（已购、未核销）
public function tickets()
{
    // 1. 取当前登录用户 $userId
    // 2. 调用 WalletService::getUserTickets($userId)
    // 3. 返回 JSON: { code: 0, data: [...] }
}
```

### Step 2 — 页面挂载

文件：`view/goods/ticket_wallet.html`

在 ShopXO 用户中心挂载点（找 `ModuleInclude('模块名')`）渲染此页面。
参考 ShopXO 现有用户中心模板路径：`app/index/view/default/user/wallet.html`

**约束**：
- 不要新建路由，只在现有用户中心挂载
- 使用 `{module_include('vr_ticket/wallet')}` 方式挂载（先查 ShopXO 是否支持此语法）
- 如不支持，改为在 `User.php` 控制器渲染时 include 票夹片段

### Step 3 — 验证

Docker 内 curl 测试：
```bash
curl "http://localhost:10000/?s=api/vr_ticket/tickets&uid=1"
```
预期：返回 JSON（含 code、data 数组）

---

## 任务卡 2：B端核销 API

**目标**：`POST /?s=api/vr_ticket/verify` — 核销一张票。

### 文件

`shopxo/app/plugins/vr_ticket/api/Ticket.php`

### 接口规范

```
POST /?s=api/vr_ticket/verify
Body: { "ticket_id": 482815 }
    或 { "short_code": "7J4F9X2M" }
    或 { "qr_payload": "eyJpZCI6NDgyODE1L..." }

Response:
  成功: { "code": 0, "msg": "核销成功", "data": { "ticket_id": 482815, "verified_at": "..." } }
  失败: { "code": 1, "msg": "票不存在/已核销/无权核销" }
```

### 实现

```php
public function verify()
{
    // 1. 解析请求（支持 ticket_id / short_code / qr_payload 三种入口）
    // 2. 短码解码: ShortCodeService::decode($short_code) → [goods_id, ticket_id]
    // 3. QR payload 验签: WalletService::verifyQrPayload($qr_payload) → ticket_id
    // 4. TicketService::verifyTicket($ticketId, $verifierId)
    // 5. AuditService::log() 记录
    // 6. 返回结果
}
```

### 约束

- 不写死 `$verifierId = 1` — 从 `$_POST['verifier_id']` 或 Session 读取
- 验签失败的 QR payload 返回 code=1（不暴露内部错误）
- 日志必须写入 `vr_audit_log` 表

---

## 任务卡 3：B端核销页面

**目标**：在 ShopXO 后台 admin 侧边栏新增「票务核销」菜单项。

### 文件

- 控制器：`shopxo/app/plugins/vr_ticket/admin/Admin.php` — 新增 `Verify()` 方法
- 视图：`shopxo/app/plugins/vr_ticket/view/admin/verify.html`

### 实现要点

1. **侧边栏入口**：通过 `event.php` 的 `plugins_service_admin_menu_data` hook（如已注册则跳过此步）
2. **核销页面**：两个入口
   - 扫码抢扫入 → 输入 QR payload 或 ticket_id
   - 手动输入短码
3. **UI 风格**：复用 ShopXO Layui（`am-btn`、`am-form` 等 class）
4. **核销结果展示**：成功后显示票面信息（场次/座位/观演人姓名），并更新数据库状态

### 参考文件

- 已有后台视图：`shopxo/app/plugins/vr_ticket/view/admin/setup.html`
- 已有后台控制器风格：`shopxo/app/plugins/vr_ticket/admin/Admin.php`

---

## 任务卡 4：出票链路闭环（支付成功 → 发票）

**目标**：ShopXO 订单支付成功后，自动触发 `TicketService::issueTicket()`。

### 现状分析

1. ShopXO 订单表 `vrt_orders` 有 `order_status` 字段
2. `vrt_vr_tickets` 表已存在（001_migration），字段完整
3. `TicketService::issueTicket()` 已实现（需要确认参数格式）

### 需要做的事

找到 ShopXO 支付成功的事件钩子：
```
plugins_service_order_pay_success_handle_end
```
（在 `event.php` 的 vr_ticket hooks 中已注册，需要确认是否在运行）

1. 确认此 hook 能否收到 `$params['order_id']`
2. 确认 `$params` 中有哪些可用数据（收货地址、观演人信息等）
3. 如 hook 数据不足，改为监听更早的事件（如 `plugins_service_orders_save_thing_end`）

### 参考

Phase 4 Plan §5：「支付回调链路」

---

## 任务卡 5：Migration 002 — 补全票夹所需表/字段

**目标**：检查 001_migration 是否缺少票夹必要的字段，补全。

### 需要确认的字段

```
vrt_vr_tickets
  ✅ id (BIGINT PK)
  ✅ order_id (BIGINT)
  ✅ goods_id (BIGINT)
  ✅ user_id (BIGINT)
  ✅ seat_info (JSON) — 场次/座位信息
  ✅ verify_status (TINYINT) — 0=未核销 1=已核销
  ✅ verified_at (DATETIME, NULL)
  ✅ created_at
  ❓ user_name (VARCHAR) — 观演人姓名，从哪来？
  ❓ user_phone (VARCHAR) — 观演人电话，从哪来？
```

### 执行方式

1. 写 `database/migrations/002_ticket_wallet.sql`
2. 确认每个字段的来源（订单表？商品表？支付回调参数？）
3. **不要直接执行** — 提交 SQL 文件，用户在本地 Docker 验证后再执行

---

## 约束提醒（必读）

1. **ShopXO 核心文件禁止修改** — `shopxo/app/`、`shopxo/config/` 等禁止改动，插件代码放在 `shopxo/app/plugins/vr_ticket/`
2. **数据库操作必须以 migration SQL 文件提交** — 不要直接 docker exec mysql 执行
3. **Docker 操作尽量避免** — 优先在宿主机写文件，重启容器验证
4. **commit 前必须自检** — `git status`，确认没有意外改动 ShopXO 核心文件
5. **任务完成后汇报格式**：
   - ✅ 完成：做了XX
   - ⚠️ 阻塞：缺少XX，需要用户确认
   - ❌ 失败：XX 报错，尝试了YY未能解决

---

*最后更新：2026-04-24 by 西莉雅*
