242 lines
6.5 KiB
Markdown
242 lines
6.5 KiB
Markdown
# docfill
|
||
|
||
`docfill` 是一个本地文档填充命令行工具。它从 Excel 或 SQLite 读取结构化数据,按业务条件筛选出需要使用的数据行,再把数据填入 Word 或 Excel 模板中的 `{{字段名}}` 占位符。
|
||
|
||
本工具的定位是“小型、稳定、便于数字员工调用”。它只负责本地数据到本地模板的填充,不内置业务系统登录、审批流、Web 界面、模板设计器或权限系统。
|
||
|
||
## 核心理解
|
||
|
||
`task.json` 是某一种业务报表的固定任务说明书,命令行 `--var` 是本次运行传入的具体条件。
|
||
|
||
```text
|
||
不同业务 = 不同 task.json
|
||
本次运行的日期、工单编号、人员、批次 = --var
|
||
真实数据 = Excel 或 SQLite
|
||
模板文件 = Word 或 Excel
|
||
```
|
||
|
||
优先级:
|
||
|
||
```text
|
||
数据表里的字段 > 命令行 --var > task.json 里的 vars
|
||
```
|
||
|
||
例如 `task.json` 中写了:
|
||
|
||
```json
|
||
"vars": {
|
||
"date": "2026-06-18"
|
||
}
|
||
```
|
||
|
||
运行时执行:
|
||
|
||
```bash
|
||
dist/docfill-darwin-arm64 run -c task.json --var date=2026-06-19 --var ticket_no=GD-001
|
||
```
|
||
|
||
实际使用的是:
|
||
|
||
```text
|
||
date = 2026-06-19
|
||
ticket_no = GD-001
|
||
```
|
||
|
||
也就是 `--var date=2026-06-19` 会覆盖 `task.json` 里的默认 `date=2026-06-18`。
|
||
|
||
## 最小实践
|
||
|
||
进入仓库目录:
|
||
|
||
```bash
|
||
cd /Users/zhaoyilun/Documents/xls_doc
|
||
```
|
||
|
||
构建本机二进制:
|
||
|
||
```bash
|
||
bash scripts/build.sh
|
||
```
|
||
|
||
输出示例:
|
||
|
||
```text
|
||
/Users/zhaoyilun/Documents/xls_doc/dist/docfill-darwin-arm64
|
||
```
|
||
|
||
运行“按日期 + 工单编号筛选一条工单并生成 Word”的测试任务:
|
||
|
||
```bash
|
||
dist/docfill-darwin-arm64 run -c manual_tests/04_filter_work_order_to_word/task.json --var date=2026-06-18 --var ticket_no=GD-002 --verbose
|
||
```
|
||
|
||
输出示例:
|
||
|
||
```text
|
||
log: load config path=manual_tests/04_filter_work_order_to_word/task.json
|
||
log: read data type=excel path=/Users/zhaoyilun/Documents/xls_doc/manual_tests/04_filter_work_order_to_word/source_work_orders.xlsx
|
||
log: read data type=excel path=/Users/zhaoyilun/Documents/xls_doc/manual_tests/04_filter_work_order_to_word/source_work_orders.xlsx rows=3
|
||
log: filter rows=3 matched=1 expect=one
|
||
log: render row=1 output=/Users/zhaoyilun/Documents/xls_doc/manual_tests/04_filter_work_order_to_word/out/work_order_2026-06-18_GD-002.docx
|
||
generated 1 file(s)
|
||
- /Users/zhaoyilun/Documents/xls_doc/manual_tests/04_filter_work_order_to_word/out/work_order_2026-06-18_GD-002.docx
|
||
```
|
||
|
||
查看生成结果:
|
||
|
||
```bash
|
||
open manual_tests/04_filter_work_order_to_word/out
|
||
```
|
||
|
||
更多可运行案例见 [HOWTO.md](HOWTO.md) 和 [manual_tests/README.md](manual_tests/README.md)。
|
||
|
||
## 常用命令
|
||
|
||
构建:
|
||
|
||
```bash
|
||
bash scripts/build.sh
|
||
```
|
||
|
||
运行一个任务:
|
||
|
||
```bash
|
||
dist/docfill-darwin-arm64 run -c task.json
|
||
```
|
||
|
||
运行任务并传入本次筛选条件:
|
||
|
||
```bash
|
||
dist/docfill-darwin-arm64 run -c 工单日报.json --var date=2026-06-18 --var ticket_no=GD-002
|
||
```
|
||
|
||
输出诊断日志:
|
||
|
||
```bash
|
||
dist/docfill-darwin-arm64 run -c task.json --verbose
|
||
```
|
||
|
||
重新生成本地测试素材:
|
||
|
||
```bash
|
||
/Users/zhaoyilun/.cache/codex-runtimes/codex-primary-runtime/dependencies/python/bin/python3 scripts/make-manual-test-materials.py
|
||
```
|
||
|
||
运行自动化冒烟测试:
|
||
|
||
```bash
|
||
bash scripts/smoke.sh
|
||
```
|
||
|
||
运行 Go 测试:
|
||
|
||
```bash
|
||
go test -count=1 ./...
|
||
```
|
||
|
||
## 筛选配置示例
|
||
|
||
Excel 工单表:
|
||
|
||
```text
|
||
日期 工单编号 客户名称 系统来源 处理结果 下一步
|
||
2026-06-18 GD-001 A 公司 PMS3.0 已派单 等待现场反馈
|
||
2026-06-18 GD-002 B 公司 D5000 已完成 归档并同步日报
|
||
2026-06-19 GD-001 C 公司 风控平台 待复核 补充截图
|
||
```
|
||
|
||
`task.json`:
|
||
|
||
```json
|
||
{
|
||
"vars": {
|
||
"date": "2026-06-18"
|
||
},
|
||
"data": {
|
||
"type": "excel",
|
||
"path": "./source_work_orders.xlsx",
|
||
"sheet": "工单",
|
||
"header_row": 1
|
||
},
|
||
"filter": {
|
||
"equals": {
|
||
"日期": "{{date}}",
|
||
"工单编号": "{{ticket_no}}"
|
||
},
|
||
"expect": "one"
|
||
},
|
||
"template": {
|
||
"path": "./work_order_template.docx"
|
||
},
|
||
"output": {
|
||
"path": "./out/work_order_{{日期}}_{{工单编号}}.docx",
|
||
"overwrite": true
|
||
}
|
||
}
|
||
```
|
||
|
||
运行:
|
||
|
||
```bash
|
||
dist/docfill-darwin-arm64 run -c task.json --var date=2026-06-18 --var ticket_no=GD-002
|
||
```
|
||
|
||
筛选含义:
|
||
|
||
```text
|
||
找到 日期 = 2026-06-18,并且 工单编号 = GD-002 的那一行。
|
||
```
|
||
|
||
`filter.expect` 支持:
|
||
|
||
- `one`: 必须只匹配一行,适合工单、单份日报、单个报表。
|
||
- `many`: 允许匹配多行,适合按日期生成多个人或多个部门的报表。
|
||
|
||
未配置 `filter` 时,工具沿用旧行为:读取到的每一行都会生成一个输出文件。
|
||
|
||
## 核心规则
|
||
|
||
- 配置文件使用 JSON。
|
||
- 数据源支持 `.xlsx` 和 SQLite `.db`。
|
||
- 模板与输出支持 `.docx` 和 `.xlsx`。
|
||
- 模板占位符格式为 `{{字段名}}`。
|
||
- Excel 数据的表头行提供字段名,SQLite 查询结果的列名提供字段名。
|
||
- 常用场景是通过 `filter.equals` 先筛选数据,再填充模板。
|
||
- 多个筛选条件之间是“全部满足”关系。
|
||
- 筛选只支持等值匹配,不支持模糊匹配、范围查询、OR 或复杂表达式。
|
||
- 复杂情况建议业务人员整理 Excel,例如新增“填报批次”“业务唯一标识”等辅助列。
|
||
- `vars` 提供默认变量,命令行 `--var key=value` 可以覆盖同名变量。
|
||
- 数据行字段优先于 `vars` 和 `--var`。
|
||
- `_row` 是内置变量,表示当前输出对应的结果行序号,从 `1` 开始。
|
||
- 默认不覆盖已存在文件,只有 `output.overwrite: true` 才允许覆盖。
|
||
- 成功结果写入 stdout,诊断日志和错误写入 stderr,便于数字员工或调度脚本判断执行结果。
|
||
|
||
## 退出码
|
||
|
||
- `0`: 执行成功。
|
||
- `1`: 配置、数据、模板或输出处理失败。
|
||
- `2`: 命令行参数错误。
|
||
|
||
错误输出格式:
|
||
|
||
```text
|
||
docfill: [ERROR_CODE] message
|
||
hint: repair suggestion
|
||
context: key=value
|
||
```
|
||
|
||
常见筛选错误:
|
||
|
||
- `DATA_FILTER_FIELD`: 筛选字段不在数据表中。
|
||
- `DATA_FILTER_VALUE`: 筛选条件引用的变量没有提供。
|
||
- `DATA_FILTER_NO_MATCH`: 没有找到符合条件的数据行。
|
||
- `DATA_FILTER_MULTI_MATCH`: 期望匹配一行,但实际匹配多行。
|
||
|
||
完整错误码、日志说明和集成建议见 [HOWTO.md](HOWTO.md)。
|
||
|
||
## 文档索引
|
||
|
||
- [HOWTO.md](HOWTO.md): 完整使用说明,包含最小实践、详细配置、输入输出示例、错误处理和数字员工调用建议。
|
||
- [manual_tests/README.md](manual_tests/README.md): 本地真实测试素材说明。
|
||
- [docs/digital-employee-runbook.md](docs/digital-employee-runbook.md): 面向数字员工或调度脚本的最小运行约定。
|