vr-shopxo-uniapp/backend-review-report.md

297 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# BackendReviewer — VR票务补充文档审查报告
> 审查时间2026-05-14
> 审查人BackendReviewer后端架构师视角
> 文档:`vr-ticket-uniapp-supplement.md`
---
## 文档评分7/10
文档结构完整覆盖了核心数据结构、API 接口、交互规范。但存在若干后端实现与文档描述不一致的问题,以及缺少关键实现细节。
---
## 一、发现的问题
### 问题 1QR payload 结构错误P0 高优先级)
**文档描述**(第 6.1 节):
```json
{ "id": 482815, "g": 118, "iat": 1745286000, "exp": 1745287800 }
```
**实际后端**`TicketService.php:191-197`
```php
$qr_payload = BaseService::signQrPayload([
'id' => $ticket_id,
'g' => $og['goods_id'],
'code' => $ticket_code, // ← 文档漏掉了这个字段!
'iat' => $now,
'exp' => $now + 1800,
]);
```
**影响**:前端按文档解析 QR payload 会缺少 `code` 字段,导致:
- 无法通过 QR 拿到 ticket_code核销时可能需要
- QR 验签逻辑可能失败(后端用 `code` 生成签名)
**修复建议**:文档第 6.1 节 QR payload 应补充 `code` 字段:
```json
{
"id": 482815,
"g": 118,
"code": "uuid格式-xxx-xxx",
"iat": 1745286000,
"exp": 1745287800
}
```
---
### 问题 2Auth 鉴权机制描述不准确P1
**文档描述**(第 2.3 节):
> 无参数(依赖 C 端 session
**实际后端**`api/Ticket.php:24-57`
```php
// 支持三种方式:
// 1. X-Token header
// 2. Authorization: Bearer xxx header
// 3. cookie user_info
// 4. ShopXO 标准 session
```
**影响**:前端需要明确使用哪个 Auth 方式。UniApp 中推荐使用 `X-Token` header。
**修复建议**:文档第 2.3 节补充鉴权说明:
```
请求 Header: X-Token: {user_token}
响应 401: 未登录,跳转登录页
```
---
### 问题 3CartSave extension_data 存储链路不清晰P1
**文档描述**(第 2.2 节):
```json
"extension_data": "{\"attendee\":{...},\"seat\":{...}}"
```
**实际后端**
1. `CartSave``extension_data` 存入订单主表 `order.extension_data`
2. `onOrderPaid` Hook 从 `order.extension_data` 读取 `attendee` 信息
3. **但**观演人信息实际上是多座位时每座一个,而不是整个订单共用一个
**问题**:当用户选多个座位时,每个座位的 `extension_data` 独立存储在各自的 `order_detail` 中,而不是订单主表。后端需要知道每个座位对应哪个观演人。
**实际实现**待确认ShopXO BuyService 是否支持将 `extension_data` 写入 `order_detail` 表?
**修复建议**:文档需要明确:
- `extension_data` 写入位置order 主表 vs order_detail 行)
- 多座位场景下,每个 `goods_data` 条目携带各自的 `extension_data`
- 后端 TicketService 如何从 `order_detail` 获取每座的 attendee 信息
---
### 问题 4seatSpecMap 获取方式未确定P1
**文档**(第 4.5 节):
> 待确认seatSpecMap 获取方式
> - 方案 A推荐后端在商品详情 API 中直接返回
> - 方案 B前端 JS 重建(不推荐)
> - 方案 C新增独立接口
**实际情况**
- `SeatSkuService::GetGoodsViewData()` 是 PHP 方法UniApp 无法直接调用
- 商品详情 API `/api/goods/detail` 默认不返回 `seatSpecMap`
- 后端需要改造:在商品详情响应中嵌入 `seatSpecMap`
**修复建议**:文档应明确推荐方案 A并列出后端改造任务
```
后端任务:在 GoodsService 或插件 hook 中,
当 goods.is_vr_ticket=1 时,在商品详情响应中注入 seatSpecMap
```
---
### 问题 5票夹列表响应字段不完整P2
**文档描述**(第 2.3 节):
```json
{
"id": 482815,
"goods_id": 118,
"goods_title": "VR演唱会",
"seat_info": "主要展厅 A区 1排1座",
"session_time": "15:00-16:59",
"venue_name": "测试场馆",
"real_name": "张三",
"verify_status": 0,
"issued_at": "2026-05-01 12:00:00",
"short_code": "003a2hgmgety"
}
```
**实际后端**`WalletService::getUserTickets`
- `seat_info` 格式:`场次|场馆|演播室|分区|座位号`5段用竖线分隔
- 需要确认返回字段是否与文档一致
**修复建议**:补充 `qr_data` 字段说明(可选,用于直接展示 QR 图)
---
## 二、关键 Gap前端开发前必须确认
### Gap 1seatSpecMap 返回方式P0
**问题**:前端无法获取座位规格映射表,导致选座功能无法实现。
**必须解决**:后端需要在商品详情 API 响应中返回 `seatSpecMap`,或在插件中新增专用接口。
**截止时间**Phase 2 开发前必须完成
---
### Gap 2CartSave extension_data 传递链路P0
**问题**:多座位下单时,每个座位的观演人信息如何传递到后端?
**必须解决**:确认 ShopXO BuyService 如何处理 `extension_data`
- 写入 `order.extension_data` 还是 `order_detail`
- 多座位场景下每座独立的 extension_data 如何存储?
**截止时间**Phase 3 开发前必须完成
---
### Gap 3QR payload 验签逻辑P1
**问题**:前端需要验证 QR payload 的有效性(含 `code` 字段的签名验证)
**必须解决**
1. 文档更新 QR payload 结构(补充 `code` 字段)
2. 后端提供签名字段 `sig` 的生成方式HMAC-SHA256
3. 前端需要知道 secret 从哪里获取(后端提供接口?)
**截止时间**:票详情页开发前必须完成
---
## 三、改进建议(具体的、可操作的)
### 建议 1更新 QR payload 文档(第 6.1 节)
```markdown
### 6.1 QR 票数据结构
```json
// QR payloadBase64 编码)
{
"id": 482815,
"g": 118,
"code": "uuid格式-xxx-xxx",
"iat": 1745286000,
"exp": 1745287800
}
// 签名sig = HMAC-SHA256("code.id.g.iat.exp", secret) 取前8位
```
```
### 建议 2补充 Auth 鉴权说明(第 2.3 节)
```markdown
### 票夹 API
**请求 Header**
```
X-Token: {user_token}
```
(也支持 Authorization: Bearer xxxShopXO session cookie
**响应 401**:未登录,跳转登录页
```
### 建议 3明确后端待配合事项第 9 节)
```markdown
## 九、后端待配合事项
1. **seatSpecMap 返回**:在商品详情 API 响应中嵌入 `seatSpecMap`
- 触发条件:`goods.is_vr_ticket = 1`
- 数据来源:`SeatSkuService::buildSeatSpecMap()`
- 预计工作量2h
2. **CartSave 链路确认**
- 确认 extension_data 是否写入 order_detail
- 多座位场景下每座独立的 attendee 信息如何存储
3. **QR 签名字段说明**
- 提供前端验签所需的 secret 获取方式
- 或提供后端验签接口
```
---
## 四、对前端开发者的建议3条
### 1. 优先确认 seatSpecMap 接口
在开始选座功能开发前,必须与后端确认:
- seatSpecMap 通过哪个 API 获取?
- 返回的数据结构是否与文档一致?
**建议**:先让后端在商品详情 API 中返回 seatSpecMap再开始前端开发。
---
### 2. Auth 统一使用 X-Token
UniApp 中统一使用 `X-Token` header 进行用户鉴权:
```javascript
uni.request({
url: '...',
header: {
'X-Token': uni.getStorageSync('token')
}
})
```
避免混用 Authorization 或 cookie。
---
### 3. QR 验签先做本地过期检查
前端先做本地过期检查,再考虑签名验证:
```javascript
const payload = JSON.parse(atob(qr_data.split('|')[1]));
if (payload.exp < Date.now() / 1000) {
// 已过期,调用 refreshQr 接口获取新 QR
}
```
签名验证sig 字段)可延后实现,先确保核心功能可用。
---
## 五、审查总结
| 维度 | 评分 | 说明 |
|------|------|------|
| 数据结构 | 9/10 | 描述清晰,与后端一致 |
| API 接口 | 6/10 | 存在不一致和缺失QR payload、Auth |
| 交互规范 | 8/10 | 详细,可直接参考 |
| 实现细节 | 5/10 | 缺少关键链路说明extension_data |
**综合评分7/10**
文档整体质量良好,但 API 部分需要后端确认和修正,特别是:
1. QR payload 结构(缺少 code 字段)
2. Auth 鉴权机制(需明确 X-Token 方式)
3. extension_data 存储链路(多座位场景)
这三个问题必须在 Phase 2 开发前解决,否则前端无法正确实现购票和票夹功能。