vr-shopxo-plugin/docs/council-research-output.md

14 KiB
Raw Blame History

ShopXO 酷炫前端模板实现方案调研报告

调研日期2026-04-20 状态:Round 3 收敛版本 参与FrontendDev (Q1/Q4)、BackendArchitect (Q2)、ProductManager (Q3)、FirstPrinciples (Q4 集成)


Q2 结论:单订单多 SKU 支持

核心答案

ShopXO 订单模型技术上支持同一商品多规格(多 SKU出现在同一订单中,但现有 vr_ticket 模板的 submit() 只传单行,完整多座位下单需要做两件事:① 让前端传多行 goods_data,② 阻止 OrderSplitService 按 warehouse 拆单。

证据来源

文件 关键代码 说明
BuyService.php:86 foreach($params['goods_data'] as $v) 循环处理每个商品项,每项独立 spec_base_id
BuyService.php:423-435 extension_data JSON 序列化 每行 item 支持挂载座位/观演人扩展数据
BuyService.php:101 md5(goods_id + spec implode) 内部用 goods_id+spec 组合生成唯一行 ID
OrderSplitService.php:52-53 GoodsWarehouseAggregate() 拆单触发点:按仓库分组,多 SKU 同一仓库则合并
OrderSplitService.php:289-310 按 spec MD5 找 spec_base_id spec_base_id 已可不同(座位级 SKU
ticket_detail.html:413-436 goodsParamsList.map() Plan A 代码已写好,但 URL 只传第一行bug

最小可行方案Multi-Seat Now

改动点仅 3 处,全在 ticket_detail.html不碰 ShopXO 核心:

ticket_detail.html submit() 函数

BEFORE:  location.href = checkoutUrl + '&goods_params=' + encodeURIComponent(goodsParams)
AFTER:   goodsParamsList 整体 base64 编码,拆分成多条 goods_data 逐条 POST 到 CartSave
         然后跳转到合并支付流程ShopXO 购物车天然支持多商品同单)

为什么走购物车路线更稳:

  • BuyCartBuyTypeGoodsList → 直接调用 BuyGoods,完美支持多 goods_data
  • 不需要hook OrderSplitService,购物车结算路径不触发按仓库拆单(只按商品拆)
  • 核销逻辑不受影响:支付成功后 plugins_service_order_pay_success_handle_end 钩子正常触发

理想方案Multi-Seat Proper

在插件中挂载 plugins_service_buy_group_goods_handle 钩子,拦截 OrderSplitService,将同一 goods_id + 不同 spec_base_id 的多行合并进同一个 order_base

plugins_service_buy_group_goods_handle:
  - 按 goods_id 聚合,而非按 warehouse_id
  - 每个 goods_id 只生成一条 order_basegoods_items 内嵌多个 spec_base_id 不同的行
  - extension_data 按座位索引扁平化存储

ShopXO 官方立场:这是非标准用法,建议走购物车路线。

最大风险点

  1. OrderSplitService 按仓库拆单 — 如果场次商品和周边商品挂在不同仓库,多座位票务订单会被拆成多个子单。用户会收到多笔支付通知,体验割裂。→ 最小方案走购物车绕过此风险
  2. 座位级 SKU 未在 ShopXO 后台创建specBaseIdMap 依赖数据库中已存在的 sxo_goods_spec_base 记录。如果模板生成的 seatKey如 "A_1")没有对应的 spec_base_idsubmit() 会降级到 Zone 级别 SKU同一 zone 全部座位共享一个 spec失去座位粒度。→ 需要后台管理员先为每个座位创建规格

优先级与依赖

  • Q2 是 Q4 的前提 — Q4 的"多座位选座流程"依赖 Q2 的多 SKU 订单能力。
  • Q2 本身不依赖 Q1可以独立推进。
  • Q3 和 Q4 无依赖,但 Q3 生成的代码需适配 Q4 选型H5 vs uni-app

Q1 结论ShopXO 自定义模板最佳实践

核心答案

票务详情页不走 DIY 设计器,直接修改 ticket_detail.html 的 PHP+原生 JSuni-app 端 fork shopxo-uniapp 改写 goods-detail.vue,无需经过 ShopXO 模板中间层。

证据来源

文件/文档 结论
docs/02_FRONTEND_CUSTOMIZATION.md DIY 设计器只支持静态 HTML 区块嵌入无法参数化uni-app 完全独立于 ShopXO 模板
docs/12_UNIAPP_FRONTEND_RESEARCH.md shopxo-uniapp 是独立 Vue 项目,通过 API 对接 ShopXOCSS 在 H5/小程序完全一致WebView 同源)
docs/14_TEMPLATE_RENDER_INVESTIGATION.md ShopXO view/goods/ 模板使用原生 PHP + 原生 JSsession/buy 等控制器直接 render
ticket_detail.html 当前已实现:场次选择 + 座位图渲染 + 观演人表单 + 购买栏

