feat: 添加 Action 协议

This commit is contained in:
2026-09-23 15:33:28 +08:00
parent f0d33ff058
commit 5ef873bfe9
14 changed files with 284 additions and 25 deletions
+24
View File
@@ -0,0 +1,24 @@
"""动作类型统一入口,新增操作时在这里显式加入联合类型"""
from typing import Annotated
from pydantic import Field, TypeAdapter
from .base import ActionModel, BaseAction
from .move import MoveAction
from .resize import ResizeAction
from .update import UpdateAction
# 按 type 选择对应模型,不维护重复的操作名称映射
Action = Annotated[MoveAction | ResizeAction | UpdateAction, Field(discriminator="type")]
action_adapter = TypeAdapter(Action)
class ActionBatch(ActionModel):
actions: list[Action] = Field(description="按数组顺序执行的动作列表,允许为空")
__all__ = [
"Action", "ActionBatch", "BaseAction", "MoveAction", "ResizeAction",
"UpdateAction", "action_adapter",
]
+14
View File
@@ -0,0 +1,14 @@
"""动作协议公共字段"""
from pydantic import BaseModel, ConfigDict, Field
from app.schemas.base import NonBlankString
class ActionModel(BaseModel):
# 操作字段显式声明,防止拼写错误被当作扩展字段忽略
model_config = ConfigDict(extra="forbid", strict=True, allow_inf_nan=False)
class BaseAction(ActionModel):
target_id: NonBlankString = Field(description="已有组件的 ID")
+19
View File
@@ -0,0 +1,19 @@
"""按相对位移移动组件"""
from typing import Literal
from pydantic import Field
from app.schemas.screen import Number
from .base import BaseAction
class MoveAction(BaseAction):
type: Literal["move"] = "move"
delta_x: Number = Field(
default=0, description="水平位移,单位 px,正数向右,负数向左"
)
delta_y: Number = Field(
default=0, description="垂直位移,单位 px,正数向下,负数向上"
)
+25
View File
@@ -0,0 +1,25 @@
"""设置组件的绝对尺寸"""
from typing import Literal, Self
from pydantic import Field, model_validator
from app.schemas.screen import PositiveNumber
from .base import BaseAction
class ResizeAction(BaseAction):
type: Literal["resize"] = "resize"
width: PositiveNumber | None = Field(
default=None, description="目标宽度,单位 px,省略或 null 表示保持原值"
)
height: PositiveNumber | None = Field(
default=None, description="目标高度,单位 px,省略或 null 表示保持原值"
)
@model_validator(mode="after")
def require_size(self) -> Self:
if self.width is None and self.height is None:
raise ValueError("resize 至少提供 width 或 height")
return self
+22
View File
@@ -0,0 +1,22 @@
"""精确更新组件 props 或 style 下的一个字段"""
from typing import Annotated, Literal
from pydantic import Field, JsonValue
from app.schemas.base import NonBlankString
from .base import BaseAction
PathSegment = NonBlankString | Annotated[int, Field(ge=0)]
class UpdateAction(BaseAction):
type: Literal["update"] = "update"
section: Literal["props", "style"] = Field(description="允许更新的组件属性区域")
path: list[PathSegment] = Field(
min_length=1, description="区域内的字段路径,字符串为对象键,整数为数组下标"
)
value: JsonValue = Field(
description="替换该路径的值,支持任意 JSON;null 是赋值,不表示删除"
)