资讯动态

AWC 4.x多级菜单定制:从命令到命令组完整实践

发布时间:2026/10/16 22:15:29 来源:尧图企业网站定制
1. 先理解AWC 4.x的菜单体系做AWC定制开发的人早晚都会碰到这么一件事业务方提了一个需求要在系统某个角落加一个菜单入口点进去还有二级菜单甚至三级。听起来不复杂真动手时才发现AWC的菜单体系和你想象的不太一样它既有配置驱动的部分也有代码注册的部分两套逻辑混在一起搞不懂底层关系就会陷入“我明明加了配置页面上就是不显示”的困境。先说一个基本判断AWC 4.x里的菜单不是简单的“在某个文件里写一行菜单名”就能搞定的。它背后是命令command、菜单项menu item、命令组command group三个层次的概念。命令决定“点击后执行什么逻辑”菜单项决定“在界面上长什么样、出现在哪里”命令组决定“它归属于哪个系统功能分组”。这三层在配置里是分开定义的再通过ID关联起来。理解了这条链路后面所有操作都是顺着走的。1.1 三种菜单形态先明确你要做哪一种AWC界面上的菜单大体可以分成三类它们的定制定位完全不同如果一开始就搞混后面容易白忙一场。第一类是主菜单栏。就是页面顶部那一条通常有“文件”“视图”“编辑”这类系统级入口有些版本还允许自定义顶层菜单把二级、三级菜单挂下去。AWC的主菜单栏本身也是一个命令组容器往里塞自定义菜单项是可行的。第二类是上下文菜单。在业务对象上右键弹出的那个菜单比如在“物料”或“工单”上右键会出现“打开”“属性”“上传文件”等入口。这类菜单的特点是“跟着对象走”所以配置的时候必须绑定对象类型否则菜单永远不出现。第三类是工具条或卡片菜单。出现在某些窗口的工具区域或者数据集卡片上的按钮组它们也属于命令组的一种形态只是呈现方式不同。我这次要做的实际上是把一个自定义多级菜单挂到“系统命令组”里去说到底就是第一类和第三类的交叉场景入口放在系统已有的命令组附近但内容是我们自己的多级菜单。AWC的灵活性在于它允许你通过扩展机制扩展点往系统命令组追加内容而不是非得去改系统自带的那份只读配置文件。1.2 菜单项、命令、命令组三者的关系为了说清楚后面怎么做这里先把三个概念掰开揉碎。命令command是AWC里最小的执行单元。它对应一个JavaScript函数或者一个调用后端服务的动作比如“打开窗口”“执行搜索”“下载文件”。每个命令有唯一的ID和对应的handler逻辑。菜单项menuItem是界面上真正渲染出来的条目。它有一个text属性显示文本、icon属性图标、以及action属性指向某个命令ID。菜单项可以嵌套就是说一个菜单项下可以挂多个子菜单项children这正好是我们做多级菜单的基础。命令组commandGroup则是一个命名的容器里面可以放置多个命令或菜单项的引用。系统自己有一堆预定义好的命令组例如“主页功能组”“搜索结果工具组”“更多操作组”等等。我们的目标就是把自己的菜单项注入到某个系统预定义好的命令组里从而实现“自定义菜单出现在系统区域”的效果。实际操作中有一种很常见的做法先新定义一个一级菜单项底下挂上若干二级菜单项每个二级菜单项再指向具体命令最后把这个一级菜单项追加到某个系统命令组的末尾。这样既保留了系统原有功能又能在指定位置看到自己的入口互不干扰。2. 多级菜单是怎么来的很多人第一次看到“多级菜单”会以为要写一堆HTML嵌套列表其实AWC里不需要那样做。它自带一个菜单渲染机制只需要在配置的菜单项定义里给某个菜单项挂上一层children数组界面上的下拉菜单就会自动渲染出多级效果。2.1 用children属性实现层级嵌套我一直觉得AWC把菜单层级这件事做得挺简单的就是递归渲染。一个菜单项的定义里有children字段children里的每一项又是标准菜单项结构可以继续挂children。想挂几层就挂几层没有硬性限制。举例来说假设业务场景是“文件处理”我们想做一个“批量工具”的一级菜单下面分“批量上传”“批量下载”“批量归档”三个二级菜单。配置结构大体是var bulkToolMenu { id: BulkToolMenu, text: 批量工具, icon: cmd-upl, children: [ { id: BulkUploadMenuItem, text: 批量上传, action: executeBulkUploadCommand }, { id: BulkDownloadMenuItem, text: 批量下载, action: executeBulkDownloadCommand }, { id: BulkArchiveMenuItem, text: 批量归档, action: executeBulkArchiveCommand } ] };这里的action指向的是命令ID说明真正执行逻辑的还是命令层。这个结构直接挂在某个命令组的items数组里前端引擎渲染时发现该菜单项有children就会渲染出一个带展开箭头的父菜单鼠标hover或点击后就展示下级菜单。如果是三级菜单只需要在某个二级菜单项下面继续挂children即可。例如“批量下载”下面再拆成“下载当前版本”“下载历史版本”把“批量下载”的children数组里放两条子项就行。2.2 两种实现路线按场景选有些项目里我们也遇到过不想动太多配置文件的情况那就走JavaScript扩展注册的路线。区别在于配置文件方式适合“静态菜单”菜单结构和命令关系相对固定代码注册方式可以在运行期动态组装菜单项比如根据用户角色动态隐藏某些二级菜单这个灵活性是配置文件做不到的。我个人的建议是菜单本身比较固定就用配置文件管理起来直观菜单需要根据数据或权限动态变化就用代码注册。在真实项目中往往是混合使用先定义一堆基础命令再在代码里组装菜单结构最后注册到命令组。这里必须提醒一句无论是哪种方式命令的定义是绕不开的。菜单项只是一个壳真正干活的还是命令Handler。所以开发顺序应该是“先命令后菜单再挂组”这个顺序别搞反了否则就会出现菜单点过去没反应或者甚至不显示。3. 实操把自定义菜单挂到系统命令组这一节是全文的重头戏我按实际操作的顺序走一遍把每个步骤的必要性讲明白。这里以某跨平台系统模拟项目X为背景需求是在AWC 4.x的“更多”命令组里加入两个层级的自定义菜单入口文本是“项目工具”下面挂“导入清单”和“导出报告”分别指向两个自研命令。3.1 环境准备看看要动哪些文件AWC 4.x的定制通常发生在客户化配置目录要修改的是扩展JSON文件和对应的JavaScript文件。在动手前先确认安装环境里有如下结构和能力客户化配置根目录一般叫customization之类配置发布机制修改完配置后需要通过某种同步手段发布到运行实例日志输出端口用于排查前端报错很多新手第一次碰到AWC第一反应是去修改系统安装目录下的原始JSON。这个操作通常行不通因为系统每次发布配置时会把原始配置覆盖掉。正确的做法是在客户化目录中追加自定义文件把修改放在系统能识别到的“扩展配置”层面。3.2 定义一个完整的多级菜单命令第一步定义一个命令。假设我们要做的是“导入清单”功能它在AWC里对应一段查询逻辑。用JavaScript注册一个命令baseCommand.extend({ id: ImportChecklistCmd, action: function(ctx) { // 这里写导入清单的业务逻辑 showMessage(开始导入清单...); } });然后定义第二个命令“导出报告”逻辑类似baseCommand.extend({ id: ExportReportCmd, action: function(ctx) { // 导出报告的业务逻辑 showMessage(开始导出报告...); } });命令定义完接下来定义菜单项并组合层级。这里我把一级菜单叫“项目工具”把两个命令挂成二级菜单var projectToolsMenu { id: ProjectToolsMenu, text: 项目工具, children: [ { id: ImportChecklistMenuItem, text: 导入清单, action: ImportChecklistCmd }, { id: ExportReportMenuItem, text: 导出报告, action: ExportReportCmd } ] };注意这里的一级菜单本身没有绑action因为它只管展开点击不触发业务逻辑。这是多级菜单的一个常见特点父菜单通常不绑定具体命令子菜单才绑定。3.3 注册到系统命令组并发布菜单结构有了现在还差“把菜单塞进系统命令组”这一步。AWC里通常有一个扩展注册区可以通过类似addCommandGroupItem之类的方法把菜单项追加到指定的系统命令组里。在模拟项目X里目标命令组是“更多操作”对应的系统命令组它的ID一般可以在系统配置文件里查到。注册代码看起来是这样configuration.regCommandGroupItem(ProjectToolsMenu, 系统更多命令组ID, 3);第三个参数表示插入位置在真实操作中位置参数不是必填且在不同版本表现略有差异最稳妥的做法是先不传位置让它追加到最后等能显示了再调整顺序。这个习惯能省掉很多“怎么显示位置不对”的调试时间。配置同步到运行端后如果一切正常在“更多”相关区域就会看到“项目工具”菜单鼠标悬停后展开“导入清单”和“导出报告”两个子菜单。3.4 权限控制与加载时机的细节菜单能显示出来只是第一步真正上生产前还要考虑两件事谁能看到这个菜单以及什么时候注册生效。权限控制可以走两条路。一是利用AWC自带的权限表达式在菜单项里配置可见性条件二是在代码里动态判断当前用户角色动态决定是否把菜单项加入命令组。两种方式各有利弊前者配置简单、适合粗粒度控制后者灵活适合细粒度控制但需要额外开发维护。加载时机主要指客户化脚本的执行顺序。AWC在启动时会加载一批配置和扩展脚本如果你的注册代码在系统命令组尚未就绪时执行就会出现“你明明注册了但菜单未显示且无报错”的现象。这个问题的排查很耗时我通常会在注册代码前后打印日志确认注册时机是否早于系统布局渲染。4. 踩坑记录与排查速查AWC菜单开发最折磨人的不是功能逻辑复杂而是“配置看着没问题页面就是没有变化”。我把这几年遇到过的典型问题梳理了一遍做成一个排查速查表供你们直接照着查。4.1 菜单不显示的五个常见原因第一个原因配置文件根本没被加载。AWC的客户化文件有严格的命名和目录要求放错位置、文件名不匹配都会被静默忽略。检查方法很简单在脚本里加一行临时日志看发布后能不能在控制台看到输出。看不到就说明你的整个客户化脚本都没加载不用再往下查菜单了。第二个原因命令组ID写错了。系统命令组的ID在不同版本可能不同同一个“更多”命令组在某个版本叫这个名字在另一个版本可能叫另一个名字。正确做法是打开系统原始配置文件搜索界面显示文本对应的命令组定义把官方ID复制过来别凭记忆写。第三个原因菜单项缺少必填属性。AWC对菜单项渲染有基础属性要求比如text不能缺、id不能重复。如果视力扫描没发现问题建议把菜单定义用JSON格式检查工具过一遍语法错误比逻辑错误更隐蔽。第四个原因层级结构闭合不对。多级菜单完全依赖children嵌套如果你在写大括号时少了一个}第二级菜单会整个失效一级菜单虽然渲染但变成一个点了没反应的死节点。这类问题很难通过肉眼发现最好用格式化工具统一整理。第五个原因命令Handler没注册成功。菜单项绑定了某个action但对应的command根本没被扩展进去表现结果同样是“菜单无反应”或者干脆不渲染。排查方式是在注册代码里手动调用一下命令看能不能弹出业务提示不能的话基本就是命令层的问题。4.2 权限和缓存带来的“幽灵问题”再讲两个很隐蔽的坑一个跟权限有关一个跟缓存有关它们都能让一行看起来正确的代码失效。权限问题多发于启用了AWC安全策略的环境。你在客户化脚本里定义的菜单在“开发账号”下看是正常的换一个业务账号登录就消失了。原因是平台根据当前用户上下文去计算菜单可见性如果自定义菜单没有绑定任何权限表达式部分环境会默认不给普通用户显示。这个不属于代码错误而是权限模型差异。处理方式是显式地在菜单定义里加上一个“全员可见”的权限配置或者指定目标角色组。缓存问题则是发布配置后前端还在使用旧配置。最常见的情况就是配置发布完浏览器刷新后菜单没出现但换台电脑或者用无痕模式打开菜单出现了。这就是缓存命中。AWC前端对配置是有缓存的发布后需要清理浏览器缓存或者启用某种强制刷新机制具体方式因部署方式而异。我个人的建议是在开发验证阶段始终用无痕窗口打开页面能减少很多假“Bug”。4.3 排查工具与一条实操经验排查前端问题最依赖的就是控制台的日志输出。AWC的JavaScript框架支持在浏览器控制台查看错误信息很多菜单不显示的问题其实控制台已经打出了原因只是没有经验的开发者不知道看哪里。我建议在客户化脚本里通过合适的方式输出关键日志例如检查命令注册成功时输出一条info菜单注册完成时输出一条info这样发布后打开控制台按时间顺序就能看出哪一步没走到。脚本加载顺序也是一个容易被忽略的因素。如果注册代码在框架基础组件初始化之前运行你的命令可能还没来得及挂到全局命名空间导致后续注册失败。处理方式是在脚本外层套一个初始化时机判断确保基础组件存在后再执行注册逻辑。类似“等组件就绪再注册”的思路在很多前端框架里都有AWC也遵循这个套路。5. 后续还能怎么扩展菜单做好之后你会发现这条技术路线还能延伸到不少相近场景。比如把同一套菜单结构复用到一个自定义的工作区页面或者在特定业务对象的上下文菜单里再挂一套层级。只要理解了命令组和菜单项的原理扩展起来边际成本很低。在后面处理类似需求时我更倾向于把菜单定义单独拆成一个模块命令层归命令层菜单层归菜单层再把注册入口独立出来。这样的话如果业务方今天说“加一个菜单入口”我只需要在菜单层加配置明天说“入口不要了”把注册那一行注释掉即可不用在业务代码里到处找入口。我踩过几次坑之后最深的体会是AWC的定制开发逻辑本身不难难在一个“托”字——它托在系统的各种约束上命令要先注册、菜单要挂载到正确的组、权限模型要匹配、缓存要清理干净。任何一个环节没对齐都会让结果像“薛定谔的猫”一样不确定。最后分享一个很小的技巧不要直接改系统自带的命令组定义文件一定要走扩展注册的方式。虽然改系统文件一时爽但版本升级之后你的改动会被覆盖得干干净净而扩展注册是随客户化配置整体发布的升级后依然存在。这个取舍做过一次版本升级的人都会懂。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