需求
流程绘制
一、配置流程
在流程工具类ActUtils.java中配置(添加)流程信息
二、在前台leaveList页面添加使用流程的触发事件(提交按钮)
三、编写代码【本文仅针对流程(提交事件),其他功能此处不做详细说明】
1、触发事件(启动流程)
(1)业务的controller
/* 发起流程: 提交按钮的触发事件 */
@RequiresPermissions("flow:leave:start")
@RequestMapping(value = "start")
public String start(String ids, RedirectAttributes redirectAttributes)
throws Exception {
String idArray[] = ids.split(",");
for (String id : idArray) {
leaveService.start(leaveService.get(id));
}
addMessage(redirectAttributes, "提交请假申请成功");
return "redirect:" + Global.getAdminPath() + "/flow/leave/?repage";
}
(2)业务的service
public void start(Leave leave) {
leave.preUpdate();
Map<String,Object> vars = Maps.newHashMap();
System.out.println(UserUtils.getRoleList());
vars.put("user0",UserUtils.getUser().getLoginName()); //重新调整的发起人
for (int i = 0; i < UserUtils.getRoleList().size(); i++) {
if(UserUtils.getRoleList().get(i).getId().contains("c7de52dc20ea43ccafea3db315197c52")){
//部门领导
leave.setState("2"); // 改变状态:改为公司领导审批
vars.put("roleType","leader");
}else{
leave.setState("1"); // 改变状态:改为部门领导审批
//普通员工
vars.put("roleType","staff"); //不同环节的流程
vars.put("user1",userDao.searchLeader(leave.getOfficeBy().getId(),leave.getCompanyBy().getId(),"depar"
+ "tment").getLoginName()); //部门领导
}
}
dao.update(leave);
vars.put("user2",userDao.searchLeader(leave.getCompanyBy().getId(),leave.getCompanyBy().getId(),"administration").getLoginName());//公司领导
Taskuser taskuser=new Taskuser();//任务分配
taskuser.setTaskindex("leave");// 任务分配中的 标识名
List<Taskuser> list=taskuserService.findList(taskuser);
for(Taskuser taskusers:list){
vars.put(taskusers.getTaskver(),taskusers.getExauser().getLoginName());
}
//开启流程
actTaskService.startProcess(ActUtils.PD_Leave[0],ActUtils.PD_Leave[1],leave.getId(),UserUtils.getUser().getName()+"|"+UserUtils.getUser().getOffice(),vars);
}
(3)流程的Service(jeeplus框架自带)
2、审核环节(需要注意的是流程开启后每个环节都要带上流程信息)
(1)前台界面(需要注意的已用截图标注)
①:流程信息的携带
②流程详情的回显
③不同环节的提示(四的实操中可看具体效果)
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ include file="/webpage/include/taglib.jsp"%>
<html>
<head>
<title>审核界面</title>
<meta name="decorator" content="default" />
<script type="text/javascript" src="${ctxStatic}/webuploader-0.1.5/imageupload.js.jsp"></script>
<script type="text/javascript">
var validateForm;
function doSubmit() {//回调函数,在编辑和保存动作时,供openDialog调用提交表单。
if (validateForm.form()) {
$("#inputForm").submit();
return true;
}
return false;
}
$(document).ready(
function() {
$("#text1").html(tohtml($("#haltreason").val()));
$("#text2").html(tohtml($("#auditopinion").val()));
$("#text3").html(tohtml($("#ratifyopinion").val()));
$("#text4").html(tohtml($("#remarks").val()));
function tohtml(text) {
var img = "";
if (text == "") {
return null;
} else {
if (text.indexOf("|") == -1) {
return "<p> "
+ text + "</p>";
} else if (text.split('|')[0] == "同意") {
img = "<img src=\"../../../userfiles/1/images/同意.png\" style=\"height:45px;width:120px;margin-top:-63px;filter:alpha(opacity=60);-moz-opacity:0.6;-khtml-opacity:0.6;opacity:0.6;\">"
return "<p> "
+ text.split('|')[1]
+ "</p><p style=\"text-align:right;\">"
+ text.split('|')[2]
+ " <br/>"
+ text.split('|')[3]
+ "<br/>"
+ img + "</p>";
} else if (text.split('|')[0] == "不同意") {
img = "<img src=\"../../../userfiles/1/images/不同意.png\" style=\"height:45px;width:80px;margin-right:18px;margin-top:-63px;filter:alpha(opacity=60);-moz-opacity:0.6;-khtml-opacity:0.6;opacity:0.6;\">"
return "<p> "
+ text.split('|')[1]
+ "</p><p style=\"text-align:right;\">"
+ text.split('|')[2]
+ " <br/>"
+ text.split('|')[3]
+ "<br/>"
+ img + "</p>";
}
}
}
var Max = [ $("#text1").height(), $("#text2").height() ];
for (var i = 1; i < Max.length; i++) {
if (Max[i] > Max[0]) {
Max[0] = Max[i];
}
}
$("#text1").height(Max[0]);
$("#text2").height(Max[0]);
$("#text3").height(Max[0]);
$("#text4").height(Max[0]);
validateForm = $("#inputForm").validate(
{
submitHandler : function(form) {
loading('正在提交,请稍等...');
form.submit();
},
errorContainer : "#messageBox",
errorPlacement : function(error, element) {
$("#messageBox").text("输入有误,请先更正。");
if (element.is(":checkbox")
|| element.is(":radio")
|| element.parent().is(
".input-append")) {
error.appendTo(element.parent()
.parent());
} else {
error.insertAfter(element);
}
}
});
});
</script>
</head>
<body class="gray-bg">
<form:form id="inputForm" modelAttribute="leave"
action="${ctx}/flow/leave/saveAudit" method="post"
class="form-horizontal">
<form:hidden path="id" />
<form:hidden path="act.taskId" />
<form:hidden path="act.taskName" />
<form:hidden path="act.taskDefKey" />
<form:hidden path="act.procInsId" />
<form:hidden path="act.procDefId" />
<sys:message content="${message}" />
<div class="row">
<div class="col-sm-9">
<div class="wrapper wrapper-content animated fadeInUp">
<div class="ibox">
<div class="ibox-content">
<div class="row">
<div class="col-sm-12">
<div class="m-b-md">
<dd style="text-align:center;">
<span><h2>请假申请</h2></span>
</dd>
</div>
</div>
</div>
<div class="row m-t-sm">
<div class="col-sm-12">
<div class="panel blank-panel">
<div class="panel-body">
<div class="tab-content">
<div class="tab-pane active" id="tab-1">
<table
class="table table-bordered table-condensed dataTables-example dataTable no-footer">
<tbody>
<tr>
<td class="width-15 active"><label class="pull-right">开始时间:</label></td>
<td class="width-35">
<input id="startTime" name="startTime" type="text" maxlength="20" class="laydate-icon form-control layer-date "
value="<fmt:formatDate value="${leave.startTime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/>
</td>
<td class="width-15 active"><label class="pull-right">截止时间:</label></td>
<td class="width-35">
<input id="endTime" name="endTime" type="text" maxlength="20" class="laydate-icon form-control layer-date "
value="<fmt:formatDate value="${leave.endTime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/>
</td>
</tr>
<tr>
<td class="width-15 active"><label class="pull-right">天数:</label></td>
<td class="width-35">
<form:input path="Days" htmlEscape="false" class="form-control "/>
</td>
<td class="width-15 active"><label class="pull-right">事由:</label></td>
<td class="width-35">
<form:input path="Reason" htmlEscape="false" class="form-control "/>
</td>
</tr>
</tbody>
</table>
<act:histoicFlow procInsId="${leave.act.procInsId}" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-3">
<div class="wrapper wrapper-content project-manager">
<c:choose>
<c:when test="${leave.act.taskDefKey eq 'testtask-0' }">
<h4>调整结果</h4>
<div class="col-sm-12">
<input id="flag1" name="act.flag" type="radio" class="i-checks required" value="yes" checked/><label>重新申请</label> <input id="flag2" name="act.flag" type="radio" class="i-checks required" value="no"/><label>放弃申请</label>
</div>
<h4>备注</h4>
</c:when>
<c:otherwise>
<h4>审批结果</h4>
<div class="col-sm-12">
<input id="flag1" name="act.flag" type="radio" class="i-checks required" value="yes" checked/><label>同意</label> <input id="flag2" name="act.flag" type="radio" class="i-checks required" value="no"/><label>不同意</label>
</div>
<h4>您的意见</h4>
</c:otherwise>
</c:choose>
<div class="col-sm-12">
<form:textarea path="act.comment" class="required" rows="5" maxlength="255" cssClass="form-control "/><br/>
<input id="btnSubmit" class="btn btn-primary" type="submit" value="提交" />
<button class="btn btn-default" data-toggle="tooltip" data-placement="left" type="button" onclick="history.go(-1)" title="返回">返回</button>
</div>
</div>
</div>
</div>
</form:form>
</body>
</html>
(2)业务代码
①controller
@RequestMapping(value = "saveAudit")
public String saveAudit(Leave leave,Model model) throws Exception {
if("testtask-0".equals(leave.getAct().getTaskDefKey())){
}else{
if ("no".equals(leave.getAct().getFlag()) && StringUtils.isBlank(leave.getAct().getComment())){
addMessage(model, "请填写审核意见。");
return form(leave, model);
}
}
leaveService.saveAudit(leave);
return "redirect:" + adminPath + "/act/task/todo/";
}
②Service
//保存审批
public void saveAudit(Leave leave){
if(StringUtils.isBlank(leave.getId())){
}
// 设置意见
leave.getAct().setComment(("yes".equals(leave.getAct().getFlag())?"同意| ":"不同意| ")+leave.getAct().getComment());
leave.preUpdate();
// 对不同环节的业务逻辑进行操作
String taskDefKey = leave.getAct().getTaskDefKey();
//获取当前任务编号
String taskId = leave.getAct().getTaskId();
//获取当前流程实例
String procInsId = leave.getAct().getProcInsId();
//获取态度
String flag = leave.getAct().getFlag();
//获取意见
String comment = leave.getAct().getComment();
// 审核环节testtask-1:部门经理 testtask-2:公司领导
if ("testtask-1".equals(taskDefKey)){
if("yes".equals(flag)){
leave.setState("2"); //部门经理审核
}else{
//不同意
leave.setState("5");
}
}else if("testtask-2".equals(taskDefKey)){
if("yes".equals(flag)){
leave.setState("4"); //公司领导审核
}else{
//不同意
leave.setState("5");
}
}else if("testtask-0".equals(taskDefKey)){
if("yes".equals(flag)){
//发起人的调整
for (int i = 0; i < UserUtils.getRoleList().size(); i++) {
if(UserUtils.getRoleList().get(i).getId().contains("c7de52dc20ea43ccafea3db315197c52")){
//部门领导
leave.setState("2"); // 改变状态:改为公司领导审批
}else{
leave.setState("1"); // 改变状态:改为部门领导审批
}
}
}else{
//放弃调整
leave.setState("3");
}
}
dao.update(leave);
// 提交流程任务
Map<String, Object> vars = Maps.newHashMap();
vars.put("pass", "yes".equals(leave.getAct().getFlag())? "1" : "0");
actTaskService.complete(taskId, procInsId, comment, vars);
}
3、form表单:可进行增、改、看操作
(1)前台页面【同样包含了流程信息的携带与回显】
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ include file="/webpage/include/taglib.jsp"%>
<html>
<head>
<title>请假表单</title>
<meta name="decorator" content="default"/>
<script type="text/javascript">
var validateForm;
function doSubmit(){//回调函数,在编辑和保存动作时,供openDialog调用提交表单。
if(validateForm.form()){
$("#inputForm").submit();
return true;
}
return false;
}
$(document).ready(function() {
validateForm = $("#inputForm").validate({
submitHandler: function(form){
loading('正在提交,请稍等...');
form.submit();
},
errorContainer: "#messageBox",
errorPlacement: function(error, element) {
$("#messageBox").text("输入有误,请先更正。");
if (element.is(":checkbox")||element.is(":radio")||element.parent().is(".input-append")){
error.appendTo(element.parent().parent());
} else {
error.insertAfter(element);
}
}
});
laydate({
elem: '#startTime' ,type: 'datetime', //目标元素。由于laydate.js封装了一个轻量级的选择器引擎,因此elem还允许你传入class、tag但必须按照这种方式 '#id .class'
event: 'focus' //响应事件。如果没有传入event,则按照默认的click
});
laydate({
elem: '#endTime' ,type: 'datetime', //目标元素。由于laydate.js封装了一个轻量级的选择器引擎,因此elem还允许你传入class、tag但必须按照这种方式 '#id .class'
type:'datetime',
event: 'focus' //响应事件。如果没有传入event,则按照默认的click
});
});
</script>
</head>
<body class="hideScroll">
<form:form id="inputForm" modelAttribute="leave" action="${ctx}/flow/leave/save" method="post" class="form-horizontal">
<form:hidden path="id"/>
<form:hidden path="act.taskId"/>
<form:hidden path="act.taskName"/>
<form:hidden path="act.taskDefKey"/>
<form:hidden path="act.procInsId"/>
<form:hidden path="act.procDefId"/>
<sys:message content="${message}"/>
<table class="table table-bordered table-condensed dataTables-example dataTable no-footer">
<tbody>
<tr>
<%-- <td class="width-15 active"><label class="pull-right">备注信息:</label></td>
<td class="width-35">
<form:textarea path="remarks" htmlEscape="false" rows="4" class="form-control "/>
</td> --%>
<td class="width-15 active"><label class="pull-right">开始时间:</label></td>
<td class="width-35">
<input id="startTime" name="startTime" type="text" maxlength="20" class="laydate-icon form-control layer-date "
value="<fmt:formatDate value="${leave.startTime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/>
</td>
<td class="width-15 active"><label class="pull-right">截止时间:</label></td>
<td class="width-35">
<input id="endTime" name="endTime" type="text" maxlength="20" class="laydate-icon form-control layer-date "
value="<fmt:formatDate value="${leave.endTime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/>
</td>
</tr>
<tr>
<td class="width-15 active"><label class="pull-right">天数:</label></td>
<td class="width-35">
<form:input path="Days" htmlEscape="false" class="form-control "/>
</td>
<td class="width-15 active"><label class="pull-right">事由:</label></td>
<td class="width-35">
<form:input path="Reason" htmlEscape="false" class="form-control "/>
</td>
</tr>
</tbody>
</table>
<c:if test="${not empty leave.processInstanceId }">
<act:histoicFlow procInsId="${leave.processInstanceId}"/>
</c:if>
</form:form>
</body>
</html>
(2)后台:根据不同的业务需求调整不同的页面
/**
* 查看,增加,编辑请假表单页面
*/
@RequiresPermissions(value={"flow:leave:view","flow:leave:add","flow:leave:edit"},logical=Logical.OR)
@RequestMapping(value = "form")
public String form(Leave leave, Model model) {
String view = "leaveForm"; //新增or修改
// 查看审批清单
if (StringUtils.isNotBlank(leave.getId())) {
String taskDefKey = leave.getAct().getTaskDefKey();// 环节编号
if ("testtask-1".equals(taskDefKey)) {
if (("1").equals(leave.getState())) {//状态等于1,等待部门领导审核
view = "leaveAudit";
} else {
view = "leaveView"; //不是审核环节,查看详情即可
}
}else if ("testtask-2".equals(taskDefKey)) {// 审核环节2【总领导审批】
if (("2").equals(leave.getState())) {//状态等于2,等待公司领导审核
view = "leaveAudit";
} else {
view = "leaveView";
}
}else if ("testtask-0".equals(taskDefKey)) {// 发起人重新调整
if (("5").equals(leave.getState())) {//状态等于5,等待重新提交
view = "leaveAudit";
} else {
view = "leaveView";
}
}
}
model.addAttribute("leave", leave);
return "modules/flow/" + view;
}
四、实操看效果
以普通职员为例(售前1号)
1、提交申请
2、提交后开启流程
3、部门领导审核:售前经理
①售前经理可在自己的待办任务中进行任务办理操作
②审核结果:此处选择不同意
4、发起人调整申请
①看到自己的申请未通过
②去待办任务中进行任务办理操作
③调整申请:重新申请
5、部门领导审核:同意申请,进入下一环节
6、公司领导申请:也是在待办任务中进行任务办理操作,同意申请,进行下一环节
7、流程完毕,发起人可看到流程已通过
五、补充
一些标签是框架自己的东西,如下图,可直接按住ctrl+具体标签,点进去查看具体的内容
1、提交按钮
包含但不限于对于提交的验证
2、流程信息的回显
对应的是具体的界面绘制