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

菜单管理 + 角色管理 + 机构管理 设计文档

需求概述

为 BASE 管理面板添加三大功能模块:

  1. 菜单管理:动态菜单替代硬编码侧边栏,菜单分"默认"和"配置"两种类型,按角色分配
  2. 角色管理:支持自定义角色,角色按机构分配(同一用户在不同机构可有不同角色)
  3. 机构管理:树形结构的组织架构,用户与机构多对多关系

核心设计决策

决策点 选择 说明
菜单分配方式 按角色分配 角色绑定菜单,用户通过角色获得菜单权限
角色类型 支持自定义角色 除系统内置角色外,可创建新角色
机构结构 树形(多级父子) 支持 总公司→分公司→部门→小组
用户-机构关系 多对多 用户可属于多个机构
角色作用域 按机构分配 同一用户在不同机构可有不同角色
机构上下文 当前机构切换器 用户登录后选择工作机构,菜单和权限随之变化

数据模型

新增表

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) 联系电话
email 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) 所有登录用户

前端设计

新页面

  1. 我的 (/my):个人信息面板,显示所属机构列表、当前角色
  2. 菜单管理 (/menus):树形表格展示菜单,支持拖拽排序、启用/禁用
  3. 角色管理 (/roles):角色列表 + 菜单分配弹窗(树形勾选)
  4. 机构管理 (/organizations):树形表格 + 成员管理抽屉(添加/移除成员、分配角色)

侧边栏改造

  • 当前Sidebar.tsx 中硬编码 navItems 数组
  • 改造后
    • 登录后从 GET /menus/current 获取菜单树
    • AuthContext 存储 userMenus state
    • Sidebar 组件从 context 读取菜单动态渲染
    • 顶部 Logo 区域下方增加机构切换下拉框

AuthContext 扩展

新增 state:

  • currentOrg: { id, name } | null
  • userOrgs: 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.go
  • model/role_entity.go, model/role_model.go
  • model/role_menu_model.go
  • model/organization_entity.go, model/organization_model.go
  • model/user_organization_entity.go, model/user_organization_model.go
  • api/menu.api, api/role.api, api/organization.api
  • internal/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_id
  • internal/util/jwt/jwt.go — Claims 增加 currentOrgId
  • internal/svc/servicecontext.go — 新模型注入 + 种子数据
  • base.api — 新路由组
  • internal/middleware/authmiddleware.go — 注入 currentOrgId
  • internal/middleware/authzmiddleware.go — 适配新策略
  • 各登录/注册 logic — GenerateToken 调用更新

新建文件(前端 ~6 个)

  • pages/MyPage.tsx
  • pages/MenuManagementPage.tsx
  • pages/RoleManagementPage.tsx
  • pages/OrganizationManagementPage.tsx
  • components/layout/OrgSwitcher.tsx

修改文件(前端 ~5 个)

  • App.tsx — 新路由
  • components/layout/Sidebar.tsx — 动态菜单
  • contexts/AuthContext.tsx — 机构/菜单 state
  • services/api.ts — 新 API 方法
  • types/index.ts — 新类型定义