欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

十六、模块集成流程审批

程序员文章站 2022-06-28 19:04:39
ERP系统中流程审批是必需的模块,流程审批需要工作流的支持,工作流实现企业业务流程重组(BPR)与系统解耦合,工作流产品有很多,国内的工作流产品比较适合国内项目的业务,国外开源的工作流更接近于标准WfMC,对国内复杂的业务支持不够灵活。通常情况软件公司都会开放适合自己的工作流模块,以适应项目开发。我们开发流程审批也是使用自己开发的流程引擎,流程的定义工具现在没有提供,需要手工配置XML流程模块。......

ERP系统中流程审批是必需的模块,流程审批需要工作流的支持,工作流实现企业业务流程重组(BPR)与系统解耦合,工作流产品有很多,国内的工作流产品比较适合国内项目的业务,国外开源的工作流更接近于标准WfMC,对国内复杂的业务支持不够灵活。通常情况软件公司都会开放适合自己的工作流模块,以适应项目开发。我们开发流程审批也是使用自己开发的流程引擎,流程的定义工具现在没有提供,需要手工配置XML流程模块。

工作流引擎关键接口

启动流程
startWorkflow(processId,startUserId,nextUser.getId(),instanceid,type,
						title,nexttask,url,hmap,flag,testMode);
提交流程
wapi.submitWorkflow(instprocessid,instactivityid,instworkitemid,userIdLst,instanceid,
						type,title,nexttask,url,hmap,flag,testMode);
获取代办列表
getWorkitemList(user.getId(), testMode);
										

工作流模板

<?xml version="1.0" encoding="gb2312"?>
<!--
注意:
流程触发外部接口,其类加载器必须位于工作流引擎类加载器平级或者更高一级
-->
<process id="testwf" name="请款流程" description="">
	<status id="Start" name="开始" type="synchronized" isstart="true">
		<tostatuses>
			<tostatus batchid="tomanager" id="account" name="财务审批" condition="false" invoke="com.gf.statusflow.TestInvokeApp" invokecommand="sendmail"/>
		</tostatuses>
		<actors>
		</actors>
	</status>
	<status id="draft" name="修改" type="synchronized" isstart="false">
		<tostatuses>
			<tostatus batchid="tomanager" id="account" name="财务审批" condition="false" invoke="" invokecommand=""/>
			<tostatus batchid="destory" id="destory" name="作废" condition="false" invoke="com.gf.statusflow.TestInvokeApp" invokecommand="orderdestory"/>
		</tostatuses>
		<actors>
			<actor type="variable" id="starter"/>
		</actors>
	</status>
	<status id="account" name="财务审批" type="asynchronized" isstart="false">
		<tostatuses>
			<tostatus batchid="vp" id="vp" name="副总审批" condition="false" invoke="com.gf.statusflow.TestInvokeApp" invokecommand="orderdestory"/>
			<tostatus batchid="destory" id="destory" name="作废" condition="false" invoke="com.gf.statusflow.TestInvokeApp" invokecommand="orderdestory"/>
			<tostatus batchid="tostarter" id="draft" name="返回修改" condition="false" invoke="" invokecommand=""/>
		</tostatuses>
		<actors>
			<actor type="user" id="fiadmin"/>
		</actors>
	</status>
	<status id="vp" name="副总审批" type="asynchronized" isstart="false">
		<tostatuses>
			<tostatus batchid="tonotice" id="notice" name="通知申请人" condition="false" invoke="" invokecommand=""/>
			<tostatus batchid="tostarter" id="draft" name="返回修改" condition="false" invoke="" invokecommand=""/>
			<tostatus batchid="destory" id="destory" name="作废" condition="false" invoke="com.gf.statusflow.TestInvokeApp" invokecommand="orderdestory"/>
		</tostatuses>
		<actors>
			<actor type="user" id="sysadmin"/>
		</actors>
	</status>
	<status id="notice" name="通知申请人" type="asynchronized" isstart="false" workflow="outstore" condition="storeName EQ '发货库A(运达)'">
		<tostatuses>
			<tostatus batchid="end" id="end" name="完成" condition="false" invoke="com.gf.statusflow.TestInvokeApp" invokecommand="outstore"/>
			<tostatus batchid="destory" id="destory" name="作废" condition="false" invoke="com.gf.statusflow.TestInvokeApp" invokecommand="outstoredestory"/>
		</tostatuses>
		<actors>
			<actor type="variable" id="starter"/>
		</actors>
	</status>
	<status id="destory" name="作废" type="synchronized" isstart="false">
		<tostatuses>
		</tostatuses>
		<actors>
		</actors>
	</status>
	<status id="end" name="结束" type="synchronized" isstart="false">
		<tostatuses>
		</tostatuses>
		<actors>
		</actors>
	</status>
</process>

模块实体类

package com.gf.model;

import java.io.Serializable;
import java.math.BigDecimal;

import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;

