add api
This commit is contained in:
parent
9032a75118
commit
a02f24a47c
1
.idea/vcs.xml
generated
1
.idea/vcs.xml
generated
@ -2,5 +2,6 @@
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/tianfeng_task_modules" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
Binary file not shown.
Binary file not shown.
BIN
api/__pycache__/task_instance_api.cpython-312.pyc
Normal file
BIN
api/__pycache__/task_instance_api.cpython-312.pyc
Normal file
Binary file not shown.
BIN
api/__pycache__/task_param_api.cpython-312.pyc
Normal file
BIN
api/__pycache__/task_param_api.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
@ -11,86 +11,3 @@ from api.models import ApiResponse
|
||||
|
||||
# 创建路由器
|
||||
router = APIRouter(prefix="/common-params", tags=["常用参数"])
|
||||
|
||||
# 创建服务实例
|
||||
common_params_service = CommonParamsService()
|
||||
|
||||
@router.get("/types", response_model=ApiResponse)
|
||||
async def get_param_types():
|
||||
"""获取所有常用参数类型"""
|
||||
try:
|
||||
param_types = CommonParamsConfig.get_param_types()
|
||||
|
||||
return {
|
||||
"code": ApiResponseCode.SUCCESS,
|
||||
"message": "获取常用参数类型成功",
|
||||
"data": {
|
||||
"param_types": param_types
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=ApiResponseCode.SERVER_ERROR,
|
||||
detail=f"获取常用参数类型失败: {str(e)}"
|
||||
)
|
||||
|
||||
@router.get("/data/{param_type}", response_model=ApiResponse)
|
||||
async def get_param_data(param_type: str):
|
||||
"""获取指定类型的常用参数数据"""
|
||||
try:
|
||||
# 检查参数类型是否有效
|
||||
param_type_config = CommonParamsConfig.get_param_type_by_type(param_type)
|
||||
if not param_type_config:
|
||||
return {
|
||||
"code": ApiResponseCode.NOT_FOUND,
|
||||
"message": f"未找到参数类型: {param_type}",
|
||||
"data": {"param_data": []}
|
||||
}
|
||||
|
||||
# 获取参数数据
|
||||
param_data = common_params_service.get_param_data(param_type)
|
||||
|
||||
return {
|
||||
"code": ApiResponseCode.SUCCESS,
|
||||
"message": f"获取{param_type_config['name']}数据成功",
|
||||
"data": {
|
||||
"param_type": param_type_config,
|
||||
"param_data": param_data
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=ApiResponseCode.SERVER_ERROR,
|
||||
detail=f"获取常用参数数据失败: {str(e)}"
|
||||
)
|
||||
|
||||
@router.get("/all", response_model=ApiResponse)
|
||||
async def get_all_param_data():
|
||||
"""获取所有常用参数数据"""
|
||||
try:
|
||||
# 获取所有参数类型
|
||||
param_types = CommonParamsConfig.get_param_types()
|
||||
|
||||
# 获取所有参数数据
|
||||
all_param_data = {}
|
||||
for param_type_config in param_types:
|
||||
param_type = param_type_config["type"]
|
||||
param_data = common_params_service.get_param_data(param_type)
|
||||
all_param_data[param_type] = {
|
||||
"param_type": param_type_config,
|
||||
"param_data": param_data
|
||||
}
|
||||
|
||||
return {
|
||||
"code": ApiResponseCode.SUCCESS,
|
||||
"message": "获取所有常用参数数据成功",
|
||||
"data": {
|
||||
"param_types": param_types,
|
||||
"all_param_data": all_param_data
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=ApiResponseCode.SERVER_ERROR,
|
||||
detail=f"获取所有常用参数数据失败: {str(e)}"
|
||||
)
|
@ -19,4 +19,15 @@ from api.models.workflow import (
|
||||
)
|
||||
|
||||
# 导出组件相关模型
|
||||
from api.models.component import ComponentDiscoverInput
|
||||
from api.models.component import ComponentDiscoverInput
|
||||
|
||||
# 导出任务实例相关模型
|
||||
from api.models.task_instance import (
|
||||
TaskInstanceCreateInput, TaskInstanceUpdateInput,
|
||||
TaskInputParamItem, TaskInputParamsInput, TaskInstanceStatus
|
||||
)
|
||||
|
||||
# 导出任务参数相关模型
|
||||
from api.models.task_param import (
|
||||
TaskInputParamModel, TaskInputParamsUpdateRequest
|
||||
)
|
Binary file not shown.
BIN
api/models/__pycache__/task_instance.cpython-312.pyc
Normal file
BIN
api/models/__pycache__/task_instance.cpython-312.pyc
Normal file
Binary file not shown.
BIN
api/models/__pycache__/task_param.cpython-312.pyc
Normal file
BIN
api/models/__pycache__/task_param.cpython-312.pyc
Normal file
Binary file not shown.
53
api/models/task_instance.py
Normal file
53
api/models/task_instance.py
Normal file
@ -0,0 +1,53 @@
|
||||
"""
|
||||
任务实例相关API模型
|
||||
包含任务实例的请求和响应的数据模型
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, List, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
from enum import Enum
|
||||
|
||||
# 请求模型
|
||||
class TaskInstanceCreateInput(BaseModel):
|
||||
"""任务实例创建输入模型"""
|
||||
task_id: str = Field(..., description="任务ID")
|
||||
name: Optional[str] = Field(None, description="任务名称")
|
||||
variables: Optional[Dict[str, Any]] = Field(None, description="任务变量")
|
||||
priority: int = Field(1, description="任务优先级")
|
||||
input_params: Optional[Dict[str, Any]] = Field(None, description="任务输入参数")
|
||||
block_outputs: Optional[Dict[str, Any]] = Field(None, description="块输出参数")
|
||||
context_params: Optional[Dict[str, Any]] = Field(None, description="上下文参数")
|
||||
|
||||
class TaskInstanceUpdateInput(BaseModel):
|
||||
"""任务实例更新输入模型"""
|
||||
variables: Optional[Dict[str, Any]] = Field(None, description="任务变量")
|
||||
priority: Optional[int] = Field(None, description="任务优先级")
|
||||
input_params: Optional[Dict[str, Any]] = Field(None, description="任务输入参数")
|
||||
block_outputs: Optional[Dict[str, Any]] = Field(None, description="块输出参数")
|
||||
context_params: Optional[Dict[str, Any]] = Field(None, description="上下文参数")
|
||||
|
||||
# 任务输入参数模型
|
||||
class TaskInputParamItem(BaseModel):
|
||||
"""任务输入参数项目"""
|
||||
key: str = Field(..., description="参数名")
|
||||
label: str = Field(..., description="参数标签")
|
||||
type: str = Field(..., description="参数类型")
|
||||
required: bool = Field(False, description="是否必填")
|
||||
default_value: Optional[Any] = Field(None, description="默认值")
|
||||
description: Optional[str] = Field(None, description="参数说明")
|
||||
options: Optional[Dict[str, Any]] = Field(None, description="选项配置,用于下拉选择、单选、多选类型")
|
||||
validation_rules: Optional[Dict[str, Any]] = Field(None, description="验证规则")
|
||||
|
||||
class TaskInputParamsInput(BaseModel):
|
||||
"""任务输入参数添加/更新模型"""
|
||||
params: List[TaskInputParamItem] = Field(..., description="输入参数列表")
|
||||
|
||||
# 任务实例状态枚举
|
||||
class TaskInstanceStatus(str, Enum):
|
||||
"""任务实例状态枚举"""
|
||||
DRAFT = "draft" # 草稿
|
||||
PUBLISHED = "published" # 已发布
|
||||
RUNNING = "running" # 运行中
|
||||
COMPLETED = "completed" # 已完成
|
||||
FAILED = "failed" # 失败
|
||||
CANCELED = "canceled" # 已取消
|
25
api/models/task_param.py
Normal file
25
api/models/task_param.py
Normal file
@ -0,0 +1,25 @@
|
||||
"""
|
||||
任务参数相关API模型
|
||||
包含任务参数的请求和响应的数据模型
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, List, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
from enum import Enum
|
||||
from config.task_config import TaskInputParamType
|
||||
|
||||
# 任务输入参数模型
|
||||
class TaskInputParamModel(BaseModel):
|
||||
"""任务输入参数模型"""
|
||||
param_id: Optional[str] = Field(None, description="参数ID,新增参数时不需要传")
|
||||
param_name: str = Field(..., description="变量名")
|
||||
label: str = Field(..., description="标签")
|
||||
param_type: TaskInputParamType = Field(..., description="类型")
|
||||
required: bool = Field(False, description="是否必填")
|
||||
default_value: Optional[Any] = Field(None, description="默认值")
|
||||
description: Optional[str] = Field(None, description="说明")
|
||||
|
||||
class TaskInputParamsUpdateRequest(BaseModel):
|
||||
"""任务输入参数更新请求"""
|
||||
task_id: str
|
||||
params: List[TaskInputParamModel]
|
296
api/task_api.py
296
api/task_api.py
@ -26,6 +26,7 @@ from api.models import (
|
||||
ApiResponse, TaskInput, TaskBatchInput, TaskIdList,
|
||||
TaskTypeInfo, SortField, SortOrder, TaskUpdateInput, TaskEditInput
|
||||
)
|
||||
# from data import get_session
|
||||
|
||||
# 创建路由器
|
||||
router = APIRouter(tags=["任务管理"])
|
||||
@ -152,29 +153,6 @@ async def create_task(task_input: TaskInput):
|
||||
raise HTTPException(status_code=500, detail=f"创建任务失败: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/task/{task_id}", response_model=ApiResponse)
|
||||
async def get_task(task_id: str):
|
||||
"""获取任务详情"""
|
||||
try:
|
||||
# 获取任务
|
||||
task = task_service.get_task_by_id(task_id)
|
||||
|
||||
if not task:
|
||||
return {
|
||||
"code": 404,
|
||||
"message": f"任务不存在: {task_id}",
|
||||
"data": None
|
||||
}
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "获取任务详情成功",
|
||||
"data": task
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"获取任务详情失败: {str(e)}")
|
||||
|
||||
|
||||
@router.delete("/task/{task_id}", response_model=ApiResponse)
|
||||
async def delete_task(task_id: str):
|
||||
"""删除任务"""
|
||||
@ -199,56 +177,56 @@ async def delete_task(task_id: str):
|
||||
raise HTTPException(status_code=500, detail=f"删除任务失败: {str(e)}")
|
||||
|
||||
|
||||
@router.post("/task/{task_id}/execute", response_model=ApiResponse)
|
||||
async def execute_task(task_id: str):
|
||||
"""执行任务"""
|
||||
try:
|
||||
# 执行任务
|
||||
task = task_service.execute_task(task_id)
|
||||
# @router.post("/task/{task_id}/execute", response_model=ApiResponse)
|
||||
# async def execute_task(task_id: str):
|
||||
# """执行任务"""
|
||||
# try:
|
||||
# # 执行任务
|
||||
# task = task_service.execute_task(task_id)
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "执行任务成功",
|
||||
"data": task
|
||||
}
|
||||
except ValueError as e:
|
||||
# 任务不存在
|
||||
return {
|
||||
"code": 404,
|
||||
"message": str(e),
|
||||
"data": None
|
||||
}
|
||||
except TianfengTaskError as e:
|
||||
# 业务逻辑错误
|
||||
return {
|
||||
"code": 400,
|
||||
"message": str(e),
|
||||
"data": None
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"执行任务失败: {str(e)}")
|
||||
# return {
|
||||
# "code": 200,
|
||||
# "message": "执行任务成功",
|
||||
# "data": task
|
||||
# }
|
||||
# except ValueError as e:
|
||||
# # 任务不存在
|
||||
# return {
|
||||
# "code": 404,
|
||||
# "message": str(e),
|
||||
# "data": None
|
||||
# }
|
||||
# except TianfengTaskError as e:
|
||||
# # 业务逻辑错误
|
||||
# return {
|
||||
# "code": 400,
|
||||
# "message": str(e),
|
||||
# "data": None
|
||||
# }
|
||||
# except Exception as e:
|
||||
# raise HTTPException(status_code=500, detail=f"执行任务失败: {str(e)}")
|
||||
|
||||
@router.post("/task/{task_id}/cancel", response_model=ApiResponse)
|
||||
async def cancel_task(task_id: str):
|
||||
"""取消任务"""
|
||||
try:
|
||||
# 取消任务
|
||||
task = task_service.cancel_task(task_id)
|
||||
# @router.post("/task/{task_id}/cancel", response_model=ApiResponse)
|
||||
# async def cancel_task(task_id: str):
|
||||
# """取消任务"""
|
||||
# try:
|
||||
# # 取消任务
|
||||
# task = task_service.cancel_task(task_id)
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "取消任务成功",
|
||||
"data": task
|
||||
}
|
||||
except ValueError as e:
|
||||
# 任务不存在或状态不允许取消
|
||||
return {
|
||||
"code": 400,
|
||||
"message": str(e),
|
||||
"data": None
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"取消任务失败: {str(e)}")
|
||||
# return {
|
||||
# "code": 200,
|
||||
# "message": "取消任务成功",
|
||||
# "data": task
|
||||
# }
|
||||
# except ValueError as e:
|
||||
# # 任务不存在或状态不允许取消
|
||||
# return {
|
||||
# "code": 400,
|
||||
# "message": str(e),
|
||||
# "data": None
|
||||
# }
|
||||
# except Exception as e:
|
||||
# raise HTTPException(status_code=500, detail=f"取消任务失败: {str(e)}")
|
||||
|
||||
|
||||
|
||||
@ -316,72 +294,6 @@ async def update_task(task_id: str, task_update: TaskUpdateInput):
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"更新任务失败: {str(e)}")
|
||||
|
||||
@router.post("/task/edit", response_model=ApiResponse)
|
||||
async def edit_task(task_edit: TaskEditInput):
|
||||
"""编辑任务流程和变量"""
|
||||
try:
|
||||
# 检查任务是否存在
|
||||
task = task_service.get_task_by_id(task_edit.task_id)
|
||||
if not task:
|
||||
return {
|
||||
"code": 404,
|
||||
"message": f"任务 {task_edit.task_id} 不存在",
|
||||
"data": None
|
||||
}
|
||||
|
||||
# 更新任务流程和变量
|
||||
updated_task = task_service.update_task_workflow(
|
||||
task_id=task_edit.task_id,
|
||||
blocks=task_edit.blocks,
|
||||
variables=task_edit.variables
|
||||
)
|
||||
|
||||
# 获取编辑中的任务实例
|
||||
editing_instance = task_instance_service.get_editing_instance_by_task_id(task_edit.task_id)
|
||||
|
||||
# 准备更新的参数
|
||||
update_params = {
|
||||
"variables": task_edit.variables,
|
||||
"priority": task_edit.priority if hasattr(task_edit, "priority") else None
|
||||
}
|
||||
|
||||
# 如果有自定义输入参数,添加到更新参数中
|
||||
if hasattr(task_edit, "input_params") and task_edit.input_params is not None:
|
||||
update_params["input_params"] = task_edit.input_params
|
||||
|
||||
# 如果有块输出参数,添加到更新参数中
|
||||
if hasattr(task_edit, "block_outputs") and task_edit.block_outputs is not None:
|
||||
update_params["block_outputs"] = task_edit.block_outputs
|
||||
|
||||
# 如果有上下文参数,添加到更新参数中
|
||||
if hasattr(task_edit, "context_params") and task_edit.context_params is not None:
|
||||
update_params["context_params"] = task_edit.context_params
|
||||
|
||||
if editing_instance:
|
||||
# 更新编辑中的任务实例
|
||||
instance = task_instance_service.update_instance(
|
||||
instance_id=editing_instance["instance_id"],
|
||||
**update_params
|
||||
)
|
||||
else:
|
||||
# 创建新的任务实例
|
||||
instance = task_instance_service.create_instance(
|
||||
task_id=task_edit.task_id,
|
||||
name=task.get("name"),
|
||||
**update_params
|
||||
)
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "编辑任务成功",
|
||||
"data": {
|
||||
"task": updated_task,
|
||||
"instance": instance
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"编辑任务失败: {str(e)}")
|
||||
|
||||
@router.get("/task/{task_id}/edit", response_model=ApiResponse)
|
||||
async def get_task_edit_info(task_id: str):
|
||||
"""获取任务编辑信息"""
|
||||
@ -398,22 +310,32 @@ async def get_task_edit_info(task_id: str):
|
||||
# 获取或创建编辑中的任务实例
|
||||
instance = task_instance_service.get_or_create_editing_instance(task_id)
|
||||
|
||||
# 获取任务输入参数
|
||||
from services.task_param_service import TaskParamService
|
||||
task_param_service = TaskParamService()
|
||||
task_input_params, _ = task_param_service.get_task_input_params(task_id, instance["instance_id"])
|
||||
|
||||
# 将任务输入参数添加到实例数据中
|
||||
instance["task_input_params"] = task_input_params
|
||||
|
||||
# 获取可用的子任务列表(排除当前任务自身)
|
||||
available_subtasks = []
|
||||
|
||||
try:
|
||||
all_tasks, _ = task_service.get_all_tasks(page=1, page_size=1000) # 获取所有任务
|
||||
for t in all_tasks:
|
||||
if t["task_id"] != task_id: # 排除当前任务
|
||||
available_subtasks.append({
|
||||
subtask_info = {
|
||||
"task_id": t["task_id"],
|
||||
"name": t["name"]
|
||||
})
|
||||
}
|
||||
available_subtasks.append(subtask_info)
|
||||
except Exception as e:
|
||||
# 如果获取任务列表失败,记录错误但继续执行
|
||||
print(f"获取可用子任务列表失败: {str(e)}")
|
||||
|
||||
# 获取组件详细信息
|
||||
from config.component_config import ComponentDetailConfig
|
||||
from config.component_config import ComponentDetailConfig, SubtaskComponentConfig
|
||||
component_details = ComponentDetailConfig.get_all_components()
|
||||
|
||||
# 获取组件类型中文名称映射
|
||||
@ -437,6 +359,14 @@ async def get_task_edit_info(task_id: str):
|
||||
# 添加组件到对应类型下
|
||||
component_types[component_type]["components"].append(component)
|
||||
|
||||
# 特殊处理subtask类型,将每个可用子任务构建为独立组件
|
||||
if "subtask" in component_types and available_subtasks:
|
||||
# 使用配置中的方法生成子任务组件
|
||||
subtask_components = SubtaskComponentConfig.generate_subtask_components(available_subtasks)
|
||||
|
||||
# 替换原有的组件列表
|
||||
component_types["subtask"]["components"] = subtask_components
|
||||
|
||||
# 获取常用参数数据
|
||||
from services.common_params_service import CommonParamsService
|
||||
from config.component_config import CommonParamsConfig
|
||||
@ -454,23 +384,6 @@ async def get_task_edit_info(task_id: str):
|
||||
"data": param_data
|
||||
}
|
||||
|
||||
# 从配置文件中获取系统默认参数
|
||||
task_input_params = TaskInputParamConfig.build_system_params_with_values(task_id, instance)
|
||||
|
||||
# 如果实例中有自定义的输入参数,添加到列表中
|
||||
if instance.get("input_params"):
|
||||
for key, value in instance["input_params"].items():
|
||||
# 检查是否已存在同名参数
|
||||
if not any(param["key"] == key for param in task_input_params):
|
||||
task_input_params.append({
|
||||
"key": key,
|
||||
"name": key, # 可以根据需要设置更友好的名称
|
||||
"value": value,
|
||||
"type": "string", # 可以根据值的类型动态设置
|
||||
"is_system": False,
|
||||
"is_readonly": False
|
||||
})
|
||||
|
||||
# 获取块输出参数和上下文参数
|
||||
block_output_params = instance.get("block_outputs", {})
|
||||
context_params = instance.get("context_params", {})
|
||||
@ -482,9 +395,8 @@ async def get_task_edit_info(task_id: str):
|
||||
"task": task,
|
||||
"instance": instance,
|
||||
"component_types": component_types,
|
||||
"available_subtasks": available_subtasks,
|
||||
"common_params": common_params,
|
||||
"task_input_params": task_input_params,
|
||||
"task_input_params": instance["task_input_params"], # 使用实例中的任务输入参数
|
||||
"block_output_params": block_output_params,
|
||||
"context_params": context_params
|
||||
}
|
||||
@ -518,42 +430,42 @@ async def get_available_subtasks(current_task_id: Optional[str] = None):
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"获取可用子任务列表失败: {str(e)}")
|
||||
|
||||
@router.post("/task/{task_id}/publish", response_model=ApiResponse)
|
||||
async def publish_task(task_id: str):
|
||||
"""发布任务(将编辑中的任务实例状态更改为已发布)"""
|
||||
try:
|
||||
# 检查任务是否存在
|
||||
task = task_service.get_task_by_id(task_id)
|
||||
if not task:
|
||||
return {
|
||||
"code": 404,
|
||||
"message": f"任务 {task_id} 不存在",
|
||||
"data": None
|
||||
}
|
||||
# @router.post("/task/{task_id}/publish", response_model=ApiResponse)
|
||||
# async def publish_task(task_id: str):
|
||||
# """发布任务(将编辑中的任务实例状态更改为已发布)"""
|
||||
# try:
|
||||
# # 检查任务是否存在
|
||||
# task = task_service.get_task_by_id(task_id)
|
||||
# if not task:
|
||||
# return {
|
||||
# "code": 404,
|
||||
# "message": f"任务 {task_id} 不存在",
|
||||
# "data": None
|
||||
# }
|
||||
|
||||
# 获取编辑中的任务实例
|
||||
editing_instance = task_instance_service.get_editing_instance_by_task_id(task_id)
|
||||
if not editing_instance:
|
||||
return {
|
||||
"code": 404,
|
||||
"message": f"任务 {task_id} 没有编辑中的实例",
|
||||
"data": None
|
||||
}
|
||||
# # 获取编辑中的任务实例
|
||||
# editing_instance = task_instance_service.get_editing_instance_by_task_id(task_id)
|
||||
# if not editing_instance:
|
||||
# return {
|
||||
# "code": 404,
|
||||
# "message": f"任务 {task_id} 没有编辑中的实例",
|
||||
# "data": None
|
||||
# }
|
||||
|
||||
# 发布任务实例
|
||||
published_instance = task_instance_service.publish_instance(editing_instance["instance_id"])
|
||||
# # 发布任务实例
|
||||
# published_instance = task_instance_service.publish_instance(editing_instance["instance_id"])
|
||||
|
||||
# 构建响应数据
|
||||
response_data = {
|
||||
"task": task,
|
||||
"instance": published_instance
|
||||
}
|
||||
# # 构建响应数据
|
||||
# response_data = {
|
||||
# "task": task,
|
||||
# "instance": published_instance
|
||||
# }
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "发布任务成功",
|
||||
"data": response_data
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"发布任务失败: {str(e)}")
|
||||
# return {
|
||||
# "code": 200,
|
||||
# "message": "发布任务成功",
|
||||
# "data": response_data
|
||||
# }
|
||||
# except Exception as e:
|
||||
# raise HTTPException(status_code=500, detail=f"发布任务失败: {str(e)}")
|
||||
|
||||
|
@ -5,8 +5,11 @@
|
||||
from typing import Dict, Any, List, Optional
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
from pydantic import BaseModel, Field
|
||||
from services.task_instance_service import TaskInstanceService, TaskInstanceStatus
|
||||
from api.models import ApiResponse
|
||||
from services.task_instance_service import TaskInstanceService
|
||||
from api.models import (
|
||||
ApiResponse, TaskInstanceCreateInput, TaskInstanceUpdateInput,
|
||||
TaskInputParamItem, TaskInputParamsInput, TaskInstanceStatus
|
||||
)
|
||||
|
||||
# 创建路由器
|
||||
router = APIRouter(prefix="/task-instances", tags=["任务实例"])
|
||||
@ -14,25 +17,6 @@ router = APIRouter(prefix="/task-instances", tags=["任务实例"])
|
||||
# 创建服务实例
|
||||
task_instance_service = TaskInstanceService()
|
||||
|
||||
# 请求模型
|
||||
class TaskInstanceCreateInput(BaseModel):
|
||||
"""任务实例创建输入模型"""
|
||||
task_id: str = Field(..., description="任务ID")
|
||||
name: Optional[str] = Field(None, description="任务名称")
|
||||
variables: Optional[Dict[str, Any]] = Field(None, description="任务变量")
|
||||
priority: int = Field(1, description="任务优先级")
|
||||
input_params: Optional[Dict[str, Any]] = Field(None, description="任务输入参数")
|
||||
block_outputs: Optional[Dict[str, Any]] = Field(None, description="块输出参数")
|
||||
context_params: Optional[Dict[str, Any]] = Field(None, description="上下文参数")
|
||||
|
||||
class TaskInstanceUpdateInput(BaseModel):
|
||||
"""任务实例更新输入模型"""
|
||||
variables: Optional[Dict[str, Any]] = Field(None, description="任务变量")
|
||||
priority: Optional[int] = Field(None, description="任务优先级")
|
||||
input_params: Optional[Dict[str, Any]] = Field(None, description="任务输入参数")
|
||||
block_outputs: Optional[Dict[str, Any]] = Field(None, description="块输出参数")
|
||||
context_params: Optional[Dict[str, Any]] = Field(None, description="上下文参数")
|
||||
|
||||
# API接口
|
||||
@router.post("/create", response_model=ApiResponse)
|
||||
async def create_task_instance(instance_input: TaskInstanceCreateInput):
|
||||
@ -63,156 +47,4 @@ async def create_task_instance(instance_input: TaskInstanceCreateInput):
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"创建任务实例失败: {str(e)}")
|
||||
|
||||
@router.get("/{instance_id}", response_model=ApiResponse)
|
||||
async def get_task_instance(instance_id: str):
|
||||
"""获取任务实例详情"""
|
||||
try:
|
||||
# 获取任务实例
|
||||
instance = task_instance_service.get_instance_by_id(instance_id)
|
||||
if not instance:
|
||||
return {
|
||||
"code": 404,
|
||||
"message": f"任务实例不存在: {instance_id}",
|
||||
"data": None
|
||||
}
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "获取任务实例成功",
|
||||
"data": instance
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"获取任务实例失败: {str(e)}")
|
||||
|
||||
@router.get("/task/{task_id}", response_model=ApiResponse)
|
||||
async def get_task_instances(task_id: str):
|
||||
"""获取任务的所有实例"""
|
||||
try:
|
||||
# 获取任务实例
|
||||
instances = task_instance_service.get_instances_by_task_id(task_id)
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "获取任务实例列表成功",
|
||||
"data": {
|
||||
"instances": instances,
|
||||
"total": len(instances)
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"获取任务实例列表失败: {str(e)}")
|
||||
|
||||
@router.get("/task/{task_id}/latest", response_model=ApiResponse)
|
||||
async def get_latest_task_instance(task_id: str):
|
||||
"""获取任务的最新实例"""
|
||||
try:
|
||||
# 获取最新任务实例
|
||||
instance = task_instance_service.get_latest_instance_by_task_id(task_id)
|
||||
if not instance:
|
||||
return {
|
||||
"code": 404,
|
||||
"message": f"任务 {task_id} 没有实例",
|
||||
"data": None
|
||||
}
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "获取最新任务实例成功",
|
||||
"data": instance
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"获取最新任务实例失败: {str(e)}")
|
||||
|
||||
@router.put("/{instance_id}", response_model=ApiResponse)
|
||||
async def update_task_instance(instance_id: str, instance_input: TaskInstanceUpdateInput):
|
||||
"""更新任务实例"""
|
||||
try:
|
||||
# 更新任务实例
|
||||
instance = task_instance_service.update_instance(
|
||||
instance_id=instance_id,
|
||||
variables=instance_input.variables,
|
||||
priority=instance_input.priority,
|
||||
input_params=instance_input.input_params,
|
||||
block_outputs=instance_input.block_outputs,
|
||||
context_params=instance_input.context_params
|
||||
)
|
||||
|
||||
if not instance:
|
||||
return {
|
||||
"code": 404,
|
||||
"message": f"任务实例不存在: {instance_id}",
|
||||
"data": None
|
||||
}
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "更新任务实例成功",
|
||||
"data": instance
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"更新任务实例失败: {str(e)}")
|
||||
|
||||
@router.delete("/{instance_id}", response_model=ApiResponse)
|
||||
async def delete_task_instance(instance_id: str):
|
||||
"""删除任务实例"""
|
||||
try:
|
||||
# 删除任务实例
|
||||
success = task_instance_service.delete_instance(instance_id)
|
||||
|
||||
if not success:
|
||||
return {
|
||||
"code": 404,
|
||||
"message": f"任务实例不存在: {instance_id}",
|
||||
"data": None
|
||||
}
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "删除任务实例成功",
|
||||
"data": None
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"删除任务实例失败: {str(e)}")
|
||||
|
||||
@router.post("/{instance_id}/publish", response_model=ApiResponse)
|
||||
async def publish_task_instance(instance_id: str):
|
||||
"""发布任务实例"""
|
||||
try:
|
||||
# 发布任务实例
|
||||
instance = task_instance_service.publish_instance(instance_id)
|
||||
|
||||
if not instance:
|
||||
return {
|
||||
"code": 404,
|
||||
"message": f"任务实例不存在: {instance_id}",
|
||||
"data": None
|
||||
}
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "发布任务实例成功",
|
||||
"data": instance
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"发布任务实例失败: {str(e)}")
|
||||
|
||||
@router.get("/task/{task_id}/editing", response_model=ApiResponse)
|
||||
async def get_or_create_editing_instance(task_id: str):
|
||||
"""获取或创建编辑中的任务实例"""
|
||||
try:
|
||||
# 获取或创建编辑中的任务实例
|
||||
instance = task_instance_service.get_or_create_editing_instance(task_id)
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "获取编辑中的任务实例成功",
|
||||
"data": instance
|
||||
}
|
||||
except ValueError as e:
|
||||
return {
|
||||
"code": 404,
|
||||
"message": str(e),
|
||||
"data": None
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"获取编辑中的任务实例失败: {str(e)}")
|
170
api/task_param_api.py
Normal file
170
api/task_param_api.py
Normal file
@ -0,0 +1,170 @@
|
||||
"""
|
||||
任务参数API
|
||||
包含任务输入参数相关的API接口
|
||||
"""
|
||||
from typing import Dict, Any, List, Optional
|
||||
from fastapi import APIRouter, HTTPException, Depends, Query, Path, Request
|
||||
from pydantic import BaseModel, Field
|
||||
from config.task_config import (
|
||||
TaskInputParamConfig,
|
||||
TaskInputParamType,
|
||||
SystemParamKey
|
||||
)
|
||||
from services.task_param_service import TaskParamService
|
||||
from core.exceptions import TianfengTaskError
|
||||
from api.models import (
|
||||
ApiResponse, TaskInputParamModel, TaskInputParamsUpdateRequest
|
||||
)
|
||||
import logging
|
||||
import json
|
||||
|
||||
# 创建日志记录器
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 创建路由器
|
||||
router = APIRouter(tags=["任务参数管理"])
|
||||
|
||||
# 创建服务实例
|
||||
task_param_service = TaskParamService()
|
||||
|
||||
@router.get("/task/input-params/fields", response_model=ApiResponse)
|
||||
async def get_task_param_types():
|
||||
"""获取任务输入参数表单字段定义"""
|
||||
try:
|
||||
# 从配置中获取表单字段定义
|
||||
form_fields = TaskInputParamConfig.get_input_params_form_fields()
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "获取任务输入参数表单字段定义成功",
|
||||
"data": {
|
||||
"form_fields": form_fields
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"获取任务输入参数表单字段定义失败: {str(e)}")
|
||||
|
||||
@router.get("/task/{task_id}/input-params", response_model=ApiResponse)
|
||||
async def get_task_input_params(
|
||||
task_id: str = Path(..., description="任务ID"),
|
||||
instance_id: str = Query(None, description="任务实例ID,不传则使用最新实例")
|
||||
):
|
||||
"""
|
||||
获取任务输入参数配置
|
||||
|
||||
返回任务输入参数的配置信息,包括系统默认参数和用户自定义参数
|
||||
"""
|
||||
try:
|
||||
# 使用任务参数服务获取参数
|
||||
params, found_instance_id = task_param_service.get_task_input_params(task_id, instance_id)
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": "获取任务输入参数成功",
|
||||
"data": {
|
||||
"task_id": task_id,
|
||||
"instance_id": found_instance_id,
|
||||
"params": params
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"获取任务输入参数失败: {str(e)}")
|
||||
|
||||
def safe_process_default_value(param_dict: Dict[str, Any]) -> None:
|
||||
"""
|
||||
安全处理参数的default_value值,确保其是JSON可序列化的
|
||||
|
||||
Args:
|
||||
param_dict: 参数字典,将被原地修改
|
||||
"""
|
||||
# 如果没有default_value键,不处理
|
||||
if "default_value" not in param_dict:
|
||||
return
|
||||
|
||||
default_value = param_dict["default_value"]
|
||||
param_type = param_dict.get("param_type", "")
|
||||
|
||||
# None值保持不变
|
||||
if default_value is None:
|
||||
return
|
||||
|
||||
# 只对json和array类型做特殊处理
|
||||
if param_type not in ["json", "array"]:
|
||||
return
|
||||
|
||||
# 如果已经是字符串,尝试解析为JSON对象
|
||||
if isinstance(default_value, str):
|
||||
try:
|
||||
param_dict["default_value"] = json.loads(default_value)
|
||||
except json.JSONDecodeError:
|
||||
# 解析失败保持原字符串
|
||||
pass
|
||||
|
||||
@router.post("/task/{task_id}/input-params", response_model=ApiResponse)
|
||||
async def update_task_input_params(
|
||||
task_id: str = Path(..., description="任务ID"),
|
||||
request: List[TaskInputParamModel] = None,
|
||||
instance_id: str = Query(None, description="任务实例ID,不传则使用最新实例或创建新实例")
|
||||
):
|
||||
"""
|
||||
更新任务输入参数配置
|
||||
|
||||
批量保存用户自定义的任务输入参数配置,只有点击"完成"按钮后才会生效
|
||||
|
||||
请求示例:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"param_name": "robotId",
|
||||
"label": "机器人ID",
|
||||
"param_type": "string",
|
||||
"required": true,
|
||||
"default_value": "",
|
||||
"description": "执行任务的机器人ID"
|
||||
},
|
||||
{
|
||||
"param_name": "timeout",
|
||||
"label": "超时时间",
|
||||
"param_type": "integer",
|
||||
"required": false,
|
||||
"default_value": 3600,
|
||||
"description": "任务执行的超时时间(秒)"
|
||||
}
|
||||
]
|
||||
```
|
||||
"""
|
||||
try:
|
||||
# 将Pydantic模型转换为字典列表,并安全处理default_value
|
||||
params = []
|
||||
for param in request:
|
||||
param_dict = param.dict(exclude_none=True)
|
||||
safe_process_default_value(param_dict)
|
||||
params.append(param_dict)
|
||||
|
||||
# 使用任务参数服务更新参数
|
||||
updated_count, found_instance_id, has_changes = task_param_service.update_task_input_params(task_id, params, instance_id)
|
||||
|
||||
# 根据是否有变动返回不同的消息
|
||||
message = "更新任务输入参数成功" if has_changes else "任务输入参数无变动"
|
||||
|
||||
return {
|
||||
"code": 200,
|
||||
"message": message,
|
||||
"data": {
|
||||
"task_id": task_id,
|
||||
"instance_id": found_instance_id,
|
||||
"updated_params_count": updated_count,
|
||||
"has_changes": has_changes
|
||||
}
|
||||
}
|
||||
except ValueError as e:
|
||||
return {
|
||||
"code": 400,
|
||||
"message": str(e),
|
||||
"data": None
|
||||
}
|
||||
except Exception as e:
|
||||
import traceback
|
||||
error_detail = f"更新任务输入参数失败: {str(e)}\n{traceback.format_exc()}"
|
||||
raise HTTPException(status_code=500, detail=error_detail)
|
||||
|
@ -16,172 +16,3 @@ router = APIRouter(prefix="/workflow", tags=["工作流管理"])
|
||||
|
||||
# 创建服务实例
|
||||
workflow_service = WorkflowService()
|
||||
|
||||
@router.get("/workflows", response_model=ApiResponse)
|
||||
async def get_workflows(
|
||||
type: Optional[str] = Query(None, description="工作流类型")
|
||||
):
|
||||
"""获取工作流列表"""
|
||||
try:
|
||||
# 获取工作流列表
|
||||
workflows = workflow_service.get_all_workflows(type)
|
||||
|
||||
# 转换为字典列表
|
||||
workflow_dicts = [wf.to_dict() for wf in workflows]
|
||||
|
||||
return {
|
||||
"code": ApiResponseCode.SUCCESS,
|
||||
"message": "获取工作流列表成功",
|
||||
"data": workflow_dicts
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=ApiResponseCode.SERVER_ERROR, detail=f"获取工作流列表失败: {str(e)}")
|
||||
|
||||
@router.get("/workflows/{workflow_id}", response_model=ApiResponse)
|
||||
async def get_workflow(workflow_id: str):
|
||||
"""获取工作流详情"""
|
||||
try:
|
||||
# 获取工作流
|
||||
workflow = workflow_service.get_workflow_by_id(workflow_id)
|
||||
|
||||
if not workflow:
|
||||
raise HTTPException(status_code=ApiResponseCode.NOT_FOUND, detail=f"找不到工作流: {workflow_id}")
|
||||
|
||||
return {
|
||||
"code": ApiResponseCode.SUCCESS,
|
||||
"message": "获取工作流详情成功",
|
||||
"data": workflow.to_dict()
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=ApiResponseCode.SERVER_ERROR, detail=f"获取工作流详情失败: {str(e)}")
|
||||
|
||||
@router.post("/workflows", response_model=ApiResponse)
|
||||
async def create_workflow(workflow_input: WorkflowInput):
|
||||
"""创建工作流"""
|
||||
try:
|
||||
# 创建工作流
|
||||
workflow = workflow_service.create_workflow(
|
||||
name=workflow_input.name,
|
||||
workflow_type=workflow_input.workflow_type,
|
||||
description=workflow_input.description,
|
||||
blocks=workflow_input.blocks,
|
||||
variables=workflow_input.variables,
|
||||
schedule=workflow_input.schedule
|
||||
)
|
||||
|
||||
return {
|
||||
"code": ApiResponseCode.SUCCESS,
|
||||
"message": ApiResponseMessage.Workflow.CREATED,
|
||||
"data": workflow.to_dict()
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=ApiResponseCode.SERVER_ERROR, detail=f"创建工作流失败: {str(e)}")
|
||||
|
||||
@router.put("/workflows/{workflow_id}", response_model=ApiResponse)
|
||||
async def update_workflow(workflow_id: str, workflow_input: WorkflowUpdateInput):
|
||||
"""更新工作流"""
|
||||
try:
|
||||
# 更新工作流
|
||||
workflow = workflow_service.update_workflow(
|
||||
workflow_id=workflow_id,
|
||||
name=workflow_input.name,
|
||||
description=workflow_input.description,
|
||||
blocks=workflow_input.blocks,
|
||||
variables=workflow_input.variables,
|
||||
schedule=workflow_input.schedule
|
||||
)
|
||||
|
||||
if not workflow:
|
||||
raise HTTPException(status_code=ApiResponseCode.NOT_FOUND, detail=f"找不到工作流: {workflow_id}")
|
||||
|
||||
return {
|
||||
"code": ApiResponseCode.SUCCESS,
|
||||
"message": ApiResponseMessage.Workflow.UPDATED,
|
||||
"data": workflow.to_dict()
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=ApiResponseCode.SERVER_ERROR, detail=f"更新工作流失败: {str(e)}")
|
||||
|
||||
@router.delete("/workflows/{workflow_id}", response_model=ApiResponse)
|
||||
async def delete_workflow(workflow_id: str):
|
||||
"""删除工作流"""
|
||||
try:
|
||||
# 删除工作流
|
||||
success = workflow_service.delete_workflow(workflow_id)
|
||||
|
||||
if not success:
|
||||
raise HTTPException(status_code=ApiResponseCode.NOT_FOUND, detail=f"找不到工作流: {workflow_id}")
|
||||
|
||||
return {
|
||||
"code": ApiResponseCode.SUCCESS,
|
||||
"message": ApiResponseMessage.Workflow.DELETED,
|
||||
"data": None
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=ApiResponseCode.SERVER_ERROR, detail=f"删除工作流失败: {str(e)}")
|
||||
|
||||
@router.post("/workflows/{workflow_id}/execute", response_model=ApiResponse)
|
||||
async def execute_workflow(workflow_id: str, execute_input: WorkflowExecuteInput):
|
||||
"""执行工作流"""
|
||||
try:
|
||||
# 获取工作流
|
||||
workflow = workflow_service.get_workflow_by_id(workflow_id)
|
||||
|
||||
if not workflow:
|
||||
raise HTTPException(status_code=ApiResponseCode.NOT_FOUND, detail=f"找不到工作流: {workflow_id}")
|
||||
|
||||
# 执行工作流
|
||||
result = workflow_service.execute_workflow(
|
||||
workflow=workflow,
|
||||
task_inputs=execute_input.task_inputs
|
||||
)
|
||||
|
||||
return {
|
||||
"code": ApiResponseCode.SUCCESS,
|
||||
"message": ApiResponseMessage.Workflow.EXECUTED,
|
||||
"data": result
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
except TianfengTaskError as e:
|
||||
raise HTTPException(status_code=ApiResponseCode.BAD_REQUEST, detail=str(e))
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=ApiResponseCode.SERVER_ERROR, detail=f"执行工作流失败: {str(e)}")
|
||||
|
||||
@router.post("/workflows/import", response_model=ApiResponse)
|
||||
async def import_workflow(import_input: WorkflowImportInput):
|
||||
"""导入工作流"""
|
||||
try:
|
||||
# 导入工作流
|
||||
workflow = workflow_service.import_workflow(import_input.workflow_json)
|
||||
|
||||
return {
|
||||
"code": ApiResponseCode.SUCCESS,
|
||||
"message": ApiResponseMessage.Workflow.IMPORTED,
|
||||
"data": workflow.to_dict()
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=ApiResponseCode.SERVER_ERROR, detail=f"导入工作流失败: {str(e)}")
|
||||
|
||||
@router.get("/workflows/{workflow_id}/export", response_model=ApiResponse)
|
||||
async def export_workflow(workflow_id: str):
|
||||
"""导出工作流"""
|
||||
try:
|
||||
# 导出工作流
|
||||
workflow_json = workflow_service.export_workflow(workflow_id)
|
||||
|
||||
return {
|
||||
"code": ApiResponseCode.SUCCESS,
|
||||
"message": ApiResponseMessage.Workflow.EXPORTED,
|
||||
"data": {"workflow_json": workflow_json}
|
||||
}
|
||||
except TianfengTaskError as e:
|
||||
raise HTTPException(status_code=ApiResponseCode.BAD_REQUEST, detail=str(e))
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=ApiResponseCode.SERVER_ERROR, detail=f"导出工作流失败: {str(e)}")
|
520
api_doc/API接口文档.md
Normal file
520
api_doc/API接口文档.md
Normal file
@ -0,0 +1,520 @@
|
||||
# 天风任务系统 API 接口文档
|
||||
|
||||
## 目录
|
||||
|
||||
- [组件管理 API](#组件管理-api)
|
||||
- [获取所有组件类型及详细信息](#获取所有组件类型及详细信息)
|
||||
- [获取指定类型的组件详细信息](#获取指定类型的组件详细信息)
|
||||
- [自动发现并注册组件](#自动发现并注册组件)
|
||||
- [任务管理 API](#任务管理-api)
|
||||
- [获取任务列表](#获取任务列表)
|
||||
- [获取任务类型列表](#获取任务类型列表)
|
||||
- [创建任务](#创建任务)
|
||||
- [删除任务](#删除任务)
|
||||
- [批量删除任务](#批量删除任务)
|
||||
- [更新任务基本信息](#更新任务基本信息)
|
||||
- [获取任务编辑信息](#获取任务编辑信息)(还没完成)
|
||||
- [获取可用的子任务列表](#获取可用的子任务列表)
|
||||
- [任务参数管理 API](#任务参数管理-api)
|
||||
- [获取任务输入参数表单字段定义](#获取任务输入参数表单字段定义)
|
||||
- [获取任务输入参数配置](#获取任务输入参数配置)
|
||||
- [更新任务输入参数配置](#更新任务输入参数配置)
|
||||
|
||||
## 组件管理 API
|
||||
|
||||
### 获取所有组件类型及详细信息
|
||||
|
||||
获取系统中所有组件类型及其详细信息。
|
||||
|
||||
**接口地址**:`/component/components`
|
||||
|
||||
**请求方式**:`GET`
|
||||
|
||||
**请求参数**:无
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取组件类型成功",
|
||||
"data": {
|
||||
"component_types": ["string"],
|
||||
"component_type_info": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "string"
|
||||
}
|
||||
],
|
||||
"component_categories": {
|
||||
"category": ["string"]
|
||||
},
|
||||
"component_details": ["object"],
|
||||
"component_details_by_type": {
|
||||
"type": ["object"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `component_types`: 所有组件类型的列表
|
||||
- `component_type_info`: 包含中文名称的组件类型信息
|
||||
- `component_categories`: 按类别分组的组件类型
|
||||
- `component_details`: 所有组件的详细配置
|
||||
- `component_details_by_type`: 按组件类型分组的详细配置
|
||||
|
||||
### 获取指定类型的组件详细信息
|
||||
|
||||
获取指定类型的组件详细信息。
|
||||
|
||||
**接口地址**:`/component/components/{component_type}`
|
||||
|
||||
**请求方式**:`GET`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必须 | 说明 |
|
||||
|-------|------|------|------|
|
||||
| component_type | string | 是 | 组件类型 |
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取组件详细信息成功",
|
||||
"data": {
|
||||
"components": ["object"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `components`: 指定类型的组件详细配置列表
|
||||
|
||||
### 自动发现并注册组件
|
||||
|
||||
自动发现并注册组件。
|
||||
|
||||
**接口地址**:`/component/components/discover`
|
||||
|
||||
**请求方式**:`POST`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
```json
|
||||
{
|
||||
"package_name": "string"
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "自动发现组件成功,共发现 x 个组件",
|
||||
"data": {
|
||||
"component_types": ["string"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `component_types`: 发现的组件类型列表
|
||||
|
||||
## 任务管理 API
|
||||
|
||||
### 获取任务列表
|
||||
|
||||
获取任务列表,支持多种筛选条件、排序和分页。
|
||||
|
||||
**接口地址**:`/tasks`
|
||||
|
||||
**请求方式**:`GET`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必须 | 说明 |
|
||||
|-------|------|------|------|
|
||||
| status | string | 否 | 任务状态 |
|
||||
| task_type | string | 否 | 任务类型 |
|
||||
| name | string | 否 | 任务名称(模糊查询)|
|
||||
| is_scheduled | boolean | 否 | 是否为定时任务 |
|
||||
| created_start | integer | 否 | 创建时间起始(毫秒时间戳)|
|
||||
| created_end | integer | 否 | 创建时间结束(毫秒时间戳)|
|
||||
| sort_by | string | 否 | 排序字段,默认为 CREATED_AT |
|
||||
| sort_order | string | 否 | 排序方式,默认为 DESC |
|
||||
| page | integer | 否 | 页码,默认为 1 |
|
||||
| page_size | integer | 否 | 每页数量,默认为 10 |
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取任务列表成功",
|
||||
"data": {
|
||||
"tasks": ["object"],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"page_size": 10,
|
||||
"total": 100,
|
||||
"total_pages": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `tasks`: 任务列表
|
||||
- `pagination`: 分页信息
|
||||
|
||||
### 获取任务类型列表
|
||||
|
||||
获取系统中所有任务类型列表。
|
||||
|
||||
**接口地址**:`/task/types`
|
||||
|
||||
**请求方式**:`GET`
|
||||
|
||||
**请求参数**:无
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取任务类型列表成功",
|
||||
"data": [
|
||||
{
|
||||
"key": "string",
|
||||
"name": "string",
|
||||
"description": "string",
|
||||
"value": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `key`: 任务类型的键
|
||||
- `name`: 任务类型的名称
|
||||
- `description`: 任务类型的描述
|
||||
- `value`: 任务类型的枚举值
|
||||
|
||||
### 创建任务
|
||||
|
||||
创建一个新任务。
|
||||
|
||||
**接口地址**:`/task/create`
|
||||
|
||||
**请求方式**:`POST`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string",
|
||||
"task_type": "string"
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "创建任务成功",
|
||||
"data": {
|
||||
"task_id": "string",
|
||||
"name": "string",
|
||||
"task_type": "string",
|
||||
"task_type_name": "string",
|
||||
"created_at": "timestamp",
|
||||
"updated_at": "timestamp"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `task_id`: 任务ID
|
||||
- `name`: 任务名称
|
||||
- `task_type`: 任务类型
|
||||
- `task_type_name`: 任务类型中文名称
|
||||
|
||||
### 删除任务
|
||||
|
||||
删除指定ID的任务。
|
||||
|
||||
**接口地址**:`/task/{task_id}`
|
||||
|
||||
**请求方式**:`DELETE`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必须 | 说明 |
|
||||
|-------|------|------|------|
|
||||
| task_id | string | 是 | 任务ID |
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "删除任务成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 批量删除任务
|
||||
|
||||
批量删除多个任务。
|
||||
|
||||
**接口地址**:`/task/batch`
|
||||
|
||||
**请求方式**:`DELETE`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
```json
|
||||
{
|
||||
"task_ids": ["string"]
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "批量删除任务成功,共删除 x 个任务",
|
||||
"data": {
|
||||
"deleted_count": 0,
|
||||
"total_count": 0,
|
||||
"not_found_ids": ["string"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `deleted_count`: 成功删除的任务数量
|
||||
- `total_count`: 总共请求删除的任务数量
|
||||
- `not_found_ids`: 未找到的任务ID列表
|
||||
|
||||
### 更新任务基本信息
|
||||
|
||||
更新任务的基本信息。
|
||||
|
||||
**接口地址**:`/task/{task_id}`
|
||||
|
||||
**请求方式**:`PUT`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必须 | 说明 |
|
||||
|-------|------|------|------|
|
||||
| task_id | string | 是 | 任务ID |
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string",
|
||||
"description": "string",
|
||||
"task_type": "string",
|
||||
"blocks": ["object"],
|
||||
"variables": ["object"],
|
||||
"schedule": "object"
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "更新任务成功",
|
||||
"data": {
|
||||
"task": "object"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 获取任务编辑信息
|
||||
|
||||
获取任务的编辑信息,包括任务实例、组件、参数等。
|
||||
|
||||
**接口地址**:`/task/{task_id}/edit`
|
||||
|
||||
**请求方式**:`GET`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必须 | 说明 |
|
||||
|-------|------|------|------|
|
||||
| task_id | string | 是 | 任务ID |
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取任务编辑信息成功",
|
||||
"data": {
|
||||
"task": "object",
|
||||
"instance": "object",
|
||||
"component_types": "object",
|
||||
"common_params": "object",
|
||||
"task_input_params": ["object"],
|
||||
"block_output_params": "object",
|
||||
"context_params": "object"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `task`: 任务基本信息
|
||||
- `instance`: 任务实例信息
|
||||
- `component_types`: 组件类型信息
|
||||
- `common_params`: 常用参数数据
|
||||
- `task_input_params`: 任务输入参数
|
||||
- `block_output_params`: 块输出参数
|
||||
- `context_params`: 上下文参数
|
||||
|
||||
### 获取可用的子任务列表
|
||||
|
||||
获取可用的子任务列表,用于任务嵌套。
|
||||
|
||||
**接口地址**:`/tasks/available-subtasks`
|
||||
|
||||
**请求方式**:`GET`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必须 | 说明 |
|
||||
|-------|------|------|------|
|
||||
| current_task_id | string | 否 | 当前任务ID,用于排除自身 |
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取可用子任务列表成功",
|
||||
"data": {
|
||||
"subtasks": [
|
||||
{
|
||||
"task_id": "string",
|
||||
"name": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 任务参数管理 API
|
||||
|
||||
### 获取任务输入参数表单字段定义
|
||||
|
||||
获取任务输入参数表单字段定义,用于前端表单生成。
|
||||
|
||||
**接口地址**:`/task/input-params/fields`
|
||||
|
||||
**请求方式**:`GET`
|
||||
|
||||
**请求参数**:无
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取任务输入参数表单字段定义成功",
|
||||
"data": {
|
||||
"form_fields": ["object"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `form_fields`: 表单字段定义列表
|
||||
|
||||
### 获取任务输入参数配置
|
||||
|
||||
获取任务输入参数配置,包括系统默认参数和用户自定义参数。
|
||||
|
||||
**接口地址**:`/task/{task_id}/input-params`
|
||||
|
||||
**请求方式**:`GET`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必须 | 说明 |
|
||||
|-------|------|------|------|
|
||||
| task_id | string | 是 | 任务ID |
|
||||
| instance_id | string | 否 | 任务实例ID,不传则使用最新实例 |
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取任务输入参数成功",
|
||||
"data": {
|
||||
"task_id": "string",
|
||||
"instance_id": "string",
|
||||
"params": ["object"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `params`: 任务输入参数列表
|
||||
|
||||
### 更新任务输入参数配置
|
||||
|
||||
更新任务输入参数配置,批量保存用户自定义的任务输入参数配置。
|
||||
|
||||
**接口地址**:`/task/{task_id}/input-params`
|
||||
|
||||
**请求方式**:`POST`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必须 | 说明 |
|
||||
|-------|------|------|------|
|
||||
| task_id | string | 是 | 任务ID |
|
||||
| instance_id | string | 否 | 任务实例ID,不传则使用最新实例或创建新实例 |
|
||||
|
||||
请求体:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"param_name": "string",
|
||||
"label": "string",
|
||||
"param_type": "string",
|
||||
"required": true,
|
||||
"default_value": "any",
|
||||
"description": "string"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "更新任务输入参数成功",
|
||||
"data": {
|
||||
"task_id": "string",
|
||||
"instance_id": "string",
|
||||
"updated_params_count": 0,
|
||||
"has_changes": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- `updated_params_count`: 更新的参数数量
|
||||
- `has_changes`: 是否有参数变动
|
119
api_doc/字段枚举值说明.md
Normal file
119
api_doc/字段枚举值说明.md
Normal file
@ -0,0 +1,119 @@
|
||||
# 天风任务系统枚举值说明文档
|
||||
|
||||
本文档详细说明了系统中使用的各种枚举值,用于开发和接口调用参考。
|
||||
|
||||
## 目录
|
||||
|
||||
- [参数类型枚举](#参数类型枚举)
|
||||
- [参数值格式枚举](#参数值格式枚举)
|
||||
- [任务类型枚举](#任务类型枚举)
|
||||
- [任务状态枚举](#任务状态枚举)
|
||||
- [任务实例状态枚举](#任务实例状态枚举)
|
||||
|
||||
## 参数类型枚举
|
||||
|
||||
组件参数定义表使用的参数类型枚举(ParameterType):
|
||||
|
||||
| 枚举值 | 说明 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| STRING | 'string' | 字符串类型参数 |
|
||||
| NUMBER | 'number' | 数字类型参数 |
|
||||
| BOOLEAN | 'boolean' | 布尔值类型参数 |
|
||||
| ARRAY | 'array' | 数组类型参数 |
|
||||
| OBJECT | 'object' | 对象类型参数 |
|
||||
| DATE | 'date' | 日期类型参数 |
|
||||
| TIME | 'time' | 时间类型参数 |
|
||||
| DATETIME | 'datetime' | 日期时间类型参数 |
|
||||
| FILE | 'file' | 文件类型参数 |
|
||||
| SELECT | 'select' | 单选选择器类型参数 |
|
||||
| MULTI_SELECT | 'multi_select' | 多选选择器类型参数 |
|
||||
| CUSTOM | 'custom' | 自定义类型参数 |
|
||||
|
||||
## 参数值格式枚举
|
||||
|
||||
组件参数值表使用的值格式枚举(ParameterValueFormat):
|
||||
|
||||
| 枚举值 | 说明 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| SIMPLE | 'simple' | 简单值格式,直接使用值 |
|
||||
| JSON | 'json' | JSON格式,值需要经过JSON解析 |
|
||||
| EXPRESSION | 'expression' | 表达式格式,值需要经过表达式引擎解析 |
|
||||
|
||||
## 任务类型枚举
|
||||
|
||||
任务表使用的任务类型枚举(TaskType):
|
||||
|
||||
| 枚举值 | 说明 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| NORMAL | 'normal' | 普通任务 |
|
||||
| SCHEDULED | 'scheduled' | 定时任务,需要按照计划自动执行 |
|
||||
|
||||
## 任务状态枚举
|
||||
|
||||
任务表使用的任务状态枚举(TaskStatus):
|
||||
|
||||
| 枚举值 | 说明 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| PENDING | 'pending' | 待执行状态,任务已创建但尚未开始执行 |
|
||||
| RUNNING | 'running' | 执行中状态,任务正在执行 |
|
||||
| COMPLETED | 'completed' | 已完成状态,任务已成功执行完成 |
|
||||
| CANCELLED | 'cancelled' | 已取消状态,任务被手动取消 |
|
||||
| FAILED | 'failed' | 执行失败状态,任务执行过程中发生错误 |
|
||||
| PAUSED | 'paused' | 暂停中状态,任务执行被暂停 |
|
||||
| WAITING | 'waiting' | 等待中状态,任务等待某些条件满足后继续执行 |
|
||||
|
||||
## 任务实例状态枚举
|
||||
|
||||
任务实例表使用的状态枚举(TaskInstanceStatus):
|
||||
|
||||
| 枚举值 | 说明 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| EDITING | 'editing' | 编辑中状态,任务实例正在被编辑 |
|
||||
| PUBLISHED | 'published' | 已发布状态,任务实例已发布,可以被执行 |
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 参数类型的使用示例
|
||||
|
||||
```python
|
||||
# 在创建组件参数定义时指定参数类型
|
||||
parameter_def = ComponentParameterDefinition.create_parameter_definition(
|
||||
component_type_id=1,
|
||||
code="input_text",
|
||||
name="输入文本",
|
||||
parameter_type=ParameterType.STRING,
|
||||
description="请输入文本内容",
|
||||
is_required=True
|
||||
)
|
||||
```
|
||||
|
||||
### 任务类型的使用示例
|
||||
|
||||
```python
|
||||
# 创建一个定时任务
|
||||
task = Task.create_task(
|
||||
name="每日数据同步",
|
||||
task_type=TaskType.SCHEDULED,
|
||||
description="每天凌晨2点执行数据同步",
|
||||
is_scheduled=True,
|
||||
schedule_expression="0 2 * * *"
|
||||
)
|
||||
```
|
||||
|
||||
### 任务状态的使用示例
|
||||
|
||||
```python
|
||||
# 检查任务是否正在执行
|
||||
if task.status == TaskStatus.RUNNING:
|
||||
print("任务正在执行中,请稍后...")
|
||||
```
|
||||
|
||||
### 任务实例状态的使用示例
|
||||
|
||||
```python
|
||||
# 获取所有编辑中的任务实例
|
||||
editing_instances = TaskInstance.query.filter(
|
||||
TaskInstance.status == TaskInstanceStatus.EDITING,
|
||||
TaskInstance.is_deleted == False
|
||||
).all()
|
||||
```
|
65
api_doc/数据模型关系图.md
Normal file
65
api_doc/数据模型关系图.md
Normal file
@ -0,0 +1,65 @@
|
||||
# 天风任务系统数据模型关系图
|
||||
|
||||
## 核心表关系
|
||||
|
||||
```
|
||||
┌───────────────────┐ ┌───────────────────┐
|
||||
│ Task │1 N │ TaskInstance │
|
||||
│ ├──────────┤ │
|
||||
│ 任务基本信息 │ │ 任务实例(编辑状态) │
|
||||
└───────────────────┘ └─────────┬─────────┘
|
||||
│
|
||||
│1
|
||||
│
|
||||
│N
|
||||
┌─────────▼─────────┐
|
||||
│ TaskInputParam │
|
||||
│ │
|
||||
│ 任务输入参数 │
|
||||
└───────────────────┘
|
||||
```
|
||||
|
||||
## 组件参数关系
|
||||
|
||||
```
|
||||
┌───────────────────┐ ┌───────────────────┐
|
||||
│ ComponentType │1 N │ ComponentParameter│
|
||||
│ ├──────────┤ Definition │
|
||||
│ 组件类型 │ │ │
|
||||
└───────────────────┘ │ 组件参数定义 │
|
||||
│ └───────────────────┘
|
||||
│1
|
||||
│
|
||||
│N
|
||||
┌────────▼──────────┐
|
||||
│ ParameterTemplate│
|
||||
│ │
|
||||
│ 参数模板 │
|
||||
└───────────────────┘
|
||||
```
|
||||
|
||||
## 详细表关系
|
||||
|
||||
天风任务系统的核心数据模型关系如下:
|
||||
|
||||
1. **任务管理**:
|
||||
- Task(任务) → TaskInstance(任务实例) → TaskInputParam(任务输入参数)
|
||||
- 一个任务可以有多个任务实例(不同编辑状态)
|
||||
- 一个任务实例有多个输入参数
|
||||
|
||||
2. **组件管理**:
|
||||
- ComponentType(组件类型) → ComponentParameterDefinition(组件参数定义)
|
||||
- ComponentType(组件类型) → ParameterTemplate(参数模板)
|
||||
|
||||
3. **任务执行**:
|
||||
- Task(任务) → TaskRecord(任务执行记录) → TaskRecordDetail(任务执行详情)
|
||||
|
||||
## 说明
|
||||
|
||||
1. **任务(Task)**是系统的核心实体,它定义了一个完整的工作流。
|
||||
|
||||
2. **任务实例(TaskInstance)**记录了任务在每次编辑过程中的状态,支持草稿和发布版本管理。
|
||||
|
||||
3. **任务输入参数(TaskInputParam)**定义了执行任务时需要的参数。
|
||||
|
||||
4. **组件(Component)**是任务的构建块,通过组件参数配置其行为。
|
192
api_doc/数据表结构文档.md
Normal file
192
api_doc/数据表结构文档.md
Normal file
@ -0,0 +1,192 @@
|
||||
# 天风任务系统数据表结构文档
|
||||
|
||||
## 目录
|
||||
|
||||
- [组件参数相关表](#组件参数相关表)
|
||||
- [组件参数定义表 (component_parameter_definitions)](#组件参数定义表-component_parameter_definitions)
|
||||
- [组件参数值表 (component_parameter_values)](#组件参数值表-component_parameter_values)
|
||||
- [参数模板表 (parameter_templates)](#参数模板表-parameter_templates)
|
||||
- [任务相关表](#任务相关表)
|
||||
- [任务表 (tasks)](#任务表-tasks)
|
||||
- [任务实例表 (task_instances)](#任务实例表-task_instances)
|
||||
- [任务输入参数表 (task_input_params)](#任务输入参数表-task_input_params)
|
||||
|
||||
## 组件参数相关表
|
||||
|
||||
### 组件参数定义表 (component_parameter_definitions)
|
||||
|
||||
该表用于定义组件类型的输入参数。
|
||||
|
||||
| 字段名 | 类型 | 是否必填 | 描述 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | Integer | 是 | 主键 |
|
||||
| component_type_id | Integer | 是 | 组件类型ID,外键关联组件类型表 |
|
||||
| code | String(100) | 是 | 参数代码 |
|
||||
| name | String(100) | 是 | 参数名称 |
|
||||
| description | String(500) | 否 | 参数描述 |
|
||||
| parameter_type | Enum(ParameterType) | 是 | 参数类型,枚举值 |
|
||||
| is_required | Boolean | 否 | 是否必填,默认False |
|
||||
| default_value | JSON | 否 | 默认值 |
|
||||
| validation_rules | JSON | 否 | 验证规则 |
|
||||
| options | JSON | 否 | 选项(用于选择器类型) |
|
||||
| ui_config | JSON | 否 | UI配置 |
|
||||
| order | Integer | 否 | 排序,默认0 |
|
||||
| created_at | DateTime | 否 | 创建时间 |
|
||||
| updated_at | DateTime | 否 | 更新时间 |
|
||||
| is_deleted | Boolean | 否 | 是否删除,默认False |
|
||||
|
||||
**参数类型枚举(ParameterType)**:
|
||||
- STRING = 'string'(字符串)
|
||||
- NUMBER = 'number'(数字)
|
||||
- BOOLEAN = 'boolean'(布尔值)
|
||||
- ARRAY = 'array'(数组)
|
||||
- OBJECT = 'object'(对象)
|
||||
- DATE = 'date'(日期)
|
||||
- TIME = 'time'(时间)
|
||||
- DATETIME = 'datetime'(日期时间)
|
||||
- FILE = 'file'(文件)
|
||||
- SELECT = 'select'(选择器)
|
||||
- MULTI_SELECT = 'multi_select'(多选选择器)
|
||||
- CUSTOM = 'custom'(自定义类型)
|
||||
|
||||
### 组件参数值表 (component_parameter_values)
|
||||
|
||||
该表用于存储组件实例的参数值。
|
||||
|
||||
| 字段名 | 类型 | 是否必填 | 描述 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | Integer | 是 | 主键 |
|
||||
| component_instance_id | Integer | 是 | 组件实例ID |
|
||||
| parameter_code | String(100) | 是 | 参数代码 |
|
||||
| value | JSON | 否 | 参数值 |
|
||||
| value_format | Enum(ParameterValueFormat) | 是 | 值格式,默认SIMPLE |
|
||||
| is_expression | Boolean | 否 | 是否为表达式,默认False |
|
||||
| expression | String(500) | 否 | 表达式内容 |
|
||||
| created_at | DateTime | 否 | 创建时间 |
|
||||
| updated_at | DateTime | 否 | 更新时间 |
|
||||
| is_deleted | Boolean | 否 | 是否删除,默认False |
|
||||
|
||||
**参数值格式枚举(ParameterValueFormat)**:
|
||||
- SIMPLE = 'simple'(简单值)
|
||||
- JSON = 'json'(JSON格式)
|
||||
- EXPRESSION = 'expression'(表达式)
|
||||
|
||||
### 参数模板表 (parameter_templates)
|
||||
|
||||
该表用于存储常用的参数配置模板。
|
||||
|
||||
| 字段名 | 类型 | 是否必填 | 描述 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | Integer | 是 | 主键 |
|
||||
| name | String(100) | 是 | 模板名称 |
|
||||
| component_type_id | Integer | 是 | 组件类型ID,外键关联组件类型表 |
|
||||
| description | String(500) | 否 | 模板描述 |
|
||||
| parameter_values | JSON | 是 | 参数值配置 |
|
||||
| is_system | Boolean | 否 | 是否为系统模板,默认False |
|
||||
| created_by | String(100) | 否 | 创建用户ID |
|
||||
| created_at | DateTime | 否 | 创建时间 |
|
||||
| updated_at | DateTime | 否 | 更新时间 |
|
||||
| is_deleted | Boolean | 否 | 是否删除,默认False |
|
||||
|
||||
## 任务相关表
|
||||
|
||||
### 任务表 (tasks)
|
||||
|
||||
该表表示一个任务的基本信息。
|
||||
|
||||
| 字段名 | 类型 | 是否必填 | 描述 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | Integer | 是 | 主键,自增 |
|
||||
| task_id | String(36) | 是 | 任务UUID,用于外部引用,唯一索引 |
|
||||
| name | String(100) | 是 | 任务名称 |
|
||||
| task_type | String(100) | 是 | 任务类型 |
|
||||
| description | String(500) | 否 | 任务描述 |
|
||||
| is_template | Boolean | 否 | 是否为模板,默认False |
|
||||
| template_description | String(500) | 否 | 模板描述 |
|
||||
| current_version_id | Integer | 否 | 当前版本ID |
|
||||
| is_enabled | Boolean | 否 | 是否启用,默认True |
|
||||
| created_by | String(100) | 否 | 创建用户ID |
|
||||
| updated_by | String(100) | 否 | 最后更新用户ID |
|
||||
| is_scheduled | Boolean | 否 | 是否为定时任务,默认False |
|
||||
| schedule_expression | String(100) | 否 | 定时表达式(Cron格式) |
|
||||
| next_run_time | DateTime | 否 | 下次执行时间 |
|
||||
| created_at | DateTime | 否 | 创建时间 |
|
||||
| updated_at | DateTime | 否 | 更新时间 |
|
||||
| is_deleted | Boolean | 否 | 是否删除,默认False |
|
||||
|
||||
**任务类型枚举(TaskType)**:
|
||||
- NORMAL(普通任务)
|
||||
- SCHEDULED(定时任务)
|
||||
|
||||
**任务状态枚举(TaskStatus)**:
|
||||
- PENDING(待执行)
|
||||
- RUNNING(执行中)
|
||||
- COMPLETED(已完成)
|
||||
- CANCELLED(已取消)
|
||||
- FAILED(执行失败)
|
||||
- PAUSED(暂停中)
|
||||
- WAITING(等待中)
|
||||
|
||||
### 任务实例表 (task_instances)
|
||||
|
||||
该表用于存储任务管理的数据,记录每次编辑任务的实例。
|
||||
|
||||
| 字段名 | 类型 | 是否必填 | 描述 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | Integer | 是 | 主键,自增 |
|
||||
| instance_id | String(36) | 是 | 实例唯一ID,用于外部引用,唯一索引 |
|
||||
| task_id | String(50) | 是 | 关联的任务ID,外键关联tasks表 |
|
||||
| name | String(100) | 是 | 任务名称(复制自任务表) |
|
||||
| variables | JSON | 否 | 任务变量 |
|
||||
| priority | Integer | 否 | 任务优先级,默认1 |
|
||||
| block_outputs | JSON | 否 | 块输出参数 |
|
||||
| context_params | JSON | 否 | 上下文参数 |
|
||||
| status | Enum(TaskInstanceStatus) | 否 | 任务实例状态,默认EDITING |
|
||||
| created_at | DateTime | 否 | 创建时间 |
|
||||
| updated_at | DateTime | 否 | 更新时间 |
|
||||
| is_deleted | Boolean | 否 | 是否删除,默认False |
|
||||
|
||||
**任务实例状态枚举(TaskInstanceStatus)**:
|
||||
- EDITING(编辑中)
|
||||
- PUBLISHED(已发布)
|
||||
|
||||
### 任务输入参数表 (task_input_params)
|
||||
|
||||
该表用于存储任务输入参数的数据。
|
||||
|
||||
| 字段名 | 类型 | 是否必填 | 描述 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | Integer | 是 | 主键ID,自增 |
|
||||
| param_id | String(36) | 是 | 参数唯一ID,用于外部引用,唯一索引 |
|
||||
| instance_id | String(36) | 是 | 关联的任务实例ID,索引 |
|
||||
| task_id | String(50) | 是 | 任务ID,冗余存储便于查询,索引 |
|
||||
| param_name | String(50) | 否 | 参数名称,变量名 |
|
||||
| label | String(100) | 否 | 参数标签,显示名称 |
|
||||
| param_type | String(20) | 是 | 参数类型 |
|
||||
| required | Boolean | 否 | 是否必填,默认False |
|
||||
| default_value | Text | 否 | 默认值(JSON序列化的字符串) |
|
||||
| description | Text | 否 | 参数说明 |
|
||||
| is_system | Boolean | 否 | 是否系统参数,默认False |
|
||||
| is_readonly | Boolean | 否 | 是否只读参数,默认False |
|
||||
| sort_order | Integer | 否 | 排序顺序,默认0 |
|
||||
| created_at | DateTime | 否 | 创建时间 |
|
||||
| updated_at | DateTime | 否 | 更新时间 |
|
||||
| is_deleted | Boolean | 否 | 是否删除,默认False |
|
||||
|
||||
## 表关系说明
|
||||
|
||||
1. **组件参数关系**:
|
||||
- `ComponentParameterDefinition` 定义了组件类型的参数
|
||||
- `ComponentParameterValue` 存储了组件实例的具体参数值
|
||||
- `ParameterTemplate` 提供了组件参数的模板配置
|
||||
|
||||
2. **任务关系**:
|
||||
- `Task` 是任务的主表,包含基本信息
|
||||
- `TaskInstance` 是任务的实例表,记录每次编辑的状态
|
||||
- `TaskInputParam` 存储任务的输入参数
|
||||
|
||||
3. **关联关系**:
|
||||
- 任务(Task) 1:N 任务实例(TaskInstance)
|
||||
- 任务实例(TaskInstance) 1:N 任务输入参数(TaskInputParam)
|
||||
- 组件类型 1:N 组件参数定义(ComponentParameterDefinition)
|
||||
- 组件类型 1:N 参数模板(ParameterTemplate)
|
56
app.py
56
app.py
@ -4,6 +4,7 @@ from fastapi.responses import JSONResponse
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
import logging
|
||||
import time
|
||||
import traceback
|
||||
from utils.logger import setup_logger
|
||||
from config.component_config import register_all_components
|
||||
from config.settings import (
|
||||
@ -12,10 +13,11 @@ from config.settings import (
|
||||
from api.task_api import router as task_router
|
||||
from api.workflow_api import router as workflow_router
|
||||
from api.component_api import router as component_router
|
||||
from api.common_params_api import router as common_params_router
|
||||
from api.task_param_api import router as task_params_router
|
||||
from core.exceptions import TianfengTaskError
|
||||
from config.api_config import ApiResponseCode, ApiResponseMessage
|
||||
from config.component_config import ComponentCategoryConfig
|
||||
from api.task_instance_api import router as task_instance_router
|
||||
# 导入数据库相关模块
|
||||
from config.database import DBConfig, CacheConfig, db_session
|
||||
import data.models # 导入所有模型以确保它们被注册
|
||||
@ -64,33 +66,53 @@ def init_database():
|
||||
"""初始化数据库,创建所有表"""
|
||||
try:
|
||||
logger.info("开始初始化数据库...")
|
||||
|
||||
# 初始化数据库表
|
||||
DBConfig.init_db()
|
||||
logger.info("数据库表创建成功")
|
||||
logger.info("开始创建数据库表...")
|
||||
try:
|
||||
DBConfig.init_db()
|
||||
logger.info("数据库表创建成功")
|
||||
except Exception as table_err:
|
||||
logger.error(f"数据库表创建失败: {str(table_err)}")
|
||||
# 打印详细错误信息和堆栈跟踪
|
||||
logger.error(traceback.format_exc())
|
||||
raise
|
||||
|
||||
# 初始化基础数据
|
||||
logger.info("开始初始化基础数据...")
|
||||
init_base_data(db_session)
|
||||
logger.info("基础数据初始化成功")
|
||||
try:
|
||||
init_base_data(db_session)
|
||||
logger.info("基础数据初始化成功")
|
||||
except Exception as data_err:
|
||||
logger.error(f"基础数据初始化失败: {str(data_err)}")
|
||||
# 打印详细错误信息和堆栈跟踪
|
||||
logger.error(traceback.format_exc())
|
||||
raise
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"数据库初始化失败: {str(e)}")
|
||||
raise
|
||||
logger.error(traceback.format_exc())
|
||||
# 继续执行程序,但记录错误
|
||||
return False
|
||||
|
||||
def init_base_data(db_session):
|
||||
"""初始化基础数据"""
|
||||
try:
|
||||
# 导入需要的模型
|
||||
# 导入需要的模型
|
||||
logger.info("检查基础数据...")
|
||||
|
||||
# 检查是否已存在组件分类
|
||||
existing_categories = db_session.query(ComponentCategory).filter(ComponentCategory.is_deleted == False).all()
|
||||
if existing_categories:
|
||||
logger.info("基础数据已存在,跳过初始化")
|
||||
logger.info(f"已存在 {len(existing_categories)} 个组件分类,跳过初始化")
|
||||
return
|
||||
|
||||
logger.info("开始创建组件分类...")
|
||||
# 创建组件分类
|
||||
categories = []
|
||||
for category_enum in ComponentCategoryEnum:
|
||||
logger.info(f"创建组件分类: {category_enum.value}")
|
||||
category = ComponentCategory(
|
||||
name=ComponentCategoryConfig.get_category_name(category_enum),
|
||||
code=category_enum,
|
||||
@ -101,27 +123,37 @@ def init_base_data(db_session):
|
||||
categories.append(category)
|
||||
db_session.add(category)
|
||||
|
||||
logger.info("提交组件分类到数据库...")
|
||||
db_session.commit()
|
||||
logger.info(f"创建了 {len(categories)} 个组件分类")
|
||||
|
||||
# 这里可以添加更多基础数据的初始化,如组件类型、系统组件等
|
||||
|
||||
except Exception as e:
|
||||
db_session.rollback()
|
||||
logger.error(f"基础数据初始化失败: {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
db_session.rollback()
|
||||
raise
|
||||
|
||||
# 初始化数据库
|
||||
init_database()
|
||||
init_result = init_database()
|
||||
if not init_result:
|
||||
logger.warning("数据库初始化失败,但程序将继续执行。请检查日志获取详细错误信息。")
|
||||
|
||||
# 注册所有组件
|
||||
register_all_components()
|
||||
try:
|
||||
register_all_components()
|
||||
except Exception as e:
|
||||
logger.error(f"组件注册失败: {str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
# 注册API路由
|
||||
app.include_router(task_router, prefix=ApiConfig.PREFIX)
|
||||
app.include_router(workflow_router, prefix=ApiConfig.PREFIX)
|
||||
app.include_router(component_router, prefix=ApiConfig.PREFIX)
|
||||
app.include_router(common_params_router, prefix=ApiConfig.PREFIX)
|
||||
app.include_router(task_instance_router, prefix=ApiConfig.PREFIX)
|
||||
app.include_router(task_params_router, prefix=ApiConfig.PREFIX)
|
||||
|
||||
|
||||
# 请求中间件
|
||||
@app.middleware("http")
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -329,37 +329,36 @@ class ScriptComponentConfig:
|
||||
"name": "function_name",
|
||||
"label": "函数名",
|
||||
"type": "string",
|
||||
"required": False,
|
||||
"required": True,
|
||||
"description": "定义脚本中的主函数名称",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": True
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": False
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "params",
|
||||
"label": "函数参数",
|
||||
"type": "array",
|
||||
"required": False,
|
||||
"description": "传递给脚本的参数",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": True
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": False
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -376,37 +375,37 @@ class ScriptComponentConfig:
|
||||
"name": "function_name",
|
||||
"label": "函数名",
|
||||
"type": "string",
|
||||
"required": False,
|
||||
"required": True,
|
||||
"description": "定义脚本中的主函数名称",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": True
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": False
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "params",
|
||||
"label": "函数参数",
|
||||
"type": "array",
|
||||
"type": "string",
|
||||
"required": False,
|
||||
"description": "传递给脚本的参数",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": True
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": False
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -418,7 +417,8 @@ class HttpComponentConfig:
|
||||
"""HTTP请求组件配置"""
|
||||
|
||||
# HTTP请求组件类型
|
||||
HTTP_REQUEST = "http_request" # HTTP请求
|
||||
HTTP_GET = "http_get" # HTTP GET请求
|
||||
HTTP_POST = "http_post" # HTTP POST请求
|
||||
|
||||
# HTTP请求组件详细配置
|
||||
@classmethod
|
||||
@ -427,46 +427,254 @@ class HttpComponentConfig:
|
||||
return [
|
||||
{
|
||||
"type": "http",
|
||||
"sub_type": cls.HTTP_REQUEST,
|
||||
"name": "HTTP请求",
|
||||
"description": "发送HTTP请求并处理响应",
|
||||
"sub_type": cls.HTTP_GET,
|
||||
"name": "GET请求",
|
||||
"description": "发送HTTP GET请求并处理响应",
|
||||
"icon": "http",
|
||||
"params": [
|
||||
{
|
||||
"name": "method",
|
||||
"label": "请求方法",
|
||||
"type": "select",
|
||||
"options": ["GET", "POST", "PUT", "DELETE", "PATCH"],
|
||||
"required": True,
|
||||
"description": "HTTP请求方法"
|
||||
},
|
||||
{
|
||||
"name": "url",
|
||||
"label": "请求URL",
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "请求的目标URL"
|
||||
"description": "请求的目标URL",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "headers",
|
||||
"name": "header",
|
||||
"label": "请求头",
|
||||
"type": "object",
|
||||
"required": False,
|
||||
"description": "HTTP请求头"
|
||||
"description": "HTTP请求头",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "key_value_array",
|
||||
"label": "键值对数组",
|
||||
"default": [],
|
||||
"key_types": [
|
||||
{
|
||||
"type": "string",
|
||||
"label": "字符串"
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式"
|
||||
}
|
||||
],
|
||||
"value_types": [
|
||||
{
|
||||
"type": "string",
|
||||
"label": "字符串"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"label": "数字"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "布尔"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"label": "对象"
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"label": "请求体",
|
||||
"name": "retry",
|
||||
"label": "是否重试",
|
||||
"type": "boolean",
|
||||
"required": False,
|
||||
"description": "请求失败时是否重试",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": False
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": "false"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "retry_interval",
|
||||
"label": "重试时间间隔",
|
||||
"type": "integer",
|
||||
"required": False,
|
||||
"description": "重试间隔时间(毫秒)",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": 0
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "http",
|
||||
"sub_type": cls.HTTP_POST,
|
||||
"name": "POST请求",
|
||||
"description": "发送HTTP POST请求并处理响应",
|
||||
"icon": "http",
|
||||
"params": [
|
||||
{
|
||||
"name": "url",
|
||||
"label": "请求URL",
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "请求的目标URL",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "header",
|
||||
"label": "请求头",
|
||||
"type": "object",
|
||||
"required": False,
|
||||
"description": "HTTP请求体"
|
||||
"description": "HTTP请求头",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "key_value_array",
|
||||
"label": "键值对数组",
|
||||
"default": [],
|
||||
"key_types": [
|
||||
{
|
||||
"type": "string",
|
||||
"label": "字符串"
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式"
|
||||
}
|
||||
],
|
||||
"value_types": [
|
||||
{
|
||||
"type": "string",
|
||||
"label": "字符串"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"label": "数字"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"label": "布尔"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"label": "对象"
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "timeout",
|
||||
"label": "超时时间",
|
||||
"type": "number",
|
||||
"name": "json",
|
||||
"label": "请求参数",
|
||||
"type": "json",
|
||||
"required": False,
|
||||
"description": "请求超时时间(毫秒)"
|
||||
"description": "POST请求的JSON参数",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": {}
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "retry",
|
||||
"label": "是否重试",
|
||||
"type": "boolean",
|
||||
"required": False,
|
||||
"description": "请求失败时是否重试",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": False
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": "false"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "retry_interval",
|
||||
"label": "重试时间间隔",
|
||||
"type": "integer",
|
||||
"required": False,
|
||||
"description": "重试间隔时间(毫秒)",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": 0
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -568,7 +776,6 @@ class FlowComponentConfig:
|
||||
|
||||
class SubtaskComponentConfig:
|
||||
"""子任务组件配置"""
|
||||
|
||||
# 子任务组件类型
|
||||
SUBTASK = "subtask" # 子任务
|
||||
|
||||
@ -576,42 +783,130 @@ class SubtaskComponentConfig:
|
||||
@classmethod
|
||||
def get_components(cls) -> List[Dict[str, Any]]:
|
||||
"""获取子任务组件列表"""
|
||||
return [
|
||||
{
|
||||
# 直接返回基础模板
|
||||
return [cls.get_subtask_component_template()]
|
||||
|
||||
@classmethod
|
||||
def get_subtask_component_template(cls) -> Dict[str, Any]:
|
||||
"""获取子任务组件模板"""
|
||||
return {
|
||||
"type": "subtask",
|
||||
"sub_type": cls.SUBTASK,
|
||||
"name": "子任务",
|
||||
"description": "执行已定义的任务作为子任务",
|
||||
"icon": "subtask",
|
||||
"params": [
|
||||
{
|
||||
"name": "wait_complete",
|
||||
"label": "是否异步执行任务",
|
||||
"type": "boolean",
|
||||
"required": False,
|
||||
"default": False,
|
||||
"description": "是否等待子任务完成后再继续执行"
|
||||
},
|
||||
{
|
||||
"name": "instance_id",
|
||||
"label": "任务实例ID",
|
||||
"type": "string",
|
||||
"required": False,
|
||||
"description": "指定任务实例ID(留空则自动创建新实例)"
|
||||
},
|
||||
{
|
||||
"name": "params",
|
||||
"label": "任务参数",
|
||||
"type": "subtask_params",
|
||||
"required": False,
|
||||
"description": "子任务输入参数配置",
|
||||
"subtask_params": [
|
||||
{
|
||||
"key": "task_id",
|
||||
"name": "任务ID",
|
||||
"type": "string",
|
||||
"is_system": True,
|
||||
"is_readonly": True,
|
||||
"description": "任务的唯一标识符"
|
||||
},
|
||||
{
|
||||
"key": "instance_id",
|
||||
"name": "任务实例ID",
|
||||
"type": "string",
|
||||
"is_system": True,
|
||||
"is_readonly": True,
|
||||
"description": "任务实例的唯一标识符"
|
||||
},
|
||||
{
|
||||
"key": "task_name",
|
||||
"name": "任务名称",
|
||||
"type": "string",
|
||||
"is_system": True,
|
||||
"is_readonly": True,
|
||||
"description": "任务的名称"
|
||||
},
|
||||
{
|
||||
"key": "created_at",
|
||||
"name": "创建时间",
|
||||
"type": "datetime",
|
||||
"is_system": True,
|
||||
"is_readonly": True,
|
||||
"description": "任务实例的创建时间"
|
||||
},
|
||||
{
|
||||
"key": "variables",
|
||||
"name": "任务变量",
|
||||
"type": "json",
|
||||
"is_system": True,
|
||||
"is_readonly": False,
|
||||
"description": "任务的变量集合"
|
||||
},
|
||||
{
|
||||
"key": "priority",
|
||||
"name": "任务优先级",
|
||||
"type": "integer",
|
||||
"is_system": True,
|
||||
"is_readonly": False,
|
||||
"description": "任务的优先级,数值越大优先级越高"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def generate_subtask_components(cls, available_subtasks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
根据可用子任务列表生成子任务组件
|
||||
|
||||
Args:
|
||||
available_subtasks: 可用子任务列表 [{"task_id": "xxx", "name": "xxx"}, ...]
|
||||
|
||||
Returns:
|
||||
生成的子任务组件列表
|
||||
"""
|
||||
components = []
|
||||
subtask_template = cls.get_subtask_component_template()
|
||||
|
||||
for subtask in available_subtasks:
|
||||
# 创建新的子任务组件
|
||||
new_subtask_component = {
|
||||
"type": "subtask",
|
||||
"sub_type": cls.SUBTASK,
|
||||
"name": "子任务",
|
||||
"description": "执行已定义的任务作为子任务",
|
||||
"sub_type": "subtask",
|
||||
"name": subtask["name"], # 使用子任务名称
|
||||
"description": f"执行子任务: {subtask['name']}",
|
||||
"icon": "subtask",
|
||||
"params": [
|
||||
{
|
||||
"name": "task_id",
|
||||
"label": "选择子任务",
|
||||
"type": "select",
|
||||
"required": True,
|
||||
"description": "选择要执行的子任务(从已创建的任务中选择)",
|
||||
"data_source": "available_subtasks", # 指示前端从API返回的available_subtasks字段获取数据
|
||||
"display_field": "name", # 显示任务名称
|
||||
"value_field": "task_id" # 使用任务ID作为值
|
||||
},
|
||||
{
|
||||
"name": "params",
|
||||
"label": "任务参数",
|
||||
"type": "object",
|
||||
"required": False,
|
||||
"description": "传递给子任务的参数"
|
||||
},
|
||||
{
|
||||
"name": "wait_complete",
|
||||
"label": "等待完成",
|
||||
"type": "boolean",
|
||||
"required": False,
|
||||
"default": True,
|
||||
"description": "是否等待子任务完成后再继续执行"
|
||||
}
|
||||
]
|
||||
"task_id": subtask["task_id"], # 添加任务ID
|
||||
"params": subtask_template["params"].copy() # 复制参数定义
|
||||
}
|
||||
]
|
||||
|
||||
# 为params中的subtask_params字段添加task_id
|
||||
for param in new_subtask_component["params"]:
|
||||
if param["name"] == "params" and "subtask_params" in param:
|
||||
for subtask_param in param["subtask_params"]:
|
||||
if subtask_param["key"] == "task_id":
|
||||
subtask_param["value"] = subtask["task_id"]
|
||||
|
||||
components.append(new_subtask_component)
|
||||
|
||||
return components
|
||||
|
||||
class ComponentDetailConfig:
|
||||
"""组件详细配置管理"""
|
||||
@ -759,6 +1054,9 @@ class ComponentDetailConfig:
|
||||
# 添加HTTP请求组件
|
||||
all_components.extend(HttpComponentConfig.get_components())
|
||||
|
||||
# 添加任务组件
|
||||
all_components.extend(TaskComponentConfig.get_components())
|
||||
|
||||
# 添加流程控制组件
|
||||
all_components.extend(FlowComponentConfig.get_components())
|
||||
|
||||
@ -903,4 +1201,271 @@ class CommonParamsConfig:
|
||||
for pt in param_types:
|
||||
if pt["type"] == param_type:
|
||||
return pt
|
||||
return None
|
||||
return None
|
||||
|
||||
class TaskComponentConfig:
|
||||
"""任务组件配置"""
|
||||
|
||||
# 任务组件类型
|
||||
CACHE_DATA = "cache_data" # 缓存数据
|
||||
CLEAR_CACHE_DATA = "clear_cache_data" # 清除缓存数据
|
||||
GET_CACHE_DATA = "get_cache_data" # 获取缓存数据
|
||||
GET_TASK_INPUT_PARAM = "get_task_input_param" # 获取任务的输入参数
|
||||
SET_TASK_STATUS = "set_task_status" # 设置任务状态
|
||||
JUMP_TO_BLOCK = "jump_to_block" # 跳到某个块
|
||||
SET_TASK_VARIABLES = "set_task_variables" # 设置任务变量
|
||||
|
||||
# 任务组件详细配置
|
||||
@classmethod
|
||||
def get_components(cls) -> List[Dict[str, Any]]:
|
||||
"""获取任务组件列表"""
|
||||
return [
|
||||
{
|
||||
"type": "task",
|
||||
"sub_type": cls.CACHE_DATA,
|
||||
"name": "缓存数据",
|
||||
"description": "将数据临时存储在任务上下文中",
|
||||
"icon": "cache",
|
||||
"params": [
|
||||
{
|
||||
"name": "cache_key",
|
||||
"label": "缓存key",
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "缓存数据的唯一标识符",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cache_value",
|
||||
"label": "缓存value",
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "要缓存的数据值",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "task",
|
||||
"sub_type": cls.CLEAR_CACHE_DATA,
|
||||
"name": "清除缓存数据",
|
||||
"description": "清除已缓存的临时数据",
|
||||
"icon": "clear-cache",
|
||||
"params": [
|
||||
{
|
||||
"name": "key",
|
||||
"label": "key",
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "要清除的缓存数据的标识符",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "task",
|
||||
"sub_type": cls.GET_CACHE_DATA,
|
||||
"name": "获取缓存数据",
|
||||
"description": "读取已缓存的临时数据",
|
||||
"icon": "get-cache",
|
||||
"params": [
|
||||
{
|
||||
"name": "cache_key",
|
||||
"label": "缓存key",
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "要获取的缓存数据的标识符",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "task",
|
||||
"sub_type": cls.GET_TASK_INPUT_PARAM,
|
||||
"name": "获取任务的输入参数",
|
||||
"description": "读取传递给任务的输入参数",
|
||||
"icon": "input-param",
|
||||
"params": [
|
||||
{
|
||||
"name": "task_instance_id",
|
||||
"label": "任务实例 Id",
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "要获取输入参数的任务实例ID",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "input_param_name",
|
||||
"label": "输入参数名",
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "要获取的输入参数的名称",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "task",
|
||||
"sub_type": cls.SET_TASK_STATUS,
|
||||
"name": "设置任务状态",
|
||||
"description": "修改任务的当前状态",
|
||||
"icon": "task-status",
|
||||
"params": [
|
||||
{
|
||||
"name": "status_description",
|
||||
"label": "状态描述",
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "要设置的任务状态描述",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "task",
|
||||
"sub_type": cls.JUMP_TO_BLOCK,
|
||||
"name": "跳到某个块",
|
||||
"description": "在任务流程中跳转到指定的节点",
|
||||
"icon": "jump",
|
||||
"params": [
|
||||
{
|
||||
"name": "block_id",
|
||||
"label": "跳到块的标识",
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "要跳转到的目标块的标识符",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "task",
|
||||
"sub_type": cls.SET_TASK_VARIABLES,
|
||||
"name": "设置任务变量",
|
||||
"description": "定义或修改任务的变量",
|
||||
"icon": "variable",
|
||||
"params": [
|
||||
{
|
||||
"name": "variable_name",
|
||||
"label": "变量名",
|
||||
"type": "string",
|
||||
"required": True,
|
||||
"description": "要设置的变量名称",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "variable_value",
|
||||
"label": "变量值",
|
||||
"type": "json",
|
||||
"required": True,
|
||||
"description": "要设置的变量值",
|
||||
"value_types": [
|
||||
{
|
||||
"type": "simple",
|
||||
"label": "简单值",
|
||||
"default": {}
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"label": "表达式",
|
||||
"default": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -11,6 +11,8 @@ import json
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
import traceback
|
||||
import sys
|
||||
|
||||
class ConfigDict:
|
||||
"""配置字典类,支持通过点号访问配置项"""
|
||||
@ -136,6 +138,18 @@ class DBConfig:
|
||||
初始化数据库
|
||||
创建所有表
|
||||
"""
|
||||
# 测试数据库连接
|
||||
try:
|
||||
print(f"尝试连接数据库: {cls.url}")
|
||||
connection = cls.engine.connect()
|
||||
print("数据库连接成功!")
|
||||
connection.close()
|
||||
except Exception as e:
|
||||
print(f"数据库连接失败: {str(e)}")
|
||||
print("详细错误信息:")
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
raise
|
||||
|
||||
# 导入所有模型,确保它们已注册到Base
|
||||
import data.models
|
||||
|
||||
@ -144,20 +158,37 @@ class DBConfig:
|
||||
from sqlalchemy import text
|
||||
# 创建一个不指定数据库的连接
|
||||
db_conf = cls.get_config()
|
||||
temp_url = (
|
||||
f"{db_conf.dialect}+{db_conf.driver}://"
|
||||
f"{db_conf.username}:{db_conf.password}@"
|
||||
f"{db_conf.host}:{db_conf.port}/"
|
||||
f"?charset={db_conf.charset}"
|
||||
)
|
||||
temp_engine = create_engine(temp_url)
|
||||
with temp_engine.connect() as conn:
|
||||
conn.execute(text(f"CREATE DATABASE IF NOT EXISTS {db_conf.database} CHARACTER SET {db_conf.charset} COLLATE {db_conf.charset}_unicode_ci;"))
|
||||
conn.commit()
|
||||
temp_engine.dispose()
|
||||
try:
|
||||
print(f"尝试创建数据库 {db_conf.database} (如果不存在)")
|
||||
temp_url = (
|
||||
f"{db_conf.dialect}+{db_conf.driver}://"
|
||||
f"{db_conf.username}:{db_conf.password}@"
|
||||
f"{db_conf.host}:{db_conf.port}/"
|
||||
f"?charset={db_conf.charset}"
|
||||
)
|
||||
print(f"临时连接URL: {temp_url}")
|
||||
temp_engine = create_engine(temp_url)
|
||||
with temp_engine.connect() as conn:
|
||||
conn.execute(text(f"CREATE DATABASE IF NOT EXISTS {db_conf.database} CHARACTER SET {db_conf.charset} COLLATE {db_conf.charset}_unicode_ci;"))
|
||||
conn.commit()
|
||||
temp_engine.dispose()
|
||||
print(f"数据库 {db_conf.database} 创建或已存在")
|
||||
except Exception as e:
|
||||
print(f"创建数据库失败: {str(e)}")
|
||||
print("详细错误信息:")
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
raise
|
||||
|
||||
# 创建所有表
|
||||
cls.base.metadata.create_all(bind=cls.engine)
|
||||
try:
|
||||
print("开始创建所有表...")
|
||||
cls.base.metadata.create_all(bind=cls.engine)
|
||||
print("所有表创建成功")
|
||||
except Exception as e:
|
||||
print(f"创建表失败: {str(e)}")
|
||||
print("详细错误信息:")
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
raise
|
||||
|
||||
@classmethod
|
||||
def shutdown_session(cls, exception=None):
|
||||
|
@ -192,6 +192,18 @@ class TaskInputParamType(str, Enum):
|
||||
ARRAY = "array"
|
||||
OBJECT = "object"
|
||||
|
||||
# 任务输入参数类型UI显示名称
|
||||
PARAM_TYPE_DISPLAY_NAMES = {
|
||||
TaskInputParamType.STRING.value: "字符串",
|
||||
TaskInputParamType.INTEGER.value: "整数",
|
||||
TaskInputParamType.FLOAT.value: "浮点数",
|
||||
TaskInputParamType.BOOLEAN.value: "布尔",
|
||||
TaskInputParamType.DATETIME.value: "日期时间",
|
||||
TaskInputParamType.JSON.value: "JSON对象",
|
||||
TaskInputParamType.ARRAY.value: "JSON数组",
|
||||
TaskInputParamType.OBJECT.value: "对象"
|
||||
}
|
||||
|
||||
class SystemParamKey(str, Enum):
|
||||
"""系统参数键名枚举"""
|
||||
TASK_ID = "task_id"
|
||||
@ -269,6 +281,31 @@ class TaskInputParamConfig:
|
||||
return param
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def build_system_params(cls, task_id: str) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
构建系统参数列表(不带值)
|
||||
|
||||
Args:
|
||||
task_id: 任务ID
|
||||
|
||||
Returns:
|
||||
系统参数列表(不带值)
|
||||
"""
|
||||
params = []
|
||||
|
||||
# 复制系统参数配置但不添加具体值
|
||||
for param_config in cls.SYSTEM_PARAMS:
|
||||
param = param_config.copy()
|
||||
|
||||
# 只为任务ID设置值,其他参数保持不变
|
||||
if param["key"] == SystemParamKey.TASK_ID:
|
||||
param["value"] = task_id
|
||||
|
||||
params.append(param)
|
||||
|
||||
return params
|
||||
|
||||
@classmethod
|
||||
def build_system_params_with_values(cls, task_id: str, instance: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
@ -304,6 +341,71 @@ class TaskInputParamConfig:
|
||||
params.append(param)
|
||||
|
||||
return params
|
||||
|
||||
@classmethod
|
||||
def get_input_params_form_fields(cls) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取任务输入参数表单字段定义
|
||||
|
||||
Returns:
|
||||
表单字段定义列表
|
||||
"""
|
||||
# 构建参数类型选项
|
||||
param_type_options = []
|
||||
for param_type in TaskInputParamType:
|
||||
param_type_options.append({
|
||||
"value": param_type.value,
|
||||
"label": PARAM_TYPE_DISPLAY_NAMES.get(param_type.value, param_type.value)
|
||||
})
|
||||
|
||||
# 返回表单字段定义
|
||||
return [
|
||||
{
|
||||
"field_name": "param_name",
|
||||
"label": "变量名",
|
||||
"field_type": "input",
|
||||
"required": True,
|
||||
"description": "参数的唯一标识符,用于在任务执行过程中引用该参数"
|
||||
},
|
||||
{
|
||||
"field_name": "label",
|
||||
"label": "标签",
|
||||
"field_type": "input",
|
||||
"required": True,
|
||||
"description": "参数的显示名称,用于在界面上展示"
|
||||
},
|
||||
{
|
||||
"field_name": "param_type",
|
||||
"label": "类型",
|
||||
"field_type": "select",
|
||||
"required": True,
|
||||
"default": TaskInputParamType.STRING.value,
|
||||
"options": param_type_options,
|
||||
"description": "参数的数据类型"
|
||||
},
|
||||
{
|
||||
"field_name": "required",
|
||||
"label": "是否必填",
|
||||
"field_type": "checkbox",
|
||||
"required": False,
|
||||
"default": False,
|
||||
"description": "标记参数是否为必填项"
|
||||
},
|
||||
{
|
||||
"field_name": "default_value",
|
||||
"label": "默认值",
|
||||
"field_type": "input",
|
||||
"required": False,
|
||||
"description": "参数的默认值,当用户未提供值时使用"
|
||||
},
|
||||
{
|
||||
"field_name": "description",
|
||||
"label": "说明",
|
||||
"field_type": "textarea",
|
||||
"required": False,
|
||||
"description": "参数的详细说明,用于帮助用户理解参数的用途"
|
||||
}
|
||||
]
|
||||
|
||||
#################################################
|
||||
# 默认值配置
|
||||
|
@ -22,6 +22,7 @@ from data.models.task_variable import TaskVariableDefinition
|
||||
from data.models.task_backup import TaskBackup
|
||||
from data.models.task_edit_history import TaskEditHistory
|
||||
from data.models.task_instance import TaskInstance, TaskInstanceStatus
|
||||
from data.models.task_input_param import TaskInputParam
|
||||
|
||||
__all__ = [
|
||||
'BaseModel',
|
||||
@ -41,5 +42,6 @@ __all__ = [
|
||||
'TaskBackup',
|
||||
'TaskEditHistory',
|
||||
'TaskInstance',
|
||||
'TaskInstanceStatus'
|
||||
'TaskInstanceStatus',
|
||||
'TaskInputParam'
|
||||
]
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
data/models/__pycache__/task_input_param.cpython-312.pyc
Normal file
BIN
data/models/__pycache__/task_input_param.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
data/models/__pycache__/task_param_config.cpython-312.pyc
Normal file
BIN
data/models/__pycache__/task_param_config.cpython-312.pyc
Normal file
Binary file not shown.
@ -1,84 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
任务输入参数模型模块
|
||||
包含任务输入参数相关的数据模型
|
||||
"""
|
||||
|
||||
import enum
|
||||
from sqlalchemy import Column, Integer, String, Text, Boolean, Enum, ForeignKey, JSON
|
||||
from sqlalchemy.orm import relationship
|
||||
from data.models.base import BaseModel
|
||||
|
||||
class InputParamType(enum.Enum):
|
||||
"""
|
||||
输入参数类型枚举
|
||||
"""
|
||||
STRING = 'string' # 字符串
|
||||
NUMBER = 'number' # 数字
|
||||
BOOLEAN = 'boolean' # 布尔值
|
||||
OBJECT = 'object' # 对象
|
||||
ARRAY = 'array' # 数组
|
||||
NULL = 'null' # 空值
|
||||
|
||||
class TaskInput(BaseModel):
|
||||
"""
|
||||
任务输入参数模型
|
||||
表示任务执行所需的输入参数
|
||||
"""
|
||||
__tablename__ = 'task_inputs'
|
||||
|
||||
task_id = Column(Integer, ForeignKey('tasks.id'), nullable=False, comment='任务ID')
|
||||
name = Column(String(100), nullable=False, comment='参数名称')
|
||||
param_type = Column(Enum(InputParamType), nullable=False, default=InputParamType.STRING, comment='参数类型')
|
||||
description = Column(String(500), nullable=True, comment='参数描述')
|
||||
is_required = Column(Boolean, default=False, comment='是否必填')
|
||||
default_value = Column(Text, nullable=True, comment='默认值')
|
||||
validation_rules = Column(JSON, nullable=True, comment='验证规则(JSON格式)')
|
||||
order = Column(Integer, default=0, comment='排序顺序')
|
||||
|
||||
def __repr__(self):
|
||||
return f"<TaskInput(id={self.id}, task_id={self.task_id}, name='{self.name}', type='{self.param_type}')>"
|
||||
|
||||
@classmethod
|
||||
def get_by_task(cls, task_id):
|
||||
"""
|
||||
获取任务的所有输入参数
|
||||
"""
|
||||
return cls.query.filter(cls.task_id == task_id, cls.is_deleted == False).order_by(cls.order).all()
|
||||
|
||||
@classmethod
|
||||
def get_by_task_and_name(cls, task_id, name):
|
||||
"""
|
||||
根据任务ID和参数名称获取输入参数
|
||||
"""
|
||||
return cls.query.filter(cls.task_id == task_id, cls.name == name, cls.is_deleted == False).first()
|
||||
|
||||
class TaskInputValue(BaseModel):
|
||||
"""
|
||||
任务输入参数值模型
|
||||
表示任务执行时的实际输入参数值
|
||||
"""
|
||||
__tablename__ = 'task_input_values'
|
||||
|
||||
task_record_id = Column(Integer, ForeignKey('task_records.id'), nullable=False, comment='任务记录ID')
|
||||
input_id = Column(Integer, ForeignKey('task_inputs.id'), nullable=False, comment='输入参数ID')
|
||||
value = Column(Text, nullable=True, comment='参数值')
|
||||
|
||||
def __repr__(self):
|
||||
return f"<TaskInputValue(id={self.id}, task_record_id={self.task_record_id}, input_id={self.input_id})>"
|
||||
|
||||
@classmethod
|
||||
def get_by_record(cls, task_record_id):
|
||||
"""
|
||||
获取任务记录的所有输入参数值
|
||||
"""
|
||||
return cls.query.filter(cls.task_record_id == task_record_id, cls.is_deleted == False).all()
|
||||
|
||||
@classmethod
|
||||
def get_by_record_and_input(cls, task_record_id, input_id):
|
||||
"""
|
||||
根据任务记录ID和输入参数ID获取输入参数值
|
||||
"""
|
||||
return cls.query.filter(cls.task_record_id == task_record_id, cls.input_id == input_id, cls.is_deleted == False).first()
|
112
data/models/task_input_param.py
Normal file
112
data/models/task_input_param.py
Normal file
@ -0,0 +1,112 @@
|
||||
"""
|
||||
任务输入参数模型
|
||||
用于存储任务输入参数的数据
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean, ForeignKey, JSON, Enum, Index
|
||||
from sqlalchemy.orm import relationship, foreign
|
||||
from sqlalchemy.sql.expression import and_
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
import json
|
||||
from data.models.base import BaseModel
|
||||
from config.task_config import TaskInputParamType
|
||||
|
||||
class TaskInputParam(BaseModel):
|
||||
"""任务输入参数模型"""
|
||||
__tablename__ = "task_input_params"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True, comment="主键ID")
|
||||
param_id = Column(String(36), nullable=False, unique=True, index=True, comment="参数唯一ID,用于外部引用")
|
||||
instance_id = Column(String(36), index=True, nullable=False, comment="关联的任务实例ID")
|
||||
task_id = Column(String(50), nullable=False, index=True, comment="任务ID,冗余存储便于查询")
|
||||
param_name = Column(String(50), nullable=True, comment="参数名称,变量名")
|
||||
label = Column(String(100), nullable=True, comment="参数标签,显示名称")
|
||||
param_type = Column(String(20), nullable=False, comment="参数类型")
|
||||
required = Column(Boolean, default=False, comment="是否必填")
|
||||
_default_value = Column('default_value', Text, nullable=True, comment="默认值")
|
||||
description = Column(Text, nullable=True, comment="参数说明")
|
||||
is_system = Column(Boolean, default=False, comment="是否系统参数")
|
||||
is_readonly = Column(Boolean, default=False, comment="是否只读参数")
|
||||
sort_order = Column(Integer, default=0, comment="排序顺序")
|
||||
|
||||
# 手动创建索引而不是使用外键约束
|
||||
__table_args__ = (
|
||||
Index('idx_task_input_params_instance_id', 'instance_id'),
|
||||
{'mysql_engine': 'InnoDB'}
|
||||
)
|
||||
|
||||
# 关联关系 - 使用foreign()显式标记外键
|
||||
instance = relationship(
|
||||
"TaskInstance",
|
||||
primaryjoin="and_(TaskInputParam.instance_id==foreign(TaskInstance.instance_id), "
|
||||
"TaskInstance.is_deleted==False)",
|
||||
foreign_keys=[instance_id],
|
||||
back_populates="input_params",
|
||||
viewonly=True
|
||||
)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""初始化实例,自动生成param_id"""
|
||||
if 'param_id' not in kwargs:
|
||||
kwargs['param_id'] = str(uuid.uuid4())
|
||||
|
||||
# 处理default_value参数
|
||||
if 'default_value' in kwargs:
|
||||
self.default_value = kwargs.pop('default_value')
|
||||
|
||||
super(TaskInputParam, self).__init__(**kwargs)
|
||||
|
||||
@property
|
||||
def default_value(self):
|
||||
"""获取默认值"""
|
||||
if self._default_value is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
return json.loads(self._default_value)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
return self._default_value
|
||||
|
||||
@default_value.setter
|
||||
def default_value(self, value):
|
||||
"""设置默认值"""
|
||||
if value is None:
|
||||
self._default_value = None
|
||||
return
|
||||
|
||||
if isinstance(value, (str, int, float, bool)):
|
||||
# 基本类型直接转为JSON字符串
|
||||
self._default_value = json.dumps(value)
|
||||
elif isinstance(value, (list, dict)):
|
||||
# 复杂类型先验证是否可序列化,然后转为JSON字符串
|
||||
try:
|
||||
self._default_value = json.dumps(value)
|
||||
except:
|
||||
self._default_value = None
|
||||
else:
|
||||
# 其他类型尝试序列化,失败则设为None
|
||||
try:
|
||||
self._default_value = json.dumps(value)
|
||||
except:
|
||||
self._default_value = None
|
||||
|
||||
def to_dict(self):
|
||||
"""转换为字典"""
|
||||
return {
|
||||
"id": self.param_id, # 使用param_id作为对外ID
|
||||
"param_id": self.param_id,
|
||||
"instance_id": self.instance_id,
|
||||
"task_id": self.task_id,
|
||||
"param_name": self.param_name,
|
||||
"label": self.label,
|
||||
"param_type": self.param_type,
|
||||
"required": self.required,
|
||||
"default_value": self.default_value,
|
||||
"description": self.description,
|
||||
"is_system": self.is_system,
|
||||
"is_readonly": self.is_readonly,
|
||||
"sort_order": self.sort_order,
|
||||
"created_at": int(self.created_at.timestamp() * 1000) if self.created_at else None,
|
||||
"updated_at": int(self.updated_at.timestamp() * 1000) if self.updated_at else None,
|
||||
"is_deleted": self.is_deleted
|
||||
}
|
@ -2,8 +2,9 @@
|
||||
任务实例模型
|
||||
用于存储任务管理表的数据,记录每次编辑任务的实例
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean, ForeignKey, JSON, Enum
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean, ForeignKey, JSON, Enum, Index
|
||||
from sqlalchemy.orm import relationship, foreign
|
||||
from sqlalchemy.sql.expression import and_
|
||||
from datetime import datetime
|
||||
import enum
|
||||
import uuid
|
||||
@ -17,23 +18,31 @@ class TaskInstanceStatus(enum.Enum):
|
||||
class TaskInstance(BaseModel):
|
||||
"""任务实例模型"""
|
||||
__tablename__ = "task_instances"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True, comment="主键ID")
|
||||
instance_id = Column(String(36), nullable=False, unique=True, index=True, comment="实例唯一ID,用于外部引用")
|
||||
task_id = Column(String(50), ForeignKey("tasks.task_id"), nullable=False, comment="关联的任务ID")
|
||||
name = Column(String(100), nullable=False, comment="任务名称(复制自任务表)")
|
||||
variables = Column(JSON, nullable=True, comment="任务变量")
|
||||
priority = Column(Integer, default=1, comment="任务优先级")
|
||||
input_params = Column(JSON, nullable=True, comment="任务输入参数")
|
||||
block_outputs = Column(JSON, nullable=True, comment="块输出参数")
|
||||
context_params = Column(JSON, nullable=True, comment="上下文参数")
|
||||
status = Column(Enum(TaskInstanceStatus), default=TaskInstanceStatus.EDITING, comment="任务实例状态")
|
||||
created_at = Column(DateTime, default=datetime.now, comment="创建时间")
|
||||
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now, comment="更新时间")
|
||||
is_deleted = Column(Boolean, default=False, comment="是否删除")
|
||||
status = Column(Enum(TaskInstanceStatus), default=TaskInstanceStatus.EDITING, comment="任务实例状态")
|
||||
|
||||
# 关联关系
|
||||
# 确保创建索引
|
||||
__table_args__ = (
|
||||
Index('idx_task_instances_instance_id', 'instance_id'),
|
||||
{'mysql_engine': 'InnoDB'}
|
||||
)
|
||||
|
||||
# 关联关系 - 使用foreign()显式标记外键
|
||||
task = relationship("Task", back_populates="instances")
|
||||
input_params = relationship(
|
||||
"TaskInputParam",
|
||||
back_populates="instance",
|
||||
primaryjoin="and_(foreign(TaskInstance.instance_id)==TaskInputParam.instance_id, "
|
||||
"TaskInputParam.is_deleted==False)",
|
||||
viewonly=False,
|
||||
cascade="all" # 移除delete-orphan级联选项
|
||||
)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""初始化实例,自动生成instance_id"""
|
||||
@ -50,11 +59,23 @@ class TaskInstance(BaseModel):
|
||||
"name": self.name,
|
||||
"variables": self.variables or {},
|
||||
"priority": self.priority,
|
||||
"input_params": self.input_params or {},
|
||||
"block_outputs": self.block_outputs or {},
|
||||
"context_params": self.context_params or {},
|
||||
"status": self.status.value if self.status else None,
|
||||
"created_at": int(self.created_at.timestamp() * 1000) if self.created_at else None,
|
||||
"updated_at": int(self.updated_at.timestamp() * 1000) if self.updated_at else None,
|
||||
"is_deleted": self.is_deleted
|
||||
}
|
||||
|
||||
def to_api_dict(self):
|
||||
"""转换为API响应字典,只返回必要的字段"""
|
||||
return {
|
||||
"instance_id": self.instance_id,
|
||||
"task_id": self.task_id,
|
||||
"name": self.name,
|
||||
"variables": self.variables or {},
|
||||
"priority": self.priority,
|
||||
"block_outputs": self.block_outputs or {},
|
||||
"context_params": self.context_params or {},
|
||||
"status": self.status.value if self.status else None
|
||||
}
|
19222
logs/tianfeng_task.log
19222
logs/tianfeng_task.log
File diff suppressed because it is too large
Load Diff
@ -184,3 +184,16 @@ CREATE TABLE task_flow_connections (
|
||||
2025-03-17 17:11:13,111 - utils.db_migration - INFO - 数据库迁移完成
|
||||
2025-03-17 17:11:13,111 - utils.db_migration - INFO - 数据库迁移成功
|
||||
2025-03-17 17:11:13,111 - migration - INFO - 数据库迁移成功完成!
|
||||
2025-03-18 14:25:55,232 - migration - INFO - 开始执行数据库自动迁移...
|
||||
2025-03-18 14:25:55,232 - utils.db_migration - INFO - 开始数据库迁移
|
||||
2025-03-18 14:25:55,309 - utils.db_migration - INFO - 发现 22 个模型
|
||||
2025-03-18 14:25:55,324 - utils.db_migration - INFO - 表 task_flow_connections 不存在,准备创建
|
||||
2025-03-18 14:25:55,398 - utils.db_migration - INFO - 创建表 task_flow_connections 成功
|
||||
2025-03-18 14:25:55,403 - utils.db_migration - INFO - 表 task_import_exports 不存在,准备创建
|
||||
2025-03-18 14:25:55,500 - utils.db_migration - INFO - 创建表 task_import_exports 成功
|
||||
2025-03-18 14:25:55,503 - utils.db_migration - INFO - 发现新增列 task_input_params.instance_id,准备添加
|
||||
2025-03-18 14:25:55,503 - utils.db_migration - INFO - 执行SQL: ALTER TABLE task_input_params ADD COLUMN instance_id VARCHAR(36) NOT NULL
|
||||
2025-03-18 14:25:55,598 - utils.db_migration - INFO - 添加列 task_input_params.instance_id 成功
|
||||
2025-03-18 14:25:55,611 - utils.db_migration - INFO - 数据库迁移完成
|
||||
2025-03-18 14:25:55,611 - utils.db_migration - INFO - 数据库迁移成功
|
||||
2025-03-18 14:25:55,611 - migration - INFO - 数据库迁移成功完成!
|
||||
|
Binary file not shown.
BIN
services/__pycache__/task_param_service.cpython-312.pyc
Normal file
BIN
services/__pycache__/task_param_service.cpython-312.pyc
Normal file
Binary file not shown.
@ -155,6 +155,18 @@ class TaskInstanceService:
|
||||
|
||||
return instance.to_dict()
|
||||
|
||||
def get_last_published_instance(self, task_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
根据任务ID获取最新的已发布任务实例(get_latest_published_instance_by_task_id的别名)
|
||||
|
||||
Args:
|
||||
task_id: 任务ID
|
||||
|
||||
Returns:
|
||||
最新的已发布任务实例字典,如果不存在则返回None
|
||||
"""
|
||||
return self.get_latest_published_instance_by_task_id(task_id)
|
||||
|
||||
def update_instance(self, instance_id: str, variables: Optional[Dict[str, Any]] = None,
|
||||
priority: Optional[int] = None, input_params: Optional[Dict[str, Any]] = None,
|
||||
block_outputs: Optional[Dict[str, Any]] = None, context_params: Optional[Dict[str, Any]] = None,
|
||||
|
304
services/task_param_service.py
Normal file
304
services/task_param_service.py
Normal file
@ -0,0 +1,304 @@
|
||||
"""
|
||||
任务参数服务模块
|
||||
负责任务输入参数的管理
|
||||
"""
|
||||
from typing import Dict, Any, List, Optional, Tuple
|
||||
import json
|
||||
from config.task_config import TaskInputParamConfig, TaskInputParamType
|
||||
from config.database import db_session
|
||||
from sqlalchemy import and_, or_, desc
|
||||
|
||||
class TaskParamService:
|
||||
"""任务参数服务类"""
|
||||
|
||||
def __init__(self):
|
||||
# 导入数据模型
|
||||
from data.models.task_input_param import TaskInputParam
|
||||
self.TaskInputParam = TaskInputParam
|
||||
|
||||
def get_param_types(self) -> List[Dict[str, Any]]:
|
||||
"""获取所有支持的参数类型"""
|
||||
param_types = []
|
||||
for param_type in TaskInputParamType:
|
||||
param_types.append({
|
||||
"key": param_type.value,
|
||||
"name": param_type.value,
|
||||
"description": f"{param_type.value}类型参数"
|
||||
})
|
||||
return param_types
|
||||
|
||||
def get_task_input_params(self, task_id: str, instance_id: str = None) -> Tuple[List[Dict[str, Any]], Optional[str]]:
|
||||
"""
|
||||
获取任务输入参数
|
||||
|
||||
Args:
|
||||
task_id: 任务ID
|
||||
instance_id: 任务实例ID,如果为None,则尝试获取最新的实例
|
||||
|
||||
Returns:
|
||||
Tuple[List[Dict[str, Any]], Optional[str]]: (任务输入参数列表, 实际使用的实例ID)
|
||||
"""
|
||||
# 如果没有提供实例ID,尝试查找最新的实例
|
||||
found_instance_id = instance_id
|
||||
if not found_instance_id:
|
||||
from data.models.task_instance import TaskInstance
|
||||
with db_session() as session:
|
||||
instance = session.query(TaskInstance).filter(
|
||||
TaskInstance.task_id == task_id,
|
||||
TaskInstance.is_deleted == False
|
||||
).order_by(TaskInstance.updated_at.desc()).first()
|
||||
|
||||
if instance:
|
||||
found_instance_id = instance.instance_id
|
||||
else:
|
||||
# 如果没有找到实例,返回空列表和None
|
||||
return [], None
|
||||
|
||||
# 从数据库中查询并获取任务的输入参数
|
||||
with db_session() as session:
|
||||
# 查询任务输入参数,过滤掉已删除的
|
||||
db_params = session.query(self.TaskInputParam).filter(
|
||||
and_(
|
||||
self.TaskInputParam.instance_id == found_instance_id,
|
||||
self.TaskInputParam.is_deleted == False
|
||||
)
|
||||
).order_by(self.TaskInputParam.sort_order).all()
|
||||
|
||||
# 将数据库查询结果转换为字典
|
||||
params = [param.to_dict() for param in db_params]
|
||||
|
||||
return params, found_instance_id
|
||||
|
||||
def update_task_input_params(self, task_id: str, params: List[Dict[str, Any]], instance_id: str = None) -> Tuple[int, str, bool]:
|
||||
"""
|
||||
更新任务输入参数
|
||||
|
||||
Args:
|
||||
task_id: 任务ID
|
||||
params: 任务输入参数列表
|
||||
instance_id: 任务实例ID,如果为None,则尝试获取最新的实例
|
||||
|
||||
Returns:
|
||||
Tuple[int, str, bool]: (更新的参数数量, 实际使用的实例ID, 是否有数据变动)
|
||||
"""
|
||||
# 如果没有提供实例ID,尝试查找最新的实例
|
||||
found_instance_id = instance_id
|
||||
if not found_instance_id:
|
||||
from data.models.task_instance import TaskInstance
|
||||
with db_session() as session:
|
||||
instance = session.query(TaskInstance).filter(
|
||||
TaskInstance.task_id == task_id,
|
||||
TaskInstance.is_deleted == False
|
||||
).order_by(TaskInstance.updated_at.desc()).first()
|
||||
|
||||
if instance:
|
||||
found_instance_id = instance.instance_id
|
||||
else:
|
||||
# 创建新的任务实例
|
||||
from data.models.task import Task
|
||||
task = session.query(Task).filter(Task.task_id == task_id).first()
|
||||
if not task:
|
||||
raise ValueError(f"任务不存在: {task_id}")
|
||||
|
||||
instance = TaskInstance(
|
||||
task_id=task_id,
|
||||
name=task.name,
|
||||
variables={},
|
||||
priority=1,
|
||||
input_params={},
|
||||
block_outputs={},
|
||||
context_params={}
|
||||
)
|
||||
session.add(instance)
|
||||
session.commit()
|
||||
found_instance_id = instance.instance_id
|
||||
# 新建实例,肯定有数据变动
|
||||
return 0, found_instance_id, True
|
||||
|
||||
# 过滤出非系统参数
|
||||
custom_params = []
|
||||
system_param_keys = [param["key"] for param in TaskInputParamConfig.get_system_params()]
|
||||
|
||||
for param in params:
|
||||
# 检查是否为系统参数
|
||||
if param["param_name"] in system_param_keys:
|
||||
continue
|
||||
|
||||
# 确保param存在default_value键
|
||||
if "default_value" not in param:
|
||||
param["default_value"] = None
|
||||
|
||||
custom_params.append(param)
|
||||
|
||||
# 检测是否有数据变动的标志
|
||||
has_changes = False
|
||||
|
||||
# 更新数据库
|
||||
with db_session() as session:
|
||||
# 查询当前任务实例的所有自定义参数
|
||||
existing_params = session.query(self.TaskInputParam).filter(
|
||||
and_(
|
||||
self.TaskInputParam.instance_id == found_instance_id,
|
||||
self.TaskInputParam.is_system == False,
|
||||
self.TaskInputParam.is_deleted == False
|
||||
)
|
||||
).all()
|
||||
|
||||
# 创建一个映射,用于快速找到现有参数
|
||||
existing_param_map = {param.param_name: param for param in existing_params}
|
||||
|
||||
# 检查参数数量是否变化
|
||||
if len(existing_param_map) != len(custom_params):
|
||||
has_changes = True
|
||||
|
||||
# 处理每个自定义参数
|
||||
for i, param_data in enumerate(custom_params):
|
||||
param_name = param_data["param_name"]
|
||||
|
||||
# 检查是否存在现有参数
|
||||
if param_name in existing_param_map:
|
||||
# 获取现有参数
|
||||
param = existing_param_map[param_name]
|
||||
|
||||
# 检查参数是否有变化
|
||||
if (param.label != param_data.get("label", "") or
|
||||
param.param_type != param_data.get("param_type", "") or
|
||||
param.required != param_data.get("required", False) or
|
||||
param.description != param_data.get("description", "") or
|
||||
param.sort_order != i):
|
||||
has_changes = True
|
||||
|
||||
# 检查default_value是否有变化(需要特殊处理)
|
||||
old_value = param.default_value
|
||||
new_value = param_data.get("default_value")
|
||||
|
||||
# 尝试比较值(考虑到None, 空字符串, 空列表等特殊情况)
|
||||
if ((old_value is None and new_value not in [None, "", [], {}]) or
|
||||
(new_value is None and old_value not in [None, "", [], {}]) or
|
||||
(str(old_value) != str(new_value))):
|
||||
has_changes = True
|
||||
|
||||
# 更新现有参数
|
||||
param.label = param_data.get("label", param_name)
|
||||
param.param_type = param_data.get("param_type", param.param_type)
|
||||
param.required = param_data.get("required", False)
|
||||
param.default_value = new_value
|
||||
param.description = param_data.get("description", "")
|
||||
param.sort_order = i
|
||||
# 从映射中移除,以便后面知道哪些需要删除
|
||||
del existing_param_map[param_name]
|
||||
else:
|
||||
# 创建新参数 - 有新增肯定是有变化的
|
||||
has_changes = True
|
||||
new_param = self.TaskInputParam(
|
||||
instance_id=found_instance_id,
|
||||
task_id=task_id, # 冗余存储任务ID,便于查询
|
||||
param_name=param_name,
|
||||
label=param_data.get("label", param_name),
|
||||
param_type=param_data.get("param_type", TaskInputParamType.STRING.value),
|
||||
required=param_data.get("required", False),
|
||||
default_value=param_data.get("default_value"),
|
||||
description=param_data.get("description", ""),
|
||||
is_system=False,
|
||||
is_readonly=False,
|
||||
sort_order=i
|
||||
)
|
||||
session.add(new_param)
|
||||
|
||||
# 如果有需要删除的参数,标记变化
|
||||
if existing_param_map:
|
||||
has_changes = True
|
||||
|
||||
# 标记需要删除的参数
|
||||
for param in existing_param_map.values():
|
||||
param.is_deleted = True
|
||||
|
||||
# 只有在有变化时才提交事务
|
||||
if has_changes:
|
||||
session.commit()
|
||||
|
||||
return len(custom_params), found_instance_id, has_changes
|
||||
|
||||
def delete_task_input_param(self, task_id: str, param_id: str, instance_id: str = None) -> bool:
|
||||
"""
|
||||
删除任务输入参数
|
||||
|
||||
Args:
|
||||
task_id: 任务ID
|
||||
param_id: 参数ID
|
||||
instance_id: 任务实例ID,如果为None,则尝试获取最新的实例
|
||||
|
||||
Returns:
|
||||
bool: 是否成功删除
|
||||
"""
|
||||
# 如果没有提供实例ID,尝试查找最新的实例
|
||||
if not instance_id:
|
||||
from data.models.task_instance import TaskInstance
|
||||
with db_session() as session:
|
||||
instance = session.query(TaskInstance).filter(
|
||||
TaskInstance.task_id == task_id,
|
||||
TaskInstance.is_deleted == False
|
||||
).order_by(TaskInstance.updated_at.desc()).first()
|
||||
|
||||
if instance:
|
||||
instance_id = instance.instance_id
|
||||
else:
|
||||
return False # 如果找不到实例,返回删除失败
|
||||
|
||||
with db_session() as session:
|
||||
# 查询参数
|
||||
param = session.query(self.TaskInputParam).filter(
|
||||
and_(
|
||||
self.TaskInputParam.instance_id == instance_id,
|
||||
self.TaskInputParam.param_id == param_id,
|
||||
self.TaskInputParam.is_deleted == False
|
||||
)
|
||||
).first()
|
||||
|
||||
if not param:
|
||||
return False
|
||||
|
||||
# 系统参数不允许删除
|
||||
if param.is_system:
|
||||
return False
|
||||
|
||||
# 标记为已删除
|
||||
param.is_deleted = True
|
||||
session.commit()
|
||||
|
||||
return True
|
||||
|
||||
def get_default_input_params(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取默认的任务输入参数
|
||||
|
||||
Returns:
|
||||
List[Dict[str, Any]]: 默认的任务输入参数列表
|
||||
"""
|
||||
# 返回一些常用的默认参数作为示例
|
||||
return [
|
||||
{
|
||||
"param_name": "robotId",
|
||||
"label": "机器人ID",
|
||||
"param_type": TaskInputParamType.STRING,
|
||||
"required": True,
|
||||
"default_value": "",
|
||||
"description": "执行任务的机器人ID"
|
||||
},
|
||||
{
|
||||
"param_name": "targetPosition",
|
||||
"label": "目标位置",
|
||||
"param_type": TaskInputParamType.STRING,
|
||||
"required": False,
|
||||
"default_value": "",
|
||||
"description": "任务执行的目标位置"
|
||||
},
|
||||
{
|
||||
"param_name": "timeout",
|
||||
"label": "超时时间",
|
||||
"param_type": TaskInputParamType.INTEGER,
|
||||
"required": False,
|
||||
"default_value": 3600,
|
||||
"description": "任务执行的超时时间(秒)"
|
||||
}
|
||||
]
|
62
utils/api_response.py
Normal file
62
utils/api_response.py
Normal file
@ -0,0 +1,62 @@
|
||||
"""
|
||||
API响应工具模块
|
||||
用于处理API响应数据的转换
|
||||
"""
|
||||
from typing import Dict, Any, List, Optional
|
||||
from data.models.task_instance import TaskInstance
|
||||
from data.models.task_input_param import TaskInputParam
|
||||
|
||||
class ApiResponseUtil:
|
||||
"""API响应工具类"""
|
||||
|
||||
@staticmethod
|
||||
def to_task_instance_response(instance: TaskInstance) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
将任务实例转换为API响应数据
|
||||
|
||||
Args:
|
||||
instance: 任务实例对象
|
||||
|
||||
Returns:
|
||||
API响应数据字典
|
||||
"""
|
||||
if not instance:
|
||||
return None
|
||||
|
||||
return {
|
||||
"instance_id": instance.instance_id,
|
||||
"task_id": instance.task_id,
|
||||
"name": instance.name,
|
||||
"variables": instance.variables or {},
|
||||
"priority": instance.priority,
|
||||
"block_outputs": instance.block_outputs or {},
|
||||
"context_params": instance.context_params or {},
|
||||
"status": instance.status.value if instance.status else None
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def to_task_input_param_response(param: TaskInputParam) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
将任务输入参数转换为API响应数据
|
||||
|
||||
Args:
|
||||
param: 任务输入参数对象
|
||||
|
||||
Returns:
|
||||
API响应数据字典
|
||||
"""
|
||||
if not param:
|
||||
return None
|
||||
|
||||
return {
|
||||
"param_id": param.param_id,
|
||||
"param_name": param.param_name,
|
||||
"label": param.label,
|
||||
"param_type": param.param_type,
|
||||
"required": param.required,
|
||||
"default_value": param.default_value,
|
||||
"description": param.description,
|
||||
"is_system": param.is_system,
|
||||
"is_readonly": param.is_readonly,
|
||||
"sort_order": param.sort_order
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user