工时表按项目拆分 (timesheet-split)
Overview
将一个包含多个项目人员工时的标准「智租业务数字化运营」Excel,按项目(组织)拆分成多个独立 Excel 文件。核心约束是:严格保留原始「工时汇总表」的格式,只做两件事——过滤员工(仅保留本项目人员)+ 替换项目号/项目名称。其余所有元素(HLOOKUP 公式、合并单元格、合计行 SUM、制表人签字行)原样保留。
标准源表结构
拆分前必须先确认源表符合以下结构(用 openpyxl 读取核对):
| Sheet | 关键内容 | 注意事项 |
|---|---|---|
| Sheet1 | 工时汇总透视表 | B1 = 项目名称;A 列员工姓名(约第 5 行起);员工行之后有「总计」行;C 列起每日工时,AG 列总计 |
| 工时汇总表 | 每日工时明细 | A2="项目号:XXXX";E2==Sheet1!B1(跟随项目名);表头约 5 行;员工行(约第 6 行起)每日工时用 HLOOKUP 引用 Sheet1;含「合计」行与「制表人签字」行 |
| 人员对应公司主体 | 员工↔组织 | A序号 B姓名 C公司主体 |
拆分流程
第 1 步:确认拆分依据
向用户确认(或根据截图/Sheet3 推断):
- 每个项目的 项目名称、项目编号
- 每个项目对应的 员工名单(来自 Sheet3「人员对应公司主体」的组织映射)
- 输出文件名
第 2 步:准备配置文件
生成 projects.json:
{
"projects": [
{
"name": "两轮换电全链路数字化运营系统",
"code": "SW2023006a",
"output": "产研202605-两轮换电全链路数字化运营系统.xlsx",
"people": ["何俊宏", "王章环", "吴尚慧"]
},
{
"name": "智租业务数字化运营系统",
"code": "SW2023006",
"output": "产研202605-智租业务数字化运营系统.xlsx",
"people": ["贾旭影", "蒋丹枫", "刘云龙", "邵文彬"]
}
]
}
第 3 步:运行拆分脚本
python3 ~/.workbuddy/skills/timesheet-split/scripts/split_timesheet.py \
--source <源文件.xlsx> \
--config projects.json \
--output-dir <输出目录>
脚本自动完成:复制源文件 → 删除非项目员工行(从下往上 delete_rows,openpyxl 自动处理合并单元格)→ Sheet1 总计行重算(空列补 0)→ 工时汇总表 HLOOKUP 的 index 按员工在 Sheet1 的新行号重映射 → 合计行 SUM 收缩到实际员工行 → A2 项目号替换 → Sheet3 过滤人员。
第 4 步:验证(必须)
用 openpyxl 逐文件核对:
1. 合并单元格范围与原始一致
2. A2 项目号已替换;E2 仍为 =Sheet1!B1
3. 员工行 = 预期名单;HLOOKUP 公式 index 正确
4. 「合计」行 SUM 公式范围 = B6:B{末员工行}
5. 「制表人签字」行保留
6. Sheet1 总计行无空列(空列应为 0)
关键坑点(务必遵守)
- 绝不用
data_only=True把公式写成静态值——用户要求保留 HLOOKUP 公式,静态值会破坏"打开 Excel 自动重算"的预期。最小改动原则:只过滤 + 替换项目号。 - HLOOKUP index 必须随 Sheet1 删行而重映射:
index = 员工在Sheet1的新行号 - table_array起始行 + 1。原始Sheet1!$4:$25起始行为 4,故index = 新行号 - 3。不重映射会导致引用错位(显示 0 或错误数据)。 - 删除行用
delete_rows从下往上删,避免行号错位;openpyxl 会自动收缩落在删除范围内的合并单元格。 - 合计行 SUM 必须收缩:原始模板预留到第 20 行(
=SUM(B6:B20)),删员工后需改为实际末员工行,否则合计包含空行(虽为 0 但格式不严谨)。 - Sheet1 总计行空列补 0:原表某些日期列全项目无人填报,过滤后该行应为 0 而非留空,保证 HLOOKUP 引用与显示一致。
- 「制表人签字」行不要删:它是原始表尾的固定结构,删除员工行后会自动上移,保留即可。
- 项目名称(E2)保持公式
=Sheet1!B1,不要写死——这样改 Sheet1 的 B1 即全局生效。
Resources
scripts/split_timesheet.py:核心拆分脚本,参数化接受源文件 + projects.json 配置,自动探测表结构并执行最小改动拆分。