BookSystem/backend/auth/apps/logs/urls.py
jayhgq 19d6db6ecc feat: 添加登录日志和操作日志功能
1. 新增日志相关数据库模型、API路由、前端页面与权限配置
2. 为现有业务接口添加操作日志记录功能
3. 优化导入顺序与权限初始化数据
2026-06-12 22:41:41 +08:00

117 lines
3.7 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_, delete
from database import get_db
from models import LoginLog, OperationLog, User
from schemas import (
LoginLogResponse,
LoginLogSearch,
LoginLogCleanRequest,
OperationLogResponse,
OperationLogSearch,
)
from middleware import get_current_user, has_permission
from utils.like_filter import ilike_contains
router = APIRouter(tags=["logs"])
# ========================================
# 登录日志
# ========================================
@router.post("/login-logs/search", response_model=list[LoginLogResponse])
async def search_login_logs(
query: LoginLogSearch,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(has_permission("log:login")),
):
"""搜索登录日志"""
stmt = select(LoginLog)
filters = []
cond = ilike_contains(LoginLog.username, query.username)
if cond is not None:
filters.append(cond)
if query.status:
filters.append(LoginLog.status == query.status)
if query.start_time:
filters.append(LoginLog.login_time >= query.start_time)
if query.end_time:
filters.append(LoginLog.login_time <= query.end_time)
if filters:
stmt = stmt.where(and_(*filters))
stmt = stmt.order_by(LoginLog.login_time.desc())
result = await db.execute(stmt)
rows = result.scalars().all()
return [LoginLogResponse.model_validate(r) for r in rows]
@router.delete("/login-logs/clean")
async def clean_login_logs(
clean_data: LoginLogCleanRequest,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(has_permission("log:clean")),
):
"""清理指定日期之前的登录日志"""
stmt = delete(LoginLog).where(LoginLog.login_time < clean_data.before_date)
result = await db.execute(stmt)
await db.commit()
return {
"message": f"已清理 {result.rowcount} 条登录日志",
"deleted_count": result.rowcount,
}
# ========================================
# 操作日志
# ========================================
@router.post("/operation-logs/search", response_model=list[OperationLogResponse])
async def search_operation_logs(
query: OperationLogSearch,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(has_permission("log:operation")),
):
"""搜索操作日志"""
stmt = select(OperationLog)
filters = []
cond = ilike_contains(OperationLog.username, query.username)
if cond is not None:
filters.append(cond)
if query.action_type:
filters.append(OperationLog.action_type == query.action_type)
if query.target_type:
filters.append(OperationLog.target_type == query.target_type)
if query.start_time:
filters.append(OperationLog.createtime >= query.start_time)
if query.end_time:
filters.append(OperationLog.createtime <= query.end_time)
if filters:
stmt = stmt.where(and_(*filters))
stmt = stmt.order_by(OperationLog.createtime.desc())
result = await db.execute(stmt)
rows = result.scalars().all()
return [OperationLogResponse.model_validate(r) for r in rows]
@router.delete("/operation-logs/clean")
async def clean_operation_logs(
clean_data: LoginLogCleanRequest,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(has_permission("log:clean")),
):
"""清理指定日期之前的操作日志"""
stmt = delete(OperationLog).where(OperationLog.createtime < clean_data.before_date)
result = await db.execute(stmt)
await db.commit()
return {
"message": f"已清理 {result.rowcount} 条操作日志",
"deleted_count": result.rowcount,
}