系统、模块、菜单:低代码平台的三层授权结构

2 阅读8分钟

权限模型不一定要单独设计。如果应用的骨架本来就是分层的,层级本身就可以当作权限模型来用。这篇文章拆解一种「三层各自可授权」的设计,并说明它的代价在哪。

一、一种常见的设计取向

低代码平台有一个绕不开的问题:用它搭出来的系统,怎么组织?

行业里有两条主流路径:

路径应用的一等公民典型形态
页面画布页面(一个应用 = 一堆页面 + 路由)拖拽设计器,最后生成页面文件
菜单体系功能入口(一个应用 = 有类型的菜单树)系统 → 模块 → 菜单,逐级授权

本文讨论的是第二条:基于菜单体系的开发平台设计。

它的核心主张可以概括成一句:开发一个业务系统,本质上是在按「系统 → 模块 → 菜单」三层,堆积一组有类型的功能入口。

  • 系统:一个应用或子系统
  • 模块:功能分组
  • 菜单:具体功能入口,且带类型

在驰骋 CCFast 中,这三层分别对应实体 MySystem、Module、Menu,落库到 GPM_System、GPM_Module、GPM_Menu 三张表。


二、为什么是「三维组织」而不是「一张页面表」

2.1 这是 MIS 系统的经典骨架

「系统 → 模块 → 菜单」并不是新发明。过去二十年绝大多数管理信息系统(MIS)的导航结构都是这个样子:

应用
├── 模块 A
│   ├── 菜单 1
│   └── 菜单 2
└── 模块 B
    └── 菜单 3

它是被反复验证过的一种组织方式,好处是结构稳定、扩展自然:加功能就在对应模块下加一个菜单,不会动到全局。

低代码平台把这个经典骨架显式建模成三张表 + 三个实体,就得到了一件很实在的东西:每一层都是一个独立的授权对象。

2.2 三维组织 = 三种授权颗粒度

看驰骋的实体定义,权限不是挂在某一个地方,而是每一层都能挂:

实体权限挂载点(代码)
MySystem(系统)map.AddRM_DtlSearch('应用权限', new PCenters(), ..., '&CtrlObj=System')
Module(模块)map.AddRM_DtlSearch('权限', new PCenters(), ..., '&CtrlObj=Module')
Menu(菜单)map.AddRM_DtlSearch('权限', new PCenters(), ..., '&CtrlObj=Menu')

三处调用的结构一致,区别只在 CtrlObj 是 System / Module 还是 Menu——同一套权限中心(GPM_PowerCenter),挂到三层不同的控制对象上。

这就是「三维组织」真正的工程含义:权限的颗粒度不是二元的(有/无),而是分层的。


三、用一个比喻把权限讲清楚:院子、房子、家具

权限分层这件事,用「院子 / 房子 / 家具」来理解最直观:

层级比喻控制什么代码载体
系统院子谁能进这个院子GPM_PowerCenter.CtrlObj = System
模块房子进了院子的人,谁能进这间房CtrlObj = Module
菜单家具进了房子的人,谁能用这件家具CtrlObj = Menu

三层是逐级收窄的关系:

  1. 先控制院子:哪些人能进入这个应用
  2. 再控制房子:进入应用的人里,谁能看到这个模块
  3. 最后控制家具:能看到模块的人里,谁能使用这个具体功能

这个模型的价值在于:它把「授权」拆成了三个可以独立回答的问题,而不是把所有权限堆在一个「用户-功能」的大表里。

举例:一个集团 OA 系统(院子)里,「人事管理」模块(房子)下有「员工花名册」「薪资查询」(家具)。可以配置成:

  • 院子:全集团可进
  • 房子:只有 HR 部门和各级管理者能进「人事管理」
  • 家具:「薪资查询」只对 HR 薪酬岗开放,「员工花名册」对本部门管理者开放

三级各有各的授权入口,互不干扰。


四、菜单是终点:功能页面与操作者的交互面

三层里,菜单是最终的功能页面,是用户真正「用」的东西。前面两层是组织结构,菜单才是交互。

所以菜单的定义里,除了归属(SystemNo / ModuleNo),还要回答「点了之后打开什么」。在 Menu.EnMap 里,这件事由几个字段共同决定:

字段作用
MenuModel菜单类型(决定用哪个解析页、绑哪类后端)
UrlPathVue 组件文件路径,如 /@/WF/Comm/Search.vue
UrlExt路由参数,如 x?EnName=TS.Demo.Student
MobileUrlExt移动端入口
Icon图标
ListModel列表模式(编辑模式 / 视图模式)
IsEnable是否启用

其中 MenuModel 是最关键的一个——它让菜单不再是「一个 URL + 一个标题」,而是「一个有语义的类型」。这一点是下一篇文章(《菜单的类型》)的主题,这里先按下。

值得注意的是 UrlPath 的约束:

此项需要配置连接对应的 vue 文件地址,仅支持 /src/ 下文件

这句话透露了菜单体系的边界:菜单指向的是平台内已存在的能力,不是任意页面。要接外部系统,走 SelfUrl 类型或 IframeOpenType(内嵌 / 外开)。这条约束是有意为之——它保证了「菜单是工具箱里的工具」,而不是「什么都能塞的洞」。


