插件开发指南
本页给出从示例插件复制、改名、开发到本地安装验证的最短路径。
选择插件形态
| 形态 | 何时使用 |
|---|---|
kind=app | 完整业务应用,需要作为租户后台一级菜单出现 |
kind=plugin | 可复用能力、配置面板、装修组件或其他插件依赖 |
如果插件会给租户提供完整业务闭环,例如商城、CMS、CRM,优先使用 kind=app。
复制示例插件
bash
cd server/plugins
cp -R mall demo-shop然后修改:
plugin.json中的code、name、description、psr4、lifecycle、entitlement。- PHP 命名空间,例如
Plugin\Mall\改为Plugin\DemoShop\。 - 菜单 code、权限 code、路由、表名和迁移文件名。
- 租户前端页面路径和 API 封装。
- UniApp 分包路径和页面路径。
后端开发
插件后端放在 server/plugins/{code}/app/,通过插件自己的 PSR-4 命名空间加载。
推荐分层:
text
app/
├── model/
├── repository/
├── service/
├── tenantapi/
│ ├── controller/
│ └── route.php
├── api/
│ ├── controller/
│ └── route.php
└── hooks/
└── Lifecycle.php租户 API 路由只写裸路由:
php
use think\facade\Route;
use Plugin\DemoShop\app\tenantapi\controller\ProductController;
Route::get('products', ProductController::class . '@index');
Route::post('products', ProductController::class . '@store');框架运行时会自动包装为 /tenantapi/{plugin_code}/products,并挂载租户上下文、认证、生命周期、权益、RBAC 和日志中间件。
租户级业务表必须包含 tenant_id,Repository 必须使用 $this->query():
php
public function list(array $params): array
{
return $this->query()
->when(!empty($params['keyword']), fn ($q) => $q->whereLike('name', "%{$params['keyword']}%"))
->order('id', 'desc')
->paginate()
->toArray();
}数据库迁移
迁移放在插件的 migrations/ 目录:
text
server/plugins/demo-shop/migrations/20260605000100_demo_shop_init.php表结构变更放迁移,不要放生命周期 hook。迁移应可重复执行或安全失败,避免升级中断后无法恢复。
租户后台页面
租户后台源码放在:
text
server/plugins/demo-shop/tenant/
├── api/
└── views/manifest 菜单中的 component 使用 plugins/{code}/{view} 约定。平台安装或重建时,scripts/sync-plugins.mjs 会把插件前端源码同步进 tenant/src 或 platform/src 构建目录。
生命周期
生命周期类用于处理安装、卸载、启用和禁用时的副作用:
php
namespace Plugin\DemoShop\hooks;
use core\plugin\contracts\LifecycleHook;
final class Lifecycle implements LifecycleHook
{
public function install(): void {}
public function uninstall(): void {}
public function enable(int $tenantId): void {}
public function disable(int $tenantId): void {}
}生命周期适合处理默认配置、缓存清理、初始化非结构化数据等工作。表结构变更仍然放迁移。
本地安装验证
- 登录平台后台。
- 插件管理中选择「登记内置插件」,填写
demo-shop。 - 执行安装。
- 到套餐管理中给目标套餐授权插件。
- 登录租户后台,在插件应用中启用插件。
- 给租户角色分配对应菜单和按钮权限。
- 访问插件菜单,创建和查询数据。
打包发布
zip 包要求:
plugin.json必须在 zip 根目录。- 插件源码路径不能使用
../或绝对路径。 - 图标建议放根目录,例如
icon.png。 - 不要打包
node_modules、运行时缓存、构建产物。
推荐结构:
text
demo-shop.zip
├── plugin.json
├── icon.png
├── app/
├── migrations/
├── tenant/
└── uniapp/发布前检查
plugin.json能通过校验。- 插件 code、菜单 code、权限 code 不与已有插件冲突。
- 依赖插件写入
depends。 - 租户级表包含
tenant_id。 - Repository 没有绕过
$this->query()。 - 启用、禁用、卸载、重新安装能安全执行。
- 移动端声明了
uniapp.pages时,源码目录存在。 - 跑一遍红线测试,确认没有破坏租户隔离。
