---
last_reviewed: 2026-06-09
---

# 阜阳师范大学财务报销系统 - 自动化操作指南

> 适用场景：日常报销录入（支持 Web 界面和 CLI 两种方式）
> 最后更新：2026-06-09

---

## 一、系统概览

```
整体流程:

信息门户(SSO登录) → 财务系统入口 → 单点登录页 → 网络报销 → 日常报销录入
(tyrz.fynu.edu.cn)   (点击"财务系统")  (新标签页)   (a:has(img))   (/expen/common/common)

目标系统: http://210.45.32.214:8081
用户: 张三 (工号: xxxxxxx)
```

### 关键 URL

| 系统 | URL | 说明 |
|------|-----|------|
| SSO 登录 | `https://tyrz.fynu.edu.cn/sso/login` | 统一认证入口 |
| 信息门户 | `https://tyrz.fynu.edu.cn/oshall` | 登录后跳转目标 |
| 报销系统 | `http://210.45.32.214:8081` | 网络报销主系统 |
| 日常报销录入 | `/expen/common/common?v=4.0` | 目标录入页面 |

---

## 二、两种使用方式

### 方式一：Web 界面（推荐）

适合日常使用，可视化操作，支持手机端拍照上传。

```bash
uv run python src/web/app.py
# 访问: http://localhost:5000
```

### 方式二：CLI 命令行

适合脚本化、批量处理。

```bash
# 全流程（发票提取 → LLM 识别 → 浏览器填报）
uv run python src/main.py

# 分步执行
uv run python src/main.py --step invoice   # 仅发票提取
uv run python src/main.py --step submit    # 仅浏览器填报

# 覆盖登录凭据
uv run python src/main.py -u 202407021 -p "your_password"
```

---

## 三、数据准备

### 3.1 发票数据 CSV

上传 PDF 发票文件和支付截图，系统自动完成：
1. 从 PDF 提取发票信息
2. 多模态 LLM 识别支付截图中的刷卡信息
3. 生成 `invoice_summary.csv`

### 3.2 发票类型分类

系统自动将发票分为两类，影响后续处理流程：

| 类型 | 判断依据 | 出库单 | 报销流程 |
|------|----------|--------|----------|
| 差旅发票 | 高铁票、酒店住宿等 | 不生成 | 差旅报销 |
| 普通发票 | 其他（办公用品、耗材等） | 自动生成 | 普通报销 |

### 3.3 附件文件

PDF 发票文件需与支付截图配对上传。系统通过金额匹配自动关联发票和支付记录。

---

## 四、Web 界面操作流程

### 4.1 启动服务

```bash
uv run python src/web/app.py
# 访问: http://localhost:5000
```

### 4.2 上传文件

1. **发票 PDF**：点击或拖拽上传 PDF 文件（支持多选）
2. **支付截图**：点击或拖拽上传图片文件（支持多选）
3. **手机扫码上传**：扫描页面二维码，通过手机拍照上传支付截图

### 4.3 配置信息

填写以下配置项（也可通过上传 `config.json` 快速填充）：

| 字段 | 说明 |
|------|------|
| 账号 | 财务系统工号 |
| 密码 | 登录密码 |
| 默认姓名 | 报销人姓名 |
| 公务卡号 | 公务卡卡号 |
| 人员编号 | 人员编号 |
| 存放地点 | 出库单存放地点 |

### 4.4 开始处理

点击"开始处理"按钮，系统自动执行：

1. **发票提取**：从 PDF 提取发票信息
2. **LLM 信息提取**：多模态 LLM 识别支付截图中的刷卡信息
3. **发票分类**：自动区分差旅发票和普通发票
4. **出库单生成**：普通发票自动生成易耗品出库单（差旅发票跳过）

处理过程中可在日志面板实时查看进度。

### 4.5 编辑发票数据

处理完成后，发票数据以可编辑表格形式展示：

- 直接点击单元格即可编辑
- 修改后点击"提交到财务系统"时自动保存
- 保存后会自动重新生成出库单

### 4.6 下载文件

处理完成后下载：

| 文件 | 说明 |
|------|------|
| `invoice_summary.csv` | 发票汇总数据 |
| `易耗品、出库单.doc` | 自动填写的出库单（仅普通发票） |

### 4.7 提交到财务系统

确认数据无误后，点击"🚀 提交到财务系统"按钮，系统自动：

1. 登录信息门户
2. 进入财务系统
3. 创建报销单
4. 填写基本信息
5. 录入报销明细
6. 录入支付方式
7. 上传附件

---

## 五、CLI 执行流程

### 5.1 全流程执行

```bash
uv run python src/main.py
```

执行步骤：

