This commit is contained in:
2025-08-28 00:55:35 +08:00
commit 410f54a65e
93 changed files with 9863 additions and 0 deletions

443
scripts/setup_demo.sh Executable file
View File

@ -0,0 +1,443 @@
#!/usr/bin/env bash
set -euo pipefail
API="http://127.0.0.1:8080/api"
extract_id() { sed -n -E 's/.*"id":([0-9]+).*/\1/p'; }
# 使用变量承载 JSON避免直接使用管道导致的 broken pipe
get_menu_id_by_parent_and_path(){
local parent_id="$1"; local path="$2"
local MENUS
MENUS=$(curl -s -X GET "$API/menus" -H "$H_AUTH")
echo "$MENUS" | P="$path" PID="$parent_id" python3 - <<'PY'
import json,sys,os
try:
data=json.load(sys.stdin)
except Exception:
sys.exit(0)
menus=data.get("data", [])
P=os.environ.get("P")
PID=os.environ.get("PID")
try:
pid_int=None if PID in (None, "", "null") else int(PID)
except Exception:
pid_int=None
for m in menus:
if m.get("path")==P and ((pid_int is None and m.get("parent_id") is None) or (pid_int is not None and m.get("parent_id")==pid_int)):
print(m.get("id"), end="")
break
PY
}
get_menu_id_by_parent_and_name(){
local parent_id="$1"; local name="$2"
local MENUS
MENUS=$(curl -s -X GET "$API/menus" -H "$H_AUTH")
echo "$MENUS" | N="$name" PID="$parent_id" python3 - <<'PY'
import json,sys,os
try:
data=json.load(sys.stdin)
except Exception:
sys.exit(0)
menus=data.get("data", [])
N=os.environ.get("N")
PID=os.environ.get("PID")
try:
pid_int=None if PID in (None, "", "null") else int(PID)
except Exception:
pid_int=None
for m in menus:
if m.get("name")==N and ((pid_int is None and m.get("parent_id") is None) or (pid_int is not None and m.get("parent_id")==pid_int)):
print(m.get("id"), end="")
break
PY
}
create_or_get_menu(){
# parent_id name type path component icon order_no [visible] [status] [keep_alive]
local parent_id="$1"; local name="$2"; local mtype="$3"; local path="$4"; local component="$5"; local icon="$6"; local order_no="$7"; local visible="${8:-true}"; local status="${9:-1}"; local keep_alive="${10:-true}"
local id=""
if [ -n "$path" ]; then id=$(get_menu_id_by_parent_and_path "$parent_id" "$path") || true; fi
if [ -z "$id" ]; then id=$(get_menu_id_by_parent_and_name "$parent_id" "$name") || true; fi
if [ -n "$id" ]; then echo "$id"; return 0; fi
# 规范化可选字段为 JSON 合法值
local j_parent j_path j_comp j_icon j_order
if [ -n "${parent_id:-}" ]; then j_parent="$parent_id"; else j_parent="null"; fi
if [ -n "${path:-}" ]; then j_path="\"$path\""; else j_path="null"; fi
if [ -n "${component:-}" ]; then j_comp="\"$component\""; else j_comp="null"; fi
if [ -n "${icon:-}" ]; then j_icon="\"$icon\""; else j_icon="null"; fi
j_order="${order_no:-0}"
local payload
payload=$(cat <<JSON
{"parent_id":$j_parent,"name":"$name","path":$j_path,"component":$j_comp,"type":$mtype,"icon":$j_icon,"order_no":$j_order,"visible":$visible,"status":$status,"keep_alive":$keep_alive}
JSON
)
local resp; resp=$(echo "$payload" | curl -s -X POST "$API/menus" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
id=$(echo "$resp" | extract_id)
echo "$id"
}
# 1) Admin login
LOGIN_JSON=$(printf '{"username":"admin","password":"Admin@123"}' | curl -s -X POST "$API/auth/login" -H "Content-Type: application/json" --data-binary @-)
TOKEN=$(echo "$LOGIN_JSON" | sed -n -E 's/.*"access_token":"([^"]*)".*/\1/p')
if [ -z "$TOKEN" ]; then echo "[ERROR] Admin 登录失败: $LOGIN_JSON"; exit 1; fi
H_AUTH="Authorization: Bearer $TOKEN"
echo "[OK] Admin 登录成功"
# 1b) 去重清理:仅保留最早创建的根菜单,删除其余重复的根及子树
cleanup_duplicate_roots(){
local ROOT_NAME="$1"; local ROOT_TYPE="$2"
local MENUS JSON
MENUS=$(curl -s -X GET "$API/menus" -H "$H_AUTH")
# 计算应保留的 root_id 与需要删除的 root_ids
JSON=$(echo "$MENUS" | NAME="$ROOT_NAME" RTYPE="$ROOT_TYPE" python3 - <<'PY'
import json,sys,os
try:
data=json.load(sys.stdin)
menus=data.get("data", [])
except Exception:
menus=[]
NAME=os.environ.get("NAME")
RTYPE=int(os.environ.get("RTYPE") or 0)
roots=[m for m in menus if m.get("name")==NAME and m.get("parent_id") is None and m.get("type")==RTYPE]
roots=sorted(roots, key=lambda m: m.get("id") or 1<<30)
keep_id=str(roots[0].get("id")) if roots else ""
duplicates=[str(m.get("id")) for m in roots[1:]]
# 构建子树映射
children={}
for m in menus:
pid=m.get("parent_id")
if pid is None: continue
children.setdefault(str(pid), []).append(str(m.get("id")))
# 计算每个重复根的删除顺序(自底向上)
orders={}
from collections import deque
for rid in duplicates:
order=[]
# BFS 收集所有节点
q=deque([rid])
seen=set()
while q:
x=q.popleft()
if x in seen: continue
seen.add(x)
for c in children.get(x, []):
q.append(c)
order.append(x)
# 逆序删除(叶 -> 根)
orders[rid]=list(reversed(order))
print(json.dumps({"keep": keep_id, "dups": duplicates, "orders": orders}))
PY
)
local KEEP_ID; KEEP_ID=$(echo "$JSON" | sed -n -E 's/.*"keep":"?([0-9]+)"?.*/\1/p')
local DUPS; DUPS=$(echo "$JSON" | sed -n -E 's/.*"dups":\[([^\]]*)\].*/\1/p' | tr -d '" ')
if [ -n "${DUPS:-}" ]; then
echo "[INFO] 发现重复根菜单: $ROOT_NAME (type=$ROOT_TYPE)保留ID=$KEEP_ID,待清理: [$DUPS]"
# 逐个根依次删除其子树
for rid in $(echo "$DUPS" | tr ',' ' '); do
local ORDER; ORDER=$(echo "$JSON" | RID="$rid" python3 - <<'PY'
import json,sys,os
obj=json.load(sys.stdin)
rid=os.environ.get("RID")
print(",".join(obj.get("orders", {}).get(rid, [])), end="")
PY
)
for id in $(echo "$ORDER" | tr ',' ' '); do
# 逐个删除(叶优先),失败重试一次
RES=$(curl -s -X DELETE "$API/menus/$id" -H "$H_AUTH" || true)
echo "$RES" | grep -q '"code":0' || {
sleep 0.2
RES=$(curl -s -X DELETE "$API/menus/$id" -H "$H_AUTH" || true)
echo "$RES" | grep -q '"code":0' || echo "[WARN] 删除菜单失败(id=$id): $RES"
}
done
done
echo "[OK] 已清理 $ROOT_NAME 重复根菜单"
fi
}
# 如数据库已存在相同根菜单,先做去重清理
cleanup_duplicate_roots "演示-系统管理" 0 || true
cleanup_duplicate_roots "系统管理" 1 || true
# 2) Create demo menus可通过环境变量 SKIP_DEMO=1 跳过)
if [ "${SKIP_DEMO:-0}" != "1" ]; then
# 幂等:优先查找已存在的“演示-系统管理”,否则创建(基于 Python 解析)
MENUS_JSON=$(curl -s -X GET "$API/menus" -H "$H_AUTH")
DEMO_ROOT_ID=$(echo "$MENUS_JSON" | python3 - <<'PY'
import json,sys
try:
data=json.load(sys.stdin)
menus=data.get("data", [])
except Exception:
menus=[]
for m in menus:
if m.get("name")=="演示-系统管理" and m.get("type")==0 and m.get("parent_id") is None:
print(m.get("id"), end="")
break
PY
)
if [ -z "${DEMO_ROOT_ID:-}" ]; then
DEMO_ROOT_JSON=$(printf '{"name":"演示-系统管理","type":0,"order_no":100,"visible":true,"status":1}' | curl -s -X POST "$API/menus" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
DEMO_ROOT_ID=$(echo "$DEMO_ROOT_JSON" | extract_id)
fi
if [ -z "${DEMO_ROOT_ID:-}" ]; then echo "[ERROR] 创建/获取 演示-系统管理 根菜单失败"; exit 1; fi
USERS_ID=$(create_or_get_menu "$DEMO_ROOT_ID" "演示-用户管理" 1 "/demo/users" "Users" "" 10)
ROLES_ID=$(create_or_get_menu "$DEMO_ROOT_ID" "演示-角色管理" 1 "/demo/roles" "Roles" "" 20)
MENUS_ID=$(create_or_get_menu "$DEMO_ROOT_ID" "演示-菜单管理" 1 "/demo/menus" "Menus" "" 30)
PERMS_ID=$(create_or_get_menu "$DEMO_ROOT_ID" "演示-权限管理" 1 "/demo/perms" "Permissions" "" 40)
DEPT_ID=$(create_or_get_menu "$DEMO_ROOT_ID" "演示-部门管理" 1 "/demo/departments" "Departments" "" 50)
POS_ID=$(create_or_get_menu "$DEMO_ROOT_ID" "演示-岗位管理" 1 "/demo/positions" "Positions" "" 60)
echo "[OK] 演示菜单准备完成: ROOT=$DEMO_ROOT_ID USERS=$USERS_ID ROLES=$ROLES_ID MENUS=$MENUS_ID PERMS=$PERMS_ID DEPT=$DEPT_ID POS=$POS_ID"
else
echo "[INFO] 已设置 SKIP_DEMO=1跳过演示菜单创建"
fi
# [INFO] 演示菜单已通过幂等逻辑创建/获取,避免重复
# 3) Create demo role
TS=$(date +%s)
ROLE_NAME="演示-经理-${TS}"
ROLE_CODE="demo_manager_${TS}"
ROLE_JSON=$(printf '{"name":"%s","code":"%s","status":1}' "$ROLE_NAME" "$ROLE_CODE" | curl -s -X POST "$API/roles" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
ROLE_ID=$(echo "$ROLE_JSON" | extract_id); if [ -z "$ROLE_ID" ]; then echo "[ERROR] 创建角色失败: $ROLE_JSON"; exit 1; fi
echo "[OK] 创建角色成功: $ROLE_NAME (id=$ROLE_ID)"
# 4) Bind menus to the role
IDS=""
for v in "${USERS_ID:-}" "${ROLES_ID:-}" "${MENUS_ID:-}" "${PERMS_ID:-}" "${DEPT_ID:-}" "${POS_ID:-}"; do
if [ -n "$v" ]; then
if [ -n "$IDS" ]; then IDS="$IDS,$v"; else IDS="$v"; fi
fi
done
if [ -n "$IDS" ]; then
BIND_MENU_JSON=$(printf '{"ids":[%s]}' "$IDS" | curl -s -X PUT "$API/roles/$ROLE_ID/menus" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
echo "$BIND_MENU_JSON" | grep -q '"code":0' || { echo "[ERROR] 绑定角色菜单失败: $BIND_MENU_JSON"; exit 1; }
echo "[OK] 绑定角色菜单成功"
else
echo "[WARN] 无可绑定的演示菜单,跳过绑定"
fi
# 5) Create a user and bind the role
USER_NAME="alice_${TS}"
USER_PASS="Password@123"
USER_JSON=$(printf '{"username":"%s","password":"%s","nickname":"Alice","status":1}' "$USER_NAME" "$USER_PASS" | curl -s -X POST "$API/users" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
USER_ID=$(echo "$USER_JSON" | extract_id); if [ -z "$USER_ID" ]; then echo "[ERROR] 创建用户失败: $USER_JSON"; exit 1; fi
echo "[OK] 创建用户成功: $USER_NAME (id=$USER_ID)"
BIND_ROLE_JSON=$(printf '{"ids":[%s]}' "$ROLE_ID" | curl -s -X PUT "$API/users/$USER_ID/roles" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
echo "$BIND_ROLE_JSON" | grep -q '"code":0' || { echo "[ERROR] 绑定用户角色失败: $BIND_ROLE_JSON"; exit 1; }
echo "[OK] 绑定用户角色成功"
# 5b) Bind demo role to admin and verify menus
ADMIN_JSON=$(curl -s -X GET "$API/users?page=1&page_size=50&keyword=admin" -H "$H_AUTH")
ADMIN_ID=$(echo "$ADMIN_JSON" | sed -n -E 's/.*"id":([0-9]+).*"username":"admin".*/\1/p')
if [ -z "$ADMIN_ID" ]; then
echo "[WARN] 未找到 admin 用户ID"
else
BIND_ADMIN_JSON=$(printf '{"ids":[%s]}' "$ROLE_ID" | curl -s -X PUT "$API/users/$ADMIN_ID/roles" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
echo "$BIND_ADMIN_JSON" | grep -q '"code":0' && echo "[OK] 已为 admin 绑定演示角色(id=$ROLE_ID)" || echo "[WARN] 为 admin 绑定角色可能失败: $BIND_ADMIN_JSON"
MENUS_ADMIN=$(curl -s -X GET "$API/auth/menus" -H "$H_AUTH")
echo "[RESULT] Admin 可见菜单响应: $MENUS_ADMIN"
fi
# 6) Login as new user and fetch menus
LOGIN2_JSON=$(printf '{"username":"%s","password":"%s"}' "$USER_NAME" "$USER_PASS" | curl -s -X POST "$API/auth/login" -H "Content-Type: application/json" --data-binary @-)
TOKEN2=$(echo "$LOGIN2_JSON" | sed -n -E 's/.*"access_token":"([^\"]*)".*/\1/p')
if [ -z "$TOKEN2" ]; then echo "[ERROR] 新用户登录失败: $LOGIN2_JSON"; exit 1; fi
MENUS2=$(curl -s -X GET "$API/auth/menus" -H "Authorization: Bearer $TOKEN2")
echo "[RESULT] 新用户可见菜单响应: $MENUS2"
# 7) Check permissions and seed defaults if empty
PERMS_LIST=$(curl -s -X GET "$API/permissions?page=1&page_size=100" -H "$H_AUTH") || true
PERMS_TOTAL=$(echo "$PERMS_LIST" | sed -n -E 's/.*"total":([0-9]+).*/\1/p') || true
[ -z "${PERMS_TOTAL:-}" ] && PERMS_TOTAL=0
echo "[RESULT] 当前权限总数: $PERMS_TOTAL"
if [ "$PERMS_TOTAL" = "0" ]; then
echo "[INFO] 权限为空,开始初始化默认权限"
curl -s -X POST "$API/permissions" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary '{"code":"users:view","name":"用户查看","description":"查看用户"}' >/dev/null || true
curl -s -X POST "$API/permissions" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary '{"code":"users:edit","name":"用户编辑","description":"编辑用户"}' >/dev/null || true
curl -s -X POST "$API/permissions" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary '{"code":"roles:view","name":"角色查看","description":"查看角色"}' >/dev/null || true
curl -s -X POST "$API/permissions" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary '{"code":"roles:edit","name":"角色编辑","description":"编辑角色"}' >/dev/null || true
curl -s -X POST "$API/permissions" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary '{"code":"menus:view","name":"菜单查看","description":"查看菜单"}' >/dev/null || true
curl -s -X POST "$API/permissions" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary '{"code":"menus:edit","name":"菜单编辑","description":"编辑菜单"}' >/dev/null || true
curl -s -X POST "$API/permissions" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary '{"code":"permissions:view","name":"权限查看","description":"查看权限"}' >/dev/null || true
curl -s -X POST "$API/permissions" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary '{"code":"permissions:edit","name":"权限编辑","description":"编辑权限"}' >/dev/null || true
curl -s -X POST "$API/permissions" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary '{"code":"departments:view","name":"部门查看","description":"查看部门"}' >/dev/null || true
curl -s -X POST "$API/permissions" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary '{"code":"departments:edit","name":"部门编辑","description":"编辑部门"}' >/dev/null || true
PERMS_LIST=$(curl -s -X GET "$API/permissions?page=1&page_size=100" -H "$H_AUTH") || true
PERMS_TOTAL=$(echo "$PERMS_LIST" | sed -n -E 's/.*"total":([0-9]+).*/\1/p') || true
[ -z "${PERMS_TOTAL:-}" ] && PERMS_TOTAL=0
echo "[RESULT] 初始化后权限总数: $PERMS_TOTAL"
fi
echo "[SUMMARY] DEMO_ROOT=${DEMO_ROOT_ID:-} USERS=${USERS_ID:-} ROLES=${ROLES_ID:-} MENUS=${MENUS_ID:-} PERMS=${PERMS_ID:-} ROLE=$ROLE_ID USER=$USER_ID USERNAME=$USER_NAME"
# 8) Seed formal "系统管理" menus and Super Admin role
# 获取或创建 系统管理 根菜单:查找时不依赖字段顺序
MENUS_JSON=$(curl -s -X GET "$API/menus" -H "$H_AUTH")
SYS_ROOT_ID=$(echo "$MENUS_JSON" | python3 - <<'PY'
import json,sys
try:
data=json.load(sys.stdin)
menus=data.get("data", [])
except Exception:
menus=[]
for m in menus:
if m.get("name")=="系统管理" and m.get("type")==1 and m.get("parent_id") is None:
print(m.get("id"), end="")
break
PY
)
if [ -z "${SYS_ROOT_ID:-}" ]; then
SYS_ROOT_JSON=$(printf '{"name":"系统管理","type":1,"icon":"SettingOutlined","order_no":10,"visible":true,"status":1}' | curl -s -X POST "$API/menus" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
SYS_ROOT_ID=$(echo "$SYS_ROOT_JSON" | extract_id)
fi
if [ -z "${SYS_ROOT_ID:-}" ]; then echo "[ERROR] 创建/获取 系统管理 根菜单失败"; exit 1; fi
# helper to create child menu under 系统管理
create_menu_under_sys(){
local name="$1"; local path="$2"; local component="$3"; local icon="$4"; local order_no="$5"
local id
id=$(get_menu_id_by_parent_and_path "$SYS_ROOT_ID" "$path") || true
if [ -z "$id" ]; then id=$(get_menu_id_by_parent_and_name "$SYS_ROOT_ID" "$name") || true; fi
if [ -n "$id" ]; then echo "$id"; return 0; fi
id=$(create_or_get_menu "$SYS_ROOT_ID" "$name" 1 "$path" "$component" "$icon" "$order_no")
echo "$id"
}
USERS2_ID=$(create_menu_under_sys "用户管理" "/users" "Users" "UserOutlined" 20); [ -z "$USERS2_ID" ] && echo "[WARN] 用户管理 菜单ID获取失败"
ROLES2_ID=$(create_menu_under_sys "角色管理" "/roles" "Roles" "TeamOutlined" 30); [ -z "$ROLES2_ID" ] && echo "[WARN] 角色管理 菜单ID获取失败"
MENUS2_ID=$(create_menu_under_sys "菜单管理" "/menus" "Menus" "AppstoreOutlined" 40); [ -z "$MENUS2_ID" ] && echo "[WARN] 菜单管理 菜单ID获取失败"
PERMS2_ID=$(create_menu_under_sys "权限管理" "/permissions" "Permissions" "KeyOutlined" 50); [ -z "$PERMS2_ID" ] && echo "[WARN] 权限管理 菜单ID获取失败"
DEPTS2_ID=$(create_menu_under_sys "部门管理" "/departments" "Departments" "AppstoreOutlined" 60); [ -z "$DEPTS2_ID" ] && echo "[WARN] 部门管理 菜单ID获取失败"
POSITIONS2_ID=$(create_menu_under_sys "岗位管理" "/positions" "Positions" "IdcardOutlined" 65); [ -z "$POSITIONS2_ID" ] && echo "[WARN] 岗位管理 菜单ID获取失败"
echo "[OK] 正式系统菜单准备完成: ROOT=$SYS_ROOT_ID USERS=$USERS2_ID ROLES=$ROLES2_ID MENUS=$MENUS2_ID PERMS=$PERMS2_ID DEPTS=$DEPTS2_ID POSITIONS=$POSITIONS2_ID"
# 工具函数:根据 parent_id + perms 查找或创建按钮菜单(使用 Python 解析)
create_or_get_button(){
local parent_id="$1"; local name="$2"; local perms="$3"; local order_no="${4:-0}"
local id MENUS
MENUS=$(curl -s -X GET "$API/menus" -H "$H_AUTH")
id=$(echo "$MENUS" | PERM="$perms" PID="$parent_id" python3 - <<'PY'
import json,sys,os
try:
data=json.load(sys.stdin)
menus=data.get("data", [])
except Exception:
menus=[]
PERM=os.environ.get("PERM")
PID=os.environ.get("PID")
pid_int=None
try:
pid_int=int(PID)
except Exception:
pass
for m in menus:
if m.get("type")==3 and m.get("perms")==PERM and m.get("parent_id")==pid_int:
print(m.get("id"), end="")
break
PY
) || true
if [ -n "$id" ]; then echo "$id"; return 0; fi
local resp; resp=$(printf '{"parent_id":%s,"name":"%s","type":3,"order_no":%s,"visible":false,"status":1,"keep_alive":false,"perms":"%s"}' \
"$parent_id" "$name" "${order_no:-0}" "$perms" | curl -s -X POST "$API/menus" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
id=$(echo "$resp" | extract_id)
echo "$id"
}
# 为系统管理下添加按钮权限(幂等)
[ -n "${USERS2_ID:-}" ] && {
create_or_get_button "$USERS2_ID" "新增" "system:user:create" 10 >/dev/null || true
create_or_get_button "$USERS2_ID" "编辑" "system:user:update" 20 >/dev/null || true
create_or_get_button "$USERS2_ID" "重置密码" "system:user:reset" 30 >/dev/null || true
create_or_get_button "$USERS2_ID" "删除" "system:user:delete" 40 >/dev/null || true
create_or_get_button "$USERS2_ID" "分配岗位" "system:user:assignPosition" 50 >/dev/null || true
}
[ -n "${ROLES2_ID:-}" ] && {
create_or_get_button "$ROLES2_ID" "新增" "system:role:create" 10 >/dev/null || true
create_or_get_button "$ROLES2_ID" "编辑" "system:role:update" 20 >/dev/null || true
create_or_get_button "$ROLES2_ID" "分配菜单" "system:role:assign" 30 >/dev/null || true
create_or_get_button "$ROLES2_ID" "删除" "system:role:delete" 40 >/dev/null || true
}
[ -n "${MENUS2_ID:-}" ] && {
create_or_get_button "$MENUS2_ID" "新增" "system:menu:create" 10 >/dev/null || true
create_or_get_button "$MENUS2_ID" "编辑" "system:menu:update" 20 >/dev/null || true
create_or_get_button "$MENUS2_ID" "删除" "system:menu:delete" 30 >/dev/null || true
}
[ -n "${POSITIONS2_ID:-}" ] && {
create_or_get_button "$POSITIONS2_ID" "新增" "system:position:create" 10 >/dev/null || true
create_or_get_button "$POSITIONS2_ID" "编辑" "system:position:update" 20 >/dev/null || true
create_or_get_button "$POSITIONS2_ID" "删除" "system:position:delete" 30 >/dev/null || true
}
# 9) Create Super Admin role if not exists (code=super_admin)
SUPER_JSON=$(curl -s -X GET "$API/roles?page=1&page_size=100&keyword=super_admin" -H "$H_AUTH")
SUPER_ROLE_ID=$(echo "$SUPER_JSON" | sed -n -E 's/.*"id":([0-9]+).*"code":"super_admin".*/\1/p')
if [ -z "${SUPER_ROLE_ID:-}" ]; then
SUPER_CREATE_JSON=$(printf '{"name":"超级管理员","code":"super_admin","status":1}' | curl -s -X POST "$API/roles" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
SUPER_ROLE_ID=$(echo "$SUPER_CREATE_JSON" | extract_id)
fi
if [ -z "${SUPER_ROLE_ID:-}" ]; then echo "[ERROR] 创建/获取 超级管理员 角色失败"; exit 1; fi
echo "[OK] 超级管理员 角色ID=$SUPER_ROLE_ID"
# 10) Bind ALL menus to Super Admin (幂等)
ALL_MENU_IDS=$(curl -s -X GET "$API/menus" -H "$H_AUTH" | python3 - <<'PY'
import json,sys
try:
data=json.load(sys.stdin)
menus=data.get("data", [])
except Exception:
menus=[]
ids=[str(m.get("id")) for m in menus if isinstance(m.get("id"), int)]
print(",".join(ids), end="")
PY
)
BIND_SUPER_JSON=$(printf '{"ids":[%s]}' "$ALL_MENU_IDS" | curl -s -X PUT "$API/roles/$SUPER_ROLE_ID/menus" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
echo "$BIND_SUPER_JSON" | grep -q '"code":0' || { echo "[ERROR] 绑定全部菜单到 超级管理员 失败: $BIND_SUPER_JSON"; exit 1; }
echo "[OK] 已将全部菜单绑定到 超级管理员 角色"
# 11) Assign Super Admin role to admin (保留演示角色)
if [ -z "${ADMIN_ID:-}" ]; then
ADMIN_JSON=$(curl -s -X GET "$API/users?page=1&page_size=50&keyword=admin" -H "$H_AUTH")
ADMIN_ID=$(echo "$ADMIN_JSON" | sed -n -E 's/.*"id":([0-9]+).*"username":"admin".*/\1/p')
fi
if [ -n "${ADMIN_ID:-}" ]; then
CUR_ROLES_JSON=$(curl -s -X GET "$API/users/$ADMIN_ID/roles" -H "$H_AUTH")
NEW_ROLE_IDS=$(echo "$CUR_ROLES_JSON" | SUPER_ROLE_ID="$SUPER_ROLE_ID" python3 -c 'import json,sys,os
try:
data=json.load(sys.stdin)
except Exception:
data={}
ids=[]
for it in data.get("data", []):
try:
i=int(it.get("id"))
s=str(i)
if s not in ids:
ids.append(s)
except Exception:
pass
sid=os.environ.get("SUPER_ROLE_ID")
if sid and sid not in ids:
ids.append(sid)
print("".join([",".join(ids)]), end="")')
if [ -z "$NEW_ROLE_IDS" ]; then NEW_ROLE_IDS="$SUPER_ROLE_ID"; fi
ASSIGN_ADMIN_JSON=$(printf '{"ids":[%s]}' "$NEW_ROLE_IDS" | curl -s -X PUT "$API/users/$ADMIN_ID/roles" -H "$H_AUTH" -H "Content-Type: application/json" --data-binary @-)
echo "$ASSIGN_ADMIN_JSON" | grep -q '"code":0' && echo "[OK] 已为 admin 分配 超级管理员 角色(id=$SUPER_ROLE_ID) 合并现有角色: [$NEW_ROLE_IDS]" || echo "[WARN] 为 admin 分配 超级管理员 可能失败: $ASSIGN_ADMIN_JSON"
MENUS_ADMIN2=$(curl -s -X GET "$API/auth/menus" -H "$H_AUTH")
echo "[RESULT] Admin 可见菜单(包含正式菜单): $MENUS_ADMIN2"
else
echo "[WARN] 未能获取 admin 用户ID跳过角色分配"
fi
echo "[SUMMARY] DEMO_ROOT=${DEMO_ROOT_ID:-} USERS=${USERS_ID:-} ROLES=${ROLES_ID:-} MENUS=${MENUS_ID:-} PERMS=${PERMS_ID:-}"