fix: 优化顶部导航栏布局与工作台摘要展示并清理旧票据数据

This commit is contained in:
caoxiaozhu
2026-06-03 17:40:52 +08:00
parent 8e2477587f
commit cb36d78fa2
45 changed files with 1017 additions and 1734 deletions

View File

@@ -1,121 +0,0 @@
{
"id": "057901b1-d38a-4e0c-9d53-44d14244317e",
"owner_key": "caoxiaozhu_xf.com",
"file_name": "2月20_武汉-上海.pdf",
"source_file_name": "2月20_武汉-上海.pdf",
"media_type": "application/pdf",
"size_bytes": 24995,
"uploaded_at": "2026-06-01T06:39:27.813933+00:00",
"status": "unlinked",
"linked_claim_id": "",
"linked_claim_no": "",
"linked_item_id": "",
"linked_at": "",
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"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中国铁路祝您旅途愉快",
"summary": "电子发票;(铁路电子客票);州",
"ocr_avg_score": 0.9580968717734019,
"ocr_line_count": 24,
"page_count": 1,
"document_type": "train_ticket",
"document_type_label": "火车/高铁票",
"scene_code": "travel",
"scene_label": "差旅票据",
"ocr_classification_source": "rule",
"ocr_classification_confidence": 0.88,
"ocr_classification_evidence": [
"铁路电子客票",
"电子客票",
"铁路",
"二等座"
],
"document_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": "武汉-上海"
},
{
"key": "invoice_date",
"label": "开票日期",
"value": "2026-05-18"
},
{
"key": "departure_station",
"label": "出发地点",
"value": "武汉"
},
{
"key": "arrival_station",
"label": "到达地点",
"value": "上海虹桥"
},
{
"key": "train_no",
"label": "车次",
"value": "G458"
},
{
"key": "passenger_name",
"label": "乘车人",
"value": "曹笑竹"
},
{
"key": "id_number",
"label": "身份证号",
"value": "4201061987****1615"
},
{
"key": "electronic_ticket_no",
"label": "电子客票号",
"value": "6580061086021391007342026"
},
{
"key": "seat_class",
"label": "席别",
"value": "二等座"
},
{
"key": "carriage_no",
"label": "车厢",
"value": "06车"
},
{
"key": "seat_no",
"label": "座位号",
"value": "01B"
},
{
"key": "fare",
"label": "票价",
"value": "354.00元"
}
],
"editable_fields": {},
"ocr_warnings": [],
"previewable": true,
"preview_kind": "image",
"preview_file_name": "preview.png",
"preview_media_type": "image/png"
}

View File

@@ -1,121 +0,0 @@
{
"id": "0abbdfaf-7952-4854-a5b2-bc34298fa1c4",
"owner_key": "caoxiaozhu_xf.com",
"file_name": "2月20_武汉-上海.pdf",
"source_file_name": "2月20_武汉-上海.pdf",
"media_type": "application/pdf",
"size_bytes": 24995,
"uploaded_at": "2026-06-01T06:08:52.697458+00:00",
"status": "linked",
"linked_claim_id": "19a8eaf2-13f2-45fc-b389-a292fadfd6d8",
"linked_claim_no": "RE-20260601060546-EE2PHJRK",
"linked_item_id": "b1b343b0-3564-4d35-919a-0e4220a9fceb",
"linked_at": "2026-06-01T06:08:52.697458+00:00",
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"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中国铁路祝您旅途愉快",
"summary": "电子发票;(铁路电子客票);州",
"ocr_avg_score": 0.9580968717734019,
"ocr_line_count": 24,
"page_count": 1,
"document_type": "train_ticket",
"document_type_label": "火车/高铁票",
"scene_code": "travel",
"scene_label": "差旅票据",
"ocr_classification_source": "rule",
"ocr_classification_confidence": 0.88,
"ocr_classification_evidence": [
"铁路电子客票",
"电子客票",
"铁路",
"二等座"
],
"document_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": "武汉-上海"
},
{
"key": "invoice_date",
"label": "开票日期",
"value": "2026-05-18"
},
{
"key": "departure_station",
"label": "出发地点",
"value": "武汉"
},
{
"key": "arrival_station",
"label": "到达地点",
"value": "上海虹桥"
},
{
"key": "train_no",
"label": "车次",
"value": "G458"
},
{
"key": "passenger_name",
"label": "乘车人",
"value": "曹笑竹"
},
{
"key": "id_number",
"label": "身份证号",
"value": "4201061987****1615"
},
{
"key": "electronic_ticket_no",
"label": "电子客票号",
"value": "6580061086021391007342026"
},
{
"key": "seat_class",
"label": "席别",
"value": "二等座"
},
{
"key": "carriage_no",
"label": "车厢",
"value": "06车"
},
{
"key": "seat_no",
"label": "座位号",
"value": "01B"
},
{
"key": "fare",
"label": "票价",
"value": "354.00元"
}
],
"editable_fields": {},
"ocr_warnings": [],
"previewable": true,
"preview_kind": "image",
"preview_file_name": "preview.png",
"preview_media_type": "image/png"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

View File

@@ -1,66 +0,0 @@
{
"id": "29ec7c4c-abc0-46f0-8eae-3136c2d6fef7",
"owner_key": "caoxiaozhu_xf.com",
"file_name": "2月20_武汉-上海.pdf",
"source_file_name": "2月20_武汉-上海.pdf",
"media_type": "application/pdf",
"size_bytes": 24995,
"uploaded_at": "2026-05-30T07:00:12.286631+00:00",
"status": "unlinked",
"linked_claim_id": "",
"linked_claim_no": "",
"linked_item_id": "",
"linked_at": "",
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"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中国铁路祝您旅途愉快",
"summary": "电子发票;(铁路电子客票);州",
"ocr_avg_score": 0.9580968717734019,
"ocr_line_count": 24,
"page_count": 1,
"document_type": "train_ticket",
"document_type_label": "火车/高铁票",
"scene_code": "travel",
"scene_label": "差旅票据",
"ocr_classification_source": "rule",
"ocr_classification_confidence": 0.88,
"ocr_classification_evidence": [
"铁路电子客票",
"电子客票",
"铁路",
"二等座"
],
"document_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": "武汉-上海"
}
],
"editable_fields": {},
"ocr_warnings": [],
"previewable": true,
"preview_kind": "image",
"preview_file_name": "preview.png",
"preview_media_type": "image/png"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

View File

