教务系统批量维护技能包 umanage-batch-ops(含下载)

技能包:umanage-batch-ops
适用:<租户>.changyan.com 系智慧教务平台(学生 / 班级 / 教师 / 任课四大模块)
体量:6 个文件、26 KB,19 条子命令
依赖:Node ≥ 22 + 一个开着远程调试端口的 Chrome,不需要 playwright / puppeteer
下载:https://7998888.xyz/wp-content/uploads/2026/10/umanage-batch-ops.zip


为什么要做成 Skill

上一篇记了这套教务系统批量维护的踩坑过程。但「记录」和「能复用」是两回事:上一次做完,
下次换一所学校、换一个学年,还是得从「怎么让 Chrome 被程序驱动」重新开始爬一遍。

所以这次把它整个收敛成一个技能包:接口、脚本、判定规则、验证规范,全部固化下来,
下次只需要换一个 config.json。

判断标准很简单——如果一套流程的知识密度高到「不看笔记做不出来」,它就值得做成 Skill。
教务系统恰好符合:接口有 10 个,坑有 12 个,而且每个坑都是静默失败,不报错、不抛异常,
只是数据没落库。

技能包长什么样

umanage-batch-ops/
├── SKILL.md                       # 工作流 + 铁律 + 坑位清单(给 AI 看的说明书)
├── references/
│   ├── api.md                     # 10 个接口的完整字段、参数位置、返回结构
│   └── chrome-cdp-setup.md        # 让 Chrome 能被驱动的那 5 个坑
└── scripts/
    ├── umanage.mjs                # 主 CLI,19 条子命令
    ├── parse-xls.mjs              # 不装库解析老式 .xls(OLE2 + BIFF8)
    └── config.example.json        # 配置模板

三个文件的分工是刻意分开的:

  • SKILL.md 回答「该怎么做」,是决策层
  • references/ 回答「为什么是这样」,是事实层,只在需要时读,不占上下文
  • scripts/ 回答「具体怎么敲」,是执行层,可独立运行

三条铁律

这三条不是风格偏好,是这次踩出来的血泪:

  1. 先 dry-run,再 --execute。 所有写操作脚本默认只读,必须显式带 --execute 才落库。
  2. 状态码不算成功。 {"status":1,"msg":"success"} 只代表请求被受理。
    实测批量删 34 个班,接口返回 status=1,实际有 1 个班因为「班级下存在用户」没删掉。
  3. 删除前先备份。 学生删除会连同账号一起清掉,先落一份 {id, userName, loginName} 快照再动手。
注意
这个平台的失败方式是静默的。参数少了不报错、请求头缺了不报错、limit 超了也不报错——
全都表现为「返回 200,但数据没变」。所以「复验」不是可选项,是流程的一部分。

六条工作流

整个技能包对外就 19 条子命令,按场景分成六条流水线:

# 工作流 关键命令
1 批量删除某年级学生 students-delete <年级> --execute
2 批量删除某年级班级 classes-delete <年级> --execute
3 解绑任课教师(删班前置) unbind <年级> --execute
4 批量导入学生名单 students-add <年级> --file plan.json --execute
5 教师建号与重名清理 teacher-add / dedupe
6 任课表格红黄提取与落库核对 grid / actual / compare

举两个例子。

批量导入学生——输入一个 {"高二1班":["张三","李四"]} 的 JSON,脚本会先读该班现有名单、
按重数扣除已存在的同名,所以重复执行是安全的:

node umanage.mjs students-add 高二 --file plan.json --execute

任课表格核对——这是最实用的一条。设置教师时表格里会标红标黄,处理完名册后要知道
「到底有没有真的存进去」,靠眼睛看表格是不行的(表格有缓存):

node umanage.mjs grid 高二 > grid.json      # 提取 Handsontable 网格 + 红黄标注
node umanage.mjs actual 高二 > actual.json  # 抓各班真实任课配置
node umanage.mjs compare grid.json actual.json
小贴士
红黄标注的语义是固化的:
红底 = 用户[xxx]不存在(教师库没这个账号);
黄底 = 用户[xxx]存在同名用户(教师库有重名,打名字区分不了)。
而且它是打开表格那一刻的快照,接口不实时校验——改完名册必须关掉弹窗重开才看得到效果。

十二个坑里最值钱的六个

坑 现象 规避
limit 超过 50 静默返回整页 HTML,不报错 分页 + startsWith('<') 探测 + 退避重试
缺 X-Requested-With 同上,返回整页 HTML 批量类接口一律带上
token 位置 多数接口放 body,/teaching/batch-* 必须放 URL 查询串 按接口分别处理
建教师「假成功」 返回 新增成功,但根本没落库 5 个可空字段(idCardNo 等)即使为空也必须带
名册缓存延迟 删完立刻查还是旧数据,误判成失败 等几十秒再复验
名册翻页漏记录 按页翻总数会漏人 查重名一律用 userLoginName=<姓名> 精确搜

还有一条是平台能力的:前端 RSA 加密是确定性的(PKCS#1 v1.5 填充),
同一明文每次密文相同。所以密码密文抓一次就能长期复用,不需要每次重新加密。

// 在页面控制台里取一次即可
window.encryptedString('laoshi12')

验证规范

批量操作的收尾必须是这四步,缺一步都不算完成:

  1. 接口复验——重拉目标列表,确认数量与内容
  2. 逐项复验——批量操作要打印每个子项结果,不能只看汇总
  3. 页面复验——刷新页面截图留证(树节点人数、空态文案)
  4. 备份落地——删除类操作必须留 JSON/CSV 快照,含 id 与关键字段

这次就是靠第 1 条抓出一个漏网之鱼:高二某个班整行 7 格任课配置提交时被漏掉了,
表格上看不出来,接口一比对就现形了。

怎么装

解压后放进 WorkBuddy 的技能目录即可:

unzip umanage-batch-ops.zip -d ~/.workbuddy/skills/
cd ~/.workbuddy/skills/umanage-batch-ops/scripts
cp config.example.json config.json   # 填 token / schoolId / campusId / teachingCycleId
node umanage.mjs help                # 看全部子命令

config.json 里的值全部来自浏览器:
token 在地址栏 ?IFLYTEK_CSRFTOKEN= 后面,
schoolId / campusId / teachingCycleId 在 F12 → Network 任意一个列表请求的 query 里。

边界

这个包只操作调用方自己有权管理的租户。凭据一律放 config.json,不要写进脚本或提交到仓库;
对外分享时学校名、账号、token、师生姓名都已脱敏。
批量删除不可逆,执行前应该先列清影响范围再确认。

技能包本身不含任何后门、不上报数据、不联外网——它只通过 CDP 驱动你自己机器上的浏览器,
所有请求都由你的浏览器带着你已有的登录态发出。

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容