mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-08 13:20:01 +08:00
✨ feat(page-template): 添加页面模板服务,支持前端布局组件和数据提交处理
- 新增页面模板服务模块,提供页面模板配置、字段定义和数据验证功能。 - 实现了前端布局组件模型,包括行、列、文本、按钮、卡片等,支持灵活的页面布局。 - 引入 FastAPI 路由,提供统一的API接口以获取模板配置和处理数据提交。 - 注册用户表单模板示例,包含提交、重置和取消按钮的功能。 - 增强了数据验证和处理逻辑,确保提交数据的有效性和安全性。
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class ComponentType(str, Enum):
|
||||
"""组件类型,名称与前端 tag 保持一致"""
|
||||
|
||||
ROW = "row"
|
||||
COL = "col"
|
||||
TEXT = "text"
|
||||
BUTTON = "button"
|
||||
CARD = "card"
|
||||
DIVIDER = "divider"
|
||||
SPACE = "space"
|
||||
FORM = "form"
|
||||
FORM_ITEM = "form_item"
|
||||
TABLE = "table"
|
||||
|
||||
|
||||
class RowProps(BaseModel):
|
||||
"""行组件属性"""
|
||||
|
||||
gutter: int | None = None # 行间距
|
||||
justify: str | None = None # 主轴对齐方式
|
||||
align: str | None = None # 交叉轴对齐方式
|
||||
|
||||
|
||||
class ColProps(BaseModel):
|
||||
"""列组件属性"""
|
||||
|
||||
span: int | None = None # 栅格占比
|
||||
offset: int | None = None # 左侧偏移
|
||||
push: int | None = None # 向右移动
|
||||
pull: int | None = None # 向左移动
|
||||
|
||||
|
||||
class TextProps(BaseModel):
|
||||
"""文本组件属性"""
|
||||
|
||||
content: str = "" # 文本内容
|
||||
tag: str | None = None # HTML 标签,如 h1/h2/p/span
|
||||
type: str | None = None # 文本类型,对应 el-text 的 type
|
||||
size: str | None = None # 文本大小
|
||||
truncated: bool = False # 是否截断
|
||||
line_clamp: int | None = None # 最多显示行数
|
||||
|
||||
|
||||
class ButtonProps(BaseModel):
|
||||
"""按钮组件属性"""
|
||||
|
||||
text: str # 按钮文本(必填)
|
||||
type: str | None = None # 按钮类型 primary/success/warning/danger/info/default
|
||||
size: str | None = None # 按钮尺寸 large/default/small
|
||||
plain: bool = False # 朴素按钮
|
||||
round: bool = False # 圆角按钮
|
||||
circle: bool = False # 圆形按钮
|
||||
link: bool = False # 文字按钮
|
||||
icon: str | None = None # 图标名称
|
||||
action: str | None = None # 按钮行为:submit/reset/cancel/custom
|
||||
confirm: bool = False # 是否需要二次确认
|
||||
confirm_text: str | None = None # 确认提示文案
|
||||
api: str | None = None # 自定义调用的后端 API(action=custom 时使用)
|
||||
api_method: str = "POST" # 自定义 API 的 HTTP 方法
|
||||
|
||||
|
||||
class CardProps(BaseModel):
|
||||
"""卡片组件属性"""
|
||||
|
||||
header: str | None = None # 卡片标题
|
||||
shadow: str | None = None # 阴影类型
|
||||
body_style: dict[str, Any] | None = None # 卡片主体样式
|
||||
|
||||
|
||||
class FormProps(BaseModel):
|
||||
"""表单组件属性"""
|
||||
|
||||
label_width: str | None = None # 标签宽度
|
||||
inline: bool = False # 行内表单
|
||||
size: str | None = None # 表单尺寸
|
||||
|
||||
|
||||
class FormItemProps(BaseModel):
|
||||
"""表单项组件属性"""
|
||||
|
||||
label: str | None = None # 标签文本
|
||||
prop: str | None = None # 绑定字段名
|
||||
required: bool = False # 是否必填
|
||||
|
||||
|
||||
class TableProps(BaseModel):
|
||||
"""表格组件属性"""
|
||||
|
||||
columns: list[dict[str, Any]] | None = None # 列配置
|
||||
data: list[dict[str, Any]] | None = None # 数据源
|
||||
|
||||
|
||||
class BaseComponent(BaseModel):
|
||||
# 这些字段在 BaseModel 中有默认值,调用时都不是必传
|
||||
# 用 Any 以便可以直接传 TextProps / ButtonProps / FormProps 等模型实例
|
||||
props: Any | None
|
||||
# 用 Any 避免 list 协变问题
|
||||
children: list[Any] | None = None
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
def __init__(self, **data: Any):
|
||||
super().__init__(**data)
|
||||
_validate_children_impl(self.__dict__)
|
||||
|
||||
|
||||
def _validate_children_impl(values: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
限定哪些组件可以拥有 children:
|
||||
- 允许 children: row, col, card, space, form, form_item, table
|
||||
- 不允许 children: text, button, divider
|
||||
"""
|
||||
t = values.get("type")
|
||||
children = values.get("children") or []
|
||||
no_children = {
|
||||
ComponentType.TEXT.value,
|
||||
ComponentType.BUTTON.value,
|
||||
ComponentType.DIVIDER.value,
|
||||
}
|
||||
if t in no_children and children:
|
||||
raise ValueError(f"组件 '{t}' 不允许包含 children")
|
||||
return values
|
||||
|
||||
|
||||
class Row(BaseComponent):
|
||||
"""行组件(对应 el-row)"""
|
||||
|
||||
type = ComponentType.ROW.value
|
||||
props: RowProps # 必填
|
||||
|
||||
|
||||
class Col(BaseComponent):
|
||||
"""列组件(对应 el-col)"""
|
||||
|
||||
type = ComponentType.COL.value
|
||||
props: ColProps # 必填
|
||||
|
||||
|
||||
class Text(BaseComponent):
|
||||
"""文本组件(对应 el-text 或基础标签)"""
|
||||
|
||||
type = ComponentType.TEXT.value
|
||||
props: TextProps # 必填
|
||||
|
||||
|
||||
class Button(BaseComponent):
|
||||
"""按钮组件(对应 el-button)"""
|
||||
|
||||
type = ComponentType.BUTTON.value
|
||||
props: ButtonProps # 必填
|
||||
|
||||
|
||||
class Card(BaseComponent):
|
||||
"""卡片组件(对应 el-card)"""
|
||||
|
||||
type = ComponentType.CARD.value
|
||||
props: CardProps # 必填
|
||||
|
||||
|
||||
class Divider(BaseComponent):
|
||||
"""分割线组件(对应 el-divider)"""
|
||||
|
||||
type = ComponentType.DIVIDER.value
|
||||
|
||||
|
||||
class Space(BaseComponent):
|
||||
"""间距组件(对应 el-space)"""
|
||||
|
||||
type = ComponentType.SPACE.value
|
||||
|
||||
|
||||
class Form(BaseComponent):
|
||||
"""表单组件(对应 el-form)"""
|
||||
|
||||
type = ComponentType.FORM.value
|
||||
props: FormProps # 必填
|
||||
|
||||
|
||||
class FormItem(BaseComponent):
|
||||
"""表单项组件(对应 el-form-item)"""
|
||||
|
||||
type = ComponentType.FORM_ITEM.value
|
||||
props: FormItemProps # 必填
|
||||
children: list[Any] | None = None
|
||||
bind_field: str | None = None
|
||||
|
||||
|
||||
class Table(BaseComponent):
|
||||
"""表格组件(对应 el-table)"""
|
||||
|
||||
type = ComponentType.TABLE.value
|
||||
|
||||
|
||||
Component = Row | Col | Text | Button | Card | Divider | Space | Form | FormItem | Table
|
||||
|
||||
|
||||
try:
|
||||
BaseComponent.model_rebuild()
|
||||
except AttributeError:
|
||||
BaseComponent.update_forward_refs()
|
||||
Reference in New Issue
Block a user