feat: 增强处理历史详情导出与通知回执展示
This commit is contained in:
@@ -142,3 +142,25 @@ def build_history_rows(logs) -> list[dict]:
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
return rows
|
return rows
|
||||||
|
|
||||||
|
|
||||||
|
def build_detail_summary(log: AgentAuditLog, conversation, notifications) -> dict:
|
||||||
|
"""
|
||||||
|
组装处理历史详情页的导出摘要与通知回执信息。
|
||||||
|
|
||||||
|
详情页模板只负责展示,字段拼装与优先级判断统一放在服务层。
|
||||||
|
"""
|
||||||
|
structured_output = log.structured_output or {}
|
||||||
|
export_node = None
|
||||||
|
if conversation and conversation.node_results:
|
||||||
|
export_node = next(
|
||||||
|
(node for node in conversation.node_results if node.get("label") == "Word 回填导出"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
latest_notification = notifications.first() if hasattr(notifications, "first") else None
|
||||||
|
return {
|
||||||
|
"export_status": structured_output.get("export_status") or (export_node or {}).get("status", "-"),
|
||||||
|
"download_url": structured_output.get("download_url", ""),
|
||||||
|
"blocked_items": structured_output.get("blocked_items") or [],
|
||||||
|
"notification_receipt": latest_notification.receipt if latest_notification else {},
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from django.shortcuts import get_object_or_404, render
|
|||||||
|
|
||||||
from .models import AgentAuditLog, NotificationRecord
|
from .models import AgentAuditLog, NotificationRecord
|
||||||
from apps.chat.models import Conversation
|
from apps.chat.models import Conversation
|
||||||
from .services import build_history_rows
|
from .services import build_detail_summary, build_history_rows
|
||||||
|
|
||||||
|
|
||||||
def log_list(request):
|
def log_list(request):
|
||||||
@@ -57,8 +57,14 @@ def log_detail(request, log_id: int):
|
|||||||
batch_id=audit_log.batch_id,
|
batch_id=audit_log.batch_id,
|
||||||
)
|
)
|
||||||
conversation = Conversation.objects.filter(conversation_id=audit_log.conversation_id).first()
|
conversation = Conversation.objects.filter(conversation_id=audit_log.conversation_id).first()
|
||||||
|
detail_summary = build_detail_summary(audit_log, conversation, notifications)
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"audit/log_detail.html",
|
"audit/log_detail.html",
|
||||||
{"log": audit_log, "notifications": notifications, "conversation": conversation},
|
{
|
||||||
|
"log": audit_log,
|
||||||
|
"notifications": notifications,
|
||||||
|
"conversation": conversation,
|
||||||
|
"detail_summary": detail_summary,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -52,6 +52,29 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="grid-2">
|
||||||
|
<article class="panel">
|
||||||
|
<h2 class="section-title">导出状态摘要</h2>
|
||||||
|
<ul class="detail-list">
|
||||||
|
<li class="detail-item"><strong>导出状态</strong><div>{{ detail_summary.export_status|default:"-" }}</div></li>
|
||||||
|
<li class="detail-item"><strong>下载地址</strong><div>{{ detail_summary.download_url|default:"-" }}</div></li>
|
||||||
|
<li class="detail-item">
|
||||||
|
<strong>阻断项</strong>
|
||||||
|
{% if detail_summary.blocked_items %}
|
||||||
|
<div>{{ detail_summary.blocked_items|join:" / " }}</div>
|
||||||
|
{% else %}
|
||||||
|
<div>-</div>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="panel">
|
||||||
|
<h2 class="section-title">通知回执</h2>
|
||||||
|
<pre class="code-block">{{ detail_summary.notification_receipt }}</pre>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="panel">
|
<section class="panel">
|
||||||
<h2 class="section-title">通知留痕</h2>
|
<h2 class="section-title">通知留痕</h2>
|
||||||
<div class="table-wrap">
|
<div class="table-wrap">
|
||||||
|
|||||||
@@ -397,3 +397,57 @@ def test_audit_list_shows_batch_scale_and_conversation_status(client, db):
|
|||||||
assert "会话状态" in content
|
assert "会话状态" in content
|
||||||
assert "failed" in content
|
assert "failed" in content
|
||||||
assert "待复核" in content
|
assert "待复核" in content
|
||||||
|
|
||||||
|
|
||||||
|
def test_audit_detail_page_shows_export_summary_and_notification_receipt(client, db):
|
||||||
|
Conversation.objects.create(
|
||||||
|
conversation_id="conv-002",
|
||||||
|
title="产品B",
|
||||||
|
product_name="产品B",
|
||||||
|
batch_id="SUB-20260604-002",
|
||||||
|
task_status="success",
|
||||||
|
node_results=[
|
||||||
|
{"label": "Word 回填导出", "status": "待复核"},
|
||||||
|
{"label": "飞书通知", "status": "已完成"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
log = create_audit_log(
|
||||||
|
"document_review",
|
||||||
|
"注册审核智能体",
|
||||||
|
"导出任务",
|
||||||
|
AgentResult(
|
||||||
|
answer="已生成导出草稿",
|
||||||
|
status="success",
|
||||||
|
structured_output={
|
||||||
|
"export_status": "draft_only",
|
||||||
|
"download_url": "/downloads/registration-report.docx",
|
||||||
|
"blocked_items": ["风险项未清零"],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
batch_id="SUB-20260604-002",
|
||||||
|
conversation_id="conv-002",
|
||||||
|
product_name="产品B",
|
||||||
|
)
|
||||||
|
create_notification_record(
|
||||||
|
batch_id="SUB-20260604-002",
|
||||||
|
conversation_id="conv-002",
|
||||||
|
product_name="产品B",
|
||||||
|
trigger_source="word_export",
|
||||||
|
notify_reason="task_completed",
|
||||||
|
owner_role="注册资料负责人",
|
||||||
|
feishu_user_id="ou_demo_9",
|
||||||
|
message_status="sent",
|
||||||
|
web_detail_url="https://example.com/detail/9",
|
||||||
|
receipt={"message_id": "msg-9", "status": "sent"},
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.get(reverse("audit:detail", args=[log.id]))
|
||||||
|
|
||||||
|
content = response.content.decode("utf-8")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "导出状态摘要" in content
|
||||||
|
assert "draft_only" in content
|
||||||
|
assert "/downloads/registration-report.docx" in content
|
||||||
|
assert "风险项未清零" in content
|
||||||
|
assert "通知回执" in content
|
||||||
|
assert "msg-9" in content
|
||||||
|
|||||||
Reference in New Issue
Block a user