zhenxun_bot/zhenxun/ui/models/core/base.py

89 lines
2.8 KiB
Python
Raw Normal View History

from abc import ABC, abstractmethod
import asyncio
from collections.abc import Awaitable, Iterator
from typing import Any
from nonebot.compat import model_dump
from pydantic import BaseModel
from zhenxun.services.renderer.protocols import Renderable
__all__ = ["ContainerComponent", "RenderableComponent"]
class RenderableComponent(BaseModel, Renderable):
"""所有可渲染UI组件的抽象基类。"""
_is_standalone_template: bool = False
@property
def template_name(self) -> str:
"""
返回用于渲染此组件的Jinja2模板的路径
这是一个抽象属性所有子类都必须覆盖它
"""
raise NotImplementedError(
"Subclasses must implement the 'template_name' property."
)
async def prepare(self) -> None:
"""[可选] 生命周期钩子,默认无操作。"""
pass
def get_required_scripts(self) -> list[str]:
"""[可选] 返回此组件所需的JS脚本路径列表 (相对于assets目录)。"""
return []
def get_required_styles(self) -> list[str]:
"""[可选] 返回此组件所需的CSS样式表路径列表 (相对于assets目录)。"""
return []
def get_render_data(self) -> dict[str, Any | Awaitable[Any]]:
"""默认实现,返回模型自身的数据字典。"""
return model_dump(self)
def get_extra_css(self, theme_manager: Any) -> str | Awaitable[str]:
return ""
class ContainerComponent(RenderableComponent, ABC):
"""
一个为容器类组件设计的抽象基类封装了预渲染子组件的通用逻辑
"""
@abstractmethod
def _get_renderable_child_items(self) -> Iterator[Any]:
"""
一个抽象方法子类必须实现它来返回一个可迭代的对象
迭代器中的每个项目都必须具有 'component' 'html_content' 属性
"""
raise NotImplementedError
async def prepare(self) -> None:
"""
通用的 prepare 方法负责预渲染所有子组件
"""
from zhenxun.services import renderer_service
child_items = list(self._get_renderable_child_items())
if not child_items:
return
components_to_render = [
item.component for item in child_items if item.component
]
prepare_tasks = [
comp.prepare() for comp in components_to_render if hasattr(comp, "prepare")
]
if prepare_tasks:
await asyncio.gather(*prepare_tasks)
render_tasks = [
renderer_service.render_to_html(comp) for comp in components_to_render
]
rendered_htmls = await asyncio.gather(*render_tasks)
for item, html in zip(child_items, rendered_htmls):
item.html_content = html