Files
qiji/backend/app/api/audit.py
T
v6ole 2187be7aeb feat: 操作日志系统 + 日期修复 + 协同去重 + 主题持久化 + 计划自动完成
本次累积提交包含以下功能:

1. 修复:el-date-picker 缺失 value-format 导致日期保存偏移(8处)
2. 新增:协同拜访 visit_group_id 去重机制(完整副本 + 周报合并 + 亮灯去重)
3. 新增:计划自动完成(创建计划检测已有拜访 / 编辑拜访触发)
4. 新增:拜访表单选择客户后自动预填过期计划内容
5. 新增:移动端主题切换按钮 + 后端持久化
6. 新增:操作日志系统 (audit_logs),全覆盖 8 个模块 CRUD
7. 新增:PC端「我的数据」支局长/领导视角客户经理列

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-30 12:01:14 +08:00

81 lines
2.8 KiB
Python

import uuid
from typing import Optional
from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from app.database import get_db
from app.middleware.auth import get_current_user
from app.models.audit_log import AuditLog
router = APIRouter(prefix="/audit-logs", tags=["AuditLogs"])
ENTITY_LABELS: dict[str, str] = {
"customer": "客户",
"visit": "拜访记录",
"daily_note": "今日纪要",
"work_plan": "工作计划",
"mini_business": "小微商机",
"key_visit": "要客拜访",
"user": "用户",
"leave": "请假",
}
@router.get("/")
async def list_audit_logs(
entity_type: Optional[str] = Query(None),
action: Optional[str] = Query(None),
operator_id: Optional[str] = Query(None),
date_from: Optional[str] = Query(None),
date_to: Optional[str] = Query(None),
page: int = Query(1, ge=1),
page_size: int = Query(50, ge=10, le=200),
current_user: dict = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""List audit logs. Only director/leader can access."""
if current_user["role"] not in ("director", "leader"):
return {"items": [], "total": 0}
base = select(AuditLog)
count_q = select(func.count(AuditLog.id))
if entity_type:
base = base.where(AuditLog.entity_type == entity_type)
count_q = count_q.where(AuditLog.entity_type == entity_type)
if action:
base = base.where(AuditLog.action == action)
count_q = count_q.where(AuditLog.action == action)
if operator_id:
base = base.where(AuditLog.operator_id == uuid.UUID(operator_id))
count_q = count_q.where(AuditLog.operator_id == uuid.UUID(operator_id))
if date_from:
base = base.where(AuditLog.created_at >= date_from)
count_q = count_q.where(AuditLog.created_at >= date_from)
if date_to:
base = base.where(AuditLog.created_at < date_to + "T23:59:59")
count_q = count_q.where(AuditLog.created_at < date_to + "T23:59:59")
total = (await db.execute(count_q)).scalar() or 0
query = base.order_by(AuditLog.created_at.desc()).offset((page - 1) * page_size).limit(page_size)
rows = (await db.execute(query)).scalars().all()
items = []
for r in rows:
items.append({
"id": str(r.id),
"entity_type": r.entity_type,
"entity_type_label": ENTITY_LABELS.get(r.entity_type, r.entity_type),
"entity_id": str(r.entity_id),
"entity_name": r.entity_name,
"action": r.action,
"operator_id": str(r.operator_id),
"operator_name": r.operator_name,
"summary": r.summary or "",
"details": r.details,
"created_at": str(r.created_at),
})
return {"items": items, "total": total}