分时填写线上课时表与总部周报
运行模式与时间
两个定时任务必须独立运行,不能在同一次定时触发中连续填写两个网页:
online-sheet:每周一 10:00(Asia/Shanghai)运行,只填写金山文档线上课时表。headquarters-report:每周二 12:00(Asia/Shanghai)运行,只填写总部周报表单。
两种模式都执行以下准备步骤:
- 将“上周”解释为触发日前最近一个完整的周一至周日,包含首尾日期。周一和周二运行时都应得到同一统计周期。
headquarters-report模式先按“用户提供的一对一附加课时”取得 n;online-sheet模式不询问 n,n 不得写入线上课时表。- 运行
scripts/prepare_weekly_report.py。总部周报模式传入--headquarters-extra-one-to-one-hours n;脚本调用calculate-teaching-hours/scripts/calculate_hours.py,同时生成总部周报字段和online_sheet.targets。不得在脚本外自行加总或猜测课时。 - 在对话中显示统计周期、班课小时数、一对一课表小时数、用户提供的 n、总部周报一对一合计与金额。若
status不是ok,列出errors并停止本次目标网页填写。 online-sheet模式只执行“线上课时表”流程,保存并核对后结束;不得打开或改动总部周报。headquarters-report模式只执行“总部周报表单”流程,核对后保留待确认页面;不得打开或改动金山文档。
用户提供的一对一附加课时
仅在 headquarters-report 模式执行:
- 每次运行都在对话中询问用户本次总部周报的一对一附加小时数 n;不得从微信或其他来源自行读取或推断。
- 只有用户在触发消息或当前对话中明确提供 n 后才继续;即使上次运行给过 n,也不得沿用。用户明确说“没有”“无”或“0”时使用
0.0。 - 将 n 规范为非负、保留一位小数的数字,并传给
scripts/prepare_weekly_report.py --headquarters-extra-one-to-one-hours n。脚本输出的one_to_one_adjustment必须同时显示课表小时数、用户提供的附加小时数和总部周报合计。 - n 只用于总部周报的“一对一小时数”和“一对一金额”。线上课时表 D 列始终只使用排课 Excel 的一对一小时数。
总部周报表单
- 读取本机
references/form-config.local.json,使用浏览器打开其中的url。 - 保持配置中的公司和教师不变;页面会保留旧值,所有目标字段都使用替换填写,不得追加。
- 日期框为只读控件,必须通过日期选择器选择
period.start和period.end。 - 数字字段一律填写一位小数;答疑无特殊说明时填
0.0;本周主要工作无特殊说明时沿用网页旧值。 - 重新读取日期和 6 个数字字段。全部与脚本输出相同后,保留待确认页面并请求用户确认。
- 页面“提交”会产生外部副作用。定时任务先保留已填写页面并请求确认;确认后只点击一次,以成功提示或结果页验证。
字段映射
| 网页字段 | 配置标识 | 脚本值 |
|---|---|---|
| 所属公司 | form.company |
保持配置值 |
| 教师名称 | form.teacher |
保持配置值 |
| 开始/结束日期 | form.fields.start_date/end_date |
period.start/end |
| 班课小时数/金额 | form.fields.class_hours/class_amount |
同名字段 |
| 一对一小时数/金额 | form.fields.one_to_one_hours/one_to_one_amount |
同名字段 |
| 答疑小时数/金额 | form.fields.qa_hours/qa_amount |
默认 0.0 |
| 本周主要工作 | form.fields.main_work |
默认沿用旧值 |
线上课时表
- 读取本机
references/online-sheet-config.local.json,打开url,确认文档标题正确且具有编辑权限。 - 选择工作表
sheet_name(当前为“黄浦江”)。使用页面中唯一的工作表选项定位,不依赖底部标签坐标。 - 使用脚本返回的每个
online_sheet.targets[]。目标包含工作表行号、日期段以及 D–M 列的完整替换值。 - 对每个单元格:
- 使用名称框
input.edit-box输入单元格地址(如D13)并按 Enter; - 在当前选中单元格输入目标值并按 Enter;
- 数值使用一位小数;目标为空字符串时清空旧值,防止重跑后残留旧班课数据。
- 使用名称框
- 只写 D–M,不写 N“周总计”和 O“季度总计”,这两列由公式自动更新。
- 写完后逐个重新选择目标单元格,核对显示值;同时确认 N/O 公式结果自动变化。金山文档自动保存,无需点击提交。
- 若页面结构、工作表名称、目标日期行或公式列与配置不一致,停止该网页填写并报告,不得猜测坐标。
线上表格列映射
| 列 | 内容 | 课时分类 |
|---|---|---|
| D | 1v1课时 | 一对一合计 |
| E | 新南(算 OH) | 新南班课 O1/O2 |
| F | 欧亚(不算 OH) | 欧亚预科(落地) |
| G | 英本(不算 OH) | 英本预科 |
| H | 沃隆港 | 伍伦贡/卧龙岗/沃隆港 |
| I | 启程双学分 | 启程 3915 门 |
| J | 云中学 | 英伦云中学一年制/两年制 |
| K | IG | IG |
| L | OSSD | OSSD |
| M | 外地项目 | VET、14800 等外地项目 |
| N/O | 自动汇总 | 禁止写入 |
脚本按表格的实际日期段生成行号;每月 20/21 日附近的一周可能拆成两行。此时按课程日期分别汇总并填写两个目标行。目标行可能包含上次运行已覆盖的日期,脚本会从该行起始日重新统计到本周结束日,保证重复运行不会叠加课时。
统计与核算规则
- 课时分类完全采用
calculate-teaching-hours的结果:只有欧亚、云中学、AP 微积分及已知历史班级(沃隆港/伍伦贡/卧龙岗、新南、双学分/启程 3915、英本、IG、OSSD、VET/14800 等)算班课;其他有有效授课时间的课程即使没有一对一后缀也算一对一;家长会与其他会议忽略。 - 班课金额:逐班计算
课时 × 每小时产出 × 人数后求和;配置来自references/class-rates.local.json。 - 总部周报一对一小时数:
排课 Excel 一对一小时数 + 用户提供的 n;总部周报一对一金额:总部周报一对一小时数 × one_to_one_hourly_output。 - 线上课时表一对一小时数只取排课 Excel,不包含用户提供的 n。
- 欧亚 OH 已由课时统计源直接排除,不计入任何课时、金额或线上表格 F 列,并写入
excluded;下游不得再次扣减或改算。 - 线上表格 G 列按表头规则排除英本 OH;E 列新南包含 OH。
- 未映射班级、缺失人数/费率、
missing_times或网页核对失败时,明确报告并停止相关填写。
本机配置
- 费率或人数变化:修改
references/class-rates.local.json。 - 总部表单变化:修改
references/form-config.local.json。 - 金山文档链接、工作表、锚点行或列映射变化:修改
references/online-sheet-config.local.json。 - 三个
*.local.json均为本机配置,不得上传。修改后运行scripts/prepare_weekly_report.py --self-check,再做只读准备测试。