@@ -1,66 +0,0 @@
{
"id": "2fd4856f-e918-4d29-a0b2-340cc1fdec03",
"owner_key": "caoxiaozhu_xf.com",
"file_name": "2月20_武汉-上海.pdf",
"source_file_name": "2月20_武汉-上海.pdf",
"media_type": "application/pdf",
"size_bytes": 24995,
"uploaded_at": "2026-05-30T07:00:40.560540+00:00",
"status": "linked",
"linked_claim_id": "6b8e29c9-8bd6-453b-b594-ed0e5b59b91f",
"linked_claim_no": "RE-20260530065944-M94FAPB9",
"linked_item_id": "329f477a-d926-4101-8ec8-4c8a95150f22",
"linked_at": "2026-05-30T07:00:40.560540+00:00",
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"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中国铁路祝您旅途愉快",
"summary": "电子发票;(铁路电子客票);州",
"ocr_avg_score": 0.9580968717734019,
"ocr_line_count": 24,
"page_count": 1,
"document_type": "train_ticket",
"document_type_label": "火车/高铁票",
"scene_code": "travel",
"scene_label": "差旅票据",
"ocr_classification_source": "rule",
"ocr_classification_confidence": 0.88,
"ocr_classification_evidence": [
"铁路电子客票",
"电子客票",
"铁路",
"二等座"
],
"document_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": "武汉-上海"
}
],
"editable_fields": {},
"ocr_warnings": [],
"previewable": true,
"preview_kind": "image",
"preview_file_name": "preview.png",
"preview_media_type": "image/png"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

View File

@@ -1,16 +1,16 @@
{ {
"id": "e8d4f21f-846f-4321-a341-52cd3dfb5acc", "id": "33a1c4b9-56e1-49d1-823e-5cb4680f5a40",
"owner_key": "caoxiaozhu_xf.com", "owner_key": "caoxiaozhu_xf.com",
"file_name": "2月20_武汉-上海.pdf", "file_name": "2月20_武汉-上海.pdf",
"source_file_name": "2月20_武汉-上海.pdf", "source_file_name": "2月20_武汉-上海.pdf",
"media_type": "application/pdf", "media_type": "application/pdf",
"size_bytes": 24995, "size_bytes": 24995,
"uploaded_at": "2026-06-01T06:57:44.644255+00:00", "uploaded_at": "2026-06-03T08:39:19.288158+00:00",
"status": "linked", "status": "linked",
"linked_claim_id": "19a8eaf2-13f2-45fc-b389-a292fadfd6d8", "linked_claim_id": "2ad80b25-b153-407e-91be-ed2651045fb1",
"linked_claim_no": "RE-20260601060546-EE2PHJRK", "linked_claim_no": "RE-20260603083825-876B85XW",
"linked_item_id": "26ccabf8-7e69-4812-acc6-fa18899ec5b2", "linked_item_id": "eb1e9fde-b7e8-4f6e-823f-d8252489e7f9",
"linked_at": "2026-06-01T06:57:44.644255+00:00", "linked_at": "2026-06-03T08:39:19.288158+00:00",
"engine": "paddleocr_mobile", "engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile", "model": "PP-OCRv5_mobile",
"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_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中国铁路祝您旅途愉快",

View File

@@ -1,121 +0,0 @@
{
"id": "64b90764-b957-4a54-b231-0646ee60d1cd",
"owner_key": "caoxiaozhu_xf.com",
"file_name": "2月20_武汉-上海.pdf",
"source_file_name": "2月20_武汉-上海.pdf",
"media_type": "application/pdf",
"size_bytes": 24995,
"uploaded_at": "2026-06-01T06:08:07.688668+00:00",
"status": "unlinked",
"linked_claim_id": "",
"linked_claim_no": "",
"linked_item_id": "",
"linked_at": "",
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"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中国铁路祝您旅途愉快",
"summary": "电子发票;(铁路电子客票);州",
"ocr_avg_score": 0.9580968717734019,
"ocr_line_count": 24,
"page_count": 1,
"document_type": "train_ticket",
"document_type_label": "火车/高铁票",
"scene_code": "travel",
"scene_label": "差旅票据",
"ocr_classification_source": "rule",
"ocr_classification_confidence": 0.88,
"ocr_classification_evidence": [
"铁路电子客票",
"电子客票",
"铁路",
"二等座"
],
"document_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": "武汉-上海"
},
{
"key": "invoice_date",
"label": "开票日期",
"value": "2026-05-18"
},
{
"key": "departure_station",
"label": "出发地点",
"value": "武汉"
},
{
"key": "arrival_station",
"label": "到达地点",
"value": "上海虹桥"
},
{
"key": "train_no",
"label": "车次",
"value": "G458"
},
{
"key": "passenger_name",
"label": "乘车人",
"value": "曹笑竹"
},
{
"key": "id_number",
"label": "身份证号",
"value": "4201061987****1615"
},
{
"key": "electronic_ticket_no",
"label": "电子客票号",
"value": "6580061086021391007342026"
},
{
"key": "seat_class",
"label": "席别",
"value": "二等座"
},
{
"key": "carriage_no",
"label": "车厢",
"value": "06车"
},
{
"key": "seat_no",
"label": "座位号",
"value": "01B"
},
{
"key": "fare",
"label": "票价",
"value": "354.00元"
}
],
"editable_fields": {},
"ocr_warnings": [],
"previewable": true,
"preview_kind": "image",
"preview_file_name": "preview.png",
"preview_media_type": "image/png"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

View File

@@ -1,121 +0,0 @@
{
"id": "67dc947b-be67-444d-9a91-897190170021",
"owner_key": "caoxiaozhu_xf.com",
"file_name": "2月20_武汉-上海.pdf",
"source_file_name": "2月20_武汉-上海.pdf",
"media_type": "application/pdf",
"size_bytes": 24995,
"uploaded_at": "2026-06-01T06:40:08.599943+00:00",
"status": "linked",
"linked_claim_id": "19a8eaf2-13f2-45fc-b389-a292fadfd6d8",
"linked_claim_no": "RE-20260601060546-EE2PHJRK",
"linked_item_id": "c1693c4a-dcbd-4a8b-941c-bb0abc6ec65a",
"linked_at": "2026-06-01T06:40:08.599943+00:00",
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"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中国铁路祝您旅途愉快",
"summary": "电子发票;(铁路电子客票);州",
"ocr_avg_score": 0.9580968717734019,
"ocr_line_count": 24,
"page_count": 1,
"document_type": "train_ticket",
"document_type_label": "火车/高铁票",
"scene_code": "travel",
"scene_label": "差旅票据",
"ocr_classification_source": "rule",
"ocr_classification_confidence": 0.88,
"ocr_classification_evidence": [
"铁路电子客票",
"电子客票",
"铁路",
"二等座"
],
"document_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": "武汉-上海"
},
{
"key": "invoice_date",
"label": "开票日期",
"value": "2026-05-18"
},
{
"key": "departure_station",
"label": "出发地点",
"value": "武汉"
},
{
"key": "arrival_station",
"label": "到达地点",
"value": "上海虹桥"
},
{
"key": "train_no",
"label": "车次",
"value": "G458"
},
{
"key": "passenger_name",
"label": "乘车人",
"value": "曹笑竹"
},
{
"key": "id_number",
"label": "身份证号",
"value": "4201061987****1615"
},
{
"key": "electronic_ticket_no",
"label": "电子客票号",
"value": "6580061086021391007342026"
},
{
"key": "seat_class",
"label": "席别",
"value": "二等座"
},
{
"key": "carriage_no",
"label": "车厢",
"value": "06车"
},
{
"key": "seat_no",
"label": "座位号",
"value": "01B"
},
{
"key": "fare",
"label": "票价",
"value": "354.00元"
}
],
"editable_fields": {},
"ocr_warnings": [],
"previewable": true,
"preview_kind": "image",
"preview_file_name": "preview.png",
"preview_media_type": "image/png"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

