From f472efc9ad1f9bda645dd39b40607c5eabb73b47 Mon Sep 17 00:00:00 2001
From: lyh <925863403@qq.com>
Date: 星期五, 27 六月 2025 16:12:38 +0800
Subject: [PATCH] 新增工作流

---
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/entity/FlowMyBusiness.java                  |  121 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowHistoricalVo.java                               |   79 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/service/impl/FlowMyBusinessServiceImpl.java |  164 +
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/mapper/FlowMyBusinessMapper.java            |   38 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/factory/FlowServiceFactory.java                               |   42 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/IFlowThirdService.java                       |   56 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IWorkTaskService.java                                 |   11 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/CustomProcessDiagramGenerator.java                       |  402 +++
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/service/IFlowMyBusinessService.java         |   41 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/FlowBeforeParams.java                         |   20 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/WorkTaskDataVo.java                                 |   97 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/WorkTaskServiceImpl.java                         |   20 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowTaskService.java                                 |  193 +
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/FlowCallBackServiceI.java                    |   46 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowTaskController.java                            |  213 +
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/FlowableUtils.java                                       |  587 ++++
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/AssignStreamFlowController.java                    |  175 +
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IHisWorkTaskMapper.java                                |   21 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/FlowCommonService.java                       |   87 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/CustomProcessDiagramCanvas.java                          |  369 ++
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/HisWorkTaskServiceImpl.java                      |   42 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/WorkTaskVoMapper.xml                               |   54 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/exception/CustomException.java                |   42 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowTaskVo.java                                     |   47 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowDefinitionService.java                           |   97 
 lxzn-module-flowable/pom.xml                                                                                                |   61 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/enums/FlowComment.java                        |   41 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/ActStatus.java                                |   16 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/WorkTaskMapper.xml                                 |    8 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IWorkTaskVoMapper.java                                 |   14 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/util/TimeUtil.java                                            |  111 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowInstanceServiceImpl.java                     |  185 +
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IHisWorkTaskService.java                              |   20 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/config/FlowableConfig.java                                    |   68 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowDefinitionController.java                      |  243 +
 lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/flow/FlowThirdServiceImpl.java                           |  107 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysUser.java                                  |  138 +
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowViewerDto.java                                 |   15 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/HisWorkTask.java                                    |   45 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IWorkTaskServiceVo.java                               |   12 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/WorkTaskServiceImplVo.java                       |   35 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/dto/FlowMyBusinessDto.java                  |  154 +
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/constant/ProcessConstants.java                |   77 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowProcDefDto.java                                |   56 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowTaskDto.java                                   |  121 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowDefinitionServiceImpl.java                   |  480 +++
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/WorkTaskData.java                                   |  117 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysCategory.java                              |   24 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowTaskServiceImpl.java                         | 1614 ++++++++++++
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowCommentDto.java                                |   24 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/listener/UserTaskListener.java                                |   15 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/HisWorkTaskMapper.xml                              |   75 
 lxzn-boot-base-core/src/main/java/org/jeecg/common/util/TranslateDictTextUtils.java                                         |  202 +
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IWorkTaskMapper.java                                   |   10 
 lxzn-module-system/lxzn-system-biz/pom.xml                                                                                  |   18 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowSaveXmlVo.java                                 |   27 
 lxzn-module-flowable/src/main/java/rebel.xml                                                                                |   16 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/config/MyDefaultProcessDiagramCanvas.java                     |   92 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/mapper/xml/FlowMyBusinessMapper.xml         |  102 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowNextDto.java                                   |   24 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/FindNextNodeUtil.java                                    |  235 +
 lxzn-module-flowable/src/main/java/org/jeecg/FlowableDatabaseConfig.java                                                    |   19 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowMy.java                                         |   42 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowInstanceService.java                             |   58 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowInstanceController.java                        |   63 
 lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysRole.java                                  |   27 
 66 files changed, 7,869 insertions(+), 6 deletions(-)

diff --git a/lxzn-boot-base-core/src/main/java/org/jeecg/common/util/TranslateDictTextUtils.java b/lxzn-boot-base-core/src/main/java/org/jeecg/common/util/TranslateDictTextUtils.java
new file mode 100644
index 0000000..623abf2
--- /dev/null
+++ b/lxzn-boot-base-core/src/main/java/org/jeecg/common/util/TranslateDictTextUtils.java
@@ -0,0 +1,202 @@
+package org.jeecg.common.util;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.common.api.CommonAPI;
+import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.system.vo.DictModel;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class TranslateDictTextUtils {
+
+    @Lazy
+    @Autowired
+    private CommonAPI commonApi;
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    public void translateField(String field, String value, JSONObject item, String dictCode) {
+        if (StringUtils.isBlank(value)) {
+            item.put(field + CommonConstant.DICT_TEXT_SUFFIX, null);
+            return;
+        }
+        // 瀛楀吀鏁版嵁鍒楄〃锛� key = 瀛楀吀code锛寁alue=鏁版嵁鍒楄〃
+        Map<String, List<String>> dataListMap = new HashMap<>(5);
+        dataListMap.put(dictCode, this.listAddAllDeduplicate(new ArrayList<>(), Arrays.asList(value.split(","))));
+        //step.2 璋冪敤缈昏瘧鏂规硶锛屼竴娆℃�х炕璇�
+        Map<String, List<DictModel>> translText = this.translateAllDict(dataListMap);
+        //缈昏瘧
+        List<DictModel> dictModels = translText.get(dictCode);
+        if (CollectionUtil.isEmpty(dictModels)) {
+            item.put(field + CommonConstant.DICT_TEXT_SUFFIX, null);
+            return;
+        }
+        String textValue = this.translDictText(dictModels, value);
+        item.put(field + CommonConstant.DICT_TEXT_SUFFIX, textValue);
+    }
+
+    /**
+     * 瀛楀吀鍊兼浛鎹㈡枃鏈�
+     *
+     * @param dictModels
+     * @param values
+     * @return
+     */
+    private String translDictText(List<DictModel> dictModels, String values) {
+        List<String> result = new ArrayList<>();
+
+        // 鍏佽澶氫釜閫楀彿鍒嗛殧锛屽厑璁镐紶鏁扮粍瀵硅薄
+        String[] splitVal = values.split(",");
+        for (String val : splitVal) {
+            String dictText = val;
+            for (DictModel dict : dictModels) {
+                if (val.equals(dict.getValue())) {
+                    dictText = dict.getText();
+                    break;
+                }
+            }
+            if(StringUtils.isNotBlank(dictText)) {
+                result.add(dictText);
+            }
+        }
+        if(CollectionUtil.isEmpty(result)) {
+            return "";
+        }
+        return String.join(",", result);
+    }
+
+    /**
+     * list 鍘婚噸娣诲姞
+     */
+    private List<String> listAddAllDeduplicate(List<String> dataList, List<String> addList) {
+        // 绛涢�夊嚭dataList涓病鏈夌殑鏁版嵁
+        List<String> filterList = addList.stream().filter(i -> !dataList.contains(i)).collect(Collectors.toList());
+        dataList.addAll(filterList);
+        return dataList;
+    }
+
+    /**
+     * 涓�娆℃�ф妸鎵�鏈夌殑瀛楀吀閮界炕璇戜簡
+     * 1.  鎵�鏈夌殑鏅�氭暟鎹瓧鍏哥殑鎵�鏈夋暟鎹彧鎵ц涓�娆QL
+     * 2.  琛ㄥ瓧鍏哥浉鍚岀殑鎵�鏈夋暟鎹彧鎵ц涓�娆QL
+     *
+     * @param dataListMap
+     * @return
+     */
+    private Map<String, List<DictModel>> translateAllDict(Map<String, List<String>> dataListMap) {
+        // 缈昏瘧鍚庣殑瀛楀吀鏂囨湰锛宬ey=dictCode
+        Map<String, List<DictModel>> translText = new HashMap<>(5);
+        // 闇�瑕佺炕璇戠殑鏁版嵁锛堟湁浜涘彲浠ヤ粠redis缂撳瓨涓幏鍙栵紝灏变笉璧版暟鎹簱鏌ヨ锛�
+        List<String> needTranslData = new ArrayList<>();
+        //step.1 鍏堥�氳繃redis涓幏鍙栫紦瀛樺瓧鍏告暟鎹�
+        for (String dictCode : dataListMap.keySet()) {
+            List<String> dataList = dataListMap.get(dictCode);
+            if (dataList.size() == 0) {
+                continue;
+            }
+            // 琛ㄥ瓧鍏搁渶瑕佺炕璇戠殑鏁版嵁
+            List<String> needTranslDataTable = new ArrayList<>();
+            for (String s : dataList) {
+                String data = s.trim();
+                if (data.length() == 0) {
+                    continue; //璺宠繃寰幆
+                }
+                if (dictCode.contains(",")) {
+                    String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, data);
+                    if (redisTemplate.hasKey(keyString)) {
+                        try {
+                            String text = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));
+                            List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
+                            list.add(new DictModel(data, text));
+                        } catch (Exception e) {
+                            log.warn(e.getMessage());
+                        }
+                    } else if (!needTranslDataTable.contains(data)) {
+                        // 鍘婚噸娣诲姞
+                        needTranslDataTable.add(data);
+                    }
+                } else {
+                    String keyString = String.format("sys:cache:dict::%s:%s", dictCode, data);
+                    if (redisTemplate.hasKey(keyString)) {
+                        try {
+                            String text = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));
+                            List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
+                            list.add(new DictModel(data, text));
+                        } catch (Exception e) {
+                            log.warn(e.getMessage());
+                        }
+                    } else if (!needTranslData.contains(data)) {
+                        // 鍘婚噸娣诲姞
+                        needTranslData.add(data);
+                    }
+                }
+
+            }
+            //step.2 璋冪敤鏁版嵁搴撶炕璇戣〃瀛楀吀
+            if (needTranslDataTable.size() > 0) {
+                String[] arr = dictCode.split(",");
+                String table = arr[0], text = arr[1], code = arr[2];
+                String values = String.join(",", needTranslDataTable);
+                log.debug("translateDictFromTableByKeys.dictCode:" + dictCode);
+                log.debug("translateDictFromTableByKeys.values:" + values);
+                List<DictModel> texts = commonApi.translateDictFromTableByKeys(table, text, code, values);
+                log.debug("translateDictFromTableByKeys.result:" + texts);
+                List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
+                list.addAll(texts);
+
+                // 鍋� redis 缂撳瓨
+                for (DictModel dict : texts) {
+                    String redisKey = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, dict.getValue());
+                    try {
+                        // update-begin-author:taoyan date:20211012 for: 瀛楀吀琛ㄧ炕璇戞敞瑙g紦瀛樻湭鏇存柊 issues/3061
+                        // 淇濈暀5鍒嗛挓
+                        redisTemplate.opsForValue().set(redisKey, dict.getText(), 300, TimeUnit.SECONDS);
+                        // update-end-author:taoyan date:20211012 for: 瀛楀吀琛ㄧ炕璇戞敞瑙g紦瀛樻湭鏇存柊 issues/3061
+                    } catch (Exception e) {
+                        log.warn(e.getMessage(), e);
+                    }
+                }
+            }
+        }
+
+        //step.3 璋冪敤鏁版嵁搴撹繘琛岀炕璇戞櫘閫氬瓧鍏�
+        if (needTranslData.size() > 0) {
+            List<String> dictCodeList = Arrays.asList(dataListMap.keySet().toArray(new String[]{}));
+            // 灏嗕笉鍖呭惈閫楀彿鐨勫瓧鍏竎ode绛涢�夊嚭鏉ワ紝鍥犱负甯﹂�楀彿鐨勬槸琛ㄥ瓧鍏革紝鑰屼笉鏄櫘閫氱殑鏁版嵁瀛楀吀
+            List<String> filterDictCodes = dictCodeList.stream().filter(key -> !key.contains(",")).collect(Collectors.toList());
+            String dictCodes = String.join(",", filterDictCodes);
+            String values = String.join(",", needTranslData);
+            log.debug("translateManyDict.dictCodes:" + dictCodes);
+            log.debug("translateManyDict.values:" + values);
+            Map<String, List<DictModel>> manyDict = commonApi.translateManyDict(dictCodes, values);
+            log.debug("translateManyDict.result:" + manyDict);
+            for (String dictCode : manyDict.keySet()) {
+                List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
+                List<DictModel> newList = manyDict.get(dictCode);
+                list.addAll(newList);
+
+                // 鍋� redis 缂撳瓨
+                for (DictModel dict : newList) {
+                    String redisKey = String.format("sys:cache:dict::%s:%s", dictCode, dict.getValue());
+                    try {
+                        redisTemplate.opsForValue().set(redisKey, dict.getText());
+                    } catch (Exception e) {
+                        log.warn(e.getMessage(), e);
+                    }
+                }
+            }
+        }
+        return translText;
+    }
+}
diff --git a/lxzn-module-flowable/pom.xml b/lxzn-module-flowable/pom.xml
new file mode 100644
index 0000000..b3339f3
--- /dev/null
+++ b/lxzn-module-flowable/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>lxzn-boot-parent</artifactId>
+        <groupId>org.jeecgframework.boot</groupId>
+        <version>3.4.3</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>lxzn-module-flowable</artifactId>
+
+    <dependencies>
+        <!--淇濇寔鐙珛锛屽彧寮曞叆jeecg鍩虹妯″潡 -->
+        <dependency>
+            <groupId>org.jeecgframework.boot</groupId>
+            <artifactId>lxzn-boot-base-core</artifactId>
+        </dependency>
+        <!--=======================================flow妯″潡鐙珛===================================-->
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-engine</artifactId>
+            <scope>compile</scope>
+            <version>6.5.0</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.mybatis</groupId>
+                    <artifactId>mybatis</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-spring-boot-starter-basic</artifactId>
+            <version>6.5.0</version>
+        </dependency>
+        <!--琛ㄨ揪寮忚В鏋愬伐鍏�-->
+        <dependency>
+            <groupId>org.eweb4j</groupId>
+            <artifactId>fel</artifactId>
+            <version>0.8</version>
+        </dependency>
+        <!--xml瑙f瀽鍖咃細濡傛灉椤圭洰涓凡鏈夛紝寮曡捣鍐茬獊锛屽彲娉ㄩ噴-->
+        <dependency>
+            <groupId>xerces</groupId>
+            <artifactId>xercesImpl</artifactId>
+            <version>2.12.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/FlowableDatabaseConfig.java b/lxzn-module-flowable/src/main/java/org/jeecg/FlowableDatabaseConfig.java
new file mode 100644
index 0000000..f67d5a9
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/FlowableDatabaseConfig.java
@@ -0,0 +1,19 @@
+package org.jeecg;
+import org.flowable.engine.ProcessEngine;
+import org.flowable.engine.ProcessEngineConfiguration;
+import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;
+
+public class FlowableDatabaseConfig {
+    public static void main(String[] args) {
+        // 鍒涘缓娴佺▼寮曟搸閰嶇疆
+        ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
+                .setJdbcUrl("jdbc:sqlserver://192.168.1.118:1433;databasename=LXZN_TEXT_HANGYU_FLOWABLE;nullCatalogMeansCurrent=true")
+                .setJdbcUsername("sa")
+                .setJdbcPassword("123")
+                .setJdbcDriver("com.microsoft.sqlserver.jdbc.SQLServerDriver")
+                .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE)
+                .setDatabaseType("mssql"); // 鎸囧畾鏁版嵁搴撶被鍨�
+        // 鏋勫缓娴佺▼寮曟搸
+        ProcessEngine processEngine = cfg.buildProcessEngine();
+    }
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/dto/FlowMyBusinessDto.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/dto/FlowMyBusinessDto.java
new file mode 100644
index 0000000..2816188
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/dto/FlowMyBusinessDto.java
@@ -0,0 +1,154 @@
+package org.jeecg.modules.flowable.apithird.business.dto;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @Description: 娴佺▼涓氬姟鎵╁睍琛�
+ * @Author: jeecg-boot
+ * @Date:   2021-11-25
+ * @Version: V1.0
+ */
+@Data
+@TableName("flow_my_business")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="flow_my_business瀵硅薄", description="娴佺▼涓氬姟鎵╁睍琛�")
+public class FlowMyBusinessDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**涓婚敭ID*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @ApiModelProperty(value = "涓婚敭ID")
+    private String id;
+	/**鍒涘缓浜�*/
+    @ApiModelProperty(value = "鍒涘缓浜�")
+    private String createBy;
+	/**鍒涘缓鏃堕棿*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @ApiModelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createTime;
+	/**淇敼浜�*/
+    @ApiModelProperty(value = "淇敼浜�")
+    private String updateBy;
+	/**淇敼鏃堕棿*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @ApiModelProperty(value = "淇敼鏃堕棿")
+    private Date updateTime;
+	/**娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d*/
+	@Excel(name = "娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d", width = 15)
+    @ApiModelProperty(value = "娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d")
+    private String processDefinitionKey;
+	/**娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�*/
+	@Excel(name = "娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�", width = 15)
+    @ApiModelProperty(value = "娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�")
+    private String processDefinitionId;
+	/**娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�*/
+	@Excel(name = "娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�", width = 15)
+    @ApiModelProperty(value = "娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�")
+    private String processInstanceId;
+    @ApiModelProperty(value = "娴佺▼绫诲瀷")
+    @Dict(dicCode = "flow_type")
+    private String category;
+	/**娴佺▼涓氬姟绠�瑕佹弿杩�*/
+	@Excel(name = "娴佺▼涓氬姟绠�瑕佹弿杩�", width = 15)
+    @ApiModelProperty(value = "娴佺▼涓氬姟绠�瑕佹弿杩�")
+    private String title;
+	/**涓氬姟琛╥d锛岀悊璁哄敮涓�*/
+	@Excel(name = "涓氬姟琛╥d锛岀悊璁哄敮涓�", width = 15)
+    @ApiModelProperty(value = "涓氬姟琛╥d锛岀悊璁哄敮涓�")
+    private String dataId;
+	/**涓氬姟绫诲悕锛岀敤鏉ヨ幏鍙杝pring瀹瑰櫒閲岀殑鏈嶅姟瀵硅薄*/
+	@Excel(name = "涓氬姟绫诲悕锛岀敤鏉ヨ幏鍙杝pring瀹瑰櫒閲岀殑鏈嶅姟瀵硅薄", width = 15)
+    @ApiModelProperty(value = "涓氬姟绫诲悕锛岀敤鏉ヨ幏鍙杝pring瀹瑰櫒閲岀殑鏈嶅姟瀵硅薄")
+    private String serviceImplName;
+	/**鐢宠浜�*/
+	@Excel(name = "鐢宠浜�", width = 15)
+    @ApiModelProperty(value = "鐢宠浜�")
+    @Dict(dictTable = "sys_user", dicCode = "username", dicText = "realname")
+    private String proposer;
+	/**娴佺▼鐘舵�佽鏄庯紝鏈夛細鍚姩  鎾ゅ洖  椹冲洖  瀹℃壒涓�  瀹℃壒閫氳繃  瀹℃壒寮傚父*/
+	@Excel(name = "娴佺▼鐘舵�佽鏄庯紝鏈夛細鍚姩  鎾ゅ洖  椹冲洖  瀹℃壒涓�  瀹℃壒閫氳繃  瀹℃壒寮傚父", width = 15)
+    @ApiModelProperty(value = "娴佺▼鐘舵�佽鏄庯紝鏈夛細鍚姩  鎾ゅ洖  椹冲洖  瀹℃壒涓�  瀹℃壒閫氳繃  瀹℃壒寮傚父")
+    private String actStatus;
+	/**褰撳墠鐨勮妭鐐瑰疄渚嬩笂鐨処d*/
+	@Excel(name = "褰撳墠鐨勮妭鐐笽d", width = 15)
+    @ApiModelProperty(value = "褰撳墠鐨勮妭鐐笽d")
+    private String taskId;
+	/**褰撳墠鐨勮妭鐐�*/
+	@Excel(name = "褰撳墠鐨勮妭鐐�", width = 15)
+    @ApiModelProperty(value = "褰撳墠鐨勮妭鐐�")
+    private String taskName;
+	/**褰撳墠鐨勮妭鐐瑰畾涔変笂鐨処d*/
+	@Excel(name = "褰撳墠鐨勮妭鐐�", width = 15)
+    @ApiModelProperty(value = "褰撳墠鐨勮妭鐐�")
+    private String taskNameId;
+	/**褰撳墠鐨勮妭鐐瑰彲浠ュ鐞嗙殑鐢ㄦ埛鍚嶏紝涓簎sername鐨勯泦鍚坖son瀛楃涓�*/
+	@Excel(name = "褰撳墠鐨勮妭鐐瑰彲浠ュ鐞嗙殑鐢ㄦ埛鍚�", width = 15)
+    @ApiModelProperty(value = "褰撳墠鐨勮妭鐐瑰彲浠ュ鐞嗙殑鐢ㄦ埛鍚�")
+    @Dict(dictTable = "sys_user", dicCode = "username", dicText = "realname")
+    private String todoUsers;
+	/**澶勭悊杩囩殑浜�,涓簎sername鐨勯泦鍚坖son瀛楃涓�*/
+	@Excel(name = "澶勭悊杩囩殑浜�", width = 15)
+    @ApiModelProperty(value = "澶勭悊杩囩殑浜�")
+    @Dict(dictTable = "sys_user", dicCode = "username", dicText = "realname")
+    private String doneUsers;
+	/**褰撳墠浠诲姟鑺傜偣鐨勪紭鍏堢骇 娴佺▼瀹氫箟鐨勬椂鍊欐墍濉�*/
+	@Excel(name = "褰撳墠浠诲姟鑺傜偣鐨勪紭鍏堢骇 娴佺▼瀹氫箟鐨勬椂鍊欐墍濉�", width = 15)
+    @ApiModelProperty(value = "褰撳墠浠诲姟鑺傜偣鐨勪紭鍏堢骇 娴佺▼瀹氫箟鐨勬椂鍊欐墍濉�")
+    private String priority;
+	/**娴佺▼鍙橀噺*/
+	@TableField(exist = false)
+    private Map<String,Object> values;
+
+    /**褰撳墠鑺傜偣鐨勭姸鎬�*/
+    @TableField(exist = false)
+    private String taskStatus;
+
+    @ApiModelProperty("鍘嗗彶娴佺▼瀹炰緥ID")
+    private transient String hisProcInsId;
+
+    private transient String flowName;
+
+    /**娴佺▼寮�濮嬫椂闂�*/
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private transient Date startTime;
+
+    /**娴佺▼缁撴潫鏃堕棿*/
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private transient Date endTime;
+
+    /**褰撳墠鐢ㄦ埛*/
+    private transient String currentUser;
+
+    @ApiModelProperty(value = "鍓嶉┍鑺傜偣")
+    private transient String preNode;
+
+    /**澶勭悊鏃堕暱锛堝垎閽燂級*/
+    @TableField(exist = false)
+    @ApiModelProperty(value = "澶勭悊鏃堕暱锛堝垎閽燂級")
+    private transient String duration;
+
+    @ApiModelProperty("浠诲姟鎻忚堪")
+    private String description;
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/entity/FlowMyBusiness.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/entity/FlowMyBusiness.java
new file mode 100644
index 0000000..2746244
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/entity/FlowMyBusiness.java
@@ -0,0 +1,121 @@
+package org.jeecg.modules.flowable.apithird.business.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @Description: 娴佺▼涓氬姟鎵╁睍琛�
+ * @Author: jeecg-boot
+ * @Date:   2021-11-25
+ * @Version: V1.0
+ */
+@Data
+@TableName("flow_my_business")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="flow_my_business瀵硅薄", description="娴佺▼涓氬姟鎵╁睍琛�")
+public class  FlowMyBusiness implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**涓婚敭ID*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @ApiModelProperty(value = "涓婚敭ID")
+    private String id;
+	/**鍒涘缓浜�*/
+    @ApiModelProperty(value = "鍒涘缓浜�")
+    private String createBy;
+	/**鍒涘缓鏃堕棿*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @ApiModelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createTime;
+	/**淇敼浜�*/
+    @ApiModelProperty(value = "淇敼浜�")
+    private String updateBy;
+	/**淇敼鏃堕棿*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @ApiModelProperty(value = "淇敼鏃堕棿")
+    private Date updateTime;
+	/**娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d*/
+	@Excel(name = "娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d", width = 15)
+    @ApiModelProperty(value = "娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d")
+    private String processDefinitionKey;
+	/**娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�*/
+	@Excel(name = "娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�", width = 15)
+    @ApiModelProperty(value = "娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�")
+    private String processDefinitionId;
+	/**娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�*/
+	@Excel(name = "娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�", width = 15)
+    @ApiModelProperty(value = "娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�")
+    private String processInstanceId;
+	/**娴佺▼涓氬姟绠�瑕佹弿杩�*/
+	@Excel(name = "娴佺▼涓氬姟绠�瑕佹弿杩�", width = 15)
+    @ApiModelProperty(value = "娴佺▼涓氬姟绠�瑕佹弿杩�")
+    private String title;
+	/**涓氬姟琛╥d锛岀悊璁哄敮涓�*/
+	@Excel(name = "涓氬姟琛╥d锛岀悊璁哄敮涓�", width = 15)
+    @ApiModelProperty(value = "涓氬姟琛╥d锛岀悊璁哄敮涓�")
+    private String dataId;
+	/**涓氬姟绫诲悕锛岀敤鏉ヨ幏鍙杝pring瀹瑰櫒閲岀殑鏈嶅姟瀵硅薄*/
+	@Excel(name = "涓氬姟绫诲悕锛岀敤鏉ヨ幏鍙杝pring瀹瑰櫒閲岀殑鏈嶅姟瀵硅薄", width = 15)
+    @ApiModelProperty(value = "涓氬姟绫诲悕锛岀敤鏉ヨ幏鍙杝pring瀹瑰櫒閲岀殑鏈嶅姟瀵硅薄")
+    private String serviceImplName;
+	/**鐢宠浜�*/
+	@Excel(name = "鐢宠浜�", width = 15)
+    @ApiModelProperty(value = "鐢宠浜�")
+    @Dict(dictTable = "sys_user", dicCode = "username", dicText = "realname")
+    private String proposer;
+	/**娴佺▼鐘舵�佽鏄庯紝鏈夛細鍚姩  鎾ゅ洖  椹冲洖  瀹℃壒涓�  瀹℃壒閫氳繃  瀹℃壒寮傚父*/
+	@Excel(name = "娴佺▼鐘舵�佽鏄庯紝鏈夛細鍚姩  鎾ゅ洖  椹冲洖  瀹℃壒涓�  瀹℃壒閫氳繃  瀹℃壒寮傚父", width = 15)
+    @ApiModelProperty(value = "娴佺▼鐘舵�佽鏄庯紝鏈夛細鍚姩  鎾ゅ洖  椹冲洖  瀹℃壒涓�  瀹℃壒閫氳繃  瀹℃壒寮傚父")
+    private String actStatus;
+	/**褰撳墠鐨勮妭鐐瑰疄渚嬩笂鐨処d*/
+	@Excel(name = "褰撳墠鐨勮妭鐐笽d", width = 15)
+    @ApiModelProperty(value = "褰撳墠鐨勮妭鐐笽d")
+    private String taskId;
+	/**褰撳墠鐨勮妭鐐�*/
+	@Excel(name = "褰撳墠鐨勮妭鐐�", width = 15)
+    @ApiModelProperty(value = "褰撳墠鐨勮妭鐐�")
+    private String taskName;
+	/**褰撳墠鐨勮妭鐐瑰畾涔変笂鐨処d*/
+	@Excel(name = "褰撳墠鐨勮妭鐐�", width = 15)
+    @ApiModelProperty(value = "褰撳墠鐨勮妭鐐�")
+    private String taskNameId;
+	/**褰撳墠鐨勮妭鐐瑰彲浠ュ鐞嗙殑鐢ㄦ埛鍚嶏紝涓簎sername鐨勯泦鍚坖son瀛楃涓�*/
+	@Excel(name = "褰撳墠鐨勮妭鐐瑰彲浠ュ鐞嗙殑鐢ㄦ埛鍚�", width = 15)
+    @ApiModelProperty(value = "褰撳墠鐨勮妭鐐瑰彲浠ュ鐞嗙殑鐢ㄦ埛鍚�")
+    @Dict(dictTable = "sys_user", dicCode = "username", dicText = "realname")
+    private String todoUsers;
+	/**澶勭悊杩囩殑浜�,涓簎sername鐨勯泦鍚坖son瀛楃涓�*/
+	@Excel(name = "澶勭悊杩囩殑浜�", width = 15)
+    @ApiModelProperty(value = "澶勭悊杩囩殑浜�")
+    @Dict(dictTable = "sys_user", dicCode = "username", dicText = "realname")
+    private String doneUsers;
+	/**褰撳墠浠诲姟鑺傜偣鐨勪紭鍏堢骇 娴佺▼瀹氫箟鐨勬椂鍊欐墍濉�*/
+	@Excel(name = "褰撳墠浠诲姟鑺傜偣鐨勪紭鍏堢骇 娴佺▼瀹氫箟鐨勬椂鍊欐墍濉�", width = 15)
+    @ApiModelProperty(value = "褰撳墠浠诲姟鑺傜偣鐨勪紭鍏堢骇 娴佺▼瀹氫箟鐨勬椂鍊欐墍濉�")
+    private String priority;
+	/**娴佺▼鍙橀噺*/
+	@TableField(exist = false)
+    private Map<String,Object> values;
+
+    /**褰撳墠鑺傜偣鐨勭姸鎬�*/
+    @TableField(exist = false)
+    private String taskStatus;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/mapper/FlowMyBusinessMapper.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/mapper/FlowMyBusinessMapper.java
new file mode 100644
index 0000000..7880ff5
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/mapper/FlowMyBusinessMapper.java
@@ -0,0 +1,38 @@
+package org.jeecg.modules.flowable.apithird.business.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.jeecg.modules.flowable.apithird.business.dto.FlowMyBusinessDto;
+import org.jeecg.modules.flowable.apithird.business.entity.FlowMyBusiness;
+import org.jeecg.modules.flowable.domain.dto.FlowTaskDto;
+
+import java.util.List;
+
+/**
+ * @Description: 娴佺▼涓氬姟鎵╁睍琛�
+ * @Author: jeecg-boot
+ * @Date:   2021-11-25
+ * @Version: V1.0
+ */
+public interface FlowMyBusinessMapper extends BaseMapper<FlowMyBusiness> {
+    /**
+     * 娴佺▼-鎴戠殑宸插姙
+     * @param dto
+     * @return
+     */
+    List<FlowTaskDto> ListMyBusiness(@Param("dto") FlowMyBusinessDto dto);
+
+    /**
+     * 娴佺▼鎬诲彴璐�
+     * @param flowMyBusinessDto
+     * @return
+     */
+    IPage<FlowMyBusinessDto> PageList(@Param("page") Page page, @Param("flowMyBusinessDto") FlowMyBusinessDto flowMyBusinessDto);
+
+    @Select("SELECT * FROM flow_my_business WITH (INDEX(idx_data_id)) \n" +
+            "WHERE data_id = #{dataId}")
+    FlowMyBusiness selectByDataId(String dataId);
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/mapper/xml/FlowMyBusinessMapper.xml b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/mapper/xml/FlowMyBusinessMapper.xml
new file mode 100644
index 0000000..2eca38b
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/mapper/xml/FlowMyBusinessMapper.xml
@@ -0,0 +1,102 @@
+<?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="org.jeecg.modules.flowable.apithird.business.mapper.FlowMyBusinessMapper">
+    <select id="PageList" resultType="org.jeecg.modules.flowable.apithird.business.dto.FlowMyBusinessDto">
+        SELECT
+        flow_my_business.id,
+        flow_my_business.title as 'description',
+        flow_my_business.proposer,
+        flow_my_business.task_name,
+        flow_my_business.task_id,
+        flow_my_business.data_id AS 'dataId',
+        flow_my_business.process_definition_key,
+        flow_my_business.process_definition_id,
+        flow_my_business.process_instance_id,
+        flow_my_business.todo_users as todoUsers,
+        flow_my_business.done_Users,
+        ACT_HI_PROCINST.START_TIME_ AS start_time,
+        ACT_HI_PROCINST.END_TIME_ AS end_time,
+        ACT_RE_PROCDEF.NAME_ AS flowName,
+        ACT_RE_PROCDEF.CATEGORY_ AS category
+        FROM
+        flow_my_business
+        LEFT JOIN ACT_HI_PROCINST ON flow_my_business.process_instance_id = ACT_HI_PROCINST.ID_
+        LEFT JOIN ACT_RE_PROCDEF ON flow_my_business.process_definition_id = ACT_RE_PROCDEF.ID_
+        left join ACT_RU_TASK on flow_my_business.task_id = ACT_RU_TASK.ID_
+        WHERE
+        1 = 1
+        <if test="flowMyBusinessDto.category != null and flowMyBusinessDto.category != ''">
+            and ACT_RE_PROCDEF.CATEGORY_ = #{flowMyBusinessDto.category}
+        </if>
+        <if test="flowMyBusinessDto.flowName!= null and flowMyBusinessDto.flowName!= ''">
+            AND ACT_RE_PROCDEF.name_ LIKE CONCAT('%',#{flowMyBusinessDto.flowName},'%')
+        </if>
+        <if test="flowMyBusinessDto.title != null and flowMyBusinessDto.title != ''">
+            AND flow_my_business.title LIKE CONCAT('%',#{flowMyBusinessDto.title},'%')
+        </if>
+        <if test="flowMyBusinessDto.startTime!= null and flowMyBusinessDto.startTime!= ''">
+            AND ACT_HI_PROCINST.START_TIME_ &gt;= #{flowMyBusinessDto.startTime}
+        </if>
+        <if test="flowMyBusinessDto.endTime!= null and flowMyBusinessDto.endTime!= ''">
+            AND ACT_HI_PROCINST.END_TIME_ &lt;= #{flowMyBusinessDto.endTime}
+        </if>
+        ORDER BY
+            flow_my_business.create_time desc
+    </select>
+
+    <select id="ListMyBusiness" resultType="org.jeecg.modules.flowable.domain.dto.FlowTaskDto">
+        SELECT
+        fmb.task_id AS 'taskId',
+        fmb.process_instance_id AS 'procInsId',
+        ACT_RE_PROCDEF.CATEGORY_ AS 'category',
+        ACT_RE_PROCDEF.NAME_ AS 'procDefName',
+        fmb.title AS 'Description',
+        fmb.data_id AS 'dataId',
+        fmb.process_definition_key AS 'processDefinitionKey',
+        fmb.process_definition_id AS 'processDefinitionId',
+        fmb.proposer,
+        fmb.todo_users,
+        fmb.task_name,
+        latest_task.NAME_ AS taskName,
+        fmb.create_time AS createTime,
+        latest_task.END_TIME_ AS finishTime
+        FROM
+        flow_my_business fmb
+        LEFT JOIN ACT_RE_PROCDEF ON fmb.process_definition_id = ACT_RE_PROCDEF.ID_
+        LEFT JOIN ACT_HI_PROCINST ON fmb.process_instance_id = ACT_HI_PROCINST.ID_
+        LEFT JOIN (
+        SELECT
+        *,
+        ROW_NUMBER() OVER (
+        PARTITION BY PROC_INST_ID_
+        ORDER BY END_TIME_ DESC
+        ) AS rn
+        FROM ACT_HI_TASKINST
+        WHERE ASSIGNEE_ = #{dto.currentUser}  <!-- 缁熶竴鍒悕 -->
+        <if test="dto.startTime != null">
+            AND START_TIME_ &gt;= #{dto.startTime}
+        </if>
+        <if test="dto.endTime != null">
+            AND END_TIME_ &lt;= #{dto.endTime}
+        </if>
+        ) latest_task
+        ON fmb.process_instance_id = latest_task.PROC_INST_ID_
+        AND latest_task.rn = 1
+        WHERE
+        <!-- 鍔ㄦ�佹潯浠剁粺涓�浣跨敤 dto -->
+        <if test="dto.currentUser != null and dto.currentUser != ''">
+            fmb.done_users like concat('%',#{dto.currentUser},'%')
+        </if>
+        <if test="dto.category != null and dto.category != ''">
+            AND ACT_RE_PROCDEF.CATEGORY_ = #{dto.category}
+        </if>
+        <if test="dto.flowName != null and dto.flowName != ''">
+            AND ACT_RE_PROCDEF.NAME_ LIKE CONCAT('%', #{dto.flowName}, '%')
+        </if>
+        <if test="dto.title != null and dto.title != ''">
+            AND fmb.title LIKE CONCAT('%', #{dto.title}, '%')
+        </if>
+        ORDER BY
+        latest_task.END_TIME_ DESC
+    </select>
+</mapper>
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/service/IFlowMyBusinessService.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/service/IFlowMyBusinessService.java
new file mode 100644
index 0000000..2e89d35
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/service/IFlowMyBusinessService.java
@@ -0,0 +1,41 @@
+package org.jeecg.modules.flowable.apithird.business.service;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.flowable.apithird.business.entity.FlowMyBusiness;
+
+import java.util.List;
+
+/**
+ * @Description: 娴佺▼涓氬姟鎵╁睍琛�
+ * @Author: jeecg-boot
+ * @Date:   2021-11-25
+ * @Version: V1.0
+ */
+public interface IFlowMyBusinessService extends IService<FlowMyBusiness> {
+    /**
+     * 鏍规嵁娴佺▼瀹炰緥id 鑾峰彇 娴佺▼瀹炰緥
+     * @param instanceId 娴佺▼瀹炰緥id
+     * @return
+     */
+    FlowMyBusiness getFlowMyBusiness(String instanceId);
+
+    /**
+     * 鏍规嵁娴佺▼瀹炰緥id 鑾峰彇 娴佺▼瀹炰緥
+     * @param instanceId 娴佺▼瀹炰緥id
+     * @return
+     */
+    FlowMyBusiness getFlowMyBusiness(String instanceId, String taskId);
+
+    /**
+     * 鑾峰彇娴佺▼瀹炰緥
+     * @param dataId 涓氬姟Id
+     * @return
+     */
+    FlowMyBusiness selectByDataId(String dataId);
+
+    /**
+     * 鑾峰彇娴佺▼瀹炰緥 澶氬疄渚嬪苟琛岋紝瀛樺湪澶氭潯璁板綍
+     * @param dataId
+     * @return
+     */
+    List<FlowMyBusiness> selectListByDataId(String dataId);
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/service/impl/FlowMyBusinessServiceImpl.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/service/impl/FlowMyBusinessServiceImpl.java
new file mode 100644
index 0000000..99720f2
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/business/service/impl/FlowMyBusinessServiceImpl.java
@@ -0,0 +1,164 @@
+package org.jeecg.modules.flowable.apithird.business.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.commons.collections4.CollectionUtils;
+import org.flowable.engine.HistoryService;
+import org.flowable.engine.history.HistoricActivityInstance;
+import org.jeecg.modules.flowable.apithird.business.dto.FlowMyBusinessDto;
+import org.jeecg.modules.flowable.apithird.business.entity.FlowMyBusiness;
+import org.jeecg.modules.flowable.apithird.business.mapper.FlowMyBusinessMapper;
+import org.jeecg.modules.flowable.apithird.business.service.IFlowMyBusinessService;
+import org.jeecg.modules.flowable.domain.dto.FlowTaskDto;
+import org.jeecg.modules.flowable.util.TimeUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @Description: 娴佺▼涓氬姟鎵╁睍琛�
+ * @Author: jeecg-boot
+ * @Date:   2021-11-25
+ * @Version: V1.0
+ */
+@Service
+public class FlowMyBusinessServiceImpl extends ServiceImpl<FlowMyBusinessMapper, FlowMyBusiness> implements IFlowMyBusinessService {
+    @Resource
+    private FlowMyBusinessMapper flowMyBusinessMapper;
+
+    @Autowired
+    private HistoryService historyService;
+
+    public HistoricActivityInstance getPreviousNode(String taskId) {
+        // 鑾峰彇褰撳墠浠诲姟鐨勬墽琛屽疄渚� ID
+        String processInstanceId = historyService.createHistoricTaskInstanceQuery()
+                .taskId(taskId)
+                .singleResult()
+                .getProcessInstanceId();
+
+        // 鏌ヨ鍘嗗彶娲诲姩瀹炰緥
+        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
+                .processInstanceId(processInstanceId)
+                .activityType("userTask")
+                .finished()
+                .orderByHistoricActivityInstanceEndTime()
+                .desc()
+                .list();
+
+        // 鍙栫涓�涓粨鏋滐紝鍗充笂涓�绾ц妭鐐�
+        if (!historicActivityInstances.isEmpty()) {
+            return historicActivityInstances.get(0);
+        }
+
+        return null;
+    }
+
+    @Transactional   // 闄嶄綆闅旂绾у埆
+    public FlowMyBusiness getByDataId(String dataId) {
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+        FlowMyBusiness business = flowMyBusinessMapper.selectByDataId(dataId);
+        return business;
+    }
+
+
+    public FlowMyBusiness getByProcessInstanceId(String processInstanceId) {
+        LambdaQueryWrapper<FlowMyBusiness> flowMyBusinessLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        flowMyBusinessLambdaQueryWrapper.eq(FlowMyBusiness::getProcessInstanceId,processInstanceId)
+        ;
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+        FlowMyBusiness business = this.getOne(flowMyBusinessLambdaQueryWrapper);
+        return business;
+    }
+
+    /**
+     * 娴佺▼-鎴戠殑宸插姙
+     * @param flowMyBusinessDto
+     * @return
+     */
+    public List<FlowTaskDto> ListMyBusiness(FlowMyBusinessDto flowMyBusinessDto){
+        return flowMyBusinessMapper.ListMyBusiness(flowMyBusinessDto);
+    }
+
+    /**
+     * 娴佺▼鎬诲彴璐�
+     * @param flowMyBusinessDto
+     * @return
+     */
+    public IPage<FlowMyBusinessDto> getPageList(Page page, FlowMyBusinessDto flowMyBusinessDto){
+        IPage<FlowMyBusinessDto> flowMyBusinessDtoIPage =flowMyBusinessMapper.PageList(page,flowMyBusinessDto);
+        flowMyBusinessDtoIPage.getRecords().forEach(item -> {
+            if (!("").equals(item.getTaskId())&&item.getTaskId()!=null){
+                HistoricActivityInstance historicActivityInstance = getPreviousNode(item.getTaskId());
+                if (historicActivityInstance != null){
+                    item.setPreNode(historicActivityInstance.getActivityName());
+                }
+            }
+            if (item.getTodoUsers() == null){
+                item.setTodoUsers("");
+            }else {
+                //鍘婚櫎[]
+                item.setTodoUsers(item.getTodoUsers().replaceAll("\\[", "").replaceAll("\\]", ""));
+                item.setTodoUsers(item.getTodoUsers().replaceAll("\"", ""));
+            }
+
+            if (item.getDoneUsers() == null){
+                item.setDoneUsers("");
+            }else {
+                //鍘婚櫎[]
+                item.setDoneUsers(item.getDoneUsers().replaceAll("\\[", "").replaceAll("\\]", ""));
+                item.setDoneUsers(item.getDoneUsers().replaceAll("\"", ""));
+            }
+            //璁$畻澶勭悊鏃堕暱
+            Date kssj=item.getStartTime();
+            Date jssj;
+            if (item.getEndTime() != null){
+                jssj=item.getEndTime();
+            }else {
+                jssj=new Date();
+            }
+            item.setDuration(TimeUtil.howLong(kssj, jssj,2));
+        });
+        return flowMyBusinessDtoIPage;
+    }
+
+    @Override
+    public FlowMyBusiness getFlowMyBusiness(String instanceId) {
+        List<FlowMyBusiness> businessList = super.list(
+                new QueryWrapper<FlowMyBusiness>().eq("process_instance_id", instanceId));
+        return businessList.isEmpty() ? null : businessList.get(0);
+    }
+
+    @Override
+    public FlowMyBusiness getFlowMyBusiness(String instanceId, String taskId) {
+        List<FlowMyBusiness> businessList = super.list(
+                new QueryWrapper<FlowMyBusiness>().eq("process_instance_id", instanceId).eq("task_id", taskId));
+        return businessList.isEmpty() ? null : businessList.get(0);
+    }
+
+    @Override
+    public FlowMyBusiness selectByDataId(String dataId) {
+        List<FlowMyBusiness> businessList = super.list(
+                new QueryWrapper<FlowMyBusiness>().eq("data_id", dataId));
+        return businessList.isEmpty() ? null : businessList.get(0);
+    }
+
+    @Override
+    public List<FlowMyBusiness> selectListByDataId(String dataId) {
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+        LambdaQueryWrapper<FlowMyBusiness> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(FlowMyBusiness::getDataId, dataId);
+        List<FlowMyBusiness> list = flowMyBusinessMapper.selectList(queryWrapper);
+        if(CollectionUtils.isEmpty(list)){
+            return Collections.emptyList();
+        }
+        return list;
+    }
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/constant/ProcessConstants.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/constant/ProcessConstants.java
new file mode 100644
index 0000000..0e08f99
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/constant/ProcessConstants.java
@@ -0,0 +1,77 @@
+package org.jeecg.modules.flowable.apithird.common.constant;
+
+/**
+ * 娴佺▼甯搁噺淇℃伅
+ *
+ */
+public class ProcessConstants {
+
+    /**
+     * 绾﹀畾鐨勫紑濮嬭妭鐐规爣璁板悕
+     */
+    public static final String START_NODE = "start";
+    /**
+     * 鍔ㄦ�佹暟鎹�
+     */
+    public static final String DATA_TYPE = "dynamic";
+
+    /**
+     * 鍗曚釜瀹℃壒浜�
+     */
+    public static final String USER_TYPE_ASSIGNEE = "assignee";
+
+
+    /**
+     * 鍊欓�変汉
+     */
+    public static final String USER_TYPE_USERS = "candidateUsers";
+
+
+    /**
+     * 瀹℃壒缁�
+     */
+    public static final String USER_TYPE_ROUPS = "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/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/enums/FlowComment.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/enums/FlowComment.java
new file mode 100644
index 0000000..4c25bec
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/enums/FlowComment.java
@@ -0,0 +1,41 @@
+package org.jeecg.modules.flowable.apithird.common.enums;
+
+/**
+ * 娴佺▼鎰忚绫诲瀷
+ *
+ */
+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/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/exception/CustomException.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/exception/CustomException.java
new file mode 100644
index 0000000..7235434
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/common/exception/CustomException.java
@@ -0,0 +1,42 @@
+package org.jeecg.modules.flowable.apithird.common.exception;
+
+/**
+ * 鑷畾涔夊紓甯�
+ *
+ */
+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/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/ActStatus.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/ActStatus.java
new file mode 100644
index 0000000..ab7368c
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/ActStatus.java
@@ -0,0 +1,16 @@
+package org.jeecg.modules.flowable.apithird.entity;
+
+/**
+ * @author PanMeiCheng
+ * @version 1.0
+ * @date 2021/11/26
+ */
+public interface ActStatus {
+    //鍚姩 鎾ゅ洖 椹冲洖 瀹℃壒涓� 瀹℃壒閫氳繃 瀹℃壒寮傚父
+    //鏈祦绋嬩笉搴旀湁鍚姩鐘舵�侊紝鍚姩鍗宠繘鍏ュ鎵癸紝绗竴涓妭鐐瑰氨鏄彂璧蜂汉鑺傜偣锛屾湭鏂逛究涓氬姟鍖哄垎锛岃瀹氫负鈥滃惎鍔ㄢ�濈姸鎬�
+    String start = "鎻愪氦鐢宠";
+    String recall = "鎾ゅ洖";
+    String reject = "椹冲洖";
+    String doing = "瀹℃壒涓�";
+    String pass = "瀹℃壒";
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/FlowBeforeParams.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/FlowBeforeParams.java
new file mode 100644
index 0000000..981e64e
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/FlowBeforeParams.java
@@ -0,0 +1,20 @@
+package org.jeecg.modules.flowable.apithird.entity;
+
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ *娴佺▼杩愯涔嬪墠浠庝笟鍔″眰鑾峰彇鐨勭浉鍏冲弬鏁�
+ *@author PanMeiCheng
+ *@date 2021/12/3
+ *@version 1.0
+ */
+@Data
+public class FlowBeforeParams {
+    /**鎸囧畾涓嬩釜鑺傜偣鐨勫�欓�変汉锛岀敤鎴峰悕username*/
+    List<String> candidateUsernames;
+    /**娴佺▼鍙橀噺*/
+    Map<String,Object> values;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysCategory.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysCategory.java
new file mode 100644
index 0000000..6a5eebb
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysCategory.java
@@ -0,0 +1,24 @@
+package org.jeecg.modules.flowable.apithird.entity;
+
+import lombok.Data;
+
+/**
+ *娴佺▼鍒嗙被
+ *@author PanMeiCheng
+ *@date 2021/11/25
+ *@version 1.0
+ */
+@Data
+public class SysCategory {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    private String id;
+
+    /**
+     * 鍒嗙被鍚嶇О
+     */
+    private String name;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysRole.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysRole.java
new file mode 100644
index 0000000..175b017
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysRole.java
@@ -0,0 +1,27 @@
+package org.jeecg.modules.flowable.apithird.entity;
+
+import lombok.Data;
+
+/**
+ * 瑙掕壊
+ * @author pmc
+ */
+@Data
+public class SysRole {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    private String id;
+
+    /**
+     * 瑙掕壊鍚嶇О
+     */
+    private String roleName;
+
+    /**
+     * 瑙掕壊缂栫爜
+     */
+    private String roleCode;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysUser.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysUser.java
new file mode 100644
index 0000000..51700ea
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/entity/SysUser.java
@@ -0,0 +1,138 @@
+package org.jeecg.modules.flowable.apithird.entity;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * 鐢ㄦ埛瀵硅薄 <br/>
+ *  //todo 鏆傛椂鏀寔鐢ㄤ簬jeecg锛屽闇�杩佺Щ鍏朵粬妗嗘灦锛岄渶瑕佹敼鍔�
+ * @author pmc
+ */
+@Data
+public class SysUser {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    private String id;
+
+    /**
+     * 鐧诲綍璐﹀彿
+     */
+    private String username;
+
+    /**
+     * 鐪熷疄濮撳悕
+     */
+    private String realname;
+
+    /**
+     * 瀵嗙爜
+     */
+    private String password;
+
+    /**
+     * md5瀵嗙爜鐩�
+     */
+    private String salt;
+
+    /**
+     * 澶村儚
+     */
+    private String avatar;
+
+    /**
+     * 鐢熸棩
+     */
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private Date birthday;
+
+    /**
+     * 鎬у埆锛�1锛氱敺 2锛氬コ锛�
+     */
+    private Integer sex;
+
+    /**
+     * 鐢靛瓙閭欢
+     */
+    private String email;
+
+    /**
+     * 鐢佃瘽
+     */
+    private String phone;
+
+    /**
+     * 閮ㄩ棬code(褰撳墠閫夋嫨鐧诲綍閮ㄩ棬)
+     */
+    private String orgCode;
+
+    /**閮ㄩ棬鍚嶇О*/
+    private transient String orgCodeTxt;
+
+    /**
+     * 鐘舵��(1锛氭甯�  2锛氬喕缁� 锛�
+     */
+    private Integer status;
+
+    /**
+     * 鍒犻櫎鐘舵�侊紙0锛屾甯革紝1宸插垹闄わ級
+     */
+    private Integer delFlag;
+
+    /**
+     * 宸ュ彿锛屽敮涓�閿�
+     */
+    private String workNo;
+
+    /**
+     * 鑱屽姟锛屽叧鑱旇亴鍔¤〃
+     */
+    private String post;
+
+    /**
+     * 搴ф満鍙�
+     */
+    private String telephone;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    private String createBy;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+
+    /**
+     * 鏇存柊浜�
+     */
+    private String updateBy;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    private Date updateTime;
+    /**
+     * 鍚屾宸ヤ綔娴佸紩鎿�1鍚屾0涓嶅悓姝�
+     */
+    private Integer activitiSync;
+
+    /**
+     * 韬唤锛�0 鏅�氭垚鍛� 1 涓婄骇锛�
+     */
+    private Integer userIdentity;
+
+    /**
+     * 璐熻矗閮ㄩ棬
+     */
+    private String departIds;
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/FlowCallBackServiceI.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/FlowCallBackServiceI.java
new file mode 100644
index 0000000..7099968
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/FlowCallBackServiceI.java
@@ -0,0 +1,46 @@
+package org.jeecg.modules.flowable.apithird.service;
+
+import org.jeecg.modules.flowable.apithird.business.entity.FlowMyBusiness;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 涓氬姟灞傚疄鐜版帴鍙f柟娉曪紝鐢ㄤ簬娴佺▼澶勭悊鍚庣殑鍥炶皟
+ * @author PanMeiCheng
+ * @version 1.0
+ * @date 2021/11/26
+ */
+public interface FlowCallBackServiceI {
+    /**
+     * 娴佺▼澶勭悊瀹屾垚鍚庣殑鍥炶皟
+     * @param business 閲岄潰鍖呭惈娴佺▼杩愯鐨勭幇鐘朵俊鎭紝涓氬姟灞傚彲鏍规嵁鍏朵俊鎭垽鏂紝涔﹀啓澧炲己涓氬姟閫昏緫鐨勪唬鐮侊紝<br/>
+     *                 1銆佹瘮濡傚皢鍏朵腑鍏抽敭淇℃伅瀛樺叆涓氬姟琛紝鍗冲彲鍗曡〃涓氬姟鎿嶄綔,鍚﹀垯闇�瑕佸叧鑱攆low_my_business琛ㄨ幏鍙栨祦绋嬩俊鎭�<br/>
+     *                 2銆佹瘮濡傚湪娴佺▼杩涜鍒版煇涓妭鐐规椂(business.taskId)锛岄渶瑕佺壒鍒繘琛屾煇浜涗笟鍔¢�昏緫鎿嶄綔绛夌瓑<br/>
+     */
+    void afterFlowHandle(FlowMyBusiness business);
+
+
+    /**
+     * 鏍规嵁涓氬姟id杩斿洖涓氬姟琛ㄥ崟鏁版嵁<br/>
+     * @param dataId
+     * @return
+     */
+    Object getBusinessDataById(String dataId);
+
+    /**
+     * 杩斿洖褰撳墠鑺傜偣鐨勬祦绋嬪彉閲�
+     * @param taskNameId 鑺傜偣瀹氫箟id
+     * @param values 鍓嶇浼犲叆鐨勫彉閲忥紝閲岄潰鍖呭惈dataId
+     * @return
+     */
+    Map<String, Object> flowValuesOfTask(String taskNameId, Map<String, Object> values);
+
+    /**
+     * 杩斿洖褰撳墠鑺傜偣鐨勫�欓�変汉username
+     * @param taskNameId 鑺傜偣瀹氫箟id
+     * @param values 鍓嶇浼犲叆鐨勫彉閲忥紝閲岄潰鍖呭惈dataId
+     * @return
+     */
+    List<String> flowCandidateUsernamesOfTask(String taskNameId, Map<String, Object> values);
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/FlowCommonService.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/FlowCommonService.java
new file mode 100644
index 0000000..90af8d8
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/FlowCommonService.java
@@ -0,0 +1,87 @@
+package org.jeecg.modules.flowable.apithird.service;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.jeecg.modules.flowable.apithird.business.entity.FlowMyBusiness;
+import org.jeecg.modules.flowable.apithird.business.service.impl.FlowMyBusinessServiceImpl;
+import org.jeecg.modules.flowable.apithird.common.exception.CustomException;
+import org.jeecg.modules.flowable.service.impl.FlowInstanceServiceImpl;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ *涓氬姟妯″潡璋冪敤API鐨勯泦鍚�
+ *@author PanMeiCheng
+ *@date 2021/11/22
+ *@version 1.0
+ */
+@Service
+public class FlowCommonService {
+    @Resource
+    FlowMyBusinessServiceImpl flowMyBusinessService;
+    @Resource
+    FlowInstanceServiceImpl flowInstanceService;
+    /**
+     * 鍒濆鐢熸垚鎴栦慨鏀逛笟鍔′笌娴佺▼鐨勫叧鑱斾俊鎭�<br/>
+     * 褰撲笟鍔℃ā鍧楁柊澧炰竴鏉℃暟鎹悗璋冪敤锛屾鏃朵笟鍔℃暟鎹叧鑱斾竴涓祦绋嬪畾涔夛紝浠ュ鍚庣画娴佺▼浣跨敤
+     * @return 鏄惁鎴愬姛
+     * @param title 蹇呭~銆傛祦绋嬩笟鍔$畝瑕佹弿杩般�備緥锛�2021骞�11鏈�26鏃xxxx鐢宠
+     * @param dataId 蹇呭~銆備笟鍔℃暟鎹甀d锛屽鏋滄槸涓�瀵瑰涓氬姟鍏崇郴锛屼紶鍏ヤ富琛ㄧ殑鏁版嵁Id
+     * @param serviceImplName 蹇呭~銆備笟鍔ervice娉ㄥ叆spring瀹瑰櫒鐨勫悕绉般��
+*                        渚嬪锛欯Service("demoService")鍒欎紶鍏� demoService
+     * @param processDefinitionKey 蹇呭~銆傛祦绋嬪畾涔塊ey锛屼紶鍏ユ鍊硷紝鏈潵鍚姩鐨勪細鏄绫绘祦绋嬬殑鏈�鏂颁竴涓増鏈�
+     * @param processDefinitionId 閫夊~銆傛祦绋嬪畾涔塈d锛屼紶鍏ユ鍊硷紝鏈潵鍚姩鐨勪负鎸囧畾鐗堟湰鐨勬祦绋�
+     */
+    public boolean initActBusiness(String title,String dataId, String serviceImplName, String processDefinitionKey, String processDefinitionId){
+        boolean hasBlank = StrUtil.hasBlank(title,dataId, serviceImplName, processDefinitionKey);
+        if (hasBlank) throw new CustomException("娴佺▼鍏抽敭鍙傛暟鏈~瀹屽叏锛乨ataId, serviceImplName, processDefinitionKey");
+        LambdaQueryWrapper<FlowMyBusiness> flowMyBusinessLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        flowMyBusinessLambdaQueryWrapper.eq(FlowMyBusiness::getDataId, dataId)
+        ;
+        FlowMyBusiness flowMyBusiness = new FlowMyBusiness();
+        FlowMyBusiness business = flowMyBusinessService.getOne(flowMyBusinessLambdaQueryWrapper);
+        if (business!=null){
+            flowMyBusiness = business;
+        } else {
+            flowMyBusiness.setId(IdUtil.fastSimpleUUID());
+        }
+        if (processDefinitionId==null){
+            // 浠ヤ究鏇存柊娴佺▼
+            processDefinitionId = "";
+        }
+        flowMyBusiness.setTitle(title)
+                .setDataId(dataId)
+                .setServiceImplName(serviceImplName)
+                .setProcessDefinitionKey(processDefinitionKey)
+                .setProcessDefinitionId(processDefinitionId)
+                ;
+        if (business!=null){
+            return flowMyBusinessService.updateById(flowMyBusiness);
+        } else {
+            return flowMyBusinessService.save(flowMyBusiness);
+        }
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼
+     * @param dataId
+     * @return
+     */
+    public boolean delActBusiness(String dataId){
+        boolean hasBlank = StrUtil.hasBlank(dataId);
+        if (hasBlank) throw new CustomException("娴佺▼鍏抽敭鍙傛暟鏈~瀹屽叏锛乨ataId");
+        LambdaQueryWrapper<FlowMyBusiness> flowMyBusinessQueryWrapper = new LambdaQueryWrapper<>();
+        flowMyBusinessQueryWrapper.eq(FlowMyBusiness::getDataId,dataId);
+        FlowMyBusiness one = flowMyBusinessService.getOne(flowMyBusinessQueryWrapper);
+        if (one.getProcessInstanceId()!=null){
+            try {
+                flowInstanceService.delete(one.getProcessInstanceId(),"鍒犻櫎娴佺▼");
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return flowMyBusinessService.remove(flowMyBusinessQueryWrapper);
+    }
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/IFlowThirdService.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/IFlowThirdService.java
new file mode 100644
index 0000000..b44dc01
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/apithird/service/IFlowThirdService.java
@@ -0,0 +1,56 @@
+package org.jeecg.modules.flowable.apithird.service;
+
+import org.jeecg.modules.flowable.apithird.entity.SysCategory;
+import org.jeecg.modules.flowable.apithird.entity.SysRole;
+import org.jeecg.modules.flowable.apithird.entity.SysUser;
+
+import java.util.List;
+
+/**
+ * 涓氬姟灞傞渶瀹炵幇鐨勬帴鍙e畾涔�<br/>
+ *  鏀拺宸ヤ綔娴佹ā鍧椾笌涓氬姟鐨勫叧鑱�
+ * @author pmc
+ */
+public interface IFlowThirdService {
+    /**
+     * 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛
+     *
+     * @return 褰撳墠鐧诲綍鐢ㄦ埛淇℃伅
+     */
+    public SysUser getLoginUser();
+    /**
+     * 鎵�鏈夌敤鎴�
+     * @return
+     */
+    List<SysUser> getAllUser();
+    /**
+     * 閫氳繃瑙掕壊id鑾峰彇鐢ㄦ埛
+     * @return
+     */
+    List<SysUser> getUsersByRoleId(String roleId);
+    /**
+     * 鏍规嵁鐢ㄦ埛username鏌ヨ鐢ㄦ埛淇℃伅
+     * @param username
+     * @return
+     */
+    SysUser getUserByUsername(String username);
+
+    /**
+     * 鑾峰彇鎵�鏈夎鑹�
+     * @return
+     */
+    public List<SysRole> getAllRole();
+    /**
+     * 鑾峰彇鎵�鏈夋祦绋嬪垎绫�
+     * @return
+     */
+    List<SysCategory> getAllCategory();
+    /**
+     * 閫氳繃鐢ㄦ埛璐﹀彿鏌ヨ閮ㄩ棬 name
+     * @param username
+     * @return 閮ㄩ棬 name
+     */
+    List<String> getDepartNamesByUsername(String username);
+
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/config/FlowableConfig.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/config/FlowableConfig.java
new file mode 100644
index 0000000..0680065
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/config/FlowableConfig.java
@@ -0,0 +1,68 @@
+package org.jeecg.modules.flowable.config;
+
+import org.flowable.engine.ProcessEngine;
+import org.flowable.engine.ProcessEngineConfiguration;
+import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;
+import org.flowable.eventregistry.impl.EventRegistryEngine;
+import org.flowable.eventregistry.impl.EventRegistryEngineConfiguration;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+
+import javax.sql.DataSource;
+
+@Configuration
+public class FlowableConfig {
+
+    @Value("${spring.datasource.dynamic.datasource.master.url}")
+    private String jdbcUrl;
+    @Value("${spring.datasource.dynamic.datasource.master.username}")
+    private String jdbcUsername;
+    @Value("${spring.datasource.dynamic.datasource.master.password}")
+    private String jdbcPassword;
+    @Value("${spring.datasource.dynamic.datasource.master.driver-class-name}")
+    private String jdbcDriver;
+
+    @Bean
+    public DataSource dataSource() {
+        DriverManagerDataSource dataSource = new DriverManagerDataSource();
+        dataSource.setUrl(jdbcUrl);
+        dataSource.setUsername(jdbcUsername);
+        dataSource.setPassword(jdbcPassword);
+        dataSource.setDriverClassName(jdbcDriver);
+        return dataSource;
+    }
+
+    @Bean(name = "processEngine")
+    @DependsOn("dataSource")
+    public ProcessEngine createProcessEngine(DataSource dataSource) {
+        StandaloneProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration();
+        cfg.setDataSource(dataSource);
+        cfg.setDatabaseType("mssql");
+
+        // 鍙互鏍规嵁闇�瑕佹坊鍔犳洿澶氶厤缃�
+        cfg.setActivityFontName("瀹嬩綋");
+        cfg.setLabelFontName("瀹嬩綋");
+        cfg.setAnnotationFontName("瀹嬩綋");
+
+        // 璁剧疆鏁版嵁搴撴ā寮忔洿鏂扮瓥鐣ヤ负鑷姩鏇存柊
+        cfg.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
+
+        return cfg.buildProcessEngine();
+    }
+
+    @Bean(name = "eventRegistryEngine")
+    public EventRegistryEngine eventRegistryEngine(DataSource dataSource) {
+        EventRegistryEngineConfiguration config = new EventRegistryEngineConfiguration();
+        config.setDataSource(dataSource);
+        //flase锛歛ctiviti鍦ㄥ惎鍔ㄦ椂锛屼細瀵规瘮鏁版嵁搴撹〃涓繚瀛樼殑鐗堟湰锛屽鏋滄病鏈夎〃鎴栬�呯増鏈笉鍖归厤锛屽皢鎶涘嚭寮傚父銆傦紙鐢熶骇鐜甯哥敤锛�
+        //true锛� activiti浼氬鏁版嵁搴撲腑鎵�鏈夎〃杩涜鏇存柊鎿嶄綔銆傚鏋滆〃涓嶅瓨鍦紝鍒欒嚜鍔ㄥ垱寤恒�傦紙寮�鍙戞椂甯哥敤锛�
+        config.setDatabaseSchemaUpdate("true");
+        return config.buildEventRegistryEngine();
+    }
+}
+
+
+
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/config/MyDefaultProcessDiagramCanvas.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/config/MyDefaultProcessDiagramCanvas.java
new file mode 100644
index 0000000..62daf40
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/config/MyDefaultProcessDiagramCanvas.java
@@ -0,0 +1,92 @@
+package org.jeecg.modules.flowable.config;
+
+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;
+
+/**
+ * 涓�浜涢厤缃�
+ */
+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/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/AssignStreamFlowController.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/AssignStreamFlowController.java
new file mode 100644
index 0000000..d41ab56
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/AssignStreamFlowController.java
@@ -0,0 +1,175 @@
+package org.jeecg.modules.flowable.controller;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.parser.Feature;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.SecurityUtils;
+import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.engine.HistoryService;
+import org.flowable.engine.ProcessEngine;
+import org.flowable.engine.ProcessEngineConfiguration;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.history.HistoricActivityInstance;
+import org.flowable.image.ProcessDiagramGenerator;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.TranslateDictTextUtils;
+import org.jeecg.modules.flowable.apithird.business.dto.FlowMyBusinessDto;
+import org.jeecg.modules.flowable.apithird.business.service.impl.FlowMyBusinessServiceImpl;
+import org.jeecg.modules.flowable.domain.dto.FlowTaskDto;
+import org.jeecg.modules.flowable.domain.vo.FlowHistoricalVo;
+import org.jeecg.modules.flowable.domain.vo.FlowMy;
+import org.jeecg.modules.flowable.domain.vo.WorkTaskDataVo;
+import org.jeecg.modules.flowable.service.IFlowTaskService;
+import org.jeecg.modules.flowable.service.IHisWorkTaskService;
+import org.jeecg.modules.flowable.service.IWorkTaskServiceVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Api(tags = "宸ヤ綔娴侀�氱敤涓氬姟鎺ュ彛")
+@RestController
+@RequestMapping("assign/flow")
+@Slf4j
+public class AssignStreamFlowController {
+    @Autowired
+    FlowMyBusinessServiceImpl flowMyBusinessService;
+    @Autowired
+    IFlowTaskService flowTaskService;
+    @Autowired
+    IWorkTaskServiceVo workTaskServicevo;
+    @Autowired
+    IHisWorkTaskService hisWorkTaskService;
+    @Autowired
+    private RepositoryService repositoryService;
+    @Autowired
+    private HistoryService historyService;
+    @Autowired
+    private ProcessEngine processEngine;
+    @Autowired
+    private ObjectMapper objectMapper;
+    @Autowired
+    private TranslateDictTextUtils translateDictTextUtils;
+
+    @ApiOperation(value = "鑾峰彇鎬诲彴璐�", response = FlowTaskDto.class)
+    @GetMapping(value = "/list")
+    public Result<IPage<FlowMyBusinessDto>> queryPageList(FlowMyBusinessDto flowMyBusinessDto,
+                                                       @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+                                                       @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+                                                       HttpServletRequest req) {
+        Page page = new Page(pageNo, pageSize);
+        IPage<FlowMyBusinessDto> pageList = flowMyBusinessService.getPageList(page, flowMyBusinessDto);
+        return Result.OK(pageList);
+    }
+
+    @ApiOperation(value = "閫氳繃浼犲叆TaskIds鍒ゆ柇鏄惁鍦ㄥ悓涓�鑺傜偣")
+    @GetMapping(value = "/isSameNode")
+    public Result isSameNode(@RequestParam(name = "taskIds") String taskIds) {
+        return flowTaskService.isSameNode(taskIds);
+    }
+
+    @ApiOperation(value = "鑾峰彇寰呭姙鍒楄〃", response = FlowTaskDto.class)
+    @GetMapping(value = "/todoList")
+    public Result todoList(@ApiParam(value = "褰撳墠椤电爜", required = true) @RequestParam (name="pageNum", defaultValue="1") Integer pageNum,
+                           @ApiParam(value = "姣忛〉鏉℃暟", required = true) @RequestParam (name="pageSize", defaultValue="10") Integer pageSize) {
+        return flowTaskService.todoList(pageNum, pageSize);
+    }
+    @ApiOperation(value = "鑾峰彇鏈韩寰呭姙", response = FlowTaskDto.class)
+    @GetMapping(value = "/toTaskBySelf")
+    public Result<IPage<WorkTaskDataVo>> toTaskBySelf(FlowMy flowMy, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                      @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
+        Page page = new Page(pageNo, pageSize);
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        flowMy.setUsername(user.getUsername());
+        return Result.OK(workTaskServicevo.toTaskBySelf(flowMy,page));
+    }
+
+    @ApiOperation(value = "鑾峰彇宸插姙浠诲姟", response = FlowTaskDto.class)
+    @GetMapping(value = "/finishedList")
+    public Result<?> finishedList(@ApiParam(value = "褰撳墠椤电爜", required = true) @RequestParam Integer pageNo,
+                               @ApiParam(value = "姣忛〉鏉℃暟", required = true) @RequestParam Integer pageSize,
+                                  FlowMyBusinessDto flowMyBusinessDto) {
+        return flowTaskService.finishedList(pageNo, pageSize,flowMyBusinessDto);
+    }
+
+
+    @ApiOperation(value = "鑾峰彇宸ヤ綔娴佸巻鍙蹭换鍔�", response = FlowTaskDto.class)
+    @GetMapping(value = "/queryHisTaskList")
+    public Result<?> queryHisTaskList(@RequestParam(name = "procInstId") String procInstId) {
+        List<FlowHistoricalVo> flowHistoricalVos = hisWorkTaskService.queryHisTaskByProcInstId(procInstId);
+        if(CollectionUtil.isEmpty(flowHistoricalVos)) {
+            return Result.OK(Collections.emptyList());
+        }
+        List<JSONObject> items = new ArrayList<>();
+        try {
+            for(FlowHistoricalVo vo : flowHistoricalVos) {
+                String json = objectMapper.writeValueAsString(vo);
+                JSONObject item = JSONObject.parseObject(json, Feature.OrderedField);
+                translateDictTextUtils.translateField("assignee", vo.getAssignee(), item, "sys_user,realname,username");
+                items.add(item);
+            }
+            return Result.OK(items);
+        }catch (Exception e) {
+            return Result.error("鏁版嵁杞瘧澶辫触锛�");
+        }
+    }
+
+    @ApiOperation(value = "瀹℃壒浠诲姟-鏌ョ湅娴佺▼鍥�")
+    @GetMapping("/diagramView")
+    public void showImages(@RequestParam(name = "processDefinitionId") String processDefinitionId,
+                           @RequestParam(name = "processInstanceId") String processInstanceId,
+                           @RequestParam(name = "TaskDefinitionKey") String TaskDefinitionKey,
+                           HttpServletResponse response) throws IOException {
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
+        List<HistoricActivityInstance> historyProcess = historyService.createHistoricActivityInstanceQuery()
+                .processInstanceId(processInstanceId)
+                .finished()
+                .list();
+
+        List<String> activityIds = new ArrayList<>();
+        List<String> flows = new ArrayList<>();
+
+        for (HistoricActivityInstance hi : historyProcess) {
+            String activityType = hi.getActivityType();
+            if (activityType.equals("sequenceFlow") || activityType.equals("exclusiveGateway")) {
+                flows.add(hi.getActivityId());
+            } else if (activityType.equals("userTask") || activityType.equals("startEvent")) {
+                activityIds.add(hi.getActivityId());
+            }
+        }
+        activityIds.add(TaskDefinitionKey);
+        ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();
+        ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator();
+
+        InputStream in = processDiagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows,
+                engConf.getActivityFontName(), engConf.getLabelFontName(), engConf.getAnnotationFontName(),
+                engConf.getClassLoader(), 1.0, true);
+
+        OutputStream out = response.getOutputStream();
+        byte[] buf = new byte[1024];
+        int length = 0;
+        while ((length = in.read(buf)) != -1) {
+            out.write(buf, 0, length);
+        }
+        in.close();
+        out.close();
+    }
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowDefinitionController.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowDefinitionController.java
new file mode 100644
index 0000000..6e17eea
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowDefinitionController.java
@@ -0,0 +1,243 @@
+package org.jeecg.modules.flowable.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.flowable.apithird.entity.SysCategory;
+import org.jeecg.modules.flowable.apithird.entity.SysRole;
+import org.jeecg.modules.flowable.apithird.entity.SysUser;
+import org.jeecg.modules.flowable.apithird.service.IFlowThirdService;
+import org.jeecg.modules.flowable.domain.dto.FlowProcDefDto;
+import org.jeecg.modules.flowable.domain.dto.FlowSaveXmlVo;
+import org.jeecg.modules.flowable.service.IFlowDefinitionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+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>
+ *
+ */
+@Slf4j
+@Api(tags = "娴佺▼瀹氫箟")
+@RestController
+@RequestMapping("/flowable/definition")
+public class FlowDefinitionController {
+
+    @Autowired
+    private IFlowDefinitionService flowDefinitionService;
+
+    @Autowired
+    private IFlowThirdService iFlowThirdService;
+
+
+
+    @GetMapping(value = "/list")
+    @ApiOperation(value = "娴佺▼瀹氫箟鍒楄〃", response = FlowProcDefDto.class)
+    public Result list(@ApiParam(value = "褰撳墠椤电爜", required = true) @RequestParam Integer pageNum,
+                           @ApiParam(value = "姣忛〉鏉℃暟", required = true) @RequestParam Integer pageSize,
+                       FlowProcDefDto flowProcDefDto
+    ) {
+        return Result.OK(flowDefinitionService.list(pageNum, pageSize,flowProcDefDto));
+    }
+
+
+    @ApiOperation(value = "瀵煎叆娴佺▼鏂囦欢", notes = "涓婁紶bpmn20鐨剎ml鏂囦欢")
+    @PostMapping("/import")
+    public Result 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 Result.OK(e.getMessage());
+        } finally {
+            try {
+                if (in != null) {
+                    in.close();
+                }
+            } catch (IOException e) {
+                log.error("鍏抽棴杈撳叆娴佸嚭閿�", e);
+            }
+        }
+
+        return Result.OK("瀵煎叆鎴愬姛");
+    }
+
+
+    @ApiOperation(value = "璇诲彇xml鏂囦欢")
+    @GetMapping("/readXml/{deployId}")
+    public Result readXml(@ApiParam(value = "娴佺▼瀹氫箟id") @PathVariable(value = "deployId") String deployId) {
+        try {
+            return flowDefinitionService.readXml(deployId);
+        } catch (Exception e) {
+            return Result.error("鍔犺浇xml鏂囦欢寮傚父");
+        }
+
+    }
+    @ApiOperation(value = "璇诲彇xml鏂囦欢")
+    @GetMapping("/readXmlByDataId/{dataId}")
+    public Result readXmlByDataId(@ApiParam(value = "娴佺▼瀹氫箟id") @PathVariable(value = "dataId") String dataId) {
+        try {
+            return flowDefinitionService.readXmlByDataId(dataId);
+        } catch (Exception e) {
+            return Result.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 = "璇诲彇鍥剧墖鏂囦欢")
+    @GetMapping("/readImageByDataId/{dataId}")
+    public void readImageByDataId(@ApiParam(value = "娴佺▼鏁版嵁涓氬姟id") @PathVariable(value = "dataId") String dataId, HttpServletResponse response) {
+        OutputStream os = null;
+        BufferedImage image = null;
+        try {
+            image = ImageIO.read(flowDefinitionService.readImageByDataId(dataId));
+            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鏂囦欢")
+    @PostMapping("/save")
+    public Result 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 Result.OK(e.getMessage());
+        } finally {
+            try {
+                if (in != null) {
+                    in.close();
+                }
+            } catch (IOException e) {
+                log.error("鍏抽棴杈撳叆娴佸嚭閿�", e);
+            }
+        }
+
+        return Result.OK("瀵煎叆鎴愬姛");
+    }
+
+
+    @ApiOperation(value = "鏍规嵁娴佺▼瀹氫箟id鍚姩娴佺▼瀹炰緥")
+    @PostMapping("/startByProcDefId/{procDefId}")
+    public Result startByProcDefId(@ApiParam(value = "娴佺▼瀹氫箟id") @PathVariable(value = "procDefId") String procDefId,
+                        @ApiParam(value = "鍙橀噺闆嗗悎,json瀵硅薄") @RequestBody Map<String, Object> variables) {
+        return flowDefinitionService.startProcessInstanceById(procDefId, variables);
+
+    }
+    @ApiOperation(value = "鏍规嵁娴佺▼瀹氫箟key鍚姩娴佺▼瀹炰緥")
+    @PostMapping("/startByProcDefKey/{procDefKey}")
+    public Result startByProcDefKey(@ApiParam(value = "娴佺▼瀹氫箟id") @PathVariable(value = "procDefKey") String procDefKey,
+                        @ApiParam(value = "鍙橀噺闆嗗悎,json瀵硅薄") @RequestBody Map<String, Object> variables) {
+        return flowDefinitionService.startProcessInstanceByKey(procDefKey, variables);
+
+    }
+    @ApiOperation(value = "鏍规嵁鏁版嵁Id鍚姩娴佺▼瀹炰緥")
+    @PostMapping("/startByDataId/{dataId}")
+    public Result startByDataId(@ApiParam(value = "娴佺▼瀹氫箟id") @PathVariable(value = "dataId") String dataId,
+                        @ApiParam(value = "鍙橀噺闆嗗悎,json瀵硅薄") @RequestBody Map<String, Object> variables) {
+        variables.put("dataId",dataId);
+        return flowDefinitionService.startProcessInstanceByDataId(dataId, variables);
+
+    }
+
+    @ApiOperation(value = "婵�娲绘垨鎸傝捣娴佺▼瀹氫箟")
+    @PutMapping(value = "/updateState")
+    public Result updateState(@ApiParam(value = "1:婵�娲�,2:鎸傝捣", required = true) @RequestParam Integer state,
+                                  @ApiParam(value = "娴佺▼閮ㄧ讲ID", required = true) @RequestParam String deployId) {
+        flowDefinitionService.updateState(state, deployId);
+        return Result.OK("鎿嶄綔鎴愬姛");
+    }
+
+    @ApiOperation(value = "鍒犻櫎娴佺▼")
+    @DeleteMapping(value = "/delete")
+    public Result delete(@ApiParam(value = "娴佺▼閮ㄧ讲ID", required = true) @RequestParam String deployId) {
+        flowDefinitionService.delete(deployId);
+        return Result.OK();
+    }
+
+    @ApiOperation(value = "鎸囧畾娴佺▼鍔炵悊浜哄憳鍒楄〃")
+    @GetMapping("/userList")
+    public Result userList(SysUser user) {
+        List<SysUser> list = iFlowThirdService.getAllUser();
+        return Result.OK(list);
+    }
+
+    @ApiOperation(value = "鎸囧畾娴佺▼鍔炵悊缁勫垪琛�")
+    @GetMapping("/roleList")
+    public Result roleList(SysRole role) {
+        List<SysRole> list = iFlowThirdService.getAllRole();
+        return Result.OK(list);
+    }
+    @ApiOperation(value = "鎸囧畾娴佺▼鍔炵悊缁勫垪琛�")
+    @GetMapping("/categoryList")
+    public Result categoryList(SysCategory category) {
+        List<SysCategory> list = iFlowThirdService.getAllCategory();
+        return Result.OK(list);
+    }
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowInstanceController.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowInstanceController.java
new file mode 100644
index 0000000..176d5cd
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowInstanceController.java
@@ -0,0 +1,63 @@
+package org.jeecg.modules.flowable.controller;
+
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.flowable.service.IFlowInstanceService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>宸ヤ綔娴佹祦绋嬪疄渚嬬鐞�<p>
+ */
+@Slf4j
+@Api(tags = "宸ヤ綔娴佹祦绋嬪疄渚嬬鐞�")
+@RestController
+@RequestMapping("/flowable/instance")
+public class FlowInstanceController {
+
+    @Autowired
+    private IFlowInstanceService flowInstanceService;
+
+    /*@ApiOperation(value = "鏍规嵁娴佺▼瀹氫箟id鍚姩娴佺▼瀹炰緥")
+    @PostMapping("/startBy/{procDefId}")
+    public Result 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 Result updateState(@ApiParam(value = "1:婵�娲�,2:鎸傝捣", required = true) @RequestParam Integer state,
+                              @ApiParam(value = "娴佺▼瀹炰緥ID", required = true) @RequestParam String instanceId) {
+        flowInstanceService.updateState(state,instanceId);
+        return Result.OK();
+    }
+
+    /*@ApiOperation("缁撴潫娴佺▼瀹炰緥")
+    @PostMapping(value = "/stopProcessInstance")
+    public Result stopProcessInstance(@RequestBody FlowTaskVo flowTaskVo) {
+        flowInstanceService.stopProcessInstance(flowTaskVo);
+        return Result.OK();
+    }*/
+
+    @ApiOperation(value = "鍒犻櫎娴佺▼瀹炰緥")
+    @DeleteMapping(value = "/delete")
+    public Result delete(@ApiParam(value = "娴佺▼瀹炰緥ID", required = true) @RequestParam String instanceId,
+                             @ApiParam(value = "鍒犻櫎鍘熷洜") @RequestParam(required = false) String deleteReason) {
+        flowInstanceService.delete(instanceId,deleteReason);
+        return Result.OK();
+    }
+    @ApiOperation(value = "鍒犻櫎娴佺▼瀹炰緥")
+    @PostMapping(value = "/deleteByDataId")
+    public Result deleteByDataId(@ApiParam(value = "娴佺▼瀹炰緥鍏宠仈涓氬姟ID", required = true) @RequestParam String dataId,
+                             @ApiParam(value = "鍒犻櫎鍘熷洜") @RequestParam(required = false) String deleteReason) {
+        flowInstanceService.deleteByDataId(dataId,deleteReason);
+        return Result.OK();
+    }
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowTaskController.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowTaskController.java
new file mode 100644
index 0000000..030a714
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/controller/FlowTaskController.java
@@ -0,0 +1,213 @@
+package org.jeecg.modules.flowable.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.flowable.domain.dto.FlowNextDto;
+import org.jeecg.modules.flowable.domain.dto.FlowTaskDto;
+import org.jeecg.modules.flowable.domain.vo.FlowTaskVo;
+import org.jeecg.modules.flowable.service.IFlowTaskService;
+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;
+import java.util.List;
+
+/**
+ * <p>宸ヤ綔娴佷换鍔$鐞�<p>
+ *
+ */
+@Slf4j
+@Api(tags = "宸ヤ綔娴佹祦绋嬩换鍔$鐞�")
+@RestController
+@RequestMapping("/flowable/task")
+public class FlowTaskController {
+
+    @Autowired
+    private IFlowTaskService flowTaskService;
+
+    @ApiOperation(value = "鎴戝彂璧风殑娴佺▼", response = FlowTaskDto.class)
+    @GetMapping(value = "/myProcess")
+    public Result myProcess(@ApiParam(value = "褰撳墠椤电爜", required = true) @RequestParam Integer pageNum,
+                                @ApiParam(value = "姣忛〉鏉℃暟", required = true) @RequestParam Integer pageSize) {
+        return flowTaskService.myProcess(pageNum, pageSize);
+    }
+
+    @ApiOperation(value = "鍙栨秷鐢宠", response = FlowTaskDto.class)
+    @PostMapping(value = "/stopProcess")
+    public Result stopProcess(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.stopProcess(flowTaskVo);
+    }
+
+    @ApiOperation(value = "鎾ゅ洖娴佺▼", response = FlowTaskDto.class)
+    @PostMapping(value = "/revokeProcess")
+    public Result revokeProcess(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.revokeProcess(flowTaskVo);
+    }
+
+    @ApiOperation(value = "鑾峰彇寰呭姙鍒楄〃", response = FlowTaskDto.class)
+    @GetMapping(value = "/todoList")
+    public Result todoList(@ApiParam(value = "褰撳墠椤电爜", required = true) @RequestParam Integer pageNum,
+                               @ApiParam(value = "姣忛〉鏉℃暟", required = true) @RequestParam Integer pageSize) {
+        return flowTaskService.todoList(pageNum, pageSize);
+    }
+
+    @ApiOperation(value = "娴佺▼鍘嗗彶娴佽浆璁板綍", response = FlowTaskDto.class)
+    @GetMapping(value = "/flowRecord")
+    public Result flowRecord(String dataId) {
+        return flowTaskService.flowRecord(dataId);
+    }
+
+    @ApiOperation(value = "鑾峰彇娴佺▼鍙橀噺", response = FlowTaskDto.class)
+    @GetMapping(value = "/processVariables/{taskId}")
+    public Result processVariables(@ApiParam(value = "娴佺▼浠诲姟Id")  @PathVariable(value = "taskId") String taskId) {
+        return flowTaskService.processVariables(taskId);
+    }
+
+    @ApiOperation(value = "瀹℃壒浠诲姟")
+    @PostMapping(value = "/complete")
+    public Result complete(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.complete(flowTaskVo);
+    }
+    @ApiOperation(value = "瀹℃壒浠诲姟")
+    @PostMapping(value = "/completeByDateId")
+    public Result completeByDateId(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.completeByDateId(flowTaskVo);
+    }
+
+    @ApiOperation(value = "椹冲洖浠诲姟")
+    @PostMapping(value = "/reject")
+    public Result taskReject(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.taskReject(flowTaskVo);
+        return Result.OK();
+    }
+    @ApiOperation(value = "椹冲洖浠诲姟")
+    @PostMapping(value = "/taskRejectByDataId")
+    public Result taskRejectByDataId(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.taskRejectByDataId(flowTaskVo);
+        return Result.OK();
+    }
+
+    @ApiOperation(value = "閫�鍥炰换鍔�")
+    @PostMapping(value = "/return")
+    public Result taskReturn(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.taskReturn(flowTaskVo);
+        return Result.OK();
+    }
+    @ApiOperation(value = "閫�鍥炰换鍔�")
+    @PostMapping(value = "/taskReturnByDataId")
+    public Result taskReturnByDataId(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.taskReturnByDataId(flowTaskVo);
+        return Result.OK();
+    }
+
+    @ApiOperation(value = "鑾峰彇鎵�鏈夊彲鍥為��鐨勮妭鐐�")
+    @PostMapping(value = "/returnList")
+    public Result findReturnTaskList(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.findReturnTaskList(flowTaskVo);
+    }
+    @ApiOperation(value = "鑾峰彇鎵�鏈夊彲鍥為��鐨勮妭鐐�")
+    @PostMapping(value = "/findReturnTaskListByDataId")
+    public Result findReturnTaskListByDataId(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.findReturnTaskListByDataId(flowTaskVo);
+    }
+
+    @ApiOperation(value = "鍒犻櫎浠诲姟")
+    @DeleteMapping(value = "/delete")
+    public Result delete(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.deleteTask(flowTaskVo);
+        return Result.OK();
+    }
+
+    @ApiOperation(value = "璁ら/绛炬敹浠诲姟")
+    @PostMapping(value = "/claim")
+    public Result claim(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.claim(flowTaskVo);
+        return Result.OK();
+    }
+
+    @ApiOperation(value = "鍙栨秷璁ら/绛炬敹浠诲姟")
+    @PostMapping(value = "/unClaim")
+    public Result unClaim(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.unClaim(flowTaskVo);
+        return Result.OK();
+    }
+
+    @ApiOperation(value = "濮旀淳浠诲姟")
+    @PostMapping(value = "/delegate")
+    public Result delegate(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.delegateTask(flowTaskVo);
+        return Result.OK();
+    }
+
+    @ApiOperation(value = "杞姙浠诲姟")
+    @PostMapping(value = "/assign")
+    public Result assign(@RequestBody FlowTaskVo flowTaskVo) {
+        flowTaskService.assignTask(flowTaskVo);
+        return Result.OK();
+    }
+
+    @ApiOperation(value = "鑾峰彇涓嬩竴鑺傜偣")
+    @PostMapping(value = "/nextFlowNode")
+    public Result<List<FlowNextDto>> getNextFlowNode(@RequestBody FlowTaskVo flowTaskVo) {
+        return flowTaskService.getNextFlowNode(flowTaskVo);
+    }
+
+    /**
+     * 鐢熸垚娴佺▼鍥�
+     *
+     * @param processId 浠诲姟ID
+     */
+    @RequestMapping("/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 浠诲姟ID
+     */
+    @RequestMapping("/flowViewer/{procInsId}")
+    public Result getFlowViewer(@PathVariable("procInsId") String procInsId) {
+        return Result.OK(flowTaskService.getFlowViewer(procInsId));
+    }
+    /**
+     * 鐢熸垚娴佺▼鍥�
+     *
+     * @param dataId 浠诲姟鏁版嵁ID
+     */
+    @RequestMapping("/flowViewerByDataId/{dataId}")
+    public Result getFlowViewerByDataId(@PathVariable("dataId") String dataId) {
+        return Result.OK(flowTaskService.getFlowViewerByDataId(dataId));
+    }
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowCommentDto.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowCommentDto.java
new file mode 100644
index 0000000..512dfc6
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowCommentDto.java
@@ -0,0 +1,24 @@
+package org.jeecg.modules.flowable.domain.dto;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 鍩虹甯搁噺
+ */
+@Data
+@Builder
+public class FlowCommentDto implements Serializable {
+
+    /**
+     * 鎰忚绫诲埆 0 姝e父鎰忚  1 閫�鍥炴剰瑙� 2 椹冲洖鎰忚
+     */
+    private String type;
+
+    /**
+     * 鎰忚鍐呭
+     */
+    private String comment;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowNextDto.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowNextDto.java
new file mode 100644
index 0000000..851333f
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowNextDto.java
@@ -0,0 +1,24 @@
+package org.jeecg.modules.flowable.domain.dto;
+
+import lombok.Data;
+import org.flowable.bpmn.model.UserTask;
+import org.jeecg.modules.flowable.apithird.entity.SysUser;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 浜哄憳銆佺粍
+ */
+@Data
+public class FlowNextDto implements Serializable {
+    /**
+     * 鑺傜偣瀵硅薄
+     */
+    private UserTask userTask;
+    /**
+     * 寰呭姙浜哄憳
+     */
+    private List<SysUser> userList;
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowProcDefDto.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowProcDefDto.java
new file mode 100644
index 0000000..24e7108
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowProcDefDto.java
@@ -0,0 +1,56 @@
+package org.jeecg.modules.flowable.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>
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@ApiModel("娴佺▼瀹氫箟")
+public class FlowProcDefDto implements Serializable {
+
+    @ApiModelProperty("娴佺▼id")
+    private String id;
+
+    @ApiModelProperty("娴佺▼鍚嶇О")
+    private String name;
+
+    @ApiModelProperty("娴佺▼key")
+    private String key;
+
+    @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("娴佺▼瀹氫箟鏄惁鏈�鏂扮増鏈�")
+    private int isLastVersion;
+
+    @ApiModelProperty("閮ㄧ讲鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date deploymentTime;
+
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowSaveXmlVo.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowSaveXmlVo.java
new file mode 100644
index 0000000..c8deb52
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowSaveXmlVo.java
@@ -0,0 +1,27 @@
+package org.jeecg.modules.flowable.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 娴佺▼瑙勮寖xml
+ */
+@Data
+public class FlowSaveXmlVo implements Serializable {
+
+    /**
+     * 娴佺▼鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 娴佺▼鍒嗙被
+     */
+    private String category;
+
+    /**
+     * xml 鏂囦欢
+     */
+    private String xml;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowTaskDto.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowTaskDto.java
new file mode 100644
index 0000000..6775bed
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowTaskDto.java
@@ -0,0 +1,121 @@
+package org.jeecg.modules.flowable.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 org.jeecg.common.aspect.annotation.Dict;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * <p>宸ヤ綔娴佷换鍔�<p>
+ *
+ */
+@Getter
+@Setter
+@ApiModel("宸ヤ綔娴佷换鍔$浉鍏�-杩斿洖鍙傛暟")
+public class FlowTaskDto implements Serializable {
+
+    @ApiModelProperty("浠诲姟缂栧彿")
+    private String taskId;
+
+    @ApiModelProperty("浠诲姟鍚嶇О")
+    private String taskName;
+
+    @ApiModelProperty("浠诲姟Key")
+    private String taskDefKey;
+
+    @ApiModelProperty("浠诲姟鎵ц浜篒d")
+    private String assigneeId;
+
+    @ApiModelProperty("浠诲姟鎻忚堪")
+    private String description;
+
+    @ApiModelProperty("閮ㄩ棬鍚嶇О")
+    private String deptName;
+
+    @ApiModelProperty("娴佺▼鍙戣捣浜洪儴闂ㄥ悕绉�")
+    private String startDeptName;
+
+    @ApiModelProperty("浠诲姟鎵ц浜哄悕绉�")
+    private String assigneeName;
+
+    @ApiModelProperty("娴佺▼鍙戣捣浜篒d")
+    private String startUserId;
+
+    @ApiModelProperty("娴佺▼鍙戣捣浜哄悕绉�")
+    private String startUserName;
+
+    @ApiModelProperty("娴佺▼绫诲瀷")
+    @Dict(dicCode = "flow_type")
+    private String category;
+
+    @ApiModelProperty("娴佺▼鍙橀噺淇℃伅")
+    private Object procVars;
+
+    @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("涓氬姟琛╥d锛岀悊璁哄敮涓�")
+    private String dataId;
+
+    @ApiModelProperty("浠诲姟鍒涘缓鏃堕棿")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    @ApiModelProperty("浠诲姟瀹屾垚鏃堕棿")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date finishTime;
+
+    /**娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d*/
+    @Excel(name = "娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d", width = 15)
+    @ApiModelProperty(value = "娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d")
+    private String processDefinitionKey;
+    /**娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�*/
+    @Excel(name = "娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�", width = 15)
+    @ApiModelProperty(value = "娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�")
+    private String processDefinitionId;
+    /**娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�*/
+    @Excel(name = "娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�", width = 15)
+    @ApiModelProperty(value = "娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�")
+    private String processInstanceId;
+    /**褰撳墠鐨勮妭鐐瑰彲浠ュ鐞嗙殑鐢ㄦ埛鍚嶏紝涓簎sername鐨勯泦鍚坖son瀛楃涓�*/
+    @Excel(name = "褰撳墠鐨勮妭鐐瑰彲浠ュ鐞嗙殑鐢ㄦ埛鍚�", width = 15)
+    @ApiModelProperty(value = "褰撳墠鐨勮妭鐐瑰彲浠ュ鐞嗙殑鐢ㄦ埛鍚�")
+    @Dict(dictTable = "sys_user", dicCode = "username", dicText = "realname")
+    private String todoUsers;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowViewerDto.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowViewerDto.java
new file mode 100644
index 0000000..a195a2a
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/dto/FlowViewerDto.java
@@ -0,0 +1,15 @@
+package org.jeecg.modules.flowable.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ */
+@Data
+public class FlowViewerDto implements Serializable {
+
+    private String key;
+    private boolean completed;
+    private boolean back;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowHistoricalVo.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowHistoricalVo.java
new file mode 100644
index 0000000..2a858bf
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowHistoricalVo.java
@@ -0,0 +1,79 @@
+package org.jeecg.modules.flowable.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ * 宸ヤ綔娴佸巻鍙茶褰曪紙閫氱敤锛�
+ *
+ */
+@Data
+@ApiModel("宸ヤ綔娴�--宸ヤ綔娴佸巻鍙茶褰曪紙閫氱敤锛�")
+public class FlowHistoricalVo {
+    /**
+     * 娴佺▼瀹炰緥ID
+     */
+    private String procInstId;
+    /**
+     * 涓氬姟閿�
+     */
+    private String businessKey;
+    /**
+     * 娴佺▼寮�濮嬫椂闂�
+     */
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date startTime;
+    /**
+     * 娴佺▼缁撴潫鏃堕棿
+     */
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date endTime;
+    /**
+     * 鑺傜偣鍚嶇О
+     */
+    private String actName;
+    /**
+     * 鑺傜偣绫诲瀷
+     */
+    private String actType;
+    /**
+     * 鑺傜偣寮�濮嬫椂闂�
+     */
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date actStartTime;
+    /**
+     * 鑺傜偣缁撴潫鏃堕棿
+     */
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date actEndTime;
+    /**
+     * 浠诲姟鍚嶇О
+     */
+    private String taskName;
+    /**
+     * 澶勭悊浜�
+     */
+    @Dict(dictTable = "sys_user", dicCode = "username", dicText = "realname")
+    private String assignee;
+    /**
+     * 浠诲姟鑰楁椂
+     */
+    private String duration;
+    /**
+     * 浠诲姟鎻忚堪
+     */
+    private String description;
+    /**
+     * 澶勭悊缁撴灉
+     */
+    private String sequenceFlowName;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowMy.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowMy.java
new file mode 100644
index 0000000..7602af0
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowMy.java
@@ -0,0 +1,42 @@
+package org.jeecg.modules.flowable.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/**
+ * <p>娴佺▼浠诲姟<p>
+ *
+ */
+@Data
+@ApiModel("宸ヤ綔娴�--寰呭姙宸插姙鍙拌处")
+public class FlowMy {
+    /**
+     * 娴佺▼鍚嶇О
+     */
+    private String flowName;
+    /**
+     * 娴佺▼涓氬姟绠�瑕佹弿杩�
+     */
+    private String title;
+    /**
+     * 鐢ㄦ埛username
+     */
+    private String username;
+    /**
+     * 寮�濮嬫椂闂�
+     */
+    private String startTime;
+    /**
+     * 缁撴潫鏃堕棿
+     */
+    private String endTime;
+    /**
+     * 娴佺▼鍒嗙被
+     */
+    private String category;
+
+    /**
+     * 褰撳墠鑺傜偣鍚嶇О
+     */
+    private String name;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowTaskVo.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowTaskVo.java
new file mode 100644
index 0000000..574c55a
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/FlowTaskVo.java
@@ -0,0 +1,47 @@
+package org.jeecg.modules.flowable.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>
+ *
+ */
+@Data
+@ApiModel("宸ヤ綔娴佷换鍔$浉鍏�--璇锋眰鍙傛暟")
+public class FlowTaskVo {
+
+    @ApiModelProperty("鏁版嵁Id")
+    private String dataId;
+    @ApiModelProperty("浠诲姟Id")
+    private String taskId;
+
+    @ApiModelProperty("鐢ㄦ埛Id")
+    private String userId;
+
+    @ApiModelProperty("浠诲姟鎰忚")
+    private String comment;
+
+    @ApiModelProperty("娴佺▼瀹炰緥Id")
+    private String instanceId;
+
+    @ApiModelProperty("鑺傜偣")
+    private String targetKey;
+
+    @ApiModelProperty("娴佺▼鍙橀噺淇℃伅")
+    private Map<String, Object> values;
+
+    @ApiModelProperty("瀹℃壒浜�")
+    private String assignee;
+
+    @ApiModelProperty("鍊欓�変汉")
+    private List<String> candidateUsers;
+
+    @ApiModelProperty("瀹℃壒缁�")
+    private List<String> candidateGroups;
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/HisWorkTask.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/HisWorkTask.java
new file mode 100644
index 0000000..e579a4f
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/HisWorkTask.java
@@ -0,0 +1,45 @@
+package org.jeecg.modules.flowable.domain.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+
+/**
+ * @Description:宸ヤ綔娴佸巻鍙�
+ */
+@Data
+@TableName("act_hi_taskinst")
+@ApiModel(value="act_hi_taskinst", description="宸ヤ綔娴佸巻鍙蹭换鍔℃暟鎹�")
+public class HisWorkTask implements Serializable {
+	/**涓婚敭*/
+    //flow_my_business
+    @TableId(value = "id")
+    private String id;
+    @TableField("name")
+    private String name;
+    @TableField("cause")
+    private String cause;
+    /**鎵ц瀹炰緥ID锛屼笌鎵ц瀹炰緥琛ㄤ腑鐨処D瀛楁鍏宠仈*/
+    @TableField("assignee")
+    private String assignee;
+    /**娴佺▼瀹炰緥ID锛屼笌娴佺▼瀹炰緥琛ㄤ腑鐨処D瀛楁鍏宠仈*/
+    @TableField("startTime")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private String startTime;
+    /**娴佺▼瀹氫箟ID锛屼笌娴佺▼瀹氫箟琛ㄤ腑鐨処D瀛楁鍏宠仈*/
+    @TableField("endTime")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private String endTime;
+
+    @Dict(dicCode = "dnc_assign_stream_status")
+    private transient String status;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/WorkTaskData.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/WorkTaskData.java
new file mode 100644
index 0000000..510285d
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/WorkTaskData.java
@@ -0,0 +1,117 @@
+package org.jeecg.modules.flowable.domain.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description:宸ヤ綔娴佷换鍔℃暟鎹�
+ */
+@Data
+@TableName("act_ru_task")
+@ApiModel(value="act_ru_task", description="宸ヤ綔娴佷换鍔℃暟鎹�")
+public class WorkTaskData implements Serializable {
+	/**涓婚敭*/
+    @TableId("id_")
+    private String id;
+    /**鐗堟湰鍙凤紝鐢ㄤ簬涔愯閿佹帶鍒跺苟鍙戞洿鏂�*/
+    @TableField("rev_")
+    private int rev;
+    /**鎵ц瀹炰緥ID锛屼笌鎵ц瀹炰緥琛ㄤ腑鐨処D瀛楁鍏宠仈*/
+    @TableField("execution_id_")
+    private String executionId;
+    /**娴佺▼瀹炰緥ID锛屼笌娴佺▼瀹炰緥琛ㄤ腑鐨処D瀛楁鍏宠仈*/
+    @TableField("proc_inst_id_")
+    private String procInstId;
+    /**娴佺▼瀹氫箟ID锛屼笌娴佺▼瀹氫箟琛ㄤ腑鐨処D瀛楁鍏宠仈*/
+    @TableField("proc_def_id_")
+    private String procDefId;
+    /**浠诲姟鍚嶇О*/
+    @TableField("name_")
+    private String name;
+    /**浠诲姟瀹氫箟Key锛屼笌娴佺▼瀹氫箟琛ㄤ腑鐨凨EY瀛楁鍏宠仈*/
+    @TableField("task_def_key_")
+    private String taskDefKey;
+    /**浠诲姟鐨勫姙鐞嗕汉锛屽嵆瀹為檯鎵ц浠诲姟鐨勭敤鎴�*/
+    @TableField("assignee_")
+    private String assignee;
+    /**浠诲姟鐨勪紭鍏堢骇*/
+    @TableField("priority_")
+    private int priority;
+    /**	浠诲姟鍒涘缓鏃堕棿*/
+    @TableField("create_time_")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+    /**		浠诲姟鐨勬殏鍋滅姸鎬侊紝鐢ㄤ簬鎺у埗浠诲姟鐨勬殏鍋滃拰鎭㈠*/
+    @TableField("suspension_state_")
+    private int suspensionState;
+
+
+
+    /**鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("task_def_id_")
+    private String taskDefId;
+    /**鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("scope_id_")
+    private String scopeId;
+    /**鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("sub_scope_id_")
+    private String subScopeId;
+    /**鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("scope_type_")
+    private String scopeType;
+    /**鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("scope_definition_id_")
+    private String scopeDefinitionId;
+    /**鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("propagated_stage_inst_id_")
+    private String propagatedStageInstId;
+    /**鐖朵换鍔D锛岀敤浜庤〃绀轰换鍔$殑灞傜骇鍏崇郴 鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("parent_task_id_")
+    private String parentTaskId;
+    /**	浠诲姟鎻忚堪 鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("description_")
+    private String description;
+    /**浠诲姟鐨勬墍鏈夎�咃紝鍗充换鍔″垎閰嶇粰鐨勭敤鎴� 鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("owner_")
+    private String owner;
+    /**濮旀淳浜猴紝鐢ㄤ簬璁板綍浠诲姟鐨勫娲句汉锛堝鏋滄湁濮旀淳鎿嶄綔锛� 鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("delegation_")
+    private String delegation;
+    /**	浠诲姟鎴鏃ユ湡 鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("due_date_")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date dueDate;
+    /**	浠诲姟鐨勫垎绫� 鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("category_")
+    private String category;
+    /**	浠诲姟琛ㄥ崟Key锛岀敤浜庝笌琛ㄥ崟寮曟搸闆嗘垚 鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("form_key_")
+    private String formKey;
+    /**	鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("claim_time_")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date claimTime;
+    /**	鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("is_count_enabled_")
+    private int iscountEnabled;
+    /**	鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("var_count_")
+    private int varCount;
+    /**	鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("id_link_count_")
+    private int idLinkCount;
+    /**	鏆傛椂鐢ㄤ笉涓�*/
+    @TableField("sub_task_count_")
+    private int subtaskCount;
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/WorkTaskDataVo.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/WorkTaskDataVo.java
new file mode 100644
index 0000000..871bc21
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/domain/vo/WorkTaskDataVo.java
@@ -0,0 +1,97 @@
+package org.jeecg.modules.flowable.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @Description:宸ヤ綔娴佷换鍔℃暟鎹�
+ */
+@Data
+@ApiModel(value="act_ru_task", description="鎴戠殑寰呭姙")
+public class WorkTaskDataVo implements Serializable {
+	/**涓婚敭*/
+//    @TableField("id_")
+    private String id;
+    /**鐗堟湰鍙凤紝鐢ㄤ簬涔愯閿佹帶鍒跺苟鍙戞洿鏂�*/
+//    @TableField("rev_")
+    private int rev;
+    /**鎵ц瀹炰緥ID锛屼笌鎵ц瀹炰緥琛ㄤ腑鐨処D瀛楁鍏宠仈*/
+//    @TableField("execution_id_")
+    private String executionId;
+    /**娴佺▼瀹炰緥ID锛屼笌娴佺▼瀹炰緥琛ㄤ腑鐨処D瀛楁鍏宠仈*/
+//    @TableField("proc_inst_id_")
+    private String procInstId;
+    /**娴佺▼瀹氫箟ID锛屼笌娴佺▼瀹氫箟琛ㄤ腑鐨処D瀛楁鍏宠仈*/
+//    @TableField("proc_def_id_")
+    private String procDefId;
+    /**浠诲姟鍚嶇О*/
+//    @TableField("name_")
+    private String name;
+    /**浠诲姟瀹氫箟Key锛屼笌娴佺▼瀹氫箟琛ㄤ腑鐨凨EY瀛楁鍏宠仈*/
+//    @TableField("task_def_key_")
+    private String taskDefKey;
+    /**浠诲姟鐨勫姙鐞嗕汉锛屽嵆瀹為檯鎵ц浠诲姟鐨勭敤鎴�*/
+//    @TableField("assignee_")
+    @Dict(dictTable = "sys_user", dicCode = "username", dicText = "realname")
+    private String assignee;
+    /**浠诲姟鐨勪紭鍏堢骇*/
+//    @TableField("priority_")
+    private int priority;
+    /**	浠诲姟鍒涘缓鏃堕棿*/
+//    @TableField("create_time_")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+    /**		浠诲姟鐨勬殏鍋滅姸鎬侊紝鐢ㄤ簬鎺у埗浠诲姟鐨勬殏鍋滃拰鎭㈠*/
+//    @TableField("suspension_state_")
+    private int suspensionState;
+    /**	娴佺▼鍙橀噺*/
+    private Map<String,Object> variables;
+//    @TableField("act_status")
+    @ApiModelProperty(value = "娴佺▼鐘舵�佽鏄庯紝鏈夛細鍚姩  鎾ゅ洖  椹冲洖  瀹℃壒涓�  瀹℃壒閫氳繃  瀹℃壒寮傚父")
+    private String actStatus;
+//    @TableField("title")
+    @ApiModelProperty(value = "娴佺▼涓氬姟绠�瑕佹弿杩�")
+    private String title;
+//    @TableField("data_id")
+    @ApiModelProperty(value = "涓氬姟琛╥d锛岀悊璁哄敮涓�")
+    private String dataId;
+    @ApiModelProperty(value = "鍓嶉┍鑺傜偣")
+    private String preNode;
+    @ApiModelProperty(value = "鍓嶉┍鑺傜偣澶勭悊浜�")
+    @Dict(dictTable = "sys_user", dicCode = "username", dicText = "realname")
+    private String preNodeAssignee;
+
+    @ApiModelProperty(value = "娴佺▼鍚嶇О")
+    private transient String flowName;
+
+    @ApiModelProperty(value = "娴佺▼绫诲瀷")
+    @Dict(dicCode = "flow_type")
+    private transient String category;
+
+    /**娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d*/
+    @Excel(name = "娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d", width = 15)
+    @ApiModelProperty(value = "娴佺▼瀹氫箟key 涓�涓猭ey浼氭湁澶氫釜鐗堟湰鐨刬d")
+    private String processDefinitionKey;
+    /**娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�*/
+    @Excel(name = "娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�", width = 15)
+    @ApiModelProperty(value = "娴佺▼瀹氫箟id 涓�涓祦绋嬪畾涔夊敮涓�")
+    private String processDefinitionId;
+    /**娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�*/
+    @Excel(name = "娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�", width = 15)
+    @ApiModelProperty(value = "娴佺▼涓氬姟瀹炰緥id 涓�涓祦绋嬩笟鍔″敮涓�锛屾湰琛ㄤ腑涔熷敮涓�")
+    private String processInstanceId;
+
+    @ApiModelProperty("浠诲姟鎻忚堪")
+    private String description;
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/factory/FlowServiceFactory.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/factory/FlowServiceFactory.java
new file mode 100644
index 0000000..b5379ed
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/factory/FlowServiceFactory.java
@@ -0,0 +1,42 @@
+package org.jeecg.modules.flowable.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 寮曟搸娉ㄥ叆灏佽
+ */
+@Component
+@Getter
+public class FlowServiceFactory {
+
+    @Resource
+    protected RepositoryService repositoryService;
+
+    @Resource
+    protected RuntimeService runtimeService;
+
+    @Resource
+    protected IdentityService identityService;
+
+    @Resource
+    protected TaskService taskService;
+
+    @Resource
+    protected FormService formService;
+
+    @Resource
+    protected HistoryService historyService;
+
+    @Resource
+    protected ManagementService managementService;
+
+    @Qualifier("processEngine")
+    @Resource
+    protected ProcessEngine processEngine;
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/CustomProcessDiagramCanvas.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/CustomProcessDiagramCanvas.java
new file mode 100644
index 0000000..471ebc6
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/CustomProcessDiagramCanvas.java
@@ -0,0 +1,369 @@
+package org.jeecg.modules.flowable.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;
+
+/**
+ * 鍩虹閰嶇疆
+ */
+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/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/CustomProcessDiagramGenerator.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/CustomProcessDiagramGenerator.java
new file mode 100644
index 0000000..38c8080
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/CustomProcessDiagramGenerator.java
@@ -0,0 +1,402 @@
+package org.jeecg.modules.flowable.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;
+
+/**
+ */
+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) {
+
+        DefaultProcessDiagramGenerator.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/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/FindNextNodeUtil.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/FindNextNodeUtil.java
new file mode 100644
index 0000000..c3b0c12
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/FindNextNodeUtil.java
@@ -0,0 +1,235 @@
+package org.jeecg.modules.flowable.flow;
+
+import com.google.common.collect.Maps;
+import com.greenpineyu.fel.FelEngine;
+import com.greenpineyu.fel.FelEngineImpl;
+import com.greenpineyu.fel.context.FelContext;
+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.*;
+
+/**
+ */
+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;
+    }
+
+    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 ||Boolean.parseBoolean(
+                                String.valueOf(
+                                        result(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 Object result(Map<String, Object> map, String expression) {
+        FelEngine fel = new FelEngineImpl();
+        FelContext ctx = fel.getContext();
+        for (Map.Entry<String, Object> entry : map.entrySet()) {
+            ctx.set(entry.getKey(), entry.getValue());
+        }
+        Object result = fel.eval(expression);
+        return result;
+    }
+
+    public static void main(String[] args) {
+        HashMap<String, Object> objectObjectHashMap = Maps.newHashMap();
+        objectObjectHashMap.put("a",100);
+        objectObjectHashMap.put("b",200);
+        objectObjectHashMap.put("c","abc");
+        Object result = result(objectObjectHashMap, "a!=00&&b=='200'&&c=='abc'");
+        System.out.println(result);
+    }
+
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/FlowableUtils.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/FlowableUtils.java
new file mode 100644
index 0000000..cd2aac5
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/flow/FlowableUtils.java
@@ -0,0 +1,587 @@
+package org.jeecg.modules.flowable.flow;
+
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.bpmn.model.*;
+import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
+import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
+import org.flowable.task.api.history.HistoricTaskInstance;
+
+import java.util.*;
+
+/**
+ */
+@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 ? false : 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 ? true : 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 == false) {
+                    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(item -> stack.push(item));
+        // 娓呮礂鍚庣殑鍘嗗彶浠诲姟瀹炰緥
+        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 && !stack.peek().getDeleteReason().equals("MI_END")) {
+                // 鍙互鐞嗚В涓鸿剰绾胯矾璧风偣
+                String dirtyPoint = "";
+                if (stack.peek().getDeleteReason().indexOf("Change activity to ") >= 0) {
+                    dirtyPoint = stack.peek().getDeleteReason().replace("Change activity to ", "");
+                }
+                // 浼氱鍥為��鍒犻櫎鍘熷洜鏈夌偣涓嶅悓
+                if (stack.peek().getDeleteReason().indexOf("Change parent activity to ") >= 0) {
+                    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;
+    }
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/listener/UserTaskListener.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/listener/UserTaskListener.java
new file mode 100644
index 0000000..ac48611
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/listener/UserTaskListener.java
@@ -0,0 +1,15 @@
+package org.jeecg.modules.flowable.listener;
+
+import org.flowable.engine.delegate.TaskListener;
+import org.flowable.task.service.delegate.DelegateTask;
+
+/**
+ */
+public class UserTaskListener implements TaskListener{
+
+    @Override
+    public void notify(DelegateTask delegateTask) {
+
+    }
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IHisWorkTaskMapper.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IHisWorkTaskMapper.java
new file mode 100644
index 0000000..b3a1ff0
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IHisWorkTaskMapper.java
@@ -0,0 +1,21 @@
+package org.jeecg.modules.flowable.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+import org.jeecg.modules.flowable.domain.vo.FlowHistoricalVo;
+import org.jeecg.modules.flowable.domain.vo.HisWorkTask;
+
+import java.util.List;
+
+public interface IHisWorkTaskMapper extends BaseMapper<HisWorkTask> {
+
+    List<HisWorkTask> queryHisTaskList(@Param("drapprovedataId") String drapprovedataId);
+
+    /**
+     * 閫氳繃娴佺▼瀹炰緥id鏌ヨ鍘嗗彶浠诲姟銆�
+     * @param procInstId
+     * @return
+     */
+    List<FlowHistoricalVo> queryHisTaskByProcInstId(@Param("procInstId") String procInstId);
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IWorkTaskMapper.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IWorkTaskMapper.java
new file mode 100644
index 0000000..0a39a3b
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IWorkTaskMapper.java
@@ -0,0 +1,10 @@
+package org.jeecg.modules.flowable.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.flowable.domain.vo.WorkTaskData;
+
+import java.util.List;
+
+public interface IWorkTaskMapper extends BaseMapper<WorkTaskData> {
+    List<WorkTaskData> queryAllworkTask();
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IWorkTaskVoMapper.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IWorkTaskVoMapper.java
new file mode 100644
index 0000000..492a969
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/IWorkTaskVoMapper.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.flowable.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.jeecg.modules.flowable.domain.vo.FlowMy;
+import org.jeecg.modules.flowable.domain.vo.WorkTaskDataVo;
+
+public interface IWorkTaskVoMapper extends BaseMapper<WorkTaskDataVo> {
+
+    IPage<WorkTaskDataVo> taskBySelf(@Param("flowMy") FlowMy flowMy, @Param("page") Page page);
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/HisWorkTaskMapper.xml b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/HisWorkTaskMapper.xml
new file mode 100644
index 0000000..edb48a8
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/HisWorkTaskMapper.xml
@@ -0,0 +1,75 @@
+<?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="org.jeecg.modules.flowable.mapper.IHisWorkTaskMapper">
+    <select id="queryHisTaskList" resultType="org.jeecg.modules.flowable.domain.vo.HisWorkTask">
+        SELECT
+            fb.id AS id,
+            aht.NAME_ AS name,
+            aht.DESCRIPTION_ AS cause,
+            su.realname AS assignee,
+            aht.START_TIME_ AS startTime,
+            aht.END_TIME_ AS endTime,
+            assign.status as status
+        FROM
+            flow_my_business fb,
+            act_hi_taskinst aht,
+            NC_ASSIGN_FILE_STREAM assign,
+            sys_user su
+        WHERE
+            fb.data_id= #{drapprovedataId}
+          AND fb.process_instance_id= aht.PROC_INST_ID_
+          AND su.username= aht.ASSIGNEE_
+          AND fb.data_id= assign.STREAM_ID
+        ORDER BY
+            aht.START_TIME_ ASC
+    </select>
+    <select id="queryHisTaskByProcInstId" resultType="org.jeecg.modules.flowable.domain.vo.FlowHistoricalVo">
+        WITH ActivitySequence AS (
+            SELECT
+                p.PROC_INST_ID_ AS procInstId,
+                p.BUSINESS_KEY_ AS businessKey,
+                p.START_TIME_ AS procStartTime,
+                p.END_TIME_ AS procEndTime,
+                a.ACT_ID_,
+                COALESCE ( a.ACT_NAME_, a.ACT_ID_ ) AS actName,
+                a.ACT_TYPE_ AS actType,
+                a.START_TIME_ AS actStartTime,
+                a.END_TIME_ AS actEndTime,
+                c.NAME_ AS taskName,
+                c.ASSIGNEE_ AS assignee,
+                c.DESCRIPTION_ AS description,
+-- 浣跨敤 LEAD 鑾峰彇涓嬩竴涓椿鍔ㄤ俊鎭�
+                LEAD ( COALESCE ( a.ACT_NAME_, a.ACT_ID_ ) ) OVER ( PARTITION BY p.PROC_INST_ID_ ORDER BY a.START_TIME_ ) AS nextActName,
+                LEAD ( a.ACT_TYPE_ ) OVER ( PARTITION BY p.PROC_INST_ID_ ORDER BY a.START_TIME_ ) AS nextActType,
+                LEAD ( a.START_TIME_ ) OVER ( PARTITION BY p.PROC_INST_ID_ ORDER BY a.START_TIME_ ) AS nextActStartTime
+            FROM
+                act_hi_procinst p
+                    LEFT JOIN act_hi_actinst a ON p.PROC_INST_ID_ = a.PROC_INST_ID_
+                    AND a.ACT_TYPE_ IN ( 'userTask', 'sequenceFlow' )
+                    LEFT JOIN ACT_HI_TASKINST c ON a.TASK_ID_ = c.ID_
+            WHERE
+                p.PROC_INST_ID_ = #{procInstId}
+        ) SELECT
+              procInstId,
+              businessKey,
+-- 褰撳墠娲诲姩锛坲serTask锛変俊鎭�
+              actName AS userTaskName,
+              taskName,
+              assignee,
+              actStartTime,
+              actEndTime,
+              description,
+-- 涓嬩竴涓椿鍔紙sequenceFlow锛変俊鎭�
+              nextActName AS sequenceFlowName,
+              nextActStartTime AS sequenceFlowStartTime
+        FROM
+            ActivitySequence
+        WHERE
+            actType = 'userTask' -- 绛涢�夊綋鍓嶆椿鍔ㄤ负 userTask
+
+          AND nextActType = 'sequenceFlow' -- 涓斾笅涓�涓椿鍔ㄤ负 sequenceFlow
+
+        ORDER BY
+            actStartTime;
+    </select>
+</mapper>
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/WorkTaskMapper.xml b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/WorkTaskMapper.xml
new file mode 100644
index 0000000..78cd2da
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/WorkTaskMapper.xml
@@ -0,0 +1,8 @@
+<?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="org.jeecg.modules.flowable.mapper.IWorkTaskMapper">
+    <select id="queryAllworkTask" resultType="org.jeecg.modules.flowable.domain.vo.WorkTaskData">
+        select id_,rev_,execution_id_,proc_inst_id_,proc_def_id_,name_,task_def_key_,assignee_,priority_,create_time_,suspension_state_,task_def_id_,scope_id_,sub_scope_id_,scope_type_,scope_definition_id_,propagated_stage_inst_id_,parent_task_id_,description_,owner_,delegation_,due_date_,category_,form_key_,claim_time_,is_count_enabled_,var_count_,id_link_count_,sub_task_count_
+        from act_ru_task ORDER BY create_time_ DESC
+    </select>
+</mapper>
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/WorkTaskVoMapper.xml b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/WorkTaskVoMapper.xml
new file mode 100644
index 0000000..6d4e32b
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/mapper/xml/WorkTaskVoMapper.xml
@@ -0,0 +1,54 @@
+<?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="org.jeecg.modules.flowable.mapper.IWorkTaskVoMapper">
+    <select id="taskBySelf" resultType="org.jeecg.modules.flowable.domain.vo.WorkTaskDataVo">
+        SELECT
+            atask.id_ AS id,
+            atask.rev_ AS rev,
+            atask.execution_id_ AS executionId,
+            atask.proc_inst_id_ AS procInstId,
+            atask.proc_def_id_ AS procDefId,
+            atask.name_ AS name,
+            atask.task_def_key_ as taskDefKey,
+            atask.priority_ AS priority,
+            atask.create_time_ AS createTime,
+            atask.suspension_state_ AS suspensionState,
+            atask.ASSIGNEE_ as assignee,
+            fmb.act_status AS actStatus,
+            fmb.title AS 'description',
+            fmb.data_id AS dataId,
+            fmb.process_definition_key AS processDefinitionKey,
+            fmb.process_definition_id AS processDefinitionId,
+            fmb.process_instance_id AS processInstanceId,
+            pro.name_ as flowName,
+            pro.CATEGORY_ as category
+        FROM
+            act_ru_task AS atask
+            LEFT JOIN flow_my_business fmb on atask.id_ = fmb.task_id
+            LEFT JOIN ACT_RE_PROCDEF pro on atask.PROC_DEF_ID_ = pro.id_
+        WHERE
+            (atask.assignee_ = #{flowMy.username}
+                OR ( atask.assignee_ IS NULL AND fmb.todo_users LIKE CONCAT('%',#{flowMy.username},'%'))
+                )
+          <if test="flowMy.flowName!= null and flowMy.flowName!= ''">
+              AND pro.name_ LIKE CONCAT('%',#{flowMy.flowName},'%')
+          </if>
+          <if test="flowMy.title != null and flowMy.title != ''">
+              AND fmb.title LIKE CONCAT('%',#{flowMy.title},'%')
+          </if>
+          <if test="flowMy.startTime!= null and flowMy.startTime!= ''">
+              AND atask.create_time_ &gt;= #{flowMy.startTime}
+          </if>
+          <if test="flowMy.endTime!= null and flowMy.endTime!= ''">
+              AND atask.create_time_ &lt;= #{flowMy.endTime}
+          </if>
+          <if test="flowMy.category!= null and flowMy.category!= ''">
+              AND pro.CATEGORY_ = #{flowMy.category}
+          </if>
+          <if test="flowMy.name!= null and flowMy.name!= ''">
+              AND atask.name_ = #{flowMy.name}
+          </if>
+        ORDER BY
+            create_time_ DESC
+    </select>
+</mapper>
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowDefinitionService.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowDefinitionService.java
new file mode 100644
index 0000000..920225e
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowDefinitionService.java
@@ -0,0 +1,97 @@
+package org.jeecg.modules.flowable.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.flowable.domain.dto.FlowProcDefDto;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ */
+public interface IFlowDefinitionService {
+
+    boolean exist(String processDefinitionKey);
+
+
+    /**
+     * 娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param pageNum  褰撳墠椤电爜
+     * @param pageSize 姣忛〉鏉℃暟
+     * @param flowProcDefDto
+     * @return 娴佺▼瀹氫箟鍒嗛〉鍒楄〃鏁版嵁
+     */
+    Page<FlowProcDefDto> list(Integer pageNum, Integer pageSize, FlowProcDefDto flowProcDefDto);
+
+    /**
+     * 瀵煎叆娴佺▼鏂囦欢
+     *
+     * @param name
+     * @param category
+     * @param in
+     */
+    void importFile(String name, String category, InputStream in);
+
+    /**
+     * 璇诲彇xml
+     * @param deployId
+     * @return
+     */
+    Result readXml(String deployId) throws IOException;
+    Result readXmlByDataId(String dataId) throws IOException;
+    /**
+     * 鏍规嵁娴佺▼瀹氫箟Key鍚姩娴佺▼瀹炰緥
+     *鍚姩鏈�鏂颁竴涓増鏈�
+     * @param procDefKey
+     * @param variables
+     * @return
+     */
+    Result startProcessInstanceByKey(String procDefKey, Map<String, Object> variables);
+
+    /**
+     * 鏍规嵁娴佺▼瀹氫箟ID鍚姩娴佺▼瀹炰緥
+     *
+     * @param procDefId
+     * @param variables
+     * @return
+     */
+
+    Result startProcessInstanceById(String procDefId, Map<String, Object> variables);
+
+    /**
+     * 鏍规嵁娴佺▼鍏宠仈鐨勬暟鎹甀D鍚姩娴佺▼瀹炰緥
+     * @param dataId
+     * @param variables
+     * @return
+     */
+    Result startProcessInstanceByDataId(String dataId, 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);
+
+
+    InputStream readImageByDataId(String dataId);
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowInstanceService.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowInstanceService.java
new file mode 100644
index 0000000..e4215ab
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowInstanceService.java
@@ -0,0 +1,58 @@
+package org.jeecg.modules.flowable.service;
+
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.task.api.Task;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.flowable.domain.vo.FlowTaskVo;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ */
+public interface IFlowInstanceService {
+
+    List<Task> queryListByInstanceId(String instanceId);
+
+    /**
+     * 缁撴潫娴佺▼瀹炰緥
+     *
+     * @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);
+    void deleteByDataId(String dataId, String deleteReason);
+    /**
+     * 鏍规嵁瀹炰緥ID鏌ヨ鍘嗗彶瀹炰緥鏁版嵁
+     *
+     * @param processInstanceId
+     * @return
+     */
+    HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId);
+
+    /**
+     * 鏍规嵁娴佺▼瀹氫箟ID鍚姩娴佺▼瀹炰緥
+     *
+     * @param procDefId 娴佺▼瀹氫箟Id
+     * @param variables 娴佺▼鍙橀噺
+     * @return
+     */
+    Result startProcessInstanceById(String procDefId, Map<String, Object> variables);
+
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowTaskService.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowTaskService.java
new file mode 100644
index 0000000..a79def8
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IFlowTaskService.java
@@ -0,0 +1,193 @@
+package org.jeecg.modules.flowable.service;
+
+import org.flowable.task.api.Task;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.flowable.apithird.business.dto.FlowMyBusinessDto;
+import org.jeecg.modules.flowable.domain.dto.FlowNextDto;
+import org.jeecg.modules.flowable.domain.dto.FlowViewerDto;
+import org.jeecg.modules.flowable.domain.vo.FlowTaskVo;
+
+import java.io.InputStream;
+import java.util.List;
+
+/**
+ */
+public interface IFlowTaskService {
+
+    /**
+     * 瀹℃壒浠诲姟
+     *
+     * @param task 璇锋眰瀹炰綋鍙傛暟
+     */
+    Result complete(FlowTaskVo task);
+
+    Result completeByDateId(FlowTaskVo flowTaskVo);
+    /**
+     * 椹冲洖浠诲姟
+     *
+     * @param flowTaskVo
+     */
+    void taskReject(FlowTaskVo flowTaskVo);
+    void taskRejectByDataId(FlowTaskVo flowTaskVo);
+
+    /**
+     * 閫�鍥炰换鍔�
+     *
+     * @param flowTaskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    void taskReturn(FlowTaskVo flowTaskVo);
+    void taskReturnByDataId(FlowTaskVo flowTaskVo);
+    /**
+     * 鑾峰彇鎵�鏈夊彲鍥為��鐨勮妭鐐�
+     *
+     * @param flowTaskVo
+     * @return
+     */
+    Result findReturnTaskList(FlowTaskVo flowTaskVo);
+    Result findReturnTaskListByDataId(FlowTaskVo flowTaskVo);
+
+    /**
+     * 缁撴潫娴佺▼
+     * @param processInstanceId
+     * @param deleteReason
+     * @return
+     */
+    Result<?> end(String processInstanceId, String deleteReason);
+
+    /**
+     * 鍒犻櫎浠诲姟
+     *
+     * @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 assignTask(FlowTaskVo flowTaskVo);
+
+    /**
+     * 鎴戝彂璧风殑娴佺▼
+     * @param pageNum
+     * @param pageSize
+     * @return
+     */
+    Result myProcess(Integer pageNum, Integer pageSize);
+
+    /**
+     * 鍙栨秷鐢宠
+     * @param flowTaskVo
+     * @return
+     */
+    Result stopProcess(FlowTaskVo flowTaskVo);
+
+    /**
+     * 鎾ゅ洖娴佺▼
+     * @param flowTaskVo
+     * @return
+     */
+    Result revokeProcess(FlowTaskVo flowTaskVo);
+
+
+    /**
+     * 浠e姙浠诲姟鍒楄〃
+     *
+     * @param pageNum  褰撳墠椤电爜
+     * @param pageSize 姣忛〉鏉℃暟
+     * @return
+     */
+    Result todoList(Integer pageNum, Integer pageSize);
+
+    /**
+     * 閫氳繃浼犲叆TaskIds鍒ゆ柇鏄惁鍦ㄥ悓涓�鑺傜偣
+     * @param taskIds
+     * @return
+     */
+    Result isSameNode(String taskIds);
+
+
+    /**
+     * 宸插姙浠诲姟鍒楄〃
+     *
+     * @param pageNum  褰撳墠椤电爜
+     * @param pageSize 姣忛〉鏉℃暟
+     * @return
+     */
+    Result finishedList(Integer pageNum, Integer pageSize,FlowMyBusinessDto flowMyBusinessDto);
+
+    /**
+     * 娴佺▼鍘嗗彶娴佽浆璁板綍
+     *
+     * @param dataId 娴佺▼瀹炰緥Id
+     * @return
+     */
+    Result flowRecord(String dataId);
+
+    /**
+     * 鏍规嵁浠诲姟ID鏌ヨ鎸傝浇鐨勮〃鍗曚俊鎭�
+     *
+     * @param taskId 浠诲姟Id
+     * @return
+     */
+    Task getTaskForm(String taskId);
+
+    /**
+     * 鑾峰彇娴佺▼杩囩▼鍥�
+     * @param processId
+     * @return
+     */
+    InputStream diagram(String processId);
+
+    /**
+     * 鑾峰彇娴佺▼鎵ц杩囩▼
+     * @param procInsId
+     * @return
+     */
+    List<FlowViewerDto> getFlowViewer(String procInsId);
+    List<FlowViewerDto> getFlowViewerByDataId(String dataId);
+    /**
+     * 鑾峰彇娴佺▼鍙橀噺
+     * @param taskId
+     * @return
+     */
+    Result processVariables(String taskId);
+
+    /**
+     * 鑾峰彇涓嬩竴鑺傜偣
+     * @param flowTaskVo 浠诲姟
+     * @return
+     */
+    Result<List<FlowNextDto>> getNextFlowNode(FlowTaskVo flowTaskVo);
+
+
+    /**
+     * 妫�鏌� 骞惰浠诲姟鑺傜偣鏄惁閮藉凡瀹屾垚
+     * @param currentTaskId
+     * @return
+     */
+    boolean checkParallelCompletion(String currentTaskId);
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IHisWorkTaskService.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IHisWorkTaskService.java
new file mode 100644
index 0000000..e269602
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IHisWorkTaskService.java
@@ -0,0 +1,20 @@
+package org.jeecg.modules.flowable.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.apache.ibatis.annotations.Param;
+import org.jeecg.modules.flowable.domain.vo.FlowHistoricalVo;
+import org.jeecg.modules.flowable.domain.vo.HisWorkTask;
+
+import java.util.List;
+
+public interface IHisWorkTaskService extends IService<HisWorkTask> {
+
+    List<HisWorkTask> queryHisTaskList(String drapprovedataId);
+
+    /**
+     * 閫氳繃娴佺▼瀹炰緥id鏌ヨ鍘嗗彶浠诲姟銆�
+     * @param procInstId
+     * @return
+     */
+    List<FlowHistoricalVo> queryHisTaskByProcInstId(@Param("procInstId") String procInstId);
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IWorkTaskService.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IWorkTaskService.java
new file mode 100644
index 0000000..ad7ca6a
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IWorkTaskService.java
@@ -0,0 +1,11 @@
+package org.jeecg.modules.flowable.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.flowable.domain.vo.WorkTaskData;
+
+import java.util.List;
+
+public interface IWorkTaskService extends IService<WorkTaskData> {
+    List<WorkTaskData> queryAllworkTask();
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IWorkTaskServiceVo.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IWorkTaskServiceVo.java
new file mode 100644
index 0000000..d69e423
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/IWorkTaskServiceVo.java
@@ -0,0 +1,12 @@
+package org.jeecg.modules.flowable.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.flowable.domain.vo.FlowMy;
+import org.jeecg.modules.flowable.domain.vo.WorkTaskDataVo;
+
+public interface IWorkTaskServiceVo extends IService<WorkTaskDataVo> {
+
+    IPage<WorkTaskDataVo> toTaskBySelf(FlowMy flowMy, Page page);
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowDefinitionServiceImpl.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowDefinitionServiceImpl.java
new file mode 100644
index 0000000..379cfdd
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowDefinitionServiceImpl.java
@@ -0,0 +1,480 @@
+package org.jeecg.modules.flowable.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.commons.io.IOUtils;
+import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.bpmn.model.UserTask;
+import org.flowable.engine.ProcessEngineConfiguration;
+import org.flowable.engine.history.HistoricActivityInstance;
+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.ProcessDiagramGenerator;
+import org.flowable.image.impl.DefaultProcessDiagramGenerator;
+import org.flowable.task.api.Task;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.modules.flowable.apithird.business.entity.FlowMyBusiness;
+import org.jeecg.modules.flowable.apithird.business.service.impl.FlowMyBusinessServiceImpl;
+import org.jeecg.modules.flowable.apithird.common.constant.ProcessConstants;
+import org.jeecg.modules.flowable.apithird.common.enums.FlowComment;
+import org.jeecg.modules.flowable.apithird.entity.SysUser;
+import org.jeecg.modules.flowable.apithird.service.FlowCallBackServiceI;
+import org.jeecg.modules.flowable.apithird.service.IFlowThirdService;
+import org.jeecg.modules.flowable.domain.dto.FlowNextDto;
+import org.jeecg.modules.flowable.domain.dto.FlowProcDefDto;
+import org.jeecg.modules.flowable.factory.FlowServiceFactory;
+import org.jeecg.modules.flowable.service.IFlowDefinitionService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 娴佺▼瀹氫箟
+ */
+@Service
+public class FlowDefinitionServiceImpl extends FlowServiceFactory implements IFlowDefinitionService {
+    @Autowired
+    IFlowThirdService iFlowThirdService;
+    @Autowired
+    FlowMyBusinessServiceImpl flowMyBusinessService;
+    @Autowired
+    FlowTaskServiceImpl flowTaskService;
+
+    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;
+    }
+
+
+    /**
+     * 娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param pageNum        褰撳墠椤电爜
+     * @param pageSize       姣忛〉鏉℃暟
+     * @param flowProcDefDto
+     * @return 娴佺▼瀹氫箟鍒嗛〉鍒楄〃鏁版嵁
+     */
+    @Override
+    public Page<FlowProcDefDto> list(Integer pageNum, Integer pageSize, FlowProcDefDto flowProcDefDto) {
+        Page<FlowProcDefDto> page = new Page<>();
+        // 娴佺▼瀹氫箟鍒楄〃鏁版嵁鏌ヨ
+        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
+        processDefinitionQuery
+                //.processDefinitionId("cs:5:15e953ed-4d09-11ec-85b8-e884a5deddfc")
+                .orderByProcessDefinitionKey().asc().orderByProcessDefinitionVersion().desc();
+        /*=====鍙傛暟=====*/
+        if (StrUtil.isNotBlank(flowProcDefDto.getName())) {
+            processDefinitionQuery.processDefinitionNameLike("%" + flowProcDefDto.getName() + "%");
+        }
+        if (StrUtil.isNotBlank(flowProcDefDto.getCategory())) {
+            processDefinitionQuery.processDefinitionCategory(flowProcDefDto.getCategory());
+        }
+        if (flowProcDefDto.getSuspensionState() == 1) {
+            processDefinitionQuery.active();
+        }
+        if (StrUtil.isNotBlank(flowProcDefDto.getKey())) {
+            processDefinitionQuery.processDefinitionKey(flowProcDefDto.getKey());
+        }
+        if (flowProcDefDto.getIsLastVersion() == 1) {
+            processDefinitionQuery.latestVersion();
+        }
+        /*============*/
+        page.setTotal(processDefinitionQuery.count());
+        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage((pageNum - 1) * pageSize, 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);
+            // 娴佺▼瀹氫箟鏃堕棿
+            reProcDef.setDeploymentTime(deployment.getDeploymentTime());
+            dataList.add(reProcDef);
+        }
+        page.setRecords(dataList);
+        return page;
+    }
+
+
+    /**
+     * 瀵煎叆娴佺▼鏂囦欢
+     *
+     * @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 Result 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);
+        return Result.OK("", result);
+    }
+
+    @Override
+    public Result readXmlByDataId(String dataId) throws IOException {
+        LambdaQueryWrapper<FlowMyBusiness> flowMyBusinessLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        flowMyBusinessLambdaQueryWrapper.eq(FlowMyBusiness::getDataId, dataId)
+        ;
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+        FlowMyBusiness business = flowMyBusinessService.getOne(flowMyBusinessLambdaQueryWrapper);
+        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionId(business.getProcessDefinitionId()).singleResult();
+        InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName());
+        String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
+        return Result.OK("", result);
+    }
+
+    /**
+     * 璇诲彇xml 鏍规嵁涓氬姟Id
+     *
+     * @param dataId
+     * @return
+     */
+    @Override
+    public InputStream readImageByDataId(String dataId) {
+        FlowMyBusiness business = flowMyBusinessService.getByDataId(dataId);
+
+        String processId = business.getProcessInstanceId();
+        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        //娴佺▼璧板畬鐨� 鏄剧ず鍏ㄥ浘
+        if (pi == null) {
+            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(business.getProcessDefinitionId()).singleResult();
+            return this.readImage(processDefinition.getDeploymentId());
+        }
+
+        List<HistoricActivityInstance> historyProcess = historyService.createHistoricActivityInstanceQuery()
+                .processInstanceId(processId).list();
+        List<String> activityIds = new ArrayList<>();
+        List<String> flows = new ArrayList<>();
+        //鑾峰彇娴佺▼鍥�
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
+        for (HistoricActivityInstance hi : historyProcess) {
+            String activityType = hi.getActivityType();
+            if (activityType.equals("sequenceFlow") || activityType.equals("exclusiveGateway")) {
+                flows.add(hi.getActivityId());
+            } else if (activityType.equals("userTask") || activityType.equals("startEvent")) {
+                activityIds.add(hi.getActivityId());
+            }
+        }
+        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processId).list();
+        for (Task task : tasks) {
+            activityIds.add(task.getTaskDefinitionKey());
+        }
+        ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();
+        //瀹氫箟娴佺▼鐢诲竷鐢熸垚鍣�
+        ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator();
+        InputStream in = processDiagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engConf.getActivityFontName(), engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);
+        return in;
+    }
+
+    /**
+     * 璇诲彇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 procDefKey 娴佺▼瀹氫箟Id
+     * @param variables  娴佺▼鍙橀噺
+     * @return
+     */
+    @Override
+    @Transactional(rollbackFor = {Exception.class})
+    public Result<?> startProcessInstanceByKey(String procDefKey, Map<String, Object> variables) {
+        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
+                .processDefinitionKey(procDefKey)
+                .latestVersion().singleResult();
+        Result result = startProcessInstanceById(processDefinition.getId(), variables);
+        return result;
+    }
+
+    /**
+     * 鏍规嵁娴佺▼瀹氫箟ID鍚姩娴佺▼瀹炰緥
+     *
+     * @param procDefId 娴佺▼瀹氫箟Id
+     * @param variables 娴佺▼鍙橀噺
+     * @return
+     */
+    @Override
+    @Transactional
+    public Result<?> startProcessInstanceById(String procDefId, Map<String, Object> variables) {
+        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
+                .processDefinitionId(procDefId)
+                .singleResult();
+        if (Objects.nonNull(processDefinition) && processDefinition.isSuspended()) {
+            return Result.error("娴佺▼宸茶鎸傝捣,璇峰厛婵�娲绘祦绋�");
+        }
+//           variables.put("skip", true);
+//           variables.put(ProcessConstants.FLOWABLE_SKIP_EXPRESSION_ENABLED, true);
+        // 璁剧疆娴佺▼鍙戣捣浜篒d鍒版祦绋嬩腑
+        SysUser sysUser = iFlowThirdService.getLoginUser();
+        identityService.setAuthenticatedUserId(sysUser.getUsername());
+        variables.put(ProcessConstants.PROCESS_INITIATOR, sysUser.getUsername());
+        ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDefId, variables);
+        // 缁欑涓�姝ョ敵璇蜂汉鑺傜偣璁剧疆浠诲姟鎵ц浜哄拰鎰忚
+        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).active().singleResult();
+        if (Objects.nonNull(task)) {
+            taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.NORMAL.getType(), variables.get("organization").toString());
+            taskService.setAssignee(task.getId(), sysUser.getUsername());
+            task.setDescription(variables.get("organization").toString());
+            //taskService.complete(task.getId(), variables);
+        }
+        //璁剧疆鎵�鏈夌敵璇蜂汉
+
+        /*======================todo 鍚姩涔嬪悗  鍥炶皟浠ュ強鍏抽敭鏁版嵁淇濆瓨======================*/
+        //涓氬姟鏁版嵁id
+        String dataId = variables.get("dataId").toString();
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+        FlowMyBusiness business = flowMyBusinessService.getByDataId(dataId);
+        //璁剧疆鏁版嵁
+        List<FlowNextDto> nextFlowNodeList = flowTaskService.getNextFlowNode(task.getId(), variables);
+        taskService.complete(task.getId(), variables);
+        //涓嬩竴涓疄渚嬭妭鐐�  澶氬疄渚嬩細鏄竴涓猯ist,闅忔剰鍙栦竴涓嵆鍙�  鏁扮粍涓畾涔塊ey鏄竴鑷寸殑
+        //Task task2 = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).active().singleResult();
+        List<Task> task2List = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).active().list();
+        String doneUsers = business.getDoneUsers();
+        // 澶勭悊杩囨祦绋嬬殑浜�
+        JSONArray doneUserList = new JSONArray();
+        if (StrUtil.isNotBlank(doneUsers)) {
+            doneUserList = JSON.parseArray(doneUsers);
+        }
+        if (!doneUserList.contains(sysUser.getUsername())) {
+            doneUserList.add(sysUser.getUsername());
+        }
+
+        if (CollectionUtil.isEmpty(nextFlowNodeList)) {
+            //    **娌℃湁涓嬩竴涓妭鐐癸紝娴佺▼宸茬粡缁撴潫浜�
+            business.setProcessDefinitionId(procDefId)
+                    .setProcessInstanceId(processInstance.getProcessInstanceId())
+//                    .setActStatus(ActStatus.pass)
+                    .setProposer(sysUser.getUsername())
+                    .setDoneUsers(doneUserList.toJSONString())
+            ;
+            flowMyBusinessService.updateById(business);
+        } else if (nextFlowNodeList.size() == 1) {
+            //涓嬩釜鑺傜偣鍙湁涓�涓�
+            FlowNextDto nextFlowNode = nextFlowNodeList.get(0);
+            UserTask nextTask = nextFlowNode.getUserTask();
+            Task task2 = null;
+            Optional<Task> first = task2List.stream().filter(t -> t.getTaskDefinitionKey().equals(nextTask.getId())).findFirst();
+            if (first.isPresent()) {
+                task2 = first.get();
+            }
+            if (task2 != null) {
+                //鑳藉澶勭悊涓嬩釜鑺傜偣鐨勫�欓�変汉
+                List<SysUser> nextFlowNodeUserList = nextFlowNode.getUserList();
+
+                List<String> collect_username = nextFlowNodeUserList.stream().map(SysUser::getUsername).collect(Collectors.toList());
+                //spring瀹瑰櫒绫诲悕
+                String serviceImplName = business.getServiceImplName();
+                FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
+                List<String> beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(task2.getTaskDefinitionId(), variables);
+                business.setProcessDefinitionId(procDefId)
+                        .setProcessInstanceId(processInstance.getProcessInstanceId())
+////                    .setActStatus(ActStatus.start)
+                        .setProposer(sysUser.getUsername())
+                        .setTaskId(task2.getId())
+                        .setTaskName(nextTask.getName())
+                        .setTaskNameId(nextTask.getId())
+                        .setPriority(nextTask.getPriority())
+                        .setDoneUsers(doneUserList.toJSONString());
+                if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
+                    // 鍒犻櫎鍚庨噸鍐�
+                    for (String oldUser : collect_username) {
+                        taskService.deleteCandidateUser(task2.getId(), oldUser);
+                    }
+                    // 涓氬姟灞傛湁鎸囧畾鍊欓�変汉锛岃鐩�
+                    for (String newUser : beforeParamsCandidateUsernames) {
+                        taskService.addCandidateUser(task2.getId(), newUser);
+                    }
+                    business.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
+                } else {
+                    // 涓氬姟灞傛病鏈夋寚瀹氬�欓�変汉锛岀洿鎺ヨ鐩�
+                    business.setTodoUsers(JSON.toJSONString(collect_username));
+                }
+                flowMyBusinessService.updateById(business);
+            }
+        } else {
+            for (FlowNextDto nextFlowNode : nextFlowNodeList) {
+                //**鏈変笅涓�涓妭鐐�
+                UserTask nextTask = nextFlowNode.getUserTask();
+                Task task2 = null;
+                Optional<Task> first = task2List.stream().filter(t -> t.getTaskDefinitionKey().equals(nextTask.getId())).findFirst();
+                if (first.isPresent()) {
+                    task2 = first.get();
+                }
+                if (task2 != null) {
+                    //鏂扮殑涓氬姟娴佺▼鑺傜偣
+                    FlowMyBusiness newBusiness =  BeanUtil.copyProperties(business, FlowMyBusiness.class, "id");
+                    //鑳藉澶勭悊涓嬩釜鑺傜偣鐨勫�欓�変汉
+                    List<SysUser> nextFlowNodeUserList = nextFlowNode.getUserList();
+
+                    List<String> collect_username = nextFlowNodeUserList.stream().map(SysUser::getUsername).collect(Collectors.toList());
+                    //spring瀹瑰櫒绫诲悕
+                    String serviceImplName = newBusiness.getServiceImplName();
+                    FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
+                    List<String> beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(task2.getTaskDefinitionId(), variables);
+                    newBusiness.setProcessDefinitionId(procDefId)
+                            .setProcessInstanceId(processInstance.getProcessInstanceId())
+////                    .setActStatus(ActStatus.start)
+                            .setProposer(sysUser.getUsername())
+                            .setTaskId(task2.getId())
+                            .setTaskName(nextTask.getName())
+                            .setTaskNameId(nextTask.getId())
+                            .setPriority(nextTask.getPriority())
+                            .setDoneUsers(doneUserList.toJSONString());
+                    if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
+                        // 鍒犻櫎鍚庨噸鍐�
+                        for (Task task2One : task2List) {
+                            for (String oldUser : beforeParamsCandidateUsernames) {
+                                taskService.deleteCandidateUser(task2One.getId(), oldUser);
+                            }
+                        }
+                        // 涓氬姟灞傛湁鎸囧畾鍊欓�変汉锛岃鐩�
+                        for (Task task2One : task2List) {
+                            for (String newUser : beforeParamsCandidateUsernames) {
+                                taskService.addCandidateUser(task2One.getId(), newUser);
+                            }
+                        }
+                        newBusiness.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
+                    } else {
+                        // 涓氬姟灞傛病鏈夋寚瀹氬�欓�変汉锛岀洿鎺ヨ鐩�
+                        newBusiness.setTodoUsers(JSON.toJSONString(collect_username));
+                        // 鍒犻櫎鍚庨噸鍐�
+                        for (Task task2One : task2List) {
+                            for (String oldUser : collect_username) {
+                                taskService.deleteCandidateUser(task2One.getId(), oldUser);
+                            }
+                        }
+                        // 涓氬姟灞傛湁鎸囧畾鍊欓�変汉锛岃鐩�
+                        for (Task task2One : task2List) {
+                            for (String newUser : collect_username) {
+                                taskService.addCandidateUser(task2One.getId(), newUser);
+                            }
+                        }
+                    }
+                    flowMyBusinessService.save(newBusiness);
+                }
+            }
+            //鍒犻櫎鍘熸湁鐨勪笟鍔℃暟鎹�
+            flowMyBusinessService.removeById(business.getId());
+        }
+        //spring瀹瑰櫒绫诲悕
+        String serviceImplName = business.getServiceImplName();
+        FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
+        // 娴佺▼澶勭悊瀹屽悗锛岃繘琛屽洖璋冧笟鍔″眰
+        business.setValues(variables);
+        if (flowCallBackService != null) {
+            flowCallBackService.afterFlowHandle(business);
+        }
+        return Result.OK("娴佺▼鍚姩鎴愬姛");
+    }
+
+    @Override
+    public Result startProcessInstanceByDataId(String dataId, Map<String, Object> variables) {
+        LambdaQueryWrapper<FlowMyBusiness> flowMyBusinessLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        flowMyBusinessLambdaQueryWrapper.eq(FlowMyBusiness::getDataId, dataId)
+        ;
+        FlowMyBusiness business = flowMyBusinessService.getOne(flowMyBusinessLambdaQueryWrapper);
+        if (business == null) {
+            return Result.error("鏈壘鍒癲ataId锛�" + dataId);
+        }
+        if (StrUtil.isNotBlank(business.getProcessDefinitionId())) {
+            return this.startProcessInstanceById(business.getProcessDefinitionId(), variables);
+        }
+        return this.startProcessInstanceByKey(business.getProcessDefinitionKey(), variables);
+    }
+
+
+    /**
+     * 婵�娲绘垨鎸傝捣娴佺▼瀹氫箟
+     *
+     * @param state    鐘舵�� 婵�娲�1 鎸傝捣2
+     * @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/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowInstanceServiceImpl.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowInstanceServiceImpl.java
new file mode 100644
index 0000000..1d0581b
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowInstanceServiceImpl.java
@@ -0,0 +1,185 @@
+package org.jeecg.modules.flowable.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.shiro.SecurityUtils;
+import org.flowable.common.engine.api.FlowableObjectNotFoundException;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.task.api.Task;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.modules.flowable.apithird.business.entity.FlowMyBusiness;
+import org.jeecg.modules.flowable.apithird.business.service.impl.FlowMyBusinessServiceImpl;
+import org.jeecg.modules.flowable.apithird.common.exception.CustomException;
+import org.jeecg.modules.flowable.apithird.entity.SysUser;
+import org.jeecg.modules.flowable.apithird.service.FlowCallBackServiceI;
+import org.jeecg.modules.flowable.apithird.service.IFlowThirdService;
+import org.jeecg.modules.flowable.domain.vo.FlowTaskVo;
+import org.jeecg.modules.flowable.factory.FlowServiceFactory;
+import org.jeecg.modules.flowable.service.IFlowInstanceService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * <p>宸ヤ綔娴佹祦绋嬪疄渚嬬鐞�<p>
+ *
+ */
+@Service
+@Slf4j
+public class FlowInstanceServiceImpl extends FlowServiceFactory implements IFlowInstanceService {
+    @Autowired
+    IFlowThirdService iFlowThirdService;
+    @Autowired
+    FlowMyBusinessServiceImpl flowMyBusinessService;
+
+    @Override
+    public List<Task> queryListByInstanceId(String instanceId) {
+        List<Task> list = taskService.createTaskQuery().processInstanceId(instanceId).active().list();
+        return list;
+    }
+
+    /**
+     * 缁撴潫娴佺▼瀹炰緥
+     *
+     * @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) {
+        List<Task> task = taskService.createTaskQuery().processInstanceId(instanceId).list();
+        if (CollectionUtils.isEmpty(task)) {
+            throw new CustomException("娴佺▼鏈惎鍔ㄦ垨宸叉墽琛屽畬鎴愶紝鍙栨秷鐢宠澶辫触");
+        }
+        // 鏌ヨ鍘嗗彶鏁版嵁
+        HistoricProcessInstance historicProcessInstance = getHistoricProcessInstanceById(instanceId);
+        if (historicProcessInstance.getEndTime() != null) {
+            historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());
+            return;
+        }
+        // 鍒犻櫎娴佺▼瀹炰緥
+        runtimeService.deleteProcessInstance(instanceId, deleteReason);
+        // 鍒犻櫎鍘嗗彶娴佺▼瀹炰緥
+        historyService.deleteHistoricProcessInstance(instanceId);
+        /*======================鎾ゅ洖鍒犻櫎 鍥炶皟浠ュ強鍏抽敭鏁版嵁淇濆瓨======================*/
+        LambdaQueryWrapper<FlowMyBusiness> flowMyBusinessLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        flowMyBusinessLambdaQueryWrapper.eq(FlowMyBusiness::getProcessInstanceId,instanceId)
+        ;
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+        FlowMyBusiness business = flowMyBusinessService.getOne(flowMyBusinessLambdaQueryWrapper);
+        //璁剧疆鏁版嵁
+        String doneUsers = business.getDoneUsers();
+        SysUser sysUser = iFlowThirdService.getLoginUser();
+        // 澶勭悊杩囨祦绋嬬殑浜�
+        JSONArray doneUserList = new JSONArray();
+        if (StrUtil.isNotBlank(doneUsers)){
+            doneUserList = JSON.parseArray(doneUsers);
+        }
+        if (!doneUserList.contains(sysUser.getUsername())){
+            doneUserList.add(sysUser.getUsername());
+        }
+            business
+//                    .setActStatus(ActStatus.recall)
+                    .setTaskId("")
+                    .setTaskName("宸叉挙鍥�")
+                    .setPriority("")
+                    .setDoneUsers(doneUserList.toJSONString())
+                    .setTodoUsers("")
+            ;
+        flowMyBusinessService.updateById(business);
+        //spring瀹瑰櫒绫诲悕
+        String serviceImplName = business.getServiceImplName();
+        FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
+        // 娴佺▼澶勭悊瀹屽悗锛岃繘琛屽洖璋冧笟鍔″眰
+        if (flowCallBackService!=null)flowCallBackService.afterFlowHandle(business);
+
+    }
+
+    @Override
+    public void deleteByDataId(String dataId, String deleteReason) {
+        LambdaQueryWrapper<FlowMyBusiness> flowMyBusinessLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        flowMyBusinessLambdaQueryWrapper.eq(FlowMyBusiness::getDataId, dataId)
+        ;
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+        FlowMyBusiness business = flowMyBusinessService.getOne(flowMyBusinessLambdaQueryWrapper);
+        this.delete(business.getProcessInstanceId(),deleteReason);
+    }
+
+    /**
+     * 鏍规嵁瀹炰緥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 Result startProcessInstanceById(String procDefId, Map<String, Object> variables) {
+
+            // 璁剧疆娴佺▼鍙戣捣浜篒d鍒版祦绋嬩腑
+            LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+            String username = user.getUsername();
+//            identityService.setAuthenticatedUserId(userId.toString());
+            variables.put("initiator",username);
+            variables.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true);
+            ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDefId, variables);
+            processInstance.getProcessInstanceId();
+            return Result.OK("娴佺▼鍚姩鎴愬姛");
+    }
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowTaskServiceImpl.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowTaskServiceImpl.java
new file mode 100644
index 0000000..fb5e489
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/FlowTaskServiceImpl.java
@@ -0,0 +1,1614 @@
+package org.jeecg.modules.flowable.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.SecurityUtils;
+import org.flowable.bpmn.model.*;
+import org.flowable.bpmn.model.Process;
+import org.flowable.common.engine.api.FlowableException;
+import org.flowable.common.engine.api.FlowableObjectNotFoundException;
+import org.flowable.common.engine.impl.identity.Authentication;
+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.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.IdentityLinkType;
+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.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.SpringContextUtils;
+import org.jeecg.modules.flowable.apithird.business.dto.FlowMyBusinessDto;
+import org.jeecg.modules.flowable.apithird.business.entity.FlowMyBusiness;
+import org.jeecg.modules.flowable.apithird.business.service.impl.FlowMyBusinessServiceImpl;
+import org.jeecg.modules.flowable.apithird.common.constant.ProcessConstants;
+import org.jeecg.modules.flowable.apithird.common.enums.FlowComment;
+import org.jeecg.modules.flowable.apithird.common.exception.CustomException;
+import org.jeecg.modules.flowable.apithird.entity.SysUser;
+import org.jeecg.modules.flowable.apithird.service.FlowCallBackServiceI;
+import org.jeecg.modules.flowable.apithird.service.IFlowThirdService;
+import org.jeecg.modules.flowable.domain.dto.FlowCommentDto;
+import org.jeecg.modules.flowable.domain.dto.FlowNextDto;
+import org.jeecg.modules.flowable.domain.dto.FlowTaskDto;
+import org.jeecg.modules.flowable.domain.dto.FlowViewerDto;
+import org.jeecg.modules.flowable.domain.vo.FlowTaskVo;
+import org.jeecg.modules.flowable.factory.FlowServiceFactory;
+import org.jeecg.modules.flowable.flow.CustomProcessDiagramGenerator;
+import org.jeecg.modules.flowable.flow.FindNextNodeUtil;
+import org.jeecg.modules.flowable.flow.FlowableUtils;
+import org.jeecg.modules.flowable.service.IFlowTaskService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.io.InputStream;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ *
+ **/
+@Service
+@Slf4j
+@Transactional
+public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTaskService {
+
+    @Resource
+    private IFlowThirdService iFlowThirdService;
+    @Autowired
+    FlowMyBusinessServiceImpl flowMyBusinessService;
+
+    /**
+     * 瀹屾垚浠诲姟
+     *
+     * @param taskVo 璇锋眰瀹炰綋鍙傛暟
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Result complete(FlowTaskVo taskVo) {
+        Task task = taskService.createTaskQuery().taskId(taskVo.getTaskId()).singleResult();
+        if (Objects.isNull(task)) {
+            return Result.error("浠诲姟涓嶅瓨鍦�");
+        }
+        if (StringUtils.isNotEmpty(taskVo.getComment())) {
+            task.setDescription(taskVo.getComment());
+            taskService.saveTask(task);
+        }
+        SysUser loginUser = iFlowThirdService.getLoginUser();
+        //鍒ゆ柇鐢ㄦ埛鏄惁鏈夋潈闄�
+        if (!task.getAssignee().equals(loginUser.getUsername())) {
+            return Result.error("褰撳墠鐢ㄦ埛鏃犳潈闄�");
+        }
+        if (DelegationState.PENDING.equals(task.getDelegationState())) {
+            taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.DELEGATE.getType(), taskVo.getComment());
+            //taskService.resolveTask(taskVo.getTaskId(), taskVo.getValues());
+        } else {
+            System.out.println("taskVo.getTaskId()--->taskVo.getInstanceId()--->FlowComment.NORMAL.getType()--->taskVo.getComment()" + taskVo.getTaskId() + "---" + taskVo.getInstanceId() + "---" + FlowComment.NORMAL.getType() + "---" + taskVo.getComment());
+            taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.NORMAL.getType(), taskVo.getComment());
+            taskService.setAssignee(taskVo.getTaskId(), loginUser.getUsername());
+        }
+        /*======================瀹℃壒缁撴潫  鍥炶皟浠ュ強鍏抽敭鏁版嵁淇濆瓨======================*/
+        //涓氬姟鏁版嵁id
+        String dataId = taskVo.getDataId();
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+        FlowMyBusiness business = flowMyBusinessService.getFlowMyBusiness(taskVo.getInstanceId(), taskVo.getTaskId());
+        //spring瀹瑰櫒绫诲悕
+        String serviceImplName = business.getServiceImplName();
+        FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
+        // 娴佺▼鍙橀噺
+        Map<String, Object> flowBeforeParamsValues = flowCallBackService.flowValuesOfTask(business.getTaskNameId(), taskVo.getValues());
+
+        //璁剧疆鏁版嵁
+        Map<String, Object> values = taskVo.getValues();
+        if (MapUtil.isNotEmpty(flowBeforeParamsValues)) {
+            //    涓氬姟灞傛湁璁剧疆鍙橀噺锛屼娇鐢ㄤ笟鍔″眰鐨勫彉閲�
+            values = flowBeforeParamsValues;
+        }
+
+        //骞惰缃戝叧 澶氫换鍔�
+        List<FlowNextDto> nextFlowNodeList = this.getNextFlowNode(task.getId(), values);
+        //涓嬩竴涓疄渚嬭妭鐐�
+        if (DelegationState.PENDING.equals(task.getDelegationState())) {
+            taskService.resolveTask(taskVo.getTaskId(), values);
+        } else {
+            taskService.complete(taskVo.getTaskId(), values);
+        }
+        List<Task> task2List = taskService.createTaskQuery().processInstanceId(business.getProcessInstanceId()).active().list();
+        String doneUsers = business.getDoneUsers();
+        // 澶勭悊杩囨祦绋嬬殑浜�
+        JSONArray doneUserList = new JSONArray();
+        if (StrUtil.isNotBlank(doneUsers)) {
+            doneUserList = JSON.parseArray(doneUsers);
+        }
+        if (!doneUserList.contains(loginUser.getUsername())) {
+            doneUserList.add(loginUser.getUsername());
+        }
+
+        if (CollectionUtils.isEmpty(nextFlowNodeList)) {
+            //    **娌℃湁涓嬩竴涓妭鐐癸紝娴佺▼宸茬粡缁撴潫浜�
+            business
+                    .setDoneUsers(doneUserList.toJSONString())
+                    .setTodoUsers("")
+                    .setTaskId("")
+                    .setTaskNameId("")
+                    .setTaskName("")
+            ;
+            flowMyBusinessService.updateById(business);
+        }
+        else if (nextFlowNodeList.size() == 1) {
+            FlowNextDto nextFlowNode = nextFlowNodeList.get(0);
+            UserTask nextTask = nextFlowNode.getUserTask();
+            Task task2 = null;
+            Optional<Task> first = task2List.stream().filter(t -> t.getTaskDefinitionKey().equals(nextTask.getId())).findFirst();
+            task2 = first.orElseGet(() -> task2List.get(0));
+            if (task2 != null) {
+                // 涓嬩釜鑺傜偣鍊欓�変汉
+                List<String> beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(task2.getTaskDefinitionKey(), taskVo.getValues());
+                List<String> candidateUsers = taskVo.getCandidateUsers();
+                if (CollUtil.isNotEmpty(candidateUsers)) {
+                    //    鍓嶇浼犲叆鍊欓�変汉 瑕嗙洊
+                    beforeParamsCandidateUsernames = candidateUsers;
+                }
+                if (task.getTaskDefinitionKey().equals(task2.getTaskDefinitionKey())) {
+                    //澶氬疄渚� 浼氱 TODO
+                    //    * 褰撳墠鑺傜偣鏄細绛捐妭鐐癸紝娌℃湁璧板畬
+                    business.setTaskId(task2.getId())
+//                    .setActStatus(ActStatus.doing)
+                            .setDoneUsers(doneUserList.toJSONString())
+                    ;
+                    String todoUsersStr = business.getTodoUsers();
+                    JSONArray todosArr = JSON.parseArray(todoUsersStr);
+                    // 鍒犻櫎鍚庨噸鍐�
+                    for (Object oldUser : todosArr) {
+                        taskService.deleteCandidateUser(task2.getId(), oldUser.toString());
+                    }
+                    // 閲嶅啓
+                    if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
+                        beforeParamsCandidateUsernames.remove(loginUser.getUsername());
+                        // 涓氬姟灞傛湁鎸囧畾鍊欓�変汉锛岃鐩�
+                        for (String newUser : beforeParamsCandidateUsernames) {
+                            taskService.addCandidateUser(task2.getId(), newUser);
+                        }
+                        business.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
+                    } else {
+                        todosArr.remove(loginUser.getUsername());
+                        for (Object oldUser : todosArr) {
+                            taskService.addCandidateUser(task2.getId(), oldUser.toString());
+                        }
+                        business.setTodoUsers(todosArr.toJSONString());
+                    }
+
+                } else {
+                    //鑳藉澶勭悊涓嬩釜鑺傜偣鐨勫�欓�変汉
+                    List<SysUser> nextFlowNodeUserList = nextFlowNode.getUserList();
+                    List<String> collect_username = nextFlowNodeUserList.stream().map(SysUser::getUsername).collect(Collectors.toList());
+                    if (CollUtil.isNotEmpty(candidateUsers)) {
+                        //    鍓嶇浼犲叆鍊欓�変汉
+                        collect_username = candidateUsers;
+                    }
+                    business
+                            .setTaskId(task2.getId())
+//                        .setActStatus(ActStatus.doing)
+                            .setTaskNameId(nextTask.getId())
+                            .setTaskName(nextTask.getName())
+                            .setPriority(nextTask.getPriority())
+                            .setDoneUsers(doneUserList.toJSONString())
+                            .setTodoUsers(JSON.toJSONString(collect_username))
+                    ;
+                    // 鍒犻櫎鍚庨噸鍐�
+                    for (String oldUser : collect_username) {
+                        taskService.deleteCandidateUser(task2.getId(), oldUser);
+                    }
+                    if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
+                        // 鍓嶇娌℃湁浼犲叆鍊欓�変汉 && 涓氬姟灞傛湁鎸囧畾鍊欓�変汉锛岃鐩�
+                        for (String newUser : beforeParamsCandidateUsernames) {
+                            taskService.addCandidateUser(task2.getId(), newUser);
+                        }
+                        business.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
+                    } else {
+                        for (String oldUser : collect_username) {
+                            taskService.addCandidateUser(task2.getId(), oldUser);
+                        }
+                        business.setTodoUsers(JSON.toJSONString(collect_username));
+                    }
+                }
+            }
+            flowMyBusinessService.updateById(business);
+        }
+        else {
+            for(FlowNextDto nextFlowNode : nextFlowNodeList) {
+                //**鏈変笅涓�涓妭鐐�
+                UserTask nextTask = nextFlowNode.getUserTask();
+                Task task2 = null;
+                Optional<Task> first = task2List.stream().filter(t -> t.getTaskDefinitionKey().equals(nextTask.getId())).findFirst();
+                if (first.isPresent()) {
+                    task2 = first.get();
+                }
+                if (task2 != null) {
+                    //鏂扮殑涓氬姟娴佺▼鑺傜偣
+                    FlowMyBusiness newBusiness =  BeanUtil.copyProperties(business, FlowMyBusiness.class, "id");
+                    // 涓嬩釜鑺傜偣鍊欓�変汉
+                    List<String> beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(task2.getTaskDefinitionKey(), taskVo.getValues());
+                    List<String> candidateUsers = taskVo.getCandidateUsers();
+                    if (CollUtil.isNotEmpty(candidateUsers)) {
+                        //    鍓嶇浼犲叆鍊欓�変汉 瑕嗙洊
+                        beforeParamsCandidateUsernames = candidateUsers;
+                    }
+                    if (task.getTaskDefinitionKey().equals(task2.getTaskDefinitionKey())) {
+                        //澶氬疄渚� 浼氱 TODO
+                        //    * 褰撳墠鑺傜偣鏄細绛捐妭鐐癸紝娌℃湁璧板畬
+                        newBusiness.setTaskId(task2.getId())
+//                    .setActStatus(ActStatus.doing)
+                                .setDoneUsers(doneUserList.toJSONString())
+                        ;
+                        String todoUsersStr = business.getTodoUsers();
+                        JSONArray todosArr = JSON.parseArray(todoUsersStr);
+                        // 鍒犻櫎鍚庨噸鍐�
+                        for (Object oldUser : todosArr) {
+                            taskService.deleteCandidateUser(task2.getId(), oldUser.toString());
+                        }
+                        // 閲嶅啓
+                        if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
+                            beforeParamsCandidateUsernames.remove(loginUser.getUsername());
+                            // 涓氬姟灞傛湁鎸囧畾鍊欓�変汉锛岃鐩�
+                            for (String newUser : beforeParamsCandidateUsernames) {
+                                taskService.addCandidateUser(task2.getId(), newUser);
+                            }
+                            newBusiness.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
+                        } else {
+                            todosArr.remove(loginUser.getUsername());
+                            for (Object oldUser : todosArr) {
+                                taskService.addCandidateUser(task2.getId(), oldUser.toString());
+                            }
+                            newBusiness.setTodoUsers(todosArr.toJSONString());
+                        }
+
+                    } else {
+                        //鑳藉澶勭悊涓嬩釜鑺傜偣鐨勫�欓�変汉
+                        List<SysUser> nextFlowNodeUserList = nextFlowNode.getUserList();
+                        List<String> collect_username = nextFlowNodeUserList.stream().map(SysUser::getUsername).collect(Collectors.toList());
+                        if (CollUtil.isNotEmpty(candidateUsers)) {
+                            //    鍓嶇浼犲叆鍊欓�変汉
+                            collect_username = candidateUsers;
+                        }
+                        newBusiness
+                                .setTaskId(task2.getId())
+//                        .setActStatus(ActStatus.doing)
+                                .setTaskNameId(nextTask.getId())
+                                .setTaskName(nextTask.getName())
+                                .setPriority(nextTask.getPriority())
+                                .setDoneUsers(doneUserList.toJSONString())
+                                .setTodoUsers(JSON.toJSONString(collect_username))
+                        ;
+                        // 鍒犻櫎鍚庨噸鍐�
+                        for (String oldUser : collect_username) {
+                            taskService.deleteCandidateUser(task2.getId(), oldUser);
+                        }
+                        if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
+                            // 鍓嶇娌℃湁浼犲叆鍊欓�変汉 && 涓氬姟灞傛湁鎸囧畾鍊欓�変汉锛岃鐩�
+                            for (String newUser : beforeParamsCandidateUsernames) {
+                                taskService.addCandidateUser(task2.getId(), newUser);
+                            }
+                            newBusiness.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
+                        } else {
+                            for (String oldUser : collect_username) {
+                                taskService.addCandidateUser(task2.getId(), oldUser);
+                            }
+                            newBusiness.setTodoUsers(JSON.toJSONString(collect_username));
+                        }
+                    }
+                    flowMyBusinessService.save(newBusiness);
+                }
+                flowMyBusinessService.updateById(business);
+            }
+            //鍒犻櫎鍘熸湁鐨勪笟鍔℃暟鎹�
+            flowMyBusinessService.removeById(business.getId());
+        }
+
+        // 娴佺▼澶勭悊瀹屽悗锛岃繘琛屽洖璋冧笟鍔″眰
+        business.setValues(values);
+        if (flowCallBackService != null) {
+            flowCallBackService.afterFlowHandle(business);
+        }
+        return Result.OK();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Result completeByDateId(FlowTaskVo flowTaskVo) {
+        return this.complete(flowTaskVo);
+    }
+
+    @Override
+    public void taskRejectByDataId(FlowTaskVo flowTaskVo) {
+        FlowMyBusiness business = flowMyBusinessService.getByDataId(flowTaskVo.getDataId());
+        flowTaskVo.setTaskId(business.getTaskId());
+        this.taskReject(flowTaskVo);
+    }
+
+    /**
+     * 椹冲洖浠诲姟
+     *
+     * @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()));
+        SysUser loginUser = iFlowThirdService.getLoginUser();
+        try {
+            // 璁剧疆澶勭悊浜�
+            taskService.setAssignee(task.getId(), loginUser.getUsername());
+            // 濡傛灉鐖剁骇浠诲姟澶氫簬 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();
+            }
+            /*======================椹冲洖  鍥炶皟浠ュ強鍏抽敭鏁版嵁淇濆瓨======================*/
+            //涓氬姟鏁版嵁id
+            String dataId = flowTaskVo.getDataId();
+            if (dataId == null) return;
+            //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+            FlowMyBusiness business = flowMyBusinessService.getByDataId(dataId);
+            // 椹冲洖鍒颁簡涓婁竴涓妭鐐圭瓑寰呭鐞�
+            List<Task> task2List = taskService.createTaskQuery().processInstanceId(business.getProcessInstanceId()).active().list();
+            Task task2 = task2List.get(0);
+            //spring瀹瑰櫒绫诲悕
+            String serviceImplName = business.getServiceImplName();
+            FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
+            Map<String, Object> values = flowTaskVo.getValues();
+            if (values == null) {
+                values = MapUtil.newHashMap();
+                values.put("dataId", dataId);
+            } else {
+                values.put("dataId", dataId);
+            }
+            List<String> beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(task2.getTaskDefinitionKey(), values);
+            //璁剧疆鏁版嵁
+            String doneUsers = business.getDoneUsers();
+            // 澶勭悊杩囨祦绋嬬殑浜�
+            JSONArray doneUserList = new JSONArray();
+            if (StrUtil.isNotBlank(doneUsers)) {
+                doneUserList = JSON.parseArray(doneUsers);
+            }
+            if (!doneUserList.contains(loginUser.getUsername())) {
+                doneUserList.add(loginUser.getUsername());
+            }
+            business
+                    .setTaskId(task2.getId())
+//                    .setActStatus(ActStatus.reject)
+                    .setTaskNameId(task2.getTaskDefinitionKey())
+                    .setTaskName(task2.getName())
+                    .setDoneUsers(doneUserList.toJSONString())
+            ;
+            FlowElement targetElement = null;
+            if (allElements != null) {
+                for (FlowElement flowElement : allElements) {
+                    // 绫诲瀷涓虹敤鎴疯妭鐐�
+                    if (flowElement.getId().equals(task2.getTaskDefinitionKey())) {
+                        // 鑾峰彇鑺傜偣淇℃伅
+                        targetElement = flowElement;
+                    }
+                }
+            }
+
+            if (targetElement != null) {
+                UserTask targetTask = (UserTask) targetElement;
+                business.setPriority(targetTask.getPriority());
+
+                if (StrUtil.equals(business.getTaskNameId(), ProcessConstants.START_NODE)) {
+                    //    寮�濮嬭妭鐐广�傝缃鐞嗕汉涓虹敵璇蜂汉
+                    business.setTodoUsers(JSON.toJSONString(Lists.newArrayList(business.getProposer())));
+                    taskService.setAssignee(business.getTaskId(), business.getProposer());
+                } else {
+                    List<SysUser> sysUserFromTask = getSysUserFromTask(targetTask);
+                    List<String> collect_username = sysUserFromTask.stream().map(SysUser::getUsername).collect(Collectors.toList());
+                    // 鍓嶇瀛樺叆鐨勫�欓�変汉
+                    List<String> candidateUsers = flowTaskVo.getCandidateUsers();
+                    if (CollUtil.isNotEmpty(candidateUsers)) {
+                        collect_username = candidateUsers;
+                    }
+                    business.setTodoUsers(JSON.toJSONString(collect_username));
+                    // 鍒犻櫎鍚庨噸鍐�
+                    for (Task task2One : task2List) {
+                        for (String oldUser : collect_username) {
+                            taskService.deleteCandidateUser(task2One.getId(), oldUser);
+                        }
+                    }
+                    if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
+                        if (CollUtil.isNotEmpty(candidateUsers)) {
+                            beforeParamsCandidateUsernames = candidateUsers;
+                        }
+                        // 涓氬姟灞傛湁鎸囧畾鍊欓�変汉锛岃鐩�
+                        for (Task task2One : task2List) {
+                            for (String newUser : beforeParamsCandidateUsernames) {
+                                taskService.addCandidateUser(task2One.getId(), newUser);
+                            }
+                        }
+                        business.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
+                    } else {
+                        for (Task task2One : task2List) {
+                            for (String oldUser : collect_username) {
+                                taskService.addCandidateUser(task2One.getId(), oldUser);
+                            }
+                        }
+                    }
+                }
+            }
+
+            flowMyBusinessService.updateById(business);
+            // 娴佺▼澶勭悊瀹屽悗锛岃繘琛屽洖璋冧笟鍔″眰
+            business.setValues(values);
+            if (flowCallBackService != null) flowCallBackService.afterFlowHandle(business);
+        } catch (FlowableObjectNotFoundException e) {
+            throw new CustomException("鏈壘鍒版祦绋嬪疄渚嬶紝娴佺▼鍙兘宸插彂鐢熷彉鍖�");
+        } catch (FlowableException e) {
+            throw new CustomException("鏃犳硶鍙栨秷鎴栧紑濮嬫椿鍔�");
+        }
+
+    }
+
+    @Override
+    public void taskReturnByDataId(FlowTaskVo flowTaskVo) {
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+        FlowMyBusiness business = flowMyBusinessService.getByDataId(flowTaskVo.getDataId());
+        flowTaskVo.setTaskId(business.getTaskId());
+        taskReturn(flowTaskVo);
+    }
+
+    /**
+     * 閫�鍥炰换鍔�
+     *
+     * @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());
+            }
+        }));
+        // 璁剧疆鍥為��鎰忚
+        for (String currentTaskId : currentTaskIds) {
+            taskService.addComment(currentTaskId, task.getProcessInstanceId(), FlowComment.REBACK.getType(), flowTaskVo.getComment());
+        }
+        SysUser loginUser = iFlowThirdService.getLoginUser();
+        try {
+            // 璁剧疆澶勭悊浜�
+            taskService.setAssignee(task.getId(), loginUser.getUsername());
+            // 1 瀵� 1 鎴� 澶� 瀵� 1 鎯呭喌锛宑urrentIds 褰撳墠瑕佽烦杞殑鑺傜偣鍒楄〃(1鎴栧)锛宼argetKey 璺宠浆鍒扮殑鑺傜偣(1)
+            runtimeService.createChangeActivityStateBuilder()
+                    .processInstanceId(task.getProcessInstanceId())
+                    .moveActivityIdsToSingleActivityId(currentIds, flowTaskVo.getTargetKey()).changeState();
+
+            /*======================閫�鍥�  鍥炶皟浠ュ強鍏抽敭鏁版嵁淇濆瓨======================*/
+            //涓氬姟鏁版嵁id
+            String dataId = flowTaskVo.getDataId();
+            if (dataId == null) return;
+            //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+            FlowMyBusiness business = flowMyBusinessService.getByDataId(dataId);
+            //spring瀹瑰櫒绫诲悕
+            String serviceImplName = business.getServiceImplName();
+            FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
+            //璁剧疆鏁版嵁
+            String doneUsers = business.getDoneUsers();
+            // 澶勭悊杩囨祦绋嬬殑浜�
+            JSONArray doneUserList = new JSONArray();
+            if (StrUtil.isNotBlank(doneUsers)) {
+                doneUserList = JSON.parseArray(doneUsers);
+            }
+
+            if (!doneUserList.contains(loginUser.getUsername())) {
+                doneUserList.add(loginUser.getUsername());
+            }
+            //**璺宠浆鍒扮洰鏍囪妭鐐�
+            List<Task> task2List = taskService.createTaskQuery().processInstanceId(business.getProcessInstanceId()).active().list();
+            Task targetTask = task2List.get(0);
+            business
+                    .setTaskId(targetTask.getId())
+//                        .setActStatus(ActStatus.reject)
+                    .setTaskNameId(targetTask.getTaskDefinitionKey())
+                    .setTaskName(targetTask.getName())
+                    .setPriority(targetTask.getPriority() + "")
+                    .setDoneUsers(doneUserList.toJSONString())
+            ;
+            if (target != null) {
+                UserTask target2 = (UserTask) target;
+                business.setPriority(target2.getPriority());
+                if (StrUtil.equals(business.getTaskNameId(), ProcessConstants.START_NODE)) {
+                    //    寮�濮嬭妭鐐广�傝缃鐞嗕汉涓虹敵璇蜂汉
+                    business.setTodoUsers(JSON.toJSONString(Lists.newArrayList(business.getProposer())));
+                    taskService.setAssignee(business.getTaskId(), business.getProposer());
+                } else {
+                    List<SysUser> sysUserFromTask = getSysUserFromTask(target2);
+                    List<String> collect_username = sysUserFromTask.stream().map(SysUser::getUsername).collect(Collectors.toList());
+                    List<String> candidateUsers = flowTaskVo.getCandidateUsers();
+                    if (CollUtil.isNotEmpty(candidateUsers)) {
+                        collect_username = candidateUsers;
+                    }
+                    business.setTodoUsers(JSON.toJSONString(collect_username));
+                    // 鍒犻櫎鍚庨噸鍐�
+                    for (Task task2One : task2List) {
+                        for (String oldUser : collect_username) {
+                            taskService.deleteCandidateUser(task2One.getId(), oldUser);
+                        }
+                    }
+                    Map<String, Object> values = flowTaskVo.getValues();
+                    if (values == null) {
+                        values = MapUtil.newHashMap();
+                        values.put("dataId", dataId);
+                    } else {
+                        values.put("dataId", dataId);
+                    }
+                    List<String> beforeParamsCandidateUsernames = flowCallBackService.flowCandidateUsernamesOfTask(targetTask.getTaskDefinitionKey(), values);
+                    if (CollUtil.isNotEmpty(beforeParamsCandidateUsernames)) {
+                        if (CollUtil.isNotEmpty(candidateUsers)) {
+                            beforeParamsCandidateUsernames = candidateUsers;
+                        }
+                        // 涓氬姟灞傛湁鎸囧畾鍊欓�変汉锛岃鐩�
+                        for (Task task2One : task2List) {
+                            for (String newUser : beforeParamsCandidateUsernames) {
+                                taskService.addCandidateUser(task2One.getId(), newUser);
+                            }
+                        }
+                        business.setTodoUsers(JSON.toJSONString(beforeParamsCandidateUsernames));
+                    } else {
+                        for (Task task2One : task2List) {
+                            for (String oldUser : collect_username) {
+                                taskService.addCandidateUser(task2One.getId(), oldUser);
+                            }
+                        }
+                    }
+                }
+            }
+            flowMyBusinessService.updateById(business);
+            // 娴佺▼澶勭悊瀹屽悗锛岃繘琛屽洖璋冧笟鍔″眰
+            business.setValues(flowTaskVo.getValues());
+            if (flowCallBackService != null) flowCallBackService.afterFlowHandle(business);
+        } catch (FlowableObjectNotFoundException e) {
+            throw new CustomException("鏈壘鍒版祦绋嬪疄渚嬶紝娴佺▼鍙兘宸插彂鐢熷彉鍖�");
+        } catch (FlowableException e) {
+            throw new CustomException("鏃犳硶鍙栨秷鎴栧紑濮嬫椿鍔�");
+        }
+    }
+
+    @Override
+    public Result findReturnTaskListByDataId(FlowTaskVo flowTaskVo) {
+        FlowMyBusiness business = flowMyBusinessService.getByDataId(flowTaskVo.getDataId());
+        flowTaskVo.setTaskId(business.getTaskId());
+        return findReturnTaskList(flowTaskVo);
+    }
+
+    /**
+     * 缁撴潫娴佺▼
+     *
+     * @param processInstanceId 娴佺▼瀹炰緥 ID
+     * @param deleteReason      瀹氫箟鍒犻櫎鍘熷洜
+     */
+    public Result<?> end(String processInstanceId, String deleteReason) {
+        try {
+            // 寮哄埗缁撴潫娴佺▼瀹炰緥
+            runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
+            // 鍒犻櫎鍏宠仈娴佺▼鐨勪笟鍔�
+            FlowMyBusiness flowMyBusiness = flowMyBusinessService.getFlowMyBusiness(processInstanceId);
+            flowMyBusinessService.removeById(flowMyBusiness.getId());
+            System.out.println("Process instance with ID " + processInstanceId + " has been forcefully ended.");
+        } catch (Exception e) {
+            System.err.println("Failed to force end process instance: " + e.getMessage());
+        }
+
+        // 鍏抽棴娴佺▼寮曟搸
+        processEngine.close();
+        return Result.OK("娴佺▼宸茬粨鏉�");
+    }
+
+    /**
+     * 鑾峰彇鎵�鏈夊彲鍥為��鐨勮妭鐐�
+     *
+     * @param flowTaskVo
+     * @return
+     */
+    @Override
+    public Result 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 Result.OK(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 assignTask(FlowTaskVo flowTaskVo) {
+        taskService.setAssignee(flowTaskVo.getTaskId(), flowTaskVo.getAssignee());
+    }
+
+    /**
+     * 鎴戝彂璧风殑娴佺▼
+     *
+     * @param pageNum
+     * @param pageSize
+     * @return
+     */
+    @Override
+    public Result myProcess(Integer pageNum, Integer pageSize) {
+        Page<FlowTaskDto> page = new Page<>();
+        String username = iFlowThirdService.getLoginUser().getUsername();
+        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
+                .startedBy(username)
+                .orderByProcessInstanceStartTime()
+                .desc();
+        List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.listPage((pageNum - 1) * pageSize, pageSize);
+        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());
+            // 褰撳墠鎵�澶勬祦绋� todo: 鏈湴鍚姩鏀惧紑浠ヤ笅娉ㄩ噴
+            List<Task> taskList = taskService.createTaskQuery().processInstanceId(hisIns.getId()).list();
+            if (CollectionUtils.isNotEmpty(taskList)) {
+                flowTask.setTaskId(taskList.get(0).getId());
+            } else {
+                List<HistoricTaskInstance> historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(hisIns.getId()).orderByHistoricTaskInstanceEndTime().desc().list();
+                flowTask.setTaskId(historicTaskInstance.get(0).getId());
+            }
+            flowList.add(flowTask);
+        }
+        page.setRecords(flowList);
+        return Result.OK(page);
+    }
+
+    /**
+     * 鍙栨秷鐢宠
+     *
+     * @param flowTaskVo
+     * @return
+     */
+    @Override
+    public Result stopProcess(FlowTaskVo flowTaskVo) {
+        List<Task> task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).list();
+        if (CollectionUtils.isEmpty(task)) {
+            throw new CustomException("娴佺▼鏈惎鍔ㄦ垨宸叉墽琛屽畬鎴愶紝鍙栨秷鐢宠澶辫触");
+        }
+
+        SysUser loginUser = iFlowThirdService.getLoginUser();
+        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)) {
+                Authentication.setAuthenticatedUserId(loginUser.getUsername());
+                taskService.addComment(task.get(0).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 Result.OK();
+    }
+
+    /**
+     * 鎾ゅ洖娴佺▼  todo 鐩墠瀛樺湪閿欒
+     *
+     * @param flowTaskVo
+     * @return
+     */
+    @Override
+    public Result revokeProcess(FlowTaskVo flowTaskVo) {
+        Task task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).singleResult();
+        if (task == null) {
+            throw new CustomException("娴佺▼鏈惎鍔ㄦ垨宸叉墽琛屽畬鎴愶紝鏃犳硶鎾ゅ洖");
+        }
+
+        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
+                .processInstanceId(task.getProcessInstanceId())
+                .orderByTaskCreateTime()
+                .asc()
+                .list();
+        String myTaskId = null;
+        HistoricTaskInstance myTask = null;
+        for (HistoricTaskInstance hti : htiList) {
+            if (loginUser.getUsername().equals(hti.getAssignee())) {
+                myTaskId = hti.getId();
+                myTask = hti;
+                break;
+            }
+        }
+        if (null == myTaskId) {
+            throw new CustomException("璇ヤ换鍔¢潪褰撳墠鐢ㄦ埛鎻愪氦锛屾棤娉曟挙鍥�");
+        }
+
+        String processDefinitionId = myTask.getProcessDefinitionId();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
+
+        //鍙橀噺
+//      Map<String, VariableInstance> variables = runtimeService.getVariableInstances(currentTask.getExecutionId());
+        String myActivityId = null;
+        List<HistoricActivityInstance> haiList = historyService.createHistoricActivityInstanceQuery()
+                .executionId(myTask.getExecutionId()).finished().list();
+        for (HistoricActivityInstance hai : haiList) {
+            if (myTaskId.equals(hai.getTaskId())) {
+                myActivityId = hai.getActivityId();
+                break;
+            }
+        }
+        FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(myActivityId);
+
+        Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
+        String activityId = execution.getActivityId();
+        FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
+
+        //璁板綍鍘熸椿鍔ㄦ柟鍚�
+        List<SequenceFlow> oriSequenceFlows = new ArrayList<>(flowNode.getOutgoingFlows());
+
+
+        return Result.OK();
+    }
+
+
+    /**
+     * 鍒ゆ柇澶氫釜浠诲姟鏄惁澶勪簬鍚屼竴娴佺▼鑺傜偣
+     *
+     * @param taskIds 閫楀彿鍒嗛殧鐨勪换鍔D瀛楃涓�
+     * @return 缁熶竴缁撴灉灏佽
+     */
+    @Override
+    public Result isSameNode(String taskIds) {
+        // 1. 鍙傛暟鏍¢獙
+        if (StringUtils.isBlank(taskIds)) {
+            return Result.error("浠诲姟ID涓嶈兘涓虹┖");
+        }
+
+        // 2. 鍒嗗壊浠诲姟ID
+        String[] taskIdArray = taskIds.split(",");
+        if (taskIdArray.length == 0) {
+            return Result.error("鏈彁渚涙湁鏁堢殑浠诲姟ID");
+        }
+
+        // 3. 鍗曚换鍔$洿鎺ヨ繑鍥瀟rue
+        if (taskIdArray.length == 1) {
+            return Result.ok(true);
+        }
+
+        // 4. 澶氫换鍔℃鏌ラ�昏緫
+        String referenceNodeId = null;
+        String currentNodeId = null;
+        for (String taskId : taskIdArray) {
+            // 4.1 鏌ヨ浠诲姟瀹炰緥
+            Task task = taskService.createTaskQuery()
+                    .taskId(taskId.trim())
+                    .singleResult();
+
+            // 4.2 浠诲姟涓嶅瓨鍦ㄥ鐞�
+            if (task == null) {
+                return Result.error("浠诲姟涓嶅瓨鍦�: " + taskId);
+            }
+
+            // 4.3 鑾峰彇鑺傜偣鏍囪瘑锛圱askDefinitionKey锛�
+            currentNodeId = task.getTaskDefinitionKey();
+
+            // 4.4 棣栨閬嶅巻鍒濆鍖栧弬鑰冭妭鐐�
+            if (referenceNodeId == null) {
+                referenceNodeId = currentNodeId;
+                continue;
+            }
+
+            // 4.5 鑺傜偣涓嶄竴鑷寸洿鎺ヨ繑鍥�
+            if (!referenceNodeId.equals(currentNodeId)) {
+                return Result.ok("鑺傜偣涓嶄竴鑷�");
+            }
+        }
+
+        // 5. 鎵�鏈変换鍔¤妭鐐逛竴鑷�
+        return Result.ok(currentNodeId);
+    }
+
+    /**
+     * 浠e姙浠诲姟鍒楄〃
+     *
+     * @param pageNum  褰撳墠椤电爜
+     * @param pageSize 姣忛〉鏉℃暟
+     * @return
+     */
+    @Override
+    public Result todoList(Integer pageNum, Integer pageSize) {
+        Page<FlowTaskDto> page = new Page<>();
+        String username = iFlowThirdService.getLoginUser().getUsername();
+        TaskQuery taskQuery = taskService.createTaskQuery()
+                .active()
+                .includeProcessVariables()
+                .taskAssignee(username)
+                .orderByTaskCreateTime().desc();
+        page.setTotal(taskQuery.count());
+        List<Task> taskList = taskQuery.listPage((pageNum - 1) * pageSize, pageSize);
+        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.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 = iFlowThirdService.getUserByUsername(historicProcessInstance.getStartUserId());
+            List<String> departNamesByUsername = iFlowThirdService.getDepartNamesByUsername(historicProcessInstance.getStartUserId());
+            flowTask.setStartUserId(startUser.getUsername());
+            flowTask.setStartUserName(startUser.getRealname());
+            flowTask.setStartDeptName(CollUtil.join(departNamesByUsername, "锛�"));
+            flowList.add(flowTask);
+        }
+
+        page.setRecords(flowList);
+        return Result.OK(page);
+    }
+
+
+    /**
+     * 宸插姙浠诲姟鍒楄〃
+     *
+     * @param pageNum  褰撳墠椤电爜
+     * @param pageSize 姣忛〉鏉℃暟
+     * @return
+     */
+    @Override
+    public Result finishedList(Integer pageNum, Integer pageSize, FlowMyBusinessDto flowMyBusinessDto) {
+        //淇敼鏌ヨ锛屾坊鍔犳煡璇㈡潯浠�
+        Page page = new Page(pageNum, pageSize);
+        String username = iFlowThirdService.getLoginUser().getUsername();
+        flowMyBusinessDto.setCurrentUser(username);
+        List<FlowTaskDto> list = flowMyBusinessService.ListMyBusiness(flowMyBusinessDto);
+        list.forEach(flowTaskDto -> {
+            // 娴佺▼鍙戣捣浜轰俊鎭�
+            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
+                    .processInstanceId(flowTaskDto.getProcInsId())
+                    .singleResult();
+            if (historicProcessInstance != null) {
+                SysUser startUser = iFlowThirdService.getUserByUsername(historicProcessInstance.getStartUserId());
+                if (startUser != null) {
+                    flowTaskDto.setStartUserId(startUser.getUsername());
+                    flowTaskDto.setStartUserName(startUser.getRealname());
+                }
+                List<String> departNamesByUsername = iFlowThirdService.getDepartNamesByUsername(historicProcessInstance.getStartUserId());
+                flowTaskDto.setStartDeptName(CollUtil.join(departNamesByUsername, "锛�"));
+                if (flowTaskDto.getTodoUsers() == null) {
+                    flowTaskDto.setTodoUsers("");
+                } else {
+                    //鍘婚櫎[]
+                    flowTaskDto.setTodoUsers(flowTaskDto.getTodoUsers().replaceAll("\\[", "").replaceAll("\\]", ""));
+                    flowTaskDto.setTodoUsers(flowTaskDto.getTodoUsers().replaceAll("\"", ""));
+                }
+            }
+        });
+        IPage<FlowTaskDto> flowTaskDtoIPage = new Page<>();
+        flowTaskDtoIPage.setRecords(list);
+        flowTaskDtoIPage.setTotal(page.getTotal());
+        return Result.OK(flowTaskDtoIPage);
+    }
+
+    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Set<Object> seen = ConcurrentHashMap.newKeySet();
+        return t -> seen.add(keyExtractor.apply(t));
+    }
+
+    /**
+     * 娴佺▼鍘嗗彶娴佽浆璁板綍
+     *
+     * @param dataId 娴佺▼鏁版嵁Id
+     * @return
+     */
+    @Override
+    public Result flowRecord(String dataId) {
+        FlowMyBusiness business = flowMyBusinessService.getByDataId(dataId);
+        String procInsId = business.getProcessInstanceId();
+        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 (StringUtils.isNotBlank(histIns.getTaskId())) {
+                    FlowTaskDto flowTask = new FlowTaskDto();
+                    flowTask.setTaskId(histIns.getTaskId());
+                    flowTask.setTaskName(histIns.getActivityName());
+                    flowTask.setTaskDefKey(histIns.getActivityId());
+                    flowTask.setCreateTime(histIns.getStartTime());
+                    flowTask.setFinishTime(histIns.getEndTime());
+                    if (StringUtils.isNotBlank(histIns.getAssignee())) {
+                        SysUser sysUser = iFlowThirdService.getUserByUsername(histIns.getAssignee());
+                        flowTask.setAssigneeId(sysUser.getUsername());
+                        flowTask.setAssigneeName(sysUser.getRealname());
+                        List<String> departNamesByUsername = iFlowThirdService.getDepartNamesByUsername(histIns.getAssignee());
+                        flowTask.setDeptName(CollUtil.join(departNamesByUsername, "锛�"));
+                        if (StrUtil.equals(histIns.getActivityId(), ProcessConstants.START_NODE)) {
+                            //    寮�濮嬭妭鐐癸紝鎶婂�欓�変汉璁剧疆涓哄彂璧蜂汉锛岃繖涓�煎凡琚叾浠栧湴鏂硅缃繃锛屼笌瀹為檯鍔炵悊浜轰竴鑷村嵆鍙�
+                            flowTask.setCandidate(sysUser.getRealname());
+                        }
+                    }
+                    // 灞曠ず瀹℃壒浜哄憳
+                    List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getTaskId());
+                    StringBuilder stringBuilder = new StringBuilder();
+                    for (HistoricIdentityLink identityLink : linksForTask) {
+                        if (IdentityLinkType.CANDIDATE.equals(identityLink.getType())) {
+                            if (StringUtils.isNotBlank(identityLink.getUserId())) {
+                                SysUser sysUser = iFlowThirdService.getUserByUsername(identityLink.getUserId());
+                                stringBuilder.append(sysUser.getRealname()).append(",");
+                            }
+                            /*宸茬粡鍏ㄩ儴璁剧疆鍒� CANDIDATE 浜嗭紝涓嶆嬁缁勪簡*/
+                            /*if (StringUtils.isNotBlank(identityLink.getGroupId())) {
+                                List<SysRole> allRole = iFlowThirdService.getAllRole();
+                                SysRole sysRole = allRole.stream().filter(o -> StringUtils.equals(identityLink.getGroupId(), o.getId())).findAny().orElse(new SysRole());
+                                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);
+        }
+        // 鑾峰彇鍒濆鍖栬〃鍗�
+        String serviceImplName = business.getServiceImplName();
+        FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName);
+        // 娴佺▼澶勭悊瀹屽悗锛岃繘琛屽洖璋冧笟鍔″眰
+        if (flowCallBackService != null) {
+            Object businessDataById = flowCallBackService.getBusinessDataById(dataId);
+            map.put("formData", businessDataById);
+        }
+        return Result.OK(map);
+    }
+
+    /**
+     * 鏍规嵁浠诲姟ID鏌ヨ鎸傝浇鐨勮〃鍗曚俊鎭�
+     *
+     * @param taskId 浠诲姟Id
+     * @return
+     */
+    @Override
+    public Task getTaskForm(String taskId) {
+        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
+        return task;
+    }
+
+    /**
+     * 鑾峰彇娴佺▼杩囩▼鍥�
+     *
+     * @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
+     * @return
+     */
+    @Override
+    public List<FlowViewerDto> getFlowViewer(String procInsId) {
+        List<FlowViewerDto> flowViewerList = new ArrayList<>();
+        FlowViewerDto flowViewerDto;
+        // 鑾峰緱娲诲姩鐨勮妭鐐�
+        List<HistoricActivityInstance> hisActIns = historyService.createHistoricActivityInstanceQuery()
+                .processInstanceId(procInsId)
+                .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()));
+
+                for (FlowViewerDto viewerDto : flowViewerList) {
+                    String key = viewerDto.getKey();
+                    if (key.equals(flowViewerDto.getKey())) {
+                        //    閲嶅鍒犻櫎鍚庨潰鏇存柊
+                        flowViewerList.remove(viewerDto);
+                        break;
+                    }
+                }
+                flowViewerList.add(flowViewerDto);
+            }
+        }
+
+        return flowViewerList;
+    }
+
+    @Override
+    public List<FlowViewerDto> getFlowViewerByDataId(String dataId) {
+        LambdaQueryWrapper<FlowMyBusiness> flowMyBusinessLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        flowMyBusinessLambdaQueryWrapper.eq(FlowMyBusiness::getDataId, dataId)
+        ;
+        //濡傛灉淇濆瓨鏁版嵁鍓嶆湭璋冪敤蹇呰皟鐨凢lowCommonService.initActBusiness鏂规硶锛屽氨浼氭湁闂
+        FlowMyBusiness business = flowMyBusinessService.getOne(flowMyBusinessLambdaQueryWrapper);
+        // 1.鎵ц杩囩殑姝ラ
+        List<FlowViewerDto> flowViewers = this.getFlowViewer(business.getProcessInstanceId());
+        // 2.鑾峰彇鎵�鏈夎妭鐐逛俊鎭紝鏍规嵁鎵�鏈夎妭鐐� 鎸夐『搴�  鍜屾墽琛岃繃鐨勬瘮杈冿紝椹冲洖鐨勮妭鐐瑰氨琚烦杩�
+        Process process = repositoryService.getBpmnModel(business.getProcessDefinitionId()).getProcesses().get(0);
+        List<FlowElement> flowElements = Lists.newArrayList(process.getFlowElements());
+        // 鑾峰彇褰撳墠浠诲姟鑺傜偣鍏冪礌
+        List<FlowViewerDto> reflowViewers = Lists.newArrayList();
+        // *椤哄簭鐨凨ey
+        List<String> orderKeys = Lists.newArrayList();
+        if (flowElements != null) {
+            for (FlowElement flowElement : flowElements) {
+                try {
+                    // 寮�濮嬭妭鐐�
+                    StartEvent stev = (StartEvent) flowElement;
+                    //绗竴涓猭ey鑺傜偣锛�
+                    String firstKey = stev.getId();
+                    orderKeys.add(firstKey);
+                    //椤哄簭鑾峰彇鑺傜偣
+                    this.appendKeys(orderKeys, firstKey, flowElements);
+                } catch (Exception e) {
+                    break;
+                }
+
+            }
+
+            for (String key : orderKeys) {
+                Optional<FlowViewerDto> any = flowViewers.stream().filter(o -> StrUtil.equals(o.getKey(), key)).findAny();
+                if (any.isPresent()) {
+                    FlowViewerDto viewerDto = any.get();
+                    reflowViewers.add(viewerDto);
+                    if (!viewerDto.isCompleted()) {
+                        //    宸插埌姝e湪绛夊緟鎵ц鐨勮妭鐐癸紝鍚庨潰鐨勪笉瑕佷簡
+                        break;
+                    }
+                }
+            }
+        }
+        for (FlowViewerDto flowViewer : flowViewers) {
+            boolean present = reflowViewers.stream().filter(o -> StrUtil.equals(o.getKey(), flowViewer.getKey())).findAny().isPresent();
+            flowViewer.setBack(!present);
+        }
+        //return reflowViewers;
+        return flowViewers;
+    }
+
+    /**
+     * 椤哄簭鎶藉彇鑺傜偣
+     *
+     * @param orderKeys    瀹瑰櫒
+     * @param sourceKey    婧�
+     * @param flowElements 鎵�鏈夌殑鑺傜偣瀵硅薄
+     */
+    private void appendKeys(List<String> orderKeys, String sourceKey, List<FlowElement> flowElements) {
+        for (FlowElement flowElement : flowElements) {
+            try {
+                SequenceFlow sf = (SequenceFlow) flowElement;
+                String sourceRef = sf.getSourceRef();
+                String targetRef = sf.getTargetRef();
+                if (sourceKey.equals(sourceRef) && targetRef != null) {
+                    orderKeys.add(targetRef);
+                    this.appendKeys(orderKeys, targetRef, flowElements);
+                }
+            } catch (Exception e) {
+                continue;
+            }
+
+        }
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鍙橀噺
+     *
+     * @param taskId
+     * @return
+     */
+    @Override
+    public Result processVariables(String taskId) {
+        // 娴佺▼鍙橀噺
+        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().includeProcessVariables().finished().taskId(taskId).singleResult();
+        if (Objects.nonNull(historicTaskInstance)) {
+            return Result.OK(historicTaskInstance.getProcessVariables());
+        } else {
+            Map<String, Object> variables = taskService.getVariables(taskId);
+            return Result.OK(variables);
+        }
+    }
+
+    /**
+     * 鑾峰彇涓嬩竴鑺傜偣
+     *
+     * @param flowTaskVo 浠诲姟
+     * @return
+     */
+    @Override
+    public Result<List<FlowNextDto>> getNextFlowNode(FlowTaskVo flowTaskVo) {
+        // todo 浼间箮閫昏緫鏈啓瀹岋紝寰呮鏌�
+        List<FlowNextDto> nextDtoList = this.getNextFlowNode(flowTaskVo.getTaskId(), flowTaskVo.getValues());
+        if (CollectionUtils.isEmpty(nextDtoList)) {
+            return Result.OK("娴佺▼宸插畬缁�", null);
+        }
+        return Result.OK(nextDtoList);
+    }
+
+    @Override
+    public boolean checkParallelCompletion(String currentTaskId) {
+        //鑾峰彇褰撳墠浠诲姟
+        Task currentTask = taskService.createTaskQuery().taskId(currentTaskId).singleResult();
+        if (currentTask == null) {
+            return false;
+        }
+        //鑾峰彇褰撳墠鎵ц
+        Execution execution = runtimeService.createExecutionQuery().executionId(currentTask.getExecutionId()).singleResult();
+        if (execution == null) {
+            return false;
+        }
+        String parentId = execution.getParentId();
+        if (StringUtils.isBlank(parentId)) {
+            //娌℃湁鐖惰妭鐐� 浠h〃娌℃湁骞惰浠诲姟
+            return true;
+        }
+        // 鑾峰彇鎵�鏈夊厔寮熸墽琛�
+        List<Execution> siblingExecutions = runtimeService.createExecutionQuery()
+                .parentId(parentId)
+                .list();
+
+        for (Execution siblingExecution : siblingExecutions) {
+            if (!siblingExecution.getId().equals(execution.getId())) {
+                //闈炶嚜韬殑鍏勫紵鑺傜偣
+                long count = runtimeService.createActivityInstanceQuery().executionId(siblingExecution.getId()).unfinished().count();
+                if (count > 0) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 鑾峰彇涓嬩竴涓妭鐐逛俊鎭�,娴佺▼瀹氫箟涓婄殑鑺傜偣淇℃伅
+     *
+     * @param taskId 褰撳墠鑺傜偣id
+     * @param values 娴佺▼鍙橀噺
+     * @return 濡傛灉杩斿洖null锛岃〃绀烘病鏈変笅涓�涓妭鐐癸紝娴佺▼缁撴潫
+     */
+    public List<FlowNextDto> getNextFlowNode(String taskId, Map<String, Object> values) {
+        //褰撳墠鑺傜偣
+        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
+        if (Objects.nonNull(task)) {
+            // 涓嬩釜浠诲姟鑺傜偣
+            List<UserTask> nextUserTask = FindNextNodeUtil.getNextUserTasks(repositoryService, task, values);
+            if (CollectionUtils.isNotEmpty(nextUserTask)) {
+                List<FlowNextDto> nextDtoList = Lists.newArrayList();
+                FlowNextDto flowNextDto;
+                for (UserTask userTask : nextUserTask) {
+                    flowNextDto = new FlowNextDto();
+                    flowNextDto.setUserTask(userTask);
+                    //寰呭姙浜哄憳
+                    List<SysUser> sysUserFromTask = this.getSysUserFromTask(userTask);
+                    flowNextDto.setUserList(sysUserFromTask);
+                    //澶氫换鍔″苟琛�
+                    Object colObj = values.get(userTask.getId());
+                    if (Objects.nonNull(colObj)) {
+                        List<String> userNameList = (List) colObj;
+                        // 寰呭姙浜哄憳浠庡彉閲忎腑鑾峰彇  鍚﹀垯灏辨槸鑺傜偣涓厤缃殑鐢ㄦ埛 sysUserFromTask
+                        List<SysUser> userList = Lists.newArrayList();
+                        for (String username : userNameList) {
+                            SysUser userByUsername = iFlowThirdService.getUserByUsername(username);
+                            if (userByUsername == null) {
+                                throw new CustomException(username + " 鐢ㄦ埛鍚嶆湭鎵惧埌");
+                            } else {
+                                userList.add(userByUsername);
+                            }
+                        }
+                        flowNextDto.setUserList(userList);
+                    } else {
+                        // 鍙橀噺涓病鏈変紶鍏ワ紝鍐欏叆鑺傜偣涓厤缃殑鐢ㄦ埛
+                        List<String> collect_username = sysUserFromTask.stream().map(SysUser::getUsername).collect(Collectors.toList());
+                        values.put(userTask.getId(), collect_username);
+                    }
+                    nextDtoList.add(flowNextDto);
+                }
+                return nextDtoList;
+            }
+        }
+        return null;
+
+    }
+
+    public List<SysUser> getSysUserFromTask(UserTask userTask) {
+        String assignee = userTask.getAssignee();
+        if (StrUtil.isNotBlank(assignee)) {
+            // 鎸囧畾鍗曚汉
+            SysUser userByUsername = iFlowThirdService.getUserByUsername(assignee);
+            return Lists.newArrayList(userByUsername);
+        }
+        List<String> candidateUsers = userTask.getCandidateUsers();
+        if (CollUtil.isNotEmpty(candidateUsers)) {
+            // 鎸囧畾澶氫汉
+            List<SysUser> list = iFlowThirdService.getAllUser();
+            return list.stream().filter(o -> candidateUsers.contains(o.getUsername())).collect(Collectors.toList());
+        }
+        List<String> candidateGroups = userTask.getCandidateGroups();
+        if (CollUtil.isNotEmpty(candidateGroups)) {
+            //    鎸囧畾澶氱粍
+            List<SysUser> userList = Lists.newArrayList();
+            for (String candidateGroup : candidateGroups) {
+                List<SysUser> usersByRoleId = iFlowThirdService.getUsersByRoleId(candidateGroup);
+                userList.addAll(usersByRoleId);
+            }
+            return userList;
+        }
+        return Lists.newArrayList();
+    }
+
+    /**
+     * 娴佺▼瀹屾垚鏃堕棿澶勭悊
+     *
+     * @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/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/HisWorkTaskServiceImpl.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/HisWorkTaskServiceImpl.java
new file mode 100644
index 0000000..87fa156
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/HisWorkTaskServiceImpl.java
@@ -0,0 +1,42 @@
+package org.jeecg.modules.flowable.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.ibatis.annotations.Param;
+import org.flowable.engine.HistoryService;
+import org.jeecg.modules.flowable.domain.vo.FlowHistoricalVo;
+import org.jeecg.modules.flowable.domain.vo.HisWorkTask;
+import org.jeecg.modules.flowable.mapper.IHisWorkTaskMapper;
+import org.jeecg.modules.flowable.service.IHisWorkTaskService;
+import org.jeecg.modules.flowable.util.TimeUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+@Service
+
+public class HisWorkTaskServiceImpl extends ServiceImpl<IHisWorkTaskMapper,HisWorkTask> implements IHisWorkTaskService {
+    @Autowired
+    private HistoryService historyService;
+    @Override
+    public List<HisWorkTask> queryHisTaskList(String drapprovedataId) {
+        return baseMapper.queryHisTaskList(drapprovedataId);
+    }
+
+
+    /**
+     * 閫氳繃娴佺▼瀹炰緥id鏌ヨ鍘嗗彶浠诲姟銆�
+     * @param procInstId
+     * @return
+     */
+    @Override
+    public List<FlowHistoricalVo> queryHisTaskByProcInstId(@Param("procInstId") String procInstId){
+        List<FlowHistoricalVo> flowHistoricalVoList=baseMapper.queryHisTaskByProcInstId(procInstId);
+        flowHistoricalVoList.forEach(flowHistoricalVo->{
+            //璁$畻鏃堕棿
+            if (flowHistoricalVo.getActStartTime()!=null && flowHistoricalVo.getActEndTime()!=null){
+                flowHistoricalVo.setDuration(TimeUtil.howLong(flowHistoricalVo.getActStartTime(),flowHistoricalVo.getActEndTime(),2));
+            }
+        });
+        return flowHistoricalVoList;
+    }
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/WorkTaskServiceImpl.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/WorkTaskServiceImpl.java
new file mode 100644
index 0000000..10f93c9
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/WorkTaskServiceImpl.java
@@ -0,0 +1,20 @@
+package org.jeecg.modules.flowable.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.flowable.domain.vo.WorkTaskData;
+import org.jeecg.modules.flowable.mapper.IWorkTaskMapper;
+import org.jeecg.modules.flowable.service.IWorkTaskService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class WorkTaskServiceImpl extends ServiceImpl<IWorkTaskMapper, WorkTaskData> implements IWorkTaskService {
+
+
+    @Override
+    public List<WorkTaskData> queryAllworkTask() {
+        return baseMapper.queryAllworkTask();
+    }
+
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/WorkTaskServiceImplVo.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/WorkTaskServiceImplVo.java
new file mode 100644
index 0000000..ee8f6ea
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/service/impl/WorkTaskServiceImplVo.java
@@ -0,0 +1,35 @@
+package org.jeecg.modules.flowable.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.flowable.engine.history.HistoricActivityInstance;
+import org.jeecg.modules.flowable.apithird.business.service.impl.FlowMyBusinessServiceImpl;
+import org.jeecg.modules.flowable.domain.vo.FlowMy;
+import org.jeecg.modules.flowable.domain.vo.WorkTaskDataVo;
+import org.jeecg.modules.flowable.mapper.IWorkTaskVoMapper;
+import org.jeecg.modules.flowable.service.IWorkTaskServiceVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class WorkTaskServiceImplVo extends ServiceImpl<IWorkTaskVoMapper, WorkTaskDataVo> implements IWorkTaskServiceVo {
+    @Autowired
+    FlowMyBusinessServiceImpl flowMyBusinessService;
+    @Override
+    public IPage<WorkTaskDataVo> toTaskBySelf(FlowMy flowMy, Page page) {
+        IPage<WorkTaskDataVo> workTaskDataVoIPage=baseMapper.taskBySelf(flowMy,page);
+        workTaskDataVoIPage.getRecords().forEach(workTaskDataVo -> {
+            HistoricActivityInstance historicActivityInstance=flowMyBusinessService.getPreviousNode(workTaskDataVo.getId());
+            if (historicActivityInstance != null){
+                workTaskDataVo.setPreNode(historicActivityInstance.getActivityName());
+                workTaskDataVo.setPreNodeAssignee(historicActivityInstance.getAssignee());
+            }
+            if (StrUtil.isEmpty(workTaskDataVo.getAssignee())){
+                workTaskDataVo.setAssignee(flowMy.getUsername());
+            }
+        });
+        return workTaskDataVoIPage;
+    }
+}
diff --git a/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/util/TimeUtil.java b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/util/TimeUtil.java
new file mode 100644
index 0000000..7590e00
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/org/jeecg/modules/flowable/util/TimeUtil.java
@@ -0,0 +1,111 @@
+package org.jeecg.modules.flowable.util;
+
+import java.util.Date;
+
+/**
+ * 鎻忚堪锛氭椂闂村伐鍏风被
+ *
+ * @Date 2023/10/11
+ */
+public class TimeUtil {
+
+    /**涓�澶�*/
+    public static final long day    = 1000 * 60 * 60 * 24;
+    /**涓�灏忔椂*/
+    public static final long hour   = 1000 * 60 * 60;
+    /**涓�鍒嗛挓*/
+    public static final long minute = 1000 * 60;
+    /**涓�绉�*/
+    public static final long second = 1000;
+
+    /**
+     * 璁$畻涓や釜鏃堕棿宸紝浠ユ椂鍒嗙鐨勬柟寮忓睍鐜般��
+     * @param start
+     * @param end
+     * @param type 1淇濈暀姣 2淇濈暀绉� 3淇濈暀鍒嗛挓 4淇濈暀灏忔椂 5淇濈暀澶�
+     * @return
+     */
+    public static String howLong(Date start, Date end, int type){
+        if(start == null || end == null)
+            return "";
+        return howLong(start.getTime(), end.getTime(), type);
+    }
+
+    /**
+     * 璁$畻涓や釜鏃堕棿宸紝浠ユ椂鍒嗙鐨勬柟寮忓睍鐜般��
+     * @param start
+     * @param end
+     * @return
+     */
+    public static String howLong(Date start, Date end){
+        if(start == null || end == null)
+            return "";
+        return howLong(start.getTime(), end.getTime(), 1);
+    }
+
+    /**
+     * 璁$畻缁欏畾鏃堕棿璺濈鐜板湪鐨勬椂闂村樊锛屼互鏃跺垎绉掔殑鏂瑰紡灞曠幇銆�
+     * @param startTime
+     * @return
+     */
+    public static String howLong(long startTime){
+        return howLong(startTime, System.currentTimeMillis(),1);
+    }
+
+    /**
+     * 璁$畻鑰楁椂鏃堕暱
+     * @param startTime 璧风偣鏃堕棿锛屾绉掓暟
+     * @return
+     */
+    public static String howLong(long startTime, long endTime ,int type) {
+        long millis = endTime - startTime;
+        return howLongByMillis(millis, type);
+    }
+
+    /**
+     * 璁$畻鑰楁椂鏃堕暱
+     * @param millis
+     * @param type
+     * @return
+     */
+    public static String howLongByMillis(long millis, int type) {
+        if(millis <= 0) return "灏忎簬1绉�";
+
+        if(type > 5) return "鏍煎紡閿欒";
+
+        StringBuilder sb = new StringBuilder();
+
+        //澶�
+        if(millis >= day && type <=5){
+            long days = millis / day;
+            sb.append(days).append("澶�");
+            millis -= days * day;
+        }
+        // 灏忔椂璁�
+        if(millis >= hour && type <=4){
+            long hours = millis / hour;
+            sb.append(hours).append("灏忔椂");
+            millis -= hours * hour;
+        }
+
+        if(millis >= minute && type <=3){
+            long minutes = millis / minute;
+            sb.append(minutes).append("鍒嗛挓");
+            millis -= minutes * minute;
+        }
+
+        if(millis >= second && type <=2){
+            long seconds = millis / second;
+            sb.append(seconds).append("绉�");
+            millis -= seconds * second;
+        }
+
+        if(millis > 0 && type <=1){
+            sb.append(millis).append("姣");
+        }
+
+        return sb.toString();
+
+    }
+
+}
diff --git a/lxzn-module-flowable/src/main/java/rebel.xml b/lxzn-module-flowable/src/main/java/rebel.xml
new file mode 100644
index 0000000..bd4644b
--- /dev/null
+++ b/lxzn-module-flowable/src/main/java/rebel.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  This is the JRebel configuration file. It maps the running application to your IDE workspace, enabling JRebel reloading for this project.
+  Refer to https://manuals.jrebel.com/jrebel/standalone/config.html for more information.
+-->
+<application generated-by="intellij" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_3.xsd">
+
+	<id>lxzn-module-flowable</id>
+
+	<classpath>
+		<dir name="D:/lx_db/mdc_hyjs/lxzn-module-flowable/target/classes">
+		</dir>
+	</classpath>
+
+</application>
diff --git a/lxzn-module-system/lxzn-system-biz/pom.xml b/lxzn-module-system/lxzn-system-biz/pom.xml
index 548ab9c..810e691 100644
--- a/lxzn-module-system/lxzn-system-biz/pom.xml
+++ b/lxzn-module-system/lxzn-system-biz/pom.xml
@@ -34,11 +34,17 @@
 			<groupId>org.jeecgframework.jimureport</groupId>
 			<artifactId>jimureport-spring-boot-starter</artifactId>
 		</dependency>
-		<!-- 绉湪鎶ヨ〃 mongo redis 鏀寔鍖� 
-		<dependency>
-			<groupId>org.jeecgframework.jimureport</groupId>
-			<artifactId>jimureport-nosql-starter</artifactId>
-		</dependency>-->
+        <dependency>
+            <groupId>org.jeecgframework.boot</groupId>
+            <artifactId>lxzn-module-flowable</artifactId>
+            <version>3.4.3</version>
+            <scope>compile</scope>
+        </dependency>
+        <!-- 绉湪鎶ヨ〃 mongo redis 鏀寔鍖�
+        <dependency>
+            <groupId>org.jeecgframework.jimureport</groupId>
+            <artifactId>jimureport-nosql-starter</artifactId>
+        </dependency>-->
 	</dependencies>
-	
+
 </project>
diff --git a/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/flow/FlowThirdServiceImpl.java b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/flow/FlowThirdServiceImpl.java
new file mode 100644
index 0000000..0bb6560
--- /dev/null
+++ b/lxzn-module-system/lxzn-system-biz/src/main/java/org/jeecg/modules/flow/FlowThirdServiceImpl.java
@@ -0,0 +1,107 @@
+package org.jeecg.modules.flow;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.google.common.collect.Lists;
+import org.apache.shiro.SecurityUtils;
+import org.jeecg.common.system.api.ISysBaseAPI;
+import org.jeecg.common.system.vo.DictModel;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.modules.flowable.apithird.entity.SysCategory;
+import org.jeecg.modules.flowable.apithird.entity.SysRole;
+import org.jeecg.modules.flowable.apithird.entity.SysUser;
+import org.jeecg.modules.flowable.apithird.service.IFlowThirdService;
+import org.jeecg.modules.system.service.ISysDictService;
+import org.jeecg.modules.system.service.impl.SysRoleServiceImpl;
+import org.jeecg.modules.system.service.impl.SysUserServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * flowable妯″潡蹇呴渶瀹炵幇绫�
+ *@author PanMeiCheng
+ *@date 2021/11/22
+ *@version 1.0
+ */
+@Service
+public class FlowThirdServiceImpl implements IFlowThirdService {
+    @Autowired
+    ISysBaseAPI sysBaseAPI;
+    @Autowired
+    SysUserServiceImpl sysUserService;
+    @Autowired
+    SysRoleServiceImpl sysRoleService;
+    @Autowired
+    ISysDictService sysDictService;
+    @Override
+    public SysUser getLoginUser() {
+        LoginUser sysUser = null;
+        SysUser copyProperties = null;
+        try {
+            sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+
+
+            System.out.println( );
+            copyProperties = BeanUtil.copyProperties(sysUser, SysUser.class);
+        } catch (Exception e) {
+            //e.printStackTrace();
+        }
+        return copyProperties;
+    }
+
+    @Override
+    public List<SysUser> getAllUser() {
+        List<org.jeecg.modules.system.entity.SysUser> list = sysUserService.list();
+        List<SysUser> userList = list.stream().map(o -> BeanUtil.copyProperties(o, SysUser.class)).collect(Collectors.toList());
+        return userList;
+    }
+
+    @Override
+    public List<SysUser> getUsersByRoleId(String roleId) {
+        Page<org.jeecg.modules.system.entity.SysUser> page = new Page<>(1,Integer.MAX_VALUE);
+        IPage<org.jeecg.modules.system.entity.SysUser> userByRoleId = sysUserService.getUserByRoleId(page, roleId, null);
+        List<org.jeecg.modules.system.entity.SysUser> records = userByRoleId.getRecords();
+        List<SysUser> userList = records.stream().map(o -> BeanUtil.copyProperties(o, SysUser.class)).collect(Collectors.toList());
+        return userList;
+    }
+
+
+    @Override
+    public SysUser getUserByUsername(String username) {
+        LoginUser userByName = sysBaseAPI.getUserByName(username);
+        return userByName==null?null:BeanUtil.copyProperties(userByName, SysUser.class);
+    }
+
+    @Override
+    public List<SysRole> getAllRole() {
+        List<org.jeecg.modules.system.entity.SysRole> list = sysRoleService.list();
+        List<SysRole> roleList = list.stream().map(o -> BeanUtil.copyProperties(o, SysRole.class)).collect(Collectors.toList());
+        return roleList;
+    }
+    @Override
+    public List<SysCategory> getAllCategory() {
+        List<DictModel> list = sysDictService.getDictItems("flow_type");
+        List<SysCategory> categoryList = Lists.newArrayList();
+        if (list == null || list.isEmpty()) {
+            return null;
+        }else {
+            list.forEach(o -> {
+                SysCategory sysCategory = new SysCategory();
+                sysCategory.setId(o.getValue());
+                sysCategory.setName(o.getText());
+                categoryList.add(sysCategory);
+            });
+        }
+        return categoryList;
+    }
+
+    @Override
+    public List<String> getDepartNamesByUsername(String username) {
+        List<String> departNamesByUsername = sysBaseAPI.getDepartNamesByUsername(username);
+        return departNamesByUsername;
+    }
+}

--
Gitblit v1.9.3