跳转至

移动菜单(ResourceVO / .mobilemenu)定义编写指南

目标:Agent 直接生成/修改 workspace **移动端**菜单定义。知识以本文为准。不写原理;不依赖外链;PC 细节仅在与移动对照时出现。

iScript:脚本链接(如 type=07)的 actionContent 须 return URL;先读 iscript-usage(含 GraalVM 差异) → menu.md

术语:实体类 ResourceVO(与 PC 菜单同源);产品文档称「Mobile菜单」。后缀 .mobilemenuisMobile=true;可选 type=100。菜单是前台**移动导航入口**,**不是**模块;模块内表单/视图须挂移动菜单才从移动端导航打开。

与 PC 关系:两套独立树。改 PC .menu **不会**自动出现在移动端;必须另建 .mobilemenu 或走「复制到移动」。

产出物一览

部分 落盘 形态
移动菜单 mobilemenu/{名}.mobilemenu/ 或扁平 {名}.mobilemenu/ 目录 + 同名元数据;JAXB 根 resourceVOisMobile=true
# 推荐(与 ModelSuffix / APPLICATION_SKILL 一致;设计态 ResourceVO.getPath)
/{应用}.application/mobilemenu/{名}.mobilemenu/{名}.mobilemenu
/{应用}.application/mobilemenu/{父}.mobilemenu/{子}.mobilemenu/{子}.mobilemenu

# 样例包常见扁平布局(无 mobilemenu 分组目录;按后缀仍可读)
/{应用}.application/{名}.mobilemenu/{名}.mobilemenu

路径相对 storage/workspace。菜单是**目录型资源**(目录名=name+.mobilemenu,目录内再放同名元数据文件)。**不是**角色那种单文件。

新建最低配置

  1. 建目录 {name}.mobilemenu/,放在推荐 mobilemenu/ 下,或应用根扁平
  2. 写同名元数据:idnameparentIdapplicationidpermissionTypestatus=1isMobile=trueorderno
  3. 顶层必须先是分类linkType 空、actionContent 空(见「硬规则」)
  4. 叶子挂在分类下:linkType + actionContent;表单/视图/报表/OLAP 等再写 moduleid
  5. 子菜单:superior=parentId=上级**移动**菜单 id;落盘在上级 .mobilemenu 目录下
  6. (按需)private 时在角色 .rolepermissions 中授权本菜单 id

