from datetime import datetime from typing import Annotated, Literal from pydantic import BaseModel, ConfigDict, Field, field_validator from pydantic.alias_generators import to_camel PositiveId = Annotated[int, Field(gt=0)] def _ensure_unique_ids(value: list[int]) -> list[int]: if len(value) != len(set(value)): raise ValueError('ID列表不能包含重复项') return value class StrainModel(BaseModel): """菌种主数据写入及展示模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) strain_id: int | None = Field(default=None, gt=0, description='菌种ID') strain_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='菌种编码') strain_name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='菌种名称') status: Literal['0', '1'] = Field(default='0', description='状态(0正常 1停用)') create_by: str | None = Field(default=None, max_length=64, description='创建者') create_time: datetime | None = Field(default=None, description='创建时间') update_by: str | None = Field(default=None, max_length=64, description='更新者') update_time: datetime | None = Field(default=None, description='更新时间') remark: str | None = Field(default=None, max_length=500, description='备注') class StrainPageQueryModel(BaseModel): """菌种分页查询模型。""" model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True) page_num: int = Field(default=1, gt=0, description='当前页码') page_size: int = Field(default=10, gt=0, le=100, description='每页记录数') strain_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='菌种编码') strain_name: str | None = Field( default=None, min_length=1, max_length=100, pattern=r'\S', description='菌种名称', ) status: Literal['0', '1'] | None = Field(default=None, description='状态') class DeleteStrainModel(BaseModel): """删除菌种模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) strain_ids: list[PositiveId] = Field(min_length=1, description='需要删除的菌种ID') _validate_unique_ids = field_validator('strain_ids')(_ensure_unique_ids) class CustomerModel(BaseModel): """客户主数据写入及展示模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) customer_id: int | None = Field(default=None, gt=0, description='客户ID') customer_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='客户编码') customer_name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='客户名称') status: Literal['0', '1'] = Field(default='0', description='状态(0正常 1停用)') create_by: str | None = Field(default=None, max_length=64, description='创建者') create_time: datetime | None = Field(default=None, description='创建时间') update_by: str | None = Field(default=None, max_length=64, description='更新者') update_time: datetime | None = Field(default=None, description='更新时间') remark: str | None = Field(default=None, max_length=500, description='备注') class CustomerPageQueryModel(BaseModel): """客户分页查询模型。""" model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True) page_num: int = Field(default=1, gt=0, description='当前页码') page_size: int = Field(default=10, gt=0, le=100, description='每页记录数') customer_code: str | None = Field( default=None, min_length=1, max_length=64, pattern=r'\S', description='客户编码', ) customer_name: str | None = Field( default=None, min_length=1, max_length=100, pattern=r'\S', description='客户名称', ) status: Literal['0', '1'] | None = Field(default=None, description='状态') class DeleteCustomerModel(BaseModel): """删除客户模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) customer_ids: list[PositiveId] = Field(min_length=1, description='需要删除的客户ID') _validate_unique_ids = field_validator('customer_ids')(_ensure_unique_ids) class SiteModel(BaseModel): """客户现场主数据写入及展示模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) site_id: int | None = Field(default=None, gt=0, description='现场ID') customer_id: int = Field(gt=0, description='客户ID') site_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='现场编码') site_name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='现场名称') address: str | None = Field(default=None, max_length=500, description='现场地址') status: Literal['0', '1'] = Field(default='0', description='状态(0正常 1停用)') create_by: str | None = Field(default=None, max_length=64, description='创建者') create_time: datetime | None = Field(default=None, description='创建时间') update_by: str | None = Field(default=None, max_length=64, description='更新者') update_time: datetime | None = Field(default=None, description='更新时间') remark: str | None = Field(default=None, max_length=500, description='备注') class SitePageQueryModel(BaseModel): """客户现场分页查询模型。""" model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True) page_num: int = Field(default=1, gt=0, description='当前页码') page_size: int = Field(default=10, gt=0, le=100, description='每页记录数') customer_id: int | None = Field(default=None, gt=0, description='客户ID') site_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='现场编码') site_name: str | None = Field( default=None, min_length=1, max_length=100, pattern=r'\S', description='现场名称', ) status: Literal['0', '1'] | None = Field(default=None, description='状态') class DeleteSiteModel(BaseModel): """删除客户现场模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) site_ids: list[PositiveId] = Field(min_length=1, description='需要删除的现场ID') _validate_unique_ids = field_validator('site_ids')(_ensure_unique_ids) class LineModel(BaseModel): """生产线主数据写入及展示模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) line_id: int | None = Field(default=None, gt=0, description='产线ID') site_id: int = Field(gt=0, description='现场ID') line_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='产线编码') line_name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='产线名称') status: Literal['0', '1'] = Field(default='0', description='状态(0正常 1停用)') create_by: str | None = Field(default=None, max_length=64, description='创建者') create_time: datetime | None = Field(default=None, description='创建时间') update_by: str | None = Field(default=None, max_length=64, description='更新者') update_time: datetime | None = Field(default=None, description='更新时间') remark: str | None = Field(default=None, max_length=500, description='备注') class LinePageQueryModel(BaseModel): """生产线分页查询模型。""" model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True) page_num: int = Field(default=1, gt=0, description='当前页码') page_size: int = Field(default=10, gt=0, le=100, description='每页记录数') site_id: int | None = Field(default=None, gt=0, description='现场ID') line_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='产线编码') line_name: str | None = Field( default=None, min_length=1, max_length=100, pattern=r'\S', description='产线名称', ) status: Literal['0', '1'] | None = Field(default=None, description='状态') class DeleteLineModel(BaseModel): """删除生产线模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) line_ids: list[PositiveId] = Field(min_length=1, description='需要删除的产线ID') _validate_unique_ids = field_validator('line_ids')(_ensure_unique_ids) class TunnelModel(BaseModel): """隧道主数据写入及展示模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) tunnel_id: int | None = Field(default=None, gt=0, description='隧道ID') site_id: int = Field(gt=0, description='现场ID') tunnel_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='隧道编号') tunnel_name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='隧道名称') status: Literal['0', '1'] = Field(default='0', description='状态(0正常 1停用)') current_trace_no: str | None = Field(default=None, max_length=64, description='当前物料溯源号') current_trace_started_at: datetime | None = Field(default=None, description='当前溯源批次开始时间') create_by: str | None = Field(default=None, max_length=64, description='创建者') create_time: datetime | None = Field(default=None, description='创建时间') update_by: str | None = Field(default=None, max_length=64, description='更新者') update_time: datetime | None = Field(default=None, description='更新时间') remark: str | None = Field(default=None, max_length=500, description='备注') class TunnelPageQueryModel(BaseModel): """隧道分页查询模型。""" model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True) page_num: int = Field(default=1, gt=0, description='当前页码') page_size: int = Field(default=10, gt=0, le=100, description='每页记录数') site_id: int | None = Field(default=None, gt=0, description='现场ID') tunnel_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='隧道编号') tunnel_name: str | None = Field( default=None, min_length=1, max_length=100, pattern=r'\S', description='隧道名称', ) status: Literal['0', '1'] | None = Field(default=None, description='状态') class DeleteTunnelModel(BaseModel): """删除隧道模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) tunnel_ids: list[PositiveId] = Field(min_length=1, description='需要删除的隧道ID') _validate_unique_ids = field_validator('tunnel_ids')(_ensure_unique_ids) class WarehouseModel(BaseModel): """仓库主数据写入及展示模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) warehouse_id: int | None = Field(default=None, gt=0, description='仓库ID') warehouse_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='仓库编码') warehouse_name: str = Field(min_length=1, max_length=100, pattern=r'\S', description='仓库名称') address: str | None = Field(default=None, max_length=500, description='仓库地址') status: Literal['0', '1'] = Field(default='0', description='状态(0正常 1停用)') create_by: str | None = Field(default=None, max_length=64, description='创建者') create_time: datetime | None = Field(default=None, description='创建时间') update_by: str | None = Field(default=None, max_length=64, description='更新者') update_time: datetime | None = Field(default=None, description='更新时间') remark: str | None = Field(default=None, max_length=500, description='备注') class WarehousePageQueryModel(BaseModel): """仓库分页查询模型。""" model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True) page_num: int = Field(default=1, gt=0, description='当前页码') page_size: int = Field(default=10, gt=0, le=100, description='每页记录数') warehouse_code: str | None = Field( default=None, min_length=1, max_length=64, pattern=r'\S', description='仓库编码', ) warehouse_name: str | None = Field( default=None, min_length=1, max_length=100, pattern=r'\S', description='仓库名称', ) status: Literal['0', '1'] | None = Field(default=None, description='状态') class DeleteWarehouseModel(BaseModel): """删除仓库模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) warehouse_ids: list[PositiveId] = Field(min_length=1, description='需要删除的仓库ID') _validate_unique_ids = field_validator('warehouse_ids')(_ensure_unique_ids) class PalletModel(BaseModel): """托盘资产展示模型。""" model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True) pallet_id: int = Field(gt=0, description='托盘ID') pallet_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='托盘编号') qr_token: str = Field(min_length=1, max_length=128, pattern=r'\S', description='二维码固定标识') capacity_packages: int = Field(strict=True, gt=0, description='容量包数') asset_status: Literal['0', '1'] = Field(description='资产状态(0正常 1停用)') remark: str | None = Field(default=None, max_length=500, description='备注') create_by: str | None = Field(default=None, max_length=64, description='创建者') create_time: datetime | None = Field(default=None, description='创建时间') update_by: str | None = Field(default=None, max_length=64, description='更新者') update_time: datetime | None = Field(default=None, description='更新时间') class PalletCreateModel(BaseModel): """新增托盘模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) pallet_code: str = Field(min_length=1, max_length=64, pattern=r'\S', description='托盘编号') capacity_packages: Literal[100] = Field(description='容量包数(固定 100 包)') remark: str | None = Field(default=None, max_length=500, description='备注') class PalletEditModel(BaseModel): """编辑托盘可变属性模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) pallet_id: int = Field(gt=0, description='托盘ID') capacity_packages: int = Field(strict=True, gt=0, description='容量包数') asset_status: Literal['0', '1'] = Field(description='资产状态(0正常 1停用)') remark: str | None = Field(default=None, max_length=500, description='备注') class PalletPageQueryModel(BaseModel): """托盘分页查询模型。""" model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True) page_num: int = Field(default=1, gt=0, description='当前页码') page_size: int = Field(default=10, gt=0, le=100, description='每页记录数') pallet_code: str | None = Field(default=None, min_length=1, max_length=64, pattern=r'\S', description='托盘编号') asset_status: Literal['0', '1'] | None = Field(default=None, description='资产状态') class DeletePalletModel(BaseModel): """删除托盘模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) pallet_ids: list[PositiveId] = Field(min_length=1, description='需要删除的托盘ID') _validate_unique_ids = field_validator('pallet_ids')(_ensure_unique_ids) class UserAssignModel(BaseModel): """用户数据范围分配模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) user_ids: list[PositiveId] = Field(description='用户ID列表') _validate_unique_ids = field_validator('user_ids')(_ensure_unique_ids) class BusinessUserOptionModel(BaseModel): """仓库或客户现场可分配用户的最小只读模型。""" model_config = ConfigDict( alias_generator=to_camel, from_attributes=True, populate_by_name=True, extra='forbid', ) user_id: PositiveId = Field(description='用户ID') user_name: str = Field(min_length=1, max_length=30, pattern=r'\S', description='用户账号') nick_name: str | None = Field(default=None, max_length=30, description='用户昵称') assigned: bool = Field(description='是否已分配')