---
last_reviewed: 2026-06-11
---

# src/web 模块设计说明

## 设计思路

`src/web` 是一个基于 Flask 的轻量级 Web 界面，为财务报销自动化管道提供可视化操作入口。核心设计原则：

- **会话隔离**：每次上传生成独立 `session_id`，文件、日志、配置、结果各自隔离在 `uploads/<session_id>/` 目录下，避免并发冲突。
- **异步处理**：耗时的 PDF 提取、LLM 调用在后台线程执行，前端通过 SSE 实时查看日志流，不阻塞 HTTP 连接。
- **前后端分离最小化**：前端使用原生 JS + Bootstrap 5，不引入构建工具，保持单页应用轻量可维护。

## 文件结构

```
src/web/
├── app.py                  # Flask 应用入口，路由、管道编排、日志收集
├── templates/
│   ├── index.html          # PC 端主界面（上传、配置、处理、编辑、提交）
│   └── mobile_upload.html  # 移动端上传页面（拍照/相册选择）
└── static/
    ├── css/
    │   └── index.css       # 全局样式（上传区、日志面板、可编辑表格）
    └── js/
        └── index.js        # 前端逻辑（上传、SSE 日志、表格编辑、二维码同步）
```

## 数据流

```mermaid
graph TD
    A[用户上传文件] --> B[创建 session]
    B --> C[文件写入 uploads/<sid>/]
    C --> D[后台线程执行管道]
    D --> E["extract_invoices()"]
    E --> F["enrich_with_llm()"]
    F --> G["save_csv()"]
    G --> H["结果写入 session 目录"]
    H --> I["invoice_summary.csv"]
    H --> J["invoice_groups.json"]
    H --> K["result.json"]
    H --> L["session.log"]
    E --> M{"判断报销类型"}
    M -->|差旅| N["extract_travel_info()"]
    M -->|普通| O["extract_normal_info()"]
    N --> P["travel_info.json"]
    O --> Q["normal_info.json"]
    K --> R["前端 SSE 轮询 → 显示完成状态"]
    R --> S["前端加载 CSV → 可编辑表格"]
    S --> T["用户修改后保存"]
    T --> U["用户点击提交"]
    U --> V["run_financial_submit()"]
    V --> W["bot 自动填报财务系统"]
    W --> X["差旅模式: travel_info.json → 填报差旅单 → 上传差旅附件"]
    W --> Y["普通模式: normal_info.json → 基本信息 → 录入明细 → 支付信息 → 上传附件"]
```

## API 路由

| 方法 | 路径 | 功能 |
|------|------|------|
| GET | `/` | 主界面 |
| POST | `/api/session` | 创建会话，返回 session_id |
| POST | `/api/upload/<sid>` | 上传 PDF/图片 |
| GET | `/api/files/<sid>` | 列出会话文件 |
| POST | `/api/process/<sid>` | 启动管道（后台线程） |
| GET | `/api/logs/<sid>` | SSE 日志流 |
| GET | `/api/data/<sid>` | 获取发票数据 JSON |
| POST | `/api/save/<sid>` | 保存前端编辑的发票数据 |
| GET | `/api/download/<sid>/<filename>` | 下载生成文件 |
| POST | `/api/submit-financial/<sid>` | 手动触发财务系统填报 |
| GET | `/mobile/<sid>` | 移动端上传页面 |

## 关键机制

### 日志收集

`_SSELogHandler` 将管道日志写入 `session.log`，SSE 端点通过文件偏移量增量读取，实现前端实时日志展示。日志收集器在管道启动时安装，完成后移除，确保线程安全。

### 发票类型分流

- **差旅发票**（高铁票/酒店住宿）：不生成易耗品出库单，走差旅报销流程
- **普通发票**：生成易耗品出库单（Word 文档），走普通报销流程

`extract_invoices()` 在提取阶段完成分类，结果保存为 `invoice_groups.json`（包含 `travel_count`、`general_count`、`application_count`）。后续步骤（出库单生成、财务填报）统一从该文件读取分类结果，避免重复解析 CSV 和 JSON 字段。

### LLM 信息提取（2026-06-11）

发票提取和匹配完成后，根据类型分流调用 LLM 提取结构化报销信息：

- **差旅发票**：调用 `extract_travel_info()`，提取出差事由、地点、时间、交通/住宿明细、补助清单、支付方式、附件清单，缓存为 `travel_info.json`。
- **普通发票**：调用 `extract_normal_info()`，提取报销说明、发票总数、总金额、支付方式、附件清单，缓存为 `normal_info.json`。

Bot 填报时优先使用 LLM 提取的信息（`travel_info`/`normal_info`），降级时从缓存加载原始发票数据。

### 移动端同步

PC 端生成二维码指向 `/mobile/<sid>`，手机端上传的图片通过 `syncFiles()` 轮询同步到 PC 端内存中的 `imgFiles` 列表，实现跨设备协作。文件来源标记（`__source`）区分本地选择和服务器同步，避免重复。

### 配置管理

配置分两层：项目级 `config.json` 提供默认值，会话级 `uploads/<sid>/config.json` 存储当次会话覆盖值。前端支持通过上传 `config.json` 快速填充配置表单。