@TableName("gf_expense")
public class ExpenseInfo implements Serializable{
	@TableId
	private String id = null;
	private String name = null;
	private String company = null;
	private String bank = null;
	private String bankAccount = null;
	private BigDecimal amount = null;
	private String userId = null;
	@TableField(exist=false)
	private String userName = null;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getCompany() {
		return company;
	}
	public void setCompany(String company) {
		this.company = company;
	}
	public String getBank() {
		return bank;
	}
	public void setBank(String bank) {
		this.bank = bank;
	}
	public String getBankAccount() {
		return bankAccount;
	}
	public void setBankAccount(String bankAccount) {
		this.bankAccount = bankAccount;
	}
	public BigDecimal getAmount() {
		return amount;
	}
	public void setAmount(BigDecimal amount) {
		this.amount = amount;
	}
	public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}	
}

SQL

create table gf_expense(id varchar(32),
	name varchar(100),
	company varchar(100),
	bank varchar(100),
	bankaccount varchar(100),
	amount decimal(10,2),
	userId varchar(100)
);

使用Mybatis-Plus操作数据

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
	PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gf.mapper.ExpenseMapper">

</mapper>

package com.gf.mapper;

import org.apache.ibatis.annotations.Mapper;

import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.gf.model.ExpenseInfo;

@Mapper
public interface ExpenseMapper extends BaseMapper<ExpenseInfo>{

}


package com.gf.service;

import com.baomidou.mybatisplus.service.IService;
import com.gf.model.ExpenseInfo;

public interface ExpenseService extends IService<ExpenseInfo>{

}


package com.gf.service.impl;

import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.gf.mapper.ExpenseMapper;
import com.gf.model.ExpenseInfo;
import com.gf.service.ExpenseService;

@Service
public class ExpenseServiceImpl extends ServiceImpl<ExpenseMapper,ExpenseInfo>
	implements ExpenseService
{

}

模块Controller集成工作流引擎

package com.gf.ctrl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.gf.model.ExpenseInfo;
import com.gf.service.ExpenseService;
import com.gf.statusflow.IOrgModel;
import com.gf.statusflow.IUser;
import com.gf.statusflow.StatusFlowData;
import com.gf.statusflow.StatusFlowMng;
import com.gf.statusflow.StatusFlowWAPI;
import com.gf.statusflow.StatusMsg;
import com.gf.statusflow.UUID;
import com.gf.statusflow.Util;

@Controller
public class ExpenseCtrl {
	@Autowired
	private StatusFlowMng sfmng;
	@Autowired
	private StatusFlowWAPI wapi;
	@Autowired
	private IOrgModel orgmodel;
	@Autowired
	private ExpenseService expserv;

	@RequestMapping("/expense.action")
	public String expense(HttpServletRequest req)
	{
		String instanceid = req.getParameter("instanceid");
		String instprocessid = req.getParameter("instprocessid");
		String instactivityid = req.getParameter("instactivityid");
		String instworkitemid = req.getParameter("instworkitemid");
		StatusMsg wfMsg = null;
		String nexttask = null;
		List<Properties> nextBtnList = null;
		List<Properties> nextActList = null;
		IUser loginUser = Util.getLoginUser();
		String userId = loginUser.getId();
		String processId = "testwf";
		HashMap hmap = null;
		StatusFlowData wfdata = sfmng.getWorkflowData(userId, processId, nexttask, instworkitemid,hmap);
		nextBtnList = wfdata.getNextBtnList();
		nextActList = wfdata.getNextActList();
		req.setAttribute("button", nextBtnList);
		if(instanceid != null)
		{
			ExpenseInfo eps = expserv.selectById(instanceid);
			req.setAttribute("eps", eps);
			req.setAttribute("instprocessid", instprocessid);
			req.setAttribute("instactivityid", instactivityid);
			req.setAttribute("instworkitemid", instworkitemid);
		}
		System.out.println("nextActList==="+nextActList);
		return "/fi/expense";
	}
	
