主题
菜单管理接口文档
概述
菜单管理模块提供子应用向一单位一平台上报和查询菜单数据的能力,支持菜单的上报、查询、树形结构查询等功能。菜单采用树形结构组织,支持多级嵌套。所有接口遵循国密 SM2/SM4 数字信封加密方案,确保数据传输安全。
交互方向
本模块包含以下交互方向:
| 交互方向 | 接口类型 | 子应用实现要求 | 说明 |
|---|---|---|---|
| 子应用→一单位一平台(上报) | 新增菜单、修改菜单、删除菜单 | ❌ 无需实现 | 子应用主动上报菜单数据,一单位一平台提供接收接口 |
| 子应用→一单位一平台(查询) | 查询菜单数据 | ❌ 无需实现 | 子应用主动查询菜单数据,一单位一平台提供查询接口 |
重要说明: 本模块所有接口均为"子应用→一单位一平台"上报/查询接口,子应用直接调用一单位一平台提供的接口,无需额外实现。
使用场景
- 子应用→一单位一平台(上报): 子应用向一单位一平台上报菜单配置数据
- 子应用→一单位一平台(查询): 子应用向一单位一平台查询菜单树、查询菜单信息
- 前端渲染: 根据用户角色动态生成菜单树
- 数据同步: 子应用定期向一单位一平台同步菜单数据
接口设计原则
所有接口均采用国密 SM2/SM4 数字信封加密方案:
- 统一 POST 方式:所有接口使用 POST 方法,业务参数在 encryptData 中加密传输
- 无路径参数:URL 路径中不包含任何业务参数,所有业务参数均在加密报文中
- 安全性:通过 SM2 混合加密和数字签名确保数据传输的机密性、完整性和不可抵赖性
- 应用隔离:每个菜单数据都包含应用标识 appId,实现多应用菜单隔离
适用范围
适用于子应用向一单位一平台上报和查询菜单数据的场景。
术语定义
核心概念
| 术语 | 说明 |
|---|---|
| 一单位一平台 | 核心管理平台,负责数据存储、权限管理、接口路由等核心功能 |
| 子应用 | 接入一单位一平台的独立业务系统,通过一单位一平台网关与其他系统交互 |
| 网关 | 一单位一平台的统一入口,负责路由转发、身份认证、权限控制、速率限制等 |
操作语义
| 术语 | 说明 | 数据流向 | 接口实现方 |
|---|---|---|---|
| 查询 | 主动请求获取数据 | 子应用→一单位一平台 | 一单位一平台实现 |
| 上报 | 主动提交业务数据 | 子应用→一单位一平台 | 一单位一平台实现 |
重要提示:
- "查询"表示子应用主动向一单位一平台请求数据,由一单位一平台提供查询接口
- "上报"表示子应用主动向一单位一平台提交数据,由一单位一平台提供接收接口
系统架构
数据流向
查询流程(子应用→一单位一平台)
子应用 → [加密请求] → 一单位一平台 → [加密响应] → 子应用上报流程(子应用→一单位一平台)
子应用 → [加密上报] → 一单位一平台 → [加密响应] → 子应用接口列表
子应用→一单位一平台(上报接口)
| 接口名称 | 请求地址 | 交互方向 | 说明 |
|---|---|---|---|
| 新增菜单 | POST /hztech-application/menu/create | 子→主(上报) | 新增单个菜单 |
| 修改菜单 | POST /hztech-application/menu/update | 子→主(上报) | 修改菜单信息 |
| 删除菜单 | POST /hztech-application/menu/delete | 子→主(上报) | 删除菜单 |
子应用→一单位一平台(查询接口)
| 接口名称 | 请求地址 | 交互方向 | 说明 |
|---|---|---|---|
| 查询菜单数据 | POST /hztech-application/menu/query | 子→主(查询) | 查询菜单列表或树 |
注: 所有业务参数均在 encryptData 中加密传输,URL 路径中不包含任何业务参数。
接口详情
1.1 新增菜单
接口说明
向一单位一平台新增菜单数据。新增的菜单必须包含应用标识,实现多应用菜单隔离。新增菜单时,菜单编码在同一应用下必须唯一。
请求方式
POST
请求地址
POST /ydyp/menu/create
交互方向
子应用 → 一单位一平台 (上报)
完整时序图
请求参数
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| name | String | 是 | 菜单名称 | "概览" |
| code | String | 是 | 菜单编码(同一应用下唯一) | "home" |
| alias | String | 否 | 菜单别名 | "home" |
| parentId | String | 否 | 父菜单ID(根菜单为"0") | "0" |
| parentName | String | 否 | 父菜单名称 | "" |
| path | String | 否 | 路由路径 | "/home" |
| component | String | 否 | 组件路径 | "views/home/Index" |
| source | String | 否 | 图标来源 | "lucide:layout-dashboard" |
| category | Integer | 否 | 分类 | 1 |
| categoryName | String | 否 | 分类名称 | "" |
| sort | Integer | 否 | 排序号 | 0 |
| action | Integer | 否 | 动作标识 | -1 |
| actionName | String | 否 | 动作名称 | "" |
| isOpen | Integer | 否 | 是否展开 | -1 |
| isOpenName | String | 否 | 展开状态名称 | "" |
| hasChildren | Boolean | 否 | 是否有子菜单 | true |
| remark | String | 否 | 备注 | "" |
| appId | String | 是 | 应用标识 | "SUB_APP_001" |
HTTP 请求示例
http
POST /ydyp/menu/create HTTP/1.1
Host: main.example.com
Content-Type: application/json
{
"appId": "SUB_APP_001",
"version": "1.0",
"timestamp": 1735516800000,
"nonce": "f6a7b8c9-d0e1-1234-5678-9abcdef01234",
"encryptKey": "MIIBOgIBAAJBAKj34GkxFhD90vcNLYLInFEX6...",
"encryptData": "U2FsdGVkX1+jmZn5KqWYEgjPkQKpH5KqWYEg...",
"sign": "MEUCIQDZ5KqWYEgjPkQKpH5KqWYEgjPkQKpH5KqWY..."
}encryptData 解密后的业务数据
json
{
"name": "概览",
"code": "home",
"alias": "home",
"parentId": "0",
"parentName": "",
"path": "/home",
"component": "views/home/Index",
"source": "lucide:layout-dashboard",
"category": 1,
"categoryName": "",
"sort": 0,
"action": -1,
"actionName": "",
"isOpen": -1,
"isOpenName": "",
"hasChildren": true,
"remark": "",
"appId": "SUB_APP_001"
}HTTP 响应示例
json
{
"code": 200,
"message": "success",
"data": {
"id": "1981548240639504386"
},
"timestamp": 1735516801500
}错误响应示例
json
{
"code": 2102,
"message": "菜单编码已存在",
"timestamp": 1735516801000
}1.2 修改菜单
接口说明
修改一单位一平台中已有的菜单数据。可以修改菜单的名称、路径、组件等信息,但菜单编码不可修改。
请求方式
POST
请求地址
POST /ydyp/menu/update
交互方向
子应用 → 一单位一平台 (上报)
完整时序图
请求参数
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| id | String | 是 | 菜单ID | "1981548240639504386" |
| name | String | 否 | 菜单名称 | "概览" |
| alias | String | 否 | 菜单别名 | "home" |
| parentId | String | 否 | 父菜单ID | "0" |
| parentName | String | 否 | 父菜单名称 | "" |
| path | String | 否 | 路由路径 | "/home" |
| component | String | 否 | 组件路径 | "views/home/Index" |
| source | String | 否 | 图标来源 | "lucide:layout-dashboard" |
| category | Integer | 否 | 分类 | 1 |
| categoryName | String | 否 | 分类名称 | "" |
| sort | Integer | 否 | 排序号 | 0 |
| action | Integer | 否 | 动作标识 | -1 |
| actionName | String | 否 | 动作名称 | "" |
| isOpen | Integer | 否 | 是否展开 | -1 |
| isOpenName | String | 否 | 展开状态名称 | "" |
| hasChildren | Boolean | 否 | 是否有子菜单 | true |
| remark | String | 否 | 备注 | "" |
| appId | String | 是 | 应用标识 | "SUB_APP_001" |
HTTP 请求示例
http
POST /ydyp/menu/update HTTP/1.1
Host: main.example.com
Content-Type: application/json
{
"appId": "SUB_APP_001",
"version": "1.0",
"timestamp": 1735516800000,
"nonce": "f6a7b8c9-d0e1-1234-5678-9abcdef01234",
"encryptKey": "MIIBOgIBAAJBAKj34GkxFhD90vcNLYLInFEX6...",
"encryptData": "U2FsdGVkX1+jmZn5KqWYEgjPkQKpH5KqWYEg...",
"sign": "MEUCIQDZ5KqWYEgjPkQKpH5KqWYEgjPkQKpH5KqWY..."
}encryptData 解密后的业务数据
json
{
"id": "1981548240639504386",
"name": "概览",
"alias": "home",
"parentId": "0",
"path": "/home",
"component": "views/home/Index",
"source": "lucide:layout-dashboard",
"category": 1,
"sort": 0,
"hasChildren": true,
"remark": "",
"appId": "SUB_APP_001"
}HTTP 响应示例
json
{
"code": 200,
"message": "success",
"data": {
"id": "1981548240639504386"
},
"timestamp": 1735516801500
}错误响应示例
json
{
"code": 2106,
"message": "菜单不存在",
"timestamp": 1735516801000
}1.3 删除菜单
接口说明
删除一单位一平台中已有的菜单数据。删除菜单时,如果菜单存在子菜单,需要先删除所有子菜单或使用级联删除。
请求方式
POST
请求地址
POST /ydyp/menu/delete
交互方向
子应用 → 一单位一平台 (上报)
完整时序图
请求参数
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| id | String | 是 | 菜单ID | "1981548240639504386" |
| appId | String | 是 | 应用标识 | "SUB_APP_001" |
| cascade | Boolean | 否 | 是否级联删除子菜单(默认false) | true |
HTTP 请求示例
http
POST /ydyp/menu/delete HTTP/1.1
Host: main.example.com
Content-Type: application/json
{
"appId": "SUB_APP_001",
"version": "1.0",
"timestamp": 1735516800000,
"nonce": "f6a7b8c9-d0e1-1234-5678-9abcdef01234",
"encryptKey": "MIIBOgIBAAJBAKj34GkxFhD90vcNLYLInFEX6...",
"encryptData": "U2FsdGVkX1+jmZn5KqWYEgjPkQKpH5KqWYEg...",
"sign": "MEUCIQDZ5KqWYEgjPkQKpH5KqWYEgjPkQKpH5KqWY..."
}encryptData 解密后的业务数据
删除单个菜单:
json
{
"id": "1981548240639504386",
"appId": "SUB_APP_001",
"cascade": false
}级联删除菜单及其子菜单:
json
{
"id": "1981548240639504386",
"appId": "SUB_APP_001",
"cascade": true
}HTTP 响应示例
成功删除:
json
{
"code": 200,
"message": "success",
"data": {
"id": "1981548240639504386",
"deletedCount": 1
},
"timestamp": 1735516801500
}级联删除响应:
json
{
"code": 200,
"message": "success",
"data": {
"id": "1981548240639504386",
"deletedCount": 5
},
"timestamp": 1735516801500
}错误响应示例
菜单不存在:
json
{
"code": 2106,
"message": "菜单不存在",
"timestamp": 1735516801000
}存在子菜单且未启用级联删除:
json
{
"code": 2108,
"message": "菜单存在子菜单,无法删除",
"timestamp": 1735516801000
}1.4 查询菜单数据
接口说明
查询菜单数据。支持按应用标识查询、查询菜单树结构、按条件筛选等功能。
请求方式
POST
请求地址
POST /hztech-application/menu/query
交互方向
子应用 → 一单位一平台 (查询)
完整时序图
请求参数
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| appId | String | 是 | 应用标识 | "SUB_APP_001" |
| queryType | String | 否 | 查询类型(list/tree,默认list) | "tree" |
| parentId | String | 否 | 父菜单ID(查询指定父菜单下的子菜单) | "0" |
| category | Integer | 否 | 分类筛选 | 1 |
| keyword | String | 否 | 关键词(模糊搜索菜单名称/编码) | "概览" |
| isDeleted | Integer | 否 | 是否删除(0:未删除,1:已删除,默认0) | 0 |
| pageNum | Integer | 否 | 页码(仅list模式有效,默认1) | 1 |
| pageSize | Integer | 否 | 每页数量(仅list模式有效,默认20) | 20 |
HTTP 请求示例
http
POST /hztech-application/menu/query HTTP/1.1
Host: main.example.com
Content-Type: application/json
{
"appId": "SUB_APP_001",
"version": "1.0",
"timestamp": 1735516800000,
"nonce": "f6a7b8c9-d0e1-1234-5678-9abcdef01234",
"encryptKey": "MIIBOgIBAAJBAKj34GkxFhD90vcNLYLInFEX6...",
"encryptData": "U2FsdGVkX1+jmZn5KqWYEgjPkQKpH5KqWYEg...",
"sign": "MEUCIQDZ5KqWYEgjPkQKpH5KqWYEgjPkQKpH5KqWY..."
}encryptData 解密后的业务数据
查询菜单树:
json
{
"appId": "SUB_APP_001",
"queryType": "tree",
"parentId": "",
"isDeleted": 0
}分页查询菜单列表:
json
{
"appId": "SUB_APP_001",
"queryType": "list",
"parentId": "0",
"category": 1,
"keyword": "",
"isDeleted": 0,
"pageNum": 1,
"pageSize": 20
}HTTP 响应示例
树形结构响应:
json
{
"code": 200,
"message": "success",
"data": [
{
"id": "1981548240639504386",
"name": "概览",
"code": "home",
"alias": "home",
"parentId": "0",
"parentName": "",
"path": "/home",
"component": "views/home/Index",
"source": "lucide:layout-dashboard",
"category": 1,
"categoryName": "",
"sort": 0,
"action": -1,
"actionName": "",
"isOpen": -1,
"isOpenName": "",
"hasChildren": true,
"remark": "",
"isDeleted": 0,
"appId": "SUB_APP_001",
"children": [
{
"id": "1981548240639504388",
"name": "数据概览",
"code": "home:data",
"alias": "data",
"parentId": "1981548240639504386",
"parentName": "概览",
"path": "/home/data",
"component": "views/home/Data",
"source": "lucide:bar-chart",
"category": 1,
"sort": 0,
"hasChildren": false,
"appId": "SUB_APP_001",
"children": []
}
]
}
],
"timestamp": 1735516801500
}列表分页响应:
json
{
"code": 200,
"message": "success",
"data": {
"total": 50,
"pageNum": 1,
"pageSize": 20,
"pages": 3,
"list": [
{
"id": "1981548240639504386",
"name": "概览",
"code": "home",
"alias": "home",
"parentId": "0",
"path": "/home",
"component": "views/home/Index",
"source": "lucide:layout-dashboard",
"category": 1,
"sort": 0,
"hasChildren": true,
"appId": "SUB_APP_001"
}
]
},
"timestamp": 1735516801500
}错误响应示例
json
{
"code": 2101,
"message": "应用不存在",
"timestamp": 1735516801000
}数据模型
菜单对象 (Menu)
完整的菜单数据结构:
json
{
"id": "string", // 菜单ID(系统生成或上报时指定)
"name": "string", // 菜单名称
"code": "string", // 菜单编码(同一应用下唯一)
"alias": "string", // 菜单别名
"parentId": "string", // 父菜单ID(根菜单为"0")
"parentName": "string", // 父菜单名称(冗余字段)
"path": "string", // 路由路径
"component": "string", // 组件路径
"source": "string", // 图标来源(如 lucide:layout-dashboard)
"category": 1, // 分类
"categoryName": "string", // 分类名称(冗余字段)
"sort": 0, // 排序号
"action": -1, // 动作标识
"actionName": "string", // 动作名称(冗余字段)
"isOpen": -1, // 是否展开
"isOpenName": "string", // 展开状态名称(冗余字段)
"hasChildren": true, // 是否有子菜单
"remark": "string", // 备注
"isDeleted": 0, // 是否删除(0:未删除,1:已删除)
"appId": "string", // 应用标识(用于多应用隔离)
"createTime": "string", // 创建时间
"updateTime": "string", // 更新时间
"children": [] // 子菜单列表(树形结构时包含)
}字段说明
| 字段 | 类型 | 必填 | 说明 | 约束 |
|---|---|---|---|---|
| id | String | 是 | 菜单唯一标识 | 同一应用下唯一 |
| name | String | 是 | 菜单名称 | 2-50个字符 |
| code | String | 是 | 菜单编码 | 同一应用下唯一 |
| alias | String | 否 | 菜单别名 | 用于路由跳转 |
| parentId | String | 否 | 父菜单ID | 根菜单为"0" |
| parentName | String | 否 | 父菜单名称 | 冗余字段 |
| path | String | 否 | 路由路径 | 以/开头 |
| component | String | 否 | 组件路径 | 前端组件路径 |
| source | String | 否 | 图标来源 | 图标标识符 |
| category | Integer | 否 | 分类 | 数字标识 |
| categoryName | String | 否 | 分类名称 | 冗余字段 |
| sort | Integer | 否 | 排序号 | 数值越小越靠前 |
| action | Integer | 否 | 动作标识 | 数字标识 |
| actionName | String | 否 | 动作名称 | 冗余字段 |
| isOpen | Integer | 否 | 是否展开 | -1:未设置,0:折叠,1:展开 |
| isOpenName | String | 否 | 展开状态名称 | 冗余字段 |
| hasChildren | Boolean | 否 | 是否有子菜单 | true或false |
| remark | String | 否 | 备注 | 菜单说明 |
| isDeleted | Integer | 是 | 是否删除 | 0或1 |
| appId | String | 是 | 应用标识 | 用于多应用菜单隔离 |
| createTime | String | 否 | 创建时间 | YYYY-MM-DD HH:mm:ss |
| updateTime | String | 否 | 更新时间 | YYYY-MM-DD HH:mm:ss |
| children | Array | 否 | 子菜单列表 | 树形结构时包含 |
枚举值说明
是否删除 (isDeleted):
0: 未删除1: 已删除
是否展开 (isOpen):
-1: 未设置0: 折叠1: 展开
查询类型 (queryType):
list: 列表查询(平铺结构,支持分页)tree: 树形查询(树形结构,包含层级关系)
树形结构说明
菜单采用递归树形结构:
- 根菜单的
parentId为"0" - 每个菜单可包含多个子菜单,存储在
children数组中 - 查询菜单树时,会递归返回所有层级的子菜单
hasChildren标识菜单是否有子菜单
应用隔离说明
通过 appId 实现多应用菜单隔离:
- 每个菜单数据必须包含
appId字段 - 查询菜单时必须指定
appId,只返回该应用的菜单数据 - 不同应用的菜单数据完全隔离,
code等字段在同一应用内唯一即可
错误码
业务错误码
| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 2101 | 应用不存在 | 检查appId是否正确注册 |
| 2102 | 菜单编码已存在 | 使用其他编码 |
| 2103 | 菜单名称已存在 | 使用其他名称 |
| 2104 | 父菜单不存在 | 检查parentId是否正确 |
| 2105 | 菜单循环引用 | 检查parentId不能是菜单自身或后代菜单 |
| 2106 | 菜单不存在 | 检查菜单ID是否正确 |
| 2107 | 参数错误 | 检查请求参数是否完整 |
| 2108 | 菜单存在子菜单,无法删除 | 先删除子菜单或使用级联删除 |
系统错误码
| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 1001 | 时间戳过期 | 同步系统时间 |
| 1002 | 重复请求 | 检查nonce生成逻辑 |
| 1003 | 签名验证失败 | 检查密钥配置 |
| 1004 | 解密失败 | 检查密钥配置 |
| 1005 | appId不存在 | 检查appId注册 |
| 1006 | 业务逻辑错误 | 根据具体错误处理 |
相关文档
文档版本: v2.0.0 最后更新: 2026-01-05