View File

@@ -1,16 +1,16 @@
{ {
"id": "fa80f870-10a3-4797-a151-39e702927eb5", "id": "67f51c17-a2bc-42bd-99a4-199ee32b18c3",
"owner_key": "caoxiaozhu_xf.com", "owner_key": "caoxiaozhu_xf.com",
"file_name": "2月23_上海-武汉.pdf", "file_name": "2月23_上海-武汉.pdf",
"source_file_name": "2月23_上海-武汉.pdf", "source_file_name": "2月23_上海-武汉.pdf",
"media_type": "application/pdf", "media_type": "application/pdf",
"size_bytes": 24940, "size_bytes": 24940,
"uploaded_at": "2026-06-01T06:40:32.249473+00:00", "uploaded_at": "2026-06-03T08:40:26.766004+00:00",
"status": "linked", "status": "linked",
"linked_claim_id": "19a8eaf2-13f2-45fc-b389-a292fadfd6d8", "linked_claim_id": "2ad80b25-b153-407e-91be-ed2651045fb1",
"linked_claim_no": "RE-20260601060546-EE2PHJRK", "linked_claim_no": "RE-20260603083825-876B85XW",
"linked_item_id": "b0b28405-30b5-4c35-9bd5-13abe4d2c4cd", "linked_item_id": "977f01f8-e7ab-487b-8055-db8864464784",
"linked_at": "2026-06-01T06:40:32.249473+00:00", "linked_at": "2026-06-03T08:40:26.766004+00:00",
"engine": "paddleocr_mobile", "engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile", "model": "PP-OCRv5_mobile",
"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_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中国铁路祝您旅途愉快",

View File

@@ -1,121 +0,0 @@
{
"id": "6a7335e9-b36a-415c-b2d5-26f421ec72b0",
"owner_key": "caoxiaozhu_xf.com",
"file_name": "2月23_上海-武汉.pdf",
"source_file_name": "2月23_上海-武汉.pdf",
"media_type": "application/pdf",
"size_bytes": 24940,
"uploaded_at": "2026-06-01T06:08:07.724830+00:00",
"status": "unlinked",
"linked_claim_id": "",
"linked_claim_no": "",
"linked_item_id": "",
"linked_at": "",
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"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中国铁路祝您旅途愉快",
"summary": "电子发票;(铁路电子客票);州",
"ocr_avg_score": 0.9620026834309101,
"ocr_line_count": 24,
"page_count": 1,
"document_type": "train_ticket",
"document_type_label": "火车/高铁票",
"scene_code": "travel",
"scene_label": "差旅票据",
"ocr_classification_source": "rule",
"ocr_classification_confidence": 0.88,
"ocr_classification_evidence": [
"铁路电子客票",
"电子客票",
"铁路",
"二等座"
],
"document_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": "上海-武汉"
},
{
"key": "invoice_date",
"label": "开票日期",
"value": "2026-05-18"
},
{
"key": "departure_station",
"label": "出发地点",
"value": "上海虹桥"
},
{
"key": "arrival_station",
"label": "到达地点",
"value": "武汉"
},
{
"key": "train_no",
"label": "车次",
"value": "G456"
},
{
"key": "passenger_name",
"label": "乘车人",
"value": "曹笑竹"
},
{
"key": "id_number",
"label": "身份证号",
"value": "4201061987****1615"
},
{
"key": "electronic_ticket_no",
"label": "电子客票号",
"value": "6610061086021394837402026"
},
{
"key": "seat_class",
"label": "席别",
"value": "二等座"
},
{
"key": "carriage_no",
"label": "车厢",
"value": "12车"
},
{
"key": "seat_no",
"label": "座位号",
"value": "08B"
},
{
"key": "fare",
"label": "票价",
"value": "354.00元"
}
],
"editable_fields": {},
"ocr_warnings": [],
"previewable": true,
"preview_kind": "image",
"preview_file_name": "preview.png",
"preview_media_type": "image/png"
}

View File

@@ -0,0 +1,55 @@
{
"id": "8678e169-d800-4846-9354-eb768a9b65f8",
"owner_key": "caoxiaozhu_xf.com",
"file_name": "酒店3.jpg",
"source_file_name": "酒店3.jpg",
"media_type": "image/jpeg",
"size_bytes": 153582,
"uploaded_at": "2026-06-03T08:41:47.393654+00:00",
"status": "linked",
"linked_claim_id": "2ad80b25-b153-407e-91be-ed2651045fb1",
"linked_claim_no": "RE-20260603083825-876B85XW",
"linked_item_id": "42250571-3e84-4f27-b3e8-aa224b5cb2f7",
"linked_at": "2026-06-03T08:41:47.393654+00:00",
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"ocr_text": "上海喜来登酒店(样例)\n住宿费用单\n单据编号SH-SAMPLE-20260223-001\n开单期2026年223\n宾客姓名曹笑\n住期2026年220\n离店期2026年223\n住晚数3晚\n房型豪华床房\n房号1808\n项目\n日期\n数量\n单价\n金额\n备注\n住宿费\n2026-02-20至2026-02-22\n3晚\n¥362/晚\n¥1086\n豪华大床房\n金额大写壹仟零捌拾陆元整\n合计¥1086\n备注\n1.如有疑问请致电前台021-28958888。\n2.退房时间为中午1200超时退房将按酒店规定收取相关费用。\n3.感谢您的下榻,期待您的再次光临!\n酒店地址上海市浦东新区银城中路88号 邮编200120\n样例票据|仅供系统测试|无效凭证",
"summary": "上海喜来登酒店样例住宿费用单单据编号SH-SAMPLE-20260223-001",
"ocr_avg_score": 0.988790222009023,
"ocr_line_count": 30,
"page_count": 1,
"document_type": "hotel_invoice",
"document_type_label": "酒店住宿票据",
"scene_code": "hotel",
"scene_label": "住宿票据",
"ocr_classification_source": "rule",
"ocr_classification_confidence": 0.71,
"ocr_classification_evidence": [
"住宿",
"离店",
"酒店"
],
"document_fields": [
{
"key": "amount",
"label": "金额",
"value": "1086元"
},
{
"key": "date",
"label": "日期",
"value": "2026-02-20"
},
{
"key": "merchant_name",
"label": "商户",
"value": "上海喜来登酒店"
}
],
"editable_fields": {},
"ocr_warnings": [],
"previewable": true,
"preview_kind": "image",
"preview_file_name": "preview.jpg",
"preview_media_type": "image/jpeg"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

View File

@@ -1,121 +0,0 @@
{
"id": "87c5ddbf-15be-4d21-982d-808267902ab0",
"owner_key": "caoxiaozhu_xf.com",
"file_name": "2月23_上海-武汉.pdf",
"source_file_name": "2月23_上海-武汉.pdf",
"media_type": "application/pdf",
"size_bytes": 24940,
"uploaded_at": "2026-06-01T06:39:27.857168+00:00",
"status": "unlinked",
"linked_claim_id": "",
"linked_claim_no": "",
"linked_item_id": "",
"linked_at": "",
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"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中国铁路祝您旅途愉快",
"summary": "电子发票;(铁路电子客票);州",
"ocr_avg_score": 0.9620026834309101,
"ocr_line_count": 24,
"page_count": 1,
"document_type": "train_ticket",
"document_type_label": "火车/高铁票",
"scene_code": "travel",
"scene_label": "差旅票据",
"ocr_classification_source": "rule",
"ocr_classification_confidence": 0.88,
"ocr_classification_evidence": [
"铁路电子客票",
"电子客票",
"铁路",
"二等座"
],
"document_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": "上海-武汉"
},
{
"key": "invoice_date",
"label": "开票日期",
"value": "2026-05-18"
},
{
"key": "departure_station",
"label": "出发地点",
"value": "上海虹桥"
},
{
"key": "arrival_station",
"label": "到达地点",
"value": "武汉"
},
{
"key": "train_no",
"label": "车次",
"value": "G456"
},
{
"key": "passenger_name",
"label": "乘车人",
"value": "曹笑竹"
},
{
"key": "id_number",
"label": "身份证号",
"value": "4201061987****1615"
},
{
"key": "electronic_ticket_no",
"label": "电子客票号",
"value": "6610061086021394837402026"
},
{
"key": "seat_class",
"label": "席别",
"value": "二等座"
},
{
"key": "carriage_no",
"label": "车厢",
"value": "12车"
},
{
"key": "seat_no",
"label": "座位号",
"value": "08B"
},
{
"key": "fare",
"label": "票价",
"value": "354.00元"
}
],
"editable_fields": {},
"ocr_warnings": [],
"previewable": true,
"preview_kind": "image",
"preview_file_name": "preview.png",
"preview_media_type": "image/png"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

