from dataclasses import dataclass from typing import Literal from fastapi import Query from pydantic import BaseModel, ConfigDict, Field, field_validator from app.api.v1.module_common.file.schema import FileOutSchema from app.api.v1.module_energy.report_template.schema import EnergyReportTemplateOutSchema from app.common.enums import QueueEnum from app.core.base_params import BaseQueryParam, TenantByQueryParam, UserByQueryParam from app.core.base_schema import BaseSchema, CommonSchema, TenantBySchema, UserBySchema class EnergyReportGenerationCreateSchema(BaseModel): """能源报告生成任务创建模型。""" generation_name: str = Field(..., min_length=1, max_length=128, description="任务名称") report_type: int = Field(default=1, ge=1, le=2, description="报告类型 1:能源报告 2:光伏报告") template_id: int = Field(..., ge=1, description="能源报告模板ID") file_id: int | None = Field(default=None, ge=1, description="生成源文档文件ID") attachment_file_id: int | None = Field(default=None, ge=1, description="附件文件ID") status: int = Field(default=0, ge=0, le=3, description="状态 0:待生成 1:生成中 2:已生成 3:生成失败") generator_id: int | None = Field(default=None, ge=1, description="生成人ID") description: str | None = Field(default=None, max_length=500, description="描述") @field_validator("generation_name") @classmethod def validate_generation_name(cls, value: str) -> str: value = value.strip() if not value: raise ValueError("任务名称不能为空") return value @field_validator("status") @classmethod def validate_status(cls, value: int) -> int: if value not in {0, 1, 2, 3}: raise ValueError("状态仅支持 0(待生成)、1(生成中)、2(已生成)、3(生成失败)") return value @field_validator("report_type") @classmethod def validate_report_type(cls, value: int) -> int: if value not in {1, 2}: raise ValueError("报告类型仅支持 1(能源报告) 或 2(光伏报告)") return value class EnergyReportGenerationUpdateSchema(EnergyReportGenerationCreateSchema): """能源报告生成任务更新模型。""" class EnergyReportGenerationOutSchema(EnergyReportGenerationCreateSchema, BaseSchema, UserBySchema, TenantBySchema): """能源报告生成任务响应模型。""" model_config = ConfigDict(from_attributes=True) template: EnergyReportTemplateOutSchema | None = Field(default=None, description="能源报告模板") file: FileOutSchema | None = Field(default=None, description="生成源文档") attachment_file: FileOutSchema | None = Field(default=None, description="附件文件") generator: CommonSchema | None = Field(default=None, description="生成人") template_name: str | None = Field(default=None, description="模板名称") generator_name: str | None = Field(default=None, description="生成人名称") report_file_url: str | None = Field(default=None, description="报告文档访问地址") report_file_original_name: str | None = Field(default=None, description="报告文档原始名称") file_url: str | None = Field(default=None, description="文档访问地址") original_name: str | None = Field(default=None, description="文档原始名称") attachment_file_url: str | None = Field(default=None, description="附件文件访问地址") attachment_file_original_name: str | None = Field(default=None, description="附件文件原始名称") attachment_url: str | None = Field(default=None, description="附件下载地址") attachment_original_name: str | None = Field(default=None, description="附件原始名称") class EnergyReportGenerationStatsSchema(BaseModel): """能源报告生成任务统计模型。""" submitted_count: int = Field(default=0, description="提交任务数") generating_count: int = Field(default=0, description="生成中任务数") generated_count: int = Field(default=0, description="已生成任务数") pending_count: int = Field(default=0, description="待生成任务数") failed_count: int = Field(default=0, description="生成失败任务数") class EnergyReportGenerationPageOutSchema(BaseModel): """能源报告生成任务分页和统计响应模型。""" page_no: int = Field(description="当前页码") page_size: int = Field(description="每页数量") total: int = Field(description="总数") has_next: bool = Field(description="是否有下一页") stats: EnergyReportGenerationStatsSchema = Field(description="统计数据") items: list[dict] = Field(default_factory=list, description="列表数据") @dataclass class EnergyReportGenerationQueryParam(BaseQueryParam, UserByQueryParam, TenantByQueryParam): """能源报告生成任务查询参数。""" generation_name: str | None = Query(None, description="任务名称") report_type: int | None = Query(None, ge=1, le=2, description="报告类型 1:能源报告 2:光伏报告") status: int | None = Query(None, ge=0, le=3, description="状态 0:待生成 1:生成中 2:已生成 3:生成失败") template_id: int | None = Query(None, ge=1, description="模板ID") generator_id: int | None = Query(None, ge=1, description="生成人ID") def __post_init__(self) -> None: if self.generation_name: self.generation_name = (QueueEnum.like.value, self.generation_name) if isinstance(self.report_type, int): self.report_type = (QueueEnum.eq.value, self.report_type) if isinstance(self.status, int): self.status = (QueueEnum.eq.value, self.status) if isinstance(self.template_id, int): self.template_id = (QueueEnum.eq.value, self.template_id) if isinstance(self.generator_id, int): self.generator_id = (QueueEnum.eq.value, self.generator_id) ReportGenerationLogActionType = Literal["create_task", "start_generation", "generation_success", "generation_failed"] class EnergyReportGenerationLogCreateSchema(BaseModel): """能源报告生成操作记录创建模型。""" report_generation_id: int = Field(..., ge=1, description="能源报告生成任务ID") action_type: ReportGenerationLogActionType = Field(..., description="操作类型") description: str | None = Field(default=None, max_length=500, description="操作描述") generation_name: str = Field(default="", description="任务名称,由后端填充") action_name: str = Field(default="", description="操作名称,由后端填充") class EnergyReportGenerationLogOutSchema(EnergyReportGenerationLogCreateSchema, BaseSchema, UserBySchema, TenantBySchema): """能源报告生成操作记录响应模型。""" model_config = ConfigDict(from_attributes=True) generation: EnergyReportGenerationOutSchema | None = Field(default=None, description="生成任务") operator_id: int | None = Field(default=None, description="操作人ID") operator_name: str | None = Field(default=None, description="操作人名称") @dataclass class EnergyReportGenerationLogQueryParam(BaseQueryParam, UserByQueryParam, TenantByQueryParam): """能源报告生成操作记录查询参数。""" report_generation_id: int | None = Query(None, ge=1, description="生成任务ID") generation_name: str | None = Query(None, description="任务名称") action_type: ReportGenerationLogActionType | None = Query(None, description="操作类型") def __post_init__(self) -> None: if isinstance(self.report_generation_id, int): self.report_generation_id = (QueueEnum.eq.value, self.report_generation_id) if self.generation_name: self.generation_name = (QueueEnum.like.value, self.generation_name) if self.action_type: self.action_type = (QueueEnum.eq.value, self.action_type)