Skip to content

插件开发 ​

插件目录 ​

每个插件是一个独立目录,放置在系统插件目录下(如 src/plugins/<name>/)。一个标准插件包含以下内容:

plugin-name/
├── index.js                # 插件注册入口(fastify-plugin)
├── info.json               # 插件元信息
├── trigger.json            # 安装时生成的触发文件(记录被复制的文件)
├── data/
│   └── index.js            # 后台菜单、API 路由、配置分类与配置项声明
├── fields/
│   └── schema.js           # 嵌入已有模型的字段定义
├── hook/                   # 应用钩子(文件名 = 应用名)
│   ├── music.js
│   ├── video.js
│   └── user.js
├── app/
│   ├── admin/controller/   # 后台控制器
│   └── index/controller/   # 前台控制器
├── library/                # 业务逻辑库
├── loader/                 # 后台列表的动态列配置
└── model/                  # 插件数据模型(集合名 aod_<name>)

info.json ​

插件元信息声明文件:

json
{
  "name": "vip",
  "title": "VIP会员",
  "intro": "付费会员、等级与点数系统",
  "author": "DJAOD",
  "website": "https://www.djaod.com",
  "version": "1.0.0",
  "state": 1,
  "install": 1
}
字段说明
name插件唯一标识
title插件标题(展示名)
intro插件简介
author / website作者与官网
version版本号
state状态,1 启用,0 禁用
install是否已安装,1 已安装

data/index.js ​

插件声明文件,导出以下配置:

  • AdminRules:后台菜单树(插件后台入口)
  • AdminRoutes:后台 API 路由
  • configTabs:配置分类
  • configList:配置项列表

安装插件时系统据此注册菜单、路由与配置;卸载时据此清理。

fields/schema.js ​

用于向已有模型嵌入插件字段,例如 VIP 插件向音乐、视频、用户模型追加 vip、vip_level、vip_expiretime 等字段。嵌入式字段无需修改核心模型代码。

loader/ ​

后台通用列表组件的动态列配置,定义表格列、搜索项、操作按钮与接口地址,按 action 名分文件存放。

插件生命周期 ​

插件注册入口 index.js 中使用插件钩子注册生命周期:

js
// 安装
plugin.setHook('install', async () => {
  // 注册配置、菜单、路由
});

// 卸载
plugin.setHook('uninstall', async () => {
  // 清理配置、菜单、路由
});

// 启用 / 禁用 / 升级
plugin.setHook('enable', async () => {});
plugin.setHook('disable', async () => {});
plugin.setHook('upgrade', async () => {});

系统在安装、卸载、启用、禁用、升级时自动调用对应钩子。

钩子函数 ​

钩子是插件与核心系统、插件与应用之间的扩展机制,分为两类:

应用钩子(plugin_hooks) ​

plugin_hooks 用于扩展指定应用(音乐、视频、用户等),事件点由应用主动触发:

plugin_hooks(应用名, 事件名, 参数)

常见事件点:

事件名说明
formAppend后台表单追加字段(如音乐 / 视频表单追加「VIP等级」下拉)
modelAfter模型查询结果追加数据(如为视频附加 VIP 权限信息)

插件的 hook/ 目录中,以应用名命名的文件(类名 = 应用名),其方法名对应事件名。例如 hook/video.js 中的 formAppend、modelAfter 方法,会在音乐 / 视频相关表单与模型查询时被调用。

以 VIP 插件为例,modelAfter 会在视频模型查询后追加:

js
{
  vipInfo: { title, label, icon },   // VIP 等级信息
  vip_points: 1,                     // 是否为点数模式(1 点数模式)
  isvip: true,                       // 用户是否 VIP
  isPaid: false                      // 是否已购买 / 在有效期内
}

前端据此控制播放、下载等操作按钮。

全局钩子(setHooks / getHooks) ​

全局钩子由系统在关键业务节点触发,插件通过 setHooks 监听,按注册顺序串行执行,单钩子超时与错误隔离,不影响主流程。

示例(监听订单支付完成):

js
fastify.setHooks('order_after', async ({ order, paytype, data }) => {
  // 支付完成后的处理(如发放积分、赠送权益)
});

全局钩子节点包括订单、模型等业务关键位置,具体事件名由各功能模块定义。

按钮权限注册 ​

插件可以在后台列表注册操作按钮,并通过按钮权限控制可见性:

js
// 注册按钮权限
fastify.setAuthButtonsList({ user_list: ['set_vip'] });

// 获取当前管理员可见的按钮
fastify.getAuthButtonsList(request);

// 权限变更后刷新缓存
fastify.clearAuthButtonsCache();

按钮权限按角色组规则过滤,管理员重新登录后生效。

开发建议 ​

  • 插件目录内新增内容时,遵循「安装时注册、卸载时清理」的原则。
  • 嵌入字段使用 fields/schema.js,不要直接修改核心模型。
  • 前台功能放在 app/index/controller,后台管理放在 app/admin/controller。
  • 插件配置统一通过配置分类声明,便于用户后台管理。

Released under the MIT License.