feat: 重构报销单服务并完善前端提交与审核交互
重构 expense_claims 服务模块结构并优化差旅票据审核逻辑, 增强用户代理服务的票据类型识别,前端报销创建页面拆分为 附件模型和会话模型模块,重构提交编排器和草稿关联确认流 程,更新知识库索引,补充单元测试。
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -3354,23 +3354,23 @@ class UserAgentService:
|
||||
location = slots.get("location")
|
||||
customer = slots.get("customer_name")
|
||||
|
||||
summary = "我先根据您当前提供的信息整理出一笔报销。"
|
||||
summary = "我先根据您当前提供的信息整理出一笔报销:"
|
||||
if expense_type and expense_type.value:
|
||||
summary = f"识别到您希望报销一笔“{expense_type.value}”费用。"
|
||||
summary = f"识别到您希望报销一笔“{expense_type.value}”费用:"
|
||||
details: list[str] = []
|
||||
if customer and customer.value:
|
||||
details.append(f"客户为 {customer.value}")
|
||||
details.append(f"客户:{customer.value}")
|
||||
if time_range and time_range.value:
|
||||
details.append(f"时间为 {time_range.value}")
|
||||
details.append(f"时间:{time_range.value}")
|
||||
if location and location.value:
|
||||
details.append(f"地点为 {location.value}")
|
||||
details.append(f"地点:{location.value}")
|
||||
if amount and amount.value:
|
||||
details.append(f"金额为 {amount.value}")
|
||||
details.append(f"金额:{amount.value}")
|
||||
reason = slots.get("reason")
|
||||
if reason and reason.value:
|
||||
details.append(f"事由是 {reason.value}")
|
||||
details.append(f"事由:{reason.value}")
|
||||
if details:
|
||||
return f"{summary} {','.join(details)}。"
|
||||
return "\n\n".join([summary, "基础信息识别结果:", "\n".join(details)])
|
||||
return summary
|
||||
|
||||
def _build_review_body_answer(
|
||||
@@ -3399,6 +3399,11 @@ class UserAgentService:
|
||||
slot_cards=review_payload.slot_cards,
|
||||
claim_groups=review_payload.claim_groups,
|
||||
)
|
||||
if payload.tool_payload.get("duplicate_attachment_blocked") or payload.tool_payload.get("duplicate_invoice_blocked"):
|
||||
return (
|
||||
str(payload.tool_payload.get("message") or "").strip()
|
||||
or "检测到本次上传票据与当前单据已有票据重复,请重新上传不同的票据后再归集。"
|
||||
)
|
||||
if review_action == "save_draft":
|
||||
if draft_payload is not None and draft_payload.claim_no:
|
||||
return (
|
||||
@@ -3441,7 +3446,7 @@ class UserAgentService:
|
||||
)
|
||||
return str(payload.tool_payload.get("message") or "").strip() or "当前报销单暂时还不能提交审批。"
|
||||
return (
|
||||
f"{self._build_review_intent_summary(payload, slot_cards=review_payload.slot_cards, claim_groups=review_payload.claim_groups)} "
|
||||
f"{self._build_review_intent_summary(payload, slot_cards=review_payload.slot_cards, claim_groups=review_payload.claim_groups)}\n\n"
|
||||
"当前关键信息已基本齐全,您确认无误后可以继续下一步。"
|
||||
)
|
||||
return review_payload.body_message or None
|
||||
@@ -3497,7 +3502,7 @@ class UserAgentService:
|
||||
expense_type_slot = next((item for item in slot_cards if item.key == "expense_type"), None)
|
||||
if expense_type_slot is not None and not str(expense_type_slot.value or "").strip():
|
||||
return (
|
||||
f"{self._build_review_intent_summary(payload, slot_cards=slot_cards, claim_groups=[])} "
|
||||
f"{self._build_review_intent_summary(payload, slot_cards=slot_cards, claim_groups=[])}\n\n"
|
||||
"我已经先保留了当前识别出的时间、地点和事由,但还不能确定这张单据应该走哪类报销流程。"
|
||||
"请先点击“选择报销类型”,在差旅费、交通费、住宿费等选项中选定;"
|
||||
"选定后,后续上传的票据都会作为这张单据的补充继续核对,不会重新改判报销类型。"
|
||||
@@ -3616,17 +3621,17 @@ class UserAgentService:
|
||||
[
|
||||
"报销测算参考:",
|
||||
"",
|
||||
(
|
||||
f"职级 {calculation.grade},目的地 {destination},匹配城市 {calculation.matched_city};"
|
||||
"补齐交通、酒店等票据后,我会按真实票据金额和规则中心标准重新复核。"
|
||||
),
|
||||
"",
|
||||
"| 项目 | 测算口径 | 金额 |",
|
||||
"| --- | --- | ---: |",
|
||||
f"| 交通票据 | {ticket_basis} | {self._format_decimal_money(ticket_amount)} 元 |",
|
||||
f"| 住宿标准 | {self._format_decimal_money(calculation.hotel_rate)} 元/天 × {calculation.days} 天 | {self._format_decimal_money(calculation.hotel_amount)} 元 |",
|
||||
f"| 出差补贴 | {self._format_decimal_money(calculation.total_allowance_rate)} 元/天 × {calculation.days} 天 | {self._format_decimal_money(calculation.allowance_amount)} 元 |",
|
||||
f"| 参考合计 | 交通票据 + 住宿标准 + 出差补贴 | {self._format_decimal_money(total_amount)} 元 |",
|
||||
"",
|
||||
(
|
||||
f"测算依据:职级 {calculation.grade},目的地 {destination},匹配城市 {calculation.matched_city};"
|
||||
"补齐交通、酒店等票据后,我会按真实票据金额和规则中心标准重新复核。"
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -3850,7 +3855,6 @@ class UserAgentService:
|
||||
*,
|
||||
mention_save_draft: bool,
|
||||
) -> str:
|
||||
missing_count = len(review_payload.missing_slots)
|
||||
reminder_count = len(review_payload.risk_briefs)
|
||||
|
||||
if review_payload.can_proceed:
|
||||
@@ -3861,18 +3865,7 @@ class UserAgentService:
|
||||
)
|
||||
return "当前关键信息已基本齐全,您确认无误后可以继续下一步。"
|
||||
|
||||
issue_parts: list[str] = []
|
||||
if missing_count:
|
||||
issue_parts.append(f"{missing_count} 项信息待补充")
|
||||
if reminder_count:
|
||||
issue_parts.append(f"{reminder_count} 条提醒")
|
||||
issue_summary = "、".join(issue_parts) if issue_parts else "一些细节还需要进一步确认"
|
||||
|
||||
suffix = ";如果想先暂存,也可以点击对话文字中的“草稿”。" if mention_save_draft else "。"
|
||||
return (
|
||||
f"当前还有 {issue_summary}。"
|
||||
f"请核查对话中的文字说明{suffix}"
|
||||
)
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def _can_proceed_review(
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"file_name": "酒店2.jpg",
|
||||
"storage_key": "5544b2a0-a6f5-4ef8-b5b6-c1ac1b03772f/07085673-a7df-4622-abb7-12f6552c780d/酒店2.jpg",
|
||||
"media_type": "image/jpeg",
|
||||
"size_bytes": 156877,
|
||||
"uploaded_at": "2026-05-21T14:19:49.450265+00:00",
|
||||
"previewable": true,
|
||||
"preview_kind": "image",
|
||||
"preview_storage_key": "5544b2a0-a6f5-4ef8-b5b6-c1ac1b03772f/07085673-a7df-4622-abb7-12f6552c780d/酒店2.preview.jpg",
|
||||
"preview_media_type": "image/jpeg",
|
||||
"preview_file_name": "酒店2.preview.jpg",
|
||||
"analysis": {
|
||||
"severity": "pass",
|
||||
"label": "AI提示符合条件",
|
||||
"headline": "AI提示:附件符合基础校验条件",
|
||||
"summary": "已识别到票据类型和关键字段,且符合当前费用场景的附件要求。",
|
||||
"points": [
|
||||
"票据类型:已识别为酒店住宿票据。",
|
||||
"附件类型要求:当前费用项目为住宿票,已识别为酒店住宿票据。",
|
||||
"金额字段:已识别到与当前明细接近的金额 2400.00 元。"
|
||||
],
|
||||
"suggestion": "建议继续核对报销分类、费用说明和业务场景是否一致。"
|
||||
},
|
||||
"document_info": {
|
||||
"document_type": "hotel_invoice",
|
||||
"document_type_label": "酒店住宿票据",
|
||||
"scene_code": "hotel",
|
||||
"scene_label": "住宿票据",
|
||||
"fields": [
|
||||
{
|
||||
"key": "amount",
|
||||
"label": "金额",
|
||||
"value": "2400元"
|
||||
},
|
||||
{
|
||||
"key": "date",
|
||||
"label": "日期",
|
||||
"value": "2026-02-23"
|
||||
},
|
||||
{
|
||||
"key": "merchant_name",
|
||||
"label": "商户",
|
||||
"value": "上海喜来登酒店"
|
||||
},
|
||||
{
|
||||
"key": "invoice_number",
|
||||
"label": "票据号码",
|
||||
"value": "SH-SAMPLE-20260223-003"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requirement_check": {
|
||||
"matches": true,
|
||||
"current_expense_type": "hotel_ticket",
|
||||
"current_expense_type_label": "住宿票",
|
||||
"allowed_scene_labels": [],
|
||||
"allowed_document_type_labels": [],
|
||||
"recognized_scene_code": "hotel",
|
||||
"recognized_scene_label": "住宿票据",
|
||||
"recognized_document_type": "hotel_invoice",
|
||||
"recognized_document_type_label": "酒店住宿票据",
|
||||
"mismatch_severity": "high",
|
||||
"rule_code": "rule.expense.scene_submission_standard",
|
||||
"rule_name": "报销场景提交与附件标准",
|
||||
"message": "当前费用项目为住宿票,已识别为酒店住宿票据。"
|
||||
},
|
||||
"ocr_status": "recognized",
|
||||
"ocr_error": "",
|
||||
"ocr_text": "上海喜来登酒店(样例)\n住宿消费明细单\n单号:SH-SAMPLE-20260223-003\n出单期:2026年2月23\n宾客姓名:\n曹笑竹\n房间类型:豪华床房\n入住日期:\n2026年2月20日\n住晚数: 3晚\n离店期: 2026年223日\n付款式: 现/信卡/其他\n日期\n项目\n计费说明\n单价\n数量\n金额\n2026年2月20日\n至\n住宿费\n豪华大床房\n¥800/晚\n3\n¥2400\n2026年2月22日\n额写:贰仟肆佰元整\n合计:¥2400\n温馨提示:如您对以上账单有任何疑问,请在离店后7天内与酒店联系,感谢您的理解与支持。\n酒店联系式:上海喜来登酒店\n地址:上海市浦东新区银城中路88号 电话:021-12345678\n样例票据|仅供系统测试|无效凭证",
|
||||
"ocr_summary": "上海喜来登酒店(样例);住宿消费明细单;单号:SH-SAMPLE-20260223-003",
|
||||
"ocr_avg_score": 0.9784442763775587,
|
||||
"ocr_line_count": 32,
|
||||
"ocr_classification_source": "rule",
|
||||
"ocr_classification_confidence": 0.84,
|
||||
"ocr_classification_evidence": [
|
||||
"住宿",
|
||||
"入住",
|
||||
"离店",
|
||||
"酒店"
|
||||
],
|
||||
"ocr_warnings": []
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
Binary file not shown.
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"file_name": "2月23_上海-武汉.pdf",
|
||||
"storage_key": "5544b2a0-a6f5-4ef8-b5b6-c1ac1b03772f/ac0a7cc8-7152-41e3-bcce-bd358459a5a8/2月23_上海-武汉.pdf",
|
||||
"media_type": "application/pdf",
|
||||
"size_bytes": 24940,
|
||||
"uploaded_at": "2026-05-21T14:03:40.109269+00:00",
|
||||
"previewable": true,
|
||||
"preview_kind": "image",
|
||||
"preview_storage_key": "5544b2a0-a6f5-4ef8-b5b6-c1ac1b03772f/ac0a7cc8-7152-41e3-bcce-bd358459a5a8/2月23_上海-武汉.preview.png",
|
||||
"preview_media_type": "image/png",
|
||||
"preview_file_name": "2月23_上海-武汉.preview.png",
|
||||
"analysis": {
|
||||
"severity": "pass",
|
||||
"label": "AI提示符合条件",
|
||||
"headline": "AI提示:附件符合基础校验条件",
|
||||
"summary": "已识别到票据类型和关键字段,且符合当前费用场景的附件要求。",
|
||||
"points": [
|
||||
"票据类型:已识别为火车/高铁票。",
|
||||
"附件类型要求:当前费用项目为火车票,已识别为火车/高铁票。",
|
||||
"金额字段:已识别到与当前明细接近的金额 354.00 元。"
|
||||
],
|
||||
"suggestion": "建议继续核对报销分类、费用说明和业务场景是否一致。"
|
||||
},
|
||||
"document_info": {
|
||||
"document_type": "train_ticket",
|
||||
"document_type_label": "火车/高铁票",
|
||||
"scene_code": "travel",
|
||||
"scene_label": "差旅票据",
|
||||
"fields": [
|
||||
{
|
||||
"key": "amount",
|
||||
"label": "金额",
|
||||
"value": "354元"
|
||||
},
|
||||
{
|
||||
"key": "date",
|
||||
"label": "列车出发时间",
|
||||
"value": "2026-02-23 13:54"
|
||||
},
|
||||
{
|
||||
"key": "merchant_name",
|
||||
"label": "商户",
|
||||
"value": "中国铁路"
|
||||
},
|
||||
{
|
||||
"key": "invoice_number",
|
||||
"label": "票据号码",
|
||||
"value": "26319166100006175398"
|
||||
},
|
||||
{
|
||||
"key": "route",
|
||||
"label": "行程",
|
||||
"value": "上海-武汉"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requirement_check": {
|
||||
"matches": true,
|
||||
"current_expense_type": "train_ticket",
|
||||
"current_expense_type_label": "火车票",
|
||||
"allowed_scene_labels": [],
|
||||
"allowed_document_type_labels": [],
|
||||
"recognized_scene_code": "travel",
|
||||
"recognized_scene_label": "差旅票据",
|
||||
"recognized_document_type": "train_ticket",
|
||||
"recognized_document_type_label": "火车/高铁票",
|
||||
"mismatch_severity": "high",
|
||||
"rule_code": "rule.expense.scene_submission_standard",
|
||||
"rule_name": "报销场景提交与附件标准",
|
||||
"message": "当前费用项目为火车票,已识别为火车/高铁票。"
|
||||
},
|
||||
"ocr_status": "recognized",
|
||||
"ocr_error": "",
|
||||
"ocr_text": "电子发票\n(铁路电子客票)\n州\n国家税务总局\n发票号码:26319166100006175398\n开票日期:2026年05月18日\n上海市税务局\n上海虹桥站\n武汉站\nG456\nShanghaihongqiao\nWuhan\n2026年02月23日\n13:54开\n12车08B号\n二等座\n票价:¥354.00\n4201061987****1615\n曹笑竹\n电子客票号:6610061086021394837402026\n购买方名称:曹笑竹\n统一社会信用代码:\n买票请到12306发货请到95306\n中国铁路祝您旅途愉快",
|
||||
"ocr_summary": "电子发票;(铁路电子客票);州",
|
||||
"ocr_avg_score": 0.9620026834309101,
|
||||
"ocr_line_count": 24,
|
||||
"ocr_classification_source": "rule",
|
||||
"ocr_classification_confidence": 0.88,
|
||||
"ocr_classification_evidence": [
|
||||
"铁路电子客票",
|
||||
"电子客票",
|
||||
"铁路",
|
||||
"二等座"
|
||||
],
|
||||
"ocr_warnings": []
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
Binary file not shown.
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"file_name": "2月20_武汉-上海.pdf",
|
||||
"storage_key": "5544b2a0-a6f5-4ef8-b5b6-c1ac1b03772f/b4143190-f375-4f6b-8836-23eee534c99e/2月20_武汉-上海.pdf",
|
||||
"media_type": "application/pdf",
|
||||
"size_bytes": 24995,
|
||||
"uploaded_at": "2026-05-21T14:03:02.982421+00:00",
|
||||
"previewable": true,
|
||||
"preview_kind": "image",
|
||||
"preview_storage_key": "5544b2a0-a6f5-4ef8-b5b6-c1ac1b03772f/b4143190-f375-4f6b-8836-23eee534c99e/2月20_武汉-上海.preview.png",
|
||||
"preview_media_type": "image/png",
|
||||
"preview_file_name": "2月20_武汉-上海.preview.png",
|
||||
"analysis": {
|
||||
"severity": "pass",
|
||||
"label": "AI提示符合条件",
|
||||
"headline": "AI提示:附件符合基础校验条件",
|
||||
"summary": "已识别到票据类型和关键字段,且符合当前费用场景的附件要求。",
|
||||
"points": [
|
||||
"票据类型:已识别为火车/高铁票。",
|
||||
"附件类型要求:当前费用项目为火车票,已识别为火车/高铁票。",
|
||||
"金额字段:已识别到与当前明细接近的金额 354.00 元。"
|
||||
],
|
||||
"suggestion": "建议继续核对报销分类、费用说明和业务场景是否一致。"
|
||||
},
|
||||
"document_info": {
|
||||
"document_type": "train_ticket",
|
||||
"document_type_label": "火车/高铁票",
|
||||
"scene_code": "travel",
|
||||
"scene_label": "差旅票据",
|
||||
"fields": [
|
||||
{
|
||||
"key": "amount",
|
||||
"label": "金额",
|
||||
"value": "354元"
|
||||
},
|
||||
{
|
||||
"key": "date",
|
||||
"label": "列车出发时间",
|
||||
"value": "2026-02-20 07:55"
|
||||
},
|
||||
{
|
||||
"key": "merchant_name",
|
||||
"label": "商户",
|
||||
"value": "中国铁路"
|
||||
},
|
||||
{
|
||||
"key": "invoice_number",
|
||||
"label": "票据号码",
|
||||
"value": "26429165800002785705"
|
||||
},
|
||||
{
|
||||
"key": "route",
|
||||
"label": "行程",
|
||||
"value": "武汉-上海"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requirement_check": {
|
||||
"matches": true,
|
||||
"current_expense_type": "train_ticket",
|
||||
"current_expense_type_label": "火车票",
|
||||
"allowed_scene_labels": [],
|
||||
"allowed_document_type_labels": [],
|
||||
"recognized_scene_code": "travel",
|
||||
"recognized_scene_label": "差旅票据",
|
||||
"recognized_document_type": "train_ticket",
|
||||
"recognized_document_type_label": "火车/高铁票",
|
||||
"mismatch_severity": "high",
|
||||
"rule_code": "rule.expense.scene_submission_standard",
|
||||
"rule_name": "报销场景提交与附件标准",
|
||||
"message": "当前费用项目为火车票,已识别为火车/高铁票。"
|
||||
},
|
||||
"ocr_status": "recognized",
|
||||
"ocr_error": "",
|
||||
"ocr_text": "电子发票\n(铁路电子客票)\n州\n国家税务总局\n发票号码:26429165800002785705\n湖北省税务局\n开票日期:2026年05月18日\n武汉站\n上海虹桥站\nG458\nWuhan\nShanghaihongqiao\n2026年02月20日\n07:55开\n06车01B号\n二等座\n票价:¥354.00\n4201061987****1615\n曹笑竹\n电子客票号:6580061086021391007342026\n购买方名称:曹笑竹\n统一社会信用代码:\n买票请到12306发货请到95306\n中国铁路祝您旅途愉快",
|
||||
"ocr_summary": "电子发票;(铁路电子客票);州",
|
||||
"ocr_avg_score": 0.9580968717734019,
|
||||
"ocr_line_count": 24,
|
||||
"ocr_classification_source": "rule",
|
||||
"ocr_classification_confidence": 0.88,
|
||||
"ocr_classification_evidence": [
|
||||
"铁路电子客票",
|
||||
"电子客票",
|
||||
"铁路",
|
||||
"二等座"
|
||||
],
|
||||
"ocr_warnings": []
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
Binary file not shown.
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"file_name": "2月20_武汉-上海.pdf",
|
||||
"storage_key": "b00cb2a5-0af3-4a49-9f7a-1f79d0ab873a/ab4d8fae-f59d-460d-94a8-eaf644c83591/2月20_武汉-上海.pdf",
|
||||
"media_type": "application/pdf",
|
||||
"size_bytes": 24995,
|
||||
"uploaded_at": "2026-05-22T00:38:09.743522+00:00",
|
||||
"previewable": true,
|
||||
"preview_kind": "image",
|
||||
"preview_storage_key": "b00cb2a5-0af3-4a49-9f7a-1f79d0ab873a/ab4d8fae-f59d-460d-94a8-eaf644c83591/2月20_武汉-上海.preview.png",
|
||||
"preview_media_type": "image/png",
|
||||
"preview_file_name": "2月20_武汉-上海.preview.png",
|
||||
"analysis": {
|
||||
"severity": "pass",
|
||||
"label": "AI提示符合条件",
|
||||
"headline": "AI提示:附件符合基础校验条件",
|
||||
"summary": "已识别到票据类型和关键字段,且符合当前费用场景的附件要求。",
|
||||
"points": [
|
||||
"票据类型:已识别为火车/高铁票。",
|
||||
"附件类型要求:当前费用项目为火车票,已识别为火车/高铁票。",
|
||||
"金额字段:已识别到与当前明细接近的金额 354.00 元。"
|
||||
],
|
||||
"rule_basis": [],
|
||||
"suggestion": "建议继续核对报销分类、费用说明和业务场景是否一致。"
|
||||
},
|
||||
"document_info": {
|
||||
"document_type": "train_ticket",
|
||||
"document_type_label": "火车/高铁票",
|
||||
"scene_code": "travel",
|
||||
"scene_label": "差旅票据",
|
||||
"fields": [
|
||||
{
|
||||
"key": "amount",
|
||||
"label": "金额",
|
||||
"value": "354元"
|
||||
},
|
||||
{
|
||||
"key": "date",
|
||||
"label": "列车出发时间",
|
||||
"value": "2026-02-20 07:55"
|
||||
},
|
||||
{
|
||||
"key": "merchant_name",
|
||||
"label": "商户",
|
||||
"value": "中国铁路"
|
||||
},
|
||||
{
|
||||
"key": "invoice_number",
|
||||
"label": "票据号码",
|
||||
"value": "26429165800002785705"
|
||||
},
|
||||
{
|
||||
"key": "route",
|
||||
"label": "行程",
|
||||
"value": "武汉-上海"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requirement_check": {
|
||||
"matches": true,
|
||||
"current_expense_type": "train_ticket",
|
||||
"current_expense_type_label": "火车票",
|
||||
"allowed_scene_labels": [],
|
||||
"allowed_document_type_labels": [],
|
||||
"recognized_scene_code": "travel",
|
||||
"recognized_scene_label": "差旅票据",
|
||||
"recognized_document_type": "train_ticket",
|
||||
"recognized_document_type_label": "火车/高铁票",
|
||||
"mismatch_severity": "high",
|
||||
"rule_code": "rule.expense.scene_submission_standard",
|
||||
"rule_name": "报销场景提交与附件标准",
|
||||
"message": "当前费用项目为火车票,已识别为火车/高铁票。"
|
||||
},
|
||||
"ocr_status": "recognized",
|
||||
"ocr_error": "",
|
||||
"ocr_text": "电子发票\n(铁路电子客票)\n州\n国家税务总局\n发票号码:26429165800002785705\n湖北省税务局\n开票日期:2026年05月18日\n武汉站\n上海虹桥站\nG458\nWuhan\nShanghaihongqiao\n2026年02月20日\n07:55开\n06车01B号\n二等座\n票价:¥354.00\n4201061987****1615\n曹笑竹\n电子客票号:6580061086021391007342026\n购买方名称:曹笑竹\n统一社会信用代码:\n买票请到12306发货请到95306\n中国铁路祝您旅途愉快",
|
||||
"ocr_summary": "电子发票;(铁路电子客票);州",
|
||||
"ocr_avg_score": 0.9580968717734019,
|
||||
"ocr_line_count": 24,
|
||||
"ocr_classification_source": "rule",
|
||||
"ocr_classification_confidence": 0.88,
|
||||
"ocr_classification_evidence": [
|
||||
"铁路电子客票",
|
||||
"电子客票",
|
||||
"铁路",
|
||||
"二等座"
|
||||
],
|
||||
"ocr_warnings": []
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
Binary file not shown.
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"file_name": "2月23_上海-武汉.pdf",
|
||||
"storage_key": "b00cb2a5-0af3-4a49-9f7a-1f79d0ab873a/b2edd3f3-9efc-44ab-bd3b-60a42f204a60/2月23_上海-武汉.pdf",
|
||||
"media_type": "application/pdf",
|
||||
"size_bytes": 24940,
|
||||
"uploaded_at": "2026-05-22T00:38:30.927361+00:00",
|
||||
"previewable": true,
|
||||
"preview_kind": "image",
|
||||
"preview_storage_key": "b00cb2a5-0af3-4a49-9f7a-1f79d0ab873a/b2edd3f3-9efc-44ab-bd3b-60a42f204a60/2月23_上海-武汉.preview.png",
|
||||
"preview_media_type": "image/png",
|
||||
"preview_file_name": "2月23_上海-武汉.preview.png",
|
||||
"analysis": {
|
||||
"severity": "pass",
|
||||
"label": "AI提示符合条件",
|
||||
"headline": "AI提示:附件符合基础校验条件",
|
||||
"summary": "已识别到票据类型和关键字段,且符合当前费用场景的附件要求。",
|
||||
"points": [
|
||||
"票据类型:已识别为火车/高铁票。",
|
||||
"附件类型要求:当前费用项目为火车票,已识别为火车/高铁票。",
|
||||
"金额字段:已识别到与当前明细接近的金额 354.00 元。"
|
||||
],
|
||||
"rule_basis": [],
|
||||
"suggestion": "建议继续核对报销分类、费用说明和业务场景是否一致。"
|
||||
},
|
||||
"document_info": {
|
||||
"document_type": "train_ticket",
|
||||
"document_type_label": "火车/高铁票",
|
||||
"scene_code": "travel",
|
||||
"scene_label": "差旅票据",
|
||||
"fields": [
|
||||
{
|
||||
"key": "amount",
|
||||
"label": "金额",
|
||||
"value": "354元"
|
||||
},
|
||||
{
|
||||
"key": "date",
|
||||
"label": "列车出发时间",
|
||||
"value": "2026-02-23 13:54"
|
||||
},
|
||||
{
|
||||
"key": "merchant_name",
|
||||
"label": "商户",
|
||||
"value": "中国铁路"
|
||||
},
|
||||
{
|
||||
"key": "invoice_number",
|
||||
"label": "票据号码",
|
||||
"value": "26319166100006175398"
|
||||
},
|
||||
{
|
||||
"key": "route",
|
||||
"label": "行程",
|
||||
"value": "上海-武汉"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requirement_check": {
|
||||
"matches": true,
|
||||
"current_expense_type": "train_ticket",
|
||||
"current_expense_type_label": "火车票",
|
||||
"allowed_scene_labels": [],
|
||||
"allowed_document_type_labels": [],
|
||||
"recognized_scene_code": "travel",
|
||||
"recognized_scene_label": "差旅票据",
|
||||
"recognized_document_type": "train_ticket",
|
||||
"recognized_document_type_label": "火车/高铁票",
|
||||
"mismatch_severity": "high",
|
||||
"rule_code": "rule.expense.scene_submission_standard",
|
||||
"rule_name": "报销场景提交与附件标准",
|
||||
"message": "当前费用项目为火车票,已识别为火车/高铁票。"
|
||||
},
|
||||
"ocr_status": "recognized",
|
||||
"ocr_error": "",
|
||||
"ocr_text": "电子发票\n(铁路电子客票)\n州\n国家税务总局\n发票号码:26319166100006175398\n开票日期:2026年05月18日\n上海市税务局\n上海虹桥站\n武汉站\nG456\nShanghaihongqiao\nWuhan\n2026年02月23日\n13:54开\n12车08B号\n二等座\n票价:¥354.00\n4201061987****1615\n曹笑竹\n电子客票号:6610061086021394837402026\n购买方名称:曹笑竹\n统一社会信用代码:\n买票请到12306发货请到95306\n中国铁路祝您旅途愉快",
|
||||
"ocr_summary": "电子发票;(铁路电子客票);州",
|
||||
"ocr_avg_score": 0.9620026834309101,
|
||||
"ocr_line_count": 24,
|
||||
"ocr_classification_source": "rule",
|
||||
"ocr_classification_confidence": 0.88,
|
||||
"ocr_classification_evidence": [
|
||||
"铁路电子客票",
|
||||
"电子客票",
|
||||
"铁路",
|
||||
"二等座"
|
||||
],
|
||||
"ocr_warnings": []
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
@@ -35,13 +35,13 @@
|
||||
"updated_at": "2026-05-17T13:00:09.485818+00:00",
|
||||
"uploaded_by": "admin",
|
||||
"version_number": 1,
|
||||
"ingest_status": 4,
|
||||
"ingest_status_updated_at": "2026-05-20T16:00:02.515903+00:00",
|
||||
"ingest_completed_at": "",
|
||||
"ingest_document_name": "",
|
||||
"ingest_document_updated_at": "",
|
||||
"ingest_document_sha256": "",
|
||||
"ingest_agent_run_id": "run_3a0b0ecb941b4c8e"
|
||||
"ingest_status": 3,
|
||||
"ingest_status_updated_at": "2026-05-21T15:56:58.286585+00:00",
|
||||
"ingest_completed_at": "2026-05-21T15:56:58.286585+00:00",
|
||||
"ingest_document_name": "无单需求文档0506.docx",
|
||||
"ingest_document_updated_at": "2026-05-17T13:00:09.485818+00:00",
|
||||
"ingest_document_sha256": "00985ec85a8163be9c9ffc5eb522df18ed52d4b131ceed12102c2d75e4df85a9",
|
||||
"ingest_agent_run_id": "run_9f4f60cf545c470f"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,8 +26,7 @@
|
||||
}
|
||||
},
|
||||
"a8f8465df08e455ebe133351721d49f8": {
|
||||
"status": "failed",
|
||||
"error_msg": "Embedding func: Worker execution timeout after 60s",
|
||||
"status": "processed",
|
||||
"chunks_count": 6,
|
||||
"chunks_list": [
|
||||
"chunk-07de6ea74f60535b689f977295770273",
|
||||
@@ -40,12 +39,29 @@
|
||||
"content_summary": "# 产品需求文档\n## 文档信息\n| 项目 | 内容 |\n|------|------|\n| 项目名称 |\n无单报销\n|\n| 版本 | V1.0 |\n| 日期 | 2026-05-06 |\n| 状态 | 正式版 |\n---\n## 1. 项目概述\n### 1.1 项目背景\n面向\n大型企业,\n从业务人员视角出发,解决现有ERP使用体验不佳的问题。\n在ERP的发展历程中,“单据化”曾是财务合规的一大进步,它确保了每笔支出都有据可查。但不可否认,传统的人工填单确实\n也制造了很多\n“枷锁”。在AI时代,解...",
|
||||
"content_length": 9088,
|
||||
"created_at": "2026-05-19T15:59:57.283110+00:00",
|
||||
"updated_at": "2026-05-19T16:00:57.323299+00:00",
|
||||
"updated_at": "2026-05-21T15:56:58.097242+00:00",
|
||||
"file_path": "/app/server/storage/knowledge/报销制度/a8f8465df08e455ebe133351721d49f8__无单需求文档0506.docx",
|
||||
"track_id": "insert_20260519_155957_88c49850",
|
||||
"metadata": {
|
||||
"processing_start_time": 1779206397,
|
||||
"processing_end_time": 1779206457
|
||||
"processing_start_time": 1779378923,
|
||||
"processing_end_time": 1779379018
|
||||
}
|
||||
},
|
||||
"dup-de90fa8775923ae9a1669c8e24d60529": {
|
||||
"status": "failed",
|
||||
"content_summary": "[DUPLICATE] Original document: a8f8465df08e455ebe133351721d49f8",
|
||||
"content_length": 9088,
|
||||
"chunks_count": 0,
|
||||
"chunks_list": [],
|
||||
"created_at": "2026-05-21T15:55:23.540372+00:00",
|
||||
"updated_at": "2026-05-21T15:55:23.540380+00:00",
|
||||
"file_path": "/app/server/storage/knowledge/报销制度/a8f8465df08e455ebe133351721d49f8__无单需求文档0506.docx",
|
||||
"track_id": "insert_20260521_155523_1e232e61",
|
||||
"error_msg": "Content already exists. Original doc_id: a8f8465df08e455ebe133351721d49f8, Status: failed",
|
||||
"metadata": {
|
||||
"is_duplicate": true,
|
||||
"original_doc_id": "a8f8465df08e455ebe133351721d49f8",
|
||||
"original_track_id": "insert_20260519_155957_88c49850"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,268 +1,387 @@
|
||||
{
|
||||
"2c1cb358f08d44ceb0e4d287133206ec": {
|
||||
"entity_names": [
|
||||
"工会委员会",
|
||||
"Business Original Documents",
|
||||
"First Approver",
|
||||
"P8",
|
||||
"一级部门总经理",
|
||||
"组织人事部",
|
||||
"业务原始凭据",
|
||||
"营销中心",
|
||||
"保证金",
|
||||
"投标保证金",
|
||||
"餐补",
|
||||
"第十四条业务招待费",
|
||||
"Chief Engineer",
|
||||
"业务招待",
|
||||
"Employee Welfare",
|
||||
"经济舱",
|
||||
"2024年4月17日",
|
||||
"三等舱",
|
||||
"财务信息化系统",
|
||||
"分管领导",
|
||||
"重点支出管理规定",
|
||||
"备用金借款",
|
||||
"Financial Review",
|
||||
"第五章附则",
|
||||
"Company Leadership",
|
||||
"第十九条",
|
||||
"经办人",
|
||||
"预算内支出",
|
||||
"Current Account Payment",
|
||||
"Business Entertainment",
|
||||
"Tax Control System Details",
|
||||
"第二十一条",
|
||||
"成本中心归属",
|
||||
"岗位支出报销审批权限表",
|
||||
"工会经费管理办法",
|
||||
"商旅系统",
|
||||
"Special Subsidy",
|
||||
"中国银行外汇折算价",
|
||||
"因公借款",
|
||||
"资产采购",
|
||||
"广告费",
|
||||
"First-Level Department General Manager",
|
||||
"正式员工",
|
||||
"一万元",
|
||||
"公司员工教育培训管理办法",
|
||||
"责任原则",
|
||||
"第二章职责分工",
|
||||
"预算先行",
|
||||
"Planning and Finance Department",
|
||||
"Accommodation Cost Reimbursement",
|
||||
"Official Vehicle Subsidy",
|
||||
"第四条归口管理部门主要职责",
|
||||
"Personal Service Compensation",
|
||||
"邮递费",
|
||||
"附表3:支出归口管理部门与归口业务范围",
|
||||
"员工",
|
||||
"第二条目的",
|
||||
"Director",
|
||||
"支出归口管理部门与归口业务范围",
|
||||
"其他支出(员工)",
|
||||
"报销标准",
|
||||
"5000000 Yuan Approval Limit",
|
||||
"第十一条备用金借款",
|
||||
"会议费",
|
||||
"第十七条",
|
||||
"第七条各级管理人员主要职责",
|
||||
"50000 Yuan Approval Limit",
|
||||
"全资子公司",
|
||||
"涉外业务汇率标准",
|
||||
"总监",
|
||||
"第十三条差旅费",
|
||||
"审批权限表",
|
||||
"商旅订票规范",
|
||||
"Final Approval Position",
|
||||
"报销资格",
|
||||
"新增报销规定",
|
||||
"公司支出管理办法",
|
||||
"Institution General Manager",
|
||||
"房屋租金",
|
||||
"Staff Activities",
|
||||
"分包外包(内部单位)",
|
||||
"报销申请时限",
|
||||
"Financial Information System",
|
||||
"Expenditure Authorization Approval Scope",
|
||||
"直辖市",
|
||||
"培训费",
|
||||
"第十二条市内交通费",
|
||||
"第十五条",
|
||||
"终审岗",
|
||||
"Remote Work Housing",
|
||||
"Centralized Management department",
|
||||
"第二十条",
|
||||
"办公室(党委办公室)",
|
||||
"Three Flows Consistency Principle",
|
||||
"审批权限",
|
||||
"VAT Special Invoice",
|
||||
"后勤服务部",
|
||||
"员工支出报销审批权限表",
|
||||
"公司总裁",
|
||||
"出差补贴",
|
||||
"Basic Level Managers",
|
||||
"预付款项",
|
||||
"附表1:员工支出报销审批权限表",
|
||||
"经办部门",
|
||||
"信息管理部",
|
||||
"通信费",
|
||||
"第十六条",
|
||||
"增值税发票",
|
||||
"财务入账条件",
|
||||
"Hotel Accommodation Standards",
|
||||
"审批流转程序",
|
||||
"Self-Driving Travel Provisions",
|
||||
"交通费",
|
||||
"第九条支出报销审批",
|
||||
"薪酬福利支出分配计划",
|
||||
"产品规划设计部",
|
||||
"因公用车补贴",
|
||||
"Committee Chairpersons",
|
||||
"Business Division General Manager",
|
||||
"组织安排",
|
||||
"1 Yuan Per Person Per Kilometer Reimbursement",
|
||||
"Separation of Approval and Processing Principle",
|
||||
"第五条计划财务部主要职责",
|
||||
"200000 Yuan Approval Limit",
|
||||
"公司各部门",
|
||||
"第十四条",
|
||||
"Other Areas",
|
||||
"分支机构",
|
||||
"Departments And Units",
|
||||
"计划财务部",
|
||||
"Other Employees",
|
||||
"第二十三条",
|
||||
"公司团建管理办法",
|
||||
"火车硬席",
|
||||
"税控系统明细清单",
|
||||
"Trade Union Fund",
|
||||
"报销标准变化情况",
|
||||
"薪酬福利支出",
|
||||
"Hong Kong, Macau, And Taiwan Region",
|
||||
"对外捐赠支出",
|
||||
"Multi-Level Approval Rule",
|
||||
"Three Working Days Deadline",
|
||||
"Employee Remuneration",
|
||||
"销售退款",
|
||||
"股权投资、兼并收购",
|
||||
"控股子公司",
|
||||
"取消报销规定",
|
||||
"Procurement Management Regulations",
|
||||
"Middle Managers",
|
||||
"差旅费",
|
||||
"批办分离",
|
||||
"住宿费",
|
||||
"Travel Allowance Standards",
|
||||
"第二十三条本办法的归口与实施",
|
||||
"Senior Vice President",
|
||||
"供应商",
|
||||
"人事归口管理部门",
|
||||
"Management Personnel At All Levels",
|
||||
"效益优先",
|
||||
"Operating Department Individual",
|
||||
"Remote Work Housing Rental Expenses",
|
||||
"取消报销规定内容",
|
||||
"Company",
|
||||
"修订说明",
|
||||
"国网数科公司",
|
||||
"Vice President",
|
||||
"分级授权",
|
||||
"Expenditure Reimbursement Application",
|
||||
"第二十四条附件",
|
||||
"第二十二条",
|
||||
"出租车",
|
||||
"Night High-Speed Rail Provision",
|
||||
"各级管理人员",
|
||||
"受益原则",
|
||||
"公司员工因公通讯费用实施细则",
|
||||
"公司支出管理办法(2024)",
|
||||
"出差补贴标准",
|
||||
"Bid Security Deposit Approval Limits Table",
|
||||
"第二条范围",
|
||||
"Company Property Rental Management",
|
||||
"调动工作",
|
||||
"远光软件股份有限公司",
|
||||
"市内交通费",
|
||||
"交通工具等级标准",
|
||||
"Operator",
|
||||
"第八条支出报销申请",
|
||||
"Directly-Controlled Municipalities And Special Administrative Regions",
|
||||
"出差规定",
|
||||
"业务招待费",
|
||||
"Senior Managers",
|
||||
"逐级审批规则",
|
||||
"Company Business Travel System",
|
||||
"广告宣传费",
|
||||
"Transportation Cost Reimbursement",
|
||||
"财务",
|
||||
"第一章总则",
|
||||
"材料采购",
|
||||
"人力资源服务部",
|
||||
"证券与法律事务部",
|
||||
"Transportation Level Standards",
|
||||
"归口管理部门",
|
||||
"商旅客服",
|
||||
"第四章重点支出管理规定",
|
||||
"出差审批程序",
|
||||
"Business Trip Approval",
|
||||
"西藏",
|
||||
"附表2:岗位支出报销审批权限表",
|
||||
"第十八条",
|
||||
"第二十四条",
|
||||
"Company Hotel Accommodation Limit Standards",
|
||||
"办法",
|
||||
"DAP研发中心",
|
||||
"新增规定内容",
|
||||
"基本补助",
|
||||
"Travel Allowance",
|
||||
"异地挂职锻炼补贴标准",
|
||||
"部门负责人",
|
||||
"Provincial Capitals",
|
||||
"特区",
|
||||
"Transportation Tickets",
|
||||
"第三章支出报销申请与审批",
|
||||
"品牌及市场运营中心",
|
||||
"分包外包(外部单位)",
|
||||
"探亲路费",
|
||||
"President",
|
||||
"凭据报销",
|
||||
"基本出差补贴",
|
||||
"Taxi Usage Regulations",
|
||||
"Government Fees",
|
||||
"Commercial Travel System",
|
||||
"远光制度〔2024〕14号",
|
||||
"审批权限变化情况",
|
||||
"基建工程",
|
||||
"支出报销申请与审批",
|
||||
"中国外汇交易中心参考汇率",
|
||||
"Department Manager",
|
||||
"支出报销审批",
|
||||
"预算调整决策程序",
|
||||
"公司1号文",
|
||||
"External Conference Accommodation",
|
||||
"厉行节约",
|
||||
"Commercial Insurance",
|
||||
"公司",
|
||||
"第三条管理原则",
|
||||
"捐赠申请",
|
||||
"分类控制",
|
||||
"业务宣传费",
|
||||
"产业投资部",
|
||||
"公司员工探亲管理办法",
|
||||
"Subsequent Approver",
|
||||
"100000 Yuan Approval Limit",
|
||||
"Tax Authority Recognized Invoice",
|
||||
"国家电网公司",
|
||||
"业务佐证材料",
|
||||
"第六条经办部门(个人)主要职责",
|
||||
"结算起点",
|
||||
"第十条支出成本中心归属",
|
||||
"母公司"
|
||||
],
|
||||
"count": 258,
|
||||
"create_time": 1779012093,
|
||||
"update_time": 1779012093,
|
||||
"_id": "2c1cb358f08d44ceb0e4d287133206ec"
|
||||
}
|
||||
{
|
||||
"2c1cb358f08d44ceb0e4d287133206ec": {
|
||||
"entity_names": [
|
||||
"工会委员会",
|
||||
"Business Original Documents",
|
||||
"First Approver",
|
||||
"P8",
|
||||
"一级部门总经理",
|
||||
"组织人事部",
|
||||
"业务原始凭据",
|
||||
"营销中心",
|
||||
"保证金",
|
||||
"投标保证金",
|
||||
"餐补",
|
||||
"第十四条业务招待费",
|
||||
"Chief Engineer",
|
||||
"业务招待",
|
||||
"Employee Welfare",
|
||||
"经济舱",
|
||||
"2024年4月17日",
|
||||
"三等舱",
|
||||
"财务信息化系统",
|
||||
"分管领导",
|
||||
"重点支出管理规定",
|
||||
"备用金借款",
|
||||
"Financial Review",
|
||||
"第五章附则",
|
||||
"Company Leadership",
|
||||
"第十九条",
|
||||
"经办人",
|
||||
"预算内支出",
|
||||
"Current Account Payment",
|
||||
"Business Entertainment",
|
||||
"Tax Control System Details",
|
||||
"第二十一条",
|
||||
"成本中心归属",
|
||||
"岗位支出报销审批权限表",
|
||||
"工会经费管理办法",
|
||||
"商旅系统",
|
||||
"Special Subsidy",
|
||||
"中国银行外汇折算价",
|
||||
"因公借款",
|
||||
"资产采购",
|
||||
"广告费",
|
||||
"First-Level Department General Manager",
|
||||
"正式员工",
|
||||
"一万元",
|
||||
"公司员工教育培训管理办法",
|
||||
"责任原则",
|
||||
"第二章职责分工",
|
||||
"预算先行",
|
||||
"Planning and Finance Department",
|
||||
"Accommodation Cost Reimbursement",
|
||||
"Official Vehicle Subsidy",
|
||||
"第四条归口管理部门主要职责",
|
||||
"Personal Service Compensation",
|
||||
"邮递费",
|
||||
"附表3:支出归口管理部门与归口业务范围",
|
||||
"员工",
|
||||
"第二条目的",
|
||||
"Director",
|
||||
"支出归口管理部门与归口业务范围",
|
||||
"其他支出(员工)",
|
||||
"报销标准",
|
||||
"5000000 Yuan Approval Limit",
|
||||
"第十一条备用金借款",
|
||||
"会议费",
|
||||
"第十七条",
|
||||
"第七条各级管理人员主要职责",
|
||||
"50000 Yuan Approval Limit",
|
||||
"全资子公司",
|
||||
"涉外业务汇率标准",
|
||||
"总监",
|
||||
"第十三条差旅费",
|
||||
"审批权限表",
|
||||
"商旅订票规范",
|
||||
"Final Approval Position",
|
||||
"报销资格",
|
||||
"新增报销规定",
|
||||
"公司支出管理办法",
|
||||
"Institution General Manager",
|
||||
"房屋租金",
|
||||
"Staff Activities",
|
||||
"分包外包(内部单位)",
|
||||
"报销申请时限",
|
||||
"Financial Information System",
|
||||
"Expenditure Authorization Approval Scope",
|
||||
"直辖市",
|
||||
"培训费",
|
||||
"第十二条市内交通费",
|
||||
"第十五条",
|
||||
"终审岗",
|
||||
"Remote Work Housing",
|
||||
"Centralized Management department",
|
||||
"第二十条",
|
||||
"办公室(党委办公室)",
|
||||
"Three Flows Consistency Principle",
|
||||
"审批权限",
|
||||
"VAT Special Invoice",
|
||||
"后勤服务部",
|
||||
"员工支出报销审批权限表",
|
||||
"公司总裁",
|
||||
"出差补贴",
|
||||
"Basic Level Managers",
|
||||
"预付款项",
|
||||
"附表1:员工支出报销审批权限表",
|
||||
"经办部门",
|
||||
"信息管理部",
|
||||
"通信费",
|
||||
"第十六条",
|
||||
"增值税发票",
|
||||
"财务入账条件",
|
||||
"Hotel Accommodation Standards",
|
||||
"审批流转程序",
|
||||
"Self-Driving Travel Provisions",
|
||||
"交通费",
|
||||
"第九条支出报销审批",
|
||||
"薪酬福利支出分配计划",
|
||||
"产品规划设计部",
|
||||
"因公用车补贴",
|
||||
"Committee Chairpersons",
|
||||
"Business Division General Manager",
|
||||
"组织安排",
|
||||
"1 Yuan Per Person Per Kilometer Reimbursement",
|
||||
"Separation of Approval and Processing Principle",
|
||||
"第五条计划财务部主要职责",
|
||||
"200000 Yuan Approval Limit",
|
||||
"公司各部门",
|
||||
"第十四条",
|
||||
"Other Areas",
|
||||
"分支机构",
|
||||
"Departments And Units",
|
||||
"计划财务部",
|
||||
"Other Employees",
|
||||
"第二十三条",
|
||||
"公司团建管理办法",
|
||||
"火车硬席",
|
||||
"税控系统明细清单",
|
||||
"Trade Union Fund",
|
||||
"报销标准变化情况",
|
||||
"薪酬福利支出",
|
||||
"Hong Kong, Macau, And Taiwan Region",
|
||||
"对外捐赠支出",
|
||||
"Multi-Level Approval Rule",
|
||||
"Three Working Days Deadline",
|
||||
"Employee Remuneration",
|
||||
"销售退款",
|
||||
"股权投资、兼并收购",
|
||||
"控股子公司",
|
||||
"取消报销规定",
|
||||
"Procurement Management Regulations",
|
||||
"Middle Managers",
|
||||
"差旅费",
|
||||
"批办分离",
|
||||
"住宿费",
|
||||
"Travel Allowance Standards",
|
||||
"第二十三条本办法的归口与实施",
|
||||
"Senior Vice President",
|
||||
"供应商",
|
||||
"人事归口管理部门",
|
||||
"Management Personnel At All Levels",
|
||||
"效益优先",
|
||||
"Operating Department Individual",
|
||||
"Remote Work Housing Rental Expenses",
|
||||
"取消报销规定内容",
|
||||
"Company",
|
||||
"修订说明",
|
||||
"国网数科公司",
|
||||
"Vice President",
|
||||
"分级授权",
|
||||
"Expenditure Reimbursement Application",
|
||||
"第二十四条附件",
|
||||
"第二十二条",
|
||||
"出租车",
|
||||
"Night High-Speed Rail Provision",
|
||||
"各级管理人员",
|
||||
"受益原则",
|
||||
"公司员工因公通讯费用实施细则",
|
||||
"公司支出管理办法(2024)",
|
||||
"出差补贴标准",
|
||||
"Bid Security Deposit Approval Limits Table",
|
||||
"第二条范围",
|
||||
"Company Property Rental Management",
|
||||
"调动工作",
|
||||
"远光软件股份有限公司",
|
||||
"市内交通费",
|
||||
"交通工具等级标准",
|
||||
"Operator",
|
||||
"第八条支出报销申请",
|
||||
"Directly-Controlled Municipalities And Special Administrative Regions",
|
||||
"出差规定",
|
||||
"业务招待费",
|
||||
"Senior Managers",
|
||||
"逐级审批规则",
|
||||
"Company Business Travel System",
|
||||
"广告宣传费",
|
||||
"Transportation Cost Reimbursement",
|
||||
"财务",
|
||||
"第一章总则",
|
||||
"材料采购",
|
||||
"人力资源服务部",
|
||||
"证券与法律事务部",
|
||||
"Transportation Level Standards",
|
||||
"归口管理部门",
|
||||
"商旅客服",
|
||||
"第四章重点支出管理规定",
|
||||
"出差审批程序",
|
||||
"Business Trip Approval",
|
||||
"西藏",
|
||||
"附表2:岗位支出报销审批权限表",
|
||||
"第十八条",
|
||||
"第二十四条",
|
||||
"Company Hotel Accommodation Limit Standards",
|
||||
"办法",
|
||||
"DAP研发中心",
|
||||
"新增规定内容",
|
||||
"基本补助",
|
||||
"Travel Allowance",
|
||||
"异地挂职锻炼补贴标准",
|
||||
"部门负责人",
|
||||
"Provincial Capitals",
|
||||
"特区",
|
||||
"Transportation Tickets",
|
||||
"第三章支出报销申请与审批",
|
||||
"品牌及市场运营中心",
|
||||
"分包外包(外部单位)",
|
||||
"探亲路费",
|
||||
"President",
|
||||
"凭据报销",
|
||||
"基本出差补贴",
|
||||
"Taxi Usage Regulations",
|
||||
"Government Fees",
|
||||
"Commercial Travel System",
|
||||
"远光制度〔2024〕14号",
|
||||
"审批权限变化情况",
|
||||
"基建工程",
|
||||
"支出报销申请与审批",
|
||||
"中国外汇交易中心参考汇率",
|
||||
"Department Manager",
|
||||
"支出报销审批",
|
||||
"预算调整决策程序",
|
||||
"公司1号文",
|
||||
"External Conference Accommodation",
|
||||
"厉行节约",
|
||||
"Commercial Insurance",
|
||||
"公司",
|
||||
"第三条管理原则",
|
||||
"捐赠申请",
|
||||
"分类控制",
|
||||
"业务宣传费",
|
||||
"产业投资部",
|
||||
"公司员工探亲管理办法",
|
||||
"Subsequent Approver",
|
||||
"100000 Yuan Approval Limit",
|
||||
"Tax Authority Recognized Invoice",
|
||||
"国家电网公司",
|
||||
"业务佐证材料",
|
||||
"第六条经办部门(个人)主要职责",
|
||||
"结算起点",
|
||||
"第十条支出成本中心归属",
|
||||
"母公司"
|
||||
],
|
||||
"count": 258,
|
||||
"create_time": 1779012093,
|
||||
"update_time": 1779012093,
|
||||
"_id": "2c1cb358f08d44ceb0e4d287133206ec"
|
||||
},
|
||||
"a8f8465df08e455ebe133351721d49f8": {
|
||||
"entity_names": [
|
||||
"User Menu",
|
||||
"Logout",
|
||||
"行政秘书",
|
||||
"配色方案",
|
||||
"Q1 Quarterly Business Progress Report",
|
||||
"补充上传按钮",
|
||||
"AI",
|
||||
"侧边栏",
|
||||
"凭证识别",
|
||||
"预审按钮",
|
||||
"标题栏",
|
||||
"Sidebar",
|
||||
"Mini Program Code",
|
||||
"Smart Platform Jiangsu Province Company Operations Support",
|
||||
"Pre-Review Result Display",
|
||||
"扫码上传",
|
||||
"出差",
|
||||
"影子ERP",
|
||||
"Preset Assistant Cards",
|
||||
"Trip Time Check",
|
||||
"合规性检查",
|
||||
"Airport Bus Ticket Check",
|
||||
"Train Ticket Compliance Check",
|
||||
"总裁办",
|
||||
"ERP系统",
|
||||
"Initiate Matter",
|
||||
"Procurement Specialist",
|
||||
"Submit Reimbursement",
|
||||
"商旅附件",
|
||||
"Title Bar",
|
||||
"Web端",
|
||||
"用户菜单",
|
||||
"Time Track",
|
||||
"2026 National AI Technology Summit in Hefei",
|
||||
"Taxi Invoice Check",
|
||||
"Activity Bar",
|
||||
"Pre-Review Problem Summary",
|
||||
"Matter List",
|
||||
"Global Chat Bar",
|
||||
"Problem Items",
|
||||
"状态栏",
|
||||
"Personal Center",
|
||||
"Flight Ticket Compliance Check",
|
||||
"UI Layout",
|
||||
"飞机票行程单",
|
||||
"Ashy有限公司",
|
||||
"User Center Module",
|
||||
"正文",
|
||||
"Go Reimburse Button",
|
||||
"Menu 2",
|
||||
"Normal Items",
|
||||
"住宿发票及流水",
|
||||
"Business Travel",
|
||||
"报销流程",
|
||||
"火车票",
|
||||
"活动栏",
|
||||
"Invoice Title Check",
|
||||
"采购专员",
|
||||
"线下自付",
|
||||
"火车票超标",
|
||||
"Document Upload",
|
||||
"Submission Confirmation Prompt",
|
||||
"功能需求",
|
||||
"零报销",
|
||||
"User Message",
|
||||
"AI Assistant",
|
||||
"ERP",
|
||||
"无单报销",
|
||||
"底部对话栏",
|
||||
"审核点",
|
||||
"Submission Result Prompt",
|
||||
"Document Recognition",
|
||||
"即效合规",
|
||||
"Main Content Area",
|
||||
"费控专责",
|
||||
"完整性检查",
|
||||
"User Center",
|
||||
"Cost Control Specialist",
|
||||
"AI Reply",
|
||||
"公共交通发票及行程单",
|
||||
"Summon Panel",
|
||||
"Receipt-Free Reimbursement",
|
||||
"Status Bar",
|
||||
"Hotel Booking Compliance Check",
|
||||
"Warning Icon",
|
||||
"Finance BP",
|
||||
"菜单1",
|
||||
"Taxi Trip Time Compliance Check",
|
||||
"大型企业",
|
||||
"AI预审",
|
||||
"凭证处理流程",
|
||||
"Expense Reimbursement Submission Process",
|
||||
"Role Prompt Templates",
|
||||
"Pre-Review Pass Notification",
|
||||
"AI Assistant Module",
|
||||
"用户中心",
|
||||
"Supplementary Upload Button",
|
||||
"问题项目标识",
|
||||
"Subway Invoice Check",
|
||||
"业务人员",
|
||||
"Role Configuration Pop-up Window",
|
||||
"AI Pre-Review",
|
||||
"出租车发票及行程单",
|
||||
"无单报销工具",
|
||||
"财务BP",
|
||||
"飞机票超标",
|
||||
"Bottom Dialog Bar",
|
||||
"商旅预订",
|
||||
"凭证缩略图",
|
||||
"Administrative Secretary",
|
||||
"问题标注"
|
||||
],
|
||||
"count": 111,
|
||||
"create_time": 1779379018,
|
||||
"update_time": 1779379018,
|
||||
"_id": "a8f8465df08e455ebe133351721d49f8"
|
||||
}
|
||||
}
|
||||
@@ -1,166 +1,278 @@
|
||||
{
|
||||
"2c1cb358f08d44ceb0e4d287133206ec": {
|
||||
"relation_pairs": [
|
||||
[
|
||||
"Departments And Units",
|
||||
"Taxi Usage Regulations"
|
||||
],
|
||||
[
|
||||
"取消报销规定内容",
|
||||
"报销标准变化情况"
|
||||
],
|
||||
[
|
||||
"业务招待费",
|
||||
"第十四条"
|
||||
],
|
||||
[
|
||||
"控股子公司",
|
||||
"计划财务部"
|
||||
],
|
||||
[
|
||||
"公司支出管理办法",
|
||||
"工会委员会"
|
||||
],
|
||||
[
|
||||
"第一章总则",
|
||||
"第三条管理原则"
|
||||
],
|
||||
[
|
||||
"广告宣传费",
|
||||
"第十六条"
|
||||
],
|
||||
[
|
||||
"Tax Control System Details",
|
||||
"VAT Special Invoice"
|
||||
],
|
||||
[
|
||||
"Expenditure Reimbursement Application",
|
||||
"Tax Authority Recognized Invoice"
|
||||
],
|
||||
[
|
||||
"远光制度〔2024〕14号",
|
||||
"远光软件股份有限公司"
|
||||
],
|
||||
[
|
||||
"Financial Review",
|
||||
"Operator"
|
||||
],
|
||||
[
|
||||
"Operating Department Individual",
|
||||
"Procurement Management Regulations"
|
||||
],
|
||||
[
|
||||
"会议费",
|
||||
"第十五条"
|
||||
],
|
||||
[
|
||||
"Company",
|
||||
"Management Personnel At All Levels"
|
||||
],
|
||||
[
|
||||
"公司",
|
||||
"第十七条"
|
||||
],
|
||||
[
|
||||
"公司",
|
||||
"第十八条"
|
||||
],
|
||||
[
|
||||
"Operator",
|
||||
"Three Working Days Deadline"
|
||||
],
|
||||
[
|
||||
"第十一条备用金借款",
|
||||
"第四章重点支出管理规定"
|
||||
],
|
||||
[
|
||||
"Expenditure Reimbursement Application",
|
||||
"Operator"
|
||||
],
|
||||
[
|
||||
"业务招待费",
|
||||
"差旅费"
|
||||
],
|
||||
[
|
||||
"公司",
|
||||
"第二十一条"
|
||||
],
|
||||
[
|
||||
"公司支出管理办法(2024)",
|
||||
"远光软件股份有限公司"
|
||||
],
|
||||
[
|
||||
"第四条归口管理部门主要职责",
|
||||
"计划财务部"
|
||||
],
|
||||
[
|
||||
"会议费",
|
||||
"差旅费"
|
||||
],
|
||||
[
|
||||
"Company",
|
||||
"Operating Department Individual"
|
||||
],
|
||||
[
|
||||
"商旅系统",
|
||||
"差旅费"
|
||||
],
|
||||
[
|
||||
"会议费",
|
||||
"公司总裁"
|
||||
],
|
||||
[
|
||||
"计划财务部",
|
||||
"远光软件股份有限公司"
|
||||
],
|
||||
[
|
||||
"公司",
|
||||
"第十九条"
|
||||
],
|
||||
[
|
||||
"公司",
|
||||
"第二十条"
|
||||
],
|
||||
[
|
||||
"Company",
|
||||
"Planning and Finance Department"
|
||||
],
|
||||
[
|
||||
"公司支出管理办法",
|
||||
"营销中心"
|
||||
],
|
||||
[
|
||||
"Business Original Documents",
|
||||
"Operator"
|
||||
],
|
||||
[
|
||||
"公司支出管理办法",
|
||||
"办公室(党委办公室)"
|
||||
],
|
||||
[
|
||||
"Departments And Units",
|
||||
"Night High-Speed Rail Provision"
|
||||
],
|
||||
[
|
||||
"Centralized Management department",
|
||||
"Company"
|
||||
],
|
||||
[
|
||||
"组织人事部",
|
||||
"调动工作"
|
||||
],
|
||||
[
|
||||
"报销标准变化情况",
|
||||
"远光软件股份有限公司"
|
||||
],
|
||||
[
|
||||
"第一章总则",
|
||||
"远光软件股份有限公司"
|
||||
]
|
||||
],
|
||||
"count": 39,
|
||||
"create_time": 1779012093,
|
||||
"update_time": 1779012093,
|
||||
"_id": "2c1cb358f08d44ceb0e4d287133206ec"
|
||||
}
|
||||
{
|
||||
"2c1cb358f08d44ceb0e4d287133206ec": {
|
||||
"relation_pairs": [
|
||||
[
|
||||
"Departments And Units",
|
||||
"Taxi Usage Regulations"
|
||||
],
|
||||
[
|
||||
"取消报销规定内容",
|
||||
"报销标准变化情况"
|
||||
],
|
||||
[
|
||||
"业务招待费",
|
||||
"第十四条"
|
||||
],
|
||||
[
|
||||
"控股子公司",
|
||||
"计划财务部"
|
||||
],
|
||||
[
|
||||
"公司支出管理办法",
|
||||
"工会委员会"
|
||||
],
|
||||
[
|
||||
"第一章总则",
|
||||
"第三条管理原则"
|
||||
],
|
||||
[
|
||||
"广告宣传费",
|
||||
"第十六条"
|
||||
],
|
||||
[
|
||||
"Tax Control System Details",
|
||||
"VAT Special Invoice"
|
||||
],
|
||||
[
|
||||
"Expenditure Reimbursement Application",
|
||||
"Tax Authority Recognized Invoice"
|
||||
],
|
||||
[
|
||||
"远光制度〔2024〕14号",
|
||||
"远光软件股份有限公司"
|
||||
],
|
||||
[
|
||||
"Financial Review",
|
||||
"Operator"
|
||||
],
|
||||
[
|
||||
"Operating Department Individual",
|
||||
"Procurement Management Regulations"
|
||||
],
|
||||
[
|
||||
"会议费",
|
||||
"第十五条"
|
||||
],
|
||||
[
|
||||
"Company",
|
||||
"Management Personnel At All Levels"
|
||||
],
|
||||
[
|
||||
"公司",
|
||||
"第十七条"
|
||||
],
|
||||
[
|
||||
"公司",
|
||||
"第十八条"
|
||||
],
|
||||
[
|
||||
"Operator",
|
||||
"Three Working Days Deadline"
|
||||
],
|
||||
[
|
||||
"第十一条备用金借款",
|
||||
"第四章重点支出管理规定"
|
||||
],
|
||||
[
|
||||
"Expenditure Reimbursement Application",
|
||||
"Operator"
|
||||
],
|
||||
[
|
||||
"业务招待费",
|
||||
"差旅费"
|
||||
],
|
||||
[
|
||||
"公司",
|
||||
"第二十一条"
|
||||
],
|
||||
[
|
||||
"公司支出管理办法(2024)",
|
||||
"远光软件股份有限公司"
|
||||
],
|
||||
[
|
||||
"第四条归口管理部门主要职责",
|
||||
"计划财务部"
|
||||
],
|
||||
[
|
||||
"会议费",
|
||||
"差旅费"
|
||||
],
|
||||
[
|
||||
"Company",
|
||||
"Operating Department Individual"
|
||||
],
|
||||
[
|
||||
"商旅系统",
|
||||
"差旅费"
|
||||
],
|
||||
[
|
||||
"会议费",
|
||||
"公司总裁"
|
||||
],
|
||||
[
|
||||
"计划财务部",
|
||||
"远光软件股份有限公司"
|
||||
],
|
||||
[
|
||||
"公司",
|
||||
"第十九条"
|
||||
],
|
||||
[
|
||||
"公司",
|
||||
"第二十条"
|
||||
],
|
||||
[
|
||||
"Company",
|
||||
"Planning and Finance Department"
|
||||
],
|
||||
[
|
||||
"公司支出管理办法",
|
||||
"营销中心"
|
||||
],
|
||||
[
|
||||
"Business Original Documents",
|
||||
"Operator"
|
||||
],
|
||||
[
|
||||
"公司支出管理办法",
|
||||
"办公室(党委办公室)"
|
||||
],
|
||||
[
|
||||
"Departments And Units",
|
||||
"Night High-Speed Rail Provision"
|
||||
],
|
||||
[
|
||||
"Centralized Management department",
|
||||
"Company"
|
||||
],
|
||||
[
|
||||
"组织人事部",
|
||||
"调动工作"
|
||||
],
|
||||
[
|
||||
"报销标准变化情况",
|
||||
"远光软件股份有限公司"
|
||||
],
|
||||
[
|
||||
"第一章总则",
|
||||
"远光软件股份有限公司"
|
||||
]
|
||||
],
|
||||
"count": 39,
|
||||
"create_time": 1779012093,
|
||||
"update_time": 1779012093,
|
||||
"_id": "2c1cb358f08d44ceb0e4d287133206ec"
|
||||
},
|
||||
"a8f8465df08e455ebe133351721d49f8": {
|
||||
"relation_pairs": [
|
||||
[
|
||||
"AI预审",
|
||||
"预审按钮"
|
||||
],
|
||||
[
|
||||
"Menu 2",
|
||||
"User Center"
|
||||
],
|
||||
[
|
||||
"Pre-Review Result Display",
|
||||
"Train Ticket Compliance Check"
|
||||
],
|
||||
[
|
||||
"AI Assistant",
|
||||
"Menu 2"
|
||||
],
|
||||
[
|
||||
"AI预审",
|
||||
"问题标注"
|
||||
],
|
||||
[
|
||||
"业务人员",
|
||||
"无单报销"
|
||||
],
|
||||
[
|
||||
"状态栏",
|
||||
"配色方案"
|
||||
],
|
||||
[
|
||||
"Matter List",
|
||||
"Smart Platform Jiangsu Province Company Operations Support"
|
||||
],
|
||||
[
|
||||
"总裁办",
|
||||
"无单报销"
|
||||
],
|
||||
[
|
||||
"Document Upload",
|
||||
"Receipt-Free Reimbursement"
|
||||
],
|
||||
[
|
||||
"Flight Ticket Compliance Check",
|
||||
"Pre-Review Result Display"
|
||||
],
|
||||
[
|
||||
"Web端",
|
||||
"无单报销"
|
||||
],
|
||||
[
|
||||
"Receipt-Free Reimbursement",
|
||||
"Submit Reimbursement"
|
||||
],
|
||||
[
|
||||
"功能需求",
|
||||
"配色方案"
|
||||
],
|
||||
[
|
||||
"完整性检查",
|
||||
"审核点"
|
||||
],
|
||||
[
|
||||
"Receipt-Free Reimbursement",
|
||||
"Time Track"
|
||||
],
|
||||
[
|
||||
"合规性检查",
|
||||
"审核点"
|
||||
],
|
||||
[
|
||||
"ERP",
|
||||
"无单报销"
|
||||
],
|
||||
[
|
||||
"AI预审",
|
||||
"完整性检查"
|
||||
],
|
||||
[
|
||||
"Matter List",
|
||||
"Q1 Quarterly Business Progress Report"
|
||||
],
|
||||
[
|
||||
"Menu 2",
|
||||
"Receipt-Free Reimbursement"
|
||||
],
|
||||
[
|
||||
"AI预审",
|
||||
"合规性检查"
|
||||
],
|
||||
[
|
||||
"Matter List",
|
||||
"Menu 2"
|
||||
],
|
||||
[
|
||||
"2026 National AI Technology Summit in Hefei",
|
||||
"Matter List"
|
||||
],
|
||||
[
|
||||
"大型企业",
|
||||
"无单报销"
|
||||
],
|
||||
[
|
||||
"Initiate Matter",
|
||||
"Receipt-Free Reimbursement"
|
||||
]
|
||||
],
|
||||
"count": 26,
|
||||
"create_time": 1779379018,
|
||||
"update_time": 1779379018,
|
||||
"_id": "a8f8465df08e455ebe133351721d49f8"
|
||||
}
|
||||
}
|
||||
@@ -1,353 +1,587 @@
|
||||
{
|
||||
"第一章总则<SEP>远光软件股份有限公司": {
|
||||
"chunk_ids": [
|
||||
"chunk-aa5435156b829944c173fa1d2d7a93d4"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012088,
|
||||
"update_time": 1779012088,
|
||||
"_id": "第一章总则<SEP>远光软件股份有限公司"
|
||||
},
|
||||
"第十一条备用金借款<SEP>第四章重点支出管理规定": {
|
||||
"chunk_ids": [
|
||||
"chunk-aa5435156b829944c173fa1d2d7a93d4"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012088,
|
||||
"update_time": 1779012088,
|
||||
"_id": "第十一条备用金借款<SEP>第四章重点支出管理规定"
|
||||
},
|
||||
"公司支出管理办法<SEP>办公室(党委办公室)": {
|
||||
"chunk_ids": [
|
||||
"chunk-afc57a0e9548d1f484da6df6c182676b"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012088,
|
||||
"update_time": 1779012088,
|
||||
"_id": "公司支出管理办法<SEP>办公室(党委办公室)"
|
||||
},
|
||||
"计划财务部<SEP>远光软件股份有限公司": {
|
||||
"chunk_ids": [
|
||||
"chunk-aa5435156b829944c173fa1d2d7a93d4"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012076,
|
||||
"update_time": 1779012076,
|
||||
"_id": "计划财务部<SEP>远光软件股份有限公司"
|
||||
},
|
||||
"第一章总则<SEP>第三条管理原则": {
|
||||
"chunk_ids": [
|
||||
"chunk-aa5435156b829944c173fa1d2d7a93d4"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012076,
|
||||
"update_time": 1779012076,
|
||||
"_id": "第一章总则<SEP>第三条管理原则"
|
||||
},
|
||||
"Company<SEP>Management Personnel At All Levels": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012076,
|
||||
"update_time": 1779012076,
|
||||
"_id": "Company<SEP>Management Personnel At All Levels"
|
||||
},
|
||||
"Centralized Management department<SEP>Company": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012077,
|
||||
"update_time": 1779012077,
|
||||
"_id": "Centralized Management department<SEP>Company"
|
||||
},
|
||||
"Company<SEP>Planning and Finance Department": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012077,
|
||||
"update_time": 1779012077,
|
||||
"_id": "Company<SEP>Planning and Finance Department"
|
||||
},
|
||||
"Company<SEP>Operating Department Individual": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012078,
|
||||
"update_time": 1779012078,
|
||||
"_id": "Company<SEP>Operating Department Individual"
|
||||
},
|
||||
"公司支出管理办法<SEP>工会委员会": {
|
||||
"chunk_ids": [
|
||||
"chunk-afc57a0e9548d1f484da6df6c182676b"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012079,
|
||||
"update_time": 1779012079,
|
||||
"_id": "公司支出管理办法<SEP>工会委员会"
|
||||
},
|
||||
"Expenditure Reimbursement Application<SEP>Operator": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012079,
|
||||
"update_time": 1779012079,
|
||||
"_id": "Expenditure Reimbursement Application<SEP>Operator"
|
||||
},
|
||||
"公司支出管理办法<SEP>营销中心": {
|
||||
"chunk_ids": [
|
||||
"chunk-afc57a0e9548d1f484da6df6c182676b"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012079,
|
||||
"update_time": 1779012079,
|
||||
"_id": "公司支出管理办法<SEP>营销中心"
|
||||
},
|
||||
"第四条归口管理部门主要职责<SEP>计划财务部": {
|
||||
"chunk_ids": [
|
||||
"chunk-aa5435156b829944c173fa1d2d7a93d4"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012079,
|
||||
"update_time": 1779012079,
|
||||
"_id": "第四条归口管理部门主要职责<SEP>计划财务部"
|
||||
},
|
||||
"Tax Control System Details<SEP>VAT Special Invoice": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012079,
|
||||
"update_time": 1779012079,
|
||||
"_id": "Tax Control System Details<SEP>VAT Special Invoice"
|
||||
},
|
||||
"Operating Department Individual<SEP>Procurement Management Regulations": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012081,
|
||||
"update_time": 1779012081,
|
||||
"_id": "Operating Department Individual<SEP>Procurement Management Regulations"
|
||||
},
|
||||
"Business Original Documents<SEP>Operator": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012094,
|
||||
"update_time": 1779012094,
|
||||
"_id": "Business Original Documents<SEP>Operator"
|
||||
},
|
||||
"Expenditure Reimbursement Application<SEP>Tax Authority Recognized Invoice": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012094,
|
||||
"update_time": 1779012094,
|
||||
"_id": "Expenditure Reimbursement Application<SEP>Tax Authority Recognized Invoice"
|
||||
},
|
||||
"公司<SEP>第十七条": {
|
||||
"chunk_ids": [
|
||||
"chunk-e9438f69c9e221d9f0f00a05ad84eac6"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012094,
|
||||
"update_time": 1779012094,
|
||||
"_id": "公司<SEP>第十七条"
|
||||
},
|
||||
"Operator<SEP>Three Working Days Deadline": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012083,
|
||||
"update_time": 1779012083,
|
||||
"_id": "Operator<SEP>Three Working Days Deadline"
|
||||
},
|
||||
"Departments And Units<SEP>Night High-Speed Rail Provision": {
|
||||
"chunk_ids": [
|
||||
"chunk-613d6dfd4c5e9c807229a3147f96b584"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012084,
|
||||
"update_time": 1779012084,
|
||||
"_id": "Departments And Units<SEP>Night High-Speed Rail Provision"
|
||||
},
|
||||
"公司<SEP>第十八条": {
|
||||
"chunk_ids": [
|
||||
"chunk-e9438f69c9e221d9f0f00a05ad84eac6"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012084,
|
||||
"update_time": 1779012084,
|
||||
"_id": "公司<SEP>第十八条"
|
||||
},
|
||||
"公司<SEP>第十九条": {
|
||||
"chunk_ids": [
|
||||
"chunk-e9438f69c9e221d9f0f00a05ad84eac6"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012084,
|
||||
"update_time": 1779012084,
|
||||
"_id": "公司<SEP>第十九条"
|
||||
},
|
||||
"报销标准变化情况<SEP>远光软件股份有限公司": {
|
||||
"chunk_ids": [
|
||||
"chunk-18d968b78afe916b419c1b5973421ebe"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012084,
|
||||
"update_time": 1779012084,
|
||||
"_id": "报销标准变化情况<SEP>远光软件股份有限公司"
|
||||
},
|
||||
"取消报销规定内容<SEP>报销标准变化情况": {
|
||||
"chunk_ids": [
|
||||
"chunk-18d968b78afe916b419c1b5973421ebe"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012085,
|
||||
"update_time": 1779012085,
|
||||
"_id": "取消报销规定内容<SEP>报销标准变化情况"
|
||||
},
|
||||
"Financial Review<SEP>Operator": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012085,
|
||||
"update_time": 1779012085,
|
||||
"_id": "Financial Review<SEP>Operator"
|
||||
},
|
||||
"公司支出管理办法(2024)<SEP>远光软件股份有限公司": {
|
||||
"chunk_ids": [
|
||||
"chunk-dd87aa5bc62cc9587ecb4c26d35a5263"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012085,
|
||||
"update_time": 1779012085,
|
||||
"_id": "公司支出管理办法(2024)<SEP>远光软件股份有限公司"
|
||||
},
|
||||
"远光制度〔2024〕14号<SEP>远光软件股份有限公司": {
|
||||
"chunk_ids": [
|
||||
"chunk-dd87aa5bc62cc9587ecb4c26d35a5263"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012086,
|
||||
"update_time": 1779012086,
|
||||
"_id": "远光制度〔2024〕14号<SEP>远光软件股份有限公司"
|
||||
},
|
||||
"Departments And Units<SEP>Taxi Usage Regulations": {
|
||||
"chunk_ids": [
|
||||
"chunk-613d6dfd4c5e9c807229a3147f96b584"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012099,
|
||||
"update_time": 1779012099,
|
||||
"_id": "Departments And Units<SEP>Taxi Usage Regulations"
|
||||
},
|
||||
"控股子公司<SEP>计划财务部": {
|
||||
"chunk_ids": [
|
||||
"chunk-dd87aa5bc62cc9587ecb4c26d35a5263"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012099,
|
||||
"update_time": 1779012099,
|
||||
"_id": "控股子公司<SEP>计划财务部"
|
||||
},
|
||||
"公司<SEP>第二十条": {
|
||||
"chunk_ids": [
|
||||
"chunk-e9438f69c9e221d9f0f00a05ad84eac6"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012086,
|
||||
"update_time": 1779012086,
|
||||
"_id": "公司<SEP>第二十条"
|
||||
},
|
||||
"商旅系统<SEP>差旅费": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012086,
|
||||
"update_time": 1779012086,
|
||||
"_id": "商旅系统<SEP>差旅费"
|
||||
},
|
||||
"业务招待费<SEP>差旅费": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012089,
|
||||
"update_time": 1779012089,
|
||||
"_id": "业务招待费<SEP>差旅费"
|
||||
},
|
||||
"公司<SEP>第二十一条": {
|
||||
"chunk_ids": [
|
||||
"chunk-e9438f69c9e221d9f0f00a05ad84eac6"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012089,
|
||||
"update_time": 1779012089,
|
||||
"_id": "公司<SEP>第二十一条"
|
||||
},
|
||||
"广告宣传费<SEP>第十六条": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012089,
|
||||
"update_time": 1779012089,
|
||||
"_id": "广告宣传费<SEP>第十六条"
|
||||
},
|
||||
"组织人事部<SEP>调动工作": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012090,
|
||||
"update_time": 1779012090,
|
||||
"_id": "组织人事部<SEP>调动工作"
|
||||
},
|
||||
"会议费<SEP>差旅费": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012092,
|
||||
"update_time": 1779012092,
|
||||
"_id": "会议费<SEP>差旅费"
|
||||
},
|
||||
"业务招待费<SEP>第十四条": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012092,
|
||||
"update_time": 1779012092,
|
||||
"_id": "业务招待费<SEP>第十四条"
|
||||
},
|
||||
"会议费<SEP>第十五条": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012092,
|
||||
"update_time": 1779012092,
|
||||
"_id": "会议费<SEP>第十五条"
|
||||
},
|
||||
"会议费<SEP>公司总裁": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012093,
|
||||
"update_time": 1779012093,
|
||||
"_id": "会议费<SEP>公司总裁"
|
||||
}
|
||||
{
|
||||
"第一章总则<SEP>远光软件股份有限公司": {
|
||||
"chunk_ids": [
|
||||
"chunk-aa5435156b829944c173fa1d2d7a93d4"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012088,
|
||||
"update_time": 1779012088,
|
||||
"_id": "第一章总则<SEP>远光软件股份有限公司"
|
||||
},
|
||||
"第十一条备用金借款<SEP>第四章重点支出管理规定": {
|
||||
"chunk_ids": [
|
||||
"chunk-aa5435156b829944c173fa1d2d7a93d4"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012088,
|
||||
"update_time": 1779012088,
|
||||
"_id": "第十一条备用金借款<SEP>第四章重点支出管理规定"
|
||||
},
|
||||
"公司支出管理办法<SEP>办公室(党委办公室)": {
|
||||
"chunk_ids": [
|
||||
"chunk-afc57a0e9548d1f484da6df6c182676b"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012088,
|
||||
"update_time": 1779012088,
|
||||
"_id": "公司支出管理办法<SEP>办公室(党委办公室)"
|
||||
},
|
||||
"计划财务部<SEP>远光软件股份有限公司": {
|
||||
"chunk_ids": [
|
||||
"chunk-aa5435156b829944c173fa1d2d7a93d4"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012076,
|
||||
"update_time": 1779012076,
|
||||
"_id": "计划财务部<SEP>远光软件股份有限公司"
|
||||
},
|
||||
"第一章总则<SEP>第三条管理原则": {
|
||||
"chunk_ids": [
|
||||
"chunk-aa5435156b829944c173fa1d2d7a93d4"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012076,
|
||||
"update_time": 1779012076,
|
||||
"_id": "第一章总则<SEP>第三条管理原则"
|
||||
},
|
||||
"Company<SEP>Management Personnel At All Levels": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012076,
|
||||
"update_time": 1779012076,
|
||||
"_id": "Company<SEP>Management Personnel At All Levels"
|
||||
},
|
||||
"Centralized Management department<SEP>Company": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012077,
|
||||
"update_time": 1779012077,
|
||||
"_id": "Centralized Management department<SEP>Company"
|
||||
},
|
||||
"Company<SEP>Planning and Finance Department": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012077,
|
||||
"update_time": 1779012077,
|
||||
"_id": "Company<SEP>Planning and Finance Department"
|
||||
},
|
||||
"Company<SEP>Operating Department Individual": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012078,
|
||||
"update_time": 1779012078,
|
||||
"_id": "Company<SEP>Operating Department Individual"
|
||||
},
|
||||
"公司支出管理办法<SEP>工会委员会": {
|
||||
"chunk_ids": [
|
||||
"chunk-afc57a0e9548d1f484da6df6c182676b"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012079,
|
||||
"update_time": 1779012079,
|
||||
"_id": "公司支出管理办法<SEP>工会委员会"
|
||||
},
|
||||
"Expenditure Reimbursement Application<SEP>Operator": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012079,
|
||||
"update_time": 1779012079,
|
||||
"_id": "Expenditure Reimbursement Application<SEP>Operator"
|
||||
},
|
||||
"公司支出管理办法<SEP>营销中心": {
|
||||
"chunk_ids": [
|
||||
"chunk-afc57a0e9548d1f484da6df6c182676b"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012079,
|
||||
"update_time": 1779012079,
|
||||
"_id": "公司支出管理办法<SEP>营销中心"
|
||||
},
|
||||
"第四条归口管理部门主要职责<SEP>计划财务部": {
|
||||
"chunk_ids": [
|
||||
"chunk-aa5435156b829944c173fa1d2d7a93d4"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012079,
|
||||
"update_time": 1779012079,
|
||||
"_id": "第四条归口管理部门主要职责<SEP>计划财务部"
|
||||
},
|
||||
"Tax Control System Details<SEP>VAT Special Invoice": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012079,
|
||||
"update_time": 1779012079,
|
||||
"_id": "Tax Control System Details<SEP>VAT Special Invoice"
|
||||
},
|
||||
"Operating Department Individual<SEP>Procurement Management Regulations": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012081,
|
||||
"update_time": 1779012081,
|
||||
"_id": "Operating Department Individual<SEP>Procurement Management Regulations"
|
||||
},
|
||||
"Business Original Documents<SEP>Operator": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012094,
|
||||
"update_time": 1779012094,
|
||||
"_id": "Business Original Documents<SEP>Operator"
|
||||
},
|
||||
"Expenditure Reimbursement Application<SEP>Tax Authority Recognized Invoice": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012094,
|
||||
"update_time": 1779012094,
|
||||
"_id": "Expenditure Reimbursement Application<SEP>Tax Authority Recognized Invoice"
|
||||
},
|
||||
"公司<SEP>第十七条": {
|
||||
"chunk_ids": [
|
||||
"chunk-e9438f69c9e221d9f0f00a05ad84eac6"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012094,
|
||||
"update_time": 1779012094,
|
||||
"_id": "公司<SEP>第十七条"
|
||||
},
|
||||
"Operator<SEP>Three Working Days Deadline": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012083,
|
||||
"update_time": 1779012083,
|
||||
"_id": "Operator<SEP>Three Working Days Deadline"
|
||||
},
|
||||
"Departments And Units<SEP>Night High-Speed Rail Provision": {
|
||||
"chunk_ids": [
|
||||
"chunk-613d6dfd4c5e9c807229a3147f96b584"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012084,
|
||||
"update_time": 1779012084,
|
||||
"_id": "Departments And Units<SEP>Night High-Speed Rail Provision"
|
||||
},
|
||||
"公司<SEP>第十八条": {
|
||||
"chunk_ids": [
|
||||
"chunk-e9438f69c9e221d9f0f00a05ad84eac6"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012084,
|
||||
"update_time": 1779012084,
|
||||
"_id": "公司<SEP>第十八条"
|
||||
},
|
||||
"公司<SEP>第十九条": {
|
||||
"chunk_ids": [
|
||||
"chunk-e9438f69c9e221d9f0f00a05ad84eac6"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012084,
|
||||
"update_time": 1779012084,
|
||||
"_id": "公司<SEP>第十九条"
|
||||
},
|
||||
"报销标准变化情况<SEP>远光软件股份有限公司": {
|
||||
"chunk_ids": [
|
||||
"chunk-18d968b78afe916b419c1b5973421ebe"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012084,
|
||||
"update_time": 1779012084,
|
||||
"_id": "报销标准变化情况<SEP>远光软件股份有限公司"
|
||||
},
|
||||
"取消报销规定内容<SEP>报销标准变化情况": {
|
||||
"chunk_ids": [
|
||||
"chunk-18d968b78afe916b419c1b5973421ebe"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012085,
|
||||
"update_time": 1779012085,
|
||||
"_id": "取消报销规定内容<SEP>报销标准变化情况"
|
||||
},
|
||||
"Financial Review<SEP>Operator": {
|
||||
"chunk_ids": [
|
||||
"chunk-74c01decac4a10cd40a491786743b0ee"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012085,
|
||||
"update_time": 1779012085,
|
||||
"_id": "Financial Review<SEP>Operator"
|
||||
},
|
||||
"公司支出管理办法(2024)<SEP>远光软件股份有限公司": {
|
||||
"chunk_ids": [
|
||||
"chunk-dd87aa5bc62cc9587ecb4c26d35a5263"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012085,
|
||||
"update_time": 1779012085,
|
||||
"_id": "公司支出管理办法(2024)<SEP>远光软件股份有限公司"
|
||||
},
|
||||
"远光制度〔2024〕14号<SEP>远光软件股份有限公司": {
|
||||
"chunk_ids": [
|
||||
"chunk-dd87aa5bc62cc9587ecb4c26d35a5263"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012086,
|
||||
"update_time": 1779012086,
|
||||
"_id": "远光制度〔2024〕14号<SEP>远光软件股份有限公司"
|
||||
},
|
||||
"Departments And Units<SEP>Taxi Usage Regulations": {
|
||||
"chunk_ids": [
|
||||
"chunk-613d6dfd4c5e9c807229a3147f96b584"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012099,
|
||||
"update_time": 1779012099,
|
||||
"_id": "Departments And Units<SEP>Taxi Usage Regulations"
|
||||
},
|
||||
"控股子公司<SEP>计划财务部": {
|
||||
"chunk_ids": [
|
||||
"chunk-dd87aa5bc62cc9587ecb4c26d35a5263"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012099,
|
||||
"update_time": 1779012099,
|
||||
"_id": "控股子公司<SEP>计划财务部"
|
||||
},
|
||||
"公司<SEP>第二十条": {
|
||||
"chunk_ids": [
|
||||
"chunk-e9438f69c9e221d9f0f00a05ad84eac6"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012086,
|
||||
"update_time": 1779012086,
|
||||
"_id": "公司<SEP>第二十条"
|
||||
},
|
||||
"商旅系统<SEP>差旅费": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012086,
|
||||
"update_time": 1779012086,
|
||||
"_id": "商旅系统<SEP>差旅费"
|
||||
},
|
||||
"业务招待费<SEP>差旅费": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012089,
|
||||
"update_time": 1779012089,
|
||||
"_id": "业务招待费<SEP>差旅费"
|
||||
},
|
||||
"公司<SEP>第二十一条": {
|
||||
"chunk_ids": [
|
||||
"chunk-e9438f69c9e221d9f0f00a05ad84eac6"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012089,
|
||||
"update_time": 1779012089,
|
||||
"_id": "公司<SEP>第二十一条"
|
||||
},
|
||||
"广告宣传费<SEP>第十六条": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012089,
|
||||
"update_time": 1779012089,
|
||||
"_id": "广告宣传费<SEP>第十六条"
|
||||
},
|
||||
"组织人事部<SEP>调动工作": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012090,
|
||||
"update_time": 1779012090,
|
||||
"_id": "组织人事部<SEP>调动工作"
|
||||
},
|
||||
"会议费<SEP>差旅费": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012092,
|
||||
"update_time": 1779012092,
|
||||
"_id": "会议费<SEP>差旅费"
|
||||
},
|
||||
"业务招待费<SEP>第十四条": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012092,
|
||||
"update_time": 1779012092,
|
||||
"_id": "业务招待费<SEP>第十四条"
|
||||
},
|
||||
"会议费<SEP>第十五条": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012092,
|
||||
"update_time": 1779012092,
|
||||
"_id": "会议费<SEP>第十五条"
|
||||
},
|
||||
"会议费<SEP>公司总裁": {
|
||||
"chunk_ids": [
|
||||
"chunk-d26b288ed4001dc5c504dce0eb841362"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779012093,
|
||||
"update_time": 1779012093,
|
||||
"_id": "会议费<SEP>公司总裁"
|
||||
},
|
||||
"总裁办<SEP>无单报销": {
|
||||
"chunk_ids": [
|
||||
"chunk-07de6ea74f60535b689f977295770273"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379014,
|
||||
"update_time": 1779379014,
|
||||
"_id": "总裁办<SEP>无单报销"
|
||||
},
|
||||
"AI预审<SEP>完整性检查": {
|
||||
"chunk_ids": [
|
||||
"chunk-1746bd83138e85e66a78e0cb9ad79272"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379014,
|
||||
"update_time": 1779379014,
|
||||
"_id": "AI预审<SEP>完整性检查"
|
||||
},
|
||||
"AI预审<SEP>合规性检查": {
|
||||
"chunk_ids": [
|
||||
"chunk-1746bd83138e85e66a78e0cb9ad79272"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "AI预审<SEP>合规性检查"
|
||||
},
|
||||
"Web端<SEP>无单报销": {
|
||||
"chunk_ids": [
|
||||
"chunk-07de6ea74f60535b689f977295770273"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "Web端<SEP>无单报销"
|
||||
},
|
||||
"完整性检查<SEP>审核点": {
|
||||
"chunk_ids": [
|
||||
"chunk-1746bd83138e85e66a78e0cb9ad79272"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "完整性检查<SEP>审核点"
|
||||
},
|
||||
"AI预审<SEP>问题标注": {
|
||||
"chunk_ids": [
|
||||
"chunk-1746bd83138e85e66a78e0cb9ad79272"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "AI预审<SEP>问题标注"
|
||||
},
|
||||
"合规性检查<SEP>审核点": {
|
||||
"chunk_ids": [
|
||||
"chunk-1746bd83138e85e66a78e0cb9ad79272"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "合规性检查<SEP>审核点"
|
||||
},
|
||||
"Pre-Review Result Display<SEP>Train Ticket Compliance Check": {
|
||||
"chunk_ids": [
|
||||
"chunk-ce44e4483e4119265b43eacb72e0326a"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "Pre-Review Result Display<SEP>Train Ticket Compliance Check"
|
||||
},
|
||||
"大型企业<SEP>无单报销": {
|
||||
"chunk_ids": [
|
||||
"chunk-07de6ea74f60535b689f977295770273"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "大型企业<SEP>无单报销"
|
||||
},
|
||||
"AI预审<SEP>预审按钮": {
|
||||
"chunk_ids": [
|
||||
"chunk-1746bd83138e85e66a78e0cb9ad79272"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "AI预审<SEP>预审按钮"
|
||||
},
|
||||
"状态栏<SEP>配色方案": {
|
||||
"chunk_ids": [
|
||||
"chunk-2224d777c0b72d0b2dab622c79096c2c"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "状态栏<SEP>配色方案"
|
||||
},
|
||||
"Flight Ticket Compliance Check<SEP>Pre-Review Result Display": {
|
||||
"chunk_ids": [
|
||||
"chunk-ce44e4483e4119265b43eacb72e0326a"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "Flight Ticket Compliance Check<SEP>Pre-Review Result Display"
|
||||
},
|
||||
"Matter List<SEP>Menu 2": {
|
||||
"chunk_ids": [
|
||||
"chunk-99c6f377dff2b9a37a7214b7b05ea9a8"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "Matter List<SEP>Menu 2"
|
||||
},
|
||||
"业务人员<SEP>无单报销": {
|
||||
"chunk_ids": [
|
||||
"chunk-07de6ea74f60535b689f977295770273"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379015,
|
||||
"update_time": 1779379015,
|
||||
"_id": "业务人员<SEP>无单报销"
|
||||
},
|
||||
"Menu 2<SEP>Receipt-Free Reimbursement": {
|
||||
"chunk_ids": [
|
||||
"chunk-99c6f377dff2b9a37a7214b7b05ea9a8"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379016,
|
||||
"update_time": 1779379016,
|
||||
"_id": "Menu 2<SEP>Receipt-Free Reimbursement"
|
||||
},
|
||||
"ERP<SEP>无单报销": {
|
||||
"chunk_ids": [
|
||||
"chunk-07de6ea74f60535b689f977295770273"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379016,
|
||||
"update_time": 1779379016,
|
||||
"_id": "ERP<SEP>无单报销"
|
||||
},
|
||||
"功能需求<SEP>配色方案": {
|
||||
"chunk_ids": [
|
||||
"chunk-2224d777c0b72d0b2dab622c79096c2c"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379016,
|
||||
"update_time": 1779379016,
|
||||
"_id": "功能需求<SEP>配色方案"
|
||||
},
|
||||
"Initiate Matter<SEP>Receipt-Free Reimbursement": {
|
||||
"chunk_ids": [
|
||||
"chunk-99c6f377dff2b9a37a7214b7b05ea9a8"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379016,
|
||||
"update_time": 1779379016,
|
||||
"_id": "Initiate Matter<SEP>Receipt-Free Reimbursement"
|
||||
},
|
||||
"AI Assistant<SEP>Menu 2": {
|
||||
"chunk_ids": [
|
||||
"chunk-99c6f377dff2b9a37a7214b7b05ea9a8"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379016,
|
||||
"update_time": 1779379016,
|
||||
"_id": "AI Assistant<SEP>Menu 2"
|
||||
},
|
||||
"Matter List<SEP>Q1 Quarterly Business Progress Report": {
|
||||
"chunk_ids": [
|
||||
"chunk-99c6f377dff2b9a37a7214b7b05ea9a8"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379016,
|
||||
"update_time": 1779379016,
|
||||
"_id": "Matter List<SEP>Q1 Quarterly Business Progress Report"
|
||||
},
|
||||
"Menu 2<SEP>User Center": {
|
||||
"chunk_ids": [
|
||||
"chunk-99c6f377dff2b9a37a7214b7b05ea9a8"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379016,
|
||||
"update_time": 1779379016,
|
||||
"_id": "Menu 2<SEP>User Center"
|
||||
},
|
||||
"2026 National AI Technology Summit in Hefei<SEP>Matter List": {
|
||||
"chunk_ids": [
|
||||
"chunk-99c6f377dff2b9a37a7214b7b05ea9a8"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379016,
|
||||
"update_time": 1779379016,
|
||||
"_id": "2026 National AI Technology Summit in Hefei<SEP>Matter List"
|
||||
},
|
||||
"Matter List<SEP>Smart Platform Jiangsu Province Company Operations Support": {
|
||||
"chunk_ids": [
|
||||
"chunk-99c6f377dff2b9a37a7214b7b05ea9a8"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379017,
|
||||
"update_time": 1779379017,
|
||||
"_id": "Matter List<SEP>Smart Platform Jiangsu Province Company Operations Support"
|
||||
},
|
||||
"Document Upload<SEP>Receipt-Free Reimbursement": {
|
||||
"chunk_ids": [
|
||||
"chunk-99c6f377dff2b9a37a7214b7b05ea9a8"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379017,
|
||||
"update_time": 1779379017,
|
||||
"_id": "Document Upload<SEP>Receipt-Free Reimbursement"
|
||||
},
|
||||
"Receipt-Free Reimbursement<SEP>Time Track": {
|
||||
"chunk_ids": [
|
||||
"chunk-99c6f377dff2b9a37a7214b7b05ea9a8"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379017,
|
||||
"update_time": 1779379017,
|
||||
"_id": "Receipt-Free Reimbursement<SEP>Time Track"
|
||||
},
|
||||
"Receipt-Free Reimbursement<SEP>Submit Reimbursement": {
|
||||
"chunk_ids": [
|
||||
"chunk-99c6f377dff2b9a37a7214b7b05ea9a8"
|
||||
],
|
||||
"count": 1,
|
||||
"create_time": 1779379017,
|
||||
"update_time": 1779379017,
|
||||
"_id": "Receipt-Free Reimbursement<SEP>Submit Reimbursement"
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -136,7 +136,9 @@ def test_save_or_submit_preview_does_not_create_claim_without_explicit_action()
|
||||
|
||||
assert result["preview_only"] is True
|
||||
assert result["status"] == "preview"
|
||||
assert "差旅费按“交通票据金额 + 住宿标准 × 出差天数 + 出差补贴 × 出差天数”估算" in result["message"]
|
||||
assert "报销测算参考:" in result["message"]
|
||||
assert "| 项目 | 当前信息 | 复核口径 |" in result["message"]
|
||||
assert "交通票据金额 + 住宿标准" not in result["message"]
|
||||
assert _count_claims(db) == before_count
|
||||
|
||||
|
||||
@@ -598,6 +600,91 @@ def test_upsert_draft_from_ontology_supports_link_or_create_for_multi_documents(
|
||||
assert float(new_claim.amount) == 50.5
|
||||
|
||||
|
||||
def test_link_existing_draft_blocks_duplicate_uploaded_invoice() -> None:
|
||||
user_id = "duplicate@example.com"
|
||||
|
||||
with build_session() as db:
|
||||
employee = Employee(
|
||||
employee_no="E5010",
|
||||
name="重复票据员工",
|
||||
email=user_id,
|
||||
)
|
||||
db.add(employee)
|
||||
db.flush()
|
||||
existing_claim = ExpenseClaim(
|
||||
claim_no="EXP-202605-021",
|
||||
employee_id=employee.id,
|
||||
employee_name="重复票据员工",
|
||||
department_name="销售部",
|
||||
project_code=None,
|
||||
expense_type="transport",
|
||||
reason="原有交通报销",
|
||||
location="上海",
|
||||
amount=Decimal("32.50"),
|
||||
currency="CNY",
|
||||
invoice_count=1,
|
||||
occurred_at=datetime(2026, 5, 13, tzinfo=UTC),
|
||||
status="draft",
|
||||
approval_stage="待提交",
|
||||
risk_flags_json=[],
|
||||
)
|
||||
existing_claim.items = [
|
||||
ExpenseClaimItem(
|
||||
claim_id=existing_claim.id,
|
||||
item_date=date(2026, 5, 13),
|
||||
item_type="transport",
|
||||
item_reason="原有交通报销",
|
||||
item_location="上海",
|
||||
item_amount=Decimal("32.50"),
|
||||
invoice_id="didi-trip.png",
|
||||
)
|
||||
]
|
||||
db.add(existing_claim)
|
||||
db.commit()
|
||||
|
||||
context_json = {
|
||||
"name": "重复票据员工",
|
||||
"review_action": "link_to_existing_draft",
|
||||
"draft_claim_id": existing_claim.id,
|
||||
"attachment_names": ["didi-trip.png"],
|
||||
"attachment_count": 1,
|
||||
"ocr_documents": [
|
||||
{
|
||||
"filename": "didi-trip.png",
|
||||
"summary": "滴滴出行 支付金额 32.50 元",
|
||||
"text": "滴滴出行 支付金额 32.50 元",
|
||||
"document_type": "taxi_receipt",
|
||||
"scene_code": "transport",
|
||||
"document_fields": [{"key": "amount", "label": "支付金额", "value": "32.50"}],
|
||||
}
|
||||
],
|
||||
}
|
||||
ontology = SemanticOntologyService(db).parse(
|
||||
OntologyParseRequest(
|
||||
query="把这张票据关联到已有草稿",
|
||||
user_id=user_id,
|
||||
context_json=context_json,
|
||||
)
|
||||
)
|
||||
|
||||
result = ExpenseClaimService(db).upsert_draft_from_ontology(
|
||||
run_id=ontology.run_id,
|
||||
user_id=user_id,
|
||||
message="把这张票据关联到已有草稿",
|
||||
ontology=ontology,
|
||||
context_json=context_json,
|
||||
)
|
||||
|
||||
db.refresh(existing_claim)
|
||||
assert result["duplicate_attachment_blocked"] is True
|
||||
assert result["submission_blocked"] is True
|
||||
assert "重复" in result["message"]
|
||||
assert "重新上传不同的票据" in result["message"]
|
||||
assert len(existing_claim.items) == 1
|
||||
assert existing_claim.invoice_count == 1
|
||||
assert float(existing_claim.amount) == 32.5
|
||||
|
||||
|
||||
def test_upsert_travel_draft_uses_ticket_item_types_and_auto_allowance() -> None:
|
||||
user_id = "travel-allowance@example.com"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -200,7 +200,7 @@
|
||||
}
|
||||
|
||||
.review-message-block {
|
||||
margin-top: 8px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.review-summary {
|
||||
@@ -208,12 +208,12 @@
|
||||
color: #1f2937;
|
||||
font-size: var(--wb-fs-bubble);
|
||||
line-height: 1.58;
|
||||
white-space: pre-line;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.review-plain-followup {
|
||||
display: grid;
|
||||
gap: 7px;
|
||||
gap: 10px;
|
||||
padding: 0;
|
||||
color: #334155;
|
||||
font-size: var(--wb-fs-bubble);
|
||||
@@ -225,13 +225,31 @@
|
||||
}
|
||||
|
||||
.review-plain-lead {
|
||||
color: #334155;
|
||||
margin: 0 0 2px;
|
||||
padding-left: 8px;
|
||||
border-left: 3px solid #2563eb;
|
||||
color: #0f172a;
|
||||
font-size: max(13px, calc(var(--wb-fs-bubble) + 1px));
|
||||
font-weight: 820;
|
||||
line-height: 1.42;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.review-plain-lead.danger {
|
||||
border-left-color: #dc2626;
|
||||
color: #b91c1c;
|
||||
}
|
||||
|
||||
.review-plain-summary {
|
||||
margin: 0;
|
||||
color: #64748b;
|
||||
line-height: 1.62;
|
||||
}
|
||||
|
||||
.review-plain-list {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
margin: 0;
|
||||
gap: 7px;
|
||||
margin: 2px 0 0;
|
||||
padding: 0 0 0 18px;
|
||||
}
|
||||
|
||||
@@ -247,11 +265,14 @@
|
||||
}
|
||||
|
||||
.review-plain-note {
|
||||
margin-top: 2px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.review-inline-save-copy {
|
||||
margin-top: 46px !important;
|
||||
color: #475569;
|
||||
line-height: 1.62;
|
||||
}
|
||||
|
||||
.review-inline-draft-link {
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
--wb-fs-welcome: 16px;
|
||||
}
|
||||
|
||||
.assistant-modal-stage .message-answer-markdown table {
|
||||
.assistant-modal-stage .message-answer-markdown :deep(table) {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
||||
@@ -661,7 +661,7 @@
|
||||
|
||||
.message-answer-content {
|
||||
display: grid;
|
||||
gap: 7px;
|
||||
gap: 9px;
|
||||
}
|
||||
|
||||
.message-answer-content p,
|
||||
@@ -672,15 +672,33 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.message-answer-markdown h1,
|
||||
.message-answer-markdown h2,
|
||||
.message-answer-markdown h3,
|
||||
.message-answer-markdown h4 {
|
||||
margin: 0;
|
||||
.message-answer-markdown :deep(h1),
|
||||
.message-answer-markdown :deep(h2),
|
||||
.message-answer-markdown :deep(h3),
|
||||
.message-answer-markdown :deep(h4) {
|
||||
margin: 12px 0 4px;
|
||||
color: #0f172a;
|
||||
font-size: var(--wb-fs-md-h3);
|
||||
font-weight: 750;
|
||||
line-height: 1.46;
|
||||
font-size: max(13px, calc(var(--wb-fs-bubble) + 1px));
|
||||
font-weight: 820;
|
||||
line-height: 1.42;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.message-answer-markdown :deep(h1:first-child),
|
||||
.message-answer-markdown :deep(h2:first-child),
|
||||
.message-answer-markdown :deep(h3:first-child),
|
||||
.message-answer-markdown :deep(h4:first-child) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.message-answer-markdown :deep(h3) {
|
||||
padding-left: 8px;
|
||||
border-left: 3px solid #2563eb;
|
||||
}
|
||||
|
||||
.message-answer-markdown :deep(h3 + p),
|
||||
.message-answer-markdown :deep(h3 + .markdown-table-wrap) {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.message-answer-markdown {
|
||||
@@ -690,26 +708,31 @@
|
||||
line-height: 1.58;
|
||||
}
|
||||
|
||||
.message-answer-markdown p,
|
||||
.message-answer-markdown li,
|
||||
.message-answer-markdown td,
|
||||
.message-answer-markdown th,
|
||||
.message-answer-markdown blockquote {
|
||||
.message-answer-markdown :deep(p),
|
||||
.message-answer-markdown :deep(li),
|
||||
.message-answer-markdown :deep(td),
|
||||
.message-answer-markdown :deep(th),
|
||||
.message-answer-markdown :deep(blockquote) {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
line-height: 1.58;
|
||||
}
|
||||
|
||||
.message-answer-markdown ul,
|
||||
.message-answer-markdown ol {
|
||||
.message-answer-markdown :deep(p) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.message-answer-markdown :deep(ul),
|
||||
.message-answer-markdown :deep(ol) {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.message-answer-markdown strong {
|
||||
.message-answer-markdown :deep(strong) {
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.message-answer-markdown blockquote {
|
||||
.message-answer-markdown :deep(blockquote) {
|
||||
padding: 8px 10px;
|
||||
border-left: 3px solid #cbd5e1;
|
||||
border-radius: 0 10px 10px 0;
|
||||
@@ -717,14 +740,14 @@
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.message-answer-markdown code {
|
||||
.message-answer-markdown :deep(code) {
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
background: #e2e8f0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.message-answer-markdown pre {
|
||||
.message-answer-markdown :deep(pre) {
|
||||
overflow-x: auto;
|
||||
padding: 12px;
|
||||
border-radius: 14px;
|
||||
@@ -732,47 +755,64 @@
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
.message-answer-markdown pre code {
|
||||
.message-answer-markdown :deep(pre code) {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.message-answer-markdown a {
|
||||
.message-answer-markdown :deep(a) {
|
||||
color: #2563eb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.message-answer-markdown table {
|
||||
width: auto;
|
||||
.message-answer-markdown :deep(.markdown-table-wrap) {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
margin: 8px 0 10px;
|
||||
overflow-x: auto;
|
||||
border: 1px solid #dbe4ee;
|
||||
border-radius: 16px;
|
||||
border-collapse: collapse;
|
||||
background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%);
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
.message-answer-markdown :deep(table) {
|
||||
width: 100%;
|
||||
min-width: 460px;
|
||||
border: 0;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
background: #fff;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.message-answer-markdown th,
|
||||
.message-answer-markdown td {
|
||||
padding: 10px 12px;
|
||||
.message-answer-markdown :deep(th),
|
||||
.message-answer-markdown :deep(td) {
|
||||
padding: 8px 10px;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
vertical-align: top;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.message-answer-markdown th {
|
||||
background: #eff6ff;
|
||||
.message-answer-markdown :deep(th) {
|
||||
background: #f8fafc;
|
||||
color: #0f172a;
|
||||
font-weight: 850;
|
||||
font-weight: 760;
|
||||
border-bottom-color: #cbd5e1;
|
||||
}
|
||||
|
||||
.message-answer-markdown td {
|
||||
.message-answer-markdown :deep(td) {
|
||||
color: #334155;
|
||||
font-weight: 650;
|
||||
font-weight: 520;
|
||||
}
|
||||
|
||||
.message-answer-markdown tbody tr:last-child td {
|
||||
.message-answer-markdown :deep(tbody tr:nth-child(even) td) {
|
||||
background: #fbfdff;
|
||||
}
|
||||
|
||||
.message-answer-markdown :deep(tbody tr:last-child td) {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { apiRequest } from './api.js'
|
||||
|
||||
export function recognizeOcrFiles(files) {
|
||||
export function recognizeOcrFiles(files, options = {}) {
|
||||
const formData = new FormData()
|
||||
for (const file of files) {
|
||||
formData.append('files', file)
|
||||
@@ -9,6 +9,7 @@ export function recognizeOcrFiles(files) {
|
||||
return apiRequest('/ocr/recognize', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
contentType: null
|
||||
contentType: null,
|
||||
...options
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,7 +6,78 @@ const markdown = new MarkdownIt({
|
||||
breaks: true
|
||||
})
|
||||
|
||||
const defaultTableOpen = markdown.renderer.rules.table_open
|
||||
const defaultTableClose = markdown.renderer.rules.table_close
|
||||
|
||||
markdown.renderer.rules.table_open = (tokens, idx, options, env, self) => (
|
||||
`<div class="markdown-table-wrap">${defaultTableOpen ? defaultTableOpen(tokens, idx, options, env, self) : '<table>'}`
|
||||
)
|
||||
|
||||
markdown.renderer.rules.table_close = (tokens, idx, options, env, self) => (
|
||||
`${defaultTableClose ? defaultTableClose(tokens, idx, options, env, self) : '</table>'}</div>`
|
||||
)
|
||||
|
||||
const ALLOWED_COLON_HEADING_TITLES = new Set([
|
||||
'基础信息识别结果',
|
||||
'报销测算参考',
|
||||
'补充信息'
|
||||
])
|
||||
|
||||
function splitColonHeadingLine(line) {
|
||||
const rawLine = String(line || '')
|
||||
const trimmed = rawLine.trim()
|
||||
if (!trimmed || trimmed.startsWith('|') || /^#{1,6}\s/.test(trimmed)) {
|
||||
return [rawLine]
|
||||
}
|
||||
|
||||
const chineseColonIndex = trimmed.indexOf(':')
|
||||
const asciiColonIndex = trimmed.indexOf(':')
|
||||
const colonIndexes = [chineseColonIndex, asciiColonIndex].filter((index) => index > 0)
|
||||
if (!colonIndexes.length) {
|
||||
return [rawLine]
|
||||
}
|
||||
|
||||
const colonIndex = Math.min(...colonIndexes)
|
||||
const title = trimmed.slice(0, colonIndex + 1)
|
||||
const titleText = title.slice(0, -1)
|
||||
const body = trimmed.slice(colonIndex + 1).trim()
|
||||
if (!ALLOWED_COLON_HEADING_TITLES.has(titleText)) {
|
||||
return [rawLine]
|
||||
}
|
||||
|
||||
return body ? [`### ${title}`, '', body] : [`### ${title}`]
|
||||
}
|
||||
|
||||
function normalizeColonHeadings(text) {
|
||||
const lines = String(text || '').replace(/\r\n?/g, '\n').split('\n')
|
||||
const normalizedLines = []
|
||||
let inFence = false
|
||||
|
||||
lines.forEach((line) => {
|
||||
if (/^\s*(```|~~~)/.test(line)) {
|
||||
inFence = !inFence
|
||||
normalizedLines.push(line)
|
||||
return
|
||||
}
|
||||
if (inFence) {
|
||||
normalizedLines.push(line)
|
||||
return
|
||||
}
|
||||
|
||||
const nextLines = splitColonHeadingLine(line)
|
||||
if (nextLines[0]?.startsWith('### ') && normalizedLines.length) {
|
||||
const previousLine = normalizedLines[normalizedLines.length - 1]
|
||||
if (String(previousLine || '').trim()) {
|
||||
normalizedLines.push('')
|
||||
}
|
||||
}
|
||||
normalizedLines.push(...nextLines)
|
||||
})
|
||||
|
||||
return normalizedLines.join('\n').replace(/\n{3,}/g, '\n\n')
|
||||
}
|
||||
|
||||
export function renderMarkdown(text = '') {
|
||||
const normalized = String(text || '').trim()
|
||||
const normalized = normalizeColonHeadings(text).trim()
|
||||
return normalized ? markdown.render(normalized) : ''
|
||||
}
|
||||
|
||||
@@ -88,9 +88,10 @@
|
||||
<time>{{ message.time }}</time>
|
||||
</header>
|
||||
<div
|
||||
v-if="message.text && message.role === 'assistant' && message.reviewPayload"
|
||||
v-if="message.text && message.role === 'assistant' && message.reviewPayload && buildReviewMainMessageText(message)"
|
||||
class="review-summary message-answer-content message-answer-markdown"
|
||||
v-html="renderMarkdown(message.text)"
|
||||
v-html="renderMarkdown(buildReviewMainMessageText(message))"
|
||||
@click="handleAssistantMarkdownClick($event, message)"
|
||||
></div>
|
||||
|
||||
<div
|
||||
@@ -103,6 +104,7 @@
|
||||
v-else-if="message.text && message.role === 'assistant'"
|
||||
class="message-answer-content message-answer-markdown"
|
||||
v-html="renderMarkdown(message.text)"
|
||||
@click="handleAssistantMarkdownClick($event, message)"
|
||||
></div>
|
||||
|
||||
<div
|
||||
@@ -298,7 +300,15 @@
|
||||
v-for="followup in [buildReviewPlainFollowupCopy(message.reviewPayload)]"
|
||||
:key="`${message.id}-review-followup`"
|
||||
>
|
||||
<p class="review-plain-lead">{{ followup.lead }}</p>
|
||||
<h3
|
||||
class="review-plain-lead"
|
||||
:class="{ danger: followup.tone === 'danger' }"
|
||||
>
|
||||
{{ followup.lead }}
|
||||
</h3>
|
||||
<p v-if="followup.summary" class="review-plain-summary">
|
||||
{{ followup.summary }}
|
||||
</p>
|
||||
<ul v-if="followup.items.length" class="review-plain-list">
|
||||
<li
|
||||
v-for="item in followup.items"
|
||||
|
||||
@@ -120,6 +120,7 @@ import {
|
||||
VISIBLE_ATTACHMENT_CHIPS,
|
||||
buildAgentInsight,
|
||||
buildErrorInsight,
|
||||
ATTACHMENT_ASSOCIATION_CONFIRM_HREF,
|
||||
buildFileIdentity,
|
||||
buildFilePreviews,
|
||||
buildOcrDocumentsFromReviewPayload,
|
||||
@@ -431,6 +432,19 @@ function buildReviewRiskConversationText(item) {
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
const REVIEW_PENDING_SUMMARY_PATTERN = /(^|\n)\s*(?:当前还有|我这边看到还有|下方还有|这笔报销还有|目前还有|还有|这次识别结果里还有|我还需要你确认|当前信息还差|本次报销还有)\s+[^\n]*(?:信息待补充|风险提醒|细节还需要进一步确认)[^\n]*(?:草稿)[^\n]*。\s*/g
|
||||
|
||||
function buildReviewMainMessageText(message) {
|
||||
const text = String(message?.text || '')
|
||||
if (!message?.reviewPayload) {
|
||||
return text
|
||||
}
|
||||
return text
|
||||
.replace(REVIEW_PENDING_SUMMARY_PATTERN, '\n')
|
||||
.replace(/\n{3,}/g, '\n\n')
|
||||
.trim()
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'TravelReimbursementCreateView',
|
||||
components: {
|
||||
@@ -779,7 +793,10 @@ export default {
|
||||
attachedFiles,
|
||||
composerFilesExpanded
|
||||
}
|
||||
const { submitComposerInternal } = useTravelReimbursementSubmitComposer({
|
||||
const {
|
||||
confirmPendingAttachmentAssociationInternal,
|
||||
submitComposerInternal
|
||||
} = useTravelReimbursementSubmitComposer({
|
||||
MAX_ATTACHMENTS,
|
||||
activeReviewPayload,
|
||||
activeSessionType,
|
||||
@@ -1303,7 +1320,8 @@ export default {
|
||||
skipUploadDecisionPrompt: true,
|
||||
extraContext: {
|
||||
draft_claim_id: claimId,
|
||||
selected_claim_id: claimId
|
||||
selected_claim_id: claimId,
|
||||
selected_claim_no: String(record?.claimNo || '').trim()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1443,6 +1461,27 @@ export default {
|
||||
// submitting.value = false
|
||||
return submitComposerInternal(options)
|
||||
}
|
||||
|
||||
async function handleAssistantMarkdownClick(event, message) {
|
||||
const anchor = event?.target?.closest?.('a')
|
||||
if (!anchor || !message || submitting.value || reviewActionBusy.value || sessionSwitchBusy.value) {
|
||||
return
|
||||
}
|
||||
|
||||
const href = String(anchor.getAttribute('href') || '').trim()
|
||||
if (href !== ATTACHMENT_ASSOCIATION_CONFIRM_HREF) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
reviewActionBusy.value = true
|
||||
try {
|
||||
await confirmPendingAttachmentAssociationInternal(message)
|
||||
} finally {
|
||||
reviewActionBusy.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleReviewAction(message, action) {
|
||||
const actionType = String(action?.action_type || '').trim()
|
||||
if (!actionType || submitting.value || reviewActionBusy.value || sessionSwitchBusy.value) return
|
||||
@@ -1481,11 +1520,11 @@ export default {
|
||||
reviewIntentText, reviewFactCards, reviewCategoryOptions, reviewOtherCategoryOptions, reviewSelectedOtherCategory, reviewInlineDirty, reviewInlineForm, reviewInlineEditorKey, reviewInlineErrors, reviewOtherCategoryOpen, reviewInlinePendingFiles, DATE_INPUT_FORMAT, REVIEW_SCENE_OTHER_OPTION, REVIEW_SCENE_OPTIONS, REVIEW_OTHER_CATEGORY_OPTIONS,
|
||||
workbenchVisible, reviewPanelConfidence, reviewRiskSummary, reviewRiskItems, reviewRiskEmpty, recognizedNarratives, reviewRecognitionNotes, reviewDocumentSummaries, reviewDocumentCount, reviewDocumentDirty, reviewHasUnsavedChanges, uploadDecisionDialogOpen,
|
||||
travelCalculatorOpen, travelCalculatorBusy, travelCalculatorError, travelCalculatorResult, travelCalculatorForm, travelCalculatorCanSubmit, deleteSessionDialogOpen, reviewActionBusy, deleteSessionBusy, documentPreviewDialog, shortcuts,
|
||||
resolveReviewMissingSlotCards, resolveReviewRiskBriefs, buildReviewHeadline, buildReviewSubline, buildReviewStateLabel, buildReviewStateTone, buildReviewPlainFollowupCopy, resolveReviewFooterActions, resolveReviewSaveDraftAction, buildReviewPrimaryButtonLabel,
|
||||
resolveReviewMissingSlotCards, resolveReviewRiskBriefs, buildReviewHeadline, buildReviewSubline, buildReviewStateLabel, buildReviewStateTone, buildReviewPlainFollowupCopy, resolveReviewFooterActions, resolveReviewSaveDraftAction, buildReviewPrimaryButtonLabel, buildReviewMainMessageText,
|
||||
renderMarkdown, buildExpenseQueryWindowLabel, buildExpenseQueryHint, getExpenseQueryActivePage, getExpenseQueryTotalPages, getExpenseQueryVisibleRecords, resolveDocumentPreview, triggerFileUpload, applyComposerDateSelection, handleFilesChange, handleComposerInput, handleComposerEnter, runShortcut, runWelcomeQuickAction: runShortcut, handleSuggestedAction, isSuggestedActionSelected, askHotKnowledgeQuestion, resolveKnowledgeRankLabel, resolveKnowledgeRankTone,
|
||||
refreshFlowRunDetail, formatFlowStepDuration, resolveFlowStepStatusLabel, resolveFlowStepDetail, toggleInsightPanel, openTravelCalculator, toggleTravelCalculator, closeTravelCalculator, submitTravelCalculator, switchToReviewOverviewDrawer, toggleReviewDocumentDrawer, toggleReviewRiskDrawer, toggleReviewFlowDrawer, toggleAttachedFilesExpanded, removeAttachedFile, clearAttachedFiles,
|
||||
requestCloseWorkbench, emitCloseAfterLeave, openExpenseQueryRecord, handleExpenseQueryRecordClick, setExpenseQueryPage, shiftExpenseQueryPage, openDeleteSessionDialog, closeDeleteSessionDialog, confirmDeleteCurrentSession, closeUploadDecisionDialog, continueExistingUpload, createNewUploadDocument, openInlineReviewEditor, closeInlineReviewEditor, commitInlineReviewEditor, clearInlineReviewFieldError, selectInlineScene, selectReviewCategory, selectReviewOtherCategory,
|
||||
queryDraftByClaimNo, appendReviewRiskBriefToConversation, goReviewDocument, openActiveReviewDocumentPreview, closeDocumentPreview, saveInlineReviewChanges, submitComposer, handleReviewAction, handleSaveDraftDirectly, canUseInlineSaveDraft, handleInlineSaveDraft
|
||||
queryDraftByClaimNo, appendReviewRiskBriefToConversation, goReviewDocument, openActiveReviewDocumentPreview, closeDocumentPreview, saveInlineReviewChanges, submitComposer, handleAssistantMarkdownClick, handleReviewAction, handleSaveDraftDirectly, canUseInlineSaveDraft, handleInlineSaveDraft
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ function resolveStatusTone(status) {
|
||||
export const MAX_ATTACHMENTS = 10
|
||||
export const MAX_OCR_DOCUMENTS = 10
|
||||
export const VISIBLE_ATTACHMENT_CHIPS = 2
|
||||
export const ATTACHMENT_ASSOCIATION_CONFIRM_HREF = '#confirm-attachment-association'
|
||||
|
||||
export function normalizeOcrDocuments(payload) {
|
||||
const documents = Array.isArray(payload?.documents) ? payload.documents : []
|
||||
@@ -85,6 +86,88 @@ export function buildOcrSummaryFromDocuments(documents) {
|
||||
.join(';')
|
||||
}
|
||||
|
||||
function resolveAssociationDocumentTypeLabel(document) {
|
||||
const explicitLabel = String(document?.document_type_label || '').trim()
|
||||
if (explicitLabel) {
|
||||
return explicitLabel
|
||||
}
|
||||
|
||||
const sceneLabel = String(document?.scene_label || '').trim()
|
||||
if (sceneLabel) {
|
||||
return sceneLabel
|
||||
}
|
||||
|
||||
const typeLabel = resolveDocumentTypeLabel(document?.document_type)
|
||||
return String(typeLabel || '').trim() || '其他票据'
|
||||
}
|
||||
|
||||
function buildAssociationDocumentContentLines(document) {
|
||||
const fields = Array.isArray(document?.document_fields) ? document.document_fields : []
|
||||
const fieldLines = fields
|
||||
.map((field) => {
|
||||
const label = String(field?.label || '').trim()
|
||||
const value = String(field?.value || '').trim()
|
||||
return label && value ? `- ${label}:${value}` : ''
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
if (fieldLines.length) {
|
||||
return fieldLines.slice(0, 8)
|
||||
}
|
||||
|
||||
const summary = String(document?.summary || document?.text || '').trim()
|
||||
if (summary) {
|
||||
return [`- 识别内容:${summary}`]
|
||||
}
|
||||
|
||||
return ['- 识别内容:暂未提取到结构化字段,请以票据原件为准。']
|
||||
}
|
||||
|
||||
export function buildAttachmentAssociationConfirmationMessage({
|
||||
claimNo = '',
|
||||
claimTitle = '',
|
||||
fileNames = [],
|
||||
ocrDocuments = []
|
||||
} = {}) {
|
||||
const documents = Array.isArray(ocrDocuments) && ocrDocuments.length
|
||||
? ocrDocuments
|
||||
: (Array.isArray(fileNames) ? fileNames : [])
|
||||
.map((filename) => ({ filename }))
|
||||
.filter((item) => String(item.filename || '').trim())
|
||||
const targetLines = [
|
||||
claimNo ? `- 草稿单号:${claimNo}` : '',
|
||||
claimTitle ? `- 单据说明:${claimTitle}` : '',
|
||||
`- 本次待归集附件:${documents.length || fileNames.length || 0} 份`
|
||||
].filter(Boolean)
|
||||
|
||||
const documentBlocks = documents.map((document, index) => {
|
||||
const filename = String(document?.filename || '').trim() || `附件 ${index + 1}`
|
||||
const typeLabel = resolveAssociationDocumentTypeLabel(document)
|
||||
const contentLines = buildAssociationDocumentContentLines(document)
|
||||
return [
|
||||
`附件 ${index + 1}:${filename}`,
|
||||
'',
|
||||
`附件类型:${typeLabel}`,
|
||||
'',
|
||||
...contentLines
|
||||
].join('\n')
|
||||
})
|
||||
|
||||
return [
|
||||
'已识别附件信息:',
|
||||
'',
|
||||
documentBlocks.join('\n\n'),
|
||||
'',
|
||||
'请问是否确定将票据信息归集到单据:',
|
||||
'',
|
||||
targetLines.join('\n'),
|
||||
'',
|
||||
`如果 [确认](${ATTACHMENT_ASSOCIATION_CONFIRM_HREF}) 该信息,我将直接将票据进行归集。`
|
||||
]
|
||||
.filter((part) => String(part || '').trim())
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
export function normalizeReviewDocumentFieldKey(label) {
|
||||
const compact = String(label || '').replace(/\s+/g, '').toLowerCase()
|
||||
if (!compact) return ''
|
||||
|
||||
@@ -167,6 +167,7 @@ export function createMessage(role, text, attachments = [], extras = {}) {
|
||||
draftPayload: null,
|
||||
reviewPayload: null,
|
||||
riskFlags: [],
|
||||
pendingAttachmentAssociation: null,
|
||||
...extras
|
||||
}
|
||||
}
|
||||
@@ -666,6 +667,7 @@ export function serializeSessionMessages(messages) {
|
||||
draftPayload: message.draftPayload || null,
|
||||
reviewPayload: message.reviewPayload || null,
|
||||
riskFlags: Array.isArray(message.riskFlags) ? message.riskFlags : [],
|
||||
pendingAttachmentAssociation: message.pendingAttachmentAssociation || null,
|
||||
assistantName: message.assistantName || '',
|
||||
isWelcome: Boolean(message.isWelcome),
|
||||
welcomeQuickActions: Array.isArray(message.welcomeQuickActions) ? message.welcomeQuickActions : []
|
||||
|
||||
@@ -224,14 +224,22 @@ export function resolveReviewMissingSlotCards(reviewPayload) {
|
||||
|
||||
export function resolveReviewExtraMissingLabels(reviewPayload) {
|
||||
const labels = Array.isArray(reviewPayload?.missing_slots)
|
||||
? reviewPayload.missing_slots.map((item) => String(item || '').trim()).filter(Boolean)
|
||||
? reviewPayload.missing_slots
|
||||
.map((item) => {
|
||||
if (item && typeof item === 'object') {
|
||||
return String(item.label || item.title || item.key || '').trim()
|
||||
}
|
||||
return String(item || '').trim()
|
||||
})
|
||||
.filter(Boolean)
|
||||
: []
|
||||
if (!labels.length) return []
|
||||
|
||||
const slotLabels = new Set(
|
||||
(Array.isArray(reviewPayload?.slot_cards) ? reviewPayload.slot_cards : [])
|
||||
.map((item) => String(item?.label || item?.key || '').trim())
|
||||
.filter(Boolean)
|
||||
(Array.isArray(reviewPayload?.slot_cards) ? reviewPayload.slot_cards : []).flatMap((item) => [
|
||||
String(item?.label || '').trim(),
|
||||
String(item?.key || '').trim()
|
||||
]).filter(Boolean)
|
||||
)
|
||||
return labels.filter((label) => !slotLabels.has(label))
|
||||
}
|
||||
@@ -1239,23 +1247,66 @@ function buildReviewPlainFollowupItem(item, pendingMode) {
|
||||
}
|
||||
}
|
||||
|
||||
const REVIEW_PENDING_SUMMARY_TEMPLATES = [
|
||||
({ issueSummary }) => `当前还有 ${issueSummary}。请核查对话中的文字说明;如果想先暂存,也可以点击对话文字中的“草稿”。`,
|
||||
({ issueSummary }) => `我这边看到还有 ${issueSummary},建议先把下方内容核对一下;暂时不处理也没关系,可以点击“草稿”先保存。`,
|
||||
({ issueSummary }) => `下方还有 ${issueSummary},需要你确认。信息没补齐前可以先核查说明,后续需要暂存时点“草稿”。`,
|
||||
({ issueSummary }) => `这笔报销还有 ${issueSummary},尚未完全确认。请先看一下下面的补充项;需要中途保存时,可以点“草稿”。`,
|
||||
({ issueSummary }) => `目前还有 ${issueSummary}。你可以先按下面的提示补充,也可以稍后再处理,点击“草稿”即可暂存当前信息。`,
|
||||
({ issueSummary }) => `还有 ${issueSummary},建议先核对下面说明;如果票据或金额暂时不全,可以通过“草稿”保留当前进度。`,
|
||||
({ issueSummary }) => `这次识别结果里还有 ${issueSummary}。请重点看下面几项,暂不提交时可以点“草稿”保存。`,
|
||||
({ issueSummary }) => `我还需要你确认 ${issueSummary}。下面列出了具体内容;如果现在不方便补齐,可以先点“草稿”。`,
|
||||
({ issueSummary }) => `当前还有 ${issueSummary},需要进一步处理。请根据下面提示核查,待补充完再继续;临时保存可点击“草稿”。`,
|
||||
({ issueSummary }) => `本次报销还有 ${issueSummary},请先检查下面的补充项;想先留存当前识别结果时可以点“草稿”。`
|
||||
]
|
||||
|
||||
function buildStableTemplateIndex(signature, total) {
|
||||
const source = String(signature || '')
|
||||
let hash = 0
|
||||
for (let index = 0; index < source.length; index += 1) {
|
||||
hash = ((hash << 5) - hash + source.charCodeAt(index)) >>> 0
|
||||
}
|
||||
return total ? hash % total : 0
|
||||
}
|
||||
|
||||
function buildReviewPendingSummary(pendingCount, riskCount, signature = '') {
|
||||
const issueParts = []
|
||||
if (pendingCount) {
|
||||
issueParts.push(`${pendingCount} 项信息待补充`)
|
||||
}
|
||||
if (riskCount) {
|
||||
issueParts.push(`${riskCount} 条风险提醒`)
|
||||
}
|
||||
const issueSummary = issueParts.length ? issueParts.join('、') : '一些细节还需要进一步确认'
|
||||
const templateIndex = buildStableTemplateIndex(signature || issueSummary, REVIEW_PENDING_SUMMARY_TEMPLATES.length)
|
||||
return REVIEW_PENDING_SUMMARY_TEMPLATES[templateIndex]({ issueSummary })
|
||||
}
|
||||
|
||||
export function buildReviewPlainFollowupCopy(reviewPayload) {
|
||||
const todoItems = buildReviewTodoItems(reviewPayload)
|
||||
const pendingCount = countReviewPendingItems(reviewPayload)
|
||||
const riskBriefs = resolvePresentationRiskBriefs(reviewPayload)
|
||||
const extraMissingCount = resolveReviewExtraMissingLabels(reviewPayload).length
|
||||
|
||||
if (pendingCount || resolveReviewExtraMissingLabels(reviewPayload).length) {
|
||||
if (pendingCount || extraMissingCount) {
|
||||
const summarySignature = [
|
||||
pendingCount || extraMissingCount,
|
||||
riskBriefs.length,
|
||||
...todoItems.map((item) => `${item.key}:${item.title}:${item.status}`)
|
||||
].join('|')
|
||||
return {
|
||||
lead: '我还需要你核查或补充下面这些信息:',
|
||||
lead: '补充信息:',
|
||||
tone: 'danger',
|
||||
summary: buildReviewPendingSummary(pendingCount || extraMissingCount, riskBriefs.length, summarySignature),
|
||||
items: todoItems.map((item) => buildReviewPlainFollowupItem(item, true)),
|
||||
notes: riskBriefs.length
|
||||
? [`另外还有 ${riskBriefs.length} 条风险提醒,提交前建议一起确认。`]
|
||||
: []
|
||||
notes: []
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
lead: todoItems.length ? '我已整理出当前识别到的关键信息:' : '当前关键信息已基本整理完成。',
|
||||
tone: 'neutral',
|
||||
summary: '',
|
||||
items: todoItems.map((item) => buildReviewPlainFollowupItem(item, false)),
|
||||
notes: [
|
||||
reviewPayload?.can_proceed ? '确认无误后,可以继续下一步。' : '',
|
||||
|
||||
@@ -103,15 +103,15 @@ export function useTravelReimbursementReviewDrawer({
|
||||
const isReviewFlowDrawer = computed(() => reviewDrawerMode.value === REVIEW_DRAWER_MODE_FLOW)
|
||||
const reviewDrawerTitle = computed(() => (
|
||||
isReviewDocumentDrawer.value
|
||||
? '绁ㄦ嵁璇嗗埆缁撴灉'
|
||||
? '票据识别结果'
|
||||
: isReviewRiskDrawer.value
|
||||
? '椋庨櫓鎻愮ず'
|
||||
? '风险提示'
|
||||
: isReviewFlowDrawer.value
|
||||
? '璋冪敤娴佺▼'
|
||||
: '鎶ラ攢璇嗗埆鏍稿'
|
||||
? '执行流程'
|
||||
: '报销识别核对'
|
||||
))
|
||||
const reviewDocumentDrawerLabel = computed(() => (
|
||||
'鍗曟嵁璇嗗埆'
|
||||
'单据识别'
|
||||
))
|
||||
const reviewDocumentDrawerIcon = computed(() => (
|
||||
isReviewDocumentDrawer.value
|
||||
@@ -119,7 +119,7 @@ export function useTravelReimbursementReviewDrawer({
|
||||
: 'mdi mdi-file-document-multiple-outline'
|
||||
))
|
||||
const reviewRiskDrawerLabel = computed(() => (
|
||||
'鏄剧ず椋庨櫓'
|
||||
'显示风险'
|
||||
))
|
||||
const reviewRiskDrawerIcon = computed(() => (
|
||||
isReviewRiskDrawer.value
|
||||
@@ -127,7 +127,7 @@ export function useTravelReimbursementReviewDrawer({
|
||||
: 'mdi mdi-shield-alert-outline'
|
||||
))
|
||||
const reviewFlowDrawerLabel = computed(() => (
|
||||
'璋冪敤娴佺▼'
|
||||
'执行流程'
|
||||
))
|
||||
const reviewFlowDrawerIcon = computed(() => (
|
||||
isReviewFlowDrawer.value
|
||||
@@ -253,7 +253,7 @@ export function useTravelReimbursementReviewDrawer({
|
||||
) {
|
||||
nextForm.reason_value = String(reviewInlineForm.value.reason_value || '').trim()
|
||||
if (!nextForm.reason_value) {
|
||||
setInlineReviewFieldError('scene', '璇烽€夋嫨鈥滃叾浠栧満鏅€濆悗锛岃琛ュ厖鍏蜂綋浜嬬敱')
|
||||
setInlineReviewFieldError('scene', '请选择“其他场景”后,请补充具体事由')
|
||||
reviewInlineForm.value = nextForm
|
||||
return false
|
||||
}
|
||||
@@ -262,14 +262,14 @@ export function useTravelReimbursementReviewDrawer({
|
||||
}
|
||||
|
||||
if (activeEditorKey === 'occurred_date' && nextForm.occurred_date && !isValidIsoDateString(nextForm.occurred_date)) {
|
||||
setInlineReviewFieldError('occurred_date', `璇疯緭鍏ユ纭殑鏃堕棿鏍煎紡锛?{DATE_INPUT_FORMAT}`)
|
||||
setInlineReviewFieldError('occurred_date', `请输入正确的时间格式:${DATE_INPUT_FORMAT}`)
|
||||
return false
|
||||
}
|
||||
|
||||
if (activeEditorKey === 'amount' && nextForm.amount) {
|
||||
const normalizedAmount = normalizeAmountValue(nextForm.amount)
|
||||
if (!normalizedAmount) {
|
||||
setInlineReviewFieldError('amount', '璇疯緭鍏ユ纭殑鏁板瓧閲戦锛屼緥濡?200 鎴?200.50')
|
||||
setInlineReviewFieldError('amount', '请输入正确的数字金额,例如 200 或 200.50')
|
||||
return false
|
||||
}
|
||||
nextForm.amount = normalizedAmount
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
import {
|
||||
ATTACHMENT_ASSOCIATION_CONFIRM_HREF,
|
||||
buildAttachmentAssociationConfirmationMessage
|
||||
} from './travelReimbursementAttachmentModel.js'
|
||||
|
||||
export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
const {
|
||||
MAX_ATTACHMENTS,
|
||||
@@ -74,6 +79,87 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
uploadDecisionDialogOpen,
|
||||
toast
|
||||
} = ctx
|
||||
|
||||
const pendingAttachmentAssociations = new Map()
|
||||
|
||||
function createPendingAttachmentAssociationId() {
|
||||
return `attachment-association-${Date.now()}-${Math.random().toString(16).slice(2)}`
|
||||
}
|
||||
|
||||
function normalizeRecognizedAttachmentData(data) {
|
||||
if (!data || typeof data !== 'object') {
|
||||
return null
|
||||
}
|
||||
const documents = Array.isArray(data.ocrDocuments) ? data.ocrDocuments : []
|
||||
if (!documents.length) {
|
||||
return null
|
||||
}
|
||||
return {
|
||||
ocrPayload: data.ocrPayload || null,
|
||||
ocrSummary: String(data.ocrSummary || '').trim(),
|
||||
ocrDocuments: documents,
|
||||
ocrFilePreviews: Array.isArray(data.ocrFilePreviews) ? data.ocrFilePreviews : []
|
||||
}
|
||||
}
|
||||
|
||||
function buildConfirmedAssociationText(message) {
|
||||
return String(message?.text || '').replace(
|
||||
`[确认](${ATTACHMENT_ASSOCIATION_CONFIRM_HREF})`,
|
||||
'已确认'
|
||||
)
|
||||
}
|
||||
|
||||
async function confirmPendingAttachmentAssociation(message) {
|
||||
if (submitting.value || sessionSwitchBusy.value) return null
|
||||
|
||||
const pending = message?.pendingAttachmentAssociation && typeof message.pendingAttachmentAssociation === 'object'
|
||||
? message.pendingAttachmentAssociation
|
||||
: null
|
||||
const associationId = String(pending?.id || '').trim()
|
||||
if (!associationId || pending?.status === 'confirmed') {
|
||||
return null
|
||||
}
|
||||
|
||||
const runtime = pendingAttachmentAssociations.get(associationId)
|
||||
if (!runtime || !Array.isArray(runtime.files) || !runtime.files.length) {
|
||||
toast('当前会话里没有可归集的附件原件,请重新上传票据后再确认。')
|
||||
return null
|
||||
}
|
||||
|
||||
pending.status = 'confirmed'
|
||||
message.pendingAttachmentAssociation = pending
|
||||
message.text = buildConfirmedAssociationText(message)
|
||||
message.meta = ['已确认归集']
|
||||
persistSessionState()
|
||||
|
||||
return submitComposer({
|
||||
rawText: `确认将本次上传的 ${runtime.fileNames.length} 份票据归集到草稿 ${runtime.claimNo || '当前草稿'}`,
|
||||
userText: `确认归集到草稿 ${runtime.claimNo || '当前草稿'}`,
|
||||
files: runtime.files,
|
||||
uploadDisposition: 'continue_existing',
|
||||
skipUploadDecisionPrompt: true,
|
||||
skipDraftAssociationPrompt: true,
|
||||
pendingText: runtime.claimNo
|
||||
? `正在将票据归集到草稿 ${runtime.claimNo}...`
|
||||
: '正在将票据归集到当前草稿...',
|
||||
associationConfirmed: true,
|
||||
recognizedAttachmentData: {
|
||||
ocrPayload: runtime.ocrPayload,
|
||||
ocrSummary: runtime.ocrSummary,
|
||||
ocrDocuments: runtime.ocrDocuments,
|
||||
ocrFilePreviews: runtime.ocrFilePreviews
|
||||
},
|
||||
extraContext: {
|
||||
...runtime.extraContext,
|
||||
review_action: 'link_to_existing_draft',
|
||||
draft_claim_id: runtime.claimId,
|
||||
selected_claim_id: runtime.claimId,
|
||||
selected_claim_no: runtime.claimNo,
|
||||
attachment_association_confirmed: true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function buildBackendMessage(rawText, fileNames, ocrSummary = '') {
|
||||
const parts = []
|
||||
const normalizedText = String(rawText || '').trim()
|
||||
@@ -128,6 +214,11 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
? initialExtraContext
|
||||
: mergeBusinessTimeIntoExtraContext(initialExtraContext, selectedBusinessTimeContext)
|
||||
const reviewAction = String(extraContext.review_action || '').trim()
|
||||
const attachmentAssociationConfirmed = Boolean(
|
||||
options.associationConfirmed ||
|
||||
extraContext.attachment_association_confirmed ||
|
||||
reviewAction === 'link_to_existing_draft'
|
||||
)
|
||||
const hasSelectedExpenseType = Boolean(
|
||||
extraContext.expense_scene_selection ||
|
||||
String(extraContext.review_form_values?.expense_type || extraContext.review_form_values?.reimbursement_type || '').trim()
|
||||
@@ -305,21 +396,100 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
let ocrSummary = ''
|
||||
let ocrDocuments = []
|
||||
let ocrFilePreviews = []
|
||||
const recognizedAttachmentData = normalizeRecognizedAttachmentData(options.recognizedAttachmentData)
|
||||
|
||||
if (files.length) {
|
||||
const ocrStartedAt = Date.now()
|
||||
startFlowStep('ocr', { detail: `正在识别 ${files.length} 份附件...`, startedAt: ocrStartedAt })
|
||||
try {
|
||||
ocrPayload = await recognizeOcrFiles(files)
|
||||
ocrSummary = buildOcrSummary(ocrPayload)
|
||||
ocrDocuments = normalizeOcrDocuments(ocrPayload)
|
||||
ocrFilePreviews = buildOcrFilePreviews(ocrPayload)
|
||||
if (recognizedAttachmentData) {
|
||||
ocrPayload = recognizedAttachmentData.ocrPayload
|
||||
ocrSummary = recognizedAttachmentData.ocrSummary || buildOcrSummaryFromDocuments(recognizedAttachmentData.ocrDocuments)
|
||||
ocrDocuments = [...recognizedAttachmentData.ocrDocuments]
|
||||
ocrFilePreviews = [...recognizedAttachmentData.ocrFilePreviews]
|
||||
rememberFilePreviews(ocrFilePreviews)
|
||||
completeFlowStep('ocr', `识别到 ${ocrDocuments.length || files.length} 张票据`, Date.now() - ocrStartedAt)
|
||||
} catch (error) {
|
||||
console.warn('OCR request failed:', error)
|
||||
completeFlowStep('ocr', 'OCR识别失败,已继续使用附件名称', Date.now() - ocrStartedAt)
|
||||
completeFlowStep('ocr', `复用已确认的 ${ocrDocuments.length || files.length} 张票据识别结果`, Date.now() - ocrStartedAt)
|
||||
} else {
|
||||
try {
|
||||
ocrPayload = await recognizeOcrFiles(files, {
|
||||
timeoutMs: 90000,
|
||||
timeoutMessage: '票据 OCR 识别超时,已继续使用附件名称处理。'
|
||||
})
|
||||
ocrSummary = buildOcrSummary(ocrPayload)
|
||||
ocrDocuments = normalizeOcrDocuments(ocrPayload)
|
||||
ocrFilePreviews = buildOcrFilePreviews(ocrPayload)
|
||||
rememberFilePreviews(ocrFilePreviews)
|
||||
completeFlowStep('ocr', `识别到 ${ocrDocuments.length || files.length} 张票据`, Date.now() - ocrStartedAt)
|
||||
} catch (error) {
|
||||
console.warn('OCR request failed:', error)
|
||||
completeFlowStep('ocr', 'OCR识别失败,已继续使用附件名称', Date.now() - ocrStartedAt)
|
||||
}
|
||||
}
|
||||
|
||||
if (resolvedUploadDisposition === 'continue_existing') {
|
||||
replaceMessage(pendingMessage.id, {
|
||||
...pendingMessage,
|
||||
text: attachmentAssociationConfirmed
|
||||
? '票据识别已完成,正在把本次附件归集到已选择的草稿...'
|
||||
: '票据识别已完成,正在整理归集前确认信息...',
|
||||
meta: attachmentAssociationConfirmed ? ['正在归集'] : ['等待确认归集']
|
||||
})
|
||||
persistSessionState()
|
||||
}
|
||||
}
|
||||
|
||||
const associationTargetClaimId = String(extraContext.draft_claim_id || draftClaimId.value || '').trim()
|
||||
const associationTargetClaimNo = String(
|
||||
extraContext.selected_claim_no ||
|
||||
extraContext.draft_claim_no ||
|
||||
''
|
||||
).trim()
|
||||
if (
|
||||
files.length &&
|
||||
resolvedUploadDisposition === 'continue_existing' &&
|
||||
associationTargetClaimId &&
|
||||
!attachmentAssociationConfirmed
|
||||
) {
|
||||
const associationId = createPendingAttachmentAssociationId()
|
||||
const pendingAssociation = {
|
||||
id: associationId,
|
||||
status: 'pending',
|
||||
claimId: associationTargetClaimId,
|
||||
claimNo: associationTargetClaimNo,
|
||||
fileNames
|
||||
}
|
||||
pendingAttachmentAssociations.set(associationId, {
|
||||
files,
|
||||
fileNames,
|
||||
ocrPayload,
|
||||
ocrSummary,
|
||||
ocrDocuments,
|
||||
ocrFilePreviews,
|
||||
filePreviews,
|
||||
claimId: associationTargetClaimId,
|
||||
claimNo: associationTargetClaimNo,
|
||||
extraContext: {
|
||||
...extraContext,
|
||||
draft_claim_id: associationTargetClaimId,
|
||||
selected_claim_id: associationTargetClaimId,
|
||||
selected_claim_no: associationTargetClaimNo
|
||||
}
|
||||
})
|
||||
replaceMessage(pendingMessage.id, createMessage(
|
||||
'assistant',
|
||||
buildAttachmentAssociationConfirmationMessage({
|
||||
claimNo: associationTargetClaimNo,
|
||||
fileNames,
|
||||
ocrDocuments
|
||||
}),
|
||||
[],
|
||||
{
|
||||
meta: ['等待确认归集'],
|
||||
pendingAttachmentAssociation: pendingAssociation
|
||||
}
|
||||
))
|
||||
persistSessionState()
|
||||
nextTick(scrollToBottom)
|
||||
return null
|
||||
}
|
||||
|
||||
let effectiveFileNames = [...fileNames]
|
||||
@@ -359,6 +529,16 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
})
|
||||
|
||||
const backendMessage = buildBackendMessage(rawText, effectiveFileNames, effectiveOcrSummary)
|
||||
const orchestratorOptions = isKnowledgeSession.value
|
||||
? {
|
||||
timeoutMs: 18000,
|
||||
timeoutMessage: '知识问答整理超时,已停止等待。建议缩小问题范围或稍后重试。'
|
||||
}
|
||||
: {
|
||||
timeoutMs: 120000,
|
||||
timeoutMessage: '票据归集处理超时,当前仍停留在原草稿,请稍后重试或重新选择附件。'
|
||||
}
|
||||
|
||||
const payload = await runOrchestrator(
|
||||
{
|
||||
source: 'user_message',
|
||||
@@ -393,12 +573,7 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
...extraContext
|
||||
}
|
||||
},
|
||||
isKnowledgeSession.value
|
||||
? {
|
||||
timeoutMs: 18000,
|
||||
timeoutMessage: '知识问答整理超时,已停止等待。建议缩小问题范围或稍后重试。'
|
||||
}
|
||||
: {}
|
||||
orchestratorOptions
|
||||
)
|
||||
responsePayload = payload
|
||||
flowRunId.value = String(payload?.run_id || '').trim()
|
||||
@@ -413,35 +588,42 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
? ''
|
||||
: String(payload?.result?.draft_payload?.claim_id || '').trim() || draftClaimId.value
|
||||
|
||||
replaceMessage(
|
||||
pendingMessage.id,
|
||||
createMessage('assistant', payload?.result?.answer || payload?.result?.message || '智能体已完成处理。', [], {
|
||||
meta: buildMessageMeta(payload, effectiveFileNames),
|
||||
citations: Array.isArray(payload?.result?.citations) ? payload.result.citations : [],
|
||||
suggestedActions: Array.isArray(payload?.result?.suggested_actions)
|
||||
? payload.result.suggested_actions
|
||||
: [],
|
||||
queryPayload: normalizeExpenseQueryPayload(payload?.result?.query_payload),
|
||||
draftPayload: payload?.result?.draft_payload || null,
|
||||
reviewPayload: payload?.result?.review_payload || null,
|
||||
riskFlags: Array.isArray(payload?.result?.risk_flags) ? payload.result.risk_flags : []
|
||||
})
|
||||
)
|
||||
const reviewActionResult = String(extraContext.review_action || '').trim()
|
||||
const resultClaimNo = String(payload?.result?.draft_payload?.claim_no || '').trim()
|
||||
const fallbackAnswer = reviewActionResult === 'link_to_existing_draft'
|
||||
? (resultClaimNo ? `已将本次上传的票据关联到草稿 ${resultClaimNo}。` : '已将本次上传的票据关联到现有草稿。')
|
||||
: '智能体已完成处理。'
|
||||
const assistantMessage = createMessage('assistant', payload?.result?.answer || payload?.result?.message || fallbackAnswer, [], {
|
||||
meta: buildMessageMeta(payload, effectiveFileNames),
|
||||
citations: Array.isArray(payload?.result?.citations) ? payload.result.citations : [],
|
||||
suggestedActions: Array.isArray(payload?.result?.suggested_actions)
|
||||
? payload.result.suggested_actions
|
||||
: [],
|
||||
queryPayload: normalizeExpenseQueryPayload(payload?.result?.query_payload),
|
||||
draftPayload: payload?.result?.draft_payload || null,
|
||||
reviewPayload: payload?.result?.review_payload || null,
|
||||
riskFlags: Array.isArray(payload?.result?.risk_flags) ? payload.result.risk_flags : []
|
||||
})
|
||||
replaceMessage(pendingMessage.id, assistantMessage)
|
||||
currentInsight.value = buildAgentInsight(
|
||||
payload,
|
||||
effectiveFileNames,
|
||||
mergeFilePreviews(filePreviews, ocrFilePreviews)
|
||||
)
|
||||
completeFlowResult(payload, flowRunDetail)
|
||||
persistSessionState()
|
||||
nextTick(scrollToBottom)
|
||||
|
||||
const resolvedDraftClaimId = String(payload?.result?.draft_payload?.claim_id || draftClaimId.value || '').trim()
|
||||
if (!isKnowledgeSession.value && resolvedDraftClaimId && files.length) {
|
||||
try {
|
||||
await syncComposerFilesToDraft(resolvedDraftClaimId, files)
|
||||
} catch (error) {
|
||||
console.warn('Failed to persist composer attachments to draft claim:', error)
|
||||
toast(error?.message || '票据已识别,但附件原件保存失败,请重试上传。')
|
||||
}
|
||||
void syncComposerFilesToDraft(resolvedDraftClaimId, files)
|
||||
.then(() => {
|
||||
persistSessionState()
|
||||
})
|
||||
.catch((error) => {
|
||||
console.warn('Failed to persist composer attachments to draft claim:', error)
|
||||
toast(error?.message || '票据已归集到草稿,但附件原件保存失败,请在单据详情中重新上传。')
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
clearFlowSimulationTimers()
|
||||
@@ -458,6 +640,7 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
)
|
||||
)
|
||||
currentInsight.value = buildErrorInsight(error, fileNames)
|
||||
persistSessionState()
|
||||
} finally {
|
||||
submitting.value = false
|
||||
composerUploadIntent.value = ''
|
||||
@@ -469,6 +652,7 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
|
||||
|
||||
return {
|
||||
confirmPendingAttachmentAssociationInternal: confirmPendingAttachmentAssociation,
|
||||
submitComposerInternal: submitComposer
|
||||
}
|
||||
}
|
||||
|
||||
34
web/tests/attachment-association-confirmation.test.mjs
Normal file
34
web/tests/attachment-association-confirmation.test.mjs
Normal file
@@ -0,0 +1,34 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
|
||||
import {
|
||||
ATTACHMENT_ASSOCIATION_CONFIRM_HREF,
|
||||
buildAttachmentAssociationConfirmationMessage
|
||||
} from '../src/views/scripts/travelReimbursementAttachmentModel.js'
|
||||
|
||||
test('attachment association prompt prints recognized receipt details before confirmation link', () => {
|
||||
const message = buildAttachmentAssociationConfirmationMessage({
|
||||
claimNo: 'EXP-202605-001',
|
||||
fileNames: ['train-ticket.pdf'],
|
||||
ocrDocuments: [
|
||||
{
|
||||
filename: 'train-ticket.pdf',
|
||||
document_type: 'train_ticket',
|
||||
scene_label: '差旅票据',
|
||||
summary: '铁路电子客票 武汉-上海 票价 354 元',
|
||||
document_fields: [
|
||||
{ key: 'route', label: '行程', value: '武汉-上海' },
|
||||
{ key: 'amount', label: '票价', value: '354.00' },
|
||||
{ key: 'date', label: '乘车日期', value: '2026-02-20' }
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
assert.match(message, /已识别附件信息:/)
|
||||
assert.match(message, /附件类型:差旅票据/)
|
||||
assert.match(message, /行程:武汉-上海/)
|
||||
assert.match(message, /票价:354.00/)
|
||||
assert.match(message, /草稿单号:EXP-202605-001/)
|
||||
assert.match(message, new RegExp(`\\[确认\\]\\(${ATTACHMENT_ASSOCIATION_CONFIRM_HREF}\\)`))
|
||||
})
|
||||
@@ -156,19 +156,19 @@ test('review drawer save action is disabled while receipt recognition is submitt
|
||||
)
|
||||
})
|
||||
|
||||
test('draft creation waits for composer attachments to be persisted before leaving submit state', () => {
|
||||
test('draft creation starts composer attachment persistence after response rendering', () => {
|
||||
assert.match(
|
||||
submitComposerScript,
|
||||
/try \{\s*await syncComposerFilesToDraft\(resolvedDraftClaimId, files\)\s*\} catch \(error\) \{/s
|
||||
/void syncComposerFilesToDraft\(resolvedDraftClaimId, files\)\s*\.then\(\(\) => \{\s*persistSessionState\(\)\s*\}\)\s*\.catch\(\(error\) => \{/s
|
||||
)
|
||||
assert.doesNotMatch(
|
||||
submitComposerScript,
|
||||
/syncComposerFilesToDraft\(resolvedDraftClaimId, files\)\.catch/
|
||||
/await syncComposerFilesToDraft\(resolvedDraftClaimId, files\)/
|
||||
)
|
||||
assert.ok(
|
||||
submitComposerScript.indexOf('await syncComposerFilesToDraft(resolvedDraftClaimId, files)') <
|
||||
submitComposerScript.indexOf('submitting.value = false'),
|
||||
'attachment persistence should finish before submit state is cleared'
|
||||
submitComposerScript.indexOf('replaceMessage(pendingMessage.id, assistantMessage)') <
|
||||
submitComposerScript.indexOf('void syncComposerFilesToDraft(resolvedDraftClaimId, files)'),
|
||||
'assistant response should render before background attachment persistence starts'
|
||||
)
|
||||
assert.match(attachmentsScript, /function normalizeAttachmentMatchName\(value\)/)
|
||||
assert.match(attachmentsScript, /const normalizedMatchBuckets = new Map\(\)/)
|
||||
|
||||
Reference in New Issue
Block a user