from django.db import models class SubmissionBatch(models.Model): """ 资料包主对象,承接导入、会话绑定和目录汇总结果。 Documents 模块负责维护资料包与文件的关系, 不在模型层耦合 Agent 执行细节。 """ STATUS_PENDING = "pending" STATUS_PROCESSING = "processing" STATUS_COMPLETED = "completed" STATUS_REVIEW_REQUIRED = "review_required" STATUS_FAILED = "failed" batch_id = models.CharField(max_length=64, unique=True, db_index=True) product_name = models.CharField(max_length=255, blank=True, db_index=True) workflow_type = models.CharField(max_length=64, default="registration") conversation_id = models.CharField(max_length=64, blank=True, db_index=True) file_count = models.PositiveIntegerField(default=0) page_count = models.PositiveIntegerField(default=0) chapter_summary = models.JSONField(default=list, blank=True) import_status = models.CharField(max_length=32, default=STATUS_PENDING, db_index=True) exception_count = models.PositiveIntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True, db_index=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["-created_at"] def __str__(self) -> str: return self.product_name or self.batch_id def get_import_status_display_text(self) -> str: return { self.STATUS_PENDING: "待导入", self.STATUS_PROCESSING: "处理中", self.STATUS_COMPLETED: "已完成", self.STATUS_REVIEW_REQUIRED: "待复核", self.STATUS_FAILED: "失败", }.get(self.import_status, self.import_status) class UploadedDocument(models.Model): """ 保存用户上传文档的元数据和入库状态。 设计上只记录“文件属于哪个场景、当前是否已入库、失败原因是什么”, 不把 RAG 细节耦合进模型层。 """ # 文档状态用于驱动前端提示和后续可操作项。 STATUS_UPLOADED = "uploaded" STATUS_INDEXED = "indexed" STATUS_FAILED = "failed" batch = models.ForeignKey( SubmissionBatch, related_name="documents", null=True, blank=True, on_delete=models.CASCADE, ) scenario_id = models.CharField(max_length=100, db_index=True) original_name = models.CharField(max_length=255) file = models.FileField(upload_to="documents/%Y%m%d/") file_type = models.CharField(max_length=20) size = models.PositiveIntegerField(default=0) relative_path = models.CharField(max_length=500, blank=True) chapter_code = models.CharField(max_length=32, blank=True) document_role = models.CharField(max_length=64, blank=True) page_count = models.PositiveIntegerField(default=0) page_count_confidence = models.CharField(max_length=32, blank=True) chapter_match_status = models.CharField(max_length=32, blank=True) needs_manual_review = models.BooleanField(default=False) status = models.CharField(max_length=20, default=STATUS_UPLOADED, db_index=True) error_message = models.TextField(blank=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["-created_at"] def __str__(self) -> str: return self.original_name def get_status_display_text(self) -> str: """为模板提供更适合演示的中文状态文案。""" return { self.STATUS_UPLOADED: "已上传,待入库", self.STATUS_INDEXED: "已入库,可检索", self.STATUS_FAILED: "入库失败", }.get(self.status, self.status) class ExportedDocument(models.Model): """ 导出文件记录。 该对象属于资料包治理范围: - Documents 维护导出产物与资料包关系 - Chat 只负责触发导出动作 - Audit 负责回看执行痕迹 """ batch = models.ForeignKey( SubmissionBatch, related_name="export_records", on_delete=models.CASCADE, ) conversation_id = models.CharField(max_length=64, db_index=True) product_name = models.CharField(max_length=255, blank=True, db_index=True) template_name = models.CharField(max_length=100, blank=True) template_version = models.CharField(max_length=50, blank=True) export_mode = models.CharField(max_length=32, db_index=True) output_type = models.CharField(max_length=100, default="registration_word_export_report") file_name = models.CharField(max_length=255) relative_path = models.CharField(max_length=500) download_url = models.CharField(max_length=500, blank=True) created_at = models.DateTimeField(auto_now_add=True, db_index=True) class Meta: ordering = ["-created_at"] def __str__(self) -> str: return self.file_name