"""计提公式模板的请求/响应模型。""" import re from pydantic import BaseModel, ConfigDict, Field, field_validator # 模板编码与历史 TPL_ 编码一致:大写字母开头,大写字母/数字/下划线,3–32 位。 TEMPLATE_CODE_PATTERN = re.compile(r"^[A-Z][A-Z0-9_]{2,31}$") class TemplateParamOut(BaseModel): """模板骨架参数角色映射(角色 → 参数编码)。""" role: str param_code: str class CalcTemplateOut(BaseModel): """模板列表/详情响应。""" model_config = ConfigDict(from_attributes=True) id: int template_code: str template_name: str formula_type: str params: dict[str, str] description: str | None = None sort_order: int = 0 status: int = 1 is_system: int = 0 role_count: int = 0 class CalcTemplateOptionOut(BaseModel): """岗位表单下拉项(仅启用模板,含骨架与参数绑定说明)。""" code: str name: str formula_type: str description: str params: list[TemplateParamOut] class FormulaOptionOut(BaseModel): """公式骨架下拉项(新增模板时选择,受控集合)。""" code: str name: str description: str roles: list[str] class CalcTemplateCreateIn(BaseModel): """新增模板。编码与骨架创建后不可修改。""" model_config = ConfigDict(str_strip_whitespace=True) template_code: str = Field(min_length=3, max_length=32, description="模板编码,创建后不可修改") template_name: str = Field(min_length=1, max_length=64, description="模板名称") formula_type: str = Field(min_length=1, max_length=32, description="公式骨架类型") params: dict[str, str] = Field(default_factory=dict, description="骨架参数角色到参数编码映射") description: str | None = Field(default=None, max_length=255) sort_order: int = Field(default=0, ge=0) @field_validator("template_code") @classmethod def _check_code(cls, value: str) -> str: if not TEMPLATE_CODE_PATTERN.match(value): raise ValueError("模板编码须以大写字母开头,仅可含大写字母、数字与下划线") return value class CalcTemplateUpdateIn(BaseModel): """编辑模板。编码与骨架锁定;参数绑定仍按骨架角色校验。""" model_config = ConfigDict(str_strip_whitespace=True) template_name: str = Field(min_length=1, max_length=64) params: dict[str, str] = Field(default_factory=dict) description: str | None = Field(default=None, max_length=255) sort_order: int = Field(default=0, ge=0)