chore: prepare docfill project for gitea

This commit is contained in:
赵义仑
2026-06-24 09:45:35 +08:00
parent ca444bd5d0
commit 32e74d0f43
38 changed files with 2915 additions and 162 deletions

281
README.md
View File

@@ -1,79 +1,151 @@
# docfill
`docfill` 是一个最小化本地填报工具:从 Excel 或 SQLite 读取数据,把 `{{字段名}}` 填入 Word/Excel 模板,生成输出文件
`docfill` 是一个本地文档填充命令行工具。它从 Excel 或 SQLite 读取结构化数据,按业务条件筛选出需要使用的数据行,再把数据填入 WordExcel 模板中的 `{{字段名}}` 占位符
## Build
本工具的定位是“小型、稳定、便于数字员工调用”。它只负责本地数据到本地模板的填充不内置业务系统登录、审批流、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
go build -o docfill ./cmd/docfill
bash scripts/build.sh
```
`scripts/build.sh` writes the local macOS arm64 binary to `dist/docfill-darwin-arm64`.
## Run
```bash
./docfill run --config task.json
./docfill run -c task.json --var date=2026-06-18 --var batch=早班
```
成功时 stdout 输出生成文件清单:
输出示例:
```text
generated 2 file(s)
- /path/to/out/report_张三.xlsx
- /path/to/out/report_李四.xlsx
/Users/zhaoyilun/Documents/xls_doc/dist/docfill-darwin-arm64
```
退出码
- `0`: 成功。
- `1`: 配置、数据、模板或输出失败。
- `2`: 命令行参数错误。
## Run Case Tests
运行“按日期 + 工单编号筛选一条工单并生成 Word”的测试任务
```bash
go test -run TestCase -v ./internal/docfill
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
```
当前案例覆盖
输出示例
- Excel 日报数据填 Excel 模板,批量生成个人日报。
- SQLite 日报数据填 Word 模板,批量生成个人日报。
- SQLite 汇总数据填 Excel 模板,批量生成部门汇总表。
```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
```
## Smoke Test
查看生成结果:
```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
```
Smoke test 会
运行 Go 测试
- 跑全量 Go 测试。
- 构建临时 `docfill` 二进制。
- 复制 `examples/` 到临时目录。
- 生成临时 Excel、Word、SQLite 示例数据。
- 执行两个示例任务并检查输出文件。
```bash
go test -count=1 ./...
```
## Digital Employee Runbook
## 筛选配置示例
给数字员工或调度脚本使用时,看
Excel 工单表
- `docs/digital-employee-runbook.md`
```text
日期 工单编号 客户名称 系统来源 处理结果 下一步
2026-06-18 GD-001 A 公司 PMS3.0 已派单 等待现场反馈
2026-06-18 GD-002 B 公司 D5000 已完成 归档并同步日报
2026-06-19 GD-001 C 公司 风控平台 待复核 补充截图
```
## Runnable Examples
示例配置在 `examples/`
- `examples/excel-to-word/task.json`
- `examples/sqlite-to-excel/task.json`
示例里的二进制 Office/SQLite 文件由 `scripts/smoke-fixtures` 临时生成,不提交到仓库。
## Excel Data Example
`task.json`
```json
{
@@ -82,63 +154,88 @@ Smoke test 会:
},
"data": {
"type": "excel",
"path": "./data.xlsx",
"sheet": "Sheet1",
"path": "./source_work_orders.xlsx",
"sheet": "工单",
"header_row": 1
},
"filter": {
"equals": {
"日期": "{{date}}",
"工单编号": "{{ticket_no}}"
},
"expect": "one"
},
"template": {
"path": "./template.docx"
"path": "./work_order_template.docx"
},
"output": {
"path": "./out/report_{{date}}_{{name}}_{{_row}}.docx",
"overwrite": false
"path": "./out/work_order_{{日期}}_{{工单编号}}.docx",
"overwrite": true
}
}
```
Excel 第一行是字段名,后续每一行生成一个文件。
运行:
## SQLite Data Example
```json
{
"vars": {
"date": "2026-06-18"
},
"data": {
"type": "sqlite",
"path": "./data.db",
"query": "select name, date, done from daily_report where date = ?",
"params": ["{{date}}"]
},
"template": {
"path": "./template.xlsx"
},
"output": {
"path": "./out/report_{{name}}_{{_row}}.xlsx"
}
}
```bash
dist/docfill-darwin-arm64 run -c task.json --var date=2026-06-18 --var ticket_no=GD-002
```
SQL 查询结果的列名就是模板占位符字段名。
筛选含义:
## P0 Rules
```text
找到 日期 = 2026-06-18并且 工单编号 = GD-002 的那一行。
```
- 配置里的相对路径按 `task.json` 所在目录解析。
- `vars` 可以提供默认变量,命令行 `--var key=value` 会覆盖同名默认变量。
- 模板填充时,每行数据字段优先于 `vars`
- `_row` 是内置变量,表示当前数据行序号,从 `1` 开始。
- SQLite `params` 对应 SQL 里的 `?` 参数。
- Excel `header_row``1` 开始,默认是 `1`
- 默认不覆盖已有输出文件;只有 `output.overwrite: true` 才允许覆盖。
- 输出文件路径中的字段值会清理 `/ \ : * ? " < > |`
- 模板里缺字段或渲染后仍有 `{{字段}}`,会直接失败。
- Word 模板支持同一段落内被拆开的文本占位符,例如 `{{na``me}}` 位于相邻文本节点。
`filter.expect` 支持:
## MVP Limits
- `one`: 必须只匹配一行,适合工单、单份日报、单个报表。
- `many`: 允许匹配多行,适合按日期生成多个人或多个部门的报表。
- 只支持 JSON 配置
- 只支持 `.xlsx` 数据源、SQLite 数据源。
- 只支持 `.docx``.xlsx` 模板。
- Word 占位符拆分只做最小兼容:支持同一段落内的文本节点拆分,不做复杂表格循环或样式级模板语法。
- 不做 Web、权限、审批流、模板设计器或业务系统直连。
未配置 `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): 面向数字员工或调度脚本的最小运行约定。