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
+ }