	@RequestMapping("/expsubmit.action")
	@ResponseBody
	public StatusMsg expsave(HttpServletRequest req,ExpenseInfo exps)
	{
		try
		{
			String instanceid = exps.getId();
			if("".equals(Util.fmtStr(instanceid)))
				instanceid = UUID.create("expense");
			String instprocessid = req.getParameter("instprocessid");
			String instactivityid = req.getParameter("instactivityid");
			String instworkitemid = req.getParameter("instworkitemid");
			String nexttask = req.getParameter("nexttask");
			String nextUserId = req.getParameter("nextUserId");
			
			IUser loginUser = Util.getLoginUser();
			String startUserId = loginUser.getId();
			String processId = "testwf";
			String type = "expense";
			IUser nextUser = orgmodel.getUserByLoginId(nextUserId);
			String title = exps.getName()+":"+exps.getAmount().toString();
			String url = "/expense.action";
			HashMap hmap = new HashMap();
			String flag = "gf";
			String testMode = "no";
			exps.setId(instanceid);
			StatusMsg wfMsg = null;
			if("".equals(Util.fmtStr(instworkitemid)))
			{
				expserv.insert(exps);
				System.out.println("nexttask==="+nexttask);
				wfMsg = wapi.startWorkflow(processId,startUserId,nextUser.getId(),instanceid,type,
						title,nexttask,url,hmap,flag,testMode);
			}
			else
			{
				List<String> userIdLst = new ArrayList<String>();
				if(nextUser != null)
					userIdLst.add(nextUser.getId());
				expserv.updateById(exps);
				wfMsg = wapi.submitWorkflow(instprocessid,instactivityid,instworkitemid,userIdLst,instanceid,
						type,title,nexttask,url,hmap,flag,testMode);
			}
			return wfMsg;
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
	}
}

JSP页面工作流集成

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<script type="text/javascript" src="/static/easyui/jquery.min.js"></script>
<script type="text/javascript" src="/static/easyui/jquery.easyui.min.js"></script>
<script type="text/javascript" src="/static/easyui/easyui-lang-zh_CN.js"></script>
<link rel="stylesheet" href="/static/easyui/themes/default/easyui.css"/>
<link rel="stylesheet" href="/static/easyui/themes/icon.css"/>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>财务报销系统</title>
<script>
function wfsubmit(nexttask,nextuserid)
{
	var rtn = $('#frm').form('validate');
	if(!rtn)
		return;
	var nextUserId = '';
	if('end' != nexttask && 'endall' != nexttask && 'destory' != nexttask)
	{
		if(nextuserid == null || nextuserid == '')
		{
			$.messager.alert('错误提示','下一办理人为空!','error');
			return;
		}

		var objdim = nextuserid.split(";");
		for(var k=0;k<objdim.length;k++)
		{
			var objdim2 = objdim[k].split(",");
			if(objdim2[0] == null || objdim2[0] == '')
			{
				$.messager.alert('错误提示','下一办理人为空!','error');
				return;
			}
			nextUserId = objdim2[0];
		}
	}
	var rtn = $('#frm').form('validate');
	if(rtn)
	{
		$('#nexttask').val(nexttask);
		$('#nextUserId').val(nextUserId);
		$('#frm').form('submit', {    
		    url:'/expsubmit.action',    
		    onSubmit: function(){    
	  
		    },    
		    success:function(data){
		    	//alert(data);
		    	$('#buttondiv').empty();
		    }
		});
	}
}
	
</script>
</head>
<body class="easyui-layout">
    <div data-options="region:'center',title:'部门维护'" style="padding:5px;">
    	<div>
    		<img height="100" width="800" src="/downimg.jsp?isorderwf=true&width=600&height=100&processid=testwf&instanceid=${eps.id}&t=<%=new Date()%>"/>
    	</div>
		<form id="frm" method="post">
			<input type="hidden" id="instprocessid" name="instprocessid" value="${instprocessid}"/>
			<input type="hidden" id="instactivityid" name="instactivityid" value="${instactivityid}"/>
			<input type="hidden" id="instworkitemid" name="instworkitemid" value="${instworkitemid}"/>
			<input type="hidden" id="id" name="id" value="${eps.id}"/>
			<input type="hidden" id="nexttask" name="nexttask"/>
			<input type="hidden" id="nextUserId" name="nextUserId"/>
			<input type="hidden" id="userId" name="userId" value="${eps.userId}"/>
		    <div style="margin-left:50px;margin-top:30px">   
		        <input class="easyui-textbox" type="text" id="name" name="name" value="${eps.name}" data-options="width:300,label:'请款名称:'" />   
		    </div>   
		    <div style="margin-left:50px;margin-top:30px"> 
		        <input class="easyui-textbox" type="text" id="company" name="company" value="${eps.company}" data-options="width:300,label:'公司名称:'" />   
		    </div>
		    <div style="margin-left:50px;margin-top:30px"> 
		        <input class="easyui-textbox" type="text" id="bank" name="bank" value="${eps.bank}" data-options="width:300,label:'银行名称:'" />   
		    </div>
		    <div style="margin-left:50px;margin-top:30px"> 
		        <input class="easyui-textbox" type="text" id="bankAccount" name="bankAccount" value="${eps.bankAccount}" data-options="width:300,label:'银行账号:'" />   
		    </div>
		    <div style="margin-left:50px;margin-top:30px"> 
		        <input class="easyui-textbox" type="text" id="amount" name="amount" value="${eps.amount}" data-options="width:300,label:'金额(单位:分):'" />   
		    </div>
  		    <div id="buttondiv" style="margin-left:50px;margin-top:30px">
<%
			List<Properties> button = (List<Properties>)request.getAttribute("button");
			for(Properties prop:button)
			{
				String name = prop.getProperty("name");
				String js = prop.getProperty("js");
%>
				<a id="btn" onclick="<%=js %>" class="easyui-linkbutton"><%=name %></a>
<%
			}
%>  
		    </div>
		</form>
    </div>
</body>
</html>

本文地址:https://blog.csdn.net/qixiang_chen/article/details/85981407