Files
X-Financial/document/development/receipt-folder/CONCEPT.md
caoxiaozhu 34457f9c3e feat: 本体字段治理与风险规则模板执行器重构
- 新增本体字段注册表与字段治理审计脚本
- 重构风险规则模板执行器、DSL 验证与清单分类器
- 完善票据夹服务与差旅请求详情页交互
- 优化趋势图表与总览页数据展示
- 增强报销平台风险分级与模拟公司筛选
- 补充本体字段、风险规则生成与票据夹服务测试覆盖
2026-06-03 15:46:56 +08:00

267 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 票据夹功能概念文档
更新时间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` 建立更强绑定。
- 多票据关联时,如果用户中途取消对话,本轮仍保留为未关联,避免误标。
## 2026-06-03 详情页与上传治理补充
本轮根据新的验收要求收敛为三块核心内容:
- 左侧为票据预览,使用共享详情页主区域承载,图片和 PDF 都以完整票据可见为优先目标,不再提供“打开源文件”按钮。
- 右侧为识别票据详情,展示当前票据所有 OCR 字段和基础字段;用户点击“编辑”后可直接修改识别内容,保存后写回票据夹元数据。
- 底部为关联信息;左侧预览卡底部同时展示用户编辑操作记录,用于后续财务判断人工修改痕迹。
编辑记录治理:
- `PATCH /receipt-folder/{receipt_id}` 在保存前后对可编辑票据信息做字段级 diff。
- 每条编辑日志记录操作者、操作时间、字段名称、修改前值、修改后值。
- 前端详情页只展示真实 `edit_logs`,不再用模拟操作日志替代。
重复上传治理:
- OCR 持久化票据时计算源文件 `sha256`
- 同一用户再次上传相同源文件时,不新建票据目录,返回已有 `receipt_id`,并在 OCR 文档 warnings 中提示“已上传过同样的单据,请不要重复上传。”
报销助手联动:
- 用户在报销助手上传新附件前,如果票据夹中存在未关联票据,先提示用户是否进入票据夹关联。
- 用户可以选择“去票据夹关联”,也可以选择“继续上传新附件”;继续上传时只跳过本次未关联提醒,不影响后续重复附件校验。
删除级联:
- 已关联票据对应的报销单被删除时,票据夹中关联该报销单的票据源文件、预览文件和元数据一并删除。