Files
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

131 lines
4.1 KiB
Python

from uuid import UUID
from fastapi import APIRouter, Depends, Query, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.middleware.auth import get_current_user
from app.schemas.leave import LeaveCreate, LeaveUpdate
from app.services import leaves as leave_service
router = APIRouter(prefix="/leaves", tags=["Leaves"])
@router.get("")
async def list_leaves(
manager_id: str | None = Query(None),
status: str | None = Query(None),
page: int = Query(1, ge=1),
page_size: int = Query(25, ge=1, le=100),
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""List leave records. Managers see only their own."""
return await leave_service.get_leaves(
db=db,
user_id=current_user["user_id"],
role=current_user["role"],
manager_id=manager_id,
status=status,
page=page,
page_size=page_size,
)
@router.post("")
async def create_leave(
data: LeaveCreate,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Create a leave record. Director can create for anyone; manager only for self."""
try:
leave = await leave_service.create_leave(
db=db,
data=data.model_dump(),
submitted_by=UUID(current_user["user_id"]),
role=current_user["role"],
operator_name=current_user["name"],
)
return {
"id": str(leave.id),
"manager_id": str(leave.manager_id),
"leave_type": leave.leave_type,
"start_date": str(leave.start_date),
"end_date": str(leave.end_date),
"reason": leave.reason,
"submitted_by": str(leave.submitted_by),
}
except PermissionError as e:
raise HTTPException(status_code=403, detail=str(e))
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.put("/{leave_id}")
async def update_leave(
leave_id: UUID,
data: LeaveUpdate,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Update a leave record."""
try:
leave = await leave_service.update_leave(
db=db,
leave_id=leave_id,
data=data.model_dump(exclude_none=True),
user_id=UUID(current_user["user_id"]),
role=current_user["role"],
operator_name=current_user["name"],
)
return {
"id": str(leave.id),
"manager_id": str(leave.manager_id),
"leave_type": leave.leave_type,
"start_date": str(leave.start_date),
"end_date": str(leave.end_date),
"reason": leave.reason,
}
except PermissionError as e:
raise HTTPException(status_code=403, detail=str(e))
except ValueError as e:
raise HTTPException(status_code=404 if "不存在" in str(e) else 400, detail=str(e))
@router.delete("/{leave_id}")
async def delete_leave(
leave_id: UUID,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Delete a leave record."""
try:
ok = await leave_service.delete_leave(
db=db,
leave_id=leave_id,
user_id=UUID(current_user["user_id"]),
role=current_user["role"],
operator_name=current_user["name"],
)
if not ok:
raise HTTPException(status_code=404, detail="请假记录不存在")
return {"status": "deleted"}
except PermissionError as e:
raise HTTPException(status_code=403, detail=str(e))
@router.get("/overview")
async def leave_overview(
reference_date: str | None = Query(None),
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Get weekly leave overview for dashboard card."""
from datetime import date
ref = date.fromisoformat(reference_date) if reference_date else None
return await leave_service.get_leave_overview(
db=db,
user_id=current_user["user_id"],
role=current_user["role"],
reference_date=ref,
)