Step 5:里程碑与任务(伦理/启动会进度)

This commit is contained in:
Cheng Zhou
2025-12-16 17:18:26 +08:00
parent 6c4a2eb1dc
commit a9e15faedc
72 changed files with 535 additions and 1 deletions
+48
View File
@@ -0,0 +1,48 @@
import uuid
from typing import Sequence
from sqlalchemy import select, update as sa_update
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.milestone import Milestone
from app.schemas.milestone import MilestoneCreate, MilestoneUpdate
async def create(db: AsyncSession, study_id: uuid.UUID, milestone_in: MilestoneCreate) -> Milestone:
milestone = Milestone(
study_id=study_id,
type=milestone_in.type,
name=milestone_in.name or milestone_in.type,
planned_date=milestone_in.planned_date,
actual_date=None,
status=milestone_in.status or "NOT_STARTED",
owner_id=milestone_in.owner_id,
notes=milestone_in.notes,
)
db.add(milestone)
await db.commit()
await db.refresh(milestone)
return milestone
async def get(db: AsyncSession, milestone_id: uuid.UUID) -> Milestone | None:
result = await db.execute(select(Milestone).where(Milestone.id == milestone_id))
return result.scalar_one_or_none()
async def list_milestones(db: AsyncSession, study_id: uuid.UUID) -> Sequence[Milestone]:
result = await db.execute(select(Milestone).where(Milestone.study_id == study_id).order_by(Milestone.planned_date))
return result.scalars().all()
async def update(db: AsyncSession, milestone: Milestone, milestone_in: MilestoneUpdate) -> Milestone:
update_data = milestone_in.model_dump(exclude_unset=True)
if update_data:
await db.execute(
sa_update(Milestone)
.where(Milestone.id == milestone.id)
.values(**update_data)
)
await db.commit()
await db.refresh(milestone)
return milestone
+77
View File
@@ -0,0 +1,77 @@
import uuid
from datetime import datetime, timezone
from typing import Sequence
from sqlalchemy import select, update as sa_update
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.task import Task
from app.schemas.task import TaskCreate, TaskUpdate
async def create(
db: AsyncSession,
study_id: uuid.UUID,
task_in: TaskCreate,
*,
created_by: uuid.UUID,
) -> Task:
task = Task(
study_id=study_id,
milestone_id=task_in.milestone_id,
title=task_in.title,
description=task_in.description,
assignee_id=task_in.assignee_id,
priority=task_in.priority,
due_date=task_in.due_date,
status="TODO",
created_by=created_by,
)
db.add(task)
await db.commit()
await db.refresh(task)
return task
async def get(db: AsyncSession, task_id: uuid.UUID) -> Task | None:
result = await db.execute(select(Task).where(Task.id == task_id))
return result.scalar_one_or_none()
async def list_tasks(
db: AsyncSession,
study_id: uuid.UUID,
milestone_id: uuid.UUID | None = None,
assignee_id: uuid.UUID | None = None,
status: str | None = None,
) -> Sequence[Task]:
stmt = select(Task).where(Task.study_id == study_id)
if milestone_id:
stmt = stmt.where(Task.milestone_id == milestone_id)
if assignee_id:
stmt = stmt.where(Task.assignee_id == assignee_id)
if status:
stmt = stmt.where(Task.status == status)
stmt = stmt.order_by(Task.due_date)
result = await db.execute(stmt)
return result.scalars().all()
async def update(db: AsyncSession, task: Task, task_in: TaskUpdate) -> Task:
update_data = task_in.model_dump(exclude_unset=True)
if "status" in update_data:
status_change = update_data["status"]
if status_change == "DONE":
update_data["completed_at"] = datetime.now(timezone.utc)
else:
update_data["completed_at"] = None
if update_data:
await db.execute(
sa_update(Task)
.where(Task.id == task.id)
.values(**update_data)
)
await db.commit()
await db.refresh(task)
return task