流程表单字段校验 上级包含申请人
title: 流程表单字段校验-上级包含申请人
场景描述
在离职流程中,校验“申请人”是否存在于 4 个上级字段(部门负责人、直接上级等)中。如果都不包含,且“离职人”已选择,则弹窗拦截提交。 e: 流程表单字段校验-上级包含申请人
场景描述
在离职流程中,校验“申请人”是否存在于 4 个上级字段(部门负责人、直接上级等)中。如果都不包含,且“离职人”已选择,则弹窗拦截提交。## 完整代码实现
注意:必须包含
setTimeout等待底层数据刷新,并使用isChecking锁防止连续弹窗。
// 1. 字段 ID 转换 (主表字段)
const F_APP = WfForm.convertFieldNameToId("applicant");
const F_LZR = WfForm.convertFieldNameToId("lzr_zb");
const F_MGR = WfForm.convertFieldNameToId("lzrbmfzr_zb"); // 部门负责人
const F_DIR = WfForm.convertFieldNameToId("lzrzjsj_zb"); // 直接上级
const F_L1 = WfForm.convertFieldNameToId("lzryjbmfzr_zb"); // 一级部门负责人
const F_IND = WfForm.convertFieldNameToId("lzrjjbmfzr_zb"); // 间接部门负责人
// 2. 执行锁:防止 E9 事件连续触发导致多次弹窗
let isChecking = false;
// 3. 核心校验逻辑
function runCheck() {
if (isChecking) return; // 正在处理或弹窗中,直接跳过
// 直接取值并安全转字符串
const lzr = String(WfForm.getFieldValue(F_LZR) || "");
const app = String(WfForm.getFieldValue(F_APP) || "");
// 离职人或申请人未选 -> 不校验 (跳过)
if (!lzr || lzr === "0" || !app || app === "0") return;
// 精确匹配辅助函数 (防止 "1" 误匹配到 "11")
const isMatch = (val) => val && val !== "0" && ("," + val + ",").indexOf("," + app + ",") !== -1;
// 逐个判断:只要有一个匹配就通过 (提前 return,停止校验)
if (isMatch(WfForm.getFieldValue(F_MGR))) return;
if (isMatch(WfForm.getFieldValue(F_DIR))) return;
if (isMatch(WfForm.getFieldValue(F_L1))) return;
if (isMatch(WfForm.getFieldValue(F_IND))) return;
// 4 个都不包含 -> 弹窗拦截
isChecking = true;
WfForm.showConfirm("非离职人上级无法提交此单", function() {
isChecking = false; // 用户点击确定后解锁
});
}
WfForm.showConfirm("非离职人上级无法提交此单", function() {
isChecking = false; // 用户点击确定后解锁
});
}// 4. 绑定变化事件 (只监听 4 个上级字段)
// setTimeout(20) 等待 E9 底层数据绑定完成,解决“获取不到值”的问题
const targetIds = [F_MGR, F_DIR, F_L1, F_IND].join(",");
WfForm.bindFieldChangeEvent(targetIds, function(obj, id, value) {
setTimeout(runCheck, 20);
});
// 5. 提交拦截校验 (同步执行)
WfForm.registerCheckEvent(WfForm.OPER_SUBMIT, function(callback) {
const lzr = String(WfForm.getFieldValue(F_LZR) || "");
const app = String(WfForm.getFieldValue(F_APP) || "");
if (lzr && lzr !== "0" && app && app !== "0") {
const isMatch = (val) => val && val !== "0" && ("," + val + ",").indexOf("," + app + ",") !== -1;
// 判断是否匹配
const ok = isMatch(WfForm.getFieldValue(F_MGR)) ||
isMatch(WfForm.getFieldValue(F_DIR)) ||
isMatch(WfForm.getFieldValue(F_L1)) ||
isMatch(WfForm.getFieldValue(F_IND));
if (!ok) {
WfForm.showConfirm("非离职人上级无法提交此单", function() {});
return; // 不调用 callback() 即拦截提交
}
}
callback(); // 放行提交
});
1. 为什么修改字段时会“多次弹窗”?
- 原因:泛微 E9 的字段联动机制非常复杂。当你修改一个字段(如离职人)时,可能会级联触发其他 4 个上级字段的
change事件。如果没有锁,校验函数会被连续执行 4-5 次。 - 解决:必须使用 状态锁 (
isChecking)。当弹窗出现时,锁住逻辑,直到用户点击“确定”才解锁。
2. 为什么 getFieldValue 获取不到值/拿到的是旧值?
- 原因:
bindFieldChangeEvent触发时,DOM 可能还没更新完毕,底层数据有几十毫秒的延迟。此时直接getFieldValue往往拿到的是undefined或修改前的旧值。 - 解决:必须加
setTimeout(..., 20)。给 E9 留出缓冲时间,确保能拿到最新数据。
3. 为什么不要用 superiors.some(...)?
- 原因:虽然
.some()是标准写法,但在 E9 环境下,展开写成 4 个独立的if (isMatch(...)) return;性能更好且更直观。一旦第一个匹配,立即退出,不再执行后续逻辑,减少不必要的 DOM 查询。
4. 精确匹配防坑 (必看)
- 错误写法:
val.indexOf(app) > -1-> 这会导致申请人 ID1被误判为匹配上级11, 21。 - 正确写法:
("," + val + ",").indexOf("," + app + ",") !== -1。首尾加逗号,彻底根除部分匹配错误。
5. 主表 vs 明细表
- 本方案仅适用于主表字段(不需要传行号)。如果是明细表,必须遍历行号并使用
WfForm.getFieldValue(id, rowIndex)。切勿在主表代码中加循环。