外系统菜单批量导入技能¶
📄 创建: 吴乐 2026-08-12
把另一个系统的菜单树(JSON)批量写入本系统
sys_resource表,以 iframe 外链方式挂载。 适用场景:综合管控平台接入第三方系统。
定位¶
第三方系统有自己的前端页面和菜单,不想重写页面,用 iframe 直接嵌入。步骤:拿对方菜单 JSON → 按规则生成 SQL → 导入 sys_resource。
输入¶
- 菜单 JSON(对方接口返回,格式见附录):含
name/code/icon/route/is_hidden/sort/parent_id/children树形结构 - 基础 URL:对方系统地址(如
http://ip:port/#) - 鉴权参数:
?key=xxx或?access_token=xxx(免登录参数,从对方系统获取) - APP_ID:本系统的应用标识(如
XNDC、TPF等) - 目标数据库:
bams-apex库,MySQL 容器名mysql,账号密码见部署文档
字段映射规则(关键)¶
| sys_resource 字段 | 来源 | 规则 |
|---|---|---|
id |
生成 | 19位雪花ID(本地自增计数器即可) |
pid |
生成 | 父菜单的新雪花ID;根菜单为 0 |
menu_type |
固定 | dir |
menu_code |
JSON code |
原样 |
menu_name |
JSON name |
原样 |
menu_icon |
JSON icon |
原样(MessageBox/List/Menu等) |
path |
JSON route |
去掉所有 /(如 /carbonInventory → carbonInventory) |
sort |
JSON sort |
原样 |
is_hide |
JSON is_hidden |
is_hidden==1 → 1(隐藏),否则 0 |
IFRAME_SRC |
拼接 | 基础URL + route + 鉴权参数(如 http://ip:port/#/home/index?access_token=xxx) |
APP_ID |
指定 | 应用标识 |
IS_ENABLE |
固定 | 1 |
OPEN_TYPE |
固定 | '0' |
is_cache/is_external_link/IS_DEFAULT_EXPAND |
固定 | 0 |
created_by/updated_by |
固定 | 103 |
corp_code |
固定 | 120101 |
导入步骤¶
① 写 Python 生成脚本(本地 /tmp/gen_menu.py)¶
import json
TOKEN = "<鉴权token,向对方系统获取>"
BASE = "<对方系统地址>" # 如 http://ip:port/#
APP = "<APP_ID>" # 如 TPF
NOW = "2026-08-12 12:00:00"
CORP = "120101"
UID = "103"
with open("/tmp/menus.json") as f:
data = json.load(f)
c = [1786100000000000000] # 计数器,起点每次换一批避免撞ID
def nid():
c[0] += 1
return str(c[0])
def process(items, pid="0"):
sqls = []
for item in items:
sid = nid()
route = item["route"].replace("\\/", "/").strip("/")
name = item["name"]; icon = item.get("icon", ""); code = item["code"]
is_hide = 1 if item.get("is_hidden") == 1 else 0
sort = item.get("sort", 0)
iframe = f"{BASE}/{route}?access_token={TOKEN}"
path = route.replace("/", "")
sql = (f"INSERT INTO sys_resource (id,pid,menu_type,menu_code,menu_name,"
f"menu_icon,path,sort,is_cache,is_hide,is_external_link,remark,"
f"IS_ENABLE,MENU_GROUP,IS_DEFAULT_EXPAND,BACKGROUND,CREATE_DEPT,"
f"CREATE_ORG,OPEN_TYPE,APP_ID,PARAMS,IFRAME_SRC,APP_PRJ_CODE,"
f"created_by,created_time,updated_by,updated_time,corp_code) VALUES ("
f"'{sid}','{pid}','dir','{code}','{name}','{icon}','{path}',{sort},"
f"0,{is_hide},0,NULL,1,'',0,'',NULL,NULL,'0','{APP}','','{iframe}','',"
f"{UID},'{NOW}',{UID},'{NOW}','{CORP}');")
sqls.append(sql)
if "children" in item:
sqls.extend(process(item["children"], sid))
return sqls
sqls = process(data["data"])
print(f"DELETE FROM sys_resource WHERE APP_ID='{APP}';")
for s in sqls: print(s)
② 生成 SQL 并导入¶
python3 /tmp/gen_menu.py > /tmp/menu_sql.txt
scp /tmp/menu_sql.txt root@<服务器>:/home/apex/
ssh root@<服务器> "docker exec -i mysql mysql -uroot -p'<密码>' --default-character-set=utf8mb4 bams-apex < /home/apex/menu_sql.txt"
③ 导入后校验(两处易错点)¶
-- 1. path 不能带 '/'
SELECT id, path FROM sys_resource WHERE APP_ID='<APP>' AND path LIKE '%/%';
-- 有结果则:UPDATE sys_resource SET path = REPLACE(path,'/','') WHERE APP_ID='<APP>';
-- 2. IFRAME_SRC 不能出现 '#//'
SELECT id, IFRAME_SRC FROM sys_resource WHERE APP_ID='<APP>' AND IFRAME_SRC LIKE '%#//%';
-- 有结果则:UPDATE sys_resource SET IFRAME_SRC = REPLACE(IFRAME_SRC,'#//','#/') WHERE APP_ID='<APP>';
踩过的坑¶
- ❌ path 带
/:旧系统 path 存的是路由,本系统要求无/,必须清洗 - ❌ IFRAME_SRC 双斜杠:
BASE结尾有#时拼接 route 易产生#//,要#/ - ❌ DELETE 误删旧数据:导入前
DELETE WHERE APP_ID='xxx'会连手工配的老记录一起删,注意保留原始记录 - ❌ ID 冲突:雪花ID计数器起点每次换一批,避免撞已有数据
- ❌ shell 脚本
UID变量:bash 里UID是只读系统变量,赋值会报错;用 Python 无此问题
附录:对方菜单 JSON 格式样例¶
{
"code": 200,
"data": [
{
"id": 6113,
"parent_id": 0,
"name": "示例菜单",
"code": "home",
"icon": "HomeFilled",
"route": "/home/index",
"is_hidden": 0,
"sort": 70,
"children": []
}
]
}
- 根菜单:
parent_id=0 - 子菜单:
parent_id= 父菜单的id,出现在父菜单的children数组里 is_hidden: 1表示隐藏页(详情页等),导入时is_hide=1
相关笔记¶
- 相关技能:
tools/skills/agent-watch.md