本文档说明 eosrole 页面「配置 EOS 菜单权限」树节点中 NodeID(前端 zTree 的 id)与 ObjectID(前端 objectId)的含义、数据库来源、后端组装与前端使用方式。
关联文档:EOS 菜单与角色关联关系说明
2026-07-31 更新:权限树接口额外返回
menuType/sysMenuId;保存 body 含 MES 按钮与 ERP 操作扩展字段。
结论摘要
| 前端字段 | 含义 | 数据库来源 | 主要用途 |
|---|---|---|---|
zTree id |
菜单节点 ID | messys.Tree.NodeID |
树结构、父子关系(pId);前端勾选态缓存键 |
zTree objectId |
EOS 权限对象 ID | messys.Tree.ObjectID = messys.ObjectRegister.ObjectID |
角色菜单授权(STPermission.ObjectID,「执行」) |
zTree menuType |
菜单类型 | EosMenuTypeHelper.resolveMenuType |
mes / erp / folder,决定右侧详情面板 |
zTree sysMenuId |
MES 菜单 ID | 优先 sys_menu_eos_node,否则 NodeDesc=MES_MENU: |
MES 菜单/按钮写入 sys_role_menu |
NodeID 与 ObjectID 是两套独立编号体系,不可混用。角色菜单「执行」授权必须使用 ObjectID;NodeID 用于树层级与 detail 查询参数。
1. NodeID 是什么
NodeID 是 EOS 菜单树 messys.dbo.Tree 的主键,标识一个菜单/目录节点在树中的位置。
在 MES 前端 zTree 中,NodeID 映射为节点的 **id**(idKey: "id"),ParentID 映射为 **pId**,用于渲染树形结构与展开/折叠。前端勾选态 permissionCheckedNodeIds 也按 NodeID 缓存。
NodeID 不写入 STPermission。权限表引用的是 ObjectID。detail 接口用 nodeId 定位节点后再解析业务 ObjectID。
2. NodeID 从哪来
2.1 数据库表
| 表 | 库 | 字段 | 说明 |
|---|---|---|---|
Tree |
messys | NodeID |
菜单节点主键 |
Tree |
messys | ParentID |
父节点 NodeID(根为 0) |
UniqueNO |
messys | No |
下一个可用 NodeID(NName='tree') |
2.2 MES 新建节点时的分配逻辑
MES 通过 TreeServiceImpl.getNextNodeIdForTree() 从 UniqueNO 表取号:
- 悲观锁查询
UniqueNO中NName='tree'的记录(PESSIMISTIC_WRITE) - 取当前
No作为新 NodeID - 将
No + 1写回,占用该编号
1 | // TreeServiceImpl.getNextNodeIdForTree() |
2.3 触发 NodeID 分配的操作
| 操作 | 方法 | 说明 |
|---|---|---|
| 新增菜单节点 | TreeServiceImpl.addNode |
先 getNextNodeIdForTree(),再写 Tree |
| sys_menu 同步 | TreeServiceImpl.syncFromSysMenu |
每个同步节点分配新 NodeID |
| 复制菜单 | TreeServiceImpl.copyMenu |
源节点及子树每个节点各分配新 NodeID |
| 交接班菜单批量创建 | createShiftLogDispatchMenus → addNode |
同上 |
2.4 EOS 原生 / 历史数据
在 MES 介入之前,NodeID 可能由 EOS 客户端或其他工具写入 Tree,同样依赖 UniqueNO 序列或历史遗留编号。MES 只保证新增/同步/复制时走 getNextNodeIdForTree() 逻辑。
2.5 NodeID 在 Functions 中的用途
Tree.Functions 字段保存菜单跳转 URL,其中 menuId 参数值为 NodeID(不是 ObjectID)。例如同步 sys_menu 时:
1 | {baseUrl}/{url}?token=%Token%&menuId={NodeID} |
复制菜单时,TreeServiceImpl 会将 Functions 里的 menuId=旧NodeID 替换为 menuId=新NodeID。
2.6 NodeID 生命周期
- 查询:
treeDao.findAll(...)、queryObject(nodeid)等 - 删除:
delete/deleteBatch按 NodeID 删除 Tree,并先ObjectRegisterDao.deleteByOwnerId(NodeID)清理关联对象
1 | flowchart LR |
3. ObjectID 是什么
ObjectID 是 EOS 对象注册表 messys.dbo.ObjectRegister 的主键。每个可授权对象在 ObjectRegister 中注册一条记录;菜单/目录节点对应 TypeID = 7,并通过 OwnerID = Tree.NodeID 与菜单树关联。
MES 维护菜单时会将 ObjectID 冗余写入 Tree.ObjectID,便于权限树接口一次查询带出。
在角色菜单授权场景下,前端勾选菜单后提交的是 objectId 列表,写入 mesdata.dbo.STPermission.ObjectID(配合 UserID=角色 OID、Oprate=「执行」、Permission=1)。
4. ObjectID 从哪来
4.1 数据库表
| 层级 | 库/表 | 字段 | 含义 |
|---|---|---|---|
| 权威主键 | messys ObjectRegister |
ObjectID |
全局对象 ID(自增:MAX+1) |
| 关联 | messys ObjectRegister |
OwnerID |
= Tree.NodeID |
| 类型 | messys ObjectRegister |
TypeID |
MES 新建菜单固定为 7(菜单/目录) |
| 冗余 | messys Tree |
ObjectID |
与 ObjectRegister.ObjectID 一致 |
| 授权 | mesdata STPermission |
ObjectID |
引用 ObjectRegister.ObjectID |
关系:Tree.NodeID ← ObjectRegister.OwnerID;Tree.ObjectID = ObjectRegister.ObjectID。
4.2 MES 新建节点时的分配逻辑
TreeServiceImpl.saveObjectRegisterForTree():
ObjectRegisterDao.findMaxObjectId()取 MAX(ObjectID) + 1- 插入
ObjectRegister(TypeID=7,OwnerID=NodeID,Object=菜单名) - 将返回的
ObjectID写入Tree.ObjectID
与 NodeID 分配在同一事务内完成(如 addNode 先取 NodeID,再创建 ObjectRegister)。
4.3 触发 ObjectID 分配的操作
与 NodeID 分配的操作相同(新增、同步、复制)。复制菜单时 NodeID 与 ObjectID 均重新分配,不会沿用源节点的 ObjectID。
| 场景 | ObjectID 来源 |
|---|---|
| MES 新增 EOS 菜单节点 | saveObjectRegisterForTree 新分配 |
| 从 sys_menu 同步 | 每个同步节点一条新 ObjectRegister |
| 复制菜单 | 新 NodeID + 新 ObjectRegister + 新 ObjectID |
| EOS 原生/历史数据 | 可能由 EOS 客户端写入;Tree.ObjectID 可能已存在 |
| 失败兜底 | object == null 时 Tree.ObjectID = 0(无有效授权对象) |
1 | flowchart LR |
5. NodeID 与 ObjectID 对照
1 | Tree.NodeID ──► zTree.id (树结构、ParentID 父子关系) |
| 对比项 | NodeID | ObjectID |
|---|---|---|
| 所属表 | messys.Tree 主键 |
messys.ObjectRegister 主键,冗余在 Tree.ObjectID |
| 分配方式 | UniqueNO(NName=’tree’)递增 |
MAX(ObjectID)+1 |
| 前端 zTree 字段 | id |
objectId |
| 是否用于 STPermission「执行」 | 否 | 是 |
| 复制菜单 | 重新分配 | 重新分配 |
5.1 业务 ObjectID 与 NodeID 的非 OwnerID 关联
菜单授权与 ERP 按钮授权使用不同的 ObjectID,且业务对象的 OwnerID 不一定等于 Tree.NodeID。
| 场景 | ObjectID 示例 | TypeID | OwnerID | STPermission 用途 |
|---|---|---|---|---|
| 菜单对象 | 468 | 7 | 430 | Oprate=执行, Permission=1 |
| 业务对象 | 965 | 1 | null | Oprate=EX61:..., Permission=0 |
解析路径(EosMenuObjectResolver.resolveBusinessObjects):
ObjectRegister.OwnerID = NodeID且TypeID != 7Tree.Functions括号内单据名 + 菜单对象名 →DjDy.DjCName→ObjectRegister.Object = DjCName且TypeID != 7- 回退:
Tree.ObjectID对应 ObjectRegister(可能含 TypeID=7)
禁止仅用 OwnerID=NodeID 或 Tree.ObjectID 推断按钮授权 ObjectID。复合页可能返回多个业务 ObjectID;同一 ObjectID 上可有多个 EXxx: 按钮 Oprate。
listAvailableOperations:标准操作 + ExFunction EXxx: + 库中已有非「执行」Oprate。
示例(NodeID=430):菜单树 objectId=468 用于勾选「执行」;按钮 EX61:组织架构分发 写在 ObjectID=965。
6. 后端组装与 API
6.1 权限菜单树
- 接口:
GET /eosrole/menu/tree(或@RequestMapping) - 实现:
EosRoleController.menuTree()→TreeService.listTreeForPermission() - 返回字段:
| 字段 | 来源 | 说明 |
|---|---|---|
id |
Tree.NodeID |
zTree 节点 ID |
pId |
Tree.ParentID(0 → -1) |
父节点 |
name |
Tree.NodeCaption |
显示名 |
objectId |
Tree.ObjectID |
STPermission「执行」键 |
menuType |
EosMenuTypeHelper.resolveMenuType |
mes / erp / folder |
sysMenuId |
sys_menu_eos_node,缺失时 NodeDesc fallback |
仅 MES 节点有值 |
1 | // TreeServiceImpl.listTreeForPermission() |
与 listTreeForSelect()(eostree 选目录)的区别:后者不含 objectId / menuType / sysMenuId,仅 id / pId / name。
6.2 权限查询与保存
| 接口 | 作用 |
|---|---|
GET /eosrole/permission/{roleId} |
返回已授权 objectId 列表(「执行」+ Permission=1) |
GET /eosrole/permission/detail/{roleId}?nodeId= |
按 NodeID 加载对象/按钮详情(MES 或 ERP) |
GET /eosrole/permission/mes-menu-ids/{roleId} |
返回 MES sys_role_menu 全部 menuId |
POST /eosrole/permission/save |
菜单执行 + ERP 操作 + MES 按钮 |
EosRolePermissionServiceImpl.queryMenuObjectIds 过滤条件:Oprate=执行 且 Permission=1(当前未按 TypeID=7 过滤)。
save body(EosRolePermissionSaveRequest):
| 字段 | 说明 |
|---|---|
roleIds |
EOS 角色 OID |
objectIds |
勾选菜单的 Tree.ObjectID → STPermission「执行」 |
mode |
append / replace |
mesMenuIds |
MES 目录/菜单 menu_id → sys_role_menu |
mesButtonMenuIds |
MES 按钮 menu_id → sys_role_menu |
operationPermissions |
ERP {objectId, oprate, granted} |
operationReplaceObjectIds |
replace 时清理非「执行」行的业务 ObjectID |
保存委托:先 EosRolePermissionServiceImpl 写「执行」,再 EosRoleObjectPermissionServiceImpl.saveMesAndObjectPermissions 写 ERP/MES。
7. 前端使用(eosrole.js)
7.1 zTree 配置
1 | var permissionTreeSetting = { |
7.2 加载与回显
loadPermissionMenuTree→ 请求/eosrole/menu/tree,用treeList初始化 zTree(含menuType/sysMenuId)- 单角色 + replace 模式:
/eosrole/permission/{roleId}→ 按 objectId 勾选菜单树(不是id)/eosrole/permission/mes-menu-ids/{roleId}→ 拆分 MES 菜单 ID / 按钮 ID 到permissionMesMenuIds等
- 点击节点 →
/eosrole/permission/detail/{roleId}?nodeId=:menuType=mes:展示 MES 按钮勾选menuType=erp:展示 ERP 操作「禁止」勾选menuType=folder:目录摘要
勾选 MES 节点时把 sysMenuId 加入 permissionMesMenuIds;取消勾选时清理对应按钮态。
7.3 保存
savePermission 收集并提交:
| 收集方法 | 字段 |
|---|---|
collectPermissionObjectIds() |
objectIds(勾选节点的 objectId,不是 id) |
collectMesMenuIdsForSave() |
mesMenuIds |
collectMesButtonMenuIdsForSave() |
mesButtonMenuIds |
collectOperationPermissionsForSave() |
operationPermissions |
collectOperationReplaceObjectIdsForSave() |
operationReplaceObjectIds |
连同 roleIds、mode 一并 POST 到 /eosrole/permission/save。
8. 验证 SQL
1 | -- NodeID 与 ObjectID 对照 |
9. 相关代码路径
| 环节 | 路径 |
|---|---|
| NodeID 分配 | TreeServiceImpl.getNextNodeIdForTree() |
| ObjectID 分配 | TreeServiceImpl.saveObjectRegisterForTree() |
| 新增/同步/复制 | TreeServiceImpl.addNode / syncFromSysMenu / copyMenu |
| 权限树 API | TreeServiceImpl.listTreeForPermission()、EosRoleController |
| 菜单类型 / sysMenuId | EosMenuTypeHelper、SysMenuEosNodeService |
| 菜单「执行」读写 | EosRolePermissionServiceImpl |
| ERP/MES 扩展保存 | EosRoleObjectPermissionServiceImpl |
| 业务 ObjectID 解析 | EosMenuObjectResolver |
| 实体 | TreeEntity、ObjectRegisterEntity、StPermissionEntity |
| 前端 | static/js/modules/security/eosrole.js |
10. 修订记录
| 日期 | 说明 |
|---|---|
| 2026-06-16 | 初版:梳理 Tree NodeID 与 ObjectID 从数据库到前端权限树的完整链路 |
| 2026-06-16 | 补充 NodeID 在 Tree.Functions URL 中作为 menuId 参数的说明 |
| 2026-07-01 | 补充业务 ObjectID 与 NodeID 非 OwnerID 关联及 eosrole 解析路径 |
| 2026-07-31 | 按最新实现修订:权限树补 menuType/sysMenuId;save/前端补 MES 与 ERP 扩展字段;代码路径补 ObjectPermission / Resolver |