From 817be6b036ba689363e127037df1fd2eea2040f6 Mon Sep 17 00:00:00 2001 From: duxingchen Date: Tue, 4 Aug 2026 17:03:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(models):=20=E6=89=A9=E5=85=85=20Task=20?= =?UTF-8?q?=E5=92=8C=20Product=20=E6=95=B0=E6=8D=AE=E5=BA=93=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task 模型新增: - received_at: DateTime (操作员确认接收时间) - completed_at: DateTime (任务完工转交时间) - reject_reason: String(500) (驳回原因) - is_rework: Boolean (是否为返工任务,默认 False) - 状态常量: PENDING/WIP/COMPLETED/REJECTED/ARCHIVED - 默认状态由 'pending' 升为大写 'PENDING' Product 模型新增: - current_location_id: String(64) (当前持有者ID 或 'virtual_warehouse') --- backend/app/models/product.py | 5 +++++ backend/app/models/task.py | 31 +++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/backend/app/models/product.py b/backend/app/models/product.py index 6c9b79d..2e1ba1f 100644 --- a/backend/app/models/product.py +++ b/backend/app/models/product.py @@ -33,6 +33,11 @@ class Product(Base): UUID(as_uuid=True), ForeignKey("products.id"), nullable=True, comment="父产品ID", ) + # ---- 当前位置追踪(逻辑外键→用户ID 或 'virtual_warehouse') ---- + current_location_id: Mapped[str | None] = mapped_column( + String(64), nullable=True, comment="当前持有者ID 或 'virtual_warehouse'(仓库)", + ) + status: Mapped[str] = mapped_column( String(50), nullable=False, default="pending", comment="产品状态", ) diff --git a/backend/app/models/task.py b/backend/app/models/task.py index dc18988..b6df1bd 100644 --- a/backend/app/models/task.py +++ b/backend/app/models/task.py @@ -1,4 +1,4 @@ -"""任务模型 — 支持无限嵌套""" +"""任务模型 — 支持无限嵌套、任务裂变分支、返工闭环""" import uuid from datetime import datetime, timezone from sqlalchemy import String, DateTime, Boolean, ForeignKey @@ -7,6 +7,13 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship from app.models.base import Base +# 任务状态常量 +TASK_STATUS_PENDING = "PENDING" # 待接收 +TASK_STATUS_WIP = "WIP" # 进行中 +TASK_STATUS_COMPLETED = "COMPLETED" # 已完成 +TASK_STATUS_REJECTED = "REJECTED" # 已驳回 +TASK_STATUS_ARCHIVED = "ARCHIVED" # 已入库 + class Task(Base): __tablename__ = "tasks" @@ -20,9 +27,9 @@ class Task(Base): UUID(as_uuid=True), ForeignKey("products.id"), nullable=False, comment="所属产品ID", ) - # ---- 物理外键(自引用:无限嵌套父子任务) ---- + # ---- 物理外键(自引用:无限嵌套父子任务 / 裂变分支) ---- parent_task_id: Mapped[uuid.UUID | None] = mapped_column( - UUID(as_uuid=True), ForeignKey("tasks.id"), nullable=True, index=True, comment="父任务ID", + UUID(as_uuid=True), ForeignKey("tasks.id"), nullable=True, index=True, comment="父任务ID(用于任务裂变树)", ) task_name: Mapped[str] = mapped_column( @@ -35,16 +42,32 @@ class Task(Base): ) status: Mapped[str] = mapped_column( - String(50), nullable=False, default="pending", comment="任务状态", + String(50), nullable=False, default=TASK_STATUS_PENDING, + comment="任务状态: PENDING(待接收) | WIP(进行中) | COMPLETED(已完成) | REJECTED(已驳回) | ARCHIVED(已入库)", ) notify_parent_on_complete: Mapped[bool] = mapped_column( Boolean, default=False, comment="完成后是否通知父任务", ) + # ---- 时间追踪 ---- created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), comment="创建时间", ) + received_at: Mapped[datetime | None] = mapped_column( + DateTime(timezone=True), nullable=True, comment="操作员确认接收时间", + ) + completed_at: Mapped[datetime | None] = mapped_column( + DateTime(timezone=True), nullable=True, comment="任务完工转交时间", + ) + + # ---- 驳回/返工 ---- + reject_reason: Mapped[str | None] = mapped_column( + String(500), nullable=True, comment="驳回原因", + ) + is_rework: Mapped[bool] = mapped_column( + Boolean, default=False, comment="是否为返工任务", + ) # ---- 关系 ---- product: Mapped["Product"] = relationship("Product", lazy="selectin")