From 1686f5664126e328b2955cdc9709e718af2232d4 Mon Sep 17 00:00:00 2001 From: Vincent <84168298+szc0616@users.noreply.github.com> Date: Thu, 6 Nov 2025 12:16:20 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=85=8D=E6=AF=94=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E8=83=BD=E5=A4=9F=E8=B7=B3=E8=BD=AC=E5=88=B0=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E9=9B=86=20(#59)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix:配比任务需要能够跳转到目标数据集 * feature:增加配比任务详情接口 * fix:删除不存在的配比详情页面 --- .../src/pages/RatioTask/Home/RatioTask.tsx | 18 +++++ frontend/src/pages/RatioTask/ratio.api.ts | 5 ++ frontend/src/pages/RatioTask/ratio.model.ts | 1 + .../module/synthesis/interface/ratio_task.py | 78 ++++++++++++++++++- .../app/module/synthesis/schema/ratio_task.py | 22 +++++- 5 files changed, 122 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/RatioTask/Home/RatioTask.tsx b/frontend/src/pages/RatioTask/Home/RatioTask.tsx index 41a40fc..e4d61cc 100644 --- a/frontend/src/pages/RatioTask/Home/RatioTask.tsx +++ b/frontend/src/pages/RatioTask/Home/RatioTask.tsx @@ -60,6 +60,9 @@ export default function RatioTasksPage() { title: "任务名称", dataIndex: "name", key: "name", + render: (text: string, record: RatioTaskItem) => ( + navigate(`/data/synthesis/ratio-task/detail/${record.id}`)}>{text} + ), }, { title: "状态", @@ -81,6 +84,9 @@ export default function RatioTasksPage() { title: "目标数据集", dataIndex: "target_dataset_name", key: "target_dataset_name", + render: (text: string, task: RatioTaskItem) => ( + navigate(`/data/management/detail/${task.target_dataset_id}`)}>{text} + ), }, { title: "创建时间", @@ -173,6 +179,17 @@ export default function RatioTasksPage() { label: "目标数量", value: (task.totals ?? 0).toLocaleString(), }, + { + label: "目标数据集", + value: task.target_dataset_name ? ( + { + e.stopPropagation(); + navigate(`/data/management/detail/${task.target_dataset_id}`); + }}> + {task.target_dataset_name} + + ) : '无', + }, { label: "创建时间", value: task.created_at || "-", @@ -182,6 +199,7 @@ export default function RatioTasksPage() { }))} pagination={pagination} operations={operations} + onView={(task) => {navigate(`/data/synthesis/ratio-task/detail/${task.id}`)}} /> ); diff --git a/frontend/src/pages/RatioTask/ratio.api.ts b/frontend/src/pages/RatioTask/ratio.api.ts index 352f74b..71ae75a 100644 --- a/frontend/src/pages/RatioTask/ratio.api.ts +++ b/frontend/src/pages/RatioTask/ratio.api.ts @@ -5,6 +5,11 @@ export function queryRatioTasksUsingGet(params?: any) { return get("/api/synthesis/ratio-task", params); } +// 查询配比任务详情 +export function getRatioTaskByIdUsingGet(id: string) { + return get(`/api/synthesis/ratio-task/${id}`); +} + // 创建配比任务 export function createRatioTaskUsingPost(data: any) { return post("/api/synthesis/ratio-task", data); diff --git a/frontend/src/pages/RatioTask/ratio.model.ts b/frontend/src/pages/RatioTask/ratio.model.ts index 96c6444..edfa60d 100644 --- a/frontend/src/pages/RatioTask/ratio.model.ts +++ b/frontend/src/pages/RatioTask/ratio.model.ts @@ -77,6 +77,7 @@ export interface RatioTaskItem { ratio_method?: RatioMethod target_dataset_id?: string target_dataset_name?: string + config: RatioConfigItem[] created_at?: string updated_at?: string } diff --git a/runtime/datamate-python/app/module/synthesis/interface/ratio_task.py b/runtime/datamate-python/app/module/synthesis/interface/ratio_task.py index dfa7e42..53821e0 100644 --- a/runtime/datamate-python/app/module/synthesis/interface/ratio_task.py +++ b/runtime/datamate-python/app/module/synthesis/interface/ratio_task.py @@ -18,9 +18,10 @@ from app.module.synthesis.schema.ratio_task import ( PagedRatioTaskResponse, RatioTaskItem, TargetDatasetInfo, + RatioTaskDetailResponse, ) from app.module.synthesis.service.ratio_task import RatioTaskService -from app.db.models.ratio_task import RatioInstance, RatioRelation +from app.db.models.ratio_task import RatioInstance, RatioRelation, RatioRelation as RatioRelationModel router = APIRouter( prefix="/ratio-task", @@ -251,3 +252,78 @@ def get_target_dataset_type(source_types: Set[str]) -> str: # 仅有一种介质类型且无其它类型 target_type = next(iter(media_involved)) return target_type + + +@router.get("/{task_id}", response_model=StandardResponse[RatioTaskDetailResponse], status_code=200) +async def get_ratio_task( + task_id: str, + db: AsyncSession = Depends(get_db), +): + """ + 获取配比任务详情 + + Path: /api/synthesis/ratio-task/{task_id} + """ + try: + # 查询任务实例 + instance_res = await db.execute( + select(RatioInstance).where(RatioInstance.id == task_id) + ) + instance = instance_res.scalar_one_or_none() + if not instance: + raise HTTPException(status_code=404, detail="Ratio task not found") + + # 查询关联的配比关系 + relations_res = await db.execute( + select(RatioRelationModel).where(RatioRelationModel.ratio_instance_id == task_id) + ) + relations = list(relations_res.scalars().all()) + + # 查询目标数据集 + target_ds = None + if instance.target_dataset_id: + ds_res = await db.execute( + select(Dataset).where(Dataset.id == instance.target_dataset_id) + ) + target_ds = ds_res.scalar_one_or_none() + + # 构建响应 + config = [ + { + "dataset_id": rel.source_dataset_id, + "counts": str(rel.counts) if rel.counts is not None else "0", + "filter_conditions": rel.filter_conditions or "", + } + for rel in relations + ] + + target_dataset_info = { + "id": str(target_ds.id) if target_ds else None, + "name": target_ds.name if target_ds else None, + "type": target_ds.dataset_type if target_ds else None, + "status": target_ds.status if target_ds else None, + "file_count": target_ds.file_count if target_ds else 0, + "size_bytes": target_ds.size_bytes if target_ds else 0, + } + + return StandardResponse( + code=200, + message="success", + data=RatioTaskDetailResponse( + id=instance.id, + name=instance.name or "", + description=instance.description, + status=instance.status or "UNKNOWN", + totals=instance.totals or 0, + ratio_method=instance.ratio_method or "", + config=config, + target_dataset=target_dataset_info, + created_at=instance.created_at, + updated_at=instance.updated_at, + ) + ) + except HTTPException: + raise + except Exception as e: + logger.error(f"Failed to get ratio task {task_id}: {e}") + raise HTTPException(status_code=500, detail="Internal server error") diff --git a/runtime/datamate-python/app/module/synthesis/schema/ratio_task.py b/runtime/datamate-python/app/module/synthesis/schema/ratio_task.py index 62af183..743eb00 100644 --- a/runtime/datamate-python/app/module/synthesis/schema/ratio_task.py +++ b/runtime/datamate-python/app/module/synthesis/schema/ratio_task.py @@ -1,4 +1,5 @@ -from typing import List, Optional +from typing import List, Optional, Dict, Any +from datetime import datetime from pydantic import BaseModel, Field, field_validator class RatioConfigItem(BaseModel): @@ -84,3 +85,22 @@ class PagedRatioTaskResponse(BaseModel): totalPages: int page: int size: int + + +class RatioTaskDetailResponse(BaseModel): + """Detailed response for a ratio task.""" + id: str = Field(..., description="任务ID") + name: str = Field(..., description="任务名称") + description: Optional[str] = Field(None, description="任务描述") + status: str = Field(..., description="任务状态") + totals: int = Field(..., description="目标总数") + ratio_method: str = Field(..., description="配比方式") + config: List[Dict[str, Any]] = Field(..., description="配比配置") + target_dataset: Dict[str, Any] = Field(..., description="目标数据集信息") + created_at: Optional[datetime] = Field(None, description="创建时间") + updated_at: Optional[datetime] = Field(None, description="更新时间") + + class Config: + json_encoders = { + datetime: lambda v: v.isoformat() if v else None + }