# 票据夹功能 TODO

更新时间：2026-05-29

## 阶段一：调研与契约

- [x] 梳理现有单据中心导航、列表样式和详情入口。[CONCEPT: 方案设计]
  证据：已确认 `DocumentsCenterView.vue`、`useNavigation.js`、`AppShellRouteView.vue` 是前端入口。

- [x] 梳理现有 OCR 和报销附件存储链路。[CONCEPT: 背景与问题]
  证据：已确认 `/ocr/recognize` 只临时识别；报销明细附件由 `expense_claim_attachment_*` 写入 `expense_claims` 存储。

- [x] 确定本轮不做数据库结构变更，先用票据文件资产和元数据 JSON 完成闭环。[CONCEPT: 目标与非目标]
  证据：避免新增迁移，降低本轮开发风险。

## 阶段二：文档

- [x] 创建 `document/development/receipt-folder/CONCEPT.md`。[CONCEPT: 全文]
  证据：本文档已落地。

- [x] 创建 `document/development/receipt-folder/TODO.md`。[CONCEPT: 测试方案]
  证据：本文档已落地。

## 阶段三：后端票据资产层

- [x] 新增 `schemas/receipt_folder.py`，定义列表项、详情、字段更新和删除响应。[CONCEPT: 后端]
  证据：已新增 `ReceiptFolderItemRead`、`ReceiptFolderDetailRead`、`ReceiptFolderUpdate`、`ReceiptFolderDeleteResponse`。

- [x] 新增 `services/receipt_folder.py`，负责源文件保存、元数据读写、预览解析、列表过滤和安全路径校验。[CONCEPT: 票据持久化]
  证据：`ReceiptFolderService` 已覆盖 OCR 批量持久化、已关联附件同步、详情更新、预览/源文件解析与目录安全校验。

- [x] 新增 `api/v1/endpoints/receipt_folder.py`，暴露列表、详情、更新、删除、预览和源文件接口。[CONCEPT: 后端]
  证据：已提供 `GET/PATCH/DELETE /receipt-folder/{receipt_id}` 及 `preview/source` 文件接口。

- [x] 在 `api/v1/router.py` 注册票据夹接口。[CONCEPT: 后端]
  证据：已 include `receipt_folder_router`。

- [x] 改造 `/ocr/recognize`，OCR 后保存源文件并把 `receipt_id` 等可选字段带回前端。[CONCEPT: OCR 改造]
  证据：`OcrRecognizeDocumentRead` 已补充 `receipt_id`、`receipt_status`、`receipt_preview_url`、`receipt_source_url`；来源于票据夹的 `receipt_ids` 会复用原票据，避免重复入库。

## 阶段四：前端票据夹页面

- [x] 新增 `services/receiptFolder.js`，封装票据夹接口和 Blob 文件读取。[CONCEPT: 前端]
  证据：已封装列表、详情、更新、删除、文件读取和 `buildReceiptFile`。

- [x] 新增 `ReceiptFolderView.vue`，实现列表、状态页签、搜索、一键关联入口和详情切换。[CONCEPT: 列表]
  证据：页面已包含未关联/已关联页签、搜索、表格、详情、编辑、预览和删除动作。

- [x] 新增 `receipt-folder-view.css`，复用单据中心紧凑企业级视觉，避免继续拉大现有 `DocumentsCenterView.vue`。[CONCEPT: 列表]
  证据：票据夹样式独立落在 `assets/styles/views/receipt-folder-view.css`，核心文件均未超过 800 行。

- [x] 在 `useNavigation.js` 增加 `receiptFolder`，并放在 `documents` 后面。[CONCEPT: 前端]
  证据：`appViews` 与 `navItems` 中 `receiptFolder` 均紧跟 `documents`。

- [x] 在 `accessControl.js` 增加默认可见权限和默认路由顺序。[CONCEPT: 前端]
  证据：已加入 `DEFAULT_APP_VIEW_ORDER` 与 `ALWAYS_VISIBLE_VIEWS`。

- [x] 在 `AppShellRouteView.vue` 渲染票据夹页面，并让页面可打开报销对话。[CONCEPT: 一键关联票据]
  证据：已接入 `ReceiptFolderView` 并转发 `open-assistant` 到 `openSmartEntry`。

## 阶段五：一键关联流程

- [x] 实现未关联票据多选弹窗第一步。[CONCEPT: 一键关联票据]
  证据：`ElDialog` 第一阶段使用 `ElCheckboxGroup` 多选未关联票据。