View File

@@ -1,121 +0,0 @@
{
"id": "fd4f2229-bf01-48ae-99b9-b98458e2b632",
"owner_key": "caoxiaozhu_xf.com",
"file_name": "2月20_武汉-上海.pdf",
"source_file_name": "2月20_武汉-上海.pdf",
"media_type": "application/pdf",
"size_bytes": 24995,
"uploaded_at": "2026-06-01T06:56:59.257104+00:00",
"status": "unlinked",
"linked_claim_id": "",
"linked_claim_no": "",
"linked_item_id": "",
"linked_at": "",
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"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中国铁路祝您旅途愉快",
"summary": "电子发票;(铁路电子客票);州",
"ocr_avg_score": 0.9580968717734019,
"ocr_line_count": 24,
"page_count": 1,
"document_type": "train_ticket",
"document_type_label": "火车/高铁票",
"scene_code": "travel",
"scene_label": "差旅票据",
"ocr_classification_source": "rule",
"ocr_classification_confidence": 0.88,
"ocr_classification_evidence": [
"铁路电子客票",
"电子客票",
"铁路",
"二等座"
],
"document_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": "武汉-上海"
},
{
"key": "invoice_date",
"label": "开票日期",
"value": "2026-05-18"
},
{
"key": "departure_station",
"label": "出发地点",
"value": "武汉"
},
{
"key": "arrival_station",
"label": "到达地点",
"value": "上海虹桥"
},
{
"key": "train_no",
"label": "车次",
"value": "G458"
},
{
"key": "passenger_name",
"label": "乘车人",
"value": "曹笑竹"
},
{
"key": "id_number",
"label": "身份证号",
"value": "4201061987****1615"
},
{
"key": "electronic_ticket_no",
"label": "电子客票号",
"value": "6580061086021391007342026"
},
{
"key": "seat_class",
"label": "席别",
"value": "二等座"
},
{
"key": "carriage_no",
"label": "车厢",
"value": "06车"
},
{
"key": "seat_no",
"label": "座位号",
"value": "01B"
},
{
"key": "fare",
"label": "票价",
"value": "354.00元"
}
],
"editable_fields": {},
"ocr_warnings": [],
"previewable": true,
"preview_kind": "image",
"preview_file_name": "preview.png",
"preview_media_type": "image/png"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

View File

@@ -73,9 +73,9 @@
.insight-metric-row, .insight-metric-row,
.insight-profile-card { .insight-profile-card {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) auto; grid-template-columns: 18px minmax(0, 1fr) auto;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
min-height: 0; min-height: 0;
padding: 7px 9px; padding: 7px 9px;
border: 1px solid rgba(var(--theme-primary-rgb, 58, 124, 165), 0.12); border: 1px solid rgba(var(--theme-primary-rgb, 58, 124, 165), 0.12);
@@ -102,6 +102,15 @@
rgba(var(--theme-primary-rgb, 58, 124, 165), 0.04); rgba(var(--theme-primary-rgb, 58, 124, 165), 0.04);
} }
.insight-metric-icon,
.insight-profile-icon {
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--workbench-muted);
font-size: 16px;
}
.insight-metric-label, .insight-metric-label,
.insight-profile-label { .insight-profile-label {
min-width: 0; min-width: 0;
@@ -136,19 +145,21 @@
font-weight: 700; font-weight: 700;
} }
.insight-metric-row--amount .insight-metric-icon,
.insight-metric-row--amount .insight-metric-value { .insight-metric-row--amount .insight-metric-value {
color: var(--workbench-primary-active); color: var(--workbench-primary-active);
} }
.insight-metric-row--warning .insight-metric-icon,
.insight-metric-row--warning .insight-metric-value { .insight-metric-row--warning .insight-metric-value {
color: var(--warning); color: var(--warning);
} }
.insight-metric-row--info .insight-metric-icon,
.insight-metric-row--info .insight-metric-value { .insight-metric-row--info .insight-metric-value {
color: var(--workbench-chart-blue); color: var(--workbench-chart-blue);
} }
.insight-profile-icon,
.insight-profile-hint { .insight-profile-hint {
display: none; display: none;
} }

View File

