GFast V4 插件 / 应用开发手册
适用版本:框架 3.4.2(
internal/consts/version.go)
面向对象:需要开发、打包、安装、维护 GFast 插件或模块的后端 / 前端开发人员
目标:读完本文即可独立完成「生成骨架 → 写代码 → 打包导出 → 安装 → 卸载」全流程
1. 概述
GFast 的「插件 / 应用」本质是一段按约定组织的源码 + 元数据 + SQL + 菜单,由后台的「插件管理」模块(internal/app/plugins/manage)负责打包、安装、卸载。
它有两种布局,能力等价,只是落盘位置不同:
| 布局 | installPath |
源码落盘位置 | 前端组件路径 | 典型例子 |
|---|---|---|---|---|
| 容器插件 | 普通路径,缺省 plugins |
internal/app/<installPath>/<name>/(例如internal/app/plugins/sms) |
src/views/<installPath>/<name> |
sms、mail |
| 一级模块(“应用”) | . |
internal/app/<name>/(例如internal/app/cms) |
src/views/<name> |
cms |
<name>:插件标识名,规则^[A-Za-z][A-Za-z0-9_]{1,63}$(字母开头,2–64 位)。- 一级模块的
<name>不能取框架保留目录:system、common、boot、plugins。 - 一级模块必须使用「原生布局」(见 §5.2),旧式
go/<name>/会被安装器直接拒绝。
2. 快速开始(最短路径)
步骤 0:先生成骨架包(强烈推荐)
后台「插件管理 → 已安装插件 Tab → 新建插件包」填写:标识名、名称、版本、作者、installPath、业务表、方言、依赖,点击「生成」。
后端对应接口 GET /api/v1/plugins/manage/scaffold,会产出一个 *-scaffold.zip,内含可直接编辑的:
<name>/
├── install.json # 已填好的元数据
├── install_mysql.sql # MySQL 建表模板(带 TODO)
├── install_pgsql.sql # PostgreSQL 建表模板
├── menus.json # 约定菜单树(目录 + 列表页 + 4 个按钮)
├── README.md # 包内说明(含目录规范与注意事项)
├── go/ # 空目录,放后端源码
└── vue/ # 空目录,放前端源码缺省方言为
mysql,pgsql(同时生成两套模板)。可在弹窗里改成只声明实际支持的方言。
步骤 1:解压骨架,按 §5 / §6 放入后端与前端源码
步骤 2:补全 install_mysql.sql / install_pgsql.sql 建表语句(§8)
步骤 3:调整 menus.json(§7)
步骤 4:压缩为 zip,根目录必须是 <name>/(不要多套一层目录)
<name>.zip
└── <name>/ ← zip 内第一层必须是插件名
├── install.json
├── ...步骤 5:安装
- 本地导入:后台「插件管理 → 在线商城 Tab → 本地导入安装」上传 zip。
- 在线安装:需先登录插件商城,从商城安装并选择版本。
安装完成后:后端必须重新编译并重启(go run main.go);前端开发模式自动热更,生产环境需重新构建。
步骤 6:给角色授权
新菜单与按钮权限插入后,需要在「角色管理」里勾选授权,才会对非超管账号可见。
3. 插件包结构
以容器插件 sms(installPath=plugins)为例,sms-3.4.0.zip 的真实结构:
sms/
├── install.json # 插件元数据(必填 name、version)
├── install_mysql.sql # MySQL 建表脚本(按方言择优执行)
├── menus.json # 菜单树(无菜单行时可不生成)
├── go/ # 后端源码(相对后端项目根,推荐原生布局)
│ ├── api/v1/plugins/sms/*.go # 接口 DTO(g.Meta 路由标签)
│ └── internal/
│ ├── app/boot/pluginsSms.go # 服务注册挂载点
│ ├── app/plugins/sms/ # 业务模块
│ │ ├── controller/ service/ logic/ model/ dao/ router/
│ │ ├── consts/ driver/ # 业务自定义子包
│ │ └── register.go # 模块自身 init 挂载(可选)
│ ├── app/plugins/sms/logic/logic.go # 模块级 Register 聚合
│ └── router/pluginsSms.go # 路由绑定挂载点
└── vue/ # 前端源码(内容相对 admin-ui/src)
├── api/modules/sms.ts # 接口封装
└── views/plugins/sms/ # 页面组件
├── index.vue log.vue
└── locale-zh.ts locale-en.ts ...各文件的作用与生成方式
| 文件 | 作用 | 安装时如何处理 |
|---|---|---|
install.json |
元数据与能力声明 | 解析校验;决定方言兼容、版本门槛、业务表清单、依赖清单 |
install_<dialect>.sql |
按方言建表 | 按当前数据库方言择优执行唯一命中者 |
install.sql |
通用建表(历史回落) | 无方言专属脚本时才用;在非 MySQL 上会给出核对提醒 |
menus.json |
菜单/权限树 | 按 name 命名空间幂等同步(复用 ID、增缺、删过期) |
go/** |
后端源码 | 解析后复制落盘 |
vue/** |
前端源码 | 复制到前端 src 对应位置 |
⚠️ 不要在包内放
go/**/data/*.sql:安装器会自动扫描并执行该目录下的 SQL,可能与根目录的install.sql重复执行。导出时也会主动排除模块根data/目录。
4. install.json 字段详解
结构定义见 model.InstallCfg。校验只强制 name 与 version(validateInstallCfg)。
{
"name": "sms",
"title": "短信发送",
"description": "",
"version": "3.4.0",
"auth": "gfast01",
"minGfastVersion": "3.4.1",
"installPath": "plugins",
"tables": ["plugin_sms_config", "plugin_sms_log"],
"dialects": ["mysql"],
"dependencies": {
"go": [
{ "target": "github.com/alibabacloud-go/darabonba-openapi", "version": "v0.2.1", "standard": false }
],
"npm": []
}
}
| 字段 | 必填 | 说明 |
|---|---|---|
name |
✅ | 插件标识名,^[A-Za-z][A-Za-z0-9_]{1,63}$;同时决定模块目录名与菜单命名空间 |
version |
✅ | 插件版本 |
title |
➖ | 展示名;缺省取 name |
description |
➖ | 介绍 |
auth |
➖ | 作者 |
minGfastVersion |
➖ | 最低框架版本;大于当前框架版本(3.4.2)时阻断安装。建议留空或填框架版本 |
installPath |
➖ | 模块相对 internal/app 的路径;. = 一级模块;缺省 plugins(骨架/导出会自动填) |
tables |
➖ | 业务表名数组(卸载时按此精确删表)。表名规则 ^[A-Za-z][A-Za-z0-9_]{1,63}$ |
dialects |
➖ | 支持方言 mysql / pgsql;缺省视为仅 mysql |
dependencies |
➖ | 前后端依赖声明(§9),形状 {"go":[...], "npm":[...]} |
installPath 合法性
归一化规则(normalizeInstallPath):\ 统一为 /;连续/首尾 / 合并;././ 归一为 .;拒绝绝对路径、盘符、..、非法字符;空值取 plugins。
5. 后端模块开发规范
5.1 推荐:原生布局
无论容器还是一级模块,go/ 内都按宿主项目的相对路径组织,安装时原样落盘:
| 文件 | 位置 | package |
|---|---|---|
| 业务模块 | internal/app/<modulePath>/(含 controller/service/logic/model/dao/router) |
各子包 |
| 接口 DTO | api/v1/<modulePath>/ |
模块名 |
| 服务注册挂载点 | internal/app/boot/<fileStem>.go |
boot |
| 路由绑定挂载点 | internal/router/<fileStem>.go |
router |
<modulePath> = installPath(一级模块时为空)+ name。例如 plugins/sms。
<fileStem> 推导规则(moduleLayout.fileStem):
| 布局 | installPath | name | fileStem | boot 文件 |
|---|---|---|---|---|
| 容器 | plugins |
sms |
pluginsSms |
internal/app/boot/pluginsSms.go |
| 容器 | demo |
demoPlugin |
demoDemoPlugin |
internal/app/boot/demoDemoPlugin.go |
| 一级 | . |
cms |
cms |
internal/app/boot/cms.go |
一级模块布局额外兼容首字母大写命名(
Ipfilter.go);容器布局只认历史命名。
三个必须的文件模板
① 服务注册挂载点 internal/app/boot/<fileStem>.go
package boot
import (
"github.com/tiger1103/gfast/v3/internal/app/plugins/sms/logic"
"github.com/tiger1103/gfast/v3/internal/register"
)
// 包初始化时上交本模块服务注册回调(无 init,增删本文件即插拔模块)
var _ = register.Add(logic.Register)
② 路由绑定挂载点 internal/router/<fileStem>.go
package router
import (
"context"
"github.com/gogf/gf/v2/net/ghttp"
smsRouter "github.com/tiger1103/gfast/v3/internal/app/plugins/sms/router"
)
func (router *Router) BindPluginsSmsModuleController(ctx context.Context, group *ghttp.RouterGroup) {
smsRouter.R.BindController(ctx, group)
}
方法名 =
Bind+ucfirst(fileStem)+ModuleController。一级模块即BindIpfilterModuleController。
③ 模块级 Register 聚合 internal/app/plugins/sms/logic/logic.go
package logic
import (
pluginSmsConfig "github.com/tiger1103/gfast/v3/internal/app/plugins/sms/logic/pluginSmsConfig"
pluginSmsLog "github.com/tiger1103/gfast/v3/internal/app/plugins/sms/logic/pluginSmsLog"
)
// Register 收集本模块所有服务注册回调(由 boot 层收集,入口文件统一执行)
func Register() {
pluginSmsConfig.Register()
pluginSmsLog.Register()
}
新增一个 logic 子包时,只需在 logic.go 的 Register() 里加一行。
5.2 兼容:容器旧式布局
go/ 顶层出现 go/<installPath>/<name>/... 时,安装器会把 go/<installPath> 重定向到 internal/app/<installPath>,其余顶层条目按原样复制到后端根。
一级模块(
installPath=.)不接受该形式。
5.3 依赖注入与路由
- 服务注册链路:
logic 子包 Register()→模块 logic/logic.go Register()→boot/<fileStem>.go用register.Add(...)上交 →main.go调register.DoRegister()。 - 全项目零
init()(个别历史插件如sms/register.go的init()属例外,新插件不必模仿)。 - 路由前缀统一
/api/v1(internal/router/router.go),模块路由自行group.Group(...)后绑定。
5.4 业务模块子包职责
internal/app/plugins/sms/
├── controller/ # HTTP 处理,嵌入 systemController.BaseController
├── service/ # 自动生成的服务接口(gf gen service,勿手改)
├── logic/ # 业务实现,New() + Register()
├── model/ # 请求/响应模型(entity/ do/ 为 gf gen dao 产物)
├── dao/ # 数据访问(gf gen dao 产物)
└── router/ # 模块路由绑定接口 DTO(api/v1/plugins/sms/plugin_sms_config.go)用 g.Meta 声明路由:
type PluginSmsConfigSearchReq struct {
g.Meta `path:"/list" tags:"插件接口/短信配置" method:"get" summary:"短信配置列表"`
commonApi.Author // 鉴权/上下文用户信息
model.PluginSmsConfigSearchReq
}
commonApi.Author提供登录用户上下文;commonApi.EmptyRes用作无数据返回。
Controller 直接转发到 service:
type pluginSmsConfigController struct{ systemController.BaseController }
var PluginSmsConfig = new(pluginSmsConfigController)
func (c *pluginSmsConfigController) List(ctx context.Context, req *sms.PluginSmsConfigSearchReq) (res *sms.PluginSmsConfigSearchRes, err error) {
res = new(sms.PluginSmsConfigSearchRes)
res.PluginSmsConfigSearchRes, err = service.PluginSmsConfig().List(ctx, &req.PluginSmsConfigSearchReq)
return
}
5.5 模块路由注册模板(router/router.go)
var R = new(Router)
type Router struct{}
func (router *Router) BindController(ctx context.Context, group *ghttp.RouterGroup) {
group.Group("/plugins/sms", func(group *ghttp.RouterGroup) {
service.GfToken().Middleware(group) // 登录验证
group.Middleware(service.Middleware().Ctx, service.Middleware().Auth) // 上下文 + 权限
group.Hook("/*", ghttp.HookAfterOutput, service.OperateLog().OperationLog) // 操作日志
if err := libRouter.RouterAutoBind(ctx, router, group); err != nil {
panic(err)
}
})
}
5.6 排障:编译 / 依赖
- 插件引入第三方 Go module 时,必须显式在
install.json.dependencies.go声明(§9),并在安装后执行「安装依赖」,否则重编译会报缺包。 - 生成
service/、dao/用项目内的 gf CLI:gf gen service -s internal/app/plugins/sms/logic -d internal/app/plugins/sms/servicegf gen dao -link "mysql:user:pass@tcp(host:port)/dbname"
6. 前端开发规范
vue/ 内的路径相对 admin-ui/src(前端根来自配置 gen.frontDir,缺省 ../admin-ui)。
| 内容 | 放置位置 | 与菜单的对应 |
|---|---|---|
| 页面组件 | vue/views/<viewPath>/index.vue |
菜单 component = <viewPath>/index |
| 接口封装 | vue/api/modules/<name>.ts(或 api/modules/<name>/、api/<name>.ts) |
任选其一,导出/安装都支持三种形态 |
| 语言包 | 与页面同目录,如 locale-zh.ts / locale-en.ts |
自行 registerLocaleModule 注册 |
<viewPath>:容器 =<installPath>/<name>,一级 =<name>。菜单component由它推导视图目录(安装器会自动从菜单 component 反推需要打包的views/目录)。- keep-alive 命名:
defineOptions({ name: 'Dyn-<component 用 - 连接>' })。例:组件plugins/manage/index→Dyn-plugins-manage-index。不匹配会导致缓存失效。 - 模板单根元素:与
<Transition>+<KeepAlive>组合时,模板必须有唯一根元素(用<div>包裹),否则动画会报错。 - 接口封装示例(
vue/api/modules/sms.ts)用项目统一请求实例,路径以/api/v1为前缀。
7. 菜单与权限(menus.json)
7.1 命名空间(最重要)
所有菜单 name 必须落在本插件命名空间内:
api/v1/<modulePath> # 命名空间前缀
api/v1/plugins/sms # 容器示例
api/v1/ipfilter # 一级示例安装时按前缀做差异化同步(planMenuSync):
- 命名空间内、本次出现的既有菜单 → 复用其 ID 做 Update(角色授权不失效);
- 命名空间内、本次未出现的 → 删除,并清理其 Casbin 授权策略;
- 命名空间外的既有菜单 → 一律不动。
- 越界的 name 会被当作新菜单插入并给出告警。
这也是为什么不要复用别人插件的 name:否则会互删菜单。
7.2 节点字段(MenuNode)
| 字段 | 说明 |
|---|---|
name |
权限标识 / 路由 name,必须带命名空间前缀 |
title |
显示标题 |
icon |
Iconify Remix 图标,必须以 ri: 开头(如 ri:puzzle-line) |
menuType |
0 目录 / 1 菜单 / 2 按钮 |
path |
前端路由地址(菜单/目录用) |
component |
组件路径;目录用 layout/routerView/parent,页面用 <viewPath>/index |
weigh |
排序权重 |
isHide |
是否隐藏(隐藏菜单内部跳转需 registerLeafRoutes 注册,否则 404) |
isCached |
是否 keep-alive 缓存 |
isIframe / isLink / linkUrl |
内嵌 / 外链相关 |
redirect / isAffix |
重定向 / 固定标签 |
moduleType |
所属模块,缺省 sys_admin |
modelId |
模型 ID |
condition / remark |
备注类字段 |
children |
子节点数组 |
7.3 权限按钮与 v-auth
menuType=2 的按钮节点 name(如 api/v1/plugins/sms/pluginSmsConfig/get)就是前端 v-auth 判断用的权限串。页面按钮写法:
<el-button v-auth="'api/v1/plugins/manage/export'">导出</el-button>
7.4 骨架生成的约定菜单
buildScaffoldMenus 会生成:目录(ri:puzzle-line)→ 列表页(component=<viewPath>/index,ri:file-list-2-line)+ 4 个按钮(get/add/edit/delete)。按实际业务增删即可。
导出插件时,
menus.json由数据库现有菜单行生成(见 §10),而不是固定模板。
8. 数据库脚本规范
文件命名与择优顺序(collectSqlFiles):
install_<dialect>.sql(方言专属,命中即只执行它)install.sql(通用回落,兼容历史包)go/**/data/*.sql(仅data目录内;同时存在方言专属时只取专属)
硬性约定
- 仅幂等 DDL:
CREATE TABLE IF NOT EXISTS ...。 - 每条语句必须以分号
;结尾(安装器按;拆分语句)。多表脚本漏分号会把多条CREATE TABLE合并成一条而整体执行失败。 - 禁止破坏性语句:
DROP TABLE/DATABASE/SCHEMA、TRUNCATE会被安装器跳过并记警告(防止清空接收方数据)。 - 不要写
INSERT等数据语句:避免把本机配置、密钥随包分发;配置应由使用方在页面填写。 - 安装时以单连接事务顺序执行,支持
LAST_INSERT_ID()等会话变量;单条失败记为警告、不中断安装。 tables(install.json)应如实列出业务表:卸载时按它精确删表。
方言
- 声明
dialects只列包内真实提供的方言。 - 声明了某方言却没有对应脚本时:该数据库上安装会直接报错阻断(tables 非空时)。
- 缺省(不声明)按历史约定视为仅 mysql;在 PostgreSQL 上会被明确阻断,而不是静默缺表。
9. 依赖声明(install.json.dependencies)
"dependencies": {
"go": [{ "target": "github.com/x/y", "version": "v1.2.3", "standard": false }],
"npm": [{ "target": "echarts", "version": "^5.6.0", "standard": true }]
}
version留空 = 安装最新版。standard标记框架标准依赖(前端弹窗据此区分展示)。- 安装时安装器把声明与接收方现状比对,得到三种判定:
install(缺失)/upgrade(版本偏低)/skip(已满足或不可判定)。绝不降级。 - 是否安装后自动进入依赖安装,由宿主配置
plugin.deps.autoInstall决定;也可在列表页用「安装依赖」手动触发。 - 依赖安装过程有进度任务(
depTaskStatus轮询),失败/取消可重试。 - 导出/生成骨架时,不填依赖会自动扫描源码:
- Go:解析
go.mod(module/require/replace)与源码 import; - npm:匹配
from 'x'/import('x')/require('x')(宁多勿漏,可在弹窗删除误报)。
- Go:解析
10. 打包导出
后台入口:「插件管理 → 已安装插件 Tab → 打包导出」或列表行「导出」。
两种来源:
| 场景 | 行为 |
|---|---|
| 已安装插件 | 只传 name,其余元数据取 sys_plugins 安装记录 |
| 未登记插件(有源码、无安装记录) | 弹窗补齐 title/version/auth/installPath/tables/dialects/依赖;其余自动探测 |
后端 Export(GET /api/v1/plugins/manage/export)生成内容:
install.json:minGfastVersion统一写当前框架版本;tables= 入参 ∪ 记录 ∪ 前缀探测;dialects= 可提供的方言集合。go/:模块目录 +api目录 + boot/router 文件;排除模块根data/目录。vue/:由菜单 component 反推的views/**目录 + 实际存在的 api 封装(三种形态)。无菜单时回退约定路径views/<viewPath>。install_<dialect>.sql:优先复用安装时缓存的原始脚本(保留插件原有其他方言版本);当前库方言无缓存时,按实际表结构重建幂等 DDL。多方言顺序固定为 mysql、pgsql。menus.json:从数据库读取当前菜单行构建树(按安装记录的菜单 ID 优先,缺省按 name 命名空间前缀匹配);查不到菜单行则完全不生成该文件。
自动探测说明:
installPath:入参 > 记录 > 源码目录探测 > 缺省plugins。tables:plugin_<name小写>与plugin_<name小写>_*前缀匹配(按方言查 information_schema / pg_tables)。
导出/导入可往返:在 MySQL 主机导出的包,只要安装时缓存过 PG 脚本,就能把 PG 版一并带回(缓存位置
<后端根>/data/pluginSql/<name>/)。
11. 安装
11.1 安装流水线(installFromZip)
- 解压(含 Zip Slip 路径穿越校验)到
data/installPlugins。 - 定位包目录(按响应头/文件名期望,否则扫描唯一顶层目录)。
- 解析 + 校验
install.json:name/version必填,installPath合法性,一级模块保留名校验。 - 方言兼容检查(在任何写操作之前):包声明的
dialects不含当前库方言 → 零副作用阻断。 - 依赖声明清洗:非法条目丢弃并记警告,不中断。
- 包目录名统一为
install.json.name。 - 收集 SQL:声明了
tables却无任何脚本 → 报错阻断(避免“装完却没有表”)。 - 框架版本门槛:
minGfastVersion> 当前版本 → 阻断。 - 覆盖闸门:
force=false且(已有安装记录 / 目标模块目录已存在)→ 返回needConfirm,未写入任何文件;前端确认后带force=true重试。 - 复制文件:复制前建快照,失败自动回滚(DDL 无事务,不回滚数据库)。
- 执行 SQL(§8)。
- 同步菜单(§7.1)。
- 写
sys_plugins记录(tables/dialects/menus/dependencies 落库)→ 此后不再回滚文件。 - 缓存包内方言 SQL,清菜单缓存。
- 依赖判定:读接收方
go.mod/package.json,返回可执行依赖项。
安装 / 卸载互斥(进程内
opMutex),同一时刻只允许一个文件操作。
11.2 安装后必做
- 重新编译并重启后端(Go 是编译型服务):
go run main.go。 - 前端:开发模式自动热更;生产需重新构建。
- 给角色授权新菜单/按钮,否则非超管看不到入口。
- 若菜单/配置没刷新:清缓存
DELETE /api/v1/system/cache/remove(Redis 菜单缓存可能跨重启残留)。 - Casbin 规则变更需重启后端才清除内存 enforcer 缓存。
- 缺失依赖:列表行「安装依赖」或安装后弹窗确认执行。
11.3 安装失败对照表
| 报错关键词 | 原因 | 处理 |
|---|---|---|
| 插件名不合法 | name 不符 ^[A-Za-z][A-Za-z0-9_]{1,63}$ |
改名后重打包 |
| 已阻断安装(方言不匹配) | dialects 不含当前库方言 |
换匹配版本,或补对应 install_<方言>.sql 并更新 dialects |
| 您的gfast版本过低 | minGfastVersion 高于 3.4.2 |
下调 minGfastVersion 或升级框架 |
| 包内未提供 install_xxx.sql | 声明了 tables 但无脚本 |
补脚本 |
| 一级模块插件包必须使用原生布局 | installPath=. 却用了 go/<name>/ |
改为 go/internal/app/<name>/ |
| 以下 SQL 语句执行失败(警告) | 语句语法/多表漏分号/方言不符 | 修脚本,确保每条 DDL 以 ; 结尾 |
| 已跳过破坏性语句(警告) | 包内含 DROP/TRUNCATE | 移除这些语句 |
| needConfirm | 覆盖确认 | 前端确认后自动带 force 重试 |
12. 卸载
「插件管理 → 已安装插件 → 卸载」,可选「同时删除业务数据表」。
Uninstall 流程:
- 读取
sys_plugins记录,推导布局与(从菜单推导的)前端视图目录。 - 删除本插件命名空间菜单,并清理其 Casbin 授权策略(避免策略悬空)。
- 后端源码、前端视图与 api 封装备份后移除,备份位置:
<后端根>/data/uninstallBackup/<name>-<时间戳>/ - 勾选删表时:对记录在案的
tables执行DROP TABLE IF EXISTS <方言引用>。 - 删除
sys_plugins安装记录;清菜单缓存。
卸载后同样需要重新编译重启后端,并重新授权已删除菜单涉及的角色项(新装时重新授权)。
13. 注意事项与常见坑
- SQL 分号:
install_<dialect>.sql每条语句必须以;结尾。尤其导出重建的脚本曾因漏分号导致多表合并、建表失败——现已修复,但历史包需重新导出。 - 菜单命名空间:
name必须带api/v1/<modulePath>前缀,避免误删他人菜单。 - 保留目录:一级模块 name 不得为
system/common/boot/plugins。 - 不要放 `go//data/.sql`*:会被自动执行,易与根目录脚本冲突。
- 不写数据/凭证:包内只放幂等 DDL 与源码,配置由使用方填写。
- 图标前缀:菜单图标必须
ri:*。 - keep-alive 名:
Dyn-<组件路径连字符>,且模板单根元素。 - 前端视图目录推导:来自菜单
component目录(跳过layout/);菜单 component 写错会导致前端源码打包/卸载路径不对。 - 缓存:菜单/配置改动不生效时先清缓存;Casbin 改动需重启。
- 并发:安装/卸载串行;不要并发触发。
- 临时目录:打包/生成骨架的临时目录默认
<后端根>/data/tmp,受限环境可用plugin.stagingDir覆盖。 - 未登记插件导出依赖源码目录存在;元数据缺失靠弹窗补齐。
附录 A:插件管理 API
前缀 /api/v1/plugins/manage:
| 端点 | 方法 | 说明 |
|---|---|---|
/localList |
GET | 已安装插件列表(含当前方言、兼容性、待装依赖数) |
/storeList |
GET | 在线商城插件列表 |
/install |
POST | 在线安装 |
/installLocal |
POST | 本地导入安装(zip 上传) |
/uninstall |
POST | 卸载(可选删表) |
/export |
GET | 导出插件包(支持未登记插件) |
/scaffold |
GET | 生成插件包骨架 |
/storeCaptcha |
GET | 商城验证码 |
/storeLogin |
POST | 商城登录 |
/scanDeps |
GET | 扫描插件依赖 |
/installDeps |
POST | 安装插件依赖 |
/depTaskStatus |
GET | 依赖任务状态 |
/cancelDepTask |
POST | 取消依赖任务 |
附录 B:相关配置(manifest/config/config.yaml)
gen:
frontDir: "../admin-ui" # 前端路径(与后端项目平级)
plugin:
serverUrl: "https://plugins.g-fast.cn" # 插件商城地址
# backendDir: "" # 后端项目根覆盖,缺省取主程序源码目录/进程工作目录
# stagingDir: "" # 打包临时目录,缺省 <后端根>/data/tmp
deps:
autoInstall: true # 安装插件后是否自动进入依赖安装
goCommand: "go" # 后端依赖安装命令
npmCommand: "pnpm" # 前端依赖安装命令
npmDir: "" # 前端项目根覆盖,缺省 gen.frontDir 的父目录
timeoutSeconds: 600 # 单条命令超时(秒)
runGoModTidy: false # go get 后是否追加 go mod tidy
附录 C:内置文件落盘位置一览(相对后端根)
| 用途 | 路径 |
|---|---|
| 安装临时目录 | data/installPlugins/ |
| 打包/骨架临时目录 | data/tmp/(可配 plugin.stagingDir) |
| 包内方言 SQL 缓存 | data/pluginSql/<name>/ |
| 卸载备份 | data/uninstallBackup/<name>-<时间戳>/ |
附录 D:可参考的真实样例
| 样例 | 布局 | 位置 |
|---|---|---|
| 短信插件 | 容器 plugins/sms |
internal/app/plugins/sms/、api/v1/plugins/sms/ |
| IP 过滤模块 | 一级 . → internal/app/ipfilter |
internal/app/ipfilter/ |
| 插件管理自身 | 容器 plugins/manage |
internal/app/plugins/manage/ |
一页速记
- 生成骨架 → 放
go/与vue/→ 补 SQL(幂等 + 分号)→ 调menus.json(命名空间)。 - zip 根目录必须是
<name>/。 - 本地导入安装 → 确认覆盖 → 按需装依赖 → 重编译重启后端 → 给角色授权。
- 导出用于分发;未登记插件靠弹窗补元数据,其余自动探测。
最后编辑:管理员 更新时间:2026-10-19 11:30