EKP其它/超级审批

1、说明

某天接到领导的一个需求,让某个用户拥有超级审批权限,当该用户执行超级审批时,同一节点的其它审批人将默认通过。例如某会签节点中,张三、李四、王五均是审批人,若此时李四和王五尚未审批通过,且张三有超级审批的权限,则可以直接让李四和王五默认通过,从而达到快速通过审批节省时间的目的。

2、编写service

总体思路:①获取所需审批节点的所有有权限审批的人员id列表  ②调用ekp自带的审批接口逐一对节点进行审批

package com.landray.kmss.xp.lbpm.workflow.service;

import java.util.List;

/**
 * @author liquid
 */
public interface IXpLbpmService {
    /**
     * 当前节点审批通过(针对当前登录人)
     * @author liquid
     * @date 2022年6月28日
     * @param fdModelId 流程实例id(km_review_main.fd_id)
     * @param factNodeId 流程id(N2\N3\N4...)
     */
    void passProcess(String fdModelId, String factNodeId);

    /**
     * 获取节点实际处理人(有权限处理)id列表
     * @param fdModelId 流程实例id(km_review_main.fd_id)
     * @param factNodeId 流程id(N2\N3\N4...)
     */
    List<String> getActualHandlesByFactNodeId(String fdModelId, String factNodeId) throws Exception;

    /**
     * 超级审批
     * @author liquid
     * @date 2022年6月28日
     * @param fdModelId 流程实例id(km_review_main.fd_id)
     * @param factNodeId 流程id(N2\N3\N4...)
     * @return 审批结果(fail、success)
     */
    String superPassProcess(String fdModelId, String factNodeId, String handleId, String approveContent, String nextFactNodeId) throws Exception;
}
package com.landray.kmss.xp.lbpm.workflow.service.spring;

import com.alibaba.fastjson.JSONObject;
import com.landray.kmss.km.review.model.KmReviewMain;
import com.landray.kmss.km.review.webservice.IKmReviewWebserviceService;
import com.landray.kmss.km.review.webservice.KmReviewParamterForm;
import com.landray.kmss.sys.lbpm.engine.api.NodeInstanceHolder;
import com.landray.kmss.sys.lbpm.engine.api.ProcessHolder;
import com.landray.kmss.sys.lbpm.engine.api.WorkitemHolder;
import com.landray.kmss.sys.lbpm.engine.integrate.expecterlog.ILbpmExpecterLogService;
import com.landray.kmss.sys.lbpm.engine.persistence.model.LbpmProcess;
import com.landray.kmss.sys.lbpmservice.api.ApproveParameter;
import com.landray.kmss.sys.lbpmservice.api.LbpmService;
import com.landray.kmss.sys.lbpmservice.operation.handler.HandlerPassData;
import com.landray.kmss.sys.lbpmservice.support.service.ILbpmProcessService;
import com.landray.kmss.sys.lbpmservice.support.service.spring.LbpmAPIService;
import com.landray.kmss.sys.lbpmservice.support.service.spring.LbpmProcessServiceImp;
import com.landray.kmss.sys.organization.model.SysOrgElement;
import com.landray.kmss.util.SpringBeanUtil;
import com.landray.kmss.util.UserUtil;
import com.landray.kmss.xp.app.km.review.util.XpReviewUtil;
import com.landray.kmss.xp.lbpm.workflow.service.IXpLbpmService;
import com.landray.kmss.xp.org.organizational.constant.XpSysOrgElementConstant;
import com.landray.kmss.xp.org.organizational.util.XpOrgUtil;

import java.util.List;
import java.util.Map;

/**
 * @author liquid
 */
public class XpLbpmServiceImp implements IXpLbpmService {
    private ILbpmProcessService lbpmProcessService;
    private ILbpmExpecterLogService lbpmExpecterLogService;
    private LbpmService lbpmApiService;
    private IKmReviewWebserviceService kmReviewWebserviceService;

    public ILbpmProcessService getLbpmProcessService() {
        if (lbpmProcessService == null) {
            lbpmProcessService = (LbpmProcessServiceImp)SpringBeanUtil.getBean("lbpmProcessServiceTarget");
        }
        return lbpmProcessService;
    }

    public ILbpmExpecterLogService getLbpmExpecterLogService() {
        if (lbpmExpecterLogService == null) {
            lbpmExpecterLogService = (ILbpmExpecterLogService)SpringBeanUtil.getBean("lbpmExpecterLogService");
        }
        return lbpmExpecterLogService;
    }

