refactor: 重构文档结构,采用渐进式信息披露模式
将 README.md 拆分为多个专题文档,减少认知负荷: - 用户文档迁移到 docs/ (用户指南、元素、模板、参考等) - 开发文档迁移到 docs/development/ (架构、模块、规范) - README.md 精简至 ~290 行,仅保留概览和导航 - 删除 README_DEV.md,内容已迁移 - 归档 OpenSpec 变更 refactor-docs-progressive-disclosure
This commit is contained in:
18
docs/development/modules/_index.md
Normal file
18
docs/development/modules/_index.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# 模块详解
|
||||
|
||||
本目录包含各代码模块的详细说明。
|
||||
|
||||
## 核心模块
|
||||
|
||||
- [Elements](elements.md) - 元素抽象层
|
||||
- [Template](template.md) - 模板系统
|
||||
- [Validators](validators.md) - 验证器
|
||||
- [Renderers](renderers.md) - 渲染器
|
||||
- [Loaders](loaders.md) - 加载器
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [架构设计](../architecture.md) - 整体代码结构
|
||||
- [开发规范](../development-guide.md) - 编码规范
|
||||
|
||||
[返回开发文档索引](../README.md)
|
||||
137
docs/development/modules/elements.md
Normal file
137
docs/development/modules/elements.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Elements 模块
|
||||
|
||||
`core/elements.py` 定义了所有元素类型的数据类和工厂函数。
|
||||
|
||||
## 职责
|
||||
|
||||
- 定义元素数据类(使用 `@dataclass`)
|
||||
- 在创建时进行元素级验证
|
||||
- 提供元素工厂函数
|
||||
|
||||
## 包含的内容
|
||||
|
||||
### FontConfig 类
|
||||
|
||||
字体配置数据类,支持所有字体属性:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class FontConfig:
|
||||
parent: Optional[str] = None
|
||||
family: Optional[str] = None
|
||||
size: Optional[int] = None
|
||||
bold: Optional[bool] = None
|
||||
italic: Optional[bool] = None
|
||||
underline: Optional[bool] = None
|
||||
strikethrough: Optional[bool] = None
|
||||
color: Optional[str] = None
|
||||
align: Optional[str] = None
|
||||
line_spacing: Optional[float] = None
|
||||
space_before: Optional[float] = None
|
||||
space_after: Optional[float] = None
|
||||
baseline: Optional[str] = None
|
||||
caps: Optional[str] = None
|
||||
```
|
||||
|
||||
在 `__post_init__` 中验证 baseline 和 caps 枚举值。
|
||||
|
||||
### 元素类
|
||||
|
||||
#### TextElement
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TextElement:
|
||||
type: str = 'text'
|
||||
content: str = ''
|
||||
box: list = field(default_factory=lambda: [1, 1, 8, 1])
|
||||
font: FontConfig | str | dict = field(default_factory=dict)
|
||||
```
|
||||
|
||||
#### ImageElement
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ImageElement:
|
||||
type: str = 'image'
|
||||
src: str = ''
|
||||
box: list = field(default_factory=lambda: [1, 1, 4, 3])
|
||||
```
|
||||
|
||||
#### ShapeElement
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ShapeElement:
|
||||
type: str = 'shape'
|
||||
box: list = field(default_factory=lambda: [1, 1, 4, 2])
|
||||
shape: str = 'rectangle'
|
||||
fill: str = '#000000'
|
||||
line: dict = field(default_factory=dict)
|
||||
```
|
||||
|
||||
#### TableElement
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TableElement:
|
||||
type: str = 'table'
|
||||
position: list = field(default_factory=lambda: [0, 0])
|
||||
col_widths: list = field(default_factory=list)
|
||||
data: list = field(default_factory=list)
|
||||
font: FontConfig | str | dict = field(default_factory=dict)
|
||||
header_font: FontConfig | str | dict = field(default_factory=dict)
|
||||
style: dict = field(default_factory=dict)
|
||||
```
|
||||
|
||||
### create_element() 工厂函数
|
||||
|
||||
```python
|
||||
def create_element(elem_dict: dict):
|
||||
elem_type = elem_dict.get('type')
|
||||
|
||||
if elem_type == 'text':
|
||||
return TextElement(**elem_dict)
|
||||
elif elem_type == 'image':
|
||||
return ImageElement(**elem_dict)
|
||||
elif elem_type == 'shape':
|
||||
return ShapeElement(**elem_dict)
|
||||
elif elem_type == 'table':
|
||||
return TableElement(**elem_dict)
|
||||
else:
|
||||
raise ValueError(f"Unknown element type: {elem_type}")
|
||||
```
|
||||
|
||||
自动将字典形式的 font 转换为 FontConfig 对象。
|
||||
|
||||
## 创建时验证
|
||||
|
||||
每个元素类在 `__post_init__` 中进行验证:
|
||||
|
||||
```python
|
||||
def __post_init__(self):
|
||||
# 检查必需字段
|
||||
if len(self.box) != 4:
|
||||
raise ValueError("box 必须包含 4 个数字")
|
||||
|
||||
# 验证颜色格式
|
||||
if self.fill and not _is_valid_color(self.fill):
|
||||
raise ValueError(f"无效的颜色格式: {self.fill}")
|
||||
```
|
||||
|
||||
## 元素级验证职责
|
||||
|
||||
- 必需字段检查
|
||||
- 数据类型检查
|
||||
- 值的有效性检查:
|
||||
- 颜色格式验证
|
||||
- 字体大小合理性
|
||||
- 枚举值检查(如形状类型)
|
||||
- 表格数据一致性
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [Template 模块](template.md) - 模板系统
|
||||
- [Validators 模块](validators.md) - 验证器详解
|
||||
|
||||
[返回开发文档索引](../README.md)
|
||||
135
docs/development/modules/loaders.md
Normal file
135
docs/development/modules/loaders.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Loaders 模块
|
||||
|
||||
`loaders/yaml_loader.py` 负责 YAML 文件加载和验证。
|
||||
|
||||
## 职责
|
||||
|
||||
- YAML 文件加载
|
||||
- 演示文稿结构验证
|
||||
- 内联模板验证
|
||||
- 外部模板验证
|
||||
|
||||
## 包含的内容
|
||||
|
||||
### YAMLError
|
||||
|
||||
自定义异常类:
|
||||
|
||||
```python
|
||||
class YAMLError(Exception):
|
||||
"""YAML 相关错误"""
|
||||
pass
|
||||
```
|
||||
|
||||
### load_yaml_file()
|
||||
|
||||
加载 YAML 文件:
|
||||
|
||||
```python
|
||||
def load_yaml_file(file_path):
|
||||
"""加载 YAML 文件并返回解析后的数据"""
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
data = yaml.safe_load(f)
|
||||
return data
|
||||
except yaml.YAMLError as e:
|
||||
raise YAMLError(f"YAML 语法错误: {e}")
|
||||
except FileNotFoundError:
|
||||
raise YAMLError(f"文件不存在: {file_path}")
|
||||
```
|
||||
|
||||
### validate_presentation_yaml()
|
||||
|
||||
验证演示文稿结构:
|
||||
|
||||
```python
|
||||
def validate_presentation_yaml(data, file_path):
|
||||
"""验证演示文稿 YAML 结构"""
|
||||
# 检查必需字段
|
||||
if 'metadata' not in data:
|
||||
raise YAMLError(f"缺少 metadata 字段: {file_path}")
|
||||
|
||||
if 'slides' not in data:
|
||||
raise YAMLError(f"缺少 slides 字段: {file_path}")
|
||||
|
||||
# 验证 metadata
|
||||
metadata = data['metadata']
|
||||
if 'size' not in metadata:
|
||||
raise YAMLError(f"metadata 缺少 size 字段: {file_path}")
|
||||
|
||||
if metadata['size'] not in ['16:9', '4:3']:
|
||||
raise YAMLError(f"无效的 size 值: {metadata['size']}")
|
||||
|
||||
# 验证内联模板(如果有)
|
||||
if 'templates' in data:
|
||||
validate_templates_yaml(data['templates'])
|
||||
|
||||
# 验证幻灯片
|
||||
for slide in data['slides']:
|
||||
# 验证 enabled 字段
|
||||
if 'enabled' in slide:
|
||||
if not isinstance(slide['enabled'], bool):
|
||||
raise YAMLError(f"enabled 必须是布尔值: {file_path}")
|
||||
```
|
||||
|
||||
### validate_template_yaml()
|
||||
|
||||
验证外部模板结构:
|
||||
|
||||
```python
|
||||
def validate_template_yaml(template_data, template_name):
|
||||
"""验证外部模板结构"""
|
||||
if 'elements' not in template_data:
|
||||
raise YAMLError(f"模板缺少 elements 字段: {template_name}")
|
||||
|
||||
if 'vars' in template_data:
|
||||
for var in template_data['vars']:
|
||||
if 'name' not in var:
|
||||
raise YAMLError(f"变量缺少 name 字段: {template_name}")
|
||||
```
|
||||
|
||||
### validate_templates_yaml()
|
||||
|
||||
验证内联模板结构:
|
||||
|
||||
```python
|
||||
def validate_templates_yaml(templates):
|
||||
"""验证内联模板结构"""
|
||||
if not isinstance(templates, dict):
|
||||
raise YAMLError("templates 必须是字典类型")
|
||||
|
||||
for name, template_data in templates.items():
|
||||
validate_template_yaml(template_data, f"templates.{name}")
|
||||
|
||||
# 检测默认值中引用不存在的变量
|
||||
vars_def = {v['name']: v for v in template_data.get('vars', [])}
|
||||
for var in template_data.get('vars', []):
|
||||
if 'default' in var:
|
||||
# 检查默认值是否引用了不存在的变量
|
||||
# 实现省略...
|
||||
```
|
||||
|
||||
## 内联模板验证
|
||||
|
||||
内联模板验证包括:
|
||||
- 结构验证(是否为字典)
|
||||
- 元素验证(是否有 elements 字段)
|
||||
- 变量定义验证(是否有 name 字段)
|
||||
- 默认值验证(检测循环引用)
|
||||
|
||||
## enabled 字段验证
|
||||
|
||||
验证 `enabled` 字段必须是布尔值:
|
||||
|
||||
```python
|
||||
if 'enabled' in slide:
|
||||
if not isinstance(slide['enabled'], bool):
|
||||
raise YAMLError(f"enabled 必须是布尔值,不能是字符串或条件表达式")
|
||||
```
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [架构设计](../architecture.md) - 代码结构
|
||||
- [验证器模块](validators.md) - 验证详解
|
||||
|
||||
[返回开发文档索引](../README.md)
|
||||
153
docs/development/modules/renderers.md
Normal file
153
docs/development/modules/renderers.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Renderers 模块
|
||||
|
||||
`renderers/` 目录包含 PPTX 和 HTML 渲染器。
|
||||
|
||||
## 模块组成
|
||||
|
||||
### pptx_renderer.py
|
||||
|
||||
PPTX 文件生成器:
|
||||
|
||||
```python
|
||||
class PptxGenerator:
|
||||
def __init__(self, size="16:9"):
|
||||
self.presentation = Presentation()
|
||||
self.slide_width = 10 # 英寸
|
||||
self.slide_height = 5.625 if size == "16:9" else 7.5
|
||||
|
||||
def add_slide(self):
|
||||
"""添加新幻灯片"""
|
||||
slide = self.presentation.slides.add_slide(self.blank_layout)
|
||||
return slide
|
||||
|
||||
def _render_element(self, slide, elem, base_path):
|
||||
"""分发元素到对应的渲染方法"""
|
||||
if isinstance(elem, TextElement):
|
||||
self._render_text(slide, elem)
|
||||
elif isinstance(elem, ImageElement):
|
||||
self._render_image(slide, elem, base_path)
|
||||
# ...
|
||||
|
||||
def _render_text(self, slide, elem):
|
||||
"""渲染文本元素"""
|
||||
# 实现...
|
||||
|
||||
def _render_image(self, slide, elem, base_path):
|
||||
"""渲染图片元素"""
|
||||
# 实现...
|
||||
|
||||
def _render_shape(self, slide, elem):
|
||||
"""渲染形状元素"""
|
||||
# 实现...
|
||||
|
||||
def _render_table(self, slide, elem):
|
||||
"""渲染表格元素"""
|
||||
# 实现...
|
||||
|
||||
def save(self, output_path):
|
||||
"""保存 PPTX 文件"""
|
||||
self.presentation.save(output_path)
|
||||
```
|
||||
|
||||
### html_renderer.py
|
||||
|
||||
HTML 预览渲染器:
|
||||
|
||||
```python
|
||||
class HtmlRenderer:
|
||||
def __init__(self, size="16:9"):
|
||||
self.slide_width = 960 # 96 DPI * 10"
|
||||
self.slide_height = 540 if size == "16:9" else 720
|
||||
|
||||
def render_slide(self, slide_data, index, base_path=None):
|
||||
"""渲染幻灯片为 HTML"""
|
||||
elements_html = ""
|
||||
|
||||
for elem in slide_data:
|
||||
if isinstance(elem, TextElement):
|
||||
elements_html += self.render_text(elem)
|
||||
elif isinstance(elem, ImageElement):
|
||||
elements_html += self.render_image(elem, base_path)
|
||||
# ...
|
||||
|
||||
return self.SLIDE_TEMPLATE.format(
|
||||
width=self.slide_width,
|
||||
height=self.slide_height,
|
||||
content=elements_html
|
||||
)
|
||||
|
||||
def render_text(self, elem):
|
||||
"""渲染文本为 HTML"""
|
||||
# 实现...
|
||||
|
||||
def render_image(self, elem, base_path):
|
||||
"""渲染图片为 HTML"""
|
||||
# 实现...
|
||||
|
||||
def render_shape(self, elem):
|
||||
"""渲染形状为 HTML"""
|
||||
# 实现...
|
||||
|
||||
def render_table(self, elem):
|
||||
"""渲染表格为 HTML"""
|
||||
# 实现...
|
||||
```
|
||||
|
||||
## 设计特点
|
||||
|
||||
### 渲染器内置在生成器中
|
||||
|
||||
- **封装性**:渲染逻辑与生成器紧密相关
|
||||
- **简单性**:不需要额外的渲染器接口
|
||||
- **性能**:避免额外的方法调用开销
|
||||
|
||||
### 使用 isinstance() 检查类型
|
||||
|
||||
```python
|
||||
if isinstance(elem, TextElement):
|
||||
self._render_text(slide, elem)
|
||||
```
|
||||
|
||||
### 通过元素对象属性访问数据
|
||||
|
||||
```python
|
||||
def _render_text(self, slide, elem):
|
||||
text_box = elem.box
|
||||
content = elem.content
|
||||
font_config = elem.font
|
||||
```
|
||||
|
||||
## 共享元素抽象层
|
||||
|
||||
两个渲染器共享相同的元素数据类:
|
||||
- `TextElement`
|
||||
- `ImageElement`
|
||||
- `ShapeElement`
|
||||
- `TableElement`
|
||||
|
||||
## 单位转换
|
||||
|
||||
### HTML 渲染器
|
||||
|
||||
使用固定 DPI (96) 进行单位转换:
|
||||
|
||||
```python
|
||||
DPI = 96
|
||||
pixels = inches * DPI
|
||||
```
|
||||
|
||||
### PPTX 渲染器
|
||||
|
||||
python-pptx 使用 Inches 单位:
|
||||
|
||||
```python
|
||||
from pptx.util import Inches
|
||||
left = Inches(box[0])
|
||||
```
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [Elements 模块](elements.md) - 元素数据类
|
||||
- [预览功能](../../user-guide.md) - 用户指南
|
||||
|
||||
[返回开发文档索引](../README.md)
|
||||
148
docs/development/modules/template.md
Normal file
148
docs/development/modules/template.md
Normal file
@@ -0,0 +1,148 @@
|
||||
# Template 模块
|
||||
|
||||
`core/template.py` 实现了模板系统,支持变量解析、条件渲染和模板渲染。
|
||||
|
||||
## 职责
|
||||
|
||||
- 模板加载和变量解析
|
||||
- 条件表达式评估
|
||||
- 模板渲染
|
||||
|
||||
## 包含的内容
|
||||
|
||||
### Template 类
|
||||
|
||||
#### from_data() 类方法
|
||||
|
||||
从字典创建模板实例(用于内联模板):
|
||||
|
||||
```python
|
||||
@classmethod
|
||||
def from_data(cls, template_data, template_name, base_dir=None):
|
||||
"""从字典创建模板(内联模板或外部模板)"""
|
||||
obj = cls.__new__(cls)
|
||||
obj.data = template_data
|
||||
obj.base_dir = base_dir
|
||||
obj.vars_def = {var['name']: var for var in template_data.get('vars', [])}
|
||||
obj.elements = template_data.get('elements', [])
|
||||
return obj
|
||||
```
|
||||
|
||||
#### 变量解析
|
||||
|
||||
**resolve_value()** - 解析变量值:
|
||||
|
||||
```python
|
||||
def resolve_value(self, value, vars_values):
|
||||
"""解析变量值,支持 {varname} 语法"""
|
||||
if isinstance(value, str) and '{' in value:
|
||||
# 替换变量
|
||||
result = value
|
||||
for var_name, var_value in vars_values.items():
|
||||
result = result.replace(f'{{{var_name}}}', str(var_value))
|
||||
return result
|
||||
return value
|
||||
```
|
||||
|
||||
**resolve_element()** - 解析元素中的变量:
|
||||
|
||||
```python
|
||||
def resolve_element(self, element, vars_values):
|
||||
"""递归解析元素中的所有变量"""
|
||||
resolved = {}
|
||||
for key, value in element.items():
|
||||
if isinstance(value, dict):
|
||||
resolved[key] = self.resolve_element(value, vars_values)
|
||||
elif isinstance(value, str):
|
||||
resolved[key] = self.resolve_value(value, vars_values)
|
||||
else:
|
||||
resolved[key] = value
|
||||
return resolved
|
||||
```
|
||||
|
||||
#### 条件渲染
|
||||
|
||||
**evaluate_condition()** - 委托给 ConditionEvaluator:
|
||||
|
||||
```python
|
||||
def evaluate_condition(self, condition, vars_values):
|
||||
"""评估条件表达式"""
|
||||
from core.condition_evaluator import ConditionEvaluator
|
||||
evaluator = ConditionEvaluator()
|
||||
return evaluator.evaluate(condition, vars_values)
|
||||
```
|
||||
|
||||
#### 模板渲染
|
||||
|
||||
**render()** - 渲染模板:
|
||||
|
||||
```python
|
||||
def render(self, vars_values):
|
||||
"""渲染模板,返回解析后的元素列表"""
|
||||
elements = []
|
||||
|
||||
for elem in self.elements:
|
||||
# 检查条件渲染
|
||||
if 'visible' in elem:
|
||||
if not self.evaluate_condition(elem['visible'], vars_values):
|
||||
continue
|
||||
|
||||
# 解析变量
|
||||
resolved_elem = self.resolve_element(elem, vars_values)
|
||||
elements.append(resolved_elem)
|
||||
|
||||
return elements
|
||||
```
|
||||
|
||||
## 特点
|
||||
|
||||
### 支持两种模板方式
|
||||
|
||||
- **外部模板**:从文件加载
|
||||
- **内联模板**:从字典创建(通过 `from_data()`)
|
||||
|
||||
### 变量替换
|
||||
|
||||
支持 `{varname}` 语法的变量替换:
|
||||
|
||||
```yaml
|
||||
templates:
|
||||
title-slide:
|
||||
vars:
|
||||
- name: title
|
||||
elements:
|
||||
- type: text
|
||||
content: "{title}" # 变量替换
|
||||
```
|
||||
|
||||
### 条件渲染
|
||||
|
||||
支持 `visible` 属性的条件表达式:
|
||||
|
||||
```yaml
|
||||
elements:
|
||||
- type: text
|
||||
content: "有数据"
|
||||
visible: "{count > 0}"
|
||||
```
|
||||
|
||||
## 内联模板支持
|
||||
|
||||
`from_data()` 类方法使模板可以从字典创建:
|
||||
|
||||
```python
|
||||
# 从内联模板定义创建
|
||||
template = Template.from_data(
|
||||
template_data=inline_template_dict,
|
||||
template_name="title-slide",
|
||||
base_dir=document_base_dir
|
||||
)
|
||||
```
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [条件评估器](../condition-rendering.md) - 条件表达式语法
|
||||
- [Elements 模块](elements.md) - 元素数据类
|
||||
- [内联模板](../../templates/inline.md) - 用户指南
|
||||
|
||||
[返回开发文档索引](../README.md)
|
||||
112
docs/development/modules/validators.md
Normal file
112
docs/development/modules/validators.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# Validators 模块
|
||||
|
||||
`validators/` 目录包含所有验证相关的代码。
|
||||
|
||||
## 模块组成
|
||||
|
||||
### validators/result.py
|
||||
|
||||
验证结果数据结构:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ValidationIssue:
|
||||
level: str # ERROR/WARNING/INFO
|
||||
message: str
|
||||
location: str = ""
|
||||
code: str = ""
|
||||
|
||||
@dataclass
|
||||
class ValidationResult:
|
||||
errors: List[ValidationIssue]
|
||||
warnings: List[ValidationIssue]
|
||||
infos: List[ValidationIssue]
|
||||
```
|
||||
|
||||
### validators/geometry.py
|
||||
|
||||
几何验证器,检查元素边界:
|
||||
|
||||
```python
|
||||
class GeometryValidator:
|
||||
def __init__(self, slide_width, slide_height):
|
||||
self.slide_width = slide_width
|
||||
self.slide_height = slide_height
|
||||
self.tolerance = 0.1 # 英寸
|
||||
|
||||
def validate_element(self, element, slide_index, elem_index):
|
||||
"""检查元素是否在页面范围内"""
|
||||
# 检查边界
|
||||
# 支持容忍度
|
||||
```
|
||||
|
||||
### validators/resource.py
|
||||
|
||||
资源验证器,检查文件存在性:
|
||||
|
||||
```python
|
||||
class ResourceValidator:
|
||||
def __init__(self, base_dir):
|
||||
self.base_dir = Path(base_dir)
|
||||
|
||||
def validate_image(self, src, slide_index, elem_index):
|
||||
"""检查图片文件是否存在"""
|
||||
# 检查文件路径
|
||||
# 验证文件存在
|
||||
```
|
||||
|
||||
### validators/validator.py
|
||||
|
||||
主验证器,协调所有子验证器:
|
||||
|
||||
```python
|
||||
class Validator:
|
||||
def __init__(self, slide_width, slide_height, base_dir):
|
||||
self.geometry_validator = GeometryValidator(slide_width, slide_height)
|
||||
self.resource_validator = ResourceValidator(base_dir)
|
||||
|
||||
def validate_presentation(self, presentation):
|
||||
"""验证整个演示文稿"""
|
||||
# 遍历所有幻灯片和元素
|
||||
# 调用子验证器
|
||||
```
|
||||
|
||||
## 验证职责分层
|
||||
|
||||
### 元素级验证
|
||||
|
||||
在元素类中完成:
|
||||
- 必需字段检查
|
||||
- 数据类型检查
|
||||
- 值的有效性检查
|
||||
|
||||
### 系统级验证
|
||||
|
||||
在验证器中完成:
|
||||
- 几何验证(需要页面尺寸)
|
||||
- 资源验证(需要文件路径)
|
||||
- 跨元素验证
|
||||
|
||||
## 验证容忍度
|
||||
|
||||
几何验证时,允许 0.1 英寸的容忍度:
|
||||
|
||||
```python
|
||||
TOLERANCE = 0.1 # 英寸
|
||||
|
||||
if right > slide_width + TOLERANCE:
|
||||
# 报告 WARNING
|
||||
```
|
||||
|
||||
## 分级错误报告
|
||||
|
||||
- **ERROR**:阻止转换的严重问题
|
||||
- **WARNING**:影响视觉效果的问题
|
||||
- **INFO**:优化建议
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [Elements 模块](elements.md) - 元素级验证
|
||||
- [开发规范](../development-guide.md) - 验证职责
|
||||
|
||||
[返回开发文档索引](../README.md)
|
||||
Reference in New Issue
Block a user