Files
shanxia2.0/backend/scripts/refresh_business_role_menus.py
T
2026-07-13 20:26:43 +08:00

116 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""仅刷新 5 个业务角色的菜单授权(不删角色、不动用户绑定)。
用于修复「角色只勾 F 按钮、缺少 C 页面 :list」导致前端侧栏为空的问题。
用法:
cd backend && ./venv/bin/python scripts/refresh_business_role_menus.py --env-file .env.production
./venv/bin/python scripts/refresh_business_role_menus.py --dry-run --env-file .env.production
"""
from __future__ import annotations
import argparse
import os
import sys
from datetime import datetime
from pathlib import Path
from sqlalchemy import create_engine, text
BACKEND_ROOT = Path(__file__).resolve().parents[1]
if str(BACKEND_ROOT) not in sys.path:
sys.path.insert(0, str(BACKEND_ROOT))
from scripts.setup_business_roles import ( # noqa: E402
MODULE_MENU_ROOTS,
NEW_ROLES,
TENANT_NO,
collect_subtree_menu_ids,
grant_module_menus,
perm_menu_ids,
)
def load_settings_env(env_file: str) -> None:
if env_file:
os.environ["ENV_FILE"] = env_file
from dotenv import load_dotenv
path = Path(env_file) if env_file else BACKEND_ROOT / ".env.production"
if not path.is_absolute():
path = BACKEND_ROOT / path
if path.is_file():
load_dotenv(path, override=True)
def load_runtime_settings():
from app.core.config import Settings
return Settings()
def verify_user_menu_codes(engine, user_no: str) -> None:
from sqlalchemy.orm import Session
from app.services.web_auth_roles import iter_user_menu_perm_codes
with Session(engine) as db:
row = db.execute(
text(
"""
SELECT id FROM sys_user
WHERE tenant_no = :tenant AND user_no = :user_no AND del_flag = 0
LIMIT 1
"""
),
{"tenant": TENANT_NO, "user_no": user_no},
).first()
if not row:
print(f" [verify] 用户不存在: {user_no}")
return
uid = str(row[0])
codes = sorted(iter_user_menu_perm_codes(db, uid, TENANT_NO))
list_codes = [c for c in codes if c.endswith(":list")]
print(f" [verify] {user_no}: 共 {len(codes)} 个 perms,其中 :list {len(list_codes)} 个")
if list_codes:
print(f" 示例: {', '.join(list_codes[:5])}...")
else:
print(" 警告: 无任何 :list 权限,前端侧栏仍会为空")
def main() -> int:
parser = argparse.ArgumentParser(description="刷新业务角色菜单授权")
parser.add_argument("--env-file", default=".env.production")
parser.add_argument("--dry-run", action="store_true")
parser.add_argument("--verify-user", default="方金强", help="刷新后校验该用户的 menuCodes")
args = parser.parse_args()
load_settings_env(args.env_file)
settings = load_runtime_settings()
engine = create_engine(settings.DATABASE_URL, pool_pre_ping=True)
print("=== refresh_business_role_menus ===")
print(f"模式: {'DRY-RUN' if args.dry_run else 'EXECUTE'}")
print(f"租户: {TENANT_NO}")
print()
with engine.begin() as conn:
subtree = collect_subtree_menu_ids(conn, MODULE_MENU_ROOTS, TENANT_NO)
grant_ids = perm_menu_ids(conn, subtree, TENANT_NO)
print(f"模块子树 {len(subtree)} 项,带 perms 菜单 {len(grant_ids)} 项")
for role_name, role_id in NEW_ROLES.items():
cnt = grant_module_menus(conn, role_id, grant_ids, TENANT_NO, args.dry_run)
print(f" {role_name}: {cnt} 项")
if not args.dry_run and args.verify_user:
print()
print("校验 menuCodes:")
verify_user_menu_codes(engine, args.verify_user)
print("完成.")
return 0
if __name__ == "__main__":
raise SystemExit(main())