2187be7aeb
本次累积提交包含以下功能: 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>
81 lines
2.8 KiB
Python
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}
|