@duxiaoma/design-rbac
v1.0.2
Published
基于 Vue3 + ant-design-vue 的 RBAC 权限组件库(资源目录 / 资源节点 / 资源行为 / 部门角色 / 用户授权)
Maintainers
Readme
@duxiaoma/design-rbac
基于 Vue 3 + ant-design-vue v4 + @duxiaoma/adm-vue3 的 RBAC(基于角色的权限控制)业务组件库,内置关系图可视化配置,开箱即用。提供四大业务页面:资源行为管理、资源权限管理、部门角色管理、用户授权管理,并对外导出权限判断方法 isHasPower。
后端接口的入参 / 反参明细见同目录 INTE.md,本文档只介绍组件库的接入与配置。
一、功能特性
- 资源行为管理:资源行为枚举(查看 / 新增 / 修改 / 删除 / 导入 / 导出等内置行为 + 自定义行为)的分页查询与维护。
- 资源权限管理:以关系图管理「资源目录 → 资源节点 → 资源行为」三级资源树,右键节点即可新增 / 编辑 / 删除 / 授权。
- 部门角色管理:以关系图管理「组织 → 部门角色」树,支持角色维护与角色资源授权。
- 用户授权管理:用户池分页检索,对用户批量授权资源行为、批量分配部门角色,支持单用户回显。
- 宿主无关设计:接口地址、前缀、HTTP 方法、请求实例全部可配置 / 可注入,不绑定任何后端框架。
- 细粒度权限控制:通过
options.power传入当前用户权限码,控制每个操作入口的显示 / 禁用;同时导出纯函数isHasPower供宿主项目在菜单、路由、按钮等场景复用。
二、环境要求
组件库以下列依赖作为 peerDependencies,由宿主项目提供(不重复打包):
| 依赖 | 版本要求 | 说明 |
| --- | --- | --- |
| vue | ^3.5.0 | Vue 3 |
| ant-design-vue | ^4.2.0 | UI 组件库,宿主需已全局注册或可自行解析其组件 |
| @duxiaoma/adm-vue3 | ^1.0.3 | 团队基础组件库(CTable / CTitle / useTable 等) |
其余运行时依赖(relation-graph、lodash、@ant-design/icons-vue)已在 dependencies 中声明,安装本包时会自动安装。
三、安装与引入
3.1 安装
pnpm add @duxiaoma/design-rbac
# 或
npm i @duxiaoma/design-rbac3.2 引入样式
组件样式与逻辑分离,必须在入口文件(如 main.ts)中手动引入一次:
import '@duxiaoma/design-rbac/style.css'关系图(relation-graph)的样式随其包内联注入,无需额外引入。
3.3 全量注册
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import DesignRbac from '@duxiaoma/design-rbac'
import '@duxiaoma/design-rbac/style.css'
const app = createApp(App)
app.use(DesignRbac) // 全局注册 GraphAction / GraphResources / GraphRole / GraphUser
app.mount('#app')3.4 按需引入(推荐)
支持局部注册,也支持 app.use(单个组件):
// 方式一:SFC 中直接引入使用
import {
GraphResources,
GraphRole,
GraphAction,
GraphUser
} from '@duxiaoma/design-rbac'// 方式二:单独全局注册某个组件
import { GraphResources } from '@duxiaoma/design-rbac'
app.use(GraphResources)四、组件与配置
4.1 组件一览
| 组件名 | 页面标题 | 说明 |
| --- | --- | --- |
| GraphAction | 资源行为列表 | 资源行为枚举的分页查询、新增、编辑、删除 |
| GraphResources | 资源权限管理 | 资源目录 / 资源节点关系图,右键维护目录与节点、配置行为 |
| GraphRole | 部门角色管理 | 组织 / 部门角色关系图,右键维护角色并为角色授权资源 |
| GraphUser | 用户授权管理 | 用户池列表,批量授权资源行为 / 部门角色 |
4.2 通用 Props
四个组件的 Props 完全一致:
| Prop | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| options | IOptions | 否 | 组件配置项(接口地址、前缀、方法、权限码、表格、弹窗等) |
| requestFc | (config) => Promise<any> | 是 | 宿主注入的请求方法,组件所有接口都经它发出 |
4.3 options 配置项
interface IOptions {
/** 接口 url 映射,仅需传需要覆盖的 key,会与内置默认地址合并 */
apis?: Record<string, string>
/** 接口 url 前缀,默认 '/api/component/rbac' */
apiPrefix?: string
/** 各操作对应的 HTTP 方法,默认 { add: 'post', del: 'delete', modify: 'put', check: 'get' } */
apisMode?: Partial<{ add: string; del: string; modify: string; check: string }>
/** 当前登录用户的权限码数组,控制组件内操作入口的显示 / 禁用,见第五章 */
power?: string[]
/** 列表页表格配置(当前对 GraphUser 生效) */
listConfig?: Partial<{
emptyTxt: string // 无数据文本,默认 '--'
resetSearch: boolean // 点击重置后是否自动查询,默认 false
pagAlign: string // 分页栏对齐方式,默认 'center'
tipLen: number // 归属组织列悬浮提示前的最大长度,默认 12
}>
/** 弹窗是否垂直居中,默认 false */
centered?: boolean
}4.4 requestFc 请求方法注入
组件内部统一调用 requestApi(url, params, method),并按下列规则组装后交给 requestFc:
- 请求地址:
apiPrefix + url GET请求:参数放在params(query);其余方法参数放在data(body)- 固定请求头:
Content-Type: application/json;charset=utf-8
因此 requestFc 收到的配置对象与 axios 的请求配置完全兼容,宿主只需返回后端响应体({ code, message, data })即可:
// api/rbac.ts
import axios from 'axios'
import type { App } from 'vue'
const request = axios.create({ timeout: 15000 })
// 请求拦截器:按需携带 token
request.interceptors.request.use((config) => {
config.headers.Authorization = `Bearer ${localStorage.getItem('token') ?? ''}`
return config
})
/**
* 组件库请求方法
* 组件判断成功的口径是响应体 code === 200,请确保 resolve 的是后端响应体而不是 AxiosResponse
*/
export const requestFc = async (config: any) => {
const { data } = await request(config)
return data
}4.5 完整使用示例
<!-- views/rbac/resources.vue -->
<template>
<GraphResources :options="options" :request-fc="requestFc" />
</template>
<script setup lang="ts">
import { GraphResources } from '@duxiaoma/design-rbac'
import { requestFc } from '@/api/rbac'
import { useUserStore } from '@/store/user'
const userStore = useUserStore()
const options = {
// 后端前缀与默认值一致时可省略
apiPrefix: '/api/component/rbac',
// 仅需覆盖与默认值不同的接口
apis: {
// resourceTree: '/custom/resource_tree'
},
// 当前用户权限码(一般取自登录态 / 用户信息接口)
power: userStore.power,
centered: true
}
</script>四个页面分别挂载到不同路由即可:
import {
GraphAction,
GraphResources,
GraphRole,
GraphUser
} from '@duxiaoma/design-rbac'
const routes = [
{ path: '/rbac/action', component: GraphAction },
{ path: '/rbac/resources', component: GraphResources },
{ path: '/rbac/role', component: GraphRole },
{ path: '/rbac/user', component: GraphUser }
]记得给每个路由组件通过 props 或模板传入
options与requestFc(可在外层包一层布局组件统一传递)。
4.6 内置接口地址(options.apis)
默认前缀 apiPrefix = '/api/component/rbac',下表为内置相对地址,宿主可按 key 整体覆盖:
| key | 默认地址 | 说明 |
| --- | --- | --- |
| resourceTree | /resource_tree | 资源树(tag: rt/uar/aar) |
| foldDetail | /resource_fold/detail | 资源目录详情 |
| foldAdd | /resource_fold/add | 新增资源目录 |
| foldModify | /resource_fold/update | 编辑资源目录 |
| foldDel | /resource_fold/delete | 删除资源目录 |
| nodeDetail | /resource/detail | 资源节点详情 |
| nodeAdd | /resource/add | 新增资源节点 |
| nodeModify | /resource/update | 编辑资源节点 |
| nodeDel | /resource/delete | 删除资源节点 |
| actionList | /resource_action_list | 资源行为分页列表 |
| actionAdd | /resource_action/add | 新增资源行为 |
| actionDetail | /resource_action/detail | 资源行为详情 |
| actionModify | /resource_action/update | 编辑资源行为 |
| actionDel | /resource_action/delete | 删除资源行为 |
| enum | /get_enum | RBAC 枚举(资源类型 / 行为 / 目录树 / 组织树) |
| userList | /user_pool | 用户池分页查询 |
| userAuth | /user_auth_resource/list | 查询用户已授权资源(回显) |
| userAuthResource | /user_auth_resource/add | 用户资源授权 |
| userAssemble | /user_auth_assemble/list | 查询用户所属部门角色(回显) |
| userAuthAssemble | /user_auth_assemble/add | 用户部门角色授权 |
| roleTree | /assemble_tree | 部门角色树(tag: at/uaa) |
| roleDetail | /assemble/detail | 部门角色详情 |
| roleAdd | /assemble/add | 新增部门角色 |
| roleDel | /assemble/delete | 删除部门角色 |
| roleModify | /assemble/update | 编辑部门角色 |
| roleResourceCheck | /assemble_auth_resource/list | 查询角色已授权资源(回显) |
| roleAuthResource | /assemble_auth_resource/add | 角色资源授权 |
HTTP 方法默认映射 apisMode:
| 操作 | 方法 | 用途 |
| --- | --- | --- |
| check | GET | tree / detail / list 等查询 |
| add | POST | 各类新增 |
| modify | PUT | 编辑、授权提交 |
| del | DELETE | 各类删除 |
五、权限控制与 isHasPower
5.1 组件内权限码(options.power)
把当前登录用户的权限码数组传给 options.power 后,组件会自动控制操作入口:
| 所属页面 | 权限码 | 控制的操作 |
| --- | --- | --- |
| 资源权限管理 | resource:fold:insert | 新增资源目录 |
| | resource:fold:update | 编辑资源目录 |
| | resource:fold:delete | 删除资源目录 |
| | resource:node:insert | 新增资源权限(节点) |
| | resource:node:update | 编辑资源权限 |
| | resource:node:delete | 删除资源权限 |
| 资源行为管理 | resource:action:insert | 新增资源行为 |
| | resource:action:update | 编辑资源行为 |
| | resource:action:delete | 删除资源行为 |
| 部门角色管理 | assemble:data:insert | 新增部门角色 |
| | assemble:data:update | 编辑部门角色 |
| | assemble:data:delete | 删除部门角色 |
| | assemble:auth:update | 授权资源权限 |
| 用户授权管理 | user:auth_resource:update | 授权资源权限 |
| | user:auth_assemble:update | 授权部门角色 |
规则说明:
power为空(未传 / 空数组)时,所有操作入口默认隐藏或禁用,请务必在接入权限后传入真实权限码;- 权限数组中包含超级管理员通配码
admin:auth:action时,拥有全部操作权限; - 权限码通常由宿主登录态 / 用户信息接口返回,组件只负责消费。
5.2 对外导出的 isHasPower
权限判断逻辑同时以纯函数形式对外导出,宿主项目可在菜单导航、路由守卫、页面按钮等任意场景复用,保证全系统口径一致。
import { isHasPower } from '@duxiaoma/design-rbac'
/**
* @param power 后端返回的权限数组
* @param needType 需要查询的某个权限码
*/
function isHasPower(power?: string[] | null, needType?: string | null): boolean判定规则:
power为空 → 返回false(用户没有任何权限);needType为空 → 返回true(菜单导航中未配置权限码的菜单默认显示;页面内操作入口则必须配置权限码);power命中needType,或包含超管码admin:auth:action→ 返回true,否则false。
使用示例:
import { isHasPower } from '@duxiaoma/design-rbac'
// 假设这是后端返回的当前用户权限数组
const power = ['resource:node:insert', 'resource:node:update']
// 1. 页面按钮 / 操作判断
isHasPower(power, 'resource:node:insert') // true
isHasPower(power, 'resource:node:delete') // false
isHasPower([], 'resource:node:insert') // false:没有任何权限
isHasPower(power, '') // true:未配置权限码的入口默认显示
isHasPower(['admin:auth:action'], 'resource:node:delete') // true:超管放行// 2. 路由守卫中控制菜单 / 页面访问
import { isHasPower } from '@duxiaoma/design-rbac'
router.beforeEach((to) => {
// to.meta.power 为该页面要求的权限码;未配置 meta.power 的路由默认放行
if (to.meta.power && !isHasPower(userStore.power, to.meta.power as string)) {
return '/403'
}
return true
})<!-- 3. 菜单 / 按钮渲染(配合 v-if) -->
<template>
<a-button v-if="isHasPower(power, 'user:auth_resource:update')">
授权资源权限
</a-button>
</template>组件内部的操作入口判断同样基于该方法(已自动绑定
options.power),无需在使用组件时重复调用。
六、后端约定
- 统一响应体:
{ code: 200, message: 'success', data, timestamp },组件以code === 200判定成功; - 分页响应:
data = { list: [], page: { total, current, page_size } }; - 每个操作都是独立 URL + 独立 HTTP 方法,请求体中没有
op字段; - 授权类接口(用户资源授权、用户角色授权、角色资源授权)均为整体替换语义,提交时需带上最终完整勾选结果,传空数组即清空;
- 树节点的
checked/indeterminate(半选)由后端根据下级状态推导,前端在授权弹窗中负责级联勾选与回显。
完整的 27 个接口入参 / 反参说明、枚举字典与注意事项,请参阅 INTE.md。
七、目录结构
src/
├── index.ts # 包入口:组件 install、类型与 isHasPower 导出
├── action/ # 【组件】GraphAction 资源行为管理
│ ├── index.vue
│ └── components/ # ActionEdit、TopForm
├── resources/ # 【组件】GraphResources 资源权限管理(目录 + 节点)
│ ├── index.vue、base.vue
│ └── components/ # FoldEdit、NodeEdit(FirstForm/SecondForm)
├── role/ # 【组件】GraphRole 部门角色管理
│ ├── index.vue、base.vue
│ └── components/ # Resource、RoleEdit
├── user/ # 【组件】GraphUser 用户授权管理
│ ├── index.vue
│ └── components/ # OrgDialog、Resource、Role、TopForm
├── _components/ # 跨模块公共组件:Explain、SeeksRelationGraph
├── _config/ # api(默认接口地址)/ columns / index(前缀、方法、tips)/ rules
├── _hooks/ # use-api(配置合并 + 请求 + 权限)、use-graph(关系图级联勾选)
├── _utils/ # 通用工具方法:isHasPower
├── _types/ # 全部 TS 类型
└── _style/ # config.less + index.less八、本地开发与构建
pnpm install # 安装依赖
pnpm type-check # vue-tsc 类型检查
pnpm build # 构建产物(es / cjs / umd + 类型声明 + style.css)
pnpm publish # 发布前会自动执行 pnpm build(prepublishOnly)构建产物:
| 产物 | 路径 |
| --- | --- |
| ES Module | dist/es/index.mjs |
| CommonJS | dist/lib/index.cjs |
| UMD | dist/umd/design-rbac.umd.js |
| 类型声明 | dist/types/index.d.ts |
| 样式 | dist/style/index.css(即包导出的 @duxiaoma/design-rbac/style.css) |
vue、ant-design-vue、@duxiaoma/adm-vue3、relation-graph、lodash、@ant-design/icons-vue 均已 external,由宿主项目提供,不会重复打包。
九、常见问题
关系图 / 按钮没有样式? 确认已在入口引入
import '@duxiaoma/design-rbac/style.css',且宿主项目已引入 ant-design-vue 的样式(v4 组件自带 css-in-js,通常无需额外引入)。接口请求地址不对 / 方法不对? 通过
options.apiPrefix覆盖前缀,通过options.apis按 key 覆盖单个地址,通过options.apisMode覆盖增删改查对应的 HTTP 方法。操作按钮全部置灰或右键菜单不显示? 新口径下
options.power为空时默认禁用所有操作入口;请传入当前用户的真实权限码,超管传入admin:auth:action。requestFc报错或列表不刷新? 确保requestFcresolve 的是后端响应体本身(包含code/data字段),而不是 axios 的AxiosResponse;成功状态码需为200。
