mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-14 21:52:56 +08:00
Some checks failed
检查bot是否运行正常 / bot check (push) Has been cancelled
CodeQL Code Security Analysis / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Has been cancelled
CodeQL Code Security Analysis / Analyze (${{ matrix.language }}) (none, python) (push) Has been cancelled
Sequential Lint and Type Check / ruff-call (push) Has been cancelled
Release Drafter / Update Release Draft (push) Has been cancelled
Force Sync to Aliyun / sync (push) Has been cancelled
Update Version / update-version (push) Has been cancelled
Sequential Lint and Type Check / pyright-call (push) Has been cancelled
* ✨ feat(table): 添加 ComponentCell 以支持表格单元格中嵌入可渲染组件 * ✨ feat(ui): 增强表格构建器并完善组件模型文档 - 增强 `TableBuilder`,新增 `_normalize_cell` 辅助方法,支持自动将原生数据类型(如 `str`, `int`, `Path`)转换为 `TableCell` 模型,简化了表格行的创建。 - 完善 `zhenxun/ui/models` 目录下所有组件模型字段的 `description` 属性和文档字符串,显著提升了代码可读性和开发者体验。 - 优化 `shop/_data_source.py` 中 `gold_rank` 函数的平台路径判断格式,并统一 `my_props` 函数中图标路径的处理逻辑。 * 🚨 auto fix by pre-commit hooks --------- Co-authored-by: webjoin111 <455457521@qq.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
163 lines
5.5 KiB
Python
163 lines
5.5 KiB
Python
from abc import ABC, abstractmethod
|
||
from typing import Any, Literal
|
||
import uuid
|
||
|
||
from pydantic import BaseModel, Field
|
||
|
||
from zhenxun.utils.pydantic_compat import model_dump
|
||
|
||
from .core.base import RenderableComponent
|
||
|
||
|
||
class EChartsTitle(BaseModel):
|
||
text: str
|
||
"""图表主标题"""
|
||
left: Literal["left", "center", "right"] = "center"
|
||
"""标题水平对齐方式"""
|
||
|
||
|
||
class EChartsAxis(BaseModel):
|
||
type: Literal["category", "value", "time", "log"]
|
||
"""坐标轴类型"""
|
||
data: list[Any] | None = None
|
||
"""类目数据"""
|
||
show: bool = True
|
||
"""是否显示坐标轴"""
|
||
|
||
|
||
class EChartsSeries(BaseModel):
|
||
type: str
|
||
"""系列类型 (e.g., 'bar', 'line', 'pie')"""
|
||
data: list[Any]
|
||
"""系列数据"""
|
||
name: str | None = None
|
||
"""系列名称,用于 tooltip 的显示"""
|
||
label: dict[str, Any] | None = None
|
||
"""图形上的文本标签"""
|
||
itemStyle: dict[str, Any] | None = None
|
||
"""图形样式"""
|
||
barMaxWidth: int | None = None
|
||
"""柱条的最大宽度"""
|
||
smooth: bool | None = None
|
||
"""是否平滑显示折线"""
|
||
|
||
|
||
class EChartsTooltip(BaseModel):
|
||
trigger: Literal["item", "axis", "none"] = Field("item", description="触发类型")
|
||
"""触发类型"""
|
||
|
||
|
||
class EChartsGrid(BaseModel):
|
||
left: str | None = None
|
||
"""grid 组件离容器左侧的距离"""
|
||
right: str | None = None
|
||
"""grid 组件离容器右侧的距离"""
|
||
top: str | None = None
|
||
"""grid 组件离容器上侧的距离"""
|
||
bottom: str | None = None
|
||
"""grid 组件离容器下侧的距离"""
|
||
containLabel: bool = True
|
||
"""grid 区域是否包含坐标轴的刻度标签"""
|
||
|
||
|
||
class BaseChartData(RenderableComponent, ABC):
|
||
"""所有图表数据模型的基类"""
|
||
|
||
style_name: str | None = None
|
||
"""组件的样式名称"""
|
||
chart_id: str = Field(
|
||
default_factory=lambda: f"chart-{uuid.uuid4().hex}",
|
||
description="图表的唯一ID,用于前端渲染",
|
||
)
|
||
"""图表的唯一ID,用于前端渲染"""
|
||
|
||
echarts_options: dict[str, Any] | None = None
|
||
"""原始ECharts选项,用于高级自定义"""
|
||
|
||
@abstractmethod
|
||
def build_option(self) -> dict[str, Any]:
|
||
"""将 Pydantic 模型序列化为 ECharts 的 option 字典。"""
|
||
raise NotImplementedError
|
||
|
||
def get_render_data(self) -> dict[str, Any]:
|
||
"""为图表组件定制渲染数据,动态构建最终的 option 对象。"""
|
||
dumped_data = model_dump(self, exclude={"template_path"})
|
||
if hasattr(self, "build_option"):
|
||
dumped_data["option"] = self.build_option()
|
||
return dumped_data
|
||
|
||
def get_required_scripts(self) -> list[str]:
|
||
"""声明此组件需要 ECharts 库。"""
|
||
return ["js/echarts.min.js"]
|
||
|
||
|
||
class EChartsData(BaseChartData):
|
||
"""统一的 ECharts 图表数据模型"""
|
||
|
||
template_path: str = Field(..., exclude=True, description="图表组件的模板路径")
|
||
"""图表组件的模板路径"""
|
||
title_model: EChartsTitle | None = Field(
|
||
None, alias="title", description="标题组件"
|
||
)
|
||
"""标题组件"""
|
||
grid_model: EChartsGrid | None = Field(None, alias="grid", description="网格组件")
|
||
"""网格组件"""
|
||
tooltip_model: EChartsTooltip | None = Field(
|
||
None, alias="tooltip", description="提示框组件"
|
||
)
|
||
"""提示框组件"""
|
||
x_axis_model: EChartsAxis | None = Field(None, alias="xAxis", description="X轴配置")
|
||
"""X轴配置"""
|
||
y_axis_model: EChartsAxis | None = Field(None, alias="yAxis", description="Y轴配置")
|
||
"""Y轴配置"""
|
||
series_models: list[EChartsSeries] = Field(
|
||
default_factory=list, alias="series", description="系列列表"
|
||
)
|
||
"""系列列表"""
|
||
legend_model: dict[str, Any] | None = Field(
|
||
default_factory=dict, alias="legend", description="图例组件"
|
||
)
|
||
"""图例组件"""
|
||
raw_options: dict[str, Any] = Field(
|
||
default_factory=dict, description="用于 set_option 的原始覆盖选项"
|
||
)
|
||
"""用于 set_option 的原始覆盖选项"""
|
||
|
||
background_image: str | None = Field(None, description="用于横向柱状图的背景图片")
|
||
"""用于横向柱状图的背景图片"""
|
||
|
||
def build_option(self) -> dict[str, Any]:
|
||
"""将 Pydantic 模型序列化为 ECharts 的 option 字典。"""
|
||
option: dict[str, Any] = {}
|
||
key_map = {
|
||
"title": "title_model",
|
||
"grid": "grid_model",
|
||
"tooltip": "tooltip_model",
|
||
"xAxis": "x_axis_model",
|
||
"yAxis": "y_axis_model",
|
||
"series": "series_models",
|
||
"legend": "legend_model",
|
||
}
|
||
for echarts_key, model_attr in key_map.items():
|
||
model_instance = getattr(self, model_attr, None)
|
||
if model_instance:
|
||
if isinstance(model_instance, list):
|
||
option[echarts_key] = [
|
||
model_dump(m, exclude_none=True) for m in model_instance
|
||
]
|
||
elif isinstance(model_instance, BaseModel):
|
||
option[echarts_key] = model_dump(model_instance, exclude_none=True)
|
||
else:
|
||
option[echarts_key] = model_instance
|
||
option.update(self.raw_options)
|
||
return option
|
||
|
||
@property
|
||
def title(self) -> str:
|
||
"""为模板提供一个简单的字符串标题,保持向后兼容性。"""
|
||
return self.title_model.text if self.title_model else ""
|
||
|
||
@property
|
||
def template_name(self) -> str:
|
||
return self.template_path
|