```
Step 1: 发票提取
  ├── 扫描 PDF 发票文件
  ├── 提取发票信息
  ├── 生成 invoice_summary.csv
  └── 自动分类（差旅/普通）

Step 2: LLM 信息提取
  ├── 扫描支付截图
  ├── 多模态 LLM 识别刷卡信息
  ├── 回填 CSV 刷卡字段
  └── 更新 invoice_summary.csv

Step 3: 报销提交
  ├── 登录信息门户
  ├── 进入财务系统
  ├── 创建报销单
  ├── 填写基本信息
  ├── 录入报销明细
  ├── 录入支付方式
  ├── 上传附件
  └── 提交（需手动确认）
```

### 5.2 分步执行

```bash
# 仅发票提取
uv run python src/main.py --step invoice

# 仅浏览器填报
uv run python src/main.py --step submit
```

### 5.3 上传目录

CLI 模式自动发现 `src/web/uploads/` 下最新的会话文件夹，该文件夹包含上传的 PDF 和图片。

---

## 六、页面元素速查

### 基本信息页

| 字段 | 选择器 | 操作 |
|------|--------|------|
| 报销说明 | `#EXPENEXPLAIN` | fill |
| 项目代码 | `#PROJECTCODE` | click → 弹窗选择 |
| 项目弹窗 | `#promodal .fixed-table-body tbody tr` | 点击第一行 |
| 下一步按钮 | `#saveAndNext` | click |

### 报销明细页

| 字段 | 选择器 | 操作 |
|------|--------|------|
| 增加按钮 | `#insertDetail` | click |
| 经济事项代码 | `#economicscode2` | click → 弹窗选择 |
| 经济科目弹窗 | `#econmodal .fixed-table-body tbody tr` | 点击第 3 行 |
| 单据数 | `input[name="expenPwCommondetail.HOWBILLS"]` | fill |
| 报销总金额 | `#je_zwzcdz` | fill |
| 确定按钮 | `#detailAdd` | click |

### 支付方式页

| 字段 | 选择器 | 操作 |
|------|--------|------|
| 增加按钮 | `#insertPay` | click |
| 人员编号 | `#personid2` | fill |
| 人员姓名 | `#accountname2` | fill |
| 刷卡日期 | `#receiptdate2` | fill |
| 公务卡号 | `#localaccount2` | fill |
| 刷卡金额 | `#receiptmoney2` | fill |
| 实报金额 | `#money2` | fill |
| 商户 | `#merchant2` | fill |
| 备注 | `#smark2` | fill |
| 确定按钮 | `#payAdd` | click |

### 附件清单页

| 字段 | 选择器 | 操作 |
|------|--------|------|
| 增加按钮 | `#insertAcc` | click |
| 附件类型 | `#fjlx` | select_option → '1'(发票) |
| 附件说明 | `#fpsmxx` | fill |
| 文件上传 | `#file` | set_input_files |
| 确定按钮 | `#cjtj` | click |

### 提交

| 操作 | 选择器 |
|------|--------|
| 提交按钮 | `#submit` |
| 提交按钮(备用) | `#submit2` |

---

## 七、数据流向

```
PDF 发票 + 支付截图
    │
    ▼ extract_invoices()
    │
    ├── 读取 PDF 发票
    ├── 提取发票信息
    ├── 自动分类（差旅/普通）
    └── 输出: invoice_summary.csv
            │
            ▼ enrich_with_llm()
            ├── 多模态 LLM 识别支付截图
            ├── 回填刷卡字段
            └── 更新 invoice_summary.csv
            │
            ▼ fill_consumable_from_template()
            ├── 仅普通发票
            ├── 从模板复制出库单
            └── 自动填写出库单
            │
            ▼ run_bot()
            ├── 登录信息门户
            ├── 进入财务系统
            ├── 创建报销单
            ├── 填写基本信息
            ├── 录入报销明细
            ├── 录入支付方式
            ├── 上传附件
            └── 提交
```

---

## 八、关键设计说明

### 8.1 浏览器启动

系统使用 Playwright 的 `sync_playwright()` 启动 Chromium 浏览器，支持 `headless` 模式。每次运行均启动新浏览器实例，需重新登录。可通过 `headless` 参数控制是否显示浏览器窗口。

### 8.2 明细录入策略

系统采用"一条总明细"策略：将所有发票合并为一条报销明细，报销总金额为所有发票刷卡金额之和，单据数为发票总张数。支付方式则逐张发票分别录入，每张发票对应一条支付记录。

### 8.3 经济科目选择

系统在经济科目弹窗中固定选择第 3 行。如需更改科目，修改 `rows[2]` 的索引即可。

### 8.4 项目选择

系统在项目选择弹窗中固定选择第 1 行。如需更改项目，修改 `first_row` 的选择逻辑即可。

