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 EnergyReportReviewCreateSchema(BaseModel): """能源报告审核任务创建模型。""" task_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 | None = Field(default=None, ge=1, description="能源报告模板ID") file_id: int = Field(..., 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:审查失败") reviewer_id: int | None = Field(default=None, ge=1, description="审查人ID") description: str | None = Field(default=None, max_length=500, description="描述") @field_validator("task_name") @classmethod def validate_task_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 EnergyReportReviewUpdateSchema(EnergyReportReviewCreateSchema): """能源报告审核任务更新模型。""" class EnergyReportReviewOutSchema(EnergyReportReviewCreateSchema, 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="附件文件") reviewer: CommonSchema | None = Field(default=None, description="审查人") template_name: str | None = Field(default=None, description="模板名称") reviewer_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 EnergyReportReviewStatsSchema(BaseModel): """能源报告审核任务统计模型。""" submitted_count: int = Field(default=0, description="提交任务数") reviewing_count: int = Field(default=0, description="审查中任务数") reviewed_count: int = Field(default=0, description="已审查任务数") pending_count: int = Field(default=0, description="待审查任务数") failed_count: int = Field(default=0, description="审查失败任务数") class EnergyReportReviewPageOutSchema(BaseModel): """能源报告审核任务分页和统计响应模型。""" page_no: int = Field(description="当前页码") page_size: int = Field(description="每页数量") total: int = Field(description="总数") has_next: bool = Field(description="是否有下一页") stats: EnergyReportReviewStatsSchema = Field(description="统计数据") items: list[dict] = Field(default_factory=list, description="列表数据") @dataclass class EnergyReportReviewQueryParam(BaseQueryParam, UserByQueryParam, TenantByQueryParam): """能源报告审核任务查询参数。""" task_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") reviewer_id: int | None = Query(None, ge=1, description="审查人ID") def __post_init__(self) -> None: if self.task_name: self.task_name = (QueueEnum.like.value, self.task_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.reviewer_id, int): self.reviewer_id = (QueueEnum.eq.value, self.reviewer_id) ReportReviewLogActionType = Literal["create_task", "start_review", "review_pass", "review_reject"] class EnergyReportReviewLogCreateSchema(BaseModel): """能源报告审核操作记录创建模型。""" report_review_id: int = Field(..., ge=1, description="能源报告审核任务ID") action_type: ReportReviewLogActionType = Field(..., description="操作类型") description: str | None = Field(default=None, max_length=500, description="操作描述") task_name: str = Field(default="", description="任务名称,由后端填充") action_name: str = Field(default="", description="操作名称,由后端填充") class EnergyReportReviewLogOutSchema(EnergyReportReviewLogCreateSchema, BaseSchema, UserBySchema, TenantBySchema): """能源报告审核操作记录响应模型。""" model_config = ConfigDict(from_attributes=True) task_name: str = Field(description="任务名称") action_name: str = Field(description="操作名称") operator_id: int | None = Field(default=None, description="操作人ID") operator_name: str | None = Field(default=None, description="操作人名称") @dataclass class EnergyReportReviewLogQueryParam(BaseQueryParam, UserByQueryParam, TenantByQueryParam): """能源报告审核操作记录查询参数。""" report_review_id: int | None = Query(None, ge=1, description="能源报告审核任务ID") task_name: str | None = Query(None, description="任务名称") action_type: str | None = Query(None, description="操作类型") def __post_init__(self) -> None: if isinstance(self.report_review_id, int): self.report_review_id = (QueueEnum.eq.value, self.report_review_id) if self.task_name: self.task_name = (QueueEnum.like.value, self.task_name) if self.action_type: self.action_type = (QueueEnum.eq.value, self.action_type)