Files
shanxia2.0/backend/app/schemas/pl/resource_snapshot.py
T
2026-06-30 23:44:22 +08:00

94 lines
3.7 KiB
Python

"""运输计划 - 安排运输时车辆/人员/证件资源快照 Schema"""
from __future__ import annotations
from datetime import date, datetime
from decimal import Decimal
from typing import Any, Optional
from pydantic import BaseModel, Field, field_validator
class SnapshotCertRead(BaseModel):
"""证书快照(车辆主车/挂车、人员证件)"""
id: str
cert_id: Optional[str] = Field(default=None, alias="certId")
vehicle_part: Optional[str] = Field(default=None, alias="vehiclePart")
cert_name: str = Field(alias="certName")
cert_no: Optional[str] = Field(default=None, alias="certNo")
expire_date: Optional[date] = Field(default=None, alias="expireDate")
remind_days: int = Field(default=30, alias="remindDays")
attachment_urls: Optional[str] = Field(default=None, alias="attachmentUrls")
owner_type: Optional[str] = Field(default=None, alias="ownerType")
owner_id: Optional[str] = Field(default=None, alias="ownerId")
status: Optional[str] = None
model_config = {"populate_by_name": True}
class SnapshotPersonnelRow(BaseModel):
"""车辆关联人员快照(含人员证件)"""
personnel_id: Optional[str] = Field(default=None, alias="personnelId")
personnel_name: str = Field(alias="personnelName")
phone_no: Optional[str] = Field(default=None, alias="phoneNo")
age: Optional[int] = None
id_card_no: Optional[str] = Field(default=None, alias="idCardNo")
role: str
is_default: int = Field(default=0, alias="isDefault")
remark: Optional[str] = None
cert_list: list[SnapshotCertRead] = Field(default_factory=list, alias="certList")
model_config = {"populate_by_name": True}
class TransportResourceSnapshot(BaseModel):
"""安排运输时的车辆+人员+证件整包快照"""
snapshotted_at: datetime = Field(alias="snapshottedAt")
vehicle_id: str = Field(alias="vehicleId")
vehicle_type: str = Field(alias="vehicleType")
carrier_id: Optional[str] = Field(default=None, alias="carrierId")
carrier_name: Optional[str] = Field(default=None, alias="carrierName")
license_plate: str = Field(alias="licensePlate")
trailer_no: Optional[str] = Field(default=None, alias="trailerNo")
load_capacity: Optional[Decimal] = Field(default=None, alias="loadCapacity")
vehicle_status: str = Field(alias="vehicleStatus")
cert_list: list[SnapshotCertRead] = Field(default_factory=list, alias="certList")
personnel_list: list[SnapshotPersonnelRow] = Field(default_factory=list, alias="personnelList")
personnel_summary: Optional[str] = Field(default=None, alias="personnelSummary")
selected_driver_id: Optional[str] = Field(default=None, alias="selectedDriverId")
model_config = {"populate_by_name": True}
def parse_resource_snapshot(raw: Any) -> Optional[TransportResourceSnapshot]:
"""从 ORM 文本列或 dict 解析快照。"""
if raw is None:
return None
if isinstance(raw, TransportResourceSnapshot):
return raw
if isinstance(raw, str):
text = raw.strip()
if not text:
return None
return TransportResourceSnapshot.model_validate_json(text)
if isinstance(raw, dict):
return TransportResourceSnapshot.model_validate(raw)
return None
class PlanResourceSnapshotMixin(BaseModel):
trailer_no: Optional[str] = Field(default=None, alias="trailerNo")
resource_snapshot: Optional[TransportResourceSnapshot] = Field(
default=None, alias="resourceSnapshot"
)
model_config = {"populate_by_name": True}
@field_validator("resource_snapshot", mode="before")
@classmethod
def _coerce_resource_snapshot(cls, value: Any) -> Any:
parsed = parse_resource_snapshot(value)
return parsed.model_dump(by_alias=True) if parsed else None