### 8.5 网络报销链接动态获取

单点登录页的"网络报销"链接参数每次不同，系统通过 `a:has(img[src*="wlbx"])` 精确定位链接，动态提取 `href` 属性后导航，不硬编码 URL。

### 8.6 发票类型分流

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

### 8.7 移动端同步

PC 端生成二维码指向移动端上传页面，手机端上传的图片通过轮询同步到 PC 端，实现跨设备协作。

---

## 九、配置说明

### config.json

项目根目录 `config.json` 包含默认配置：

```json
{
    "username": "202407021",
    "password": "your_password",
    "sso_login_url": "https://tyrz.fynu.edu.cn/sso/login",
    "portal_url": "https://tyrz.fynu.edu.cn/oshall",
    "reimburse_url": "http://210.45.32.214:8081",
    "reimburse_page": "/expen/common/common?v=4.0",
    "default_name": "王建锋",
    "default_card_no": "6282880139161682",
    "default_person_id": "202407021",
    "consumable_storage": "躬行楼 C205",
    "llm": {
        "model": "qwen3.5-9b",
        "api_base": "http://100.123.83.115:1234/v1",
        "api_key": "123456"
    }
}
```

| 字段 | 说明 |
|------|------|
| `username` | 财务系统工号 |
| `password` | 登录密码 |
| `sso_login_url` | SSO 登录地址 |
| `portal_url` | 信息门户地址 |
| `reimburse_url` | 报销系统地址 |
| `reimburse_page` | 报销录入页面路径 |
| `default_name` | 默认报销人姓名 |
| `default_card_no` | 默认公务卡号 |
| `default_person_id` | 默认人员编号 |
| `consumable_storage` | 出库单存放地点 |
| `llm.model` | LLM 模型名称 |
| `llm.api_base` | LLM API 地址 |
| `llm.api_key` | LLM API 密钥 |

---

## 十、日志与调试

### 日志输出

- 控制台实时输出（INFO 级别）
- 文件日志：`logs/<日期>.log`（UTF-8 编码）
- Web 界面：实时 SSE 日志流

### 截图保存

每个关键步骤自动截图到 `images/` 目录：

| 截图文件 | 对应步骤 |
|----------|----------|
| `debug_portal_loaded.png` | 登录成功 |
| `debug_step3_project_modal.png` | 项目弹窗打开 |
| `debug_step3_project_selected.png` | 项目选择完成 |
| `debug_step3_done.png` | 基本信息完成 |
| `debug_after_add_click.png` | 点击新增后 |
| `debug_item_total.png` | 总明细录入完成 |
| `debug_step5_done.png` | 支付方式完成 |
| `debug_step6_done.png` | 附件上传完成 |
| `debug_error.png` | 异常状态 |

### 超时设置

- 页面默认超时：30 秒
- 登录门户等待：最多 30 秒
- 单点登录页等待：最多 15 秒
- SSE 日志流超时：10 分钟（600 秒）

---

## 十一、常见问题

| 问题 | 原因 | 解决方案 |
|------|------|----------|
| 登录超时 | SSO 需要手动验证码/微信扫码 | 手动完成验证后脚本继续 |
| 未找到财务系统入口 | 门户页面结构变化 | 检查 `images/debug_*` 截图定位 |
| 经济科目选择失败 | 弹窗加载延迟 | 检查超时设置，增加等待时间 |
| 附件上传失败 | PDF 文件不存在或路径错误 | 确认 PDF 在当前工作目录 |
| 金额不匹配 | 明细合计 ≠ 支付合计 | 检查 CSV 数据中刷卡金额 |
| 提交被拦截 | 必填项为空 | 检查 `logs/<日期>.log` 定位失败步骤 |
| LLM 多模态提取失败 | llama-index 版本不兼容 | 确保使用 llama-index-core >= 0.14.x，多模态消息使用 `blocks` 格式 |
| 出库单生成失败 | 缺少 pywin32 或模板文件 | 安装 `pywin32`，确保项目根目录有 `易耗品、出库单.doc` 模板 |
| 差旅发票生成了出库单 | 分类不准确 | 检查发票内容是否包含"高铁票""酒店住宿"等关键词 |

---

## 十二、相关 CLI 命令

### 单独填写出库单

```bash
uv run python -m src.doc.fill_consumable_doc --csv invoice_summary.csv --doc "易耗品、出库单.doc"
```

### 分步执行管道

```bash
# 仅发票提取
uv run python src/main.py --step invoice

# 仅浏览器填报
uv run python src/main.py --step submit
```

### 启动 Web 服务

```bash
uv run python src/web/app.py
# 访问: http://localhost:5000
```

---

## 附录：API 文档

详细的 API 接口文档见 [API.md](./API.md)。