# ShopXO 技术能力完整调研 > 调研时间:2026-04-14(上午) > 调研方式:源码分析 + 官方文档交叉验证 > 官方文档站:https://doc.shopxo.net/(**开发前必查**) > 源码位置:`council-research/shopxo-eval/.worktrees/shopxo-evaluator/shopxo-src/` --- ## 一、DIY 设计器组件系统 ### 1.1 组件定义机制 ShopXO DIY 设计器是 **Vue3 SPA**: - 入口:`public/static/diy/js/entry/index-*.js` - 组件列表定义在前端 JS 中(组件面板) - 后端只存储布局配置 JSON(`sxo_diy` 表) ### 1.2 渲染层支持的组件类型 模板位置: `app/module/view/layout/public/common/module_view.html` | 组件值 (value) | 功能 | AI 参与度 | |---|---|---| | `images` | 单图 | ✅ 替换链接即可 | | `many-images` | 多图(多种布局) | ✅ | | `images-text` | 图文混排 | ✅ | | `images-magic-cube` | 图片魔方(复杂宫格) | ✅ | | `video` | 视频 | ✅ | | `goods` | 商品列表(3 种样式:routine/leftright/rolling) | ✅ | | `title` | 标题文字 | ✅ | | **`custom`** | **自定义 HTML** | **✅✅ 完全自由** | ### 1.3 `custom` 组件渲染逻辑 ```php {{case custom}} {{if !empty($vss['config']['custom'])}} {{$vss.config.custom|raw}} {{/if}} {{/case}} ``` 直接输出原始 HTML,无任何过滤。 **⚠️ 注意**:`custom` 组件在后端渲染层存在,但 admin DIY Vue3 设计器的组件面板 UI 入口不明确(未在源码中找到 admin 侧配置)。**替代方案**:使用 CustomView 完全弥补(见下节)。 ### 1.4 DIY 设计器局限性 - **展示型页面**(首页/专题页):重度依赖拖拽装修,JSON 数据库存储,AI 无法直接参与视觉设计 - **业务型页面**(商品/订单/会员):表格 + 表单,AI 参与度高 - **票务插件 UI**:完全走代码,不依赖 DIY 系统 → AI 参与度极高 --- ## 二、CustomView 自定义页面系统 ⭐ 重大发现 ### 2.1 功能概述 ShopXO 内置全代码自定义页面编辑器(Ace Playground Web Component)。 后台入口:**营销菜单 → 自定义页面管理** ### 2.2 技术细节 | 能力 | 详情 | |---|---| | **编辑器** | Ace Playground(非 iframe,是原生 Web Component) | | **语言** | HTML + CSS + JavaScript 三栏独立编辑 | | **实时预览** | iframe 渲染,实时刷新 | | **模板语法** | ThinkPHP `{{$data.xxx|raw}}` 可用(会员信息、商品数据等) | | **访问地址** | `/index/customview/index?id=xxx` | | **全屏模式** | 支持 `is_full_screen` 参数 | ### 2.3 存储内容 | 字段 | 渲染方式 | |---|---| | `html_content` | `{{$data.html_content\|raw}}` 在 div 内 | | `css_content` | `` 自动包裹 | | `js_content` | `` 自动包裹 | ### 2.4 admin 端 Ace 编辑器实现 文件:`app/admin/view/default/customview/saveinfo.html` ```javascript class AcePlayground extends HTMLElement { constructor() { var shadow = this.attachShadow({mode: 'open'}); dom.buildDom(['div', {id: 'host'}, ['div', {id: 'html'}], // HTML 编辑器 ['div', {id: 'css'}], // CSS 编辑器 ['div', {id: 'js'}], // JS 编辑器 ['iframe', {id: 'preview'}] // 实时预览 ], shadow); this.htmlEditor = ace.edit(shadow.querySelector('#html'), {...}); this.cssEditor = ace.edit(shadow.querySelector('#css'), {...}); this.jsEditor = ace.edit(shadow.querySelector('#js'), {...}); this.preview = shadow.querySelector('#preview'); this.updatePreview(); // 实时更新预览 } } ``` ### 2.5 对票务的意义 ✅ **CustomView 可以实现完全自定义的票务辅助页面**: - 票夹页面(用户的所有电子票) - 观演人管理页面 - 活动专题页面 在 DIY 设计器中,通过 `custom` 组件引用 CustomView 页面 URL,或直接在插件钩子中链接到 CustomView 页面。 --- ## 三、商品详情页钩子系统(30+ 钩子) ### 3.1 核心文件 - 控制器:`app/index/controller/Goods.php`(`PluginsHook()` 方法) - 模板:`app/index/view/default/goods/module/middle_base/right/` 目录下各模板 ### 3.2 钩子完整列表 ``` 📍 相册区域 plugins_view_goods_detail_photo_within ← 相册内部 plugins_view_goods_detail_photo_bottom ← 相册底部 📍 右侧购买面板 plugins_view_goods_detail_panel_original_price_top ← 原价上方 plugins_view_goods_detail_panel_price_top ← 现价上方 plugins_view_goods_detail_panel_price_bottom ← 现价下方 plugins_view_goods_detail_panel_bottom ← 整个面板底部 📍 规格/库存区域 ← 🎯 票务最佳注入点 plugins_view_goods_detail_base_sku_top ← 规格选择区顶部 ⭐ plugins_view_goods_detail_base_inventory_top ← 库存区域顶部 plugins_view_goods_detail_base_inventory_bottom ← 库存区域底部 ⭐ 📍 购买导航 plugins_view_goods_detail_base_buy_nav_min_inside_begin ← 购买区内部前 plugins_view_goods_detail_base_buy_nav_min_inside ← 购买区内部后 📍 底部信息(标签页) plugins_view_goods_detail_tabs_top / _content / _bottom plugins_view_goods_detail_tabs_comments_top/bottom plugins_view_goods_detail_tabs_guess_like_top/bottom 📍 全局 plugins_view_goods_detail_content_top/bottom plugins_view_goods_detail_left_top plugins_view_goods_detail_title ``` ### 3.3 钩子渲染机制 控制器中: ```php foreach($hook_arr as $hook_name) { $assign[$hook_name.'_data'] = MyEventTrigger($hook_name, [ 'hook_name' => $hook_name, 'is_backend' => false, 'goods_id' => $goods_id, 'goods' => &$goods, ]); } MyViewAssign($assign); ``` 模板中渲染: ```php {{foreach $plugins_view_goods_detail_base_sku_top_data as $hook}} {{if is_string($hook) or is_int($hook)}} {{$hook|raw}} {{/if}} {{/foreach}} ``` ### 3.4 最佳注入点分析 **票务选座 UI 最佳位置**:`plugins_view_goods_detail_base_sku_top` - 位于规格选择区顶部 - 在购买按钮上方 - 可以完全占据购买区域 - 插件返回 HTML 字符串即可渲染 --- ## 四、按商品类型完全替换模板 ### 4.1 主题机制 `MyView()` 函数(`app/common.php`)支持主题覆盖: ```php function MyView($view = '', $data = []) { $theme = DefaultTheme(); // 从配置读取主题名 $file = APP_PATH.$group.DS.'view'.DS.$theme.DS.$view_new.$suffix; // 如果当前主题有这个文件,就用主题的;否则用 default } ``` 主题目录:`app/index/view/{theme_name}/goods/index.html` 主题切换配置:`sxo_config` 表中 `common_default_theme` 字段。 **⚠️ 限制**:主题是全局的,所有商品共用同一套模板。 ### 4.2 按商品类型动态选择模板 在 `Goods.php Index()` 方法中加 1 行判断: ```php // Goods.php Index() 方法,约第 440 行 // 在 return MyView(); 之前插入: if(!empty($goods['item_type']) && $goods['item_type'] == 'ticket') { return MyView('/goods/ticket_detail'); // 自定义票务模板 } return MyView(); // 默认模板 ``` 对应模板文件:`app/index/view/default/goods/ticket_detail.html` **这是 ShopXO 允许范围内,唯一能让特定类型商品使用独立模板的方式。** --- ## 五、插件系统架构 ### 5.1 目录结构 ``` app/plugins/{PluginName}/ ├── service/ │ └── BaseService.php ← 必须:配置字段 + 安装/卸载逻辑 ├── view/ │ ├── User.php ← 用户中心钩子实现 │ ├── Goods.php ← 商品详情页钩子实现 │ └── ... ├── js/ │ └── ... └── 配置文件 ``` ### 5.2 BaseService.php 必须实现 ```php namespace app\plugins\{PluginName}\service; class BaseService { // 1. 插件配置表单字段 public static function Config($params = []) { return [ 'title' => '插件名称', 'base' => [...], // 基础配置 'items' => [...], // 自定义配置项 ]; } // 2. 安装回调 public static function Install($params = []) { ... } // 3. 卸载回调 public static function Uninstall($params = []) { ... } } ``` ### 5.3 视图钩子实现示例 插件 `view/Goods.php`: ```php namespace app\plugins\vr_ticket\view; class Goods { // 钩子:plugins_view_goods_detail_base_sku_top public static function PluginsViewGoodsDetailBaseSkuTop($params) { $goods = $params['goods']; if(empty($goods['item_type']) || $goods['item_type'] != 'ticket') { return ''; // 非票务商品,不输出 } return '