diff --git a/backend/routers/projects.py b/backend/routers/projects.py index 6efd5a4..8c990da 100644 --- a/backend/routers/projects.py +++ b/backend/routers/projects.py @@ -46,14 +46,37 @@ def _build_milestone_out(m) -> MilestoneOut: def enrich_project(p: Project, db: Session) -> ProjectOut: """将项目对象转为带计算字段的输出""" - # 累计提交秒数 + # 累计提交秒数(全部) total_secs = db.query(sa_func.sum(Submission.total_seconds)).filter( Submission.project_id == p.id, Submission.total_seconds > 0 ).scalar() or 0 + # 中期产出(动画制作)— 对标目标时长 + animation_secs = db.query(sa_func.sum(Submission.total_seconds)).filter( + Submission.project_id == p.id, + Submission.total_seconds > 0, + Submission.project_phase == PhaseGroup.PRODUCTION, + ).scalar() or 0 + + # 后期产出:按内容类型分组 + post_rows = db.query( + Submission.content_type, + sa_func.sum(Submission.total_seconds).label("secs"), + ).filter( + Submission.project_id == p.id, + Submission.total_seconds > 0, + Submission.project_phase == PhaseGroup.POST, + ).group_by(Submission.content_type).all() + + post_secs = sum(row.secs for row in post_rows) + post_breakdown = [ + {"type": ct.value if hasattr(ct, 'value') else ct, "seconds": round(secs, 1)} + for ct, secs in post_rows + ] + target = p.target_total_seconds - progress = round(total_secs / target * 100, 1) if target > 0 else 0 + progress = round(animation_secs / target * 100, 1) if target > 0 else 0 # 集中损耗计算 waste_data = calc_waste_for_project(p.id, db) @@ -83,7 +106,7 @@ def enrich_project(p: Project, db: Session) -> ProjectOut: }, "production": { "progress_percent": progress, - "submitted_seconds": round(total_secs, 1), + "submitted_seconds": round(animation_secs, 1), "target_seconds": target, "waste": waste_data.get("production_waste", {}), }, @@ -103,10 +126,9 @@ def enrich_project(p: Project, db: Session) -> ProjectOut: else: current_stage = "已完成" - # EP 集数进度(批量查询,避免 N+1) + # EP 集数进度(批量查询,避免 N+1)— 只统计中期产出 episode_progress = [] ep_target = p.episode_duration_minutes * 60 # 每集目标秒数 - # 一次查出所有有提交的集数数据 ep_rows = db.query( Submission.episode_number, User.name, @@ -115,6 +137,7 @@ def enrich_project(p: Project, db: Session) -> ProjectOut: Submission.project_id == p.id, Submission.episode_number.isnot(None), Submission.total_seconds > 0, + Submission.project_phase == PhaseGroup.PRODUCTION, ).group_by(Submission.episode_number, User.name).all() # 按集数聚合 @@ -154,6 +177,9 @@ def enrich_project(p: Project, db: Session) -> ProjectOut: contract_amount=p.contract_amount, created_at=p.created_at, total_submitted_seconds=round(total_secs, 1), + animation_seconds=round(animation_secs, 1), + post_production_seconds=round(post_secs, 1), + post_production_breakdown=post_breakdown, progress_percent=progress, waste_seconds=round(waste_seconds, 1), waste_hours=waste_hours, diff --git a/backend/routers/submissions.py b/backend/routers/submissions.py index fb8b00f..34548cf 100644 --- a/backend/routers/submissions.py +++ b/backend/routers/submissions.py @@ -95,8 +95,8 @@ def create_submission( episode_list = [None] # 项目级,单条无集数 elif req.episode_numbers and len(req.episode_numbers) > 0: episode_list = req.episode_numbers # 批量多集 - elif req.episode_number: - episode_list = [req.episode_number] # 单集 + elif req.episode_number is not None: + episode_list = [req.episode_number] # 单集(含0=全集通用) else: raise HTTPException(status_code=422, detail="请选择集数") diff --git a/backend/schemas.py b/backend/schemas.py index 7a20210..8278042 100644 --- a/backend/schemas.py +++ b/backend/schemas.py @@ -136,6 +136,9 @@ class ProjectOut(BaseModel): created_at: Optional[datetime] = None # 动态计算字段 total_submitted_seconds: Optional[float] = 0 + animation_seconds: Optional[float] = 0 # 中期动画产出 + post_production_seconds: Optional[float] = 0 # 后期产出合计 + post_production_breakdown: Optional[List[dict]] = [] # [{"type":"剪辑","seconds":300}, ...] progress_percent: Optional[float] = 0 waste_seconds: Optional[float] = 0 waste_hours: Optional[float] = 0 diff --git a/frontend/src/views/ProjectDetail.vue b/frontend/src/views/ProjectDetail.vue index ba0ac78..934946c 100644 --- a/frontend/src/views/ProjectDetail.vue +++ b/frontend/src/views/ProjectDetail.vue @@ -53,8 +53,8 @@