From a3ef16034ec1409040b39932d0f2d09d2464dc34 Mon Sep 17 00:00:00 2001 From: Council Date: Wed, 15 Apr 2026 19:40:44 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E7=94=B2=E6=96=B9=E6=96=B0=E9=9C=80?= =?UTF-8?q?=E6=B1=82=E6=96=87=E6=A1=A3=EF=BC=88=E5=A4=9A=E5=BA=A7=E4=BD=8D?= =?UTF-8?q?=E5=8D=95=E8=AE=A2=E5=8D=95/=E6=A0=B8=E9=94=80=E7=A0=81?= =?UTF-8?q?=E5=8D=A1=E5=A4=B9/ext=E5=BF=85=E5=A1=AB=E5=AD=97=E6=AE=B5/?= =?UTF-8?q?=E6=89=8B=E6=9C=BA=E5=8F=B7=E8=AE=A2=E5=8D=95=E7=BA=A7=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/10_NEW_REQUIREMENTS_20260415.md | 165 +++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 docs/10_NEW_REQUIREMENTS_20260415.md diff --git a/docs/10_NEW_REQUIREMENTS_20260415.md b/docs/10_NEW_REQUIREMENTS_20260415.md new file mode 100644 index 0000000..aaf0b0c --- /dev/null +++ b/docs/10_NEW_REQUIREMENTS_20260415.md @@ -0,0 +1,165 @@ +# 甲方新需求文档(2026-04-15) + +## 来源 + +2026-04-15 下午,甲方补充需求,已与大头确认。 + +--- + +## 需求内容 + +### 需求 1:多座位单订单 +一个订单可包含多个座位,每个座位生成独立核销码。 + +**技术要求**: +- 每个座位 = 一个 ShopXO SKU(spec_base_id),stock=1 +- 一次购买多个不同座位 = 多个 goods_params 条目(同一 goods_id + 不同 spec_base_id) +- ShopXO 原生支持多 spec_base_id 同单购买,各生成独立 order_goods 行 ✅ + +### 需求 2:核销码卡夹展示(订单详情页) +订单详情展示多个 QR 核销码,交互如下: +- 手动滑切换(类似轮播,但手动) +- 每个 QR 独立状态:已核销 → 灰掉 +- 自动切换到下一张未核销的 QR +- 买了 N 个座位 → 显示 N 个 QR + +**技术要求**: +- 多行 `order_goods` → 多张 `vr_tickets` QR +- 前端轮播组件(uni-app) +- Realtime 订阅:核销状态变更 → 前端自动更新 + +### 需求 3:商品级必填信息配置 +商品 `ext` 字段声明购买时用户需填写的必填信息。 + +**字段设计(建议)**: +```json +{ + "required_fields": ["id_card", "phone"], + "field_labels": { + "id_card": "身份证号", + "phone": "手机号" + } +} +``` + +**逻辑**: +- `ext` 为空 → 下单不弹窗,直接购买 +- `ext` 有内容 → 弹窗要求填写,填写后附在订单备注 + +### 需求 4:手机号自动填充(订单级) +- 默认自动填微信认证手机号(wx.getPhoneNumber),可编辑 +- 手机号是**购买凭据**(售后定位用) +- **同一订单多个座位/核销码 → 只需填一份联系信息**(订单级,非座位级) + +--- + +## ShopXO 多 Spec_base_id 同单购买验证 + +### 源码分析结论 + +**问题**:ShopXO 能否在同一次购买中,用同一个 `goods_id` + 不同 `spec_base_id`,各买 1 个? + +**结论:✅ 支持** + +### 源码证据 + +**BuyService.php 关键路径**: + +``` +goods_params = [ + { goods_id: 112, spec_base_id: 1001, stock: 1 }, ← 座位A1 + { goods_id: 112, spec_base_id: 1002, stock: 1 } ← 座位B2 +] +``` + +1. **BuyGoods()**:`foreach($params['goods_data'] as $v)` → 每个 goods_params 条目 → 一个 `$data[]` 元素 +2. **OrderSplitService::Run()**:按 warehouse 分组(非 goods_id 合并)→ 不同 spec_base_id 保留为不同 goods_items[] +3. **OrderInsert()**:`foreach($v['goods_items'] as $vs)` → 每个 goods_items 条目 → **一行 order_goods** + +```php +// BuyService.php:786 +foreach($v['goods_items'] as $vs) +{ + $order['detail_data'][] = [ + 'goods_id' => $vs['goods_id'], + 'price' => $vs['price'], + 'buy_number' => intval($vs['stock']), // = 1 + // ... + ]; +} +``` + +**结果**: +- goods_id=112, spec_base_id=1001 → order_goods 第1行(座位A1) +- goods_id=112, spec_base_id=1002 → order_goods 第2行(座位B2) +- 两个座位,同一订单,各生成独立 vr_tickets QR ✅ + +### 与需求对应关系 + +| 甲方需求 | 技术实现 | 状态 | +|---------|---------|------| +| 多座位单订单 | 每座位 = 独立 spec_base_id,stock=1 | ✅ | +| 多核销码 | 多行 order_goods → 多张 vr_tickets QR | ✅ | +| ext 必填字段 | extension_data.required_fields | ✅ | +| 手机号订单级 | 联系信息挂 order 备注,非 goods_params | ✅ | + +--- + +## 当前数据库状态(已验证) + +```sql +-- 商品 112 票务商品 +is_exist_many_spec = 0 -- ShopXO 认为无多规格 +spec_base 表 = 空的 -- 没有任何 SKU + +-- vr_seat_templates.spec_base_id_map +-- {"A": 1001, "B": 1002, "C": 1003} ← 这些 ID 在 DB 里不存在! +``` + +**问题**:ShopXO 防超卖机制完全未启用,购买走裸商品逻辑。 + +--- + +## spec_value 绑定方案($vr- 前缀) + +### 方案已确认 + +ShopXO spec name 允许特殊字符($,-,中文),无字符过滤。 + +### 插件专用规格命名 + +``` +$vr-场馆 → 场馆名称(如 $vr-场馆 = "鸟巢") +$vr-分区 → 座位分区(Zone) +$vr-时段 → 场次时间 +``` + +### 为什么不会与用户规格冲突 + +- 插件票务商品使用自定义模板 `ticket_detail.html` +- 前端 UI 不走 ShopXO 默认规格选择器 +- 用户无法通过默认界面触碰到 `$vr-` 规格 + +--- + +## 方案 A(每个座位一个 SPEC)兼容性 + +**结论:方案 A 完全兼容甲方全部 4 项新需求** + +| 需求 | 方案 A 如何满足 | +|-----|---------------| +| 多座位单订单 | 每座位 = SKU,ShopXO 原生支持多 SKU 同单 ✅ | +| 核销码卡夹 | order_goods × N → vr_tickets × N → N 张 QR ✅ | +| ext 必填字段 | goods.extension_data.required_fields ✅ | +| 手机号订单级 | 联系信息不写在 goods_params,写在 order 备注 ✅ | + +--- + +## 待办事项 + +- [ ] Issue #9:方案 A vs B 最终决策 +- [ ] 紧急修复:is_exist_many_spec → 1 + 正确生成每个座位的 SKU +- [ ] 后台批量创建 SKU 实现(方案 A 关键路径) +- [ ] ext.required_fields 前端弹窗实现 +- [ ] 订单详情核销码卡夹组件 +- [ ] 微信手机号自动填充 API 集成