#!/usr/bin/env python # -*- coding: utf-8 -*- """ 天风任务编辑API模型模块 包含任务编辑相关的请求和响应数据模型 """ from typing import Optional, List, Dict, Any, Union from enum import Enum from datetime import datetime from pydantic import BaseModel, Field, validator import re from routes.model.base import PageResult, PaginationParams # 参数类型枚举 class ParamType(str, Enum): ROBOT_ID = "robotId" ROBOT_GROUP = "robotGroup" SITE_ID = "siteId" AREA = "area" STATION = "station" BUILT_IN_FUNCTION = "builtInFunction" # 参数值类型枚举 class ParamValueType(str, Enum): SIMPLE = "Simple" EXPRESSION = "Expression" JSON = "JSON" # 任务参数模型 class TaskParam(BaseModel): """任务参数模型""" name: str = Field(..., description="参数名称") type: str = Field(..., description="参数类型") label: str = Field(..., description="参数显示名称") required: bool = Field(False, description="是否必填") defaultValue: Optional[Any] = Field(None, description="默认值") remark: Optional[str] = Field(None, description="备注说明") description: Optional[str] = Field(None, description="详细描述") options: List[Dict[str, Any]] = Field(default=[], description="可选值列表") # 参数值模型 class ParamValue(BaseModel): """参数值模型""" type: ParamValueType = Field(..., description="值类型") value: Any = Field(..., description="参数值") required: Optional[bool] = Field(None, description="是否必填") # 块基本模型 class BlockBase(BaseModel): """块基本模型""" id: int = Field(..., description="块ID") name: str = Field(..., description="块名称") blockType: str = Field(..., description="块类型") inputParams: Dict[str, ParamValue] = Field(default={}, description="输入参数") children: Dict[str, List[Any]] = Field(default={}, description="子块列表") selected: bool = Field(False, description="是否选中") expanded: bool = Field(True, description="是否展开") refTaskDefId: Optional[str] = Field(None, description="引用的任务定义ID") # 任务详细定义模型 class TaskDetail(BaseModel): """任务详细定义模型""" inputParams: List[TaskParam] = Field(default=[], description="输入参数列表") outputParams: List[TaskParam] = Field(default=[], description="输出参数列表") rootBlock: BlockBase = Field(..., description="根块配置") # 任务定义模型 class TaskDefinition(BaseModel): """任务定义模型""" id: str = Field(..., description="任务ID") label: str = Field(..., description="任务名称") detail: TaskDetail = Field(..., description="任务详细定义") version: Optional[int] = Field(None, description="任务版本号") delay: Optional[int] = Field(None, description="延迟时间(毫秒)") if_enable: Optional[int] = Field(None, description="是否启用") period: Optional[int] = Field(None, description="周期时间(毫秒)") periodic_task: Optional[int] = Field(None, description="是否为周期任务") remark: Optional[str] = Field(None, description="备注") status: Optional[int] = Field(None, description="任务状态") template_name: Optional[str] = Field(None, description="模板名称") template_description: Optional[str] = Field(None, description="模板描述") create_date: Optional[datetime] = Field(None, description="创建时间") created_by: Optional[str] = Field(None, description="创建者") update_date: Optional[datetime] = Field(None, description="更新时间") updated_by: Optional[str] = Field(None, description="更新者") # 任务基本信息模型 class TaskBasicInfo(BaseModel): """任务基本信息""" label: str = Field(..., description="任务名称") remark: Optional[str] = Field(None, description="备注") releaseSites: bool = Field(True, description="是否释放站点") @validator('label') def label_must_not_be_empty_or_whitespace(cls, v): """验证任务名称不为空且不只包含空白字符""" if not v or v.strip() == "": raise ValueError('任务名称不能为空') # 检查是否只包含空白字符 if re.match(r'^\s+$', v): raise ValueError('任务名称不能只包含空格') # 检查是否包含特殊字符 if re.search(r'[<>:"/\\|?*]', v): raise ValueError('任务名称不能包含特殊字符 < > : " / \\ | ? *') return v.strip() # 任务备份请求模型 class TaskBackupRequest(BaseModel): """任务备份请求模型""" backup_name: Optional[str] = Field(None, description="备份后的任务名称") remark: Optional[str] = Field(None, description="备份任务的备注信息") # 子任务列表查询参数 class SubTaskListParams(PaginationParams): """子任务列表查询参数""" keyword: Optional[str] = Field(None, description="搜索关键词") exclude_id: str = Field(..., description="要排除的任务ID,必填") # 子任务列表项模型 class SubTaskListItem(BaseModel): """子任务列表项模型""" id: str = Field(..., description="任务ID") label: str = Field(..., description="任务名称") version: int = Field(..., description="版本号") templateName: str = Field(..., description="模板名称") remark: Optional[str] = Field(None, description="备注") createDate: str = Field(..., description="创建时间") createdBy: str = Field(..., description="创建者") status: int = Field(..., description="状态") inputParams: List[TaskParam] = Field(..., description="输入参数") # 子任务列表响应模型 class SubTaskListResponse(BaseModel): """子任务列表响应模型""" total: int = Field(..., description="总记录数") list: List[SubTaskListItem] = Field(..., description="子任务列表") # 常用参数字段模型 class CommonParamField(BaseModel): """常用参数字段模型""" id: str = Field(..., description="字段ID") label: str = Field(..., description="字段标签") type: str = Field(..., description="字段类型") description: Optional[str] = Field(None, description="字段描述") example: Optional[str] = Field(None, description="示例值") placeholder: Optional[str] = Field(None, description="占位提示") order: int = Field(..., description="排序") values: List[Dict[str, Any]] = Field(default=[], description="可选值列表") # 输入参数类型信息模型 class InputParamTypeInfo(BaseModel): """输入参数类型信息模型""" types: List[Dict[str, Any]] = Field(..., description="参数类型列表") fields: List[Dict[str, Any]] = Field(..., description="字段配置列表") # 输入参数类型枚举 class InputParamType(str, Enum): """输入参数类型枚举""" STRING = "STRING" # 字符串 BOOLEAN = "BOOLEAN" # 布尔 INTEGER = "INTEGER" # 整数 FLOAT = "FLOAT" # 浮点数 OBJECT = "OBJECT" # JSON对象 ARRAY = "ARRAY" # JSON数组 class TaskInputParam(BaseModel): """任务输入参数模型""" name: str = Field(..., description="参数名称") type: InputParamType = Field(..., description="参数类型") label: str = Field(..., description="参数显示名称") required: bool = Field(False, description="是否必填") defaultValue: str = Field("", description="默认值") remark: str = Field("", description="参数说明") class TaskInputParamNew(BaseModel): """任务输入参数模型""" name: str = Field(..., description="参数名称") type: InputParamType = Field(..., description="参数类型") label: str = Field(..., description="参数显示名称") required: bool = Field(False, description="是否必填") defaultValue: str = Field(..., description="默认值") remark: str = Field("", description="参数说明") # 任务运行请求模型 class TaskEditRunRequest(BaseModel): """任务运行请求模型""" taskId: str = Field(..., description="要运行的任务ID") params: List[TaskInputParamNew] = Field(None, description="任务运行参数,根据任务定义中的inputParams字段确定") source_type: Optional[int] = Field(..., description="任务来源类型(1: 系统调度, 2: 呼叫机, 3: 第三方系统, 4: 手持电脑)") source_system: Optional[str] = Field(..., description="来源系统标识(如:WMS、MES等系统编号)") source_device: Optional[str] = Field(..., description="下达任务的硬件设备标识(设备ID、MAC地址等)") # 重新定义更准确的任务参数模型,确保包含所有必要字段 class TaskParamSave(BaseModel): """任务参数保存模型""" name: str = Field(..., description="参数名称") type: str = Field(..., description="参数类型") label: str = Field(..., description="参数显示名称") remark: str = Field("", description="备注说明") defaultValue: str = Field("", description="默认值") required: bool = Field(False, description="是否必填") # 重新定义块参数值模型 class BlockParamValue(BaseModel): """块参数值模型""" type: ParamValueType = Field(..., description="值类型") value: Any = Field(..., description="参数值") required: Optional[bool] = Field(None, description="是否必填") # 递归定义块模型 class BlockModel(BaseModel): """块模型,可以递归包含子块""" id: int = Field(..., description="块ID") name: str = Field(..., description="块名称") blockType: str = Field(..., description="块类型") inputParams: Dict[str, BlockParamValue] = Field(default_factory=dict, description="输入参数") children: Dict[str, List['BlockModel']] = Field(default_factory=dict, description="子块列表") refTaskDefId: str = Field("", description="引用的任务定义ID") selected: bool = Field(False, description="是否选中") expanded: bool = Field(True, description="是否展开") # 支持递归定义 BlockModel.update_forward_refs() # 任务详细定义保存模型 class TaskDetailSave(BaseModel): """任务详细定义保存模型""" inputParams: List[TaskParamSave] = Field(default_factory=list, description="输入参数列表") outputParams: List[TaskParamSave] = Field(default_factory=list, description="输出参数列表") rootBlock: BlockModel = Field(..., description="根块配置") # 任务保存请求模型 class TaskSaveRequest(BaseModel): """任务保存请求模型""" id: str = Field(..., description="任务ID") detail: TaskDetailSave = Field(..., description="任务详细定义") @validator('detail') def validate_detail(cls, v): """验证任务详细定义""" # 验证rootBlock的blockType是否为RootBp if v.rootBlock.blockType != 'RootBp': raise ValueError('rootBlock的blockType必须为RootBp') return v