From 3832f51c8d596645d8f24f385a72e5c5d448a751 Mon Sep 17 00:00:00 2001
From: luohairen <3399054449@qq.com>
Date: 星期二, 26 十一月 2024 15:52:18 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 flowable/src/main/java/com/ycl/controller/FlowDefinitionController.java    |  203 +
 flowable/src/main/java/com/ycl/flow/FindNextNodeUtil.java                  |  262 ++
 flowable/src/main/java/com/ycl/mapper/SysTaskFormMapper.java               |   63 
 flowable/src/main/java/com/ycl/service/impl/SysListenerServiceImpl.java    |   92 
 flowable/src/main/java/com/ycl/service/impl/FlowTaskServiceImpl.java       | 1263 +++++++++
 start/src/main/resources/application.yml                                   |    3 
 flowable/src/main/java/com/ycl/domain/entity/SysListener.java              |  126 
 flowable/src/main/java/com/ycl/domain/entity/SysDeployForm.java            |   64 
 flowable/src/main/java/com/ycl/domain/dto/FlowViewerDto.java               |   23 
 flowable/src/main/resources/mapper/SysExpressionMapper.xml                 |   90 
 common/src/main/java/com/ycl/common/exception/CustomException.java         |   43 
 flowable/src/main/java/com/ycl/service/impl/FlowDefinitionServiceImpl.java |  246 +
 flowable/src/main/java/com/ycl/service/impl/SysExpressionServiceImpl.java  |   92 
 flowable/src/main/java/com/ycl/domain/dto/FlowCommentDto.java              |   25 
 flowable/src/main/java/com/ycl/service/ISysDeployFormService.java          |   70 
 business/src/main/java/com/ycl/controller/FlowableTypeController.java      |   27 
 flowable/src/main/resources/mapper/SysListenerMapper.xml                   |  115 
 start/src/main/resources/processes/mytest.bpmn20.xml                       |  101 
 flowable/src/main/java/com/ycl/domain/dto/FlowProcDefDto.java              |   56 
 flowable/src/main/java/com/ycl/mapper/SysExpressionMapper.java             |   62 
 flowable/src/main/java/com/ycl/service/impl/SysFormServiceImpl.java        |   92 
 flowable/src/main/java/com/ycl/common/expand/el/BaseEl.java                |   12 
 flowable/src/main/java/com/ycl/domain/dto/FlowTaskDto.java                 |  102 
 business/src/main/resources/mapper/FlowableTypeMapper.xml                  |   12 
 flowable/src/main/java/com/ycl/domain/entity/SysTaskForm.java              |   65 
 flowable/src/main/java/com/ycl/controller/SysExpressionController.java     |   99 
 business/src/main/java/com/ycl/controller/ProjectInfoController.java       |   16 
 flowable/src/main/resources/mapper/SysDeployFormMapper.xml                 |   66 
 flowable/src/main/java/com/ycl/mapper/SysDeployFormMapper.java             |   72 
 flowable/src/main/java/com/ycl/service/ISysExpressionService.java          |   62 
 business/src/main/java/com/ycl/mapper/FlowableTypeMapper.java              |    4 
 flowable/src/main/java/com/ycl/config/MyDefaultProcessDiagramCanvas.java   |   95 
 flowable/src/main/java/com/ycl/config/FlowableConfig.java                  |   23 
 flowable/src/main/java/com/ycl/factory/FlowServiceFactory.java             |   41 
 flowable/src/main/java/com/ycl/service/IFlowTaskService.java               |  216 +
 flowable/src/main/java/com/ycl/domain/vo/ReturnTaskNodeVo.java             |   23 
 flowable/src/main/java/com/ycl/service/IFlowInstanceService.java           |   54 
 flowable/src/main/java/com/ycl/domain/dto/FlowFromFieldDTO.java            |   15 
 flowable/src/main/java/com/ycl/domain/dto/FlowSaveXmlVo.java               |   28 
 flowable/src/main/java/com/ycl/mapper/SysFormMapper.java                   |   62 
 flowable/src/main/java/com/ycl/controller/FlowInstanceController.java      |   67 
 flowable/src/main/java/com/ycl/common/enums/FlowComment.java               |   43 
 flowable/src/main/java/com/ycl/controller/FlowTaskController.java          |  278 ++
 flowable/src/main/java/com/ycl/listener/FlowExecutionListener.java         |   36 
 flowable/src/main/java/com/ycl/controller/SysListenerController.java       |   99 
 flowable/src/main/resources/mapper/SysFormMapper.xml                       |   82 
 flowable/src/main/java/com/ycl/service/impl/FlowInstanceServiceImpl.java   |  120 
 flowable/src/main/resources/mapper/SysTaskFormMapper.xml                   |   61 
 flowable/src/main/resources/mapper/FlowDeployMapper.xml                    |   31 
 flowable/src/main/java/com/ycl/common/expand/el/FlowEl.java                |   32 
 flowable/src/main/java/com/ycl/service/ISysListenerService.java            |   62 
 flowable/src/main/java/com/ycl/domain/entity/SysExpression.java            |   95 
 flowable/pom.xml                                                           |    7 
 business/src/main/java/com/ycl/service/impl/FlowableTypeServiceImpl.java   |   73 
 flowable/src/main/java/com/ycl/domain/entity/SysForm.java                  |   70 
 flowable/src/main/java/com/ycl/flow/CustomProcessDiagramCanvas.java        |  370 ++
 flowable/src/main/java/com/ycl/service/impl/SysDeployFormServiceImpl.java  |  107 
 flowable/src/main/java/com/ycl/common/constant/ProcessConstants.java       |   80 
 flowable/src/main/java/com/ycl/flow/FlowableUtils.java                     |  702 +++++
 flowable/src/main/java/com/ycl/domain/vo/FlowQueryVo.java                  |   33 
 flowable/src/main/java/com/ycl/listener/FlowTaskListener.java              |   32 
 business/src/main/java/com/ycl/service/FlowableTypeService.java            |    3 
 flowable/src/main/java/com/ycl/service/IFlowDefinitionService.java         |   80 
 /dev/null                                                                  |   72 
 flowable/src/main/java/com/ycl/controller/SysFormController.java           |  111 
 flowable/src/main/java/com/ycl/mapper/FlowDeployMapper.java                |   22 
 flowable/src/main/java/com/ycl/flow/CustomProcessDiagramGenerator.java     |  404 +++
 business/src/main/java/com/ycl/domain/entity/FlowableType.java             |   49 
 flowable/src/main/java/com/ycl/domain/vo/FlowTaskVo.java                   |   56 
 flowable/src/main/java/com/ycl/domain/dto/FlowNextDto.java                 |   30 
 flowable/src/main/java/com/ycl/service/ISysFormService.java                |   61 
 flowable/src/main/java/com/ycl/mapper/SysListenerMapper.java               |   62 
 72 files changed, 7,512 insertions(+), 103 deletions(-)

diff --git a/business/src/main/java/com/ycl/controller/FlowableTypeController.java b/business/src/main/java/com/ycl/controller/FlowableTypeController.java
index 3541bf4..e7f1588 100644
--- a/business/src/main/java/com/ycl/controller/FlowableTypeController.java
+++ b/business/src/main/java/com/ycl/controller/FlowableTypeController.java
@@ -3,6 +3,10 @@
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.ycl.common.base.Result;
+import com.ycl.common.constant.UserConstants;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.domain.entity.SysMenu;
 import com.ycl.common.group.Add;
 import com.ycl.common.group.Update;
 import com.ycl.domain.entity.FlowableType;
@@ -21,6 +25,7 @@
 import org.springframework.web.bind.annotation.*;
 
 import javax.validation.constraints.NotEmpty;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -31,7 +36,7 @@
 @Api(value = "宸ヤ綔娴佸垎绫�", tags = "宸ヤ綔娴佸垎绫荤鐞�")
 @RestController
 @RequestMapping("/flowable_type")
-public class FlowableTypeController {
+public class FlowableTypeController extends BaseController {
 
     private final FlowableTypeService flowableTypeService;
 
@@ -39,6 +44,10 @@
     @ApiOperation(value = "娣诲姞", notes = "娣诲姞")
 //    @PreAuthorize("hasAuthority('flowableType:add')")
     public Result add(@RequestBody @Validated(Add.class) FlowableType form) {
+        form.setCreateBy(getUsername());
+        form.setCreateTime(new Date());
+        form.setUpdateBy(getUsername());
+        form.setUpdateTime(new Date());
         flowableTypeService.save(form);
         return Result.ok();
     }
@@ -60,13 +69,15 @@
     }
 
 
-    @GetMapping("/page")
-    @ApiOperation(value = "鍒嗛〉", notes = "鍒嗛〉")
+    @GetMapping("/list")
 //    @PreAuthorize("hasAuthority('flowableType:page')")
-    public Result page(AbsQuery query) {
-        IPage<FlowableType> page = PageUtil.getPage(query, FlowableType.class);
-        flowableTypeService.page(page);
-        return Result.ok().data(page.getRecords()).total(page.getTotal());
+    public Result list(FlowableType flowableType) {
+        List<FlowableType> list = flowableTypeService.selectTypeList(flowableType);
+        return Result.ok().data(list);
     }
-
+    @GetMapping("/tree_select")
+    public AjaxResult treeSelect(FlowableType flowableType) {
+        List<FlowableType> list = flowableTypeService.selectTypeList(flowableType);
+        return success(flowableTypeService.buildTreeSelect(list));
+    }
 }
diff --git a/business/src/main/java/com/ycl/controller/ProjectInfoController.java b/business/src/main/java/com/ycl/controller/ProjectInfoController.java
index d0144ee..1d14514 100644
--- a/business/src/main/java/com/ycl/controller/ProjectInfoController.java
+++ b/business/src/main/java/com/ycl/controller/ProjectInfoController.java
@@ -26,55 +26,55 @@
 @RequiredArgsConstructor
 @Api(value = "椤圭洰绠$悊鍩虹淇℃伅琛�", tags = "椤圭洰绠$悊鍩虹淇℃伅琛ㄧ鐞�")
 @RestController
-@RequestMapping("/api/project-info")
+@RequestMapping("/project/info")
 public class ProjectInfoController {
 
     private final ProjectInfoService projectInfoService;
 
     @PostMapping
     @ApiOperation(value = "娣诲姞", notes = "娣诲姞")
-    @PreAuthorize("hasAuthority('projectInfo:add')")
+//    @PreAuthorize("hasAuthority('projectInfo:add')")
     public Result add(@RequestBody @Validated(Add.class) ProjectInfoForm form) {
         return projectInfoService.add(form);
     }
 
     @PutMapping
     @ApiOperation(value = "淇敼", notes = "淇敼")
-    @PreAuthorize("hasAuthority('projectInfo:edit')")
+//    @PreAuthorize("hasAuthority('projectInfo:edit')")
     public Result update(@RequestBody @Validated(Update.class) ProjectInfoForm form) {
         return projectInfoService.update(form);
     }
 
     @DeleteMapping("/{id}")
     @ApiOperation(value = "ID鍒犻櫎", notes = "ID鍒犻櫎")
-    @PreAuthorize("hasAuthority('projectInfo:del')")
+//    @PreAuthorize("hasAuthority('projectInfo:del')")
     public Result removeById(@PathVariable("id") String id) {
         return projectInfoService.removeById(id);
     }
 
     @DeleteMapping("/batch")
     @ApiOperation(value = "鎵归噺鍒犻櫎", notes = "鎵归噺鍒犻櫎")
-    @PreAuthorize("hasAuthority('projectInfo:del:batch')")
+//    @PreAuthorize("hasAuthority('projectInfo:del:batch')")
     public Result remove(@RequestBody @NotEmpty(message = "璇烽�夋嫨鏁版嵁") List<String> ids) {
         return projectInfoService.remove(ids);
     }
 
     @GetMapping("/page")
     @ApiOperation(value = "鍒嗛〉", notes = "鍒嗛〉")
-    @PreAuthorize("hasAuthority('projectInfo:page')")
+//    @PreAuthorize("hasAuthority('projectInfo:page')")
     public Result page(ProjectInfoQuery query) {
         return projectInfoService.page(query);
     }
 
     @GetMapping("/{id}")
     @ApiOperation(value = "璇︽儏", notes = "璇︽儏")
-    @PreAuthorize("hasAuthority('projectInfo:detail')")
+//    @PreAuthorize("hasAuthority('projectInfo:detail')")
     public Result detail(@PathVariable("id") Integer id) {
         return projectInfoService.detail(id);
     }
 
     @GetMapping("/list")
-    @PreAuthorize("hasAuthority('projectInfo:list')")
+//    @PreAuthorize("hasAuthority('projectInfo:list')")
     @ApiOperation(value = "鍒楄〃", notes = "鍒楄〃")
     public Result list() {
         return projectInfoService.all();
diff --git a/business/src/main/java/com/ycl/domain/entity/FlowableType.java b/business/src/main/java/com/ycl/domain/entity/FlowableType.java
index fa18704..553b018 100644
--- a/business/src/main/java/com/ycl/domain/entity/FlowableType.java
+++ b/business/src/main/java/com/ycl/domain/entity/FlowableType.java
@@ -1,21 +1,28 @@
 package com.ycl.domain.entity;
 
-import com.baomidou.mybatisplus.annotation.FieldFill;
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ycl.common.core.domain.BaseEntity;
+import com.ycl.common.core.domain.entity.SysMenu;
 import com.ycl.system.domain.base.AbsEntity;
 import lombok.Data;
 
+import java.io.Serializable;
 import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
 
 /**
  * 娴佺▼鍒嗙被
  */
 @Data
 @TableName("t_flowable_type")
-public class FlowableType extends AbsEntity {
+public class FlowableType implements Serializable {
 
     private static final long serialVersionUID = 1L;
+    @TableId(value = "id", type = IdType.ASSIGN_ID)
+    private Integer id;
 
     @TableField(value = "name")
     private String name;
@@ -23,17 +30,43 @@
     @TableField(value = "parent_id")
     private Integer parentId;
 
-    @TableField(value = "level")
-    private Integer level;
+    @TableField(value = "order_num")
+    private Integer orderNum;
 
-    @TableField(value = "leaf")
-    private Boolean leaf;
+//    @TableField(value = "level")
+//    private Integer level;
+//
+//    @TableField(value = "leaf")
+//    private Boolean leaf;
 
+    /**
+     * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @TableField(value = "status")
+    private String status;
+
+    /** 鍒涘缓鑰� */
     @TableField(value = "create_by")
     private String createBy;
 
+    /** 鍒涘缓鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(value = "create_time")
+    private Date createTime;
+
+    /** 鏇存柊鑰� */
     @TableField(value = "update_by")
     private String updateBy;
 
+    /** 鏇存柊鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(value = "update_time")
+    private Date updateTime;
 
+    /** 澶囨敞 */
+    @TableField(value = "remark")
+    private String remark;
+
+    @TableField(exist = false)
+    private List<FlowableType> children = new ArrayList<FlowableType>();
 }
diff --git a/business/src/main/java/com/ycl/mapper/FlowableTypeMapper.java b/business/src/main/java/com/ycl/mapper/FlowableTypeMapper.java
index 428a7ee..d867543 100644
--- a/business/src/main/java/com/ycl/mapper/FlowableTypeMapper.java
+++ b/business/src/main/java/com/ycl/mapper/FlowableTypeMapper.java
@@ -4,8 +4,10 @@
 import com.ycl.domain.entity.FlowableType;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 @Mapper
 public interface FlowableTypeMapper extends BaseMapper<FlowableType> {
 
-
+    List<FlowableType> selectTypeList(FlowableType flowableType);
 }
diff --git a/business/src/main/java/com/ycl/service/FlowableTypeService.java b/business/src/main/java/com/ycl/service/FlowableTypeService.java
index 924b6e9..0a8e314 100644
--- a/business/src/main/java/com/ycl/service/FlowableTypeService.java
+++ b/business/src/main/java/com/ycl/service/FlowableTypeService.java
@@ -9,4 +9,7 @@
 public interface FlowableTypeService extends IService<FlowableType> {
 
 
+    List<FlowableType> selectTypeList(FlowableType flowableType);
+
+    List<FlowableType> buildTreeSelect(List<FlowableType> list);
 }
diff --git a/business/src/main/java/com/ycl/service/impl/FlowableTypeServiceImpl.java b/business/src/main/java/com/ycl/service/impl/FlowableTypeServiceImpl.java
index c871d79..63aaca0 100644
--- a/business/src/main/java/com/ycl/service/impl/FlowableTypeServiceImpl.java
+++ b/business/src/main/java/com/ycl/service/impl/FlowableTypeServiceImpl.java
@@ -1,17 +1,14 @@
 package com.ycl.service.impl;
 
-import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ycl.common.base.Result;
 import com.ycl.domain.entity.FlowableType;
-import com.ycl.framework.utils.PageUtil;
 import com.ycl.mapper.FlowableTypeMapper;
 import com.ycl.service.FlowableTypeService;
 import lombok.RequiredArgsConstructor;
-import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
-import org.springframework.util.Assert;
 
+import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -20,4 +17,70 @@
 @RequiredArgsConstructor
 public class FlowableTypeServiceImpl extends ServiceImpl<FlowableTypeMapper, FlowableType> implements FlowableTypeService {
 
+    @Override
+    public List<FlowableType> selectTypeList(FlowableType flowableType) {
+        return baseMapper.selectTypeList(flowableType);
+    }
+
+    @Override
+    public List<FlowableType> buildTreeSelect(List<FlowableType> list) {
+        List<FlowableType> returnList = new ArrayList<FlowableType>();
+        List<Integer> tempList = list.stream().map(FlowableType::getId).collect(Collectors.toList());
+        for (Iterator<FlowableType> iterator = list.iterator(); iterator.hasNext();)
+        {
+            FlowableType type = (FlowableType) iterator.next();
+            // 濡傛灉鏄《绾ц妭鐐�, 閬嶅巻璇ョ埗鑺傜偣鐨勬墍鏈夊瓙鑺傜偣
+            if (!tempList.contains(type.getParentId()))
+            {
+                recursionFn(list, type);
+                returnList.add(type);
+            }
+        }
+        if (returnList.isEmpty())
+        {
+            returnList = list;
+        }
+        return returnList;
+    }
+
+    private void recursionFn(List<FlowableType> list, FlowableType t)
+    {
+        // 寰楀埌瀛愯妭鐐瑰垪琛�
+        List<FlowableType> childList = getChildList(list, t);
+        t.setChildren(childList);
+        for (FlowableType tChild : childList)
+        {
+            if (hasChild(list, tChild))
+            {
+                recursionFn(list, tChild);
+            }
+        }
+    }
+
+    /**
+     * 寰楀埌瀛愯妭鐐瑰垪琛�
+     */
+    private List<FlowableType> getChildList(List<FlowableType> list, FlowableType t)
+    {
+        List<FlowableType> tlist = new ArrayList<FlowableType>();
+        Iterator<FlowableType> it = list.iterator();
+        while (it.hasNext())
+        {
+            FlowableType n = (FlowableType) it.next();
+            if (n.getParentId().longValue() == t.getId().longValue())
+            {
+                tlist.add(n);
+            }
+        }
+        return tlist;
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁鏈夊瓙鑺傜偣
+     */
+    private boolean hasChild(List<FlowableType> list, FlowableType t)
+    {
+        return getChildList(list, t).size() > 0;
+    }
+
 }
diff --git a/business/src/main/resources/mapper/FlowableTypeMapper.xml b/business/src/main/resources/mapper/FlowableTypeMapper.xml
index 456f26d..5fc2af2 100644
--- a/business/src/main/resources/mapper/FlowableTypeMapper.xml
+++ b/business/src/main/resources/mapper/FlowableTypeMapper.xml
@@ -53,5 +53,17 @@
         WHERE
             TP.deleted = 0
     </select>
+    <select id="selectTypeList" parameterType="com.ycl.domain.entity.FlowableType" resultType="com.ycl.domain.entity.FlowableType">
+        select * from t_flowable_type
+        <where>
+            <if test="name != null and name != ''">
+                AND name like concat('%', #{name}, '%')
+            </if>
+            <if test="status != null and status != ''">
+                AND status = #{status}
+            </if>
+        </where>
+        order by parent_id, order_num
+    </select>
 
 </mapper>
diff --git a/common/src/main/java/com/ycl/common/exception/CustomException.java b/common/src/main/java/com/ycl/common/exception/CustomException.java
new file mode 100644
index 0000000..7968b4d
--- /dev/null
+++ b/common/src/main/java/com/ycl/common/exception/CustomException.java
@@ -0,0 +1,43 @@
+package com.ycl.common.exception;
+
+/**
+ * 鑷畾涔夊紓甯�
+ *
+ * @author ruoyi
+ */
+public class CustomException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    private Integer code;
+
+    private String message;
+
+    public CustomException(String message)
+    {
+        this.message = message;
+    }
+
+    public CustomException(String message, Integer code)
+    {
+        this.message = message;
+        this.code = code;
+    }
+
+    public CustomException(String message, Throwable e)
+    {
+        super(message, e);
+        this.message = message;
+    }
+
+    @Override
+    public String getMessage()
+    {
+        return message;
+    }
+
+    public Integer getCode()
+    {
+        return code;
+    }
+}
diff --git a/flowable/pom.xml b/flowable/pom.xml
index a1e8957..6ce5447 100644
--- a/flowable/pom.xml
+++ b/flowable/pom.xml
@@ -44,6 +44,13 @@
             <artifactId>business</artifactId>
         </dependency>
 
+        <!--el琛ㄨ揪寮忚绠�-->
+        <dependency>
+            <groupId>com.googlecode.aviator</groupId>
+            <artifactId>aviator</artifactId>
+            <version>5.3.3</version>
+        </dependency>
+
     </dependencies>
 
 </project>
diff --git a/flowable/src/main/java/com/ycl/common/constant/ProcessConstants.java b/flowable/src/main/java/com/ycl/common/constant/ProcessConstants.java
new file mode 100644
index 0000000..161e31f
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/common/constant/ProcessConstants.java
@@ -0,0 +1,80 @@
+package com.ycl.common.constant;
+
+/**
+ * 娴佺▼甯搁噺淇℃伅
+ *
+ * @author Tony
+ * @date 2021/4/17 22:46
+ */
+public class ProcessConstants {
+
+    /**
+     * 鍔ㄦ�佹暟鎹�
+     */
+    public static final String DYNAMIC = "dynamic";
+
+    /**
+     * 鍥哄畾浠诲姟鎺ユ敹
+     */
+    public static final String FIXED = "fixed";
+
+    /**
+     * 鍗曚釜瀹℃壒浜�
+     */
+    public static final String ASSIGNEE = "assignee";
+
+
+    /**
+     * 鍊欓�変汉
+     */
+    public static final String CANDIDATE_USERS = "candidateUsers";
+
+
+    /**
+     * 瀹℃壒缁�
+     */
+    public static final String CANDIDATE_GROUPS = "candidateGroups";
+
+    /**
+     * 鍗曚釜瀹℃壒浜�
+     */
+    public static final String PROCESS_APPROVAL = "approval";
+
+    /**
+     * 浼氱浜哄憳
+     */
+    public static final String PROCESS_MULTI_INSTANCE_USER = "userList";
+
+    /**
+     * nameapace
+     */
+    public static final String NAMASPASE = "http://flowable.org/bpmn";
+
+    /**
+     * 浼氱鑺傜偣
+     */
+    public static final String PROCESS_MULTI_INSTANCE = "multiInstance";
+
+    /**
+     * 鑷畾涔夊睘鎬� dataType
+     */
+    public static final String PROCESS_CUSTOM_DATA_TYPE = "dataType";
+
+    /**
+     * 鑷畾涔夊睘鎬� userType
+     */
+    public static final String PROCESS_CUSTOM_USER_TYPE = "userType";
+
+    /**
+     * 鍒濆鍖栦汉鍛�
+     */
+    public static final String PROCESS_INITIATOR = "INITIATOR";
+
+
+    /**
+     * 娴佺▼璺宠繃
+     */
+    public static final String FLOWABLE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED";
+
+
+}
diff --git a/flowable/src/main/java/com/ycl/common/enums/FlowComment.java b/flowable/src/main/java/com/ycl/common/enums/FlowComment.java
new file mode 100644
index 0000000..e066c76
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/common/enums/FlowComment.java
@@ -0,0 +1,43 @@
+package com.ycl.common.enums;
+
+/**
+ * 娴佺▼鎰忚绫诲瀷
+ *
+ * @author Tony
+ * @date 2021/4/19
+ */
+public enum FlowComment {
+
+    /**
+     * 璇存槑
+     */
+    NORMAL("1", "姝e父鎰忚"),
+    REBACK("2", "閫�鍥炴剰瑙�"),
+    REJECT("3", "椹冲洖鎰忚"),
+    DELEGATE("4", "濮旀淳鎰忚"),
+    ASSIGN("5", "杞姙鎰忚"),
+    STOP("6", "缁堟娴佺▼");
+
+    /**
+     * 绫诲瀷
+     */
+    private final String type;
+
+    /**
+     * 璇存槑
+     */
+    private final String remark;
+
+    FlowComment(String type, String remark) {
+        this.type = type;
+        this.remark = remark;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/common/expand/el/BaseEl.java b/flowable/src/main/java/com/ycl/common/expand/el/BaseEl.java
new file mode 100644
index 0000000..f7bdad4
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/common/expand/el/BaseEl.java
@@ -0,0 +1,12 @@
+package com.ycl.common.expand.el;
+
+/**
+ * 鎵╁睍琛ㄨ揪寮�
+ *
+ * @author Tony
+ * @date 2023-03-04 09:10
+ */
+public interface BaseEl {
+
+}
+
diff --git a/flowable/src/main/java/com/ycl/common/expand/el/FlowEl.java b/flowable/src/main/java/com/ycl/common/expand/el/FlowEl.java
new file mode 100644
index 0000000..ea7c857
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/common/expand/el/FlowEl.java
@@ -0,0 +1,32 @@
+package com.ycl.common.expand.el;
+
+import com.ycl.system.service.ISysDeptService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 鎵╁睍琛ㄨ揪寮�
+ *
+ * @author Tony
+ * @date 2023-03-04 12:10
+ */
+@Component
+@Slf4j
+public class FlowEl implements BaseEl {
+
+    @Resource
+    private ISysDeptService sysDeptService;
+
+    public String findDeptLeader(String name){
+        log.info("寮�濮嬫煡璇㈣〃杈惧紡鍙橀噺鍊�,getName");
+        return name;
+    }
+
+    public String getName(String name){
+        log.info("寮�濮嬫煡璇㈣〃杈惧紡鍙橀噺鍊�,getName");
+        return name;
+    }
+}
+
diff --git a/flowable/src/main/java/com/ycl/config/FlowableConfig.java b/flowable/src/main/java/com/ycl/config/FlowableConfig.java
new file mode 100644
index 0000000..35f7875
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/config/FlowableConfig.java
@@ -0,0 +1,23 @@
+package com.ycl.config;
+
+import org.flowable.engine.impl.db.DbIdGenerator;
+import org.flowable.spring.SpringProcessEngineConfiguration;
+import org.flowable.spring.boot.EngineConfigurationConfigurer;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 鎵╁睍娴佺▼閰嶇疆
+ * @author Tony
+ * @date 2022-12-26 10:24
+ */
+@Configuration
+public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
+    @Override
+    public void configure(SpringProcessEngineConfiguration engineConfiguration) {
+        engineConfiguration.setActivityFontName("瀹嬩綋");
+        engineConfiguration.setLabelFontName("瀹嬩綋");
+        engineConfiguration.setAnnotationFontName("瀹嬩綋");
+        engineConfiguration.setIdGenerator(new DbIdGenerator());
+    }
+
+}
diff --git a/flowable/src/main/java/com/ycl/config/MyDefaultProcessDiagramCanvas.java b/flowable/src/main/java/com/ycl/config/MyDefaultProcessDiagramCanvas.java
new file mode 100644
index 0000000..9ae30a2
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/config/MyDefaultProcessDiagramCanvas.java
@@ -0,0 +1,95 @@
+package com.ycl.config;//package com.ruoyi.flowable.config;
+//
+//import com.sun.prism.paint.Color;
+//import org.flowable.bpmn.model.AssociationDirection;
+//import org.flowable.image.impl.DefaultProcessDiagramCanvas;
+//
+//import java.awt.*;
+//import java.awt.geom.Line2D;
+//import java.awt.geom.RoundRectangle2D;
+//
+///**
+// * @author Tony
+// * @date 2021-04-03
+// */
+//public class MyDefaultProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
+//    //璁剧疆楂樹寒绾跨殑棰滆壊  杩欓噷鎴戣缃垚缁胯壊
+//    protected static Color HIGHLIGHT_SEQUENCEFLOW_COLOR = Color.GREEN;
+//
+//    public MyDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
+//        super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
+//    }
+//
+//    public MyDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType) {
+//        super(width, height, minX, minY, imageType);
+//    }
+//
+//
+//    /**
+//     * 鐢荤嚎棰滆壊璁剧疆
+//     */
+//    @Override
+//    public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType,
+//                               AssociationDirection associationDirection, boolean highLighted, double scaleFactor) {
+//
+//        Paint originalPaint = g.getPaint();
+//        Stroke originalStroke = g.getStroke();
+//
+//        g.setPaint(CONNECTION_COLOR);
+//        if (connectionType.equals("association")) {
+//            g.setStroke(ASSOCIATION_STROKE);
+//        } else if (highLighted) {
+//            //璁剧疆绾跨殑棰滆壊
+//            g.setPaint(originalPaint);
+//            g.setStroke(HIGHLIGHT_FLOW_STROKE);
+//        }
+//
+//        for (int i = 1; i < xPoints.length; i++) {
+//            Integer sourceX = xPoints[i - 1];
+//            Integer sourceY = yPoints[i - 1];
+//            Integer targetX = xPoints[i];
+//            Integer targetY = yPoints[i];
+//            Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY);
+//            g.draw(line);
+//        }
+//
+//        if (isDefault) {
+//            Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
+//            drawDefaultSequenceFlowIndicator(line, scaleFactor);
+//        }
+//
+//        if (conditional) {
+//            Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
+//            drawConditionalSequenceFlowIndicator(line, scaleFactor);
+//        }
+//
+//        if (associationDirection == AssociationDirection.ONE || associationDirection == AssociationDirection.BOTH) {
+//            Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]);
+//            drawArrowHead(line, scaleFactor);
+//        }
+//        if (associationDirection == AssociationDirection.BOTH) {
+//            Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]);
+//            drawArrowHead(line, scaleFactor);
+//        }
+//        g.setPaint(originalPaint);
+//        g.setStroke(originalStroke);
+//    }
+//
+//    /**
+//     * 楂樹寒鑺傜偣璁剧疆
+//     */
+//    @Override
+//    public void drawHighLight(int x, int y, int width, int height) {
+//        Paint originalPaint = g.getPaint();
+//        Stroke originalStroke = g.getStroke();
+//        //璁剧疆楂樹寒鑺傜偣鐨勯鑹�
+//        g.setPaint(HIGHLIGHT_COLOR);
+//        g.setStroke(THICK_TASK_BORDER_STROKE);
+//
+//        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
+//        g.draw(rect);
+//
+//        g.setPaint(originalPaint);
+//        g.setStroke(originalStroke);
+//    }
+//}
diff --git a/flowable/src/main/java/com/ycl/controller/DynamicFlowController.java b/flowable/src/main/java/com/ycl/controller/DynamicFlowController.java
deleted file mode 100644
index 82ea0c1..0000000
--- a/flowable/src/main/java/com/ycl/controller/DynamicFlowController.java
+++ /dev/null
@@ -1,208 +0,0 @@
-package com.ycl.controller;
-
-
-import com.ycl.common.core.domain.AjaxResult;
-import com.ycl.common.utils.StringUtils;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import org.flowable.bpmn.BpmnAutoLayout;
-import org.flowable.bpmn.model.Process;
-import org.flowable.bpmn.model.*;
-import org.flowable.engine.HistoryService;
-import org.flowable.engine.RepositoryService;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.repository.Deployment;
-import org.flowable.engine.runtime.Execution;
-import org.flowable.task.api.Task;
-import org.flowable.validation.ValidationError;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-@Api(value = "鍔ㄦ�佹祦绋嬫帴鍙�")
-@Controller
-@RequiredArgsConstructor
-@RequestMapping("/dynamic/flow")
-public class DynamicFlowController {
-
-    private final RuntimeService runtimeService;
-
-    private final TaskService taskService;
-
-    private final RepositoryService repositoryService;
-
-    private final HistoryService historyService;
-
-
-    @ApiOperation("閬嶅巻娴佺▼淇℃伅")
-    @GetMapping(value = "/info/{processInstanceId}")
-    @ResponseBody
-    public AjaxResult remove(@PathVariable String processInstanceId) {
-        String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult().getProcessDefinitionId();
-        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
-        Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
-        for (FlowElement flowElement : flowElements) {
-            if (flowElement instanceof UserTask) {
-                UserTask userTask = (UserTask) flowElement;
-                System.out.println(flowElement.getName());
-                System.out.println(flowElement.getId());
-                System.out.println(userTask.getAssignee());
-                String assigneeEl = userTask.getAssignee();
-                if (StringUtils.isBlank(assigneeEl)) {
-                    continue;
-                }
-                if (assigneeEl.startsWith("${") && assigneeEl.endsWith("}") && assigneeEl.length() > 3) {
-                    String assignee = assigneeEl.substring(2, assigneeEl.length() - 2);
-                    System.out.println("assignee:" + assignee);
-                }
-            }
-        }
-        return AjaxResult.success(flowElements);
-    }
-
-    @ApiOperation("鎾ら攢:寮哄埗缁撴潫涓�涓祦绋�")
-    @GetMapping(value = "/forceEnd/{taskId}")
-    @ResponseBody
-    public AjaxResult forceEnd(@PathVariable String taskId) {
-        Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
-        String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult().getProcessDefinitionId();
-        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
-        // 瀵绘壘娴佺▼瀹炰緥褰撳墠浠诲姟鐨刟ctiveId
-        Execution execution = runtimeService.createExecutionQuery().executionId(t.getExecutionId()).singleResult();
-        String activityId = execution.getActivityId();
-        FlowNode currentNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
-        // 鍒涘缓缁撴潫鑺傜偣鍜岃繛鎺ョ嚎
-        EndEvent end = new EndEvent();
-        end.setName("寮哄埗缁撴潫");
-        end.setId("forceEnd");
-        List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
-        SequenceFlow newSequenceFlow = new SequenceFlow();
-        newSequenceFlow.setId("newFlow");
-        newSequenceFlow.setSourceFlowElement(currentNode);
-        newSequenceFlow.setTargetFlowElement(end);
-        newSequenceFlowList.add(newSequenceFlow);
-        // 澶囦唤鍘熸湁鏂瑰悜
-        List<SequenceFlow> dataflows = currentNode.getOutgoingFlows();
-        List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
-        oriSequenceFlows.addAll(dataflows);
-        // 娓呯┖鍘熸湁鏂瑰悜
-        currentNode.getOutgoingFlows().clear();
-        // 璁剧疆鏂版柟鍚�
-        currentNode.setOutgoingFlows(newSequenceFlowList);
-        // 瀹屾垚褰撳墠浠诲姟
-        taskService.addComment(taskId, t.getProcessInstanceId(), "comment", "鎾ら攢娴佺▼");
-        taskService.complete(taskId);
-        // 鎭㈠鍘熸湁鏂瑰悜
-        currentNode.setOutgoingFlows(oriSequenceFlows);
-        return AjaxResult.success();
-    }
-
-    @ApiOperation("椹冲洖鎴栬烦杞埌鎸囧畾鑺傜偣")
-    @GetMapping(value = "/jump/{taskId}/{sid}")
-    @ResponseBody
-    public AjaxResult jump(@PathVariable String taskId, @PathVariable String sid) {
-        Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
-        String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult().getProcessDefinitionId();
-        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
-        // 瀵绘壘娴佺▼瀹炰緥褰撳墠浠诲姟鐨刟ctiveId
-        Execution execution = runtimeService.createExecutionQuery().executionId(t.getExecutionId()).singleResult();
-        String activityId = execution.getActivityId();
-        FlowNode currentNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
-        FlowNode targetNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sid);
-        // 鍒涘缓杩炴帴绾�
-        List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
-        SequenceFlow newSequenceFlow = new SequenceFlow();
-        newSequenceFlow.setId("newFlow");
-        newSequenceFlow.setSourceFlowElement(currentNode);
-        newSequenceFlow.setTargetFlowElement(targetNode);
-        newSequenceFlowList.add(newSequenceFlow);
-        // 澶囦唤鍘熸湁鏂瑰悜
-        List<SequenceFlow> dataflows = currentNode.getOutgoingFlows();
-        List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
-        oriSequenceFlows.addAll(dataflows);
-        // 娓呯┖鍘熸湁鏂瑰悜
-        currentNode.getOutgoingFlows().clear();
-        // 璁剧疆鏂版柟鍚�
-        currentNode.setOutgoingFlows(newSequenceFlowList);
-        // 瀹屾垚褰撳墠浠诲姟
-        taskService.addComment(taskId, t.getProcessInstanceId(), "comment", "璺宠浆鑺傜偣");
-        taskService.complete(taskId);
-        // 鎭㈠鍘熸湁鏂瑰悜
-        currentNode.setOutgoingFlows(oriSequenceFlows);
-        return AjaxResult.success();
-    }
-
-    @ApiOperation("鍔ㄦ�佸垱寤烘祦绋�")
-    @GetMapping(value = "/createProcess")
-    @ResponseBody
-    public AjaxResult createProcess() {
-        // 寮�濮嬭妭鐐圭殑灞炴��
-        StartEvent startEvent = new StartEvent();
-        startEvent.setId("start");
-        startEvent.setName("start");
-        // 鏅�歎serTask鑺傜偣
-        UserTask userTask = new UserTask();
-        userTask.setId("userTask");
-        userTask.setName("瀹℃壒浠诲姟");
-        // 缁撴潫鑺傜偣灞炴��
-        EndEvent endEvent = new EndEvent();
-        endEvent.setId("end");
-        endEvent.setName("end");
-        // 杩炵嚎淇℃伅
-        List<SequenceFlow> flows = new ArrayList<SequenceFlow>();
-        List<SequenceFlow> toEnd = new ArrayList<SequenceFlow>();
-        SequenceFlow s1 = new SequenceFlow();
-        s1.setId("flow1");
-        s1.setName("flow1");
-        s1.setSourceRef(startEvent.getId());
-        s1.setTargetRef(userTask.getId());
-        flows.add(s1);
-
-        SequenceFlow s2 = new SequenceFlow();
-        s2.setId("flow2");
-        s2.setName("flow2");
-        s2.setSourceRef(userTask.getId());
-        s2.setTargetRef(endEvent.getId());
-        toEnd.add(s2);
-        startEvent.setOutgoingFlows(flows);
-        userTask.setOutgoingFlows(toEnd);
-
-        // 缁欐祦绋嬪璞℃坊鍔犲厓绱�
-        Process process = new Process();
-        process.setId("dynamicProcess");
-        process.setName("鍔ㄦ�佹祦绋�");
-        process.addFlowElement(startEvent);
-        process.addFlowElement(s1);
-        process.addFlowElement(userTask);
-        process.addFlowElement(s2);
-        process.addFlowElement(endEvent);
-        // 鍒涘缓妯″瀷瀵硅薄
-        BpmnModel bpmnModel = new BpmnModel();
-        bpmnModel.addProcess(process);
-        // 娴佺▼鍥捐嚜鍔ㄥ竷灞�
-        new BpmnAutoLayout(bpmnModel).execute();
-
-        // 妯″瀷鍚堟硶鎬ф牎楠�
-        List<ValidationError> validationErrorList = repositoryService.validateProcess(bpmnModel);
-        if (validationErrorList.size() == 0) {
-            // 妯″瀷鍚堟硶灏遍儴缃叉祦绋�
-            Deployment deploy = repositoryService.createDeployment().category("dynamic")
-                    .key("dynamicProcess")
-                    .addBpmnModel("dynamicProcess.bpmn20.xml", bpmnModel)
-                    .deploy();
-            return AjaxResult.success("success");
-        } else {
-            return AjaxResult.error("fail");
-        }
-    }
-
-}
diff --git a/flowable/src/main/java/com/ycl/controller/FlowController.java b/flowable/src/main/java/com/ycl/controller/FlowController.java
deleted file mode 100644
index 55cfc4a..0000000
--- a/flowable/src/main/java/com/ycl/controller/FlowController.java
+++ /dev/null
@@ -1,223 +0,0 @@
-package com.ycl.controller;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.ycl.common.core.controller.BaseController;
-import com.ycl.common.core.domain.AjaxResult;
-import com.ycl.common.core.page.TableDataInfo;
-import com.ycl.common.utils.StringUtils;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import org.apache.commons.io.IOUtils;
-
-import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.editor.constants.ModelDataJsonConstants;
-import org.flowable.editor.language.json.converter.BpmnJsonConverter;
-import org.flowable.engine.ProcessEngineConfiguration;
-import org.flowable.engine.RepositoryService;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.repository.Model;
-import org.flowable.engine.repository.ProcessDefinition;
-import org.flowable.engine.repository.ProcessDefinitionQuery;
-import org.flowable.image.ProcessDiagramGenerator;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
-import com.ycl.system.domain.Process;
-
-import javax.annotation.Resource;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletResponse;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.zip.ZipInputStream;
-
-/**
- * 娴佺▼绠$悊
- */
-@Api(value = "閮ㄧ讲绠$悊鎺ュ彛")
-@Controller
-@RequiredArgsConstructor
-@RequestMapping("/flow/manage")
-public class FlowController extends BaseController {
-
-    private final RuntimeService runtimeService;
-
-    private final TaskService taskService;
-
-    private final RepositoryService repositoryService;
-
-    private final ProcessEngineConfiguration configuration;
-
-    private static final String prefix = "flowable/manage";
-
-    @GetMapping("")
-    public String processList()
-    {
-        return prefix + "/processList";
-    }
-
-    @GetMapping("deploy")
-    public String deploy()
-    {
-        return prefix + "/deployProcess";
-    }
-
-    @ApiOperation("涓婁紶涓�涓伐浣滄祦鏂囦欢")
-    @RequestMapping(value = "/uploadworkflow", method = RequestMethod.POST)
-    @ResponseBody
-    public AjaxResult fileupload(@RequestParam MultipartFile uploadfile) {
-        try {
-            String filename = uploadfile.getOriginalFilename();
-            InputStream is = uploadfile.getInputStream();
-            if (filename.endsWith("zip")) {
-                repositoryService.createDeployment().name(filename).addZipInputStream(new ZipInputStream(is)).deploy();
-            } else if (filename.endsWith("bpmn") || filename.endsWith("xml")) {
-                repositoryService.createDeployment().name(filename).addInputStream(filename, is).deploy();
-            } else {
-                return AjaxResult.error("鏂囦欢鏍煎紡閿欒");
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-            return AjaxResult.error("閮ㄧ讲澶辫触");
-        }
-        return AjaxResult.success("閮ㄧ讲鎴愬姛");
-    }
-
-    @ApiOperation("鏌ヨ宸查儴缃插伐浣滄祦鍒楄〃")
-    @GetMapping(value = "/getprocesslists")
-    @ResponseBody
-    public TableDataInfo getlist(@RequestParam(required = false) String key, @RequestParam(required = false) String name,
-                                 @RequestParam(required = true) Boolean latest, Integer pageSize, Integer pageNum) {
-        ProcessDefinitionQuery queryCondition = repositoryService.createProcessDefinitionQuery();
-        if (StringUtils.isNotEmpty(key)) {
-            queryCondition.processDefinitionKey(key);
-        }
-        if (StringUtils.isNotEmpty(name)) {
-            queryCondition.processDefinitionName(name);
-        }
-        if (latest) {
-            queryCondition.latestVersion();
-        }
-        int total = queryCondition.list().size();
-        int start = (pageNum - 1) * pageSize;
-        List<ProcessDefinition> pageList = queryCondition.orderByDeploymentId().desc().listPage(start, pageSize);
-        List<Process> mylist = new ArrayList<Process>();
-        for (int i = 0; i < pageList.size(); i++) {
-            Process p = new Process();
-            p.setDeploymentId(pageList.get(i).getDeploymentId());
-            p.setId(pageList.get(i).getId());
-            p.setKey(pageList.get(i).getKey());
-            p.setName(pageList.get(i).getName());
-            p.setResourceName(pageList.get(i).getResourceName());
-            p.setDiagramresourceName(pageList.get(i).getDiagramResourceName());
-            p.setSuspended(pageList.get(i).isSuspended());
-            p.setVersion(pageList.get(i).getVersion());
-            mylist.add(p);
-        }
-        TableDataInfo rspData = new TableDataInfo();
-        rspData.setCode(0);
-        rspData.setRows(mylist);
-        rspData.setTotal(total);
-        return rspData;
-    }
-
-    @ApiOperation("鍒犻櫎涓�娆¢儴缃茬殑宸ヤ綔娴�")
-    @RequestMapping(value = "/remove/{deploymentId}", method = RequestMethod.POST)
-    @ResponseBody
-    public AjaxResult remove(@PathVariable String deploymentId) {
-        repositoryService.deleteDeployment(deploymentId, true);
-        return AjaxResult.success();
-    }
-
-
-    @ApiOperation("鏌ョ湅宸ヤ綔娴佸浘鐗�")
-    @RequestMapping(value = "/showresource", method = RequestMethod.GET)
-    public void showresource(@RequestParam("pdid") String pdid,
-                       HttpServletResponse response) throws Exception {
-        response.setContentType("image/jpeg;charset=UTF-8");
-        response.setHeader("Content-Disposition","inline;filename=process.jpg");
-        BpmnModel bpmnModel = repositoryService.getBpmnModel(pdid);
-        ProcessDiagramGenerator diagramGenerator = configuration.getProcessDiagramGenerator();
-        InputStream is = diagramGenerator.generateDiagram(bpmnModel, "png",  "瀹嬩綋", "瀹嬩綋", "瀹嬩綋", configuration.getClassLoader(), true);
-        ServletOutputStream output = response.getOutputStream();
-        IOUtils.copy(is, output);
-    }
-
-    @ApiOperation("鏌ョ湅宸ヤ綔娴佸畾涔�")
-    @RequestMapping(value = "/showProcessDefinition/{pdid}/{resource}", method = RequestMethod.GET)
-    public void showProcessDefinition(@PathVariable("pdid") String pdid, @PathVariable(value="resource") String resource,
-                       HttpServletResponse response) throws Exception {
-        response.setContentType("application/xml");
-        response.setHeader("Content-Disposition","inline;filename=process.bpmn20.xml");
-        InputStream is = repositoryService.getResourceAsStream(pdid, resource);
-        ServletOutputStream output = response.getOutputStream();
-        IOUtils.copy(is, output);
-    }
-
-    @ApiOperation("灏嗘祦绋嬪畾涔夎浆涓烘ā鍨�")
-    @RequestMapping(value = "/exchangeProcessToModel/{pdid}", method = RequestMethod.GET)
-    @ResponseBody
-    public String exchangeProcessToModel(@PathVariable("pdid") String pdid, HttpServletResponse response) throws Exception {
-        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionId(pdid).singleResult();
-        BpmnModel bpmnModel = repositoryService.getBpmnModel(definition.getId());
-        ObjectNode objectNode = new BpmnJsonConverter().convertToJson(bpmnModel);
-        Model modelData = repositoryService.newModel();
-        modelData.setKey(definition.getKey());
-        modelData.setName(definition.getName());
-        modelData.setCategory(definition.getCategory());
-        ObjectNode modelJson = new ObjectMapper().createObjectNode();
-        modelJson.put(ModelDataJsonConstants.MODEL_NAME, definition.getName());
-        modelJson.put(ModelDataJsonConstants.MODEL_DESCRIPTION, definition.getDescription());
-        List<Model> models = repositoryService.createModelQuery().modelKey(definition.getKey()).list();
-        if (models.size() > 0) {
-            Integer version = models.get(0).getVersion();
-            version++;
-            modelJson.put(ModelDataJsonConstants.MODEL_REVISION, version);
-            // 鍒犻櫎鏃фā鍨�
-            repositoryService.deleteModel(models.get(0).getId());
-            modelData.setVersion(version);
-        } else {
-            modelJson.put(ModelDataJsonConstants.MODEL_REVISION, 1);
-        }
-        modelData.setMetaInfo(modelJson.toString());
-        modelData.setDeploymentId(definition.getDeploymentId());
-        // 淇濆瓨鏂版ā鍨�
-        repositoryService.saveModel(modelData);
-        // 淇濆瓨妯″瀷json
-        repositoryService.addModelEditorSource(modelData.getId(), objectNode.toString().getBytes(StandardCharsets.UTF_8));
-        return objectNode.toString();
-    }
-
-    @ApiOperation("鎸傝捣涓�涓祦绋嬪畾涔�")
-    @RequestMapping(value = "/suspendProcessDefinition", method = RequestMethod.GET)
-    @ResponseBody
-    public AjaxResult suspendProcessDefinition(@RequestParam("pdid") String pdid, @RequestParam("flag") Boolean flag,
-                                               @RequestParam(value="date", required = false) String date) throws Exception {
-        if (StringUtils.isNotEmpty(date)) {
-            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-            repositoryService.suspendProcessDefinitionById(pdid, flag,  sdf.parse(date));
-        } else {
-            repositoryService.suspendProcessDefinitionById(pdid, flag, null);
-        }
-        return AjaxResult.success();
-    }
-
-    @ApiOperation("婵�娲讳竴涓祦绋嬪畾涔�")
-    @RequestMapping(value = "/activateProcessDefinition", method = RequestMethod.GET)
-    @ResponseBody
-    public AjaxResult activateProcessDefinition(@RequestParam("pdid") String pdid, @RequestParam("flag") Boolean flag, @RequestParam(value="date", required = false) String date) throws Exception {
-        if (StringUtils.isNotEmpty(date)) {
-            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-            repositoryService.activateProcessDefinitionById(pdid, flag,  sdf.parse(date));
-        } else {
-            repositoryService.activateProcessDefinitionById(pdid, flag, null);
-        }
-        return AjaxResult.success();
-    }
-}
diff --git a/flowable/src/main/java/com/ycl/controller/FlowDefinitionController.java b/flowable/src/main/java/com/ycl/controller/FlowDefinitionController.java
new file mode 100644
index 0000000..ed436a0
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/FlowDefinitionController.java
@@ -0,0 +1,203 @@
+package com.ycl.controller;
+
+import com.ycl.common.annotation.Log;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.domain.entity.SysRole;
+import com.ycl.common.core.domain.entity.SysUser;
+import com.ycl.common.enums.BusinessType;
+import com.ycl.domain.dto.FlowProcDefDto;
+import com.ycl.domain.dto.FlowSaveXmlVo;
+import com.ycl.domain.entity.SysExpression;
+import com.ycl.service.IFlowDefinitionService;
+import com.ycl.service.ISysExpressionService;
+import com.ycl.system.service.ISysRoleService;
+import com.ycl.system.service.ISysUserService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletResponse;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 宸ヤ綔娴佺▼瀹氫箟
+ * </p>
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Slf4j
+@Api(tags = "娴佺▼瀹氫箟")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/flowable/definition")
+public class FlowDefinitionController extends BaseController {
+
+    private final IFlowDefinitionService flowDefinitionService;
+    private final ISysUserService userService;
+    private final ISysRoleService sysRoleService;
+    private final ISysExpressionService sysExpressionService;
+
+    @GetMapping(value = "/list")
+    @ApiOperation(value = "娴佺▼瀹氫箟鍒楄〃", response = FlowProcDefDto.class)
+    public AjaxResult list(@ApiParam(value = "褰撳墠椤电爜", required = true) @RequestParam Integer pageNum,
+                           @ApiParam(value = "姣忛〉鏉℃暟", required = true) @RequestParam Integer pageSize,
+                           @ApiParam(value = "娴佺▼鍚嶇О", required = false) @RequestParam(required = false) String name) {
+        return AjaxResult.success(flowDefinitionService.list(name, pageNum, pageSize));
+    }
+
+
+    @ApiOperation(value = "瀵煎叆娴佺▼鏂囦欢", notes = "涓婁紶bpmn20鐨剎ml鏂囦欢")
+    @PostMapping("/import")
+    public AjaxResult importFile(@RequestParam(required = false) String name,
+                                 @RequestParam(required = false) String category,
+                                 MultipartFile file) {
+        InputStream in = null;
+        try {
+            in = file.getInputStream();
+            flowDefinitionService.importFile(name, category, in);
+        } catch (Exception e) {
+            log.error("瀵煎叆澶辫触:", e);
+            return AjaxResult.success(e.getMessage());
+        } finally {
+            try {
+                if (in != null) {
+                    in.close();
+                }
+            } catch (IOException e) {
+                log.error("鍏抽棴杈撳叆娴佸嚭閿�", e);
+            }
+        }
+
+        return AjaxResult.success("瀵煎叆鎴愬姛");
+    }
+
+
+    @ApiOperation(value = "璇诲彇xml鏂囦欢")
+    @GetMapping("/readXml/{deployId}")
+    public AjaxResult readXml(@ApiParam(value = "娴佺▼瀹氫箟id") @PathVariable(value = "deployId") String deployId) {
+        try {
+            return flowDefinitionService.readXml(deployId);
+        } catch (Exception e) {
+            return AjaxResult.error("鍔犺浇xml鏂囦欢寮傚父");
+        }
+
+    }
+
+    @ApiOperation(value = "璇诲彇鍥剧墖鏂囦欢")
+    @GetMapping("/readImage/{deployId}")
+    public void readImage(@ApiParam(value = "娴佺▼瀹氫箟id") @PathVariable(value = "deployId") String deployId, HttpServletResponse response) {
+        OutputStream os = null;
+        BufferedImage image = null;
+        try {
+            image = ImageIO.read(flowDefinitionService.readImage(deployId));
+            response.setContentType("image/png");
+            os = response.getOutputStream();
+            if (image != null) {
+                ImageIO.write(image, "png", os);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (os != null) {
+                    os.flush();
+                    os.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+
+
+    @ApiOperation(value = "淇濆瓨娴佺▼璁捐鍣ㄥ唴鐨剎ml鏂囦欢")
+    @Log(title = "娴佺▼瀹氫箟", businessType = BusinessType.INSERT)
+    @PostMapping("/save")
+    public AjaxResult save(@RequestBody FlowSaveXmlVo vo) {
+        InputStream in = null;
+        try {
+            in = new ByteArrayInputStream(vo.getXml().getBytes(StandardCharsets.UTF_8));
+            flowDefinitionService.importFile(vo.getName(), vo.getCategory(), in);
+        } catch (Exception e) {
+            log.error("瀵煎叆澶辫触:", e);
+            return AjaxResult.error(e.getMessage());
+        } finally {
+            try {
+                if (in != null) {
+                    in.close();
+                }
+            } catch (IOException e) {
+                log.error("鍏抽棴杈撳叆娴佸嚭閿�", e);
+            }
+        }
+
+        return AjaxResult.success("瀵煎叆鎴愬姛");
+    }
+
+    @ApiOperation(value = "鍙戣捣娴佺▼")
+    @Log(title = "鍙戣捣娴佺▼", businessType = BusinessType.INSERT)
+    @PostMapping("/start/{procDefId}")
+    public AjaxResult start(@ApiParam(value = "娴佺▼瀹氫箟id") @PathVariable(value = "procDefId") String procDefId,
+                            @ApiParam(value = "鍙橀噺闆嗗悎,json瀵硅薄") @RequestBody Map<String, Object> variables) {
+        return flowDefinitionService.startProcessInstanceById(procDefId, variables);
+    }
+
+    @ApiOperation(value = "婵�娲绘垨鎸傝捣娴佺▼瀹氫箟")
+    @Log(title = "婵�娲�/鎸傝捣娴佺▼", businessType = BusinessType.UPDATE)
+    @PutMapping(value = "/updateState")
+    public AjaxResult updateState(@ApiParam(value = "1:婵�娲�,2:鎸傝捣", required = true) @RequestParam Integer state,
+                                  @ApiParam(value = "娴佺▼閮ㄧ讲ID", required = true) @RequestParam String deployId) {
+        flowDefinitionService.updateState(state, deployId);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "鍒犻櫎娴佺▼")
+    @Log(title = "鍒犻櫎娴佺▼", businessType = BusinessType.DELETE)
+    @DeleteMapping(value = "/{deployIds}")
+    public AjaxResult delete(@PathVariable String[] deployIds) {
+        for (String deployId : deployIds) {
+            flowDefinitionService.delete(deployId);
+        }
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "鎸囧畾娴佺▼鍔炵悊浜哄憳鍒楄〃")
+    @GetMapping("/userList")
+    public AjaxResult userList(SysUser user) {
+        List<SysUser> list = userService.selectUserList(user);
+        return AjaxResult.success(list);
+    }
+
+    @ApiOperation(value = "鎸囧畾娴佺▼鍔炵悊缁勫垪琛�")
+    @GetMapping("/roleList")
+    public AjaxResult roleList(SysRole role) {
+        List<SysRole> list = sysRoleService.selectRoleList(role);
+        return AjaxResult.success(list);
+    }
+
+    @ApiOperation(value = "鎸囧畾娴佺▼杈惧紡鍒楄〃")
+    @GetMapping("/expList")
+    public AjaxResult expList(SysExpression sysExpression) {
+        List<SysExpression> list = sysExpressionService.selectSysExpressionList(sysExpression);
+        return AjaxResult.success(list);
+    }
+
+}
diff --git a/flowable/src/main/java/com/ycl/controller/FlowDesignerController.java b/flowable/src/main/java/com/ycl/controller/FlowDesignerController.java
deleted file mode 100644
index ba2d4b7..0000000
--- a/flowable/src/main/java/com/ycl/controller/FlowDesignerController.java
+++ /dev/null
@@ -1,139 +0,0 @@
-package com.ycl.controller;
-
-import com.alibaba.fastjson2.JSONObject;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import lombok.RequiredArgsConstructor;
-import org.apache.commons.lang3.StringUtils;
-import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.editor.constants.ModelDataJsonConstants;
-import org.flowable.editor.language.json.converter.BpmnJsonConverter;
-import org.flowable.engine.IdentityService;
-import org.flowable.engine.RepositoryService;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.repository.Model;
-import org.flowable.validation.ProcessValidator;
-import org.flowable.validation.ProcessValidatorFactory;
-import org.flowable.validation.ValidationError;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.bind.annotation.*;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.Collections;
-import java.util.List;
-
-@RestController
-@RequiredArgsConstructor
-@RequestMapping("/app/rest/")
-public class FlowDesignerController {
-
-    private final RepositoryService repositoryService;
-
-    private final IdentityService identityService;
-
-    private final RuntimeService runtimeService;
-
-    private final TaskService taskService;
-
-    private final ObjectMapper objectMapper;
-
-    /**
-     * 鑾峰緱
-     * @param modelId
-     * @return
-     */
-    @RequestMapping(value = "/models/{modelId}/editor/json", method = RequestMethod.GET, produces = "application/json")
-    public ObjectNode getModelJSON(@PathVariable String modelId) {
-        Model model = repositoryService.getModel(modelId);
-        ObjectNode modelNode = objectMapper.createObjectNode();
-        modelNode.put("modelId", model.getId());
-        modelNode.put("name", model.getName());
-        modelNode.put("key", model.getKey());
-        modelNode.put("description", JSONObject.parseObject(model.getMetaInfo()).getString("description"));
-        modelNode.putPOJO("lastUpdated", model.getLastUpdateTime());
-        byte[] modelEditorSource = repositoryService.getModelEditorSource(modelId);
-        if (null != modelEditorSource && modelEditorSource.length > 0) {
-            try {
-                ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(modelEditorSource);
-                editorJsonNode.put("modelType", "model");
-                modelNode.put("model", editorJsonNode);
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-
-        } else {
-            ObjectNode editorJsonNode = objectMapper.createObjectNode();
-            editorJsonNode.put("id", "canvas");
-            editorJsonNode.put("resourceId", "canvas");
-            ObjectNode stencilSetNode = objectMapper.createObjectNode();
-            stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
-            editorJsonNode.put("modelType", "model");
-            modelNode.put("model", editorJsonNode);
-        }
-        return modelNode;
-    }
-
-    /**
-     * 淇濆瓨
-     * @param modelId
-     * @param values
-     */
-    @RequestMapping(value = "models/{modelId}/editor/json", method = RequestMethod.POST)
-    public void saveModel(@PathVariable String modelId, @RequestBody MultiValueMap<String, String> values) {
-
-        String json = values.getFirst("json_xml");
-        String name = values.getFirst("name");
-        String description = values.getFirst("description");
-        String key = values.getFirst("key");
-
-        Model modelData = repositoryService.getModel(modelId);
-        if (null == modelData) {
-            modelData = repositoryService.newModel();
-        }
-
-        ObjectNode modelNode = null;
-        try {
-            modelNode = (ObjectNode) new ObjectMapper().readTree(json);
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-
-        ObjectNode modelObjectNode = objectMapper.createObjectNode();
-        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
-        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
-        description = StringUtils.defaultString(description);
-        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
-        modelData.setMetaInfo(modelObjectNode.toString());
-        modelData.setName(name);
-        modelData.setKey(StringUtils.defaultString(key));
-        // 鏄剧ず鍙戝竷鎸夐挳
-        modelData.setDeploymentId(null);
-        repositoryService.saveModel(modelData);
-        try {
-            repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));
-        } catch (UnsupportedEncodingException e) {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * 鏍¢獙娴佺▼鍥�
-     */
-    @PostMapping(value = "/model/validate", consumes = MediaType.APPLICATION_JSON_VALUE)
-    public List<ValidationError> validate(@RequestBody JsonNode body) {
-        if (body != null && body.has("stencilset")) {
-            BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(body);
-            ProcessValidator validator = new ProcessValidatorFactory().createDefaultProcessValidator();
-            List<ValidationError> errors = validator.validate(bpmnModel);
-            return errors;
-        }
-        return Collections.emptyList();
-    }
-
-
-}
diff --git a/flowable/src/main/java/com/ycl/controller/FlowInstanceController.java b/flowable/src/main/java/com/ycl/controller/FlowInstanceController.java
new file mode 100644
index 0000000..de3877d
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/FlowInstanceController.java
@@ -0,0 +1,67 @@
+package com.ycl.controller;
+
+import com.ycl.common.annotation.Log;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.enums.BusinessType;
+import com.ycl.domain.vo.FlowTaskVo;
+import com.ycl.service.IFlowInstanceService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+/**
+ * <p>宸ヤ綔娴佹祦绋嬪疄渚嬬鐞�<p>
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Slf4j
+@Api(tags = "宸ヤ綔娴佹祦绋嬪疄渚嬬鐞�")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/flowable/instance")
+public class FlowInstanceController extends BaseController {
+
+    private final IFlowInstanceService flowInstanceService;
+
+    @ApiOperation(value = "鏍规嵁娴佺▼瀹氫箟id鍚姩娴佺▼瀹炰緥")
+    @PostMapping("/startBy/{procDefId}")
+    public AjaxResult startById(@ApiParam(value = "娴佺▼瀹氫箟id") @PathVariable(value = "procDefId") String procDefId,
+                                @ApiParam(value = "鍙橀噺闆嗗悎,json瀵硅薄") @RequestBody Map<String, Object> variables) {
+        return flowInstanceService.startProcessInstanceById(procDefId, variables);
+
+    }
+
+    @ApiOperation(value = "婵�娲绘垨鎸傝捣娴佺▼瀹炰緥")
+    @PostMapping(value = "/updateState")
+    public AjaxResult updateState(@ApiParam(value = "1:婵�娲�,2:鎸傝捣", required = true) @RequestParam Integer state,
+                                  @ApiParam(value = "娴佺▼瀹炰緥ID", required = true) @RequestParam String instanceId) {
+        flowInstanceService.updateState(state,instanceId);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("缁撴潫娴佺▼瀹炰緥")
+    @PostMapping(value = "/stopProcessInstance")
+    public AjaxResult stopProcessInstance(@RequestBody FlowTaskVo flowTaskVo) {
+        flowInstanceService.stopProcessInstance(flowTaskVo);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "鍒犻櫎娴佺▼瀹炰緥")
+    @Log(title = "鍒犻櫎浠诲姟", businessType = BusinessType.DELETE)
+    @DeleteMapping(value = "/delete/{instanceIds}")
+    public AjaxResult delete(@ApiParam(value = "娴佺▼瀹炰緥ID", required = true) @PathVariable String[] instanceIds,
+                             @ApiParam(value = "鍒犻櫎鍘熷洜") @RequestParam(required = false) String deleteReason) {
+        for (String instanceId : instanceIds) {
+            flowInstanceService.delete(instanceId,deleteReason);
+        }
+        return AjaxResult.success();
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/controller/FlowMonitorController.java b/flowable/src/main/java/com/ycl/controller/FlowMonitorController.java
deleted file mode 100644
index eaa271f..0000000
--- a/flowable/src/main/java/com/ycl/controller/FlowMonitorController.java
+++ /dev/null
@@ -1,403 +0,0 @@
-package com.ycl.controller;
-
-import com.ycl.common.core.controller.BaseController;
-import com.ycl.common.core.domain.AjaxResult;
-import com.ycl.common.core.page.TableDataInfo;
-import com.ycl.common.utils.StringUtils;
-import com.ycl.common.utils.bean.BeanUtils;
-import com.ycl.system.domain.*;
-import com.ycl.mapper.ActRuExecutionMapper;
-import com.ycl.util.ActivitiTracingChart;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.bpmn.model.FlowElement;
-import org.flowable.engine.*;
-import org.flowable.engine.history.HistoricActivityInstance;
-import org.flowable.engine.history.HistoricProcessInstance;
-import org.flowable.engine.history.HistoricProcessInstanceQuery;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.flowable.engine.runtime.ProcessInstanceQuery;
-import org.flowable.engine.task.Comment;
-import org.flowable.job.api.*;
-import org.flowable.task.api.Task;
-import org.flowable.variable.api.history.HistoricVariableInstance;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.ModelMap;
-import org.springframework.web.bind.annotation.*;
-
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.*;
-
-/**
- * 娴佺▼鐩戞帶
- */
-@Api(value = "娴佺▼鐩戞帶鎺ュ彛")
-@Controller
-@RequiredArgsConstructor
-@RequestMapping("/flow/monitor")
-public class FlowMonitorController extends BaseController {
-
-    private final RuntimeService runtimeService;
-
-    private final TaskService taskService;
-
-    private final HistoryService historyService;
-
-    private final ManagementService managementService;
-
-    private final RepositoryService repositoryService;
-
-    private final ProcessEngineConfiguration configuration;
-
-    private final ActivitiTracingChart activitiTracingChart;
-
-    private final ActRuExecutionMapper actRuExecutionMapper;
-
-    private static final String prefix = "flowable/monitor";
-
-    @GetMapping("/instance")
-    public String processList() {
-        return prefix + "/processInstance";
-    }
-
-    @GetMapping("/history")
-    public String processHistory() {
-        return prefix + "/processHistory";
-    }
-
-    @GetMapping("/execution")
-    public String execution() {
-        return prefix + "/execution";
-    }
-
-    @GetMapping("/historyDetail")
-    public String historyDetail(String processInstanceId, ModelMap mmap) {
-        mmap.put("processInstanceId", processInstanceId);
-        return prefix + "/processHistoryDetail";
-    }
-
-    @GetMapping("/processVariablesDetail")
-    public String processVariablesDetail(String processInstanceId, ModelMap mmap) {
-        mmap.put("processInstanceId", processInstanceId);
-        return prefix + "/processVariablesDetail";
-    }
-
-    @ApiOperation("鏌ヨ鎵�鏈夋鍦ㄨ繍琛岀殑娴佺▼瀹炰緥鍒楄〃")
-    @RequestMapping(value = "/listProcess", method = RequestMethod.POST)
-    @ResponseBody
-    public TableDataInfo getlist(@RequestParam(required = false) String bussinesskey, @RequestParam(required = false) String name,
-                                 Integer pageSize, Integer pageNum) {
-        int start = (pageNum - 1) * pageSize;
-        ProcessInstanceQuery condition = runtimeService.createProcessInstanceQuery();
-        if (StringUtils.isNotEmpty(bussinesskey)) {
-            condition.processInstanceBusinessKey(bussinesskey);
-        }
-        if (StringUtils.isNotEmpty(name)) {
-            condition.processDefinitionName(name);
-        }
-        int total = condition.orderByProcessDefinitionId().desc().list().size();
-        List<ProcessInstance> processList = condition.orderByProcessDefinitionId().desc().listPage(start, pageSize);
-        List<FlowInfo> flows = new ArrayList<>();
-        processList.stream().forEach(p -> {
-            FlowInfo info = new FlowInfo();
-            info.setProcessInstanceId(p.getProcessInstanceId());
-            info.setBusinessKey(p.getBusinessKey());
-            info.setName(p.getProcessDefinitionName());
-            info.setStartTime(p.getStartTime());
-            info.setStartUserId(p.getStartUserId());
-            info.setSuspended(p.isSuspended());
-            info.setEnded(p.isEnded());
-            // 鏌ョ湅褰撳墠娲诲姩浠诲姟
-            List<Task> tasks =  taskService.createTaskQuery().processInstanceId(p.getProcessInstanceId()).list();
-            String taskName = "";
-            String assignee = "";
-            for (Task t : tasks) {
-                taskName += t.getName() + ",";
-                assignee += t.getAssignee() + ",";
-            }
-            taskName = taskName.substring(0, taskName.length() -1);
-            assignee = assignee.substring(0, assignee.length() -1);
-            info.setCurrentTask(taskName);
-            info.setAssignee(assignee);
-            flows.add(info);
-        });
-        TableDataInfo rspData = new TableDataInfo();
-        rspData.setCode(0);
-        rspData.setRows(flows);
-        rspData.setTotal(total);
-        return rspData;
-    }
-
-    @ApiOperation("鏌ヨ鎵�鏈夋祦绋嬪疄渚嬪垪琛�-鍖呭惈鍦ㄨ繍琛屽拰宸茬粨鏉�")
-    @RequestMapping(value = "/listHistoryProcess", method = RequestMethod.POST)
-    @ResponseBody
-    public TableDataInfo listHistoryProcess(@RequestParam(required = false) String bussinesskey, @RequestParam(required = false) String name,
-                                            Integer pageSize, Integer pageNum) {
-        int start = (pageNum - 1) * pageSize;
-        HistoricProcessInstanceQuery condition = historyService.createHistoricProcessInstanceQuery();
-        if (StringUtils.isNotEmpty(bussinesskey)) {
-            condition.processInstanceBusinessKey(bussinesskey);
-        }
-        if (StringUtils.isNotEmpty(name)) {
-            condition.processDefinitionName(name);
-        }
-        int total = condition.orderByProcessInstanceStartTime().desc().list().size();
-        List<HistoricProcessInstance> processList = condition.orderByProcessInstanceStartTime().desc().listPage(start, pageSize);
-        List<FlowInfo> flows = new ArrayList<>();
-        processList.stream().forEach(p -> {
-            FlowInfo info = new FlowInfo();
-            info.setProcessInstanceId(p.getId());
-            info.setBusinessKey(p.getBusinessKey());
-            info.setName(p.getProcessDefinitionName());
-            info.setStartTime(p.getStartTime());
-            info.setEndTime(p.getEndTime());
-            info.setStartUserId(p.getStartUserId());
-            if (p.getEndTime() == null) {
-                info.setEnded(false);
-                // 鏌ョ湅褰撳墠娲诲姩浠诲姟
-                List<Task> tasks =  taskService.createTaskQuery().processInstanceId(p.getId()).list();
-                String taskName = "";
-                String assignee = "";
-                for (Task t : tasks) {
-                    taskName += t.getName() + ",";
-                    assignee += t.getAssignee() + ",";
-                }
-                taskName = taskName.substring(0, taskName.length() -1);
-                assignee = assignee.substring(0, assignee.length() -1);
-                info.setCurrentTask(taskName);
-                info.setAssignee(assignee);
-            } else {
-                info.setEnded(true);
-            }
-            flows.add(info);
-        });
-        TableDataInfo rspData = new TableDataInfo();
-        rspData.setCode(0);
-        rspData.setRows(flows);
-        rspData.setTotal(total);
-        return rspData;
-    }
-
-    @ApiOperation("鏌ヨ涓�涓祦绋嬬殑娲诲姩鍘嗗彶")
-    @RequestMapping(value = "/history/{processInstanceId}", method = RequestMethod.POST)
-    @ResponseBody
-    public TableDataInfo history(@PathVariable String processInstanceId, Integer pageSize, Integer pageNum) {
-        int start = (pageNum - 1) * pageSize;
-        List<HistoricActivityInstance> history = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").orderByHistoricActivityInstanceStartTime().asc().listPage(start, pageSize);
-        int total = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").orderByHistoricActivityInstanceStartTime().asc().list().size();
-        List<TaskInfo> infos  = new ArrayList<>();
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        history.stream().forEach(h->{
-            TaskInfo info = new TaskInfo();
-            info.setProcessInstanceId(h.getProcessInstanceId());
-            info.setStartTime(sdf.format(h.getStartTime()));
-            if (h.getEndTime() != null) {
-                info.setEndTime(sdf.format(h.getEndTime()));
-            }
-            info.setAssignee(h.getAssignee());
-            info.setTaskName(h.getActivityName());
-            List<Comment> comments = taskService.getTaskComments(h.getTaskId());
-            if (comments.size() > 0) {
-                info.setComment(comments.get(0).getFullMessage());
-            }
-            infos.add(info);
-        });
-        TableDataInfo rspData = new TableDataInfo();
-        rspData.setCode(0);
-        rspData.setRows(infos);
-        rspData.setTotal(total);
-        return rspData;
-    }
-
-    @ApiOperation("鏌ヨ鎵�鏈夋鍦ㄨ繍琛岀殑鎵ц瀹炰緥鍒楄〃")
-    @RequestMapping(value = "/listExecutions", method = RequestMethod.POST)
-    @ResponseBody
-    public List<FlowInfo> listExecutions(@RequestParam(required = false) String name) {
-        List<ActRuExecution> executionList = actRuExecutionMapper.selectActRuExecutionListByProcessName(name);
-        List<FlowInfo> flows = new ArrayList<>();
-        executionList.stream().forEach(p -> {
-            FlowInfo info = new FlowInfo();
-            info.setProcessInstanceId(p.getProcInstId());
-            if (p.getSuspensionState() == 1L) {
-                info.setSuspended(false);
-            } else {
-                info.setSuspended(true);
-            }
-            if (p.getIsActive() == 0) {
-                info.setActive(false);
-            } else {
-                info.setActive(true);
-            }
-            if (p.getActId() != null) {
-                ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(p.getProcInstId()).singleResult();
-                BpmnModel bpmnModel = repositoryService.getBpmnModel(process.getProcessDefinitionId());
-                Map<String, FlowElement> nodes = bpmnModel.getMainProcess().getFlowElementMap();
-                info.setCurrentTask(nodes.get(p.getActId()).getName());
-                info.setName(process.getProcessDefinitionName());
-            } else {
-                ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(p.getProcInstId()).singleResult();
-                info.setStartTime(process.getStartTime());
-                info.setStartUserId(process.getStartUserId());
-                info.setName(process.getProcessDefinitionName());
-                List<Task> tasks =  taskService.createTaskQuery().processInstanceId(p.getProcInstId()).list();
-                String taskName = "";
-                for (Task t : tasks) {
-                    taskName += t.getName() + ",";
-                }
-                taskName = taskName.substring(0, taskName.length() -1);
-                info.setCurrentTask(taskName);
-            }
-            info.setStartTime(p.getStartTime());
-            info.setExecutionId(p.getId());
-            if (p.getParentId() == null) {
-                info.setParentExecutionId("0");
-            } else {
-                info.setParentExecutionId(p.getParentId());
-            }
-            flows.add(info);
-        });
-        return flows;
-    }
-
-    @ApiOperation("娴佺▼鍥捐繘搴﹁拷韪�")
-    @RequestMapping(value = {"/traceProcess/{processInstanceId}"}, method = RequestMethod.GET)
-    public void traceprocess(@PathVariable String processInstanceId, HttpServletResponse response) throws IOException {
-        response.setContentType("image/jpeg;charset=UTF-8");
-        response.setHeader("Content-Disposition", "inline; filename= trace.png");
-        activitiTracingChart.generateFlowChart(processInstanceId, response.getOutputStream());
-    }
-
-    @ApiOperation("鎸傝捣涓�涓祦绋嬪疄渚�")
-    @RequestMapping(value = "/suspend/{processInstanceId}", method = RequestMethod.GET)
-    @ResponseBody
-    public AjaxResult suspend(@PathVariable String processInstanceId) {
-        runtimeService.suspendProcessInstanceById(processInstanceId);
-        return AjaxResult.success();
-    }
-
-    @ApiOperation("鍞ら啋涓�涓寕璧风殑娴佺▼瀹炰緥")
-    @RequestMapping(value = "/run/{processInstanceId}", method = RequestMethod.GET)
-    @ResponseBody
-    public AjaxResult rerun(@PathVariable String processInstanceId) {
-        runtimeService.activateProcessInstanceById(processInstanceId);
-        return AjaxResult.success();
-    }
-
-    @ApiOperation("鏌ヨ涓�涓祦绋嬬殑鍙橀噺")
-    @RequestMapping(value = "/variables/{processInstanceId}", method = RequestMethod.POST)
-    @ResponseBody
-    public TableDataInfo variables(@PathVariable String processInstanceId, Integer pageSize, Integer pageNum) {
-        int start = (pageNum - 1) * pageSize;
-        List<HistoricVariableInstance> variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).orderByVariableName().asc().listPage(start, pageSize);
-        int total = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).orderByVariableName().asc().list().size();
-        List<VariableInfo> infos = new ArrayList<>();
-        variables.forEach(v->{
-            VariableInfo info = new VariableInfo();
-            BeanUtils.copyBeanProp(info, v);
-            if (v.getValue() != null) {
-                info.setValue(v.getValue().toString());
-            }
-            infos.add(info);
-        });
-        TableDataInfo rspData = new TableDataInfo();
-        rspData.setCode(0);
-        rspData.setRows(infos);
-        rspData.setTotal(total);
-        return rspData;
-    }
-
-    @ApiOperation("鎸夌被鍨嬫煡璇㈡墍鏈夌殑浣滀笟鍒楄〃:瀹氭椂浣滀笟銆佸紓姝ヤ綔涓氥�佹寕璧蜂綔涓氥�佹浜′綔涓�")
-    @PostMapping(value = "/listJobs")
-    @ResponseBody
-    public TableDataInfo listJobs(@RequestParam(required = false) String processDefinitionId, @RequestParam(required = false) String startDate,
-                                  @RequestParam(required = false) String endDate,@RequestParam Integer type, Integer pageSize, Integer pageNum) throws Exception {
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        int start = (pageNum - 1) * pageSize;
-        int total = 0;
-        List<Job> jobList = null;
-        ArrayList<DeadLetterJob> jobs = new ArrayList<>();
-        TableDataInfo rspData = new TableDataInfo();
-        if (type == 1) {
-            // 瀹氭椂浣滀笟
-            TimerJobQuery condition = managementService.createTimerJobQuery();
-            if (StringUtils.isNotEmpty(processDefinitionId)) {
-                condition.processDefinitionId(processDefinitionId);
-            }
-            if (StringUtils.isNotEmpty(startDate)) {
-                condition.duedateHigherThan(sdf.parse(startDate));
-            }
-            if (StringUtils.isNotEmpty(endDate)) {
-                condition.duedateLowerThan(sdf.parse(endDate));
-            }
-            total = condition.orderByJobDuedate().desc().list().size();
-            jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize);
-            rspData.setRows(jobList);
-        } else if (type == 2) {
-            // 寮傛浣滀笟
-            JobQuery condition = managementService.createJobQuery();
-            if (StringUtils.isNotEmpty(processDefinitionId)) {
-                condition.processDefinitionId(processDefinitionId);
-            }
-            if (StringUtils.isNotEmpty(startDate)) {
-                condition.duedateHigherThan(sdf.parse(startDate));
-            }
-            if (StringUtils.isNotEmpty(endDate)) {
-                condition.duedateLowerThan(sdf.parse(endDate));
-            }
-            total = condition.orderByJobDuedate().desc().list().size();
-            jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize);
-            rspData.setRows(jobList);
-        } else if (type == 3) {
-            // 鎸傝捣浣滀笟
-            SuspendedJobQuery condition = managementService.createSuspendedJobQuery();
-            if (StringUtils.isNotEmpty(processDefinitionId)) {
-                condition.processDefinitionId(processDefinitionId);
-            }
-            if (StringUtils.isNotEmpty(startDate)) {
-                condition.duedateHigherThan(sdf.parse(startDate));
-            }
-            if (StringUtils.isNotEmpty(endDate)) {
-                condition.duedateLowerThan(sdf.parse(endDate));
-            }
-            total = condition.orderByJobDuedate().desc().list().size();
-            jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize);
-            rspData.setRows(jobList);
-        } else if (type == 4) {
-            // 姝讳骸浣滀笟
-            DeadLetterJobQuery condition = managementService.createDeadLetterJobQuery();
-            if (StringUtils.isNotEmpty(processDefinitionId)) {
-                condition.processDefinitionId(processDefinitionId);
-            }
-            if (StringUtils.isNotEmpty(startDate)) {
-                condition.duedateHigherThan(sdf.parse(startDate));
-            }
-            if (StringUtils.isNotEmpty(endDate)) {
-                condition.duedateLowerThan(sdf.parse(endDate));
-            }
-            total = condition.orderByJobDuedate().desc().list().size();
-            jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize);
-
-            jobList.forEach(j->{
-                DeadLetterJob job = new DeadLetterJob();
-                job.setId(j.getId());
-                job.setDueDate(j.getDuedate());
-                job.setJobType(j.getJobType());
-                job.setExceptionMessage(j.getExceptionMessage());
-                job.setJobHandlerType(j.getJobHandlerType());
-                job.setProcessDefId(j.getProcessDefinitionId());
-                job.setProcessInstanceId(j.getProcessInstanceId());
-                job.setExecutionId(j.getExecutionId());
-                jobs.add(job);
-            });
-            rspData.setRows(jobs);
-        }
-        rspData.setCode(0);
-        rspData.setTotal(total);
-        return rspData;
-    }
-
-}
diff --git a/flowable/src/main/java/com/ycl/controller/FlowTaskController.java b/flowable/src/main/java/com/ycl/controller/FlowTaskController.java
new file mode 100644
index 0000000..ef3110d
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/FlowTaskController.java
@@ -0,0 +1,278 @@
+package com.ycl.controller;
+
+import com.ycl.common.annotation.Log;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.enums.BusinessType;
+import com.ycl.domain.dto.FlowTaskDto;
+import com.ycl.domain.vo.FlowQueryVo;
+import com.ycl.domain.vo.FlowTaskVo;
+import com.ycl.service.IFlowTaskService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletResponse;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * <p>宸ヤ綔娴佷换鍔$鐞�<p>
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Slf4j
+@Api(tags = "宸ヤ綔娴佹祦绋嬩换鍔$鐞�")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/flowable/task")
+public class FlowTaskController extends BaseController {
+
+    private final IFlowTaskService flowTaskService;
+
+    @ApiOperation(value = "鎴戝彂璧风殑娴佺▼", response = FlowTaskDto.class)
+    @GetMapping(value = "/myProcess")
+    public AjaxResult myProcess(FlowQueryVo queryVo) {
+        return flowTaskService.myProcess(queryVo);
+    }
+
+    @ApiOperation(value = "鍙栨秷鐢宠", response = FlowTaskDto.class)
+    @Log(title = "鍙栨秷鐢宠", businessType = BusinessType.UPDATE)
+    @PostMapping(value = "/stopProcess")
+    public AjaxResult stopProcess(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.stopProcess(flowTaskVo);
+    }
+
+    @ApiOperation(value = "鎾ゅ洖娴佺▼", response = FlowTaskDto.class)
+    @Log(title = "鎾ゅ洖娴佺▼", businessType = BusinessType.UPDATE)
+    @PostMapping(value = "/revokeProcess")
+    public AjaxResult revokeProcess(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.revokeProcess(flowTaskVo);
+    }
+
+    @ApiOperation(value = "鑾峰彇寰呭姙鍒楄〃", response = FlowTaskDto.class)
+    @GetMapping(value = "/todoList")
+    public AjaxResult todoList(FlowQueryVo queryVo) {
+        return flowTaskService.todoList(queryVo);
+    }
+
+    @ApiOperation(value = "鑾峰彇宸插姙浠诲姟", response = FlowTaskDto.class)
+    @GetMapping(value = "/finishedList")
+    public AjaxResult finishedList(FlowQueryVo queryVo) {
+        return flowTaskService.finishedList(queryVo);
+    }
+
+
+    @ApiOperation(value = "娴佺▼鍘嗗彶娴佽浆璁板綍", response = FlowTaskDto.class)
+    @GetMapping(value = "/flowRecord")
+    public AjaxResult flowRecord(String procInsId, String deployId) {
+        return flowTaskService.flowRecord(procInsId, deployId);
+    }
+
+    @ApiOperation(value = "鏍规嵁浠诲姟ID鏌ヨ鎸傝浇鐨勮〃鍗曚俊鎭�")
+    @GetMapping(value = "/getTaskForm")
+    public AjaxResult getTaskForm(String taskId) {
+        return flowTaskService.getTaskForm(taskId);
+    }
+
+
+    @ApiOperation(value = "娴佺▼鍒濆鍖栬〃鍗�", response = FlowTaskDto.class)
+    @GetMapping(value = "/flowFormData")
+    public AjaxResult flowFormData(String deployId) {
+        return flowTaskService.flowFormData(deployId);
+    }
+
+    @ApiOperation(value = "鑾峰彇娴佺▼鍙橀噺", response = FlowTaskDto.class)
+    @GetMapping(value = "/processVariables/{taskId}")
+    public AjaxResult processVariables(@ApiParam(value = "娴佺▼浠诲姟Id") @PathVariable(value = "taskId") String taskId) {
+        return flowTaskService.processVariables(taskId);
+    }
+
+    @ApiOperation(value = "瀹℃壒浠诲姟")
+    @Log(title = "瀹℃壒浠诲姟", businessType = BusinessType.UPDATE)
+    @PostMapping(value = "/complete")
+    public AjaxResult complete(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.complete(flowTaskVo);
+    }
+
+    @ApiOperation(value = "椹冲洖浠诲姟")
+    @Log(title = "椹冲洖浠诲姟", businessType = BusinessType.UPDATE)
+    @PostMapping(value = "/reject")
+    public AjaxResult taskReject(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.taskReject(flowTaskVo);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "閫�鍥炰换鍔�")
+    @Log(title = "閫�鍥炰换鍔�", businessType = BusinessType.UPDATE)
+    @PostMapping(value = "/return")
+    public AjaxResult taskReturn(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.taskReturn(flowTaskVo);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "鑾峰彇鎵�鏈夊彲鍥為��鐨勮妭鐐�")
+    @PostMapping(value = "/returnList")
+    public AjaxResult findReturnTaskList(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.findReturnTaskList(flowTaskVo);
+    }
+
+    @ApiOperation(value = "鍒犻櫎浠诲姟")
+    @Log(title = "鍒犻櫎浠诲姟", businessType = BusinessType.DELETE)
+    @DeleteMapping(value = "/delete")
+    public AjaxResult delete(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.deleteTask(flowTaskVo);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "璁ら/绛炬敹浠诲姟")
+    @PostMapping(value = "/claim")
+    public AjaxResult claim(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.claim(flowTaskVo);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "鍙栨秷璁ら/绛炬敹浠诲姟")
+    @PostMapping(value = "/unClaim")
+    public AjaxResult unClaim(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.unClaim(flowTaskVo);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "濮旀淳浠诲姟")
+    @PostMapping(value = "/delegateTask")
+    public AjaxResult delegate(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.delegateTask(flowTaskVo);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "浠诲姟褰掕繕")
+    @PostMapping(value = "/resolveTask")
+    public AjaxResult resolveTask(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.resolveTask(flowTaskVo);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "杞姙浠诲姟")
+    @PostMapping(value = "/assignTask")
+    public AjaxResult assign(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.assignTask(flowTaskVo);
+        return AjaxResult.success();
+    }
+
+    @PostMapping(value = "/addMultiInstanceExecution")
+    @ApiOperation(value = "澶氬疄渚嬪姞绛�")
+    public AjaxResult addMultiInstanceExecution(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.addMultiInstanceExecution(flowTaskVo);
+        return AjaxResult.success("鍔犵鎴愬姛");
+    }
+
+    @PostMapping(value = "/deleteMultiInstanceExecution")
+    @ApiOperation(value = "澶氬疄渚嬪噺绛�")
+    public AjaxResult deleteMultiInstanceExecution(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.deleteMultiInstanceExecution(flowTaskVo);
+        return AjaxResult.success("鍑忕鎴愬姛");
+    }
+
+    @ApiOperation(value = "鑾峰彇涓嬩竴鑺傜偣")
+    @PostMapping(value = "/nextFlowNode")
+    public AjaxResult getNextFlowNode(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.getNextFlowNode(flowTaskVo);
+    }
+
+    @ApiOperation(value = "娴佺▼鍙戣捣鏃惰幏鍙栦笅涓�鑺傜偣")
+    @PostMapping(value = "/nextFlowNodeByStart")
+    public AjaxResult getNextFlowNodeByStart(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.getNextFlowNodeByStart(flowTaskVo);
+    }
+
+    /**
+     * 鐢熸垚娴佺▼鍥�
+     *
+     * @param processId 浠诲姟ID
+     */
+    @GetMapping("/diagram/{processId}")
+    public void genProcessDiagram(HttpServletResponse response,
+                                  @PathVariable("processId") String processId) {
+        InputStream inputStream = flowTaskService.diagram(processId);
+        OutputStream os = null;
+        BufferedImage image = null;
+        try {
+            image = ImageIO.read(inputStream);
+            response.setContentType("image/png");
+            os = response.getOutputStream();
+            if (image != null) {
+                ImageIO.write(image, "png", os);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (os != null) {
+                    os.flush();
+                    os.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鎵ц鑺傜偣
+     *
+     * @param procInsId 娴佺▼瀹炰緥缂栧彿
+     * @param procInsId 浠诲姟鎵ц缂栧彿
+     */
+    @GetMapping("/flowViewer/{procInsId}/{executionId}")
+    public AjaxResult getFlowViewer(@PathVariable("procInsId") String procInsId,
+                                    @PathVariable("executionId") String executionId) {
+        return flowTaskService.getFlowViewer(procInsId, executionId);
+    }
+
+    /**
+     * 娴佺▼鑺傜偣淇℃伅
+     *
+     * @param procInsId 娴佺▼瀹炰緥id
+     * @return
+     */
+    @GetMapping("/flowXmlAndNode")
+    public AjaxResult flowXmlAndNode(@RequestParam(value = "procInsId", required = false) String procInsId,
+                                     @RequestParam(value = "deployId", required = false) String deployId) {
+        return flowTaskService.flowXmlAndNode(procInsId, deployId);
+    }
+
+    /**
+     * 娴佺▼鑺傜偣琛ㄥ崟
+     *
+     * @param taskId 娴佺▼浠诲姟缂栧彿
+     * @return
+     */
+    @GetMapping("/flowTaskForm")
+    public AjaxResult flowTaskForm(@RequestParam(value = "taskId", required = false) String taskId) throws Exception {
+        return flowTaskService.flowTaskForm(taskId);
+    }
+
+
+    /**
+     * 娴佺▼鑺傜偣淇℃伅
+     *
+     * @param procInsId 娴佺▼瀹炰緥缂栧彿
+     * @param elementId 娴佺▼鑺傜偣缂栧彿
+     * @return
+     */
+    @GetMapping("/flowTaskInfo")
+    public AjaxResult flowTaskInfo(@RequestParam(value = "procInsId") String procInsId,
+                                   @RequestParam(value = "elementId") String elementId){
+        return flowTaskService.flowTaskInfo(procInsId,elementId);
+    }
+
+}
diff --git a/flowable/src/main/java/com/ycl/controller/LeaveapplyController.java b/flowable/src/main/java/com/ycl/controller/LeaveapplyController.java
deleted file mode 100644
index 3282bad..0000000
--- a/flowable/src/main/java/com/ycl/controller/LeaveapplyController.java
+++ /dev/null
@@ -1,226 +0,0 @@
-package com.ycl.controller;
-
-import com.ycl.common.annotation.Log;
-import com.ycl.common.core.controller.BaseController;
-import com.ycl.common.core.domain.AjaxResult;
-import com.ycl.common.core.domain.entity.SysUser;
-import com.ycl.common.core.page.TableDataInfo;
-import com.ycl.common.enums.BusinessType;
-import com.ycl.common.utils.SecurityUtils;
-import com.ycl.common.utils.poi.ExcelUtil;
-import com.ycl.system.domain.Leaveapply;
-import com.ycl.service.ILeaveapplyService;
-import com.ycl.system.service.ISysUserService;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.flowable.task.api.Task;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-import java.util.Date;
-import java.util.List;
-
-/**
- * 璇峰亣Controller
- *
- * @author shenzhanwang
- * @date 2022-04-02
- */
-@Controller
-@RequiredArgsConstructor
-@RequestMapping("/leaveapply")
-public class LeaveapplyController extends BaseController
-{
-    private static final String prefix = "flowable/leaveapply";
-
-    private final ILeaveapplyService leaveapplyService;
-
-    private final ISysUserService userService;
-
-    private final RuntimeService runtimeService;
-
-    private final TaskService taskService;
-
-    @GetMapping()
-    public String leaveapply()
-    {
-        return prefix + "/leaveapply";
-    }
-
-    /**
-     * 閮ㄩ棬棰嗗瀹℃壒
-     * @return
-     */
-    @ApiOperation("閮ㄩ棬棰嗗瀹℃壒")
-    @GetMapping("/deptleadercheck")
-    @ResponseBody
-    public AjaxResult deptleadercheck(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-
-    /**
-     * 浜轰簨瀹℃壒
-     * @return
-     */
-    @ApiOperation("浜轰簨瀹℃壒")
-    @GetMapping("/hrcheck")
-    @ResponseBody
-    public AjaxResult hrcheck(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-
-    /**
-     * 閿�鍋�
-     * @return
-     */
-    @ApiOperation("閿�鍋�")
-    @GetMapping("/destroyapply")
-    @ResponseBody
-    public AjaxResult destroyapply(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-
-
-    /**
-     * 璋冩暣鐢宠
-     * @return
-     */
-    @ApiOperation("璋冩暣鐢宠")
-    @GetMapping("/modifyapply")
-    @ResponseBody
-    public AjaxResult modifyapply(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-
-    /**
-     * 鍙戣捣璇峰亣鐢宠
-     * 椹冲洖鍚庝娇鐢�
-     * @return
-     */
-    @ApiOperation("鍙戣捣璇峰亣鐢宠-椹冲洖鍚庝娇鐢�")
-    @GetMapping("/addleave")
-    @ResponseBody
-    public AjaxResult addLeave(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-
-    /**
-     * 鏌ヨ璇峰亣鍒楄〃
-     */
-    @PostMapping("/list")
-    @ResponseBody
-    public TableDataInfo list(Leaveapply leaveapply)
-    {
-        String username = getUsername();
-        leaveapply.setUserId(username);
-        startPage();
-        List<Leaveapply> list = leaveapplyService.selectLeaveapplyList(leaveapply);
-        return getDataTable(list);
-    }
-
-    /**
-     * 瀵煎嚭璇峰亣鍒楄〃
-     */
-    @Log(title = "璇峰亣", businessType = BusinessType.EXPORT)
-    @PostMapping("/export")
-    @ResponseBody
-    public AjaxResult export(Leaveapply leaveapply)
-    {
-        SysUser user = SecurityUtils.getLoginUser().getUser();
-        String username = getUsername();
-        leaveapply.setUserId(username);
-        List<Leaveapply> list = leaveapplyService.selectLeaveapplyList(leaveapply);
-        ExcelUtil<Leaveapply> util = new ExcelUtil<Leaveapply>(Leaveapply.class);
-        return util.exportExcel(list, "璇峰亣鏁版嵁");
-    }
-
-    /**
-     * 褰撳墠鐧诲綍鐢ㄦ埛
-     */
-    @ApiOperation("褰撳墠鐧诲綍鐢ㄦ埛")
-    @GetMapping("/cuurentUser")
-    @ResponseBody
-    public AjaxResult cuurentUser()
-    {
-        SysUser user = SecurityUtils.getLoginUser().getUser();
-        return AjaxResult.success(user);
-    }
-
-
-    /**
-     * 鍙戣捣璇峰亣娴佺▼
-     */
-    @Log(title = "璇峰亣", businessType = BusinessType.INSERT)
-    @PostMapping("/add")
-    @ResponseBody
-    public AjaxResult addSave(Leaveapply leaveapply)
-    {
-        leaveapply.setApplyTime(new Date());
-        return toAjax(leaveapplyService.insertLeaveapply(leaveapply));
-    }
-
-    @PostMapping("/update")
-    @ResponseBody
-    public AjaxResult update(Leaveapply leaveapply)
-    {
-        return toAjax(leaveapplyService.updateLeaveapply(leaveapply));
-    }
-
-    /**
-     * 鍒犻櫎璇峰亣
-     */
-    @Log(title = "璇峰亣", businessType = BusinessType.DELETE)
-    @PostMapping( "/remove")
-    @ResponseBody
-    public AjaxResult remove(String ids)
-    {
-        return toAjax(leaveapplyService.deleteLeaveapplyByIds(ids));
-    }
-
-}
diff --git a/flowable/src/main/java/com/ycl/controller/MeetingController.java b/flowable/src/main/java/com/ycl/controller/MeetingController.java
deleted file mode 100644
index 7326a04..0000000
--- a/flowable/src/main/java/com/ycl/controller/MeetingController.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package com.ycl.controller;
-
-import com.ycl.common.core.controller.BaseController;
-import com.ycl.common.core.domain.AjaxResult;
-import com.ycl.common.core.page.TableDataInfo;
-import com.ycl.common.utils.poi.ExcelUtil;
-import com.ycl.system.domain.Meeting;
-import com.ycl.service.IMeetingService;
-import com.ycl.system.service.ISysUserService;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.flowable.task.api.Task;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-import java.util.List;
-
-@Controller
-@RequiredArgsConstructor
-@RequestMapping("/meeting")
-public class MeetingController extends BaseController {
-
-    private static final String prefix = "flowable/meeting";
-
-    private final RuntimeService runtimeService;
-
-    private final TaskService taskService;
-
-    private final ISysUserService userService;
-
-    private final IMeetingService meetingService;
-
-
-    /**
-     * 鏌ヨ浼氳鍒楄〃
-     */
-    @PostMapping("/list")
-    @ResponseBody
-    public TableDataInfo list(Meeting meeting)
-    {
-        startPage();
-        List<Meeting> list = meetingService.selectMeetingList(meeting);
-        return getDataTable(list);
-    }
-
-    /**
-     * 瀵煎嚭浼氳鍒楄〃
-     */
-    @PostMapping("/export")
-    @ResponseBody
-    public AjaxResult export(Meeting meeting)
-    {
-        List<Meeting> list = meetingService.selectMeetingList(meeting);
-        ExcelUtil<Meeting> util = new ExcelUtil<Meeting>(Meeting.class);
-        return util.exportExcel(list, "浼氳鏁版嵁");
-    }
-
-
-    /**
-     * 鏂板淇濆瓨浼氳
-     */
-    @ApiOperation("鏂板淇濆瓨浼氳")
-    @PostMapping("/add")
-    @ResponseBody
-    public AjaxResult addSave(Meeting meeting)
-    {
-        return toAjax(meetingService.insertMeeting(meeting));
-    }
-
-    @PostMapping("/edit")
-    @ResponseBody
-    public AjaxResult edit(Meeting meeting)
-    {
-        return toAjax(meetingService.updateMeeting(meeting));
-    }
-
-    /**
-     * 鍒犻櫎浼氳
-     */
-    @PostMapping( "/remove")
-    @ResponseBody
-    public AjaxResult remove(String ids)
-    {
-        return toAjax(meetingService.deleteMeetingByIds(ids));
-    }
-
-    /**
-     * 浼氳绛惧埌
-     */
-    @ApiOperation("浼氳绛惧埌")
-    @GetMapping("/signate")
-    @ResponseBody
-    public AjaxResult signate(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Meeting apply = meetingService.selectMeetingById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-
-    /**
-     * 濉啓浼氳绾
-     */
-    @ApiOperation("濉啓浼氳绾")
-    @GetMapping("/input")
-    @ResponseBody
-    public AjaxResult input(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Meeting apply = meetingService.selectMeetingById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-}
diff --git a/flowable/src/main/java/com/ycl/controller/ModelManageController.java b/flowable/src/main/java/com/ycl/controller/ModelManageController.java
deleted file mode 100644
index 365d1b8..0000000
--- a/flowable/src/main/java/com/ycl/controller/ModelManageController.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package com.ycl.controller;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.ycl.common.core.controller.BaseController;
-import com.ycl.common.core.domain.AjaxResult;
-import com.ycl.common.core.page.TableDataInfo;
-import com.ycl.common.utils.StringUtils;
-import com.ycl.system.domain.ModelParam;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import org.apache.poi.util.IOUtils;
-import org.flowable.bpmn.converter.BpmnXMLConverter;
-import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.editor.constants.ModelDataJsonConstants;
-import org.flowable.editor.language.json.converter.BpmnJsonConverter;
-import org.flowable.engine.RepositoryService;
-import org.flowable.engine.repository.Deployment;
-import org.flowable.engine.repository.Model;
-import org.flowable.engine.repository.ModelQuery;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletResponse;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-
-@Api(value = "妯″瀷绠$悊鎺ュ彛")
-@Controller
-@RequiredArgsConstructor
-@RequestMapping("/model/manage")
-public class ModelManageController extends BaseController {
-
-    private final RepositoryService repositoryService;
-
-    private final ObjectMapper objectMapper;
-
-    private static final String prefix = "flowable/manage";
-
-
-    @ApiOperation("鏌ヨ鎵�鏈夋ā鍨�")
-    @GetMapping(value = "/modelLists")
-    @ResponseBody
-    public TableDataInfo modelLists(@RequestParam(required = false) String key, @RequestParam(required = false) String name,
-                                    Integer pageSize, Integer pageNum) {
-        ModelQuery query = repositoryService.createModelQuery();
-        if (StringUtils.isNotEmpty(key)) {
-            query.modelKey(key);
-        }
-        if (StringUtils.isNotEmpty(name)) {
-            query.modelName(name);
-        }
-        int start = (pageNum - 1) * pageSize;
-        List<Model> page = query.orderByCreateTime().desc().listPage(start, pageSize);
-        int total = repositoryService.createModelQuery().list().size();
-        TableDataInfo rspData = new TableDataInfo();
-        rspData.setCode(0);
-        rspData.setRows(page);
-        rspData.setTotal(total);
-        return rspData;
-    }
-
-    /**
-     * 鏂板妯″瀷椤甸潰
-     * @return
-     */
-    @GetMapping("/add")
-    public String add()
-    {
-        return prefix + "/add";
-    }
-
-    /**
-     * 鏂板妯″瀷
-     */
-    @PostMapping("/add")
-    @ResponseBody
-    public AjaxResult addSave(ModelParam modelRequest) throws JsonProcessingException {
-        Model model = repositoryService.newModel();
-        model.setCategory(modelRequest.getCategory());
-        model.setKey(modelRequest.getKey());
-        ObjectNode modelNode = objectMapper.createObjectNode();
-        modelNode.put(ModelDataJsonConstants.MODEL_NAME, modelRequest.getName());
-        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, modelRequest.getDescription());
-        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, modelRequest.getVersion());
-        model.setMetaInfo(modelNode.toString());
-        model.setName(modelRequest.getName());
-        model.setVersion(modelRequest.getVersion());
-        ModelQuery modelQuery = repositoryService.createModelQuery();
-        List<Model> list = modelQuery.modelKey(modelRequest.getKey()).list();
-        if (list.size() > 0) {
-            return AjaxResult.error("妯″瀷鏍囪瘑涓嶈兘閲嶅");
-        } else {
-            // 淇濆瓨妯″瀷鍒癮ct_re_model琛�
-            repositoryService.saveModel(model);
-            HashMap<String, Object> content = new HashMap();
-            content.put("resourceId", model.getId());
-            HashMap<String, String> properties = new HashMap();
-            properties.put("process_id", modelRequest.getKey());
-            properties.put("name", modelRequest.getName());
-            properties.put("category", modelRequest.getCategory());
-            content.put("properties", properties);
-            HashMap<String, String> stencilset = new HashMap();
-            stencilset.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
-            content.put("stencilset", stencilset);
-            // 淇濆瓨妯″瀷鏂囦欢鍒癮ct_ge_bytearray琛�
-            repositoryService.addModelEditorSource(model.getId(), objectMapper.writeValueAsBytes(content));
-            return AjaxResult.success(model);
-        }
-    }
-
-    @RequestMapping("/deploy/{modelId}")
-    @ResponseBody
-    public AjaxResult modelDeployment(@PathVariable String modelId) {
-        try {
-            Model model = repositoryService.getModel(modelId);
-            byte[] modelData = repositoryService.getModelEditorSource(modelId);
-            JsonNode jsonNode = objectMapper.readTree(modelData);
-            BpmnModel bpmnModel = (new BpmnJsonConverter()).convertToBpmnModel(jsonNode);
-            Deployment deploy = repositoryService.createDeployment().category(model.getCategory())
-                    .name(model.getName()).key(model.getKey())
-                    .addBpmnModel(model.getKey() + ".bpmn20.xml", bpmnModel)
-                    .deploy();
-            model.setDeploymentId(deploy.getId());
-            repositoryService.saveModel(model);
-            return AjaxResult.success();
-        } catch (Exception e) {
-            e.printStackTrace();
-            return AjaxResult.error("娴佺▼鍥句笉鍚堣鑼冿紝璇烽噸鏂拌璁�");
-        }
-    }
-
-    @PostMapping("/remove/{modelId}")
-    @ResponseBody
-    public AjaxResult removeModel(@PathVariable String modelId) {
-        repositoryService.deleteModel(modelId);
-        return AjaxResult.success("鍒犻櫎鎴愬姛");
-    }
-
-    @GetMapping("/export/{modelId}")
-    public void modelExport(@PathVariable String modelId, HttpServletResponse response) throws IOException {
-        byte[] modelData = repositoryService.getModelEditorSource(modelId);
-        JsonNode jsonNode = objectMapper.readTree(modelData);
-        BpmnModel bpmnModel = (new BpmnJsonConverter()).convertToBpmnModel(jsonNode);
-        byte[] xmlBytes = (new BpmnXMLConverter()).convertToXML(bpmnModel, "UTF-8");
-        ByteArrayInputStream in = new ByteArrayInputStream(xmlBytes);
-        String filename = bpmnModel.getMainProcess().getId() + ".bpmn20.xml";
-        response.setHeader("Content-Disposition","attachment;filename=" + filename);
-        response.setHeader("content-Type", "application/xml");
-        response.flushBuffer();
-        IOUtils.copy(in, response.getOutputStream());
-    }
-
-
-}
diff --git a/flowable/src/main/java/com/ycl/controller/PurchaseController.java b/flowable/src/main/java/com/ycl/controller/PurchaseController.java
deleted file mode 100644
index 558527f..0000000
--- a/flowable/src/main/java/com/ycl/controller/PurchaseController.java
+++ /dev/null
@@ -1,217 +0,0 @@
-package com.ycl.controller;
-
-import com.ycl.common.annotation.Log;
-import com.ycl.common.core.controller.BaseController;
-import com.ycl.common.core.domain.AjaxResult;
-import com.ycl.common.core.page.TableDataInfo;
-import com.ycl.common.enums.BusinessType;
-import com.ycl.common.utils.poi.ExcelUtil;
-import com.ycl.system.domain.Purchase;
-import com.ycl.service.IPurchaseService;
-import com.ycl.system.service.ISysUserService;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.flowable.task.api.Task;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-import java.util.Date;
-import java.util.List;
-
-/**
- * 閲囪喘Controller
- *
- * @author shenzhanwang
- * @date 2022-05-28
- */
-@Controller
-@RequiredArgsConstructor
-@RequestMapping("/purchase")
-public class PurchaseController extends BaseController
-{
-    private static final String prefix = "flowable/purchase";
-
-    private final IPurchaseService purchaseService;
-
-    private final ISysUserService userService;
-
-    private final RuntimeService runtimeService;
-
-    private final TaskService taskService;
-
-    @GetMapping()
-    public String purchase()
-    {
-        return prefix + "/purchase";
-    }
-
-    /**
-     * 鏌ヨ閲囪喘鍒楄〃
-     */
-    @PostMapping("/list")
-    @ResponseBody
-    public TableDataInfo list(Purchase purchase)
-    {
-        startPage();
-        List<Purchase> list = purchaseService.selectPurchaseList(purchase);
-        return getDataTable(list);
-    }
-
-    /**
-     * 瀵煎嚭閲囪喘鍒楄〃
-     */
-    @PostMapping("/export")
-    @ResponseBody
-    public AjaxResult export(Purchase purchase)
-    {
-        List<Purchase> list = purchaseService.selectPurchaseList(purchase);
-        ExcelUtil<Purchase> util = new ExcelUtil<Purchase>(Purchase.class);
-        return util.exportExcel(list, "閲囪喘鏁版嵁");
-    }
-
-
-    /**
-     * 鏂板淇濆瓨閲囪喘
-     */
-    @ApiOperation("鏂板淇濆瓨閲囪喘")
-    @Log(title = "閲囪喘", businessType = BusinessType.INSERT)
-    @PostMapping("/add")
-    @ResponseBody
-    public AjaxResult addSave(Purchase purchase)
-    {
-        purchase.setApplytime(new Date());
-        return toAjax(purchaseService.insertPurchase(purchase));
-    }
-
-    @PostMapping("/edit")
-    @ResponseBody
-    public AjaxResult edit(Purchase purchase)
-    {
-        return toAjax(purchaseService.updatePurchase(purchase));
-    }
-
-    /**
-     * 鍒犻櫎閲囪喘
-     */
-    @Log(title = "閲囪喘", businessType = BusinessType.DELETE)
-    @PostMapping( "/remove")
-    @ResponseBody
-    public AjaxResult remove(String ids)
-    {
-        return toAjax(purchaseService.deletePurchaseByIds(ids));
-    }
-
-    /**
-     * 閲囪喘缁忕悊瀹℃壒
-     */
-    @ApiOperation("閲囪喘缁忕悊瀹℃壒")
-    @GetMapping("/purchasemanager")
-    @ResponseBody
-    public AjaxResult purchasemanager(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-
-    /**
-     * 璐㈠姟瀹℃壒
-     */
-    @ApiOperation("璐㈠姟瀹℃壒")
-    @GetMapping("/finance")
-    @ResponseBody
-    public AjaxResult finance(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-
-    /**
-     * 鎬荤粡鐞嗗鎵�
-     */
-    @ApiOperation("鎬荤粡鐞嗗鎵�")
-    @GetMapping("/manager")
-    @ResponseBody
-    public AjaxResult manager(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-
-    /**
-     * 鍑虹撼浠樻
-     */
-    @ApiOperation("鍑虹撼浠樻")
-    @GetMapping("/pay")
-    @ResponseBody
-    public AjaxResult pay(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-
-    /**
-     * 鏀惰揣纭
-     */
-    @ApiOperation("鏀惰揣纭")
-    @GetMapping("/receiveitem")
-    @ResponseBody
-    public AjaxResult receiveitem(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-
-    /**
-     * 璋冩暣鐢宠
-     */
-    @ApiOperation("璋冩暣鐢宠")
-    @GetMapping("/updateapply")
-    @ResponseBody
-    public AjaxResult updateapply(String taskid)
-    {
-        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
-        String processId = t.getProcessInstanceId();
-        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
-        if (p != null) {
-            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
-            return AjaxResult.success(apply);
-        }
-        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
-    }
-}
diff --git a/flowable/src/main/java/com/ycl/controller/SysExpressionController.java b/flowable/src/main/java/com/ycl/controller/SysExpressionController.java
new file mode 100644
index 0000000..7646b9a
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/SysExpressionController.java
@@ -0,0 +1,99 @@
+package com.ycl.controller;
+
+import com.ycl.common.annotation.Log;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.page.TableDataInfo;
+import com.ycl.common.enums.BusinessType;
+import com.ycl.common.utils.poi.ExcelUtil;
+import com.ycl.domain.entity.SysExpression;
+import com.ycl.service.ISysExpressionService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 娴佺▼杈惧紡Controller
+ *
+ * @author ruoyi
+ * @date 2022-12-12
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/system/expression")
+public class SysExpressionController extends BaseController
+{
+    private final ISysExpressionService sysExpressionService;
+
+    /**
+     * 鏌ヨ娴佺▼杈惧紡鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:expression:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysExpression sysExpression)
+    {
+        startPage();
+        List<SysExpression> list = sysExpressionService.selectSysExpressionList(sysExpression);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭娴佺▼杈惧紡鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:expression:export')")
+    @Log(title = "娴佺▼杈惧紡", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysExpression sysExpression)
+    {
+        List<SysExpression> list = sysExpressionService.selectSysExpressionList(sysExpression);
+        ExcelUtil<SysExpression> util = new ExcelUtil<SysExpression>(SysExpression.class);
+        util.exportExcel(response, list, "娴佺▼杈惧紡鏁版嵁");
+    }
+
+    /**
+     * 鑾峰彇娴佺▼杈惧紡璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:expression:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(sysExpressionService.selectSysExpressionById(id));
+    }
+
+    /**
+     * 鏂板娴佺▼杈惧紡
+     */
+    @PreAuthorize("@ss.hasPermi('system:expression:add')")
+    @Log(title = "娴佺▼杈惧紡", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysExpression sysExpression)
+    {
+        return toAjax(sysExpressionService.insertSysExpression(sysExpression));
+    }
+
+    /**
+     * 淇敼娴佺▼杈惧紡
+     */
+    @PreAuthorize("@ss.hasPermi('system:expression:edit')")
+    @Log(title = "娴佺▼杈惧紡", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysExpression sysExpression)
+    {
+        return toAjax(sysExpressionService.updateSysExpression(sysExpression));
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼杈惧紡
+     */
+    @PreAuthorize("@ss.hasPermi('system:expression:remove')")
+    @Log(title = "娴佺▼杈惧紡", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(sysExpressionService.deleteSysExpressionByIds(ids));
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/controller/SysFormController.java b/flowable/src/main/java/com/ycl/controller/SysFormController.java
new file mode 100644
index 0000000..327d4bd
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/SysFormController.java
@@ -0,0 +1,111 @@
+package com.ycl.controller;
+
+import com.ycl.common.annotation.Log;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.page.TableDataInfo;
+import com.ycl.common.enums.BusinessType;
+import com.ycl.common.utils.poi.ExcelUtil;
+import com.ycl.domain.entity.SysDeployForm;
+import com.ycl.domain.entity.SysForm;
+import com.ycl.service.ISysDeployFormService;
+import com.ycl.service.ISysFormService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 娴佺▼琛ㄥ崟Controller
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/flowable/form")
+public class SysFormController extends BaseController {
+
+    private final ISysFormService SysFormService;
+
+    private final ISysDeployFormService sysDeployFormService;
+
+    /**
+     * 鏌ヨ娴佺▼琛ㄥ崟鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('flowable:form:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysForm sysForm) {
+        startPage();
+        List<SysForm> list = SysFormService.selectSysFormList(sysForm);
+        return getDataTable(list);
+    }
+
+    @GetMapping("/formList")
+    public AjaxResult formList(SysForm sysForm) {
+        List<SysForm> list = SysFormService.selectSysFormList(sysForm);
+        return AjaxResult.success(list);
+    }
+    /**
+     * 瀵煎嚭娴佺▼琛ㄥ崟鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('flowable:form:export')")
+    @Log(title = "娴佺▼琛ㄥ崟", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(SysForm sysForm) {
+        List<SysForm> list = SysFormService.selectSysFormList(sysForm);
+        ExcelUtil<SysForm> util = new ExcelUtil<SysForm>(SysForm.class);
+        return util.exportExcel(list, "form");
+    }
+
+    /**
+     * 鑾峰彇娴佺▼琛ㄥ崟璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('flowable:form:query')")
+    @GetMapping(value = "/{formId}")
+    public AjaxResult getInfo(@PathVariable("formId") Long formId) {
+        return AjaxResult.success(SysFormService.selectSysFormById(formId));
+    }
+
+    /**
+     * 鏂板娴佺▼琛ㄥ崟
+     */
+    @PreAuthorize("@ss.hasPermi('flowable:form:add')")
+    @Log(title = "娴佺▼琛ㄥ崟", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysForm sysForm) {
+        return toAjax(SysFormService.insertSysForm(sysForm));
+    }
+
+    /**
+     * 淇敼娴佺▼琛ㄥ崟
+     */
+    @PreAuthorize("@ss.hasPermi('flowable:form:edit')")
+    @Log(title = "娴佺▼琛ㄥ崟", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysForm sysForm) {
+        return toAjax(SysFormService.updateSysForm(sysForm));
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼琛ㄥ崟
+     */
+    @PreAuthorize("@ss.hasPermi('flowable:form:remove')")
+    @Log(title = "娴佺▼琛ㄥ崟", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{formIds}")
+    public AjaxResult remove(@PathVariable Long[] formIds) {
+        return toAjax(SysFormService.deleteSysFormByIds(formIds));
+    }
+
+
+    /**
+     * 鎸傝浇娴佺▼琛ㄥ崟
+     */
+    @Log(title = "娴佺▼琛ㄥ崟", businessType = BusinessType.INSERT)
+    @PostMapping("/addDeployForm")
+    public AjaxResult addDeployForm(@RequestBody SysDeployForm sysDeployForm) {
+        return toAjax(sysDeployFormService.insertSysDeployForm(sysDeployForm));
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/controller/SysListenerController.java b/flowable/src/main/java/com/ycl/controller/SysListenerController.java
new file mode 100644
index 0000000..b74164e
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/SysListenerController.java
@@ -0,0 +1,99 @@
+package com.ycl.controller;
+
+import com.ycl.common.annotation.Log;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.page.TableDataInfo;
+import com.ycl.common.enums.BusinessType;
+import com.ycl.common.utils.poi.ExcelUtil;
+import com.ycl.domain.entity.SysListener;
+import com.ycl.service.ISysListenerService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 娴佺▼鐩戝惉Controller
+ *
+ * @author Tony
+ * @date 2022-12-25
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/system/listener")
+public class SysListenerController extends BaseController
+{
+    private final ISysListenerService sysListenerService;
+
+    /**
+     * 鏌ヨ娴佺▼鐩戝惉鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:listener:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysListener sysListener)
+    {
+        startPage();
+        List<SysListener> list = sysListenerService.selectSysListenerList(sysListener);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭娴佺▼鐩戝惉鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:listener:export')")
+    @Log(title = "娴佺▼鐩戝惉", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysListener sysListener)
+    {
+        List<SysListener> list = sysListenerService.selectSysListenerList(sysListener);
+        ExcelUtil<SysListener> util = new ExcelUtil<SysListener>(SysListener.class);
+        util.exportExcel(response, list, "娴佺▼鐩戝惉鏁版嵁");
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鐩戝惉璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:listener:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(sysListenerService.selectSysListenerById(id));
+    }
+
+    /**
+     * 鏂板娴佺▼鐩戝惉
+     */
+    @PreAuthorize("@ss.hasPermi('system:listener:add')")
+    @Log(title = "娴佺▼鐩戝惉", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysListener sysListener)
+    {
+        return toAjax(sysListenerService.insertSysListener(sysListener));
+    }
+
+    /**
+     * 淇敼娴佺▼鐩戝惉
+     */
+    @PreAuthorize("@ss.hasPermi('system:listener:edit')")
+    @Log(title = "娴佺▼鐩戝惉", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysListener sysListener)
+    {
+        return toAjax(sysListenerService.updateSysListener(sysListener));
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼鐩戝惉
+     */
+    @PreAuthorize("@ss.hasPermi('system:listener:remove')")
+    @Log(title = "娴佺▼鐩戝惉", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(sysListenerService.deleteSysListenerByIds(ids));
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/controller/TaskController.java b/flowable/src/main/java/com/ycl/controller/TaskController.java
deleted file mode 100644
index 8746d9e..0000000
--- a/flowable/src/main/java/com/ycl/controller/TaskController.java
+++ /dev/null
@@ -1,208 +0,0 @@
-package com.ycl.controller;
-
-import com.ycl.common.core.controller.BaseController;
-import com.ycl.common.core.domain.AjaxResult;
-import com.ycl.common.core.domain.entity.SysUser;
-import com.ycl.common.core.page.TableDataInfo;
-import com.ycl.common.utils.SecurityUtils;
-import com.ycl.common.utils.StringUtils;
-import com.ycl.system.domain.TaskInfo;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import org.flowable.engine.FormService;
-import org.flowable.engine.HistoryService;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.history.HistoricActivityInstance;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.flowable.engine.task.Comment;
-import org.flowable.task.api.Task;
-import org.flowable.task.api.TaskQuery;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.*;
-
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-@Api(value = "寰呭姙浠诲姟鎺ュ彛")
-@Controller
-@RequiredArgsConstructor
-@RequestMapping("/task/manage")
-public class TaskController extends BaseController {
-
-    private final RuntimeService runtimeService;
-
-    private final TaskService taskService;
-
-    private final FormService formService;
-
-    private final HistoryService historyService;
-
-    private static final String prefix = "flowable/task";
-
-    @GetMapping("/mytask")
-    public String mytasks()
-    {
-        return prefix + "/mytasks";
-    }
-
-    @GetMapping("/alltasks")
-    public String alltasks()
-    {
-        return prefix + "/alltasks";
-    }
-
-    /**
-     * 鏌ヨ鎴戠殑寰呭姙浠诲姟鍒楄〃
-     */
-    @ApiOperation("鏌ヨ鎴戠殑寰呭姙浠诲姟鍒楄〃")
-    @PostMapping("/mylist")
-    @ResponseBody
-    public TableDataInfo mylist(TaskInfo param)
-    {
-        SysUser user = SecurityUtils.getLoginUser().getUser();
-        String username = getUsername();
-        TaskQuery condition = taskService.createTaskQuery().taskAssignee(username);
-        if (StringUtils.isNotEmpty(param.getTaskName())) {
-            condition.taskName(param.getTaskName());
-        }
-        if (StringUtils.isNotEmpty(param.getProcessName())) {
-            condition.processDefinitionName(param.getProcessName());
-        }
-        // 杩囨护鎺夋祦绋嬫寕璧风殑寰呭姙浠诲姟
-        int total = condition.active().orderByTaskCreateTime().desc().list().size();
-        int start = (param.getPageNum()-1) * param.getPageSize();
-        List<Task> taskList = condition.active().orderByTaskCreateTime().desc().listPage(start, param.getPageSize());
-        List<TaskInfo> tasks = new ArrayList<>();
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        taskList.stream().forEach(a->{
-            ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(a.getProcessInstanceId()).singleResult();
-            TaskInfo info = new TaskInfo();
-            info.setAssignee(a.getAssignee());
-            info.setBusinessKey(process.getBusinessKey());
-            info.setCreateTime(sdf.format(a.getCreateTime()));
-            info.setTaskName(a.getName());
-            info.setExecutionId(a.getExecutionId());
-            info.setProcessInstanceId(a.getProcessInstanceId());
-            info.setProcessName(process.getProcessDefinitionName());
-            info.setStarter(process.getStartUserId());
-            info.setStartTime(sdf.format(process.getStartTime()));
-            info.setTaskId(a.getId());
-            String formKey = formService.getTaskFormData(a.getId()).getFormKey();
-            info.setFormKey(formKey);
-            tasks.add(info);
-        });
-        TableDataInfo rspData = new TableDataInfo();
-        rspData.setCode(0);
-        rspData.setRows(tasks);
-        rspData.setTotal(total);
-        return rspData;
-    }
-
-    /**
-     * 鏌ヨ鎵�鏈夊緟鍔炰换鍔″垪琛�
-     */
-    @ApiOperation("鏌ヨ鎵�鏈夊緟鍔炰换鍔″垪琛�")
-    @PostMapping("/alllist")
-    @ResponseBody
-    public TableDataInfo alllist(TaskInfo param)
-    {
-        TaskQuery condition = taskService.createTaskQuery();
-        if (StringUtils.isNotEmpty(param.getTaskName())) {
-            condition.taskName(param.getTaskName());
-        }
-        if (StringUtils.isNotEmpty(param.getProcessName())) {
-            condition.processDefinitionName(param.getProcessName());
-        }
-        int total = condition.active().orderByTaskCreateTime().desc().list().size();
-        int start = (param.getPageNum()-1) * param.getPageSize();
-        List<Task> taskList = condition.active().orderByTaskCreateTime().desc().listPage(start, param.getPageSize());
-        List<TaskInfo> tasks = new ArrayList<>();
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        taskList.stream().forEach(a->{
-            ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(a.getProcessInstanceId()).singleResult();
-            TaskInfo info = new TaskInfo();
-            info.setAssignee(a.getAssignee());
-            info.setBusinessKey(process.getBusinessKey());
-            info.setCreateTime(sdf.format(a.getCreateTime()));
-            info.setTaskName(a.getName());
-            info.setExecutionId(a.getExecutionId());
-            info.setProcessInstanceId(a.getProcessInstanceId());
-            info.setProcessName(process.getProcessDefinitionName());
-            info.setStarter(process.getStartUserId());
-            info.setStartTime(sdf.format(process.getStartTime()));
-            info.setTaskId(a.getId());
-            String formKey = formService.getTaskFormData(a.getId()).getFormKey();
-            info.setFormKey(formKey);
-            tasks.add(info);
-        });
-        TableDataInfo rspData = new TableDataInfo();
-        rspData.setCode(0);
-        rspData.setRows(tasks);
-        rspData.setTotal(total);
-        return rspData;
-    }
-
-    /**
-     * 鐢╰askid鏌ヨformkey
-     **/
-    @ApiOperation("鐢╰askid鏌ヨformkey")
-    @PostMapping("/forminfo/{taskId}")
-    @ResponseBody
-    public AjaxResult alllist(@PathVariable String taskId)
-    {
-        String formKey = formService.getTaskFormData(taskId).getFormKey();
-        return AjaxResult.success(formKey);
-    }
-
-    @ApiOperation("鍔炵悊涓�涓敤鎴蜂换鍔�")
-    @RequestMapping(value = "/completeTask/{taskId}", method = RequestMethod.POST)
-    @ResponseBody
-    public AjaxResult completeTask(@PathVariable("taskId") String taskId, @RequestBody(required=false) Map<String, Object> variables) {
-        SysUser user = SecurityUtils.getLoginUser().getUser();
-        String username = getUsername();
-        taskService.setAssignee(taskId, username);
-        // 鏌ュ嚭娴佺▼瀹炰緥id
-        String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
-        if (variables == null) {
-            taskService.complete(taskId);
-        } else {
-            // 娣诲姞瀹℃壒鎰忚
-            if (variables.get("comment") != null) {
-                taskService.addComment(taskId, processInstanceId, (String) variables.get("comment"));
-                variables.remove("comment");
-            }
-            taskService.complete(taskId, variables);
-        }
-        return AjaxResult.success();
-    }
-
-    @ApiOperation("浠诲姟鍔炵悊鏃堕棿杞�")
-    @RequestMapping(value = "/history/{taskId}", method = RequestMethod.GET)
-    @ResponseBody
-    public List<TaskInfo> history(@PathVariable String taskId) {
-        String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
-        List<HistoricActivityInstance> history = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").orderByHistoricActivityInstanceStartTime().asc().list();
-        List<TaskInfo> infos  = new ArrayList<>();
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        history.stream().forEach(h->{
-            TaskInfo info = new TaskInfo();
-            info.setProcessInstanceId(h.getProcessInstanceId());
-            info.setStartTime(sdf.format(h.getStartTime()));
-            if (h.getEndTime() != null) {
-                info.setEndTime(sdf.format(h.getEndTime()));
-            }
-            info.setAssignee(h.getAssignee());
-            info.setTaskName(h.getActivityName());
-            List<Comment> comments = taskService.getTaskComments(h.getTaskId());
-            if (comments.size() > 0) {
-                info.setComment(comments.get(0).getFullMessage());
-            }
-            infos.add(info);
-        });
-        return infos;
-    }
-}
diff --git a/flowable/src/main/java/com/ycl/domain/dto/FlowCommentDto.java b/flowable/src/main/java/com/ycl/domain/dto/FlowCommentDto.java
new file mode 100644
index 0000000..6d9f9ca
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/dto/FlowCommentDto.java
@@ -0,0 +1,25 @@
+package com.ycl.domain.dto;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author Tony
+ * @date 2021/3/28 15:50
+ */
+@Data
+@Builder
+public class FlowCommentDto implements Serializable {
+
+    /**
+     * 鎰忚绫诲埆 0 姝e父鎰忚  1 閫�鍥炴剰瑙� 2 椹冲洖鎰忚
+     */
+    private String type;
+
+    /**
+     * 鎰忚鍐呭
+     */
+    private String comment;
+}
diff --git a/flowable/src/main/java/com/ycl/domain/dto/FlowFromFieldDTO.java b/flowable/src/main/java/com/ycl/domain/dto/FlowFromFieldDTO.java
new file mode 100644
index 0000000..d25c3a0
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/dto/FlowFromFieldDTO.java
@@ -0,0 +1,15 @@
+package com.ycl.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author Tony
+ * @date 2021/3/31 23:20
+ */
+@Data
+public class FlowFromFieldDTO implements Serializable {
+
+    private Object fields;
+}
diff --git a/flowable/src/main/java/com/ycl/domain/dto/FlowNextDto.java b/flowable/src/main/java/com/ycl/domain/dto/FlowNextDto.java
new file mode 100644
index 0000000..c1251c4
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/dto/FlowNextDto.java
@@ -0,0 +1,30 @@
+package com.ycl.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 鍔ㄦ�佷汉鍛樸�佺粍
+ * @author Tony
+ * @date 2021/4/17 22:59
+ */
+@Data
+public class FlowNextDto implements Serializable {
+
+    /**
+     * 瀹℃壒浜虹被鍨�
+     */
+    private String type;
+
+    /**
+     * 鏄惁闇�瑕佸姩鎬佹寚瀹氫换鍔″鎵逛汉
+     */
+    private String dataType;
+
+    /**
+     * 娴佺▼鍙橀噺
+     */
+    private String vars;
+
+}
diff --git a/flowable/src/main/java/com/ycl/domain/dto/FlowProcDefDto.java b/flowable/src/main/java/com/ycl/domain/dto/FlowProcDefDto.java
new file mode 100644
index 0000000..f93760e
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/dto/FlowProcDefDto.java
@@ -0,0 +1,56 @@
+package com.ycl.domain.dto;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * <p>娴佺▼瀹氫箟<p>
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@ApiModel("娴佺▼瀹氫箟")
+public class FlowProcDefDto implements Serializable {
+
+    @ApiModelProperty("娴佺▼id")
+    private String id;
+
+    @ApiModelProperty("娴佺▼鍚嶇О")
+    private String name;
+
+    @ApiModelProperty("娴佺▼key")
+    private String flowKey;
+
+    @ApiModelProperty("娴佺▼鍒嗙被")
+    private String category;
+
+    @ApiModelProperty("閰嶇疆琛ㄥ崟鍚嶇О")
+    private String formName;
+
+    @ApiModelProperty("閰嶇疆琛ㄥ崟id")
+    private Long formId;
+
+    @ApiModelProperty("鐗堟湰")
+    private int version;
+
+    @ApiModelProperty("閮ㄧ讲ID")
+    private String deploymentId;
+
+    @ApiModelProperty("娴佺▼瀹氫箟鐘舵��: 1:婵�娲� , 2:涓")
+    private int suspensionState;
+
+    @ApiModelProperty("閮ㄧ讲鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date deploymentTime;
+
+
+}
diff --git a/flowable/src/main/java/com/ycl/domain/dto/FlowSaveXmlVo.java b/flowable/src/main/java/com/ycl/domain/dto/FlowSaveXmlVo.java
new file mode 100644
index 0000000..ab61566
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/dto/FlowSaveXmlVo.java
@@ -0,0 +1,28 @@
+package com.ycl.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author Tony
+ * @date 2021/3/28 19:48
+ */
+@Data
+public class FlowSaveXmlVo implements Serializable {
+
+    /**
+     * 娴佺▼鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 娴佺▼鍒嗙被
+     */
+    private String category;
+
+    /**
+     * xml 鏂囦欢
+     */
+    private String xml;
+}
diff --git a/flowable/src/main/java/com/ycl/domain/dto/FlowTaskDto.java b/flowable/src/main/java/com/ycl/domain/dto/FlowTaskDto.java
new file mode 100644
index 0000000..ce641bd
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/dto/FlowTaskDto.java
@@ -0,0 +1,102 @@
+package com.ycl.domain.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * <p>宸ヤ綔娴佷换鍔�<p>
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Getter
+@Setter
+@ApiModel("宸ヤ綔娴佷换鍔$浉鍏�-杩斿洖鍙傛暟")
+public class FlowTaskDto implements Serializable {
+
+    @ApiModelProperty("浠诲姟缂栧彿")
+    private String taskId;
+
+    @ApiModelProperty("浠诲姟鎵ц缂栧彿")
+    private String executionId;
+
+    @ApiModelProperty("浠诲姟鍚嶇О")
+    private String taskName;
+
+    @ApiModelProperty("浠诲姟Key")
+    private String taskDefKey;
+
+    @ApiModelProperty("浠诲姟鎵ц浜篒d")
+    private Long assigneeId;
+
+    @ApiModelProperty("閮ㄩ棬鍚嶇О")
+    private String deptName;
+
+    @ApiModelProperty("娴佺▼鍙戣捣浜洪儴闂ㄥ悕绉�")
+    private String startDeptName;
+
+    @ApiModelProperty("浠诲姟鎵ц浜哄悕绉�")
+    private String assigneeName;
+    @ApiModelProperty("浠诲姟鎵ц浜洪儴闂�")
+    private String assigneeDeptName;;
+
+    @ApiModelProperty("娴佺▼鍙戣捣浜篒d")
+    private String startUserId;
+
+    @ApiModelProperty("娴佺▼鍙戣捣浜哄悕绉�")
+    private String startUserName;
+
+    @ApiModelProperty("娴佺▼绫诲瀷")
+    private String category;
+
+    @ApiModelProperty("娴佺▼鍙橀噺淇℃伅")
+    private Object variables;
+
+    @ApiModelProperty("灞�閮ㄥ彉閲忎俊鎭�")
+    private Object taskLocalVars;
+
+    @ApiModelProperty("娴佺▼閮ㄧ讲缂栧彿")
+    private String deployId;
+
+    @ApiModelProperty("娴佺▼ID")
+    private String procDefId;
+
+    @ApiModelProperty("娴佺▼key")
+    private String procDefKey;
+
+    @ApiModelProperty("娴佺▼瀹氫箟鍚嶇О")
+    private String procDefName;
+
+    @ApiModelProperty("娴佺▼瀹氫箟鍐呯疆浣跨敤鐗堟湰")
+    private int procDefVersion;
+
+    @ApiModelProperty("娴佺▼瀹炰緥ID")
+    private String procInsId;
+
+    @ApiModelProperty("鍘嗗彶娴佺▼瀹炰緥ID")
+    private String hisProcInsId;
+
+    @ApiModelProperty("浠诲姟鑰楁椂")
+    private String duration;
+
+    @ApiModelProperty("浠诲姟鎰忚")
+    private FlowCommentDto comment;
+
+    @ApiModelProperty("鍊欓�夋墽琛屼汉")
+    private String candidate;
+
+    @ApiModelProperty("浠诲姟鍒涘缓鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    @ApiModelProperty("浠诲姟瀹屾垚鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date finishTime;
+
+}
diff --git a/flowable/src/main/java/com/ycl/domain/dto/FlowViewerDto.java b/flowable/src/main/java/com/ycl/domain/dto/FlowViewerDto.java
new file mode 100644
index 0000000..be8bb9c
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/dto/FlowViewerDto.java
@@ -0,0 +1,23 @@
+package com.ycl.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author Tony
+ * @date 2021/4/21 20:55
+ */
+@Data
+public class FlowViewerDto implements Serializable {
+
+    /**
+     * 娴佺▼key
+     */
+    private String key;
+
+    /**
+     * 鏄惁瀹屾垚(宸茬粡瀹℃壒)
+     */
+    private boolean completed;
+}
diff --git a/flowable/src/main/java/com/ycl/domain/entity/SysDeployForm.java b/flowable/src/main/java/com/ycl/domain/entity/SysDeployForm.java
new file mode 100644
index 0000000..68bfac3
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/entity/SysDeployForm.java
@@ -0,0 +1,64 @@
+package com.ycl.domain.entity;
+
+import com.ycl.common.annotation.Excel;
+import com.ycl.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟瀵硅薄 sys_instance_form
+ *
+ * @author Tony
+ * @date 2021-03-30
+ */
+public class SysDeployForm extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 涓婚敭 */
+    private Long id;
+
+    /** 琛ㄥ崟涓婚敭 */
+    @Excel(name = "琛ㄥ崟涓婚敭")
+    private Long formId;
+
+    /** 娴佺▼瀹氫箟涓婚敭 */
+    @Excel(name = "娴佺▼瀹氫箟涓婚敭")
+    private String deployId;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setFormId(Long formId)
+    {
+        this.formId = formId;
+    }
+
+    public Long getFormId()
+    {
+        return formId;
+    }
+
+    public String getDeployId() {
+        return deployId;
+    }
+
+    public void setDeployId(String deployId) {
+        this.deployId = deployId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("formId", getFormId())
+            .append("deployId", getDeployId())
+            .toString();
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/domain/entity/SysExpression.java b/flowable/src/main/java/com/ycl/domain/entity/SysExpression.java
new file mode 100644
index 0000000..6e9b497
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/entity/SysExpression.java
@@ -0,0 +1,95 @@
+package com.ycl.domain.entity;
+
+import com.ycl.common.annotation.Excel;
+import com.ycl.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 娴佺▼杈惧紡瀵硅薄 sys_expression
+ *
+ * @author ruoyi
+ * @date 2022-12-12
+ */
+public class SysExpression extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 琛ㄥ崟涓婚敭 */
+    private Long id;
+
+    /** 琛ㄨ揪寮忓悕绉� */
+    @Excel(name = "琛ㄨ揪寮忓悕绉�")
+    private String name;
+
+    /** 琛ㄨ揪寮忓唴瀹� */
+    @Excel(name = "琛ㄨ揪寮忓唴瀹�")
+    private String expression;
+    /** 琛ㄨ揪寮忕被鍨� */
+    @Excel(name = "琛ㄨ揪寮忕被鍨�")
+    private String dataType;
+
+    /** 鐘舵�� */
+    private Integer status;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+    public void setExpression(String expression)
+    {
+        this.expression = expression;
+    }
+
+    public String getExpression()
+    {
+        return expression;
+    }
+    public void setStatus(Integer status)
+    {
+        this.status = status;
+    }
+
+    public Integer getStatus()
+    {
+        return status;
+    }
+
+    public void setDataType(String dataType) {
+        this.dataType = dataType;
+    }
+    public String getDataType() {
+        return dataType;
+    }
+
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("name", getName())
+            .append("expression", getExpression())
+            .append("dataType", getDataType())
+            .append("createTime", getCreateTime())
+            .append("updateTime", getUpdateTime())
+            .append("createBy", getCreateBy())
+            .append("updateBy", getUpdateBy())
+            .append("status", getStatus())
+            .append("remark", getRemark())
+            .toString();
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/domain/entity/SysForm.java b/flowable/src/main/java/com/ycl/domain/entity/SysForm.java
new file mode 100644
index 0000000..c55a24f
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/entity/SysForm.java
@@ -0,0 +1,70 @@
+package com.ycl.domain.entity;
+
+import com.ycl.common.annotation.Excel;
+import com.ycl.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 娴佺▼琛ㄥ崟瀵硅薄 sys_task_form
+ *
+ * @author Tony
+ * @date 2021-03-30
+ */
+public class SysForm extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 琛ㄥ崟涓婚敭 */
+    private Long formId;
+
+    /** 琛ㄥ崟鍚嶇О */
+    @Excel(name = "琛ㄥ崟鍚嶇О")
+    private String formName;
+
+    /** 琛ㄥ崟鍐呭 */
+    @Excel(name = "琛ㄥ崟鍐呭")
+    private String formContent;
+
+    public void setFormId(Long formId)
+    {
+        this.formId = formId;
+    }
+
+    public Long getFormId()
+    {
+        return formId;
+    }
+    public void setFormName(String formName)
+    {
+        this.formName = formName;
+    }
+
+    public String getFormName()
+    {
+        return formName;
+    }
+    public void setFormContent(String formContent)
+    {
+        this.formContent = formContent;
+    }
+
+    public String getFormContent()
+    {
+        return formContent;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("formId", getFormId())
+            .append("formName", getFormName())
+            .append("formContent", getFormContent())
+            .append("createTime", getCreateTime())
+            .append("updateTime", getUpdateTime())
+            .append("createBy", getCreateBy())
+            .append("updateBy", getUpdateBy())
+            .append("remark", getRemark())
+            .toString();
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/domain/entity/SysListener.java b/flowable/src/main/java/com/ycl/domain/entity/SysListener.java
new file mode 100644
index 0000000..a54d394
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/entity/SysListener.java
@@ -0,0 +1,126 @@
+package com.ycl.domain.entity;
+
+import com.ycl.common.annotation.Excel;
+import com.ycl.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 娴佺▼鐩戝惉瀵硅薄 sys_listener
+ *
+ * @author Tony
+ * @date 2022-12-25
+ */
+public class SysListener extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 琛ㄥ崟涓婚敭 */
+    private Long id;
+
+    /** 鍚嶇О */
+    @Excel(name = "鍚嶇О")
+    private String name;
+
+    /** 鐩戝惉绫诲瀷 */
+    @Excel(name = "鐩戝惉绫诲瀷")
+    private String type;
+
+    /** 浜嬩欢绫诲瀷 */
+    @Excel(name = "浜嬩欢绫诲瀷")
+    private String eventType;
+
+    /** 鍊肩被鍨� */
+    @Excel(name = "鍊肩被鍨�")
+    private String valueType;
+
+    /** 鎵ц鍐呭 */
+    @Excel(name = "鎵ц鍐呭")
+    private String value;
+
+    /** 鐘舵�� */
+    @Excel(name = "鐘舵��")
+    private Integer status;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+    public void setType(String type)
+    {
+        this.type = type;
+    }
+
+    public String getType()
+    {
+        return type;
+    }
+    public void setEventType(String eventType)
+    {
+        this.eventType = eventType;
+    }
+
+    public String getEventType()
+    {
+        return eventType;
+    }
+    public void setValueType(String valueType)
+    {
+        this.valueType = valueType;
+    }
+
+    public String getValueType()
+    {
+        return valueType;
+    }
+    public void setValue(String value)
+    {
+        this.value = value;
+    }
+
+    public String getValue()
+    {
+        return value;
+    }
+    public void setStatus(Integer status)
+    {
+        this.status = status;
+    }
+
+    public Integer getStatus()
+    {
+        return status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("name", getName())
+            .append("type", getType())
+            .append("eventType", getEventType())
+            .append("valueType", getValueType())
+            .append("value", getValue())
+            .append("createTime", getCreateTime())
+            .append("updateTime", getUpdateTime())
+            .append("createBy", getCreateBy())
+            .append("updateBy", getUpdateBy())
+            .append("status", getStatus())
+            .append("remark", getRemark())
+            .toString();
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/domain/entity/SysTaskForm.java b/flowable/src/main/java/com/ycl/domain/entity/SysTaskForm.java
new file mode 100644
index 0000000..05611fa
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/entity/SysTaskForm.java
@@ -0,0 +1,65 @@
+package com.ycl.domain.entity;
+
+import com.ycl.common.annotation.Excel;
+import com.ycl.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 娴佺▼浠诲姟鍏宠仈鍗曞璞� sys_task_form
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+public class SysTaskForm extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 涓婚敭 */
+    private Long id;
+
+    /** 琛ㄥ崟涓婚敭 */
+    @Excel(name = "琛ㄥ崟涓婚敭")
+    private Long formId;
+
+    /** 鎵�灞炰换鍔� */
+    @Excel(name = "鎵�灞炰换鍔�")
+    private String taskId;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setFormId(Long formId)
+    {
+        this.formId = formId;
+    }
+
+    public Long getFormId()
+    {
+        return formId;
+    }
+    public void setTaskId(String taskId)
+    {
+        this.taskId = taskId;
+    }
+
+    public String getTaskId()
+    {
+        return taskId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("formId", getFormId())
+            .append("taskId", getTaskId())
+            .toString();
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/domain/vo/FlowQueryVo.java b/flowable/src/main/java/com/ycl/domain/vo/FlowQueryVo.java
new file mode 100644
index 0000000..dbd686a
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/vo/FlowQueryVo.java
@@ -0,0 +1,33 @@
+package com.ycl.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * <p>娴佺▼浠诲姟<p>
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Data
+@ApiModel("宸ヤ綔娴佷换鍔$浉鍏�--璇锋眰鍙傛暟")
+public class FlowQueryVo {
+
+    @ApiModelProperty("娴佺▼鍚嶇О")
+    private String name;
+
+    @ApiModelProperty("寮�濮嬫椂闂�")
+    private String startTime;
+
+    @ApiModelProperty("缁撴潫鏃堕棿")
+    private String endTime;
+
+    @ApiModelProperty("褰撳墠椤电爜")
+    private Integer pageNum;
+
+    @ApiModelProperty("姣忛〉鏉℃暟")
+    private Integer pageSize;
+
+
+}
diff --git a/flowable/src/main/java/com/ycl/domain/vo/FlowTaskVo.java b/flowable/src/main/java/com/ycl/domain/vo/FlowTaskVo.java
new file mode 100644
index 0000000..90962be
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/vo/FlowTaskVo.java
@@ -0,0 +1,56 @@
+package com.ycl.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>娴佺▼浠诲姟<p>
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Data
+@ApiModel("宸ヤ綔娴佷换鍔$浉鍏�--璇锋眰鍙傛暟")
+public class FlowTaskVo {
+
+    @ApiModelProperty("浠诲姟Id")
+    private String taskId;
+
+    @ApiModelProperty("鐢ㄦ埛Id")
+    private String userId;
+
+    @ApiModelProperty("浠诲姟鎰忚")
+    private String comment;
+
+    @ApiModelProperty("娴佺▼瀹炰緥Id")
+    private String instanceId;
+
+    @ApiModelProperty("鑺傜偣")
+    private String targetKey;
+
+    private String deploymentId;
+    @ApiModelProperty("娴佺▼鐜妭瀹氫箟ID")
+    private String defId;
+
+    @ApiModelProperty("瀛愭墽琛屾祦ID")
+    private String currentChildExecutionId;
+
+    @ApiModelProperty("瀛愭墽琛屾祦鏄惁宸叉墽琛�")
+    private Boolean flag;
+
+    @ApiModelProperty("娴佺▼鍙橀噺淇℃伅")
+    private Map<String, Object> variables;
+
+    @ApiModelProperty("瀹℃壒浜�")
+    private String assignee;
+
+    @ApiModelProperty("鍊欓�変汉")
+    private List<String> candidateUsers;
+
+    @ApiModelProperty("瀹℃壒缁�")
+    private List<String> candidateGroups;
+}
diff --git a/flowable/src/main/java/com/ycl/domain/vo/ReturnTaskNodeVo.java b/flowable/src/main/java/com/ycl/domain/vo/ReturnTaskNodeVo.java
new file mode 100644
index 0000000..eed6afe
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/domain/vo/ReturnTaskNodeVo.java
@@ -0,0 +1,23 @@
+package com.ycl.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * <p>鍙��鍥炶妭鐐�<p>
+ *
+ * @author tony
+ * @date 2022-04-23 11:01:52
+ */
+@Data
+@ApiModel("鍙��鍥炶妭鐐�")
+public class ReturnTaskNodeVo {
+
+    @ApiModelProperty("浠诲姟Id")
+    private String id;
+
+    @ApiModelProperty("鐢ㄦ埛Id")
+    private String name;
+
+}
diff --git a/flowable/src/main/java/com/ycl/factory/FlowServiceFactory.java b/flowable/src/main/java/com/ycl/factory/FlowServiceFactory.java
new file mode 100644
index 0000000..046b03a
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/factory/FlowServiceFactory.java
@@ -0,0 +1,41 @@
+package com.ycl.factory;
+
+import lombok.Getter;
+import org.flowable.engine.*;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * flowable 寮曟搸娉ㄥ叆灏佽
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Component
+@Getter
+public class FlowServiceFactory {
+
+    @Resource
+    protected RepositoryService repositoryService;
+
+    @Resource
+    protected RuntimeService runtimeService;
+
+    @Resource
+    protected IdentityService identityService;
+
+    @Resource
+    protected TaskService taskService;
+
+    @Resource
+    protected HistoryService historyService;
+
+    @Resource
+    protected ManagementService managementService;
+
+    @Qualifier("processEngine")
+    @Resource
+    protected ProcessEngine processEngine;
+
+}
diff --git a/flowable/src/main/java/com/ycl/flow/CustomProcessDiagramCanvas.java b/flowable/src/main/java/com/ycl/flow/CustomProcessDiagramCanvas.java
new file mode 100644
index 0000000..bfc60d4
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/flow/CustomProcessDiagramCanvas.java
@@ -0,0 +1,370 @@
+package com.ycl.flow;
+
+import org.flowable.bpmn.model.AssociationDirection;
+import org.flowable.bpmn.model.GraphicInfo;
+import org.flowable.image.impl.DefaultProcessDiagramCanvas;
+import org.flowable.image.util.ReflectUtil;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineBreakMeasurer;
+import java.awt.font.TextAttribute;
+import java.awt.font.TextLayout;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+
+/**
+ * @author Tony
+ * @date 2021/4/4 23:58
+ */
+public class CustomProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
+    //瀹氫箟璧拌繃娴佺▼杩炵嚎棰滆壊涓虹豢鑹�
+    protected static Color HIGHLIGHT_SequenceFlow_COLOR = Color.GREEN;
+    //璁剧疆鏈蛋杩囨祦绋嬬殑杩炴帴绾块鑹�
+    protected static Color CONNECTION_COLOR = Color.BLACK;
+    //璁剧疆flows杩炴帴绾垮瓧浣撻鑹瞨ed
+    protected static Color LABEL_COLOR = new Color(0, 0, 0);
+    //楂樹寒鏄剧ずtask妗嗛鑹�
+    protected static Color HIGHLIGHT_COLOR = Color.GREEN;
+    protected static Color HIGHLIGHT_COLOR1 = Color.RED;
+
+    public CustomProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
+        super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
+        this.initialize(imageType);
+    }
+
+    /**
+     * 閲嶅啓缁樺埗杩炵嚎鐨勬柟寮�,璁剧疆缁樺埗棰滆壊
+     * @param xPoints
+     * @param yPoints
+     * @param conditional
+     * @param isDefault
+     * @param connectionType
+     * @param associationDirection
+     * @param highLighted
+     * @param scaleFactor
+     */
+    @Override
+    public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType, AssociationDirection associationDirection, boolean highLighted, double scaleFactor) {
+        Paint originalPaint = this.g.getPaint();
+        Stroke originalStroke = this.g.getStroke();
+        this.g.setPaint(CONNECTION_COLOR);
+        if (connectionType.equals("association")) {
+            this.g.setStroke(ASSOCIATION_STROKE);
+        } else if (highLighted) {
+            this.g.setPaint(HIGHLIGHT_SequenceFlow_COLOR);
+            this.g.setStroke(HIGHLIGHT_FLOW_STROKE);
+        }
+
+        for (int i = 1; i < xPoints.length; ++i) {
+            Integer sourceX = xPoints[i - 1];
+            Integer sourceY = yPoints[i - 1];
+            Integer targetX = xPoints[i];
+            Integer targetY = yPoints[i];
+            java.awt.geom.Line2D.Double line = new java.awt.geom.Line2D.Double((double) sourceX, (double) sourceY, (double) targetX, (double) targetY);
+            this.g.draw(line);
+        }
+
+        java.awt.geom.Line2D.Double line;
+        if (isDefault) {
+            line = new java.awt.geom.Line2D.Double((double) xPoints[0], (double) yPoints[0], (double) xPoints[1], (double) yPoints[1]);
+            this.drawDefaultSequenceFlowIndicator(line, scaleFactor);
+        }
+
+        if (conditional) {
+            line = new java.awt.geom.Line2D.Double((double) xPoints[0], (double) yPoints[0], (double) xPoints[1], (double) yPoints[1]);
+            this.drawConditionalSequenceFlowIndicator(line, scaleFactor);
+        }
+
+        if (associationDirection.equals(AssociationDirection.ONE) || associationDirection.equals(AssociationDirection.BOTH)) {
+            line = new java.awt.geom.Line2D.Double((double) xPoints[xPoints.length - 2], (double) yPoints[xPoints.length - 2], (double) xPoints[xPoints.length - 1], (double) yPoints[xPoints.length - 1]);
+            this.drawArrowHead(line, scaleFactor);
+        }
+
+        if (associationDirection.equals(AssociationDirection.BOTH)) {
+            line = new java.awt.geom.Line2D.Double((double) xPoints[1], (double) yPoints[1], (double) xPoints[0], (double) yPoints[0]);
+            this.drawArrowHead(line, scaleFactor);
+        }
+
+        this.g.setPaint(originalPaint);
+        this.g.setStroke(originalStroke);
+    }
+
+    /**
+     * 璁剧疆瀛椾綋澶у皬鍥炬爣棰滆壊
+     * @param imageType
+     */
+    @Override
+    public void initialize(String imageType) {
+        if ("png".equalsIgnoreCase(imageType)) {
+            this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 2);
+        } else {
+            this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 1);
+        }
+
+        this.g = this.processDiagram.createGraphics();
+        if (!"png".equalsIgnoreCase(imageType)) {
+            this.g.setBackground(new Color(255, 255, 255, 0));
+            this.g.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+        }
+
+        this.g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        //淇敼鍥炬爣棰滆壊锛屼慨鏀瑰浘鏍囧瓧浣撳ぇ灏�
+        this.g.setPaint(Color.black);
+        Font font = new Font(this.activityFontName, 10, 14);
+        this.g.setFont(font);
+        this.fontMetrics = this.g.getFontMetrics();
+        //淇敼杩炴帴绾垮瓧浣撳ぇ灏�
+        LABEL_FONT = new Font(this.labelFontName, 10, 15);
+        ANNOTATION_FONT = new Font(this.annotationFontName, 0, 11);
+
+        try {
+            USERTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/userTask.png", this.customClassLoader));
+            SCRIPTTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/scriptTask.png", this.customClassLoader));
+            SERVICETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/serviceTask.png", this.customClassLoader));
+            RECEIVETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/receiveTask.png", this.customClassLoader));
+            SENDTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/sendTask.png", this.customClassLoader));
+            MANUALTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/manualTask.png", this.customClassLoader));
+            BUSINESS_RULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/businessRuleTask.png", this.customClassLoader));
+            SHELL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/shellTask.png", this.customClassLoader));
+            DMN_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/dmnTask.png", this.customClassLoader));
+            CAMEL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/camelTask.png", this.customClassLoader));
+            MULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/muleTask.png", this.customClassLoader));
+            HTTP_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/httpTask.png", this.customClassLoader));
+            TIMER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/timer.png", this.customClassLoader));
+            COMPENSATE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/compensate-throw.png", this.customClassLoader));
+            COMPENSATE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/compensate.png", this.customClassLoader));
+            ERROR_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/error-throw.png", this.customClassLoader));
+            ERROR_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/error.png", this.customClassLoader));
+            MESSAGE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/message-throw.png", this.customClassLoader));
+            MESSAGE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/message.png", this.customClassLoader));
+            SIGNAL_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/signal-throw.png", this.customClassLoader));
+            SIGNAL_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/signal.png", this.customClassLoader));
+        } catch (IOException var4) {
+            LOGGER.warn("Could not load image for process diagram creation: {}", var4.getMessage());
+        }
+
+    }
+
+    /**
+     * 璁剧疆杩炴帴绾垮瓧浣�
+     * @param text
+     * @param graphicInfo
+     * @param centered
+     */
+    @Override
+    public void drawLabel(String text, GraphicInfo graphicInfo, boolean centered) {
+        float interline = 1.0f;
+
+        // text
+        if (text != null && text.length() > 0) {
+            Paint originalPaint = g.getPaint();
+            Font originalFont = g.getFont();
+
+            g.setPaint(LABEL_COLOR);
+            g.setFont(LABEL_FONT);
+
+            int wrapWidth = 100;
+            int textY = (int) graphicInfo.getY();
+
+            // TODO: use drawMultilineText()
+            AttributedString as = new AttributedString(text);
+            as.addAttribute(TextAttribute.FOREGROUND, g.getPaint());
+            as.addAttribute(TextAttribute.FONT, g.getFont());
+            AttributedCharacterIterator aci = as.getIterator();
+            FontRenderContext frc = new FontRenderContext(null, true, false);
+            LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
+
+            while (lbm.getPosition() < text.length()) {
+                TextLayout tl = lbm.nextLayout(wrapWidth);
+                textY += tl.getAscent();
+
+                Rectangle2D bb = tl.getBounds();
+                double tX = graphicInfo.getX();
+
+                if (centered) {
+                    tX += (int) (graphicInfo.getWidth() / 2 - bb.getWidth() / 2);
+                }
+                tl.draw(g, (float) tX, textY);
+                textY += tl.getDescent() + tl.getLeading() + (interline - 1.0f) * tl.getAscent();
+            }
+
+            // restore originals
+            g.setFont(originalFont);
+            g.setPaint(originalPaint);
+        }
+    }
+
+    /**
+     * 楂樹寒鏄剧ずtask妗嗗畬鎴愮殑
+     * @param x
+     * @param y
+     * @param width
+     * @param height
+     */
+    @Override
+    public void drawHighLight(int x, int y, int width, int height) {
+        Paint originalPaint = g.getPaint();
+        Stroke originalStroke = g.getStroke();
+
+        g.setPaint(HIGHLIGHT_COLOR);
+        g.setStroke(THICK_TASK_BORDER_STROKE);
+
+        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
+        g.draw(rect);
+
+        g.setPaint(originalPaint);
+        g.setStroke(originalStroke);
+    }
+
+    /**
+     * 鑷畾涔塼ask妗嗗綋鍓嶇殑浣嶇疆
+     * @param x
+     * @param y
+     * @param width
+     * @param height
+     */
+    public void drawHighLightNow(int x, int y, int width, int height) {
+        Paint originalPaint = g.getPaint();
+        Stroke originalStroke = g.getStroke();
+
+        g.setPaint(HIGHLIGHT_COLOR1);
+        g.setStroke(THICK_TASK_BORDER_STROKE);
+
+        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
+        g.draw(rect);
+
+        g.setPaint(originalPaint);
+        g.setStroke(originalStroke);
+    }
+
+    /**
+     * 鑷畾涔夌粨鏉熻妭鐐�
+     * @param x
+     * @param y
+     * @param width
+     * @param height
+     */
+    public void drawHighLightEnd(int x, int y, int width, int height) {
+        Paint originalPaint = g.getPaint();
+        Stroke originalStroke = g.getStroke();
+
+        g.setPaint(HIGHLIGHT_COLOR);
+        g.setStroke(THICK_TASK_BORDER_STROKE);
+
+        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
+        g.draw(rect);
+
+        g.setPaint(originalPaint);
+        g.setStroke(originalStroke);
+    }
+
+    /**
+     * task妗嗚嚜瀹氫箟鏂囧瓧
+     * @param name
+     * @param graphicInfo
+     * @param thickBorder
+     * @param scaleFactor
+     */
+    @Override
+    protected void drawTask(String name, GraphicInfo graphicInfo, boolean thickBorder, double scaleFactor) {
+
+        Paint originalPaint = g.getPaint();
+        int x = (int) graphicInfo.getX();
+        int y = (int) graphicInfo.getY();
+        int width = (int) graphicInfo.getWidth();
+        int height = (int) graphicInfo.getHeight();
+
+        // Create a new gradient paint for every task box, gradient depends on x and y and is not relative
+        g.setPaint(TASK_BOX_COLOR);
+
+        int arcR = 6;
+        if (thickBorder) {
+            arcR = 3;
+        }
+
+        // shape
+        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, arcR, arcR);
+        g.fill(rect);
+        g.setPaint(TASK_BORDER_COLOR);
+
+        if (thickBorder) {
+            Stroke originalStroke = g.getStroke();
+            g.setStroke(THICK_TASK_BORDER_STROKE);
+            g.draw(rect);
+            g.setStroke(originalStroke);
+        } else {
+            g.draw(rect);
+        }
+
+        g.setPaint(originalPaint);
+        // text
+        if (scaleFactor == 1.0 && name != null && name.length() > 0) {
+            int boxWidth = width - (2 * TEXT_PADDING);
+            int boxHeight = height - 16 - ICON_PADDING - ICON_PADDING - MARKER_WIDTH - 2 - 2;
+            int boxX = x + width / 2 - boxWidth / 2;
+            int boxY = y + height / 2 - boxHeight / 2 + ICON_PADDING + ICON_PADDING - 2 - 2;
+
+            drawMultilineCentredText(name, boxX, boxY, boxWidth, boxHeight);
+        }
+    }
+
+    protected static Color EVENT_COLOR = new Color(255, 255, 255);
+
+    /**
+     * 閲嶅啓寮�濮嬩簨浠�
+     * @param graphicInfo
+     * @param image
+     * @param scaleFactor
+     */
+    @Override
+    public void drawStartEvent(GraphicInfo graphicInfo, BufferedImage image, double scaleFactor) {
+        Paint originalPaint = g.getPaint();
+        g.setPaint(EVENT_COLOR);
+        Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(),
+                graphicInfo.getWidth(), graphicInfo.getHeight());
+        g.fill(circle);
+        g.setPaint(EVENT_BORDER_COLOR);
+        g.draw(circle);
+        g.setPaint(originalPaint);
+        if (image != null) {
+            // calculate coordinates to center image
+            int imageX = (int) Math.round(graphicInfo.getX() + (graphicInfo.getWidth() / 2) - (image.getWidth() / (2 * scaleFactor)));
+            int imageY = (int) Math.round(graphicInfo.getY() + (graphicInfo.getHeight() / 2) - (image.getHeight() / (2 * scaleFactor)));
+            g.drawImage(image, imageX, imageY,
+                    (int) (image.getWidth() / scaleFactor), (int) (image.getHeight() / scaleFactor), null);
+        }
+
+    }
+
+    /**
+     * 閲嶅啓缁撴潫浜嬩欢
+     * @param graphicInfo
+     * @param scaleFactor
+     */
+    @Override
+    public void drawNoneEndEvent(GraphicInfo graphicInfo, double scaleFactor) {
+        Paint originalPaint = g.getPaint();
+        Stroke originalStroke = g.getStroke();
+        g.setPaint(EVENT_COLOR);
+        Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(),
+                graphicInfo.getWidth(), graphicInfo.getHeight());
+        g.fill(circle);
+        g.setPaint(EVENT_BORDER_COLOR);
+//        g.setPaint(HIGHLIGHT_COLOR);
+        if (scaleFactor == 1.0) {
+            g.setStroke(END_EVENT_STROKE);
+        } else {
+            g.setStroke(new BasicStroke(2.0f));
+        }
+        g.draw(circle);
+        g.setStroke(originalStroke);
+        g.setPaint(originalPaint);
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/flow/CustomProcessDiagramGenerator.java b/flowable/src/main/java/com/ycl/flow/CustomProcessDiagramGenerator.java
new file mode 100644
index 0000000..f782072
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/flow/CustomProcessDiagramGenerator.java
@@ -0,0 +1,404 @@
+package com.ycl.flow;
+
+
+import org.flowable.bpmn.model.Process;
+import org.flowable.bpmn.model.*;
+import org.flowable.image.impl.DefaultProcessDiagramCanvas;
+import org.flowable.image.impl.DefaultProcessDiagramGenerator;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author Tony
+ * @date 2021/4/5 0:31
+ */
+public class CustomProcessDiagramGenerator extends DefaultProcessDiagramGenerator {
+    @Override
+    protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
+        this.prepareBpmnModel(bpmnModel);
+        DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
+        Iterator var13 = bpmnModel.getPools().iterator();
+
+        while (var13.hasNext()) {
+            Pool process = (Pool) var13.next();
+            GraphicInfo subProcesses = bpmnModel.getGraphicInfo(process.getId());
+            processDiagramCanvas.drawPoolOrLane(process.getName(), subProcesses, scaleFactor);
+        }
+
+        var13 = bpmnModel.getProcesses().iterator();
+
+        Process process1;
+        Iterator subProcesses1;
+        while (var13.hasNext()) {
+            process1 = (Process) var13.next();
+            subProcesses1 = process1.getLanes().iterator();
+
+            while (subProcesses1.hasNext()) {
+                Lane artifact = (Lane) subProcesses1.next();
+                GraphicInfo subProcess = bpmnModel.getGraphicInfo(artifact.getId());
+                processDiagramCanvas.drawPoolOrLane(artifact.getName(), subProcess, scaleFactor);
+            }
+        }
+
+        var13 = bpmnModel.getProcesses().iterator();
+
+        while (var13.hasNext()) {
+            process1 = (Process) var13.next();
+            subProcesses1 = process1.findFlowElementsOfType(FlowNode.class).iterator();
+
+            while (subProcesses1.hasNext()) {
+                FlowNode artifact1 = (FlowNode) subProcesses1.next();
+                if (!this.isPartOfCollapsedSubProcess(artifact1, bpmnModel)) {
+                    this.drawActivity(processDiagramCanvas, bpmnModel, artifact1, highLightedActivities, highLightedFlows, scaleFactor, Boolean.valueOf(drawSequenceFlowNameWithNoLabelDI));
+                }
+            }
+        }
+
+        var13 = bpmnModel.getProcesses().iterator();
+
+        label75:
+        while (true) {
+            List subProcesses2;
+            do {
+                if (!var13.hasNext()) {
+                    return processDiagramCanvas;
+                }
+
+                process1 = (Process) var13.next();
+                subProcesses1 = process1.getArtifacts().iterator();
+
+                while (subProcesses1.hasNext()) {
+                    Artifact artifact2 = (Artifact) subProcesses1.next();
+                    this.drawArtifact(processDiagramCanvas, bpmnModel, artifact2);
+                }
+
+                subProcesses2 = process1.findFlowElementsOfType(SubProcess.class, true);
+            } while (subProcesses2 == null);
+
+            Iterator artifact3 = subProcesses2.iterator();
+
+            while (true) {
+                GraphicInfo graphicInfo;
+                SubProcess subProcess1;
+                do {
+                    do {
+                        if (!artifact3.hasNext()) {
+                            continue label75;
+                        }
+
+                        subProcess1 = (SubProcess) artifact3.next();
+                        graphicInfo = bpmnModel.getGraphicInfo(subProcess1.getId());
+                    } while (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded().booleanValue());
+                } while (this.isPartOfCollapsedSubProcess(subProcess1, bpmnModel));
+
+                Iterator var19 = subProcess1.getArtifacts().iterator();
+
+                while (var19.hasNext()) {
+                    Artifact subProcessArtifact = (Artifact) var19.next();
+                    this.drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact);
+                }
+            }
+        }
+    }
+
+    protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
+        double minX = 1.7976931348623157E308D;
+        double maxX = 0.0D;
+        double minY = 1.7976931348623157E308D;
+        double maxY = 0.0D;
+
+        GraphicInfo nrOfLanes;
+        for (Iterator flowNodes = bpmnModel.getPools().iterator(); flowNodes.hasNext(); maxY = nrOfLanes.getY() + nrOfLanes.getHeight()) {
+            Pool artifacts = (Pool) flowNodes.next();
+            nrOfLanes = bpmnModel.getGraphicInfo(artifacts.getId());
+            minX = nrOfLanes.getX();
+            maxX = nrOfLanes.getX() + nrOfLanes.getWidth();
+            minY = nrOfLanes.getY();
+        }
+
+        List var23 = gatherAllFlowNodes(bpmnModel);
+        Iterator var24 = var23.iterator();
+
+        label155:
+        while (var24.hasNext()) {
+            FlowNode var26 = (FlowNode) var24.next();
+            GraphicInfo artifact = bpmnModel.getGraphicInfo(var26.getId());
+            if (artifact.getX() + artifact.getWidth() > maxX) {
+                maxX = artifact.getX() + artifact.getWidth();
+            }
+
+            if (artifact.getX() < minX) {
+                minX = artifact.getX();
+            }
+
+            if (artifact.getY() + artifact.getHeight() > maxY) {
+                maxY = artifact.getY() + artifact.getHeight();
+            }
+
+            if (artifact.getY() < minY) {
+                minY = artifact.getY();
+            }
+
+            Iterator process = var26.getOutgoingFlows().iterator();
+
+            while (true) {
+                List l;
+                do {
+                    if (!process.hasNext()) {
+                        continue label155;
+                    }
+
+                    SequenceFlow graphicInfoList = (SequenceFlow) process.next();
+                    l = bpmnModel.getFlowLocationGraphicInfo(graphicInfoList.getId());
+                } while (l == null);
+
+                Iterator graphicInfo = l.iterator();
+
+                while (graphicInfo.hasNext()) {
+                    GraphicInfo graphicInfo1 = (GraphicInfo) graphicInfo.next();
+                    if (graphicInfo1.getX() > maxX) {
+                        maxX = graphicInfo1.getX();
+                    }
+
+                    if (graphicInfo1.getX() < minX) {
+                        minX = graphicInfo1.getX();
+                    }
+
+                    if (graphicInfo1.getY() > maxY) {
+                        maxY = graphicInfo1.getY();
+                    }
+
+                    if (graphicInfo1.getY() < minY) {
+                        minY = graphicInfo1.getY();
+                    }
+                }
+            }
+        }
+
+        List var25 = gatherAllArtifacts(bpmnModel);
+        Iterator var27 = var25.iterator();
+
+        GraphicInfo var37;
+        while (var27.hasNext()) {
+            Artifact var29 = (Artifact) var27.next();
+            GraphicInfo var31 = bpmnModel.getGraphicInfo(var29.getId());
+            if (var31 != null) {
+                if (var31.getX() + var31.getWidth() > maxX) {
+                    maxX = var31.getX() + var31.getWidth();
+                }
+
+                if (var31.getX() < minX) {
+                    minX = var31.getX();
+                }
+
+                if (var31.getY() + var31.getHeight() > maxY) {
+                    maxY = var31.getY() + var31.getHeight();
+                }
+
+                if (var31.getY() < minY) {
+                    minY = var31.getY();
+                }
+            }
+
+            List var33 = bpmnModel.getFlowLocationGraphicInfo(var29.getId());
+            if (var33 != null) {
+                Iterator var35 = var33.iterator();
+
+                while (var35.hasNext()) {
+                    var37 = (GraphicInfo) var35.next();
+                    if (var37.getX() > maxX) {
+                        maxX = var37.getX();
+                    }
+
+                    if (var37.getX() < minX) {
+                        minX = var37.getX();
+                    }
+
+                    if (var37.getY() > maxY) {
+                        maxY = var37.getY();
+                    }
+
+                    if (var37.getY() < minY) {
+                        minY = var37.getY();
+                    }
+                }
+            }
+        }
+
+        int var28 = 0;
+        Iterator var30 = bpmnModel.getProcesses().iterator();
+
+        while (var30.hasNext()) {
+            Process var32 = (Process) var30.next();
+            Iterator var34 = var32.getLanes().iterator();
+
+            while (var34.hasNext()) {
+                Lane var36 = (Lane) var34.next();
+                ++var28;
+                var37 = bpmnModel.getGraphicInfo(var36.getId());
+                if (var37.getX() + var37.getWidth() > maxX) {
+                    maxX = var37.getX() + var37.getWidth();
+                }
+
+                if (var37.getX() < minX) {
+                    minX = var37.getX();
+                }
+
+                if (var37.getY() + var37.getHeight() > maxY) {
+                    maxY = var37.getY() + var37.getHeight();
+                }
+
+                if (var37.getY() < minY) {
+                    minY = var37.getY();
+                }
+            }
+        }
+
+        if (var23.isEmpty() && bpmnModel.getPools().isEmpty() && var28 == 0) {
+            minX = 0.0D;
+            minY = 0.0D;
+        }
+
+        return new CustomProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
+    }
+
+
+    private static void drawHighLight(DefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
+        processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
+
+    }
+
+    private static void drawHighLightNow(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
+        processDiagramCanvas.drawHighLightNow((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
+
+    }
+
+    private static void drawHighLightEnd(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
+        processDiagramCanvas.drawHighLightEnd((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
+
+    }
+
+    @Override
+    protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel,
+                                FlowNode flowNode, List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor, Boolean drawSequenceFlowNameWithNoLabelDI) {
+
+        ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass());
+        if (drawInstruction != null) {
+
+            drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode);
+
+            // Gather info on the multi instance marker
+            boolean multiInstanceSequential = false;
+            boolean multiInstanceParallel = false;
+            boolean collapsed = false;
+            if (flowNode instanceof Activity) {
+                Activity activity = (Activity) flowNode;
+                MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics();
+                if (multiInstanceLoopCharacteristics != null) {
+                    multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential();
+                    multiInstanceParallel = !multiInstanceSequential;
+                }
+            }
+
+            // Gather info on the collapsed marker
+            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+            if (flowNode instanceof SubProcess) {
+                collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded();
+            } else if (flowNode instanceof CallActivity) {
+                collapsed = true;
+            }
+
+            if (scaleFactor == 1.0) {
+                // Actually draw the markers
+                processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(),
+                        multiInstanceSequential, multiInstanceParallel, collapsed);
+            }
+
+            // Draw highlighted activities
+            if (highLightedActivities.contains(flowNode.getId())) {
+
+                if (highLightedActivities.get(highLightedActivities.size() - 1).equals(flowNode.getId())
+                        && !"endenv".equals(flowNode.getId())) {
+                    if ((flowNode.getId().contains("Event_"))) {
+                        drawHighLightEnd((CustomProcessDiagramCanvas) processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
+                    } else {
+                        drawHighLightNow((CustomProcessDiagramCanvas) processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
+                    }
+                } else {
+                    drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
+                }
+
+
+            }
+
+        }
+
+        // Outgoing transitions of activity
+        for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
+            boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId()));
+            String defaultFlow = null;
+            if (flowNode instanceof Activity) {
+                defaultFlow = ((Activity) flowNode).getDefaultFlow();
+            } else if (flowNode instanceof Gateway) {
+                defaultFlow = ((Gateway) flowNode).getDefaultFlow();
+            }
+
+            boolean isDefault = false;
+            if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) {
+                isDefault = true;
+            }
+            boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && !(flowNode instanceof Gateway);
+
+            String sourceRef = sequenceFlow.getSourceRef();
+            String targetRef = sequenceFlow.getTargetRef();
+            FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef);
+            FlowElement targetElement = bpmnModel.getFlowElement(targetRef);
+            List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
+            if (graphicInfoList != null && graphicInfoList.size() > 0) {
+                graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList);
+                int xPoints[] = new int[graphicInfoList.size()];
+                int yPoints[] = new int[graphicInfoList.size()];
+
+                for (int i = 1; i < graphicInfoList.size(); i++) {
+                    GraphicInfo graphicInfo = graphicInfoList.get(i);
+                    GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);
+
+                    if (i == 1) {
+                        xPoints[0] = (int) previousGraphicInfo.getX();
+                        yPoints[0] = (int) previousGraphicInfo.getY();
+                    }
+                    xPoints[i] = (int) graphicInfo.getX();
+                    yPoints[i] = (int) graphicInfo.getY();
+
+                }
+
+                processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault, highLighted, scaleFactor);
+
+
+                // Draw sequenceflow label
+                GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId());
+                if (labelGraphicInfo != null) {
+                    processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
+                } else {
+                    if (drawSequenceFlowNameWithNoLabelDI) {
+                        GraphicInfo lineCenter = getLineCenter(graphicInfoList);
+                        processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineCenter, false);
+                    }
+
+                }
+            }
+        }
+
+        // Nested elements
+        if (flowNode instanceof FlowElementsContainer) {
+            for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
+                if (nestedFlowElement instanceof FlowNode && !isPartOfCollapsedSubProcess(nestedFlowElement, bpmnModel)) {
+                    drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement,
+                            highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
+                }
+            }
+        }
+    }
+}
+
diff --git a/flowable/src/main/java/com/ycl/flow/FindNextNodeUtil.java b/flowable/src/main/java/com/ycl/flow/FindNextNodeUtil.java
new file mode 100644
index 0000000..be3d0aa
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/flow/FindNextNodeUtil.java
@@ -0,0 +1,262 @@
+package com.ycl.flow;
+
+import com.googlecode.aviator.AviatorEvaluator;
+import com.googlecode.aviator.Expression;
+import org.flowable.bpmn.model.Process;
+import org.flowable.bpmn.model.*;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.repository.ProcessDefinition;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Tony
+ * @date 2021/4/19 20:51
+ */
+public class FindNextNodeUtil {
+
+    /**
+     * 鑾峰彇涓嬩竴姝ラ鐨勭敤鎴蜂换鍔�
+     *
+     * @param repositoryService
+     * @param map
+     * @return
+     */
+    public static List<UserTask> getNextUserTasks(RepositoryService repositoryService, org.flowable.task.api.Task task, Map<String, Object> map) {
+        List<UserTask> data = new ArrayList<>();
+        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
+        Process mainProcess = bpmnModel.getMainProcess();
+        Collection<FlowElement> flowElements = mainProcess.getFlowElements();
+        String key = task.getTaskDefinitionKey();
+        FlowElement flowElement = bpmnModel.getFlowElement(key);
+        next(flowElements, flowElement, map, data);
+        return data;
+    }
+
+    /**
+     * 鍚姩娴佺▼鏃惰幏鍙栦笅涓�姝ラ鐨勭敤鎴蜂换鍔�
+     *
+     * @param repositoryService
+     * @param map
+     * @return
+     */
+    public static List<UserTask> getNextUserTasksByStart(RepositoryService repositoryService, ProcessDefinition processDefinition, Map<String, Object> map) {
+        List<UserTask> data = new ArrayList<>();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
+        Process mainProcess = bpmnModel.getMainProcess();
+        Collection<FlowElement> flowElements = mainProcess.getFlowElements();
+        String key = null;
+        // 鎵惧埌寮�濮嬭妭鐐� 骞惰幏鍙栧敮涓�key
+        for (FlowElement flowElement : flowElements) {
+            if (flowElement instanceof StartEvent) {
+                key = flowElement.getId();
+                break;
+            }
+        }
+        FlowElement flowElement = bpmnModel.getFlowElement(key);
+        List<SequenceFlow> sequenceFlows = ((StartEvent)flowElement).getOutgoingFlows();
+        // 鑾峰彇鍑哄彛杩炵嚎, 姝ゆ椂浠庡紑濮嬭妭鐐瑰線鍚�,鍙兘鏄竴涓嚭鍙�
+        if (!sequenceFlows.isEmpty()) {
+            SequenceFlow sequenceFlow = sequenceFlows.get(0);
+            FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
+            next(flowElements, targetFlowElement, map, data);
+        }
+        return data;
+    }
+
+
+    /**
+     * 鏌ユ壘涓嬩竴鑺傜偣
+     *
+     * @param flowElements
+     * @param flowElement
+     * @param map
+     * @param nextUser
+     */
+    public static void next(Collection<FlowElement> flowElements, FlowElement flowElement, Map<String, Object> map, List<UserTask> nextUser) {
+        //濡傛灉鏄粨鏉熻妭鐐�
+        if (flowElement instanceof EndEvent) {
+            //濡傛灉鏄瓙浠诲姟鐨勭粨鏉熻妭鐐�
+            if (getSubProcess(flowElements, flowElement) != null) {
+                flowElement = getSubProcess(flowElements, flowElement);
+            }
+        }
+        //鑾峰彇Task鐨勫嚭绾夸俊鎭�--鍙互鎷ユ湁澶氫釜
+        List<SequenceFlow> outGoingFlows = null;
+        if (flowElement instanceof Task) {
+            outGoingFlows = ((Task) flowElement).getOutgoingFlows();
+        } else if (flowElement instanceof Gateway) {
+            outGoingFlows = ((Gateway) flowElement).getOutgoingFlows();
+        } else if (flowElement instanceof StartEvent) {
+            outGoingFlows = ((StartEvent) flowElement).getOutgoingFlows();
+        } else if (flowElement instanceof SubProcess) {
+            outGoingFlows = ((SubProcess) flowElement).getOutgoingFlows();
+        } else if (flowElement instanceof CallActivity) {
+            outGoingFlows = ((CallActivity) flowElement).getOutgoingFlows();
+        }
+        if (outGoingFlows != null && outGoingFlows.size() > 0) {
+            //閬嶅巻鎵�鏈夌殑鍑虹嚎--鎵惧埌鍙互姝g‘鎵ц鐨勯偅涓�鏉�
+            for (SequenceFlow sequenceFlow : outGoingFlows) {
+                //1.鏈夎〃杈惧紡锛屼笖涓簍rue
+                //2.鏃犺〃杈惧紡
+                String expression = sequenceFlow.getConditionExpression();
+                if (expression == null ||
+                        expressionResult(map, expression.substring(expression.lastIndexOf("{") + 1, expression.lastIndexOf("}")))) {
+                    //鍑虹嚎鐨勪笅涓�鑺傜偣
+                    String nextFlowElementID = sequenceFlow.getTargetRef();
+                    if (checkSubProcess(nextFlowElementID, flowElements, nextUser)) {
+                        continue;
+                    }
+
+                    //鏌ヨ涓嬩竴鑺傜偣鐨勪俊鎭�
+                    FlowElement nextFlowElement = getFlowElementById(nextFlowElementID, flowElements);
+                    //璋冪敤娴佺▼
+                    if (nextFlowElement instanceof CallActivity) {
+                        CallActivity ca = (CallActivity) nextFlowElement;
+                        if (ca.getLoopCharacteristics() != null) {
+                            UserTask userTask = new UserTask();
+                            userTask.setId(ca.getId());
+
+                            userTask.setId(ca.getId());
+                            userTask.setLoopCharacteristics(ca.getLoopCharacteristics());
+                            userTask.setName(ca.getName());
+                            nextUser.add(userTask);
+                        }
+                        next(flowElements, nextFlowElement, map, nextUser);
+                    }
+                    //鐢ㄦ埛浠诲姟
+                    if (nextFlowElement instanceof UserTask) {
+                        nextUser.add((UserTask) nextFlowElement);
+                    }
+                    //鎺掍粬缃戝叧
+                    else if (nextFlowElement instanceof ExclusiveGateway) {
+                        next(flowElements, nextFlowElement, map, nextUser);
+                    }
+                    //骞惰缃戝叧
+                    else if (nextFlowElement instanceof ParallelGateway) {
+                        next(flowElements, nextFlowElement, map, nextUser);
+                    }
+                    //鎺ユ敹浠诲姟
+                    else if (nextFlowElement instanceof ReceiveTask) {
+                        next(flowElements, nextFlowElement, map, nextUser);
+                    }
+                    //鏈嶅姟浠诲姟
+                    else if (nextFlowElement instanceof ServiceTask) {
+                        next(flowElements, nextFlowElement, map, nextUser);
+                    }
+                    //瀛愪换鍔$殑璧风偣
+                    else if (nextFlowElement instanceof StartEvent) {
+                        next(flowElements, nextFlowElement, map, nextUser);
+                    }
+                    //缁撴潫鑺傜偣
+                    else if (nextFlowElement instanceof EndEvent) {
+                        next(flowElements, nextFlowElement, map, nextUser);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁鏄瀹炰緥瀛愭祦绋嬪苟涓旈渶瑕佽缃泦鍚堢被鍨嬪彉閲�
+     */
+    public static boolean checkSubProcess(String id, Collection<FlowElement> flowElements, List<UserTask> nextUser) {
+        for (FlowElement flowElement1 : flowElements) {
+            if (flowElement1 instanceof SubProcess && flowElement1.getId().equals(id)) {
+
+                SubProcess sp = (SubProcess) flowElement1;
+                if (sp.getLoopCharacteristics() != null) {
+//                    String inputDataItem = sp.getLoopCharacteristics().getInputDataItem();
+                    UserTask userTask = new UserTask();
+                    userTask.setId(sp.getId());
+                    userTask.setLoopCharacteristics(sp.getLoopCharacteristics());
+                    userTask.setName(sp.getName());
+                    nextUser.add(userTask);
+                    return true;
+                }
+            }
+        }
+
+        return false;
+
+    }
+
+    /**
+     * 鏌ヨ涓�涓妭鐐圭殑鏄惁瀛愪换鍔′腑鐨勮妭鐐癸紝濡傛灉鏄紝杩斿洖瀛愪换鍔�
+     *
+     * @param flowElements 鍏ㄦ祦绋嬬殑鑺傜偣闆嗗悎
+     * @param flowElement  褰撳墠鑺傜偣
+     * @return
+     */
+    public static FlowElement getSubProcess(Collection<FlowElement> flowElements, FlowElement flowElement) {
+        for (FlowElement flowElement1 : flowElements) {
+            if (flowElement1 instanceof SubProcess) {
+                for (FlowElement flowElement2 : ((SubProcess) flowElement1).getFlowElements()) {
+                    if (flowElement.equals(flowElement2)) {
+                        return flowElement1;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * 鏍规嵁ID鏌ヨ娴佺▼鑺傜偣瀵硅薄, 濡傛灉鏄瓙浠诲姟锛屽垯杩斿洖瀛愪换鍔$殑寮�濮嬭妭鐐�
+     *
+     * @param Id           鑺傜偣ID
+     * @param flowElements 娴佺▼鑺傜偣闆嗗悎
+     * @return
+     */
+    public static FlowElement getFlowElementById(String Id, Collection<FlowElement> flowElements) {
+        for (FlowElement flowElement : flowElements) {
+            if (flowElement.getId().equals(Id)) {
+                //濡傛灉鏄瓙浠诲姟锛屽垯鏌ヨ鍑哄瓙浠诲姟鐨勫紑濮嬭妭鐐�
+                if (flowElement instanceof SubProcess) {
+                    return getStartFlowElement(((SubProcess) flowElement).getFlowElements());
+                }
+                return flowElement;
+            }
+            if (flowElement instanceof SubProcess) {
+                FlowElement flowElement1 = getFlowElementById(Id, ((SubProcess) flowElement).getFlowElements());
+                if (flowElement1 != null) {
+                    return flowElement1;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 杩斿洖娴佺▼鐨勫紑濮嬭妭鐐�
+     *
+     * @param flowElements 鑺傜偣闆嗗悎
+     * @description:
+     */
+    public static FlowElement getStartFlowElement(Collection<FlowElement> flowElements) {
+        for (FlowElement flowElement : flowElements) {
+            if (flowElement instanceof StartEvent) {
+                return flowElement;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 鏍¢獙el琛ㄨ揪寮�
+     *
+     * @param map
+     * @param expression
+     * @return
+     */
+    public static boolean expressionResult(Map<String, Object> map, String expression) {
+        Expression exp = AviatorEvaluator.compile(expression);
+        return (Boolean) exp.execute(map);
+//        return true;
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/flow/FlowableUtils.java b/flowable/src/main/java/com/ycl/flow/FlowableUtils.java
new file mode 100644
index 0000000..4e5ea28
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/flow/FlowableUtils.java
@@ -0,0 +1,702 @@
+package com.ycl.flow;
+
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.bpmn.model.*;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
+import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
+import org.flowable.engine.repository.ProcessDefinition;
+import org.flowable.task.api.history.HistoricTaskInstance;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author Tony
+ * @date 2021-04-03 23:57
+ */
+@Slf4j
+public class FlowableUtils {
+
+    /**
+     * 鏍规嵁鑺傜偣锛岃幏鍙栧叆鍙h繛绾�
+     *
+     * @param source
+     * @return
+     */
+    public static List<SequenceFlow> getElementIncomingFlows(FlowElement source) {
+        List<SequenceFlow> sequenceFlows = null;
+        if (source instanceof FlowNode) {
+            sequenceFlows = ((FlowNode) source).getIncomingFlows();
+        } else if (source instanceof Gateway) {
+            sequenceFlows = ((Gateway) source).getIncomingFlows();
+        } else if (source instanceof SubProcess) {
+            sequenceFlows = ((SubProcess) source).getIncomingFlows();
+        } else if (source instanceof StartEvent) {
+            sequenceFlows = ((StartEvent) source).getIncomingFlows();
+        } else if (source instanceof EndEvent) {
+            sequenceFlows = ((EndEvent) source).getIncomingFlows();
+        }
+        return sequenceFlows;
+    }
+
+    /**
+     * 鏍规嵁鑺傜偣锛岃幏鍙栧嚭鍙h繛绾�
+     *
+     * @param source
+     * @return
+     */
+    public static List<SequenceFlow> getElementOutgoingFlows(FlowElement source) {
+        List<SequenceFlow> sequenceFlows = null;
+        if (source instanceof FlowNode) {
+            sequenceFlows = ((FlowNode) source).getOutgoingFlows();
+        } else if (source instanceof Gateway) {
+            sequenceFlows = ((Gateway) source).getOutgoingFlows();
+        } else if (source instanceof SubProcess) {
+            sequenceFlows = ((SubProcess) source).getOutgoingFlows();
+        } else if (source instanceof StartEvent) {
+            sequenceFlows = ((StartEvent) source).getOutgoingFlows();
+        } else if (source instanceof EndEvent) {
+            sequenceFlows = ((EndEvent) source).getOutgoingFlows();
+        }
+        return sequenceFlows;
+    }
+
+    /**
+     * 鑾峰彇鍏ㄩ儴鑺傜偣鍒楄〃锛屽寘鍚瓙娴佺▼鑺傜偣
+     *
+     * @param flowElements
+     * @param allElements
+     * @return
+     */
+    public static Collection<FlowElement> getAllElements(Collection<FlowElement> flowElements, Collection<FlowElement> allElements) {
+        allElements = allElements == null ? new ArrayList<>() : allElements;
+
+        for (FlowElement flowElement : flowElements) {
+            allElements.add(flowElement);
+            if (flowElement instanceof SubProcess) {
+                // 缁х画娣卞叆瀛愭祦绋嬶紝杩涗竴姝ヨ幏鍙栧瓙娴佺▼
+                allElements = FlowableUtils.getAllElements(((SubProcess) flowElement).getFlowElements(), allElements);
+            }
+        }
+        return allElements;
+    }
+
+    /**
+     * 杩唬鑾峰彇鐖剁骇浠诲姟鑺傜偣鍒楄〃锛屽悜鍓嶆壘
+     *
+     * @param source          璧峰鑺傜偣
+     * @param hasSequenceFlow 宸茬粡缁忚繃鐨勮繛绾跨殑 ID锛岀敤浜庡垽鏂嚎璺槸鍚﹂噸澶�
+     * @param userTaskList    宸叉壘鍒扮殑鐢ㄦ埛浠诲姟鑺傜偣
+     * @return
+     */
+    public static List<UserTask> iteratorFindParentUserTasks(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
+        userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
+        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
+
+        // 濡傛灉璇ヨ妭鐐逛负寮�濮嬭妭鐐癸紝涓斿瓨鍦ㄤ笂绾у瓙鑺傜偣锛屽垯椤虹潃涓婄骇瀛愯妭鐐圭户缁凯浠�
+        if (source instanceof StartEvent && source.getSubProcess() != null) {
+            userTaskList = iteratorFindParentUserTasks(source.getSubProcess(), hasSequenceFlow, userTaskList);
+        }
+
+        // 鏍规嵁绫诲瀷锛岃幏鍙栧叆鍙h繛绾�
+        List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
+
+        if (sequenceFlows != null) {
+            // 寰幆鎵惧埌鐩爣鍏冪礌
+            for (SequenceFlow sequenceFlow : sequenceFlows) {
+                // 濡傛灉鍙戠幇杩炵嚎閲嶅锛岃鏄庡惊鐜簡锛岃烦杩囪繖涓惊鐜�
+                if (hasSequenceFlow.contains(sequenceFlow.getId())) {
+                    continue;
+                }
+                // 娣诲姞宸茬粡璧拌繃鐨勮繛绾�
+                hasSequenceFlow.add(sequenceFlow.getId());
+                // 绫诲瀷涓虹敤鎴疯妭鐐癸紝鍒欐柊澧炵埗绾ц妭鐐�
+                if (sequenceFlow.getSourceFlowElement() instanceof UserTask) {
+                    userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement());
+                    continue;
+                }
+                // 绫诲瀷涓哄瓙娴佺▼锛屽垯娣诲姞瀛愭祦绋嬪紑濮嬭妭鐐瑰嚭鍙e鐩歌繛鐨勮妭鐐�
+                if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) {
+                    // 鑾峰彇瀛愭祦绋嬬敤鎴蜂换鍔¤妭鐐�
+                    List<UserTask> childUserTaskList = findChildProcessUserTasks((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, null);
+                    // 濡傛灉鎵惧埌鑺傜偣锛屽垯璇存槑璇ョ嚎璺壘鍒拌妭鐐癸紝涓嶇户缁悜涓嬫壘锛屽弽涔嬬户缁�
+                    if (childUserTaskList != null && childUserTaskList.size() > 0) {
+                        userTaskList.addAll(childUserTaskList);
+                        continue;
+                    }
+                }
+                // 缁х画杩唬
+                userTaskList = iteratorFindParentUserTasks(sequenceFlow.getSourceFlowElement(), hasSequenceFlow, userTaskList);
+            }
+        }
+        return userTaskList;
+    }
+
+    /**
+     * 鏍规嵁姝e湪杩愯鐨勪换鍔¤妭鐐癸紝杩唬鑾峰彇瀛愮骇浠诲姟鑺傜偣鍒楄〃锛屽悜鍚庢壘
+     *
+     * @param source          璧峰鑺傜偣(閫�鍥炶妭鐐�)
+     * @param runTaskKeyList  姝e湪杩愯鐨勪换鍔� Key锛岀敤浜庢牎楠屼换鍔¤妭鐐规槸鍚︽槸姝e湪杩愯鐨勮妭鐐�
+     * @param hasSequenceFlow 宸茬粡缁忚繃鐨勮繛绾跨殑 ID锛岀敤浜庡垽鏂嚎璺槸鍚﹂噸澶�
+     * @param userTaskList    闇�瑕佹挙鍥炵殑鐢ㄦ埛浠诲姟鍒楄〃
+     * @return
+     */
+    public static List<UserTask> iteratorFindChildUserTasks(FlowElement source, List<String> runTaskKeyList, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
+        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
+        userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
+
+        // 濡傛灉璇ヨ妭鐐逛负寮�濮嬭妭鐐癸紝涓斿瓨鍦ㄤ笂绾у瓙鑺傜偣锛屽垯椤虹潃涓婄骇瀛愯妭鐐圭户缁凯浠�
+        if (source instanceof EndEvent && source.getSubProcess() != null) {
+            userTaskList = iteratorFindChildUserTasks(source.getSubProcess(), runTaskKeyList, hasSequenceFlow, userTaskList);
+        }
+
+        // 鏍规嵁绫诲瀷锛岃幏鍙栧嚭鍙h繛绾�
+        List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
+
+        if (sequenceFlows != null) {
+            // 寰幆鎵惧埌鐩爣鍏冪礌
+            for (SequenceFlow sequenceFlow : sequenceFlows) {
+                // 濡傛灉鍙戠幇杩炵嚎閲嶅锛岃鏄庡惊鐜簡锛岃烦杩囪繖涓惊鐜�
+                if (hasSequenceFlow.contains(sequenceFlow.getId())) {
+                    continue;
+                }
+                // 娣诲姞宸茬粡璧拌繃鐨勮繛绾�
+                hasSequenceFlow.add(sequenceFlow.getId());
+                // 濡傛灉涓虹敤鎴蜂换鍔$被鍨嬶紝涓斾换鍔¤妭鐐圭殑 Key 姝e湪杩愯鐨勪换鍔′腑瀛樺湪锛屾坊鍔�
+                if (sequenceFlow.getTargetFlowElement() instanceof UserTask && runTaskKeyList.contains((sequenceFlow.getTargetFlowElement()).getId())) {
+                    userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
+                    continue;
+                }
+                // 濡傛灉鑺傜偣涓哄瓙娴佺▼鑺傜偣鎯呭喌锛屽垯浠庤妭鐐逛腑鐨勭涓�涓妭鐐瑰紑濮嬭幏鍙�
+                if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
+                    List<UserTask> childUserTaskList = iteratorFindChildUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), runTaskKeyList, hasSequenceFlow, null);
+                    // 濡傛灉鎵惧埌鑺傜偣锛屽垯璇存槑璇ョ嚎璺壘鍒拌妭鐐癸紝涓嶇户缁悜涓嬫壘锛屽弽涔嬬户缁�
+                    if (childUserTaskList != null && childUserTaskList.size() > 0) {
+                        userTaskList.addAll(childUserTaskList);
+                        continue;
+                    }
+                }
+                // 缁х画杩唬
+                userTaskList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, hasSequenceFlow, userTaskList);
+            }
+        }
+        return userTaskList;
+    }
+
+    /**
+     * 杩唬鑾峰彇瀛愭祦绋嬬敤鎴蜂换鍔¤妭鐐�
+     *
+     * @param source          璧峰鑺傜偣
+     * @param hasSequenceFlow 宸茬粡缁忚繃鐨勮繛绾跨殑 ID锛岀敤浜庡垽鏂嚎璺槸鍚﹂噸澶�
+     * @param userTaskList    闇�瑕佹挙鍥炵殑鐢ㄦ埛浠诲姟鍒楄〃
+     * @return
+     */
+    public static List<UserTask> findChildProcessUserTasks(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
+        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
+        userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
+
+        // 鏍规嵁绫诲瀷锛岃幏鍙栧嚭鍙h繛绾�
+        List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
+
+        if (sequenceFlows != null) {
+            // 寰幆鎵惧埌鐩爣鍏冪礌
+            for (SequenceFlow sequenceFlow : sequenceFlows) {
+                // 濡傛灉鍙戠幇杩炵嚎閲嶅锛岃鏄庡惊鐜簡锛岃烦杩囪繖涓惊鐜�
+                if (hasSequenceFlow.contains(sequenceFlow.getId())) {
+                    continue;
+                }
+                // 娣诲姞宸茬粡璧拌繃鐨勮繛绾�
+                hasSequenceFlow.add(sequenceFlow.getId());
+                // 濡傛灉涓虹敤鎴蜂换鍔$被鍨嬶紝涓斾换鍔¤妭鐐圭殑 Key 姝e湪杩愯鐨勪换鍔′腑瀛樺湪锛屾坊鍔�
+                if (sequenceFlow.getTargetFlowElement() instanceof UserTask) {
+                    userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
+                    continue;
+                }
+                // 濡傛灉鑺傜偣涓哄瓙娴佺▼鑺傜偣鎯呭喌锛屽垯浠庤妭鐐逛腑鐨勭涓�涓妭鐐瑰紑濮嬭幏鍙�
+                if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
+                    List<UserTask> childUserTaskList = findChildProcessUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, null);
+                    // 濡傛灉鎵惧埌鑺傜偣锛屽垯璇存槑璇ョ嚎璺壘鍒拌妭鐐癸紝涓嶇户缁悜涓嬫壘锛屽弽涔嬬户缁�
+                    if (childUserTaskList != null && childUserTaskList.size() > 0) {
+                        userTaskList.addAll(childUserTaskList);
+                        continue;
+                    }
+                }
+                // 缁х画杩唬
+                userTaskList = findChildProcessUserTasks(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, userTaskList);
+            }
+        }
+        return userTaskList;
+    }
+
+    /**
+     * 浠庡悗鍚戝墠瀵昏矾锛岃幏鍙栨墍鏈夎剰绾胯矾涓婄殑鐐�
+     *
+     * @param source          璧峰鑺傜偣
+     * @param passRoads       宸茬粡缁忚繃鐨勭偣闆嗗悎
+     * @param hasSequenceFlow 宸茬粡缁忚繃鐨勮繛绾跨殑 ID锛岀敤浜庡垽鏂嚎璺槸鍚﹂噸澶�
+     * @param targets         鐩爣鑴忕嚎璺粓鐐�
+     * @param dirtyRoads      纭畾涓鸿剰鏁版嵁鐨勭偣锛屽洜涓轰笉闇�瑕侀噸澶嶏紝鍥犳浣跨敤 set 瀛樺偍
+     * @return
+     */
+    public static Set<String> iteratorFindDirtyRoads(FlowElement source, List<String> passRoads, Set<String> hasSequenceFlow, List<String> targets, Set<String> dirtyRoads) {
+        passRoads = passRoads == null ? new ArrayList<>() : passRoads;
+        dirtyRoads = dirtyRoads == null ? new HashSet<>() : dirtyRoads;
+        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
+
+        // 濡傛灉璇ヨ妭鐐逛负寮�濮嬭妭鐐癸紝涓斿瓨鍦ㄤ笂绾у瓙鑺傜偣锛屽垯椤虹潃涓婄骇瀛愯妭鐐圭户缁凯浠�
+        if (source instanceof StartEvent && source.getSubProcess() != null) {
+            dirtyRoads = iteratorFindDirtyRoads(source.getSubProcess(), passRoads, hasSequenceFlow, targets, dirtyRoads);
+        }
+
+        // 鏍规嵁绫诲瀷锛岃幏鍙栧叆鍙h繛绾�
+        List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
+
+        if (sequenceFlows != null) {
+            // 寰幆鎵惧埌鐩爣鍏冪礌
+            for (SequenceFlow sequenceFlow : sequenceFlows) {
+                // 濡傛灉鍙戠幇杩炵嚎閲嶅锛岃鏄庡惊鐜簡锛岃烦杩囪繖涓惊鐜�
+                if (hasSequenceFlow.contains(sequenceFlow.getId())) {
+                    continue;
+                }
+                // 娣诲姞宸茬粡璧拌繃鐨勮繛绾�
+                hasSequenceFlow.add(sequenceFlow.getId());
+                // 鏂板缁忚繃鐨勮矾绾�
+                passRoads.add(sequenceFlow.getSourceFlowElement().getId());
+                // 濡傛灉姝ょ偣涓虹洰鏍囩偣锛岀‘瀹氱粡杩囩殑璺嚎涓鸿剰绾胯矾锛屾坊鍔犵偣鍒拌剰绾胯矾涓紝鐒跺悗鎵句笅涓繛绾�
+                if (targets.contains(sequenceFlow.getSourceFlowElement().getId())) {
+                    dirtyRoads.addAll(passRoads);
+                    continue;
+                }
+                // 濡傛灉璇ヨ妭鐐逛负寮�濮嬭妭鐐癸紝涓斿瓨鍦ㄤ笂绾у瓙鑺傜偣锛屽垯椤虹潃涓婄骇瀛愯妭鐐圭户缁凯浠�
+                if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) {
+                    dirtyRoads = findChildProcessAllDirtyRoad((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, dirtyRoads);
+                    // 鏄惁瀛樺湪瀛愭祦绋嬩笂锛宼rue 鏄紝false 鍚�
+                    Boolean isInChildProcess = dirtyTargetInChildProcess((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, targets, null);
+                    if (isInChildProcess) {
+                        // 宸插湪瀛愭祦绋嬩笂鎵惧埌锛岃璺嚎缁撴潫
+                        continue;
+                    }
+                }
+                // 缁х画杩唬
+                dirtyRoads = iteratorFindDirtyRoads(sequenceFlow.getSourceFlowElement(), passRoads, hasSequenceFlow, targets, dirtyRoads);
+            }
+        }
+        return dirtyRoads;
+    }
+
+    /**
+     * 杩唬鑾峰彇瀛愭祦绋嬭剰璺嚎
+     * 璇存槑锛屽亣濡傚洖閫�鐨勭偣灏辨槸瀛愭祦绋嬶紝閭d箞涔熻偗瀹氫細鍥為��鍒板瓙娴佺▼鏈�鍒濈殑鐢ㄦ埛浠诲姟鑺傜偣锛屽洜姝ゅ瓙娴佺▼涓殑鑺傜偣鍏ㄦ槸鑴忚矾绾�
+     *
+     * @param source          璧峰鑺傜偣
+     * @param hasSequenceFlow 宸茬粡缁忚繃鐨勮繛绾跨殑 ID锛岀敤浜庡垽鏂嚎璺槸鍚﹂噸澶�
+     * @param dirtyRoads      纭畾涓鸿剰鏁版嵁鐨勭偣锛屽洜涓轰笉闇�瑕侀噸澶嶏紝鍥犳浣跨敤 set 瀛樺偍
+     * @return
+     */
+    public static Set<String> findChildProcessAllDirtyRoad(FlowElement source, Set<String> hasSequenceFlow, Set<String> dirtyRoads) {
+        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
+        dirtyRoads = dirtyRoads == null ? new HashSet<>() : dirtyRoads;
+
+        // 鏍规嵁绫诲瀷锛岃幏鍙栧嚭鍙h繛绾�
+        List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
+
+        if (sequenceFlows != null) {
+            // 寰幆鎵惧埌鐩爣鍏冪礌
+            for (SequenceFlow sequenceFlow : sequenceFlows) {
+                // 濡傛灉鍙戠幇杩炵嚎閲嶅锛岃鏄庡惊鐜簡锛岃烦杩囪繖涓惊鐜�
+                if (hasSequenceFlow.contains(sequenceFlow.getId())) {
+                    continue;
+                }
+                // 娣诲姞宸茬粡璧拌繃鐨勮繛绾�
+                hasSequenceFlow.add(sequenceFlow.getId());
+                // 娣诲姞鑴忚矾绾�
+                dirtyRoads.add(sequenceFlow.getTargetFlowElement().getId());
+                // 濡傛灉鑺傜偣涓哄瓙娴佺▼鑺傜偣鎯呭喌锛屽垯浠庤妭鐐逛腑鐨勭涓�涓妭鐐瑰紑濮嬭幏鍙�
+                if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
+                    dirtyRoads = findChildProcessAllDirtyRoad((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, dirtyRoads);
+                }
+                // 缁х画杩唬
+                dirtyRoads = findChildProcessAllDirtyRoad(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, dirtyRoads);
+            }
+        }
+        return dirtyRoads;
+    }
+
+    /**
+     * 鍒ゆ柇鑴忚矾绾跨粨鏉熻妭鐐规槸鍚﹀湪瀛愭祦绋嬩笂
+     *
+     * @param source          璧峰鑺傜偣
+     * @param hasSequenceFlow 宸茬粡缁忚繃鐨勮繛绾跨殑 ID锛岀敤浜庡垽鏂嚎璺槸鍚﹂噸澶�
+     * @param targets         鍒ゆ柇鑴忚矾绾胯妭鐐规槸鍚﹀瓨鍦ㄥ瓙娴佺▼涓婏紝鍙瀛樺湪涓�涓紝璇存槑鑴忚矾绾垮彧鍒板瓙娴佺▼涓烘
+     * @param inChildProcess  鏄惁瀛樺湪瀛愭祦绋嬩笂锛宼rue 鏄紝false 鍚�
+     * @return
+     */
+    public static Boolean dirtyTargetInChildProcess(FlowElement source, Set<String> hasSequenceFlow, List<String> targets, Boolean inChildProcess) {
+        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
+        inChildProcess = inChildProcess != null && inChildProcess;
+
+        // 鏍规嵁绫诲瀷锛岃幏鍙栧嚭鍙h繛绾�
+        List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
+
+        if (sequenceFlows != null && !inChildProcess) {
+            // 寰幆鎵惧埌鐩爣鍏冪礌
+            for (SequenceFlow sequenceFlow : sequenceFlows) {
+                // 濡傛灉鍙戠幇杩炵嚎閲嶅锛岃鏄庡惊鐜簡锛岃烦杩囪繖涓惊鐜�
+                if (hasSequenceFlow.contains(sequenceFlow.getId())) {
+                    continue;
+                }
+                // 娣诲姞宸茬粡璧拌繃鐨勮繛绾�
+                hasSequenceFlow.add(sequenceFlow.getId());
+                // 濡傛灉鍙戠幇鐩爣鐐瑰湪瀛愭祦绋嬩笂瀛樺湪锛岃鏄庡彧鍒板瓙娴佺▼涓烘
+                if (targets.contains(sequenceFlow.getTargetFlowElement().getId())) {
+                    inChildProcess = true;
+                    break;
+                }
+                // 濡傛灉鑺傜偣涓哄瓙娴佺▼鑺傜偣鎯呭喌锛屽垯浠庤妭鐐逛腑鐨勭涓�涓妭鐐瑰紑濮嬭幏鍙�
+                if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
+                    inChildProcess = dirtyTargetInChildProcess((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, targets, inChildProcess);
+                }
+                // 缁х画杩唬
+                inChildProcess = dirtyTargetInChildProcess(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, targets, inChildProcess);
+            }
+        }
+        return inChildProcess;
+    }
+
+    /**
+     * 杩唬浠庡悗鍚戝墠鎵弿锛屽垽鏂洰鏍囪妭鐐圭浉瀵逛簬褰撳墠鑺傜偣鏄惁鏄覆琛�
+     * 涓嶅瓨鍦ㄧ洿鎺ュ洖閫�鍒板瓙娴佺▼涓殑鎯呭喌锛屼絾瀛樺湪浠庡瓙娴佺▼鍑哄幓鍒扮埗娴佺▼鎯呭喌
+     *
+     * @param source          璧峰鑺傜偣
+     * @param isSequential    鏄惁涓茶
+     * @param hasSequenceFlow 宸茬粡缁忚繃鐨勮繛绾跨殑 ID锛岀敤浜庡垽鏂嚎璺槸鍚﹂噸澶�
+     * @param targetKsy       鐩爣鑺傜偣
+     * @return
+     */
+    public static Boolean iteratorCheckSequentialReferTarget(FlowElement source, String targetKsy, Set<String> hasSequenceFlow, Boolean isSequential) {
+        isSequential = isSequential == null || isSequential;
+        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
+
+        // 濡傛灉璇ヨ妭鐐逛负寮�濮嬭妭鐐癸紝涓斿瓨鍦ㄤ笂绾у瓙鑺傜偣锛屽垯椤虹潃涓婄骇瀛愯妭鐐圭户缁凯浠�
+        if (source instanceof StartEvent && source.getSubProcess() != null) {
+            isSequential = iteratorCheckSequentialReferTarget(source.getSubProcess(), targetKsy, hasSequenceFlow, isSequential);
+        }
+
+        // 鏍规嵁绫诲瀷锛岃幏鍙栧叆鍙h繛绾�
+        List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
+
+        if (sequenceFlows != null) {
+            // 寰幆鎵惧埌鐩爣鍏冪礌
+            for (SequenceFlow sequenceFlow : sequenceFlows) {
+                // 濡傛灉鍙戠幇杩炵嚎閲嶅锛岃鏄庡惊鐜簡锛岃烦杩囪繖涓惊鐜�
+                if (hasSequenceFlow.contains(sequenceFlow.getId())) {
+                    continue;
+                }
+                // 娣诲姞宸茬粡璧拌繃鐨勮繛绾�
+                hasSequenceFlow.add(sequenceFlow.getId());
+                // 濡傛灉鐩爣鑺傜偣宸茶鍒ゆ柇涓哄苟琛岋紝鍚庨潰閮戒笉闇�瑕佹墽琛岋紝鐩存帴杩斿洖
+                if (!isSequential) {
+                    break;
+                }
+                // 杩欐潯绾胯矾瀛樺湪鐩爣鑺傜偣锛岃繖鏉$嚎璺畬鎴愶紝杩涘叆涓嬩釜绾胯矾
+                if (targetKsy.equals(sequenceFlow.getSourceFlowElement().getId())) {
+                    continue;
+                }
+                if (sequenceFlow.getSourceFlowElement() instanceof StartEvent) {
+                    isSequential = false;
+                    break;
+                }
+                // 鍚﹀垯灏辩户缁凯浠�
+                isSequential = iteratorCheckSequentialReferTarget(sequenceFlow.getSourceFlowElement(), targetKsy, hasSequenceFlow, isSequential);
+            }
+        }
+        return isSequential;
+    }
+
+    /**
+     * 浠庡悗鍚戝墠瀵昏矾锛岃幏鍙栧埌杈捐妭鐐圭殑鎵�鏈夎矾绾�
+     * 涓嶅瓨鍦ㄧ洿鎺ュ洖閫�鍒板瓙娴佺▼锛屼絾鏄瓨鍦ㄥ洖閫�鍒扮埗绾ф祦绋嬬殑鎯呭喌
+     *
+     * @param source    璧峰鑺傜偣
+     * @param passRoads 宸茬粡缁忚繃鐨勭偣闆嗗悎
+     * @param roads     璺嚎
+     * @return
+     */
+    public static List<List<UserTask>> findRoad(FlowElement source, List<UserTask> passRoads, Set<String> hasSequenceFlow, List<List<UserTask>> roads) {
+        passRoads = passRoads == null ? new ArrayList<>() : passRoads;
+        roads = roads == null ? new ArrayList<>() : roads;
+        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
+
+        // 濡傛灉璇ヨ妭鐐逛负寮�濮嬭妭鐐癸紝涓斿瓨鍦ㄤ笂绾у瓙鑺傜偣锛屽垯椤虹潃涓婄骇瀛愯妭鐐圭户缁凯浠�
+        if (source instanceof StartEvent && source.getSubProcess() != null) {
+            roads = findRoad(source.getSubProcess(), passRoads, hasSequenceFlow, roads);
+        }
+
+        // 鏍规嵁绫诲瀷锛岃幏鍙栧叆鍙h繛绾�
+        List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
+
+        if (sequenceFlows != null && sequenceFlows.size() != 0) {
+            for (SequenceFlow sequenceFlow : sequenceFlows) {
+                // 濡傛灉鍙戠幇杩炵嚎閲嶅锛岃鏄庡惊鐜簡锛岃烦杩囪繖涓惊鐜�
+                if (hasSequenceFlow.contains(sequenceFlow.getId())) {
+                    continue;
+                }
+                // 娣诲姞宸茬粡璧拌繃鐨勮繛绾�
+                hasSequenceFlow.add(sequenceFlow.getId());
+                // 娣诲姞缁忚繃璺嚎
+                if (sequenceFlow.getSourceFlowElement() instanceof UserTask) {
+                    passRoads.add((UserTask) sequenceFlow.getSourceFlowElement());
+                }
+                // 缁х画杩唬
+                roads = findRoad(sequenceFlow.getSourceFlowElement(), passRoads, hasSequenceFlow, roads);
+            }
+        } else {
+            // 娣诲姞璺嚎
+            roads.add(passRoads);
+        }
+        return roads;
+    }
+
+    /**
+     * 鍘嗗彶鑺傜偣鏁版嵁娓呮礂锛屾竻娲楁帀鍙堝洖婊氬鑷寸殑鑴忔暟鎹�
+     *
+     * @param allElements              鍏ㄩ儴鑺傜偣淇℃伅
+     * @param historicTaskInstanceList 鍘嗗彶浠诲姟瀹炰緥淇℃伅锛屾暟鎹噰鐢ㄥ紑濮嬫椂闂村崌搴�
+     * @return
+     */
+    public static List<String> historicTaskInstanceClean(Collection<FlowElement> allElements, List<HistoricTaskInstance> historicTaskInstanceList) {
+        // 浼氱鑺傜偣鏀堕泦
+        List<String> multiTask = new ArrayList<>();
+        allElements.forEach(flowElement -> {
+            if (flowElement instanceof UserTask) {
+                // 濡傛灉璇ヨ妭鐐圭殑琛屼负涓轰細绛捐涓猴紝璇存槑璇ヨ妭鐐逛负浼氱鑺傜偣
+                if (((UserTask) flowElement).getBehavior() instanceof ParallelMultiInstanceBehavior || ((UserTask) flowElement).getBehavior() instanceof SequentialMultiInstanceBehavior) {
+                    multiTask.add(flowElement.getId());
+                }
+            }
+        });
+        // 寰幆鏀惧叆鏍堬紝鏍� LIFO锛氬悗杩涘厛鍑�
+        Stack<HistoricTaskInstance> stack = new Stack<>();
+        historicTaskInstanceList.forEach(stack::push);
+        // 娓呮礂鍚庣殑鍘嗗彶浠诲姟瀹炰緥
+        List<String> lastHistoricTaskInstanceList = new ArrayList<>();
+        // 缃戝叧瀛樺湪鍙兘鍙蛋浜嗛儴鍒嗗垎鏀儏鍐碉紝涓旇繕瀛樺湪璺宠浆搴熷純鏁版嵁浠ュ強鍏朵粬鍒嗘敮鏁版嵁鐨勫共鎵帮紝鍥犳闇�瑕佸鍘嗗彶鑺傜偣鏁版嵁杩涜娓呮礂
+        // 涓存椂鐢ㄦ埛浠诲姟 key
+        StringBuilder userTaskKey = null;
+        // 涓存椂琚垹鎺夌殑浠诲姟 key锛屽瓨鍦ㄥ苟琛屾儏鍐�
+        List<String> deleteKeyList = new ArrayList<>();
+        // 涓存椂鑴忔暟鎹嚎璺�
+        List<Set<String>> dirtyDataLineList = new ArrayList<>();
+        // 鐢辨煇涓偣璺冲埌浼氱鐐�,姝ゆ椂鍑虹幇澶氫釜浼氱瀹炰緥瀵瑰簲 1 涓烦杞儏鍐碉紝闇�瑕佹妸杩欎簺杩炵画鑴忔暟鎹兘鎵惧埌
+        // 浼氱鐗规畩澶勭悊涓嬫爣
+        int multiIndex = -1;
+        // 浼氱鐗规畩澶勭悊 key
+        StringBuilder multiKey = null;
+        // 浼氱鐗规畩澶勭悊鎿嶄綔鏍囪瘑
+        boolean multiOpera = false;
+        while (!stack.empty()) {
+            // 浠庤繖閲屽紑濮� userTaskKey 閮借繕鏄笂涓爤鐨� key
+            // 鏄惁鏄剰鏁版嵁绾胯矾涓婄殑鐐�
+            final boolean[] isDirtyData = {false};
+            for (Set<String> oldDirtyDataLine : dirtyDataLineList) {
+                if (oldDirtyDataLine.contains(stack.peek().getTaskDefinitionKey())) {
+                    isDirtyData[0] = true;
+                }
+            }
+            // 鍒犻櫎鍘熷洜涓嶄负绌猴紝璇存槑浠庤繖鏉℃暟鎹紑濮嬪洖璺虫垨鑰呭洖閫�鐨�
+            // MI_END锛氫細绛惧畬鎴愬悗锛屽叾浠栨湭绛惧埌鑺傜偣鐨勫垹闄ゅ師鍥狅紝涓嶅湪澶勭悊鑼冨洿鍐�
+            if (stack.peek().getDeleteReason() != null && !"MI_END".equals(stack.peek().getDeleteReason())) {
+                // 鍙互鐞嗚В涓鸿剰绾胯矾璧风偣
+                String dirtyPoint = "";
+                if (stack.peek().getDeleteReason().contains("Change activity to ")) {
+                    dirtyPoint = stack.peek().getDeleteReason().replace("Change activity to ", "");
+                }
+                // 浼氱鍥為��鍒犻櫎鍘熷洜鏈夌偣涓嶅悓
+                if (stack.peek().getDeleteReason().contains("Change parent activity to ")) {
+                    dirtyPoint = stack.peek().getDeleteReason().replace("Change parent activity to ", "");
+                }
+                FlowElement dirtyTask = null;
+                // 鑾峰彇鍙樻洿鑺傜偣鐨勫搴旂殑鍏ュ彛澶勮繛绾�
+                // 濡傛灉鏄綉鍏冲苟琛屽洖閫�鎯呭喌锛屼細鍙樻垚涓ゆ潯鑴忔暟鎹矾绾匡紝鏁堟灉涓�鏍�
+                for (FlowElement flowElement : allElements) {
+                    if (flowElement.getId().equals(stack.peek().getTaskDefinitionKey())) {
+                        dirtyTask = flowElement;
+                    }
+                }
+                // 鑾峰彇鑴忔暟鎹嚎璺�
+                Set<String> dirtyDataLine = FlowableUtils.iteratorFindDirtyRoads(dirtyTask, null, null, Arrays.asList(dirtyPoint.split(",")), null);
+                // 鑷繁鏈韩涔熸槸鑴忕嚎璺笂鐨勭偣锛屽姞杩涘幓
+                dirtyDataLine.add(stack.peek().getTaskDefinitionKey());
+                log.info(stack.peek().getTaskDefinitionKey() + "鐐硅剰璺嚎闆嗗悎锛�" + dirtyDataLine);
+                // 鏄叏鏂扮殑闇�瑕佹坊鍔犵殑鑴忕嚎璺�
+                boolean isNewDirtyData = true;
+                for (int i = 0; i < dirtyDataLineList.size(); i++) {
+                    // 濡傛灉鍙戠幇浠栫殑涓婁釜鑺傜偣鍦ㄨ剰绾胯矾鍐咃紝璇存槑杩欎釜鐐瑰彲鑳芥槸骞惰鐨勮妭鐐癸紝鎴栬�呰繛缁┏鍥�
+                    // 杩欐椂锛岄兘浠ヤ箣鍓嶇殑鑴忕嚎璺妭鐐逛负鏍囧噯锛屽彧闇�鍚堝苟鑴忕嚎璺嵆鍙紝涔熷氨鏄矾绾胯ˉ鍏�
+                    if (dirtyDataLineList.get(i).contains(userTaskKey.toString())) {
+                        isNewDirtyData = false;
+                        dirtyDataLineList.get(i).addAll(dirtyDataLine);
+                    }
+                }
+                // 宸茬‘瀹氭椂鍏ㄦ柊鐨勮剰绾胯矾
+                if (isNewDirtyData) {
+                    // deleteKey 鍗曚竴璺嚎椹冲洖鍒板苟琛岋紝杩欑鍚屾椂鐢熸垚澶氫釜鏂板疄渚嬭褰曟儏鍐碉紝杩欐椂 deleteKey 鍏跺疄鏄敱澶氫釜鍊肩粍鎴�
+                    // 鎸夌収閫昏緫锛屽洖閫�鍚庣珛鍒荤敓鎴愮殑瀹炰緥璁板綍灏辨槸鍥為��鐨勮褰�
+                    // 鑷充簬椹冲洖鎵�鐢熸垚鐨� Key锛岀洿鎺ヤ粠鍒犻櫎鍘熷洜涓幏鍙栵紝鍥犱负瀛樺湪椹冲洖鍒板苟琛岀殑鎯呭喌
+                    deleteKeyList.add(dirtyPoint + ",");
+                    dirtyDataLineList.add(dirtyDataLine);
+                }
+                // 娣诲姞鍚庯紝鐜板湪杩欎釜鐐瑰彉鎴愯剰绾胯矾涓婄殑鐐逛簡
+                isDirtyData[0] = true;
+            }
+            // 濡傛灉涓嶆槸鑴忕嚎璺笂鐨勭偣锛岃鏄庢槸鏈夋晥鏁版嵁锛屾坊鍔犲巻鍙插疄渚� Key
+            if (!isDirtyData[0]) {
+                lastHistoricTaskInstanceList.add(stack.peek().getTaskDefinitionKey());
+            }
+            // 鏍¢獙鑴忕嚎璺槸鍚︾粨鏉�
+            for (int i = 0; i < deleteKeyList.size(); i++) {
+                // 濡傛灉鍙戠幇鑴忔暟鎹睘浜庝細绛撅紝璁板綍涓嬩笅鏍囦笌瀵瑰簲 Key锛屼互澶囧悗缁瘮瀵癸紝浼氱鑴忔暟鎹寖鐣村紑濮�
+                if (multiKey == null && multiTask.contains(stack.peek().getTaskDefinitionKey())
+                        && deleteKeyList.get(i).contains(stack.peek().getTaskDefinitionKey())) {
+                    multiIndex = i;
+                    multiKey = new StringBuilder(stack.peek().getTaskDefinitionKey());
+                }
+                // 浼氱鑴忔暟鎹鐞嗭紝鑺傜偣閫�鍥炰細绛炬竻绌�
+                // 濡傛灉鍦ㄤ細绛捐剰鏁版嵁鑼冪暣涓彂鐜� Key鏀瑰彉锛岃鏄庝細绛捐剰鏁版嵁鍦ㄤ笂涓妭鐐瑰氨缁撴潫浜嗭紝鍙互鎶婁細绛捐剰鏁版嵁鍒犳帀
+                if (multiKey != null && !multiKey.toString().equals(stack.peek().getTaskDefinitionKey())) {
+                    deleteKeyList.set(multiIndex, deleteKeyList.get(multiIndex).replace(stack.peek().getTaskDefinitionKey() + ",", ""));
+                    multiKey = null;
+                    // 缁撴潫杩涜涓嬫牎楠屽垹闄�
+                    multiOpera = true;
+                }
+                // 鍏朵粬鑴忔暟鎹鐞�
+                // 鍙戠幇璇ヨ矾绾挎渶鍚庝竴鏉¤剰鏁版嵁锛岃鏄庤繖鏉¤剰鏁版嵁绾胯矾澶勭悊瀹屼簡锛屽垹闄よ剰鏁版嵁淇℃伅
+                // 鑴忔暟鎹骇鐢熺殑鏂板疄渚嬩腑鏄惁鍖呭惈杩欐潯鏁版嵁
+                if (multiKey == null && deleteKeyList.get(i).contains(stack.peek().getTaskDefinitionKey())) {
+                    // 鍒犻櫎鍖归厤鍒扮殑閮ㄥ垎
+                    deleteKeyList.set(i, deleteKeyList.get(i).replace(stack.peek().getTaskDefinitionKey() + ",", ""));
+                }
+                // 濡傛灉姣忕粍涓殑鍏冪礌閮戒互鍖归厤杩囷紝璇存槑鑴忔暟鎹粨鏉�
+                if ("".equals(deleteKeyList.get(i))) {
+                    // 鍚屾椂鍒犻櫎鑴忔暟鎹�
+                    deleteKeyList.remove(i);
+                    dirtyDataLineList.remove(i);
+                    break;
+                }
+            }
+            // 浼氱鏁版嵁澶勭悊闇�瑕佸湪寰幆澶栧鐞嗭紝鍚﹀垯鍙兘瀵艰嚧婧㈠嚭
+            // 浼氱鐨勬暟鎹偗瀹氭槸涔嬪墠鏀捐繘鍘荤殑鎵�浠ョ悊璁轰笂涓嶄細婧㈠嚭锛屼絾杩樻槸鏍¢獙涓�
+            if (multiOpera && deleteKeyList.size() > multiIndex && "".equals(deleteKeyList.get(multiIndex))) {
+                // 鍚屾椂鍒犻櫎鑴忔暟鎹�
+                deleteKeyList.remove(multiIndex);
+                dirtyDataLineList.remove(multiIndex);
+                multiIndex = -1;
+                multiOpera = false;
+            }
+            // pop() 鏂规硶涓� peek() 鏂规硶涓嶅悓锛屽湪杩斿洖鍊肩殑鍚屾椂锛屼細鎶婂�间粠鏍堜腑绉婚櫎
+            // 淇濆瓨鏂扮殑 userTaskKey 鍦ㄤ笅涓惊鐜腑浣跨敤
+            userTaskKey = new StringBuilder(stack.pop().getTaskDefinitionKey());
+        }
+        log.info("娓呮礂鍚庣殑鍘嗗彶鑺傜偣鏁版嵁锛�" + lastHistoricTaskInstanceList);
+        return lastHistoricTaskInstanceList;
+    }
+
+    /**
+     * 浠� flowElement 鑾峰彇 鎸囧畾鍚嶇О鐨� 鎷撳睍鍏冪礌
+     *
+     * @param flowElement          鍏冪礌
+     * @param extensionElementName 鎷撳睍鍏冪礌鍚嶇О
+     */
+    public static ExtensionElement getExtensionElementFromFlowElementByName(FlowElement flowElement, String extensionElementName) {
+
+        if (flowElement == null) {
+            return null;
+        }
+        Map<String, List<ExtensionElement>> extensionElements = flowElement.getExtensionElements();
+        for (Map.Entry<String, List<ExtensionElement>> stringEntry : extensionElements.entrySet()) {
+            if (stringEntry.getKey().equals(extensionElementName)) {
+                for (ExtensionElement extensionElement : stringEntry.getValue()) {
+                    if (extensionElement.getName().equals(extensionElementName)) {
+                        return extensionElement;
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 鑾峰彇褰撳墠浠诲姟鑺傜偣鎵╁睍灞炴�т俊鎭�
+     *
+     * @param repositoryService
+     * @param task 褰撳墠浠诲姟
+     * @return 鑷畾涔夊睘鎬у垪琛�
+     */
+    public static List<Object> getPropertyElement(RepositoryService repositoryService, org.flowable.task.api.Task task) {
+        FlowElement flowElement = getCurrentElement(repositoryService, task);
+        ExtensionElement extensionElement = FlowableUtils.getExtensionElementFromFlowElementByName(flowElement, "properties");
+        if (extensionElement == null) {
+            return Collections.emptyList();
+        }
+        return getPropertyExtensionElementByName(extensionElement, "property");
+    }
+
+    /**
+     * 鑾峰彇褰撳墠浠诲姟鑺傜偣
+     *
+     * @param repositoryService
+     * @param task
+     * @return
+     */
+    public static FlowElement getCurrentElement(RepositoryService repositoryService, org.flowable.task.api.Task task) {
+        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
+        return bpmnModel.getFlowElement(task.getTaskDefinitionKey());
+    }
+
+    /**
+     * 鏍规嵁灞炴�у悕鑾峰彇鎵╁睍鍏冪礌涓殑鎵╁睍灞炴�у垪琛�
+     *
+     * @param extensionElement 鎵╁睍鍏冪礌
+     * @param attributesName   灞炴�у悕
+     * @return 鎵╁睍灞炴�у垪琛�
+     */
+    public static List<Object> getPropertyExtensionElementByName(ExtensionElement extensionElement, String attributesName) {
+        try {
+            // 鑾峰彇鍚嶇О涓篴ttributesName鐨勫瓙鍏冪礌
+            return Optional.ofNullable(extensionElement.getChildElements().get(attributesName))
+                    .orElse(Collections.emptyList()) // 濡傛灉瀛愬厓绱犱笉瀛樺湪鍒欒繑鍥炵┖闆嗗悎锛岄伩鍏峮ull寮曠敤
+                    .stream()
+                    .map(element -> {
+                        // 鑾峰彇瀛愬厓绱犵殑灞炴��
+                        Map<String, List<ExtensionAttribute>> attributes = element.getAttributes();
+                        Object propertyDto = new Object();
+                        // 鑾峰彇FlowPropertyDto鐨勬墍鏈夊睘鎬�
+                        Arrays.stream(propertyDto.getClass().getDeclaredFields())
+                                .forEach(field -> {
+                                    field.setAccessible(true);
+                                    // 鑾峰彇灞炴�у悕绉板拰鍊�
+                                    attributes.getOrDefault(field.getName(), Collections.emptyList())
+                                            .stream()
+                                            .findFirst()
+                                            .ifPresent(attribute -> {
+                                                try {
+                                                    // 鍙嶅皠璁剧疆灞炴�у��
+                                                    field.set(propertyDto, attribute.getValue());
+                                                } catch (IllegalAccessException e) {
+                                                    e.printStackTrace();
+                                                    // 濡傛灉鍙嶅皠璁剧疆澶辫触鍒欏拷鐣ヨ灞炴��
+                                                }
+                                            });
+                                });
+                        return propertyDto;
+                    }).collect(Collectors.toList());
+        } catch (Exception e) {
+            e.printStackTrace();
+            return Collections.emptyList(); // 濡傛灉鍙戠敓寮傚父鍒欒繑鍥炵┖鍒楄〃
+        }
+    }
+
+}
diff --git a/flowable/src/main/java/com/ycl/listener/FlowExecutionListener.java b/flowable/src/main/java/com/ycl/listener/FlowExecutionListener.java
new file mode 100644
index 0000000..d8c11e1
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/listener/FlowExecutionListener.java
@@ -0,0 +1,36 @@
+package com.ycl.listener;
+
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.common.engine.api.delegate.Expression;
+import org.flowable.engine.delegate.DelegateExecution;
+import org.flowable.engine.delegate.ExecutionListener;
+import org.springframework.stereotype.Component;
+
+/**
+ * 鎵ц鐩戝惉鍣�
+ *
+ * 鎵ц鐩戝惉鍣ㄥ厑璁稿湪鎵ц杩囩▼涓墽琛孞ava浠g爜銆�
+ * 鎵ц鐩戝惉鍣ㄥ彲浠ユ崟鑾蜂簨浠剁殑绫诲瀷锛�
+ * 娴佺▼瀹炰緥鍚姩锛岀粨鏉�
+ * 杈撳嚭娴佹崟鑾�
+ * 鑾峰彇鍚姩锛岀粨鏉�
+ * 璺敱寮�濮嬶紝缁撴潫
+ * 涓棿浜嬩欢寮�濮嬶紝缁撴潫
+ * 瑙﹀彂寮�濮嬩簨浠讹紝瑙﹀彂缁撴潫浜嬩欢
+ *
+ * @author Tony
+ * @date 2022/12/16
+ */
+@Slf4j
+@Component
+public class FlowExecutionListener implements ExecutionListener {
+    /**
+     * 娴佺▼璁捐鍣ㄦ坊鍔犵殑鍙傛暟
+     */
+    private Expression param;
+
+    @Override
+    public void notify(DelegateExecution execution) {
+        log.info("鎵ц鐩戝惉鍣�:{}", execution);
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/listener/FlowTaskListener.java b/flowable/src/main/java/com/ycl/listener/FlowTaskListener.java
new file mode 100644
index 0000000..a4d6137
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/listener/FlowTaskListener.java
@@ -0,0 +1,32 @@
+package com.ycl.listener;
+
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.engine.delegate.TaskListener;
+import org.flowable.task.service.delegate.DelegateTask;
+import org.springframework.stereotype.Component;
+
+/**
+ * 浠诲姟鐩戝惉鍣�
+ *
+ * create锛堝垱寤猴級:鍦ㄤ换鍔¤鍒涘缓涓旀墍鏈夌殑浠诲姟灞炴�ц缃畬鎴愬悗鎵嶈Е鍙�
+ * assignment锛堟寚娲撅級锛氬湪浠诲姟琚垎閰嶇粰鏌愪釜鍔炵悊浜轰箣鍚庤Е鍙�
+ * complete锛堝畬鎴愶級锛氬湪閰嶇疆浜嗙洃鍚櫒鐨勪笂涓�涓换鍔″畬鎴愭椂瑙﹀彂
+ * delete锛堝垹闄わ級锛氬湪浠诲姟鍗冲皢琚垹闄ゅ墠瑙﹀彂銆傝娉ㄦ剰浠诲姟鐢眂ompleteTask姝e父瀹屾垚鏃朵篃浼氳Е鍙�
+ *
+ * @author Tony
+ * @date 2021/4/20
+ */
+@Slf4j
+@Component
+public class FlowTaskListener implements TaskListener{
+
+    @Override
+    public void notify(DelegateTask delegateTask) {
+
+        log.info("浠诲姟鐩戝惉鍣�:{}", delegateTask);
+        // TODO  鑾峰彇浜嬩欢绫诲瀷 delegateTask.getEventName(),鍙互閫氳繃鐩戝惉鍣ㄧ粰浠诲姟鎵ц浜哄彂閫佺浉搴旂殑閫氱煡娑堟伅
+
+
+    }
+
+}
diff --git a/flowable/src/main/java/com/ycl/mapper/ActRuExecutionMapper.java b/flowable/src/main/java/com/ycl/mapper/ActRuExecutionMapper.java
deleted file mode 100644
index e1ac6b7..0000000
--- a/flowable/src/main/java/com/ycl/mapper/ActRuExecutionMapper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.ycl.mapper;
-
-import java.util.List;
-import com.ycl.system.domain.ActRuExecution;
-import org.apache.ibatis.annotations.Param;
-
-/**
- * 鎵ц瀹炰緥Mapper鎺ュ彛
- *
- * @date 2022-07-13
- */
-public interface ActRuExecutionMapper
-{
-    /**
-     * 鏌ヨ鎵ц瀹炰緥
-     *
-     * @param id 鎵ц瀹炰緥涓婚敭
-     * @return 鎵ц瀹炰緥
-     */
-    public ActRuExecution selectActRuExecutionById(String id);
-
-    /**
-     * 鏌ヨ鎵ц瀹炰緥鍒楄〃
-     *
-     * @param actRuExecution 鎵ц瀹炰緥
-     * @return 鎵ц瀹炰緥闆嗗悎
-     */
-    public List<ActRuExecution> selectActRuExecutionList(ActRuExecution actRuExecution);
-
-    /**
-     * 鐢ㄦ祦绋嬪悕绉版煡璇㈠疄渚�
-     * @return
-     */
-    public List<ActRuExecution> selectActRuExecutionListByProcessName(@Param("name") String name);
-
-    /**
-     * 鏂板鎵ц瀹炰緥
-     *
-     * @param actRuExecution 鎵ц瀹炰緥
-     * @return 缁撴灉
-     */
-    public int insertActRuExecution(ActRuExecution actRuExecution);
-
-    /**
-     * 淇敼鎵ц瀹炰緥
-     *
-     * @param actRuExecution 鎵ц瀹炰緥
-     * @return 缁撴灉
-     */
-    public int updateActRuExecution(ActRuExecution actRuExecution);
-
-    /**
-     * 鍒犻櫎鎵ц瀹炰緥
-     *
-     * @param id 鎵ц瀹炰緥涓婚敭
-     * @return 缁撴灉
-     */
-    public int deleteActRuExecutionById(String id);
-
-    /**
-     * 鎵归噺鍒犻櫎鎵ц瀹炰緥
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
-     * @return 缁撴灉
-     */
-    public int deleteActRuExecutionByIds(String[] ids);
-}
diff --git a/flowable/src/main/java/com/ycl/mapper/FlowDeployMapper.java b/flowable/src/main/java/com/ycl/mapper/FlowDeployMapper.java
new file mode 100644
index 0000000..ccb3f06
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/mapper/FlowDeployMapper.java
@@ -0,0 +1,22 @@
+package com.ycl.mapper;
+
+import com.ycl.domain.dto.FlowProcDefDto;
+
+import java.util.List;
+
+/**
+ * 娴佺▼瀹氫箟鏌ヨ
+ *
+ * @author Tony
+ * @email
+ * @date 2022/1/29 5:44 涓嬪崍
+ **/
+public interface FlowDeployMapper {
+
+    /**
+     * 娴佺▼瀹氫箟鍒楄〃
+     * @param name
+     * @return
+     */
+    List<FlowProcDefDto> selectDeployList(String name);
+}
diff --git a/flowable/src/main/java/com/ycl/mapper/LeaveapplyMapper.java b/flowable/src/main/java/com/ycl/mapper/LeaveapplyMapper.java
deleted file mode 100644
index 21946c5..0000000
--- a/flowable/src/main/java/com/ycl/mapper/LeaveapplyMapper.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.ycl.mapper;
-
-import java.util.List;
-import com.ycl.system.domain.Leaveapply;
-
-/**
- * 璇峰亣Mapper鎺ュ彛
- *
- * @author shenzhanwang
- * @date 2022-04-02
- */
-public interface LeaveapplyMapper
-{
-    /**
-     * 鏌ヨ璇峰亣
-     *
-     * @param id 璇峰亣涓婚敭
-     * @return 璇峰亣
-     */
-    public Leaveapply selectLeaveapplyById(Long id);
-
-    /**
-     * 鏌ヨ璇峰亣鍒楄〃
-     *
-     * @param leaveapply 璇峰亣
-     * @return 璇峰亣闆嗗悎
-     */
-    public List<Leaveapply> selectLeaveapplyList(Leaveapply leaveapply);
-
-    /**
-     * 鏂板璇峰亣
-     *
-     * @param leaveapply 璇峰亣
-     * @return 缁撴灉
-     */
-    public int insertLeaveapply(Leaveapply leaveapply);
-
-    /**
-     * 淇敼璇峰亣
-     *
-     * @param leaveapply 璇峰亣
-     * @return 缁撴灉
-     */
-    public int updateLeaveapply(Leaveapply leaveapply);
-
-    /**
-     * 鍒犻櫎璇峰亣
-     *
-     * @param id 璇峰亣涓婚敭
-     * @return 缁撴灉
-     */
-    public int deleteLeaveapplyById(Long id);
-
-    /**
-     * 鎵归噺鍒犻櫎璇峰亣
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
-     * @return 缁撴灉
-     */
-    public int deleteLeaveapplyByIds(String[] ids);
-}
diff --git a/flowable/src/main/java/com/ycl/mapper/MeetingMapper.java b/flowable/src/main/java/com/ycl/mapper/MeetingMapper.java
deleted file mode 100644
index 5c1209d..0000000
--- a/flowable/src/main/java/com/ycl/mapper/MeetingMapper.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.ycl.mapper;
-
-import java.util.List;
-import com.ycl.system.domain.Meeting;
-
-/**
- * 浼氳Mapper鎺ュ彛
- *
- * @author shenzhanwang
- * @date 2022-05-30
- */
-public interface MeetingMapper
-{
-    /**
-     * 鏌ヨ浼氳
-     *
-     * @param id 浼氳涓婚敭
-     * @return 浼氳
-     */
-    public Meeting selectMeetingById(Long id);
-
-    /**
-     * 鏌ヨ浼氳鍒楄〃
-     *
-     * @param meeting 浼氳
-     * @return 浼氳闆嗗悎
-     */
-    public List<Meeting> selectMeetingList(Meeting meeting);
-
-    /**
-     * 鏂板浼氳
-     *
-     * @param meeting 浼氳
-     * @return 缁撴灉
-     */
-    public int insertMeeting(Meeting meeting);
-
-    /**
-     * 淇敼浼氳
-     *
-     * @param meeting 浼氳
-     * @return 缁撴灉
-     */
-    public int updateMeeting(Meeting meeting);
-
-    /**
-     * 鍒犻櫎浼氳
-     *
-     * @param id 浼氳涓婚敭
-     * @return 缁撴灉
-     */
-    public int deleteMeetingById(Long id);
-
-    /**
-     * 鎵归噺鍒犻櫎浼氳
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
-     * @return 缁撴灉
-     */
-    public int deleteMeetingByIds(String[] ids);
-}
diff --git a/flowable/src/main/java/com/ycl/mapper/PurchaseMapper.java b/flowable/src/main/java/com/ycl/mapper/PurchaseMapper.java
deleted file mode 100644
index 54e0a7a..0000000
--- a/flowable/src/main/java/com/ycl/mapper/PurchaseMapper.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.ycl.mapper;
-
-import java.util.List;
-import com.ycl.system.domain.Purchase;
-
-/**
- * 閲囪喘Mapper鎺ュ彛
- *
- * @author shenzhanwang
- * @date 2022-05-28
- */
-public interface PurchaseMapper
-{
-    /**
-     * 鏌ヨ閲囪喘
-     *
-     * @param id 閲囪喘涓婚敭
-     * @return 閲囪喘
-     */
-    public Purchase selectPurchaseById(Long id);
-
-    /**
-     * 鏌ヨ閲囪喘鍒楄〃
-     *
-     * @param purchase 閲囪喘
-     * @return 閲囪喘闆嗗悎
-     */
-    public List<Purchase> selectPurchaseList(Purchase purchase);
-
-    /**
-     * 鏂板閲囪喘
-     *
-     * @param purchase 閲囪喘
-     * @return 缁撴灉
-     */
-    public int insertPurchase(Purchase purchase);
-
-    /**
-     * 淇敼閲囪喘
-     *
-     * @param purchase 閲囪喘
-     * @return 缁撴灉
-     */
-    public int updatePurchase(Purchase purchase);
-
-    /**
-     * 鍒犻櫎閲囪喘
-     *
-     * @param id 閲囪喘涓婚敭
-     * @return 缁撴灉
-     */
-    public int deletePurchaseById(Long id);
-
-    /**
-     * 鎵归噺鍒犻櫎閲囪喘
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
-     * @return 缁撴灉
-     */
-    public int deletePurchaseByIds(String[] ids);
-}
diff --git a/flowable/src/main/java/com/ycl/mapper/SysDeployFormMapper.java b/flowable/src/main/java/com/ycl/mapper/SysDeployFormMapper.java
new file mode 100644
index 0000000..665702c
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/mapper/SysDeployFormMapper.java
@@ -0,0 +1,72 @@
+package com.ycl.mapper;
+
+import com.ycl.domain.entity.SysDeployForm;
+import com.ycl.domain.entity.SysForm;
+
+import java.util.List;
+
+/**
+ * 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟Mapper鎺ュ彛
+ *
+ * @author Tony
+ * @date 2021-03-30
+ */
+public interface SysDeployFormMapper
+{
+    /**
+     * 鏌ヨ娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param id 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟ID
+     * @return 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     */
+    public SysDeployForm selectSysDeployFormById(Long id);
+
+    /**
+     * 鏌ヨ娴佺▼瀹炰緥鍏宠仈琛ㄥ崟鍒楄〃
+     *
+     * @param SysDeployForm 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     * @return 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟闆嗗悎
+     */
+    public List<SysDeployForm> selectSysDeployFormList(SysDeployForm SysDeployForm);
+
+    /**
+     * 鏂板娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param SysDeployForm 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     * @return 缁撴灉
+     */
+    public int insertSysDeployForm(SysDeployForm SysDeployForm);
+
+    /**
+     * 淇敼娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param SysDeployForm 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     * @return 缁撴灉
+     */
+    public int updateSysDeployForm(SysDeployForm SysDeployForm);
+
+    /**
+     * 鍒犻櫎娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param id 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟ID
+     * @return 缁撴灉
+     */
+    public int deleteSysDeployFormById(Long id);
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteSysDeployFormByIds(Long[] ids);
+
+
+
+    /**
+     * 鏌ヨ娴佺▼鎸傜潃鐨勮〃鍗�
+     * @param deployId
+     * @return
+     */
+    SysForm selectSysDeployFormByDeployId(String deployId);
+}
diff --git a/flowable/src/main/java/com/ycl/mapper/SysExpressionMapper.java b/flowable/src/main/java/com/ycl/mapper/SysExpressionMapper.java
new file mode 100644
index 0000000..ab93b9a
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/mapper/SysExpressionMapper.java
@@ -0,0 +1,62 @@
+package com.ycl.mapper;
+
+import com.ycl.domain.entity.SysExpression;
+
+import java.util.List;
+
+/**
+ * 娴佺▼杈惧紡Mapper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2022-12-12
+ */
+public interface SysExpressionMapper
+{
+    /**
+     * 鏌ヨ娴佺▼杈惧紡
+     *
+     * @param id 娴佺▼杈惧紡涓婚敭
+     * @return 娴佺▼杈惧紡
+     */
+    public SysExpression selectSysExpressionById(Long id);
+
+    /**
+     * 鏌ヨ娴佺▼杈惧紡鍒楄〃
+     *
+     * @param sysExpression 娴佺▼杈惧紡
+     * @return 娴佺▼杈惧紡闆嗗悎
+     */
+    public List<SysExpression> selectSysExpressionList(SysExpression sysExpression);
+
+    /**
+     * 鏂板娴佺▼杈惧紡
+     *
+     * @param sysExpression 娴佺▼杈惧紡
+     * @return 缁撴灉
+     */
+    public int insertSysExpression(SysExpression sysExpression);
+
+    /**
+     * 淇敼娴佺▼杈惧紡
+     *
+     * @param sysExpression 娴佺▼杈惧紡
+     * @return 缁撴灉
+     */
+    public int updateSysExpression(SysExpression sysExpression);
+
+    /**
+     * 鍒犻櫎娴佺▼杈惧紡
+     *
+     * @param id 娴佺▼杈惧紡涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteSysExpressionById(Long id);
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼杈惧紡
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteSysExpressionByIds(Long[] ids);
+}
diff --git a/flowable/src/main/java/com/ycl/mapper/SysFormMapper.java b/flowable/src/main/java/com/ycl/mapper/SysFormMapper.java
new file mode 100644
index 0000000..3ea8ebe
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/mapper/SysFormMapper.java
@@ -0,0 +1,62 @@
+package com.ycl.mapper;
+
+import com.ycl.domain.entity.SysForm;
+
+import java.util.List;
+
+/**
+ * 娴佺▼琛ㄥ崟Mapper鎺ュ彛
+ *
+ * @author Tony
+ * @date 2021-03-30
+ */
+public interface SysFormMapper
+{
+    /**
+     * 鏌ヨ娴佺▼琛ㄥ崟
+     *
+     * @param formId 娴佺▼琛ㄥ崟ID
+     * @return 娴佺▼琛ㄥ崟
+     */
+    public SysForm selectSysFormById(Long formId);
+
+    /**
+     * 鏌ヨ娴佺▼琛ㄥ崟鍒楄〃
+     *
+     * @param sysForm 娴佺▼琛ㄥ崟
+     * @return 娴佺▼琛ㄥ崟闆嗗悎
+     */
+    public List<SysForm> selectSysFormList(SysForm sysForm);
+
+    /**
+     * 鏂板娴佺▼琛ㄥ崟
+     *
+     * @param sysForm 娴佺▼琛ㄥ崟
+     * @return 缁撴灉
+     */
+    public int insertSysForm(SysForm sysForm);
+
+    /**
+     * 淇敼娴佺▼琛ㄥ崟
+     *
+     * @param sysForm 娴佺▼琛ㄥ崟
+     * @return 缁撴灉
+     */
+    public int updateSysForm(SysForm sysForm);
+
+    /**
+     * 鍒犻櫎娴佺▼琛ㄥ崟
+     *
+     * @param formId 娴佺▼琛ㄥ崟ID
+     * @return 缁撴灉
+     */
+    public int deleteSysFormById(Long formId);
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼琛ㄥ崟
+     *
+     * @param formIds 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteSysFormByIds(Long[] formIds);
+}
diff --git a/flowable/src/main/java/com/ycl/mapper/SysListenerMapper.java b/flowable/src/main/java/com/ycl/mapper/SysListenerMapper.java
new file mode 100644
index 0000000..13f4f24
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/mapper/SysListenerMapper.java
@@ -0,0 +1,62 @@
+package com.ycl.mapper;
+
+import com.ycl.domain.entity.SysListener;
+
+import java.util.List;
+
+/**
+ * 娴佺▼鐩戝惉Mapper鎺ュ彛
+ *
+ * @author Tony
+ * @date 2022-12-25
+ */
+public interface SysListenerMapper
+{
+    /**
+     * 鏌ヨ娴佺▼鐩戝惉
+     *
+     * @param id 娴佺▼鐩戝惉涓婚敭
+     * @return 娴佺▼鐩戝惉
+     */
+    public SysListener selectSysListenerById(Long id);
+
+    /**
+     * 鏌ヨ娴佺▼鐩戝惉鍒楄〃
+     *
+     * @param sysListener 娴佺▼鐩戝惉
+     * @return 娴佺▼鐩戝惉闆嗗悎
+     */
+    public List<SysListener> selectSysListenerList(SysListener sysListener);
+
+    /**
+     * 鏂板娴佺▼鐩戝惉
+     *
+     * @param sysListener 娴佺▼鐩戝惉
+     * @return 缁撴灉
+     */
+    public int insertSysListener(SysListener sysListener);
+
+    /**
+     * 淇敼娴佺▼鐩戝惉
+     *
+     * @param sysListener 娴佺▼鐩戝惉
+     * @return 缁撴灉
+     */
+    public int updateSysListener(SysListener sysListener);
+
+    /**
+     * 鍒犻櫎娴佺▼鐩戝惉
+     *
+     * @param id 娴佺▼鐩戝惉涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteSysListenerById(Long id);
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼鐩戝惉
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteSysListenerByIds(Long[] ids);
+}
diff --git a/flowable/src/main/java/com/ycl/mapper/SysTaskFormMapper.java b/flowable/src/main/java/com/ycl/mapper/SysTaskFormMapper.java
new file mode 100644
index 0000000..8fe9964
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/mapper/SysTaskFormMapper.java
@@ -0,0 +1,63 @@
+package com.ycl.mapper;
+
+
+import com.ycl.domain.entity.SysTaskForm;
+
+import java.util.List;
+
+/**
+ * 娴佺▼浠诲姟鍏宠仈鍗昅apper鎺ュ彛
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+public interface SysTaskFormMapper
+{
+    /**
+     * 鏌ヨ娴佺▼浠诲姟鍏宠仈鍗�
+     *
+     * @param id 娴佺▼浠诲姟鍏宠仈鍗旾D
+     * @return 娴佺▼浠诲姟鍏宠仈鍗�
+     */
+    public SysTaskForm selectSysTaskFormById(Long id);
+
+    /**
+     * 鏌ヨ娴佺▼浠诲姟鍏宠仈鍗曞垪琛�
+     *
+     * @param sysTaskForm 娴佺▼浠诲姟鍏宠仈鍗�
+     * @return 娴佺▼浠诲姟鍏宠仈鍗曢泦鍚�
+     */
+    public List<SysTaskForm> selectSysTaskFormList(SysTaskForm sysTaskForm);
+
+    /**
+     * 鏂板娴佺▼浠诲姟鍏宠仈鍗�
+     *
+     * @param sysTaskForm 娴佺▼浠诲姟鍏宠仈鍗�
+     * @return 缁撴灉
+     */
+    public int insertSysTaskForm(SysTaskForm sysTaskForm);
+
+    /**
+     * 淇敼娴佺▼浠诲姟鍏宠仈鍗�
+     *
+     * @param sysTaskForm 娴佺▼浠诲姟鍏宠仈鍗�
+     * @return 缁撴灉
+     */
+    public int updateSysTaskForm(SysTaskForm sysTaskForm);
+
+    /**
+     * 鍒犻櫎娴佺▼浠诲姟鍏宠仈鍗�
+     *
+     * @param id 娴佺▼浠诲姟鍏宠仈鍗旾D
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskFormById(Long id);
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼浠诲姟鍏宠仈鍗�
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteSysTaskFormByIds(Long[] ids);
+}
diff --git a/flowable/src/main/java/com/ycl/service/IFlowDefinitionService.java b/flowable/src/main/java/com/ycl/service/IFlowDefinitionService.java
new file mode 100644
index 0000000..6839c33
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/IFlowDefinitionService.java
@@ -0,0 +1,80 @@
+package com.ycl.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.domain.dto.FlowProcDefDto;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * @author Tony
+ * @date 2021-04-03 14:41
+ */
+public interface IFlowDefinitionService {
+
+    boolean exist(String processDefinitionKey);
+
+
+    /**
+     * 娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param pageNum  褰撳墠椤电爜
+     * @param pageSize 姣忛〉鏉℃暟
+     * @return 娴佺▼瀹氫箟鍒嗛〉鍒楄〃鏁版嵁
+     */
+    Page<FlowProcDefDto> list(String name, Integer pageNum, Integer pageSize);
+
+    /**
+     * 瀵煎叆娴佺▼鏂囦欢
+     * 褰撴瘡涓猭ey鐨勬祦绋嬬涓�娆¢儴缃叉椂锛屾寚瀹氱増鏈负1銆傚鍏跺悗鎵�鏈変娇鐢ㄧ浉鍚宬ey鐨勬祦绋嬪畾涔夛紝
+     * 閮ㄧ讲鏃剁増鏈細鍦ㄨkey褰撳墠宸查儴缃茬殑鏈�楂樼増鏈彿鍩虹涓婂姞1銆俴ey鍙傛暟鐢ㄤ簬鍖哄垎娴佺▼瀹氫箟
+     * @param name
+     * @param category
+     * @param in
+     */
+    void importFile(String name, String category, InputStream in);
+
+    /**
+     * 璇诲彇xml
+     * @param deployId
+     * @return
+     */
+    AjaxResult readXml(String deployId) throws IOException;
+
+    /**
+     * 鏍规嵁娴佺▼瀹氫箟ID鍚姩娴佺▼瀹炰緥
+     *
+     * @param procDefId
+     * @param variables
+     * @return
+     */
+
+    AjaxResult startProcessInstanceById(String procDefId, Map<String, Object> variables);
+
+
+    /**
+     * 婵�娲绘垨鎸傝捣娴佺▼瀹氫箟
+     *
+     * @param state    鐘舵��
+     * @param deployId 娴佺▼閮ㄧ讲ID
+     */
+    void updateState(Integer state, String deployId);
+
+
+    /**
+     * 鍒犻櫎娴佺▼瀹氫箟
+     *
+     * @param deployId 娴佺▼閮ㄧ讲ID act_ge_bytearray 琛ㄤ腑 deployment_id鍊�
+     */
+    void delete(String deployId);
+
+
+    /**
+     * 璇诲彇鍥剧墖鏂囦欢
+     * @param deployId
+     * @return
+     */
+    InputStream readImage(String deployId);
+}
diff --git a/flowable/src/main/java/com/ycl/service/IFlowInstanceService.java b/flowable/src/main/java/com/ycl/service/IFlowInstanceService.java
new file mode 100644
index 0000000..39fcce9
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/IFlowInstanceService.java
@@ -0,0 +1,54 @@
+package com.ycl.service;
+
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.domain.vo.FlowTaskVo;
+import org.flowable.engine.history.HistoricProcessInstance;
+
+import java.util.Map;
+
+/**
+ * @author Tony
+ * @date 2021-04-03 14:40
+ */
+public interface IFlowInstanceService {
+
+    /**
+     * 缁撴潫娴佺▼瀹炰緥
+     *
+     * @param vo
+     */
+    void stopProcessInstance(FlowTaskVo vo);
+
+    /**
+     * 婵�娲绘垨鎸傝捣娴佺▼瀹炰緥
+     *
+     * @param state      鐘舵��
+     * @param instanceId 娴佺▼瀹炰緥ID
+     */
+    void updateState(Integer state, String instanceId);
+
+    /**
+     * 鍒犻櫎娴佺▼瀹炰緥ID
+     *
+     * @param instanceId   娴佺▼瀹炰緥ID
+     * @param deleteReason 鍒犻櫎鍘熷洜
+     */
+    void delete(String instanceId, String deleteReason);
+
+    /**
+     * 鏍规嵁瀹炰緥ID鏌ヨ鍘嗗彶瀹炰緥鏁版嵁
+     *
+     * @param processInstanceId
+     * @return
+     */
+    HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId);
+
+    /**
+     * 鏍规嵁娴佺▼瀹氫箟ID鍚姩娴佺▼瀹炰緥
+     *
+     * @param procDefId 娴佺▼瀹氫箟Id
+     * @param variables 娴佺▼鍙橀噺
+     * @return
+     */
+    AjaxResult startProcessInstanceById(String procDefId, Map<String, Object> variables);
+}
diff --git a/flowable/src/main/java/com/ycl/service/IFlowTaskService.java b/flowable/src/main/java/com/ycl/service/IFlowTaskService.java
new file mode 100644
index 0000000..2c088c2
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/IFlowTaskService.java
@@ -0,0 +1,216 @@
+package com.ycl.service;
+
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.domain.vo.FlowQueryVo;
+import com.ycl.domain.vo.FlowTaskVo;
+
+import java.io.InputStream;
+
+/**
+ * @author Tony
+ * @date 2021-04-03 14:42
+ */
+public interface IFlowTaskService {
+
+    /**
+     * 瀹℃壒浠诲姟
+     *
+     * @param task 璇锋眰瀹炰綋鍙傛暟
+     */
+    AjaxResult complete(FlowTaskVo task);
+
+    /**
+     * 椹冲洖浠诲姟
+     *
+     * @param flowTaskVo
+     */
+    void taskReject(FlowTaskVo flowTaskVo);
+
+
+    /**
+     * 閫�鍥炰换鍔�
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    void taskReturn(FlowTaskVo flowTaskVo);
+
+    /**
+     * 鑾峰彇鎵�鏈夊彲鍥為��鐨勮妭鐐�
+     *
+     * @param flowTaskVo
+     * @return
+     */
+    AjaxResult findReturnTaskList(FlowTaskVo flowTaskVo);
+
+    /**
+     * 鍒犻櫎浠诲姟
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    void deleteTask(FlowTaskVo flowTaskVo);
+
+    /**
+     * 璁ら/绛炬敹浠诲姟
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    void claim(FlowTaskVo flowTaskVo);
+
+    /**
+     * 鍙栨秷璁ら/绛炬敹浠诲姟
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    void unClaim(FlowTaskVo flowTaskVo);
+
+    /**
+     * 濮旀淳浠诲姟
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    void delegateTask(FlowTaskVo flowTaskVo);
+
+    /**
+     * 浠诲姟褰掕繕
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    void resolveTask(FlowTaskVo flowTaskVo);
+
+
+    /**
+     * 杞姙浠诲姟
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    void assignTask(FlowTaskVo flowTaskVo);
+
+
+    /**
+     * 澶氬疄渚嬪姞绛�
+     * @param flowTaskVo
+     */
+    void addMultiInstanceExecution(FlowTaskVo flowTaskVo);
+
+    /**
+     * 澶氬疄渚嬪噺绛�
+     * @param flowTaskVo
+     */
+    void deleteMultiInstanceExecution(FlowTaskVo flowTaskVo);
+
+    /**
+     * 鎴戝彂璧风殑娴佺▼
+     * @param queryVo  璇锋眰鍙傛暟
+     * @return
+     */
+    AjaxResult myProcess(FlowQueryVo queryVo);
+
+    /**
+     * 鍙栨秷鐢宠
+     * 鐩墠瀹炵幇鏂瑰紡: 鐩存帴灏嗗綋鍓嶆祦绋嬪彉鏇翠负宸插畬鎴�
+     * @param flowTaskVo
+     * @return
+     */
+    AjaxResult stopProcess(FlowTaskVo flowTaskVo);
+
+    /**
+     * 鎾ゅ洖娴佺▼
+     * @param flowTaskVo
+     * @return
+     */
+    AjaxResult revokeProcess(FlowTaskVo flowTaskVo);
+
+
+    /**
+     * 浠e姙浠诲姟鍒楄〃
+     *
+     * @param queryVo  璇锋眰鍙傛暟
+     * @return
+     */
+    AjaxResult todoList(FlowQueryVo queryVo);
+
+
+    /**
+     * 宸插姙浠诲姟鍒楄〃
+     *
+     * @param queryVo  璇锋眰鍙傛暟
+     * @return
+     */
+    AjaxResult finishedList(FlowQueryVo queryVo);
+
+    /**
+     * 娴佺▼鍘嗗彶娴佽浆璁板綍
+     *
+     * @param procInsId 娴佺▼瀹炰緥Id
+     * @return
+     */
+    AjaxResult flowRecord(String procInsId,String deployId);
+
+    /**
+     * 鏍规嵁浠诲姟ID鏌ヨ鎸傝浇鐨勮〃鍗曚俊鎭�
+     *
+     * @param taskId 浠诲姟Id
+     * @return
+     */
+    AjaxResult getTaskForm(String taskId);
+
+    /**
+     * 鑾峰彇娴佺▼杩囩▼鍥�
+     * @param processId
+     * @return
+     */
+    InputStream diagram(String processId);
+
+    /**
+     * 鑾峰彇娴佺▼鎵ц鑺傜偣
+     * @param procInsId
+     * @return
+     */
+    AjaxResult getFlowViewer(String procInsId,String executionId);
+
+    /**
+     * 鑾峰彇娴佺▼鍙橀噺
+     * @param taskId
+     * @return
+     */
+    AjaxResult processVariables(String taskId);
+
+    /**
+     * 鑾峰彇涓嬩竴鑺傜偣
+     * @param flowTaskVo 浠诲姟
+     * @return
+     */
+    AjaxResult getNextFlowNode(FlowTaskVo flowTaskVo);
+
+    AjaxResult getNextFlowNodeByStart(FlowTaskVo flowTaskVo);
+
+    /**
+     * 娴佺▼鍒濆鍖栬〃鍗�
+     * @param deployId
+     * @return
+     */
+    AjaxResult flowFormData(String deployId);
+
+    /**
+     * 娴佺▼鑺傜偣淇℃伅
+     * @param procInsId
+     * @return
+     */
+    AjaxResult flowXmlAndNode(String procInsId,String deployId);
+
+    /**
+     * 娴佺▼鑺傜偣琛ㄥ崟
+     * @param taskId 娴佺▼浠诲姟缂栧彿
+     * @return
+     */
+    AjaxResult flowTaskForm(String taskId) throws Exception;
+
+
+    /**
+     * 娴佺▼鑺傜偣淇℃伅
+     * @param procInsId
+     * @param elementId
+     * @return
+     */
+    AjaxResult flowTaskInfo(String procInsId, String elementId);
+}
diff --git a/flowable/src/main/java/com/ycl/service/ILeaveapplyService.java b/flowable/src/main/java/com/ycl/service/ILeaveapplyService.java
deleted file mode 100644
index 85fe0dc..0000000
--- a/flowable/src/main/java/com/ycl/service/ILeaveapplyService.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.ycl.service;
-
-import java.util.List;
-import com.ycl.system.domain.Leaveapply;
-
-/**
- * 璇峰亣Service鎺ュ彛
- *
- * @author shenzhanwang
- * @date 2022-04-02
- */
-public interface ILeaveapplyService
-{
-    /**
-     * 鏌ヨ璇峰亣
-     *
-     * @param id 璇峰亣涓婚敭
-     * @return 璇峰亣
-     */
-    public Leaveapply selectLeaveapplyById(Long id);
-
-    /**
-     * 鏌ヨ璇峰亣鍒楄〃
-     *
-     * @param leaveapply 璇峰亣
-     * @return 璇峰亣闆嗗悎
-     */
-    public List<Leaveapply> selectLeaveapplyList(Leaveapply leaveapply);
-
-    /**
-     * 鏂板璇峰亣
-     *
-     * @param leaveapply 璇峰亣
-     * @return 缁撴灉
-     */
-    public int insertLeaveapply(Leaveapply leaveapply);
-
-    /**
-     * 淇敼璇峰亣
-     *
-     * @param leaveapply 璇峰亣
-     * @return 缁撴灉
-     */
-    public int updateLeaveapply(Leaveapply leaveapply);
-
-    /**
-     * 鎵归噺鍒犻櫎璇峰亣
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑璇峰亣涓婚敭闆嗗悎
-     * @return 缁撴灉
-     */
-    public int deleteLeaveapplyByIds(String ids);
-
-    /**
-     * 鍒犻櫎璇峰亣淇℃伅
-     *
-     * @param id 璇峰亣涓婚敭
-     * @return 缁撴灉
-     */
-    public int deleteLeaveapplyById(Long id);
-}
diff --git a/flowable/src/main/java/com/ycl/service/IMeetingService.java b/flowable/src/main/java/com/ycl/service/IMeetingService.java
deleted file mode 100644
index bef2b9e..0000000
--- a/flowable/src/main/java/com/ycl/service/IMeetingService.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.ycl.service;
-
-import java.util.List;
-import com.ycl.system.domain.Meeting;
-
-/**
- * 浼氳Service鎺ュ彛
- *
- * @author shenzhanwang
- * @date 2022-05-30
- */
-public interface IMeetingService
-{
-    /**
-     * 鏌ヨ浼氳
-     *
-     * @param id 浼氳涓婚敭
-     * @return 浼氳
-     */
-    public Meeting selectMeetingById(Long id);
-
-    /**
-     * 鏌ヨ浼氳鍒楄〃
-     *
-     * @param meeting 浼氳
-     * @return 浼氳闆嗗悎
-     */
-    public List<Meeting> selectMeetingList(Meeting meeting);
-
-    /**
-     * 鏂板浼氳
-     *
-     * @param meeting 浼氳
-     * @return 缁撴灉
-     */
-    public int insertMeeting(Meeting meeting);
-
-    /**
-     * 淇敼浼氳
-     *
-     * @param meeting 浼氳
-     * @return 缁撴灉
-     */
-    public int updateMeeting(Meeting meeting);
-
-    /**
-     * 鎵归噺鍒犻櫎浼氳
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑浼氳涓婚敭闆嗗悎
-     * @return 缁撴灉
-     */
-    public int deleteMeetingByIds(String ids);
-
-    /**
-     * 鍒犻櫎浼氳淇℃伅
-     *
-     * @param id 浼氳涓婚敭
-     * @return 缁撴灉
-     */
-    public int deleteMeetingById(Long id);
-}
diff --git a/flowable/src/main/java/com/ycl/service/IPurchaseService.java b/flowable/src/main/java/com/ycl/service/IPurchaseService.java
deleted file mode 100644
index 7986e61..0000000
--- a/flowable/src/main/java/com/ycl/service/IPurchaseService.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.ycl.service;
-
-import java.util.List;
-import com.ycl.system.domain.Purchase;
-
-/**
- * 閲囪喘Service鎺ュ彛
- *
- * @author shenzhanwang
- * @date 2022-05-28
- */
-public interface IPurchaseService
-{
-    /**
-     * 鏌ヨ閲囪喘
-     *
-     * @param id 閲囪喘涓婚敭
-     * @return 閲囪喘
-     */
-    public Purchase selectPurchaseById(Long id);
-
-    /**
-     * 鏌ヨ閲囪喘鍒楄〃
-     *
-     * @param purchase 閲囪喘
-     * @return 閲囪喘闆嗗悎
-     */
-    public List<Purchase> selectPurchaseList(Purchase purchase);
-
-    /**
-     * 鏂板閲囪喘
-     *
-     * @param purchase 閲囪喘
-     * @return 缁撴灉
-     */
-    public int insertPurchase(Purchase purchase);
-
-    /**
-     * 淇敼閲囪喘
-     *
-     * @param purchase 閲囪喘
-     * @return 缁撴灉
-     */
-    public int updatePurchase(Purchase purchase);
-
-    /**
-     * 鎵归噺鍒犻櫎閲囪喘
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑閲囪喘涓婚敭闆嗗悎
-     * @return 缁撴灉
-     */
-    public int deletePurchaseByIds(String ids);
-
-    /**
-     * 鍒犻櫎閲囪喘淇℃伅
-     *
-     * @param id 閲囪喘涓婚敭
-     * @return 缁撴灉
-     */
-    public int deletePurchaseById(Long id);
-}
diff --git a/flowable/src/main/java/com/ycl/service/ISysDeployFormService.java b/flowable/src/main/java/com/ycl/service/ISysDeployFormService.java
new file mode 100644
index 0000000..3aa3b32
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/ISysDeployFormService.java
@@ -0,0 +1,70 @@
+package com.ycl.service;
+
+import com.ycl.domain.entity.SysDeployForm;
+import com.ycl.domain.entity.SysForm;
+
+import java.util.List;
+
+/**
+ * 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟Service鎺ュ彛
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+public interface ISysDeployFormService
+{
+    /**
+     * 鏌ヨ娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param id 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟ID
+     * @return 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     */
+    public SysDeployForm selectSysDeployFormById(Long id);
+
+    /**
+     * 鏌ヨ娴佺▼瀹炰緥鍏宠仈琛ㄥ崟鍒楄〃
+     *
+     * @param sysDeployForm 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     * @return 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟闆嗗悎
+     */
+    public List<SysDeployForm> selectSysDeployFormList(SysDeployForm sysDeployForm);
+
+    /**
+     * 鏂板娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param sysDeployForm 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     * @return 缁撴灉
+     */
+    public int insertSysDeployForm(SysDeployForm sysDeployForm);
+
+    /**
+     * 淇敼娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param sysDeployForm 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     * @return 缁撴灉
+     */
+    public int updateSysDeployForm(SysDeployForm sysDeployForm);
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑娴佺▼瀹炰緥鍏宠仈琛ㄥ崟ID
+     * @return 缁撴灉
+     */
+    public int deleteSysDeployFormByIds(Long[] ids);
+
+    /**
+     * 鍒犻櫎娴佺▼瀹炰緥鍏宠仈琛ㄥ崟淇℃伅
+     *
+     * @param id 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟ID
+     * @return 缁撴灉
+     */
+    public int deleteSysDeployFormById(Long id);
+
+    /**
+     * 鏌ヨ娴佺▼鎸傜潃鐨勮〃鍗�
+     * @param deployId
+     * @return
+     */
+    SysForm selectSysDeployFormByDeployId(String deployId);
+}
diff --git a/flowable/src/main/java/com/ycl/service/ISysExpressionService.java b/flowable/src/main/java/com/ycl/service/ISysExpressionService.java
new file mode 100644
index 0000000..302178a
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/ISysExpressionService.java
@@ -0,0 +1,62 @@
+package com.ycl.service;
+
+import com.ycl.domain.entity.SysExpression;
+
+import java.util.List;
+
+/**
+ * 娴佺▼杈惧紡Service鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2022-12-12
+ */
+public interface ISysExpressionService
+{
+    /**
+     * 鏌ヨ娴佺▼杈惧紡
+     *
+     * @param id 娴佺▼杈惧紡涓婚敭
+     * @return 娴佺▼杈惧紡
+     */
+    public SysExpression selectSysExpressionById(Long id);
+
+    /**
+     * 鏌ヨ娴佺▼杈惧紡鍒楄〃
+     *
+     * @param sysExpression 娴佺▼杈惧紡
+     * @return 娴佺▼杈惧紡闆嗗悎
+     */
+    public List<SysExpression> selectSysExpressionList(SysExpression sysExpression);
+
+    /**
+     * 鏂板娴佺▼杈惧紡
+     *
+     * @param sysExpression 娴佺▼杈惧紡
+     * @return 缁撴灉
+     */
+    public int insertSysExpression(SysExpression sysExpression);
+
+    /**
+     * 淇敼娴佺▼杈惧紡
+     *
+     * @param sysExpression 娴佺▼杈惧紡
+     * @return 缁撴灉
+     */
+    public int updateSysExpression(SysExpression sysExpression);
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼杈惧紡
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑娴佺▼杈惧紡涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteSysExpressionByIds(Long[] ids);
+
+    /**
+     * 鍒犻櫎娴佺▼杈惧紡淇℃伅
+     *
+     * @param id 娴佺▼杈惧紡涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteSysExpressionById(Long id);
+}
diff --git a/flowable/src/main/java/com/ycl/service/ISysFormService.java b/flowable/src/main/java/com/ycl/service/ISysFormService.java
new file mode 100644
index 0000000..00e0f74
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/ISysFormService.java
@@ -0,0 +1,61 @@
+package com.ycl.service;
+
+import com.ycl.domain.entity.SysForm;
+
+import java.util.List;
+
+/**
+ * 琛ㄥ崟
+ * @author Tony
+ * @date 2021-04-03
+ */
+public interface ISysFormService
+{
+    /**
+     * 鏌ヨ娴佺▼琛ㄥ崟
+     *
+     * @param formId 娴佺▼琛ㄥ崟ID
+     * @return 娴佺▼琛ㄥ崟
+     */
+    public SysForm selectSysFormById(Long formId);
+
+    /**
+     * 鏌ヨ娴佺▼琛ㄥ崟鍒楄〃
+     *
+     * @param sysForm 娴佺▼琛ㄥ崟
+     * @return 娴佺▼琛ㄥ崟闆嗗悎
+     */
+    public List<SysForm> selectSysFormList(SysForm sysForm);
+
+    /**
+     * 鏂板娴佺▼琛ㄥ崟
+     *
+     * @param sysForm 娴佺▼琛ㄥ崟
+     * @return 缁撴灉
+     */
+    public int insertSysForm(SysForm sysForm);
+
+    /**
+     * 淇敼娴佺▼琛ㄥ崟
+     *
+     * @param sysForm 娴佺▼琛ㄥ崟
+     * @return 缁撴灉
+     */
+    public int updateSysForm(SysForm sysForm);
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼琛ㄥ崟
+     *
+     * @param formIds 闇�瑕佸垹闄ょ殑娴佺▼琛ㄥ崟ID
+     * @return 缁撴灉
+     */
+    public int deleteSysFormByIds(Long[] formIds);
+
+    /**
+     * 鍒犻櫎娴佺▼琛ㄥ崟淇℃伅
+     *
+     * @param formId 娴佺▼琛ㄥ崟ID
+     * @return 缁撴灉
+     */
+    public int deleteSysFormById(Long formId);
+}
diff --git a/flowable/src/main/java/com/ycl/service/ISysListenerService.java b/flowable/src/main/java/com/ycl/service/ISysListenerService.java
new file mode 100644
index 0000000..a29b639
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/ISysListenerService.java
@@ -0,0 +1,62 @@
+package com.ycl.service;
+
+import com.ycl.domain.entity.SysListener;
+
+import java.util.List;
+
+/**
+ * 娴佺▼鐩戝惉Service鎺ュ彛
+ *
+ * @author Tony
+ * @date 2022-12-25
+ */
+public interface ISysListenerService
+{
+    /**
+     * 鏌ヨ娴佺▼鐩戝惉
+     *
+     * @param id 娴佺▼鐩戝惉涓婚敭
+     * @return 娴佺▼鐩戝惉
+     */
+    public SysListener selectSysListenerById(Long id);
+
+    /**
+     * 鏌ヨ娴佺▼鐩戝惉鍒楄〃
+     *
+     * @param sysListener 娴佺▼鐩戝惉
+     * @return 娴佺▼鐩戝惉闆嗗悎
+     */
+    public List<SysListener> selectSysListenerList(SysListener sysListener);
+
+    /**
+     * 鏂板娴佺▼鐩戝惉
+     *
+     * @param sysListener 娴佺▼鐩戝惉
+     * @return 缁撴灉
+     */
+    public int insertSysListener(SysListener sysListener);
+
+    /**
+     * 淇敼娴佺▼鐩戝惉
+     *
+     * @param sysListener 娴佺▼鐩戝惉
+     * @return 缁撴灉
+     */
+    public int updateSysListener(SysListener sysListener);
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼鐩戝惉
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑娴佺▼鐩戝惉涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteSysListenerByIds(Long[] ids);
+
+    /**
+     * 鍒犻櫎娴佺▼鐩戝惉淇℃伅
+     *
+     * @param id 娴佺▼鐩戝惉涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteSysListenerById(Long id);
+}
diff --git a/flowable/src/main/java/com/ycl/service/impl/FlowDefinitionServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/FlowDefinitionServiceImpl.java
new file mode 100644
index 0000000..f1ff087
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/impl/FlowDefinitionServiceImpl.java
@@ -0,0 +1,246 @@
+package com.ycl.service.impl;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.ycl.common.constant.ProcessConstants;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.domain.entity.SysUser;
+import com.ycl.common.enums.FlowComment;
+import com.ycl.common.utils.SecurityUtils;
+import com.ycl.domain.dto.FlowProcDefDto;
+import com.ycl.domain.entity.SysForm;
+import com.ycl.factory.FlowServiceFactory;
+import com.ycl.mapper.FlowDeployMapper;
+import com.ycl.service.IFlowDefinitionService;
+import com.ycl.service.ISysDeployFormService;
+import com.ycl.system.service.ISysDeptService;
+import com.ycl.system.service.ISysUserService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.engine.repository.Deployment;
+import org.flowable.engine.repository.ProcessDefinition;
+import org.flowable.engine.repository.ProcessDefinitionQuery;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.image.impl.DefaultProcessDiagramGenerator;
+import org.flowable.task.api.Task;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 娴佺▼瀹氫箟
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class FlowDefinitionServiceImpl extends FlowServiceFactory implements IFlowDefinitionService {
+
+    private final ISysDeployFormService sysDeployFormService;
+
+    private final ISysUserService sysUserService;
+
+    private final ISysDeptService sysDeptService;
+
+    private final FlowDeployMapper flowDeployMapper;
+
+    private static final String BPMN_FILE_SUFFIX = ".bpmn";
+
+    @Override
+    public boolean exist(String processDefinitionKey) {
+        ProcessDefinitionQuery processDefinitionQuery
+                = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDefinitionKey);
+        long count = processDefinitionQuery.count();
+        return count > 0 ? true : false;
+    }
+
+
+    /**
+     * 娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param pageNum  褰撳墠椤电爜
+     * @param pageSize 姣忛〉鏉℃暟
+     * @return 娴佺▼瀹氫箟鍒嗛〉鍒楄〃鏁版嵁
+     */
+    @Override
+    public Page<FlowProcDefDto> list(String name, Integer pageNum, Integer pageSize) {
+        Page<FlowProcDefDto> page = new Page<>();
+//        // 娴佺▼瀹氫箟鍒楄〃鏁版嵁鏌ヨ
+//        final ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
+//        if (StringUtils.isNotEmpty(name)) {
+//            processDefinitionQuery.processDefinitionNameLike(name);
+//        }
+////        processDefinitionQuery.orderByProcessDefinitionKey().asc();
+//        page.setTotal(processDefinitionQuery.count());
+//        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(pageSize * (pageNum - 1), pageSize);
+//
+//        List<FlowProcDefDto> dataList = new ArrayList<>();
+//        for (ProcessDefinition processDefinition : processDefinitionList) {
+//            String deploymentId = processDefinition.getDeploymentId();
+//            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
+//            FlowProcDefDto reProcDef = new FlowProcDefDto();
+//            BeanUtils.copyProperties(processDefinition, reProcDef);
+//            SysForm sysForm = sysDeployFormService.selectSysDeployFormByDeployId(deploymentId);
+//            if (Objects.nonNull(sysForm)) {
+//                reProcDef.setFormName(sysForm.getFormName());
+//                reProcDef.setFormId(sysForm.getFormId());
+//            }
+//            // 娴佺▼瀹氫箟鏃堕棿
+//            reProcDef.setDeploymentTime(deployment.getDeploymentTime());
+//            dataList.add(reProcDef);
+//        }
+        PageHelper.startPage(pageNum, pageSize);
+        final List<FlowProcDefDto> dataList = flowDeployMapper.selectDeployList(name);
+        // 鍔犺浇鎸傝〃鍗�
+        for (FlowProcDefDto procDef : dataList) {
+            SysForm sysForm = sysDeployFormService.selectSysDeployFormByDeployId(procDef.getDeploymentId());
+            if (Objects.nonNull(sysForm)) {
+                procDef.setFormName(sysForm.getFormName());
+                procDef.setFormId(sysForm.getFormId());
+            }
+        }
+        page.setTotal(new PageInfo(dataList).getTotal());
+        page.setRecords(dataList);
+        return page;
+    }
+
+
+    /**
+     * 瀵煎叆娴佺▼鏂囦欢
+     *
+     * 褰撴瘡涓猭ey鐨勬祦绋嬬涓�娆¢儴缃叉椂锛屾寚瀹氱増鏈负1銆傚鍏跺悗鎵�鏈変娇鐢ㄧ浉鍚宬ey鐨勬祦绋嬪畾涔夛紝
+     * 閮ㄧ讲鏃剁増鏈細鍦ㄨkey褰撳墠宸查儴缃茬殑鏈�楂樼増鏈彿鍩虹涓婂姞1銆俴ey鍙傛暟鐢ㄤ簬鍖哄垎娴佺▼瀹氫箟
+     * @param name
+     * @param category
+     * @param in
+     */
+    @Override
+    public void importFile(String name, String category, InputStream in) {
+        Deployment deploy = repositoryService.createDeployment().addInputStream(name + BPMN_FILE_SUFFIX, in).name(name).category(category).deploy();
+        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();
+        repositoryService.setProcessDefinitionCategory(definition.getId(), category);
+
+    }
+
+    /**
+     * 璇诲彇xml
+     *
+     * @param deployId
+     * @return
+     */
+    @Override
+    public AjaxResult readXml(String deployId) throws IOException {
+        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult();
+        InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName());
+        String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8.name());
+        return AjaxResult.success("", result);
+    }
+
+    /**
+     * 璇诲彇xml
+     *
+     * @param deployId
+     * @return
+     */
+    @Override
+    public InputStream readImage(String deployId) {
+        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult();
+        //鑾峰緱鍥剧墖娴�
+        DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
+        //杈撳嚭涓哄浘鐗�
+        return diagramGenerator.generateDiagram(
+                bpmnModel,
+                "png",
+                Collections.emptyList(),
+                Collections.emptyList(),
+                "瀹嬩綋",
+                "瀹嬩綋",
+                "瀹嬩綋",
+                null,
+                1.0,
+                false);
+
+    }
+
+    /**
+     * 鏍规嵁娴佺▼瀹氫箟ID鍚姩娴佺▼瀹炰緥
+     *
+     * @param procDefId 娴佺▼妯℃澘ID
+     * @param variables 娴佺▼鍙橀噺
+     * @return
+     */
+    @Override
+    public AjaxResult startProcessInstanceById(String procDefId, Map<String, Object> variables) {
+        try {
+            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId)
+                    .latestVersion().singleResult();
+            if (Objects.nonNull(processDefinition) && processDefinition.isSuspended()) {
+                return AjaxResult.error("娴佺▼宸茶鎸傝捣,璇峰厛婵�娲绘祦绋�");
+            }
+            // 璁剧疆娴佺▼鍙戣捣浜篒d鍒版祦绋嬩腑
+            SysUser sysUser = SecurityUtils.getLoginUser().getUser();
+            identityService.setAuthenticatedUserId(sysUser.getUserId().toString());
+            variables.put(ProcessConstants.PROCESS_INITIATOR, sysUser.getUserId());
+
+            // 娴佺▼鍙戣捣鏃� 璺宠繃鍙戣捣浜鸿妭鐐�
+            ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDefId, variables);
+            // 缁欑涓�姝ョ敵璇蜂汉鑺傜偣璁剧疆浠诲姟鎵ц浜哄拰鎰忚
+            Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();
+            if (Objects.nonNull(task)) {
+                taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.NORMAL.getType(), sysUser.getNickName() + "鍙戣捣娴佺▼鐢宠");
+                taskService.complete(task.getId(), variables);
+            }
+            return AjaxResult.success("娴佺▼鍚姩鎴愬姛");
+        } catch (Exception e) {
+            e.printStackTrace();
+            return AjaxResult.error("娴佺▼鍚姩閿欒");
+        }
+    }
+
+
+    /**
+     * 婵�娲绘垨鎸傝捣娴佺▼瀹氫箟
+     *
+     * @param state    鐘舵��
+     * @param deployId 娴佺▼閮ㄧ讲ID
+     */
+    @Override
+    public void updateState(Integer state, String deployId) {
+        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult();
+        // 婵�娲�
+        if (state == 1) {
+            repositoryService.activateProcessDefinitionById(procDef.getId(), true, null);
+        }
+        // 鎸傝捣
+        if (state == 2) {
+            repositoryService.suspendProcessDefinitionById(procDef.getId(), true, null);
+        }
+    }
+
+
+    /**
+     * 鍒犻櫎娴佺▼瀹氫箟
+     *
+     * @param deployId 娴佺▼閮ㄧ讲ID act_ge_bytearray 琛ㄤ腑 deployment_id鍊�
+     */
+    @Override
+    public void delete(String deployId) {
+        // true 鍏佽绾ц仈鍒犻櫎 ,涓嶈缃細瀵艰嚧鏁版嵁搴撳閿叧鑱斿紓甯�
+        repositoryService.deleteDeployment(deployId, true);
+    }
+
+
+}
diff --git a/flowable/src/main/java/com/ycl/service/impl/FlowInstanceServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/FlowInstanceServiceImpl.java
new file mode 100644
index 0000000..80d7d0b
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/impl/FlowInstanceServiceImpl.java
@@ -0,0 +1,120 @@
+package com.ycl.service.impl;
+
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.utils.SecurityUtils;
+import com.ycl.domain.vo.FlowTaskVo;
+import com.ycl.factory.FlowServiceFactory;
+import com.ycl.service.IFlowInstanceService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.common.engine.api.FlowableObjectNotFoundException;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * <p>宸ヤ綔娴佹祦绋嬪疄渚嬬鐞�<p>
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class FlowInstanceServiceImpl extends FlowServiceFactory implements IFlowInstanceService {
+
+    /**
+     * 缁撴潫娴佺▼瀹炰緥
+     *
+     * @param vo
+     */
+    @Override
+    public void stopProcessInstance(FlowTaskVo vo) {
+        String taskId = vo.getTaskId();
+
+    }
+
+    /**
+     * 婵�娲绘垨鎸傝捣娴佺▼瀹炰緥
+     *
+     * @param state      鐘舵��
+     * @param instanceId 娴佺▼瀹炰緥ID
+     */
+    @Override
+    public void updateState(Integer state, String instanceId) {
+
+        // 婵�娲�
+        if (state == 1) {
+            runtimeService.activateProcessInstanceById(instanceId);
+        }
+        // 鎸傝捣
+        if (state == 2) {
+            runtimeService.suspendProcessInstanceById(instanceId);
+        }
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼瀹炰緥ID
+     *
+     * @param instanceId   娴佺▼瀹炰緥ID
+     * @param deleteReason 鍒犻櫎鍘熷洜
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void delete(String instanceId, String deleteReason) {
+
+        // 鏌ヨ鍘嗗彶鏁版嵁
+        HistoricProcessInstance historicProcessInstance = getHistoricProcessInstanceById(instanceId);
+        if (historicProcessInstance.getEndTime() != null) {
+            historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());
+            return;
+        }
+        // 鍒犻櫎娴佺▼瀹炰緥
+        runtimeService.deleteProcessInstance(instanceId, deleteReason);
+        // 鍒犻櫎鍘嗗彶娴佺▼瀹炰緥
+        historyService.deleteHistoricProcessInstance(instanceId);
+    }
+
+    /**
+     * 鏍规嵁瀹炰緥ID鏌ヨ鍘嗗彶瀹炰緥鏁版嵁
+     *
+     * @param processInstanceId
+     * @return
+     */
+    @Override
+    public HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId) {
+        HistoricProcessInstance historicProcessInstance =
+                historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
+        if (Objects.isNull(historicProcessInstance)) {
+            throw new FlowableObjectNotFoundException("娴佺▼瀹炰緥涓嶅瓨鍦�: " + processInstanceId);
+        }
+        return historicProcessInstance;
+    }
+
+    /**
+     * 鏍规嵁娴佺▼瀹氫箟ID鍚姩娴佺▼瀹炰緥
+     *
+     * @param procDefId 娴佺▼瀹氫箟Id
+     * @param variables 娴佺▼鍙橀噺
+     * @return
+     */
+    @Override
+    public AjaxResult startProcessInstanceById(String procDefId, Map<String, Object> variables) {
+
+        try {
+            // 璁剧疆娴佺▼鍙戣捣浜篒d鍒版祦绋嬩腑
+            Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
+//            identityService.setAuthenticatedUserId(userId.toString());
+            variables.put("initiator",userId);
+            variables.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true);
+            runtimeService.startProcessInstanceById(procDefId, variables);
+            return AjaxResult.success("娴佺▼鍚姩鎴愬姛");
+        } catch (Exception e) {
+            e.printStackTrace();
+            return AjaxResult.error("娴佺▼鍚姩閿欒");
+        }
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/service/impl/FlowTaskServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/FlowTaskServiceImpl.java
new file mode 100644
index 0000000..4bcfac6
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/impl/FlowTaskServiceImpl.java
@@ -0,0 +1,1263 @@
+package com.ycl.service.impl;
+
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.TypeReference;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ycl.common.constant.ProcessConstants;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.domain.entity.SysRole;
+import com.ycl.common.core.domain.entity.SysUser;
+import com.ycl.common.enums.FlowComment;
+import com.ycl.common.exception.CustomException;
+import com.ycl.common.utils.SecurityUtils;
+import com.ycl.domain.dto.FlowCommentDto;
+import com.ycl.domain.dto.FlowNextDto;
+import com.ycl.domain.dto.FlowTaskDto;
+import com.ycl.domain.dto.FlowViewerDto;
+import com.ycl.domain.entity.SysForm;
+import com.ycl.domain.vo.FlowQueryVo;
+import com.ycl.domain.vo.FlowTaskVo;
+import com.ycl.factory.FlowServiceFactory;
+import com.ycl.flow.CustomProcessDiagramGenerator;
+import com.ycl.flow.FindNextNodeUtil;
+import com.ycl.flow.FlowableUtils;
+import com.ycl.service.IFlowTaskService;
+import com.ycl.service.ISysDeployFormService;
+import com.ycl.service.ISysFormService;
+import com.ycl.system.service.ISysRoleService;
+import com.ycl.system.service.ISysUserService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.flowable.bpmn.model.Process;
+import org.flowable.bpmn.model.*;
+import org.flowable.common.engine.api.FlowableException;
+import org.flowable.common.engine.api.FlowableObjectNotFoundException;
+import org.flowable.engine.ProcessEngineConfiguration;
+import org.flowable.engine.history.HistoricActivityInstance;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.history.HistoricProcessInstanceQuery;
+import org.flowable.engine.impl.cmd.AddMultiInstanceExecutionCmd;
+import org.flowable.engine.impl.cmd.DeleteMultiInstanceExecutionCmd;
+import org.flowable.engine.repository.ProcessDefinition;
+import org.flowable.engine.runtime.Execution;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.engine.task.Comment;
+import org.flowable.identitylink.api.history.HistoricIdentityLink;
+import org.flowable.image.ProcessDiagramGenerator;
+import org.flowable.task.api.DelegationState;
+import org.flowable.task.api.Task;
+import org.flowable.task.api.TaskQuery;
+import org.flowable.task.api.history.HistoricTaskInstance;
+import org.flowable.task.api.history.HistoricTaskInstanceQuery;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * @author Tony
+ * @date 2021-04-03
+ **/
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTaskService {
+
+    private final ISysUserService sysUserService;
+    private final ISysRoleService sysRoleService;
+    private final ISysDeployFormService sysInstanceFormService;
+    private final ISysFormService sysFormService;
+
+    /**
+     * 瀹屾垚浠诲姟
+     *
+     * @param taskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public AjaxResult complete(FlowTaskVo taskVo) {
+        Task task = taskService.createTaskQuery().taskId(taskVo.getTaskId()).singleResult();
+        if (Objects.isNull(task)) {
+            return AjaxResult.error("浠诲姟涓嶅瓨鍦�");
+        }
+        if (DelegationState.PENDING.equals(task.getDelegationState())) {
+            taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.DELEGATE.getType(), taskVo.getComment());
+            taskService.resolveTask(taskVo.getTaskId(), taskVo.getVariables());
+        } else {
+            taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.NORMAL.getType(), taskVo.getComment());
+            Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
+            taskService.setAssignee(taskVo.getTaskId(), userId.toString());
+            taskService.complete(taskVo.getTaskId(), taskVo.getVariables());
+        }
+        return AjaxResult.success();
+    }
+
+    /**
+     * 椹冲洖浠诲姟
+     *
+     * @param flowTaskVo
+     */
+    @Override
+    public void taskReject(FlowTaskVo flowTaskVo) {
+        if (taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult().isSuspended()) {
+            throw new CustomException("浠诲姟澶勪簬鎸傝捣鐘舵��!");
+        }
+        // 褰撳墠浠诲姟 task
+        Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult();
+        // 鑾峰彇娴佺▼瀹氫箟淇℃伅
+        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
+        // 鑾峰彇鎵�鏈夎妭鐐逛俊鎭�
+        Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0);
+        // 鑾峰彇鍏ㄩ儴鑺傜偣鍒楄〃锛屽寘鍚瓙鑺傜偣
+        Collection<FlowElement> allElements = FlowableUtils.getAllElements(process.getFlowElements(), null);
+        // 鑾峰彇褰撳墠浠诲姟鑺傜偣鍏冪礌
+        FlowElement source = null;
+        if (allElements != null) {
+            for (FlowElement flowElement : allElements) {
+                // 绫诲瀷涓虹敤鎴疯妭鐐�
+                if (flowElement.getId().equals(task.getTaskDefinitionKey())) {
+                    // 鑾峰彇鑺傜偣淇℃伅
+                    source = flowElement;
+                }
+            }
+        }
+
+        // 鐩殑鑾峰彇鎵�鏈夎烦杞埌鐨勮妭鐐� targetIds
+        // 鑾峰彇褰撳墠鑺傜偣鐨勬墍鏈夌埗绾х敤鎴蜂换鍔¤妭鐐�
+        // 娣卞害浼樺厛绠楁硶鎬濇兂锛氬欢杈硅凯浠f繁鍏�
+        List<UserTask> parentUserTaskList = FlowableUtils.iteratorFindParentUserTasks(source, null, null);
+        if (parentUserTaskList == null || parentUserTaskList.size() == 0) {
+            throw new CustomException("褰撳墠鑺傜偣涓哄垵濮嬩换鍔¤妭鐐癸紝涓嶈兘椹冲洖");
+        }
+        // 鑾峰彇娲诲姩 ID 鍗宠妭鐐� Key
+        List<String> parentUserTaskKeyList = new ArrayList<>();
+        parentUserTaskList.forEach(item -> parentUserTaskKeyList.add(item.getId()));
+        // 鑾峰彇鍏ㄩ儴鍘嗗彶鑺傜偣娲诲姩瀹炰緥锛屽嵆宸茬粡璧拌繃鐨勮妭鐐瑰巻鍙诧紝鏁版嵁閲囩敤寮�濮嬫椂闂村崌搴�
+        List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()).orderByHistoricTaskInstanceStartTime().asc().list();
+        // 鏁版嵁娓呮礂锛屽皢鍥炴粴瀵艰嚧鐨勮剰鏁版嵁娓呮礂鎺�
+        List<String> lastHistoricTaskInstanceList = FlowableUtils.historicTaskInstanceClean(allElements, historicTaskInstanceList);
+        // 姝ゆ椂鍘嗗彶浠诲姟瀹炰緥涓哄�掑簭锛岃幏鍙栨渶鍚庤蛋鐨勮妭鐐�
+        List<String> targetIds = new ArrayList<>();
+        // 寰幆缁撴潫鏍囪瘑锛岄亣鍒板綋鍓嶇洰鏍囪妭鐐圭殑娆℃暟
+        int number = 0;
+        StringBuilder parentHistoricTaskKey = new StringBuilder();
+        for (String historicTaskInstanceKey : lastHistoricTaskInstanceList) {
+            // 褰撲細绛炬椂鍊欎細鍑虹幇鐗规畩鐨勶紝杩炵画閮芥槸鍚屼竴涓妭鐐瑰巻鍙叉暟鎹殑鎯呭喌锛岃繖绉嶆椂鍊欒烦杩�
+            if (parentHistoricTaskKey.toString().equals(historicTaskInstanceKey)) {
+                continue;
+            }
+            parentHistoricTaskKey = new StringBuilder(historicTaskInstanceKey);
+            if (historicTaskInstanceKey.equals(task.getTaskDefinitionKey())) {
+                number++;
+            }
+            // 鍦ㄦ暟鎹竻娲楀悗锛屽巻鍙茶妭鐐瑰氨鏄敮涓�涓�鏉′粠璧峰鍒板綋鍓嶈妭鐐圭殑鍘嗗彶璁板綍锛岀悊璁轰笂姣忎釜鐐瑰彧浼氬嚭鐜颁竴娆�
+            // 鍦ㄦ祦绋嬩腑濡傛灉鍑虹幇寰幆锛岄偅涔堟瘡娆″惊鐜腑闂寸殑鐐逛篃鍙細鍑虹幇涓�娆★紝鍐嶅嚭鐜板氨鏄笅娆″惊鐜�
+            // number == 1锛岀涓�娆¢亣鍒板綋鍓嶈妭鐐�
+            // number == 2锛岀浜屾閬囧埌锛屼唬琛ㄦ渶鍚庝竴娆$殑寰幆鑼冨洿
+            if (number == 2) {
+                break;
+            }
+            // 濡傛灉褰撳墠鍘嗗彶鑺傜偣锛屽睘浜庣埗绾х殑鑺傜偣锛岃鏄庢渶鍚庝竴娆$粡杩囦簡杩欎釜鐐癸紝闇�瑕侀��鍥炶繖涓偣
+            if (parentUserTaskKeyList.contains(historicTaskInstanceKey)) {
+                targetIds.add(historicTaskInstanceKey);
+            }
+        }
+
+
+        // 鐩殑鑾峰彇鎵�鏈夐渶瑕佽璺宠浆鐨勮妭鐐� currentIds
+        // 鍙栧叾涓竴涓埗绾т换鍔★紝鍥犱负鍚庣画瑕佷箞瀛樺湪鍏叡缃戝叧锛岃涔堝氨鏄覆琛屽叕鍏辩嚎璺�
+        UserTask oneUserTask = parentUserTaskList.get(0);
+        // 鑾峰彇鎵�鏈夋甯歌繘琛岀殑浠诲姟鑺傜偣 Key锛岃繖浜涗换鍔′笉鑳界洿鎺ヤ娇鐢紝闇�瑕佹壘鍑哄叾涓渶瑕佹挙鍥炵殑浠诲姟
+        List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
+        List<String> runTaskKeyList = new ArrayList<>();
+        runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey()));
+        // 闇�椹冲洖浠诲姟鍒楄〃
+        List<String> currentIds = new ArrayList<>();
+        // 閫氳繃鐖剁骇缃戝叧鐨勫嚭鍙h繛绾匡紝缁撳悎 runTaskList 姣斿锛岃幏鍙栭渶瑕佹挙鍥炵殑浠诲姟
+        List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(oneUserTask, runTaskKeyList, null, null);
+        currentUserTaskList.forEach(item -> currentIds.add(item.getId()));
+
+
+        // 瑙勫畾锛氬苟琛岀綉鍏充箣鍓嶈妭鐐瑰繀椤婚渶瀛樺湪鍞竴鐢ㄦ埛浠诲姟鑺傜偣锛屽鏋滃嚭鐜板涓换鍔¤妭鐐癸紝鍒欏苟琛岀綉鍏宠妭鐐归粯璁や负缁撴潫鑺傜偣锛屽師鍥犱负涓嶈�冭檻澶氬澶氭儏鍐�
+        if (targetIds.size() > 1 && currentIds.size() > 1) {
+            throw new CustomException("浠诲姟鍑虹幇澶氬澶氭儏鍐碉紝鏃犳硶鎾ゅ洖");
+        }
+
+        // 寰幆鑾峰彇閭d簺闇�瑕佽鎾ゅ洖鐨勮妭鐐圭殑ID锛岀敤鏉ヨ缃┏鍥炲師鍥�
+        List<String> currentTaskIds = new ArrayList<>();
+        currentIds.forEach(currentId -> runTaskList.forEach(runTask -> {
+            if (currentId.equals(runTask.getTaskDefinitionKey())) {
+                currentTaskIds.add(runTask.getId());
+            }
+        }));
+        // 璁剧疆椹冲洖鎰忚
+        currentTaskIds.forEach(item -> taskService.addComment(item, task.getProcessInstanceId(), FlowComment.REJECT.getType(), flowTaskVo.getComment()));
+
+        try {
+            // 濡傛灉鐖剁骇浠诲姟澶氫簬 1 涓紝璇存槑褰撳墠鑺傜偣涓嶆槸骞惰鑺傜偣锛屽師鍥犱负涓嶈�冭檻澶氬澶氭儏鍐�
+            if (targetIds.size() > 1) {
+                // 1 瀵� 澶氫换鍔¤烦杞紝currentIds 褰撳墠鑺傜偣(1)锛宼argetIds 璺宠浆鍒扮殑鑺傜偣(澶�)
+                runtimeService.createChangeActivityStateBuilder()
+                        .processInstanceId(task.getProcessInstanceId()).
+                        moveSingleActivityIdToActivityIds(currentIds.get(0), targetIds).changeState();
+            }
+            // 濡傛灉鐖剁骇浠诲姟鍙湁涓�涓紝鍥犳褰撳墠浠诲姟鍙兘涓虹綉鍏充腑鐨勪换鍔�
+            if (targetIds.size() == 1) {
+                // 1 瀵� 1 鎴� 澶� 瀵� 1 鎯呭喌锛宑urrentIds 褰撳墠瑕佽烦杞殑鑺傜偣鍒楄〃(1鎴栧)锛宼argetIds.get(0) 璺宠浆鍒扮殑鑺傜偣(1)
+                runtimeService.createChangeActivityStateBuilder()
+                        .processInstanceId(task.getProcessInstanceId())
+                        .moveActivityIdsToSingleActivityId(currentIds, targetIds.get(0)).changeState();
+            }
+        } catch (FlowableObjectNotFoundException e) {
+            throw new CustomException("鏈壘鍒版祦绋嬪疄渚嬶紝娴佺▼鍙兘宸插彂鐢熷彉鍖�");
+        } catch (FlowableException e) {
+            throw new CustomException("鏃犳硶鍙栨秷鎴栧紑濮嬫椿鍔�");
+        }
+
+    }
+
+    /**
+     * 閫�鍥炰换鍔�
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void taskReturn(FlowTaskVo flowTaskVo) {
+        if (taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult().isSuspended()) {
+            throw new CustomException("浠诲姟澶勪簬鎸傝捣鐘舵��");
+        }
+        // 褰撳墠浠诲姟 task
+        Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult();
+        // 鑾峰彇娴佺▼瀹氫箟淇℃伅
+        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
+        // 鑾峰彇鎵�鏈夎妭鐐逛俊鎭�
+        Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0);
+        // 鑾峰彇鍏ㄩ儴鑺傜偣鍒楄〃锛屽寘鍚瓙鑺傜偣
+        Collection<FlowElement> allElements = FlowableUtils.getAllElements(process.getFlowElements(), null);
+        // 鑾峰彇褰撳墠浠诲姟鑺傜偣鍏冪礌
+        FlowElement source = null;
+        // 鑾峰彇璺宠浆鐨勮妭鐐瑰厓绱�
+        FlowElement target = null;
+        if (allElements != null) {
+            for (FlowElement flowElement : allElements) {
+                // 褰撳墠浠诲姟鑺傜偣鍏冪礌
+                if (flowElement.getId().equals(task.getTaskDefinitionKey())) {
+                    source = flowElement;
+                }
+                // 璺宠浆鐨勮妭鐐瑰厓绱�
+                if (flowElement.getId().equals(flowTaskVo.getTargetKey())) {
+                    target = flowElement;
+                }
+            }
+        }
+
+        // 浠庡綋鍓嶈妭鐐瑰悜鍓嶆壂鎻�
+        // 濡傛灉瀛樺湪璺嚎涓婁笉瀛樺湪鐩爣鑺傜偣锛岃鏄庣洰鏍囪妭鐐规槸鍦ㄧ綉鍏充笂鎴栭潪鍚屼竴璺嚎涓婏紝涓嶅彲璺宠浆
+        // 鍚﹀垯鐩爣鑺傜偣鐩稿浜庡綋鍓嶈妭鐐癸紝灞炰簬涓茶
+        Boolean isSequential = FlowableUtils.iteratorCheckSequentialReferTarget(source, flowTaskVo.getTargetKey(), null, null);
+        if (!isSequential) {
+            throw new CustomException("褰撳墠鑺傜偣鐩稿浜庣洰鏍囪妭鐐癸紝涓嶅睘浜庝覆琛屽叧绯伙紝鏃犳硶鍥為��");
+        }
+
+
+        // 鑾峰彇鎵�鏈夋甯歌繘琛岀殑浠诲姟鑺傜偣 Key锛岃繖浜涗换鍔′笉鑳界洿鎺ヤ娇鐢紝闇�瑕佹壘鍑哄叾涓渶瑕佹挙鍥炵殑浠诲姟
+        List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
+        List<String> runTaskKeyList = new ArrayList<>();
+        runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey()));
+        // 闇�閫�鍥炰换鍔″垪琛�
+        List<String> currentIds = new ArrayList<>();
+        // 閫氳繃鐖剁骇缃戝叧鐨勫嚭鍙h繛绾匡紝缁撳悎 runTaskList 姣斿锛岃幏鍙栭渶瑕佹挙鍥炵殑浠诲姟
+        List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(target, runTaskKeyList, null, null);
+        currentUserTaskList.forEach(item -> currentIds.add(item.getId()));
+
+        // 寰幆鑾峰彇閭d簺闇�瑕佽鎾ゅ洖鐨勮妭鐐圭殑ID锛岀敤鏉ヨ缃┏鍥炲師鍥�
+        List<String> currentTaskIds = new ArrayList<>();
+        currentIds.forEach(currentId -> runTaskList.forEach(runTask -> {
+            if (currentId.equals(runTask.getTaskDefinitionKey())) {
+                currentTaskIds.add(runTask.getId());
+            }
+        }));
+        // 璁剧疆鍥為��鎰忚
+        currentTaskIds.forEach(currentTaskId -> taskService.addComment(currentTaskId, task.getProcessInstanceId(), FlowComment.REBACK.getType(), flowTaskVo.getComment()));
+
+        try {
+            // 1 瀵� 1 鎴� 澶� 瀵� 1 鎯呭喌锛宑urrentIds 褰撳墠瑕佽烦杞殑鑺傜偣鍒楄〃(1鎴栧)锛宼argetKey 璺宠浆鍒扮殑鑺傜偣(1)
+            runtimeService.createChangeActivityStateBuilder()
+                    .processInstanceId(task.getProcessInstanceId())
+                    .moveActivityIdsToSingleActivityId(currentIds, flowTaskVo.getTargetKey()).changeState();
+        } catch (FlowableObjectNotFoundException e) {
+            throw new CustomException("鏈壘鍒版祦绋嬪疄渚嬶紝娴佺▼鍙兘宸插彂鐢熷彉鍖�");
+        } catch (FlowableException e) {
+            throw new CustomException("鏃犳硶鍙栨秷鎴栧紑濮嬫椿鍔�");
+        }
+    }
+
+
+    /**
+     * 鑾峰彇鎵�鏈夊彲鍥為��鐨勮妭鐐�
+     *
+     * @param flowTaskVo
+     * @return
+     */
+    @Override
+    public AjaxResult findReturnTaskList(FlowTaskVo flowTaskVo) {
+        // 褰撳墠浠诲姟 task
+        Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult();
+        // 鑾峰彇娴佺▼瀹氫箟淇℃伅
+        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
+        // 鑾峰彇鎵�鏈夎妭鐐逛俊鎭紝鏆備笉鑰冭檻瀛愭祦绋嬫儏鍐�
+        Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0);
+        Collection<FlowElement> flowElements = process.getFlowElements();
+        // 鑾峰彇褰撳墠浠诲姟鑺傜偣鍏冪礌
+        UserTask source = null;
+        if (flowElements != null) {
+            for (FlowElement flowElement : flowElements) {
+                // 绫诲瀷涓虹敤鎴疯妭鐐�
+                if (flowElement.getId().equals(task.getTaskDefinitionKey())) {
+                    source = (UserTask) flowElement;
+                }
+            }
+        }
+        // 鑾峰彇鑺傜偣鐨勬墍鏈夎矾绾�
+        List<List<UserTask>> roads = FlowableUtils.findRoad(source, null, null, null);
+        // 鍙洖閫�鐨勮妭鐐瑰垪琛�
+        List<UserTask> userTaskList = new ArrayList<>();
+        for (List<UserTask> road : roads) {
+            if (userTaskList.size() == 0) {
+                // 杩樻病鏈夊彲鍥為��鑺傜偣鐩存帴娣诲姞
+                userTaskList = road;
+            } else {
+                // 濡傛灉宸叉湁鍥為��鑺傜偣锛屽垯姣斿鍙栦氦闆嗛儴鍒�
+                userTaskList.retainAll(road);
+            }
+        }
+        return AjaxResult.success(userTaskList);
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    @Override
+    public void deleteTask(FlowTaskVo flowTaskVo) {
+        // todo 寰呯‘璁ゅ垹闄や换鍔℃槸鐗╃悊鍒犻櫎浠诲姟 杩樻槸閫昏緫鍒犻櫎锛岃杩欎釜浠诲姟鐩存帴閫氳繃锛�
+        taskService.deleteTask(flowTaskVo.getTaskId(), flowTaskVo.getComment());
+    }
+
+    /**
+     * 璁ら/绛炬敹浠诲姟
+     * 璁ら浠ュ悗,杩欎釜鐢ㄦ埛灏变細鎴愪负浠诲姟鐨勬墽琛屼汉,浠诲姟浼氫粠鍏朵粬鎴愬憳鐨勪换鍔″垪琛ㄤ腑娑堝け
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void claim(FlowTaskVo flowTaskVo) {
+        taskService.claim(flowTaskVo.getTaskId(), flowTaskVo.getUserId());
+    }
+
+    /**
+     * 鍙栨秷璁ら/绛炬敹浠诲姟
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void unClaim(FlowTaskVo flowTaskVo) {
+        taskService.unclaim(flowTaskVo.getTaskId());
+    }
+
+    /**
+     * 濮旀淳浠诲姟
+     * 浠诲姟濮旀淳鍙槸濮旀淳浜哄皢褰撳墠鐨勪换鍔′氦缁欒濮旀淳浜鸿繘琛屽鎵癸紝澶勭悊浠诲姟鍚庡張閲嶆柊鍥炲埌濮旀淳浜鸿韩涓娿��
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void delegateTask(FlowTaskVo flowTaskVo) {
+        taskService.delegateTask(flowTaskVo.getTaskId(), flowTaskVo.getAssignee());
+    }
+
+    /**
+     * 浠诲姟褰掕繕
+     * 琚娲句汉瀹屾垚浠诲姟涔嬪悗锛屽皢浠诲姟褰掕繕濮旀淳浜�
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void resolveTask(FlowTaskVo flowTaskVo) {
+        taskService.resolveTask(flowTaskVo.getTaskId());
+    }
+
+
+    /**
+     * 杞姙浠诲姟
+     * 鐩存帴灏嗗姙鐞嗕汉鎹㈡垚鍒汉锛岃繖鏃朵换鍔$殑鎷ユ湁鑰呬笉鍐嶆槸杞姙浜�
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void assignTask(FlowTaskVo flowTaskVo) {
+        // 鐩存帴杞淳灏卞彲浠ヨ鐩栨帀涔嬪墠鐨�
+        taskService.setAssignee(flowTaskVo.getTaskId(), flowTaskVo.getAssignee());
+//        // 鍒犻櫎鎸囨淳浜洪噸鏂版寚娲�
+//        taskService.deleteCandidateUser(flowTaskVo.getTaskId(),flowTaskVo.getAssignee());
+//        taskService.addCandidateUser(flowTaskVo.getTaskId(),flowTaskVo.getAssignee());
+//        // 濡傛灉瑕佹煡璇㈣浆缁欎粬浜哄鐞嗙殑浠诲姟锛屽彲浠ュ悓鏃跺皢OWNER杩涜璁剧疆锛�
+//        taskService.setOwner(flowTaskVo.getTaskId(), flowTaskVo.getAssignee());
+
+    }
+
+    /**
+     * 澶氬疄渚嬪姞绛�
+     * act_ru_task銆乤ct_ru_identitylink鍚勭敓鎴愪竴鏉¤褰�
+     *
+     * @param flowTaskVo
+     */
+    @Override
+    public void addMultiInstanceExecution(FlowTaskVo flowTaskVo) {
+        managementService.executeCommand(new AddMultiInstanceExecutionCmd(flowTaskVo.getDefId(), flowTaskVo.getInstanceId(), flowTaskVo.getVariables()));
+    }
+
+    /**
+     * 澶氬疄渚嬪噺绛�
+     * act_ru_task鍑�1銆乤ct_ru_identitylink涓嶅彉
+     *
+     * @param flowTaskVo
+     */
+    @Override
+    public void deleteMultiInstanceExecution(FlowTaskVo flowTaskVo) {
+        managementService.executeCommand(new DeleteMultiInstanceExecutionCmd(flowTaskVo.getCurrentChildExecutionId(), flowTaskVo.getFlag()));
+    }
+
+    /**
+     * 鎴戝彂璧风殑娴佺▼
+     *
+     * @param queryVo 璇锋眰鍙傛暟
+     * @return
+     */
+    @Override
+    public AjaxResult myProcess(FlowQueryVo queryVo) {
+        Page<FlowTaskDto> page = new Page<>();
+        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
+        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
+                .startedBy(userId.toString())
+                .orderByProcessInstanceStartTime()
+                .desc();
+        List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize());
+        page.setTotal(historicProcessInstanceQuery.count());
+        List<FlowTaskDto> flowList = new ArrayList<>();
+        for (HistoricProcessInstance hisIns : historicProcessInstances) {
+            FlowTaskDto flowTask = new FlowTaskDto();
+            flowTask.setCreateTime(hisIns.getStartTime());
+            flowTask.setFinishTime(hisIns.getEndTime());
+            flowTask.setProcInsId(hisIns.getId());
+
+            // 璁$畻鑰楁椂
+            if (Objects.nonNull(hisIns.getEndTime())) {
+                long time = hisIns.getEndTime().getTime() - hisIns.getStartTime().getTime();
+                flowTask.setDuration(getDate(time));
+            } else {
+                long time = System.currentTimeMillis() - hisIns.getStartTime().getTime();
+                flowTask.setDuration(getDate(time));
+            }
+            // 娴佺▼瀹氫箟淇℃伅
+            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
+                    .processDefinitionId(hisIns.getProcessDefinitionId())
+                    .singleResult();
+            flowTask.setDeployId(pd.getDeploymentId());
+            flowTask.setProcDefName(pd.getName());
+            flowTask.setProcDefVersion(pd.getVersion());
+            flowTask.setCategory(pd.getCategory());
+            flowTask.setProcDefVersion(pd.getVersion());
+            // 褰撳墠鎵�澶勬祦绋�
+            List<Task> taskList = taskService.createTaskQuery().processInstanceId(hisIns.getId()).list();
+            if (CollectionUtils.isNotEmpty(taskList)) {
+                flowTask.setTaskId(taskList.get(0).getId());
+                flowTask.setTaskName(taskList.get(0).getName());
+                if (StringUtils.isNotBlank(taskList.get(0).getAssignee())) {
+                    // 褰撳墠浠诲姟鑺傜偣鍔炵悊浜轰俊鎭�
+                    SysUser sysUser = sysUserService.selectUserById(Long.parseLong(taskList.get(0).getAssignee()));
+                    if (Objects.nonNull(sysUser)) {
+                        flowTask.setAssigneeId(sysUser.getUserId());
+                        flowTask.setAssigneeName(sysUser.getNickName());
+                        flowTask.setAssigneeDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : "");
+                    }
+                }
+            } else {
+                List<HistoricTaskInstance> historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(hisIns.getId()).orderByHistoricTaskInstanceEndTime().desc().list();
+                flowTask.setTaskId(historicTaskInstance.get(0).getId());
+                flowTask.setTaskName(historicTaskInstance.get(0).getName());
+                if (StringUtils.isNotBlank(historicTaskInstance.get(0).getAssignee())) {
+                    // 褰撳墠浠诲姟鑺傜偣鍔炵悊浜轰俊鎭�
+                    SysUser sysUser = sysUserService.selectUserById(Long.parseLong(historicTaskInstance.get(0).getAssignee()));
+                    if (Objects.nonNull(sysUser)) {
+                        flowTask.setAssigneeId(sysUser.getUserId());
+                        flowTask.setAssigneeName(sysUser.getNickName());
+                        flowTask.setAssigneeDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : "");
+                    }
+                }
+            }
+            flowList.add(flowTask);
+        }
+        page.setRecords(flowList);
+        return AjaxResult.success(page);
+    }
+
+    /**
+     * 鍙栨秷鐢宠
+     * 鐩墠瀹炵幇鏂瑰紡: 鐩存帴灏嗗綋鍓嶆祦绋嬪彉鏇翠负宸插畬鎴�
+     *
+     * @param flowTaskVo
+     * @return
+     */
+    @Override
+    public AjaxResult stopProcess(FlowTaskVo flowTaskVo) {
+        List<Task> task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).list();
+        if (CollectionUtils.isEmpty(task)) {
+            throw new CustomException("娴佺▼鏈惎鍔ㄦ垨宸叉墽琛屽畬鎴愶紝鍙栨秷鐢宠澶辫触");
+        }
+        // 鑾峰彇褰撳墠娴佺▼瀹炰緥
+        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
+                .processInstanceId(flowTaskVo.getInstanceId())
+                .singleResult();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
+        if (Objects.nonNull(bpmnModel)) {
+            Process process = bpmnModel.getMainProcess();
+            List<EndEvent> endNodes = process.findFlowElementsOfType(EndEvent.class, false);
+            if (CollectionUtils.isNotEmpty(endNodes)) {
+                // TODO 鍙栨秷娴佺▼涓轰粈涔堣璁剧疆娴佺▼鍙戣捣浜�?
+//                SysUser loginUser = SecurityUtils.getLoginUser().getUser();
+//                Authentication.setAuthenticatedUserId(loginUser.getUserId().toString());
+
+//                taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.STOP.getType(),
+//                        StringUtils.isBlank(flowTaskVo.getComment()) ? "鍙栨秷鐢宠" : flowTaskVo.getComment());
+                // 鑾峰彇褰撳墠娴佺▼鏈�鍚庝竴涓妭鐐�
+                String endId = endNodes.get(0).getId();
+                List<Execution> executions = runtimeService.createExecutionQuery()
+                        .parentId(processInstance.getProcessInstanceId()).list();
+                List<String> executionIds = new ArrayList<>();
+                executions.forEach(execution -> executionIds.add(execution.getId()));
+                // 鍙樻洿娴佺▼涓哄凡缁撴潫鐘舵��
+                runtimeService.createChangeActivityStateBuilder()
+                        .moveExecutionsToSingleActivityId(executionIds, endId).changeState();
+            }
+        }
+
+        return AjaxResult.success();
+    }
+
+    /**
+     * 鎾ゅ洖娴佺▼  鐩墠瀛樺湪閿欒
+     *
+     * @param flowTaskVo
+     * @return
+     */
+    @Override
+    public AjaxResult revokeProcess(FlowTaskVo flowTaskVo) {
+        Task task = taskService.createTaskQuery()
+                .processInstanceId(flowTaskVo.getInstanceId())
+                .singleResult();
+        if (task == null) {
+            throw new CustomException("娴佺▼鏈惎鍔ㄦ垨宸叉墽琛屽畬鎴愶紝鏃犳硶鎾ゅ洖");
+        }
+
+        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
+        List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
+                .processInstanceId(task.getProcessInstanceId())
+                .orderByTaskCreateTime()
+                .asc()
+                .list();
+        String myTaskId = null;
+        for (HistoricTaskInstance hti : htiList) {
+            if (loginUser.getUserId().toString().equals(hti.getAssignee())) {
+                myTaskId = hti.getId();
+                break;
+            }
+        }
+        if (null == myTaskId) {
+            throw new CustomException("璇ヤ换鍔¢潪褰撳墠鐢ㄦ埛鎻愪氦锛屾棤娉曟挙鍥�");
+        }
+        List<HistoricTaskInstance> historicTaskInstanceList = historyService
+                .createHistoricTaskInstanceQuery()
+                .processInstanceId(task.getProcessInstanceId())
+                .orderByHistoricTaskInstanceStartTime()
+                .asc()
+                .list();
+        Iterator<HistoricTaskInstance> it = historicTaskInstanceList.iterator();
+        //寰幆鑺傜偣锛岃幏鍙栧綋鍓嶈妭鐐圭殑涓婁竴鑺傜偣鐨刱ey
+        String tarKey = "";
+        while (it.hasNext()) {
+            HistoricTaskInstance his = it.next();
+            if (!task.getTaskDefinitionKey().equals(his.getTaskDefinitionKey())) {
+                tarKey = his.getTaskDefinitionKey();
+            }
+        }
+        // 璺宠浆鑺傜偣
+        runtimeService.createChangeActivityStateBuilder()
+                .processInstanceId(flowTaskVo.getInstanceId())
+                .moveActivityIdTo(task.getTaskDefinitionKey(), tarKey)
+                .changeState();
+
+        return AjaxResult.success();
+    }
+
+    /**
+     * 浠e姙浠诲姟鍒楄〃
+     *
+     * @param queryVo 璇锋眰鍙傛暟
+     * @return
+     */
+    @Override
+    public AjaxResult todoList(FlowQueryVo queryVo) {
+        Page<FlowTaskDto> page = new Page<>();
+        // 鍙煡鐪嬭嚜宸辩殑鏁版嵁
+        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
+        TaskQuery taskQuery = taskService.createTaskQuery()
+                .active()
+                .includeProcessVariables()
+                .taskCandidateGroupIn(sysUser.getRoles().stream().map(role -> role.getRoleId().toString()).collect(Collectors.toList()))
+                .taskCandidateOrAssigned(sysUser.getUserId().toString())
+                .orderByTaskCreateTime().desc();
+
+//        TODO 浼犲叆鍚嶇О鏌ヨ涓嶅埌鏁版嵁?
+        if (StringUtils.isNotBlank(queryVo.getName())) {
+            taskQuery.processDefinitionNameLike(queryVo.getName());
+        }
+        page.setTotal(taskQuery.count());
+        List<Task> taskList = taskQuery.listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize());
+        List<FlowTaskDto> flowList = new ArrayList<>();
+        for (Task task : taskList) {
+            FlowTaskDto flowTask = new FlowTaskDto();
+            // 褰撳墠娴佺▼淇℃伅
+            flowTask.setTaskId(task.getId());
+            flowTask.setTaskDefKey(task.getTaskDefinitionKey());
+            flowTask.setCreateTime(task.getCreateTime());
+            flowTask.setProcDefId(task.getProcessDefinitionId());
+            flowTask.setExecutionId(task.getExecutionId());
+            flowTask.setTaskName(task.getName());
+            // 娴佺▼瀹氫箟淇℃伅
+            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
+                    .processDefinitionId(task.getProcessDefinitionId())
+                    .singleResult();
+            flowTask.setDeployId(pd.getDeploymentId());
+            flowTask.setProcDefName(pd.getName());
+            flowTask.setProcDefVersion(pd.getVersion());
+            flowTask.setProcInsId(task.getProcessInstanceId());
+
+            // 娴佺▼鍙戣捣浜轰俊鎭�
+            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
+                    .processInstanceId(task.getProcessInstanceId())
+                    .singleResult();
+            SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId()));
+            flowTask.setStartUserId(startUser.getUserId().toString());
+            flowTask.setStartUserName(startUser.getNickName());
+            flowTask.setStartDeptName(Objects.nonNull(startUser.getDept()) ? startUser.getDept().getDeptName() : "");
+            flowList.add(flowTask);
+        }
+
+        page.setRecords(flowList);
+        return AjaxResult.success(page);
+    }
+
+
+    /**
+     * 宸插姙浠诲姟鍒楄〃
+     *
+     * @param queryVo 璇锋眰鍙傛暟
+     * @return
+     */
+    @Override
+    public AjaxResult finishedList(FlowQueryVo queryVo) {
+        Page<FlowTaskDto> page = new Page<>();
+        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
+        HistoricTaskInstanceQuery taskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
+                .includeProcessVariables()
+                .finished()
+                .taskAssignee(userId.toString())
+                .orderByHistoricTaskInstanceEndTime()
+                .desc();
+        List<HistoricTaskInstance> historicTaskInstanceList = taskInstanceQuery.listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize());
+        List<FlowTaskDto> hisTaskList = new ArrayList<>();
+        for (HistoricTaskInstance histTask : historicTaskInstanceList) {
+            FlowTaskDto flowTask = new FlowTaskDto();
+            // 褰撳墠娴佺▼淇℃伅
+            flowTask.setTaskId(histTask.getId());
+            // 瀹℃壒浜哄憳淇℃伅
+            flowTask.setCreateTime(histTask.getCreateTime());
+            flowTask.setFinishTime(histTask.getEndTime());
+            flowTask.setDuration(getDate(histTask.getDurationInMillis()));
+            flowTask.setProcDefId(histTask.getProcessDefinitionId());
+            flowTask.setTaskDefKey(histTask.getTaskDefinitionKey());
+            flowTask.setTaskName(histTask.getName());
+
+            // 娴佺▼瀹氫箟淇℃伅
+            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
+                    .processDefinitionId(histTask.getProcessDefinitionId())
+                    .singleResult();
+            flowTask.setDeployId(pd.getDeploymentId());
+            flowTask.setProcDefName(pd.getName());
+            flowTask.setProcDefVersion(pd.getVersion());
+            flowTask.setProcInsId(histTask.getProcessInstanceId());
+            flowTask.setHisProcInsId(histTask.getProcessInstanceId());
+
+            // 娴佺▼鍙戣捣浜轰俊鎭�
+            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
+                    .processInstanceId(histTask.getProcessInstanceId())
+                    .singleResult();
+            SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId()));
+            flowTask.setStartUserId(startUser.getNickName());
+            flowTask.setStartUserName(startUser.getNickName());
+            flowTask.setStartDeptName(Objects.nonNull(startUser.getDept()) ? startUser.getDept().getDeptName() : "");
+            hisTaskList.add(flowTask);
+        }
+        page.setTotal(taskInstanceQuery.count());
+        page.setRecords(hisTaskList);
+        return AjaxResult.success(page);
+    }
+
+    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Set<Object> seen = ConcurrentHashMap.newKeySet();
+        return t -> seen.add(keyExtractor.apply(t));
+    }
+
+    /**
+     * 娴佺▼鍘嗗彶娴佽浆璁板綍
+     *
+     * @param procInsId 娴佺▼瀹炰緥Id
+     * @return
+     */
+    @Override
+    public AjaxResult flowRecord(String procInsId, String deployId) {
+        Map<String, Object> map = new HashMap<String, Object>();
+        if (StringUtils.isNotBlank(procInsId)) {
+            List<HistoricActivityInstance> list = historyService
+                    .createHistoricActivityInstanceQuery()
+                    .processInstanceId(procInsId)
+                    .orderByHistoricActivityInstanceStartTime()
+                    .desc().list();
+            List<FlowTaskDto> hisFlowList = new ArrayList<>();
+            for (HistoricActivityInstance histIns : list) {
+                // 灞曠ず寮�濮嬭妭鐐�
+//                if ("startEvent".equals(histIns.getActivityType())) {
+//                    FlowTaskDto flowTask = new FlowTaskDto();
+//                    // 娴佺▼鍙戣捣浜轰俊鎭�
+//                    HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
+//                            .processInstanceId(histIns.getProcessInstanceId())
+//                            .singleResult();
+//                    SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId()));
+//                    flowTask.setTaskName(startUser.getNickName() + "(" + startUser.getDept().getDeptName() + ")鍙戣捣鐢宠");
+//                    flowTask.setFinishTime(histIns.getEndTime());
+//                    hisFlowList.add(flowTask);
+//                } else if ("endEvent".equals(histIns.getActivityType())) {
+//                    FlowTaskDto flowTask = new FlowTaskDto();
+//                    flowTask.setTaskName(StringUtils.isNotBlank(histIns.getActivityName()) ? histIns.getActivityName() : "缁撴潫");
+//                    flowTask.setFinishTime(histIns.getEndTime());
+//                    hisFlowList.add(flowTask);
+//                } else
+                if (StringUtils.isNotBlank(histIns.getTaskId())) {
+                    FlowTaskDto flowTask = new FlowTaskDto();
+                    flowTask.setTaskId(histIns.getTaskId());
+                    flowTask.setTaskName(histIns.getActivityName());
+                    flowTask.setCreateTime(histIns.getStartTime());
+                    flowTask.setFinishTime(histIns.getEndTime());
+                    if (StringUtils.isNotBlank(histIns.getAssignee())) {
+                        SysUser sysUser = sysUserService.selectUserById(Long.parseLong(histIns.getAssignee()));
+                        flowTask.setAssigneeId(sysUser.getUserId());
+                        flowTask.setAssigneeName(sysUser.getNickName());
+                        flowTask.setDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : "");
+                    }
+                    // 灞曠ず瀹℃壒浜哄憳
+                    List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getTaskId());
+                    StringBuilder stringBuilder = new StringBuilder();
+                    for (HistoricIdentityLink identityLink : linksForTask) {
+                        // 鑾烽�変汉,鍊欓�夌粍/瑙掕壊(澶氫釜)
+                        if ("candidate".equals(identityLink.getType())) {
+                            if (StringUtils.isNotBlank(identityLink.getUserId())) {
+                                SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId()));
+                                stringBuilder.append(sysUser.getNickName()).append(",");
+                            }
+                            if (StringUtils.isNotBlank(identityLink.getGroupId())) {
+                                SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId()));
+                                stringBuilder.append(sysRole.getRoleName()).append(",");
+                            }
+                        }
+                    }
+                    if (StringUtils.isNotBlank(stringBuilder)) {
+                        flowTask.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1));
+                    }
+
+                    flowTask.setDuration(histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null : getDate(histIns.getDurationInMillis()));
+                    // 鑾峰彇鎰忚璇勮鍐呭
+                    List<Comment> commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId());
+                    commentList.forEach(comment -> {
+                        if (histIns.getTaskId().equals(comment.getTaskId())) {
+                            flowTask.setComment(FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build());
+                        }
+                    });
+                    hisFlowList.add(flowTask);
+                }
+            }
+            map.put("flowList", hisFlowList);
+        }
+        // 绗竴娆$敵璇疯幏鍙栧垵濮嬪寲琛ㄥ崟
+        if (StringUtils.isNotBlank(deployId)) {
+            SysForm sysForm = sysInstanceFormService.selectSysDeployFormByDeployId(deployId);
+            if (Objects.isNull(sysForm)) {
+                return AjaxResult.error("璇峰厛閰嶇疆娴佺▼琛ㄥ崟");
+            }
+            map.put("formData", JSONObject.parseObject(sysForm.getFormContent()));
+        }
+        return AjaxResult.success(map);
+    }
+
+    /**
+     * 鏍规嵁浠诲姟ID鏌ヨ鎸傝浇鐨勮〃鍗曚俊鎭�
+     *
+     * @param taskId 浠诲姟Id
+     * @return
+     */
+    @Override
+    public AjaxResult getTaskForm(String taskId) {
+        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
+        SysForm sysForm = sysFormService.selectSysFormById(Long.parseLong(task.getFormKey()));
+        return AjaxResult.success(sysForm.getFormContent());
+    }
+
+    /**
+     * 鑾峰彇娴佺▼杩囩▼鍥�
+     *
+     * @param processId
+     * @return
+     */
+    @Override
+    public InputStream diagram(String processId) {
+        String processDefinitionId;
+        // 鑾峰彇褰撳墠鐨勬祦绋嬪疄渚�
+        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        // 濡傛灉娴佺▼宸茬粡缁撴潫锛屽垯寰楀埌缁撴潫鑺傜偣
+        if (Objects.isNull(processInstance)) {
+            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
+
+            processDefinitionId = pi.getProcessDefinitionId();
+        } else {// 濡傛灉娴佺▼娌℃湁缁撴潫锛屽垯鍙栧綋鍓嶆椿鍔ㄨ妭鐐�
+            // 鏍规嵁娴佺▼瀹炰緥ID鑾峰緱褰撳墠澶勪簬娲诲姩鐘舵�佺殑ActivityId鍚堥泦
+            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+            processDefinitionId = pi.getProcessDefinitionId();
+        }
+
+        // 鑾峰緱娲诲姩鐨勮妭鐐�
+        List<HistoricActivityInstance> highLightedFlowList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
+
+        List<String> highLightedFlows = new ArrayList<>();
+        List<String> highLightedNodes = new ArrayList<>();
+        //楂樹寒绾�
+        for (HistoricActivityInstance tempActivity : highLightedFlowList) {
+            if ("sequenceFlow".equals(tempActivity.getActivityType())) {
+                //楂樹寒绾�
+                highLightedFlows.add(tempActivity.getActivityId());
+            } else {
+                //楂樹寒鑺傜偣
+                highLightedNodes.add(tempActivity.getActivityId());
+            }
+        }
+
+        //鑾峰彇娴佺▼鍥�
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
+        ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration();
+        //鑾峰彇鑷畾涔夊浘鐗囩敓鎴愬櫒
+        ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator();
+        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodes, highLightedFlows, configuration.getActivityFontName(),
+                configuration.getLabelFontName(), configuration.getAnnotationFontName(), configuration.getClassLoader(), 1.0, true);
+        return in;
+
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鎵ц鑺傜偣
+     *
+     * @param procInsId 娴佺▼瀹炰緥id
+     * @return
+     */
+    @Override
+    public AjaxResult getFlowViewer(String procInsId, String executionId) {
+        List<FlowViewerDto> flowViewerList = new ArrayList<>();
+        FlowViewerDto flowViewerDto;
+        // 鑾峰彇浠诲姟寮�濮嬭妭鐐�(涓存椂澶勭悊鏂瑰紡)
+        List<HistoricActivityInstance> startNodeList = historyService.createHistoricActivityInstanceQuery()
+                .processInstanceId(procInsId)
+                .orderByHistoricActivityInstanceStartTime()
+                .asc().listPage(0, 3);
+        for (HistoricActivityInstance startInstance : startNodeList) {
+            if (!"sequenceFlow".equals(startInstance.getActivityType())) {
+                flowViewerDto = new FlowViewerDto();
+                if (!"sequenceFlow".equals(startInstance.getActivityType())) {
+                    flowViewerDto.setKey(startInstance.getActivityId());
+                    // 鏍规嵁娴佺▼鑺傜偣澶勭悊鏃堕棿鏍¢獙鏀硅妭鐐规槸鍚﹀凡瀹屾垚
+                    flowViewerDto.setCompleted(!Objects.isNull(startInstance.getEndTime()));
+                    flowViewerList.add(flowViewerDto);
+                }
+            }
+        }
+        // 鍘嗗彶鑺傜偣
+        List<HistoricActivityInstance> hisActIns = historyService.createHistoricActivityInstanceQuery()
+                .executionId(executionId)
+                .orderByHistoricActivityInstanceStartTime()
+                .asc().list();
+        for (HistoricActivityInstance activityInstance : hisActIns) {
+            if (!"sequenceFlow".equals(activityInstance.getActivityType())) {
+                flowViewerDto = new FlowViewerDto();
+                flowViewerDto.setKey(activityInstance.getActivityId());
+                // 鏍规嵁娴佺▼鑺傜偣澶勭悊鏃堕棿鏍¢獙鏀硅妭鐐规槸鍚﹀凡瀹屾垚
+                flowViewerDto.setCompleted(!Objects.isNull(activityInstance.getEndTime()));
+                flowViewerList.add(flowViewerDto);
+            }
+        }
+        return AjaxResult.success(flowViewerList);
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鍙橀噺
+     *
+     * @param taskId
+     * @return
+     */
+    @Override
+    public AjaxResult processVariables(String taskId) {
+        // 娴佺▼鍙橀噺
+        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().includeProcessVariables().finished().taskId(taskId).singleResult();
+        if (Objects.nonNull(historicTaskInstance)) {
+            return AjaxResult.success(historicTaskInstance.getProcessVariables());
+        } else {
+            Map<String, Object> variables = taskService.getVariables(taskId);
+            return AjaxResult.success(variables);
+        }
+    }
+
+    /**
+     * 瀹℃壒浠诲姟鑾峰彇涓嬩竴鑺傜偣
+     *
+     * @param flowTaskVo 浠诲姟
+     * @return
+     */
+    @Override
+    public AjaxResult getNextFlowNode(FlowTaskVo flowTaskVo) {
+        // Step 1. 鑾峰彇褰撳墠鑺傜偣骞舵壘鍒颁笅涓�姝ヨ妭鐐�
+        Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult();
+        if (Objects.isNull(task)) {
+            return AjaxResult.error("浠诲姟涓嶅瓨鍦ㄦ垨宸茶瀹℃壒!");
+        }
+        // Step 2. 鑾峰彇褰撳墠娴佺▼鎵�鏈夋祦绋嬪彉閲�(缃戝叧鑺傜偣鏃堕渶瑕佹牎楠岃〃杈惧紡)
+        Map<String, Object> variables = taskService.getVariables(task.getId());
+        List<UserTask> nextUserTask = FindNextNodeUtil.getNextUserTasks(repositoryService, task, variables);
+        if (CollectionUtils.isEmpty(nextUserTask)) {
+            return AjaxResult.success("娴佺▼宸插畬缁�!", null);
+        }
+        return getFlowAttribute(nextUserTask);
+    }
+
+    /**
+     * 鍙戣捣娴佺▼鑾峰彇涓嬩竴鑺傜偣
+     *
+     * @param flowTaskVo 浠诲姟
+     * @return
+     */
+    @Override
+    public AjaxResult getNextFlowNodeByStart(FlowTaskVo flowTaskVo) {
+        // Step 1. 鏌ユ壘娴佺▼瀹氫箟淇℃伅
+        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(flowTaskVo.getDeploymentId()).singleResult();
+        if (Objects.isNull(processDefinition)) {
+            return AjaxResult.error("娴佺▼淇℃伅涓嶅瓨鍦�!");
+        }
+        // Step 2. 鑾峰彇涓嬩竴浠诲姟鑺傜偣(缃戝叧鑺傜偣鏃堕渶瑕佹牎楠岃〃杈惧紡)
+        List<UserTask> nextUserTask = FindNextNodeUtil.getNextUserTasksByStart(repositoryService, processDefinition, flowTaskVo.getVariables());
+        if (CollectionUtils.isEmpty(nextUserTask)) {
+            return AjaxResult.error("鏆傛湭鏌ユ壘鍒颁笅涓�浠诲姟,璇锋鏌ユ祦绋嬭璁℃槸鍚︽纭�!");
+        }
+        return getFlowAttribute(nextUserTask);
+    }
+
+
+    /**
+     * 鑾峰彇浠诲姟鑺傜偣灞炴��,鍖呭惈鑷畾涔夊睘鎬х瓑
+     *
+     * @param nextUserTask
+     */
+    private AjaxResult getFlowAttribute(List<UserTask> nextUserTask) {
+        FlowNextDto flowNextDto = new FlowNextDto();
+        for (UserTask userTask : nextUserTask) {
+            MultiInstanceLoopCharacteristics multiInstance = userTask.getLoopCharacteristics();
+            // 浼氱鑺傜偣
+            if (Objects.nonNull(multiInstance)) {
+                flowNextDto.setVars(multiInstance.getInputDataItem());
+                flowNextDto.setType(ProcessConstants.PROCESS_MULTI_INSTANCE);
+                flowNextDto.setDataType(ProcessConstants.DYNAMIC);
+            } else {
+                // 璇诲彇鑷畾涔夎妭鐐瑰睘鎬� 鍒ゆ柇鏄惁鏄惁闇�瑕佸姩鎬佹寚瀹氫换鍔℃帴鏀朵汉鍛樸�佺粍
+                String dataType = userTask.getAttributeValue(ProcessConstants.NAMASPASE, ProcessConstants.PROCESS_CUSTOM_DATA_TYPE);
+                String userType = userTask.getAttributeValue(ProcessConstants.NAMASPASE, ProcessConstants.PROCESS_CUSTOM_USER_TYPE);
+                flowNextDto.setVars(ProcessConstants.PROCESS_APPROVAL);
+                flowNextDto.setType(userType);
+                flowNextDto.setDataType(dataType);
+            }
+        }
+        return AjaxResult.success(flowNextDto);
+    }
+
+    /**
+     * 娴佺▼鍒濆鍖栬〃鍗�
+     *
+     * @param deployId
+     * @return
+     */
+    @Override
+    public AjaxResult flowFormData(String deployId) {
+        // 绗竴娆$敵璇疯幏鍙栧垵濮嬪寲琛ㄥ崟
+        if (StringUtils.isNotBlank(deployId)) {
+            SysForm sysForm = sysInstanceFormService.selectSysDeployFormByDeployId(deployId);
+            if (Objects.isNull(sysForm)) {
+                return AjaxResult.error("璇峰厛閰嶇疆娴佺▼琛ㄥ崟!");
+            }
+            return AjaxResult.success(JSONObject.parseObject(sysForm.getFormContent()));
+        } else {
+            return AjaxResult.error("鍙傛暟閿欒!");
+        }
+    }
+
+    /**
+     * 娴佺▼鑺傜偣淇℃伅
+     *
+     * @param procInsId
+     * @return
+     */
+    @Override
+    public AjaxResult flowXmlAndNode(String procInsId, String deployId) {
+        try {
+            List<FlowViewerDto> flowViewerList = new ArrayList<>();
+            // 鑾峰彇宸茬粡瀹屾垚鐨勮妭鐐�
+            List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
+                    .processInstanceId(procInsId)
+                    .finished()
+                    .list();
+
+            // 淇濆瓨宸茬粡瀹屾垚鐨勬祦绋嬭妭鐐圭紪鍙�
+            listFinished.forEach(s -> {
+                FlowViewerDto flowViewerDto = new FlowViewerDto();
+                flowViewerDto.setKey(s.getActivityId());
+                flowViewerDto.setCompleted(true);
+                // 閫�鍥炶妭鐐逛笉杩涜灞曠ず
+                if (StringUtils.isBlank(s.getDeleteReason())) {
+                    flowViewerList.add(flowViewerDto);
+                }
+            });
+
+            // 鑾峰彇浠e姙鑺傜偣
+            List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery()
+                    .processInstanceId(procInsId)
+                    .unfinished()
+                    .list();
+
+            // 淇濆瓨闇�瑕佷唬鍔炵殑鑺傜偣缂栧彿
+            listUnFinished.forEach(s -> {
+                // 鍒犻櫎宸查��鍥炶妭鐐�
+                flowViewerList.removeIf(task -> task.getKey().equals(s.getActivityId()));
+                FlowViewerDto flowViewerDto = new FlowViewerDto();
+                flowViewerDto.setKey(s.getActivityId());
+                flowViewerDto.setCompleted(false);
+                flowViewerList.add(flowViewerDto);
+            });
+            Map<String, Object> result = new HashMap();
+            // xmlData 鏁版嵁
+            ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult();
+            InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName());
+            String xmlData = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
+            result.put("nodeData", flowViewerList);
+            result.put("xmlData", xmlData);
+            return AjaxResult.success(result);
+        } catch (Exception e) {
+            return AjaxResult.error("楂樹寒鍘嗗彶浠诲姟澶辫触");
+        }
+    }
+
+    /**
+     * 娴佺▼鑺傜偣琛ㄥ崟
+     *
+     * @param taskId 娴佺▼浠诲姟缂栧彿
+     * @return
+     */
+    @Override
+    public AjaxResult flowTaskForm(String taskId) throws Exception {
+        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
+        // 娴佺▼鍙橀噺
+        Map<String, Object> parameters = new HashMap<>();
+        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().includeProcessVariables().finished().taskId(taskId).singleResult();
+        if (Objects.nonNull(historicTaskInstance)) {
+            parameters = historicTaskInstance.getProcessVariables();
+        } else {
+            parameters = taskService.getVariables(taskId);
+        }
+        JSONObject oldVariables = JSONObject.parseObject(JSON.toJSONString(parameters.get("formJson")));
+        List<JSONObject> oldFields = JSON.parseObject(JSON.toJSONString(oldVariables.get("widgetList")), new TypeReference<List<JSONObject>>() {
+        });
+        // 璁剧疆宸插~鍐欑殑琛ㄥ崟涓虹鐢ㄧ姸鎬�
+        for (JSONObject oldField : oldFields) {
+            JSONObject options = oldField.getJSONObject("options");
+            options.put("disabled", true);
+        }
+        // TODO 鏆傛椂鍙鐞嗙敤鎴蜂换鍔′笂鐨勮〃鍗�
+        if (StringUtils.isNotBlank(task.getFormKey())) {
+            SysForm sysForm = sysFormService.selectSysFormById(Long.parseLong(task.getFormKey()));
+            JSONObject data = JSONObject.parseObject(sysForm.getFormContent());
+            List<JSONObject> newFields = JSON.parseObject(JSON.toJSONString(data.get("widgetList")), new TypeReference<List<JSONObject>>() {
+            });
+            // 琛ㄥ崟鍥炴樉鏃� 鍔犲叆瀛愯〃鍗曚俊鎭埌娴佺▼鍙橀噺涓�
+            for (JSONObject newField : newFields) {
+                String key = newField.getString("id");
+                // 澶勭悊鍥剧墖涓婁紶缁勪欢鍥炴樉闂
+                if ("picture-upload".equals(newField.getString("type"))) {
+                    parameters.put(key, new ArrayList<>());
+                } else {
+                    parameters.put(key, null);
+                }
+            }
+            oldFields.addAll(newFields);
+        }
+        oldVariables.put("widgetList", oldFields);
+        parameters.put("formJson", oldVariables);
+        return AjaxResult.success(parameters);
+    }
+
+    /**
+     * 娴佺▼鑺傜偣淇℃伅
+     *
+     * @param procInsId
+     * @param elementId
+     * @return
+     */
+    @Override
+    public AjaxResult flowTaskInfo(String procInsId, String elementId) {
+        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
+                .processInstanceId(procInsId)
+                .activityId(elementId)
+                .list();
+        // 閫�鍥炰换鍔″悗鏈夊鏉℃暟鎹� 鍙彇寰呭姙浠诲姟杩涜灞曠ず
+        list.removeIf(task -> StringUtils.isNotBlank(task.getDeleteReason()));
+        if (CollectionUtils.isEmpty(list)) {
+            return AjaxResult.success();
+        }
+        if (list.size() > 1) {
+            list.removeIf(task -> Objects.nonNull(task.getEndTime()));
+        }
+        HistoricActivityInstance histIns = list.get(0);
+        FlowTaskDto flowTask = new FlowTaskDto();
+        flowTask.setTaskId(histIns.getTaskId());
+        flowTask.setTaskName(histIns.getActivityName());
+        flowTask.setCreateTime(histIns.getStartTime());
+        flowTask.setFinishTime(histIns.getEndTime());
+        if (StringUtils.isNotBlank(histIns.getAssignee())) {
+            SysUser sysUser = sysUserService.selectUserById(Long.parseLong(histIns.getAssignee()));
+            flowTask.setAssigneeId(sysUser.getUserId());
+            flowTask.setAssigneeName(sysUser.getNickName());
+            flowTask.setDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : "");
+
+        }
+        // 娴佺▼鍙橀噺淇℃伅
+//        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery()
+//                .includeProcessVariables().finished().taskId(histIns.getTaskId()).singleResult();
+//        flowTask.setVariables(historicTaskInstance.getProcessVariables());
+
+        // 灞曠ず瀹℃壒浜哄憳
+        List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getTaskId());
+        StringBuilder stringBuilder = new StringBuilder();
+        for (HistoricIdentityLink identityLink : linksForTask) {
+            // 鑾烽�変汉,鍊欓�夌粍/瑙掕壊(澶氫釜)
+            if ("candidate".equals(identityLink.getType())) {
+                if (StringUtils.isNotBlank(identityLink.getUserId())) {
+                    SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId()));
+                    stringBuilder.append(sysUser.getNickName()).append(",");
+                }
+                if (StringUtils.isNotBlank(identityLink.getGroupId())) {
+                    SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId()));
+                    stringBuilder.append(sysRole.getRoleName()).append(",");
+                }
+            }
+        }
+        if (StringUtils.isNotBlank(stringBuilder)) {
+            flowTask.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1));
+        }
+
+        flowTask.setDuration(histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null : getDate(histIns.getDurationInMillis()));
+        // 鑾峰彇鎰忚璇勮鍐呭
+        List<Comment> commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId());
+        commentList.forEach(comment -> {
+            if (histIns.getTaskId().equals(comment.getTaskId())) {
+                flowTask.setComment(FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build());
+            }
+        });
+        return AjaxResult.success(flowTask);
+    }
+
+    /**
+     * 灏哋bject绫诲瀷鐨勬暟鎹浆鍖栨垚Map<String,Object>
+     *
+     * @param obj
+     * @return
+     * @throws Exception
+     */
+    public Map<String, Object> obj2Map(Object obj) throws Exception {
+        Map<String, Object> map = new HashMap<String, Object>();
+        Field[] fields = obj.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            field.setAccessible(true);
+            map.put(field.getName(), field.get(obj));
+        }
+        return map;
+    }
+
+    /**
+     * 娴佺▼瀹屾垚鏃堕棿澶勭悊
+     *
+     * @param ms
+     * @return
+     */
+    private String getDate(long ms) {
+
+        long day = ms / (24 * 60 * 60 * 1000);
+        long hour = (ms / (60 * 60 * 1000) - day * 24);
+        long minute = ((ms / (60 * 1000)) - day * 24 * 60 - hour * 60);
+        long second = (ms / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60);
+
+        if (day > 0) {
+            return day + "澶�" + hour + "灏忔椂" + minute + "鍒嗛挓";
+        }
+        if (hour > 0) {
+            return hour + "灏忔椂" + minute + "鍒嗛挓";
+        }
+        if (minute > 0) {
+            return minute + "鍒嗛挓";
+        }
+        if (second > 0) {
+            return second + "绉�";
+        } else {
+            return 0 + "绉�";
+        }
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/service/impl/LeaveapplyServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/LeaveapplyServiceImpl.java
deleted file mode 100644
index 9b77f5f..0000000
--- a/flowable/src/main/java/com/ycl/service/impl/LeaveapplyServiceImpl.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package com.ycl.service.impl;
-
-import com.ycl.common.core.text.Convert;
-import com.ycl.service.ILeaveapplyService;
-import com.ycl.system.domain.Leaveapply;
-import com.ycl.mapper.LeaveapplyMapper;
-import lombok.RequiredArgsConstructor;
-import org.flowable.engine.HistoryService;
-import org.flowable.engine.IdentityService;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.history.HistoricProcessInstance;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.flowable.task.api.Task;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * 璇峰亣Service涓氬姟灞傚鐞�
- *
- * @author shenzhanwang
- * @date 2022-04-02
- */
-@Service
-@Transactional
-@RequiredArgsConstructor
-public class LeaveapplyServiceImpl implements ILeaveapplyService {
-
-    private final LeaveapplyMapper leaveapplyMapper;
-
-    private final RuntimeService runtimeService;
-
-    private final TaskService taskService;
-
-    private final IdentityService identityService;
-
-    private final HistoryService historyService;
-
-    /**
-     * 鏌ヨ璇峰亣
-     *
-     * @param id 璇峰亣涓婚敭
-     * @return 璇峰亣
-     */
-    @Override
-    public Leaveapply selectLeaveapplyById(Long id) {
-        return leaveapplyMapper.selectLeaveapplyById(id);
-    }
-
-    /**
-     * 鏌ヨ璇峰亣鍒楄〃
-     *
-     * @param leaveapply 璇峰亣
-     * @return 璇峰亣
-     */
-    @Override
-    public List<Leaveapply> selectLeaveapplyList(Leaveapply leaveapply) {
-        return leaveapplyMapper.selectLeaveapplyList(leaveapply);
-    }
-
-    /**
-     * 鏂板璇峰亣
-     *
-     * @param leaveapply 璇峰亣
-     * @return 缁撴灉
-     */
-    @Override
-    public int insertLeaveapply(Leaveapply leaveapply) {
-        int rows = leaveapplyMapper.insertLeaveapply(leaveapply);
-        // 鍙戣捣璇峰亣娴佺▼
-        identityService.setAuthenticatedUserId(leaveapply.getUserId());
-        HashMap<String, Object> variables = new HashMap<>();
-        variables.put("applyuserid", leaveapply.getUserId());
-        variables.put("deptleader", leaveapply.getDeptleader());
-        runtimeService.startProcessInstanceByKey("leave", String.valueOf(leaveapply.getId()), variables);
-        // 鑷姩瀹屾垚绗竴涓换鍔�
-        Task autoTask = taskService.createTaskQuery().processDefinitionKey("leave").processInstanceBusinessKey(String.valueOf(leaveapply.getId())).singleResult();
-        taskService.complete(autoTask.getId());
-        return rows;
-    }
-
-    /**
-     * 淇敼璇峰亣
-     *
-     * @param leaveapply 璇峰亣
-     * @return 缁撴灉
-     */
-    @Override
-    public int updateLeaveapply(Leaveapply leaveapply) {
-        return leaveapplyMapper.updateLeaveapply(leaveapply);
-    }
-
-    /**
-     * 鎵归噺鍒犻櫎璇峰亣
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑璇峰亣涓婚敭
-     * @return 缁撴灉
-     */
-    @Override
-    public int deleteLeaveapplyByIds(String ids) {
-        String[] keys = Convert.toStrArray(ids);
-        for (String key : keys) {
-            ProcessInstance process = runtimeService.createProcessInstanceQuery().processDefinitionKey("leave").processInstanceBusinessKey(key).singleResult();
-            if (process != null) {
-                runtimeService.deleteProcessInstance(process.getId(), "鍒犻櫎");
-            }
-            // 鍒犻櫎鍘嗗彶鏁版嵁
-            HistoricProcessInstance history = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("leave").processInstanceBusinessKey(key).singleResult();
-            if (history != null) {
-                historyService.deleteHistoricProcessInstance(history.getId());
-            }
-            leaveapplyMapper.deleteLeaveapplyById(Long.parseLong(key));
-        }
-        return keys.length;
-    }
-
-    /**
-     * 鍒犻櫎璇峰亣淇℃伅
-     *
-     * @param id 璇峰亣涓婚敭
-     * @return 缁撴灉
-     */
-    @Override
-    public int deleteLeaveapplyById(Long id) {
-        return leaveapplyMapper.deleteLeaveapplyById(id);
-    }
-}
diff --git a/flowable/src/main/java/com/ycl/service/impl/MeetingServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/MeetingServiceImpl.java
deleted file mode 100644
index 98793b9..0000000
--- a/flowable/src/main/java/com/ycl/service/impl/MeetingServiceImpl.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package com.ycl.service.impl;
-
-import com.ycl.common.core.text.Convert;
-import com.ycl.service.IMeetingService;
-import com.ycl.system.domain.Meeting;
-import com.ycl.mapper.MeetingMapper;
-import com.ycl.mapper.PurchaseMapper;
-import lombok.RequiredArgsConstructor;
-import org.flowable.engine.HistoryService;
-import org.flowable.engine.IdentityService;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.history.HistoricProcessInstance;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * 浼氳Service涓氬姟灞傚鐞�
- *
- * @author shenzhanwang
- * @date 2022-05-30
- */
-@Service
-@RequiredArgsConstructor
-@Transactional
-public class MeetingServiceImpl implements IMeetingService {
-
-    private final MeetingMapper meetingMapper;
-
-    private final PurchaseMapper purchaseMapper;
-
-    private final RuntimeService runtimeService;
-
-    private final TaskService taskService;
-
-    private final IdentityService identityService;
-
-    private final HistoryService historyService;
-
-    /**
-     * 鏌ヨ浼氳
-     *
-     * @param id 浼氳涓婚敭
-     * @return 浼氳
-     */
-    @Override
-    public Meeting selectMeetingById(Long id) {
-        return meetingMapper.selectMeetingById(id);
-    }
-
-    /**
-     * 鏌ヨ浼氳鍒楄〃
-     *
-     * @param meeting 浼氳
-     * @return 浼氳
-     */
-    @Override
-    public List<Meeting> selectMeetingList(Meeting meeting) {
-        return meetingMapper.selectMeetingList(meeting);
-    }
-
-    /**
-     * 鏂板浼氳
-     *
-     * @param meeting 浼氳
-     * @return 缁撴灉
-     */
-    @Override
-    public int insertMeeting(Meeting meeting) {
-        int row = meetingMapper.insertMeeting(meeting);
-        // 鍚姩浼氳娴佺▼
-        identityService.setAuthenticatedUserId(meeting.getHost());
-        HashMap<String, Object> variables = new HashMap<>();
-        variables.put("host", meeting.getHost());
-        String[] person = meeting.getPeoplelist().split(",");
-        variables.put("people", Arrays.asList(person));
-        runtimeService.startProcessInstanceByKey("meeting", String.valueOf(meeting.getId()), variables);
-        return row;
-    }
-
-    /**
-     * 淇敼浼氳
-     *
-     * @param meeting 浼氳
-     * @return 缁撴灉
-     */
-    @Override
-    public int updateMeeting(Meeting meeting) {
-        return meetingMapper.updateMeeting(meeting);
-    }
-
-    /**
-     * 鎵归噺鍒犻櫎浼氳
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑浼氳涓婚敭
-     * @return 缁撴灉
-     */
-    @Override
-    public int deleteMeetingByIds(String ids) {
-        String[] keys = Convert.toStrArray(ids);
-        for (String key : keys) {
-            ProcessInstance process = runtimeService.createProcessInstanceQuery().processDefinitionKey("meeting").processInstanceBusinessKey(key).singleResult();
-            if (process != null) {
-                runtimeService.deleteProcessInstance(process.getId(), "鍒犻櫎");
-            }
-            // 鍒犻櫎鍘嗗彶鏁版嵁
-            HistoricProcessInstance history = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("meeting").processInstanceBusinessKey(key).singleResult();
-            if (history != null) {
-                historyService.deleteHistoricProcessInstance(history.getId());
-            }
-            meetingMapper.deleteMeetingByIds(Convert.toStrArray(ids));
-        }
-        return keys.length;
-    }
-
-    /**
-     * 鍒犻櫎浼氳淇℃伅
-     *
-     * @param id 浼氳涓婚敭
-     * @return 缁撴灉
-     */
-    @Override
-    public int deleteMeetingById(Long id) {
-        return meetingMapper.deleteMeetingById(id);
-    }
-}
diff --git a/flowable/src/main/java/com/ycl/service/impl/PurchaseServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/PurchaseServiceImpl.java
deleted file mode 100644
index f9987db..0000000
--- a/flowable/src/main/java/com/ycl/service/impl/PurchaseServiceImpl.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package com.ycl.service.impl;
-
-import com.ycl.common.core.text.Convert;
-import com.ycl.service.IPurchaseService;
-import com.ycl.system.domain.Purchase;
-import com.ycl.mapper.PurchaseMapper;
-import lombok.RequiredArgsConstructor;
-import org.flowable.engine.HistoryService;
-import org.flowable.engine.IdentityService;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.TaskService;
-import org.flowable.engine.history.HistoricProcessInstance;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * 閲囪喘Service涓氬姟灞傚鐞�
- *
- * @author shenzhanwang
- * @date 2022-05-28
- */
-@Service
-@Transactional
-@RequiredArgsConstructor
-public class PurchaseServiceImpl implements IPurchaseService {
-
-    private final PurchaseMapper purchaseMapper;
-
-    private final RuntimeService runtimeService;
-
-    private final TaskService taskService;
-
-    private final IdentityService identityService;
-
-    private final HistoryService historyService;
-
-    /**
-     * 鏌ヨ閲囪喘
-     *
-     * @param id 閲囪喘涓婚敭
-     * @return 閲囪喘
-     */
-    @Override
-    public Purchase selectPurchaseById(Long id) {
-        return purchaseMapper.selectPurchaseById(id);
-    }
-
-    /**
-     * 鏌ヨ閲囪喘鍒楄〃
-     *
-     * @param purchase 閲囪喘
-     * @return 閲囪喘
-     */
-    @Override
-    public List<Purchase> selectPurchaseList(Purchase purchase) {
-        return purchaseMapper.selectPurchaseList(purchase);
-    }
-
-    /**
-     * 鏂板閲囪喘
-     *
-     * @param purchase 閲囪喘
-     * @return 缁撴灉
-     */
-    @Override
-    public int insertPurchase(Purchase purchase) {
-        int row = purchaseMapper.insertPurchase(purchase);
-        // 鍚姩閲囪喘娴佺▼
-        identityService.setAuthenticatedUserId(purchase.getApplyer());
-        HashMap<String, Object> variables = new HashMap<>();
-        variables.put("starter", purchase.getApplyer());
-        variables.put("purchasemanager", purchase.getPurchasemanager());
-        variables.put("financeName", purchase.getFinanceName());
-        variables.put("pay", purchase.getPay());
-        variables.put("managerName", purchase.getManagerName());
-        variables.put("money", Double.parseDouble(purchase.getTotal()));
-        runtimeService.startProcessInstanceByKey("purchase", String.valueOf(purchase.getId()), variables);
-        return row;
-    }
-
-    /**
-     * 淇敼閲囪喘
-     *
-     * @param purchase 閲囪喘
-     * @return 缁撴灉
-     */
-    @Override
-    public int updatePurchase(Purchase purchase) {
-        return purchaseMapper.updatePurchase(purchase);
-    }
-
-    /**
-     * 鎵归噺鍒犻櫎閲囪喘
-     *
-     * @param ids 闇�瑕佸垹闄ょ殑閲囪喘涓婚敭
-     * @return 缁撴灉
-     */
-    @Override
-    public int deletePurchaseByIds(String ids) {
-        String[] keys = Convert.toStrArray(ids);
-        for (String key : keys) {
-            ProcessInstance process = runtimeService.createProcessInstanceQuery().processDefinitionKey("purchase").processInstanceBusinessKey(key).singleResult();
-            if (process != null) {
-                runtimeService.deleteProcessInstance(process.getId(), "鍒犻櫎");
-            }
-            // 鍒犻櫎鍘嗗彶鏁版嵁
-            HistoricProcessInstance history = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("purchase").processInstanceBusinessKey(key).singleResult();
-            if (history != null) {
-                historyService.deleteHistoricProcessInstance(history.getId());
-            }
-            purchaseMapper.deletePurchaseByIds(Convert.toStrArray(ids));
-        }
-        return keys.length;
-    }
-
-    /**
-     * 鍒犻櫎閲囪喘淇℃伅
-     *
-     * @param id 閲囪喘涓婚敭
-     * @return 缁撴灉
-     */
-    @Override
-    public int deletePurchaseById(Long id) {
-        return purchaseMapper.deletePurchaseById(id);
-    }
-}
diff --git a/flowable/src/main/java/com/ycl/service/impl/SysDeployFormServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/SysDeployFormServiceImpl.java
new file mode 100644
index 0000000..20d6040
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/impl/SysDeployFormServiceImpl.java
@@ -0,0 +1,107 @@
+package com.ycl.service.impl;
+
+import com.ycl.domain.entity.SysDeployForm;
+import com.ycl.domain.entity.SysForm;
+import com.ycl.mapper.SysDeployFormMapper;
+import com.ycl.service.ISysDeployFormService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟Service涓氬姟灞傚鐞�
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Service
+@RequiredArgsConstructor
+public class SysDeployFormServiceImpl implements ISysDeployFormService {
+
+    private final SysDeployFormMapper sysDeployFormMapper;
+
+    /**
+     * 鏌ヨ娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param id 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟ID
+     * @return 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     */
+    @Override
+    public SysDeployForm selectSysDeployFormById(Long id) {
+        return sysDeployFormMapper.selectSysDeployFormById(id);
+    }
+
+    /**
+     * 鏌ヨ娴佺▼瀹炰緥鍏宠仈琛ㄥ崟鍒楄〃
+     *
+     * @param sysDeployForm 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     * @return 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     */
+    @Override
+    public List<SysDeployForm> selectSysDeployFormList(SysDeployForm sysDeployForm) {
+        return sysDeployFormMapper.selectSysDeployFormList(sysDeployForm);
+    }
+
+    /**
+     * 鏂板娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param sysDeployForm 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertSysDeployForm(SysDeployForm sysDeployForm) {
+        SysForm sysForm = sysDeployFormMapper.selectSysDeployFormByDeployId(sysDeployForm.getDeployId());
+        if (Objects.isNull(sysForm)) {
+            return sysDeployFormMapper.insertSysDeployForm(sysDeployForm);
+        } else {
+            return 1;
+        }
+    }
+
+    /**
+     * 淇敼娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param sysDeployForm 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateSysDeployForm(SysDeployForm sysDeployForm) {
+        return sysDeployFormMapper.updateSysDeployForm(sysDeployForm);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼瀹炰緥鍏宠仈琛ㄥ崟
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑娴佺▼瀹炰緥鍏宠仈琛ㄥ崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteSysDeployFormByIds(Long[] ids) {
+        return sysDeployFormMapper.deleteSysDeployFormByIds(ids);
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼瀹炰緥鍏宠仈琛ㄥ崟淇℃伅
+     *
+     * @param id 娴佺▼瀹炰緥鍏宠仈琛ㄥ崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteSysDeployFormById(Long id) {
+        return sysDeployFormMapper.deleteSysDeployFormById(id);
+    }
+
+    /**
+     * 鏌ヨ娴佺▼鎸傜潃鐨勮〃鍗�
+     *
+     * @param deployId
+     * @return
+     */
+    @Override
+    public SysForm selectSysDeployFormByDeployId(String deployId) {
+        return sysDeployFormMapper.selectSysDeployFormByDeployId(deployId);
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/service/impl/SysExpressionServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/SysExpressionServiceImpl.java
new file mode 100644
index 0000000..5af682e
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/impl/SysExpressionServiceImpl.java
@@ -0,0 +1,92 @@
+package com.ycl.service.impl;
+
+import com.ycl.common.utils.DateUtils;
+import com.ycl.domain.entity.SysExpression;
+import com.ycl.mapper.SysExpressionMapper;
+import com.ycl.service.ISysExpressionService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 娴佺▼杈惧紡Service涓氬姟灞傚鐞�
+ *
+ * @author ruoyi
+ * @date 2022-12-12
+ */
+@Service
+@RequiredArgsConstructor
+public class SysExpressionServiceImpl implements ISysExpressionService {
+
+    private final SysExpressionMapper sysExpressionMapper;
+
+    /**
+     * 鏌ヨ娴佺▼杈惧紡
+     *
+     * @param id 娴佺▼杈惧紡涓婚敭
+     * @return 娴佺▼杈惧紡
+     */
+    @Override
+    public SysExpression selectSysExpressionById(Long id) {
+        return sysExpressionMapper.selectSysExpressionById(id);
+    }
+
+    /**
+     * 鏌ヨ娴佺▼杈惧紡鍒楄〃
+     *
+     * @param sysExpression 娴佺▼杈惧紡
+     * @return 娴佺▼杈惧紡
+     */
+    @Override
+    public List<SysExpression> selectSysExpressionList(SysExpression sysExpression) {
+        return sysExpressionMapper.selectSysExpressionList(sysExpression);
+    }
+
+    /**
+     * 鏂板娴佺▼杈惧紡
+     *
+     * @param sysExpression 娴佺▼杈惧紡
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertSysExpression(SysExpression sysExpression) {
+        sysExpression.setCreateTime(DateUtils.getNowDate());
+        return sysExpressionMapper.insertSysExpression(sysExpression);
+    }
+
+    /**
+     * 淇敼娴佺▼杈惧紡
+     *
+     * @param sysExpression 娴佺▼杈惧紡
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateSysExpression(SysExpression sysExpression) {
+        sysExpression.setUpdateTime(DateUtils.getNowDate());
+        return sysExpressionMapper.updateSysExpression(sysExpression);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼杈惧紡
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑娴佺▼杈惧紡涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteSysExpressionByIds(Long[] ids) {
+        return sysExpressionMapper.deleteSysExpressionByIds(ids);
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼杈惧紡淇℃伅
+     *
+     * @param id 娴佺▼杈惧紡涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteSysExpressionById(Long id) {
+        return sysExpressionMapper.deleteSysExpressionById(id);
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/service/impl/SysFormServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/SysFormServiceImpl.java
new file mode 100644
index 0000000..e115f52
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/impl/SysFormServiceImpl.java
@@ -0,0 +1,92 @@
+package com.ycl.service.impl;
+
+import com.ycl.common.utils.DateUtils;
+import com.ycl.domain.entity.SysForm;
+import com.ycl.mapper.SysFormMapper;
+import com.ycl.service.ISysFormService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 娴佺▼琛ㄥ崟Service涓氬姟灞傚鐞�
+ *
+ * @author Tony
+ * @date 2021-04-03
+ */
+@Service
+@RequiredArgsConstructor
+public class SysFormServiceImpl implements ISysFormService {
+
+    private final SysFormMapper sysFormMapper;
+
+    /**
+     * 鏌ヨ娴佺▼琛ㄥ崟
+     *
+     * @param formId 娴佺▼琛ㄥ崟ID
+     * @return 娴佺▼琛ㄥ崟
+     */
+    @Override
+    public SysForm selectSysFormById(Long formId) {
+        return sysFormMapper.selectSysFormById(formId);
+    }
+
+    /**
+     * 鏌ヨ娴佺▼琛ㄥ崟鍒楄〃
+     *
+     * @param sysForm 娴佺▼琛ㄥ崟
+     * @return 娴佺▼琛ㄥ崟
+     */
+    @Override
+    public List<SysForm> selectSysFormList(SysForm sysForm) {
+        return sysFormMapper.selectSysFormList(sysForm);
+    }
+
+    /**
+     * 鏂板娴佺▼琛ㄥ崟
+     *
+     * @param sysForm 娴佺▼琛ㄥ崟
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertSysForm(SysForm sysForm) {
+        sysForm.setCreateTime(DateUtils.getNowDate());
+        return sysFormMapper.insertSysForm(sysForm);
+    }
+
+    /**
+     * 淇敼娴佺▼琛ㄥ崟
+     *
+     * @param sysForm 娴佺▼琛ㄥ崟
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateSysForm(SysForm sysForm) {
+        sysForm.setUpdateTime(DateUtils.getNowDate());
+        return sysFormMapper.updateSysForm(sysForm);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼琛ㄥ崟
+     *
+     * @param formIds 闇�瑕佸垹闄ょ殑娴佺▼琛ㄥ崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteSysFormByIds(Long[] formIds) {
+        return sysFormMapper.deleteSysFormByIds(formIds);
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼琛ㄥ崟淇℃伅
+     *
+     * @param formId 娴佺▼琛ㄥ崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteSysFormById(Long formId) {
+        return sysFormMapper.deleteSysFormById(formId);
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/service/impl/SysListenerServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/SysListenerServiceImpl.java
new file mode 100644
index 0000000..f0a6259
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/impl/SysListenerServiceImpl.java
@@ -0,0 +1,92 @@
+package com.ycl.service.impl;
+
+import com.ycl.common.utils.DateUtils;
+import com.ycl.domain.entity.SysListener;
+import com.ycl.mapper.SysListenerMapper;
+import com.ycl.service.ISysListenerService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 娴佺▼鐩戝惉Service涓氬姟灞傚鐞�
+ *
+ * @author Tony
+ * @date 2022-12-25
+ */
+@Service
+@RequiredArgsConstructor
+public class SysListenerServiceImpl implements ISysListenerService {
+
+    private final SysListenerMapper sysListenerMapper;
+
+    /**
+     * 鏌ヨ娴佺▼鐩戝惉
+     *
+     * @param id 娴佺▼鐩戝惉涓婚敭
+     * @return 娴佺▼鐩戝惉
+     */
+    @Override
+    public SysListener selectSysListenerById(Long id) {
+        return sysListenerMapper.selectSysListenerById(id);
+    }
+
+    /**
+     * 鏌ヨ娴佺▼鐩戝惉鍒楄〃
+     *
+     * @param sysListener 娴佺▼鐩戝惉
+     * @return 娴佺▼鐩戝惉
+     */
+    @Override
+    public List<SysListener> selectSysListenerList(SysListener sysListener) {
+        return sysListenerMapper.selectSysListenerList(sysListener);
+    }
+
+    /**
+     * 鏂板娴佺▼鐩戝惉
+     *
+     * @param sysListener 娴佺▼鐩戝惉
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertSysListener(SysListener sysListener) {
+        sysListener.setCreateTime(DateUtils.getNowDate());
+        return sysListenerMapper.insertSysListener(sysListener);
+    }
+
+    /**
+     * 淇敼娴佺▼鐩戝惉
+     *
+     * @param sysListener 娴佺▼鐩戝惉
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateSysListener(SysListener sysListener) {
+        sysListener.setUpdateTime(DateUtils.getNowDate());
+        return sysListenerMapper.updateSysListener(sysListener);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼鐩戝惉
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑娴佺▼鐩戝惉涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteSysListenerByIds(Long[] ids) {
+        return sysListenerMapper.deleteSysListenerByIds(ids);
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼鐩戝惉淇℃伅
+     *
+     * @param id 娴佺▼鐩戝惉涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteSysListenerById(Long id) {
+        return sysListenerMapper.deleteSysListenerById(id);
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/util/ActivitiTracingChart.java b/flowable/src/main/java/com/ycl/util/ActivitiTracingChart.java
deleted file mode 100644
index bb40ff2..0000000
--- a/flowable/src/main/java/com/ycl/util/ActivitiTracingChart.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.ycl.util;
-
-import org.apache.commons.lang3.StringUtils;
-import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.common.engine.impl.util.IoUtil;
-import org.flowable.engine.HistoryService;
-import org.flowable.engine.ProcessEngineConfiguration;
-import org.flowable.engine.RepositoryService;
-import org.flowable.engine.history.HistoricActivityInstance;
-import org.flowable.engine.history.HistoricProcessInstance;
-import org.flowable.image.ProcessDiagramGenerator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 娴佺▼杩借釜鍥�
- */
-@Component
-public class ActivitiTracingChart {
-
-    private static final Logger logger = LoggerFactory.getLogger(ActivitiTracingChart.class);
-
-
-    @Resource
-    private HistoryService historyService;
-
-    @Resource
-    private RepositoryService repositoryService;
-
-    @Resource
-    private ProcessEngineConfiguration processEngineConfiguration;
-
-    /**
-     * 鐢熸垚娴佺▼杩借釜鍥�
-     *
-     * @param processInstanceId 娴佺▼瀹炰緥id
-     * @param outputStream      杈撳嚭娴�
-     */
-    public void generateFlowChart(String processInstanceId, OutputStream outputStream) {
-            if (StringUtils.isEmpty(processInstanceId)) {
-                logger.error("processInstanceId is null");
-                return;
-            }
-            // 鑾峰彇鍘嗗彶娴佺▼瀹炰緥
-            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId)
-                .singleResult();
-            // 鑾峰彇娴佺▼涓凡缁忔墽琛岀殑鑺傜偣
-            String processDefinitionId = historicProcessInstance.getProcessDefinitionId();
-            List<String> highLightedActivities = new ArrayList<>();
-            // 鑾峰緱娲诲姩鐨勮妭鐐�
-            List<HistoricActivityInstance> highLightedActivityList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
-            List<String> highLightedFlows = new ArrayList<>();
-            for (HistoricActivityInstance tempActivity : highLightedActivityList) {
-                String activityId = tempActivity.getActivityId();
-                highLightedActivities.add(activityId);
-                if ("sequenceFlow".equals(tempActivity.getActivityType())) {
-                    highLightedFlows.add(tempActivity.getActivityId());
-                }
-            }
-            // 鑾峰彇娴佺▼鍥�
-            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
-            ProcessEngineConfiguration engConf = processEngineConfiguration.getProcessEngineConfiguration();
-
-            ProcessDiagramGenerator diagramGenerator = engConf.getProcessDiagramGenerator();
-            InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivities, highLightedFlows, "瀹嬩綋",
-                    "瀹嬩綋", "瀹嬩綋", engConf.getClassLoader(), 1.0, true);
-            byte[] buf = new byte[1024];
-            int length;
-            try {
-                while ((length = in.read(buf)) != -1) {
-                    outputStream.write(buf, 0, length);
-                }
-            } catch (IOException e) {
-                e.printStackTrace();
-            } finally {
-                IoUtil.closeSilently(outputStream);
-                IoUtil.closeSilently(in);
-            }
-    }
-}
diff --git a/flowable/src/main/resources/mapper/ActRuExecutionMapper.xml b/flowable/src/main/resources/mapper/ActRuExecutionMapper.xml
deleted file mode 100644
index cfab5de..0000000
--- a/flowable/src/main/resources/mapper/ActRuExecutionMapper.xml
+++ /dev/null
@@ -1,213 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ycl.mapper.ActRuExecutionMapper">
-
-    <resultMap type="ActRuExecution" id="ActRuExecutionResult">
-        <result property="id"    column="ID_"    />
-        <result property="rev"    column="REV_"    />
-        <result property="procInstId"    column="PROC_INST_ID_"    />
-        <result property="businessKey"    column="BUSINESS_KEY_"    />
-        <result property="parentId"    column="PARENT_ID_"    />
-        <result property="procDefId"    column="PROC_DEF_ID_"    />
-        <result property="superExec"    column="SUPER_EXEC_"    />
-        <result property="rootProcInstId"    column="ROOT_PROC_INST_ID_"    />
-        <result property="actId"    column="ACT_ID_"    />
-        <result property="isActive"    column="IS_ACTIVE_"    />
-        <result property="isConcurrent"    column="IS_CONCURRENT_"    />
-        <result property="isScope"    column="IS_SCOPE_"    />
-        <result property="isEventScope"    column="IS_EVENT_SCOPE_"    />
-        <result property="isMiRoot"    column="IS_MI_ROOT_"    />
-        <result property="suspensionState"    column="SUSPENSION_STATE_"    />
-        <result property="cachedEntState"    column="CACHED_ENT_STATE_"    />
-        <result property="tenantId"    column="TENANT_ID_"    />
-        <result property="name"    column="NAME_"    />
-        <result property="startTime"    column="START_TIME_"    />
-        <result property="startUserId"    column="START_USER_ID_"    />
-        <result property="lockTime"    column="LOCK_TIME_"    />
-        <result property="isCountEnabled"    column="IS_COUNT_ENABLED_"    />
-        <result property="evtSubscrCount"    column="EVT_SUBSCR_COUNT_"    />
-        <result property="taskCount"    column="TASK_COUNT_"    />
-        <result property="jobCount"    column="JOB_COUNT_"    />
-        <result property="timerJobCount"    column="TIMER_JOB_COUNT_"    />
-        <result property="suspJobCount"    column="SUSP_JOB_COUNT_"    />
-        <result property="deadletterJobCount"    column="DEADLETTER_JOB_COUNT_"    />
-        <result property="varCount"    column="VAR_COUNT_"    />
-        <result property="idLinkCount"    column="ID_LINK_COUNT_"    />
-    </resultMap>
-
-    <sql id="selectActRuExecutionVo">
-        select ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_, PARENT_ID_, PROC_DEF_ID_, SUPER_EXEC_, ROOT_PROC_INST_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_, IS_EVENT_SCOPE_, IS_MI_ROOT_, SUSPENSION_STATE_, CACHED_ENT_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, LOCK_TIME_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_, TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_ from act_ru_execution
-    </sql>
-
-    <select id="selectActRuExecutionList" parameterType="ActRuExecution" resultMap="ActRuExecutionResult">
-        <include refid="selectActRuExecutionVo"/>
-        <where>
-            <if test="rev != null "> and REV_ = #{rev}</if>
-            <if test="procInstId != null  and procInstId != ''"> and PROC_INST_ID_ = #{procInstId}</if>
-            <if test="businessKey != null  and businessKey != ''"> and BUSINESS_KEY_ = #{businessKey}</if>
-            <if test="parentId != null  and parentId != ''"> and PARENT_ID_ = #{parentId}</if>
-            <if test="procDefId != null  and procDefId != ''"> and PROC_DEF_ID_ = #{procDefId}</if>
-            <if test="superExec != null  and superExec != ''"> and SUPER_EXEC_ = #{superExec}</if>
-            <if test="rootProcInstId != null  and rootProcInstId != ''"> and ROOT_PROC_INST_ID_ = #{rootProcInstId}</if>
-            <if test="actId != null  and actId != ''"> and ACT_ID_ = #{actId}</if>
-            <if test="isActive != null "> and IS_ACTIVE_ = #{isActive}</if>
-            <if test="isConcurrent != null "> and IS_CONCURRENT_ = #{isConcurrent}</if>
-            <if test="isScope != null "> and IS_SCOPE_ = #{isScope}</if>
-            <if test="isEventScope != null "> and IS_EVENT_SCOPE_ = #{isEventScope}</if>
-            <if test="isMiRoot != null "> and IS_MI_ROOT_ = #{isMiRoot}</if>
-            <if test="suspensionState != null "> and SUSPENSION_STATE_ = #{suspensionState}</if>
-            <if test="cachedEntState != null "> and CACHED_ENT_STATE_ = #{cachedEntState}</if>
-            <if test="tenantId != null  and tenantId != ''"> and TENANT_ID_ = #{tenantId}</if>
-            <if test="name != null  and name != ''"> and NAME_ = #{name}</if>
-            <if test="startTime != null "> and START_TIME_ = #{startTime}</if>
-            <if test="startUserId != null  and startUserId != ''"> and START_USER_ID_ = #{startUserId}</if>
-            <if test="lockTime != null "> and LOCK_TIME_ = #{lockTime}</if>
-            <if test="isCountEnabled != null "> and IS_COUNT_ENABLED_ = #{isCountEnabled}</if>
-            <if test="evtSubscrCount != null "> and EVT_SUBSCR_COUNT_ = #{evtSubscrCount}</if>
-            <if test="taskCount != null "> and TASK_COUNT_ = #{taskCount}</if>
-            <if test="jobCount != null "> and JOB_COUNT_ = #{jobCount}</if>
-            <if test="timerJobCount != null "> and TIMER_JOB_COUNT_ = #{timerJobCount}</if>
-            <if test="suspJobCount != null "> and SUSP_JOB_COUNT_ = #{suspJobCount}</if>
-            <if test="deadletterJobCount != null "> and DEADLETTER_JOB_COUNT_ = #{deadletterJobCount}</if>
-            <if test="varCount != null "> and VAR_COUNT_ = #{varCount}</if>
-            <if test="idLinkCount != null "> and ID_LINK_COUNT_ = #{idLinkCount}</if>
-        </where>
-    </select>
-
-    <select id="selectActRuExecutionListByProcessName" resultMap="ActRuExecutionResult">
-        SELECT
-            act_ru_execution.*
-        FROM
-            act_ru_execution
-                LEFT JOIN act_re_procdef ON act_ru_execution.PROC_DEF_ID_ = act_re_procdef.ID_
-        WHERE
-            1=1
-        <if test="name != null ">
-            and act_re_procdef.NAME_ = #{name}
-        </if>
-        order by proc_inst_id_
-    </select>
-
-    <select id="selectActRuExecutionById" parameterType="String" resultMap="ActRuExecutionResult">
-        <include refid="selectActRuExecutionVo"/>
-        where ID_ = #{id}
-    </select>
-
-    <insert id="insertActRuExecution" parameterType="ActRuExecution">
-        insert into act_ru_execution
-        <trim prefix="(" suffix=")" suffixOverrides=",">
-            <if test="id != null">ID_,</if>
-            <if test="rev != null">REV_,</if>
-            <if test="procInstId != null">PROC_INST_ID_,</if>
-            <if test="businessKey != null">BUSINESS_KEY_,</if>
-            <if test="parentId != null">PARENT_ID_,</if>
-            <if test="procDefId != null">PROC_DEF_ID_,</if>
-            <if test="superExec != null">SUPER_EXEC_,</if>
-            <if test="rootProcInstId != null">ROOT_PROC_INST_ID_,</if>
-            <if test="actId != null">ACT_ID_,</if>
-            <if test="isActive != null">IS_ACTIVE_,</if>
-            <if test="isConcurrent != null">IS_CONCURRENT_,</if>
-            <if test="isScope != null">IS_SCOPE_,</if>
-            <if test="isEventScope != null">IS_EVENT_SCOPE_,</if>
-            <if test="isMiRoot != null">IS_MI_ROOT_,</if>
-            <if test="suspensionState != null">SUSPENSION_STATE_,</if>
-            <if test="cachedEntState != null">CACHED_ENT_STATE_,</if>
-            <if test="tenantId != null">TENANT_ID_,</if>
-            <if test="name != null">NAME_,</if>
-            <if test="startTime != null">START_TIME_,</if>
-            <if test="startUserId != null">START_USER_ID_,</if>
-            <if test="lockTime != null">LOCK_TIME_,</if>
-            <if test="isCountEnabled != null">IS_COUNT_ENABLED_,</if>
-            <if test="evtSubscrCount != null">EVT_SUBSCR_COUNT_,</if>
-            <if test="taskCount != null">TASK_COUNT_,</if>
-            <if test="jobCount != null">JOB_COUNT_,</if>
-            <if test="timerJobCount != null">TIMER_JOB_COUNT_,</if>
-            <if test="suspJobCount != null">SUSP_JOB_COUNT_,</if>
-            <if test="deadletterJobCount != null">DEADLETTER_JOB_COUNT_,</if>
-            <if test="varCount != null">VAR_COUNT_,</if>
-            <if test="idLinkCount != null">ID_LINK_COUNT_,</if>
-         </trim>
-        <trim prefix="values (" suffix=")" suffixOverrides=",">
-            <if test="id != null">#{id},</if>
-            <if test="rev != null">#{rev},</if>
-            <if test="procInstId != null">#{procInstId},</if>
-            <if test="businessKey != null">#{businessKey},</if>
-            <if test="parentId != null">#{parentId},</if>
-            <if test="procDefId != null">#{procDefId},</if>
-            <if test="superExec != null">#{superExec},</if>
-            <if test="rootProcInstId != null">#{rootProcInstId},</if>
-            <if test="actId != null">#{actId},</if>
-            <if test="isActive != null">#{isActive},</if>
-            <if test="isConcurrent != null">#{isConcurrent},</if>
-            <if test="isScope != null">#{isScope},</if>
-            <if test="isEventScope != null">#{isEventScope},</if>
-            <if test="isMiRoot != null">#{isMiRoot},</if>
-            <if test="suspensionState != null">#{suspensionState},</if>
-            <if test="cachedEntState != null">#{cachedEntState},</if>
-            <if test="tenantId != null">#{tenantId},</if>
-            <if test="name != null">#{name},</if>
-            <if test="startTime != null">#{startTime},</if>
-            <if test="startUserId != null">#{startUserId},</if>
-            <if test="lockTime != null">#{lockTime},</if>
-            <if test="isCountEnabled != null">#{isCountEnabled},</if>
-            <if test="evtSubscrCount != null">#{evtSubscrCount},</if>
-            <if test="taskCount != null">#{taskCount},</if>
-            <if test="jobCount != null">#{jobCount},</if>
-            <if test="timerJobCount != null">#{timerJobCount},</if>
-            <if test="suspJobCount != null">#{suspJobCount},</if>
-            <if test="deadletterJobCount != null">#{deadletterJobCount},</if>
-            <if test="varCount != null">#{varCount},</if>
-            <if test="idLinkCount != null">#{idLinkCount},</if>
-         </trim>
-    </insert>
-
-    <update id="updateActRuExecution" parameterType="ActRuExecution">
-        update act_ru_execution
-        <trim prefix="SET" suffixOverrides=",">
-            <if test="rev != null">REV_ = #{rev},</if>
-            <if test="procInstId != null">PROC_INST_ID_ = #{procInstId},</if>
-            <if test="businessKey != null">BUSINESS_KEY_ = #{businessKey},</if>
-            <if test="parentId != null">PARENT_ID_ = #{parentId},</if>
-            <if test="procDefId != null">PROC_DEF_ID_ = #{procDefId},</if>
-            <if test="superExec != null">SUPER_EXEC_ = #{superExec},</if>
-            <if test="rootProcInstId != null">ROOT_PROC_INST_ID_ = #{rootProcInstId},</if>
-            <if test="actId != null">ACT_ID_ = #{actId},</if>
-            <if test="isActive != null">IS_ACTIVE_ = #{isActive},</if>
-            <if test="isConcurrent != null">IS_CONCURRENT_ = #{isConcurrent},</if>
-            <if test="isScope != null">IS_SCOPE_ = #{isScope},</if>
-            <if test="isEventScope != null">IS_EVENT_SCOPE_ = #{isEventScope},</if>
-            <if test="isMiRoot != null">IS_MI_ROOT_ = #{isMiRoot},</if>
-            <if test="suspensionState != null">SUSPENSION_STATE_ = #{suspensionState},</if>
-            <if test="cachedEntState != null">CACHED_ENT_STATE_ = #{cachedEntState},</if>
-            <if test="tenantId != null">TENANT_ID_ = #{tenantId},</if>
-            <if test="name != null">NAME_ = #{name},</if>
-            <if test="startTime != null">START_TIME_ = #{startTime},</if>
-            <if test="startUserId != null">START_USER_ID_ = #{startUserId},</if>
-            <if test="lockTime != null">LOCK_TIME_ = #{lockTime},</if>
-            <if test="isCountEnabled != null">IS_COUNT_ENABLED_ = #{isCountEnabled},</if>
-            <if test="evtSubscrCount != null">EVT_SUBSCR_COUNT_ = #{evtSubscrCount},</if>
-            <if test="taskCount != null">TASK_COUNT_ = #{taskCount},</if>
-            <if test="jobCount != null">JOB_COUNT_ = #{jobCount},</if>
-            <if test="timerJobCount != null">TIMER_JOB_COUNT_ = #{timerJobCount},</if>
-            <if test="suspJobCount != null">SUSP_JOB_COUNT_ = #{suspJobCount},</if>
-            <if test="deadletterJobCount != null">DEADLETTER_JOB_COUNT_ = #{deadletterJobCount},</if>
-            <if test="varCount != null">VAR_COUNT_ = #{varCount},</if>
-            <if test="idLinkCount != null">ID_LINK_COUNT_ = #{idLinkCount},</if>
-        </trim>
-        where ID_ = #{id}
-    </update>
-
-    <delete id="deleteActRuExecutionById" parameterType="String">
-        delete from act_ru_execution where ID_ = #{id}
-    </delete>
-
-    <delete id="deleteActRuExecutionByIds" parameterType="String">
-        delete from act_ru_execution where ID_ in
-        <foreach item="id" collection="array" open="(" separator="," close=")">
-            #{id}
-        </foreach>
-    </delete>
-
-</mapper>
diff --git a/flowable/src/main/resources/mapper/FlowDeployMapper.xml b/flowable/src/main/resources/mapper/FlowDeployMapper.xml
new file mode 100644
index 0000000..754f6ce
--- /dev/null
+++ b/flowable/src/main/resources/mapper/FlowDeployMapper.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ycl.mapper.FlowDeployMapper">
+
+
+    <select id="selectDeployList" resultType="com.ycl.domain.dto.FlowProcDefDto">
+
+        SELECT
+            rp.id_ as id,
+            rp.deployment_id_ as deploymentId,
+            rd.name_ as name,
+            rd.category_ as category,
+            rp.key_ as flowKey,
+            rp.version_ as version,
+            rp.suspension_state_ as suspensionState,
+            rd.deploy_time_  as deploymentTime
+        FROM
+            act_re_procdef rp
+                LEFT JOIN act_re_deployment rd ON rp.deployment_id_ = rd.id_
+        <where>
+            <if test="name != null and name != ''">
+               and rd.name_ like concat('%', #{name}, '%')
+            </if>
+        </where>
+        order by rd.deploy_time_ desc
+    </select>
+
+
+</mapper>
diff --git a/flowable/src/main/resources/mapper/LeaveapplyMapper.xml b/flowable/src/main/resources/mapper/LeaveapplyMapper.xml
deleted file mode 100644
index 9fb53f6..0000000
--- a/flowable/src/main/resources/mapper/LeaveapplyMapper.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ycl.mapper.LeaveapplyMapper">
-
-    <resultMap type="Leaveapply" id="LeaveapplyResult">
-        <result property="id"    column="id"    />
-        <result property="userId"    column="user_id"    />
-        <result property="startTime"    column="start_time"    />
-        <result property="endTime"    column="end_time"    />
-        <result property="leaveType"    column="leave_type"    />
-        <result property="reason"    column="reason"    />
-        <result property="applyTime"    column="apply_time"    />
-        <result property="realityStartTime"    column="reality_start_time"    />
-        <result property="realityEndTime"    column="reality_end_time"    />
-    </resultMap>
-
-    <sql id="selectLeaveapplyVo">
-        select id, user_id, start_time, end_time, leave_type, reason, apply_time, reality_start_time, reality_end_time from leaveapply
-    </sql>
-
-    <select id="selectLeaveapplyList" parameterType="Leaveapply" resultMap="LeaveapplyResult">
-        <include refid="selectLeaveapplyVo"/>
-        <where>
-            <if test="leaveType != null  and leaveType != ''"> and leave_type = #{leaveType}</if>
-            <if test="params.beginApplyTime != null and params.beginApplyTime != '' and params.endApplyTime != null and params.endApplyTime != ''"> and apply_time between #{params.beginApplyTime} and #{params.endApplyTime}</if>
-            <if test="userId != null  and userId != ''"> and user_id = #{userId}</if>
-        </where>
-    </select>
-
-    <select id="selectLeaveapplyById" parameterType="Long" resultMap="LeaveapplyResult">
-        <include refid="selectLeaveapplyVo"/>
-        where id = #{id}
-    </select>
-
-    <insert id="insertLeaveapply" parameterType="Leaveapply" useGeneratedKeys="true" keyProperty="id">
-        insert into leaveapply
-        <trim prefix="(" suffix=")" suffixOverrides=",">
-            <if test="userId != null">user_id,</if>
-            <if test="startTime != null">start_time,</if>
-            <if test="endTime != null">end_time,</if>
-            <if test="leaveType != null">leave_type,</if>
-            <if test="reason != null">reason,</if>
-            <if test="applyTime != null">apply_time,</if>
-            <if test="realityStartTime != null">reality_start_time,</if>
-            <if test="realityEndTime != null">reality_end_time,</if>
-         </trim>
-        <trim prefix="values (" suffix=")" suffixOverrides=",">
-            <if test="userId != null">#{userId},</if>
-            <if test="startTime != null">#{startTime},</if>
-            <if test="endTime != null">#{endTime},</if>
-            <if test="leaveType != null">#{leaveType},</if>
-            <if test="reason != null">#{reason},</if>
-            <if test="applyTime != null">#{applyTime},</if>
-            <if test="realityStartTime != null">#{realityStartTime},</if>
-            <if test="realityEndTime != null">#{realityEndTime},</if>
-         </trim>
-    </insert>
-
-    <update id="updateLeaveapply" parameterType="Leaveapply">
-        update leaveapply
-        <trim prefix="SET" suffixOverrides=",">
-            <if test="userId != null">user_id = #{userId},</if>
-            <if test="startTime != null">start_time = #{startTime},</if>
-            <if test="endTime != null">end_time = #{endTime},</if>
-            <if test="leaveType != null">leave_type = #{leaveType},</if>
-            <if test="reason != null">reason = #{reason},</if>
-            <if test="applyTime != null">apply_time = #{applyTime},</if>
-            <if test="realityStartTime != null">reality_start_time = #{realityStartTime},</if>
-            <if test="realityEndTime != null">reality_end_time = #{realityEndTime},</if>
-        </trim>
-        where id = #{id}
-    </update>
-
-    <delete id="deleteLeaveapplyById" parameterType="Long">
-        delete from leaveapply where id = #{id}
-    </delete>
-
-    <delete id="deleteLeaveapplyByIds" parameterType="String">
-        delete from leaveapply where id in
-        <foreach item="id" collection="array" open="(" separator="," close=")">
-            #{id}
-        </foreach>
-    </delete>
-
-</mapper>
diff --git a/flowable/src/main/resources/mapper/MeetingMapper.xml b/flowable/src/main/resources/mapper/MeetingMapper.xml
deleted file mode 100644
index 617cf9a..0000000
--- a/flowable/src/main/resources/mapper/MeetingMapper.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ycl.mapper.MeetingMapper">
-
-    <resultMap type="Meeting" id="MeetingResult">
-        <result property="id"    column="id"    />
-        <result property="topic"    column="topic"    />
-        <result property="host"    column="host"    />
-        <result property="place"    column="place"    />
-        <result property="peoplelist"    column="peoplelist"    />
-        <result property="startTime"    column="start_time"    />
-        <result property="endTime"    column="end_time"    />
-        <result property="content"    column="content"    />
-    </resultMap>
-
-    <sql id="selectMeetingVo">
-        select id, topic, host, place, peoplelist, start_time, end_time, content from meeting
-    </sql>
-
-    <select id="selectMeetingList" parameterType="Meeting" resultMap="MeetingResult">
-        <include refid="selectMeetingVo"/>
-        <where>
-            <if test="topic != null  and topic != ''"> and topic = #{topic}</if>
-            <if test="host != null  and host != ''"> and host = #{host}</if>
-            <if test="place != null  and place != ''"> and place = #{place}</if>
-            <if test="peoplelist != null  and peoplelist != ''"> and peoplelist like concat('%', #{peoplelist}, '%')</if>
-            <if test="content != null  and content != ''"> and content = #{content}</if>
-        </where>
-    </select>
-
-    <select id="selectMeetingById" parameterType="Long" resultMap="MeetingResult">
-        <include refid="selectMeetingVo"/>
-        where id = #{id}
-    </select>
-
-    <insert id="insertMeeting" parameterType="Meeting" useGeneratedKeys="true" keyProperty="id">
-        insert into meeting
-        <trim prefix="(" suffix=")" suffixOverrides=",">
-            <if test="topic != null">topic,</if>
-            <if test="host != null">host,</if>
-            <if test="place != null">place,</if>
-            <if test="peoplelist != null">peoplelist,</if>
-            <if test="startTime != null">start_time,</if>
-            <if test="endTime != null">end_time,</if>
-            <if test="content != null">content,</if>
-         </trim>
-        <trim prefix="values (" suffix=")" suffixOverrides=",">
-            <if test="topic != null">#{topic},</if>
-            <if test="host != null">#{host},</if>
-            <if test="place != null">#{place},</if>
-            <if test="peoplelist != null">#{peoplelist},</if>
-            <if test="startTime != null">#{startTime},</if>
-            <if test="endTime != null">#{endTime},</if>
-            <if test="content != null">#{content},</if>
-         </trim>
-    </insert>
-
-    <update id="updateMeeting" parameterType="Meeting">
-        update meeting
-        <trim prefix="SET" suffixOverrides=",">
-            <if test="topic != null">topic = #{topic},</if>
-            <if test="host != null">host = #{host},</if>
-            <if test="place != null">place = #{place},</if>
-            <if test="peoplelist != null">peoplelist = #{peoplelist},</if>
-            <if test="startTime != null">start_time = #{startTime},</if>
-            <if test="endTime != null">end_time = #{endTime},</if>
-            <if test="content != null">content = #{content},</if>
-        </trim>
-        where id = #{id}
-    </update>
-
-    <delete id="deleteMeetingById" parameterType="Long">
-        delete from meeting where id = #{id}
-    </delete>
-
-    <delete id="deleteMeetingByIds" parameterType="String">
-        delete from meeting where id in
-        <foreach item="id" collection="array" open="(" separator="," close=")">
-            #{id}
-        </foreach>
-    </delete>
-
-</mapper>
diff --git a/flowable/src/main/resources/mapper/PurchaseMapper.xml b/flowable/src/main/resources/mapper/PurchaseMapper.xml
deleted file mode 100644
index 73097d8..0000000
--- a/flowable/src/main/resources/mapper/PurchaseMapper.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ycl.mapper.PurchaseMapper">
-
-    <resultMap type="Purchase" id="PurchaseResult">
-        <result property="id"    column="id"    />
-        <result property="itemlist"    column="itemlist"    />
-        <result property="total"    column="total"    />
-        <result property="applytime"    column="applytime"    />
-        <result property="applyer"    column="applyer"    />
-    </resultMap>
-
-    <sql id="selectPurchaseVo">
-        select id, itemlist, total, applytime, applyer from purchase
-    </sql>
-
-    <select id="selectPurchaseList" parameterType="Purchase" resultMap="PurchaseResult">
-        <include refid="selectPurchaseVo"/>
-        <where>
-            <if test="itemlist != null  and itemlist != ''"> and itemlist = #{itemlist}</if>
-            <if test="total != null  and total != ''"> and total = #{total}</if>
-            <if test="params.beginApplyTime != null and params.beginApplyTime != '' and params.endApplyTime != null and params.endApplyTime != ''"> and applytime between #{params.beginApplyTime} and #{params.endApplyTime}</if>
-            <if test="applyer != null  and applyer != ''"> and applyer = #{applyer}</if>
-        </where>
-    </select>
-
-    <select id="selectPurchaseById" parameterType="Long" resultMap="PurchaseResult">
-        <include refid="selectPurchaseVo"/>
-        where id = #{id}
-    </select>
-
-    <insert id="insertPurchase" parameterType="Purchase" useGeneratedKeys="true" keyProperty="id">
-        insert into purchase
-        <trim prefix="(" suffix=")" suffixOverrides=",">
-            <if test="itemlist != null and itemlist != ''">itemlist,</if>
-            <if test="total != null and total != ''">total,</if>
-            <if test="applytime != null">applytime,</if>
-            <if test="applyer != null">applyer,</if>
-         </trim>
-        <trim prefix="values (" suffix=")" suffixOverrides=",">
-            <if test="itemlist != null and itemlist != ''">#{itemlist},</if>
-            <if test="total != null and total != ''">#{total},</if>
-            <if test="applytime != null">#{applytime},</if>
-            <if test="applyer != null">#{applyer},</if>
-         </trim>
-    </insert>
-
-    <update id="updatePurchase" parameterType="Purchase">
-        update purchase
-        <trim prefix="SET" suffixOverrides=",">
-            <if test="itemlist != null and itemlist != ''">itemlist = #{itemlist},</if>
-            <if test="total != null and total != ''">total = #{total},</if>
-            <if test="applytime != null">applytime = #{applytime},</if>
-            <if test="applyer != null">applyer = #{applyer},</if>
-        </trim>
-        where id = #{id}
-    </update>
-
-    <delete id="deletePurchaseById" parameterType="Long">
-        delete from purchase where id = #{id}
-    </delete>
-
-    <delete id="deletePurchaseByIds" parameterType="String">
-        delete from purchase where id in
-        <foreach item="id" collection="array" open="(" separator="," close=")">
-            #{id}
-        </foreach>
-    </delete>
-
-</mapper>
diff --git a/flowable/src/main/resources/mapper/SysDeployFormMapper.xml b/flowable/src/main/resources/mapper/SysDeployFormMapper.xml
new file mode 100644
index 0000000..184af63
--- /dev/null
+++ b/flowable/src/main/resources/mapper/SysDeployFormMapper.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ycl.mapper.SysDeployFormMapper">
+
+    <resultMap type="com.ycl.domain.entity.SysDeployForm" id="SysDeployFormResult">
+        <result property="id"    column="id"    />
+        <result property="formId"    column="form_id"    />
+        <result property="deployId"    column="deploy_id"    />
+    </resultMap>
+
+    <sql id="selectSysDeployFormVo">
+        select id, form_id, deploy_id from sys_deploy_form
+    </sql>
+
+    <select id="selectSysDeployFormList" parameterType="com.ycl.domain.entity.SysDeployForm" resultMap="SysDeployFormResult">
+        <include refid="selectSysDeployFormVo"/>
+        <where>
+            <if test="formId != null "> and form_id = #{formId}</if>
+            <if test="deployId != null  and deployId != ''"> and deploy_id = #{deployId}</if>
+        </where>
+    </select>
+
+    <select id="selectSysDeployFormById" parameterType="Long" resultMap="SysDeployFormResult">
+        <include refid="selectSysDeployFormVo"/>
+        where id = #{id}
+    </select>
+
+    <select id="selectSysDeployFormByDeployId" resultType="com.ycl.domain.entity.SysForm">
+        select t1.form_content as formContent,t1.form_name as formName,t1.form_id as formId from sys_form t1 left join sys_deploy_form t2 on t1.form_id = t2.form_id
+        where t2.deploy_id = #{deployId} limit 1
+    </select>
+
+    <insert id="insertSysDeployForm" parameterType="com.ycl.domain.entity.SysDeployForm" useGeneratedKeys="true" keyProperty="id">
+        insert into sys_deploy_form
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="formId != null">form_id,</if>
+            <if test="deployId != null">deploy_id,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="formId != null">#{formId},</if>
+            <if test="deployId != null">#{deployId},</if>
+         </trim>
+    </insert>
+
+    <update id="updateSysDeployForm" parameterType="com.ycl.domain.entity.SysDeployForm">
+        update sys_deploy_form
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="formId != null">form_id = #{formId},</if>
+            <if test="deployId != null">deploy_id = #{deployId},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteSysDeployFormById" parameterType="Long">
+        delete from sys_deploy_form where id = #{id}
+    </delete>
+
+    <delete id="deleteSysDeployFormByIds" parameterType="String">
+        delete from sys_deploy_form where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>
diff --git a/flowable/src/main/resources/mapper/SysExpressionMapper.xml b/flowable/src/main/resources/mapper/SysExpressionMapper.xml
new file mode 100644
index 0000000..f896043
--- /dev/null
+++ b/flowable/src/main/resources/mapper/SysExpressionMapper.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ycl.mapper.SysExpressionMapper">
+
+    <resultMap type="com.ycl.domain.entity.SysExpression" id="SysExpressionResult">
+        <result property="id"    column="id"    />
+        <result property="name"    column="name"    />
+        <result property="expression"    column="expression"    />
+        <result property="dataType" column="data_type"/>
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="status"    column="status"    />
+        <result property="remark"    column="remark"    />
+    </resultMap>
+
+    <sql id="selectSysExpressionVo">
+        select id, name, expression, data_type,create_time, update_time, create_by, update_by, status, remark from sys_expression
+    </sql>
+
+    <select id="selectSysExpressionList" parameterType="com.ycl.domain.entity.SysExpression" resultMap="SysExpressionResult">
+        <include refid="selectSysExpressionVo"/>
+        <where>
+            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
+            <if test="expression != null  and expression != ''"> and expression = #{expression}</if>
+            <if test="status != null "> and status = #{status}</if>
+        </where>
+    </select>
+
+    <select id="selectSysExpressionById" parameterType="Long" resultMap="SysExpressionResult">
+        <include refid="selectSysExpressionVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertSysExpression" parameterType="com.ycl.domain.entity.SysExpression" useGeneratedKeys="true" keyProperty="id">
+        insert into sys_expression
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="name != null">name,</if>
+            <if test="expression != null">expression,</if>
+            <if test="dataType != null">data_type,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="status != null">status,</if>
+            <if test="remark != null">remark,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="name != null">#{name},</if>
+            <if test="expression != null">#{expression},</if>
+            <if test="dataType != null">#{dataType},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="status != null">#{status},</if>
+            <if test="remark != null">#{remark},</if>
+         </trim>
+    </insert>
+
+    <update id="updateSysExpression" parameterType="com.ycl.domain.entity.SysExpression">
+        update sys_expression
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="name != null">name = #{name},</if>
+            <if test="expression != null">expression = #{expression},</if>
+            <if test="dataType != null">data_type = #{dataType},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="remark != null">remark = #{remark},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteSysExpressionById" parameterType="Long">
+        delete from sys_expression where id = #{id}
+    </delete>
+
+    <delete id="deleteSysExpressionByIds" parameterType="String">
+        delete from sys_expression where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>
diff --git a/flowable/src/main/resources/mapper/SysFormMapper.xml b/flowable/src/main/resources/mapper/SysFormMapper.xml
new file mode 100644
index 0000000..99c099d
--- /dev/null
+++ b/flowable/src/main/resources/mapper/SysFormMapper.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ycl.mapper.SysFormMapper">
+
+    <resultMap type="com.ycl.domain.entity.SysForm" id="SysFormResult">
+        <result property="formId"    column="form_id"    />
+        <result property="formName"    column="form_name"    />
+        <result property="formContent"    column="form_content"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="remark"    column="remark"    />
+    </resultMap>
+
+    <sql id="selectSysFormVo">
+        select form_id, form_name, form_content, create_time, update_time, create_by, update_by, remark from sys_form
+    </sql>
+
+    <select id="selectSysFormList" parameterType="com.ycl.domain.entity.SysForm" resultMap="SysFormResult">
+        <include refid="selectSysFormVo"/>
+        <where>
+            <if test="formName != null  and formName != ''"> and form_name like concat('%', #{formName}, '%')</if>
+            <if test="formContent != null  and formContent != ''"> and form_content = #{formContent}</if>
+        </where>
+        order by create_time desc
+    </select>
+
+    <select id="selectSysFormById" parameterType="Long" resultMap="SysFormResult">
+        <include refid="selectSysFormVo"/>
+        where form_id = #{formId}
+    </select>
+
+    <insert id="insertSysForm" parameterType="com.ycl.domain.entity.SysForm" useGeneratedKeys="true" keyProperty="formId">
+        insert into sys_form
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="formName != null">form_name,</if>
+            <if test="formContent != null">form_content,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="remark != null">remark,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="formName != null">#{formName},</if>
+            <if test="formContent != null">#{formContent},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="remark != null">#{remark},</if>
+         </trim>
+    </insert>
+
+    <update id="updateSysForm" parameterType="com.ycl.domain.entity.SysForm">
+        update sys_form
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="formName != null">form_name = #{formName},</if>
+            <if test="formContent != null">form_content = #{formContent},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="remark != null">remark = #{remark},</if>
+        </trim>
+        where form_id = #{formId}
+    </update>
+
+    <delete id="deleteSysFormById" parameterType="Long">
+        delete from sys_form where form_id = #{formId}
+    </delete>
+
+    <delete id="deleteSysFormByIds" parameterType="String">
+        delete from sys_form where form_id in
+        <foreach item="formId" collection="array" open="(" separator="," close=")">
+            #{formId}
+        </foreach>
+    </delete>
+</mapper>
diff --git a/flowable/src/main/resources/mapper/SysListenerMapper.xml b/flowable/src/main/resources/mapper/SysListenerMapper.xml
new file mode 100644
index 0000000..379533b
--- /dev/null
+++ b/flowable/src/main/resources/mapper/SysListenerMapper.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ycl.mapper.SysListenerMapper">
+
+    <resultMap type="com.ycl.domain.entity.SysListener" id="SysListenerResult">
+        <result property="id" column="id"/>
+        <result property="name" column="name"/>
+        <result property="type" column="type"/>
+        <result property="eventType" column="event_type"/>
+        <result property="valueType" column="value_type"/>
+        <result property="value" column="value"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateTime" column="update_time"/>
+        <result property="createBy" column="create_by"/>
+        <result property="updateBy" column="update_by"/>
+        <result property="status" column="status"/>
+        <result property="remark" column="remark"/>
+    </resultMap>
+
+    <sql id="selectSysListenerVo">
+        select id,
+               name,
+               type,
+               event_type,
+               value_type,
+               value,
+               create_time,
+               update_time,
+               create_by,
+               update_by,
+               status,
+               remark
+        from sys_listener
+    </sql>
+
+    <select id="selectSysListenerList" parameterType="com.ycl.domain.entity.SysListener" resultMap="SysListenerResult">
+        <include refid="selectSysListenerVo"/>
+        <where>
+            <if test="name != null  and name != ''">and name like concat('%', #{name}, '%')</if>
+            <if test="type != null  and type != ''">and type = #{type}</if>
+            <if test="eventType != null  and eventType != ''">and event_type = #{eventType}</if>
+            <if test="valueType != null  and valueType != ''">and value_type = #{valueType}</if>
+            <if test="value != null  and value != ''">and value = #{value}</if>
+            <if test="status != null ">and status = #{status}</if>
+        </where>
+    </select>
+
+    <select id="selectSysListenerById" parameterType="Long" resultMap="SysListenerResult">
+        <include refid="selectSysListenerVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertSysListener" parameterType="com.ycl.domain.entity.SysListener" useGeneratedKeys="true" keyProperty="id">
+        insert into sys_listener
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="name != null">name,</if>
+            <if test="type != null">type,</if>
+            <if test="eventType != null">event_type,</if>
+            <if test="valueType != null">value_type,</if>
+            <if test="value != null">value,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="status != null">status,</if>
+            <if test="remark != null">remark,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="name != null">#{name},</if>
+            <if test="type != null">#{type},</if>
+            <if test="eventType != null">#{eventType},</if>
+            <if test="valueType != null">#{valueType},</if>
+            <if test="value != null">#{value},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="status != null">#{status},</if>
+            <if test="remark != null">#{remark},</if>
+        </trim>
+    </insert>
+
+    <update id="updateSysListener" parameterType="com.ycl.domain.entity.SysListener">
+        update sys_listener
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="name != null">name = #{name},</if>
+            <if test="type != null">type = #{type},</if>
+            <if test="eventType != null">event_type = #{eventType},</if>
+            <if test="valueType != null">value_type = #{valueType},</if>
+            <if test="value != null">value = #{value},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="remark != null">remark = #{remark},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteSysListenerById" parameterType="Long">
+        delete
+        from sys_listener
+        where id = #{id}
+    </delete>
+
+    <delete id="deleteSysListenerByIds" parameterType="String">
+        delete from sys_listener where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>
diff --git a/flowable/src/main/resources/mapper/SysTaskFormMapper.xml b/flowable/src/main/resources/mapper/SysTaskFormMapper.xml
new file mode 100644
index 0000000..8353e2b
--- /dev/null
+++ b/flowable/src/main/resources/mapper/SysTaskFormMapper.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ycl.mapper.SysTaskFormMapper">
+
+    <resultMap type="com.ycl.domain.entity.SysTaskForm" id="SysTaskFormResult">
+        <result property="id"    column="id"    />
+        <result property="formId"    column="form_id"    />
+        <result property="taskId"    column="task_id"    />
+    </resultMap>
+
+    <sql id="selectSysTaskFormVo">
+        select id, form_id, task_id from sys_task_form
+    </sql>
+
+    <select id="selectSysTaskFormList" parameterType="com.ycl.domain.entity.SysTaskForm" resultMap="SysTaskFormResult">
+        <include refid="selectSysTaskFormVo"/>
+        <where>
+            <if test="formId != null "> and form_id = #{formId}</if>
+            <if test="taskId != null  and taskId != ''"> and task_id = #{taskId}</if>
+        </where>
+    </select>
+
+    <select id="selectSysTaskFormById" parameterType="Long" resultMap="SysTaskFormResult">
+        <include refid="selectSysTaskFormVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertSysTaskForm" parameterType="com.ycl.domain.entity.SysTaskForm" useGeneratedKeys="true" keyProperty="id">
+        insert into sys_task_form
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="formId != null">form_id,</if>
+            <if test="taskId != null">task_id,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="formId != null">#{formId},</if>
+            <if test="taskId != null">#{taskId},</if>
+         </trim>
+    </insert>
+
+    <update id="updateSysTaskForm" parameterType="com.ycl.domain.entity.SysTaskForm">
+        update sys_task_form
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="formId != null">form_id = #{formId},</if>
+            <if test="taskId != null">task_id = #{taskId},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteSysTaskFormById" parameterType="Long">
+        delete from sys_task_form where id = #{id}
+    </delete>
+
+    <delete id="deleteSysTaskFormByIds" parameterType="String">
+        delete from sys_task_form where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>
diff --git a/start/src/main/resources/application.yml b/start/src/main/resources/application.yml
index 3ad8615..80c9de9 100644
--- a/start/src/main/resources/application.yml
+++ b/start/src/main/resources/application.yml
@@ -126,8 +126,9 @@
   idm:  # idm鏄痜lowable鐨勮韩浠界鐞嗘ā鍧楋細鍗崇敤鎴枫�佽璇併�佹潈闄愮瓑
     enabled: false
   cmmn: # cmmn鏄痜lowable鐨勬渚嬬鐞嗘ā鍧楋紝浣撶幇鍦╢lowable-ui涓殑锛氭祦绋嬪缓妯″櫒銆乁I锛孈see https://www.flowable.com/open-source/docs/cmmn/ch06-cmmn
-    enabled: false
+    enabled: true
   dmn: # dmn鏄痜lowable鐨勫喅绛栨ā鍨嬶紝浣撶幇鍦╢lowable-ui涓殑鍐崇瓥琛�  @see https://www.flowable.com/open-source/docs/dmn/ch06-DMN-Introduction
     enabled: false
   app: # app鐨勫姛鑳芥槸涓篺lowable鍦╯pring涓珮鏁堣繍琛岃�屾彁渚涗簡寰堝bean锛屼笌flowable鏈韩鐨勫唴瀹规棤鍏�
     enabled: true
+  check-process-definitions: true
diff --git a/start/src/main/resources/processes/mytest.bpmn20.xml b/start/src/main/resources/processes/mytest.bpmn20.xml
new file mode 100644
index 0000000..55340d1
--- /dev/null
+++ b/start/src/main/resources/processes/mytest.bpmn20.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef" exporter="Flowable Open Source Modeler" exporterVersion="6.8.1">
+  <process id="mytest" name="mytest" isExecutable="true">
+    <startEvent id="sid-2B88E115-ED64-4D32-A093-21905A8483B5" flowable:formFieldValidation="true"></startEvent>
+    <userTask id="sid-52037585-93EB-4EBA-8CBB-6214556A0A2F" name="鎻愪氦瀹℃牳" flowable:assignee="#{testUser}" flowable:formFieldValidation="true">
+      <extensionElements>
+        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
+      </extensionElements>
+    </userTask>
+    <sequenceFlow id="sid-214047A3-771E-40D2-A835-13B127D336E8" sourceRef="sid-2B88E115-ED64-4D32-A093-21905A8483B5" targetRef="sid-52037585-93EB-4EBA-8CBB-6214556A0A2F"></sequenceFlow>
+    <sequenceFlow id="sid-2F71C4D2-0515-4964-BB59-FA206DC62900" sourceRef="sid-52037585-93EB-4EBA-8CBB-6214556A0A2F" targetRef="sid-F59D55CF-E5C6-477C-9ED2-83774272663B"></sequenceFlow>
+    <parallelGateway id="sid-F59D55CF-E5C6-477C-9ED2-83774272663B" name="棰嗗瀹℃牳"></parallelGateway>
+    <userTask id="sid-9FAA3BCC-F09C-4BF6-B3D5-C0E08E793D5F" name="缁忕悊瀹℃牳" flowable:assignee="#{shenpi2}" flowable:formFieldValidation="true">
+      <extensionElements>
+        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
+      </extensionElements>
+    </userTask>
+    <sequenceFlow id="sid-E1EC25C2-4BFE-4001-937F-1DE84ED940BD" sourceRef="sid-F59D55CF-E5C6-477C-9ED2-83774272663B" targetRef="sid-9FAA3BCC-F09C-4BF6-B3D5-C0E08E793D5F"></sequenceFlow>
+    <userTask id="sid-0E43E29B-4A78-4BE2-85F3-017612AB5DF1" name="棰嗗瀹℃牳" flowable:assignee="#{shenpi1}" flowable:formFieldValidation="true">
+      <extensionElements>
+        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
+      </extensionElements>
+    </userTask>
+    <sequenceFlow id="sid-ED264B2E-436B-4946-AB56-08436AC8FF71" sourceRef="sid-0E43E29B-4A78-4BE2-85F3-017612AB5DF1" targetRef="sid-0B60481F-602F-48CF-8476-4BB848AB0882"></sequenceFlow>
+    <parallelGateway id="sid-0B60481F-602F-48CF-8476-4BB848AB0882"></parallelGateway>
+    <sequenceFlow id="sid-F79E008A-DCA4-418C-B2EE-157C66E47EE3" sourceRef="sid-9FAA3BCC-F09C-4BF6-B3D5-C0E08E793D5F" targetRef="sid-0B60481F-602F-48CF-8476-4BB848AB0882"></sequenceFlow>
+    <userTask id="sid-80D317F8-65EB-4354-891C-09035A2299E8" name="鎬荤粡鐞嗗鎵�" flowable:assignee="#{shenpi3}" flowable:formFieldValidation="true">
+      <extensionElements>
+        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
+      </extensionElements>
+    </userTask>
+    <sequenceFlow id="sid-7E23B320-994F-4997-A2CD-8905D5E6ECB1" sourceRef="sid-0B60481F-602F-48CF-8476-4BB848AB0882" targetRef="sid-80D317F8-65EB-4354-891C-09035A2299E8"></sequenceFlow>
+    <endEvent id="sid-68DB756C-7B0B-462A-A938-1161B9C0535B"></endEvent>
+    <sequenceFlow id="sid-09DB9373-D96C-4333-98C9-E3AB1BBF4EB2" sourceRef="sid-80D317F8-65EB-4354-891C-09035A2299E8" targetRef="sid-68DB756C-7B0B-462A-A938-1161B9C0535B"></sequenceFlow>
+    <sequenceFlow id="sid-BF19FACD-1B7A-4E15-8DE0-9E5F4E31237D" sourceRef="sid-F59D55CF-E5C6-477C-9ED2-83774272663B" targetRef="sid-0E43E29B-4A78-4BE2-85F3-017612AB5DF1"></sequenceFlow>
+  </process>
+  <bpmndi:BPMNDiagram id="BPMNDiagram_mytest">
+    <bpmndi:BPMNPlane bpmnElement="mytest" id="BPMNPlane_mytest">
+      <bpmndi:BPMNShape bpmnElement="sid-2B88E115-ED64-4D32-A093-21905A8483B5" id="BPMNShape_sid-2B88E115-ED64-4D32-A093-21905A8483B5">
+        <omgdc:Bounds height="30.0" width="30.0" x="237.5" y="205.0"></omgdc:Bounds>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="sid-52037585-93EB-4EBA-8CBB-6214556A0A2F" id="BPMNShape_sid-52037585-93EB-4EBA-8CBB-6214556A0A2F">
+        <omgdc:Bounds height="80.0" width="100.0" x="312.5" y="180.0"></omgdc:Bounds>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="sid-F59D55CF-E5C6-477C-9ED2-83774272663B" id="BPMNShape_sid-F59D55CF-E5C6-477C-9ED2-83774272663B">
+        <omgdc:Bounds height="40.0" width="40.0" x="457.75" y="200.0"></omgdc:Bounds>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="sid-9FAA3BCC-F09C-4BF6-B3D5-C0E08E793D5F" id="BPMNShape_sid-9FAA3BCC-F09C-4BF6-B3D5-C0E08E793D5F">
+        <omgdc:Bounds height="80.0" width="100.0" x="630.0" y="315.0"></omgdc:Bounds>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="sid-0E43E29B-4A78-4BE2-85F3-017612AB5DF1" id="BPMNShape_sid-0E43E29B-4A78-4BE2-85F3-017612AB5DF1">
+        <omgdc:Bounds height="80.0" width="100.0" x="630.0" y="60.0"></omgdc:Bounds>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="sid-0B60481F-602F-48CF-8476-4BB848AB0882" id="BPMNShape_sid-0B60481F-602F-48CF-8476-4BB848AB0882">
+        <omgdc:Bounds height="40.0" width="40.0" x="870.0" y="270.0"></omgdc:Bounds>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="sid-80D317F8-65EB-4354-891C-09035A2299E8" id="BPMNShape_sid-80D317F8-65EB-4354-891C-09035A2299E8">
+        <omgdc:Bounds height="80.0" width="100.0" x="955.0" y="250.0"></omgdc:Bounds>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape bpmnElement="sid-68DB756C-7B0B-462A-A938-1161B9C0535B" id="BPMNShape_sid-68DB756C-7B0B-462A-A938-1161B9C0535B">
+        <omgdc:Bounds height="28.0" width="28.0" x="1100.0" y="276.0"></omgdc:Bounds>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge bpmnElement="sid-ED264B2E-436B-4946-AB56-08436AC8FF71" id="BPMNEdge_sid-ED264B2E-436B-4946-AB56-08436AC8FF71" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="20.5" flowable:targetDockerY="20.5">
+        <omgdi:waypoint x="729.9499999999999" y="100.0"></omgdi:waypoint>
+        <omgdi:waypoint x="890.5" y="100.0"></omgdi:waypoint>
+        <omgdi:waypoint x="890.5" y="270.5"></omgdi:waypoint>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-214047A3-771E-40D2-A835-13B127D336E8" id="BPMNEdge_sid-214047A3-771E-40D2-A835-13B127D336E8" flowable:sourceDockerX="15.0" flowable:sourceDockerY="15.0" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
+        <omgdi:waypoint x="267.4499984899576" y="220.0"></omgdi:waypoint>
+        <omgdi:waypoint x="312.5" y="220.0"></omgdi:waypoint>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-BF19FACD-1B7A-4E15-8DE0-9E5F4E31237D" id="BPMNEdge_sid-BF19FACD-1B7A-4E15-8DE0-9E5F4E31237D" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="1.0" flowable:targetDockerY="40.0">
+        <omgdi:waypoint x="478.25" y="200.5"></omgdi:waypoint>
+        <omgdi:waypoint x="478.25" y="104.0"></omgdi:waypoint>
+        <omgdi:waypoint x="629.9999999999997" y="100.02487725040916"></omgdi:waypoint>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-F79E008A-DCA4-418C-B2EE-157C66E47EE3" id="BPMNEdge_sid-F79E008A-DCA4-418C-B2EE-157C66E47EE3" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="20.0" flowable:targetDockerY="20.0">
+        <omgdi:waypoint x="729.9499999999999" y="355.0"></omgdi:waypoint>
+        <omgdi:waypoint x="890.0" y="355.0"></omgdi:waypoint>
+        <omgdi:waypoint x="890.0" y="309.9152927580894"></omgdi:waypoint>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-2F71C4D2-0515-4964-BB59-FA206DC62900" id="BPMNEdge_sid-2F71C4D2-0515-4964-BB59-FA206DC62900" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="20.759493670886076" flowable:targetDockerY="20.5">
+        <omgdi:waypoint x="412.44999999999243" y="220.21528410485826"></omgdi:waypoint>
+        <omgdi:waypoint x="458.1623037724898" y="220.41230377249934"></omgdi:waypoint>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-09DB9373-D96C-4333-98C9-E3AB1BBF4EB2" id="BPMNEdge_sid-09DB9373-D96C-4333-98C9-E3AB1BBF4EB2" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="14.0" flowable:targetDockerY="14.0">
+        <omgdi:waypoint x="1054.95" y="290.0"></omgdi:waypoint>
+        <omgdi:waypoint x="1100.0" y="290.0"></omgdi:waypoint>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-7E23B320-994F-4997-A2CD-8905D5E6ECB1" id="BPMNEdge_sid-7E23B320-994F-4997-A2CD-8905D5E6ECB1" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
+        <omgdi:waypoint x="909.5247370727432" y="290.4166666666667"></omgdi:waypoint>
+        <omgdi:waypoint x="955.0" y="290.21812227074236"></omgdi:waypoint>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge bpmnElement="sid-E1EC25C2-4BFE-4001-937F-1DE84ED940BD" id="BPMNEdge_sid-E1EC25C2-4BFE-4001-937F-1DE84ED940BD" flowable:sourceDockerX="20.5" flowable:sourceDockerY="20.5" flowable:targetDockerX="1.0" flowable:targetDockerY="40.0">
+        <omgdi:waypoint x="478.25" y="239.44296062407133"></omgdi:waypoint>
+        <omgdi:waypoint x="478.25" y="355.0"></omgdi:waypoint>
+        <omgdi:waypoint x="630.0" y="355.0"></omgdi:waypoint>
+      </bpmndi:BPMNEdge>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</definitions>
\ No newline at end of file

--
Gitblit v1.8.0