Vol.12 SaaS平台菜单管理
01
菜单对应的是我们界面功能导航的入口,通常来说我们的导航会分为2-3级菜单,其中最末级的菜单对应的就是具体的页面。在系统中管理菜单的目的主要有两个,一是控制页面级的访问权限,二是可以按页面统计访问行为。对于对于平台侧而言,页面统计业务价值不大,因此主要是用来控制用户页面级的访问权限。对于租户侧而言,菜单可以控制租户能够使用的功能范围,同时也可以通过埋点统计分析租户最常用的功能。
02
说到页面,就不得不说一个概念,那就是页面路由。我们在Web端访问某个页面的方式通常是基于网页地址来的,比如以腾讯体育为例,访问NBA的页面对应的网址是:https://sports.qq.com/nba,这里其实对应两部分:网站域名和页面路由,页面路由又可以分为多级,这个多级实际上就可以对应我们的多级菜单。

我们可以理解页面路由就是前端页面的资源定位符,当输入对应的页面访问网址时,实际上就是告知前端应用找到对应的页面资源并通过浏览器展现出来。
现代化的前端技术是一个单体应用(SPA),可以基于动态路由技术实现页面资源的动态加载,这样的好处是如果用户没有相应的页面访问权限,就不会加载对应的页面资源。因此,即便是用户知道未授权的页面网址,直接输入这个未授权的网址的话,也无法访问到相应的页面,通常会是跳转到一个404页面(404在HTTP中代表该资源未找到) —— 这就阻断了非授权访问的路径。这里说一下为什么跳转到的是404页面,而不是403未授权页面。如果是403未授权就意味着该页面是存在的,只是未授权,这会暴露可访问的网址。另外,动态路由机制下确实未加载相应的页面,因此也确实是找不到对应的页面资源。
早期的前端技术则是加载全部资源,如果用户知道未授权的页面网址的话,是可以直接输入未授权的网址访问的。所以,在早期的技术解决方案是前后端不分离,最终依靠后端程序来拦截未授权的访问。机制上来说,就是对于每个用户或角色有一个可访问的页面路由清单,访问的时候后端程序来判断当前用户是否有权限访问该页面,如果没有权限则跳转到403未授权页面。
03
我们的菜单是多层级的,因此是一个树状结构,也就是新增菜单的时候要指定所属的上级菜单,如果不指定则默认为最顶层的一级菜单。我们列举一下一个菜单对象的字段属性:
所属上级菜单:可以为空,为空表示为一级菜单。 菜单名称:即前端页面展示的菜单名称。 菜单图标:通常在一级菜单前面会有个图标进行菜单区分,推荐使用SVG格式的图标,这样缩放不会出现模糊、锯齿的情况。 路由标识:页面路由标识,如上面讲到的/nba,/nba/video。 页面路由组件名称:对应的前端页面路由组件,通过这种方式可以后台动态更改要显示的页面。 排序值:即当前菜单在同一个上级菜单里的排序,通过这个值可以调整菜单次序。 是否启用:当前菜单是否处于启用状态,如果是停用状态,则在前端不可见(通常用于发版前提前配置好新增的菜单,上线时可以逐个或批量启用)。 菜单说明:当前菜单的功能说明,可以方便授权操作时知道该菜单能做什么。
对于菜单管理本身,实际上涉及到的功能不多,包括列表、新增、编辑、删除、启用/停用,从业务严谨的角度来说,只有处于停用状态的菜单才能够被删除。
我们来看一下具体的原型设计。

菜单列表
菜单列表为树状列表,由于菜单不会很多,而且树状列表不便于分页展示,因此列表展示了全部的菜单数据。菜单列表包括如下交互:
对于有下级的菜单,可以点击左侧的图标按钮展开下级菜单。 支持按菜单名称和路由标识搜索菜单,由于列表已经展示了全部数据,因此搜索可以直接由前端完成,这样可以减少后端数据请求。搜索统一点击“查询”按钮才执行数据筛选,重置时清空筛选表单内容,并刷新列表。 点击“添加菜单”按钮弹出添加菜单表单弹层,点击某个菜单所在行的“编辑”按钮弹出编辑该菜单的表单弹层。 对于“已启用”状态的菜单,不可以删除,删除按钮为禁用状态。已启用状态的菜单可以进行停用操作,点击“停用”按钮弹出停用确认弹层。对于“已停用”状态的按钮,删除按钮为正常状态,点击弹出删除确认弹层。已停用状态的菜单可以进行启用操作,点击“启用”按钮弹出启用确认弹层 可以选择多个菜单进行批量操作,批量操作包括批量启用、批量停用和批量删除,所有批量操作均需要二次确认才进行。

添加菜单

编辑菜单
添加和编辑菜单的表单完全一致,编辑表单会自动填充相应的菜单字段内容。表单填写说明如下:
所有带“*”号的为必填字段,不能提交空内容,包括空字符; 表单提交时需要去除首尾两端的空字符(输入空字符无法分辨出来,且首尾空字符没有意义); 考虑显示效果,菜单名称不能超过6个字,菜单说明不超过30个字; 上级菜单可以为空,为空时表示该菜单为一级菜单。点击上级菜单弹出任意级可选择的级联菜单,选中某个菜单点击空白处可收起,选中的菜单即为该菜单的上级菜单; 路由标识和组件名称由前端开发提供,需保证大小写一致,长度不超过60个字; 排序值只能输入大于0的整数,且数值不超过99。 菜单默认为已启用状态,如果选择了停用,则设置为已停用状态。

停用菜单
启用、停用和删除菜单均需要进行二次确认,避免误操作。这里启用和删除菜单的原型和停用类似,没有粘贴相应的图片。在“产品海豚湾”公众号回复“菜单管理”即可获取原型链接。
04
菜单对应的是页面,但是到了页面内还会有其他的操作入口,比如操作按钮、页签(一个菜单有多组页面)等等,这些也可以理解为菜单的下级操作入口。在具体产品设计上有两种方式可以参考。
第一种是类似PaaS方式。在PaaS平台中,可以基于PaaS能力,使用预设的模块组合出来一个页面,按钮实际上也是一种预设的页面元素。这个时候如果涉及到授权,可以针对这些操作入口来配置权限,比如限定角色哪些角色可以使用。这种方式的优点是高度灵活,缺点是技术实现代价太高,如果没有强大的PaaS研发团队,不建议采用这种方式。
第二种处理方式是将这些操作入口配置为菜单的下级,只是增加一个类型标识,标记为页面操作入口(也可以统一叫按钮)。为了简化权限配置,如果这些入口不需要做权限控制,那么就默认开放,也不需要录入。如果需要权限控制再配置菜单下的按钮级别权限控制点。在授权的时候,就可以和菜单授权一样去控制页面内操作入口的权限,实现起来会更简单。
对于列表某一个行的操作按钮,实际上操作的是对应的某一个业务对象,因此合理的方式是通过数据权限来控制,这块我们会在权限管理的篇章中讲解。