feat: 查询页增强 + 权限体系优化

- Redis DB0~DB15 下拉选择,默认DB0
- 查询历史粘贴按钮(一键填入SQL编辑器)
- 去掉导出历史按钮
- SchemaSidebar 按目标数据库筛选
- SQL自动补全 schema 双层注册(db→tables, table→columns)
- 后端 db-schema 接口(INFORMATION_SCHEMA.COLUMNS 一次加载)
- autocompletion 扩展激活
- Redis key 树形结构(冒号分隔层级)
- Redis 查询模板 GET/HGETALL/HGET
- guest 角色彻底移除,改为 auditor
- 登录页优化:去掉演示账号、placeholder 中文提示
This commit is contained in:
logan committed 2026-05-24 18:50:08 +08:00
1 parent aa2e26c827
commit 35a014e571
13 files changed
+345 -111

No files matched your search

+3
View File
@@ -22,6 +22,9 @@ async def login(req: LoginRequest, db: AsyncSession = Depends(get_db)):
if not user.is_active:
raise HTTPException(status_code=403, detail="用户已禁用")
if user.role == "guest":
raise HTTPException(status_code=403, detail="访客账户已禁用,请联系管理员")
user.last_login = datetime.now(timezone.utc)
await db.commit()
@@ -30,7 +30,7 @@ async def _get_decrypted_instance(db: AsyncSession, instance_id: int) -> Instanc
return instance
async def _mysql_query(instance: Instance, sql: str, database: Optional[str] = None) -> list:
async def _mysql_query(instance: Instance, sql: str, database: Optional[str] = None, params: Optional[list] = None) -> list:
"""Execute a MySQL query and return rows as list of dicts."""
import aiomysql
conn = await aiomysql.connect(
@@ -40,7 +40,7 @@ async def _mysql_query(instance: Instance, sql: str, database: Optional[str] = N
)
try:
async with conn.cursor(aiomysql.DictCursor) as cur:
await cur.execute(sql)
await cur.execute(sql, params)
rows = await cur.fetchall()
return rows
finally:
@@ -120,6 +120,38 @@ async def list_tables(
raise HTTPException(status_code=500, detail="查询表列表失败: " + str(e))
# ---- DB Schema (for autocomplete) ----
@router.get("/{instance_id}/detail/db-schema")
async def get_db_schema(
instance_id: int,
database: str = Query(..., description="数据库名"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(require_role("admin", "dba", "developer")),
):
"""一次性返回整个库的 {table: [columns]} 结构,用于前端 SQL 自动补全"""
instance = await _get_decrypted_instance(db, instance_id)
await check_instance_access(current_user, instance, db)
if instance.db_type != "mysql":
raise HTTPException(status_code=400, detail="仅支持MySQL实例")
try:
rows = await _mysql_query(
instance,
"SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS "
"WHERE TABLE_SCHEMA = %s ORDER BY TABLE_NAME, ORDINAL_POSITION",
database=database,
params=[database],
)
schema: dict[str, list[str]] = {}
for row in rows:
tbl = row["TABLE_NAME"]
col = row["COLUMN_NAME"]
schema.setdefault(tbl, []).append(col)
return schema
except Exception as e:
raise HTTPException(status_code=500, detail="获取库结构失败: " + str(e))
# ---- Table Detail ----
@router.get("/{instance_id}/detail/table-detail")