"""保存的大屏:存储记录与接口模型。页面本身(PageSchema)按原始 JSON 存取,校验见 app/schemas/screen.py""" from datetime import datetime from typing import Annotated, Any, Literal from pydantic import BaseModel, Field, StringConstraints NAME_MAX_LENGTH = 100 DEFAULT_NAME = "未命名大屏" ScreenName = Annotated[ str, StringConstraints(strip_whitespace=True, min_length=1, max_length=NAME_MAX_LENGTH), ] PublishStatus = Literal["published", "offline"] ListStatus = Literal["draft", "published", "offline"] SortField = Literal["updated_at", "created_at", "name"] class PublishInfo(BaseModel): """screens.publish:线上版本的指针,快照本身在 screen_publishes""" status: PublishStatus version: int # 当前线上版本号 revision: int # 线上版本是从哪个 revision 发出去的 share_id: str published_at: datetime class ScreenSummary(BaseModel): """不含页面的大屏记录,列表、元数据更新和线上读取用""" screen_id: str owner_id: int name: str thumbnail: str | None = None canvas: dict[str, Any] | None = None revision: int created_at: datetime updated_at: datetime deleted_at: datetime | None = None publish: PublishInfo | None = None class ScreenRecord(ScreenSummary): page: dict[str, Any] class PublishEntry(BaseModel): screen_id: str version: int revision: int published_at: datetime published_by: int class PublishSnapshot(PublishEntry): """发布快照,只增不改""" page: dict[str, Any] # ---- 请求 ---- class ScreenCreate(BaseModel): name: ScreenName = DEFAULT_NAME page: dict[str, Any] | None = None class ScreenSave(BaseModel): page: dict[str, Any] revision: int = Field(ge=0) class ScreenRename(BaseModel): name: ScreenName class ScreenPublishRequest(BaseModel): revision: int = Field(ge=0) class ScreenCopyRequest(BaseModel): name: ScreenName | None = None # ---- 响应 ---- class ScreenCreated(BaseModel): screen_id: str revision: int class PublishBrief(BaseModel): status: PublishStatus version: int share_id: str published_at: datetime class ScreenDetail(BaseModel): screen_id: str name: str page: dict[str, Any] revision: int updated_at: datetime publish: PublishBrief | None class ScreenSaved(BaseModel): revision: int updated_at: datetime class ScreenPublished(BaseModel): version: int share_id: str published_at: datetime class ScreenListItem(BaseModel): screen_id: str name: str thumbnail_url: str | None canvas: dict[str, Any] | None status: ListStatus has_unpublished_changes: bool share_id: str | None updated_at: datetime published_at: datetime | None deleted_at: datetime | None # 在回收站里的大屏,到这个时间会被自动彻底删除 purge_at: datetime | None class ScreenList(BaseModel): items: list[ScreenListItem] total: int class TrashEmptied(BaseModel): count: int class ScreenCopied(BaseModel): screen_id: str class ThumbnailResult(BaseModel): thumbnail_url: str class PublishHistoryItem(BaseModel): version: int revision: int published_at: datetime published_by: int class PublishHistory(BaseModel): items: list[PublishHistoryItem] total: int class ScreenRestored(BaseModel): revision: int class PublicScreen(BaseModel): name: str page: dict[str, Any] version: int published_at: datetime