chenkun vor 1 Monat
Ursprung
Commit
2bdaa79c15
48 geänderte Dateien mit 6157 neuen und 6 gelöschten Zeilen
  1. 370 0
      create_rbac_tables.py
  2. 72 0
      drop_rbac_tables.py
  3. 1328 6
      full_server.py
  4. 0 0
      net
  5. 562 0
      rbac_api.py
  6. 1183 0
      reinit_menus_by_requirements.py
  7. 852 0
      reinit_rbac_data.py
  8. 1002 0
      reinit_rbac_data_fixed.py
  9. BIN
      src/app/__pycache__/__init__.cpython-311.pyc
  10. BIN
      src/app/__pycache__/main.cpython-311.pyc
  11. BIN
      src/app/api/__pycache__/__init__.cpython-311.pyc
  12. BIN
      src/app/api/v1/__pycache__/__init__.cpython-311.pyc
  13. BIN
      src/app/api/v1/__pycache__/api_router.cpython-311.pyc
  14. BIN
      src/app/api/v1/auth/__pycache__/__init__.cpython-311.pyc
  15. BIN
      src/app/api/v1/auth/__pycache__/endpoints.cpython-311.pyc
  16. BIN
      src/app/api/v1/auth/__pycache__/router.cpython-311.pyc
  17. BIN
      src/app/api/v1/oauth/__pycache__/__init__.cpython-311.pyc
  18. BIN
      src/app/api/v1/oauth/__pycache__/endpoints.cpython-311.pyc
  19. BIN
      src/app/api/v1/oauth/__pycache__/router.cpython-311.pyc
  20. BIN
      src/app/config/__pycache__/__init__.cpython-311.pyc
  21. BIN
      src/app/config/__pycache__/database.cpython-311.pyc
  22. BIN
      src/app/config/__pycache__/simple_settings.cpython-311.pyc
  23. BIN
      src/app/core/__pycache__/__init__.cpython-311.pyc
  24. BIN
      src/app/core/__pycache__/exceptions.cpython-311.pyc
  25. BIN
      src/app/models/__pycache__/__init__.cpython-311.pyc
  26. BIN
      src/app/models/__pycache__/app.cpython-311.pyc
  27. BIN
      src/app/models/__pycache__/base.cpython-311.pyc
  28. BIN
      src/app/models/__pycache__/log.cpython-311.pyc
  29. BIN
      src/app/models/__pycache__/token.cpython-311.pyc
  30. BIN
      src/app/models/__pycache__/user.cpython-311.pyc
  31. BIN
      src/app/schemas/__pycache__/__init__.cpython-311.pyc
  32. BIN
      src/app/schemas/__pycache__/auth.cpython-311.pyc
  33. BIN
      src/app/schemas/__pycache__/base.cpython-311.pyc
  34. BIN
      src/app/services/__pycache__/__init__.cpython-311.pyc
  35. BIN
      src/app/services/__pycache__/auth_service.cpython-311.pyc
  36. BIN
      src/app/services/__pycache__/oauth_service.cpython-311.pyc
  37. BIN
      src/app/utils/__pycache__/__init__.cpython-311.pyc
  38. BIN
      src/app/utils/__pycache__/security.cpython-311.pyc
  39. 101 0
      test_app_user_applications.py
  40. 61 0
      test_app_user_menus.py
  41. 87 0
      test_app_user_profile.py
  42. 106 0
      test_frontend_role_api.py
  43. 61 0
      test_regular_user_applications.py
  44. 53 0
      test_user_menus.py
  45. 116 0
      test_user_role_menus_api.py
  46. 60 0
      test_zhangsan_menus.py
  47. 143 0
      update_menu_structure.py
  48. 0 0
      update_menu_tree.py

+ 370 - 0
create_rbac_tables.py

@@ -0,0 +1,370 @@
+#!/usr/bin/env python3
+"""
+创建RBAC权限管理相关数据库表
+"""
+import pymysql
+from dotenv import load_dotenv
+import os
+
+load_dotenv()
+
+def get_db_connection():
+    """获取数据库连接"""
+    try:
+        config = {
+            'host': os.getenv('DB_HOST', 'localhost'),
+            'port': int(os.getenv('DB_PORT', 3306)),
+            'user': os.getenv('DB_USER', 'root'),
+            'password': os.getenv('DB_PASSWORD', 'admin'),
+            'database': os.getenv('DB_NAME', 'lq_db'),
+            'charset': 'utf8mb4',
+            'autocommit': True
+        }
+        return pymysql.connect(**config)
+    except Exception as e:
+        print(f"数据库连接失败: {e}")
+        return None
+
+def create_rbac_tables():
+    """创建RBAC权限管理表"""
+    print("🗄️ 创建RBAC权限管理表...")
+    print("=" * 60)
+    
+    conn = get_db_connection()
+    if not conn:
+        print("❌ 数据库连接失败")
+        return False
+    
+    cursor = conn.cursor()
+    
+    try:
+        # 1. 菜单表 - 存储系统菜单结构
+        print("📋 创建菜单表 (menus)...")
+        cursor.execute("""
+            CREATE TABLE IF NOT EXISTS menus (
+                id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
+                parent_id CHAR(36) NULL,
+                name VARCHAR(100) NOT NULL COMMENT '菜单名称',
+                title VARCHAR(100) NOT NULL COMMENT '菜单标题',
+                path VARCHAR(200) NULL COMMENT '菜单路径',
+                component VARCHAR(200) NULL COMMENT '组件路径',
+                icon VARCHAR(50) NULL COMMENT '菜单图标',
+                sort_order INT DEFAULT 0 COMMENT '排序顺序',
+                menu_type ENUM('menu', 'button') DEFAULT 'menu' COMMENT '菜单类型',
+                is_hidden BOOLEAN DEFAULT FALSE COMMENT '是否隐藏',
+                is_active BOOLEAN DEFAULT TRUE COMMENT '是否启用',
+                description TEXT NULL COMMENT '菜单描述',
+                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+                INDEX idx_parent_id (parent_id),
+                INDEX idx_path (path),
+                INDEX idx_sort_order (sort_order)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统菜单表'
+        """)
+        
+        # 2. 角色表 - 存储用户角色
+        print("👥 创建角色表 (roles)...")
+        cursor.execute("""
+            CREATE TABLE IF NOT EXISTS roles (
+                id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
+                name VARCHAR(50) NOT NULL UNIQUE COMMENT '角色名称',
+                display_name VARCHAR(100) NOT NULL COMMENT '角色显示名称',
+                description TEXT NULL COMMENT '角色描述',
+                is_active BOOLEAN DEFAULT TRUE COMMENT '是否启用',
+                is_system BOOLEAN DEFAULT FALSE COMMENT '是否系统角色',
+                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+                INDEX idx_name (name),
+                INDEX idx_is_active (is_active)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'
+        """)
+        
+        # 3. 权限表 - 存储系统权限
+        print("🔐 创建权限表 (permissions)...")
+        cursor.execute("""
+            CREATE TABLE IF NOT EXISTS permissions (
+                id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
+                name VARCHAR(100) NOT NULL UNIQUE COMMENT '权限名称',
+                display_name VARCHAR(100) NOT NULL COMMENT '权限显示名称',
+                resource VARCHAR(100) NOT NULL COMMENT '资源标识',
+                action VARCHAR(50) NOT NULL COMMENT '操作类型',
+                description TEXT NULL COMMENT '权限描述',
+                is_active BOOLEAN DEFAULT TRUE COMMENT '是否启用',
+                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+                INDEX idx_name (name),
+                INDEX idx_resource_action (resource, action),
+                UNIQUE KEY uk_resource_action (resource, action)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限表'
+        """)
+        
+        # 4. 角色菜单关联表 - 角色可访问的菜单
+        print("🔗 创建角色菜单关联表 (role_menus)...")
+        cursor.execute("""
+            CREATE TABLE IF NOT EXISTS role_menus (
+                id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
+                role_id CHAR(36) NOT NULL,
+                menu_id CHAR(36) NOT NULL,
+                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+                UNIQUE KEY uk_role_menu (role_id, menu_id),
+                INDEX idx_role_id (role_id),
+                INDEX idx_menu_id (menu_id)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色菜单关联表'
+        """)
+        
+        # 5. 角色权限关联表 - 角色拥有的权限
+        print("🔗 创建角色权限关联表 (role_permissions)...")
+        cursor.execute("""
+            CREATE TABLE IF NOT EXISTS role_permissions (
+                id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
+                role_id CHAR(36) NOT NULL,
+                permission_id CHAR(36) NOT NULL,
+                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+                UNIQUE KEY uk_role_permission (role_id, permission_id),
+                INDEX idx_role_id (role_id),
+                INDEX idx_permission_id (permission_id)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色权限关联表'
+        """)
+        
+        # 6. 用户角色关联表 - 用户拥有的角色
+        print("🔗 创建用户角色关联表 (user_roles)...")
+        cursor.execute("""
+            CREATE TABLE IF NOT EXISTS user_roles (
+                id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
+                user_id CHAR(36) NOT NULL,
+                role_id CHAR(36) NOT NULL,
+                assigned_by CHAR(36) NULL COMMENT '分配者ID',
+                assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+                expires_at TIMESTAMP NULL COMMENT '过期时间',
+                is_active BOOLEAN DEFAULT TRUE COMMENT '是否启用',
+                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+                UNIQUE KEY uk_user_role (user_id, role_id),
+                INDEX idx_user_id (user_id),
+                INDEX idx_role_id (role_id),
+                INDEX idx_expires_at (expires_at)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色关联表'
+        """)
+        
+        print("✅ 所有RBAC表创建成功")
+        
+        # 插入初始数据
+        print("\n📝 插入初始数据...")
+        insert_initial_data(cursor)
+        
+        conn.commit()
+        cursor.close()
+        conn.close()
+        
+        print("\n" + "=" * 60)
+        print("🎉 RBAC权限管理系统初始化完成!")
+        print("=" * 60)
+        
+        return True
+        
+    except Exception as e:
+        print(f"❌ 创建表失败: {e}")
+        conn.rollback()
+        cursor.close()
+        conn.close()
+        return False
+
+def insert_initial_data(cursor):
+    """插入初始数据"""
+    
+    # 1. 插入系统菜单
+    print("   📋 插入系统菜单...")
+    menus_data = [
+        # 主菜单
+        ('dashboard-menu', None, 'dashboard', '仪表盘', '/dashboard', 'dashboard/Index', 'House', 1, 'menu', False),
+        ('profile-menu', None, 'profile', '个人资料', '/profile', 'user/Profile', 'User', 2, 'menu', False),
+        ('admin-menu', None, 'admin', '系统管理', '/admin', None, 'Setting', 3, 'menu', False),
+        
+        # 系统管理子菜单
+        ('admin-dashboard-menu', 'admin-menu', 'admin-dashboard', '管理概览', '/admin/dashboard', 'admin/Dashboard', 'Monitor', 1, 'menu', False),
+        ('admin-users-menu', 'admin-menu', 'admin-users', '用户管理', '/admin/users', 'admin/Users', 'UserFilled', 2, 'menu', False),
+        ('admin-roles-menu', 'admin-menu', 'admin-roles', '角色管理', '/admin/roles', 'admin/Roles', 'Avatar', 3, 'menu', False),
+        ('admin-menus-menu', 'admin-menu', 'admin-menus', '菜单管理', '/admin/menus', 'admin/Menus', 'Menu', 4, 'menu', False),
+        ('admin-permissions-menu', 'admin-menu', 'admin-permissions', '权限管理', '/admin/permissions', 'admin/Permissions', 'Key', 5, 'menu', False),
+        ('admin-apps-menu', 'admin-menu', 'admin-apps', '应用管理', '/admin/apps', 'admin/Apps', 'Grid', 6, 'menu', False),
+        ('admin-logs-menu', 'admin-menu', 'admin-logs', '系统日志', '/admin/logs', 'admin/Logs', 'Document', 7, 'menu', False),
+        ('admin-settings-menu', 'admin-menu', 'admin-settings', '系统设置', '/admin/settings', 'admin/Settings', 'Tools', 8, 'menu', False),
+        
+        # 应用管理按钮权限
+        ('apps-create-btn', 'admin-apps-menu', 'apps-create', '创建应用', None, None, 'Plus', 1, 'button', False),
+        ('apps-edit-btn', 'admin-apps-menu', 'apps-edit', '编辑应用', None, None, 'Edit', 2, 'button', False),
+        ('apps-delete-btn', 'admin-apps-menu', 'apps-delete', '删除应用', None, None, 'Delete', 3, 'button', False),
+        ('apps-secret-btn', 'admin-apps-menu', 'apps-secret', '查看密钥', None, None, 'Key', 4, 'button', False),
+    ]
+    
+    # 先插入父菜单,再插入子菜单
+    menu_id_map = {}
+    
+    for menu_data in menus_data:
+        name, parent_name, key, title, path, component, icon, sort_order, menu_type, is_hidden = menu_data
+        parent_id = menu_id_map.get(parent_name) if parent_name else None
+        
+        cursor.execute("""
+            INSERT INTO menus (id, parent_id, name, title, path, component, icon, sort_order, menu_type, is_hidden)
+            VALUES (UUID(), %s, %s, %s, %s, %s, %s, %s, %s, %s)
+        """, (parent_id, key, title, path, component, icon, sort_order, menu_type, is_hidden))
+        
+        # 获取插入的菜单ID
+        cursor.execute("SELECT id FROM menus WHERE name = %s ORDER BY created_at DESC LIMIT 1", (key,))
+        menu_id = cursor.fetchone()[0]
+        menu_id_map[name] = menu_id
+    
+    # 2. 插入系统角色
+    print("   👥 插入系统角色...")
+    roles_data = [
+        ('super_admin', '超级管理员', '拥有系统所有权限的超级管理员', True, True),
+        ('admin', '管理员', '拥有大部分管理权限的管理员', True, True),
+        ('user_manager', '用户管理员', '负责用户管理的管理员', True, False),
+        ('app_manager', '应用管理员', '负责应用管理的管理员', True, False),
+        ('user', '普通用户', '系统普通用户', True, True),
+    ]
+    
+    role_id_map = {}
+    for role_data in roles_data:
+        name, display_name, description, is_active, is_system = role_data
+        cursor.execute("""
+            INSERT INTO roles (id, name, display_name, description, is_active, is_system)
+            VALUES (UUID(), %s, %s, %s, %s, %s)
+        """, (name, display_name, description, is_active, is_system))
+        
+        # 获取插入的角色ID
+        cursor.execute("SELECT id FROM roles WHERE name = %s", (name,))
+        role_id = cursor.fetchone()[0]
+        role_id_map[name] = role_id
+    
+    # 3. 插入系统权限
+    print("   🔐 插入系统权限...")
+    permissions_data = [
+        # 用户管理权限
+        ('user.view', '查看用户', 'user', 'view', '查看用户列表和详情'),
+        ('user.create', '创建用户', 'user', 'create', '创建新用户'),
+        ('user.edit', '编辑用户', 'user', 'edit', '编辑用户信息'),
+        ('user.delete', '删除用户', 'user', 'delete', '删除用户'),
+        ('user.assign_role', '分配角色', 'user', 'assign_role', '为用户分配角色'),
+        
+        # 角色管理权限
+        ('role.view', '查看角色', 'role', 'view', '查看角色列表和详情'),
+        ('role.create', '创建角色', 'role', 'create', '创建新角色'),
+        ('role.edit', '编辑角色', 'role', 'edit', '编辑角色信息'),
+        ('role.delete', '删除角色', 'role', 'delete', '删除角色'),
+        ('role.assign_permission', '分配权限', 'role', 'assign_permission', '为角色分配权限'),
+        
+        # 菜单管理权限
+        ('menu.view', '查看菜单', 'menu', 'view', '查看菜单列表和详情'),
+        ('menu.create', '创建菜单', 'menu', 'create', '创建新菜单'),
+        ('menu.edit', '编辑菜单', 'menu', 'edit', '编辑菜单信息'),
+        ('menu.delete', '删除菜单', 'menu', 'delete', '删除菜单'),
+        
+        # 应用管理权限
+        ('app.view', '查看应用', 'app', 'view', '查看应用列表和详情'),
+        ('app.create', '创建应用', 'app', 'create', '创建新应用'),
+        ('app.edit', '编辑应用', 'app', 'edit', '编辑应用信息'),
+        ('app.delete', '删除应用', 'app', 'delete', '删除应用'),
+        ('app.secret', '查看密钥', 'app', 'secret', '查看应用密钥'),
+        
+        # 系统管理权限
+        ('system.view', '查看系统', 'system', 'view', '查看系统信息'),
+        ('system.config', '系统配置', 'system', 'config', '修改系统配置'),
+        ('system.log', '查看日志', 'system', 'log', '查看系统日志'),
+    ]
+    
+    permission_id_map = {}
+    for perm_data in permissions_data:
+        name, display_name, resource, action, description = perm_data
+        cursor.execute("""
+            INSERT INTO permissions (id, name, display_name, resource, action, description)
+            VALUES (UUID(), %s, %s, %s, %s, %s)
+        """, (name, display_name, resource, action, description))
+        
+        # 获取插入的权限ID
+        cursor.execute("SELECT id FROM permissions WHERE name = %s", (name,))
+        permission_id = cursor.fetchone()[0]
+        permission_id_map[name] = permission_id
+    
+    # 4. 分配角色菜单权限
+    print("   🔗 分配角色菜单权限...")
+    
+    # 超级管理员 - 所有菜单
+    super_admin_id = role_id_map['super_admin']
+    cursor.execute("SELECT id FROM menus")
+    all_menu_ids = [row[0] for row in cursor.fetchall()]
+    
+    for menu_id in all_menu_ids:
+        cursor.execute("""
+            INSERT INTO role_menus (id, role_id, menu_id)
+            VALUES (UUID(), %s, %s)
+        """, (super_admin_id, menu_id))
+    
+    # 管理员 - 除了系统设置外的所有菜单
+    admin_id = role_id_map['admin']
+    cursor.execute("SELECT id FROM menus WHERE name != 'admin-settings'")
+    admin_menu_ids = [row[0] for row in cursor.fetchall()]
+    
+    for menu_id in admin_menu_ids:
+        cursor.execute("""
+            INSERT INTO role_menus (id, role_id, menu_id)
+            VALUES (UUID(), %s, %s)
+        """, (admin_id, menu_id))
+    
+    # 普通用户 - 基础菜单
+    user_id = role_id_map['user']
+    basic_menus = ['dashboard', 'profile', 'apps']
+    cursor.execute("SELECT id FROM menus WHERE name IN %s", (basic_menus,))
+    user_menu_ids = [row[0] for row in cursor.fetchall()]
+    
+    for menu_id in user_menu_ids:
+        cursor.execute("""
+            INSERT INTO role_menus (id, role_id, menu_id)
+            VALUES (UUID(), %s, %s)
+        """, (user_id, menu_id))
+    
+    # 5. 分配角色权限
+    print("   🔗 分配角色权限...")
+    
+    # 超级管理员 - 所有权限
+    for permission_id in permission_id_map.values():
+        cursor.execute("""
+            INSERT INTO role_permissions (id, role_id, permission_id)
+            VALUES (UUID(), %s, %s)
+        """, (super_admin_id, permission_id))
+    
+    # 管理员 - 除了系统配置外的权限
+    admin_permissions = [p for p in permission_id_map.keys() if not p.startswith('system.config')]
+    for perm_name in admin_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (id, role_id, permission_id)
+            VALUES (UUID(), %s, %s)
+        """, (admin_id, permission_id_map[perm_name]))
+    
+    # 普通用户 - 基础权限
+    user_permissions = ['app.view', 'app.create', 'app.edit', 'app.secret']
+    for perm_name in user_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (id, role_id, permission_id)
+            VALUES (UUID(), %s, %s)
+        """, (user_id, permission_id_map[perm_name]))
+    
+    # 6. 为现有admin用户分配超级管理员角色
+    print("   👤 为admin用户分配超级管理员角色...")
+    cursor.execute("SELECT id FROM users WHERE username = 'admin'")
+    admin_user = cursor.fetchone()
+    
+    if admin_user:
+        admin_user_id = admin_user[0]
+        cursor.execute("""
+            INSERT INTO user_roles (id, user_id, role_id, assigned_by)
+            VALUES (UUID(), %s, %s, %s)
+        """, (admin_user_id, super_admin_id, admin_user_id))
+        print("   ✅ admin用户已分配超级管理员角色")
+    else:
+        print("   ⚠️ 未找到admin用户")
+    
+    print("   ✅ 初始数据插入完成")
+
+if __name__ == "__main__":
+    create_rbac_tables()

+ 72 - 0
drop_rbac_tables.py

@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+"""
+删除现有的RBAC相关表
+"""
+import pymysql
+from dotenv import load_dotenv
+import os
+
+load_dotenv()
+
+def get_db_connection():
+    """获取数据库连接"""
+    try:
+        config = {
+            'host': os.getenv('DB_HOST', 'localhost'),
+            'port': int(os.getenv('DB_PORT', 3306)),
+            'user': os.getenv('DB_USER', 'root'),
+            'password': os.getenv('DB_PASSWORD', 'admin'),
+            'database': os.getenv('DB_NAME', 'lq_db'),
+            'charset': 'utf8mb4',
+            'autocommit': True
+        }
+        return pymysql.connect(**config)
+    except Exception as e:
+        print(f"数据库连接失败: {e}")
+        return None
+
+def drop_rbac_tables():
+    """删除RBAC相关表"""
+    print("🗑️ 删除现有RBAC相关表...")
+    print("=" * 50)
+    
+    conn = get_db_connection()
+    if not conn:
+        print("❌ 数据库连接失败")
+        return False
+    
+    cursor = conn.cursor()
+    
+    try:
+        # 按依赖关系顺序删除表
+        tables_to_drop = [
+            'user_roles',
+            'role_permissions', 
+            'role_menus',
+            'permissions',
+            'roles',
+            'menus'
+        ]
+        
+        for table in tables_to_drop:
+            try:
+                cursor.execute(f"DROP TABLE IF EXISTS {table}")
+                print(f"   ✅ 删除表: {table}")
+            except Exception as e:
+                print(f"   ⚠️ 删除表 {table} 失败: {e}")
+        
+        conn.commit()
+        cursor.close()
+        conn.close()
+        
+        print("\n✅ RBAC表删除完成")
+        return True
+        
+    except Exception as e:
+        print(f"❌ 删除表失败: {e}")
+        cursor.close()
+        conn.close()
+        return False
+
+if __name__ == "__main__":
+    drop_rbac_tables()

+ 1328 - 6
full_server.py

@@ -19,7 +19,7 @@ from fastapi import FastAPI, HTTPException, Depends, Request
 from fastapi.middleware.cors import CORSMiddleware
 from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
 from pydantic import BaseModel
-from typing import Optional
+from typing import Optional, Any
 import hashlib
 import secrets
 # 修复JWT导入 - 确保使用正确的JWT库
@@ -54,6 +54,9 @@ from datetime import datetime, timedelta, timezone
 import pymysql
 from urllib.parse import urlparse
 
+# 导入RBAC API - 移除循环导入
+# from rbac_api import get_user_menus, get_all_menus, get_all_roles, get_user_permissions
+
 # 数据模型
 class LoginRequest(BaseModel):
     username: str
@@ -81,7 +84,7 @@ class UserInfo(BaseModel):
 class ApiResponse(BaseModel):
     code: int
     message: str
-    data: Optional[dict] = None
+    data: Optional[Any] = None
     timestamp: str
 
 # 配置
@@ -348,6 +351,17 @@ async def get_user_profile(credentials: HTTPAuthorizationCredentials = Depends(s
         """, (user_id,))
         
         user_data = cursor.fetchone()
+        
+        # 获取用户角色
+        cursor.execute("""
+            SELECT r.name
+            FROM user_roles ur
+            JOIN roles r ON ur.role_id = r.id
+            WHERE ur.user_id = %s AND ur.is_active = 1
+        """, (user_id,))
+        
+        roles = [row[0] for row in cursor.fetchall()]
+        
         cursor.close()
         conn.close()
         
@@ -373,7 +387,8 @@ async def get_user_profile(credentials: HTTPAuthorizationCredentials = Depends(s
             "real_name": user_data[10],
             "company": user_data[11],
             "department": user_data[12],
-            "position": user_data[13]
+            "position": user_data[13],
+            "roles": roles
         }
         
         return ApiResponse(
@@ -1418,9 +1433,23 @@ async def get_apps(
         
         cursor = conn.cursor()
         
+        # 检查用户角色,决定是否显示所有应用
+        cursor.execute("""
+            SELECT COUNT(*) FROM user_roles ur
+            JOIN roles r ON ur.role_id = r.id
+            WHERE ur.user_id = %s AND r.name IN ('super_admin', 'admin', 'app_manager') AND ur.is_active = 1
+        """, (user_id,))
+        
+        is_app_manager = cursor.fetchone()[0] > 0
+        
         # 构建查询条件
-        where_conditions = ["created_by = %s"]
-        params = [user_id]
+        where_conditions = []
+        params = []
+        
+        # 如果不是应用管理员,只显示自己创建的应用
+        if not is_app_manager:
+            where_conditions.append("created_by = %s")
+            params.append(user_id)
         
         if keyword:
             where_conditions.append("(name LIKE %s OR description LIKE %s)")
@@ -1431,7 +1460,7 @@ async def get_apps(
         elif status == "inactive":
             where_conditions.append("is_active = 0")
         
-        where_clause = " AND ".join(where_conditions)
+        where_clause = " AND ".join(where_conditions) if where_conditions else "1=1"
         
         # 查询总数
         cursor.execute(f"SELECT COUNT(*) FROM apps WHERE {where_clause}", params)
@@ -2184,6 +2213,1299 @@ def generate_captcha():
         # 返回默认验证码
         return "1234", "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIwIiBoZWlnaHQ9IjQwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iNDAiIGZpbGw9IiNmMGYwZjAiIHN0cm9rZT0iI2NjYyIvPjx0ZXh0IHg9IjYwIiB5PSIyNSIgZm9udC1mYW1pbHk9IkFyaWFsIiBmb250LXNpemU9IjE4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMzMzIj4xMjM0PC90ZXh0Pjwvc3ZnPg=="
 
+# RBAC权限管理API
+@app.get("/api/v1/user/menus")
+async def api_get_user_menus(credentials: HTTPAuthorizationCredentials = Depends(security)):
+    """获取用户菜单"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(
+                code=401,
+                message="无效的访问令牌",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        user_id = payload.get("sub")
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(
+                code=500,
+                message="数据库连接失败",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 检查用户是否是超级管理员
+        cursor.execute("""
+            SELECT COUNT(*) FROM user_roles ur
+            JOIN roles r ON ur.role_id = r.id
+            WHERE ur.user_id = %s AND r.name = 'super_admin' AND ur.is_active = 1
+        """, (user_id,))
+        
+        is_super_admin = cursor.fetchone()[0] > 0
+        
+        if is_super_admin:
+            # 超级管理员返回所有活跃菜单
+            cursor.execute("""
+                SELECT m.id, m.parent_id, m.name, m.title, m.path, 
+                       m.component, m.icon, m.sort_order, m.menu_type, 
+                       m.is_hidden, m.is_active
+                FROM menus m
+                WHERE m.is_active = 1
+                ORDER BY m.sort_order
+            """)
+        else:
+            # 普通用户根据角色权限获取菜单
+            cursor.execute("""
+                SELECT m.id, m.parent_id, m.name, m.title, m.path, 
+                       m.component, m.icon, m.sort_order, m.menu_type, 
+                       m.is_hidden, m.is_active
+                FROM menus m
+                JOIN role_menus rm ON m.id = rm.menu_id
+                JOIN user_roles ur ON rm.role_id = ur.role_id
+                WHERE ur.user_id = %s 
+                AND ur.is_active = 1
+                AND m.is_active = 1
+                GROUP BY m.id, m.parent_id, m.name, m.title, m.path, 
+                         m.component, m.icon, m.sort_order, m.menu_type, 
+                         m.is_hidden, m.is_active
+                ORDER BY m.sort_order
+            """, (user_id,))
+        
+        menus = []
+        for row in cursor.fetchall():
+            menu = {
+                "id": row[0],
+                "parent_id": row[1],
+                "name": row[2],
+                "title": row[3],
+                "path": row[4],
+                "component": row[5],
+                "icon": row[6],
+                "sort_order": row[7],
+                "menu_type": row[8],
+                "is_hidden": bool(row[9]),
+                "is_active": bool(row[10]),
+                "children": []
+            }
+            menus.append(menu)
+        
+        # 构建菜单树
+        menu_tree = build_menu_tree(menus)
+        
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(
+            code=0,
+            message="获取用户菜单成功",
+            data=menu_tree,
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+        
+    except Exception as e:
+        print(f"获取用户菜单错误: {e}")
+        return ApiResponse(
+            code=500,
+            message="服务器内部错误",
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+
+def build_menu_tree(menus):
+    """构建菜单树结构"""
+    menu_map = {menu["id"]: menu for menu in menus}
+    tree = []
+    
+    for menu in menus:
+        if menu["parent_id"] is None:
+            tree.append(menu)
+        else:
+            parent = menu_map.get(menu["parent_id"])
+            if parent:
+                parent["children"].append(menu)
+    
+    return tree
+
+@app.get("/api/v1/admin/menus")
+async def api_get_all_menus(
+    page: int = 1,
+    page_size: int = 1000,  # 增大默认页面大小,确保返回所有菜单
+    keyword: Optional[str] = None,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """获取所有菜单(管理员)"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(
+                code=401,
+                message="无效的访问令牌",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        # 简化权限检查 - 只检查是否为管理员
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(
+                code=403,
+                message="权限不足",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(
+                code=500,
+                message="数据库连接失败",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 构建查询条件
+        where_conditions = []
+        params = []
+        
+        if keyword:
+            where_conditions.append("(m.title LIKE %s OR m.name LIKE %s)")
+            params.extend([f"%{keyword}%", f"%{keyword}%"])
+        
+        where_clause = " AND ".join(where_conditions) if where_conditions else "1=1"
+        
+        # 查询总数
+        cursor.execute(f"SELECT COUNT(*) FROM menus m WHERE {where_clause}", params)
+        total = cursor.fetchone()[0]
+        
+        # 查询菜单列表 - 修改排序逻辑以支持树形结构
+        cursor.execute(f"""
+            SELECT m.id, m.parent_id, m.name, m.title, m.path, m.component,
+                   m.icon, m.sort_order, m.menu_type, m.is_hidden, m.is_active,
+                   m.description, m.created_at, m.updated_at,
+                   pm.title as parent_title
+            FROM menus m
+            LEFT JOIN menus pm ON m.parent_id = pm.id
+            WHERE {where_clause}
+            ORDER BY 
+                CASE WHEN m.parent_id IS NULL THEN 0 ELSE 1 END,
+                m.sort_order, 
+                CASE WHEN m.menu_type = 'menu' THEN 0 ELSE 1 END,
+                m.created_at
+            LIMIT %s OFFSET %s
+        """, params + [page_size, (page - 1) * page_size])
+        
+        menus = []
+        for row in cursor.fetchall():
+            menu = {
+                "id": row[0],
+                "parent_id": row[1],
+                "name": row[2],
+                "title": row[3],
+                "path": row[4],
+                "component": row[5],
+                "icon": row[6],
+                "sort_order": row[7],
+                "menu_type": row[8],
+                "is_hidden": bool(row[9]),
+                "is_active": bool(row[10]),
+                "description": row[11],
+                "created_at": row[12].isoformat() if row[12] else None,
+                "updated_at": row[13].isoformat() if row[13] else None,
+                "parent_title": row[14]
+            }
+            menus.append(menu)
+        
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(
+            code=0,
+            message="获取菜单列表成功",
+            data={
+                "items": menus,
+                "total": total,
+                "page": page,
+                "page_size": page_size
+            },
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+        
+    except Exception as e:
+        print(f"获取菜单列表错误: {e}")
+        return ApiResponse(
+            code=500,
+            message="服务器内部错误",
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+
+@app.get("/api/v1/admin/roles")
+async def api_get_all_roles(
+    page: int = 1,
+    page_size: int = 20,
+    keyword: Optional[str] = None,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """获取所有角色"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(
+                code=401,
+                message="无效的访问令牌",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        # 简化权限检查 - 只检查是否为管理员
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(
+                code=403,
+                message="权限不足",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(
+                code=500,
+                message="数据库连接失败",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 构建查询条件
+        where_conditions = []
+        params = []
+        
+        if keyword:
+            where_conditions.append("(r.display_name LIKE %s OR r.name LIKE %s)")
+            params.extend([f"%{keyword}%", f"%{keyword}%"])
+        
+        where_clause = " AND ".join(where_conditions) if where_conditions else "1=1"
+        
+        # 查询总数
+        cursor.execute(f"SELECT COUNT(*) FROM roles r WHERE {where_clause}", params)
+        total = cursor.fetchone()[0]
+        
+        # 查询角色列表
+        offset = (page - 1) * page_size
+        cursor.execute(f"""
+            SELECT r.id, r.name, r.display_name, r.description, r.is_active,
+                   r.is_system, r.created_at, r.updated_at,
+                   COUNT(ur.user_id) as user_count
+            FROM roles r
+            LEFT JOIN user_roles ur ON r.id = ur.role_id AND ur.is_active = 1
+            WHERE {where_clause}
+            GROUP BY r.id
+            ORDER BY r.is_system DESC, r.created_at
+            LIMIT %s OFFSET %s
+        """, params + [page_size, offset])
+        
+        roles = []
+        for row in cursor.fetchall():
+            role = {
+                "id": row[0],
+                "name": row[1],
+                "display_name": row[2],
+                "description": row[3],
+                "is_active": bool(row[4]),
+                "is_system": bool(row[5]),
+                "created_at": row[6].isoformat() if row[6] else None,
+                "updated_at": row[7].isoformat() if row[7] else None,
+                "user_count": row[8]
+            }
+            roles.append(role)
+        
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(
+            code=0,
+            message="获取角色列表成功",
+            data={
+                "items": roles,
+                "total": total,
+                "page": page,
+                "page_size": page_size
+            },
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+        
+    except Exception as e:
+        print(f"获取角色列表错误: {e}")
+        return ApiResponse(
+            code=500,
+            message="服务器内部错误",
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+
+@app.get("/api/v1/user/permissions")
+async def api_get_user_permissions(credentials: HTTPAuthorizationCredentials = Depends(security)):
+    """获取用户权限"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(
+                code=401,
+                message="无效的访问令牌",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        user_id = payload.get("sub")
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(
+                code=500,
+                message="数据库连接失败",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 获取用户权限
+        cursor.execute("""
+            SELECT DISTINCT p.name, p.resource, p.action
+            FROM permissions p
+            JOIN role_permissions rp ON p.id = rp.permission_id
+            JOIN user_roles ur ON rp.role_id = ur.role_id
+            WHERE ur.user_id = %s 
+            AND ur.is_active = 1
+            AND p.is_active = 1
+        """, (user_id,))
+        
+        permissions = []
+        for row in cursor.fetchall():
+            permissions.append({
+                "name": row[0],
+                "resource": row[1],
+                "action": row[2]
+            })
+        
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(
+            code=0,
+            message="获取用户权限成功",
+            data=permissions,
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+        
+    except Exception as e:
+        print(f"获取用户权限错误: {e}")
+        return ApiResponse(
+            code=500,
+            message="服务器内部错误",
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+
+# 用户管理API
+@app.get("/api/v1/admin/users")
+async def get_users(
+    page: int = 1,
+    page_size: int = 20,
+    keyword: Optional[str] = None,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """获取用户列表"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(code=500, message="数据库连接失败", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 构建查询条件
+        where_conditions = []
+        params = []
+        
+        if keyword:
+            where_conditions.append("(u.username LIKE %s OR u.email LIKE %s OR up.real_name LIKE %s)")
+            params.extend([f"%{keyword}%", f"%{keyword}%", f"%{keyword}%"])
+        
+        where_clause = " AND ".join(where_conditions) if where_conditions else "1=1"
+        
+        # 查询总数
+        cursor.execute(f"SELECT COUNT(*) FROM users u LEFT JOIN user_profiles up ON u.id = up.user_id WHERE {where_clause}", params)
+        total = cursor.fetchone()[0]
+        
+        # 查询用户列表
+        offset = (page - 1) * page_size
+        cursor.execute(f"""
+            SELECT u.id, u.username, u.email, u.phone, u.is_active, u.is_superuser,
+                   u.last_login_at, u.created_at, up.real_name, up.company, up.department,
+                   GROUP_CONCAT(r.display_name) as roles
+            FROM users u
+            LEFT JOIN user_profiles up ON u.id = up.user_id
+            LEFT JOIN user_roles ur ON u.id = ur.user_id AND ur.is_active = 1
+            LEFT JOIN roles r ON ur.role_id = r.id
+            WHERE {where_clause}
+            GROUP BY u.id, u.username, u.email, u.phone, u.is_active, u.is_superuser,
+                     u.last_login_at, u.created_at, up.real_name, up.company, up.department
+            ORDER BY u.created_at DESC
+            LIMIT %s OFFSET %s
+        """, params + [page_size, offset])
+        
+        users = []
+        for row in cursor.fetchall():
+            users.append({
+                "id": row[0],
+                "username": row[1],
+                "email": row[2],
+                "phone": row[3],
+                "is_active": bool(row[4]),
+                "is_superuser": bool(row[5]),
+                "last_login_at": row[6].isoformat() if row[6] else None,
+                "created_at": row[7].isoformat() if row[7] else None,
+                "real_name": row[8],
+                "company": row[9],
+                "department": row[10],
+                "roles": row[11].split(',') if row[11] else []
+            })
+        
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(
+            code=0,
+            message="获取用户列表成功",
+            data={"items": users, "total": total, "page": page, "page_size": page_size},
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+        
+    except Exception as e:
+        print(f"获取用户列表错误: {e}")
+        return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+
+@app.post("/api/v1/admin/users")
+async def create_user(
+    user_data: dict,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """创建用户"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(code=500, message="数据库连接失败", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 检查用户名和邮箱是否已存在
+        cursor.execute("SELECT id FROM users WHERE username = %s OR email = %s", 
+                      (user_data['username'], user_data['email']))
+        if cursor.fetchone():
+            cursor.close()
+            conn.close()
+            return ApiResponse(code=400, message="用户名或邮箱已存在", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        # 生成用户ID
+        user_id = str(uuid.uuid4())
+        
+        # 创建密码哈希
+        password_hash = hash_password_simple(user_data['password'])
+        
+        # 插入用户
+        cursor.execute("""
+            INSERT INTO users (id, username, email, phone, password_hash, is_active, is_superuser, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (user_id, user_data['username'], user_data['email'], user_data.get('phone'), 
+              password_hash, user_data.get('is_active', True), user_data.get('is_superuser', False)))
+        
+        # 插入用户详情
+        if any(key in user_data for key in ['real_name', 'company', 'department']):
+            profile_id = str(uuid.uuid4())
+            cursor.execute("""
+                INSERT INTO user_profiles (id, user_id, real_name, company, department, created_at, updated_at)
+                VALUES (%s, %s, %s, %s, %s, NOW(), NOW())
+            """, (profile_id, user_id, user_data.get('real_name'), user_data.get('company'), user_data.get('department')))
+        
+        # 分配角色
+        if 'role_ids' in user_data and user_data['role_ids']:
+            for role_id in user_data['role_ids']:
+                role_assignment_id = str(uuid.uuid4())
+                cursor.execute("""
+                    INSERT INTO user_roles (id, user_id, role_id, assigned_by, created_at)
+                    VALUES (%s, %s, %s, %s, NOW())
+                """, (role_assignment_id, user_id, role_id, payload.get("sub")))
+        
+        conn.commit()
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(code=0, message="用户创建成功", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+    except Exception as e:
+        print(f"创建用户错误: {e}")
+        return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+
+@app.put("/api/v1/admin/users/{user_id}")
+async def update_user(
+    user_id: str,
+    user_data: dict,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """更新用户"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(code=500, message="数据库连接失败", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 更新用户基本信息
+        update_fields = []
+        update_values = []
+        
+        for field in ['email', 'phone', 'is_active', 'is_superuser']:
+            if field in user_data:
+                update_fields.append(f'{field} = %s')
+                update_values.append(user_data[field])
+        
+        if update_fields:
+            update_values.append(user_id)
+            cursor.execute(f"""
+                UPDATE users 
+                SET {', '.join(update_fields)}, updated_at = NOW()
+                WHERE id = %s
+            """, update_values)
+        
+        # 更新用户详情
+        profile_fields = ['real_name', 'company', 'department']
+        profile_updates = {k: v for k, v in user_data.items() if k in profile_fields}
+        
+        if profile_updates:
+            # 检查是否已有记录
+            cursor.execute("SELECT id FROM user_profiles WHERE user_id = %s", (user_id,))
+            profile_exists = cursor.fetchone()
+            
+            if profile_exists:
+                update_fields = []
+                update_values = []
+                for field, value in profile_updates.items():
+                    update_fields.append(f'{field} = %s')
+                    update_values.append(value)
+                
+                update_values.append(user_id)
+                cursor.execute(f"""
+                    UPDATE user_profiles 
+                    SET {', '.join(update_fields)}, updated_at = NOW()
+                    WHERE user_id = %s
+                """, update_values)
+            else:
+                profile_id = str(uuid.uuid4())
+                fields = ['id', 'user_id'] + list(profile_updates.keys())
+                values = [profile_id, user_id] + list(profile_updates.values())
+                placeholders = ', '.join(['%s'] * len(values))
+                
+                cursor.execute(f"""
+                    INSERT INTO user_profiles ({', '.join(fields)}, created_at, updated_at)
+                    VALUES ({placeholders}, NOW(), NOW())
+                """, values)
+        
+        # 更新用户角色
+        if 'role_ids' in user_data:
+            # 删除现有角色
+            cursor.execute("DELETE FROM user_roles WHERE user_id = %s", (user_id,))
+            
+            # 添加新角色
+            for role_id in user_data['role_ids']:
+                assignment_id = str(uuid.uuid4())
+                cursor.execute("""
+                    INSERT INTO user_roles (id, user_id, role_id, assigned_by, created_at)
+                    VALUES (%s, %s, %s, %s, NOW())
+                """, (assignment_id, user_id, role_id, payload.get("sub")))
+        
+        conn.commit()
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(code=0, message="用户更新成功", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+    except Exception as e:
+        print(f"更新用户错误: {e}")
+        return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+
+@app.delete("/api/v1/admin/users/{user_id}")
+async def delete_user(
+    user_id: str,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """删除用户"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        # 不能删除自己
+        if user_id == payload.get("sub"):
+            return ApiResponse(code=400, message="不能删除自己", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(code=500, message="数据库连接失败", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 检查是否为超级管理员
+        cursor.execute("""
+            SELECT COUNT(*) FROM user_roles ur
+            JOIN roles r ON ur.role_id = r.id
+            WHERE ur.user_id = %s AND r.name = 'super_admin' AND ur.is_active = 1
+        """, (user_id,))
+        
+        if cursor.fetchone()[0] > 0:
+            cursor.close()
+            conn.close()
+            return ApiResponse(code=400, message="不能删除超级管理员", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        # 删除相关数据
+        cursor.execute("DELETE FROM user_roles WHERE user_id = %s", (user_id,))
+        cursor.execute("DELETE FROM user_profiles WHERE user_id = %s", (user_id,))
+        cursor.execute("DELETE FROM users WHERE id = %s", (user_id,))
+        
+        conn.commit()
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(code=0, message="用户删除成功", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+    except Exception as e:
+        print(f"删除用户错误: {e}")
+        return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+
+# 角色管理API
+@app.post("/api/v1/admin/roles")
+async def create_role(
+    role_data: dict,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """创建角色"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(code=500, message="数据库连接失败", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 检查角色名是否已存在
+        cursor.execute("SELECT id FROM roles WHERE name = %s", (role_data['name'],))
+        if cursor.fetchone():
+            cursor.close()
+            conn.close()
+            return ApiResponse(code=400, message="角色名已存在", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        # 创建角色
+        role_id = str(uuid.uuid4())
+        cursor.execute("""
+            INSERT INTO roles (id, name, display_name, description, is_active, is_system, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (role_id, role_data['name'], role_data['display_name'], role_data.get('description'), 
+              role_data.get('is_active', True), False))
+        
+        conn.commit()
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(code=0, message="角色创建成功", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+    except Exception as e:
+        print(f"创建角色错误: {e}")
+        return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+
+@app.put("/api/v1/admin/roles/{role_id}")
+async def update_role(
+    role_id: str,
+    role_data: dict,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """更新角色"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(code=500, message="数据库连接失败", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 检查是否为系统角色
+        cursor.execute("SELECT is_system FROM roles WHERE id = %s", (role_id,))
+        role = cursor.fetchone()
+        if not role:
+            cursor.close()
+            conn.close()
+            return ApiResponse(code=404, message="角色不存在", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        if role[0]:  # is_system
+            cursor.close()
+            conn.close()
+            return ApiResponse(code=400, message="不能修改系统角色", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        # 更新角色
+        update_fields = []
+        update_values = []
+        
+        for field in ['display_name', 'description', 'is_active']:
+            if field in role_data:
+                update_fields.append(f'{field} = %s')
+                update_values.append(role_data[field])
+        
+        if update_fields:
+            update_values.append(role_id)
+            cursor.execute(f"""
+                UPDATE roles 
+                SET {', '.join(update_fields)}, updated_at = NOW()
+                WHERE id = %s
+            """, update_values)
+        
+        conn.commit()
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(code=0, message="角色更新成功", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+    except Exception as e:
+        print(f"更新角色错误: {e}")
+        return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+
+@app.delete("/api/v1/admin/roles/{role_id}")
+async def delete_role(
+    role_id: str,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """删除角色"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(code=500, message="数据库连接失败", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 检查是否为系统角色
+        cursor.execute("SELECT is_system FROM roles WHERE id = %s", (role_id,))
+        role = cursor.fetchone()
+        if not role:
+            cursor.close()
+            conn.close()
+            return ApiResponse(code=404, message="角色不存在", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        if role[0]:  # is_system
+            cursor.close()
+            conn.close()
+            return ApiResponse(code=400, message="不能删除系统角色", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        # 检查是否有用户使用此角色
+        cursor.execute("SELECT COUNT(*) FROM user_roles WHERE role_id = %s", (role_id,))
+        if cursor.fetchone()[0] > 0:
+            cursor.close()
+            conn.close()
+            return ApiResponse(code=400, message="该角色正在被使用,无法删除", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        # 删除角色相关数据
+        cursor.execute("DELETE FROM role_permissions WHERE role_id = %s", (role_id,))
+        cursor.execute("DELETE FROM role_menus WHERE role_id = %s", (role_id,))
+        cursor.execute("DELETE FROM roles WHERE id = %s", (role_id,))
+        
+        conn.commit()
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(code=0, message="角色删除成功", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+    except Exception as e:
+        print(f"删除角色错误: {e}")
+        return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+
+# 角色菜单权限管理API
+@app.get("/api/v1/admin/roles/{role_id}/menus")
+async def get_role_menus(
+    role_id: str,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """获取角色的菜单权限"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(
+                code=401,
+                message="无效的访问令牌",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        # 检查管理员权限
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(
+                code=403,
+                message="权限不足",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(
+                code=500,
+                message="数据库连接失败",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 检查角色是否存在
+        cursor.execute("SELECT id, name FROM roles WHERE id = %s", (role_id,))
+        role = cursor.fetchone()
+        
+        if not role:
+            cursor.close()
+            conn.close()
+            return ApiResponse(
+                code=404,
+                message="角色不存在",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        # 检查是否为超级管理员角色
+        role_name = role[1]
+        is_super_admin_role = role_name == "super_admin"
+        
+        if is_super_admin_role:
+            # 超级管理员默认拥有所有菜单权限
+            cursor.execute("""
+                SELECT id, name, title, parent_id, menu_type
+                FROM menus
+                WHERE is_active = 1
+                ORDER BY sort_order
+            """)
+            menu_permissions = cursor.fetchall()
+        else:
+            # 普通角色查询已分配的菜单权限
+            cursor.execute("""
+                SELECT m.id, m.name, m.title, m.parent_id, m.menu_type
+                FROM role_menus rm
+                JOIN menus m ON rm.menu_id = m.id
+                WHERE rm.role_id = %s AND m.is_active = 1
+                ORDER BY m.sort_order
+            """, (role_id,))
+            menu_permissions = cursor.fetchall()
+        
+        cursor.close()
+        conn.close()
+        
+        # 构建返回数据
+        menu_ids = [menu[0] for menu in menu_permissions]
+        menu_details = []
+        
+        for menu in menu_permissions:
+            menu_details.append({
+                "id": menu[0],
+                "name": menu[1],
+                "title": menu[2],
+                "parent_id": menu[3],
+                "menu_type": menu[4]
+            })
+        
+        return ApiResponse(
+            code=0,
+            message="获取角色菜单权限成功",
+            data={
+                "role_id": role_id,
+                "role_name": role[1],
+                "menu_ids": menu_ids,
+                "menu_details": menu_details,
+                "total": len(menu_ids)
+            },
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+        
+    except Exception as e:
+        print(f"获取角色菜单权限错误: {e}")
+        return ApiResponse(
+            code=500,
+            message="服务器内部错误",
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+
+@app.put("/api/v1/admin/roles/{role_id}/menus")
+async def update_role_menus(
+    role_id: str,
+    request: Request,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """更新角色的菜单权限"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(
+                code=401,
+                message="无效的访问令牌",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        # 检查管理员权限
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(
+                code=403,
+                message="权限不足",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        # 获取请求数据
+        body = await request.json()
+        menu_ids = body.get("menu_ids", [])
+        
+        if not isinstance(menu_ids, list):
+            return ApiResponse(
+                code=400,
+                message="菜单ID列表格式错误",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(
+                code=500,
+                message="数据库连接失败",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 检查角色是否存在
+        cursor.execute("SELECT id, name FROM roles WHERE id = %s", (role_id,))
+        role = cursor.fetchone()
+        
+        if not role:
+            cursor.close()
+            conn.close()
+            return ApiResponse(
+                code=404,
+                message="角色不存在",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        # 检查是否为超级管理员角色
+        role_name = role[1]
+        is_super_admin_role = role_name == "super_admin"
+        
+        if is_super_admin_role:
+            # 超级管理员角色不允许修改权限,始终拥有全部权限
+            cursor.close()
+            conn.close()
+            return ApiResponse(
+                code=400,
+                message="超级管理员角色拥有全部权限,无需修改",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        # 验证菜单ID是否存在
+        if menu_ids:
+            placeholders = ','.join(['%s'] * len(menu_ids))
+            cursor.execute(f"""
+                SELECT id FROM menus 
+                WHERE id IN ({placeholders}) AND is_active = 1
+            """, menu_ids)
+            
+            valid_menu_ids = [row[0] for row in cursor.fetchall()]
+            invalid_menu_ids = set(menu_ids) - set(valid_menu_ids)
+            
+            if invalid_menu_ids:
+                cursor.close()
+                conn.close()
+                return ApiResponse(
+                    code=400,
+                    message=f"无效的菜单ID: {', '.join(invalid_menu_ids)}",
+                    timestamp=datetime.now(timezone.utc).isoformat()
+                ).model_dump()
+        
+        # 开始事务
+        cursor.execute("START TRANSACTION")
+        
+        try:
+            # 删除角色现有的菜单权限
+            cursor.execute("DELETE FROM role_menus WHERE role_id = %s", (role_id,))
+            
+            # 添加新的菜单权限
+            if menu_ids:
+                values = [(role_id, menu_id) for menu_id in menu_ids]
+                cursor.executemany("""
+                    INSERT INTO role_menus (role_id, menu_id, created_at)
+                    VALUES (%s, %s, NOW())
+                """, values)
+            
+            # 提交事务
+            conn.commit()
+            
+            cursor.close()
+            conn.close()
+            
+            return ApiResponse(
+                code=0,
+                message="角色菜单权限更新成功",
+                data={
+                    "role_id": role_id,
+                    "role_name": role[1],
+                    "menu_ids": menu_ids,
+                    "updated_count": len(menu_ids)
+                },
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+            
+        except Exception as e:
+            # 回滚事务
+            conn.rollback()
+            cursor.close()
+            conn.close()
+            raise e
+            
+    except Exception as e:
+        print(f"更新角色菜单权限错误: {e}")
+        return ApiResponse(
+            code=500,
+            message="服务器内部错误",
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+
+# 菜单管理API
+@app.post("/api/v1/admin/menus")
+async def create_menu(
+    menu_data: dict,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """创建菜单"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(code=500, message="数据库连接失败", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 检查菜单名是否已存在
+        cursor.execute("SELECT id FROM menus WHERE name = %s", (menu_data['name'],))
+        if cursor.fetchone():
+            cursor.close()
+            conn.close()
+            return ApiResponse(code=400, message="菜单标识已存在", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        # 创建菜单
+        menu_id = str(uuid.uuid4())
+        cursor.execute("""
+            INSERT INTO menus (id, parent_id, name, title, path, component, icon, 
+                             sort_order, menu_type, is_hidden, is_active, description, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (
+            menu_id, menu_data.get('parent_id'), menu_data['name'], menu_data['title'],
+            menu_data.get('path'), menu_data.get('component'), menu_data.get('icon'),
+            menu_data.get('sort_order', 0), menu_data.get('menu_type', 'menu'),
+            menu_data.get('is_hidden', False), menu_data.get('is_active', True),
+            menu_data.get('description')
+        ))
+        
+        conn.commit()
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(code=0, message="菜单创建成功", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+    except Exception as e:
+        print(f"创建菜单错误: {e}")
+        return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+
+@app.put("/api/v1/admin/menus/{menu_id}")
+async def update_menu(
+    menu_id: str,
+    menu_data: dict,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """更新菜单"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(code=500, message="数据库连接失败", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 更新菜单
+        update_fields = []
+        update_values = []
+        
+        for field in ['parent_id', 'title', 'path', 'component', 'icon', 'sort_order', 
+                     'menu_type', 'is_hidden', 'is_active', 'description']:
+            if field in menu_data:
+                update_fields.append(f'{field} = %s')
+                update_values.append(menu_data[field])
+        
+        if update_fields:
+            update_values.append(menu_id)
+            cursor.execute(f"""
+                UPDATE menus 
+                SET {', '.join(update_fields)}, updated_at = NOW()
+                WHERE id = %s
+            """, update_values)
+        
+        conn.commit()
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(code=0, message="菜单更新成功", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+    except Exception as e:
+        print(f"更新菜单错误: {e}")
+        return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+
+@app.delete("/api/v1/admin/menus/{menu_id}")
+async def delete_menu(
+    menu_id: str,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """删除菜单"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        is_superuser = payload.get("is_superuser", False)
+        if not is_superuser:
+            return ApiResponse(code=403, message="权限不足", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(code=500, message="数据库连接失败", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 检查是否有子菜单
+        cursor.execute("SELECT COUNT(*) FROM menus WHERE parent_id = %s", (menu_id,))
+        if cursor.fetchone()[0] > 0:
+            cursor.close()
+            conn.close()
+            return ApiResponse(code=400, message="该菜单下有子菜单,无法删除", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        # 删除菜单相关数据
+        cursor.execute("DELETE FROM role_menus WHERE menu_id = %s", (menu_id,))
+        cursor.execute("DELETE FROM menus WHERE id = %s", (menu_id,))
+        
+        conn.commit()
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(code=0, message="菜单删除成功", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+    except Exception as e:
+        print(f"删除菜单错误: {e}")
+        return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+
+# 获取所有角色(用于下拉选择)
+@app.get("/api/v1/roles/all")
+async def get_all_roles_simple(credentials: HTTPAuthorizationCredentials = Depends(security)):
+    """获取所有角色(简化版,用于下拉选择)"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(code=401, message="无效的访问令牌", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(code=500, message="数据库连接失败", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+        cursor = conn.cursor()
+        
+        cursor.execute("""
+            SELECT id, name, display_name, is_system, is_active
+            FROM roles 
+            WHERE is_active = 1
+            ORDER BY is_system DESC, display_name
+        """)
+        
+        roles = []
+        for row in cursor.fetchall():
+            roles.append({
+                "id": row[0],
+                "name": row[1],
+                "display_name": row[2],
+                "is_system": bool(row[3]),
+                "is_active": bool(row[4])
+            })
+        
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(code=0, message="获取角色列表成功", data=roles, timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+        
+    except Exception as e:
+        print(f"获取角色列表错误: {e}")
+        return ApiResponse(code=500, message="服务器内部错误", timestamp=datetime.now(timezone.utc).isoformat()).model_dump()
+
 if __name__ == "__main__":
     import uvicorn
     

+ 0 - 0
net


+ 562 - 0
rbac_api.py

@@ -0,0 +1,562 @@
+#!/usr/bin/env python3
+"""
+RBAC权限管理API接口
+"""
+from fastapi import HTTPException, Depends
+from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
+from pydantic import BaseModel
+from typing import Optional, List, Dict, Any
+import json
+from datetime import datetime, timezone
+
+# 导入必要的模块
+import pymysql
+from urllib.parse import urlparse
+import os
+from dotenv import load_dotenv
+
+load_dotenv()
+
+# 复制必要的工具函数以避免循环导入
+def get_db_connection():
+    """获取数据库连接"""
+    try:
+        database_url = os.getenv('DATABASE_URL', '')
+        if not database_url:
+            return None
+            
+        parsed = urlparse(database_url)
+        config = {
+            'host': parsed.hostname or 'localhost',
+            'port': parsed.port or 3306,
+            'user': parsed.username or 'root',
+            'password': parsed.password or '',
+            'database': parsed.path[1:] if parsed.path else 'sso_db',
+            'charset': 'utf8mb4'
+        }
+        
+        return pymysql.connect(**config)
+    except Exception as e:
+        print(f"数据库连接失败: {e}")
+        return None
+
+def verify_token(token: str) -> Optional[dict]:
+    """验证令牌"""
+    try:
+        # 导入JWT库
+        try:
+            import jwt as pyjwt
+            test_token = pyjwt.encode({"test": "data"}, "secret", algorithm="HS256")
+            jwt = pyjwt
+        except (ImportError, AttributeError, TypeError):
+            from jose import jwt
+        
+        JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "dev-jwt-secret-key-12345")
+        payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=["HS256"])
+        return payload
+    except Exception:
+        return None
+
+class ApiResponse(BaseModel):
+    code: int
+    message: str
+    data: Optional[dict] = None
+    timestamp: str
+
+security = HTTPBearer()
+
+# 数据模型
+class MenuCreate(BaseModel):
+    parent_id: Optional[str] = None
+    name: str
+    title: str
+    path: Optional[str] = None
+    component: Optional[str] = None
+    icon: Optional[str] = None
+    sort_order: int = 0
+    menu_type: str = 'menu'
+    is_hidden: bool = False
+    description: Optional[str] = None
+
+class MenuUpdate(BaseModel):
+    parent_id: Optional[str] = None
+    title: str
+    path: Optional[str] = None
+    component: Optional[str] = None
+    icon: Optional[str] = None
+    sort_order: int = 0
+    menu_type: str = 'menu'
+    is_hidden: bool = False
+    is_active: bool = True
+    description: Optional[str] = None
+
+class RoleCreate(BaseModel):
+    name: str
+    display_name: str
+    description: Optional[str] = None
+
+class RoleUpdate(BaseModel):
+    display_name: str
+    description: Optional[str] = None
+    is_active: bool = True
+
+class PermissionCreate(BaseModel):
+    name: str
+    display_name: str
+    resource: str
+    action: str
+    description: Optional[str] = None
+
+class UserRoleAssign(BaseModel):
+    user_id: str
+    role_ids: List[str]
+
+class RoleMenuAssign(BaseModel):
+    role_id: str
+    menu_ids: List[str]
+
+class RolePermissionAssign(BaseModel):
+    role_id: str
+    permission_ids: List[str]
+
+# 权限检查装饰器
+def check_permission(resource: str, action: str):
+    """检查用户权限"""
+    def decorator(func):
+        async def wrapper(*args, **kwargs):
+            # 从kwargs中获取credentials
+            credentials = kwargs.get('credentials')
+            if not credentials:
+                return ApiResponse(
+                    code=401,
+                    message="未提供访问令牌",
+                    timestamp=datetime.now(timezone.utc).isoformat()
+                ).model_dump()
+            
+            # 验证token
+            payload = verify_token(credentials.credentials)
+            if not payload:
+                return ApiResponse(
+                    code=401,
+                    message="无效的访问令牌",
+                    timestamp=datetime.now(timezone.utc).isoformat()
+                ).model_dump()
+            
+            user_id = payload.get("sub")
+            
+            # 检查用户权限
+            if not await has_permission(user_id, resource, action):
+                return ApiResponse(
+                    code=403,
+                    message="权限不足",
+                    timestamp=datetime.now(timezone.utc).isoformat()
+                ).model_dump()
+            
+            # 将user_id添加到kwargs中
+            kwargs['current_user_id'] = user_id
+            return await func(*args, **kwargs)
+        return wrapper
+    return decorator
+
+async def has_permission(user_id: str, resource: str, action: str) -> bool:
+    """检查用户是否有指定权限"""
+    conn = get_db_connection()
+    if not conn:
+        return False
+    
+    cursor = conn.cursor()
+    
+    try:
+        # 查询用户是否有指定权限
+        cursor.execute("""
+            SELECT COUNT(*) FROM user_roles ur
+            JOIN role_permissions rp ON ur.role_id = rp.role_id
+            JOIN permissions p ON rp.permission_id = p.id
+            WHERE ur.user_id = %s 
+            AND ur.is_active = 1
+            AND p.resource = %s 
+            AND p.action = %s
+            AND p.is_active = 1
+        """, (user_id, resource, action))
+        
+        count = cursor.fetchone()[0]
+        return count > 0
+        
+    except Exception as e:
+        print(f"权限检查错误: {e}")
+        return False
+    finally:
+        cursor.close()
+        conn.close()
+
+# 菜单管理API
+async def get_user_menus(credentials: HTTPAuthorizationCredentials = Depends(security)):
+    """获取用户菜单"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(
+                code=401,
+                message="无效的访问令牌",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        user_id = payload.get("sub")
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(
+                code=500,
+                message="数据库连接失败",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 获取用户可访问的菜单
+        cursor.execute("""
+            SELECT DISTINCT m.id, m.parent_id, m.name, m.title, m.path, 
+                   m.component, m.icon, m.sort_order, m.menu_type, 
+                   m.is_hidden, m.is_active
+            FROM menus m
+            JOIN role_menus rm ON m.id = rm.menu_id
+            JOIN user_roles ur ON rm.role_id = ur.role_id
+            WHERE ur.user_id = %s 
+            AND ur.is_active = 1
+            AND m.is_active = 1
+            ORDER BY m.sort_order, m.created_at
+        """, (user_id,))
+        
+        menus = []
+        for row in cursor.fetchall():
+            menu = {
+                "id": row[0],
+                "parent_id": row[1],
+                "name": row[2],
+                "title": row[3],
+                "path": row[4],
+                "component": row[5],
+                "icon": row[6],
+                "sort_order": row[7],
+                "menu_type": row[8],
+                "is_hidden": bool(row[9]),
+                "is_active": bool(row[10]),
+                "children": []
+            }
+            menus.append(menu)
+        
+        # 构建菜单树
+        menu_tree = build_menu_tree(menus)
+        
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(
+            code=0,
+            message="获取用户菜单成功",
+            data=menu_tree,
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+        
+    except Exception as e:
+        print(f"获取用户菜单错误: {e}")
+        return ApiResponse(
+            code=500,
+            message="服务器内部错误",
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+
+def build_menu_tree(menus: List[Dict]) -> List[Dict]:
+    """构建菜单树结构"""
+    menu_map = {menu["id"]: menu for menu in menus}
+    tree = []
+    
+    for menu in menus:
+        if menu["parent_id"] is None:
+            tree.append(menu)
+        else:
+            parent = menu_map.get(menu["parent_id"])
+            if parent:
+                parent["children"].append(menu)
+    
+    return tree
+
+async def get_all_menus(
+    page: int = 1,
+    page_size: int = 20,
+    keyword: Optional[str] = None,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """获取所有菜单(管理员)"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(
+                code=401,
+                message="无效的访问令牌",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        user_id = payload.get("sub")
+        
+        # 检查权限
+        if not await has_permission(user_id, "menu", "view"):
+            return ApiResponse(
+                code=403,
+                message="权限不足",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(
+                code=500,
+                message="数据库连接失败",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 构建查询条件
+        where_conditions = []
+        params = []
+        
+        if keyword:
+            where_conditions.append("(m.title LIKE %s OR m.name LIKE %s)")
+            params.extend([f"%{keyword}%", f"%{keyword}%"])
+        
+        where_clause = " AND ".join(where_conditions) if where_conditions else "1=1"
+        
+        # 查询总数
+        cursor.execute(f"SELECT COUNT(*) FROM menus m WHERE {where_clause}", params)
+        total = cursor.fetchone()[0]
+        
+        # 查询菜单列表
+        offset = (page - 1) * page_size
+        cursor.execute(f"""
+            SELECT m.id, m.parent_id, m.name, m.title, m.path, m.component,
+                   m.icon, m.sort_order, m.menu_type, m.is_hidden, m.is_active,
+                   m.description, m.created_at, m.updated_at,
+                   pm.title as parent_title
+            FROM menus m
+            LEFT JOIN menus pm ON m.parent_id = pm.id
+            WHERE {where_clause}
+            ORDER BY m.sort_order, m.created_at
+            LIMIT %s OFFSET %s
+        """, params + [page_size, offset])
+        
+        menus = []
+        for row in cursor.fetchall():
+            menu = {
+                "id": row[0],
+                "parent_id": row[1],
+                "name": row[2],
+                "title": row[3],
+                "path": row[4],
+                "component": row[5],
+                "icon": row[6],
+                "sort_order": row[7],
+                "menu_type": row[8],
+                "is_hidden": bool(row[9]),
+                "is_active": bool(row[10]),
+                "description": row[11],
+                "created_at": row[12].isoformat() if row[12] else None,
+                "updated_at": row[13].isoformat() if row[13] else None,
+                "parent_title": row[14]
+            }
+            menus.append(menu)
+        
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(
+            code=0,
+            message="获取菜单列表成功",
+            data={
+                "items": menus,
+                "total": total,
+                "page": page,
+                "page_size": page_size
+            },
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+        
+    except Exception as e:
+        print(f"获取菜单列表错误: {e}")
+        return ApiResponse(
+            code=500,
+            message="服务器内部错误",
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+
+# 角色管理API
+async def get_all_roles(
+    page: int = 1,
+    page_size: int = 20,
+    keyword: Optional[str] = None,
+    credentials: HTTPAuthorizationCredentials = Depends(security)
+):
+    """获取所有角色"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(
+                code=401,
+                message="无效的访问令牌",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        user_id = payload.get("sub")
+        
+        # 检查权限
+        if not await has_permission(user_id, "role", "view"):
+            return ApiResponse(
+                code=403,
+                message="权限不足",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(
+                code=500,
+                message="数据库连接失败",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 构建查询条件
+        where_conditions = []
+        params = []
+        
+        if keyword:
+            where_conditions.append("(r.display_name LIKE %s OR r.name LIKE %s)")
+            params.extend([f"%{keyword}%", f"%{keyword}%"])
+        
+        where_clause = " AND ".join(where_conditions) if where_conditions else "1=1"
+        
+        # 查询总数
+        cursor.execute(f"SELECT COUNT(*) FROM roles r WHERE {where_clause}", params)
+        total = cursor.fetchone()[0]
+        
+        # 查询角色列表
+        offset = (page - 1) * page_size
+        cursor.execute(f"""
+            SELECT r.id, r.name, r.display_name, r.description, r.is_active,
+                   r.is_system, r.created_at, r.updated_at,
+                   COUNT(ur.user_id) as user_count
+            FROM roles r
+            LEFT JOIN user_roles ur ON r.id = ur.role_id AND ur.is_active = 1
+            WHERE {where_clause}
+            GROUP BY r.id
+            ORDER BY r.is_system DESC, r.created_at
+            LIMIT %s OFFSET %s
+        """, params + [page_size, offset])
+        
+        roles = []
+        for row in cursor.fetchall():
+            role = {
+                "id": row[0],
+                "name": row[1],
+                "display_name": row[2],
+                "description": row[3],
+                "is_active": bool(row[4]),
+                "is_system": bool(row[5]),
+                "created_at": row[6].isoformat() if row[6] else None,
+                "updated_at": row[7].isoformat() if row[7] else None,
+                "user_count": row[8]
+            }
+            roles.append(role)
+        
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(
+            code=0,
+            message="获取角色列表成功",
+            data={
+                "items": roles,
+                "total": total,
+                "page": page,
+                "page_size": page_size
+            },
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+        
+    except Exception as e:
+        print(f"获取角色列表错误: {e}")
+        return ApiResponse(
+            code=500,
+            message="服务器内部错误",
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+
+async def get_user_permissions(credentials: HTTPAuthorizationCredentials = Depends(security)):
+    """获取用户权限"""
+    try:
+        payload = verify_token(credentials.credentials)
+        if not payload:
+            return ApiResponse(
+                code=401,
+                message="无效的访问令牌",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        user_id = payload.get("sub")
+        
+        conn = get_db_connection()
+        if not conn:
+            return ApiResponse(
+                code=500,
+                message="数据库连接失败",
+                timestamp=datetime.now(timezone.utc).isoformat()
+            ).model_dump()
+        
+        cursor = conn.cursor()
+        
+        # 获取用户权限
+        cursor.execute("""
+            SELECT DISTINCT p.name, p.resource, p.action
+            FROM permissions p
+            JOIN role_permissions rp ON p.id = rp.permission_id
+            JOIN user_roles ur ON rp.role_id = ur.role_id
+            WHERE ur.user_id = %s 
+            AND ur.is_active = 1
+            AND p.is_active = 1
+        """, (user_id,))
+        
+        permissions = []
+        for row in cursor.fetchall():
+            permissions.append({
+                "name": row[0],
+                "resource": row[1],
+                "action": row[2]
+            })
+        
+        cursor.close()
+        conn.close()
+        
+        return ApiResponse(
+            code=0,
+            message="获取用户权限成功",
+            data=permissions,
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+        
+    except Exception as e:
+        print(f"获取用户权限错误: {e}")
+        return ApiResponse(
+            code=500,
+            message="服务器内部错误",
+            timestamp=datetime.now(timezone.utc).isoformat()
+        ).model_dump()
+
+# 导出API函数供main server使用
+__all__ = [
+    'get_user_menus',
+    'get_all_menus', 
+    'get_all_roles',
+    'get_user_permissions',
+    'has_permission'
+]

+ 1183 - 0
reinit_menus_by_requirements.py

@@ -0,0 +1,1183 @@
+#!/usr/bin/env python3
+"""
+根据需求/菜单.md重新初始化菜单数据
+严格按照需求文档的菜单结构设计
+"""
+import pymysql
+from dotenv import load_dotenv
+import os
+import uuid
+from datetime import datetime
+
+load_dotenv()
+
+def get_db_connection():
+    """获取数据库连接"""
+    try:
+        config = {
+            'host': os.getenv('DB_HOST', 'localhost'),
+            'port': int(os.getenv('DB_PORT', 3306)),
+            'user': os.getenv('DB_USER', 'root'),
+            'password': os.getenv('DB_PASSWORD', 'admin'),
+            'database': os.getenv('DB_NAME', 'lq_db'),
+            'charset': 'utf8mb4',
+            'autocommit': True
+        }
+        return pymysql.connect(**config)
+    except Exception as e:
+        print(f"数据库连接失败: {e}")
+        return None
+
+def clear_rbac_data(cursor):
+    """清理现有RBAC数据"""
+    print("🧹 清理现有RBAC数据...")
+    
+    # 清理关联表
+    cursor.execute("DELETE FROM role_permissions")
+    cursor.execute("DELETE FROM role_menus")
+    cursor.execute("DELETE FROM user_roles")
+    
+    # 清理主表
+    cursor.execute("DELETE FROM permissions")
+    cursor.execute("DELETE FROM menus")
+    cursor.execute("DELETE FROM roles")
+    
+    print("   ✅ 清理完成")
+
+def insert_menus(cursor):
+    """根据需求文档插入菜单数据"""
+    print("📋 根据需求文档插入菜单数据...")
+    
+    menus_data = [
+        # ==================== 第一级:主菜单 ====================
+        {
+            'id': 'dashboard-main',
+            'parent_id': None,
+            'name': 'dashboard',
+            'title': '仪表盘',
+            'path': '/dashboard',
+            'component': 'dashboard/Index',
+            'icon': 'House',
+            'sort_order': 1,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统概览和统计信息'
+        },
+        {
+            'id': 'profile-main',
+            'parent_id': None,
+            'name': 'profile',
+            'title': '个人资料',
+            'path': '/profile',
+            'component': 'user/Profile',
+            'icon': 'User',
+            'sort_order': 2,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '个人信息管理'
+        },
+        {
+            'id': 'admin-main',
+            'parent_id': None,
+            'name': 'admin',
+            'title': '系统管理',
+            'path': '/admin',
+            'component': None,
+            'icon': 'Setting',
+            'sort_order': 3,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统管理功能'
+        },
+        
+        # ==================== 个人资料的按钮权限 ====================
+        {
+            'id': 'profile-save-btn',
+            'parent_id': 'profile-main',
+            'name': 'profile-save',
+            'title': '保存修改',
+            'path': None,
+            'component': None,
+            'icon': 'Check',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '保存个人资料修改'
+        },
+        {
+            'id': 'profile-reset-btn',
+            'parent_id': 'profile-main',
+            'name': 'profile-reset',
+            'title': '重置',
+            'path': None,
+            'component': None,
+            'icon': 'RefreshLeft',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '重置个人资料表单'
+        },
+        {
+            'id': 'profile-change-password-btn',
+            'parent_id': 'profile-main',
+            'name': 'profile-change-password',
+            'title': '修改密码',
+            'path': None,
+            'component': None,
+            'icon': 'Key',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '修改登录密码'
+        },
+        
+        # ==================== 第二级:系统管理下的功能菜单 ====================
+        {
+            'id': 'admin-dashboard',
+            'parent_id': 'admin-main',
+            'name': 'admin-dashboard',
+            'title': '管理概览',
+            'path': '/admin/dashboard',
+            'component': 'admin/Dashboard',
+            'icon': 'Monitor',
+            'sort_order': 1,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '管理员仪表盘'
+        },
+        {
+            'id': 'user-management',
+            'parent_id': 'admin-main',
+            'name': 'user-management',
+            'title': '用户管理',
+            'path': '/admin/users',
+            'component': 'admin/Users',
+            'icon': 'UserFilled',
+            'sort_order': 2,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '用户信息管理'
+        },
+        {
+            'id': 'role-management',
+            'parent_id': 'admin-main',
+            'name': 'role-management',
+            'title': '角色管理',
+            'path': '/admin/roles',
+            'component': 'admin/Roles',
+            'icon': 'Avatar',
+            'sort_order': 3,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '角色权限管理'
+        },
+        {
+            'id': 'menu-management',
+            'parent_id': 'admin-main',
+            'name': 'menu-management',
+            'title': '菜单管理',
+            'path': '/admin/menus',
+            'component': 'admin/Menus',
+            'icon': 'Menu',
+            'sort_order': 4,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '菜单结构管理'
+        },
+        {
+            'id': 'permission-management',
+            'parent_id': 'admin-main',
+            'name': 'permission-management',
+            'title': '权限管理',
+            'path': '/admin/permissions',
+            'component': 'admin/Permissions',
+            'icon': 'Key',
+            'sort_order': 5,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '权限配置管理'
+        },
+        {
+            'id': 'app-management',
+            'parent_id': 'admin-main',
+            'name': 'app-management',
+            'title': '应用管理',
+            'path': '/admin/apps',
+            'component': 'admin/Apps',
+            'icon': 'Grid',
+            'sort_order': 6,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': 'OAuth2应用管理'
+        },
+        {
+            'id': 'log-management',
+            'parent_id': 'admin-main',
+            'name': 'log-management',
+            'title': '系统日志',
+            'path': '/admin/logs',
+            'component': 'admin/Logs',
+            'icon': 'Document',
+            'sort_order': 7,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统操作日志'
+        },
+        {
+            'id': 'system-settings',
+            'parent_id': 'admin-main',
+            'name': 'system-settings',
+            'title': '系统设置',
+            'path': '/admin/settings',
+            'component': 'admin/Settings',
+            'icon': 'Tools',
+            'sort_order': 8,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统配置设置'
+        },
+        
+        # ==================== 管理概览的按钮权限 ====================
+        {
+            'id': 'admin-dashboard-user-mgmt-btn',
+            'parent_id': 'admin-dashboard',
+            'name': 'admin-dashboard-user-mgmt',
+            'title': '用户管理',
+            'path': None,
+            'component': None,
+            'icon': 'UserFilled',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '快速跳转到用户管理'
+        },
+        {
+            'id': 'admin-dashboard-create-user-btn',
+            'parent_id': 'admin-dashboard',
+            'name': 'admin-dashboard-create-user',
+            'title': '创建用户',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '快速创建用户'
+        },
+        {
+            'id': 'admin-dashboard-app-mgmt-btn',
+            'parent_id': 'admin-dashboard',
+            'name': 'admin-dashboard-app-mgmt',
+            'title': '应用管理',
+            'path': None,
+            'component': None,
+            'icon': 'Grid',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '快速跳转到应用管理'
+        },
+        {
+            'id': 'admin-dashboard-create-app-btn',
+            'parent_id': 'admin-dashboard',
+            'name': 'admin-dashboard-create-app',
+            'title': '创建应用',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '快速创建应用'
+        },
+        {
+            'id': 'admin-dashboard-view-logs-btn',
+            'parent_id': 'admin-dashboard',
+            'name': 'admin-dashboard-view-logs',
+            'title': '查看日志',
+            'path': None,
+            'component': None,
+            'icon': 'View',
+            'sort_order': 5,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '快速查看系统日志'
+        },
+        {
+            'id': 'admin-dashboard-export-logs-btn',
+            'parent_id': 'admin-dashboard',
+            'name': 'admin-dashboard-export-logs',
+            'title': '导出日志',
+            'path': None,
+            'component': None,
+            'icon': 'Download',
+            'sort_order': 6,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '快速导出日志'
+        },
+        {
+            'id': 'admin-dashboard-settings-btn',
+            'parent_id': 'admin-dashboard',
+            'name': 'admin-dashboard-settings',
+            'title': '系统设置',
+            'path': None,
+            'component': None,
+            'icon': 'Tools',
+            'sort_order': 7,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '快速跳转到系统设置'
+        },
+        
+        # ==================== 用户管理的按钮权限 ====================
+        {
+            'id': 'user-create-btn',
+            'parent_id': 'user-management',
+            'name': 'user-create',
+            'title': '创建用户',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新用户'
+        },
+        {
+            'id': 'user-edit-btn',
+            'parent_id': 'user-management',
+            'name': 'user-edit',
+            'title': '编辑用户',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑用户信息'
+        },
+        {
+            'id': 'user-delete-btn',
+            'parent_id': 'user-management',
+            'name': 'user-delete',
+            'title': '删除用户',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除用户'
+        },
+        {
+            'id': 'user-batch-delete-btn',
+            'parent_id': 'user-management',
+            'name': 'user-batch-delete',
+            'title': '批量删除用户',
+            'path': None,
+            'component': None,
+            'icon': 'DeleteFilled',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '批量删除用户'
+        },
+        {
+            'id': 'user-assign-role-btn',
+            'parent_id': 'user-management',
+            'name': 'user-assign-role',
+            'title': '分配角色',
+            'path': None,
+            'component': None,
+            'icon': 'Avatar',
+            'sort_order': 5,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '为用户分配角色'
+        },
+        {
+            'id': 'user-reset-password-btn',
+            'parent_id': 'user-management',
+            'name': 'user-reset-password',
+            'title': '重置密码',
+            'path': None,
+            'component': None,
+            'icon': 'Key',
+            'sort_order': 6,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '重置用户密码'
+        },
+        
+        # ==================== 角色管理的按钮权限 ====================
+        {
+            'id': 'role-create-btn',
+            'parent_id': 'role-management',
+            'name': 'role-create',
+            'title': '创建角色',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新角色'
+        },
+        {
+            'id': 'role-edit-btn',
+            'parent_id': 'role-management',
+            'name': 'role-edit',
+            'title': '编辑角色',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑角色信息'
+        },
+        {
+            'id': 'role-delete-btn',
+            'parent_id': 'role-management',
+            'name': 'role-delete',
+            'title': '删除角色',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除角色'
+        },
+        {
+            'id': 'role-permission-mgmt-btn',
+            'parent_id': 'role-management',
+            'name': 'role-permission-mgmt',
+            'title': '权限管理',
+            'path': None,
+            'component': None,
+            'icon': 'Key',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '管理角色权限'
+        },
+        
+        # ==================== 菜单管理的按钮权限 ====================
+        {
+            'id': 'menu-create-btn',
+            'parent_id': 'menu-management',
+            'name': 'menu-create',
+            'title': '创建菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新菜单'
+        },
+        {
+            'id': 'menu-edit-btn',
+            'parent_id': 'menu-management',
+            'name': 'menu-edit',
+            'title': '编辑菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑菜单信息'
+        },
+        {
+            'id': 'menu-delete-btn',
+            'parent_id': 'menu-management',
+            'name': 'menu-delete',
+            'title': '删除菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除菜单'
+        },
+        {
+            'id': 'menu-sort-btn',
+            'parent_id': 'menu-management',
+            'name': 'menu-sort',
+            'title': '排序菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Sort',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '调整菜单排序'
+        },
+        
+        # ==================== 权限管理的按钮权限 ====================
+        {
+            'id': 'permission-create-btn',
+            'parent_id': 'permission-management',
+            'name': 'permission-create',
+            'title': '创建权限',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新权限'
+        },
+        {
+            'id': 'permission-edit-btn',
+            'parent_id': 'permission-management',
+            'name': 'permission-edit',
+            'title': '编辑权限',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑权限信息'
+        },
+        {
+            'id': 'permission-delete-btn',
+            'parent_id': 'permission-management',
+            'name': 'permission-delete',
+            'title': '删除权限',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除权限'
+        },
+        {
+            'id': 'permission-view-roles-btn',
+            'parent_id': 'permission-management',
+            'name': 'permission-view-roles',
+            'title': '查看角色',
+            'path': None,
+            'component': None,
+            'icon': 'View',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '查看权限关联的角色'
+        },
+        
+        # ==================== 应用管理的按钮权限 ====================
+        {
+            'id': 'app-create-btn',
+            'parent_id': 'app-management',
+            'name': 'app-create',
+            'title': '创建应用',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建OAuth2应用'
+        },
+        {
+            'id': 'app-edit-btn',
+            'parent_id': 'app-management',
+            'name': 'app-edit',
+            'title': '编辑应用',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑应用信息'
+        },
+        {
+            'id': 'app-delete-btn',
+            'parent_id': 'app-management',
+            'name': 'app-delete',
+            'title': '删除应用',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除应用'
+        },
+        {
+            'id': 'app-view-secret-btn',
+            'parent_id': 'app-management',
+            'name': 'app-view-secret',
+            'title': '查看密钥',
+            'path': None,
+            'component': None,
+            'icon': 'View',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '查看应用密钥'
+        },
+        {
+            'id': 'app-reset-secret-btn',
+            'parent_id': 'app-management',
+            'name': 'app-reset-secret',
+            'title': '重置密钥',
+            'path': None,
+            'component': None,
+            'icon': 'RefreshRight',
+            'sort_order': 5,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '重置应用密钥'
+        },
+        {
+            'id': 'app-view-logs-btn',
+            'parent_id': 'app-management',
+            'name': 'app-view-logs',
+            'title': '查看日志',
+            'path': None,
+            'component': None,
+            'icon': 'Document',
+            'sort_order': 6,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '查看应用相关日志'
+        },
+        
+        # ==================== 系统日志的按钮权限 ====================
+        {
+            'id': 'log-view-btn',
+            'parent_id': 'log-management',
+            'name': 'log-view',
+            'title': '查看日志',
+            'path': None,
+            'component': None,
+            'icon': 'View',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '查看系统日志'
+        },
+        {
+            'id': 'log-export-btn',
+            'parent_id': 'log-management',
+            'name': 'log-export',
+            'title': '导出日志',
+            'path': None,
+            'component': None,
+            'icon': 'Download',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '导出系统日志'
+        },
+        {
+            'id': 'log-clear-btn',
+            'parent_id': 'log-management',
+            'name': 'log-clear',
+            'title': '清理日志',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '清理历史日志'
+        },
+        
+        # ==================== 系统设置的按钮权限 ====================
+        {
+            'id': 'settings-view-btn',
+            'parent_id': 'system-settings',
+            'name': 'settings-view',
+            'title': '查看设置',
+            'path': None,
+            'component': None,
+            'icon': 'View',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '查看系统设置'
+        },
+        {
+            'id': 'settings-edit-btn',
+            'parent_id': 'system-settings',
+            'name': 'settings-edit',
+            'title': '修改设置',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '修改系统设置'
+        }
+    ]
+    
+    for menu in menus_data:
+        cursor.execute("""
+            INSERT INTO menus (id, parent_id, name, title, path, component, icon, sort_order, menu_type, is_hidden, is_active, description, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (
+            menu['id'], menu['parent_id'], menu['name'], menu['title'], 
+            menu['path'], menu['component'], menu['icon'], menu['sort_order'],
+            menu['menu_type'], menu['is_hidden'], True, menu['description']
+        ))
+    
+    print(f"   ✅ 插入了 {len(menus_data)} 个菜单项")
+    
+    # 统计各级菜单数量
+    main_menus = len([m for m in menus_data if not m['parent_id']])
+    function_menus = len([m for m in menus_data if m['parent_id'] and m['menu_type'] == 'menu'])
+    button_permissions = len([m for m in menus_data if m['menu_type'] == 'button'])
+    
+    print(f"   📊 菜单结构统计:")
+    print(f"      📁 主菜单: {main_menus} 个")
+    print(f"      📄 功能菜单: {function_menus} 个")
+    print(f"      🔘 按钮权限: {button_permissions} 个")
+
+def insert_roles(cursor):
+    """插入角色数据"""
+    print("👥 插入角色数据...")
+    
+    roles_data = [
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'super_admin',
+            'display_name': '超级管理员',
+            'description': '拥有系统所有权限的超级管理员',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'admin',
+            'display_name': '管理员',
+            'description': '系统管理员,拥有大部分管理权限',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'user_manager',
+            'display_name': '用户管理员',
+            'description': '负责用户和角色管理的管理员',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'app_manager',
+            'display_name': '应用管理员',
+            'description': '负责应用管理的管理员',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'user',
+            'display_name': '普通用户',
+            'description': '系统普通用户',
+            'is_system': True
+        }
+    ]
+    
+    role_ids = {}
+    for role in roles_data:
+        cursor.execute("""
+            INSERT INTO roles (id, name, display_name, description, is_active, is_system, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (role['id'], role['name'], role['display_name'], role['description'], True, role['is_system']))
+        role_ids[role['name']] = role['id']
+    
+    print(f"   ✅ 插入了 {len(roles_data)} 个角色")
+    return role_ids
+
+def insert_permissions(cursor):
+    """插入权限数据"""
+    print("🔐 插入权限数据...")
+    
+    permissions_data = [
+        # 个人资料权限
+        {'name': 'profile.save', 'display_name': '保存个人资料', 'resource': 'profile', 'action': 'save', 'description': '保存个人资料修改'},
+        {'name': 'profile.reset', 'display_name': '重置个人资料', 'resource': 'profile', 'action': 'reset', 'description': '重置个人资料表单'},
+        {'name': 'profile.change_password', 'display_name': '修改密码', 'resource': 'profile', 'action': 'change_password', 'description': '修改登录密码'},
+        
+        # 管理概览权限
+        {'name': 'admin.dashboard', 'display_name': '管理概览', 'resource': 'admin', 'action': 'dashboard', 'description': '查看管理概览'},
+        {'name': 'admin.quick_user_mgmt', 'display_name': '快速用户管理', 'resource': 'admin', 'action': 'quick_user_mgmt', 'description': '快速跳转到用户管理'},
+        {'name': 'admin.quick_create_user', 'display_name': '快速创建用户', 'resource': 'admin', 'action': 'quick_create_user', 'description': '快速创建用户'},
+        {'name': 'admin.quick_app_mgmt', 'display_name': '快速应用管理', 'resource': 'admin', 'action': 'quick_app_mgmt', 'description': '快速跳转到应用管理'},
+        {'name': 'admin.quick_create_app', 'display_name': '快速创建应用', 'resource': 'admin', 'action': 'quick_create_app', 'description': '快速创建应用'},
+        {'name': 'admin.quick_view_logs', 'display_name': '快速查看日志', 'resource': 'admin', 'action': 'quick_view_logs', 'description': '快速查看系统日志'},
+        {'name': 'admin.quick_export_logs', 'display_name': '快速导出日志', 'resource': 'admin', 'action': 'quick_export_logs', 'description': '快速导出日志'},
+        {'name': 'admin.quick_settings', 'display_name': '快速系统设置', 'resource': 'admin', 'action': 'quick_settings', 'description': '快速跳转到系统设置'},
+        
+        # 用户管理权限
+        {'name': 'user.view', 'display_name': '查看用户', 'resource': 'user', 'action': 'view', 'description': '查看用户列表和详情'},
+        {'name': 'user.create', 'display_name': '创建用户', 'resource': 'user', 'action': 'create', 'description': '创建新用户'},
+        {'name': 'user.edit', 'display_name': '编辑用户', 'resource': 'user', 'action': 'edit', 'description': '编辑用户信息'},
+        {'name': 'user.delete', 'display_name': '删除用户', 'resource': 'user', 'action': 'delete', 'description': '删除用户'},
+        {'name': 'user.batch_delete', 'display_name': '批量删除用户', 'resource': 'user', 'action': 'batch_delete', 'description': '批量删除用户'},
+        {'name': 'user.assign_role', 'display_name': '分配用户角色', 'resource': 'user', 'action': 'assign_role', 'description': '为用户分配角色'},
+        {'name': 'user.reset_password', 'display_name': '重置用户密码', 'resource': 'user', 'action': 'reset_password', 'description': '重置用户密码'},
+        
+        # 角色管理权限
+        {'name': 'role.view', 'display_name': '查看角色', 'resource': 'role', 'action': 'view', 'description': '查看角色列表和详情'},
+        {'name': 'role.create', 'display_name': '创建角色', 'resource': 'role', 'action': 'create', 'description': '创建新角色'},
+        {'name': 'role.edit', 'display_name': '编辑角色', 'resource': 'role', 'action': 'edit', 'description': '编辑角色信息'},
+        {'name': 'role.delete', 'display_name': '删除角色', 'resource': 'role', 'action': 'delete', 'description': '删除角色'},
+        {'name': 'role.permission_mgmt', 'display_name': '角色权限管理', 'resource': 'role', 'action': 'permission_mgmt', 'description': '管理角色权限'},
+        
+        # 菜单管理权限
+        {'name': 'menu.view', 'display_name': '查看菜单', 'resource': 'menu', 'action': 'view', 'description': '查看菜单列表和详情'},
+        {'name': 'menu.create', 'display_name': '创建菜单', 'resource': 'menu', 'action': 'create', 'description': '创建新菜单'},
+        {'name': 'menu.edit', 'display_name': '编辑菜单', 'resource': 'menu', 'action': 'edit', 'description': '编辑菜单信息'},
+        {'name': 'menu.delete', 'display_name': '删除菜单', 'resource': 'menu', 'action': 'delete', 'description': '删除菜单'},
+        {'name': 'menu.sort', 'display_name': '排序菜单', 'resource': 'menu', 'action': 'sort', 'description': '调整菜单排序'},
+        
+        # 权限管理权限
+        {'name': 'permission.view', 'display_name': '查看权限', 'resource': 'permission', 'action': 'view', 'description': '查看权限列表和详情'},
+        {'name': 'permission.create', 'display_name': '创建权限', 'resource': 'permission', 'action': 'create', 'description': '创建新权限'},
+        {'name': 'permission.edit', 'display_name': '编辑权限', 'resource': 'permission', 'action': 'edit', 'description': '编辑权限信息'},
+        {'name': 'permission.delete', 'display_name': '删除权限', 'resource': 'permission', 'action': 'delete', 'description': '删除权限'},
+        {'name': 'permission.view_roles', 'display_name': '查看权限角色', 'resource': 'permission', 'action': 'view_roles', 'description': '查看权限关联的角色'},
+        
+        # 应用管理权限
+        {'name': 'app.view', 'display_name': '查看应用', 'resource': 'app', 'action': 'view', 'description': '查看应用列表和详情'},
+        {'name': 'app.create', 'display_name': '创建应用', 'resource': 'app', 'action': 'create', 'description': '创建OAuth2应用'},
+        {'name': 'app.edit', 'display_name': '编辑应用', 'resource': 'app', 'action': 'edit', 'description': '编辑应用信息'},
+        {'name': 'app.delete', 'display_name': '删除应用', 'resource': 'app', 'action': 'delete', 'description': '删除应用'},
+        {'name': 'app.view_secret', 'display_name': '查看应用密钥', 'resource': 'app', 'action': 'view_secret', 'description': '查看应用密钥'},
+        {'name': 'app.reset_secret', 'display_name': '重置应用密钥', 'resource': 'app', 'action': 'reset_secret', 'description': '重置应用密钥'},
+        {'name': 'app.view_logs', 'display_name': '查看应用日志', 'resource': 'app', 'action': 'view_logs', 'description': '查看应用相关日志'},
+        
+        # 系统日志权限
+        {'name': 'log.view', 'display_name': '查看系统日志', 'resource': 'log', 'action': 'view', 'description': '查看系统操作日志'},
+        {'name': 'log.export', 'display_name': '导出系统日志', 'resource': 'log', 'action': 'export', 'description': '导出系统日志'},
+        {'name': 'log.clear', 'display_name': '清理系统日志', 'resource': 'log', 'action': 'clear', 'description': '清理历史日志'},
+        
+        # 系统设置权限
+        {'name': 'settings.view', 'display_name': '查看系统设置', 'resource': 'settings', 'action': 'view', 'description': '查看系统配置'},
+        {'name': 'settings.edit', 'display_name': '修改系统设置', 'resource': 'settings', 'action': 'edit', 'description': '修改系统配置'},
+    ]
+    
+    permission_ids = {}
+    for perm in permissions_data:
+        perm_id = str(uuid.uuid4())
+        cursor.execute("""
+            INSERT INTO permissions (id, name, display_name, resource, action, description, is_active, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (perm_id, perm['name'], perm['display_name'], perm['resource'], perm['action'], perm['description'], True))
+        permission_ids[perm['name']] = perm_id
+    
+    print(f"   ✅ 插入了 {len(permissions_data)} 个权限")
+    return permission_ids
+
+def assign_role_permissions(cursor, role_ids, permission_ids):
+    """分配角色权限"""
+    print("🔗 分配角色权限...")
+    
+    # 超级管理员拥有所有权限
+    super_admin_id = role_ids['super_admin']
+    for perm_name, perm_id in permission_ids.items():
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (super_admin_id, perm_id))
+    
+    # 管理员拥有大部分权限(除了系统设置修改)
+    admin_id = role_ids['admin']
+    admin_permissions = [perm for perm in permission_ids.keys() if not perm.startswith('settings.edit')]
+    for perm_name in admin_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (admin_id, permission_ids[perm_name]))
+    
+    # 用户管理员只有用户和角色相关权限
+    user_manager_id = role_ids['user_manager']
+    user_permissions = [perm for perm in permission_ids.keys() if perm.startswith(('user.', 'role.', 'admin.dashboard', 'admin.quick_user', 'profile.'))]
+    for perm_name in user_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (user_manager_id, permission_ids[perm_name]))
+    
+    # 应用管理员只有应用相关权限
+    app_manager_id = role_ids['app_manager']
+    app_permissions = [perm for perm in permission_ids.keys() if perm.startswith(('app.', 'admin.dashboard', 'admin.quick_app', 'profile.'))]
+    for perm_name in app_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (app_manager_id, permission_ids[perm_name]))
+    
+    # 普通用户只有基础权限
+    user_id = role_ids['user']
+    user_permissions = [perm for perm in permission_ids.keys() if perm.startswith('profile.')]
+    for perm_name in user_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (user_id, permission_ids[perm_name]))
+    
+    print("   ✅ 角色权限分配完成")
+
+def assign_role_menus(cursor, role_ids):
+    """分配角色菜单"""
+    print("🔗 分配角色菜单...")
+    
+    # 获取所有菜单ID
+    cursor.execute("SELECT id, parent_id, menu_type FROM menus")
+    all_menus = cursor.fetchall()
+    menu_ids = [menu[0] for menu in all_menus]
+    
+    # 超级管理员和管理员拥有所有菜单
+    for role_name in ['super_admin', 'admin']:
+        role_id = role_ids[role_name]
+        for menu_id in menu_ids:
+            cursor.execute("""
+                INSERT INTO role_menus (role_id, menu_id, created_at)
+                VALUES (%s, %s, NOW())
+            """, (role_id, menu_id))
+    
+    # 用户管理员只有基础菜单和用户管理相关菜单
+    user_manager_id = role_ids['user_manager']
+    user_manager_menus = [
+        'dashboard-main', 'profile-main', 'admin-main', 'admin-dashboard', 
+        'user-management', 'role-management'
+    ]
+    # 添加相关的按钮权限
+    cursor.execute("SELECT id FROM menus WHERE parent_id IN ('profile-main', 'admin-dashboard', 'user-management', 'role-management')")
+    user_buttons = cursor.fetchall()
+    user_manager_menus.extend([btn[0] for btn in user_buttons])
+    
+    for menu_id in user_manager_menus:
+        cursor.execute("""
+            INSERT INTO role_menus (role_id, menu_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (user_manager_id, menu_id))
+    
+    # 应用管理员只有基础菜单和应用管理相关菜单
+    app_manager_id = role_ids['app_manager']
+    app_manager_menus = [
+        'dashboard-main', 'profile-main', 'admin-main', 'admin-dashboard', 
+        'app-management'
+    ]
+    # 添加相关的按钮权限
+    cursor.execute("SELECT id FROM menus WHERE parent_id IN ('profile-main', 'admin-dashboard', 'app-management')")
+    app_buttons = cursor.fetchall()
+    app_manager_menus.extend([btn[0] for btn in app_buttons])
+    
+    for menu_id in app_manager_menus:
+        cursor.execute("""
+            INSERT INTO role_menus (role_id, menu_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (app_manager_id, menu_id))
+    
+    # 普通用户只有基础菜单
+    user_id = role_ids['user']
+    user_menus = ['dashboard-main', 'profile-main']
+    # 添加个人资料的按钮权限
+    cursor.execute("SELECT id FROM menus WHERE parent_id = 'profile-main'")
+    profile_buttons = cursor.fetchall()
+    user_menus.extend([btn[0] for btn in profile_buttons])
+    
+    for menu_id in user_menus:
+        cursor.execute("""
+            INSERT INTO role_menus (role_id, menu_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (user_id, menu_id))
+    
+    print("   ✅ 角色菜单分配完成")
+
+def assign_user_roles(cursor, role_ids):
+    """为现有用户分配角色"""
+    print("👤 为用户分配角色...")
+    
+    # 获取admin用户
+    cursor.execute("SELECT id FROM users WHERE username = 'admin'")
+    admin_user = cursor.fetchone()
+    if admin_user:
+        admin_user_id = admin_user[0]
+        # 为admin用户分配超级管理员角色
+        cursor.execute("""
+            INSERT INTO user_roles (user_id, role_id, is_active, created_at)
+            VALUES (%s, %s, %s, NOW())
+        """, (admin_user_id, role_ids['super_admin'], True))
+        print(f"   ✅ 为admin用户分配了超级管理员角色")
+    
+    # 获取其他用户并分配普通用户角色
+    cursor.execute("SELECT id, username FROM users WHERE username != 'admin'")
+    other_users = cursor.fetchall()
+    for user in other_users:
+        user_id, username = user
+        cursor.execute("""
+            INSERT INTO user_roles (user_id, role_id, is_active, created_at)
+            VALUES (%s, %s, %s, NOW())
+        """, (user_id, role_ids['user'], True))
+        print(f"   ✅ 为用户 {username} 分配了普通用户角色")
+
+def print_menu_structure(cursor):
+    """打印菜单结构验证"""
+    print("\n🌳 根据需求文档的菜单结构:")
+    print("=" * 60)
+    
+    # 获取所有菜单
+    cursor.execute("""
+        SELECT id, parent_id, title, menu_type, sort_order 
+        FROM menus 
+        ORDER BY 
+            CASE WHEN parent_id IS NULL THEN 0 ELSE 1 END,
+            sort_order, 
+            CASE WHEN menu_type = 'menu' THEN 0 ELSE 1 END
+    """)
+    all_menus = cursor.fetchall()
+    
+    # 构建菜单树
+    menu_dict = {}
+    for menu in all_menus:
+        menu_id, parent_id, title, menu_type, sort_order = menu
+        menu_dict[menu_id] = {
+            'id': menu_id,
+            'parent_id': parent_id,
+            'title': title,
+            'menu_type': menu_type,
+            'sort_order': sort_order,
+            'children': []
+        }
+    
+    # 建立父子关系
+    root_menus = []
+    for menu_id, menu_data in menu_dict.items():
+        if menu_data['parent_id']:
+            if menu_data['parent_id'] in menu_dict:
+                menu_dict[menu_data['parent_id']]['children'].append(menu_data)
+        else:
+            root_menus.append(menu_data)
+    
+    # 打印树形结构
+    def print_menu_tree(menus, level=0):
+        for menu in sorted(menus, key=lambda x: x['sort_order']):
+            indent = "  " * level
+            if menu['menu_type'] == 'menu' and level == 0:
+                icon = "📄" if menu['title'] == '仪表盘' else "📁"
+            elif menu['menu_type'] == 'menu':
+                icon = "📄"
+            else:
+                icon = "🔘"
+            
+            print(f"{indent}{icon} {menu['title']} ({menu['menu_type']})")
+            
+            if menu['children']:
+                # 先显示菜单类型的子项,再显示按钮类型的子项
+                menu_children = [c for c in menu['children'] if c['menu_type'] == 'menu']
+                button_children = [c for c in menu['children'] if c['menu_type'] == 'button']
+                print_menu_tree(menu_children, level + 1)
+                print_menu_tree(button_children, level + 1)
+    
+    print_menu_tree(root_menus)
+
+def reinit_menus_by_requirements():
+    """根据需求文档重新初始化菜单数据"""
+    print("🚀 根据需求/菜单.md重新初始化RBAC数据")
+    print("=" * 60)
+    
+    conn = get_db_connection()
+    if not conn:
+        print("❌ 数据库连接失败")
+        return False
+    
+    cursor = conn.cursor()
+    
+    try:
+        # 1. 清理现有数据
+        clear_rbac_data(cursor)
+        
+        # 2. 根据需求文档插入菜单数据
+        insert_menus(cursor)
+        
+        # 3. 插入角色数据
+        role_ids = insert_roles(cursor)
+        
+        # 4. 插入权限数据
+        permission_ids = insert_permissions(cursor)
+        
+        # 5. 分配角色权限
+        assign_role_permissions(cursor, role_ids, permission_ids)
+        
+        # 6. 分配角色菜单
+        assign_role_menus(cursor, role_ids)
+        
+        # 7. 为用户分配角色
+        assign_user_roles(cursor, role_ids)
+        
+        # 8. 打印菜单结构验证
+        print_menu_structure(cursor)
+        
+        conn.commit()
+        
+        print("\n" + "=" * 60)
+        print("🎉 根据需求文档的RBAC数据初始化完成!")
+        print("=" * 60)
+        print("📊 数据统计:")
+        
+        # 统计数据
+        cursor.execute("SELECT COUNT(*) FROM menus")
+        menu_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM menus WHERE menu_type = 'menu' AND parent_id IS NULL")
+        main_menu_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM menus WHERE menu_type = 'menu' AND parent_id IS NOT NULL")
+        function_menu_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM menus WHERE menu_type = 'button'")
+        button_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM roles")
+        role_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM permissions")
+        permission_count = cursor.fetchone()[0]
+        
+        print(f"   📁 主菜单: {main_menu_count} 个")
+        print(f"   📄 功能菜单: {function_menu_count} 个")
+        print(f"   🔘 按钮权限: {button_count} 个")
+        print(f"   📋 菜单总数: {menu_count} 个")
+        print(f"   👥 角色数量: {role_count} 个")
+        print(f"   🔐 权限数量: {permission_count} 个")
+        print("=" * 60)
+        
+        return True
+        
+    except Exception as e:
+        print(f"❌ 初始化失败: {e}")
+        conn.rollback()
+        return False
+    finally:
+        cursor.close()
+        conn.close()
+
+def main():
+    """主函数"""
+    success = reinit_menus_by_requirements()
+    if success:
+        print("\n🎯 根据需求文档的菜单初始化成功!")
+        print("💡 建议重启前端服务以刷新菜单缓存。")
+        print("\n🌐 访问地址:")
+        print("   前端: http://localhost:3000")
+        print("   菜单管理: http://localhost:3000/admin/menus")
+        print("\n🔑 登录信息:")
+        print("   用户名: admin")
+        print("   密码: Admin123456")
+        print("\n📋 需求文档对应:")
+        print("   - 严格按照 OAuth2_system/需求/菜单.md 的结构设计")
+        print("   - 包含个人资料的按钮权限(保存修改、重置、修改密码)")
+        print("   - 管理概览包含快速操作按钮")
+        print("   - 所有功能菜单都有对应的按钮权限")
+    else:
+        print("\n❌ 根据需求文档的菜单初始化失败!")
+
+if __name__ == "__main__":
+    main()

+ 852 - 0
reinit_rbac_data.py

@@ -0,0 +1,852 @@
+#!/usr/bin/env python3
+"""
+重新初始化RBAC数据 - 包含完整的树形菜单结构
+"""
+import pymysql
+from dotenv import load_dotenv
+import os
+import uuid
+from datetime import datetime
+
+load_dotenv()
+
+def get_db_connection():
+    """获取数据库连接"""
+    try:
+        config = {
+            'host': os.getenv('DB_HOST', 'localhost'),
+            'port': int(os.getenv('DB_PORT', 3306)),
+            'user': os.getenv('DB_USER', 'root'),
+            'password': os.getenv('DB_PASSWORD', 'admin'),
+            'database': os.getenv('DB_NAME', 'lq_db'),
+            'charset': 'utf8mb4',
+            'autocommit': True
+        }
+        return pymysql.connect(**config)
+    except Exception as e:
+        print(f"数据库连接失败: {e}")
+        return None
+
+def clear_rbac_data(cursor):
+    """清理现有RBAC数据"""
+    print("🧹 清理现有RBAC数据...")
+    
+    # 清理关联表
+    cursor.execute("DELETE FROM role_permissions")
+    cursor.execute("DELETE FROM role_menus")
+    cursor.execute("DELETE FROM user_roles")
+    
+    # 清理主表
+    cursor.execute("DELETE FROM permissions")
+    cursor.execute("DELETE FROM menus")
+    cursor.execute("DELETE FROM roles")
+    
+    print("   ✅ 清理完成")
+
+def insert_menus(cursor):
+    """插入菜单数据"""
+    print("📋 插入菜单数据...")
+    
+    menus_data = [
+        # 主菜单
+        {
+            'id': 'dashboard-menu',
+            'parent_id': None,
+            'name': 'dashboard',
+            'title': '仪表盘',
+            'path': '/dashboard',
+            'component': 'dashboard/Index',
+            'icon': 'House',
+            'sort_order': 1,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统概览和统计信息'
+        },
+        {
+            'id': 'profile-menu',
+            'parent_id': None,
+            'name': 'profile',
+            'title': '个人资料',
+            'path': '/profile',
+            'component': 'user/Profile',
+            'icon': 'User',
+            'sort_order': 2,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '个人信息管理'
+        },
+        {
+            'id': 'admin-menu',
+            'parent_id': None,
+            'name': 'admin',
+            'title': '系统管理',
+            'path': '/admin',
+            'component': None,
+            'icon': 'Setting',
+            'sort_order': 3,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统管理功能'
+        },
+        
+        # 系统管理子菜单
+        {
+            'id': 'admin-dashboard-menu',
+            'parent_id': 'admin-menu',
+            'name': 'admin-dashboard',
+            'title': '管理概览',
+            'path': '/admin/dashboard',
+            'component': 'admin/Dashboard',
+            'icon': 'Monitor',
+            'sort_order': 1,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '管理员仪表盘'
+        },
+        {
+            'id': 'admin-users-menu',
+            'parent_id': 'admin-menu',
+            'name': 'admin-users',
+            'title': '用户管理',
+            'path': '/admin/users',
+            'component': 'admin/Users',
+            'icon': 'UserFilled',
+            'sort_order': 2,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '用户信息管理'
+        },
+        {
+            'id': 'admin-roles-menu',
+            'parent_id': 'admin-menu',
+            'name': 'admin-roles',
+            'title': '角色管理',
+            'path': '/admin/roles',
+            'component': 'admin/Roles',
+            'icon': 'Avatar',
+            'sort_order': 3,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '角色权限管理'
+        },
+        {
+            'id': 'admin-menus-menu',
+            'parent_id': 'admin-menu',
+            'name': 'admin-menus',
+            'title': '菜单管理',
+            'path': '/admin/menus',
+            'component': 'admin/Menus',
+            'icon': 'Menu',
+            'sort_order': 4,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '菜单结构管理'
+        },
+        {
+            'id': 'admin-permissions-menu',
+            'parent_id': 'admin-menu',
+            'name': 'admin-permissions',
+            'title': '权限管理',
+            'path': '/admin/permissions',
+            'component': 'admin/Permissions',
+            'icon': 'Key',
+            'sort_order': 5,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '权限配置管理'
+        },
+        {
+            'id': 'admin-apps-menu',
+            'parent_id': 'admin-menu',
+            'name': 'admin-apps',
+            'title': '应用管理',
+            'path': '/admin/apps',
+            'component': 'admin/Apps',
+            'icon': 'Grid',
+            'sort_order': 6,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': 'OAuth2应用管理'
+        },
+        {
+            'id': 'admin-logs-menu',
+            'parent_id': 'admin-menu',
+            'name': 'admin-logs',
+            'title': '系统日志',
+            'path': '/admin/logs',
+            'component': 'admin/Logs',
+            'icon': 'Document',
+            'sort_order': 7,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统操作日志'
+        },
+        {
+            'id': 'admin-settings-menu',
+            'parent_id': 'admin-menu',
+            'name': 'admin-settings',
+            'title': '系统设置',
+            'path': '/admin/settings',
+            'component': 'admin/Settings',
+            'icon': 'Tools',
+            'sort_order': 8,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统配置设置'
+        },
+        
+        # 用户管理按钮权限
+        {
+            'id': 'users-create-btn',
+            'parent_id': 'admin-users-menu',
+            'name': 'users-create',
+            'title': '创建用户',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新用户'
+        },
+        {
+            'id': 'users-edit-btn',
+            'parent_id': 'admin-users-menu',
+            'name': 'users-edit',
+            'title': '编辑用户',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑用户信息'
+        },
+        {
+            'id': 'users-delete-btn',
+            'parent_id': 'admin-users-menu',
+            'name': 'users-delete',
+            'title': '删除用户',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除用户'
+        },
+        {
+            'id': 'users-batch-delete-btn',
+            'parent_id': 'admin-users-menu',
+            'name': 'users-batch-delete',
+            'title': '批量删除',
+            'path': None,
+            'component': None,
+            'icon': 'DeleteFilled',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '批量删除用户'
+        },
+        {
+            'id': 'users-assign-role-btn',
+            'parent_id': 'admin-users-menu',
+            'name': 'users-assign-role',
+            'title': '分配角色',
+            'path': None,
+            'component': None,
+            'icon': 'Avatar',
+            'sort_order': 5,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '为用户分配角色'
+        },
+        {
+            'id': 'users-reset-password-btn',
+            'parent_id': 'admin-users-menu',
+            'name': 'users-reset-password',
+            'title': '重置密码',
+            'path': None,
+            'component': None,
+            'icon': 'Key',
+            'sort_order': 6,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '重置用户密码'
+        },
+        
+        # 角色管理按钮权限
+        {
+            'id': 'roles-create-btn',
+            'parent_id': 'admin-roles-menu',
+            'name': 'roles-create',
+            'title': '创建角色',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新角色'
+        },
+        {
+            'id': 'roles-edit-btn',
+            'parent_id': 'admin-roles-menu',
+            'name': 'roles-edit',
+            'title': '编辑角色',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑角色信息'
+        },
+        {
+            'id': 'roles-delete-btn',
+            'parent_id': 'admin-roles-menu',
+            'name': 'roles-delete',
+            'title': '删除角色',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除角色'
+        },
+        {
+            'id': 'roles-assign-permission-btn',
+            'parent_id': 'admin-roles-menu',
+            'name': 'roles-assign-permission',
+            'title': '分配权限',
+            'path': None,
+            'component': None,
+            'icon': 'Key',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '为角色分配权限'
+        },
+        {
+            'id': 'roles-assign-menu-btn',
+            'parent_id': 'admin-roles-menu',
+            'name': 'roles-assign-menu',
+            'title': '分配菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Menu',
+            'sort_order': 5,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '为角色分配菜单'
+        },
+        
+        # 菜单管理按钮权限
+        {
+            'id': 'menus-create-btn',
+            'parent_id': 'admin-menus-menu',
+            'name': 'menus-create',
+            'title': '创建菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新菜单'
+        },
+        {
+            'id': 'menus-edit-btn',
+            'parent_id': 'admin-menus-menu',
+            'name': 'menus-edit',
+            'title': '编辑菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑菜单信息'
+        },
+        {
+            'id': 'menus-delete-btn',
+            'parent_id': 'admin-menus-menu',
+            'name': 'menus-delete',
+            'title': '删除菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除菜单'
+        },
+        {
+            'id': 'menus-sort-btn',
+            'parent_id': 'admin-menus-menu',
+            'name': 'menus-sort',
+            'title': '排序菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Sort',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '调整菜单排序'
+        },
+        
+        # 权限管理按钮权限
+        {
+            'id': 'permissions-create-btn',
+            'parent_id': 'admin-permissions-menu',
+            'name': 'permissions-create',
+            'title': '创建权限',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新权限'
+        },
+        {
+            'id': 'permissions-edit-btn',
+            'parent_id': 'admin-permissions-menu',
+            'name': 'permissions-edit',
+            'title': '编辑权限',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑权限信息'
+        },
+        {
+            'id': 'permissions-delete-btn',
+            'parent_id': 'admin-permissions-menu',
+            'name': 'permissions-delete',
+            'title': '删除权限',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除权限'
+        },
+        
+        # 应用管理按钮权限
+        {
+            'id': 'apps-create-btn',
+            'parent_id': 'admin-apps-menu',
+            'name': 'apps-create',
+            'title': '创建应用',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建OAuth2应用'
+        },
+        {
+            'id': 'apps-edit-btn',
+            'parent_id': 'admin-apps-menu',
+            'name': 'apps-edit',
+            'title': '编辑应用',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑应用信息'
+        },
+        {
+            'id': 'apps-delete-btn',
+            'parent_id': 'admin-apps-menu',
+            'name': 'apps-delete',
+            'title': '删除应用',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除应用'
+        },
+        {
+            'id': 'apps-secret-btn',
+            'parent_id': 'admin-apps-menu',
+            'name': 'apps-secret',
+            'title': '查看密钥',
+            'path': None,
+            'component': None,
+            'icon': 'Key',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '查看应用密钥'
+        },
+        {
+            'id': 'apps-reset-secret-btn',
+            'parent_id': 'admin-apps-menu',
+            'name': 'apps-reset-secret',
+            'title': '重置密钥',
+            'path': None,
+            'component': None,
+            'icon': 'RefreshRight',
+            'sort_order': 5,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '重置应用密钥'
+        }
+    ]
+    
+    for menu in menus_data:
+        cursor.execute("""
+            INSERT INTO menus (id, parent_id, name, title, path, component, icon, sort_order, menu_type, is_hidden, is_active, description, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (
+            menu['id'], menu['parent_id'], menu['name'], menu['title'], 
+            menu['path'], menu['component'], menu['icon'], menu['sort_order'],
+            menu['menu_type'], menu['is_hidden'], True, menu['description']
+        ))
+    
+    print(f"   ✅ 插入了 {len(menus_data)} 个菜单项")
+
+def insert_roles(cursor):
+    """插入角色数据"""
+    print("👥 插入角色数据...")
+    
+    roles_data = [
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'super_admin',
+            'display_name': '超级管理员',
+            'description': '拥有系统所有权限的超级管理员',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'admin',
+            'display_name': '管理员',
+            'description': '系统管理员,拥有大部分管理权限',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'user_manager',
+            'display_name': '用户管理员',
+            'description': '负责用户管理的管理员',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'app_manager',
+            'display_name': '应用管理员',
+            'description': '负责应用管理的管理员',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'user',
+            'display_name': '普通用户',
+            'description': '系统普通用户',
+            'is_system': True
+        }
+    ]
+    
+    role_ids = {}
+    for role in roles_data:
+        cursor.execute("""
+            INSERT INTO roles (id, name, display_name, description, is_active, is_system, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (role['id'], role['name'], role['display_name'], role['description'], True, role['is_system']))
+        role_ids[role['name']] = role['id']
+    
+    print(f"   ✅ 插入了 {len(roles_data)} 个角色")
+    return role_ids
+
+def insert_permissions(cursor):
+    """插入权限数据"""
+    print("🔐 插入权限数据...")
+    
+    permissions_data = [
+        # 用户管理权限
+        {'name': 'user.view', 'display_name': '查看用户', 'resource': 'user', 'action': 'view', 'description': '查看用户列表和详情'},
+        {'name': 'user.create', 'display_name': '创建用户', 'resource': 'user', 'action': 'create', 'description': '创建新用户'},
+        {'name': 'user.edit', 'display_name': '编辑用户', 'resource': 'user', 'action': 'edit', 'description': '编辑用户信息'},
+        {'name': 'user.delete', 'display_name': '删除用户', 'resource': 'user', 'action': 'delete', 'description': '删除用户'},
+        {'name': 'user.batch_delete', 'display_name': '批量删除用户', 'resource': 'user', 'action': 'batch_delete', 'description': '批量删除用户'},
+        {'name': 'user.assign_role', 'display_name': '分配用户角色', 'resource': 'user', 'action': 'assign_role', 'description': '为用户分配角色'},
+        {'name': 'user.reset_password', 'display_name': '重置用户密码', 'resource': 'user', 'action': 'reset_password', 'description': '重置用户密码'},
+        
+        # 角色管理权限
+        {'name': 'role.view', 'display_name': '查看角色', 'resource': 'role', 'action': 'view', 'description': '查看角色列表和详情'},
+        {'name': 'role.create', 'display_name': '创建角色', 'resource': 'role', 'action': 'create', 'description': '创建新角色'},
+        {'name': 'role.edit', 'display_name': '编辑角色', 'resource': 'role', 'action': 'edit', 'description': '编辑角色信息'},
+        {'name': 'role.delete', 'display_name': '删除角色', 'resource': 'role', 'action': 'delete', 'description': '删除角色'},
+        {'name': 'role.assign_permission', 'display_name': '分配角色权限', 'resource': 'role', 'action': 'assign_permission', 'description': '为角色分配权限'},
+        {'name': 'role.assign_menu', 'display_name': '分配角色菜单', 'resource': 'role', 'action': 'assign_menu', 'description': '为角色分配菜单'},
+        
+        # 菜单管理权限
+        {'name': 'menu.view', 'display_name': '查看菜单', 'resource': 'menu', 'action': 'view', 'description': '查看菜单列表和详情'},
+        {'name': 'menu.create', 'display_name': '创建菜单', 'resource': 'menu', 'action': 'create', 'description': '创建新菜单'},
+        {'name': 'menu.edit', 'display_name': '编辑菜单', 'resource': 'menu', 'action': 'edit', 'description': '编辑菜单信息'},
+        {'name': 'menu.delete', 'display_name': '删除菜单', 'resource': 'menu', 'action': 'delete', 'description': '删除菜单'},
+        {'name': 'menu.sort', 'display_name': '排序菜单', 'resource': 'menu', 'action': 'sort', 'description': '调整菜单排序'},
+        
+        # 权限管理权限
+        {'name': 'permission.view', 'display_name': '查看权限', 'resource': 'permission', 'action': 'view', 'description': '查看权限列表和详情'},
+        {'name': 'permission.create', 'display_name': '创建权限', 'resource': 'permission', 'action': 'create', 'description': '创建新权限'},
+        {'name': 'permission.edit', 'display_name': '编辑权限', 'resource': 'permission', 'action': 'edit', 'description': '编辑权限信息'},
+        {'name': 'permission.delete', 'display_name': '删除权限', 'resource': 'permission', 'action': 'delete', 'description': '删除权限'},
+        
+        # 应用管理权限
+        {'name': 'app.view', 'display_name': '查看应用', 'resource': 'app', 'action': 'view', 'description': '查看应用列表和详情'},
+        {'name': 'app.create', 'display_name': '创建应用', 'resource': 'app', 'action': 'create', 'description': '创建OAuth2应用'},
+        {'name': 'app.edit', 'display_name': '编辑应用', 'resource': 'app', 'action': 'edit', 'description': '编辑应用信息'},
+        {'name': 'app.delete', 'display_name': '删除应用', 'resource': 'app', 'action': 'delete', 'description': '删除应用'},
+        {'name': 'app.secret', 'display_name': '查看应用密钥', 'resource': 'app', 'action': 'secret', 'description': '查看应用密钥'},
+        {'name': 'app.reset_secret', 'display_name': '重置应用密钥', 'resource': 'app', 'action': 'reset_secret', 'description': '重置应用密钥'},
+        
+        # 系统管理权限
+        {'name': 'system.view', 'display_name': '查看系统信息', 'resource': 'system', 'action': 'view', 'description': '查看系统信息和统计'},
+        {'name': 'system.config', 'display_name': '系统配置', 'resource': 'system', 'action': 'config', 'description': '修改系统配置'},
+        {'name': 'system.log', 'display_name': '查看系统日志', 'resource': 'system', 'action': 'log', 'description': '查看系统操作日志'},
+    ]
+    
+    permission_ids = {}
+    for perm in permissions_data:
+        perm_id = str(uuid.uuid4())
+        cursor.execute("""
+            INSERT INTO permissions (id, name, display_name, resource, action, description, is_active, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (perm_id, perm['name'], perm['display_name'], perm['resource'], perm['action'], perm['description'], True))
+        permission_ids[perm['name']] = perm_id
+    
+    print(f"   ✅ 插入了 {len(permissions_data)} 个权限")
+    return permission_ids
+
+def assign_role_permissions(cursor, role_ids, permission_ids):
+    """分配角色权限"""
+    print("🔗 分配角色权限...")
+    
+    # 超级管理员拥有所有权限
+    super_admin_id = role_ids['super_admin']
+    for perm_name, perm_id in permission_ids.items():
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (super_admin_id, perm_id))
+    
+    # 管理员拥有大部分权限(除了系统配置)
+    admin_id = role_ids['admin']
+    admin_permissions = [perm for perm in permission_ids.keys() if not perm.startswith('system.config')]
+    for perm_name in admin_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (admin_id, permission_ids[perm_name]))
+    
+    # 用户管理员只有用户相关权限
+    user_manager_id = role_ids['user_manager']
+    user_permissions = [perm for perm in permission_ids.keys() if perm.startswith('user.') or perm.startswith('role.')]
+    for perm_name in user_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (user_manager_id, permission_ids[perm_name]))
+    
+    # 应用管理员只有应用相关权限
+    app_manager_id = role_ids['app_manager']
+    app_permissions = [perm for perm in permission_ids.keys() if perm.startswith('app.')]
+    for perm_name in app_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (app_manager_id, permission_ids[perm_name]))
+    
+    print("   ✅ 角色权限分配完成")
+
+def assign_role_menus(cursor, role_ids):
+    """分配角色菜单"""
+    print("🔗 分配角色菜单...")
+    
+    # 获取所有菜单ID
+    cursor.execute("SELECT id, parent_id FROM menus")
+    all_menus = cursor.fetchall()
+    menu_ids = [menu[0] for menu in all_menus]
+    
+    # 超级管理员和管理员拥有所有菜单
+    for role_name in ['super_admin', 'admin']:
+        role_id = role_ids[role_name]
+        for menu_id in menu_ids:
+            cursor.execute("""
+                INSERT INTO role_menus (role_id, menu_id, created_at)
+                VALUES (%s, %s, NOW())
+            """, (role_id, menu_id))
+    
+    # 用户管理员只有基础菜单和用户管理相关菜单
+    user_manager_id = role_ids['user_manager']
+    user_manager_menus = [
+        'dashboard-menu', 'profile-menu', 'admin-menu', 'admin-dashboard-menu', 
+        'admin-users-menu', 'admin-roles-menu'
+    ]
+    # 添加用户管理相关的按钮权限
+    cursor.execute("SELECT id FROM menus WHERE parent_id IN ('admin-users-menu', 'admin-roles-menu')")
+    user_buttons = cursor.fetchall()
+    user_manager_menus.extend([btn[0] for btn in user_buttons])
+    
+    for menu_id in user_manager_menus:
+        cursor.execute("""
+            INSERT INTO role_menus (role_id, menu_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (user_manager_id, menu_id))
+    
+    # 应用管理员只有基础菜单和应用管理相关菜单
+    app_manager_id = role_ids['app_manager']
+    app_manager_menus = [
+        'dashboard-menu', 'profile-menu', 'admin-menu', 'admin-dashboard-menu', 
+        'admin-apps-menu'
+    ]
+    # 添加应用管理相关的按钮权限
+    cursor.execute("SELECT id FROM menus WHERE parent_id = 'admin-apps-menu'")
+    app_buttons = cursor.fetchall()
+    app_manager_menus.extend([btn[0] for btn in app_buttons])
+    
+    for menu_id in app_manager_menus:
+        cursor.execute("""
+            INSERT INTO role_menus (role_id, menu_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (app_manager_id, menu_id))
+    
+    # 普通用户只有基础菜单
+    user_id = role_ids['user']
+    user_menus = ['dashboard-menu', 'profile-menu']
+    for menu_id in user_menus:
+        cursor.execute("""
+            INSERT INTO role_menus (role_id, menu_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (user_id, menu_id))
+    
+    print("   ✅ 角色菜单分配完成")
+
+def assign_user_roles(cursor, role_ids):
+    """为现有用户分配角色"""
+    print("👤 为用户分配角色...")
+    
+    # 获取admin用户
+    cursor.execute("SELECT id FROM users WHERE username = 'admin'")
+    admin_user = cursor.fetchone()
+    if admin_user:
+        admin_user_id = admin_user[0]
+        # 为admin用户分配超级管理员角色
+        cursor.execute("""
+            INSERT INTO user_roles (user_id, role_id, is_active, created_at)
+            VALUES (%s, %s, %s, NOW())
+        """, (admin_user_id, role_ids['super_admin'], True))
+        print(f"   ✅ 为admin用户分配了超级管理员角色")
+    
+    # 获取其他用户并分配普通用户角色
+    cursor.execute("SELECT id, username FROM users WHERE username != 'admin'")
+    other_users = cursor.fetchall()
+    for user in other_users:
+        user_id, username = user
+        cursor.execute("""
+            INSERT INTO user_roles (user_id, role_id, is_active, created_at)
+            VALUES (%s, %s, %s, NOW())
+        """, (user_id, role_ids['user'], True))
+        print(f"   ✅ 为用户 {username} 分配了普通用户角色")
+
+def reinit_rbac_data():
+    """重新初始化RBAC数据"""
+    print("🚀 开始重新初始化RBAC数据")
+    print("=" * 60)
+    
+    conn = get_db_connection()
+    if not conn:
+        print("❌ 数据库连接失败")
+        return False
+    
+    cursor = conn.cursor()
+    
+    try:
+        # 1. 清理现有数据
+        clear_rbac_data(cursor)
+        
+        # 2. 插入菜单数据
+        insert_menus(cursor)
+        
+        # 3. 插入角色数据
+        role_ids = insert_roles(cursor)
+        
+        # 4. 插入权限数据
+        permission_ids = insert_permissions(cursor)
+        
+        # 5. 分配角色权限
+        assign_role_permissions(cursor, role_ids, permission_ids)
+        
+        # 6. 分配角色菜单
+        assign_role_menus(cursor, role_ids)
+        
+        # 7. 为用户分配角色
+        assign_user_roles(cursor, role_ids)
+        
+        conn.commit()
+        
+        print("\n" + "=" * 60)
+        print("🎉 RBAC数据重新初始化完成!")
+        print("=" * 60)
+        print("📊 数据统计:")
+        
+        # 统计数据
+        cursor.execute("SELECT COUNT(*) FROM menus")
+        menu_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM menus WHERE menu_type = 'menu'")
+        menu_menu_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM menus WHERE menu_type = 'button'")
+        button_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM roles")
+        role_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM permissions")
+        permission_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM role_permissions")
+        role_permission_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM role_menus")
+        role_menu_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM user_roles")
+        user_role_count = cursor.fetchone()[0]
+        
+        print(f"   📋 菜单总数: {menu_count} (菜单: {menu_menu_count}, 按钮: {button_count})")
+        print(f"   👥 角色数量: {role_count}")
+        print(f"   🔐 权限数量: {permission_count}")
+        print(f"   🔗 角色权限关联: {role_permission_count}")
+        print(f"   🔗 角色菜单关联: {role_menu_count}")
+        print(f"   👤 用户角色关联: {user_role_count}")
+        print("=" * 60)
+        
+        return True
+        
+    except Exception as e:
+        print(f"❌ 初始化失败: {e}")
+        conn.rollback()
+        return False
+    finally:
+        cursor.close()
+        conn.close()
+
+def main():
+    """主函数"""
+    success = reinit_rbac_data()
+    if success:
+        print("\n🎯 重新初始化成功!现在可以测试完整的树形菜单结构了。")
+        print("💡 建议重启前端服务以刷新菜单缓存。")
+    else:
+        print("\n❌ 重新初始化失败!")
+
+if __name__ == "__main__":
+    main()

+ 1002 - 0
reinit_rbac_data_fixed.py

@@ -0,0 +1,1002 @@
+#!/usr/bin/env python3
+"""
+重新初始化RBAC数据 - 修复菜单层级关系混乱问题
+清晰的三级结构:父目录菜单 > 功能菜单 > 按钮权限
+"""
+import pymysql
+from dotenv import load_dotenv
+import os
+import uuid
+from datetime import datetime
+
+load_dotenv()
+
+def get_db_connection():
+    """获取数据库连接"""
+    try:
+        config = {
+            'host': os.getenv('DB_HOST', 'localhost'),
+            'port': int(os.getenv('DB_PORT', 3306)),
+            'user': os.getenv('DB_USER', 'root'),
+            'password': os.getenv('DB_PASSWORD', 'admin'),
+            'database': os.getenv('DB_NAME', 'lq_db'),
+            'charset': 'utf8mb4',
+            'autocommit': True
+        }
+        return pymysql.connect(**config)
+    except Exception as e:
+        print(f"数据库连接失败: {e}")
+        return None
+
+def clear_rbac_data(cursor):
+    """清理现有RBAC数据"""
+    print("🧹 清理现有RBAC数据...")
+    
+    # 清理关联表
+    cursor.execute("DELETE FROM role_permissions")
+    cursor.execute("DELETE FROM role_menus")
+    cursor.execute("DELETE FROM user_roles")
+    
+    # 清理主表
+    cursor.execute("DELETE FROM permissions")
+    cursor.execute("DELETE FROM menus")
+    cursor.execute("DELETE FROM roles")
+    
+    print("   ✅ 清理完成")
+
+def insert_menus(cursor):
+    """插入菜单数据 - 清晰的三级结构"""
+    print("📋 插入菜单数据(修复层级关系)...")
+    
+    menus_data = [
+        # ==================== 第一级:主菜单(父目录菜单) ====================
+        {
+            'id': 'dashboard-main',
+            'parent_id': None,
+            'name': 'dashboard',
+            'title': '仪表盘',
+            'path': '/dashboard',
+            'component': 'dashboard/Index',
+            'icon': 'House',
+            'sort_order': 1,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统概览和统计信息'
+        },
+        {
+            'id': 'profile-main',
+            'parent_id': None,
+            'name': 'profile',
+            'title': '个人资料',
+            'path': '/profile',
+            'component': 'user/Profile',
+            'icon': 'User',
+            'sort_order': 2,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '个人信息管理'
+        },
+        {
+            'id': 'admin-main',
+            'parent_id': None,
+            'name': 'admin',
+            'title': '系统管理',
+            'path': '/admin',
+            'component': None,
+            'icon': 'Setting',
+            'sort_order': 3,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统管理功能目录'
+        },
+        
+        # ==================== 第二级:功能菜单 ====================
+        # 系统管理下的功能菜单
+        {
+            'id': 'admin-dashboard',
+            'parent_id': 'admin-main',
+            'name': 'admin-dashboard',
+            'title': '管理概览',
+            'path': '/admin/dashboard',
+            'component': 'admin/Dashboard',
+            'icon': 'Monitor',
+            'sort_order': 1,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '管理员仪表盘'
+        },
+        {
+            'id': 'user-management',
+            'parent_id': 'admin-main',
+            'name': 'user-management',
+            'title': '用户管理',
+            'path': '/admin/users',
+            'component': 'admin/Users',
+            'icon': 'UserFilled',
+            'sort_order': 2,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '用户信息管理'
+        },
+        {
+            'id': 'role-management',
+            'parent_id': 'admin-main',
+            'name': 'role-management',
+            'title': '角色管理',
+            'path': '/admin/roles',
+            'component': 'admin/Roles',
+            'icon': 'Avatar',
+            'sort_order': 3,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '角色权限管理'
+        },
+        {
+            'id': 'menu-management',
+            'parent_id': 'admin-main',
+            'name': 'menu-management',
+            'title': '菜单管理',
+            'path': '/admin/menus',
+            'component': 'admin/Menus',
+            'icon': 'Menu',
+            'sort_order': 4,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '菜单结构管理'
+        },
+        {
+            'id': 'permission-management',
+            'parent_id': 'admin-main',
+            'name': 'permission-management',
+            'title': '权限管理',
+            'path': '/admin/permissions',
+            'component': 'admin/Permissions',
+            'icon': 'Key',
+            'sort_order': 5,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '权限配置管理'
+        },
+        {
+            'id': 'app-management',
+            'parent_id': 'admin-main',
+            'name': 'app-management',
+            'title': '应用管理',
+            'path': '/admin/apps',
+            'component': 'admin/Apps',
+            'icon': 'Grid',
+            'sort_order': 6,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': 'OAuth2应用管理'
+        },
+        {
+            'id': 'log-management',
+            'parent_id': 'admin-main',
+            'name': 'log-management',
+            'title': '系统日志',
+            'path': '/admin/logs',
+            'component': 'admin/Logs',
+            'icon': 'Document',
+            'sort_order': 7,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统操作日志'
+        },
+        {
+            'id': 'system-settings',
+            'parent_id': 'admin-main',
+            'name': 'system-settings',
+            'title': '系统设置',
+            'path': '/admin/settings',
+            'component': 'admin/Settings',
+            'icon': 'Tools',
+            'sort_order': 8,
+            'menu_type': 'menu',
+            'is_hidden': False,
+            'description': '系统配置设置'
+        },
+        
+        # ==================== 第三级:按钮权限 ====================
+        # 用户管理的按钮权限
+        {
+            'id': 'user-create-btn',
+            'parent_id': 'user-management',
+            'name': 'user-create',
+            'title': '创建用户',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新用户'
+        },
+        {
+            'id': 'user-edit-btn',
+            'parent_id': 'user-management',
+            'name': 'user-edit',
+            'title': '编辑用户',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑用户信息'
+        },
+        {
+            'id': 'user-delete-btn',
+            'parent_id': 'user-management',
+            'name': 'user-delete',
+            'title': '删除用户',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除用户'
+        },
+        {
+            'id': 'user-batch-delete-btn',
+            'parent_id': 'user-management',
+            'name': 'user-batch-delete',
+            'title': '批量删除用户',
+            'path': None,
+            'component': None,
+            'icon': 'DeleteFilled',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '批量删除用户'
+        },
+        {
+            'id': 'user-assign-role-btn',
+            'parent_id': 'user-management',
+            'name': 'user-assign-role',
+            'title': '分配角色',
+            'path': None,
+            'component': None,
+            'icon': 'Avatar',
+            'sort_order': 5,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '为用户分配角色'
+        },
+        {
+            'id': 'user-reset-password-btn',
+            'parent_id': 'user-management',
+            'name': 'user-reset-password',
+            'title': '重置密码',
+            'path': None,
+            'component': None,
+            'icon': 'Key',
+            'sort_order': 6,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '重置用户密码'
+        },
+        
+        # 角色管理的按钮权限
+        {
+            'id': 'role-create-btn',
+            'parent_id': 'role-management',
+            'name': 'role-create',
+            'title': '创建角色',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新角色'
+        },
+        {
+            'id': 'role-edit-btn',
+            'parent_id': 'role-management',
+            'name': 'role-edit',
+            'title': '编辑角色',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑角色信息'
+        },
+        {
+            'id': 'role-delete-btn',
+            'parent_id': 'role-management',
+            'name': 'role-delete',
+            'title': '删除角色',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除角色'
+        },
+        {
+            'id': 'role-assign-permission-btn',
+            'parent_id': 'role-management',
+            'name': 'role-assign-permission',
+            'title': '分配权限',
+            'path': None,
+            'component': None,
+            'icon': 'Key',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '为角色分配权限'
+        },
+        {
+            'id': 'role-assign-menu-btn',
+            'parent_id': 'role-management',
+            'name': 'role-assign-menu',
+            'title': '分配菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Menu',
+            'sort_order': 5,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '为角色分配菜单'
+        },
+        
+        # 菜单管理的按钮权限
+        {
+            'id': 'menu-create-btn',
+            'parent_id': 'menu-management',
+            'name': 'menu-create',
+            'title': '创建菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新菜单'
+        },
+        {
+            'id': 'menu-edit-btn',
+            'parent_id': 'menu-management',
+            'name': 'menu-edit',
+            'title': '编辑菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑菜单信息'
+        },
+        {
+            'id': 'menu-delete-btn',
+            'parent_id': 'menu-management',
+            'name': 'menu-delete',
+            'title': '删除菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除菜单'
+        },
+        {
+            'id': 'menu-sort-btn',
+            'parent_id': 'menu-management',
+            'name': 'menu-sort',
+            'title': '排序菜单',
+            'path': None,
+            'component': None,
+            'icon': 'Sort',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '调整菜单排序'
+        },
+        
+        # 权限管理的按钮权限
+        {
+            'id': 'permission-create-btn',
+            'parent_id': 'permission-management',
+            'name': 'permission-create',
+            'title': '创建权限',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建新权限'
+        },
+        {
+            'id': 'permission-edit-btn',
+            'parent_id': 'permission-management',
+            'name': 'permission-edit',
+            'title': '编辑权限',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑权限信息'
+        },
+        {
+            'id': 'permission-delete-btn',
+            'parent_id': 'permission-management',
+            'name': 'permission-delete',
+            'title': '删除权限',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除权限'
+        },
+        
+        # 应用管理的按钮权限
+        {
+            'id': 'app-create-btn',
+            'parent_id': 'app-management',
+            'name': 'app-create',
+            'title': '创建应用',
+            'path': None,
+            'component': None,
+            'icon': 'Plus',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '创建OAuth2应用'
+        },
+        {
+            'id': 'app-edit-btn',
+            'parent_id': 'app-management',
+            'name': 'app-edit',
+            'title': '编辑应用',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '编辑应用信息'
+        },
+        {
+            'id': 'app-delete-btn',
+            'parent_id': 'app-management',
+            'name': 'app-delete',
+            'title': '删除应用',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '删除应用'
+        },
+        {
+            'id': 'app-view-secret-btn',
+            'parent_id': 'app-management',
+            'name': 'app-view-secret',
+            'title': '查看密钥',
+            'path': None,
+            'component': None,
+            'icon': 'View',
+            'sort_order': 4,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '查看应用密钥'
+        },
+        {
+            'id': 'app-reset-secret-btn',
+            'parent_id': 'app-management',
+            'name': 'app-reset-secret',
+            'title': '重置密钥',
+            'path': None,
+            'component': None,
+            'icon': 'RefreshRight',
+            'sort_order': 5,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '重置应用密钥'
+        },
+        
+        # 系统日志的按钮权限
+        {
+            'id': 'log-view-btn',
+            'parent_id': 'log-management',
+            'name': 'log-view',
+            'title': '查看日志',
+            'path': None,
+            'component': None,
+            'icon': 'View',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '查看系统日志'
+        },
+        {
+            'id': 'log-export-btn',
+            'parent_id': 'log-management',
+            'name': 'log-export',
+            'title': '导出日志',
+            'path': None,
+            'component': None,
+            'icon': 'Download',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '导出系统日志'
+        },
+        {
+            'id': 'log-clear-btn',
+            'parent_id': 'log-management',
+            'name': 'log-clear',
+            'title': '清理日志',
+            'path': None,
+            'component': None,
+            'icon': 'Delete',
+            'sort_order': 3,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '清理历史日志'
+        },
+        
+        # 系统设置的按钮权限
+        {
+            'id': 'settings-view-btn',
+            'parent_id': 'system-settings',
+            'name': 'settings-view',
+            'title': '查看设置',
+            'path': None,
+            'component': None,
+            'icon': 'View',
+            'sort_order': 1,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '查看系统设置'
+        },
+        {
+            'id': 'settings-edit-btn',
+            'parent_id': 'system-settings',
+            'name': 'settings-edit',
+            'title': '修改设置',
+            'path': None,
+            'component': None,
+            'icon': 'Edit',
+            'sort_order': 2,
+            'menu_type': 'button',
+            'is_hidden': False,
+            'description': '修改系统设置'
+        }
+    ]
+    
+    for menu in menus_data:
+        cursor.execute("""
+            INSERT INTO menus (id, parent_id, name, title, path, component, icon, sort_order, menu_type, is_hidden, is_active, description, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (
+            menu['id'], menu['parent_id'], menu['name'], menu['title'], 
+            menu['path'], menu['component'], menu['icon'], menu['sort_order'],
+            menu['menu_type'], menu['is_hidden'], True, menu['description']
+        ))
+    
+    print(f"   ✅ 插入了 {len(menus_data)} 个菜单项")
+    
+    # 统计各级菜单数量
+    main_menus = len([m for m in menus_data if not m['parent_id']])
+    function_menus = len([m for m in menus_data if m['parent_id'] and m['menu_type'] == 'menu'])
+    button_permissions = len([m for m in menus_data if m['menu_type'] == 'button'])
+    
+    print(f"   📊 菜单结构统计:")
+    print(f"      📁 主菜单(父目录): {main_menus} 个")
+    print(f"      📄 功能菜单: {function_menus} 个")
+    print(f"      🔘 按钮权限: {button_permissions} 个")
+
+def insert_roles(cursor):
+    """插入角色数据"""
+    print("👥 插入角色数据...")
+    
+    roles_data = [
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'super_admin',
+            'display_name': '超级管理员',
+            'description': '拥有系统所有权限的超级管理员',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'admin',
+            'display_name': '管理员',
+            'description': '系统管理员,拥有大部分管理权限',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'user_manager',
+            'display_name': '用户管理员',
+            'description': '负责用户和角色管理的管理员',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'app_manager',
+            'display_name': '应用管理员',
+            'description': '负责应用管理的管理员',
+            'is_system': True
+        },
+        {
+            'id': str(uuid.uuid4()),
+            'name': 'user',
+            'display_name': '普通用户',
+            'description': '系统普通用户',
+            'is_system': True
+        }
+    ]
+    
+    role_ids = {}
+    for role in roles_data:
+        cursor.execute("""
+            INSERT INTO roles (id, name, display_name, description, is_active, is_system, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (role['id'], role['name'], role['display_name'], role['description'], True, role['is_system']))
+        role_ids[role['name']] = role['id']
+    
+    print(f"   ✅ 插入了 {len(roles_data)} 个角色")
+    return role_ids
+
+def insert_permissions(cursor):
+    """插入权限数据"""
+    print("🔐 插入权限数据...")
+    
+    permissions_data = [
+        # 用户管理权限
+        {'name': 'user.view', 'display_name': '查看用户', 'resource': 'user', 'action': 'view', 'description': '查看用户列表和详情'},
+        {'name': 'user.create', 'display_name': '创建用户', 'resource': 'user', 'action': 'create', 'description': '创建新用户'},
+        {'name': 'user.edit', 'display_name': '编辑用户', 'resource': 'user', 'action': 'edit', 'description': '编辑用户信息'},
+        {'name': 'user.delete', 'display_name': '删除用户', 'resource': 'user', 'action': 'delete', 'description': '删除用户'},
+        {'name': 'user.batch_delete', 'display_name': '批量删除用户', 'resource': 'user', 'action': 'batch_delete', 'description': '批量删除用户'},
+        {'name': 'user.assign_role', 'display_name': '分配用户角色', 'resource': 'user', 'action': 'assign_role', 'description': '为用户分配角色'},
+        {'name': 'user.reset_password', 'display_name': '重置用户密码', 'resource': 'user', 'action': 'reset_password', 'description': '重置用户密码'},
+        
+        # 角色管理权限
+        {'name': 'role.view', 'display_name': '查看角色', 'resource': 'role', 'action': 'view', 'description': '查看角色列表和详情'},
+        {'name': 'role.create', 'display_name': '创建角色', 'resource': 'role', 'action': 'create', 'description': '创建新角色'},
+        {'name': 'role.edit', 'display_name': '编辑角色', 'resource': 'role', 'action': 'edit', 'description': '编辑角色信息'},
+        {'name': 'role.delete', 'display_name': '删除角色', 'resource': 'role', 'action': 'delete', 'description': '删除角色'},
+        {'name': 'role.assign_permission', 'display_name': '分配角色权限', 'resource': 'role', 'action': 'assign_permission', 'description': '为角色分配权限'},
+        {'name': 'role.assign_menu', 'display_name': '分配角色菜单', 'resource': 'role', 'action': 'assign_menu', 'description': '为角色分配菜单'},
+        
+        # 菜单管理权限
+        {'name': 'menu.view', 'display_name': '查看菜单', 'resource': 'menu', 'action': 'view', 'description': '查看菜单列表和详情'},
+        {'name': 'menu.create', 'display_name': '创建菜单', 'resource': 'menu', 'action': 'create', 'description': '创建新菜单'},
+        {'name': 'menu.edit', 'display_name': '编辑菜单', 'resource': 'menu', 'action': 'edit', 'description': '编辑菜单信息'},
+        {'name': 'menu.delete', 'display_name': '删除菜单', 'resource': 'menu', 'action': 'delete', 'description': '删除菜单'},
+        {'name': 'menu.sort', 'display_name': '排序菜单', 'resource': 'menu', 'action': 'sort', 'description': '调整菜单排序'},
+        
+        # 权限管理权限
+        {'name': 'permission.view', 'display_name': '查看权限', 'resource': 'permission', 'action': 'view', 'description': '查看权限列表和详情'},
+        {'name': 'permission.create', 'display_name': '创建权限', 'resource': 'permission', 'action': 'create', 'description': '创建新权限'},
+        {'name': 'permission.edit', 'display_name': '编辑权限', 'resource': 'permission', 'action': 'edit', 'description': '编辑权限信息'},
+        {'name': 'permission.delete', 'display_name': '删除权限', 'resource': 'permission', 'action': 'delete', 'description': '删除权限'},
+        
+        # 应用管理权限
+        {'name': 'app.view', 'display_name': '查看应用', 'resource': 'app', 'action': 'view', 'description': '查看应用列表和详情'},
+        {'name': 'app.create', 'display_name': '创建应用', 'resource': 'app', 'action': 'create', 'description': '创建OAuth2应用'},
+        {'name': 'app.edit', 'display_name': '编辑应用', 'resource': 'app', 'action': 'edit', 'description': '编辑应用信息'},
+        {'name': 'app.delete', 'display_name': '删除应用', 'resource': 'app', 'action': 'delete', 'description': '删除应用'},
+        {'name': 'app.view_secret', 'display_name': '查看应用密钥', 'resource': 'app', 'action': 'view_secret', 'description': '查看应用密钥'},
+        {'name': 'app.reset_secret', 'display_name': '重置应用密钥', 'resource': 'app', 'action': 'reset_secret', 'description': '重置应用密钥'},
+        
+        # 系统管理权限
+        {'name': 'system.dashboard', 'display_name': '管理概览', 'resource': 'system', 'action': 'dashboard', 'description': '查看管理概览'},
+        {'name': 'system.log_view', 'display_name': '查看系统日志', 'resource': 'system', 'action': 'log_view', 'description': '查看系统操作日志'},
+        {'name': 'system.log_export', 'display_name': '导出系统日志', 'resource': 'system', 'action': 'log_export', 'description': '导出系统日志'},
+        {'name': 'system.log_clear', 'display_name': '清理系统日志', 'resource': 'system', 'action': 'log_clear', 'description': '清理历史日志'},
+        {'name': 'system.settings_view', 'display_name': '查看系统设置', 'resource': 'system', 'action': 'settings_view', 'description': '查看系统配置'},
+        {'name': 'system.settings_edit', 'display_name': '修改系统设置', 'resource': 'system', 'action': 'settings_edit', 'description': '修改系统配置'},
+    ]
+    
+    permission_ids = {}
+    for perm in permissions_data:
+        perm_id = str(uuid.uuid4())
+        cursor.execute("""
+            INSERT INTO permissions (id, name, display_name, resource, action, description, is_active, created_at, updated_at)
+            VALUES (%s, %s, %s, %s, %s, %s, %s, NOW(), NOW())
+        """, (perm_id, perm['name'], perm['display_name'], perm['resource'], perm['action'], perm['description'], True))
+        permission_ids[perm['name']] = perm_id
+    
+    print(f"   ✅ 插入了 {len(permissions_data)} 个权限")
+    return permission_ids
+
+def assign_role_permissions(cursor, role_ids, permission_ids):
+    """分配角色权限"""
+    print("🔗 分配角色权限...")
+    
+    # 超级管理员拥有所有权限
+    super_admin_id = role_ids['super_admin']
+    for perm_name, perm_id in permission_ids.items():
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (super_admin_id, perm_id))
+    
+    # 管理员拥有大部分权限(除了系统设置修改)
+    admin_id = role_ids['admin']
+    admin_permissions = [perm for perm in permission_ids.keys() if not perm.startswith('system.settings_edit')]
+    for perm_name in admin_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (admin_id, permission_ids[perm_name]))
+    
+    # 用户管理员只有用户和角色相关权限
+    user_manager_id = role_ids['user_manager']
+    user_permissions = [perm for perm in permission_ids.keys() if perm.startswith(('user.', 'role.', 'system.dashboard'))]
+    for perm_name in user_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (user_manager_id, permission_ids[perm_name]))
+    
+    # 应用管理员只有应用相关权限
+    app_manager_id = role_ids['app_manager']
+    app_permissions = [perm for perm in permission_ids.keys() if perm.startswith(('app.', 'system.dashboard'))]
+    for perm_name in app_permissions:
+        cursor.execute("""
+            INSERT INTO role_permissions (role_id, permission_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (app_manager_id, permission_ids[perm_name]))
+    
+    print("   ✅ 角色权限分配完成")
+
+def assign_role_menus(cursor, role_ids):
+    """分配角色菜单"""
+    print("🔗 分配角色菜单...")
+    
+    # 获取所有菜单ID
+    cursor.execute("SELECT id, parent_id, menu_type FROM menus")
+    all_menus = cursor.fetchall()
+    menu_ids = [menu[0] for menu in all_menus]
+    
+    # 超级管理员和管理员拥有所有菜单
+    for role_name in ['super_admin', 'admin']:
+        role_id = role_ids[role_name]
+        for menu_id in menu_ids:
+            cursor.execute("""
+                INSERT INTO role_menus (role_id, menu_id, created_at)
+                VALUES (%s, %s, NOW())
+            """, (role_id, menu_id))
+    
+    # 用户管理员只有基础菜单和用户管理相关菜单
+    user_manager_id = role_ids['user_manager']
+    user_manager_menus = [
+        'dashboard-main', 'profile-main', 'admin-main', 'admin-dashboard', 
+        'user-management', 'role-management'
+    ]
+    # 添加用户管理和角色管理相关的按钮权限
+    cursor.execute("SELECT id FROM menus WHERE parent_id IN ('user-management', 'role-management')")
+    user_buttons = cursor.fetchall()
+    user_manager_menus.extend([btn[0] for btn in user_buttons])
+    
+    for menu_id in user_manager_menus:
+        cursor.execute("""
+            INSERT INTO role_menus (role_id, menu_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (user_manager_id, menu_id))
+    
+    # 应用管理员只有基础菜单和应用管理相关菜单
+    app_manager_id = role_ids['app_manager']
+    app_manager_menus = [
+        'dashboard-main', 'profile-main', 'admin-main', 'admin-dashboard', 
+        'app-management'
+    ]
+    # 添加应用管理相关的按钮权限
+    cursor.execute("SELECT id FROM menus WHERE parent_id = 'app-management'")
+    app_buttons = cursor.fetchall()
+    app_manager_menus.extend([btn[0] for btn in app_buttons])
+    
+    for menu_id in app_manager_menus:
+        cursor.execute("""
+            INSERT INTO role_menus (role_id, menu_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (app_manager_id, menu_id))
+    
+    # 普通用户只有基础菜单
+    user_id = role_ids['user']
+    user_menus = ['dashboard-main', 'profile-main']
+    for menu_id in user_menus:
+        cursor.execute("""
+            INSERT INTO role_menus (role_id, menu_id, created_at)
+            VALUES (%s, %s, NOW())
+        """, (user_id, menu_id))
+    
+    print("   ✅ 角色菜单分配完成")
+
+def assign_user_roles(cursor, role_ids):
+    """为现有用户分配角色"""
+    print("👤 为用户分配角色...")
+    
+    # 获取admin用户
+    cursor.execute("SELECT id FROM users WHERE username = 'admin'")
+    admin_user = cursor.fetchone()
+    if admin_user:
+        admin_user_id = admin_user[0]
+        # 为admin用户分配超级管理员角色
+        cursor.execute("""
+            INSERT INTO user_roles (user_id, role_id, is_active, created_at)
+            VALUES (%s, %s, %s, NOW())
+        """, (admin_user_id, role_ids['super_admin'], True))
+        print(f"   ✅ 为admin用户分配了超级管理员角色")
+    
+    # 获取其他用户并分配普通用户角色
+    cursor.execute("SELECT id, username FROM users WHERE username != 'admin'")
+    other_users = cursor.fetchall()
+    for user in other_users:
+        user_id, username = user
+        cursor.execute("""
+            INSERT INTO user_roles (user_id, role_id, is_active, created_at)
+            VALUES (%s, %s, %s, NOW())
+        """, (user_id, role_ids['user'], True))
+        print(f"   ✅ 为用户 {username} 分配了普通用户角色")
+
+def print_menu_structure(cursor):
+    """打印菜单结构验证"""
+    print("\n🌳 菜单结构验证:")
+    print("=" * 60)
+    
+    # 获取所有菜单
+    cursor.execute("""
+        SELECT id, parent_id, title, menu_type, sort_order 
+        FROM menus 
+        ORDER BY 
+            CASE WHEN parent_id IS NULL THEN 0 ELSE 1 END,
+            sort_order, 
+            CASE WHEN menu_type = 'menu' THEN 0 ELSE 1 END
+    """)
+    all_menus = cursor.fetchall()
+    
+    # 构建菜单树
+    menu_dict = {}
+    for menu in all_menus:
+        menu_id, parent_id, title, menu_type, sort_order = menu
+        menu_dict[menu_id] = {
+            'id': menu_id,
+            'parent_id': parent_id,
+            'title': title,
+            'menu_type': menu_type,
+            'sort_order': sort_order,
+            'children': []
+        }
+    
+    # 建立父子关系
+    root_menus = []
+    for menu_id, menu_data in menu_dict.items():
+        if menu_data['parent_id']:
+            if menu_data['parent_id'] in menu_dict:
+                menu_dict[menu_data['parent_id']]['children'].append(menu_data)
+        else:
+            root_menus.append(menu_data)
+    
+    # 打印树形结构
+    def print_menu_tree(menus, level=0):
+        for menu in sorted(menus, key=lambda x: x['sort_order']):
+            indent = "  " * level
+            if menu['menu_type'] == 'menu' and level == 0:
+                icon = "📁"
+            elif menu['menu_type'] == 'menu':
+                icon = "📄"
+            else:
+                icon = "🔘"
+            
+            print(f"{indent}{icon} {menu['title']} ({menu['menu_type']})")
+            
+            if menu['children']:
+                # 先显示菜单类型的子项,再显示按钮类型的子项
+                menu_children = [c for c in menu['children'] if c['menu_type'] == 'menu']
+                button_children = [c for c in menu['children'] if c['menu_type'] == 'button']
+                print_menu_tree(menu_children, level + 1)
+                print_menu_tree(button_children, level + 1)
+    
+    print_menu_tree(root_menus)
+
+def reinit_rbac_data():
+    """重新初始化RBAC数据 - 修复层级关系"""
+    print("🚀 开始重新初始化RBAC数据(修复层级关系)")
+    print("=" * 60)
+    
+    conn = get_db_connection()
+    if not conn:
+        print("❌ 数据库连接失败")
+        return False
+    
+    cursor = conn.cursor()
+    
+    try:
+        # 1. 清理现有数据
+        clear_rbac_data(cursor)
+        
+        # 2. 插入菜单数据(修复层级关系)
+        insert_menus(cursor)
+        
+        # 3. 插入角色数据
+        role_ids = insert_roles(cursor)
+        
+        # 4. 插入权限数据
+        permission_ids = insert_permissions(cursor)
+        
+        # 5. 分配角色权限
+        assign_role_permissions(cursor, role_ids, permission_ids)
+        
+        # 6. 分配角色菜单
+        assign_role_menus(cursor, role_ids)
+        
+        # 7. 为用户分配角色
+        assign_user_roles(cursor, role_ids)
+        
+        # 8. 打印菜单结构验证
+        print_menu_structure(cursor)
+        
+        conn.commit()
+        
+        print("\n" + "=" * 60)
+        print("🎉 RBAC数据重新初始化完成!(层级关系已修复)")
+        print("=" * 60)
+        print("📊 数据统计:")
+        
+        # 统计数据
+        cursor.execute("SELECT COUNT(*) FROM menus")
+        menu_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM menus WHERE menu_type = 'menu' AND parent_id IS NULL")
+        main_menu_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM menus WHERE menu_type = 'menu' AND parent_id IS NOT NULL")
+        function_menu_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM menus WHERE menu_type = 'button'")
+        button_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM roles")
+        role_count = cursor.fetchone()[0]
+        cursor.execute("SELECT COUNT(*) FROM permissions")
+        permission_count = cursor.fetchone()[0]
+        
+        print(f"   📁 主菜单(父目录): {main_menu_count} 个")
+        print(f"   📄 功能菜单: {function_menu_count} 个")
+        print(f"   🔘 按钮权限: {button_count} 个")
+        print(f"   📋 菜单总数: {menu_count} 个")
+        print(f"   👥 角色数量: {role_count} 个")
+        print(f"   🔐 权限数量: {permission_count} 个")
+        print("=" * 60)
+        
+        return True
+        
+    except Exception as e:
+        print(f"❌ 初始化失败: {e}")
+        conn.rollback()
+        return False
+    finally:
+        cursor.close()
+        conn.close()
+
+def main():
+    """主函数"""
+    success = reinit_rbac_data()
+    if success:
+        print("\n🎯 重新初始化成功!菜单层级关系已修复。")
+        print("💡 建议重启前端服务以刷新菜单缓存。")
+        print("\n🌐 访问地址:")
+        print("   前端: http://localhost:3000")
+        print("   菜单管理: http://localhost:3000/admin/menus")
+        print("\n🔑 登录信息:")
+        print("   用户名: admin")
+        print("   密码: Admin123456")
+    else:
+        print("\n❌ 重新初始化失败!")
+
+if __name__ == "__main__":
+    main()

BIN
src/app/__pycache__/__init__.cpython-311.pyc


BIN
src/app/__pycache__/main.cpython-311.pyc


BIN
src/app/api/__pycache__/__init__.cpython-311.pyc


BIN
src/app/api/v1/__pycache__/__init__.cpython-311.pyc


BIN
src/app/api/v1/__pycache__/api_router.cpython-311.pyc


BIN
src/app/api/v1/auth/__pycache__/__init__.cpython-311.pyc


BIN
src/app/api/v1/auth/__pycache__/endpoints.cpython-311.pyc


BIN
src/app/api/v1/auth/__pycache__/router.cpython-311.pyc


BIN
src/app/api/v1/oauth/__pycache__/__init__.cpython-311.pyc


BIN
src/app/api/v1/oauth/__pycache__/endpoints.cpython-311.pyc


BIN
src/app/api/v1/oauth/__pycache__/router.cpython-311.pyc


BIN
src/app/config/__pycache__/__init__.cpython-311.pyc


BIN
src/app/config/__pycache__/database.cpython-311.pyc


BIN
src/app/config/__pycache__/simple_settings.cpython-311.pyc


BIN
src/app/core/__pycache__/__init__.cpython-311.pyc


BIN
src/app/core/__pycache__/exceptions.cpython-311.pyc


BIN
src/app/models/__pycache__/__init__.cpython-311.pyc


BIN
src/app/models/__pycache__/app.cpython-311.pyc


BIN
src/app/models/__pycache__/base.cpython-311.pyc


BIN
src/app/models/__pycache__/log.cpython-311.pyc


BIN
src/app/models/__pycache__/token.cpython-311.pyc


BIN
src/app/models/__pycache__/user.cpython-311.pyc


BIN
src/app/schemas/__pycache__/__init__.cpython-311.pyc


BIN
src/app/schemas/__pycache__/auth.cpython-311.pyc


BIN
src/app/schemas/__pycache__/base.cpython-311.pyc


BIN
src/app/services/__pycache__/__init__.cpython-311.pyc


BIN
src/app/services/__pycache__/auth_service.cpython-311.pyc


BIN
src/app/services/__pycache__/oauth_service.cpython-311.pyc


BIN
src/app/utils/__pycache__/__init__.cpython-311.pyc


BIN
src/app/utils/__pycache__/security.cpython-311.pyc


+ 101 - 0
test_app_user_applications.py

@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+import requests
+import json
+
+# Test app user applications access
+login_data = {
+    'username': 'app',
+    'password': '123456'
+}
+
+try:
+    # Login as app user
+    login_response = requests.post('http://localhost:8000/api/v1/auth/login', json=login_data)
+    if login_response.status_code == 200:
+        login_result = login_response.json()
+        if login_result.get('code') == 0:
+            token = login_result['data']['access_token']
+            print('✅ App user login successful')
+            
+            # Get applications list
+            headers = {'Authorization': f'Bearer {token}'}
+            apps_response = requests.get('http://localhost:8000/api/v1/apps', headers=headers)
+            
+            if apps_response.status_code == 200:
+                apps_result = apps_response.json()
+                if apps_result.get('code') == 0:
+                    apps_data = apps_result['data']
+                    apps = apps_data.get('items', [])
+                    total = apps_data.get('total', 0)
+                    
+                    print(f'✅ App user can access applications API')
+                    print(f'📱 Found {len(apps)} applications (total: {total})')
+                    
+                    if apps:
+                        for app in apps:
+                            print(f'   App: {app["name"]} (Key: {app["app_key"]})')
+                            print(f'     Description: {app.get("description", "N/A")}')
+                            print(f'     Active: {app["is_active"]}')
+                            print(f'     Created: {app["created_at"]}')
+                            print()
+                        
+                        print('🎉 App user can now see all applications!')
+                    else:
+                        print('❌ No applications returned - still empty!')
+                        
+                else:
+                    print(f'❌ Applications API error: {apps_result.get("message")}')
+            else:
+                print(f'❌ Applications API HTTP error: {apps_response.status_code}')
+                print(f'Response: {apps_response.text}')
+        else:
+            print(f'❌ Login error: {login_result.get("message")}')
+    else:
+        print(f'❌ Login HTTP error: {login_response.status_code}')
+        
+except Exception as e:
+    print(f'❌ Request error: {e}')
+
+# Also test with admin user for comparison
+print('\n' + '='*50)
+print('Testing admin user for comparison...')
+
+admin_login_data = {
+    'username': 'admin',
+    'password': 'Admin123456'
+}
+
+try:
+    # Login as admin user
+    login_response = requests.post('http://localhost:8000/api/v1/auth/login', json=admin_login_data)
+    if login_response.status_code == 200:
+        login_result = login_response.json()
+        if login_result.get('code') == 0:
+            token = login_result['data']['access_token']
+            print('✅ Admin user login successful')
+            
+            # Get applications list
+            headers = {'Authorization': f'Bearer {token}'}
+            apps_response = requests.get('http://localhost:8000/api/v1/apps', headers=headers)
+            
+            if apps_response.status_code == 200:
+                apps_result = apps_response.json()
+                if apps_result.get('code') == 0:
+                    apps_data = apps_result['data']
+                    apps = apps_data.get('items', [])
+                    total = apps_data.get('total', 0)
+                    
+                    print(f'✅ Admin user can access applications API')
+                    print(f'📱 Admin sees {len(apps)} applications (total: {total})')
+                    
+                else:
+                    print(f'❌ Applications API error: {apps_result.get("message")}')
+            else:
+                print(f'❌ Applications API HTTP error: {apps_response.status_code}')
+        else:
+            print(f'❌ Admin login error: {login_result.get("message")}')
+    else:
+        print(f'❌ Admin login HTTP error: {login_response.status_code}')
+        
+except Exception as e:
+    print(f'❌ Admin request error: {e}')

+ 61 - 0
test_app_user_menus.py

@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+import requests
+import json
+
+# Test app user menu access
+login_data = {
+    'username': 'app',
+    'password': '123456'
+}
+
+try:
+    # Login as app user
+    login_response = requests.post('http://localhost:8000/api/v1/auth/login', json=login_data)
+    if login_response.status_code == 200:
+        login_result = login_response.json()
+        if login_result.get('code') == 0:
+            token = login_result['data']['access_token']
+            print('✅ App user login successful')
+            
+            # Get user menus
+            headers = {'Authorization': f'Bearer {token}'}
+            menus_response = requests.get('http://localhost:8000/api/v1/user/menus', headers=headers)
+            if menus_response.status_code == 200:
+                menus_result = menus_response.json()
+                if menus_result.get('code') == 0:
+                    menus = menus_result['data']
+                    print(f'✅ App user has access to {len(menus)} menu items')
+                    
+                    # Check specifically for /admin/apps path
+                    has_admin_apps = False
+                    for menu in menus:
+                        if menu.get('menu_type') == 'menu':
+                            print(f'📁 {menu["title"]} ({menu["name"]}) - Path: {menu.get("path", "N/A")}')
+                            if menu.get('path') == '/admin/apps':
+                                has_admin_apps = True
+                                print('   ✅ Found /admin/apps access!')
+                            
+                            if menu.get('children'):
+                                for child in menu['children']:
+                                    if child.get('menu_type') == 'menu':
+                                        print(f'   📄 {child["title"]} ({child["name"]}) - Path: {child.get("path", "N/A")}')
+                                        if child.get('path') == '/admin/apps':
+                                            has_admin_apps = True
+                                            print('      ✅ Found /admin/apps access!')
+                    
+                    if has_admin_apps:
+                        print('\n🎉 App user has access to /admin/apps path!')
+                    else:
+                        print('\n❌ App user does NOT have access to /admin/apps path!')
+                        
+                else:
+                    print(f'❌ Menus API error: {menus_result.get("message")}')
+            else:
+                print(f'❌ Menus API HTTP error: {menus_response.status_code}')
+        else:
+            print(f'❌ Login error: {login_result.get("message")}')
+    else:
+        print(f'❌ Login HTTP error: {login_response.status_code}')
+        
+except Exception as e:
+    print(f'❌ Request error: {e}')

+ 87 - 0
test_app_user_profile.py

@@ -0,0 +1,87 @@
+#!/usr/bin/env python3
+import requests
+import json
+
+# Test admin user profile to see roles
+login_data = {
+    'username': 'admin',
+    'password': 'Admin123456'
+}
+
+try:
+    # Login as admin user
+    login_response = requests.post('http://localhost:8000/api/v1/auth/login', json=login_data)
+    if login_response.status_code == 200:
+        login_result = login_response.json()
+        if login_result.get('code') == 0:
+            token = login_result['data']['access_token']
+            print('✅ Admin user login successful')
+            
+            # Get user profile
+            headers = {'Authorization': f'Bearer {token}'}
+            profile_response = requests.get('http://localhost:8000/api/v1/users/profile', headers=headers)
+            
+            if profile_response.status_code == 200:
+                profile_result = profile_response.json()
+                if profile_result.get('code') == 0:
+                    profile = profile_result['data']
+                    print('✅ Admin user profile:')
+                    print(f'   Username: {profile.get("username")}')
+                    print(f'   Email: {profile.get("email")}')
+                    print(f'   Is Superuser: {profile.get("is_superuser")}')
+                    print(f'   Is Active: {profile.get("is_active")}')
+                    print(f'   Roles: {profile.get("roles", [])}')
+                else:
+                    print(f'❌ Profile API error: {profile_result.get("message")}')
+            else:
+                print(f'❌ Profile API HTTP error: {profile_response.status_code}')
+        else:
+            print(f'❌ Login error: {login_result.get("message")}')
+    else:
+        print(f'❌ Login HTTP error: {login_response.status_code}')
+        
+except Exception as e:
+    print(f'❌ Request error: {e}')
+
+# Now test with app user (need to find correct password first)
+print('\n' + '='*50)
+print('Testing app user...')
+
+# Try common passwords for app user
+app_passwords = ['App123456', 'app123456', 'password', '123456', 'admin']
+
+for password in app_passwords:
+    try:
+        login_data = {'username': 'app', 'password': password}
+        login_response = requests.post('http://localhost:8000/api/v1/auth/login', json=login_data)
+        if login_response.status_code == 200:
+            login_result = login_response.json()
+            if login_result.get('code') == 0:
+                token = login_result['data']['access_token']
+                print(f'✅ App user login successful with password: {password}')
+                
+                # Get user profile
+                headers = {'Authorization': f'Bearer {token}'}
+                profile_response = requests.get('http://localhost:8000/api/v1/users/profile', headers=headers)
+                
+                if profile_response.status_code == 200:
+                    profile_result = profile_response.json()
+                    if profile_result.get('code') == 0:
+                        profile = profile_result['data']
+                        print('✅ App user profile:')
+                        print(f'   Username: {profile.get("username")}')
+                        print(f'   Email: {profile.get("email")}')
+                        print(f'   Is Superuser: {profile.get("is_superuser")}')
+                        print(f'   Is Active: {profile.get("is_active")}')
+                        print(f'   Roles: {profile.get("roles", [])}')
+                        break
+                    else:
+                        print(f'❌ Profile API error: {profile_result.get("message")}')
+                else:
+                    print(f'❌ Profile API HTTP error: {profile_response.status_code}')
+                break
+    except Exception as e:
+        continue
+
+else:
+    print('❌ Could not find correct password for app user')

+ 106 - 0
test_frontend_role_api.py

@@ -0,0 +1,106 @@
+#!/usr/bin/env python3
+import requests
+import json
+
+# Test the exact API call that the frontend makes
+admin_login_data = {
+    'username': 'admin',
+    'password': 'Admin123456'
+}
+
+try:
+    # Login as admin
+    login_response = requests.post('http://localhost:8000/api/v1/auth/login', json=admin_login_data)
+    if login_response.status_code == 200:
+        login_result = login_response.json()
+        if login_result.get('code') == 0:
+            token = login_result['data']['access_token']
+            print('✅ Admin login successful')
+            
+            headers = {'Authorization': f'Bearer {token}'}
+            
+            # First get all menus (what frontend loads for the tree)
+            print('\n=== Testing All Menus API (for tree data) ===')
+            all_menus_response = requests.get('http://localhost:8000/api/v1/admin/menus?page_size=1000', headers=headers)
+            if all_menus_response.status_code == 200:
+                all_menus_result = all_menus_response.json()
+                if all_menus_result.get('code') == 0:
+                    all_menus = all_menus_result['data']['items']
+                    print(f'✅ All menus API: {len(all_menus)} total menus')
+                    
+                    # Count menu types
+                    main_menus = [m for m in all_menus if m['menu_type'] == 'menu' and not m['parent_id']]
+                    sub_menus = [m for m in all_menus if m['menu_type'] == 'menu' and m['parent_id']]
+                    buttons = [m for m in all_menus if m['menu_type'] == 'button']
+                    
+                    print(f'   Main menus: {len(main_menus)}')
+                    print(f'   Sub menus: {len(sub_menus)}')
+                    print(f'   Buttons: {len(buttons)}')
+                else:
+                    print(f'❌ All menus API error: {all_menus_result.get("message")}')
+            else:
+                print(f'❌ All menus API HTTP error: {all_menus_response.status_code}')
+            
+            # Get user role ID
+            roles_response = requests.get('http://localhost:8000/api/v1/admin/roles', headers=headers)
+            if roles_response.status_code == 200:
+                roles_result = roles_response.json()
+                if roles_result.get('code') == 0:
+                    roles = roles_result['data']['items']
+                    user_role = next((r for r in roles if r['name'] == 'user'), None)
+                    
+                    if user_role:
+                        user_role_id = user_role['id']
+                        print(f'\n=== Testing User Role Permissions API ===')
+                        print(f'User role ID: {user_role_id}')
+                        
+                        # Get role permissions (what frontend uses for checked keys)
+                        role_perms_response = requests.get(
+                            f'http://localhost:8000/api/v1/admin/roles/{user_role_id}/menus',
+                            headers=headers
+                        )
+                        
+                        if role_perms_response.status_code == 200:
+                            role_perms_result = role_perms_response.json()
+                            if role_perms_result.get('code') == 0:
+                                data = role_perms_result['data']
+                                menu_ids = data.get('menu_ids', [])
+                                
+                                print(f'✅ Role permissions API successful')
+                                print(f'📋 Returned menu_ids: {menu_ids}')
+                                print(f'📊 Count: {len(menu_ids)} permissions')
+                                
+                                # Check if any problematic menu IDs are in the list
+                                problematic_ids = []
+                                if all_menus:
+                                    for menu in all_menus:
+                                        if menu['name'] in ['user-management', 'role-management', 'menu-management', 'permission-management', 'app-management', 'log-management']:
+                                            if menu['id'] in menu_ids:
+                                                problematic_ids.append(menu['name'])
+                                
+                                if problematic_ids:
+                                    print(f'❌ PROBLEM: Found problematic menu IDs in response: {problematic_ids}')
+                                else:
+                                    print('✅ No problematic menu IDs found in API response')
+                                
+                                # Show first few menu IDs for debugging
+                                print(f'📝 First 10 menu IDs: {menu_ids[:10]}')
+                                
+                            else:
+                                print(f'❌ Role permissions API error: {role_perms_result.get("message")}')
+                        else:
+                            print(f'❌ Role permissions API HTTP error: {role_perms_response.status_code}')
+                            print(f'Response: {role_perms_response.text}')
+                    else:
+                        print('❌ User role not found in roles list')
+                else:
+                    print(f'❌ Roles API error: {roles_result.get("message")}')
+            else:
+                print(f'❌ Roles API HTTP error: {roles_response.status_code}')
+        else:
+            print(f'❌ Login error: {login_result.get("message")}')
+    else:
+        print(f'❌ Login HTTP error: {login_response.status_code}')
+        
+except Exception as e:
+    print(f'❌ Request error: {e}')

+ 61 - 0
test_regular_user_applications.py

@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+import requests
+import json
+
+# Test regular user (zhangsan) applications access to ensure they only see their own
+login_data = {
+    'username': 'zhangsan',
+    'password': '123456'
+}
+
+try:
+    # Login as zhangsan user
+    login_response = requests.post('http://localhost:8000/api/v1/auth/login', json=login_data)
+    if login_response.status_code == 200:
+        login_result = login_response.json()
+        if login_result.get('code') == 0:
+            token = login_result['data']['access_token']
+            print('✅ Zhangsan user login successful')
+            
+            # Get user profile to check roles
+            headers = {'Authorization': f'Bearer {token}'}
+            profile_response = requests.get('http://localhost:8000/api/v1/users/profile', headers=headers)
+            if profile_response.status_code == 200:
+                profile_result = profile_response.json()
+                if profile_result.get('code') == 0:
+                    profile = profile_result['data']
+                    print(f'👤 Zhangsan roles: {profile.get("roles", [])}')
+            
+            # Get applications list
+            apps_response = requests.get('http://localhost:8000/api/v1/apps', headers=headers)
+            
+            if apps_response.status_code == 200:
+                apps_result = apps_response.json()
+                if apps_result.get('code') == 0:
+                    apps_data = apps_result['data']
+                    apps = apps_data.get('items', [])
+                    total = apps_data.get('total', 0)
+                    
+                    print(f'✅ Zhangsan can access applications API')
+                    print(f'📱 Zhangsan sees {len(apps)} applications (total: {total})')
+                    
+                    if apps:
+                        for app in apps:
+                            print(f'   App: {app["name"]} (Key: {app["app_key"]})')
+                            print(f'     Description: {app.get("description", "N/A")}')
+                            print()
+                        print('⚠️  Regular user should only see their own applications!')
+                    else:
+                        print('✅ Regular user sees no applications (correct - they have not created any)')
+                        
+                else:
+                    print(f'❌ Applications API error: {apps_result.get("message")}')
+            else:
+                print(f'❌ Applications API HTTP error: {apps_response.status_code}')
+        else:
+            print(f'❌ Login error: {login_result.get("message")}')
+    else:
+        print(f'❌ Login HTTP error: {login_response.status_code}')
+        
+except Exception as e:
+    print(f'❌ Request error: {e}')

+ 53 - 0
test_user_menus.py

@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+import requests
+import json
+
+# First login to get token
+login_data = {
+    'username': 'admin',
+    'password': 'Admin123456'
+}
+
+try:
+    # Login
+    login_response = requests.post('http://localhost:8000/api/v1/auth/login', json=login_data)
+    if login_response.status_code == 200:
+        login_result = login_response.json()
+        if login_result.get('code') == 0:
+            token = login_result['data']['access_token']
+            print('✅ Login successful')
+            
+            # Get user menus
+            headers = {'Authorization': f'Bearer {token}'}
+            menus_response = requests.get('http://localhost:8000/api/v1/user/menus', headers=headers)
+            
+            if menus_response.status_code == 200:
+                menus_result = menus_response.json()
+                if menus_result.get('code') == 0:
+                    menus = menus_result['data']
+                    print(f'✅ Got {len(menus)} total items for admin user')
+                    
+                    # Count menu types
+                    menu_count = 0
+                    for menu in menus:
+                        if menu.get('menu_type') == 'menu':
+                            menu_count += 1
+                            print(f'📁 Menu: {menu["title"]} ({menu["name"]})')
+                            if menu.get('children'):
+                                for child in menu['children']:
+                                    if child.get('menu_type') == 'menu':
+                                        menu_count += 1
+                                        print(f'   📄 {child["title"]} ({child["name"]})')
+                    
+                    print(f'📊 Total menu items (type=menu): {menu_count}')
+                else:
+                    print(f'❌ Menu API error: {menus_result.get("message")}')
+            else:
+                print(f'❌ Menu API HTTP error: {menus_response.status_code}')
+        else:
+            print(f'❌ Login error: {login_result.get("message")}')
+    else:
+        print(f'❌ Login HTTP error: {login_response.status_code}')
+        
+except Exception as e:
+    print(f'❌ Request error: {e}')

+ 116 - 0
test_user_role_menus_api.py

@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+import requests
+import json
+
+# Test the role menus API for user role
+admin_login_data = {
+    'username': 'admin',
+    'password': 'Admin123456'
+}
+
+try:
+    # Login as admin to get access to role management APIs
+    login_response = requests.post('http://localhost:8000/api/v1/auth/login', json=admin_login_data)
+    if login_response.status_code == 200:
+        login_result = login_response.json()
+        if login_result.get('code') == 0:
+            token = login_result['data']['access_token']
+            print('✅ Admin login successful')
+            
+            # Get user role ID first
+            headers = {'Authorization': f'Bearer {token}'}
+            roles_response = requests.get('http://localhost:8000/api/v1/admin/roles', headers=headers)
+            
+            if roles_response.status_code == 200:
+                roles_result = roles_response.json()
+                if roles_result.get('code') == 0:
+                    roles = roles_result['data']['items']
+                    user_role_id = None
+                    
+                    for role in roles:
+                        if role['name'] == 'user':
+                            user_role_id = role['id']
+                            print(f'✅ Found user role ID: {user_role_id}')
+                            break
+                    
+                    if user_role_id:
+                        # Get role menu permissions
+                        role_menus_response = requests.get(
+                            f'http://localhost:8000/api/v1/admin/roles/{user_role_id}/menus', 
+                            headers=headers
+                        )
+                        
+                        if role_menus_response.status_code == 200:
+                            role_menus_result = role_menus_response.json()
+                            if role_menus_result.get('code') == 0:
+                                data = role_menus_result['data']
+                                menu_ids = data.get('menu_ids', [])
+                                menu_details = data.get('menu_details', [])
+                                
+                                print(f'✅ Role menus API successful')
+                                print(f'📊 User role has {len(menu_ids)} menu permissions')
+                                print(f'📋 Menu IDs: {menu_ids[:5]}...' if len(menu_ids) > 5 else f'📋 Menu IDs: {menu_ids}')
+                                
+                                # Categorize menus
+                                main_menus = []
+                                sub_menus = []
+                                buttons = []
+                                
+                                for menu in menu_details:
+                                    if menu['menu_type'] == 'menu' and menu['parent_id'] is None:
+                                        main_menus.append(menu)
+                                    elif menu['menu_type'] == 'menu' and menu['parent_id'] is not None:
+                                        sub_menus.append(menu)
+                                    elif menu['menu_type'] == 'button':
+                                        buttons.append(menu)
+                                
+                                print(f'\n📁 Main Menus ({len(main_menus)}):')
+                                for menu in main_menus:
+                                    print(f'   - {menu["title"]} ({menu["name"]})')
+                                
+                                print(f'\n📄 Sub Menus ({len(sub_menus)}):')
+                                for menu in sub_menus:
+                                    print(f'   - {menu["title"]} ({menu["name"]})')
+                                
+                                print(f'\n🔘 Buttons ({len(buttons)}):')
+                                for menu in buttons[:10]:  # Show first 10 buttons
+                                    print(f'   - {menu["title"]} ({menu["name"]})')
+                                if len(buttons) > 10:
+                                    print(f'   ... and {len(buttons) - 10} more buttons')
+                                
+                                # Check for problematic menus
+                                problematic_menu_names = [
+                                    'user-management', 'role-management', 'menu-management',
+                                    'permission-management', 'app-management', 'log-management'
+                                ]
+                                
+                                print(f'\n🔍 Checking for problematic menus:')
+                                found_problematic = []
+                                for menu in menu_details:
+                                    if menu['name'] in problematic_menu_names:
+                                        found_problematic.append(menu['name'])
+                                        print(f'   ❌ FOUND: {menu["title"]} ({menu["name"]})')
+                                
+                                if not found_problematic:
+                                    print('   ✅ No problematic menus found - API is correct!')
+                                else:
+                                    print(f'   ❌ Found {len(found_problematic)} problematic menus in API response!')
+                                
+                            else:
+                                print(f'❌ Role menus API error: {role_menus_result.get("message")}')
+                        else:
+                            print(f'❌ Role menus API HTTP error: {role_menus_response.status_code}')
+                            print(f'Response: {role_menus_response.text}')
+                    else:
+                        print('❌ User role not found!')
+                else:
+                    print(f'❌ Roles API error: {roles_result.get("message")}')
+            else:
+                print(f'❌ Roles API HTTP error: {roles_response.status_code}')
+        else:
+            print(f'❌ Login error: {login_result.get("message")}')
+    else:
+        print(f'❌ Login HTTP error: {login_response.status_code}')
+        
+except Exception as e:
+    print(f'❌ Request error: {e}')

+ 60 - 0
test_zhangsan_menus.py

@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+import requests
+import json
+
+# Test zhangsan user menu access
+login_data = {
+    'username': 'zhangsan',
+    'password': 'zhangsan123'  # Try common password
+}
+
+# Try different passwords for zhangsan
+passwords = ['zhangsan123', 'Zhangsan123', '123456', 'password', 'zhangsan']
+
+for password in passwords:
+    try:
+        login_data['password'] = password
+        login_response = requests.post('http://localhost:8000/api/v1/auth/login', json=login_data)
+        if login_response.status_code == 200:
+            login_result = login_response.json()
+            if login_result.get('code') == 0:
+                token = login_result['data']['access_token']
+                print(f'✅ Zhangsan login successful with password: {password}')
+                
+                # Get user menus
+                headers = {'Authorization': f'Bearer {token}'}
+                menus_response = requests.get('http://localhost:8000/api/v1/user/menus', headers=headers)
+                if menus_response.status_code == 200:
+                    menus_result = menus_response.json()
+                    if menus_result.get('code') == 0:
+                        menus = menus_result['data']
+                        print(f'✅ Zhangsan has access to {len(menus)} menu items')
+                        
+                        # Check for admin-dashboard menu
+                        has_admin_dashboard = False
+                        for menu in menus:
+                            if menu.get('menu_type') == 'menu':
+                                print(f'📁 {menu["title"]} ({menu["name"]}) - Path: {menu.get("path", "N/A")}')
+                                
+                                if menu.get('children'):
+                                    for child in menu['children']:
+                                        if child.get('menu_type') == 'menu':
+                                            print(f'   📄 {child["title"]} ({child["name"]}) - Path: {child.get("path", "N/A")}')
+                                            if child.get('name') == 'admin-dashboard':
+                                                has_admin_dashboard = True
+                                                print('      ✅ Found 管理概览 (admin-dashboard) menu!')
+                        
+                        if has_admin_dashboard:
+                            print('\n🎉 Zhangsan can now see the 管理概览 menu!')
+                        else:
+                            print('\n❌ Zhangsan still cannot see the 管理概览 menu!')
+                            
+                    else:
+                        print(f'❌ Menus API error: {menus_result.get("message")}')
+                else:
+                    print(f'❌ Menus API HTTP error: {menus_response.status_code}')
+                break
+    except Exception as e:
+        continue
+else:
+    print('❌ Could not find correct password for zhangsan user')

+ 143 - 0
update_menu_structure.py

@@ -0,0 +1,143 @@
+#!/usr/bin/env python3
+"""
+更新菜单结构 - 移除"我的应用"菜单,将应用管理功能迁移到管理员菜单下
+"""
+import pymysql
+from dotenv import load_dotenv
+import os
+
+load_dotenv()
+
+def get_db_connection():
+    """获取数据库连接"""
+    try:
+        config = {
+            'host': os.getenv('DB_HOST', 'localhost'),
+            'port': int(os.getenv('DB_PORT', 3306)),
+            'user': os.getenv('DB_USER', 'root'),
+            'password': os.getenv('DB_PASSWORD', 'admin'),
+            'database': os.getenv('DB_NAME', 'lq_db'),
+            'charset': 'utf8mb4',
+            'autocommit': True
+        }
+        return pymysql.connect(**config)
+    except Exception as e:
+        print(f"数据库连接失败: {e}")
+        return None
+
+def update_menu_structure():
+    """更新菜单结构"""
+    print("🔄 更新菜单结构...")
+    print("=" * 50)
+    
+    conn = get_db_connection()
+    if not conn:
+        print("❌ 数据库连接失败")
+        return False
+    
+    cursor = conn.cursor()
+    
+    try:
+        # 1. 删除"我的应用"相关菜单和按钮
+        print("🗑️  删除旧的'我的应用'菜单...")
+        
+        # 删除应用管理按钮权限
+        cursor.execute("DELETE FROM menus WHERE parent_id = 'apps-menu'")
+        print(f"   删除了应用管理按钮权限")
+        
+        # 删除"我的应用"主菜单
+        cursor.execute("DELETE FROM menus WHERE id = 'apps-menu'")
+        print(f"   删除了'我的应用'主菜单")
+        
+        # 2. 更新菜单排序
+        print("📝 更新菜单排序...")
+        cursor.execute("UPDATE menus SET sort_order = 3 WHERE id = 'admin-menu'")
+        print("   更新了系统管理菜单排序")
+        
+        # 3. 确保应用管理按钮权限在管理员应用管理菜单下
+        print("➕ 添加应用管理按钮权限...")
+        
+        apps_buttons = [
+            ('apps-create-btn', 'admin-apps-menu', 'apps-create', '创建应用', None, None, 'Plus', 1, 'button', False),
+            ('apps-edit-btn', 'admin-apps-menu', 'apps-edit', '编辑应用', None, None, 'Edit', 2, 'button', False),
+            ('apps-delete-btn', 'admin-apps-menu', 'apps-delete', '删除应用', None, None, 'Delete', 3, 'button', False),
+            ('apps-secret-btn', 'admin-apps-menu', 'apps-secret', '查看密钥', None, None, 'Key', 4, 'button', False),
+        ]
+        
+        for button_data in apps_buttons:
+            # 检查是否已存在
+            cursor.execute("SELECT COUNT(*) FROM menus WHERE id = %s", (button_data[0],))
+            if cursor.fetchone()[0] == 0:
+                cursor.execute("""
+                    INSERT INTO menus (id, parent_id, name, title, path, component, icon, sort_order, menu_type, is_hidden)
+                    VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
+                """, button_data)
+                print(f"   添加了按钮权限: {button_data[3]}")
+            else:
+                print(f"   按钮权限已存在: {button_data[3]}")
+        
+        # 4. 清理角色菜单关联中的"我的应用"菜单
+        print("🧹 清理角色菜单关联...")
+        cursor.execute("DELETE FROM role_menus WHERE menu_id = 'apps-menu'")
+        cursor.execute("DELETE FROM role_menus WHERE menu_id LIKE 'apps-%' AND menu_id != 'admin-apps-menu'")
+        print("   清理了旧的角色菜单关联")
+        
+        # 5. 为管理员角色添加应用管理权限
+        print("🔐 为管理员角色添加应用管理权限...")
+        
+        # 获取管理员相关角色
+        admin_roles = ['super_admin', 'admin', 'app_manager']
+        
+        for role_name in admin_roles:
+            # 获取角色ID
+            cursor.execute("SELECT id FROM roles WHERE name = %s", (role_name,))
+            role_result = cursor.fetchone()
+            if role_result:
+                role_id = role_result[0]
+                
+                # 添加应用管理菜单权限
+                cursor.execute("""
+                    INSERT IGNORE INTO role_menus (role_id, menu_id, created_at)
+                    VALUES (%s, 'admin-apps-menu', NOW())
+                """, (role_id,))
+                
+                # 添加应用管理按钮权限
+                for button_data in apps_buttons:
+                    cursor.execute("""
+                        INSERT IGNORE INTO role_menus (role_id, menu_id, created_at)
+                        VALUES (%s, %s, NOW())
+                    """, (role_id, button_data[0]))
+                
+                print(f"   为角色 {role_name} 添加了应用管理权限")
+        
+        conn.commit()
+        
+        print("\n" + "=" * 50)
+        print("✅ 菜单结构更新完成!")
+        print("📋 更新内容:")
+        print("   - 删除了'我的应用'菜单")
+        print("   - 应用管理功能迁移到系统管理下")
+        print("   - 更新了菜单排序")
+        print("   - 更新了角色权限")
+        print("=" * 50)
+        
+        return True
+        
+    except Exception as e:
+        print(f"❌ 更新失败: {e}")
+        conn.rollback()
+        return False
+    finally:
+        cursor.close()
+        conn.close()
+
+def main():
+    """主函数"""
+    success = update_menu_structure()
+    if success:
+        print("\n🎉 菜单结构更新成功!请重启前端服务以查看更改。")
+    else:
+        print("\n❌ 菜单结构更新失败!")
+
+if __name__ == "__main__":
+    main()

+ 0 - 0
update_menu_tree.py