文章目录
安装activiti插件
设计工作流
部署工作流(导入Bpmn文件)
Bpmn文件(demo.bpmn)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1578711271300" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="allowance" isClosed="false" isExecutable="true" name="补贴申请" processType="None">
<startEvent id="begin" name="开始"></startEvent>
<userTask activiti:assignee="#{username}" activiti:exclusive="true" id="selfVerify" name="申请人办理">
</userTask>
<endEvent id="end" name="结束"/>
<sequenceFlow id="_5" name="发起申请" sourceRef="begin" targetRef="selfVerify"/>
<userTask activiti:exclusive="true" id="leaderVerify" name="主管审核">
<extensionElements>
<activiti:taskListener event="create" class="com.yangzc.studentboot.workflow.allowance.listener.MyTaskListener">
</activiti:taskListener>
</extensionElements>
</userTask>
<sequenceFlow id="_8" name="提交" sourceRef="selfVerify" targetRef="leaderVerify">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='提交'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_9" name="同意" sourceRef="leaderVerify" targetRef="end">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_6" name="放弃" sourceRef="selfVerify" targetRef="end">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='撤回'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_10" name="不同意" sourceRef="leaderVerify" targetRef="selfVerify">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="allowance">
<bpmndi:BPMNShape bpmnElement="begin" id="Shape-begin">
<omgdc:Bounds height="32.0" width="32.0" x="215.0" y="30.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="selfVerify" id="Shape-selfVerify">
<omgdc:Bounds height="55.0" width="85.0" x="190.0" y="155.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="end" id="Shape-end">
<omgdc:Bounds height="32.0" width="32.0" x="215.0" y="415.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="leaderVerify" id="Shape-leaderVerify">
<omgdc:Bounds height="55.0" width="85.0" x="190.0" y="290.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_5" id="BPMNEdge__5" sourceElement="_2" targetElement="_3">
<omgdi:waypoint x="231.0" y="62.0"/>
<omgdi:waypoint x="231.0" y="155.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6" id="BPMNEdge__6" sourceElement="_3" targetElement="_4">
<omgdi:waypoint x="190.0" y="182.5"/>
<omgdi:waypoint x="125.0" y="305.0"/>
<omgdi:waypoint x="215.0" y="431.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_3" targetElement="_7">
<omgdi:waypoint x="232.5" y="210.0"/>
<omgdi:waypoint x="232.5" y="290.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_7" targetElement="_4">
<omgdi:waypoint x="231.0" y="345.0"/>
<omgdi:waypoint x="231.0" y="415.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_7" targetElement="_3">
<omgdi:waypoint x="275.0" y="317.5"/>
<omgdi:waypoint x="345.0" y="250.0"/>
<omgdi:waypoint x="275.0" y="182.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
依赖配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.yangzc</groupId>
<artifactId>studentboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>studentboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<mysql.version>5.1.41</mysql.version>
<!--Activiti 启动器版本-->
<activiti.starter.version>6.0.0</activiti.starter.version>
<pagehelper.boot.version>1.2.5</pagehelper.boot.version>
</properties>
<dependencies>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!--druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<!--commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<!-- 文件上传工具类 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!-- shiro ehcache -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
</exclusion>
</exclusions>
<version>1.4.0</version>
</dependency>
<!-- ehchache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<!-- 添加redis支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!-- shiro-redis -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>${activiti.starter.version}</version>
</dependency>
<!-- yml解析器 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<!-- pagehelper 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper.boot.version}</version>
</dependency>
<!--activiti modeler 5.22 start-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>6.0.0</version>
<exclusions>
<exclusion>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- xml解析依赖-->
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-codec</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-css</artifactId>
<version> 1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-svg-dom</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-svggen</artifactId>
<version>1.7</version>
</dependency>
<!-- xml解析依赖-->
<!--activiti modeler 5.22 end-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
<dependencies>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
配置SpringBoot(application.yml)
server:
session-timeout: 1800
# tomcat:
# max-threads: 1000
# min-spare-threads: 30
port: 8080
# uri-encoding: utf-8
#security:
# basic:
# enabled: false
spring:
thymeleaf:
mode: LEGACYHTML5
cache: false
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
profiles:
active: dev
servlet:
multipart:
max-file-size: 30MB
max-request-size: 30MB
devtools:
restart:
enabled: true
cache:
type: redis
# ehcache:
# config: classpath:config/ehcache.xml
# RuoYi-Process 模块
# 解决启动报错:class path resource [processes/] cannot be resolved to URL because it does not exist
activiti:
check-process-definitions: false
# 检测身份信息表是否存在
db-identity-used: true
mybatis:
configuration:
map-underscore-to-camel-case: true
mapper-locations: mybatis/**/*Mapper.xml
typeAliasesPackage: com.yangzc.studentboot.**.domain
#[弃用]配置缓存和session存储方式,默认ehcache,可选redis,[弃用]调整至 spring cache type【shiro.用户,权限,session,spring.cache通用】
#[弃用]cacheType: ehcache
工作流部署接口
package com.yangzc.studentboot.workflow.definition.controller;
import com.yangzc.studentboot.common.annotation.Log;
import com.yangzc.studentboot.common.config.Global;
import com.yangzc.studentboot.common.config.Constant;
import com.yangzc.studentboot.common.controller.BaseController;
import com.yangzc.studentboot.common.domain.AjaxResult;
import com.yangzc.studentboot.common.domain.TableDataInfo;
import com.yangzc.studentboot.common.utils.StringUtils;
import com.yangzc.studentboot.common.utils.FileUploadUtils;
import com.yangzc.studentboot.common.utils.ExcelUtil;
import com.yangzc.studentboot.workflow.definition.domain.ProcessDefinition;
import com.yangzc.studentboot.workflow.definition.service.ProcessDefinitionService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@Controller
@RequestMapping("/workflow/definition")
public class ProcessDefinitionController extends BaseController {
private static final Logger log = LoggerFactory.getLogger(ProcessDefinitionController.class);
private String prefix = "workflow/definition";
@Autowired
private ProcessDefinitionService processDefinitionService;
@RequiresPermissions("workflow:definition:list")
@GetMapping("/list")
public String processDefinition() {
return prefix + "/definition";
}
@PostMapping("/data")
@RequiresPermissions("workflow:definition:list")
@ResponseBody
public TableDataInfo list(ProcessDefinition processDefinition) {
List<ProcessDefinition> list = processDefinitionService.listProcessDefinition(processDefinition);
return getDataTable(list);
}
/**
* 部署流程定义
*/
@RequiresPermissions("workflow:definition:list")
@Log("流程定义导入")
@PostMapping("/upload")
@ResponseBody
public AjaxResult upload(@RequestParam("processDefinition") MultipartFile file) {
try {
if (!file.isEmpty()) {
String extensionName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.') + 1);
if (!"bpmn".equalsIgnoreCase(extensionName)
&& !"zip".equalsIgnoreCase(extensionName)
&& !"bar".equalsIgnoreCase(extensionName)) {
return error("流程定义文件仅支持 bpmn, zip 和 bar 格式!");
}
// p.s. 此时 FileUploadUtils.upload() 返回字符串 fileName 前缀为 Constants.RESOURCE_PREFIX,需剔除
// 详见: FileUploadUtils.getPathFileName(...)
String fileName = FileUploadUtils.upload(Global.getProfile() + "/processDefiniton", file);
if (StringUtils.isNotBlank(fileName)) {
String realFilePath = Global.getProfile() + fileName.substring(Constant.RESOURCE_PREFIX.length());
processDefinitionService.deployProcessDefinition(realFilePath);
return success();
}
}
return error("不允许上传空文件!");
}
catch (Exception e) {
log.error("上传流程定义文件失败!", e);
return error(e.getMessage());
}
}
@RequiresPermissions("workflow:definition:list")
@Log("流程定义删除")
@PostMapping("/remove")
@ResponseBody
public AjaxResult remove(String ids) {
try {
return toAjax(processDefinitionService.deleteProcessDeploymentByIds(ids));
}
catch (Exception e) {
return error(e.getMessage());
}
}
@Log("流程定义导出")
@RequiresPermissions("workflow:definition:list")
@PostMapping("/export")
@ResponseBody
public AjaxResult export() {
List<ProcessDefinition> list = processDefinitionService.listProcessDefinition(new ProcessDefinition());
ExcelUtil<ProcessDefinition> util = new ExcelUtil<>(ProcessDefinition.class);
return util.exportExcel(list, "流程定义数据");
}
}
工作流部署页面
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<th:block th:include="include :: header" />
<th:block th:include="include :: jasny-bootstrap-css" />
<th:block th:include="include :: bootstrap-fileinput-css" />
</head>
<body class="gray-bg">
<div class="container-div">
<div class="row">
<div class="col-sm-12 search-collapse">
<form id="formId">
<div class="select-list">
<ul>
<li>
<p>流程KEY:</p>
<input type="text" name="key"/>
</li>
<li>
<p>名称:</p>
<input type="text" name="name"/>
</li>
<li>
<p>所属分类:</p>
<input type="text" name="category"/>
</li>
<!--<li class="select-time">
<label>部署时间: </label>
<input type="text" class="time-input" id="startTime" placeholder="开始时间" name="params[beginTime]"/>
<span>-</span>
<input type="text" class="time-input" id="endTime" placeholder="结束时间" name="params[endTime]"/>
</li>-->
<li>
<a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i> 搜索</a>
<a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i> 重置</a>
</li>
</ul>
</div>
</form>
</div>
<div class="btn-group-sm" id="toolbar" role="group">
<div id="processDefinitionDiv" class="fileinput fileinput-new" data-provides="fileinput" style="margin-bottom: 0; margin-right: -3px;">
<span class="btn btn-success btn-file" style="font-size: 12px;">
<span><i class="fa fa-upload"></i> 部署流程定义</span>
<input type="file" name="processDefinition" multiple>
</span>
<span class="fileinput-filename"></span>
<a href="#" class="close fileinput-exists" data-dismiss="fileinput" style="float: none">×</a>
</div>
<a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="workflow:definition:list">
<i class="fa fa-remove"></i> 删除
</a>
<a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="workflow:definition:list">
<i class="fa fa-download"></i> 导出
</a>
</div>
<div class="col-sm-12 select-table table-striped">
<table id="bootstrap-table"></table>
</div>
</div>
</div>
<div th:include="include :: footer"></div>
<th:block th:include="include :: jasny-bootstrap-js" />
<th:block th:include="include :: bootstrap-fileinput-js" />
<script th:inline="javascript">
var editFlag = [[${@permission.hasPermi('workflow:definition:list')}]];
var removeFlag = [[${@permission.hasPermi('workflow:definition:list')}]];
var prefix = ctx + "workflow/definition";
$(function() {
var options = {
url: prefix + "/data",
removeUrl: prefix + "/remove",
exportUrl: prefix + "/export",
modalName: "流程定义",
uniqueId: "deploymentId",
columns: [{
checkbox: true
},
{
field : 'id',
title : '流程ID'
},
{
field : 'key',
title : '流程KEY'
},
{
field : 'name',
title : '流程名称'
},
{
field : 'version',
title : '版本'
},
{
field : 'description',
title : '流程描述'
},
{
field : 'category',
title : '所属分类'
},
{
field : 'deploymentTime',
title : '部署时间'
},
{
title: '操作',
align: 'center',
formatter: function(value, row, index) {
var actions = [];
actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" οnclick="$.operate.remove(\'' + row.deploymentId + '\')"><i class="fa fa-remove"></i> 删除</a>');
return actions.join('');
}
}]
};
$.table.init(options);
initProcessDefinitionFileInput();
});
function initProcessDefinitionFileInput() {
$('#processDefinitionDiv').on('change.bs.fileinput', function (e) {
// 处理自己的业务
var formdata = new FormData();
formdata.append("processDefinition", $('input[type=file]')[0].files[0]);
$.ajax({
url: prefix + '/upload',
data: formdata,
type: "post",
processData: false,
contentType: false,
success: function(result) {
$('#processDefinitionDiv').fileinput('reset'); // 重置
$.operate.ajaxSuccess(result);
}
})
});
}
</script>
</body>
</html>
工作流管理接口
package com.yangzc.studentboot.workflow.allowance.controller;
import com.yangzc.studentboot.common.annotation.Log;
import com.yangzc.studentboot.common.controller.BaseController;
import com.yangzc.studentboot.common.domain.AjaxResult;
import com.yangzc.studentboot.common.domain.TableDataInfo;
import com.yangzc.studentboot.common.utils.StringUtils;
import com.yangzc.studentboot.common.utils.ExcelUtil;
import com.yangzc.studentboot.common.utils.ShiroUtils;
import com.yangzc.studentboot.workflow.allowance.domain.BizAllowanceVo;
import com.yangzc.studentboot.workflow.allowance.service.BizAllowanceService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: yangzc
* @Description:
* @Date: Created on 16:45 2020/1/11
* @Modified By:
*/
@Controller
@RequestMapping("/workflow/allowance")
public class BizAllowanceController extends BaseController {
private String prefix = "workflow/allowance";
@Autowired
private BizAllowanceService bizAllowanceService;
@Autowired
private TaskService taskService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private IdentityService identityService;
@RequiresPermissions("workflow:allowance:apply:list")
@GetMapping("/apply/list")
public String allowance(ModelMap mmap) {
mmap.put("currentUser", ShiroUtils.getUser());
return prefix + "/allowance";
}
/**
* 查询补贴申请列表
*/
@RequiresPermissions("workflow:allowance:apply:list")
@PostMapping("/data")
@ResponseBody
public TableDataInfo list(BizAllowanceVo bizAllowance) {
if (!ShiroUtils.getUser().getUsername().equals("admin")) {
bizAllowance.setCreateBy(ShiroUtils.getUser().getUsername());
}
startPage();
List<BizAllowanceVo> list = bizAllowanceService.selectBizAllowanceList(bizAllowance);
return getDataTable(list);
}
/**
* 导出补贴申请列表
*/
@RequiresPermissions("process:allowance:export")
@PostMapping("/export")
@ResponseBody
public AjaxResult export(BizAllowanceVo bizAllowance) {
List<BizAllowanceVo> list = bizAllowanceService.selectBizAllowanceList(bizAllowance);
ExcelUtil<BizAllowanceVo> util = new ExcelUtil<BizAllowanceVo>(BizAllowanceVo.class);
return util.exportExcel(list, "allowance");
}
/**
* 新增补贴申请
*/
@GetMapping("/add")
public String add() {
return prefix + "/add";
}
/**
* 新增保存补贴申请
*/
@RequiresPermissions("workflow:allowance:apply:add")
@Log("补贴申请")
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(BizAllowanceVo bizAllowance) {
Long userId = ShiroUtils.getUserId();
if (ShiroUtils.getUser().getUsername().equals("admin")) {
return error("提交申请失败:不允许管理员提交申请!");
}
return toAjax(bizAllowanceService.insertBizAllowance(bizAllowance));
}
/**
* 修改补贴申请
*/
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") Long id, ModelMap mmap) {
BizAllowanceVo bizAllowance = bizAllowanceService.selectBizAllowanceById(id);
mmap.put("bizAllowance", bizAllowance);
return prefix + "/edit";
}
/**
* 修改保存补贴申请
*/
@RequiresPermissions("process:allowance:edit")
@Log("补贴申请修改")
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(BizAllowanceVo bizAllowance) {
return toAjax(bizAllowanceService.updateBizAllowance(bizAllowance));
}
/**
* 删除补贴申请
*/
@RequiresPermissions("process:allowance:remove")
@Log("补贴申请删除")
@PostMapping( "/remove")
@ResponseBody
public AjaxResult remove(String ids) {
return toAjax(bizAllowanceService.deleteBizAllowanceByIds(ids));
}
/**
* 提交申请
*/
@Log("补贴申请提交")
@PostMapping( "/submitApply")
@ResponseBody
public AjaxResult submitApply(Long id) {
BizAllowanceVo allowance = bizAllowanceService.selectBizAllowanceById(id);
String applyUserId = ShiroUtils.getUser().getUsername();
bizAllowanceService.submitApply(allowance, applyUserId);
return success();
}
@RequiresPermissions("workflow:allowance:task:list")
@GetMapping("/task/list")
public String todoView() {
return prefix + "/allowanceToDo";
}
/**
* 我的待办列表
* @param bizAllowance
* @return
*/
@RequiresPermissions("workflow:allowance:task:list")
@PostMapping("/task/data")
@ResponseBody
public TableDataInfo taskList(BizAllowanceVo bizAllowance) {
startPage();
List<BizAllowanceVo> list = bizAllowanceService.findTodoTasks(bizAllowance, ShiroUtils.getUser().getUsername());
return getDataTable(list);
}
/**
* 加载审批弹窗
* @param taskId
* @param mmap
* @return
*/
@GetMapping("/showVerifyDialog/{taskId}")
public String showVerifyDialog(@PathVariable("taskId") String taskId, ModelMap mmap) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
String processInstanceId = task.getProcessInstanceId();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
BizAllowanceVo bizAllowance = bizAllowanceService.selectBizAllowanceById(new Long(processInstance.getBusinessKey()));
mmap.put("bizAllowance", bizAllowance);
mmap.put("taskId", taskId);
String verifyName = task.getTaskDefinitionKey().substring(0, 1).toUpperCase() + task.getTaskDefinitionKey().substring(1);
return prefix + "/task" + verifyName;
}
/**
* 完成任务
*
* @return
*/
@RequestMapping(value = "/complete/{taskId}", method = {RequestMethod.POST, RequestMethod.GET})
@ResponseBody
public AjaxResult complete(@PathVariable("taskId") String taskId, @RequestParam(value = "saveEntity", required = false) String saveEntity,
@ModelAttribute("preloadAllowance") BizAllowanceVo allowance, HttpServletRequest request) {
boolean saveEntityBoolean = BooleanUtils.toBoolean(saveEntity);
Map<String, Object> variables = new HashMap<String, Object>();
Enumeration<String> parameterNames = request.getParameterNames();
String comment = null; // 批注
try {
while (parameterNames.hasMoreElements()) {
String parameterName = (String) parameterNames.nextElement();
if (parameterName.startsWith("p_")) {
// 参数结构:p_B_name,p为参数的前缀,B为类型,name为属性名称
String[] parameter = parameterName.split("_");
if (parameter.length == 3) {
String paramValue = request.getParameter(parameterName);
Object value = paramValue;
if (parameter[1].equals("B")) {
value = BooleanUtils.toBoolean(paramValue);
} else if (parameter[1].equals("DT")) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
value = sdf.parse(paramValue);
} else if (parameter[1].equals("COM")) {
comment = paramValue;
} else if (parameter[1].equals("STR")) {
value = paramValue;
}
variables.put(parameter[2], value);
} else {
throw new RuntimeException("invalid parameter for activiti variable: " + parameterName);
}
}
}
if (StringUtils.isNotEmpty(comment)) {
identityService.setAuthenticatedUserId(ShiroUtils.getUser().getUsername());
taskService.addComment(taskId, allowance.getInstanceId(), comment);
}
bizAllowanceService.complete(allowance, saveEntityBoolean, taskId, variables);
return success("任务已完成");
} catch (Exception e) {
//logger.error("error on complete task {}, variables={}", new Object[]{taskId, variables, e});
return error("完成任务失败");
}
}
/**
* 自动绑定页面字段
*/
@ModelAttribute("preloadAllowance")
public BizAllowanceVo getAllowance(@RequestParam(value = "id", required = false) Long id, HttpSession session) {
if (id != null) {
return bizAllowanceService.selectBizAllowanceById(id);
}
return new BizAllowanceVo();
}
@RequiresPermissions("workflow:allowance:done:list")
@GetMapping("/done/list")
public String doneView() {
return prefix + "/allowanceDone";
}
/**
* 我的已办列表
* @param bizAllowance
* @return
*/
@RequiresPermissions("workflow:allowance:done:list")
@PostMapping("/done/data")
@ResponseBody
public TableDataInfo taskDoneList(BizAllowanceVo bizAllowance) {
startPage();
List<BizAllowanceVo> list = bizAllowanceService.findDoneTasks(bizAllowance, ShiroUtils.getUser().getUsername());
return getDataTable(list);
}
}
申请单列表页面
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<th:block th:include="include :: header" />
<th:block th:include="include :: select2-css" />
</head>
<body class="gray-bg">
<div class="container-div">
<div class="row">
<div class="col-sm-12 search-collapse">
<form id="formId">
<div class="select-list">
<ul>
<li>
<p>标题:</p>
<input type="text" name="title"/>
</li>
<li class="select-time">
<p>申请时间:</p>
<input type="text" class="time-input" id="startTime" placeholder="开始时间" name="params[beginTime]"/>
<span>-</span>
<input type="text" class="time-input" id="endTime" placeholder="结束时间" name="params[endTime]"/>
</li>
<li>
<p>流程实例ID:</p>
<input type="text" name="instanceId"/>
</li>
<li>
<a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i> 搜索</a>
<a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i> 重置</a>
</li>
</ul>
</div>
</form>
</div>
<div class="btn-group-sm" id="toolbar" role="group">
<a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="workflow:allowance:apply:add">
<i class="fa fa-plus"></i> 添加
</a>
<!--<a class="btn btn-warning" οnclick="$.table.exportExcel()" shiro:hasPermission="process:allowance:export">
<i class="fa fa-download"></i> 导出
</a>-->
</div>
<div class="col-sm-12 select-table table-striped">
<table id="bootstrap-table"></table>
</div>
</div>
</div>
<th:block th:include="include :: footer" />
<th:block th:include="include :: select2-js" />
<script th:inline="javascript">
var editFlag = [[${@permission.hasPermi('workflow:allowance:edit')}]];
var removeFlag = [[${@permission.hasPermi('workflow:allowance:remove')}]];
var prefix = ctx + "workflow/allowance";
var currentUser = [[${currentUser}]];
console.log("==============" + currentUser.username);
$(function() {
var options = {
url: prefix + "/data",
createUrl: prefix + "/add",
updateUrl: prefix + "/edit/{id}",
removeUrl: prefix + "/remove",
exportUrl: prefix + "/export",
detailUrl: prefix + "/edit/{id}",
sortName: "applyTime",
sortOrder: "desc",
modalName: "补贴申请",
columns: [{
checkbox: true
},
{
field : 'id',
title : '主键ID',
visible: false
},
{
field : 'title',
title : '标题'
},
{
field : 'reason',
title : '原因'
},
{
field : 'totalMoney',
title : '补贴金额',
formatter: function(value, row, index) {
if (!value) return '未知';
return parseFloat(value).toFixed(2);
}
},
{
field : 'instanceId',
title : '流程实例ID'
},
{
field: 'createBy',
title: '创建人ID',
visible: false
},
{
field: 'createUserName',
title: '创建人'
},
{
field: 'applyUser',
title: '申请人ID',
visible: false
},
{
field: 'applyUserName',
title: '<span style="color: blue;">申请人</span>',
formatter: function(value, row, index) {
return '<span style="color: blue;">' + (value ? value : "-") + '</span>';
}
},
{
field: 'applyTime',
title: '申请时间'
},
{
field: 'taskId',
title: '当前任务ID',
visible: false
},
{
field: 'taskName',
title: '当前任务名称',
align: 'center',
formatter: function(value, row, index) {
return '<span class="badge badge-primary">' + value + '</span>';
}
},
{
title: '操作',
align: 'center',
formatter: function(value, row, index) {
var actions = [];
if (row.instanceId) {
actions.push('<a class="btn btn-primary btn-xs" href="javascript:void(0)" οnclick="$.operate.detail(\'' + row.id + '\')"><i class="fa fa-eye"></i> 表单数据</a> ');
actions.push('<a class="btn btn-warning btn-xs" href="javascript:void(0)" οnclick="showHistoryDialog(\'' + row.instanceId + '\')"><i class="fa fa-list"></i> 审批历史</a> ');
actions.push('<a class="btn btn-info btn-xs" href="javascript:void(0)" οnclick="showProcessImgDialog(\'' + row.instanceId + '\')"><i class="fa fa-image"></i> 进度查看</a> ');
} else {
actions.push('<a class="btn btn-success btn-xs" href="javascript:void(0)" οnclick="submitApply(\'' + row.id + '\',\'' + row.createBy + '\')"><i class="fa fa-user"></i> 提交申请</a> ');
actions.push('<a class="btn btn-primary btn-xs" href="javascript:void(0)" οnclick="editForm(\'' + row.id + '\',\'' + row.createBy + '\')"><i class="fa fa-edit"></i> 编辑</a> ');
actions.push('<a class="btn btn-danger btn-xs" href="javascript:void(0)" οnclick="removeForm(\'' + row.id + '\',\'' + row.createBy + '\')"><i class="fa fa-remove"></i> 删除</a>');
}
return actions.join('');
}
}]
};
$.table.init(options);
});
function submitApply(id, createBy) {
if (createBy !== currentUser.username) {
$.modal.alertWarning("不允许非创建人提交申请!");
return;
}
$.modal.confirm("确认要提交申请吗?", function() {
var url = prefix + "/submitApply";
var data = { "id": id };
$.operate.submit(url, "post", "json", data);
});
}
function editForm(id, createBy) {
if (createBy !== currentUser.username) {
$.modal.alertWarning("不允许非创建人编辑表单!");
return;
}
$.operate.edit(id);
}
function removeForm(id, createBy) {
if (createBy !== currentUser.username) {
$.modal.alertWarning("不允许非创建人删除表单!");
return;
}
$.operate.remove(id);
}
/* 查看审批历史 */
function showHistoryDialog(instanceId) {
var url = ctx + 'workflow/general/historyList/' + instanceId;
$.modal.open("查看审批历史", url);
}
function showProcessImgDialog(instanceId) {
var url = ctx + 'workflow/general/processImg/' + instanceId;
$.modal.open("查看流程图 (标红表示已结束或活动中的流程)", url);
}
</script>
</body>
</html>
申请单新增页面
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
<head>
<th:block th:include="include :: header" />
</head>
<body class="white-bg">
<div class="wrapper wrapper-content animated fadeInRight ibox-content">
<form class="form-horizontal m" id="form-allowance-add">
<div class="form-group">
<label class="col-sm-3 control-label"><span style="color: red; ">*</span>标题:</label>
<div class="col-sm-8">
<input name="title" class="form-control" type="text" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label"><span style="color: red; ">*</span>原因:</label>
<div class="col-sm-8">
<textarea name="reason" class="form-control" required></textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">补贴金额:</label>
<div class="col-sm-8">
<input name="totalMoney" class="form-control" type="text">
</div>
</div>
</form>
</div>
<th:block th:include="include :: footer" />
<script th:inline="javascript">
var prefix = ctx + "workflow/allowance"
$("#form-allowance-add").validate({
focusCleanup: true
});
function submitHandler() {
if ($.validate.form()) {
$.operate.save(prefix + "/add", $('#form-allowance-add').serialize());
}
}
</script>
</body>
</html>
申请单详情页面
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
<head>
<th:block th:include="include :: header" />
<th:block th:include="include :: datetimepicker-css" />
<th:block th:include="include :: select2-css" />
</head>
<body class="white-bg">
<div class="wrapper wrapper-content animated fadeInRight ibox-content">
<form class="form-horizontal m" id="form-allowance-edit" th:object="${bizAllowance}">
<input name="id" th:field="*{id}" type="hidden">
<div class="form-group">
<label class="col-sm-3 control-label">申请人:</label>
<div class="col-sm-8">
<input name="applyUserName" th:field="*{applyUserName}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">申请时间:</label>
<div class="col-sm-8">
<div class="input-group date">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input name="applyTime" th:value="${#dates.format(bizAllowance.applyTime, 'yyyy-MM-dd HH:mm')}" class="form-control" type="text" readonly>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label"><span style="color: red; ">*</span>标题:</label>
<div class="col-sm-8">
<input name="title" th:field="*{title}" class="form-control" type="text" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label"><span style="color: red; ">*</span>原因:</label>
<div class="col-sm-8">
<textarea name="reason" class="form-control" required>[[*{reason}]]</textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">补贴金额:</label>
<div class="col-sm-8">
<input name="totalMoney" th:field="*{totalMoney}" class="form-control" type="text">
</div>
</div>
</form>
</div>
<th:block th:include="include :: footer" />
<th:block th:include="include :: datetimepicker-js" />
<th:block th:include="include :: select2-js" />
<script th:inline="javascript">
var prefix = ctx + "process/allowance";
$("#form-allowance-edit").validate({
focusCleanup: true
});
function submitHandler() {
if ($.validate.form() && validateStartTimeAndEndTime()) {
$.operate.save(prefix + "/edit", $('#form-allowance-edit').serialize());
}
}
</script>
</body>
</html>
申请单审批页面(申请人办理)
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
<head>
<th:block th:include="include :: header" />
<th:block th:include="include :: select2-css" />
</head>
<body class="white-bg">
<div class="wrapper wrapper-content animated fadeInRight ibox-content">
<form class="form-horizontal m" id="form-allowance-edit" th:object="${bizAllowance}">
<input name="id" th:field="*{id}" type="hidden">
<input name="taskId" th:field="*{taskId}" type="hidden">
<input type="hidden" name="p_COM_comment" />
<div class="form-group">
<label class="col-sm-3 control-label">申请人:</label>
<div class="col-sm-8">
<input name="applyUserName" th:field="*{applyUserName}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">申请时间:</label>
<div class="col-sm-8">
<div class="input-group date">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input name="applyTime" th:value="${#dates.format(bizAllowance.applyTime, 'yyyy-MM-dd HH:mm')}" class="form-control" type="text" disabled>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">标题:</label>
<div class="col-sm-8">
<input name="title" th:field="*{title}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">原因:</label>
<div class="col-sm-8">
<textarea name="reason" class="form-control" readonly>[[*{reason}]]</textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">补贴金额:</label>
<div class="col-sm-8">
<input name="totalMoney" th:field="*{totalMoney}" class="form-control" type="text" readonly>
</div>
</div>
<hr />
<div class="form-group">
<label class="col-sm-3 control-label" for="selfApproved">处理任务:</label>
<div class="col-sm-8">
<select name="p_STR_outcome" id="selfApproved" class="form-control m-b">
<option value="提交">提交</option>
<option value="撤回">放弃</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">批注:</label>
<div class="col-sm-8">
<textarea name="comment" class="form-control"></textarea>
</div>
</div>
</form>
</div>
<th:block th:include="include :: footer" />
<th:block th:include="include :: select2-js" />
<script th:inline="javascript">
var prefix = ctx + "workflow/allowance";
$("#form-allowance-edit").validate({
focusCleanup: true
});
function submitHandler() {
if ($.validate.form()) {
if ($('textarea[name="comment"]').val()) {
$('input[name="p_COM_comment"]').val($('textarea[name="comment"]').val());
}
var taskId = [[${taskId}]];
$.operate.save(prefix + "/complete/" + taskId, $('#form-allowance-edit').serialize());
}
}
</script>
</body>
</html>
申请单审批页面(领导审核)
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
<head>
<th:block th:include="include :: header" />
<th:block th:include="include :: select2-css" />
</head>
<body class="white-bg">
<div class="wrapper wrapper-content animated fadeInRight ibox-content">
<form class="form-horizontal m" id="form-allowance-edit" th:object="${bizAllowance}">
<input name="id" th:field="*{id}" type="hidden">
<input name="taskId" th:field="*{taskId}" type="hidden">
<input type="hidden" name="p_COM_comment" />
<div class="form-group">
<label class="col-sm-3 control-label">申请人:</label>
<div class="col-sm-8">
<input name="applyUserName" th:field="*{applyUserName}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">申请时间:</label>
<div class="col-sm-8">
<div class="input-group date">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input name="applyTime" th:value="${#dates.format(bizAllowance.applyTime, 'yyyy-MM-dd HH:mm')}" class="form-control" type="text" disabled>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">标题:</label>
<div class="col-sm-8">
<input name="title" th:field="*{title}" class="form-control" type="text" readonly>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">原因:</label>
<div class="col-sm-8">
<textarea name="reason" class="form-control" readonly>[[*{reason}]]</textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">补贴金额:</label>
<div class="col-sm-8">
<input name="totalMoney" th:field="*{totalMoney}" class="form-control" type="text" readonly>
</div>
</div>
<hr />
<div class="form-group">
<label class="col-sm-3 control-label" for="deptLeaderApproved">审批意见:</label>
<div class="col-sm-8">
<select name="p_STR_outcome" id="deptLeaderApproved" class="form-control m-b">
<option value="通过">同意</option>
<option value="驳回">拒绝</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">批注:</label>
<div class="col-sm-8">
<textarea name="comment" class="form-control"></textarea>
</div>
</div>
</form>
</div>
<th:block th:include="include :: footer" />
<th:block th:include="include :: select2-js" />
<script th:inline="javascript">
var prefix = ctx + "workflow/allowance";
$("#form-allowance-edit").validate({
focusCleanup: true
});
function submitHandler() {
if ($.validate.form()) {
if ($('textarea[name="comment"]').val()) {
$('input[name="p_COM_comment"]').val($('textarea[name="comment"]').val());
}
var taskId = [[${taskId}]];
$.operate.save(prefix + "/complete/" + taskId, $('#form-allowance-edit').serialize());
}
}
</script>
</body>
</html>
任务待办列表页面
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<th:block th:include="include :: header" />
</head>
<body class="gray-bg">
<div class="container-div">
<div class="row">
<div class="col-sm-12 search-collapse">
<form id="formId">
<div class="select-list">
<ul>
<li>
<p>流程实例ID:</p>
<input type="text" name="instanceId"/>
</li>
<li>
<a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i> 搜索</a>
<a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i> 重置</a>
</li>
</ul>
</div>
</form>
</div>
<div class="btn-group-sm" id="toolbar" role="group">
<!--<a class="btn btn-warning" οnclick="$.table.exportExcel()" shiro:hasPermission="process:allowance:export">
<i class="fa fa-download"></i> 导出
</a>-->
</div>
<div class="col-sm-12 select-table table-striped">
<table id="bootstrap-table"></table>
</div>
</div>
</div>
<th:block th:include="include :: footer" />
<script th:inline="javascript">
var editFlag = [[${@permission.hasPermi('workflow:allowance:edit')}]];
var removeFlag = [[${@permission.hasPermi('workflow:allowance:remove')}]];
var prefix = ctx + "workflow/allowance";
$(function() {
var options = {
url: prefix + "/task/data",
createUrl: prefix + "/add",
updateUrl: prefix + "/edit/{id}",
removeUrl: prefix + "/remove",
exportUrl: prefix + "/export",
detailUrl: prefix + "/edit/{id}",
modalName: "补贴申请",
columns: [{
checkbox: true
},
{
field : 'id',
title : '主键ID',
visible: false
},
{
field : 'title',
title : '标题'
},
{
field : 'reason',
title : '原因'
},
{
field : 'totalMoney',
title : '补贴金额',
formatter: function(value, row, index) {
if (!value) return '未知';
return parseFloat(value).toFixed(2);
}
},
{
field : 'instanceId',
title : '流程实例ID'
},
{
field: 'applyUserName',
title: '<span style="color: red;">申请人</span>',
formatter: function(value, row, index) {
return '<span style="color: red;">' + (value ? value : "-") + '</span>';
}
},
{
field: 'applyTime',
title: '申请时间'
},
{
field: 'taskId',
title: '任务ID',
visible: false
},
{
field: 'taskName',
title: '当前任务名称',
align: 'center',
formatter: function(value, row, index) {
return '<span class="badge badge-primary">' + value + '</span>';
}
},
{
title: '操作',
align: 'center',
formatter: function(value, row, index) {
var actions = [];
if (row.taskName.indexOf('审批') !== -1) {
actions.push('<a class="btn btn-success btn-xs" href="javascript:void(0)" οnclick="showVerifyDialog(\'' + row.taskId + '\', \'' + row.taskName + '\')"><i class="fa fa-edit"></i> 审批</a> ');
} else {
actions.push('<a class="btn btn-success btn-xs" href="javascript:void(0)" οnclick="showVerifyDialog(\'' + row.taskId + '\', \'' + row.taskName + '\')"><i class="fa fa-edit"></i> ' + row.taskName + '</a> ');
}
actions.push('<a class="btn btn-primary btn-xs" href="javascript:void(0)" οnclick="$.operate.detail(\'' + row.id + '\')"><i class="fa fa-eye"></i> 申请详情</a> ');
actions.push('<a class="btn btn-warning btn-xs" href="javascript:void(0)" οnclick="showHistoryDialog(\'' + row.instanceId + '\')"><i class="fa fa-list"></i> 审批历史</a> ');
return actions.join('');
}
}]
};
$.table.init(options);
});
function submitApply(id) {
$.modal.confirm("确认要提交申请吗?", function() {
var url = prefix + "/submitApply";
var data = { "id": id };
$.operate.submit(url, "post", "json", data);
});
}
function showVerifyDialog(taskId, taskName) {
var url = prefix + "/showVerifyDialog/" + taskId;
$.modal.open(taskName, url);
}
/* 查看审批历史 */
function showHistoryDialog(instanceId) {
var url = ctx + 'workflow/general/historyList/' + instanceId;
$.modal.open("查看审批历史", url);
}
</script>
</body>
</html>
已办理任务列表页面
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<th:block th:include="include :: header" />
</head>
<body class="gray-bg">
<div class="container-div">
<div class="row">
<div class="col-sm-12 search-collapse">
<form id="formId">
<div class="select-list">
<ul>
<li>
<p>流程实例ID:</p>
<input type="text" name="instanceId"/>
</li>
<li>
<a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i> 搜索</a>
<a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i> 重置</a>
</li>
</ul>
</div>
</form>
</div>
<div class="btn-group-sm" id="toolbar" role="group">
<!--<a class="btn btn-warning" οnclick="$.table.exportExcel()" shiro:hasPermission="process:allowance:export">
<i class="fa fa-download"></i> 导出
</a>-->
</div>
<div class="col-sm-12 select-table table-striped">
<table id="bootstrap-table"></table>
</div>
</div>
</div>
<th:block th:include="include :: footer" />
<script th:inline="javascript">
var editFlag = [[${@permission.hasPermi('workflow:allowance:edit')}]];
var removeFlag = [[${@permission.hasPermi('workflow:allowance:remove')}]];
var prefix = ctx + "workflow/allowance";
$(function() {
var options = {
url: prefix + "/done/data",
createUrl: prefix + "/add",
updateUrl: prefix + "/edit/{id}",
removeUrl: prefix + "/remove",
exportUrl: prefix + "/export",
detailUrl: prefix + "/edit/{id}",
modalName: "补贴申请",
columns: [{
checkbox: true
},
{
field : 'id',
title : '主键ID',
visible: false
},
{
field : 'title',
title : '标题'
},
{
field : 'reason',
title : '原因'
},
{
field : 'totalMoney',
title : '补贴金额',
formatter: function(value, row, index) {
if (!value) return '未知';
return parseFloat(value).toFixed(2);
}
},
{
field : 'instanceId',
title : '流程实例ID'
},
{
field: 'applyUserName',
title: '<span style="color: red;">申请人</span>',
formatter: function(value, row, index) {
return '<span style="color: red;">' + (value ? value : "-") + '</span>';
}
},
{
field: 'applyTime',
title: '申请时间'
},
{
field: 'taskId',
title: '任务ID',
visible: false
},
{
field: 'taskName',
title: '已办任务名称',
align: 'center',
formatter: function(value, row, index) {
return '<span class="badge badge-primary">' + value + '</span>';
}
},
{
field: 'doneTime',
title: '办理时间'
},
{
title: '操作',
align: 'center',
formatter: function(value, row, index) {
var actions = [];
actions.push('<a class="btn btn-primary btn-xs" href="javascript:void(0)" οnclick="$.operate.detail(\'' + row.id + '\')"><i class="fa fa-eye"></i> 申请详情</a> ');
actions.push('<a class="btn btn-warning btn-xs" href="javascript:void(0)" οnclick="showHistoryDialog(\'' + row.instanceId + '\')"><i class="fa fa-list"></i> 审批历史</a> ');
return actions.join('');
}
}]
};
$.table.init(options);
});
function submitApply(id) {
$.modal.confirm("确认要提交申请吗?", function() {
var url = prefix + "/submitApply";
var data = { "id": id };
$.operate.submit(url, "post", "json", data);
});
}
function showVerifyDialog(taskId, taskName) {
var url = prefix + "/showVerifyDialog/" + taskId;
$.modal.open(taskName, url);
}
/* 查看审批历史 */
function showHistoryDialog(instanceId) {
var url = ctx + 'workflow/general/historyList/' + instanceId;
$.modal.open("查看审批历史", url);
}
</script>
</body>
</html>
github项目地址
https://github.com/yangzc23/studentboot
参考资料
[01] idea 2019 集成activiti, idea activiti 新建bpmn文件
[02] Activiti,自定义表单,外置表单,工作流,微服务,子系统
[03] activiti监听器设置审批人
[04] springboot-activiti TaskListener无法注入service
[05] Activiti的环节监听taskListener中注入spring bean
[06] Activiti6生成实例历史活动追踪图片
[07] Spring Boot整合Activiti,查看流程图出现中文乱码问题
[08] 一篇文章让你轻松搞定springboot+activiti
[09] Springboot 集成 Activiti时启动报错
[10] SpringBoot 集成 Activiti 一路踩得坑
[11] springboot2.x整合工作流activiti6.0问题及解决方案
[12] activiti会签多人审批(通过以及驳回)
[13] activiti工作流,驳回问题详细解析(尤其会签的驳回问题)
[14] 在工作流开发中,一般会签有哪几种模式
[15] activity6 会签以及会签驳回操作
[16] activiti 动态自定义流程(包含会签流程)
[17] activiti自定义各种流程
[18] activiti动态创建流程
微信扫一扫关注公众号
点击链接加入群聊
https://jq.qq.com/?_wv=1027&k=5eVEhfN
软件测试学习交流QQ群号:511619105