菜单的类型:为什么「菜单」需要分类——结合驰骋 GPN_Menu 的设计驰骋BPM驰骋低代码低代码工作流引擎

菜单的类型:为什么「菜单」需要分类------结合驰骋 GPN_Menu 的设计


一、问题的起点:如果菜单只存「URL + 标题」会怎样

上一篇文章说到,菜单是「功能页面与操作者的交互面」。那么一个很自然的问题:菜单表里到底要存什么?

最朴素的做法是存两个字段:

复制代码
菜单 = { 标题: "待办工作", URL: "/WF/GL/TodoList" }

这么做能跑,但很快会遇到几个绕不开的问题:

  1. 打开哪个页面、怎么解析? 待办列表和一张表单,长得完全不一样,光靠 URL 前端不知道拉哪套渲染逻辑。
  2. 权限怎么配? 「待办」和「薪资查询」的授权方式可能完全不同。
  3. 移动端怎么办? PC 页面和移动端页面是两套入口。
  4. 参数从哪来? 同一类列表,绑不同实体就是不同菜单,参数不能写死。

根本原因在于:菜单承载的不只是一个跳转,而是一类功能的行为约定。 这些约定需要一个显式的字段来表达------这就是「菜单类型」(MenuModel)。


二、驰骋的答案:MenuModel 菜单类型

在 Menu.ts 的实体定义里,MenuModel 是菜单的必填字段之一:

复制代码
map.AddTBString('MenuModel', null, '菜单模式', true, true, 0, 50, 200);

而所有合法的类型值,集中定义在 MenuModel.ts 里。把这份常量表读一遍,会发现它不是随便堆的------它是按「功能形态」分组的。

下面结合 GPN_Menu 向导的分组,把菜单类型分类说明。


三、菜单类型的分类

MenuModel.ts 里有一个 menuCategory,把类型粗分为三档:

ts 复制代码
const menuCategory = {
  highCode: '高代码',
  lowCode: '低代码',
  oa: 'OA类菜单',
};

按这个骨架,再结合 GPN_Menu 的向导分组,菜单类型可以这样归类:

3.1 流程类

类型 说明
Start / StartSpecFlow 发起流程(全部 / 指定流程)
Todolist / TodolistSpecFlow 待办(全部 / 指定流程)
Runing / RuningSpecNo 在途
CC / CCSpecFlow 抄送
SearchFlow / SearchSpecFlow 流程查询

特点 :带 SpecFlow / SpecNo 后缀的,是把「全部流程」收窄为「指定流程」。这就是为什么流程类要正反两种类型------避免所有流程挤在同一个待办入口里。

3.2 单据类(流水,偏「叙事」)

类型 说明
Bill / BillRef / BillRptWhite 单据及其关联
SearchBill / FrmBill 单据查询 / 单据表单

单据的定义在向导帮助里写得很直白:有单号、标题字段,记录事情的经过,具有时间、地点、任务,叙事文性质------报销单、出库单、出门单。

3.3 实体类(主数据,偏「说明」)

类型 说明
EntityNoName 编号名称实体(资产、学生、车辆)
Dict / DictTable / DictTableTree 字典(键值对、树)
EntityRptWhite / EnRptWhite 基于实体的报表
FrmDtlView 从表视图

实体的定义与单据相对:有编号、名称字段,描述事物的属性,说明文性质。

单据 vs 实体,是菜单类型里最容易被实施人员搞混的一对。向导的帮助文案(GPN_Menu.ts 的 AddGroup 描述)其实就是在教这件事:叙事文 vs 说明文。

3.4 视图类(不建表,只看数)

类型 说明
DBList 分页视图
GenerList 不分页视图
GanttDBView 甘特图视图
FrmDtlView / FlowDtlView 从表明细视图

视图的共同点是:用数据源配置「怎么看数据」,不新建业务表。

3.5 大屏 / 报表类

类型 说明
RptWhite 白色大屏
RptBlue / RptBluePage 蓝色大屏
Rpt2DLowCode / Rpt3DLowCode 二维 / 三维报表
FlowRptWhite / BillRptWhite / EnRptWhite / EntityRptWhite 分别基于流程 / 单据 / 实体 / 高代码的大屏

这里也能看到「基础形态 + 数据来源」的组合思路:白色大屏是通用形态,再按数据来源分化成四种。

3.6 高代码类

类型 说明
Search / Group / Tree 查询 / 分组 / 树
TreeEns 左树右表
GL 通用列表
Tabs 标签页容器
GPN / Ens / En / EnOnly 新建 / 批量编辑 / 属性卡片
Data_V 大屏
Self 自定义 URL

这些类型对应上一系列的「面向模式的编程」------每个类型背后是一个基类 + 解析页面 。选 GL,前端就走 GenerList.vue 解析;选 TreeEns,就走 TreeEns.vue。

3.7 OA 类

类型 说明
Calendar / Notepad / WorkRec 日历 / 记事本 / 工作日志
KnowledgeManagement 知识管理
Info / Message 信息发布 / 消息
NetDisk 网盘
Task 任务

OA 类的特点是:功能已开发好,配上菜单即可使用,不需要再设计。


四、类型背后的三种「承载方式」

MenuModel.ts 只是类型清单,真正有意思的是 readme.md 里对功能页面属性如何存储的说明。它把菜单按「属性复杂程度」分成三类,称之为 A / B / C:

类别 适用场景 存储方式
A 类:菜单承载通用方式 属性简单或没有属性(日志、日历) 用 MenuGenerPage 类,属性存菜单表
B 类:菜单承载个性方式 属性相对复杂,但不想单独建表 属性写进 GPM_Menu,与菜单属性共表
C 类:独立实体方式 属性复杂,需要独立表 创建菜单时生成独立记录,如 Frm_XXXXX

对应的代码写法(readme 原文):

复制代码
A类: Menu.SetPara('EnName', 'TS.GPM.MenunGenerPage')
B类: Menu.SetPara('EnName', 'TS.XXX.MenuXX')
C类: Menu.SetPara('EnName', 'TS.XXX.XXXX'), Menu.SetPKVal('EnPKVal', 'Frm_XXXXX')

这是一个很务实的分级设计 :不是所有菜单都值得建一张表。日历这种「打开即用」的,共表就够了;表单这种属性复杂的,才给独立实体。复杂度按需分配,避免为简单功能制造冗余表。


五、为什么需要这样设计:优点

5.1 类型决定解析方式,前端不做 if-else 地狱

菜单存了 MenuModel,前端就能「按类型路由」:GL → GenerList.vue,TreeEns → TreeEns.vue。这和「面向模式编程」是同一套哲学------用类型分发,而不是用条件判断。

如果没有类型,前端就得根据 URL 猜、根据实体名猜,最终变成一堆 if...else。

5.2 类型是「工具箱的分类」,降低选错成本

GPN_Menu 向导不是让人从空白路由开始填,而是先选类型、再配置。类型本身就是一份「这类功能是什么、适合什么场景」的说明书:

  • 单据:叙事文,有单号标题
  • 实体:说明文,有编号名称
  • 视图:不建表,只看数

实施人员选类型的过程,就是一次需求归类。选对了类型,后面的配置就是顺理成章。

5.3 类型是权限与移动端的挂载点

有了类型,才能做到:

  • 权限按类型初始化:不同功能的默认按钮、数据范围不同;
  • 移动端单独配置 :Menu.MobileUrlExt 字段让 PC 与移动端各走各的入口;
  • 参数化复用 :UrlExt 携带参数(如 x?EnName=TS.Demo.Student),同一类型可生成 N 个菜单。

5.4 类型让「低代码」与「高代码」在同一棵树上共存

menuCategory 里明确区分了高代码与低代码。这不是文字游戏------它意味着:

  • 低代码菜单:配置元数据即可用;
  • 高代码菜单:挂一个 TS 子类,走解析页面。

