239 lines
8.3 KiB
Markdown
239 lines
8.3 KiB
Markdown
|
|
# 票据夹功能概念文档
|
|||
|
|
|
|||
|
|
更新时间:2026-05-29
|
|||
|
|
|
|||
|
|
## 功能一句话
|
|||
|
|
|
|||
|
|
票据夹用于归集用户已上传并经过 OCR 识别的原始票据文件,避免票据已识别但忘记关联报销单后无法找回。
|
|||
|
|
|
|||
|
|
## 背景与问题
|
|||
|
|
|
|||
|
|
当前系统有两条票据路径:
|
|||
|
|
|
|||
|
|
- 报销明细附件路径:票据上传到某个草稿费用明细后,会存入 `expense_claims` 附件目录,并写入附件元数据。
|
|||
|
|
- 独立 OCR 识别路径:报销对话里先上传票据识别时,`/ocr/recognize` 只返回识别结果,源文件使用临时目录,识别结束后会清理。
|
|||
|
|
|
|||
|
|
这会导致一个业务缺口:用户可能已经上传票据并完成 OCR,但还没有把票据关联到报销草稿。只要用户关闭会话、切走页面或忘记继续操作,原始票据就没有一个稳定入口可追溯。
|
|||
|
|
|
|||
|
|
票据夹要补齐这个缺口:凡是系统对用户上传文件做过 OCR 并持久化源文件,就应进入票据夹列表;后续用户可以查看、修正票据信息、删除无效票据,或一键把未关联票据带入报销对话。
|
|||
|
|
|
|||
|
|
## 目标与非目标
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
- 在左侧侧边栏的“单据中心”下面新增“票据夹”入口。
|
|||
|
|
- 建立票据源文件持久化能力,OCR 后保留原始文件、预览文件和识别元数据。
|
|||
|
|
- 提供票据夹列表,复用单据中心的紧凑列表视觉语言。
|
|||
|
|
- 支持“未关联票据 / 已关联票据”两个状态切换。
|
|||
|
|
- 支持票据详情:基本票据信息可编辑、原始文件可预览、底部返回列表和删除票据。
|
|||
|
|
- 支持“一键关联票据”:选择未关联票据,选择未提交草稿或新建报销单,再跳转到报销对话继续填写和关联。
|
|||
|
|
|
|||
|
|
非目标:
|
|||
|
|
|
|||
|
|
- 本轮不引入 `document_assets` 等数据库结构变更;先用文件资产和元数据 JSON 完成产品闭环。
|
|||
|
|
- 本轮不替换现有报销明细附件接口。
|
|||
|
|
- 本轮不把票据夹做成财务共享的全公司档案库;默认只展示当前登录用户自己的票据。
|
|||
|
|
- 本轮不在列表页直接完成报销单提交,提交仍回到现有对话核对流程。
|
|||
|
|
|
|||
|
|
## 用户与场景
|
|||
|
|
|
|||
|
|
涉及角色:
|
|||
|
|
|
|||
|
|
- 普通员工:上传票据后稍后再归集到草稿。
|
|||
|
|
- 经理或财务用户:在自己名下上传票据时同样需要留存和追溯。
|
|||
|
|
|
|||
|
|
典型场景:
|
|||
|
|
|
|||
|
|
1. 用户在个人工作台上传 3 张票据,OCR 成功后暂时没有保存草稿。
|
|||
|
|
2. 用户第二天打开票据夹,看到这 3 张票据仍在“未关联票据”。
|
|||
|
|
3. 用户进入详情,修正票据类型、金额或日期。
|
|||
|
|
4. 用户点击“一键关联票据”,多选未关联票据。
|
|||
|
|
5. 用户选择已有草稿,或选择新建报销单。
|
|||
|
|
6. 系统打开报销对话,把票据源文件和 OCR 信息带入现有核对流程。
|
|||
|
|
|
|||
|
|
## 功能能力
|
|||
|
|
|
|||
|
|
### 票据持久化
|
|||
|
|
|
|||
|
|
- OCR 入口接收文件后,在识别完成阶段保存源文件。
|
|||
|
|
- 保存位置建议为 `storage/receipt_folder/<owner_key>/<receipt_id>/`。
|
|||
|
|
- 每个票据目录包含:
|
|||
|
|
- 原始文件:`source.<ext>`
|
|||
|
|
- 预览文件:`preview.<ext>`,可为空
|
|||
|
|
- 元数据:`meta.json`
|
|||
|
|
- 元数据记录:
|
|||
|
|
- `id`
|
|||
|
|
- `owner_key`
|
|||
|
|
- `file_name`
|
|||
|
|
- `media_type`
|
|||
|
|
- `size_bytes`
|
|||
|
|
- `uploaded_at`
|
|||
|
|
- `status`: `unlinked` / `linked`
|
|||
|
|
- `linked_claim_id`
|
|||
|
|
- `linked_claim_no`
|
|||
|
|
- `linked_item_id`
|
|||
|
|
- `linked_at`
|
|||
|
|
- OCR 引擎、模型、文本、摘要、置信度、票据类型、场景、结构化字段、提示信息
|
|||
|
|
|
|||
|
|
### 列表
|
|||
|
|
|
|||
|
|
- 页签:
|
|||
|
|
- 未关联票据
|
|||
|
|
- 已关联票据
|
|||
|
|
- 表格字段建议:
|
|||
|
|
- 票据文件
|
|||
|
|
- 识别类型
|
|||
|
|
- 费用场景
|
|||
|
|
- 金额
|
|||
|
|
- 票据日期
|
|||
|
|
- OCR 置信度
|
|||
|
|
- 关联状态
|
|||
|
|
- 上传时间
|
|||
|
|
- 交互:
|
|||
|
|
- 搜索文件名、摘要、字段值、关联单号
|
|||
|
|
- 按状态切换
|
|||
|
|
- 点击行进入详情
|
|||
|
|
- 未关联页显示“一键关联票据”
|
|||
|
|
|
|||
|
|
### 详情
|
|||
|
|
|
|||
|
|
- 基本票据信息:
|
|||
|
|
- 文件名只读
|
|||
|
|
- 票据类型可编辑
|
|||
|
|
- 费用场景可编辑
|
|||
|
|
- 票据日期可编辑
|
|||
|
|
- 金额可编辑
|
|||
|
|
- 商户 / 出发地 / 到达地 / 票据号码等 OCR 字段可编辑
|
|||
|
|
- 原始文件展示:
|
|||
|
|
- 图片直接预览
|
|||
|
|
- PDF 用浏览器内嵌预览
|
|||
|
|
- 不可预览类型提供下载入口
|
|||
|
|
- 底部动作:
|
|||
|
|
- 返回列表
|
|||
|
|
- 删除票据
|
|||
|
|
|
|||
|
|
### 一键关联票据
|
|||
|
|
|
|||
|
|
流程:
|
|||
|
|
|
|||
|
|
1. 打开关联弹窗,展示未关联票据多选列表。
|
|||
|
|
2. 下一步展示当前用户未提交草稿报销单,也提供“新建报销单”选项。
|
|||
|
|
3. 确认后打开现有报销对话。
|
|||
|
|
4. 如果选择已有草稿:
|
|||
|
|
- 对话以 `link_to_existing_draft` 语义继续。
|
|||
|
|
- 携带 `draft_claim_id` 和票据文件。
|
|||
|
|
5. 如果选择新建报销单:
|
|||
|
|
- 对话以 `create_new_claim_from_documents` 语义继续。
|
|||
|
|
- 携带票据文件和 OCR 元数据。
|
|||
|
|
|
|||
|
|
## 方案设计
|
|||
|
|
|
|||
|
|
### 后端
|
|||
|
|
|
|||
|
|
新增模块:
|
|||
|
|
|
|||
|
|
- `schemas/receipt_folder.py`
|
|||
|
|
- `services/receipt_folder.py`
|
|||
|
|
- `api/v1/endpoints/receipt_folder.py`
|
|||
|
|
|
|||
|
|
接口建议:
|
|||
|
|
|
|||
|
|
- `GET /api/v1/receipt-folder?status=unlinked|linked|all`
|
|||
|
|
- `GET /api/v1/receipt-folder/{receipt_id}`
|
|||
|
|
- `PATCH /api/v1/receipt-folder/{receipt_id}`
|
|||
|
|
- `DELETE /api/v1/receipt-folder/{receipt_id}`
|
|||
|
|
- `GET /api/v1/receipt-folder/{receipt_id}/preview`
|
|||
|
|
- `GET /api/v1/receipt-folder/{receipt_id}/source`
|
|||
|
|
|
|||
|
|
OCR 改造:
|
|||
|
|
|
|||
|
|
- `/api/v1/ocr/recognize` 保持现有响应结构兼容。
|
|||
|
|
- 在识别后调用票据夹服务保存源文件和识别结果。
|
|||
|
|
- 给每个返回的 OCR 文档补充可选 `receipt_id`、`receipt_preview_url`、`receipt_source_url` 字段。
|
|||
|
|
|
|||
|
|
### 前端
|
|||
|
|
|
|||
|
|
新增模块:
|
|||
|
|
|
|||
|
|
- `services/receiptFolder.js`
|
|||
|
|
- `views/ReceiptFolderView.vue`
|
|||
|
|
- `assets/styles/views/receipt-folder-view.css`
|
|||
|
|
|
|||
|
|
导航改造:
|
|||
|
|
|
|||
|
|
- `useNavigation.js` 新增 `receiptFolder`,放在 `documents` 后面。
|
|||
|
|
- `accessControl.js` 将 `receiptFolder` 作为默认可见视图。
|
|||
|
|
- `router/index.js` 自动生成 `/app/receiptFolder` 路由。
|
|||
|
|
- `AppShellRouteView.vue` 渲染新页面,并允许页面触发 `openSmartEntry`。
|
|||
|
|
|
|||
|
|
对话衔接:
|
|||
|
|
|
|||
|
|
- 票据夹确认关联时,前端从 `source` 接口取回 Blob,构造 `File` 对象传给 `openSmartEntry`。
|
|||
|
|
- 同时把已编辑 OCR 元数据转为 `initialReceiptDocuments` 或直接通过 `prompt` / `extraContext` 进入对话。
|
|||
|
|
- 本轮优先用现有 `initial-files` 和 `initial-prompt` 打开对话,确保用户可以继续核对和保存。
|
|||
|
|
|
|||
|
|
## 算法与公式
|
|||
|
|
|
|||
|
|
当前功能不涉及显式数学公式。
|
|||
|
|
|
|||
|
|
列表排序使用上传时间倒序:
|
|||
|
|
|
|||
|
|
$$
|
|||
|
|
sortKey(receipt) = uploadedAt(receipt)
|
|||
|
|
$$
|
|||
|
|
|
|||
|
|
状态归类:
|
|||
|
|
|
|||
|
|
$$
|
|||
|
|
status(receipt) =
|
|||
|
|
\begin{cases}
|
|||
|
|
linked, & linkedClaimId \neq \emptyset \\
|
|||
|
|
unlinked, & linkedClaimId = \emptyset
|
|||
|
|
\end{cases}
|
|||
|
|
$$
|
|||
|
|
|
|||
|
|
## 测试方案
|
|||
|
|
|
|||
|
|
后端:
|
|||
|
|
|
|||
|
|
- OCR 识别后会保存源文件和 `meta.json`。
|
|||
|
|
- 列表只返回当前用户票据。
|
|||
|
|
- `status=unlinked` 只返回未关联票据。
|
|||
|
|
- 详情可读取 OCR 字段。
|
|||
|
|
- PATCH 后字段持久化。
|
|||
|
|
- 预览接口能返回图片或 PDF。
|
|||
|
|
- DELETE 只删除票据夹根目录下的目标票据。
|
|||
|
|
|
|||
|
|
前端:
|
|||
|
|
|
|||
|
|
- 导航中“票据夹”位于“单据中心”下面。
|
|||
|
|
- 列表空态、加载态、错误态可用。
|
|||
|
|
- 未关联和已关联两个页签计数正确。
|
|||
|
|
- 点击行进入详情。
|
|||
|
|
- 详情可保存字段、返回列表、删除票据。
|
|||
|
|
- 一键关联弹窗能完成票据选择和草稿选择。
|
|||
|
|
|
|||
|
|
集成:
|
|||
|
|
|
|||
|
|
- 上传票据触发 OCR 后,票据出现在票据夹。
|
|||
|
|
- 从票据夹选择未关联票据,可打开报销对话。
|
|||
|
|
- 选择已有草稿时,对话带入草稿单号。
|
|||
|
|
- 选择新建报销单时,对话提示基于票据新建。
|
|||
|
|
|
|||
|
|
## 指标与验收
|
|||
|
|
|
|||
|
|
- OCR 成功返回后,票据夹列表能查到对应源文件。
|
|||
|
|
- 票据源文件和预览文件在重启后仍可访问。
|
|||
|
|
- 未关联票据和已关联票据状态切换正确。
|
|||
|
|
- 票据详情字段修改后刷新仍保留。
|
|||
|
|
- 删除票据后列表不再显示,预览接口返回 404。
|
|||
|
|
- 侧边栏位置符合要求:票据夹在单据中心下面。
|
|||
|
|
- 单个新增核心前端和后端模块不超过 800 行。
|
|||
|
|
|
|||
|
|
## 风险与开放问题
|
|||
|
|
|
|||
|
|
- 当前报销草稿流主要持久化 OCR 文本和文件名,真实文件复制到报销明细附件目录仍需要进一步打通。
|
|||
|
|
- 本轮采用文件元数据而非数据库,适合先完成闭环;后续若需要审计、权限、跨用户协作和全文检索,应升级到资产表。
|
|||
|
|
- 已关联状态如何自动回写,需要在后续把票据夹 ID 与报销明细 `invoice_id` 建立更强绑定。
|
|||
|
|
- 多票据关联时,如果用户中途取消对话,本轮仍保留为未关联,避免误标。
|