feat: 补齐Word导出报告结构化字段口径

This commit is contained in:
2026-06-04 02:44:50 +08:00
parent ab3d520642
commit 08dcb62834
2 changed files with 80 additions and 8 deletions

View File

@@ -6,6 +6,7 @@ from xml.sax.saxutils import escape
import zipfile
from django.conf import settings
from django.utils import timezone
from agent_core.governance import load_governance_config
from apps.documents.services import create_export_record
@@ -31,6 +32,8 @@ def generate_registration_export(*, batch, conversation, upstream_summary: dict
absolute_path.parent.mkdir(parents=True, exist_ok=True)
fillable_items = _build_fillable_items(batch, conversation)
filled_fields = _build_filled_fields(fillable_items)
blocked_fields = _build_blocked_fields(blocked_items)
_write_minimal_docx(
absolute_path,
product_name=batch.product_name or conversation.product_name or "未命名资料包",
@@ -59,11 +62,13 @@ def generate_registration_export(*, batch, conversation, upstream_summary: dict
"formal_export_status": "completed" if can_export_formally else "blocked",
"can_export_formally": can_export_formally,
"fillable_items": fillable_items,
"filled_fields": filled_fields,
"fillable_field_count": len(fillable_items),
"filled_field_count": len(fillable_items),
"filled_field_count": len(filled_fields),
"blocked_items": blocked_items,
"blocked_field_count": len(blocked_items),
"manual_review_field_count": len(blocked_items),
"blocked_fields": blocked_fields,
"blocked_field_count": len(blocked_fields),
"manual_review_field_count": len(blocked_fields),
"layout_check_status": "passed",
"download_url": download_url,
"output_file": {
@@ -71,6 +76,8 @@ def generate_registration_export(*, batch, conversation, upstream_summary: dict
"relative_path": relative_path.as_posix(),
"absolute_path": str(absolute_path),
"export_mode": export_mode,
"output_version": export_mode,
"generated_at": timezone.now().isoformat(),
},
}
create_export_record(
@@ -142,11 +149,71 @@ def _can_export_formally(upstream_summary: dict, blocked_items: list[str]) -> bo
def _build_fillable_items(batch, conversation) -> list[dict]:
return [
{"placeholder": "{{ product_name }}", "field_name": "产品名称", "field_value": batch.product_name},
{"placeholder": "{{ batch_id }}", "field_name": "批次号", "field_value": batch.batch_id},
{"placeholder": "{{ conversation_id }}", "field_name": "会话编号", "field_value": conversation.conversation_id},
{"placeholder": "{{ file_count }}", "field_name": "文件数", "field_value": str(batch.file_count)},
{"placeholder": "{{ page_count }}", "field_name": "页数", "field_value": str(batch.page_count)},
{
"placeholder": "{{ product_name }}",
"field_name": "产品名称",
"field_value": batch.product_name,
"source": "资料包主信息",
"fill_status": "filled",
"required": True,
},
{
"placeholder": "{{ batch_id }}",
"field_name": "批次号",
"field_value": batch.batch_id,
"source": "资料包主信息",
"fill_status": "filled",
"required": True,
},
{
"placeholder": "{{ conversation_id }}",
"field_name": "会话编号",
"field_value": conversation.conversation_id,
"source": "会话主信息",
"fill_status": "filled",
"required": True,
},
{
"placeholder": "{{ file_count }}",
"field_name": "文件数",
"field_value": str(batch.file_count),
"source": "资料包统计",
"fill_status": "filled",
"required": False,
},
{
"placeholder": "{{ page_count }}",
"field_name": "页数",
"field_value": str(batch.page_count),
"source": "资料包统计",
"fill_status": "filled",
"required": False,
},
]
def _build_filled_fields(fillable_items: list[dict]) -> list[dict]:
return [
{
"placeholder": item["placeholder"],
"field_name": item["field_name"],
"field_value": item["field_value"],
"source": item["source"],
"fill_status": item["fill_status"],
"required": item["required"],
}
for item in fillable_items
]
def _build_blocked_fields(blocked_items: list[str]) -> list[dict]:
return [
{
"field_name": item,
"block_reason": "待人工复核",
"risk_source": "registration_risk_report",
}
for item in blocked_items
]

View File

@@ -497,6 +497,11 @@ def test_generate_registration_export_creates_real_docx_file(db, tmp_path, setti
assert report["output_type"] == "registration_word_export_report"
assert report["can_export_formally"] is False
assert report["export_status"] == "draft_only"
assert report["filled_fields"][0]["field_name"] == "产品名称"
assert report["filled_fields"][0]["fill_status"] == "filled"
assert report["blocked_fields"][0]["block_reason"] == "待人工复核"
assert report["output_file"]["output_version"] == "draft"
assert report["output_file"]["generated_at"]
assert report["download_url"].startswith("/media/exports/")
assert export_path.exists()
with zipfile.ZipFile(export_path) as archive: