跳转至

流程表单字段校验 上级包含申请人


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(); // 放行提交
});
n() {}); 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 -> 这会导致申请人 ID 1 被误判为匹配上级 11, 21
  • 正确写法("," + val + ",").indexOf("," + app + ",") !== -1。首尾加逗号,彻底根除部分匹配错误。

5. 主表 vs 明细表

  • 本方案仅适用于主表字段(不需要传行号)。如果是明细表,必须遍历行号并使用 WfForm.getFieldValue(id, rowIndex)。切勿在主表代码中加循环。