最小可行方案

H5 端:在现有 ticket_detail.html 基础上增强,引入:

  • 座位类型图例(已完成)
  • 已售座位 AJAX 实时标记(待实现 loadSoldSeats()
  • 座位缩放/拖拽交互(原生 JS<200 行)
  • 动态场次切换时重置已选座位(已写但未调用)

技术栈原生 HTML + 内联 CSS + 内联 JS无框架依赖ShopXO 模板系统直接渲染,无需构建。

理想方案

uni-app 端

  1. Fork shopxo-uniappvr-shopxo-uniapp
  2. 重写 pages/goods-detail/goods-detail.vue,接入 vr_ticket API
  3. 新建 pages/ticket-seat/ticket-seat.vue(选座主流程)
  4. 新建 pages/ticket-wallet/ticket-wallet.vue(票夹)
  5. H5 本地预览 = 小程序编译效果CSS 完全一致

关键约束uni-app 开发规范)

  • rpx 不用 vw/vh
  • <view> 不用 <div>
  • 避免 calc() 混用单位
  • position: fixed 吸顶在 H5 正常,小程序需 shopxo-uniapp 已有方案

最大风险点

  1. shopxo-uniapp fork 同步成本 — 官方 shopxo-uniapp 更新后需要手动同步,未来维护成本高。→ 建议在 fork 分支上做票务专属页面,官方页面保持独立升级路径。
  2. ShopXO 版本 vs shopxo-diy 版本匹配 — shopxo-diy v1.4.2 ↔ ShopXO v6.8.0,如果使用 DIY 设计器管理非票务页面,版本必须严格匹配。

优先级与依赖

  • Q1 是 Q4 的技术基础Q1 的结论直接支撑 Q4 的技术选型决策。
  • Q3 依赖 Q1 的约束条件输出。

Q3 结论:第三方无代码构建服务提示词策略

核心答案

用"模板 + 示例 + 约束"三层结构撰写 PromptShopXO 模板的特殊性(模块化 PHP 标签、ShopXO 资源路径 API在 Prompt 中明确声明,生成代码后只需做两件事后处理:① 替换静态资源路径为 ModuleInclude() 调用,② 注入座位图数据结构(从 PHP 模板变量传入)。

Prompt 三层结构

【第一层:角色定义】
你是一个 ShopXO v6.8.0 模板开发者,擅长编写票务商品详情页。

【第二层:约束清单】
- HTML 结构:使用 <?php echo ModuleInclude('public/header'); ?> 包裹页面头
- 样式:全部内联 <style>CSS 类名前缀 vr- 避免冲突
- JS 数据注入const app = <?php echo json_encode($php_var); ?>
- 资源路径:静态资源用 <?php echo ModuleInclude('images/foo.png'); ?>
- 不使用Vue/React CDN、外部 CDNShopXO 必须离线可用)

【第三层:具体需求】
[座位图 UI 规格rpx 规范、颜色、尺寸 + 交互事件定义]
[ShopXO 数据契约goods_spec_data、vr_seat_template、extension_data]

生成代码后处理步骤

  1. 路径替换:全局搜索 src="/static/<?php echo ModuleInclude('static/') ?>
  2. 变量注入点:在 <script> 顶部注入 var seatMap = <?php echo json_encode($vr_seat_template['seat_map']); ?>
  3. 事件绑定onclick 属性需改为 onclick="vrTicketApp.toggleSeat(this)" 格式(原生 JS
  4. 样式隔离:检查是否覆盖 .goods-detail-* 等 ShopXO 全局类名,如有则加 .vr-ticket-page 限定符

最大风险点

  1. 无代码服务生成的 UI 过于复杂 — 座位图等高交互组件无法用无代码工具精确生成,强行生成会导致大量调试工作。→ 无代码服务适合静态展示区块(票务商品介绍、艺人信息图),座位图选座交互必须手写
  2. ShopXO 离线可用约束 — ShopXO 运行在企业内部/私有化部署场景,所有资源必须本地化,无代码服务默认 CDN 引用必须全部替换。

Q4 结论uni-app 兼容性技术栈选型

核心答案

推荐方案:一套 shopxo-uniapp fork + 条件编译票务页面走独立路由H5/小程序双端),商城标准页面复用 shopxo-uniapp 原生实现。

技术选型对比

