feat: 新增归档中心页面并完善知识库与报销查询能力

新增前端归档中心视图及相关工具函数,扩充知识库文档分类和
提取器支持多种格式,增强编排器报销查询的多维度检索,优
化本体规则和用户代理审核消息,前端完善报销创建和审批详
情交互细节,补充单元测试覆盖。
This commit is contained in:
caoxiaozhu
2026-05-22 16:00:19 +08:00
parent 1f15699013
commit 88ff04bef8
120 changed files with 6236 additions and 643 deletions

View File

@@ -700,6 +700,37 @@ def test_user_agent_guides_riding_fare_as_transport_expense() -> None:
assert "“交通费”" in response.review_payload.intent_summary
def test_user_agent_keeps_taxi_ticket_for_customer_dropoff_as_transport_expense() -> None:
session_factory = build_session_factory()
with session_factory() as db:
message = "送客户去机场,报销的士票"
ontology = SemanticOntologyService(db).parse(
OntologyParseRequest(
query=message,
user_id="pytest",
)
)
response = UserAgentService(db).respond(
UserAgentRequest(
run_id=ontology.run_id,
user_id="pytest",
message=message,
ontology=ontology,
tool_payload={"draft_only": True},
)
)
assert ontology.intent == "draft"
assert response.review_payload is not None
slot_map = {item.key: item for item in response.review_payload.slot_cards}
assert slot_map["expense_type"].value == "交通费"
assert slot_map["expense_type"].normalized_value == "transport"
assert slot_map["reason"].value == "送客户去机场,报销的士票"
assert "业务招待费" not in response.review_payload.intent_summary
assert "客户名称" not in response.review_payload.missing_slots
assert "参与人员" not in response.review_payload.missing_slots
def test_user_agent_keeps_travel_range_when_user_adds_receipts_after_text_context() -> None:
session_factory = build_session_factory()
with session_factory() as db:
@@ -1060,6 +1091,40 @@ def test_user_agent_returns_draft_limit_message_when_save_is_blocked() -> None:
)
def test_user_agent_save_draft_answer_guides_followup_to_existing_draft() -> None:
session_factory = build_session_factory()
with session_factory() as db:
context_json = {"review_action": "save_draft"}
ontology = SemanticOntologyService(db).parse(
OntologyParseRequest(
query="请按当前识别信息保存报销草稿",
user_id="pytest",
context_json=context_json,
)
)
response = UserAgentService(db).respond(
UserAgentRequest(
run_id=ontology.run_id,
user_id="pytest",
message="请按当前识别信息保存报销草稿",
ontology=ontology,
context_json=context_json,
tool_payload={
"claim_id": "claim-1",
"claim_no": "BX202605220001",
"status": "draft",
"approval_stage": "待提交",
},
)
)
assert response.draft_payload is not None
assert response.draft_payload.claim_no == "BX202605220001"
assert "已按您当前确认的信息保存为草稿 BX202605220001" in response.answer
assert "请关联这张草稿" in response.answer
assert "继续保存草稿" not in response.answer
def test_user_agent_returns_submitted_draft_payload_for_review_next_step() -> None:
session_factory = build_session_factory()
with session_factory() as db:
@@ -2022,6 +2087,8 @@ def test_user_agent_filters_deprecated_review_risk_briefs() -> None:
def test_user_agent_submission_blocked_risk_level_only_marks_amount_reasons_high() -> None:
assert UserAgentService._resolve_submission_blocked_risk_level("住宿金额超出当前职级差标") == "high"
assert UserAgentService._resolve_submission_blocked_risk_level("缺少直属领导或参与人员信息") == "warning"
assert UserAgentService._is_submission_exception_explanation_reason("住宿金额超出当前职级差标,且未补充超标说明。")
assert not UserAgentService._is_submission_exception_explanation_reason("缺少直属领导或参与人员信息")
def test_user_agent_review_payload_shows_ai_precheck_failure_in_main_message() -> None:
@@ -2066,11 +2133,13 @@ def test_user_agent_review_payload_shows_ai_precheck_failure_in_main_message() -
assert response.review_payload is not None
assert response.answer == response.review_payload.body_message
assert response.answer.startswith("AI预审未通过住宿金额超出当前职级差标")
assert "整改后再继续提交" in response.answer
assert response.answer.startswith("检测到当前单据存在需要说明的超标风险")
assert "票据会先正常归集到单据中" in response.answer
assert "附加说明" in response.answer
assert response.review_payload.can_proceed is False
blocked_brief = next(item for item in response.review_payload.risk_briefs if item.title == "提交风险提示")
assert blocked_brief.level == "high"
assert "不是票据归集阻断条件" in blocked_brief.detail
assert not any(item.title == "AI预审未通过" for item in response.review_payload.risk_briefs)