流程回退¶
本文档内容来源于 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可能有所不同
使用场景¶
- 需要重新审批
- 修正错误
- 补充材料
- 流程纠正
- 管理员干预
如需查看完整脚本代码,请访问源文档链接。