    public LbpmService getLbpmApiService() {
        if (lbpmApiService == null) {
            lbpmApiService = (LbpmAPIService)SpringBeanUtil.getBean("lbpmServiceTarget");
        }
        return lbpmApiService;
    }

    public IKmReviewWebserviceService getKmReviewWebserviceService() {
        if (kmReviewWebserviceService == null) {
            kmReviewWebserviceService = (IKmReviewWebserviceService)SpringBeanUtil.getBean("kmReviewWebserviceServiceTarget");
        }
        return kmReviewWebserviceService;
    }

    /**
     * 当前节点审批通过(针对当前登录人)
     * @author liquid
     * @date 2022年6月28日
     * @param fdModelId 流程实例id(km_review_main.fd_id)
     * @param factNodeId 流程id(N2\N3\N4...)
     */
    @Override
    public void passProcess(String fdModelId, String factNodeId) {
        // 获取【主文档实例】
        KmReviewMain mainModel = (KmReviewMain) XpReviewUtil.getReviewMainModelById(fdModelId);

        // 获取【主文档实例对应的流程信息】
        LbpmService lbpmApiService = getLbpmApiService();
        ProcessHolder processHolder = lbpmApiService.load(mainModel);

        // 流程当前节点信息列表
        List<? extends NodeInstanceHolder> nodeInstHolders = processHolder.getCurrentNodeInfos();
        for (NodeInstanceHolder nodeInstHolder : nodeInstHolders) {
            // 非目标节点 → 跳过
            String thisFactNodeId = nodeInstHolder.getNodeInstance().getFdFactNodeId();
            if (!thisFactNodeId.equalsIgnoreCase(factNodeId)) {
                continue;
            }

            // 当前登录人此节点的全部事项
            List<? extends WorkitemHolder> workitemHolders = nodeInstHolder.getHandlerWrokitemInfos();
            for (WorkitemHolder workitemHolder : workitemHolders) {
                // 创建[通过]操作数据,此处就需要去参考[通过]操作的扩展描述
                HandlerPassData data = new HandlerPassData();

                // 驱动流程的操作参数,此处第二个参数参考[通过]操作的扩展描述
                ApproveParameter parameter = new ApproveParameter(workitemHolder, "handler_pass");
                parameter.setData(data);
                // 设置后续处理人的通知方式
                parameter.setNotifyType("todo;email");
                // 设置流程结束时通知当前处理人
                parameter.setNotifyOnFinish(true);
                // 设置审批意见
                parameter.setAuditNote(UserUtil.getUser().getFdName() + ": 执行超级审批");

                // 驱动流程...
                lbpmApiService.approveProcess(mainModel, parameter);
            }
        }
    }

    /**
     * 获取节点实际处理人(有权限处理)id列表
     * @param fdModelId 流程实例id(km_review_main.fd_id)
     * @param factNodeId 流程id(N2\N3\N4...)
     * @throws Exception 异常
     */
    @Override
    public List<String> getActualHandlesByFactNodeId(String fdModelId, String factNodeId) throws Exception {
        /* 获取实际处理人列表 */
        ILbpmExpecterLogService lbpmExpecterLogService = getLbpmExpecterLogService();
        Map<String, List<String>> nodeHandlersMap = lbpmExpecterLogService.findCurrentNodeIdHandlerIds(fdModelId);
        return nodeHandlersMap.get(factNodeId);
    }

