mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-20 20:39:55 +00:00
- 移除各路由文件顶部冗余注释 - 将 JobRouter/NodeRouter 重命名为 CornJobRouter/CornJobNodeRouter - 新增存储浏览、节点、传输、工作流路由注册 - 调整路由导入来源与任务表名 - 优化 main.py 启动方式及环境配置加载
179 lines
8.6 KiB
Python
179 lines
8.6 KiB
Python
from typing import Literal
|
||
|
||
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||
|
||
from app.core.base_schema import BaseQueryParam, BaseSchema, UserByQueryParam, UserBySchema
|
||
|
||
WorkflowTaskType = Literal["parallel", "chain"]
|
||
|
||
|
||
class WorkflowTargetSchema(BaseModel):
|
||
"""流程目标节点配置(目标目录由目标节点默认源目录决定)"""
|
||
|
||
target_id: int = Field(..., ge=1, description="目标节点ID(存储源)")
|
||
target_path: str = Field(..., max_length=1024, description="目标路径")
|
||
|
||
|
||
class WorkflowSourceSchema(BaseModel):
|
||
"""流程源节点概览(由画布连线实时派生)"""
|
||
|
||
source_id: int = Field(..., ge=1, description="源节点ID(存储源)")
|
||
source_name: str | None = Field(default=None, description="源存储源名称")
|
||
|
||
|
||
class WorkflowNodeSchema(BaseModel):
|
||
"""画布节点业务配置(由画布拆分,落 flow_node 表)"""
|
||
|
||
node_key: str = Field(..., description="画布节点ID")
|
||
source_id: int = Field(..., ge=1, description="存储源ID")
|
||
source_path: str | None = Field(default=None, max_length=1024, description="默认源目录")
|
||
|
||
|
||
class WorkflowEdgeSchema(BaseModel):
|
||
"""画布连线业务配置(由画布拆分,落 flow_edge 表)
|
||
|
||
连线只定义传输方式;目标目录由目标节点的默认源目录(source_path)决定。
|
||
"""
|
||
|
||
edge_key: str = Field(..., description="画布连线ID")
|
||
source_node_key: str = Field(..., description="源画布节点ID")
|
||
target_node_key: str = Field(..., description="目标画布节点ID")
|
||
enabled: bool = Field(default=True, description="是否启用(禁用则不执行)")
|
||
transfer_mode: str | None = Field(default=None, max_length=16, description="传输方式(stream/multipart,空用存储源默认)")
|
||
multipart_part_size: int | None = Field(default=None, ge=1, description="分片大小(MB)")
|
||
multipart_concurrency: int | None = Field(default=None, ge=1, description="分片并发数")
|
||
|
||
|
||
class WorkflowLayoutNodeSchema(BaseModel):
|
||
"""画布节点布局展示字段(存 flow.graph,业务配置在 flow_node 表)"""
|
||
|
||
id: str = Field(..., description="画布节点ID")
|
||
type: str = Field("storage", description="节点类型")
|
||
position: dict = Field(default_factory=lambda: {"x": 0, "y": 0}, description="节点位置")
|
||
label: str | None = Field(default=None, description="节点显示名")
|
||
style: dict | None = Field(default=None, description="节点样式")
|
||
|
||
|
||
class WorkflowLayoutEdgeSchema(BaseModel):
|
||
"""画布连线布局展示字段(存 flow.graph,业务配置在 flow_edge 表)"""
|
||
|
||
id: str = Field(..., description="画布连线ID")
|
||
source: str = Field(..., description="源画布节点ID")
|
||
target: str = Field(..., description="目标画布节点ID")
|
||
type: str = Field("smoothstep", description="连线类型")
|
||
animated: bool | None = Field(default=None, description="连线动画")
|
||
style: dict | None = Field(default=None, description="连线样式")
|
||
label: str | None = Field(default=None, description="连线显示名")
|
||
|
||
|
||
class WorkflowGraphNodeDataSchema(BaseModel):
|
||
"""画布节点回显数据(组装完整画布时写入 node.data)"""
|
||
|
||
source_id: int = Field(..., ge=1, description="存储源ID")
|
||
source_path: str | None = Field(default=None, description="默认源目录")
|
||
label: str | None = Field(default=None, description="节点显示名")
|
||
protocol: str | None = Field(default=None, description="存储源协议")
|
||
host: str | None = Field(default=None, description="主机地址")
|
||
bucket: str | None = Field(default=None, description="桶名(对象存储)")
|
||
endpoint: str | None = Field(default=None, description="对象存储地址")
|
||
region: str | None = Field(default=None, description="区域")
|
||
path_prefix: str | None = Field(default=None, description="路径前缀")
|
||
|
||
|
||
class WorkflowGraphEdgeDataSchema(BaseModel):
|
||
"""画布连线回显数据(组装完整画布时写入 edge.data)"""
|
||
|
||
enabled: bool = Field(default=True, description="是否启用(禁用则不执行)")
|
||
transfer_mode: str | None = Field(default=None, description="传输方式")
|
||
multipart_part_size: int | None = Field(default=None, description="分片大小(MB)")
|
||
multipart_concurrency: int | None = Field(default=None, description="分片并发数")
|
||
source_label: str | None = Field(default=None, description="源存储源名称")
|
||
target_label: str | None = Field(default=None, description="目标存储源名称")
|
||
source_protocol: str | None = Field(default=None, description="源存储源协议")
|
||
target_protocol: str | None = Field(default=None, description="目标存储源协议")
|
||
source_storage_id: int | None = Field(default=None, description="源存储源ID")
|
||
target_storage_id: int | None = Field(default=None, description="目标存储源ID")
|
||
|
||
|
||
class WorkflowSplitResultSchema(BaseModel):
|
||
"""画布拆分结果:业务明细(node/edge)+ 精简布局 + 派生概览"""
|
||
|
||
layout: dict = Field(..., description="精简后的画布布局 {nodes:[{id,type,position,label}],edges:[{id,source,target,type,animated,style,label}]}")
|
||
nodes: list[WorkflowNodeSchema] = Field(default_factory=list, description="节点业务明细")
|
||
edges: list[WorkflowEdgeSchema] = Field(default_factory=list, description="连线业务明细")
|
||
sources: list[WorkflowSourceSchema] = Field(default_factory=list, description="源节点列表(去重)")
|
||
targets: list[WorkflowTargetSchema] = Field(default_factory=list, description="目标列表(去重)")
|
||
|
||
|
||
class WorkflowTransferPlanSchema(BaseModel):
|
||
"""执行计划:单条连线生成的传输任务参数"""
|
||
|
||
src_id: int = Field(..., ge=1, description="源存储源ID")
|
||
tgt_id: int = Field(..., ge=1, description="目标存储源ID")
|
||
src_path: str = Field(..., description="源文件/目录路径")
|
||
tgt_path: str = Field(..., description="目标路径")
|
||
transfer_mode: str = Field("stream", description="传输方式(stream/multipart)")
|
||
multipart_part_size: int | None = Field(default=None, description="分片大小(MB)")
|
||
multipart_concurrency: int | None = Field(default=None, description="分片并发数")
|
||
|
||
|
||
class WorkflowCreateSchema(BaseModel):
|
||
"""创建传输流程(画布驱动:业务配置解析后落 flow_node/flow_edge 表)"""
|
||
|
||
name: str = Field(..., min_length=1, max_length=64, description="流程名称")
|
||
task_type: WorkflowTaskType = Field("parallel", description="类型(parallel:多目标 chain:链式)")
|
||
graph: dict = Field(..., description="VueFlow画布数据 {nodes:[{id,type,position,data}],edges:[{id,source,target,data}]}")
|
||
status: int = Field(default=0, ge=0, le=1, description="状态(0:启用 1:停用)")
|
||
description: str | None = Field(default=None, max_length=255, description="备注")
|
||
|
||
@field_validator("name")
|
||
@classmethod
|
||
def validate_name(cls, value: str) -> str:
|
||
value = value.strip()
|
||
if not value:
|
||
raise ValueError("流程名称不能为空")
|
||
return value
|
||
|
||
@model_validator(mode="after")
|
||
def validate_graph(self):
|
||
"""画布必须包含传输连线(源节点 → 目标节点)。"""
|
||
if not self.graph or not self.graph.get("edges"):
|
||
raise ValueError("请至少添加一条传输连线(源节点 → 目标节点)")
|
||
return self
|
||
|
||
|
||
class WorkflowUpdateSchema(WorkflowCreateSchema):
|
||
"""更新传输流程"""
|
||
|
||
|
||
class WorkflowExecuteSchema(BaseModel):
|
||
"""执行传输流程参数"""
|
||
|
||
source_paths: dict[str, str] | None = Field(
|
||
default=None,
|
||
description="源文件/目录路径映射 {源存储源ID: 路径},执行时必须为每条连线的源存储源指定",
|
||
)
|
||
|
||
|
||
class WorkflowOutSchema(BaseSchema, UserBySchema):
|
||
"""传输流程详情响应模型(sources/targets 由 service 从明细表派生)"""
|
||
|
||
model_config = ConfigDict(from_attributes=True)
|
||
|
||
name: str | None = None
|
||
task_type: WorkflowTaskType = "parallel"
|
||
sources: list[WorkflowSourceSchema] = Field(default_factory=list, description="源节点列表(由画布派生)")
|
||
targets: list[WorkflowTargetSchema] = Field(default_factory=list)
|
||
graph: dict | None = None
|
||
graph_stats: dict | None = None
|
||
status: int = 0
|
||
description: str | None = None
|
||
|
||
|
||
class WorkflowQueryParam(BaseQueryParam, UserByQueryParam):
|
||
"""传输流程查询参数"""
|
||
|
||
name: str | None = Field(None, description="流程名称", json_schema_extra={"q": "like"})
|
||
task_type: WorkflowTaskType | None = Field(None, description="类型(parallel/chain)", json_schema_extra={"q": "eq"})
|
||
status: int | None = Field(None, ge=0, le=1, description="状态(0:启用 1:停用)", json_schema_extra={"q": "eq"})
|