提交代码
parent
1a776f79ea
commit
ab67fcc363
|
@ -1,11 +1,10 @@
|
||||||
package com.yanzhu.common.utils;
|
package com.yanzhu.common.utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Collection;
|
import java.nio.charset.Charset;
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import io.netty.util.CharsetUtil;
|
||||||
import java.util.Set;
|
|
||||||
import org.springframework.util.AntPathMatcher;
|
import org.springframework.util.AntPathMatcher;
|
||||||
import com.yanzhu.common.constant.Constants;
|
import com.yanzhu.common.constant.Constants;
|
||||||
import com.yanzhu.common.core.text.StrFormatter;
|
import com.yanzhu.common.core.text.StrFormatter;
|
||||||
|
@ -565,6 +564,105 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断指定集合是否包含指定值,如果集合为空(null或者空),返回{@code false},否则找到元素返回{@code true}
|
||||||
|
*
|
||||||
|
* @param collection 集合
|
||||||
|
* @param value 需要查找的值
|
||||||
|
* @return 如果集合为空(null或者空),返回{@code false},否则找到元素返回{@code true}
|
||||||
|
* @throws ClassCastException 如果类型不一致会抛出转换异常
|
||||||
|
* @throws NullPointerException 当指定的元素 值为 null ,或集合类不支持null 时抛出该异常
|
||||||
|
* @see Collection#contains(Object)
|
||||||
|
* @since 4.1.10
|
||||||
|
*/
|
||||||
|
public static boolean contains(Collection<?> collection, Object value) {
|
||||||
|
return isNotEmpty(collection) && collection.contains(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象转为字符串<br>
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组
|
||||||
|
* 2、对象数组会调用Arrays.toString方法
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param obj 对象
|
||||||
|
* @return 字符串
|
||||||
|
*/
|
||||||
|
public static String utf8Str(Object obj) {
|
||||||
|
return str(obj, CharsetUtil.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象转为字符串
|
||||||
|
* <pre>
|
||||||
|
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组
|
||||||
|
* 2、对象数组会调用Arrays.toString方法
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param obj 对象
|
||||||
|
* @param charset 字符集
|
||||||
|
* @return 字符串
|
||||||
|
*/
|
||||||
|
public static String str(Object obj, Charset charset) {
|
||||||
|
if (null == obj) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj instanceof String) {
|
||||||
|
return (String) obj;
|
||||||
|
} else if (obj instanceof byte[]) {
|
||||||
|
return str((byte[]) obj, charset);
|
||||||
|
} else if (obj instanceof Byte[]) {
|
||||||
|
return str((Byte[]) obj, charset);
|
||||||
|
} else if (obj instanceof ByteBuffer) {
|
||||||
|
return str((ByteBuffer) obj, charset);
|
||||||
|
} else if (isArray(obj)) {
|
||||||
|
return toString(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数组或集合转String
|
||||||
|
*
|
||||||
|
* @param obj 集合或数组对象
|
||||||
|
* @return 数组字符串,与集合转字符串格式相同
|
||||||
|
*/
|
||||||
|
public static String toString(Object obj) {
|
||||||
|
if (null == obj) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (obj instanceof long[]) {
|
||||||
|
return Arrays.toString((long[]) obj);
|
||||||
|
} else if (obj instanceof int[]) {
|
||||||
|
return Arrays.toString((int[]) obj);
|
||||||
|
} else if (obj instanceof short[]) {
|
||||||
|
return Arrays.toString((short[]) obj);
|
||||||
|
} else if (obj instanceof char[]) {
|
||||||
|
return Arrays.toString((char[]) obj);
|
||||||
|
} else if (obj instanceof byte[]) {
|
||||||
|
return Arrays.toString((byte[]) obj);
|
||||||
|
} else if (obj instanceof boolean[]) {
|
||||||
|
return Arrays.toString((boolean[]) obj);
|
||||||
|
} else if (obj instanceof float[]) {
|
||||||
|
return Arrays.toString((float[]) obj);
|
||||||
|
} else if (obj instanceof double[]) {
|
||||||
|
return Arrays.toString((double[]) obj);
|
||||||
|
} else if (isArray(obj)) {
|
||||||
|
// 对象数组
|
||||||
|
try {
|
||||||
|
return Arrays.deepToString((Object[]) obj);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断url是否与规则配置:
|
* 判断url是否与规则配置:
|
||||||
* ? 表示单个字符;
|
* ? 表示单个字符;
|
||||||
|
|
|
@ -16,8 +16,8 @@ public enum FlowComment {
|
||||||
REJECT("3", "驳回意见"),
|
REJECT("3", "驳回意见"),
|
||||||
DELEGATE("4", "委派意见"),
|
DELEGATE("4", "委派意见"),
|
||||||
ASSIGN("5", "转办意见"),
|
ASSIGN("5", "转办意见"),
|
||||||
STOP("6", "终止流程");
|
STOP("6", "终止流程"),
|
||||||
|
REVOKE("7", "撤回流程");
|
||||||
/**
|
/**
|
||||||
* 类型
|
* 类型
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package com.yanzhu.flowable.controller;
|
package com.yanzhu.flowable.controller;
|
||||||
|
|
||||||
|
import com.yanzhu.common.annotation.Log;
|
||||||
import com.yanzhu.common.core.controller.BaseController;
|
import com.yanzhu.common.core.controller.BaseController;
|
||||||
import com.yanzhu.common.core.domain.AjaxResult;
|
import com.yanzhu.common.core.domain.AjaxResult;
|
||||||
import com.yanzhu.common.core.domain.entity.SysRole;
|
import com.yanzhu.common.core.domain.entity.SysRole;
|
||||||
import com.yanzhu.common.core.domain.entity.SysUser;
|
import com.yanzhu.common.core.domain.entity.SysUser;
|
||||||
import com.yanzhu.common.core.text.Convert;
|
import com.yanzhu.common.core.text.Convert;
|
||||||
|
import com.yanzhu.common.enums.BusinessType;
|
||||||
import com.yanzhu.flowable.domain.FlowSaveXmlVo;
|
import com.yanzhu.flowable.domain.FlowSaveXmlVo;
|
||||||
import com.yanzhu.project.domain.ProProjectApply;
|
import com.yanzhu.project.domain.ProProjectApply;
|
||||||
import com.yanzhu.system.domain.flowable.FlowQueryVo;
|
import com.yanzhu.system.domain.flowable.FlowQueryVo;
|
||||||
|
@ -75,6 +77,7 @@ public class FlowDefinitionController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "导入流程文件", notes = "上传bpmn20的xml文件")
|
@ApiOperation(value = "导入流程文件", notes = "上传bpmn20的xml文件")
|
||||||
|
@Log(title = "导入流程文件", businessType = BusinessType.INSERT)
|
||||||
@PostMapping("/import")
|
@PostMapping("/import")
|
||||||
public AjaxResult importFile(@RequestParam(required = false) String name,
|
public AjaxResult importFile(@RequestParam(required = false) String name,
|
||||||
@RequestParam(required = false) String category,
|
@RequestParam(required = false) String category,
|
||||||
|
@ -136,6 +139,7 @@ public class FlowDefinitionController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "保存流程设计器内的xml文件")
|
@ApiOperation(value = "保存流程设计器内的xml文件")
|
||||||
|
@Log(title = "保存流程设计", businessType = BusinessType.INSERT)
|
||||||
@PostMapping("/save")
|
@PostMapping("/save")
|
||||||
public AjaxResult save(@RequestBody FlowSaveXmlVo vo) {
|
public AjaxResult save(@RequestBody FlowSaveXmlVo vo) {
|
||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
|
@ -159,6 +163,7 @@ public class FlowDefinitionController extends BaseController {
|
||||||
|
|
||||||
|
|
||||||
@ApiOperation(value = "发起流程")
|
@ApiOperation(value = "发起流程")
|
||||||
|
@Log(title = "发起流程申请", businessType = BusinessType.INSERT)
|
||||||
@PostMapping("/start/{procDefId}")
|
@PostMapping("/start/{procDefId}")
|
||||||
public AjaxResult start(@ApiParam(value = "流程定义id") @PathVariable(value = "procDefId") String procDefId,
|
public AjaxResult start(@ApiParam(value = "流程定义id") @PathVariable(value = "procDefId") String procDefId,
|
||||||
@ApiParam(value = "申请表单") @RequestBody ProProjectApply proProjectApply) {
|
@ApiParam(value = "申请表单") @RequestBody ProProjectApply proProjectApply) {
|
||||||
|
@ -166,6 +171,7 @@ public class FlowDefinitionController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "激活或挂起流程定义")
|
@ApiOperation(value = "激活或挂起流程定义")
|
||||||
|
@Log(title = "激活/挂起流程", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping(value = "/updateState")
|
@PutMapping(value = "/updateState")
|
||||||
public AjaxResult updateState(@ApiParam(value = "1:激活,2:挂起", required = true) @RequestParam Integer state,
|
public AjaxResult updateState(@ApiParam(value = "1:激活,2:挂起", required = true) @RequestParam Integer state,
|
||||||
@ApiParam(value = "流程部署ID", required = true) @RequestParam String deployId) {
|
@ApiParam(value = "流程部署ID", required = true) @RequestParam String deployId) {
|
||||||
|
@ -174,6 +180,7 @@ public class FlowDefinitionController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "删除流程")
|
@ApiOperation(value = "删除流程")
|
||||||
|
@Log(title = "删除流程定义", businessType = BusinessType.UPDATE)
|
||||||
@DeleteMapping(value = "/{deployIds}")
|
@DeleteMapping(value = "/{deployIds}")
|
||||||
public AjaxResult delete(@PathVariable String[] deployIds) {
|
public AjaxResult delete(@PathVariable String[] deployIds) {
|
||||||
for (String deployId : deployIds) {
|
for (String deployId : deployIds) {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package com.yanzhu.flowable.controller;
|
package com.yanzhu.flowable.controller;
|
||||||
|
|
||||||
|
import com.yanzhu.common.annotation.Log;
|
||||||
import com.yanzhu.common.core.domain.AjaxResult;
|
import com.yanzhu.common.core.domain.AjaxResult;
|
||||||
|
import com.yanzhu.common.enums.BusinessType;
|
||||||
import com.yanzhu.flowable.domain.FlowTaskDto;
|
import com.yanzhu.flowable.domain.FlowTaskDto;
|
||||||
import com.yanzhu.system.domain.flowable.FlowQueryVo;
|
import com.yanzhu.system.domain.flowable.FlowQueryVo;
|
||||||
import com.yanzhu.system.domain.flowable.FlowTaskVo;
|
import com.yanzhu.system.domain.flowable.FlowTaskVo;
|
||||||
|
@ -41,12 +43,14 @@ public class FlowTaskController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "取消申请", response = FlowTaskDto.class)
|
@ApiOperation(value = "取消申请", response = FlowTaskDto.class)
|
||||||
|
@Log(title = "终止申请", businessType = BusinessType.UPDATE)
|
||||||
@PostMapping(value = "/stopProcess")
|
@PostMapping(value = "/stopProcess")
|
||||||
public AjaxResult stopProcess(@RequestBody FlowTaskVo flowTaskVo) {
|
public AjaxResult stopProcess(@RequestBody FlowTaskVo flowTaskVo) {
|
||||||
return flowTaskService.stopProcess(flowTaskVo);
|
return flowTaskService.stopProcess(flowTaskVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "撤回流程", response = FlowTaskDto.class)
|
@ApiOperation(value = "撤回流程", response = FlowTaskDto.class)
|
||||||
|
@Log(title = "撤回流程", businessType = BusinessType.UPDATE)
|
||||||
@PostMapping(value = "/revokeProcess")
|
@PostMapping(value = "/revokeProcess")
|
||||||
public AjaxResult revokeProcess(@RequestBody FlowTaskVo flowTaskVo) {
|
public AjaxResult revokeProcess(@RequestBody FlowTaskVo flowTaskVo) {
|
||||||
return flowTaskService.revokeProcess(flowTaskVo);
|
return flowTaskService.revokeProcess(flowTaskVo);
|
||||||
|
@ -85,12 +89,14 @@ public class FlowTaskController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "审批任务")
|
@ApiOperation(value = "审批任务")
|
||||||
|
@Log(title = "审批流程", businessType = BusinessType.UPDATE)
|
||||||
@PostMapping(value = "/complete")
|
@PostMapping(value = "/complete")
|
||||||
public AjaxResult complete(@RequestBody FlowTaskVo flowTaskVo) {
|
public AjaxResult complete(@RequestBody FlowTaskVo flowTaskVo) {
|
||||||
return flowTaskService.complete(flowTaskVo);
|
return flowTaskService.complete(flowTaskVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "驳回任务")
|
@ApiOperation(value = "驳回任务")
|
||||||
|
@Log(title = "驳回流程", businessType = BusinessType.UPDATE)
|
||||||
@PostMapping(value = "/reject")
|
@PostMapping(value = "/reject")
|
||||||
public AjaxResult taskReject(@RequestBody FlowTaskVo flowTaskVo) {
|
public AjaxResult taskReject(@RequestBody FlowTaskVo flowTaskVo) {
|
||||||
flowTaskService.taskReject(flowTaskVo);
|
flowTaskService.taskReject(flowTaskVo);
|
||||||
|
@ -98,6 +104,7 @@ public class FlowTaskController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "退回任务")
|
@ApiOperation(value = "退回任务")
|
||||||
|
@Log(title = "退回流程", businessType = BusinessType.UPDATE)
|
||||||
@PostMapping(value = "/return")
|
@PostMapping(value = "/return")
|
||||||
public AjaxResult taskReturn(@RequestBody FlowTaskVo flowTaskVo) {
|
public AjaxResult taskReturn(@RequestBody FlowTaskVo flowTaskVo) {
|
||||||
flowTaskService.taskReturn(flowTaskVo);
|
flowTaskService.taskReturn(flowTaskVo);
|
||||||
|
@ -111,6 +118,7 @@ public class FlowTaskController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "删除任务")
|
@ApiOperation(value = "删除任务")
|
||||||
|
@Log(title = "删除流程", businessType = BusinessType.DELETE)
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public AjaxResult delete(@RequestBody FlowTaskVo flowTaskVo) {
|
public AjaxResult delete(@RequestBody FlowTaskVo flowTaskVo) {
|
||||||
flowTaskService.deleteTask(flowTaskVo);
|
flowTaskService.deleteTask(flowTaskVo);
|
||||||
|
@ -118,6 +126,7 @@ public class FlowTaskController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "认领/签收任务")
|
@ApiOperation(value = "认领/签收任务")
|
||||||
|
@Log(title = "认领/签收流程", businessType = BusinessType.INSERT)
|
||||||
@PostMapping(value = "/claim")
|
@PostMapping(value = "/claim")
|
||||||
public AjaxResult claim(@RequestBody FlowTaskVo flowTaskVo) {
|
public AjaxResult claim(@RequestBody FlowTaskVo flowTaskVo) {
|
||||||
flowTaskService.claim(flowTaskVo);
|
flowTaskService.claim(flowTaskVo);
|
||||||
|
@ -125,6 +134,7 @@ public class FlowTaskController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "取消认领/签收任务")
|
@ApiOperation(value = "取消认领/签收任务")
|
||||||
|
@Log(title = "取消认领/签收流程", businessType = BusinessType.UPDATE)
|
||||||
@PostMapping(value = "/unClaim")
|
@PostMapping(value = "/unClaim")
|
||||||
public AjaxResult unClaim(@RequestBody FlowTaskVo flowTaskVo) {
|
public AjaxResult unClaim(@RequestBody FlowTaskVo flowTaskVo) {
|
||||||
flowTaskService.unClaim(flowTaskVo);
|
flowTaskService.unClaim(flowTaskVo);
|
||||||
|
@ -132,6 +142,7 @@ public class FlowTaskController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "委派任务")
|
@ApiOperation(value = "委派任务")
|
||||||
|
@Log(title = "委派流程", businessType = BusinessType.UPDATE)
|
||||||
@PostMapping(value = "/delegateTask")
|
@PostMapping(value = "/delegateTask")
|
||||||
public AjaxResult delegate(@RequestBody FlowTaskVo flowTaskVo) {
|
public AjaxResult delegate(@RequestBody FlowTaskVo flowTaskVo) {
|
||||||
flowTaskService.delegateTask(flowTaskVo);
|
flowTaskService.delegateTask(flowTaskVo);
|
||||||
|
@ -139,6 +150,7 @@ public class FlowTaskController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "任务归还")
|
@ApiOperation(value = "任务归还")
|
||||||
|
@Log(title = "归还流程", businessType = BusinessType.UPDATE)
|
||||||
@PostMapping(value = "/resolveTask")
|
@PostMapping(value = "/resolveTask")
|
||||||
public AjaxResult resolveTask(@RequestBody FlowTaskVo flowTaskVo) {
|
public AjaxResult resolveTask(@RequestBody FlowTaskVo flowTaskVo) {
|
||||||
flowTaskService.resolveTask(flowTaskVo);
|
flowTaskService.resolveTask(flowTaskVo);
|
||||||
|
@ -146,6 +158,7 @@ public class FlowTaskController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "转办任务")
|
@ApiOperation(value = "转办任务")
|
||||||
|
@Log(title = "转办流程", businessType = BusinessType.UPDATE)
|
||||||
@PostMapping(value = "/assignTask")
|
@PostMapping(value = "/assignTask")
|
||||||
public AjaxResult assign(@RequestBody FlowTaskVo flowTaskVo) {
|
public AjaxResult assign(@RequestBody FlowTaskVo flowTaskVo) {
|
||||||
flowTaskService.assignTask(flowTaskVo);
|
flowTaskService.assignTask(flowTaskVo);
|
||||||
|
|
|
@ -0,0 +1,372 @@
|
||||||
|
package com.yanzhu.flowable.flow;
|
||||||
|
|
||||||
|
import com.yanzhu.common.utils.StringUtils;
|
||||||
|
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||||
|
import org.flowable.bpmn.model.Process;
|
||||||
|
import org.flowable.bpmn.model.*;
|
||||||
|
import org.flowable.common.engine.impl.util.io.StringStreamSource;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author KonBAI
|
||||||
|
* @createTime 2022/3/26 19:04
|
||||||
|
*/
|
||||||
|
public class ModelUtils {
|
||||||
|
|
||||||
|
private static final BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xml转bpmnModel对象
|
||||||
|
*
|
||||||
|
* @param xml xml
|
||||||
|
* @return bpmnModel对象
|
||||||
|
*/
|
||||||
|
public static BpmnModel getBpmnModel(String xml) {
|
||||||
|
return bpmnXMLConverter.convertToBpmnModel(new StringStreamSource(xml), false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bpmnModel转xml字符串
|
||||||
|
*
|
||||||
|
* @deprecated 存在会丢失 bpmn 连线问题
|
||||||
|
* @param bpmnModel bpmnModel对象
|
||||||
|
* @return xml字符串
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static String getBpmnXmlStr(BpmnModel bpmnModel) {
|
||||||
|
return StringUtils.utf8Str(getBpmnXml(bpmnModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bpmnModel转xml对象
|
||||||
|
*
|
||||||
|
* @deprecated 存在丢失 bpmn 连线问题
|
||||||
|
* @param bpmnModel bpmnModel对象
|
||||||
|
* @return xml
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static byte[] getBpmnXml(BpmnModel bpmnModel) {
|
||||||
|
return bpmnXMLConverter.convertToXML(bpmnModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据节点,获取入口连线
|
||||||
|
*
|
||||||
|
* @param source 起始节点
|
||||||
|
* @return 入口连线列表
|
||||||
|
*/
|
||||||
|
public static List<SequenceFlow> getElementIncomingFlows(FlowElement source) {
|
||||||
|
List<SequenceFlow> sequenceFlows = new ArrayList<>();
|
||||||
|
if (source instanceof FlowNode) {
|
||||||
|
sequenceFlows = ((FlowNode) source).getIncomingFlows();
|
||||||
|
}
|
||||||
|
return sequenceFlows;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据节点,获取出口连线
|
||||||
|
*
|
||||||
|
* @param source 起始节点
|
||||||
|
* @return 出口连线列表
|
||||||
|
*/
|
||||||
|
public static List<SequenceFlow> getElementOutgoingFlows(FlowElement source) {
|
||||||
|
List<SequenceFlow> sequenceFlows = new ArrayList<>();
|
||||||
|
if (source instanceof FlowNode) {
|
||||||
|
sequenceFlows = ((FlowNode) source).getOutgoingFlows();
|
||||||
|
}
|
||||||
|
return sequenceFlows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取开始节点
|
||||||
|
*
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @return 开始节点(未找到开始节点,返回null)
|
||||||
|
*/
|
||||||
|
public static StartEvent getStartEvent(BpmnModel model) {
|
||||||
|
Process process = model.getMainProcess();
|
||||||
|
FlowElement startElement = process.getInitialFlowElement();
|
||||||
|
if (startElement instanceof StartEvent) {
|
||||||
|
return (StartEvent) startElement;
|
||||||
|
}
|
||||||
|
return getStartEvent(process.getFlowElements());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取开始节点
|
||||||
|
*
|
||||||
|
* @param flowElements 流程元素集合
|
||||||
|
* @return 开始节点(未找到开始节点,返回null)
|
||||||
|
*/
|
||||||
|
public static StartEvent getStartEvent(Collection<FlowElement> flowElements) {
|
||||||
|
for (FlowElement flowElement : flowElements) {
|
||||||
|
if (flowElement instanceof StartEvent) {
|
||||||
|
return (StartEvent) flowElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取结束节点
|
||||||
|
*
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @return 结束节点(未找到开始节点,返回null)
|
||||||
|
*/
|
||||||
|
public static EndEvent getEndEvent(BpmnModel model) {
|
||||||
|
Process process = model.getMainProcess();
|
||||||
|
return getEndEvent(process.getFlowElements());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取结束节点
|
||||||
|
*
|
||||||
|
* @param flowElements 流程元素集合
|
||||||
|
* @return 结束节点(未找到开始节点,返回null)
|
||||||
|
*/
|
||||||
|
public static EndEvent getEndEvent(Collection<FlowElement> flowElements) {
|
||||||
|
for (FlowElement flowElement : flowElements) {
|
||||||
|
if (flowElement instanceof EndEvent) {
|
||||||
|
return (EndEvent) flowElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserTask getUserTaskByKey(BpmnModel model, String taskKey) {
|
||||||
|
Process process = model.getMainProcess();
|
||||||
|
FlowElement flowElement = process.getFlowElement(taskKey);
|
||||||
|
if (flowElement instanceof UserTask) {
|
||||||
|
return (UserTask) flowElement;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程元素信息
|
||||||
|
*
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @param flowElementId 元素ID
|
||||||
|
* @return 元素信息
|
||||||
|
*/
|
||||||
|
public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) {
|
||||||
|
Process process = model.getMainProcess();
|
||||||
|
return process.getFlowElement(flowElementId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取元素表单Key(限开始节点和用户节点可用)
|
||||||
|
*
|
||||||
|
* @param flowElement 元素
|
||||||
|
* @return 表单Key
|
||||||
|
*/
|
||||||
|
public static String getFormKey(FlowElement flowElement) {
|
||||||
|
if (flowElement != null) {
|
||||||
|
if (flowElement instanceof StartEvent) {
|
||||||
|
return ((StartEvent) flowElement).getFormKey();
|
||||||
|
} else if (flowElement instanceof UserTask) {
|
||||||
|
return ((UserTask) flowElement).getFormKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取开始节点属性值
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @param name 属性名
|
||||||
|
* @return 属性值
|
||||||
|
*/
|
||||||
|
public static String getStartEventAttributeValue(BpmnModel model, String name) {
|
||||||
|
StartEvent startEvent = getStartEvent(model);
|
||||||
|
return getElementAttributeValue(startEvent, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取结束节点属性值
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @param name 属性名
|
||||||
|
* @return 属性值
|
||||||
|
*/
|
||||||
|
public static String getEndEventAttributeValue(BpmnModel model, String name) {
|
||||||
|
EndEvent endEvent = getEndEvent(model);
|
||||||
|
return getElementAttributeValue(endEvent, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户任务节点属性值
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @param taskKey 任务Key
|
||||||
|
* @param name 属性名
|
||||||
|
* @return 属性值
|
||||||
|
*/
|
||||||
|
public static String getUserTaskAttributeValue(BpmnModel model, String taskKey, String name) {
|
||||||
|
UserTask userTask = getUserTaskByKey(model, taskKey);
|
||||||
|
return getElementAttributeValue(userTask, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取元素属性值
|
||||||
|
* @param baseElement 流程元素
|
||||||
|
* @param name 属性名
|
||||||
|
* @return 属性值
|
||||||
|
*/
|
||||||
|
public static String getElementAttributeValue(BaseElement baseElement, String name) {
|
||||||
|
if (baseElement != null) {
|
||||||
|
List<ExtensionAttribute> attributes = baseElement.getAttributes().get(name);
|
||||||
|
if (attributes != null && !attributes.isEmpty()) {
|
||||||
|
attributes.iterator().next().getValue();
|
||||||
|
Iterator<ExtensionAttribute> attrIterator = attributes.iterator();
|
||||||
|
if(attrIterator.hasNext()) {
|
||||||
|
ExtensionAttribute attribute = attrIterator.next();
|
||||||
|
return attribute.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isMultiInstance(BpmnModel model, String taskKey) {
|
||||||
|
UserTask userTask = getUserTaskByKey(model, taskKey);
|
||||||
|
if (!Objects.isNull(userTask)) {
|
||||||
|
return userTask.hasMultiInstanceLoopCharacteristics();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有用户任务节点
|
||||||
|
*
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @return 用户任务节点列表
|
||||||
|
*/
|
||||||
|
public static Collection<UserTask> getAllUserTaskEvent(BpmnModel model) {
|
||||||
|
Process process = model.getMainProcess();
|
||||||
|
Collection<FlowElement> flowElements = process.getFlowElements();
|
||||||
|
return getAllUserTaskEvent(flowElements, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有用户任务节点
|
||||||
|
* @param flowElements 流程元素集合
|
||||||
|
* @param allElements 所有流程元素集合
|
||||||
|
* @return 用户任务节点列表
|
||||||
|
*/
|
||||||
|
public static Collection<UserTask> getAllUserTaskEvent(Collection<FlowElement> flowElements, Collection<UserTask> allElements) {
|
||||||
|
allElements = allElements == null ? new ArrayList<>() : allElements;
|
||||||
|
for (FlowElement flowElement : flowElements) {
|
||||||
|
if (flowElement instanceof UserTask) {
|
||||||
|
allElements.add((UserTask) flowElement);
|
||||||
|
}
|
||||||
|
if (flowElement instanceof SubProcess) {
|
||||||
|
// 继续深入子流程,进一步获取子流程
|
||||||
|
allElements = getAllUserTaskEvent(((SubProcess) flowElement).getFlowElements(), allElements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找起始节点下一个用户任务列表列表
|
||||||
|
* @param source 起始节点
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static List<UserTask> findNextUserTasks(FlowElement source) {
|
||||||
|
return findNextUserTasks(source, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找起始节点下一个用户任务列表列表
|
||||||
|
* @param source 起始节点
|
||||||
|
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
|
||||||
|
* @param userTaskList 用户任务列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static List<UserTask> findNextUserTasks(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
|
||||||
|
hasSequenceFlow = Optional.ofNullable(hasSequenceFlow).orElse(new HashSet<>());
|
||||||
|
userTaskList = Optional.ofNullable(userTaskList).orElse(new ArrayList<>());
|
||||||
|
// 获取出口连线
|
||||||
|
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
|
||||||
|
if (!sequenceFlows.isEmpty()) {
|
||||||
|
for (SequenceFlow sequenceFlow : sequenceFlows) {
|
||||||
|
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||||
|
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 添加已经走过的连线
|
||||||
|
hasSequenceFlow.add(sequenceFlow.getId());
|
||||||
|
FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
|
||||||
|
if (targetFlowElement instanceof UserTask) {
|
||||||
|
// 若节点为用户任务,加入到结果列表中
|
||||||
|
userTaskList.add((UserTask) targetFlowElement);
|
||||||
|
} else {
|
||||||
|
// 若节点非用户任务,继续递归查找下一个节点
|
||||||
|
findNextUserTasks(targetFlowElement, hasSequenceFlow, userTaskList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return userTaskList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行
|
||||||
|
* 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况
|
||||||
|
* @param source 起始节点
|
||||||
|
* @param target 目标节点
|
||||||
|
* @param visitedElements 已经经过的连线的 ID,用于判断线路是否重复
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set<String> visitedElements) {
|
||||||
|
visitedElements = visitedElements == null ? new HashSet<>() : visitedElements;
|
||||||
|
if (source instanceof StartEvent && isInEventSubprocess(source)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据类型,获取入口连线
|
||||||
|
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
|
||||||
|
if (sequenceFlows != null && sequenceFlows.size() > 0) {
|
||||||
|
// 循环找到目标元素
|
||||||
|
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||||
|
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||||
|
if (visitedElements.contains(sequenceFlow.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 添加已经走过的连线
|
||||||
|
visitedElements.add(sequenceFlow.getId());
|
||||||
|
FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();
|
||||||
|
// 这条线路存在目标节点,这条线路完成,进入下个线路
|
||||||
|
if (target.getId().equals(sourceFlowElement.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 如果目标节点为并行网关,则不继续
|
||||||
|
if (sourceFlowElement instanceof ParallelGateway) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 否则就继续迭代
|
||||||
|
boolean isSequential = isSequentialReachable(sourceFlowElement, target, visitedElements);
|
||||||
|
if (!isSequential) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean isInEventSubprocess(FlowElement flowElement) {
|
||||||
|
FlowElementsContainer flowElementsContainer = flowElement.getParentContainer();
|
||||||
|
while (flowElementsContainer != null) {
|
||||||
|
if (flowElementsContainer instanceof EventSubProcess) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flowElementsContainer instanceof FlowElement) {
|
||||||
|
flowElementsContainer = ((FlowElement) flowElementsContainer).getParentContainer();
|
||||||
|
} else {
|
||||||
|
flowElementsContainer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,8 @@ import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.alibaba.fastjson2.TypeReference;
|
import com.alibaba.fastjson2.TypeReference;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.yanzhu.common.core.text.Convert;
|
||||||
|
import com.yanzhu.common.utils.StringUtils;
|
||||||
import com.yanzhu.flowable.common.constant.ProcessConstants;
|
import com.yanzhu.flowable.common.constant.ProcessConstants;
|
||||||
import com.yanzhu.common.core.domain.AjaxResult;
|
import com.yanzhu.common.core.domain.AjaxResult;
|
||||||
import com.yanzhu.common.core.domain.entity.SysRole;
|
import com.yanzhu.common.core.domain.entity.SysRole;
|
||||||
|
@ -16,6 +18,7 @@ import com.yanzhu.flowable.domain.FlowCommentDto;
|
||||||
import com.yanzhu.flowable.domain.FlowNextDto;
|
import com.yanzhu.flowable.domain.FlowNextDto;
|
||||||
import com.yanzhu.flowable.domain.FlowTaskDto;
|
import com.yanzhu.flowable.domain.FlowTaskDto;
|
||||||
import com.yanzhu.flowable.domain.FlowViewerDto;
|
import com.yanzhu.flowable.domain.FlowViewerDto;
|
||||||
|
import com.yanzhu.flowable.flow.ModelUtils;
|
||||||
import com.yanzhu.system.domain.flowable.FlowQueryVo;
|
import com.yanzhu.system.domain.flowable.FlowQueryVo;
|
||||||
import com.yanzhu.system.domain.flowable.FlowTaskVo;
|
import com.yanzhu.system.domain.flowable.FlowTaskVo;
|
||||||
import com.yanzhu.flowable.factory.FlowServiceFactory;
|
import com.yanzhu.flowable.factory.FlowServiceFactory;
|
||||||
|
@ -31,11 +34,11 @@ import com.yanzhu.system.service.ISysUserService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.flowable.bpmn.model.Process;
|
import org.flowable.bpmn.model.Process;
|
||||||
import org.flowable.bpmn.model.*;
|
import org.flowable.bpmn.model.*;
|
||||||
import org.flowable.common.engine.api.FlowableException;
|
import org.flowable.common.engine.api.FlowableException;
|
||||||
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
|
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
|
||||||
|
import org.flowable.common.engine.impl.identity.Authentication;
|
||||||
import org.flowable.engine.ProcessEngineConfiguration;
|
import org.flowable.engine.ProcessEngineConfiguration;
|
||||||
import org.flowable.engine.history.HistoricActivityInstance;
|
import org.flowable.engine.history.HistoricActivityInstance;
|
||||||
import org.flowable.engine.history.HistoricProcessInstance;
|
import org.flowable.engine.history.HistoricProcessInstance;
|
||||||
|
@ -590,6 +593,7 @@ public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTask
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional
|
||||||
public AjaxResult stopProcess(FlowTaskVo flowTaskVo) {
|
public AjaxResult stopProcess(FlowTaskVo flowTaskVo) {
|
||||||
List<Task> task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).list();
|
List<Task> task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).list();
|
||||||
if (CollectionUtils.isEmpty(task)) {
|
if (CollectionUtils.isEmpty(task)) {
|
||||||
|
@ -604,25 +608,27 @@ public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTask
|
||||||
Process process = bpmnModel.getMainProcess();
|
Process process = bpmnModel.getMainProcess();
|
||||||
List<EndEvent> endNodes = process.findFlowElementsOfType(EndEvent.class, false);
|
List<EndEvent> endNodes = process.findFlowElementsOfType(EndEvent.class, false);
|
||||||
if (CollectionUtils.isNotEmpty(endNodes)) {
|
if (CollectionUtils.isNotEmpty(endNodes)) {
|
||||||
// TODO 取消流程为什么要设置流程发起人?
|
String userIdStr = Convert.toStr(SecurityUtils.getUserId());
|
||||||
// SysUser loginUser = SecurityUtils.getLoginUser().getUser();
|
if(StringUtils.isNotEmpty(userIdStr)){
|
||||||
// Authentication.setAuthenticatedUserId(loginUser.getUserId().toString());
|
Authentication.setAuthenticatedUserId(userIdStr);
|
||||||
|
taskService.addComment(task.get(0).getId(), processInstance.getProcessInstanceId(), FlowComment.STOP.getType(),
|
||||||
// taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.STOP.getType(),
|
StringUtils.isBlank(flowTaskVo.getComment()) ? "取消申请" : flowTaskVo.getComment());
|
||||||
// StringUtils.isBlank(flowTaskVo.getComment()) ? "取消申请" : flowTaskVo.getComment());
|
// 设置流程经办人为当前登录人员
|
||||||
// 获取当前流程最后一个节点
|
taskService.setAssignee(task.get(0).getId(), userIdStr);
|
||||||
String endId = endNodes.get(0).getId();
|
// 获取当前流程最后一个节点
|
||||||
List<Execution> executions = runtimeService.createExecutionQuery()
|
String endId = endNodes.get(0).getId();
|
||||||
.parentId(processInstance.getProcessInstanceId()).list();
|
List<Execution> executions = runtimeService.createExecutionQuery()
|
||||||
List<String> executionIds = new ArrayList<>();
|
.parentId(processInstance.getProcessInstanceId()).list();
|
||||||
executions.forEach(execution -> executionIds.add(execution.getId()));
|
List<String> executionIds = new ArrayList<>();
|
||||||
// 变更流程为已结束状态
|
executions.forEach(execution -> executionIds.add(execution.getId()));
|
||||||
runtimeService.createChangeActivityStateBuilder()
|
// 变更流程为已结束状态
|
||||||
.moveExecutionsToSingleActivityId(executionIds, endId).changeState();
|
runtimeService.createChangeActivityStateBuilder()
|
||||||
|
.moveExecutionsToSingleActivityId(executionIds, endId).changeState();
|
||||||
|
return AjaxResult.success();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return AjaxResult.error();
|
||||||
return AjaxResult.success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -632,55 +638,66 @@ public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTask
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional
|
||||||
public AjaxResult revokeProcess(FlowTaskVo flowTaskVo) {
|
public AjaxResult revokeProcess(FlowTaskVo flowTaskVo) {
|
||||||
Task task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).singleResult();
|
String procInsId = flowTaskVo.getInstanceId();
|
||||||
if (task == null) {
|
String taskId = flowTaskVo.getTaskId();
|
||||||
throw new CustomException("流程未启动或已执行完成,无法撤回");
|
// 校验流程是否结束
|
||||||
|
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
||||||
|
.processInstanceId(procInsId)
|
||||||
|
.active()
|
||||||
|
.singleResult();
|
||||||
|
if(Objects.isNull(processInstance)) {
|
||||||
|
throw new RuntimeException("流程已结束或已挂起,无法执行撤回操作");
|
||||||
}
|
}
|
||||||
|
// 获取待撤回任务实例
|
||||||
|
HistoricTaskInstance currTaskIns = historyService.createHistoricTaskInstanceQuery()
|
||||||
|
.taskId(taskId)
|
||||||
|
.taskAssignee(flowTaskVo.getUserId())
|
||||||
|
.singleResult();
|
||||||
|
if (Objects.isNull(currTaskIns)) {
|
||||||
|
throw new RuntimeException("当前任务不存在,无法执行撤回操作");
|
||||||
|
}
|
||||||
|
// 获取 bpmn 模型
|
||||||
|
BpmnModel bpmnModel = repositoryService.getBpmnModel(currTaskIns.getProcessDefinitionId());
|
||||||
|
UserTask currUserTask = ModelUtils.getUserTaskByKey(bpmnModel, currTaskIns.getTaskDefinitionKey());
|
||||||
|
// 查找下一级用户任务列表
|
||||||
|
List<UserTask> nextUserTaskList = ModelUtils.findNextUserTasks(currUserTask);
|
||||||
|
List<String> nextUserTaskKeys = nextUserTaskList.stream().map(UserTask::getId).collect(Collectors.toList());
|
||||||
|
|
||||||
SysUser loginUser = SecurityUtils.getLoginUser().getUser();
|
// 获取当前节点之后已完成的流程历史节点
|
||||||
List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
|
List<HistoricTaskInstance> finishedTaskInsList = historyService.createHistoricTaskInstanceQuery()
|
||||||
.processInstanceId(task.getProcessInstanceId())
|
.processInstanceId(procInsId)
|
||||||
.orderByTaskCreateTime()
|
.taskCreatedAfter(currTaskIns.getEndTime())
|
||||||
.asc()
|
.finished()
|
||||||
.list();
|
.list();
|
||||||
String myTaskId = null;
|
for (HistoricTaskInstance finishedTaskInstance : finishedTaskInsList) {
|
||||||
HistoricTaskInstance myTask = null;
|
// 检查已完成流程历史节点是否存在下一级中
|
||||||
for (HistoricTaskInstance hti : htiList) {
|
if (StringUtils.contains(nextUserTaskKeys, finishedTaskInstance.getTaskDefinitionKey())) {
|
||||||
if (loginUser.getUserId().toString().equals(hti.getAssignee())) {
|
throw new RuntimeException("下一流程已处理,无法执行撤回操作");
|
||||||
myTaskId = hti.getId();
|
|
||||||
myTask = hti;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (null == myTaskId) {
|
// 获取所有激活的任务节点,找到需要撤回的任务
|
||||||
throw new CustomException("该任务非当前用户提交,无法撤回");
|
List<Task> activateTaskList = taskService.createTaskQuery().processInstanceId(procInsId).list();
|
||||||
}
|
List<String> revokeExecutionIds = new ArrayList<>();
|
||||||
|
for (Task task : activateTaskList) {
|
||||||
String processDefinitionId = myTask.getProcessDefinitionId();
|
// 检查激活的任务节点是否存在下一级中,如果存在,则加入到需要撤回的节点
|
||||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
|
if (StringUtils.contains(nextUserTaskKeys, task.getTaskDefinitionKey())) {
|
||||||
|
// 添加撤回审批信息
|
||||||
//变量
|
taskService.setAssignee(task.getId(), flowTaskVo.getUserId());
|
||||||
// Map<String, VariableInstance> variables = runtimeService.getVariableInstances(currentTask.getExecutionId());
|
taskService.addComment(task.getId(), task.getProcessInstanceId(), FlowComment.REVOKE.getType(), flowTaskVo.getAssignee() + "撤回流程审批");
|
||||||
String myActivityId = null;
|
revokeExecutionIds.add(task.getExecutionId());
|
||||||
List<HistoricActivityInstance> haiList = historyService.createHistoricActivityInstanceQuery()
|
|
||||||
.executionId(myTask.getExecutionId()).finished().list();
|
|
||||||
for (HistoricActivityInstance hai : haiList) {
|
|
||||||
if (myTaskId.equals(hai.getTaskId())) {
|
|
||||||
myActivityId = hai.getActivityId();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(myActivityId);
|
try {
|
||||||
|
runtimeService.createChangeActivityStateBuilder()
|
||||||
Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
|
.processInstanceId(procInsId)
|
||||||
String activityId = execution.getActivityId();
|
.moveExecutionsToSingleActivityId(revokeExecutionIds, currTaskIns.getTaskDefinitionKey()).changeState();
|
||||||
FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
|
} catch (FlowableObjectNotFoundException e) {
|
||||||
|
throw new RuntimeException("未找到流程实例,流程可能已发生变化");
|
||||||
//记录原活动方向
|
} catch (FlowableException e) {
|
||||||
List<SequenceFlow> oriSequenceFlows = new ArrayList<>(flowNode.getOutgoingFlows());
|
throw new RuntimeException("执行撤回操作失败");
|
||||||
|
}
|
||||||
|
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,9 @@ public class ProProjectApply extends BaseEntity
|
||||||
@Excel(name = "是否删除")
|
@Excel(name = "是否删除")
|
||||||
private String isDel;
|
private String isDel;
|
||||||
|
|
||||||
|
/** 申请人单位名称 */
|
||||||
|
private String createByDeptName;
|
||||||
|
|
||||||
/** 项目申请明细信息 */
|
/** 项目申请明细信息 */
|
||||||
private List<ProProjectApplyDetail> proProjectApplyDetailList;
|
private List<ProProjectApplyDetail> proProjectApplyDetailList;
|
||||||
|
|
||||||
|
@ -176,6 +179,14 @@ public class ProProjectApply extends BaseEntity
|
||||||
this.parProjName = parProjName;
|
this.parProjName = parProjName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCreateByDeptName() {
|
||||||
|
return createByDeptName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateByDeptName(String createByDeptName) {
|
||||||
|
this.createByDeptName = createByDeptName;
|
||||||
|
}
|
||||||
|
|
||||||
public List<ProProjectApplyDetail> getProProjectApplyDetailList()
|
public List<ProProjectApplyDetail> getProProjectApplyDetailList()
|
||||||
{
|
{
|
||||||
return proProjectApplyDetailList;
|
return proProjectApplyDetailList;
|
||||||
|
|
|
@ -17,6 +17,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<result property="applyUser" column="apply_user" />
|
<result property="applyUser" column="apply_user" />
|
||||||
<result property="useTime" column="use_time" />
|
<result property="useTime" column="use_time" />
|
||||||
<result property="isDel" column="is_del" />
|
<result property="isDel" column="is_del" />
|
||||||
|
<result property="createByDeptName" column="createByDeptName" />
|
||||||
<result property="createBy" column="create_by" />
|
<result property="createBy" column="create_by" />
|
||||||
<result property="createTime" column="create_time" />
|
<result property="createTime" column="create_time" />
|
||||||
<result property="updateBy" column="update_by" />
|
<result property="updateBy" column="update_by" />
|
||||||
|
@ -71,9 +72,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectProProjectApplyById" parameterType="Long" resultMap="ProProjectApplyProProjectApplyDetailResult">
|
<select id="selectProProjectApplyById" parameterType="Long" resultMap="ProProjectApplyProProjectApplyDetailResult">
|
||||||
select a.id, a.dept_id, a.proj_id, a.proj_name, a.par_proj_name, a.apply_type, a.apply_status, a.apply_reason, a.apply_files, a.apply_user, a.use_time, a.is_del, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,
|
select a.id, a.dept_id, a.proj_id, a.proj_name, a.par_proj_name, a.apply_type, a.apply_status, a.apply_reason, a.apply_files, a.apply_user, a.use_time, a.is_del, sd.dept_name as createByDeptName, a.create_by, a.create_time, a.update_by, a.update_time, a.remark,
|
||||||
b.id as sub_id, b.apply_id as sub_apply_id, b.super_type_key as sub_super_type_key, b.super_type_name as sub_super_type_name, b.type_id as sub_type_id, b.type_name as sub_type_name, b.assets_id as sub_assets_id, b.assets_name as sub_assets_name, b.assets_unit as sub_assets_unit, b.number as sub_number, b.use_time as sub_use_time, b.use_reason as sub_use_reason, b.price as sub_price, b.total_price as sub_total_price, b.is_del as sub_is_del, b.create_by as sub_create_by, b.create_time as sub_create_time, b.update_by as sub_update_by, b.update_time as sub_update_time, b.remark as sub_remark
|
b.id as sub_id, b.apply_id as sub_apply_id, b.super_type_key as sub_super_type_key, b.super_type_name as sub_super_type_name, b.type_id as sub_type_id, b.type_name as sub_type_name, b.assets_id as sub_assets_id, b.assets_name as sub_assets_name, b.assets_unit as sub_assets_unit, b.number as sub_number, b.use_time as sub_use_time, b.use_reason as sub_use_reason, b.price as sub_price, b.total_price as sub_total_price, b.is_del as sub_is_del, b.create_by as sub_create_by, b.create_time as sub_create_time, b.update_by as sub_update_by, b.update_time as sub_update_time, b.remark as sub_remark
|
||||||
from pro_project_apply a
|
from pro_project_apply a
|
||||||
|
left join sys_dept sd on a.dept_id = sd.dept_id
|
||||||
left join pro_project_apply_detail b on b.apply_id = a.id
|
left join pro_project_apply_detail b on b.apply_id = a.id
|
||||||
where a.id = #{id}
|
where a.id = #{id}
|
||||||
</select>
|
</select>
|
||||||
|
|
|
@ -98,10 +98,10 @@
|
||||||
<div class="drawerRight">
|
<div class="drawerRight">
|
||||||
<el-form label-width="80px">
|
<el-form label-width="80px">
|
||||||
<el-form-item label="项目单位">
|
<el-form-item label="项目单位">
|
||||||
{{ initData.projParName }}
|
{{ initData.parProjName }}
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="项目名称">
|
<el-form-item label="项目名称">
|
||||||
{{ initData.projParName }}
|
{{ initData.projName }}
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="申请类型">
|
<el-form-item label="申请类型">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
|
@ -131,16 +131,23 @@
|
||||||
<el-form-item label="申请时间">
|
<el-form-item label="申请时间">
|
||||||
{{ parseTime(initData.createTime, "{y}-{m}-{d} {h}:{i}") }}
|
{{ parseTime(initData.createTime, "{y}-{m}-{d} {h}:{i}") }}
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="使用时间">
|
<el-form-item label="使用时间" v-if="initData.useTime">
|
||||||
{{ initData.applyReason }}
|
{{ parseTime(initData.useTime, "{y}-{m}-{d} {h}:{i}") }}
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-divider content-position="left">申请明细</el-divider>
|
<el-divider content-position="left">申请明细信息</el-divider>
|
||||||
<el-table stripe :data="initData.proProjectApplyDetailList">
|
<el-table
|
||||||
<el-table-column label="序号" width="40" type="index"></el-table-column>
|
ref="proProjectApplyDetail"
|
||||||
|
:data="initData.proProjectApplyDetailList"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
label="序号"
|
||||||
|
width="50"
|
||||||
|
type="index"
|
||||||
|
align="center"
|
||||||
|
></el-table-column>
|
||||||
<el-table-column label="申请明细" align="left">
|
<el-table-column label="申请明细" align="left">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-breadcrumb separator=">">
|
<el-breadcrumb separator=">">
|
||||||
<el-breadcrumb-item>{{ scope.row.superTypeName }}</el-breadcrumb-item>
|
|
||||||
<el-breadcrumb-item>{{ scope.row.typeName }}</el-breadcrumb-item>
|
<el-breadcrumb-item>{{ scope.row.typeName }}</el-breadcrumb-item>
|
||||||
<el-breadcrumb-item class="assetsName">{{
|
<el-breadcrumb-item class="assetsName">{{
|
||||||
scope.row.assetsName
|
scope.row.assetsName
|
||||||
|
@ -148,24 +155,25 @@
|
||||||
</el-breadcrumb>
|
</el-breadcrumb>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="规格" prop="assetsVersion"></el-table-column>
|
<el-table-column
|
||||||
<el-table-column label="数量" prop="number">
|
label="申请规格"
|
||||||
|
prop="assetsVersion"
|
||||||
|
width="180"
|
||||||
|
align="center"
|
||||||
|
v-if="showAssetsVersion"
|
||||||
|
></el-table-column>
|
||||||
|
<el-table-column label="申请数量" prop="number" width="180" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<label
|
<label>{{ scope.row.number }} {{ scope.row.assetsUnit }}</label>
|
||||||
>{{ scope.row.number }}
|
|
||||||
<el-tag type="info" size="mini">{{
|
|
||||||
scope.row.assetsUnit
|
|
||||||
}}</el-tag></label
|
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="说明"
|
label="使用说明"
|
||||||
prop="useReason"
|
prop="useReason"
|
||||||
width="150"
|
align="center"
|
||||||
></el-table-column>
|
></el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div style="text-align: center">
|
<div style="text-align: center; margin: 20px 0px">
|
||||||
<el-button type="danger" @click="doCanel">关 闭</el-button>
|
<el-button type="danger" @click="doCanel">关 闭</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
@ -204,6 +212,7 @@ export default {
|
||||||
//label样式
|
//label样式
|
||||||
labelStyle: { width: "180px" },
|
labelStyle: { width: "180px" },
|
||||||
initData: {},
|
initData: {},
|
||||||
|
showAssetsVersion: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {},
|
computed: {},
|
||||||
|
@ -246,6 +255,12 @@ export default {
|
||||||
},
|
},
|
||||||
show(options) {
|
show(options) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
//物资设备类需要输入规格
|
||||||
|
if (options.category == 1) {
|
||||||
|
this.showAssetsVersion = true;
|
||||||
|
} else {
|
||||||
|
this.showAssetsVersion = false;
|
||||||
|
}
|
||||||
this.title = options.procDefName;
|
this.title = options.procDefName;
|
||||||
this.deptName = options.startDeptName;
|
this.deptName = options.startDeptName;
|
||||||
this.nickName = options.startUserName;
|
this.nickName = options.startUserName;
|
||||||
|
@ -571,8 +586,8 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.assetsName {
|
.assetsName .el-breadcrumb__inner {
|
||||||
font-weight: 800;
|
font-weight: 800 !important;
|
||||||
color: #409eff;
|
color: #409eff !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -189,22 +189,41 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="操作"
|
label="操作"
|
||||||
width="150"
|
width="200"
|
||||||
fixed="right"
|
fixed="right"
|
||||||
class-name="small-padding fixed-width"
|
class-name="small-padding fixed-width"
|
||||||
>
|
>
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button @click="handleFlowRecord(scope.row)" type="text" size="small"
|
<el-button
|
||||||
|
v-if="getActivate(scope.row)"
|
||||||
|
@click="handleActivate(scope.row)"
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon="el-icon-edit-outline"
|
||||||
|
>处理</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
@click="handleFlowRecord(scope.row)"
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon="el-icon-finished"
|
||||||
>详情</el-button
|
>详情</el-button
|
||||||
>
|
>
|
||||||
<el-button @click="handleStop(scope.row)" type="text" size="small"
|
<el-button
|
||||||
|
v-if="scope.row.finishTime == null"
|
||||||
|
@click="handleStop(scope.row)"
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon="el-icon-switch-button"
|
||||||
>取消申请</el-button
|
>取消申请</el-button
|
||||||
>
|
>
|
||||||
<el-button
|
<el-button
|
||||||
|
v-if="scope.row.finishTime == null"
|
||||||
@click="handleDelete(scope.row)"
|
@click="handleDelete(scope.row)"
|
||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
v-hasPermi="['system:deployment:remove']"
|
v-hasPermi="['system:deployment:remove']"
|
||||||
|
icon="el-icon-delete"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
|
@ -319,6 +338,36 @@
|
||||||
@pagination="listDefinition"
|
@pagination="listDefinition"
|
||||||
/>
|
/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<!-- 终止流程 -->
|
||||||
|
<el-dialog
|
||||||
|
:title="title"
|
||||||
|
:visible.sync="stopOpen"
|
||||||
|
width="30%"
|
||||||
|
append-to-body
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="form"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
v-loading="stopLoading"
|
||||||
|
label-width="80px"
|
||||||
|
>
|
||||||
|
<el-form-item label="取消原因" prop="comment">
|
||||||
|
<el-input
|
||||||
|
type="textarea"
|
||||||
|
v-model="form.comment"
|
||||||
|
placeholder="请输入取消原因"
|
||||||
|
rows="5"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="handleStopClick">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
<detailDrawer ref="detailDrawer"></detailDrawer>
|
<detailDrawer ref="detailDrawer"></detailDrawer>
|
||||||
<editTaskDrawer ref="editTaskDrawer" :closeCallBack="getList"></editTaskDrawer>
|
<editTaskDrawer ref="editTaskDrawer" :closeCallBack="getList"></editTaskDrawer>
|
||||||
<initTaskDrawer ref="initTaskDrawer" :closeCallBack="getList"></initTaskDrawer>
|
<initTaskDrawer ref="initTaskDrawer" :closeCallBack="getList"></initTaskDrawer>
|
||||||
|
@ -349,6 +398,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
// 遮罩层
|
// 遮罩层
|
||||||
loading: true,
|
loading: true,
|
||||||
|
stopLoading: false,
|
||||||
processLoading: true,
|
processLoading: true,
|
||||||
// 选中数组
|
// 选中数组
|
||||||
ids: [],
|
ids: [],
|
||||||
|
@ -404,7 +454,16 @@ export default {
|
||||||
// 表单参数
|
// 表单参数
|
||||||
form: {},
|
form: {},
|
||||||
// 表单校验
|
// 表单校验
|
||||||
rules: {},
|
rules: {
|
||||||
|
comment: [
|
||||||
|
{ required: true, message: "请输入取消原因", trigger: "blur" },
|
||||||
|
{
|
||||||
|
max: 500,
|
||||||
|
message: "取消原因最多输入500字",
|
||||||
|
trigger: "blur",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
tabs: {
|
tabs: {
|
||||||
all: 0,
|
all: 0,
|
||||||
await: 0,
|
await: 0,
|
||||||
|
@ -496,6 +555,18 @@ export default {
|
||||||
this.single = selection.length !== 1;
|
this.single = selection.length !== 1;
|
||||||
this.multiple = !selection.length;
|
this.multiple = !selection.length;
|
||||||
},
|
},
|
||||||
|
/** 继续办理 */
|
||||||
|
handleActivate(row) {
|
||||||
|
this.$refs.editTaskDrawer.show(row);
|
||||||
|
},
|
||||||
|
/** 判断是否继续办理 */
|
||||||
|
getActivate(row) {
|
||||||
|
if (row.taskName == "提交申请" && row.assigneeId == this.$store.getters.userId) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
handleAdd() {
|
handleAdd() {
|
||||||
this.open = true;
|
this.open = true;
|
||||||
|
@ -524,6 +595,33 @@ export default {
|
||||||
this.getList();
|
this.getList();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
/** 取消流程申请 */
|
||||||
|
handleStop(row) {
|
||||||
|
this.form.taskId = row.taskId;
|
||||||
|
this.form.userId = this.$store.getters.userId;
|
||||||
|
this.form.instanceId = row.procInsId;
|
||||||
|
this.stopOpen = true;
|
||||||
|
},
|
||||||
|
/** 取消流程申请 */
|
||||||
|
handleStopClick() {
|
||||||
|
let that = this;
|
||||||
|
this.$refs["form"].validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
this.$modal
|
||||||
|
.confirm("是否确认取消当前流程申请?")
|
||||||
|
.then(function () {
|
||||||
|
that.stopLoading = true;
|
||||||
|
return stopProcess(that.form);
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
that.$modal.msgSuccess(res.msg);
|
||||||
|
that.stopLoading = false;
|
||||||
|
that.stopOpen = false;
|
||||||
|
that.getList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
/** 流程流转记录 */
|
/** 流程流转记录 */
|
||||||
handleFlowRecord(row) {
|
handleFlowRecord(row) {
|
||||||
/** this.$router.push({
|
/** this.$router.push({
|
||||||
|
|
|
@ -153,7 +153,7 @@
|
||||||
label="申请规格"
|
label="申请规格"
|
||||||
align="center"
|
align="center"
|
||||||
prop="assetsVersion"
|
prop="assetsVersion"
|
||||||
width="160"
|
width="180"
|
||||||
>
|
>
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input
|
<el-input
|
||||||
|
@ -180,7 +180,7 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div style="text-align: center; margin: 20px 0px">
|
<div style="text-align: center; margin: 20px 0px;">
|
||||||
<el-button type="primary" @click="submitForm">提交申请</el-button>
|
<el-button type="primary" @click="submitForm">提交申请</el-button>
|
||||||
<el-button @click="doCanel">取 消</el-button>
|
<el-button @click="doCanel">取 消</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue