diff --git a/docs/AGENT_TASKS.md b/docs/AGENT_TASKS.md new file mode 100644 index 0000000..0df5a46 --- /dev/null +++ b/docs/AGENT_TASKS.md @@ -0,0 +1,215 @@ +# 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 西莉雅*