12 KiB
角色管理 — 前端对接文档
遵循《业务中台产品接口说明书》全局契约
接口基础路径:/api/roles
权限控制:纯hasAuthority,权限码由DataInitializer种子化到权限资源树
1. 接口总览
| 方法 | 路径 | 用途 | 权限码 |
|---|---|---|---|
POST |
/api/roles/page |
分页查询角色列表 | crm:role:list |
POST |
/api/roles/saveOrUpdate |
新增或编辑角色 | crm:role:save |
GET |
/api/roles/detail |
角色详情(含已授权资源集合) | crm:role:detail |
POST |
/api/roles/assign-resources |
分配角色权限资源(祖先补全 + 全量替换) | crm:role:assign |
POST |
/api/roles/delete |
删除角色(级联清理关联表) | crm:role:delete |
认证方式:所有接口需在请求头携带 Authorization: Bearer {token},且 token 对应用户必须拥有对应权限码。
请求格式:
GET请求:参数放 URL queryPOST请求:Content-Type: application/x-www-form-urlencoded,参数为表单字段
⚠️ 注意:POST 请求不使用 JSON body,复杂字段(对象/数组)各自
JSON.stringify后作为普通表单字段传递。
2. 数据模型
2.1 SysRole(列表/编辑)
interface SysRole {
id: string; // 角色 ID(字符串,雪花 ID)
roleName: string; // 角色名称
roleCode: string; // 角色编码(如 ROLE_SALES)
dataScope: number; // 数据范围:1=本人 2=本部门 3=本部门及子部门 4=全部
sort: number; // 排序号,值越小越靠前
remark: string | null; // 备注
builtin: boolean; // 是否内置角色(true=系统内置,不可删除、不可改编码)
}
2.2 RoleDetailVO(详情接口返回)
interface RoleDTO {
id: string; // 角色 ID
roleName: string; // 角色名称
roleCode: string; // 角色编码
dataScope: number; // 数据范围:1=本人 2=本部门 3=本部门及子部门 4=全部
sort: number; // 排序
remark: string | null; // 备注
builtin: boolean; // 是否内置角色
resourceIds: string[]; // 已授权的资源 ID 集合(存储态,已含祖先补全)
}
⚠️ ID 一律按字符串收发。后端返回的 id 是字符串(雪花 ID 超出 JS Number 安全范围),前端回传原样传字符串即可,不要转 Number。
2.3 dataScope 枚举
| 值 | 含义 | 说明 |
|---|---|---|
| 1 | 仅本人 | 只能看到自己创建的数据 |
| 2 | 本部门 | 能看到本部门所有成员的数据 |
| 3 | 本部门及子部门 | 能看到本部门及其下属部门的数据 |
| 4 | 全部数据 | 能看到所有数据 |
注:值 5(自定义)存在于枚举中,但角色接口不允许设置,仅 1-4 合法。
3. 统一响应结构
所有接口返回统一结构:
interface Result<T> {
code: number; // 0=成功,非 0=失败
success: boolean; // 是否成功
message: string; // 错误信息(成功时为 null)
data: T; // 业务数据(无数据时为 null)
}
分页接口的 data 为 PageResult:
interface PageResult<T> {
content: T[]; // 数据列表
total: number; // 总条数
size: number; // 每页条数
current: number; // 当前页码(从 1 开始)
pages: number; // 总页数
empty: boolean; // 是否为空结果
}
4. 接口详情
4.1 分页查询角色列表
POST /api/roles/page
权限码:crm:role:list
请求参数(表单字段):
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
current |
number | 否 | 1 | 当前页码 |
size |
number | 否 | 10 | 每页条数 |
keyword |
string | 否 | - | 按角色名称模糊搜索 |
请求示例:
POST /api/roles/page
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {token}
current=1&size=10&keyword=销售
响应示例:
{
"code": 0,
"success": true,
"data": {
"content": [
{
"id": "1",
"roleName": "管理员",
"roleCode": "ROLE_ADMIN",
"dataScope": 4,
"sort": 0,
"remark": null,
"builtin": true
},
{
"id": "2",
"roleName": "销售",
"roleCode": "ROLE_SALES",
"dataScope": 2,
"sort": 1,
"remark": "销售团队角色",
"builtin": false
}
],
"total": 2,
"size": 10,
"current": 1,
"pages": 1,
"empty": false
}
}
4.2 新增或编辑角色
POST /api/roles/saveOrUpdate
权限码:crm:role:save
请求参数(表单字段):
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
id |
string | 否 | - | 不传=新增,传=编辑 |
roleName |
string | 是 | - | 角色名称 |
roleCode |
string | 是 | - | 角色编码(编辑内置角色时不可修改) |
dataScope |
number | 否 | 1 | 数据范围 1-4 |
sort |
number | 否 | 0 | 排序号 |
remark |
string | 否 | - | 备注 |
⚠️
builtin字段不接受前端传入。新建角色固定builtin=false,内置角色由系统初始化创建。
校验规则:
| 规则 | 触发条件 | 错误码 | 错误信息 |
|---|---|---|---|
| 角色名称为空 | roleName 为空 |
61010 | 角色名称不能为空 |
| 角色编码为空 | roleCode 为空 |
61010 | 角色编码不能为空 |
| 数据范围不合法 | dataScope 不在 1-4 |
61010 | 数据范围不合法 |
| 编码已存在 | roleCode 与其他角色重复 |
61011 | 角色编码已存在:{roleCode} |
| 内置角色改编码 | 编辑内置角色时修改了 roleCode |
61012 | 内置角色的编码不可修改 |
| 非法创建内置角色 | 尝试设置 builtin=true |
61012 | 不允许通过接口创建内置角色 |
新增请求示例:
POST /api/roles/saveOrUpdate
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {token}
roleName=销售&roleCode=ROLE_SALES&dataScope=2&sort=1&remark=销售团队角色
编辑请求示例:
POST /api/roles/saveOrUpdate
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {token}
id=2&roleName=销售&roleCode=ROLE_SALES&dataScope=3&sort=1&remark=改为本部门及子部门
响应:
{
"code": 0,
"success": true,
"data": null
}
4.3 角色详情
GET /api/roles/detail
权限码:crm:role:detail
请求参数(URL query):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
roleId |
string | 是 | 角色 ID |
请求示例:
GET /api/roles/detail?roleId=2
Authorization: Bearer {token}
响应示例:
{
"code": 0,
"success": true,
"data": {
"id": "2",
"roleName": "销售",
"roleCode": "ROLE_SALES",
"dataScope": 2,
"sort": 1,
"remark": "销售团队角色",
"builtin": false,
"resourceIds": ["1", "10", "100", "200"]
}
}
resourceIds是存储态的完整授权集合(已含祖先补全)。前端在回显权限树勾选状态时,需要用这个集合与资源树做交集——但只需勾选叶子节点,祖先节点会自动包含在集合中但不需要在前端勾选。
4.4 分配角色权限资源
POST /api/roles/assign-resources
权限码:crm:role:assign
请求参数(表单字段):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
roleId |
string | 是 | 角色 ID |
resourceIds |
string | 否 | 逗号分隔的资源 ID,不传或空字符串=清空权限 |
⚠️ 前端只需传用户勾选的叶子节点 ID。后端会自动沿 parentId 向上遍历补全所有祖先节点(ADR-0005),确保菜单可见性链路完整。
例如:前端勾选了叶子节点100,其祖先为10→1,后端会自动补全为{1, 10, 100}写入数据库。
请求示例:
POST /api/roles/assign-resources
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {token}
roleId=2&resourceIds=100,200,300
清空权限示例:
POST /api/roles/assign-resources
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {token}
roleId=2&resourceIds=
响应:
{
"code": 0,
"success": true,
"data": null
}
实现说明:
- 后端调用
getAncestorIds补全全部祖先 ID - 先删除该角色的所有旧关联(全量替换,非增量)
- 批量插入补全后的完整 ID 集合
- 整个操作在
@Transactional事务中执行
4.5 删除角色
POST /api/roles/delete
权限码:crm:role:delete
请求参数(表单字段):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 角色 ID |
请求示例:
POST /api/roles/delete
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer {token}
id=2
响应:
{
"code": 0,
"success": true,
"data": null
}
级联清理说明:
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | 内置角色检查 | builtin=true 的角色拒绝删除,返回错误码 61012 |
| 2 | 清理 sys_role_menu |
删除该角色与所有菜单/权限点的关联 |
| 3 | 清理 sys_user_role |
解除该角色与所有用户的绑定 |
| 4 | 删除角色记录 | 从 sys_role 表删除 |
| 5 | 全部在事务中执行 | 任一步骤失败则回滚 |
内置角色删除失败示例:
{
"code": 61012,
"success": false,
"message": "内置角色不允许删除"
}
5. 错误码
| 错误码 | 含义 | 触发场景 |
|---|---|---|
| 61010 | 角色参数非法 | 角色名称/编码为空、数据范围不合法 |
| 61011 | 角色编码已存在 | 新建或编辑时 roleCode 与其他角色重复 |
| 61012 | 内置角色保护 | 删除内置角色、修改内置角色编码、尝试创建内置角色 |
6. 权限码与前端按钮控制
角色管理页面的按钮需要根据权限码控制显示:
| 权限码 | 对应按钮 | 说明 |
|---|---|---|
crm:role:list |
角色列表页面访问 | 控制菜单可见性 |
crm:role:detail |
查看/编辑按钮 | 点击后调用详情接口 |
crm:role:save |
新增/编辑保存按钮 | 弹窗保存时调用 |
crm:role:assign |
权限分配按钮 | 打开权限树弹窗时调用 |
crm:role:delete |
删除按钮 | 列表行操作列 |
这些权限码在系统启动时由
DataInitializer自动创建为 button 类型权限点,并分配给管理员角色。其他角色需要通过权限分配接口授予。
7. 前端典型流程
7.1 角色列表页
1. 进入页面 → POST /api/roles/page?current=1&size=10
2. 输入关键词搜索 → POST /api/roles/page?current=1&size=10&keyword=销售
3. 点击"新增" → 弹窗填写 → POST /api/roles/saveOrUpdate
4. 点击"编辑" → GET /api/roles/detail?roleId=xxx → 回填表单 → POST /api/roles/saveOrUpdate
5. 点击"删除" → 确认 → POST /api/roles/delete?id=xxx
7.2 权限分配弹窗
1. 打开弹窗 → 调用 /api/resources/list 获取资源树
2. 回显已选 → GET /api/roles/detail?roleId=xxx → 取 resourceIds 与资源树做交集
3. 用户勾选/取消勾选叶子节点
4. 点击"保存" → POST /api/roles/assign-resources?roleId=xxx&resourceIds=100,200,300
前端只需提交用户勾选的叶子节点 ID。后端自动补全祖先,无需前端处理。
7.3 内置角色处理
- 管理员角色(
builtin=true)在列表中展示时,删除按钮应置灰或隐藏 - 编辑内置角色时,角色编码字段应设为只读(后端会拒绝修改)