2026-03-29 20:31:13 +08:00
|
|
|
from datetime import UTC, date, datetime
|
|
|
|
|
|
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
|
|
|
from sqlalchemy import desc, select
|
2026-03-21 10:13:29 +08:00
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
|
from app.database import get_db
|
|
|
|
|
from app.models.task import Task, TaskStatus
|
|
|
|
|
from app.models.user import User
|
|
|
|
|
from app.routers.auth import get_current_user
|
|
|
|
|
from app.schemas.task import TaskCreate, TaskUpdate, TaskOut
|
|
|
|
|
|
|
|
|
|
router = APIRouter(prefix="/api/tasks", tags=["看板"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("", response_model=list[TaskOut])
|
|
|
|
|
async def list_tasks(
|
|
|
|
|
status: TaskStatus | None = None,
|
2026-03-29 20:31:13 +08:00
|
|
|
due_date: date | None = Query(default=None),
|
|
|
|
|
date_from: date | None = Query(default=None),
|
|
|
|
|
date_to: date | None = Query(default=None),
|
2026-03-21 10:13:29 +08:00
|
|
|
current_user: User = Depends(get_current_user),
|
|
|
|
|
db: AsyncSession = Depends(get_db),
|
|
|
|
|
):
|
|
|
|
|
query = select(Task).where(Task.user_id == current_user.id)
|
|
|
|
|
if status:
|
|
|
|
|
query = query.where(Task.status == status)
|
2026-03-29 20:31:13 +08:00
|
|
|
if due_date:
|
|
|
|
|
start = datetime.combine(due_date, datetime.min.time())
|
|
|
|
|
end = datetime.combine(due_date, datetime.max.time())
|
|
|
|
|
query = query.where(Task.due_date.is_not(None), Task.due_date >= start, Task.due_date <= end)
|
|
|
|
|
else:
|
|
|
|
|
start = datetime.combine(date_from, datetime.min.time()) if date_from else None
|
|
|
|
|
end = datetime.combine(date_to, datetime.max.time()) if date_to else None
|
|
|
|
|
if start and end and start > end:
|
|
|
|
|
raise HTTPException(status_code=400, detail="开始日期不能晚于结束日期")
|
|
|
|
|
if start is not None:
|
|
|
|
|
query = query.where(Task.due_date.is_not(None), Task.due_date >= start)
|
|
|
|
|
if end is not None:
|
|
|
|
|
query = query.where(Task.due_date.is_not(None), Task.due_date <= end)
|
2026-03-21 10:13:29 +08:00
|
|
|
query = query.order_by(desc(Task.created_at))
|
|
|
|
|
result = await db.execute(query)
|
|
|
|
|
return result.scalars().all()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("", response_model=TaskOut, status_code=201)
|
|
|
|
|
async def create_task(
|
|
|
|
|
data: TaskCreate,
|
|
|
|
|
current_user: User = Depends(get_current_user),
|
|
|
|
|
db: AsyncSession = Depends(get_db),
|
|
|
|
|
):
|
|
|
|
|
import json
|
|
|
|
|
task = Task(
|
|
|
|
|
user_id=current_user.id,
|
|
|
|
|
title=data.title,
|
|
|
|
|
description=data.description,
|
|
|
|
|
priority=data.priority,
|
|
|
|
|
due_date=data.due_date,
|
|
|
|
|
tags=json.dumps(data.tags) if data.tags else None,
|
|
|
|
|
)
|
|
|
|
|
db.add(task)
|
|
|
|
|
await db.commit()
|
|
|
|
|
await db.refresh(task)
|
|
|
|
|
return task
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.patch("/{task_id}", response_model=TaskOut)
|
|
|
|
|
async def update_task(
|
|
|
|
|
task_id: str,
|
|
|
|
|
data: TaskUpdate,
|
|
|
|
|
current_user: User = Depends(get_current_user),
|
|
|
|
|
db: AsyncSession = Depends(get_db),
|
|
|
|
|
):
|
|
|
|
|
import json
|
|
|
|
|
result = await db.execute(
|
|
|
|
|
select(Task).where(Task.id == task_id, Task.user_id == current_user.id)
|
|
|
|
|
)
|
|
|
|
|
task = result.scalar_one_or_none()
|
|
|
|
|
if not task:
|
|
|
|
|
raise HTTPException(status_code=404, detail="任务不存在")
|
|
|
|
|
|
|
|
|
|
for field, value in data.model_dump(exclude_none=True).items():
|
|
|
|
|
if field == "tags":
|
|
|
|
|
setattr(task, field, json.dumps(value))
|
|
|
|
|
elif field == "status" and value == TaskStatus.DONE:
|
2026-03-22 13:42:16 +08:00
|
|
|
task.completed_at = datetime.now(UTC)
|
2026-03-21 10:13:29 +08:00
|
|
|
setattr(task, field, value)
|
2026-03-29 20:31:13 +08:00
|
|
|
elif field == "status":
|
|
|
|
|
task.completed_at = None
|
2026-03-21 10:13:29 +08:00
|
|
|
setattr(task, field, value)
|
|
|
|
|
|
|
|
|
|
await db.commit()
|
|
|
|
|
await db.refresh(task)
|
|
|
|
|
return task
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.delete("/{task_id}", status_code=204)
|
|
|
|
|
async def delete_task(
|
|
|
|
|
task_id: str,
|
|
|
|
|
current_user: User = Depends(get_current_user),
|
|
|
|
|
db: AsyncSession = Depends(get_db),
|
|
|
|
|
):
|
|
|
|
|
result = await db.execute(
|
|
|
|
|
select(Task).where(Task.id == task_id, Task.user_id == current_user.id)
|
|
|
|
|
)
|
|
|
|
|
task = result.scalar_one_or_none()
|
|
|
|
|
if not task:
|
|
|
|
|
raise HTTPException(status_code=404, detail="任务不存在")
|
|
|
|
|
await db.delete(task)
|
|
|
|
|
await db.commit()
|