五、这套设计怎么落地:菜单向导与层级维护

设计理念要能落地,得有对应的操作入口。从代码看,至少有三类:

5.1 新建菜单走向导,不走空白路由

GPN_Menu.ts 是「新建积木菜单」向导,Init() 里用 AddGroup 把工具分组:

分组内容
A 流程公文、请假、订单、物联网流程等
B 单据报销单、出库单、出门单
C 实体资产、学生、车辆等主数据
U 字典管理省份、职位、大类小类
P 工程项目管理、甘特图、任务跟踪
E 大屏列表白色 / 蓝色大屏
J 视图数据源驱动的列表、左树右表、甘特视图
D 高代码TS 全栈配置,基于页面模式
G 页面引用自定义 URL、Tabs 容器
H OA 应用日历、知识库、工作日志等

实施人员是先选工具类型,再配置,而不是从空白开始。这就是「低」的来源——类型决定了打开哪个解析页、绑哪类实体、初始化哪些按钮与权限。

5.2 模块 → 菜单的层级维护

PG_Module2Menu.ts 是「分组编辑面板」模式:左侧是模块列表、右侧是该模块下的菜单,支持拖拽排序、组内新建。它的 Init() 直接从 GPM_Module / GPM_Menu 取数:

this.GroupsEns = await new Modules().Retrieve('SystemNo', this.PKVal, 'Idx');
this.DtlEns = await new Menus().Retrieve('SystemNo', this.PKVal, 'Idx');
this.RefKey = MenuAttr.ModuleNo;

RefKey = ModuleNo 就是「菜单属于哪个模块」的关联键——层级关系在数据层是外键,不是靠命名约定。

5.3 权限在三级各自配置

GPN_PCenter.ts 是权限配置向导,把授权方式建模成一组选项(AddBlank / SelectItemsBy*):

授权方式代码含义
所有人AuthType.Anyone本组织所有人
管理员AuthType.Adminer管理员
管理员 + 二级管理员AuthType.AdminerAndAdmin2两级管理员
按人员AuthType.Emps选人
按角色AuthType.Stations选角色
按部门AuthType.Depts选部门
按 SQLAuthType.SQLSQL 返回数量
指定组织的指定岗位AuthType.SpecOrgStations高级权限(集团场景)

同一套向导,换个 CtrlObj 就能用在系统、模块、菜单上——授权方式复用、授权对象分层。


六、这套设计的优点

6.1 权限颗粒度天然分层

不需要额外设计「权限模型」,因为层级本身就是权限模型。系统 / 模块 / 菜单三级各自可授权,避免了「只能整应用授权」或「只能功能级授权」的两个极端。

6.2 结构稳定,扩展自然

「系统 → 模块 → 菜单」是 MIS 的经典骨架,团队不需要学习新概念。加功能 = 加菜单,加分组 = 加模块,不会牵动全局。

6.3 菜单与实现解耦

菜单存的是「类型 + 路径 + 参数」(MenuModel / UrlPath / UrlExt),不是硬编码的页面。同一类功能,换实体名就是另一个菜单;换个模块归属,就是另一个位置。菜单是元数据,不是代码。

6.4 与流程、表单、权限共享底座

CCFast 的菜单不是独立于 BPM 的另一套东西。它把流程、单据、实体、大屏、视图都挂到同一棵导航树上,共享同一套组织(Port_*)与权限中心(GPM_PowerCenter)。一个应用导航树背后是同一套引擎。

6.5 交付物明确

按菜单体系搭出来的交付物,是一棵「可导航、可授权、可运行」的菜单树,而不是一堆零散页面文件。这对项目验收、权限交接、后期维护都更友好。


七、代价与边界

任何设计都有代价,这套菜单体系也不例外:

边界说明
需要理解分类实施人员必须懂「单据 / 实体 / 字典 / 视图」的区别,否则容易选错工具
强定制 UI 受限菜单指向平台内能力,重度定制前端仍要走高代码或外部页面
层级不是越深越好系统 / 模块 / 菜单三层够用;再往下加层级,授权与导航都会变复杂
组织模型是前提三级授权依赖 Port_* 组织数据,组织不准,权限就会失真

需要说清楚的是:菜单体系是「一种」设计取向,不是唯一解。 如果应用形态本身不是「功能入口的集合」(比如强流程编排、纯数据加工),页面画布或模型驱动可能更合适。选型看场景,不看口号。


八、小结

基于菜单体系的开发平台设计,可以归纳成三句话:

  1. 应用 = 系统 / 模块 / 菜单 三层的堆积,每一层是有类型、有归属、可授权的结构;
  2. 三层 = 三种权限颗粒度,像院子、房子、家具一样逐级收窄;
  3. 菜单是终点,是功能页面与操作者交互的界面,其它两层是它的组织与授权骨架。

在驰骋 CCFast 中,这三句话分别落地为 GPM_System / GPM_Module / GPM_Menu 三张表、CtrlObj = System/Module/Menu 的三级授权,以及 GPN_Menu 向导 + PG_Module2Menu 层级维护的操作入口。