同一个 GPM_Menu 体系,既能挂配置出来的功能,也能挂写代码出来的功能,而不是两套导航。这就是「标准能力配置化,例外能力代码化」在菜单层的体现。

5.5 类型让功能可以「按需收窄」

流程类里 Todolist(全部)与 TodolistSpecFlow(指定流程)并存,是很好的例子。它承认了一个现实:大系统里,不同部门关心的待办范围不一样。 用类型把「全部」和「指定」分开,就避免了「一个待办入口所有人共用」的混乱。


六、一张总表

类型分组 代表类型 解决的问题 解析去向
流程 Start / Todolist / Runing / CC 按节点推进的事务 流程列表解析页
单据 Bill / SearchBill 流水、事件、过程 单据解析页
实体 EntityNoName / Dict 主数据、属性说明 实体解析页
视图 DBList / GenerList / GanttDBView 不建表的展现 视图解析页
大屏报表 RptWhite / RptBlue / Rpt2D/3D 分析与可视化 大屏解析页
高代码 GL / TreeEns / GPN / Self 定制功能 模式解析页(GL_* 等)
OA Calendar / Notepad / Task 办公配套 已开发页面

七、结论

菜单需要分类,本质上是因为**「菜单」这个词承载了太多不同性质的功能**。把类型显式化,能同时解决四件事:

  1. 怎么打开(解析方式)
  2. 谁能用(权限初始化)
  3. 在哪用(PC / 移动端)
  4. 用什么参数(路由复用)

驰骋的做法是:用 MenuModel 定义类型、用 menuCategory 粗分高/低代码、用 A/B/C 三种承载方式控制属性复杂度,最后用 GPN_Menu 向导把「选类型」这一步变成「需求归类」。

回过头看,MenuModel.ts 那一长串常量并不只是枚举------它是这套低代码平台对「一个业务系统由哪些功能组成」的一份分类学。 分类清晰,堆积才不会乱。


附录:本文涉及的代码索引

主题 路径
菜单类型常量 Vue3/src/CCFast/GPM/CCMenu/MenuModel.ts
新建菜单向导 Vue3/src/CCFast/GPM/CCMenu/GPN_Menu.ts
菜单实体(MenuModel 字段) Vue3/src/CCFast/GPM/CCMenu/Menu.ts
A/B/C 承载方式说明 Vue3/src/CCFast/GPM/CCMenu/readme.md
菜单类型 → 解析页面映射 Vue3/src/CCFast/GPM/CCMenu/GPN_Menu.ts(ClassFactory 映射表)
页面模式框架 doc/低代码部分/面向模式编程思想-的高代码开发.md

本文基于当前仓库源码静态分析整理,类型清单随版本迭代变化,具体以你所使用的版本为准。

相关推荐
SL_staff1 天前
私有化低代码运维三重雷区:JVS开源栈中的Kafka/ES/RabbitMQ治理实践
java·低代码·全栈
快乐非自愿1 天前
低代码落地费控系统:从报销流程到业财闭环的实操方案
android·低代码·rxjava·ai低代码
她的男孩1 天前
页面已发布用户仍进不去:Forge Admin 门户入口与系统菜单挂载解耦
java·spring boot·低代码
窗边看云2 天前
库存 ABC 分类:好钢用在刀刃上
低代码
什么嘻嘻果冻3 天前
无代码开发平台的技术架构,恐象 AI 的生成引擎拆解
大数据·人工智能·低代码
驰骋工作流3 天前
低代码开发平台设计方向之一:基于菜单体系的开发平台设计驰骋BPM驰骋低代码低代码工作流引擎
低代码
risc1234564 天前
万变不离其宗
人工智能·低代码·云原生
Java小卷4 天前
Vue3 动态表单支持弹框组件
前端·vue.js·低代码
CORNERSTONE3654 天前
准备上MES,企业要先整理哪些基础数据?
低代码·erp·mes·企业数字化