diff --git a/app/api/v1/module_energy/report_review/model.py b/app/api/v1/module_energy/report_review/model.py index 26c3366..09d9834 100644 --- a/app/api/v1/module_energy/report_review/model.py +++ b/app/api/v1/module_energy/report_review/model.py @@ -12,6 +12,7 @@ class EnergyReportReviewModel(ModelMixin, TenantMixin, UserMixin): __loader_options__: list[str] = [ "template", "file", + "attachment_file", "reviewer", "created_by", "updated_by", @@ -34,7 +35,26 @@ class EnergyReportReviewModel(ModelMixin, TenantMixin, UserMixin): index=True, comment="审核文档文件ID", ) - status: Mapped[int] = mapped_column(Integer, default=0, nullable=False, comment="状态 0:待审查 1:审核通过 2:审核不通过", index=True) + attachment_file_id: Mapped[int | None] = mapped_column( + Integer, + ForeignKey("common_file.id", ondelete="SET NULL", onupdate="CASCADE"), + nullable=True, + index=True, + comment="附件文件ID", + ) + attachment_url: Mapped[str | None] = mapped_column( + String(512), + default=None, + nullable=True, + comment="附件下载地址", + ) + status: Mapped[int] = mapped_column( + Integer, + default=0, + nullable=False, + comment="状态 0:待审查 1:审核通过 2:审核不通过", + index=True, + ) reviewer_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("sys_user.id", ondelete="SET NULL", onupdate="CASCADE"), @@ -46,6 +66,12 @@ class EnergyReportReviewModel(ModelMixin, TenantMixin, UserMixin): template = relationship("EnergyReportTemplateModel", lazy="selectin", foreign_keys=[template_id], uselist=False) file = relationship("FileModel", lazy="selectin", foreign_keys=[file_id], uselist=False) + attachment_file = relationship( + "FileModel", + lazy="selectin", + foreign_keys=[attachment_file_id], + uselist=False, + ) reviewer = relationship("UserModel", lazy="selectin", foreign_keys=[reviewer_id], uselist=False) diff --git a/app/api/v1/module_energy/report_review/schema.py b/app/api/v1/module_energy/report_review/schema.py index 2bb7665..018c1fe 100644 --- a/app/api/v1/module_energy/report_review/schema.py +++ b/app/api/v1/module_energy/report_review/schema.py @@ -17,6 +17,7 @@ class EnergyReportReviewCreateSchema(BaseModel): task_name: str = Field(..., min_length=1, max_length=128, description="任务名称") template_id: int = Field(..., 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=2, description="状态 0:待审查 1:审核通过 2:审核不通过") reviewer_id: int | None = Field(default=None, ge=1, description="审查人ID") description: str | None = Field(default=None, max_length=500, description="描述") @@ -48,11 +49,14 @@ class EnergyReportReviewOutSchema(EnergyReportReviewCreateSchema, BaseSchema, Us 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="审查人名称") file_url: str | None = Field(default=None, description="文档访问地址") 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): diff --git a/app/api/v1/module_energy/report_review/service.py b/app/api/v1/module_energy/report_review/service.py index 984c363..7c92bb8 100644 --- a/app/api/v1/module_energy/report_review/service.py +++ b/app/api/v1/module_energy/report_review/service.py @@ -1,4 +1,5 @@ from app.api.v1.module_common.file.crud import FileCRUD +from app.api.v1.module_common.file.service import FileService from app.api.v1.module_energy.report_template.crud import EnergyReportTemplateCRUD from app.api.v1.module_system.user.crud import UserCRUD from app.core.base_schema import AuthSchema, PageResultSchema @@ -66,9 +67,17 @@ class EnergyReportReviewService: async def create(self, data: EnergyReportReviewCreateSchema) -> EnergyReportReviewOutSchema: await self._validate_template(template_id=data.template_id) await self._validate_file(file_id=data.file_id) + attachment_file = await self._validate_attachment_file( + attachment_file_id=data.attachment_file_id, + file_id=data.file_id, + ) await self._validate_reviewer(reviewer_id=data.reviewer_id) - review = await EnergyReportReviewCRUD(self.auth).create(data=data) + create_data = data.model_dump() + create_data["attachment_url"] = attachment_file.file_url if attachment_file else None + review = await EnergyReportReviewCRUD(self.auth).create(data=create_data) await self._bind_file(file_id=data.file_id, review_id=review.id) + if data.attachment_file_id: + await self._bind_file(file_id=data.attachment_file_id, review_id=review.id) await EnergyReportReviewLogService(self.auth).create_system_log( report_review_id=review.id, task_name=review.task_name, @@ -81,11 +90,26 @@ class EnergyReportReviewService: old_review = await EnergyReportReviewCRUD(self.auth).get_or_404(id=id, msg="更新失败,能源报告审核任务不存在") await self._validate_template(template_id=data.template_id) await self._validate_file(file_id=data.file_id, current_review_id=id) + if old_review.attachment_file_id and old_review.attachment_file_id == data.file_id: + raise CustomException(msg="更新失败,上传文档不能使用原附件文件") + if old_review.file_id == data.attachment_file_id: + raise CustomException(msg="更新失败,附件不能使用原审核文档文件") + attachment_file = await self._validate_attachment_file( + attachment_file_id=data.attachment_file_id, + file_id=data.file_id, + current_review_id=id, + ) await self._validate_reviewer(reviewer_id=data.reviewer_id) - review = await EnergyReportReviewCRUD(self.auth).update(id=id, data=data) + update_data = data.model_dump(exclude_unset=True) + update_data["attachment_url"] = attachment_file.file_url if attachment_file else None + review = await EnergyReportReviewCRUD(self.auth).update(id=id, data=update_data) if old_review.file_id != data.file_id: - await self._unbind_file(file_id=old_review.file_id, review_id=id) + await self._delete_file_record(file_id=old_review.file_id) await self._bind_file(file_id=data.file_id, review_id=id) + if data.attachment_file_id: + await self._bind_file(file_id=data.attachment_file_id, review_id=id) + if old_review.attachment_file_id and old_review.attachment_file_id != data.attachment_file_id: + await self._delete_file_record(file_id=old_review.attachment_file_id) return self._to_out_schema(review) async def delete(self, ids: list[int]) -> None: @@ -122,6 +146,9 @@ class EnergyReportReviewService: if review_out.file: review_out.file_url = review_out.file.file_url review_out.original_name = review_out.file.original_name + if review_out.attachment_file: + review_out.attachment_url = review_out.attachment_file.file_url + review_out.attachment_original_name = review_out.attachment_file.original_name if hasattr(review, "reviewer") and review.reviewer: review_out.reviewer_name = review.reviewer.name return review_out @@ -129,10 +156,13 @@ class EnergyReportReviewService: def _fill_out_dict(self, item: dict) -> dict: template_info = item.get("template") or {} file_info = item.get("file") or {} + attachment_file_info = item.get("attachment_file") or {} reviewer_info = item.get("reviewer") or {} item["template_name"] = template_info.get("template_name") item["file_url"] = file_info.get("file_url") item["original_name"] = file_info.get("original_name") + item["attachment_url"] = attachment_file_info.get("file_url") or item.get("attachment_url") + item["attachment_original_name"] = attachment_file_info.get("original_name") item["reviewer_name"] = reviewer_info.get("name") return item @@ -150,6 +180,25 @@ class EnergyReportReviewService: if file_record.business_id and file_record.business_id != current_review_id: raise CustomException(msg="文件已绑定到其他能源报告审核任务") + async def _validate_attachment_file( + self, + attachment_file_id: int | None, + file_id: int, + current_review_id: int | None = None, + ): + if attachment_file_id is None: + return None + if attachment_file_id == file_id: + raise CustomException(msg="附件文件不能和上传文档相同") + file_record = await FileCRUD(self.auth).get(id=attachment_file_id) + if not file_record: + raise CustomException(msg="附件文件记录不存在") + if file_record.business_type and file_record.business_type != ENERGY_REPORT_REVIEW_BUSINESS_TYPE: + raise CustomException(msg="附件文件已绑定到其他业务类型") + if file_record.business_id and file_record.business_id != current_review_id: + raise CustomException(msg="附件文件已绑定到其他能源报告审核任务") + return file_record + async def _validate_reviewer(self, reviewer_id: int | None) -> None: if reviewer_id is None: return @@ -171,6 +220,9 @@ class EnergyReportReviewService: if file_record.business_type == ENERGY_REPORT_REVIEW_BUSINESS_TYPE and file_record.business_id == review_id: await FileCRUD(self.auth).set(ids=[file_id], business_id=None) + async def _delete_file_record(self, file_id: int) -> None: + await FileService.delete_service(auth=self.auth, ids=[file_id], delete_object=True) + class EnergyReportReviewLogService: """能源报告审核操作记录服务。"""