修改普通用户的数据类型转换在数据集管理看不见的问题
This commit is contained in:
@@ -122,3 +122,143 @@ def audit_logs_export(
|
||||
media_type="text/csv",
|
||||
headers={"Content-Disposition": "attachment; filename=audit_logs.csv"},
|
||||
)
|
||||
|
||||
|
||||
# ===================== 操作日志 =====================
|
||||
|
||||
@router.get("/operation-logs")
|
||||
def operation_logs(
|
||||
user_id: str | None = Query(default=None, description="按用户 ID 筛选"),
|
||||
module: str | None = Query(default=None, description="按模块筛选: fine-tune/model-eval/model-inference/dataset/data-convert/model-manage"),
|
||||
action: str | None = Query(default=None, description="按动作筛选: create/start/stop/delete/upload/convert/merge"),
|
||||
status: str | None = Query(default=None, description="按状态筛选: success/failure(不传则查全部)"),
|
||||
keyword: str | None = Query(default=None, description="关键字搜索报错信息(error_message)"),
|
||||
start_time: str | None = Query(default=None, description="ISO8601 起始时间"),
|
||||
end_time: str | None = Query(default=None, description="ISO8601 结束时间"),
|
||||
limit: int = Query(default=50, ge=1, le=200),
|
||||
offset: int = Query(default=0, ge=0),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
) -> dict:
|
||||
"""操作日志查询:按用户/模块/动作/状态/关键字/时间范围分页过滤。"""
|
||||
if not is_admin(current_user):
|
||||
from app.api.v1.endpoints.platform import fail
|
||||
raise fail(403, "admin permission required")
|
||||
store = get_platform_store()
|
||||
conditions = []
|
||||
params: list = []
|
||||
if user_id:
|
||||
conditions.append("user_id = %s")
|
||||
params.append(user_id)
|
||||
if module:
|
||||
conditions.append("module = %s")
|
||||
params.append(module)
|
||||
if action:
|
||||
conditions.append("action = %s")
|
||||
params.append(action)
|
||||
if status:
|
||||
conditions.append("status = %s")
|
||||
params.append(status)
|
||||
if keyword:
|
||||
conditions.append("(error_message ILIKE %s OR error_type ILIKE %s)")
|
||||
params.append(f"%{keyword}%")
|
||||
params.append(f"%{keyword}%")
|
||||
if start_time:
|
||||
conditions.append("create_time >= %s")
|
||||
params.append(start_time)
|
||||
if end_time:
|
||||
conditions.append("create_time <= %s")
|
||||
params.append(end_time)
|
||||
where = " WHERE " + " AND ".join(conditions) if conditions else ""
|
||||
with store.connect() as conn:
|
||||
rows = conn.execute(
|
||||
f"SELECT * FROM operation_logs{where} ORDER BY create_time DESC LIMIT %s OFFSET %s",
|
||||
tuple(params + [limit, offset]),
|
||||
).fetchall()
|
||||
total = conn.execute(f"SELECT COUNT(*) FROM operation_logs{where}", tuple(params)).fetchone()[0]
|
||||
return {"code": 0, "message": "ok", "data": {"items": [dict(r) for r in rows], "total": total}}
|
||||
|
||||
|
||||
@router.get("/operation-logs/stats")
|
||||
def operation_logs_stats(
|
||||
start_time: str | None = Query(default=None, description="ISO8601 起始时间"),
|
||||
end_time: str | None = Query(default=None, description="ISO8601 结束时间"),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
) -> dict:
|
||||
"""操作日志统计:总操作数、成功数、失败数、失败率、各模块失败分布、最近错误列表。"""
|
||||
if not is_admin(current_user):
|
||||
from app.api.v1.endpoints.platform import fail
|
||||
raise fail(403, "admin permission required")
|
||||
store = get_platform_store()
|
||||
conditions = []
|
||||
params: list = []
|
||||
if start_time:
|
||||
conditions.append("create_time >= %s")
|
||||
params.append(start_time)
|
||||
if end_time:
|
||||
conditions.append("create_time <= %s")
|
||||
params.append(end_time)
|
||||
where = " WHERE " + " AND ".join(conditions) if conditions else ""
|
||||
failure_where = where + " AND status = 'failure'" if where else " WHERE status = 'failure'"
|
||||
|
||||
with store.connect() as conn:
|
||||
# 总计
|
||||
row = conn.execute(
|
||||
f"SELECT status, COUNT(*) as cnt FROM operation_logs{where} GROUP BY status", tuple(params)
|
||||
).fetchall()
|
||||
total_count = 0
|
||||
success_count = 0
|
||||
failure_count = 0
|
||||
for r in row:
|
||||
total_count += r["cnt"]
|
||||
if r["status"] == "success":
|
||||
success_count = r["cnt"]
|
||||
elif r["status"] == "failure":
|
||||
failure_count = r["cnt"]
|
||||
failure_rate = round(failure_count / total_count * 100, 2) if total_count > 0 else 0
|
||||
|
||||
# 各模块失败数
|
||||
module_stats = conn.execute(
|
||||
f"SELECT module, COUNT(*) as cnt FROM operation_logs{failure_where} GROUP BY module ORDER BY cnt DESC",
|
||||
tuple(params),
|
||||
).fetchall()
|
||||
|
||||
# 各异常类型分布
|
||||
error_type_stats = conn.execute(
|
||||
f"SELECT error_type, COUNT(*) as cnt FROM operation_logs{failure_where} AND error_type IS NOT NULL GROUP BY error_type ORDER BY cnt DESC LIMIT 10",
|
||||
tuple(params),
|
||||
).fetchall()
|
||||
|
||||
# 最近的 10 条错误
|
||||
recent_errors = conn.execute(
|
||||
f"SELECT * FROM operation_logs{failure_where} ORDER BY create_time DESC LIMIT 10",
|
||||
tuple(params),
|
||||
).fetchall()
|
||||
|
||||
return {
|
||||
"code": 0,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"total": total_count,
|
||||
"success": success_count,
|
||||
"failure": failure_count,
|
||||
"failure_rate": failure_rate,
|
||||
"module_failures": [{"module": r["module"], "count": r["cnt"]} for r in module_stats],
|
||||
"error_types": [{"type": r["error_type"], "count": r["cnt"]} for r in error_type_stats],
|
||||
"recent_errors": [dict(r) for r in recent_errors],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@router.get("/operation-logs/modules")
|
||||
def operation_log_modules(current_user: dict = Depends(get_current_user)) -> dict:
|
||||
"""返回操作日志中出现的模块列表(用于筛选下拉框)。"""
|
||||
if not is_admin(current_user):
|
||||
from app.api.v1.endpoints.platform import fail
|
||||
raise fail(403, "admin permission required")
|
||||
store = get_platform_store()
|
||||
with store.connect() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT DISTINCT module FROM operation_logs WHERE module IS NOT NULL ORDER BY module"
|
||||
).fetchall()
|
||||
modules = [{"value": r["module"], "label": r["module"]} for r in rows]
|
||||
return {"code": 0, "message": "ok", "data": modules}
|
||||
|
||||
Reference in New Issue
Block a user