feat(schemas): 更新 Pydantic Schema,新增请求/响应模型
Task Schema 更新: - TaskResponse/TaskSummaryResponse 新增 is_rework, reject_reason, received_at, completed_at 字段 - 新增 TaskRejectRequest (品质驳回请求, reason 必填) - 新增 TaskTransferRequest (裂变转交请求, next_assignees + next_task_name 必填) - 新增 TaskTransferResponse (裂变转交响应) - TaskCreate 新增 is_rework 字段 Product Schema 更新: - ProductResponse/ProductScanResponse 新增 current_location_id 字段 - ProductScanResponse 新增 task_tree 字段 (递归任务树,供十字矩阵树状图)
This commit is contained in:
@ -0,0 +1,45 @@
|
|||||||
|
"""Pydantic Schemas — 请求/响应数据模型"""
|
||||||
|
from app.schemas.product import (
|
||||||
|
ProductCreate,
|
||||||
|
ProductUpdate,
|
||||||
|
ProductResponse,
|
||||||
|
ProductScanResponse,
|
||||||
|
)
|
||||||
|
from app.schemas.task import (
|
||||||
|
TaskCreate,
|
||||||
|
TaskUpdate,
|
||||||
|
TaskCompleteRequest,
|
||||||
|
TaskRejectRequest,
|
||||||
|
TaskTransferRequest,
|
||||||
|
SubtaskCreate,
|
||||||
|
TaskSummaryResponse,
|
||||||
|
TaskResponse,
|
||||||
|
TaskCompleteResponse,
|
||||||
|
TaskTransferResponse,
|
||||||
|
TaskListResponse,
|
||||||
|
)
|
||||||
|
from app.schemas.task_log import (
|
||||||
|
TaskLogResponse,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
# Product
|
||||||
|
"ProductCreate",
|
||||||
|
"ProductUpdate",
|
||||||
|
"ProductResponse",
|
||||||
|
"ProductScanResponse",
|
||||||
|
# Task
|
||||||
|
"TaskCreate",
|
||||||
|
"TaskUpdate",
|
||||||
|
"TaskCompleteRequest",
|
||||||
|
"TaskRejectRequest",
|
||||||
|
"TaskTransferRequest",
|
||||||
|
"SubtaskCreate",
|
||||||
|
"TaskSummaryResponse",
|
||||||
|
"TaskResponse",
|
||||||
|
"TaskCompleteResponse",
|
||||||
|
"TaskTransferResponse",
|
||||||
|
"TaskListResponse",
|
||||||
|
# TaskLog
|
||||||
|
"TaskLogResponse",
|
||||||
|
]
|
||||||
|
|||||||
61
backend/app/schemas/product.py
Normal file
61
backend/app/schemas/product.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
"""产品 Pydantic Schemas"""
|
||||||
|
from __future__ import annotations
|
||||||
|
import uuid
|
||||||
|
from datetime import datetime
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class ProductCreate(BaseModel):
|
||||||
|
"""创建产品"""
|
||||||
|
serial_number: str = Field(..., min_length=16, max_length=16, description="产品序列号(16位)")
|
||||||
|
order_id: uuid.UUID = Field(..., description="所属订单ID")
|
||||||
|
material_id: str | None = Field(None, max_length=64, description="物料ID(逻辑外键→老系统)")
|
||||||
|
parent_product_id: uuid.UUID | None = Field(None, description="父产品ID")
|
||||||
|
|
||||||
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
class ProductUpdate(BaseModel):
|
||||||
|
"""更新产品"""
|
||||||
|
serial_number: str | None = Field(None, min_length=16, max_length=16)
|
||||||
|
material_id: str | None = Field(None, max_length=64)
|
||||||
|
status: str | None = Field(None, max_length=50, description="产品状态")
|
||||||
|
parent_product_id: uuid.UUID | None = Field(None)
|
||||||
|
|
||||||
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
class ProductResponse(BaseModel):
|
||||||
|
"""产品响应"""
|
||||||
|
id: uuid.UUID
|
||||||
|
serial_number: str
|
||||||
|
order_id: uuid.UUID
|
||||||
|
material_id: str | None
|
||||||
|
parent_product_id: uuid.UUID | None
|
||||||
|
current_location_id: str | None = None
|
||||||
|
status: str
|
||||||
|
created_at: datetime
|
||||||
|
|
||||||
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
class ProductScanResponse(BaseModel):
|
||||||
|
"""扫码查询响应 — 产品信息 + 完整任务树(递归嵌套)"""
|
||||||
|
id: uuid.UUID
|
||||||
|
serial_number: str
|
||||||
|
order_id: uuid.UUID
|
||||||
|
order_no: str = ""
|
||||||
|
material_id: str | None
|
||||||
|
parent_product_id: uuid.UUID | None
|
||||||
|
current_location_id: str | None = None
|
||||||
|
status: str
|
||||||
|
created_at: datetime
|
||||||
|
top_level_tasks: list[TaskSummaryResponse] = []
|
||||||
|
task_tree: list[TaskResponse] = []
|
||||||
|
|
||||||
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
# 延迟导入,避免循环引用 — TaskSummaryResponse 在 tasks.py 中定义
|
||||||
|
from app.schemas.task import TaskSummaryResponse # noqa: E402
|
||||||
|
ProductScanResponse.model_rebuild()
|
||||||
120
backend/app/schemas/task.py
Normal file
120
backend/app/schemas/task.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
"""任务 Pydantic Schemas — 支持无限嵌套子任务、裂变转交、驳回返工"""
|
||||||
|
from __future__ import annotations
|
||||||
|
import uuid
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 请求模型
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
class TaskCreate(BaseModel):
|
||||||
|
"""创建任务"""
|
||||||
|
product_id: uuid.UUID = Field(..., description="所属产品ID")
|
||||||
|
parent_task_id: uuid.UUID | None = Field(None, description="父任务ID(用于嵌套子任务/裂变分支)")
|
||||||
|
task_name: str = Field(..., max_length=200, description="任务名称")
|
||||||
|
assignee_id: str | None = Field(None, max_length=64, description="负责人ID(逻辑外键→老系统)")
|
||||||
|
notify_parent_on_complete: bool = Field(False, description="完成后是否通知父任务")
|
||||||
|
is_rework: bool = Field(False, description="是否为返工任务")
|
||||||
|
|
||||||
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
class TaskUpdate(BaseModel):
|
||||||
|
"""更新任务"""
|
||||||
|
task_name: str | None = Field(None, max_length=200)
|
||||||
|
assignee_id: str | None = Field(None, max_length=64)
|
||||||
|
status: str | None = Field(None, max_length=50, description="任务状态")
|
||||||
|
notify_parent_on_complete: bool | None = Field(None)
|
||||||
|
|
||||||
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
class TaskCompleteRequest(BaseModel):
|
||||||
|
"""完成任务请求 — 携带转交信息(保留兼容旧版单步转交)"""
|
||||||
|
operator_id: str | None = Field(None, max_length=64, description="操作人ID")
|
||||||
|
next_assignee_id: str | None = Field(None, max_length=64, description="下一步任务负责人ID")
|
||||||
|
next_task_name: str | None = Field(None, max_length=200, description="下一步任务名称")
|
||||||
|
remark: str | None = Field(None, description="完成备注")
|
||||||
|
|
||||||
|
|
||||||
|
class SubtaskCreate(BaseModel):
|
||||||
|
"""创建子任务"""
|
||||||
|
task_name: str = Field(..., max_length=200, description="子任务名称")
|
||||||
|
assignee_id: str | None = Field(None, max_length=64, description="负责人ID")
|
||||||
|
notify_parent_on_complete: bool = Field(False, description="完成后是否通知父任务")
|
||||||
|
|
||||||
|
|
||||||
|
class TaskRejectRequest(BaseModel):
|
||||||
|
"""品质驳回请求"""
|
||||||
|
reason: str = Field(..., min_length=1, max_length=500, description="驳回原因(必填)")
|
||||||
|
|
||||||
|
|
||||||
|
class TaskTransferRequest(BaseModel):
|
||||||
|
"""完工裂变转交请求"""
|
||||||
|
next_assignees: list[str] = Field(..., min_length=1, description="下一道工序接收人列表(必填)")
|
||||||
|
next_task_name: str = Field(..., min_length=1, max_length=200, description="下一道工序名称(必填)")
|
||||||
|
note: str | None = Field(None, description="交接备注")
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 响应模型
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
class TaskSummaryResponse(BaseModel):
|
||||||
|
"""任务摘要 — 扫码时用,不含嵌套子任务"""
|
||||||
|
id: uuid.UUID
|
||||||
|
product_id: uuid.UUID
|
||||||
|
parent_task_id: uuid.UUID | None
|
||||||
|
task_name: str
|
||||||
|
assignee_id: str | None
|
||||||
|
status: str
|
||||||
|
notify_parent_on_complete: bool
|
||||||
|
is_rework: bool = False
|
||||||
|
reject_reason: str | None = None
|
||||||
|
received_at: datetime | None = None
|
||||||
|
completed_at: datetime | None = None
|
||||||
|
created_at: datetime
|
||||||
|
|
||||||
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
class TaskResponse(BaseModel):
|
||||||
|
"""任务详情响应 — 递归包含所有子任务"""
|
||||||
|
id: uuid.UUID
|
||||||
|
product_id: uuid.UUID
|
||||||
|
parent_task_id: uuid.UUID | None
|
||||||
|
task_name: str
|
||||||
|
assignee_id: str | None
|
||||||
|
status: str
|
||||||
|
notify_parent_on_complete: bool
|
||||||
|
is_rework: bool = False
|
||||||
|
reject_reason: str | None = None
|
||||||
|
received_at: datetime | None = None
|
||||||
|
completed_at: datetime | None = None
|
||||||
|
created_at: datetime
|
||||||
|
child_tasks: list[TaskResponse] = []
|
||||||
|
|
||||||
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
class TaskCompleteResponse(BaseModel):
|
||||||
|
"""任务完成响应"""
|
||||||
|
completed_task: TaskResponse
|
||||||
|
next_task: TaskResponse | None = None
|
||||||
|
message: str
|
||||||
|
|
||||||
|
|
||||||
|
class TaskTransferResponse(BaseModel):
|
||||||
|
"""裂变转交响应"""
|
||||||
|
completed_task: TaskResponse
|
||||||
|
created_tasks: list[TaskResponse] = []
|
||||||
|
message: str
|
||||||
|
|
||||||
|
|
||||||
|
class TaskListResponse(BaseModel):
|
||||||
|
"""任务列表响应"""
|
||||||
|
tasks: list[TaskResponse]
|
||||||
|
total: int
|
||||||
Reference in New Issue
Block a user