约定

  • JAXB;根元素 resourceVOid根属性
  • 脚本/长文本/queryString/actionContent/description<![CDATA[...]]>
  • 目录名 = 元数据文件名 = name + .mobilemenu 三者一致
  • parentId:顶层=软件 id;子=上级移动菜单 id
  • superior:顶层省略或空;子=上级移动菜单 id(与 parentId 同值)
  • applicationid 建议始终写 = 软件 id
  • name 勿含 / % \(落盘替换为 =47/=37/=92
  • **勿**把菜单放到 module/ 下;勿写到 menu/(那是 PC)
  • 排序字段 XML 名 orderno(全小写),不是 orderNo
  • 必须 isMobile=true;建议 type=100(可省略,以 isMobile+后缀为准)
  • PC id 与移动 id 必须不同(复制会生成新 id;手写勿复用 PC 菜单 id)

1. 心智模型与硬规则

软件 Application
  ├─ module/*.module/ … 表单/视图/流程/报表/图表
  ├─ menu/*.menu/              ← PC 树(isMobile=false)— 本文不生成
  ├─ mobilemenu/*.mobilemenu/  ← 移动树(isMobile=true)— 本文目标
  │    └─ 一级分类.mobilemenu/
  │         ├─ 分类元数据(linkType 空)
  │         └─ 叶子.mobilemenu/ …(linkType+actionContent)
  └─ role/*.role               ← permissions 可授权菜单 id(resType=2)
概念 说明
一级分类 顶层、linkType 空;仅作上级;移动 UI 用其分组九宫格/分组列表
叶子菜单 二级及以下;有 linkType+actionContent;真正打开表单/视图等
moduleid 先选模块 id,再在模块下选目标;目标 id 进 actionContent
权限 public:有软件角色即可见;private:须 role.permissions 含本菜单

模块 菜单。无移动菜单则用户无法从移动端侧栏/九宫格进入模块资源(PC 菜单不可替代)。

硬规则(移动端特有;违反则前台空白)

  1. 一级菜单默认当分类用。顶层只建带 linkType 的叶子 → 移动端往往不显示
  2. 正确流程:先建一级分类(无链接)→ 再建/复制子叶子挂到该分类下。
  3. 产品 UI 推荐路径:后台「Mobile菜单」新建一级 → PC 菜单列表选中 →「复制菜单」→ 复制到指定移动一级分类。
  4. Agent 手写等价:直接写两层 .mobilemenu 目录嵌套,不必调复制 API。
  5. 从 PC 复制时,不支持的 linkType 会被**清空**(见 §5);手写时只写移动支持的码。

2. ResourceVO 属性 → .mobilemenu XML

属性表

属性 XML 类型 默认 移动侧说明
id 根属性 string 须生成 __ + 短 UUID;角色授权 resId/operationId勿与 PC 菜单 id 相同
name 子元素 string 必填;目录名与文件名
parentId 子元素 string 顶层=软件 id;子=上级移动菜单 id
applicationid 子元素 string 建议=软件 id
description CDATA string 常用=名称
remark CDATA string 少用
multiLanguageLabel 子元素 string 多语言标签名
type 子元素 string 移动写 100;PC 为 00;可省略
opentarget 子元素 string detail detail=工作区;target=新窗口(移动端意义弱于 PC)
ico 子元素 string 图标 JSON 字符串;移动九宫格靠图标
mobileIco 子元素 string **旧**移动图标码;新配置用 ico
superior 子元素 string 顶层空 逻辑上级;顶层不写;子=上级 id
linkName 子元素 string 常=name
linkType 子元素 string 见 §3;空=分类
moduleid 子元素 string linkType 为 00/01/02/09/34 等时需要
directory 子元素 string portal 内部自定义链接前缀;05
actionContent CDATA string 目标 id / URL / 脚本
actionExcelImport 子元素 string Excel 导入配置 id;可选
queryString CDATA string [] 请求参数 JSON 数组
permissionType 子元素 string public public / private
showType 子元素 int 0 0双显 / 1仅菜单 / 2仅流程中心
status 子元素 int 1 1有效 / 0失效(前台不展示)
isUsual 子元素 string false 是否常用(字符串布尔)
isMobile 子元素 string 固定写 true;决定落盘 .mobilemenu
orderno 子元素 int 0 同级排序;越小越前
showtotalrow 子元素 string false 仅视图链接;显示记录总数(性能差)
report / reportAppliction / reportModule 子元素 string 历史报表字段;新配置用 linkType+actionContent+moduleid
widgetGroupId 子元素 string 关联 widget 分组;少用
uri / path / children 推导/运行期 不进 XML

不落盘:childrentotalRownewIcoallowOpenFromallowOpenView

id 生成

统一规则:__ + 短 UUID。示例:__MpEzTToulqZtNEFisw6。**同一软件内**不与其它菜单(含 PC)id 冲突。

permissionType

含义
public 对该软件有有效角色即可见(不强制查 permissions 菜单项)
private 须在角色 permissions 中显式授权本菜单(resType=2operationCode=1002operationId=resId=菜单 id)

空串写入时后端会当成 private。新建默认写 public

showType

常量 含义
0 SHOW_TYPE_BOTH 菜单与流程中心都可出现
1 SHOW_TYPE_MENU 仅菜单
2 SHOW_TYPE_FLOW_CENTER 仅流程中心

表单启动(00)/图表(02)设计器会展示此项。从 PC「创建菜单」且 showType=mobile 时设 type=100isMobile=true

opentarget

说明
detail 工作区域打开(默认)
target 新窗口打开

ico 格式

字符串形式 JSON(不是嵌套 XML)。移动端分类/叶子都应尽量配图标(九宫格展示):

{"icon":"/uploads/lib/icon_menu_default.png","icontype":"img"}
{"icon":"fa fa-cube","icontype":"font","iconFontColor":"rgba(228, 89, 117, 1)"}
说明
icon 图片路径或字体类名
icontype img / font
iconFontColor 仅 font;CSS 颜色

默认图常见:/uploads/lib/icon_menu_default.png

旧字段 mobileIco:历史数字/码表图标;新写文件不要用,统一 ico

queryString

CDATA 内为 JSON **数组**字符串:

[{"paramKey":"test","paramValue":"11111"}]

空:[]。勿用对象。运行时拼到打开 URL 的 query。

superiorparentId(移动)

场景 superior parentId 磁盘(推荐)
移动顶层分类 空/省略 软件 id …/mobilemenu/{name}.mobilemenu/
移动子菜单(任意深度) 上级**移动**菜单 id 同上 嵌套在上级 .mobilemenu

设计态:有 superiorparentId=superior;无则 parentId=applicationId
设计器上级下拉第一项可能把 id 设成软件 id(表示顶层)——生成文件时顶层 留空 superiorparentId=软件 id。

禁止:移动菜单的 superior/parentId 指向 PC .menu 的 id(两套树,跨树挂载无效或错位)。

校验(设计态,PC/移动同规则,后缀分开):

  • name 空 → 菜单名称不能为空
  • 同级(相同 parentId + 相同文件后缀 .mobilemenu)重名 → 同级菜单名称已存在
  • name 与直接上级 name 相同 → 名称不可以跟上级相同
  • 改名与直属下级重名 → 菜单名不能与直属下级菜单重名

同级 PC .menu 与移动 .mobilemenu 可以同名(后缀不同,算不同文件)。


3. 链接类型 linkType(移动)

两位字符串码。空或省略 = 无链接(分类;一级必备)。

移动端优先使用的码(Agent 默认只写这些)

常量/UI actionContent moduleid 说明
(空) 分类 不需 一级必须;下级也可作文件夹
00 表单启动 FORM 表单 id 必填 打开新建/表单
01 视图 VIEW 视图 id 必填 可配 showtotalrow;视图侧可有 mobileDisplayMode
02 图表/统计图 CHART 图表 id 必填
07 脚本链接 SCRIPT iScript 源码 可选 运行返回 URL 字符串
09 自定义报表 CUSTOMIZE_REPORT 报表 id 建议有 ureport/jasper 等
33 大屏 BIGSCREEN 大屏 id 不需 应用下 bigscreen/
34 OLAP OLAP id 必填 模块下 OLAP

移动设计器选项通常**少于** PC:一般无 05/06 或较少暴露。PC→移动复制时,**不在**可保留集合内的 linkType 会被清空(见 §5)。

模型枚举中仍有、移动少用/复制常丢的码

枚举 移动侧注意
05 MANUAL_INTERNAL PC 内部页;复制到移动常被清空
06 MANUAL_EXTERNAL 外部 URL;复制到移动常被清空;可用 07 脚本返回 URL 替代
03 EXCELIMPORT 少用
04 ACTION 少用
08 EMAIL 少用
10 BBS 少用
11 NetworkDisk 少用
12 RUNQIAN_REPORT 润乾;复制到移动时保留类之一
@@ NONE 占位

旧数据:linkType=09 且无 moduleid 时,详情 API 会从 actionContent 解析报表 id 并回填 moduleid。

actionContent 按类型

linkType 内容
00/01/02/09/12/33/34 目标资源 id(裸 id,非 URL)
05 内部路径;可与 directory=portal 组合
06 外部绝对 URL
07 iScript;执行后 return URL 字符串

脚本链接示例(CDATA 内):

(function () {
    var url = "https://hao.360.com/";
    return url;
})()

自定义页常见返回:

(function(){
    var pageId = "自定义页面ID";
    var applicationId = getApplication();
    var domainId = getWebUser().getDomainid();
    var request = getParamsTable().getHttpRequest();
    var baseUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
    return baseUrl + "/static/portal/vue/pageIndexHtml/index.html#/?pageId=" + pageId
        + "&appId=" + applicationId + "&domainId=" + domainId;
})();

运行时也可先落到 /portal/LinkForScript?_resourceid={菜单id} 再服务端执行。

表单/视图「创建菜单」快捷写入(移动)

请求参数 showType=mobile(或等价)时:

来源 linkType actionContent moduleid queryString opentarget 强制字段
表单 00 formId form.parentId [] detail type=100isMobile=true
视图 01 viewId view.parentId [] detail 同上

name/linkName/description/superior 由请求指定。**仍须**挂到已有一级分类下(superior=分类菜单 id),不要直接挂软件 id 当唯一叶子。

标签页/查询表单/模板表单:**不可**单独创建菜单。


4. XML 示例(全部 isMobile=true

4.1 一级分类(无链接;必须先有)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<resourceVO id="__mMenuFolderLeave001">
  <name>请假管理</name>
  <parentId>__a1b2c3d4e5f6g7h8i9j</parentId>
  <applicationid>__a1b2c3d4e5f6g7h8i9j</applicationid>
  <description><![CDATA[请假管理]]></description>
  <type>100</type>
  <opentarget>detail</opentarget>
  <ico>{"icon":"/uploads/lib/icon_menu_default.png","icontype":"img"}</ico>
  <linkName>请假管理</linkName>
  <linkType></linkType>
  <directory>portal</directory>
  <actionContent><![CDATA[]]></actionContent>
  <queryString><![CDATA[[]]]></queryString>
  <permissionType>public</permissionType>
  <showType>0</showType>
  <status>1</status>
  <isUsual>false</isUsual>
  <isMobile>true</isMobile>
  <orderno>0</orderno>
  <showtotalrow>false</showtotalrow>
</resourceVO>

路径:LeaveOA.application/mobilemenu/请假管理.mobilemenu/请假管理.mobilemenu

4.2 二级叶子:打开视图

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<resourceVO id="__mMenuViewLeaveList01">
  <name>请假列表</name>
  <parentId>__mMenuFolderLeave001</parentId>
  <applicationid>__a1b2c3d4e5f6g7h8i9j</applicationid>
  <description><![CDATA[请假列表]]></description>
  <type>100</type>
  <opentarget>detail</opentarget>
  <ico>{"icon":"fa fa-list","icontype":"font","iconFontColor":"rgba(64,158,255,1)"}</ico>
  <superior>__mMenuFolderLeave001</superior>
  <linkName>请假列表</linkName>
  <linkType>01</linkType>
  <moduleid>__moduleLeave00000001</moduleid>
  <directory>portal</directory>
  <actionContent><![CDATA[__viewLeaveList000001]]></actionContent>
  <queryString><![CDATA[[{"paramKey":"status","paramValue":"1"}]]]></queryString>
  <permissionType>public</permissionType>
  <showType>0</showType>
  <status>1</status>
  <isUsual>false</isUsual>
  <isMobile>true</isMobile>
  <orderno>0</orderno>
  <showtotalrow>false</showtotalrow>
</resourceVO>

路径:…/mobilemenu/请假管理.mobilemenu/请假列表.mobilemenu/请假列表.mobilemenu

4.3 二级叶子:打开表单

与 4.2 相同骨架,改:

  <linkType>00</linkType>
  <moduleid>__moduleLeave00000001</moduleid>
  <actionContent><![CDATA[__formLeaveApply00001]]></actionContent>

4.4 脚本链接

  <linkType>07</linkType>
  <actionContent><![CDATA[(function () {
    return "https://hao.360.com/";
})()]]></actionContent>

4.5 自定义报表 / 大屏 / OLAP / 图表

  <linkType>09</linkType>
  <moduleid>{模块id}</moduleid>
  <actionContent><![CDATA[{报表id}]]></actionContent>
  <linkType>33</linkType>
  <actionContent><![CDATA[{大屏id}]]></actionContent>
  <linkType>34</linkType>
  <moduleid>{模块id}</moduleid>
  <actionContent><![CDATA[{olapId}]]></actionContent>
  <linkType>02</linkType>
  <moduleid>{模块id}</moduleid>
  <actionContent><![CDATA[{图表id}]]></actionContent>

4.6 错误示例(不要生成)

顶层直接叶子(无分类父):

mobilemenu/请假列表.mobilemenu/请假列表.mobilemenu
  isMobile=true, parentId=软件id, linkType=01  ← 易导致移动端不显示

写成 PC 后缀或 isMobile=false

menu/….menu + isMobile=false  ← 进 PC 树,移动导航读不到

isMobile=true 但放在 menu/ 目录、或 isMobile=false 放在 mobilemenu/:路径与标记不一致,设计态 path/后缀逻辑会错。


5. PC → 移动复制(设计态行为;手写可跳过)

产品配置步骤等价:

  1. 新建移动端一级分类
  2. PC 菜单列表选中源菜单 → 复制菜单
  3. 目标选该移动一级分类,填名称

API:POST …/menus/copy?destid=&isMobile=

方向 请求 isMobile 参数语义 结果
复制到 PC true(表示源为移动) 新菜单 isMobile=false;挂到 dest
复制到移动 false(表示源为 PC) 新菜单 isMobile=true仅保留 linkType ∈ {00,01,02,09,12}(及空/分类);其它 linkType 清空

复制会 clone 字段、清 id/uri、改 parent/superior、改 isMobile。子树一般按选中节点复制到 dest 下。

Agent 手写:直接建 .mobilemenu,设 isMobile=true,挂到已有分类 id;换新 id;只写移动支持的 linkType。不必先有同结构 PC 菜单。

从 PC 平移字段对照:

字段 处理
id 新生成
isMobile true
type 100(建议)
parentId/superior → 目标分类 id
linkType/actionContent/moduleid/ico/queryString/permissionType/orderno 可拷;注意不支持类型被清
磁盘路径 必须进 mobilemenu/ + .mobilemenu 后缀

6. 权限与角色(完整形状;PC/移动同形)

菜单自身

  • permissionType=public:有该软件有效角色即可见
  • permissionType=private:还须角色 permissions 含本**移动菜单 id**(授权 PC 菜单 id **不等于**授权对应移动菜单)

写入 .rolepermissions(CDATA JSON 数组中的一项)

{
  "operationCode": 1002,
  "operationId": "{mobileMenuId}",
  "resId": "{mobileMenuId}",
  "resName": "菜单",
  "resType": 2,
  "roleId": "",
  "type": 1
}
字段
resType 2 = MENU_TYPE
operationCode 1002(历史名 MENU_INVISIBLE;实际写入表示允许菜单可见,type=ALLOW)
operationId / resId 均为该 .mobilemenuid
type 1 = TYPE_ALLOW

仅有菜单授权不够打开 private 表单/视图时,还须对表单/视图写「打开」等:

{
  "operationCode": 1032,
  "operationId": "{formOrViewId}",
  "resId": "{formOrViewId}",
  "resName": "打开",
  "resType": 0,
  "type": 1
}

resType:视图=0,表单=1

运行鉴权缓存键:{roleId}_{resId}_{operationId}_{operationCode}

分类菜单若为 private,通常也要对分类 id 授权,否则子项可能无法从树上展开(按产品鉴权实现;保险做法:分类 public,叶子按需 private)。


7. 设计态 / 运行态 API(可选;优先直接写文件)

Base 设计态:/api/designtime(设计器常加 /designer 前缀)。{appId}=软件 id。

方法 路径 作用
GET /applications/{appId}/menus?isMobile=true&parentId= 移动子菜单列表
GET /applications/{appId}/menus/{menuId} 详情
POST /applications/{appId}/menus?isMobile=true 新建移动菜单;body=ResourceVO JSON
PUT /applications/{appId}/menus/{menuId} 更新;按 superior 重算 parentId
DELETE /applications/{appId}/menus body=id 数组
POST /applications/{appId}/menus/copy?destid={移动分类id}&isMobile=false PC→该分类
POST /applications/{appId}/form/{formId}/menus 按表单建菜单;要 mobile 时带 showType=mobile 等
POST /applications/{appId}/view/{viewId}/menus 按视图建菜单
GET /applications/{appId}/menu/getAllMenus?showType=mobile 移动上级树下拉
GET /applications/{appId}/icons 图标库

运行态:GET /api/runtime/{applicationId}/menus?isMobile=true → 当前用户可见**移动**菜单树(含权限过滤)。isMobile=false 为 PC 树。


8. 命名、路径、挂载

规则 要求
文件/目录 {name}.mobilemenu / {name}.mobilemenu/{name}.mobilemenu
同级不重名 相同 parentId + 后缀 .mobilemenu
顶层挂载 parent=Application → 插入 file group /mobilemenu
子菜单挂载 parent=ResourceVO → **不再**插 group,直接挂在上级 .mobilemenu 目录下
moduleid 真实模块 id;actionContent 目标须属该模块(大屏等除外)
改名 同步改目录名、元数据文件名、XML <name>

跨资源:

菜单要打开 先有
表单/视图/报表/图表/OLAP 对应模块内资源 + 正确 moduleid
大屏 应用下 bigscreen
脚本 actionContent 自洽

与 PC 并存时包结构示例:

LeaveOA.application/
  LeaveOA.application
  menu/                          # PC,本文不生成
    请假管理.menu/
  mobilemenu/                    # 移动
    请假管理.mobilemenu/
      请假管理.mobilemenu        # 一级分类 linkType 空
      请假列表.mobilemenu/
        请假列表.mobilemenu      # linkType=01
      新建请假.mobilemenu/
        新建请假.mobilemenu      # linkType=00
  module/
    leave.module/
  role/
    员工.role

9. 新建清单(Agent 落盘顺序)

1. 已有软件 id、(按需)模块与表单/视图 id
2. 生成分类 menuId、叶子 menuId(均新 id;isMobile=true)
3. 建目录:
   storage/workspace/{软件}.application/mobilemenu/{分类名}.mobilemenu/
4. 写分类元数据:linkType 空、parentId=软件 id、isMobile=true、type=100
5. 在分类目录下建叶子目录并写元数据:
   superior=parentId=分类 id;linkType+actionContent(+moduleid)
6. private → 改角色 permissions(用移动菜单 id)
7. 勿只落叶子、勿写到 menu/、勿复用 PC 菜单 id

最小可运行(仅移动):

{软件}.application/mobilemenu/{分类}.mobilemenu/{分类}.mobilemenu
{软件}.application/mobilemenu/{分类}.mobilemenu/{叶子}.mobilemenu/{叶子}.mobilemenu

10. 校验与常见错误

问题 处理
移动端空白 / 看不到菜单 是否只有一级叶子;先建一级分类再挂子;查 status=1isMobile=true、后缀 .mobilemenu
配了 PC 菜单移动仍空 PC/移动两套树;须另有 .mobilemenu
菜单名称不能为空 非空 name
同级菜单名称已存在 换名或换上级(同后缀同级)
名称与上级/下级相同 改名
打开报错/空 linkTypeactionContent/moduleid 匹配;目标存在
复制后链接没了 源 linkType 不在保留集;改用 00/01/02/07/09/12/33/34 重写
showtotalrow=true 视图总数;非必要勿开
根元素错误 必须 resourceVO(不是 menu/mobilemenu
写成单文件无目录 须目录型 {name}.mobilemenu/{name}.mobilemenu
放到 module/ 或 menu/ 移到 mobilemenu/(或扁平应用根 + .mobilemenu
isMobile=false.mobilemenu 改为 true
orderNo 无效 字段是 orderno
private 仍全员可见 / 授权无效 查是否授权了**移动**菜单 id 而非 PC id;权限缓存;status
图标不显示 ico JSON;勿依赖废弃 mobileIco

11. 与其它技能边界

内容 本文 其它
.mobilemenu / isMobile / 一级分类硬规则 / 移动 linkType / PC→移动复制
PC .menu 全量 仅对照与复制 MENU_SKILL
软件目录、mobilemenu/ 路径 路径 APPLICATION_SKILL
模块 id、表单/视图归属 moduleid 指向 MODULE_SKILL / FORM_SKILL / VIEW_SKILL
permissions 全表、用户绑定 菜单项形状已自含 ROLE_SKILL
视图 mobileDisplayMode 等展示 不定义 VIEW_SKILL
表单 JsonTemplate 字段 mobile 不定义 FORM_SKILL

生成业务功能需移动入口时:先有模块内表单/视图(及角色)→ 先写移动一级分类 → 再写叶子 .mobilemenu 指向资源;PC 菜单按需另建,互不替代。