You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9.9 KiB
9.9 KiB
菜单管理 + 角色管理 + 机构管理 设计文档
需求概述
为 BASE 管理面板添加三大功能模块:
- 菜单管理:动态菜单替代硬编码侧边栏,菜单分"默认"和"配置"两种类型,按角色分配
- 角色管理:支持自定义角色,角色按机构分配(同一用户在不同机构可有不同角色)
- 机构管理:树形结构的组织架构,用户与机构多对多关系
核心设计决策
| 决策点 | 选择 | 说明 |
|---|---|---|
| 菜单分配方式 | 按角色分配 | 角色绑定菜单,用户通过角色获得菜单权限 |
| 角色类型 | 支持自定义角色 | 除系统内置角色外,可创建新角色 |
| 机构结构 | 树形(多级父子) | 支持 总公司→分公司→部门→小组 |
| 用户-机构关系 | 多对多 | 用户可属于多个机构 |
| 角色作用域 | 按机构分配 | 同一用户在不同机构可有不同角色 |
| 机构上下文 | 当前机构切换器 | 用户登录后选择工作机构,菜单和权限随之变化 |
数据模型
新增表
menus(菜单表)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | uint, PK | 自增主键 |
| parent_id | uint | 父菜单ID,0为顶级 |
| name | varchar(50) | 菜单名称 |
| path | varchar(200) | 前端路由路径 |
| icon | varchar(50) | 图标名称(lucide-react) |
| component | varchar(200) | 前端组件路径 |
| type | varchar(20) | 'default' 或 'config' |
| sort_order | int | 排序序号 |
| visible | bool | 是否在侧边栏显示 |
| status | int | 1=启用, 0=禁用 |
| created_at | datetime | |
| updated_at | datetime |
roles(角色表)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | uint, PK | 自增主键 |
| name | varchar(50) | 角色显示名称 |
| code | varchar(50), unique | 角色编码,如 super_admin |
| description | varchar(255) | 角色描述 |
| is_system | bool | 系统内置角色不可删除 |
| sort_order | int | 排序 |
| status | int | 1=启用, 0=禁用 |
| created_at | datetime | |
| updated_at | datetime |
role_menus(角色-菜单关联表)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | uint, PK | |
| role_id | uint | 角色ID |
| menu_id | uint | 菜单ID |
organizations(机构表,树形)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | uint, PK | |
| parent_id | uint | 父机构ID,0为顶级 |
| name | varchar(100) | 机构名称 |
| code | varchar(50) | 机构编码 |
| leader | varchar(50) | 负责人 |
| phone | varchar(20) | 联系电话 |
| varchar(100) | 联系邮箱 | |
| sort_order | int | 排序 |
| status | int | 1=启用, 0=禁用 |
| created_at | datetime | |
| updated_at | datetime |
user_organizations(用户-机构-角色关联表)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | uint, PK | |
| user_id | uint | 用户ID |
| org_id | uint | 机构ID |
| role_id | uint | 该用户在该机构的角色ID |
| created_at | datetime |
现有表改动
users 表:
- 保留
role字段作为无机构时的默认角色 - 新增
current_org_id(uint):记住用户上次选择的机构
JWT Claims:
- 新增
currentOrgId(uint64) role字段值来源改为:有当前机构时用机构角色,否则用默认角色
种子数据
系统内置角色(is_system=true):
| code | name | sort_order |
|---|---|---|
| super_admin | 超级管理员 | 1 |
| admin | 管理员 | 2 |
| user | 普通用户 | 3 |
| guest | 访客 | 4 |
默认菜单:
| name | path | icon | type | sort_order |
|---|---|---|---|---|
| 我的 | /my | User | default | 1 |
| 仪表盘 | /dashboard | LayoutDashboard | config | 2 |
| 用户管理 | /users | Users | config | 3 |
| 文件管理 | /files | FolderOpen | config | 4 |
| 角色管理 | /roles | Shield | config | 5 |
| 菜单管理 | /menus | Menu | config | 6 |
| 机构管理 | /organizations | Building2 | config | 7 |
| 设置 | /settings | Settings | default | 8 |
super_admin 角色自动绑定所有菜单(default + config)。 user 角色只绑定 default 类型菜单(我的 + 设置)。
核心流程
登录流程
用户登录
→ JWT签发 (userId, username, email, role=默认角色, currentOrgId=user.current_org_id)
→ 前端拿到 token
→ GET /profile/orgs 获取用户机构列表
→ 如果有机构 && current_org_id > 0 → 使用该机构
→ 如果有机构 && current_org_id == 0 → 使用第一个机构
→ 如果无机构 → 使用默认角色
→ GET /menus/current 获取当前角色的菜单
→ 渲染动态侧边栏
机构切换
用户点击机构切换器选择新机构
→ PUT /profile/current-org { orgId: xxx }
→ 后端:更新 user.current_org_id,查 user_organizations 获取新角色
→ 后端:重新签发 JWT (含新角色和新orgId)
→ 前端:更新 token,刷新菜单,刷新页面
权限校验
请求到达
→ Auth middleware: 解析 JWT,注入 userId, role, currentOrgId 到 context
→ Authz middleware: Casbin enforce(role, path, method)
→ 通过 → handler
→ 拒绝 → 403
API 设计
菜单管理
| 方法 | 路径 | 说明 | 权限 |
|---|---|---|---|
| GET | /api/v1/menus/current | 当前用户可见菜单(树形) | 所有登录用户 |
| GET | /api/v1/menus | 全部菜单列表(树形) | admin+ |
| POST | /api/v1/menu | 创建菜单 | super_admin |
| PUT | /api/v1/menu/:id | 更新菜单 | super_admin |
| DELETE | /api/v1/menu/:id | 删除菜单 | super_admin |
角色管理
| 方法 | 路径 | 说明 | 权限 |
|---|---|---|---|
| GET | /api/v1/roles | 角色列表 | admin+ |
| POST | /api/v1/role | 创建角色 | super_admin |
| PUT | /api/v1/role/:id | 更新角色 | super_admin |
| DELETE | /api/v1/role/:id | 删除角色(非系统角色) | super_admin |
| GET | /api/v1/role/:id/menus | 获取角色的菜单ID列表 | admin+ |
| PUT | /api/v1/role/:id/menus | 设置角色的菜单(全量替换) | super_admin |
机构管理
| 方法 | 路径 | 说明 | 权限 |
|---|---|---|---|
| GET | /api/v1/organizations | 机构列表(树形) | admin+ |
| POST | /api/v1/organization | 创建机构 | super_admin |
| PUT | /api/v1/organization/:id | 更新机构 | admin+ |
| DELETE | /api/v1/organization/:id | 删除机构(无子机构) | super_admin |
| GET | /api/v1/organization/:id/members | 机构成员列表 | admin+ |
| POST | /api/v1/organization/:id/member | 添加成员(含角色) | admin+ |
| PUT | /api/v1/organization/:id/member/:userId | 更新成员角色 | admin+ |
| DELETE | /api/v1/organization/:id/member/:userId | 移除成员 | admin+ |
用户上下文
| 方法 | 路径 | 说明 | 权限 |
|---|---|---|---|
| GET | /api/v1/profile/orgs | 我的机构列表(含各机构角色) | 所有登录用户 |
| PUT | /api/v1/profile/current-org | 切换当前机构(返回新token) | 所有登录用户 |
前端设计
新页面
- 我的 (
/my):个人信息面板,显示所属机构列表、当前角色 - 菜单管理 (
/menus):树形表格展示菜单,支持拖拽排序、启用/禁用 - 角色管理 (
/roles):角色列表 + 菜单分配弹窗(树形勾选) - 机构管理 (
/organizations):树形表格 + 成员管理抽屉(添加/移除成员、分配角色)
侧边栏改造
- 当前:
Sidebar.tsx中硬编码navItems数组 - 改造后:
- 登录后从
GET /menus/current获取菜单树 AuthContext存储userMenusstateSidebar组件从 context 读取菜单动态渲染- 顶部 Logo 区域下方增加机构切换下拉框
- 登录后从
AuthContext 扩展
新增 state:
currentOrg: { id, name } | nulluserOrgs: Array<{ orgId, orgName, roleId, roleName }>userMenus: MenuTree[]
新增方法:
switchOrg(orgId: number): Promise<void>— 切换机构,刷新 token 和菜单refreshMenus(): Promise<void>— 重新获取菜单
机构切换器
位置:侧边栏 Logo 区域下方
样式:下拉选择框,显示当前机构名称
行为:切换时调用 switchOrg(),自动刷新菜单和页面数据
Casbin 策略更新
新增资源的 Casbin 策略需要同步更新,自定义角色创建时由管理员配置具体权限。
系统内置角色默认策略:
- super_admin:所有 API 端点的所有方法
- admin:菜单/角色/机构的读取 + 机构成员管理
- user:仅 /menus/current, /profile/orgs, /profile/current-org
- guest:仅 /menus/current
文件变更预估
新建文件(后端 ~20 个)
model/menu_entity.go,model/menu_model.gomodel/role_entity.go,model/role_model.gomodel/role_menu_model.gomodel/organization_entity.go,model/organization_model.gomodel/user_organization_entity.go,model/user_organization_model.goapi/menu.api,api/role.api,api/organization.apiinternal/logic/menu/*.go(5 个 logic)internal/logic/role/*.go(6 个 logic)internal/logic/organization/*.go(7 个 logic)internal/logic/profile/(2 个新 logic)
修改文件(后端 ~8 个)
model/user_entity.go— 增加 current_org_idinternal/util/jwt/jwt.go— Claims 增加 currentOrgIdinternal/svc/servicecontext.go— 新模型注入 + 种子数据base.api— 新路由组internal/middleware/authmiddleware.go— 注入 currentOrgIdinternal/middleware/authzmiddleware.go— 适配新策略- 各登录/注册 logic — GenerateToken 调用更新
新建文件(前端 ~6 个)
pages/MyPage.tsxpages/MenuManagementPage.tsxpages/RoleManagementPage.tsxpages/OrganizationManagementPage.tsxcomponents/layout/OrgSwitcher.tsx
修改文件(前端 ~5 个)
App.tsx— 新路由components/layout/Sidebar.tsx— 动态菜单contexts/AuthContext.tsx— 机构/菜单 stateservices/api.ts— 新 API 方法types/index.ts— 新类型定义