"""精确更新组件名称,或 props / style 下的一个字段""" from typing import Annotated, Literal, Self from pydantic import Field, JsonValue, model_validator from app.schemas.base import NonBlankString from .base import BaseAction PathSegment = NonBlankString | Annotated[int, Field(ge=0)] class UpdateAction(BaseAction): """替换组件的一个字段,不做深度合并;组件中还没有的中间对象由后端补齐。位置和尺寸用 move / resize,不用 update""" type: Literal["update"] = "update" section: Literal["name", "props", "style"] = Field( description="字段路径的第一段:name 为组件名称,props / style 为组件属性区域" ) path: list[PathSegment] = Field( description='字段路径第一段之后的各段,字符串为对象键,整数为数组下标;name 没有后续路径,传空列表。例如字段 props.option.title.text 写成 section=props、path=["option", "title", "text"]' ) value: JsonValue = Field(description="替换该字段的值,必须符合字段定义的类型和取值") @model_validator(mode="after") def path_matches_section(self) -> Self: if (self.section == "name") != (not self.path): raise ValueError("section 为 name 时 path 为空,props / style 至少一段路径") return self @property def field_path(self) -> str: """与物料字段定义一致的点路径,例如 props.option.title.text""" return ".".join([self.section, *map(str, self.path)])