    /**
     * 超级审批
     * @author liquid
     * @date 2022年6月28日
     * @param fdModelId 流程实例id(km_review_main.fd_id)
     * @param factNodeId 流程id(N2\N3\N4...)
     * @return 审批结果(fail、success)
     * @throws Exception 异常
     */
    @Override
    public String superPassProcess(String fdModelId, String factNodeId, String handleId, String approveContent, String nextFactNodeId) throws Exception {
        ILbpmProcessService lbpmProcessService = getLbpmProcessService();
        IKmReviewWebserviceService kmReviewWebserviceService = getKmReviewWebserviceService();

        /* 获取主文档实例 */
        KmReviewMain mainModel = (KmReviewMain) XpReviewUtil.getReviewMainModelById(fdModelId);

        /* 获取流程实例 */
        LbpmProcess process = (LbpmProcess) lbpmProcessService.findByPrimaryKey(fdModelId);

        /* 设置审批参数 */
        KmReviewParamterForm kmParamForm = new KmReviewParamterForm();
        // 流程模板id
        kmParamForm.setFdTemplateId(mainModel.getFdTemplate().getFdId());
        // 流程起草人
        JSONObject docCreator = new JSONObject();
        docCreator.put("Id", process.getFdCreator().getFdId());
        kmParamForm.setDocCreator(docCreator.toJSONString());
        // 流程实例id
        kmParamForm.setFdId(fdModelId);
        // 流程主题
        kmParamForm.setDocSubject(mainModel.getDocSubject());
        // 富文本(如果流程存在富文本内容,则不允许为空)
        kmParamForm.setDocContent("");
        JSONObject flowParam = new JSONObject();
        // 设置处理人
        SysOrgElement actualHandler = XpOrgUtil.getSysOrgElementById(handleId, SysOrgElement.class);
        // 如处理人是非人员类型(如岗位), 需获取岗位人员(多个取第一个)
        if (!actualHandler.getFdOrgType().equals(XpSysOrgElementConstant.ORG_TYPE_PERSON)) {
            handleId = ((SysOrgElement)actualHandler.getFdPersons().get(0)).getFdId();
        }
        JSONObject handler = new JSONObject();
        handler.put("Id", handleId);
        flowParam.put("handler", handler.toJSONString());
        // 操作类型(审批)
        flowParam.put("operationType", "handler_pass");
        // 审批意见
        flowParam.put("auditNote", approveContent);
        // 流向下一节点的ID,需要人工决策时设置此参数
        flowParam.put("futureNodeId", nextFactNodeId);
        kmParamForm.setFlowParam(flowParam.toJSONString());

        /* 执行超级审批 */
        try {
            // 多个处理人操作同一份文档时采用锁机制,必须等上一个处理人操作完成后才能操作下一个
            System.out.println("超级审批(参数): " + JSONObject.toJSONString(kmParamForm));
            kmReviewWebserviceService.approveProcess(kmParamForm);
        } catch (Exception e) {
            e.printStackTrace();
            return "fail";
        }

        return "success";
    }
}

相关xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <bean
            id="xpLbpmTarget"
            class="com.landray.kmss.xp.lbpm.workflow.service.spring.XpLbpmServiceImp">
    </bean>
</beans>

3、编写action

package com.landray.kmss.xp.app.km.review.actions;

import com.alibaba.fastjson.JSONObject;
import com.landray.kmss.common.actions.ExtendAction;
import com.landray.kmss.common.service.IBaseService;
import com.landray.kmss.sys.formula.provider.function.OrgFunction;
import com.landray.kmss.util.SpringBeanUtil;
import com.landray.kmss.util.StringUtil;
import com.landray.kmss.util.UserUtil;
import com.landray.kmss.web.action.ActionForm;
import com.landray.kmss.web.action.ActionForward;
import com.landray.kmss.web.action.ActionMapping;
import com.landray.kmss.xp.lbpm.workflow.service.IXpLbpmService;
import com.landray.kmss.xp.util.XpRequestUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

import static com.landray.kmss.tic.core.common.actions.TicCoreInvokeFuncAction.ReadAsChars;

/**
 * @author liquid
 */
public class XpReviewMainAction extends ExtendAction {
    private IXpLbpmService xpLbpmService;

    @Override
    protected IBaseService getServiceImp(HttpServletRequest request) {
        return null;
    }

    public IXpLbpmService getXpLbpmService() {
        if (xpLbpmService == null) {
            xpLbpmService = (IXpLbpmService)SpringBeanUtil.getBean("xpLbpmTarget");
        }
        return xpLbpmService;
    }

    /**
     * @apiNote 当前节点实际审批人(有审批权限)列表
     * @author liquid
     * @date 2022年6月28日
     * 传入参数-
     * modelId 流程模板实例id(km_review_main.fd_id,前端lbpm.modelId)
     * factNodeId 流程节点id(N1\N2\N3...)
     * 返回参数-
     * handles 审批人id列表
     */
    public ActionForward getActualHandlesByFactNodeId(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        JSONObject result = new JSONObject();
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        String bodyStr = ReadAsChars(request);
        JSONObject o = JSONObject.parseObject(bodyStr);

        /* 获取body参数 */
        String fdModelId = o.getString("modelId");
        String factNodeId = o.getString("factNodeId");
        // 参数校验
        if (StringUtil.isNull(fdModelId) || StringUtil.isNull(factNodeId)) {
            XpRequestUtil.setFailure(response, "调用失败:请检查参数[名]和[值]");
            return null;
        }

        /* 业务逻辑 */
        IXpLbpmService xpLbpmService = getXpLbpmService();
        List<String> handles = xpLbpmService.getActualHandlesByFactNodeId(fdModelId, factNodeId);

        /* 响应数据 */
        result.put("status", XpRequestUtil.STATUS_SUCCESS);
        result.put("code", XpRequestUtil.CODE_SUCCESS);
        result.put("msg", "调用成功");
        result.put("handles", handles == null ? new ArrayList<>() : handles);
        XpRequestUtil.setResponseResult(response, result);

        return null;
    }

