feat: AI Worker 平台 MVP v1.0.0 - 多租户/项目管理/AI Worker/任务编排/HITL审核/成本治理
This commit is contained in:
@@ -0,0 +1,114 @@
|
|||||||
|
"""Project service: CRUD + lifecycle management."""
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from typing import List, Optional
|
||||||
|
from app.models.project import Project
|
||||||
|
from app.models.task import Task
|
||||||
|
from app.models.cost import CostLog
|
||||||
|
from app.models.artifact import Artifact
|
||||||
|
from app.models.review import Review
|
||||||
|
from app.schemas.project import ProjectCreate, ProjectUpdate, ProjectStats
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectService:
|
||||||
|
@staticmethod
|
||||||
|
def list_projects(
|
||||||
|
db: Session,
|
||||||
|
tenant_id: int,
|
||||||
|
status: Optional[str] = None,
|
||||||
|
skip: int = 0,
|
||||||
|
limit: int = 100,
|
||||||
|
) -> List[Project]:
|
||||||
|
q = db.query(Project).filter(Project.tenant_id == tenant_id)
|
||||||
|
if status:
|
||||||
|
q = q.filter(Project.status == status)
|
||||||
|
return q.order_by(Project.created_at.desc()).offset(skip).limit(limit).all()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_project(db: Session, tenant_id: int, project_id: int) -> Optional[Project]:
|
||||||
|
return (
|
||||||
|
db.query(Project)
|
||||||
|
.filter(Project.id == project_id, Project.tenant_id == tenant_id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_project(
|
||||||
|
db: Session, tenant_id: int, owner_id: int, req: ProjectCreate
|
||||||
|
) -> Project:
|
||||||
|
project = Project(
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
owner_id=owner_id,
|
||||||
|
name=req.name,
|
||||||
|
description=req.description,
|
||||||
|
start_date=req.start_date,
|
||||||
|
end_date=req.end_date,
|
||||||
|
budget_limit_cents=req.budget_limit_cents,
|
||||||
|
acceptance_criteria=req.acceptance_criteria,
|
||||||
|
tags=req.tags,
|
||||||
|
status="draft",
|
||||||
|
)
|
||||||
|
db.add(project)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(project)
|
||||||
|
return project
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def update_project(
|
||||||
|
db: Session, tenant_id: int, project_id: int, req: ProjectUpdate
|
||||||
|
) -> Project:
|
||||||
|
project = ProjectService.get_project(db, tenant_id, project_id)
|
||||||
|
if not project:
|
||||||
|
raise ValueError(f"Project #{project_id} not found")
|
||||||
|
for field, value in req.model_dump(exclude_unset=True).items():
|
||||||
|
setattr(project, field, value)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(project)
|
||||||
|
return project
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete_project(db: Session, tenant_id: int, project_id: int) -> bool:
|
||||||
|
project = ProjectService.get_project(db, tenant_id, project_id)
|
||||||
|
if not project:
|
||||||
|
return False
|
||||||
|
db.delete(project)
|
||||||
|
db.commit()
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_stats(db: Session, tenant_id: int, project_id: int) -> ProjectStats:
|
||||||
|
tasks = (
|
||||||
|
db.query(Task)
|
||||||
|
.filter(Task.project_id == project_id, Task.tenant_id == tenant_id)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
cost_logs = (
|
||||||
|
db.query(CostLog)
|
||||||
|
.filter(CostLog.project_id == project_id, CostLog.tenant_id == tenant_id)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
artifacts = (
|
||||||
|
db.query(Artifact)
|
||||||
|
.filter(Artifact.project_id == project_id, Artifact.tenant_id == tenant_id)
|
||||||
|
.count()
|
||||||
|
)
|
||||||
|
pending_reviews = (
|
||||||
|
db.query(Review)
|
||||||
|
.filter(
|
||||||
|
Review.project_id == project_id,
|
||||||
|
Review.tenant_id == tenant_id,
|
||||||
|
Review.status == "pending",
|
||||||
|
)
|
||||||
|
.count()
|
||||||
|
)
|
||||||
|
total_cost = sum(c.cost_cents for c in cost_logs)
|
||||||
|
|
||||||
|
return ProjectStats(
|
||||||
|
total_tasks=len(tasks),
|
||||||
|
pending_tasks=sum(1 for t in tasks if t.status == "pending"),
|
||||||
|
in_progress_tasks=sum(1 for t in tasks if t.status == "in_progress"),
|
||||||
|
review_tasks=sum(1 for t in tasks if t.status == "review"),
|
||||||
|
done_tasks=sum(1 for t in tasks if t.status == "done"),
|
||||||
|
total_cost_cents=total_cost,
|
||||||
|
total_artifacts=artifacts,
|
||||||
|
pending_reviews=pending_reviews,
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user