- [x] 实现未提交草稿选择和“新建报销单”选择第二步。[CONCEPT: 一键关联票据]
  证据：第二阶段读取草稿报销单，并保留 `新建报销单` 选项。

- [x] 从票据源文件接口取回 Blob 并构造 `File` 对象传给报销对话。[CONCEPT: 对话衔接]
  证据：`buildReceiptFile` 从 `source_url` 读取 Blob 并生成带 `receiptId` 的 `File`。

- [x] 选择已有草稿时，打开对话并带入草稿单号和关联提示。[CONCEPT: 一键关联票据]
  证据：选择草稿后以 `source: 'detail'`、`request` 和关联 prompt 打开报销对话；附件上传会携带 `receipt_id` 并回写原票据为已关联。

- [x] 选择新建报销单时，打开对话并带入基于票据新建的提示。[CONCEPT: 一键关联票据]
  证据：新建路径以 `source: 'receipt-folder'` 携带票据文件和新建 prompt。

## 阶段六：测试与验证

- [x] 补充后端票据夹服务和接口测试，超时时间控制在 60s 内。[CONCEPT: 测试方案]
  证据：`docker exec x-financial-main ... pytest server/tests/test_ocr_endpoints.py server/tests/test_reimbursement_endpoints.py -q` 通过，8 passed，耗时 11.41s。

- [x] 补充前端导航和票据夹视图模型测试。[CONCEPT: 测试方案]
  证据：`navigation-route-resolution.test.mjs` 已覆盖路由顺序，新增 `receipt-folder-view.test.mjs` 覆盖视图关键能力。

- [x] 运行前端构建或定向测试。[CONCEPT: 指标与验收]
  证据：`node web/tests/navigation-route-resolution.test.mjs`、`node web/tests/receipt-folder-view.test.mjs`、`npm.cmd run build` 均通过。

- [x] 在 Docker `x-financial-main` 的 `/app` 内运行后端定向测试。[CONCEPT: 测试方案]
  证据：`pytest server/tests/test_ocr_endpoints.py server/tests/test_reimbursement_endpoints.py -q` 在容器内通过，8 passed。

- [x] 手动核对侧边栏位置、列表密度、详情预览和关联弹窗。[CONCEPT: 指标与验收]
  证据：内置浏览器打开 `http://localhost:5173/app/receiptFolder`，侧边栏中“票据夹”位于“单据中心”下方，未关联/已关联页签与空态渲染正常，控制台无相关错误。

## 阶段七：收口

- [x] 回看 `CONCEPT.md` 验收标准，确认已实现项均有证据。[CONCEPT: 指标与验收]
  证据：OCR 持久化、列表/详情/预览、侧边栏位置、一键关联入口和文件行数约束均已覆盖。

- [x] 更新本 TODO 的完成状态和验证记录。[CONCEPT: 测试方案]
  证据：本文件已补充完成勾选和验证命令记录。

## 阶段八：2026-06-03 详情页与上传治理收口

- [x] 将票据夹详情页收敛为共享详情布局下的三块内容：左侧完整预览、右侧识别票据详情、底部关联信息。[CONCEPT: 2026-06-03 详情页与上传治理补充]
  证据：`node web/tests/receipt-folder-view.test.mjs`、`npm.cmd run build`、容器内 `cd /app/web && npm run build` 均通过。
- [x] 支持识别票据详情编辑，并在后端保存字段级编辑日志。[CONCEPT: 编辑记录治理]
  证据：容器内 `pytest -q server/tests/test_ocr_endpoints.py server/tests/test_receipt_folder_service.py` 通过，3 passed。
- [x] OCR 持久化时识别同一用户重复上传的相同源文件，返回已有票据并提示不要重复上传。[CONCEPT: 重复上传治理]
  证据：`test_ocr_endpoints.py` 已覆盖重复上传返回原 `receipt_id` 和 warnings。
- [x] 报销助手上传附件前提示票据夹中存在未关联票据，并提供进入票据夹关联或继续上传的建议动作。[CONCEPT: 报销助手联动]
  证据：`receipt-folder-view.test.mjs` 覆盖 `fetchReceiptFolderItems('unlinked')`、`open_receipt_folder` 和 `continue_upload_with_unlinked_receipts`。
- [x] 删除已关联报销单时，同步删除票据夹中关联该报销单的票据文件。[CONCEPT: 删除级联]
  证据：`test_receipt_folder_service.py` 已覆盖 `delete_receipts_for_claim` 删除后不可再读取票据。