    /**
     * @apiNote 当前节点审批通过(针对当前登录人)
     * @author liquid
     * @date 2022年6月28日
     * 传入参数-
     * modelId 流程模板实例id(km_review_main.fd_id,前端lbpm.modelId)
     * factNodeId 流程节点id(N1\N2\N3...)
     * 返回参数-
     * approveInfo 审批通过信息
     */
    public ActionForward approveProcessByFactNodeId(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        JSONObject result = new JSONObject();
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        String bodyStr = ReadAsChars(request);
        JSONObject o = JSONObject.parseObject(bodyStr);

        /* 获取body参数 */
        String fdModelId = o.getString("modelId");
        String factNodeId = o.getString("factNodeId");

        /* 业务逻辑 */
        IXpLbpmService xpLbpmService = getXpLbpmService();
        xpLbpmService.passProcess(fdModelId, factNodeId);

        /* 响应数据 */
        result.put("status", XpRequestUtil.STATUS_SUCCESS);
        result.put("code", XpRequestUtil.CODE_SUCCESS);
        result.put("msg", "调用成功");
        result.put("approveInfo", "审批成功");
        XpRequestUtil.setResponseResult(response, result);

        return null;
    }

    /**
     * @apiNote 超级审批(一次仅审批一个处理人)
     * @author liquid
     * @date 2022年6月29日
     * 传入参数-
     * modelId 流程模板实例id(km_review_main.fd_id,前端lbpm.modelId)
     * factNodeId 流程节点id(N1\N2\N3...)
     * handleId 处理人id
     * approveContent (可选)审批意见,默认值为:(特权人)特权人姓名 : 超级审批
     * nextFactNodeId (可选)当下流为人工决策时,需传入(N1\N2\N3...)
     * 返回参数-
     * approveInfo 审批通过信息
     * approveStatus 审批结果(fail、success、noPermission:无权限)
     */
    public ActionForward superApproveProcessByFactNodeId(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        JSONObject result = new JSONObject();
        response.setHeader("Content-Type", "application/json;charset=utf-8");
        String bodyStr = ReadAsChars(request);
        JSONObject o = JSONObject.parseObject(bodyStr);

        /* 获取body参数 */
        String fdModelId = o.getString("modelId");
        String factNodeId = o.getString("factNodeId");
        String handleId = o.getString("handleId");
        String approveContent = o.getString("approveContent");
        String nextFactNodeId = o.getString("nextFactNodeId");
        // 参数校验
        if (StringUtil.isNull(fdModelId) || StringUtil.isNull(factNodeId) || StringUtil.isNull(handleId)) {
            result.put("status", XpRequestUtil.STATUS_ERROR);
            result.put("code", XpRequestUtil.CODE_ERROR);
            result.put("msg", "调用失败:请检查参数[名]和[值]");
            result.put("approveInfo", "审批失败");
            XpRequestUtil.setResponseResult(response, result);
            return null;
        }
        // 设置可选参数默认值
        approveContent = StringUtil.isNull(approveContent) ? "超级审批" : approveContent;
        approveContent = "(特权人)"+ UserUtil.getUser().getFdName() + " : " + approveContent;
        nextFactNodeId = StringUtil.isNull(approveContent) ? "" : nextFactNodeId;

        /* 业务逻辑 */
        // 1、校验调用者权限
        boolean isPrivileged = OrgFunction.chechPersonInGroup(UserUtil.getUser(), "超级审批");
        if (!isPrivileged) {
            /* 响应数据 - 成功 - 无审批权限 */
            result.put("status", XpRequestUtil.STATUS_SUCCESS);
            result.put("code", XpRequestUtil.CODE_SUCCESS);
            result.put("msg", "调用失败:当前登录人没有超级审批权限");
            result.put("approveInfo", "审批失败");
            result.put("approveStatus", "noPermission");
            XpRequestUtil.setResponseResult(response, result);
            return null;
        }
        // 2、执行超级审批
        IXpLbpmService xpLbpmService = getXpLbpmService();
        String approveStatus;
        try{
            approveStatus = xpLbpmService.superPassProcess(fdModelId, factNodeId, handleId, approveContent, nextFactNodeId);
        } catch (Exception e) {
            e.printStackTrace();
            /* 响应数据 - 失败 */
            result.put("status", XpRequestUtil.STATUS_ERROR);
            result.put("code", XpRequestUtil.CODE_ERROR);
            result.put("msg", "调用失败:请检查参数[名]和[值]");
            result.put("approveInfo", "审批失败");
            result.put("approveStatus", "fail");
            XpRequestUtil.setResponseResult(response, result);
            return null;
        }

        /* 响应数据 - 成功 */
        result.put("status", XpRequestUtil.STATUS_SUCCESS);
        result.put("code", XpRequestUtil.CODE_SUCCESS);
        result.put("msg", "调用成功");
        result.put("approveInfo", "success".equals(approveStatus) ? "审批成功" : "审批失败");
        result.put("approveStatus", approveStatus);
        XpRequestUtil.setResponseResult(response, result);

        return null;
    }
}

