feat: 增强审核智能体页Word导出能力卡展示
This commit is contained in:
@@ -85,6 +85,7 @@ def detail(request, conversation_id: str):
|
|||||||
active_node = "risk"
|
active_node = "risk"
|
||||||
conversation.refresh_from_db()
|
conversation.refresh_from_db()
|
||||||
workspace_summary = _build_workspace_summary(conversation, batch)
|
workspace_summary = _build_workspace_summary(conversation, batch)
|
||||||
|
export_card = _build_export_card(result, conversation)
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
@@ -103,6 +104,7 @@ def detail(request, conversation_id: str):
|
|||||||
"active_node": active_node,
|
"active_node": active_node,
|
||||||
"workspace_summary": workspace_summary,
|
"workspace_summary": workspace_summary,
|
||||||
"upload_form": upload_form,
|
"upload_form": upload_form,
|
||||||
|
"export_card": export_card,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -240,6 +242,29 @@ def _build_workspace_summary(conversation: Conversation, batch: SubmissionBatch
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _build_export_card(result: AgentResult | None, conversation: Conversation) -> dict:
|
||||||
|
"""
|
||||||
|
统一组装 Word 导出能力卡上下文。
|
||||||
|
|
||||||
|
优先使用本次执行结果;若本次未执行,则回退到会话最新摘要。
|
||||||
|
"""
|
||||||
|
structured_output = {}
|
||||||
|
if result and result.structured_output:
|
||||||
|
structured_output = result.structured_output
|
||||||
|
else:
|
||||||
|
structured_output = (conversation.latest_summary or {}).get("structured_output") or {}
|
||||||
|
if structured_output.get("output_type") != "registration_word_export_report":
|
||||||
|
return {}
|
||||||
|
return {
|
||||||
|
"template_name": structured_output.get("template_name", ""),
|
||||||
|
"template_version": structured_output.get("template_version", ""),
|
||||||
|
"export_status": structured_output.get("export_status", ""),
|
||||||
|
"filled_fields": structured_output.get("filled_fields") or [],
|
||||||
|
"blocked_fields": structured_output.get("blocked_fields") or [],
|
||||||
|
"download_url": structured_output.get("download_url", ""),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _apply_agent_result_to_conversation(conversation: Conversation, result: AgentResult) -> None:
|
def _apply_agent_result_to_conversation(conversation: Conversation, result: AgentResult) -> None:
|
||||||
conversation.task_status = result.status
|
conversation.task_status = result.status
|
||||||
if result.node_results:
|
if result.node_results:
|
||||||
|
|||||||
@@ -88,7 +88,68 @@
|
|||||||
|
|
||||||
<article class="panel">
|
<article class="panel">
|
||||||
<h2 class="section-title">节点式结果</h2>
|
<h2 class="section-title">节点式结果</h2>
|
||||||
{% if result and result.structured_output %}
|
{% if export_card %}
|
||||||
|
<div class="stack">
|
||||||
|
<div class="detail-item">
|
||||||
|
<strong>Word 导出能力卡</strong>
|
||||||
|
<div>模板:{{ export_card.template_name }} / {{ export_card.template_version|default:"-" }}</div>
|
||||||
|
<div>当前导出状态:{{ export_card.export_status|default:"-" }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel" style="padding: 14px;">
|
||||||
|
<h3 class="section-title" style="font-size: 1rem;">回填字段表</h3>
|
||||||
|
<div class="table-wrap">
|
||||||
|
<table class="data-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>占位符</th>
|
||||||
|
<th>字段名</th>
|
||||||
|
<th>字段值</th>
|
||||||
|
<th>来源</th>
|
||||||
|
<th>回填状态</th>
|
||||||
|
<th>是否必填</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in export_card.filled_fields %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ item.placeholder }}</td>
|
||||||
|
<td>{{ item.field_name }}</td>
|
||||||
|
<td>{{ item.field_value }}</td>
|
||||||
|
<td>{{ item.source }}</td>
|
||||||
|
<td>{{ item.fill_status }}</td>
|
||||||
|
<td>{{ item.required|yesno:"是,否" }}</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td colspan="6">当前暂无回填字段。</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel" style="padding: 14px;">
|
||||||
|
<h3 class="section-title" style="font-size: 1rem;">拦截项区</h3>
|
||||||
|
<ul class="detail-list">
|
||||||
|
{% for item in export_card.blocked_fields %}
|
||||||
|
<li class="detail-item">
|
||||||
|
<strong>{{ item.field_name }}</strong>
|
||||||
|
<div>拦截原因:{{ item.block_reason }}</div>
|
||||||
|
<div class="muted">来源:{{ item.risk_source }}</div>
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<li class="detail-item">当前无拦截项。</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-row">
|
||||||
|
<a class="button" href="{% url 'platform_ui:knowledge-base' %}?view=template_mappings">维护 Word 模板</a>
|
||||||
|
<a class="button" href="{% url 'platform_ui:knowledge-base' %}?view=field_schemas">维护字段映射</a>
|
||||||
|
<a class="button" href="{% url 'audit:list' %}">查看导出记录</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% elif result and result.structured_output %}
|
||||||
<table class="kv-table">
|
<table class="kv-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for key, value in result.structured_output.items %}
|
{% for key, value in result.structured_output.items %}
|
||||||
|
|||||||
@@ -433,6 +433,60 @@ def test_chat_page_uses_structured_formal_export_flag_when_node_status_is_comple
|
|||||||
assert "/downloads/review-only.docx" in content
|
assert "/downloads/review-only.docx" in content
|
||||||
|
|
||||||
|
|
||||||
|
def test_chat_page_shows_word_export_field_table_and_governance_entries(client, db):
|
||||||
|
batch, conversation = _create_conversation_with_batch()
|
||||||
|
conversation.node_results = [
|
||||||
|
{"label": "资料包导入", "status": "已完成"},
|
||||||
|
{"label": "目录汇总", "status": "已完成"},
|
||||||
|
{"label": "法规完整性检查", "status": "已完成"},
|
||||||
|
{"label": "字段抽取", "status": "已完成"},
|
||||||
|
{"label": "一致性核查", "status": "已完成"},
|
||||||
|
{"label": "风险预警", "status": "已阻断"},
|
||||||
|
{"label": "Word 回填导出", "status": "待复核"},
|
||||||
|
{"label": "飞书通知", "status": "待处理"},
|
||||||
|
]
|
||||||
|
conversation.latest_summary = {
|
||||||
|
"structured_output": {
|
||||||
|
"output_type": "registration_word_export_report",
|
||||||
|
"template_name": "注册证导出模板",
|
||||||
|
"template_version": "V1.0",
|
||||||
|
"export_status": "draft_only",
|
||||||
|
"filled_fields": [
|
||||||
|
{
|
||||||
|
"placeholder": "{{ product_name }}",
|
||||||
|
"field_name": "产品名称",
|
||||||
|
"field_value": "新型冠状病毒 2019-nCoV 核酸检测试剂盒",
|
||||||
|
"source": "资料包主信息",
|
||||||
|
"fill_status": "filled",
|
||||||
|
"required": True,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"blocked_fields": [
|
||||||
|
{
|
||||||
|
"field_name": "产品名称跨文档不一致",
|
||||||
|
"block_reason": "待人工复核",
|
||||||
|
"risk_source": "registration_risk_report",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"download_url": "/media/exports/20260604/SUB-20260604-001-draft.docx",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conversation.save(update_fields=["node_results", "latest_summary", "updated_at"])
|
||||||
|
|
||||||
|
response = client.get(reverse("chat:detail", args=[conversation.conversation_id]))
|
||||||
|
|
||||||
|
content = response.content.decode("utf-8")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "Word 导出能力卡" in content
|
||||||
|
assert "回填字段表" in content
|
||||||
|
assert "产品名称" in content
|
||||||
|
assert "资料包主信息" in content
|
||||||
|
assert "拦截项区" in content
|
||||||
|
assert "产品名称跨文档不一致" in content
|
||||||
|
assert "维护 Word 模板" in content
|
||||||
|
assert "维护字段映射" in content
|
||||||
|
|
||||||
|
|
||||||
def test_chat_upload_keeps_existing_conversation_binding_and_adds_documents(client, db):
|
def test_chat_upload_keeps_existing_conversation_binding_and_adds_documents(client, db):
|
||||||
batch, conversation = _create_conversation_with_batch()
|
batch, conversation = _create_conversation_with_batch()
|
||||||
existing_document = UploadedDocument.objects.create(
|
existing_document = UploadedDocument.objects.create(
|
||||||
|
|||||||
Reference in New Issue
Block a user