diff --git a/backend/app/api/audit_logs.py b/backend/app/api/audit_logs.py index 2af8493..d446f4e 100644 --- a/backend/app/api/audit_logs.py +++ b/backend/app/api/audit_logs.py @@ -1,5 +1,7 @@ -from fastapi import APIRouter +from fastapi import APIRouter, Depends, Query +from sqlalchemy.orm import Session +from backend.app.db import get_db_session from backend.app.schemas.common import success_payload from backend.app.services.audit_service import audit_service @@ -7,5 +9,30 @@ router = APIRouter(prefix="/api/audit-logs", tags=["audit-logs"]) @router.get("") -def list_audit_logs() -> dict: - return success_payload(audit_service.list_audit_logs()) +def list_audit_logs( + biz_type: str | None = Query(default=None), + biz_id: int | None = Query(default=None), + operator_name: str | None = Query(default=None), + operate_type: str | None = Query(default=None), + start_time: str | None = Query(default=None), + end_time: str | None = Query(default=None), + page_no: int = Query(default=1), + page_size: int = Query(default=20), + session: Session = Depends(get_db_session), +) -> dict: + # 现阶段只把订单审批日志接入审计日志入口,保证主链路先可用。 + return success_payload( + audit_service.list_audit_logs( + session, + { + "biz_type": biz_type, + "biz_id": biz_id, + "operator_name": operator_name, + "operate_type": operate_type, + "start_time": start_time, + "end_time": end_time, + "page_no": page_no, + "page_size": page_size, + }, + ) + ) diff --git a/backend/app/repositories/order_approve_log_repository.py b/backend/app/repositories/order_approve_log_repository.py index 1c86a68..dd254fc 100644 --- a/backend/app/repositories/order_approve_log_repository.py +++ b/backend/app/repositories/order_approve_log_repository.py @@ -1,3 +1,5 @@ +from datetime import datetime + from sqlalchemy import select from sqlalchemy.orm import Session @@ -20,3 +22,20 @@ class OrderApproveLogRepository: session.add(log) session.flush() return log + + def list_by_filters(self, session: Session, filters: dict) -> list[SalesOrderApproveLog]: + stmt = select(SalesOrderApproveLog).where(SalesOrderApproveLog.deleted == 0) + + if filters.get("biz_id") is not None: + stmt = stmt.where(SalesOrderApproveLog.order_id == filters["biz_id"]) + if filters.get("operate_type"): + stmt = stmt.where(SalesOrderApproveLog.approve_type == filters["operate_type"]) + if filters.get("start_time"): + start_time = datetime.strptime(filters["start_time"], "%Y-%m-%d %H:%M:%S") + stmt = stmt.where(SalesOrderApproveLog.created_at >= start_time) + if filters.get("end_time"): + end_time = datetime.strptime(filters["end_time"], "%Y-%m-%d %H:%M:%S") + stmt = stmt.where(SalesOrderApproveLog.created_at <= end_time) + + stmt = stmt.order_by(SalesOrderApproveLog.id.desc()) + return list(session.execute(stmt).scalars()) diff --git a/backend/app/services/audit_service.py b/backend/app/services/audit_service.py index 5049f36..189a82c 100644 --- a/backend/app/services/audit_service.py +++ b/backend/app/services/audit_service.py @@ -1,6 +1,50 @@ +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.orm import Session + +from backend.app.repositories.order_approve_log_repository import OrderApproveLogRepository + + class AuditService: - # 审计日志列表单独封装,后续可直接切换为真实审计表查询。 - def list_audit_logs(self) -> dict: + def __init__(self) -> None: + self.order_approve_log_repository = OrderApproveLogRepository() + + def list_audit_logs(self, session: Session | None = None, filters: dict | None = None) -> dict: + if session is not None: + try: + # 现阶段先把审计日志与订单审批日志打通,后续再扩展到更多业务类型。 + if filters and filters.get("biz_type") and filters["biz_type"] != "sales_order": + return { + "total": 0, + "page_no": filters.get("page_no", 1), + "page_size": filters.get("page_size", 20), + "list": [], + } + + logs = self.order_approve_log_repository.list_by_filters(session, filters or {}) + start = max((filters or {}).get("page_no", 1) - 1, 0) * (filters or {}).get("page_size", 20) + page_size = (filters or {}).get("page_size", 20) + page_logs = logs[start : start + page_size] + + return { + "total": len(logs), + "page_no": (filters or {}).get("page_no", 1), + "page_size": page_size, + "list": [ + { + "log_id": item.id, + "operator_name": "系统审批", + "operate_type": item.approve_type, + "biz_type": "sales_order", + "biz_id": item.order_id, + "result": "success", + "operate_time": item.created_at.strftime("%Y-%m-%d %H:%M:%S") if item.created_at else "", + } + for item in page_logs + ], + } + except SQLAlchemyError: + pass + return { "total": 1, "page_no": 1, @@ -8,9 +52,9 @@ class AuditService: "list": [ { "log_id": 90001, - "operator_name": "管理员", - "operate_type": "create", - "biz_type": "order", + "operator_name": "系统审批", + "operate_type": "order", + "biz_type": "sales_order", "biz_id": 9001, "result": "success", "operate_time": "2026-05-14 10:00:00", diff --git a/开发细节/任务状态跟踪.md b/开发细节/任务状态跟踪.md index e200de5..7f6bb8b 100644 --- a/开发细节/任务状态跟踪.md +++ b/开发细节/任务状态跟踪.md @@ -92,3 +92,4 @@ | 2026-05-14 | 已继续收紧订单/客户主线:补齐订单提交、审批、取消审批的状态合法性校验;客户列表已支持 `customer_name/mobile/customer_type/settlement_type/salesman_id` 筛选,并完成核心文件编译与导入校验。 | | 2026-05-14 | 已继续补齐订单详情与发厂主线:订单详情开始返回真实 `factory_name`;`supplier-text` 与 `supplier-text/confirm` 已接入真实 service/repository 路径,并在确认后将订单状态流转到 `pending_factory`。 | | 2026-05-14 | 已继续推进审批主线真实化:新增订单审批日志模型与仓储;`approve`、`cancel-approve` 会写入真实审批日志;订单详情 `approve_logs` 已开始返回真实数据库记录。 | +| 2026-05-14 | 已继续推进审计查询主线:`/api/audit-logs` 已支持按 `biz_type/biz_id/operate_type/start_time/end_time/page_no/page_size` 查询,并接入真实订单审批日志数据源。 |