@@ -505,12 +505,19 @@
border-top: 0; border-top: 0;
} }
.progress-identity,
.progress-result {
gap: 12px;
}
.progress-identity strong, .progress-identity strong,
.progress-result strong { .progress-result strong {
margin-bottom: 2px;
overflow: hidden; overflow: hidden;
color: var(--workbench-ink); color: var(--workbench-ink);
font-size: 13px; font-size: 13px;
font-weight: 850; font-weight: bold;
line-height: 1.25; line-height: 1.25;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@@ -573,24 +580,29 @@
} }
.progress-status--warning { .progress-status--warning {
background: var(--warning-soft); background: var(--warning-soft, #fff7ed);
color: var(--warning); color: var(--warning, #ea580c);
} }
.progress-status--success { .progress-status--success {
background: var(--workbench-primary-soft); background: var(--workbench-primary-soft, #eaf4fa);
color: var(--workbench-primary-active); color: var(--workbench-primary-active, #255b7d);
} }
.progress-status--muted { .progress-status--muted {
background: var(--info-soft); background: var(--info-soft, #f1f5f9);
color: var(--workbench-muted); color: var(--workbench-muted, #64748b);
}
.progress-status--danger {
background: var(--danger-soft, #fef2f2);
color: var(--danger, #dc2626);
} }
.progress-row { .progress-row {
position: relative; position: relative;
display: grid; display: grid;
grid-template-columns: minmax(78px, 0.42fr) minmax(132px, 0.74fr) minmax(84px, 0.42fr) minmax(260px, 1.28fr) minmax(92px, auto); grid-template-columns: minmax(118px, 0.58fr) minmax(132px, 0.74fr) minmax(84px, 0.42fr) minmax(260px, 1.28fr) minmax(92px, auto);
align-items: center; align-items: center;
gap: 12px; gap: 12px;
width: 100%; width: 100%;
@@ -638,6 +650,54 @@
pointer-events: none; pointer-events: none;
} }
.progress-time-wrapper {
display: flex;
align-items: center;
gap: 14px;
min-width: 0;
}
.expense-type-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 8px;
font-size: 20px;
flex-shrink: 0;
}
.expense-type-icon--blue {
background: color-mix(in srgb, var(--workbench-primary, #3a7ca5) 12%, #ffffff);
color: var(--workbench-primary, #3a7ca5);
}
.expense-type-icon--amber {
background: color-mix(in srgb, var(--workbench-chart-amber, #b58b4c) 12%, #ffffff);
color: var(--workbench-chart-amber, #b58b4c);
}
.expense-type-icon--emerald {
background: color-mix(in srgb, #10b981 12%, #ffffff);
color: #10b981;
}
.expense-type-icon--violet {
background: color-mix(in srgb, #8b5cf6 12%, #ffffff);
color: #8b5cf6;
}
.expense-type-icon--cyan {
background: color-mix(in srgb, #06b6d4 12%, #ffffff);
color: #06b6d4;
}
.expense-type-icon--muted {
background: var(--info-soft, #f1f5f9);
color: var(--workbench-muted, #64748b);
}
.progress-time, .progress-time,
.progress-identity, .progress-identity,
.progress-type, .progress-type,
@@ -649,6 +709,7 @@
.progress-time { .progress-time {
color: var(--workbench-muted); color: var(--workbench-muted);
justify-items: center;
} }
.progress-time time { .progress-time time {
@@ -669,6 +730,16 @@
line-height: 1.2; line-height: 1.2;
} }
.progress-time .time-capsule {
margin-top: 4px;
padding: 2px 6px;
border-radius: 999px;
background: var(--danger-soft, #fef2f2);
color: var(--danger, #dc2626);
font-weight: 850;
line-height: 1.2;
}
.progress-result { .progress-result {
justify-items: end; justify-items: end;
} }

View File

@@ -408,115 +408,168 @@
display: inline-flex; display: inline-flex;
} }
.notification-wrap.is-open .notification-btn {
border: 1px solid var(--theme-primary-light-5);
background: var(--theme-primary-light-9);
color: var(--theme-primary-active);
}
.notification-btn { .notification-btn {
position: relative; position: relative;
overflow: visible; overflow: visible;
border: 1px solid transparent;
border-radius: 4px;
transition:
border-color 180ms var(--ease),
background 180ms var(--ease),
color 180ms var(--ease);
} }
.notification-badge { .notification-badge {
position: absolute; position: absolute;
top: 1px; top: 2px;
right: 0; right: 2px;
min-width: 15px; min-width: 16px;
height: 15px; height: 16px;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 0 4px; padding: 0 4px;
border: 2px solid #fff; border: 2px solid #fff;
border-radius: 999px; border-radius: 4px;
background: #ef4444; background: #dc2626;
color: #fff; color: #fff;
font-size: 9px; font-size: 10px;
font-weight: 850; font-weight: 800;
line-height: 1; line-height: 1;
box-shadow: 0 5px 10px rgba(239, 68, 68, .22); letter-spacing: -0.02em;
}
.notification-panel-enter-active,
.notification-panel-leave-active {
transition:
opacity 220ms var(--ease),
transform 220ms var(--ease);
}
.notification-panel-enter-from,
.notification-panel-leave-to {
opacity: 0;
transform: translateY(-6px);
}
@media (prefers-reduced-motion: reduce) {
.notification-panel-enter-active,
.notification-panel-leave-active {
transition-duration: 1ms;
}
.notification-panel-enter-from,
.notification-panel-leave-to {
transform: none;
}
} }
.notification-popover { .notification-popover {
position: absolute; position: absolute;
top: calc(100% + 10px); top: calc(100% + 8px);
right: -8px; right: 0;
z-index: 60; z-index: 60;
width: min(392px, calc(100vw - 32px)); width: min(380px, calc(100vw - 32px));
display: grid; display: grid;
gap: 12px; grid-template-rows: auto auto minmax(0, 1fr);
padding: 14px; gap: 0;
border: 1px solid #e5edf5; overflow: hidden;
border: 1px solid #d7e0ea;
border-radius: 4px; border-radius: 4px;
background: #fff; background: #fff;
box-shadow: box-shadow: 0 16px 40px rgba(15, 23, 42, 0.12);
0 18px 46px rgba(15, 23, 42, 0.14),
inset 0 1px 0 rgba(255, 255, 255, 0.92);
} }
.notification-popover::before { .notification-popover::before {
content: ""; content: "";
position: absolute; display: block;
top: -6px; height: 3px;
right: 18px; background: linear-gradient(
width: 10px; 90deg,
height: 10px; var(--theme-primary-active) 0%,
border-top: 1px solid #e5edf5; var(--theme-primary-light-3, #7eb3d4) 100%
border-left: 1px solid #e5edf5; );
background: #fff;
transform: rotate(45deg);
}
.notification-head,
.notification-tabs {
position: relative;
z-index: 1;
display: flex;
align-items: center;
} }
.notification-head { .notification-head {
display: flex;
align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 10px; gap: 12px;
padding-bottom: 10px; padding: 12px 14px 10px;
border-bottom: 1px solid #edf2f7; border-bottom: 1px solid #edf2f7;
background: #fafbfd;
}
.notification-head-brand {
min-width: 0;
display: flex;
align-items: center;
gap: 10px;
}
.notification-head-icon {
width: 32px;
height: 32px;
flex: 0 0 auto;
display: grid;
place-items: center;
border: 1px solid var(--theme-primary-light-6);
border-radius: 4px;
background: #fff;
color: var(--theme-primary-active);
font-size: 17px;
} }
.notification-head-copy { .notification-head-copy {
min-width: 0;
display: grid; display: grid;
gap: 3px; gap: 2px;
} }
.notification-head strong { .notification-head strong {
color: #0f172a; color: #0f172a;
font-size: 15px; font-size: 14px;
font-weight: 850; font-weight: 800;
letter-spacing: 0.01em;
} }
.notification-head small { .notification-head small {
color: #64748b; color: #64748b;
font-size: 12px; font-size: 12px;
font-weight: 650; font-weight: 600;
} }
.notification-head-actions { .notification-head-actions {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 8px; gap: 4px;
flex: 0 0 auto; flex: 0 0 auto;
} }
.notification-clear-btn { .notification-clear-btn {
height: 26px; height: 28px;
padding: 0 9px; padding: 0 10px;
border: 1px solid #dbe4ee; border: 0;
border-radius: 4px; border-radius: 4px;
background: #fff; background: transparent;
color: #475569; color: var(--theme-primary-active);
font-size: 12px; font-size: 12px;
font-weight: 800; font-weight: 750;
white-space: nowrap;
transition:
background 160ms var(--ease),
color 160ms var(--ease);
} }
.notification-clear-btn:hover:not(:disabled) { .notification-clear-btn:hover:not(:disabled) {
border-color: var(--theme-primary-light-5);
background: var(--theme-primary-light-9); background: var(--theme-primary-light-9);
color: var(--theme-primary-active);
} }
.notification-clear-btn:disabled { .notification-clear-btn:disabled {
@@ -525,111 +578,92 @@
} }
.notification-close-btn { .notification-close-btn {
position: relative; width: 28px;
width: 26px; height: 28px;
height: 26px;
display: inline-grid; display: inline-grid;
place-items: center; place-items: center;
border: 1px solid transparent; border: 0;
border-radius: 4px; border-radius: 4px;
background: transparent;
color: #64748b; color: #64748b;
} font-size: 18px;
transition:
.notification-close-btn span, background 160ms var(--ease),
.notification-close-btn span::before, color 160ms var(--ease);
.notification-close-btn span::after {
position: absolute;
display: block;
}
.notification-close-btn span {
inset: 0;
}
.notification-close-btn span::before,
.notification-close-btn span::after {
content: "";
top: 50%;
left: 50%;
width: 12px;
height: 2px;
border-radius: 999px;
background: currentColor;
transform-origin: center;
}
.notification-close-btn span::before {
transform: translate(-50%, -50%) rotate(45deg);
}
.notification-close-btn span::after {
transform: translate(-50%, -50%) rotate(-45deg);
} }
.notification-close-btn:hover { .notification-close-btn:hover {
border-color: #e2e8f0; background: #eef2f7;
background: #f8fafc;
color: #0f172a; color: #0f172a;
} }
.notification-tabs { .notification-tabs {
gap: 6px; display: flex;
padding: 3px; align-items: stretch;
border: 1px solid #edf2f7; gap: 0;
border-radius: 4px; padding: 0 14px;
background: #f8fafc; border-bottom: 1px solid #edf2f7;
background: #fff;
} }
.notification-tabs button { .notification-tabs button {
position: relative;
flex: 1 1 0; flex: 1 1 0;
height: 30px; height: 38px;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 6px; gap: 6px;
border-radius: 3px; border: 0;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
background: transparent;
color: #64748b; color: #64748b;
font-size: 12px; font-size: 13px;
font-weight: 800; font-weight: 750;
transition:
color 180ms var(--ease),
border-color 180ms var(--ease);
} }
.notification-tabs button em { .notification-tabs button em {
min-width: 18px; min-width: 20px;
height: 18px; height: 20px;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 0 6px; padding: 0 6px;
border-radius: 999px; border-radius: 4px;
background: #e2e8f0; background: #f1f5f9;
color: #475569; color: #475569;
font-style: normal; font-style: normal;
font-size: 11px; font-size: 11px;
font-weight: 800;
line-height: 1; line-height: 1;
transition:
background 180ms var(--ease),
color 180ms var(--ease);
} }
.notification-tabs button.active { .notification-tabs button.active {
background: #fff;
color: var(--theme-primary-active); color: var(--theme-primary-active);
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08); border-bottom-color: var(--theme-primary-active);
} }
.notification-tabs button.active em { .notification-tabs button.active em {
background: var(--theme-primary-light-8); background: var(--theme-primary-light-9);
color: var(--theme-primary-active); color: var(--theme-primary-active);
} }
.notification-list { .notification-list {
position: relative; display: flex;
z-index: 1; flex-direction: column;
display: grid; max-height: 280px;
gap: 8px;
max-height: 244px;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
padding-right: 2px; padding: 6px 0;
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: #cbd5e1 transparent; scrollbar-color: #cbd5e1 #f8fafc;
} }
.notification-list::-webkit-scrollbar { .notification-list::-webkit-scrollbar {
@@ -637,45 +671,56 @@
} }
.notification-list::-webkit-scrollbar-track { .notification-list::-webkit-scrollbar-track {
background: transparent; background: #f8fafc;
} }
.notification-list::-webkit-scrollbar-thumb { .notification-list::-webkit-scrollbar-thumb {
border-radius: 999px; border-radius: 4px;
background: #cbd5e1; background: #cbd5e1;
} }
.notification-row { .notification-row {
display: grid; display: grid;
grid-template-columns: 34px minmax(0, 1fr) 16px; grid-template-columns: 36px minmax(0, 1fr) 14px;
align-items: start; align-items: center;
gap: 10px; gap: 10px;
min-height: 72px; min-height: 0;
padding: 10px; padding: 10px 14px;
border: 1px solid #edf2f7; border: 0;
border-radius: 4px; border-left: 3px solid transparent;
background: #fff; border-radius: 0;
background: transparent;
text-align: left; text-align: left;
transition: transition:
border-color 160ms var(--ease), background 180ms var(--ease),
background 160ms var(--ease), border-color 180ms var(--ease);
box-shadow 160ms var(--ease); }
.notification-row + .notification-row {
border-top: 1px solid #f1f5f9;
}
.notification-row.unread {
border-left-color: var(--theme-primary-active);
background: linear-gradient(90deg, var(--theme-primary-light-9) 0%, #fff 42%);
} }
.notification-row:hover { .notification-row:hover {
border-color: var(--theme-primary-light-5); background: #f8fafc;
background: #f8fbff; }
box-shadow: 0 8px 18px rgba(37, 99, 235, 0.08);
.notification-row.unread:hover {
background: linear-gradient(90deg, var(--theme-primary-light-8) 0%, #f8fafc 48%);
} }
.notification-type-icon { .notification-type-icon {
width: 34px; width: 36px;
height: 34px; height: 36px;
display: grid; display: grid;
place-items: center; place-items: center;
border: 1px solid var(--theme-primary-light-6); border: 1px solid var(--theme-primary-light-6);
border-radius: 4px; border-radius: 4px;
background: var(--theme-primary-light-9); background: #fff;
color: var(--theme-primary-active); color: var(--theme-primary-active);
font-size: 18px; font-size: 18px;
} }
@@ -707,7 +752,7 @@
.notification-copy { .notification-copy {
min-width: 0; min-width: 0;
display: grid; display: grid;
gap: 5px; gap: 4px;
} }
.notification-copy strong, .notification-copy strong,
@@ -728,7 +773,7 @@
min-width: 0; min-width: 0;
color: #0f172a; color: #0f172a;
font-size: 13px; font-size: 13px;
font-weight: 850; font-weight: 800;
} }
.notification-title-line b { .notification-title-line b {
@@ -738,17 +783,19 @@
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 0 6px; padding: 0 5px;
border-radius: 999px; border-radius: 4px;
background: #ef4444; background: #dc2626;
color: #fff; color: #fff;
font-size: 10px; font-size: 10px;
font-weight: 800;
line-height: 1; line-height: 1;
} }
.notification-copy small { .notification-copy small {
color: #475569; color: #475569;
font-size: 12px; font-size: 12px;
line-height: 1.4;
} }
.notification-meta { .notification-meta {
@@ -764,25 +811,54 @@
color: #94a3b8; color: #94a3b8;
font-size: 11px; font-size: 11px;
font-style: normal; font-style: normal;
font-weight: 600;
} }
.notification-row > .mdi { .notification-row-arrow {
align-self: center; color: #cbd5e1;
color: #94a3b8; font-size: 18px;
font-size: 16px; transition: color 160ms var(--ease), transform 160ms var(--ease);
}
.notification-row:hover .notification-row-arrow {
color: var(--theme-primary-active);
transform: translateX(2px);
} }
.notification-empty { .notification-empty {
min-height: 112px; min-height: 148px;
display: grid; display: grid;
place-items: center; place-items: center;
gap: 8px; justify-items: center;
color: #94a3b8; gap: 6px;
font-size: 13px; padding: 24px 20px;
text-align: center;
} }
.notification-empty .mdi { .notification-empty-icon {
font-size: 24px; width: 44px;
height: 44px;
display: grid;
place-items: center;
margin-bottom: 4px;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: #f8fafc;
color: #94a3b8;
font-size: 22px;
}
.notification-empty strong {
color: #334155;
font-size: 14px;
font-weight: 800;
}
.notification-empty > span:last-child {
max-width: 220px;
color: #94a3b8;
font-size: 12px;
line-height: 1.5;
} }
.company-switcher { .company-switcher {

View File

@@ -291,6 +291,7 @@
.receipt-all-field-grid { .receipt-all-field-grid {
max-height: clamp(360px, 60vh, 640px); max-height: clamp(360px, 60vh, 640px);
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 10px; gap: 10px;
padding-right: 4px; padding-right: 4px;
overflow-y: auto; overflow-y: auto;
@@ -666,6 +667,7 @@
} }
.receipt-static-grid, .receipt-static-grid,
.receipt-all-field-grid,
.receipt-data-list.association { .receipt-data-list.association {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }

View File

@@ -205,18 +205,23 @@
:class="{ 'has-long-duration-divider': item.hasLongDurationDivider }" :class="{ 'has-long-duration-divider': item.hasLongDurationDivider }"
@click="openWorkbenchTarget(item)" @click="openWorkbenchTarget(item)"
> >
<span class="progress-time"> <span class="progress-time-wrapper">
<time :datetime="item.updatedAt || ''">{{ item.displayTime }}</time> <span class="expense-type-icon" :class="`expense-type-icon--${item.expenseTypeTone}`">
<small>更新</small> <i :class="item.expenseTypeIcon"></i>
</span>
<span class="progress-time">
<time :datetime="item.updatedAt || ''">{{ item.displayTime }}</time>
<small v-if="item.showTimeCapsule" class="time-capsule">更新时间</small>
<small v-if="item.showUpdateText">更新</small>
</span>
</span> </span>
<span class="progress-identity"> <span class="progress-identity">
<strong>{{ item.id }}</strong> <strong>{{ item.title }}</strong>
<small>{{ item.title }}</small> <small>{{ item.id }}</small>
</span> </span>
<span class="progress-type" :title="item.expenseTypeLabel || '其他费用'"> <span class="progress-type" :title="item.expenseTypeLabel || '其他费用'">
<small>费用类型</small>
<strong>{{ item.expenseTypeLabel || '其他费用' }}</strong> <strong>{{ item.expenseTypeLabel || '其他费用' }}</strong>
</span> </span>
@@ -237,8 +242,8 @@
</span> </span>
<span class="progress-result"> <span class="progress-result">
<span class="progress-status" :class="`progress-status--${item.statusTone}`">{{ item.status }}</span>
<strong>{{ item.amount }}</strong> <strong>{{ item.amount }}</strong>
<span class="progress-status" :class="`progress-status--${item.statusTone}`">{{ item.status }}</span>
</span> </span>
</button> </button>
</div> </div>
@@ -268,6 +273,9 @@
class="insight-metric-row" class="insight-metric-row"
:class="`insight-metric-row--${item.tone}`" :class="`insight-metric-row--${item.tone}`"
> >
<span class="insight-metric-icon" aria-hidden="true">
<i :class="item.icon"></i>
</span>
<span class="insight-metric-label">{{ item.label }}</span> <span class="insight-metric-label">{{ item.label }}</span>
<strong class="insight-metric-value"> <strong class="insight-metric-value">
{{ item.value }}<small v-if="item.unit">{{ item.unit }}</small> {{ item.value }}<small v-if="item.unit">{{ item.unit }}</small>
@@ -478,6 +486,15 @@ const currentUserProfileKey = computed(() => {
user.employee_no user.employee_no
].map((item) => String(item || '').trim()).filter(Boolean).join('|') ].map((item) => String(item || '').trim()).filter(Boolean).join('|')
}) })
function resolveExpenseTypeStyle(label) {
if (label === '差旅交通') return { icon: 'mdi mdi-airplane', tone: 'blue' }
if (label === '业务招待') return { icon: 'mdi mdi-silverware-fork-knife', tone: 'amber' }
if (label === '办公采购') return { icon: 'mdi mdi-cart-outline', tone: 'emerald' }
if (label === '培训会议') return { icon: 'mdi mdi-projector', tone: 'violet' }
if (label === '市场活动') return { icon: 'mdi mdi-bullhorn-outline', tone: 'cyan' }
return { icon: 'mdi mdi-receipt-text-outline', tone: 'muted' }
}
const visibleProgressItems = computed(() => { const visibleProgressItems = computed(() => {
const rows = Array.isArray(props.workbenchSummary.progressItems) const rows = Array.isArray(props.workbenchSummary.progressItems)
? props.workbenchSummary.progressItems ? props.workbenchSummary.progressItems
@@ -488,10 +505,18 @@ const visibleProgressItems = computed(() => {
isLongDuration: isLongDurationProgress(item?.updatedAt) isLongDuration: isLongDurationProgress(item?.updatedAt)
})) }))
return progressRows.map((item, index) => ({ return progressRows.map((item, index) => {
...item, const isCompleted = item.statusTone === 'muted';
hasLongDurationDivider: item.isLongDuration && !progressRows[index - 1]?.isLongDuration const expenseStyle = resolveExpenseTypeStyle(item.expenseTypeLabel);
})) return {
...item,
expenseTypeIcon: expenseStyle.icon,
expenseTypeTone: expenseStyle.tone,
showTimeCapsule: !item.isLongDuration,
showUpdateText: item.isLongDuration && !isCompleted,
hasLongDurationDivider: item.isLongDuration && !progressRows[index - 1]?.isLongDuration
}
})
}) })
const LONG_DURATION_DAYS = 10 const LONG_DURATION_DAYS = 10

File diff suppressed because it is too large Load Diff

View File

@@ -196,42 +196,48 @@ export function buildExpenseStatItems(summary = {}) {
label: '本月报销笔数', label: '本月报销笔数',
value: summary.monthlyCount ?? 0, value: summary.monthlyCount ?? 0,
unit: '笔', unit: '笔',
tone: 'primary' tone: 'primary',
icon: 'mdi mdi-text-box-check-outline'
}, },
{ {
key: 'monthly-amount', key: 'monthly-amount',
label: '本月报销金额', label: '本月报销金额',
value: summary.monthlyAmountLabel || '¥0', value: summary.monthlyAmountLabel || '¥0',
unit: '', unit: '',
tone: 'amount' tone: 'amount',
icon: 'mdi mdi-cash-multiple'
}, },
{ {
key: 'total-count', key: 'total-count',
label: '累计报销笔数', label: '累计报销笔数',
value: summary.totalCount ?? 0, value: summary.totalCount ?? 0,
unit: '笔', unit: '笔',
tone: 'muted' tone: 'muted',
icon: 'mdi mdi-clipboard-text-outline'
}, },
{ {
key: 'total-amount', key: 'total-amount',
label: '累计报销金额', label: '累计报销金额',
value: summary.totalAmountLabel || '¥0', value: summary.totalAmountLabel || '¥0',
unit: '', unit: '',
tone: 'amount' tone: 'amount',
icon: 'mdi mdi-bank-outline'
}, },
{ {
key: 'in-review', key: 'in-review',
label: '审批中单据', label: '审批中单据',
value: summary.inReviewCount ?? 0, value: summary.inReviewCount ?? 0,
unit: '笔', unit: '笔',
tone: 'warning' tone: 'warning',
icon: 'mdi mdi-timer-sand'
}, },
{ {
key: 'pending-payment', key: 'pending-payment',
label: '待付款单据', label: '待付款单据',
value: summary.pendingPaymentCount ?? 0, value: summary.pendingPaymentCount ?? 0,
unit: '笔', unit: '笔',
tone: 'info' tone: 'info',
icon: 'mdi mdi-credit-card-outline'
} }
] ]
} }

View File

@@ -194,10 +194,11 @@ function buildTodoItems(ownedRequests) {
.sort((left, right) => normalizeText(right.due).localeCompare(normalizeText(left.due))) .sort((left, right) => normalizeText(right.due).localeCompare(normalizeText(left.due)))
} }
function resolveProgressStatusTone(approvalKey) { function resolveProgressStatusTone(approvalKey, statusText = '') {
if (approvalKey === 'completed') return 'muted' const status = String(statusText || '').trim()
if (approvalKey === 'pending_payment') return 'warning' if (approvalKey === 'completed' || /完成|结束|通过/i.test(status)) return 'muted'
if (approvalKey === 'supplement' || approvalKey === 'rejected') return 'danger' if (approvalKey === 'pending_payment' || /付款|支付/i.test(status)) return 'warning'
if (approvalKey === 'supplement' || approvalKey === 'rejected' || /退回|驳回|修改/i.test(status)) return 'danger'
return 'success' return 'success'
} }
@@ -243,14 +244,15 @@ function buildProgressItems(ownedRequests) {
const currentStep = steps.find((step) => step.current) const currentStep = steps.find((step) => step.current)
const title = normalizeText(request?.title || request?.note || request?.sceneLabel) || '费用单据' const title = normalizeText(request?.title || request?.note || request?.sceneLabel) || '费用单据'
const status = normalizeText(request?.approvalStatus || currentStep?.label) || '处理中'
return { return {
id: requestId, id: requestId,
requestId, requestId,
title, title,
expenseTypeLabel: resolveExpenseCategory(request), expenseTypeLabel: resolveExpenseCategory(request),
amount: formatCurrency(request?.amount), amount: formatCurrency(request?.amount),
status: normalizeText(request?.approvalStatus || currentStep?.label) || '处理中', status,
statusTone: resolveProgressStatusTone(normalizeText(request?.approvalKey)), statusTone: resolveProgressStatusTone(normalizeText(request?.approvalKey), status),
updatedAt: normalizeText(request?.updatedAt || request?.submittedAt || request?.createdAt), updatedAt: normalizeText(request?.updatedAt || request?.submittedAt || request?.createdAt),
steps, steps,
target: resolveRequestTarget(request), target: resolveRequestTarget(request),
@@ -391,12 +393,14 @@ function buildExpenseProcessingRows(ownedRequests) {
const latestAt = dates[dates.length - 1] || toDate(request?.updatedAt || request?.submittedAt || request?.createdAt) const latestAt = dates[dates.length - 1] || toDate(request?.updatedAt || request?.submittedAt || request?.createdAt)
const stepCount = Array.isArray(request?.progressSteps) ? request.progressSteps.length : 0 const stepCount = Array.isArray(request?.progressSteps) ? request.progressSteps.length : 0
const status = normalizeText(request?.approvalStatus || request?.status) || '处理中'
return { return {
id: requestId || title, id: requestId || title,
requestId, requestId,
title, title,
status: normalizeText(request?.approvalStatus || request?.status) || '处理中', status,
statusTone: resolveProgressStatusTone(normalizeText(request?.approvalKey)), statusTone: resolveProgressStatusTone(normalizeText(request?.approvalKey), status),
startedAt: startedAt ? formatDateTimeLabel(startedAt) : '暂无开始时间', startedAt: startedAt ? formatDateTimeLabel(startedAt) : '暂无开始时间',
updatedAt: latestAt ? formatDateTimeLabel(latestAt) : '暂无更新时间', updatedAt: latestAt ? formatDateTimeLabel(latestAt) : '暂无更新时间',
durationLabel: startedAt && latestAt ? formatDurationLabel(latestAt.getTime() - startedAt.getTime()) : '暂无耗时', durationLabel: startedAt && latestAt ? formatDurationLabel(latestAt.getTime() - startedAt.getTime()) : '暂无耗时',

View File

@@ -127,6 +127,7 @@ function testReceiptFolderDetailLayoutAdjustments() {
assert.match(receiptStyles, /\.receipt-association-panel/) assert.match(receiptStyles, /\.receipt-association-panel/)
assert.match(receiptStyles, /\.receipt-preview-box[\s\S]*height: clamp\(380px, 56vh, 640px\)/) assert.match(receiptStyles, /\.receipt-preview-box[\s\S]*height: clamp\(380px, 56vh, 640px\)/)
assert.match(receiptStyles, /\.receipt-all-field-grid/) assert.match(receiptStyles, /\.receipt-all-field-grid/)
assert.match(receiptStyles, /\.receipt-all-field-grid[\s\S]*grid-template-columns: repeat\(auto-fit, minmax\(260px, 1fr\)\)/)
assert.match(receiptStyles, /\.receipt-edit-log-list/) assert.match(receiptStyles, /\.receipt-edit-log-list/)
assert.doesNotMatch(receiptStyles, /\.receipt-detail-toolbar/) assert.doesNotMatch(receiptStyles, /\.receipt-detail-toolbar/)
assert.doesNotMatch(receiptStyles, /\.receipt-side-stack/) assert.doesNotMatch(receiptStyles, /\.receipt-side-stack/)