2026-07-22 代码优化
本文档说明 2026-07-22 后端改动。重点为 泰额版 租户业务库菜单表(menu)的增删改查接口。
与 2026-07-21 文档中的「平台 SaaS 菜单权限分配」(主库 fl_th_tenant_menu_permission / menuPermissionKeys)不同:
本文接口操作的是当前租户业务库的 menu 表(RBAC 菜单资源),不是平台静态权限目录。
一、变更概述
| 项 |
说明 |
| 范围 |
泰额版 Yi.Abp.Net8 / FoodLabeling.Th.* |
| 实现 |
ThRbacMenuAppService(Swagger 分组:食品标签-泰额版接口) |
| 数据表 |
租户业务库 menu(如 Default 租户对应 antis-foodlabeling-us) |
| 路由前缀 |
/api/app/th-rbac-menu/* |
| Id 生成 |
新建菜单 Id 使用 YitIdHelper.NextId().ToString()(雪花字符串) |
| 组树方式 |
MenuDbEntity + 字符串 ParentId 自行组树;禁止 MenuAggregateRoot(Guid) + TreeHelper |
| 与旧接口关系 |
美国版模块仍保留 /api/app/rbac-menu/*;泰额前端建议改调 th-rbac-menu |
二、接口一览
鉴权:全部需登录(Authorization: Bearer {token})。
Token 建议通过 POST /api/app/th-web-auth/login 获取(JWT 含 TenantId,操作当前租户业务库)。
| 方法 |
路径 |
说明 |
| GET |
/api/app/th-rbac-menu/list |
分页列表 |
| GET |
/api/app/th-rbac-menu/{id} |
单条详情 |
| POST |
/api/app/th-rbac-menu |
新增 |
| PUT |
/api/app/th-rbac-menu/{id} |
修改 |
| DELETE |
/api/app/th-rbac-menu |
批量逻辑删除 |
| GET |
/api/app/th-rbac-menu/tree |
全量菜单树(不分页) |
路由说明:ABP RootPath 为 api/app;自定义路由必须带 th-rbac-menu/ 前缀,完整路径才是 /api/app/th-rbac-menu/...。
三、分页列表
3.1 接口
| 项 |
值 |
| 方法 / 路径 |
GET /api/app/th-rbac-menu/list |
| 说明 |
查询当前租户业务库未删除菜单,支持筛选与分页 |
3.2 入参(Query)
| 字段 |
说明 |
skipCount |
跳过条数 |
maxResultCount |
每页条数 |
menuName |
菜单名称模糊匹配(可选) |
state |
启用状态(可选) |
menuSource |
菜单来源枚举(可选) |
menuType |
菜单类型枚举(可选) |
3.3 出参示例
{
"totalCount": 2,
"items": [
{
"id": "1234567890123456789",
"parentId": "0",
"menuName": "Settings",
"routerName": "settings",
"router": "/settings",
"permissionCode": "system:settings",
"menuType": 1,
"menuSource": 2,
"orderNum": 10,
"state": true
}
]
}
排序:orderNum 降序。
四、单条详情
4.1 接口
| 项 |
值 |
| 方法 / 路径 |
GET /api/app/th-rbac-menu/{id} |
| 说明 |
按主键查询未删除菜单;不存在返回业务友好错误 |
出参字段与列表 items 项一致(ThRbacMenuGetListOutputDto)。
五、新增菜单
5.1 接口
| 项 |
值 |
| 方法 / 路径 |
POST /api/app/th-rbac-menu |
| Content-Type |
application/json |
5.2 入参
{
"menuName": "Settings",
"parentId": "0",
"menuType": 1,
"menuSource": 2,
"permissionCode": "system:settings",
"router": "/settings",
"routerName": "settings",
"component": "views/settings/index",
"menuIcon": "Setting",
"orderNum": 10,
"state": true,
"isShow": true
}
| 字段 |
必填 |
说明 |
menuName |
是 |
菜单名称 |
parentId |
否 |
父级 Id;空或根用 "0"(兼容全 0 Guid) |
menuType |
是 |
MenuTypeEnum:0=Catalogue,1=Menu,2=Component |
menuSource |
是 |
MenuSourceEnum:0=Ruoyi,1=Pure,2=Vben5 |
permissionCode |
否 |
权限码 |
router / routerName / component / menuIcon |
否 |
路由与展示 |
orderNum |
否 |
排序号 |
state |
否 |
启用状态,默认 true |
isShow |
否 |
是否显示,默认 true |
5.3 处理规则
- 校验
menuName 非空
- 规范化
parentId;非根时校验父菜单存在且未删除
- Id =
YitIdHelper.NextId().ToString()
- 插入当前租户业务库
menu,返回新建详情
六、修改菜单
6.1 接口
| 项 |
值 |
| 方法 / 路径 |
PUT /api/app/th-rbac-menu/{id} |
| Content-Type |
application/json |
入参字段与新增相同(ThRbacMenuUpdateInputVo 继承 ThRbacMenuCreateInputVo)。
6.2 处理规则
- 菜单必须存在且未删除
menuName 必填
- 禁止
parentId 等于自身
- 禁止将菜单移动到其子节点下(一级校验)
- 更新后返回最新详情
七、批量删除
7.1 接口
| 项 |
值 |
| 方法 / 路径 |
DELETE /api/app/th-rbac-menu |
| Content-Type |
application/json |
| 说明 |
逻辑删除(IsDeleted = true),非物理删 |
7.2 入参
["1234567890123456789", "9876543210987654321"]
空列表或全空白 Id 时直接返回(无操作)。
八、菜单树
8.1 接口
| 项 |
值 |
| 方法 / 路径 |
GET /api/app/th-rbac-menu/tree |
| 说明 |
返回当前租户全部未删除菜单,按字符串 ParentId 组树 |
8.2 出参要点
- 根节点:
parentId 为 "0"(或全 0 Guid)
- 子节点:
children 数组嵌套
- 同级排序:
orderNum 降序
- 树节点字段比列表更全(含
menuIcon、isShow、component、remark、审计字段等)
8.3 出参示例(节选)
[
{
"id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"parentId": "0",
"menuName": "System",
"menuType": 0,
"menuSource": 2,
"orderNum": 100,
"state": true,
"isShow": true,
"children": [
{
"id": "1234567890123456789",
"parentId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"menuName": "Settings",
"menuType": 1,
"orderNum": 10,
"children": []
}
]
}
]
九、数据表与枚举
| 字段 |
类型要点 |
说明 |
Id |
varchar |
主键;历史多为 UUID 字符串,新建为雪花字符串 |
ParentId |
varchar |
父级;根为 "0" |
MenuName |
varchar |
菜单名称 |
MenuType |
int |
见 MenuTypeEnum |
MenuSource |
int |
见 MenuSourceEnum |
IsDeleted |
tinyint/bool |
逻辑删除 |
| 其他 |
— |
Router、Component、PermissionCode、OrderNum、State、IsShow 等 |
平台主库 antis-foodlabeling-host 无此业务 menu 表。
9.2 枚举
| 枚举 |
值 |
MenuTypeEnum |
0=Catalogue(目录),1=Menu(菜单),2=Component(组件/按钮) |
MenuSourceEnum |
0=Ruoyi,1=Pure,2=Vben5 |
十、代码文件
| 类型 |
路径 |
| 服务 |
FoodLabeling.Th.Application/Services/ThRbacMenuAppService.cs |
| 接口 |
FoodLabeling.Th.Application.Contracts/IServices/IThRbacMenuAppService.cs |
| DTO |
FoodLabeling.Th.Application.Contracts/Dtos/RbacMenu/ThRbacMenu*.cs |
| 实体映射 |
复用 FoodLabeling.Application.Services.DbModels.MenuDbEntity(字符串 Id) |
十一、curl 示例
# 1) 登录拿 Token(按环境改 host / 账号 / 租户名)
curl -X POST "http://127.0.0.1:19002/api/app/th-web-auth/login" \
-H "Content-Type: application/json" \
-d "{\"tenantName\":\"Default\",\"userName\":\"admin\",\"password\":\"123456\"}"
# 2) 菜单树
curl -X GET "http://127.0.0.1:19002/api/app/th-rbac-menu/tree" \
-H "Authorization: Bearer <token>"
# 3) 分页列表
curl -X GET "http://127.0.0.1:19002/api/app/th-rbac-menu/list?skipCount=0&maxResultCount=20" \
-H "Authorization: Bearer <token>"
# 4) 新增
curl -X POST "http://127.0.0.1:19002/api/app/th-rbac-menu" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d "{\"menuName\":\"Settings\",\"parentId\":\"0\",\"menuType\":1,\"menuSource\":2,\"router\":\"/settings\",\"orderNum\":10,\"state\":true,\"isShow\":true}"
# 5) 修改
curl -X PUT "http://127.0.0.1:19002/api/app/th-rbac-menu/<id>" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d "{\"menuName\":\"Settings\",\"parentId\":\"0\",\"menuType\":1,\"menuSource\":2,\"orderNum\":20,\"state\":true,\"isShow\":true}"
# 6) 批量删除
curl -X DELETE "http://127.0.0.1:19002/api/app/th-rbac-menu" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d "[\"<id1>\",\"<id2>\"]"
新增后可用查库核对:
SELECT Id, ParentId, MenuName, MenuType, MenuSource, IsDeleted, OrderNum
FROM menu
WHERE Id = '<新Id>';
十二、前端对接注意
- 路由前缀使用
/api/app/th-rbac-menu/*,不要与旧 /rbac-menu 混淆。
- 字段 camelCase:
menuName、parentId、menuType、menuSource、orderNum 等。
- 树管理页用
/tree;表格/筛选页用 /list 分页。
- 根节点
parentId 传 "0"。
- 必须在正确租户上下文下调用(登录 JWT 含
TenantId);写入的是该租户业务库,不是 host。
- 部署后需重启后端进程,新路由才会注册生效。
十三、与 2026-07-21「菜单权限」的区分
| 维度 |
2026-07-21 平台菜单权限 |
2026-07-22 业务菜单 CRUD(本文) |
| 库 |
平台主库 antis-foodlabeling-host |
租户业务库(如 antis-foodlabeling-us) |
| 表 |
fl_th_tenant_menu_permission |
menu |
| 语义 |
SaaS 公司可开通的功能 Key |
RBAC 菜单资源(路由/组件/权限码) |
| 典型接口 |
th-multi-tenancy/company-menus 等 |
th-rbac-menu/* |