feat(workbench): persist operational workflows and events

This commit is contained in:
2026-09-24 04:19:02 +08:00
parent baff7dfe9e
commit 9335bdc1ea
66 changed files with 16580 additions and 238 deletions
+42 -1
View File
@@ -5,6 +5,7 @@ from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictFloat, StrictInt, model_validator
from app.domain.schemas.shared import ObjectRef, TimeRange, WireDateTime
from app.domain.schemas.workbench_runtime import WorkbenchRuntimeWorkOrderSubtask
Text = Annotated[str, Field(min_length=1, max_length=4000)]
PositiveInt = Annotated[StrictInt, Field(ge=1)]
@@ -116,8 +117,21 @@ class TaskPage(Model):
next_cursor: UUID | None
WorkOrderStatus = Literal["draft", "open", "in_progress", "completed", "cancelled"]
WorkOrderStatus = Literal[
"draft", "open", "in_progress", "awaiting_reply", "completed", "cancelled"
]
Priority = Literal["low", "normal", "high", "urgent"]
WorkOrderType = Literal["general", "water_quality_complaint", "burst_report"]
WorkOrderSubtasks = Annotated[
list[WorkbenchRuntimeWorkOrderSubtask], Field(min_length=1, max_length=50)
]
def _validate_unique_subtasks(
subtasks: list[WorkbenchRuntimeWorkOrderSubtask] | None,
) -> None:
if subtasks is not None and len({item.id for item in subtasks}) != len(subtasks):
raise ValueError("work order subtask ids must be unique")
class CreateWorkOrder(Model):
@@ -128,11 +142,16 @@ class CreateWorkOrder(Model):
priority: Priority = "normal"
assignee: Annotated[str, Field(min_length=1, max_length=200)] | None = None
scheduled_at: WireDateTime | None = None
work_order_type: WorkOrderType = "general"
location: Annotated[str, Field(min_length=1, max_length=200)] | None = None
scenario_code: Annotated[str, Field(min_length=1, max_length=128)] | None = None
subtasks: WorkOrderSubtasks | None = None
@model_validator(mode="after")
def aware_schedule(self):
if self.scheduled_at is not None and self.scheduled_at.tzinfo is None:
raise ValueError("scheduled_at must include timezone")
_validate_unique_subtasks(self.subtasks)
return self
@@ -147,6 +166,12 @@ class UpdateWorkOrder(Model):
clear_assignee: StrictBool = False
scheduled_at: WireDateTime | None = None
clear_scheduled_at: StrictBool = False
location: Annotated[str, Field(min_length=1, max_length=200)] | None = None
clear_location: StrictBool = False
scenario_code: Annotated[str, Field(min_length=1, max_length=128)] | None = None
clear_scenario_code: StrictBool = False
subtasks: WorkOrderSubtasks | None = None
clear_subtasks: StrictBool = False
@model_validator(mode="after")
def valid_update(self):
@@ -157,8 +182,15 @@ class UpdateWorkOrder(Model):
raise ValueError("clear_assignee conflicts with assignee")
if self.clear_scheduled_at and self.scheduled_at is not None:
raise ValueError("clear_scheduled_at conflicts with scheduled_at")
if self.clear_location and self.location is not None:
raise ValueError("clear_location conflicts with location")
if self.clear_scenario_code and self.scenario_code is not None:
raise ValueError("clear_scenario_code conflicts with scenario_code")
if self.clear_subtasks and self.subtasks is not None:
raise ValueError("clear_subtasks conflicts with subtasks")
if self.scheduled_at is not None and self.scheduled_at.tzinfo is None:
raise ValueError("scheduled_at must include timezone")
_validate_unique_subtasks(self.subtasks)
return self
@@ -182,6 +214,15 @@ class WorkOrder(Model):
updated_at: WireDateTime
created_by: str
updated_by: str
work_order_type: WorkOrderType = "general"
location: str | None = None
scenario_code: str | None = None
subtasks: WorkOrderSubtasks | None = None
@model_validator(mode="after")
def unique_subtasks(self):
_validate_unique_subtasks(self.subtasks)
return self
class WorkOrderPage(Model):