489 lines
13 KiB
Markdown
489 lines
13 KiB
Markdown
|
|
# ShopXO 插件开发文档
|
|||
|
|
|
|||
|
|
> 来源:doc.shopxo.net 官方文档 + PluginsService.php 源码 + CSDN/搜索补充
|
|||
|
|
> 版本:ShopXO v2.2.0+(基于 ThinkPHP 8)
|
|||
|
|
> 整理:西莉雅
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、目录结构
|
|||
|
|
|
|||
|
|
### 系统结构(v2.2.0+)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
www/ # WEB部署目录(或子目录)
|
|||
|
|
├─ app/ # 应用目录
|
|||
|
|
│ ├─ plugins/ # 插件目录
|
|||
|
|
│ │ ├─ {plugins_name}/ # 插件目录(目录名 = config.json 的 plugins 字段)
|
|||
|
|
│ │ │ ├─ config.json # ★ 插件配置(核心文件)
|
|||
|
|
│ │ │ ├─ admin/ # 后台管理
|
|||
|
|
│ │ │ │ ├─ controller/ # 控制器
|
|||
|
|
│ │ │ │ └─ view/ # Blade 视图(app/plugins/{name}/view/admin/)
|
|||
|
|
│ │ │ ├─ index/ # 前台用户端
|
|||
|
|
│ │ │ │ ├─ controller/
|
|||
|
|
│ │ │ │ └─ view/
|
|||
|
|
│ │ │ ├─ api/ # API接口端
|
|||
|
|
│ │ │ │ └─ controller/
|
|||
|
|
│ │ │ ├─ service/
|
|||
|
|
│ │ │ │ └─ BaseService.php # ★ 基础服务类(配置处理、菜单等)
|
|||
|
|
│ │ │ ├─ Event.php # ★ 生命周期事件类
|
|||
|
|
│ │ │ ├─ common.php # 公共函数
|
|||
|
|
│ │ │ └─ hook/ # 钩子类目录(可选)
|
|||
|
|
│ │ └─ ...
|
|||
|
|
│ ├─ admin/ # 后台管理模块
|
|||
|
|
│ ├─ index/ # 前台模块
|
|||
|
|
│ ├─ api/ # API接口模块
|
|||
|
|
│ ├─ common.php # 公共函数文件
|
|||
|
|
│ └─ event.php # 事件定义文件
|
|||
|
|
├─ config/ # 全局配置
|
|||
|
|
├─ public/ # WEB目录(对外访问)
|
|||
|
|
│ ├─ index.php # 前端入口
|
|||
|
|
│ ├─ admin.php # 后台入口
|
|||
|
|
│ └─ api.php # API入口
|
|||
|
|
└─ vendor/ # Composer依赖
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 插件静态资源路径
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
public/static/plugins/{plugins_name}/ # JS/CSS/图片
|
|||
|
|
├─ index/ # 前台静态资源
|
|||
|
|
└─ admin/ # 后台静态资源
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、config.json — 插件配置文件(核心)
|
|||
|
|
|
|||
|
|
### 标准结构
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"base": {
|
|||
|
|
"name": "插件显示名称",
|
|||
|
|
"version": "1.0.0",
|
|||
|
|
"author": "作者名",
|
|||
|
|
"desc": "插件描述",
|
|||
|
|
"plugins": "vr_ticket", // ★ 必须与目录名一致(唯一标识)
|
|||
|
|
"is_apps_ten_pay": 0
|
|||
|
|
},
|
|||
|
|
"element": [
|
|||
|
|
{
|
|||
|
|
"element": "input",
|
|||
|
|
"type": "text",
|
|||
|
|
"name": "api_key",
|
|||
|
|
"title": "API密钥",
|
|||
|
|
"value": "",
|
|||
|
|
"message": "请输入API密钥"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"hook": {
|
|||
|
|
"app_init": ["\\app\\plugins\\vr_ticket\\hook\\AppInit"]
|
|||
|
|
},
|
|||
|
|
"backend_hook": {
|
|||
|
|
"admin_user_view_right": ["\\app\\plugins\\vr_ticket\\hook\\AdminUserViewRight"]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### element 支持的表单类型
|
|||
|
|
|
|||
|
|
| element | 说明 | 关键参数 |
|
|||
|
|
|---------|------|---------|
|
|||
|
|
| `input` | 单行文本 | `type`: text/password/number |
|
|||
|
|
| `textarea` | 多行文本 | |
|
|||
|
|
| `radio` | 单选 | `data`: `[{name, value}]` |
|
|||
|
|
| `checkbox` | 多选 | `data`: 同上 |
|
|||
|
|
| `select` | 下拉选择 | 同上 |
|
|||
|
|
| `upload` | 文件上传 | |
|
|||
|
|
|
|||
|
|
### hook vs backend_hook
|
|||
|
|
|
|||
|
|
- `hook`:前端/全局钩子,在用户端触发
|
|||
|
|
- `backend_hook`:后台管理钩子,在 admin 模块触发
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、钩子系统(Hook)
|
|||
|
|
|
|||
|
|
ShopXO 基于 ThinkPHP 6 的 Event/Facade 机制实现插件钩子。
|
|||
|
|
|
|||
|
|
### 已知系统钩子(从源码/文档整理)
|
|||
|
|
|
|||
|
|
| 钩子名称 | 触发时机 | 常见用途 |
|
|||
|
|
|---------|---------|---------|
|
|||
|
|
| `app_init` | 应用初始化(最早) | 全局预处理 |
|
|||
|
|
| `app_begin` | 应用开始 | 初始化扩展 |
|
|||
|
|
| `module_init` | 模块初始化 | 模块级别扩展 |
|
|||
|
|
| `action_begin` | 操作开始执行前 | 权限校验、前置处理 |
|
|||
|
|
| `view_filter` | 视图内容过滤 | 输出内容处理 |
|
|||
|
|
| `log_write` | 日志写入 | 自定义日志 |
|
|||
|
|
| `app_end` | 应用结束 | 收尾处理 |
|
|||
|
|
| `admin_user_view_right` | 管理员查看用户详情右侧 | 扩展用户信息面板 |
|
|||
|
|
| `plugins_view_welcome` | 插件欢迎页 | 自定义插件首页 |
|
|||
|
|
|
|||
|
|
> **重要**:开启开发者模式后,后台应用管理页面会显示所有可用钩子的提示名称。
|
|||
|
|
> 路径:`config/shopxo.php` → `is_develop: true`
|
|||
|
|
|
|||
|
|
### 前端钩子注册方式
|
|||
|
|
|
|||
|
|
在 `config.json` 中:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
"hook": {
|
|||
|
|
"钩子名称": ["\\app\\plugins\\{name}\\hook\\HookClass"]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 后台钩子注册方式
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
"backend_hook": {
|
|||
|
|
"钩子名称": ["\\app\\plugins\\{name}\\hook\\HookClass"]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 钩子类示例
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
<?php
|
|||
|
|
// app/plugins/vr_ticket/hook/AppInit.php
|
|||
|
|
namespace app\plugins\vr_ticket\hook;
|
|||
|
|
|
|||
|
|
class AppInit
|
|||
|
|
{
|
|||
|
|
public function handle($params = [])
|
|||
|
|
{
|
|||
|
|
// 处理逻辑
|
|||
|
|
return ['code' => 0, 'msg' => 'success'];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、插件生命周期事件(Event)
|
|||
|
|
|
|||
|
|
插件可以通过 `Event.php` 响应系统生命周期回调。
|
|||
|
|
|
|||
|
|
### 生命周期事件列表
|
|||
|
|
|
|||
|
|
| 事件方法 | 触发时机 | 返回值意义 |
|
|||
|
|
|---------|---------|-----------|
|
|||
|
|
| `Upload` | 上传插件包时 | |
|
|||
|
|
| `BeginInstall` | 安装前(验证) | 非0 → 阻止安装 |
|
|||
|
|
| `Install` | 执行安装 | |
|
|||
|
|
| `Uninstall` | 卸载插件 | |
|
|||
|
|
| `Download` | 下载插件 | |
|
|||
|
|
| `BeginUpgrade` | 更新前(验证) | 非0 → 阻止更新 |
|
|||
|
|
| `Upgrade` | 执行更新 | |
|
|||
|
|
| `Delete` | 删除插件 | |
|
|||
|
|
|
|||
|
|
### Event.php 示例
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
<?php
|
|||
|
|
// app/plugins/vr_ticket/Event.php
|
|||
|
|
namespace app\plugins\vr_ticket;
|
|||
|
|
|
|||
|
|
class Event
|
|||
|
|
{
|
|||
|
|
// 安装前验证
|
|||
|
|
public function BeginInstall($params = [])
|
|||
|
|
{
|
|||
|
|
// 检查依赖等
|
|||
|
|
return DataReturn('可以安装', 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 执行安装
|
|||
|
|
public function Install($params = [])
|
|||
|
|
{
|
|||
|
|
// 创建数据库表等
|
|||
|
|
return DataReturn('安装成功', 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 卸载
|
|||
|
|
public function Uninstall($params = [])
|
|||
|
|
{
|
|||
|
|
// 清理数据等
|
|||
|
|
return DataReturn('卸载成功', 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 支付回调事件(需配合支付插件使用)
|
|||
|
|
public function PaySuccess($params = [])
|
|||
|
|
{
|
|||
|
|
// $params 包含 order_id, pay_price, payment 等
|
|||
|
|
return DataReturn('处理成功', 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、控制器与路由
|
|||
|
|
|
|||
|
|
### URL 路由格式
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
/plugins/{group}?pluginsname={plugins}&pluginscontrol={control}&pluginsaction={action}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
示例:
|
|||
|
|
```
|
|||
|
|
/plugins/index?pluginsname=vr_ticket&pluginscontrol=index&pluginsaction=index
|
|||
|
|
/plugins/admin?pluginsname=vr_ticket&pluginscontrol=admin&pluginsaction=index
|
|||
|
|
/plugins/api?pluginsname=vr_ticket&pluginscontrol=api&pluginsaction=notify
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 控制器命名规范
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
app/plugins/{name}/{group}/controller/{Control}.php
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- `group`: `index`(前台)| `admin`(后台)| `api`(API)
|
|||
|
|
- `Control`: 首字母大写,如 `Index`, `Admin`, `Order`
|
|||
|
|
|
|||
|
|
### 控制器基类结构
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
<?php
|
|||
|
|
// app/plugins/vr_ticket/index/controller/Index.php
|
|||
|
|
namespace app\plugins\vr_ticket\index\controller;
|
|||
|
|
|
|||
|
|
class Index
|
|||
|
|
{
|
|||
|
|
// 前台首页
|
|||
|
|
public function index($params = [])
|
|||
|
|
{
|
|||
|
|
return MyView('', ['data' => $data]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// JSON API
|
|||
|
|
public function detail($params = [])
|
|||
|
|
{
|
|||
|
|
return DataReturn('success', 0, $data);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
<?php
|
|||
|
|
// app/plugins/vr_ticket/admin/controller/Index.php
|
|||
|
|
namespace app\plugins\vr_ticket\admin\controller;
|
|||
|
|
|
|||
|
|
class Index
|
|||
|
|
{
|
|||
|
|
public function index($params = [])
|
|||
|
|
{
|
|||
|
|
IsLogin(); // 后台需登录校验
|
|||
|
|
return MyView('', []);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、BaseService — 基础服务类
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
<?php
|
|||
|
|
// app/plugins/vr_ticket/service/BaseService.php
|
|||
|
|
namespace app\plugins\vr_ticket\service;
|
|||
|
|
|
|||
|
|
use think\facade\Db;
|
|||
|
|
|
|||
|
|
class BaseService
|
|||
|
|
{
|
|||
|
|
// 附件字段(配置中涉及文件上传的字段名)
|
|||
|
|
public static $base_config_attachment_field = [];
|
|||
|
|
|
|||
|
|
// 私有字段(不返回给前端的敏感字段)
|
|||
|
|
public static $base_config_private_field = ['secret_key'];
|
|||
|
|
|
|||
|
|
// 后台权限菜单(可选)
|
|||
|
|
public static function AdminPowerMenu()
|
|||
|
|
{
|
|||
|
|
return [
|
|||
|
|
['name' => '场次管理', 'url' => MyUrl('plugins/admin', ['pluginsname' => 'vr_ticket', 'pluginscontrol' => 'event', 'pluginsaction' => 'index'])],
|
|||
|
|
['name' => '门票核销', 'url' => MyUrl('plugins/admin', ['pluginsname' => 'vr_ticket', 'pluginscontrol' => 'verify', 'pluginsaction' => 'index'])],
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 配置数据处理(可选)
|
|||
|
|
public static function BaseConfigHandle($config)
|
|||
|
|
{
|
|||
|
|
return $config;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 读取插件配置
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
use app\service\PluginsService;
|
|||
|
|
|
|||
|
|
$data = PluginsService::PluginsData('vr_ticket');
|
|||
|
|
// 返回 ['code' => 0, 'msg' => 'success', 'data' => [...配置数据]]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 保存插件配置
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
PluginsService::PluginsDataSave([
|
|||
|
|
'plugins' => 'vr_ticket',
|
|||
|
|
'data' => $params
|
|||
|
|
], $attachment_field);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、模板引擎(Blade)
|
|||
|
|
|
|||
|
|
ShopXO 使用 Blade 模板(.blade.php)。
|
|||
|
|
|
|||
|
|
### 前台视图路径
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
app/plugins/vr_ticket/view/index/index.blade.php # 前台
|
|||
|
|
app/plugins/vr_ticket/view/admin/index.blade.php # 后台
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 视图中引用静态资源
|
|||
|
|
|
|||
|
|
```blade
|
|||
|
|
<img src="{{ \app\common.phpStaticAttachmentUrl('logo.png', 'images', 'vr_ticket') }}" />
|
|||
|
|
|
|||
|
|
<!-- 或直接写死路径 -->
|
|||
|
|
<link href="/static/plugins/vr_ticket/index/css/style.css" rel="stylesheet">
|
|||
|
|
<script src="/static/plugins/vr_ticket/index/js/app.js"></script>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 视图渲染
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// 渲染插件视图(自动读取插件view目录)
|
|||
|
|
return MyView('index', ['data' => $data]);
|
|||
|
|
// 路径:app/plugins/vr_ticket/view/index/index.blade.php
|
|||
|
|
|
|||
|
|
// 渲染后台视图
|
|||
|
|
return MyView('admin/index', ['data' => $data]);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 公共模板变量
|
|||
|
|
|
|||
|
|
在 `app/plugins/vr_ticket/common.php` 中定义函数,可供所有视图调用。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 八、调试与开发模式
|
|||
|
|
|
|||
|
|
### 开启开发者模式
|
|||
|
|
|
|||
|
|
路径:`config/shopxo.php`
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
'is_develop' => true, // 从 false 改为 true
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
开启后后台应用管理页面会显示钩子名称提示。
|
|||
|
|
|
|||
|
|
### 日志文件
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
runtime/log/{年份}/{月份}.log
|
|||
|
|
例:runtime/log/2025/09.log
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 调试模式
|
|||
|
|
|
|||
|
|
在 `.env` 中设置:
|
|||
|
|
|
|||
|
|
```env
|
|||
|
|
APP_DEBUG=true
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 九、支付插件(extend/ 方式)
|
|||
|
|
|
|||
|
|
ShopXO 的支付插件放在 `extend/payment/` 目录,与通用插件不同。
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
extend/
|
|||
|
|
└─ payment/
|
|||
|
|
├─ Alipay.php # 支付宝支付
|
|||
|
|
└─ Weixin.php # 微信支付
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
支付插件实现支付接口集成,订单支付成功后会触发事件通知。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十、与 vr-shopxo-plugin 需求对应的关键点
|
|||
|
|
|
|||
|
|
### VR 票务插件需要对接的核心功能
|
|||
|
|
|
|||
|
|
#### 1. 票务场次管理(后台)
|
|||
|
|
|
|||
|
|
- **路由**:`/plugins/admin?pluginsname=vr_ticket&pluginscontrol=event&pluginsaction=index`
|
|||
|
|
- **数据库**:需创建 `vr_events`(场次)、`vr_sessions`(场次时间/库存)、`vr_tickets`(电子票)
|
|||
|
|
- **后台菜单**:通过 `BaseService::AdminPowerMenu()` 注册
|
|||
|
|
|
|||
|
|
#### 2. 支付回调处理(API)
|
|||
|
|
|
|||
|
|
- **路由**:`/plugins/api?pluginsname=vr_ticket&pluginscontrol=api&pluginsaction=notify`
|
|||
|
|
- **触发方式**:支付插件在支付成功后调用此接口
|
|||
|
|
- **关键逻辑**:
|
|||
|
|
1. 验证支付签名
|
|||
|
|
2. 创建 `vr_tickets` 记录(AES_Encrypt 防伪造 QR)
|
|||
|
|
3. 更新 `vr_sessions` 库存
|
|||
|
|
|
|||
|
|
#### 3. 观演人信息收集
|
|||
|
|
|
|||
|
|
- **触发时机**:订单 `pending` → `paid` 过渡阶段
|
|||
|
|
- **实现方式**:可在订单扩展字段或 `OrderService` 中 hook
|
|||
|
|
- **字段**:姓名、手机号、身份证(可选)
|
|||
|
|
|
|||
|
|
#### 4. QR 电子票展示(前台)
|
|||
|
|
|
|||
|
|
- **路由**:`/plugins/index?pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=detail`
|
|||
|
|
- **数据源**:`vr_tickets` 表
|
|||
|
|
- **展示**:票面信息 + QR 码图片
|
|||
|
|
|
|||
|
|
#### 5. B 端扫码核销(后台)
|
|||
|
|
|
|||
|
|
- **路由**:`/plugins/admin?pluginsname=vr_ticket&pluginscontrol=verify&pluginsaction=index`
|
|||
|
|
- **方式**:微信扫码枪或管理员扫码页面
|
|||
|
|
- **逻辑**:`vr_tickets.status = 'used'` + 核销时间戳
|
|||
|
|
|
|||
|
|
### 关键开发顺序
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Phase 1: 插件骨架(config.json + BaseService + Event)
|
|||
|
|
↓
|
|||
|
|
Phase 2: 数据库迁移(vr_events, vr_sessions, vr_tickets)
|
|||
|
|
↓
|
|||
|
|
Phase 3: 后台场次管理 CRUD(admin/controller)
|
|||
|
|
↓
|
|||
|
|
Phase 4: 前台购票流程 + 支付回调(api/controller + notify)
|
|||
|
|
↓
|
|||
|
|
Phase 5: QR 票生成 + 观演人信息
|
|||
|
|
↓
|
|||
|
|
Phase 6: B 端核销页面
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 十一、参考资源
|
|||
|
|
|
|||
|
|
| 资源 | URL |
|
|||
|
|
|------|-----|
|
|||
|
|
| 官方文档站 | https://doc.shopxo.net/ |
|
|||
|
|
| 插件开发索引 | https://doc.shopxo.net/article/3.html |
|
|||
|
|
| 目录结构 | https://doc.shopxo.net/article/4/265292898306621440.html |
|
|||
|
|
| 应用商店 | https://store.shopxo.net/ |
|
|||
|
|
| GitHub 源码 | https://github.com/gongfuxiang/shopxo |
|
|||
|
|
| Gitee 源码 | https://gitee.com/zongzhige/shopxo |
|
|||
|
|
| ThinkPHP 8 文档 | https://www.kancloud.cn/manual/thinkphp6_0/ |
|