"""请求数据模型定义"""
from typing import Any, List, Literal, Optional
from pydantic import BaseModel, Field, model_validator
class DataField(BaseModel):
"""数据字段定义模型"""
name: str = Field(..., description="列标题显示名称")
field: Optional[str] = Field(None, description="JSON格式字段名")
index: Optional[int] = Field(None, ge=0, description="数组格式索引位置")
@model_validator(mode='after')
def validate_field_or_index(self) -> 'DataField':
"""验证field和index的有效性
允许field和index都为空,表示该列不绑定数据
"""
# 移除强制要求field或index必须有一个的验证
# 允许两者都为空,表示该列不需要数据绑定
return self
class DataStruct(BaseModel):
"""数据结构定义模型"""
collectName: str = Field(
...,
min_length=1,
description="集合变量名称,用于JXLS批注中的items参数"
)
itemVariable: str = Field(
...,
min_length=1,
description="循环项变量名,用于JXLS批注中的var参数"
)
dataFields: List[DataField] = Field(
...,
min_length=1,
description="字段定义数组"
)
class GenerateTemplateRequest(BaseModel):
"""生成模板请求模型"""
templateName: str = Field(
...,
min_length=1,
max_length=100,
description="模板文件名称"
)
dataStruct: DataStruct = Field(..., description="数据结构定义")
dataFormat: Literal["json", "array"] = Field(..., description="数据格式类型")
sampleData: Optional[List[Any]] = Field(None, description="示例数据(用于验证)")
outputPath: Optional[str] = Field(None, description="导出文件路径")
@model_validator(mode='after')
def validate_data_format_consistency(self) -> 'GenerateTemplateRequest':
"""验证数据格式与dataStruct的一致性
对于需要数据绑定的字段:
- JSON格式需要提供field属性
- 数组格式需要提供index属性
允许field和index都为空,表示该列不需要数据绑定
"""
if self.dataFormat == "json":
# JSON格式时,如果提供了index但没有field,则报错
for field in self.dataStruct.dataFields:
if field.index is not None and not field.field:
raise ValueError(
f"JSON格式时字段'{field.name}'不应提供index属性,"
f"请使用field属性或留空表示不绑定数据"
)
elif self.dataFormat == "array":
# 数组格式时,如果提供了field但没有index,则报错
for field in self.dataStruct.dataFields:
if field.field and field.index is None:
raise ValueError(
f"数组格式时字段'{field.name}'不应提供field属性,"
f"请使用index属性或留空表示不绑定数据"
)
return self
@model_validator(mode='after')
def validate_template_name_safe(self) -> 'GenerateTemplateRequest':
"""验证模板名称安全性"""
unsafe_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|']
for char in unsafe_chars:
if char in self.templateName:
raise ValueError(f"模板名称不能包含字符: {char}")
return self