相关xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean
            class="com.landray.kmss.xp.app.km.review.actions.XpReviewMainAction"
            name="/xp/app/km/review/actions/XpReviewMainAction.do"
            lazy-init="true"
            parent="KmssBaseAction">
    </bean>
</beans>

4、前端调用

/**
 * 超级审批
 * 注意:仅适用于[非编辑状态]的审批节点
 * 审批权限:群组 → 系统类 → 超级审批
 * 2022年7月2日22:21:04 测试通过
 * 2022年7月3日17:37:43 测试通过
 * @author liquid
 * @date 2022年7月2日
 * @param {string}[factNodeId=当前节点] 节点id(N1\N2\N3...)
 * @param {string}[approveContent] 审批意见
 * @param {string}[nextFactNodeId] 当下流为人工决策时,需传入(N1\N2\N3...)
 */
let superApprovalCountLimit = 15;// 审批失败尝试次数上限(避免未知错误导致不断循环执行审批调用)
let superApprovalCount = 0;
function superApprove(factNodeId, approveContent, nextFactNodeId) {
	factNodeId = factNodeId || lbpm.nowNodeId;
	lui_loading(true, "<div style='text-align:center;width:100%;color:#6584ed'>正在执行超级审批...</div>");
	// 延迟执行超级审批,避免同步执行导致阻塞loading的显示
	setTimeout(()=>{
		__superApprove();
	}, 200);

	function __superApprove() {
		superApprovalCount ++;
		// (同步)获取节点实际审批人id
		let handlers;
		const _path_1 = "xp/app/km/review/actions/XpReviewMainAction.do?method=getActualHandlesByFactNodeId";
		const _data_1 = {
			modelId: lbpm.modelId,
			factNodeId: factNodeId,
		}
		ajaxAction(_path_1, _data_1, false, {
			success:(res)=>{
				if (res.status !== "success") { errorHandler(res); return; }
				handlers =  res.handles;
			}
		})
		// 可能在点击超级审批的前一刻,最后一个审批人刚好审批完
		if (handlers.length === 0) {
			lui_loading(false);
			lui_fail("当前节点无审批人!");
			setTimeout(()=>{
				location.reload();
			}, 200)
			return;
		}

		// (同步)执行超级审批
		let isReturn = false;
		for (const handlerId of handlers) {
			if (isReturn) return;
			const _path_2 = "xp/app/km/review/actions/XpReviewMainAction.do?method=superApproveProcessByFactNodeId";
			const _data_2 = {
				modelId: lbpm.modelId,
				factNodeId: factNodeId,
				handleId: handlerId,
				approveContent: approveContent,
				nextFactNodeId: nextFactNodeId
			}
			ajaxAction(_path_2, _data_2, false, {
				success:(res)=>{
					if (res.status !== "success") {
						errorHandler(res, false);
						lui_loading(false);
						return;
					}
					// 成功回调
					console.log("超级审批返回:", res);
					// 无权限
					if (res.approveStatus === 'noPermission'){
						lui_loading(false);
						lui_fail("抱歉,您尚无超级审批权限!");
						isReturn = true;
					}
					// 有权限,审批失败(同时操作同一个文档导致)
					else if (res.approveStatus === "fail" && superApprovalCount <= superApprovalCountLimit) {
						console.log("审批失败,重新调用superApproval(),已调用次数:" + superApprovalCount);
						// 失败递归调用
						__superApprove(factNodeId);
						isReturn = true;
					}
					else if (superApprovalCount > superApprovalCountLimit) {
						console.log("审批失败,重新调用superApproval(),已达调用次数上限:" + superApprovalCount);
						lui_loading(false);
						lui_fail("超级审批:未知错误,请联系管理员");
						isReturn = true;
					}
				}
			})
		}

		lui_loading(false);
		lui_success("超级审批:执行完毕!");
		// 延迟刷新页面(以保证获取到最的流程状态信息)
		setTimeout(()=>{
			location.reload();
		}, 500)
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liquid-Li

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值