跳转至

流程回退

本文档内容来源于 http://doc.myapps.cn/docs/common-script/common-script-1f1a68qhurkko

脚本说明

该脚本用于实现流程回退功能。流程回退是指将流程从当前节点回退到之前的某个节点,通常用于需要重新审批或修正错误的场景。

常见实现方式

方式1:回退到上一个节点

(function(){
    var doc = getCurrentDocument();
    var flowProcess = getFlowProcess();
    var flow = flowProcess.doViewByDocument(doc);

    if(flow != null){
        var currentNode = flow.getCurrentNode();
        var nodes = flow.getNodes();

        if(nodes != null && nodes.size() > 0){
            // 找到当前节点的索引
            var currentIndex = -1;
            for(var i = 0; i < nodes.size(); i++){
                if(nodes.get(i).getId() === currentNode.getId()){
                    currentIndex = i;
                    break;
                }
            }

            // 回退到上一个节点
            if(currentIndex > 0){
                var previousNode = nodes.get(currentIndex - 1);
                var params = createParamsTable();
                params.setParameter("_attitude", "回退到上一节点");
                flowProcess.doBack(flow, previousNode, params, getWebUser());

                return "回退成功";
            }
        }
    }

    return "回退失败";
})();

方式2:回退到指定节点

(function(){
    var doc = getCurrentDocument();
    var targetNodeId = "目标节点ID";
    var flowProcess = getFlowProcess();
    var flow = flowProcess.doViewByDocument(doc);

    if(flow != null){
        var targetNode = flow.getNodeById(targetNodeId);

        if(targetNode != null){
            var params = createParamsTable();
            params.setParameter("_attitude", "回退到指定节点");
            flowProcess.doBack(flow, targetNode, params, getWebUser());

            return "回退成功";
        }
    }

    return "回退失败";
})();

方式3:回退并更新审批历史

(function(){
    var doc = getCurrentDocument();
    var docId = doc.getId();
    var targetNodeId = "目标节点ID";
    var flowProcess = getFlowProcess();
    var flow = flowProcess.doViewByDocument(doc);

    if(flow != null){
        var targetNode = flow.getNodeById(targetNodeId);

        if(targetNode != null){
            // 更新审批历史
            var dName = sys_function.DATASOURCENAME;
            var flowStateSql = "select domainid,id ";
            flowStateSql += "from t_flowstatert ";
            flowStateSql += "where docid = '"+docId+"'";
            var flowState = findBySQL(flowStateSql);

            if(flowState != null){
                var flowStateId = flowState.getId();
                var attitude = "回退到节点:" + targetNode.getName();

                // 更新最后一条审批意见
                var updateSql = " UPDATE T_ACTORHIS SET [ATTITUDE] = '"+attitude+"' ";
                updateSql += " WHERE PROCESSTIME = ";
                updateSql += " (SELECT MAX(PROCESSTIME) FROM T_ACTORHIS ";
                updateSql += " WHERE DOC_ID = '"+docId+"' ";
                updateSql += " AND FLOWSTATERT_ID = '"+flowStateId+"') ";
                updateSql += " AND FLOWSTATERT_ID = '"+flowStateId+"' ";
                updateByDSName(dName, updateSql);
            }

            // 执行回退
            var params = createParamsTable();
            params.setParameter("_attitude", "流程回退");
            flowProcess.doBack(flow, targetNode, params, getWebUser());

            return "回退成功";
        }
    }

    return "回退失败";
})();

方式4:根据条件回退

(function(){
    var doc = getCurrentDocument();
    var condition = doc.getItemValueAsString("条件字段");
    var flowProcess = getFlowProcess();
    var flow = flowProcess.doViewByDocument(doc);

    if(flow != null){
        var targetNodeId = "";

        // 根据条件选择回退目标节点
        if(condition != null && condition === "回退到部门"){
            targetNodeId = "部门节点ID";
        }else if(condition != null && condition === "回退到财务"){
            targetNodeId = "财务节点ID";
        }else{
            return "条件不符合,无法回退";
        }

        var targetNode = flow.getNodeById(targetNodeId);

        if(targetNode != null){
            var params = createParamsTable();
            params.setParameter("_attitude", "条件回退");
            flowProcess.doBack(flow, targetNode, params, getWebUser());

            return "回退成功";
        }
    }

    return "回退失败";
})();

扩展示例

示例1:回退并记录日志

(function(){
    var doc = getCurrentDocument();
    var docId = doc.getId();
    var targetNodeId = "目标节点ID";
    var flowProcess = getFlowProcess();
    var flow = flowProcess.doViewByDocument(doc);

    if(flow != null){
        var targetNode = flow.getNodeById(targetNodeId);

        if(targetNode != null){
            // 记录回退日志
            var dName = sys_function.DATASOURCENAME;
            var logSql = "insert into tlk_流程日志 (item_文档ID, item_操作类型, item_目标节点, item_操作人, item_操作时间) ";
            logSql += "values ('"+docId+"', '流程回退', '"+targetNode.getName()+"', '"+getWebUser().getName()+"', '"+format(new Date(), "yyyy-MM-dd HH:mm:ss")+"')";
            updateByDSName(dName, logSql);

            // 执行回退
            var params = createParamsTable();
            params.setParameter("_attitude", "流程回退");
            flowProcess.doBack(flow, targetNode, params, getWebUser());

            return "回退成功,已记录日志";
        }
    }

    return "回退失败";
})();

示例2:回退并更新文档字段

