DHG 考勤确认单模块维护
用途
维护华星 DHG(东宝)平台上「考勤确认单」模块:主表 hr_attendance_confirm + 子表 hr_attendance_confirm_detail,含选择考勤数据弹框、查询方案、结果窗、明细删除与月报拉取标记释放。
本技能封装了该模块的准确 id 地图、已上线的业务代码块、已验证的表单全局 JS,以及一套经过踩坑验证的 DHG 表单改造方法(formdata / saveTemplate / 子表加列 / 合并单元格 / 保存校验 / CDP 验证)。
何时使用
- 在考勤确认单里加字段、调布局、改全局 JS、加校验/联动
- 调整【选择考勤数据】/【查询方案】/结果窗行为
- 排查"表单字段不渲染""保存被拦/保存后丢值""选组织查不到数据"
- 参考本模块做法,在 DHG 上开发其它带子表、弹框、自定义 SQL 的模块
先读什么
| 文件 | 内容 |
|---|---|
references/module-map.md |
模块/表单/资源/按钮/代码块 id、主子表字段、表单网格与合并单元格 |
references/business-rules.md |
同组织/月份/派遣公司规则、拉取/追加/删除/查询方案口径 |
references/platform-patterns.md |
formdata 结构、类型码、四大布局坑、保存钩子、载荷、提示、CDP 验证 |
assets/form_global_js.js |
主表单全局代码(v9,已上线验证) |
assets/pick_form_global_js.js |
选择考勤数据弹框全局代码(含派遣公司回填、月份联动) |
assets/code_blocks/*.txt |
四个业务代码块源码(后缀为 .txt,内容为 Groovy 脚本语法,读取/写入时按 Groovy 解析) |
打包约定
- 技能包内所有 Groovy 脚本文件一律使用
.txt后缀(如assets/code_blocks/hr_att_query_report.txt) - 读取这些文件时必须按 Groovy 脚本语法解析(
def、jdbcTemplate、tool.selectSql等),不要当纯文本处理 - 写回平台代码块时同样按 Groovy 语法校验,不要因
.txt后缀而误判为普通文本
环境与自检
# 复用项目已有登录会话(默认读取 DHG_TOOLS_DIR 下的 dhg_login.py)
export DHG_TOOLS_DIR="F:/WorkBuddy/designs/2026-10-18-hx-attendance-confirm-v2/tools"
# 或改用账号登录(不要把密码写进技能文件)
export DHG_USER=... DHG_PASSWORD=...
python scripts/dhg_client.py --selftest
脚本说明:
scripts/dhg_client.py:会话复用、execsql(走wb_sql_exec代码块)、get_formdata/save_formdatascripts/save_form_js.py:把本地 JS 写入表单全局代码(先读最新 formdata,只替换 js)scripts/add_field.py:ALTER TABLE+sys_table_field注册(幂等)scripts/verify_form.py:真实浏览器(CDP)验证渲染与表单模型
标准工作流
A. 修改表单全局 JS
- 读
assets/form_global_js.js作为基线,确认要改的函数 - 本地改文件 →
node --check语法校验 - 写入平台:
bash python scripts/save_form_js.py \ --resource-id 2111782293122314241 --form-id 2111782292795158530 \ --module-id 2111779382753488897 --js-file ./my_js.js \ --check chooseEmp --check attPickData - 刷新页面(F5)后验证;子表/弹框行为用
verify_form.py或按platform-patterns.md的 CDP 方法实测
B. 新增字段(四件套,缺一不可)
python scripts/add_field.py --table-name hr_attendance_confirm --table-id 2111779382719934465 --column xxx --name 中文名 --type bigint- 表单 formdata 加单元格:
- 先查mergeCells,目标列若被合并区覆盖,先缩小 colspan
- 标签单元格cell.label = true,控制单元格label = false;controlId唯一
- 只读展示用type 0 + readOnly 1 + disabling true - 全局 JS 写值(拉取/联动处),并在
checkValid做兜底回填 - F5 →
verify_form.py --expect-label 中文名 --expect-key 列名
C. 子表加列
- 定位
cell.field[0].type == 61→tables[0].data[0](列网格) - deepcopy 现有列 → 改
field/name/tl/controlId→cols.insert(index, newcol) - 同时更新
tables[0].colWidths(漏了会列宽错位) - 保存 formdata → 刷新验证列头与首行取值
D. 加校验 / 联动
- 保存拦截:在全局 JS 定义
checkValid(覆盖实例方法),返回false中止;原校验用this.$options.methods.checkValid.call(this)回代 - 跨弹窗传值:先写
window.__xxx,目标表单模板里用全局方法读取 - 弹框取值:
beforeClose里this.$refs.form.mainForm
E. 验证(不可跳过)
- 启动无头 Chrome(后台):
bash chrome.exe --no-proxy-server --remote-debugging-port=9222 --headless=new \ --remote-allow-origins=* --user-data-dir=<临时目录> python scripts/verify_form.py --template-code hr_attendance_confirm_FormTabs --expect-label 考勤组织名称 --expect-key c_kq_org_id --open-form- 判定标准:
errs=[]、missingLabels=[]、missingKeys=[] - 设计器画布不渲染 type99;
innerText会忽略 overflow 裁剪,均不可作为验证依据
关键红线(违反必踩坑)
row0是折叠面板标题槽,只放标题;内容从row1开始mergeCells覆盖范围内的单元格不渲染- 标签单元格必须
cell.label = true - 模板标签是
${lang_<表>.<列>},搜中文搜不到,搜列名 - 全局 JS 函数互调必须带实例前缀(
_than.foo()/p.foo());实例可能为空的分支回退JsUlits - 写 js 只能走
saveTemplate;每次先读最新 formdata,只改目标字段 - 新字段必须同时改 DDL +
sys_table_field+ 表单单元格 - 组织 id 一律用
origin_id(per_orgs存在 id≠origin_id 的重复行;组织树回传的也是 originId) - 提示默认 3 秒且
JsUlits不支持时长;要 2 秒用vm.$message({duration:2000}) - 汇总 SQL 必须显式
GROUP BY,否则零命中返回 1 行空聚合,前端判空失效
业务硬约束
一张单据只允许 同一组织 + 同一月份 + 同一派遣公司:
- 拉取前:月份/派遣公司不一致 → 拦截(派遣公司校验不发请求)
- 拉取后:结果含多组织 / 与已有明细组织不一致 → 拦截
- 保存时:子表多月份、多组织、主表与明细不一致 → 拦截
- 追加而不是覆盖;去重键
attendance_report_id,缺失用工号|姓名|月份 - 删除明细行要释放
att_work_hour_month.c_sflq='0'