维度 原生 HTML 模板 uni-app fork shopxo-uniapp Flutter / React Native
H5 本地预览 直接浏览器打开 HBuilderX H5 运行 需真机调试
微信小程序 不支持 一键编译 需分别开发
ShopXO API 对接 需手动 HTTP shopxo-uniapp 已封装 需手动 HTTP
学习成本 中(需熟悉 Vue
座位图等复杂交互 原生 JS 手写 Vue 组件手写 手写
开发速度 快(单文件)

最终推荐fork shopxo-uniapp,用 Vue 3 + SCSS票务页面自研其他页面复用。

票务页面与商城标准页面共存方案

vr-shopxo-uniapp/
├── pages/index/index.vue         ← 改写:底部 Tab 新增「票务」Tab
├── pages/goods-detail/            ← 改写:票务商品跳 ticket-seat 页面
├── pages/ticket-seat/             ← 新建:选座 + 购票主流程Vue 组件)
├── pages/ticket-wallet/           ← 新建:票夹(我的票)
├── pages/ticket-verify/           ← 新建B 端核销
├── App.vue                        ← request_url 指向目标商城
└── pages.json                     ← 路由配置

H5/小程序一致性uni-app H5 和小程序都基于 WebViewCSS 渲染一致。关键:用 rpx,用 <view>,避免浏览器私有前缀。

最大风险点

  1. shopxo-uniapp 官方更新同步 — 100+ forks官方更新需手动 cherry-pick 到 vr fork。建议将票务专属页面与商城原生页面放在不同目录改动隔离升级时只同步商城页面。
  2. ShopXO 版本与 shopxo-uniapp 版本匹配 — shopxo-uniapp 的 API 契约随 ShopXO 后端版本变化vr_ticket 插件如使用 shopxo-uniapp请确认 ShopXO 版本(当前 v6.8.0),使用对应的 shopxo-uniapp 版本。

优先级与依赖

  • Q4 依赖 Q2多座位选座和 Q1H5 模板基础)
  • Q4 本身是最终落地执行层,前三个 Q 的结论在 Q4 中整合实现

优先级矩阵

优先级 任务 负责 Agent 前置条件
P0 Q2 多 SKU — 走购物车路线打通多座位下单 BackendArchitect
P1 Q4 uni-app fork — 建立项目骨架 FrontendDev Q1 结论
P2 Q4 ticket-seat.vue — 选座核心组件 FrontendDev P0 完成
P3 Q1 ticket_detail.html 增强 — 已售座位实时标记 FrontendDev
P4 Q3 提示词策略落地 — 无代码服务辅助静态区块 ProductManager Q1 结论
P5 Q2 理想方案 — 插件 hook 拦截 OrderSplitService BackendArchitect P0 验证

最小可行方案 vs 理想方案对比

维度 最小可行方案 理想方案
多座位下单 购物车路线(不碰 OrderSplitService 插件 hook 拦截,实现原生多 SKU 单订单
前端 H5 增强 ticket_detail.html< 3 处改动) 迁移到 uni-app H5
前端小程序 shopxo-uniapp fork票务页面 Vue 自研 完整迁移,小程序体验与 H5 一致
座位图 原生 JS< 200 行 Vue 组件,含缩放/拖拽/动画
观演人表单 HTML + JS支持动态增减 Vue 组件化,数据校验
核销 B 端 复用现有后台核销页面 新建小程序核销页面(扫码 + API
交付周期 1 天(可上线 demo 2-3 周(完整票务流程)

最大技术风险点汇总

风险 严重程度 缓解措施
OrderSplitService 拆单导致多座位订单被拆 最小方案走购物车绕过;理想方案用插件 hook 拦截
座位级 SKU 未在后台创建 后台管理界面增加「批量生成座位规格」功能
shopxo-uniapp fork 同步成本 票务页面与商城页面目录隔离,改动隔离升级
无代码服务无法生成高交互组件 低(已有认知) 座位图等核心交互手写,静态区块用无代码辅助
ShopXO 版本不匹配 shopxo-diy 低(不走 DIY 不使用 DIY 设计器

关键文件清单

文件 用途
shopxo/app/service/BuyService.php 订单创建入口,多 SKU 关键代码
shopxo/app/service/OrderSplitService.php 拆单逻辑,多座位订单被拆的风险点
shopxo/app/plugins/vr_ticket/view/goods/ticket_detail.html 当前票务详情页模板Q2 多 SKU Plan A 代码已在此
docs/12_UNIAPP_FRONTEND_RESEARCH.md uni-app 调研存档Q1/Q4 依赖此文档
docs/02_FRONTEND_CUSTOMIZATION.md ShopXO DIY 设计器局限性证明
docs/14_TEMPLATE_RENDER_INVESTIGATION.md 模板渲染机制调查
docs/09_SHOPXO_HOOKS_REFERENCE.md 插件钩子清单Q2 理想方案所需 hook 在此

结论

  1. 多座位下单可行走购物车路线1 天内可上线多座位下单 Demo。
  2. uni-app 是最终目标fork shopxo-uniapp 票务页面自研商城页面复用H5 预览 = 小程序编译效果。
  3. 无代码服务辅助有限:适合静态展示区块,座位图等核心交互必须手写。
  4. Immediate ActionBackendArchitect 提交 Q2 Plan A购物车路线FrontendDev 启动 shopxo-uniapp fork 项目骨架。