# ============================================================================= # 企微IT智能服务台 — 审计日志 API (v0.7.1 task #89) # ============================================================================= # 说明: 审计日志只读端点,给 auditor / admin 用 # 权限要求: audit_log:read:all (由 RBAC 装饰器校验) # ============================================================================= import logging from datetime import datetime from typing import Optional from fastapi import APIRouter, Depends, Query from sqlalchemy.ext.asyncio import AsyncSession from app.dependencies import require_permission, UserInfo from app.database import get_db from app.services.audit_log_service import list_audit_logs from app.utils.response import success_response logger = logging.getLogger(__name__) router = APIRouter(prefix="/admin/audit-logs", tags=["审计日志"]) @router.get("") @require_permission("audit_log", "read", "all") async def get_audit_logs( employee_id: Optional[str] = Query(None, description="按操作人过滤"), action: Optional[str] = Query(None, description="按操作类型过滤"), resource: Optional[str] = Query(None, description="按资源类型过滤"), from_time: Optional[datetime] = Query(None, alias="from", description="起始时间(ISO8601)"), to_time: Optional[datetime] = Query(None, alias="to", description="结束时间(ISO8601)"), page: int = Query(1, ge=1, description="页码"), page_size: int = Query(50, ge=1, le=500, description="每页条数"), admin: UserInfo = None, # 由 require_permission 注入(签名合并) db: AsyncSession = Depends(get_db), ): """查询审计日志(分页)。 权限: 需要 audit_log:read:all (admin / auditor 角色拥有) Returns: Dict: 统一响应格式,包含 items/total/page/page_size """ result = await list_audit_logs( db, employee_id=employee_id, action=action, resource=resource, from_time=from_time, to_time=to_time, page=page, page_size=page_size, ) return success_response(data={ "items": [ { "id": log.id, "employee_id": log.employee_id, "action": log.action, "resource": log.resource, "resource_id": log.resource_id, "details": log.details, "result": log.result, "ip_address": log.ip_address, "user_agent": log.user_agent, "created_at": log.created_at.isoformat() if log.created_at else None, } for log in result["items"] ], "total": result["total"], "page": result["page"], "page_size": result["page_size"], })