You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dynamics CRM JavaScript表单保存拦截功能实现求助

问题修复:Dynamics 365表单保存时的层级冲突验证

核心问题分析

你的脚本问题出在异步操作与表单保存事件的时序不匹配:Xrm.WebApi的请求是异步的,表单保存事件会在异步请求完成前就执行完毕。直接调用preventDefault会完全阻止保存,但不调用的话又会在验证结果出来前就完成保存。此外,全局状态变量的错误使用导致后续保存操作无法重新触发验证。

修复后的完整代码

// On Save validation
var ProjectMainForm = (function () {
    "use strict";

    var SaveMode = {
        Save: 1,
        SaveAndClose: 2,
        SaveAndNew: 59,
        Autosave: 70
    };

    var saveMode;

    function OnSave(executionContext) {
        var eventArgs = executionContext.getEventArgs();
        var formContext = executionContext.getFormContext();
        
        saveMode = eventArgs.getSaveMode();

        // 仅对已存在的记录进行验证(表单类型2)
        if (formContext.ui.getFormType() === 2) {
            // 先阻止默认保存,等待异步验证结果
            eventArgs.preventDefault();
            
            // 过滤不需要验证的保存模式
            if (![SaveMode.Save, SaveMode.SaveAndClose, SaveMode.SaveAndNew, SaveMode.Autosave].includes(saveMode)) {
                return;
            }

            fetchChildrenProjects(formContext, eventArgs);
        } else {
            console.log("跳过新建记录的验证");
        }
    }

    function fetchChildrenProjects(formContext) {
        var projectID = formContext.getAttribute("dmis_dmisid").getValue();
        var projectLevel = formContext.getAttribute("dmis_displaylevel").getValue();

        var fetchXML = "<fetch top='1'>" +
            "<entity name='dmis_dmishierarchy'>" +
            "<attribute name='dmis_dmishierarchyid'/>" +
            "<filter>" +
            "<condition attribute='dmis_dmisid' operator='eq' value='" + projectID + "'/>" +
            "</filter>" +
            "</entity>" +
            "</fetch>";

        var encodedFetchXML = encodeURIComponent(fetchXML);
        Xrm.WebApi.retrieveMultipleRecords("dmis_dmishierarchy", "?fetchXml=" + encodedFetchXML).then(
            function success(result) {
                if (result.entities.length > 0) {
                    var hierarchyId = result.entities[0].dmis_dmishierarchyid;
                    checkForConflict(formContext, projectLevel, hierarchyId);
                } else {
                    console.log("未找到当前项目的层级记录");
                    // 无层级记录,允许保存
                    triggerSave(formContext);
                }
            },
            function (error) {
                Xrm.Navigation.openAlertDialog({ text: "获取层级ID失败: " + error.message });
            }
        );
    }

    function checkForConflict(formContext, projectLevel, hierarchyId) {
        var fetchXML = "<fetch>" +
            "<entity name='dmis_dmishierarchy'>" +
            "<attribute name='dmis_displaylevel'/>" +
            "<filter>" +
            "<condition attribute='dmis_parent' operator='eq' value='" + hierarchyId + "'/>" +
            "</filter>" +
            "</entity>" +
            "</fetch>";

        var encodedFetchXML = encodeURIComponent(fetchXML);
        Xrm.WebApi.retrieveMultipleRecords("dmis_dmishierarchy", "?fetchXml=" + encodedFetchXML).then(
            function success(result) {
                if (result.entities.some(entity => entity.dmis_displaylevel <= projectLevel)) {
                    Xrm.Navigation.openAlertDialog({
                        title: "保存冲突",
                        text: "无法保存:当前项目存在同级或更低层级的子项目。"
                    });
                } else {
                    // 验证通过,执行手动保存
                    triggerSave(formContext);
                }
            },
            function (error) {
                Xrm.Navigation.openAlertDialog({ text: "检查层级冲突失败: " + error.message });
            }
        );
    }

    // 根据保存模式触发对应的保存操作
    function triggerSave(formContext) {
        switch (saveMode) {
            case SaveMode.Save:
            case SaveMode.Autosave:
                formContext.data.entity.save();
                break;
            case SaveMode.SaveAndClose:
                formContext.data.entity.save("saveandclose");
                break;
            case SaveMode.SaveAndNew:
                formContext.data.entity.save("saveandnew");
                break;
            default:
                formContext.data.entity.save();
        }
    }

    return {
        OnSave: OnSave
    };
})();

关键修改点

  1. 强制阻止默认保存:在OnSave事件开头就调用eventArgs.preventDefault(),确保表单不会在异步验证完成前自动保存。
  2. 移除冗余全局变量:删除hasCheckedConflict,避免状态残留导致后续保存操作异常。
  3. 拆分保存逻辑:新增triggerSave函数统一处理不同保存模式的手动触发,代码更简洁可维护。
  4. 完善异常场景处理:在获取层级记录为空的场景下直接允许保存,避免验证逻辑遗漏。

内容的提问来源于stack exchange,提问作者Gareth Wilson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:06:05