(function(){
    var doc = getCurrentDocument();
    var docId = doc.getId();
    var targetNodeId = "目标节点ID";
    var flowProcess = getFlowProcess();
    var flow = flowProcess.doViewByDocument(doc);

    if(flow != null){
        var targetNode = flow.getNodeById(targetNodeId);

        if(targetNode != null){
            // 更新文档字段
            doc.findItem("回退操作").setValue("是");
            doc.findItem("回退时间").setValue(format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            doc.findItem("回退人").setValue(getWebUser().getName());
            doc.findItem("回退目标节点").setValue(targetNode.getName());
            doc.findItem("回退原因").setValue(doc.getItemValueAsString("回退原因字段"));

            // 执行回退
            var params = createParamsTable();
            params.setParameter("_attitude", doc.getItemValueAsString("回退原因字段"));
            flowProcess.doBack(flow, targetNode, params, getWebUser());

            // 保存文档
            var docProcess = getDocumentProcess();
            docProcess.doUpdate(doc);

            return "回退成功";
        }
    }

    return "回退失败";
})();

示例3:回退前验证权限

(function(){
    var currentUser = getWebUser();
    var userRole = currentUser.getRole();

    // 验证是否有回退权限
    var hasPermission = false;
    if(userRole != null){
        var roleName = userRole.getName();
        if(roleName === "管理员" || roleName === "流程管理员"){
            hasPermission = true;
        }
    }

    if(!hasPermission){
        return "您没有流程回退权限";
    }

    var doc = getCurrentDocument();
    var targetNodeId = "目标节点ID";
    var flowProcess = getFlowProcess();
    var flow = flowProcess.doViewByDocument(doc);

    if(flow != null){
        var targetNode = flow.getNodeById(targetNodeId);

        if(targetNode != null){
            var params = createParamsTable();
            params.setParameter("_attitude", "管理员回退");
            flowProcess.doBack(flow, targetNode, params, currentUser);

            return "回退成功";
        }
    }

    return "回退失败";
})();

示例4:回退并发送通知

(function(){
    var doc = getCurrentDocument();
    var docId = doc.getId();
    var targetNodeId = "目标节点ID";
    var flowProcess = getFlowProcess();
    var flow = flowProcess.doViewByDocument(doc);

    if(flow != null){
        var targetNode = flow.getNodeById(targetNodeId);

        if(targetNode != null){
            // 执行回退
            var params = createParamsTable();
            params.setParameter("_attitude", "流程回退");
            flowProcess.doBack(flow, targetNode, params, getWebUser());

            // 获取目标节点的审批人
            var flowStateSql = "select domainid,id ";
            flowStateSql += "from t_flowstatert ";
            flowStateSql += "where docid = '"+docId+"'";
            var flowState = findBySQL(flowStateSql);

            if(flowState != null){
                var flowStateId = flowState.getId();

                var actorSql = "select domainid,actor_id ";
                actorSql += "from t_actor ";
                actorSql += "where flowstatert_id = '"+flowStateId+"' ";
                actorSql += "and node_id = '"+targetNodeId+"' ";
                actorSql += "and state = 0";

                var actors = queryBySQL(actorSql);
                if(actors != null && actors.size() > 0){
                    for(var it = actors.iterator(); it.hasNext(); ){
                        var actor = it.next();
                        var actorId = actor.getItemValueAsString("actor_id");
                        sendMessage(actorId, "流程已回退到您的节点,请重新处理");
                    }
                }
            }

            return "回退成功,已发送通知";
        }
    }

    return "回退失败";
})();

示例5:回退到第一个节点

(function(){
    var doc = getCurrentDocument();
    var flowProcess = getFlowProcess();
    var flow = flowProcess.doViewByDocument(doc);

    if(flow != null){
        var nodes = flow.getNodes();

        if(nodes != null && nodes.size() > 0){
            // 获取第一个节点
            var firstNode = nodes.get(0);

            var params = createParamsTable();
            params.setParameter("_attitude", "回退到第一个节点");
            flowProcess.doBack(flow, firstNode, params, getWebUser());

            return "回退到第一个节点成功";
        }
    }

    return "回退失败";
})();

关键函数说明

  • getFlowProcess(): 获取流程处理对象
  • flowProcess.doViewByDocument(doc): 根据文档获取流程对象
  • flow.getCurrentNode(): 获取当前节点对象
  • flow.getNodeById(nodeId): 根据节点ID获取节点对象
  • flow.getNodes(): 获取所有节点列表
  • flowProcess.doBack(flow, node, params, user): 回退到指定节点
  • 参数1: 流程对象
  • 参数2: 目标节点对象
  • 参数3: 参数表
  • 参数4: 用户对象

流程回退说明

  • 流程回退: 将流程从当前节点回退到之前的某个节点
  • 用途: 用于需要重新审批、修正错误、补充材料等场景
  • 特点: 流程会回到目标节点,目标节点的审批人需要重新处理

系统表说明

  • t_flowstatert: 流程状态运行时表,存储流程的运行时状态
  • t_actor: 流程执行人表,存储当前待处理的执行人信息
  • t_actorhis: 流程执行人历史表,存储审批历史记录

注意事项

  • ⚠️ 目标节点: 需要确保目标节点ID正确且存在
  • ⚠️ 回退原因: 建议设置回退原因,便于追溯
  • ⚠️ 权限控制: 流程回退需要相应权限,建议添加权限验证
  • ⚠️ 流程状态: 回退操作会改变流程状态,需要谨慎使用
  • ⚠️ 审批历史: 建议更新审批历史,记录回退原因
  • 回退操作不可恢复,建议先确认再执行
  • 建议记录回退日志,便于追溯
  • 不同版本的API可能有所不同

使用场景

  • 需要重新审批
  • 修正错误
  • 补充材料
  • 流程纠正
  • 管理员干预

如需查看完整脚本代码,请访问源文档链接。