From c8bc73954b11b40cc62945099a4f7ca1a73154a1 Mon Sep 17 00:00:00 2001
From: xiangpei <xiangpei@timesnew.cn>
Date: 星期五, 22 十一月 2024 10:22:43 +0800
Subject: [PATCH] 集成flowable接口

---
 flowable/src/main/java/com/ycl/controller/TaskController.java          |  208 +++++
 flowable/src/main/resources/mapper/PurchaseMapper.xml                  |    2 
 flowable/src/main/java/com/ycl/mapper/ActRuExecutionMapper.java        |    2 
 flowable/src/main/java/com/ycl/service/ILeaveapplyService.java         |    2 
 flowable/src/main/java/com/ycl/mapper/PurchaseMapper.java              |    2 
 flowable/src/main/java/com/ycl/controller/FlowDesignerController.java  |  139 +++
 flowable/src/main/java/com/ycl/controller/FlowController.java          |  223 +++++
 flowable/src/main/java/com/ycl/controller/LeaveapplyController.java    |  226 +++++
 flowable/src/main/java/com/ycl/mapper/MeetingMapper.java               |    2 
 flowable/src/main/java/com/ycl/mapper/LeaveapplyMapper.java            |    2 
 flowable/src/main/java/com/ycl/service/impl/LeaveapplyServiceImpl.java |  130 +++
 flowable/src/main/java/com/ycl/service/IMeetingService.java            |    2 
 flowable/src/main/java/com/ycl/controller/MeetingController.java       |  128 +++
 flowable/src/main/resources/mapper/LeaveapplyMapper.xml                |    2 
 flowable/src/main/java/com/ycl/controller/DynamicFlowController.java   |  208 +++++
 flowable/src/main/java/com/ycl/controller/ModelManageController.java   |  161 ++++
 flowable/src/main/java/com/ycl/service/impl/PurchaseServiceImpl.java   |  130 +++
 flowable/src/main/resources/mapper/MeetingMapper.xml                   |    2 
 flowable/src/main/java/com/ycl/controller/PurchaseController.java      |  217 +++++
 flowable/src/main/java/com/ycl/service/IPurchaseService.java           |   18 
 /dev/null                                                              |    7 
 flowable/src/main/java/com/ycl/service/impl/MeetingServiceImpl.java    |  131 +++
 flowable/src/main/resources/mapper/ActRuExecutionMapper.xml            |    2 
 flowable/src/main/java/com/ycl/util/ActivitiTracingChart.java          |    8 
 flowable/src/main/java/com/ycl/controller/FlowMonitorController.java   |  403 ++++++++++
 25 files changed, 2,324 insertions(+), 33 deletions(-)

diff --git a/flowable/gradle/wrapper/gradle-wrapper.jar b/flowable/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index d64cd49..0000000
--- a/flowable/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/flowable/gradle/wrapper/gradle-wrapper.properties b/flowable/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index ac2064c..0000000
--- a/flowable/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
-networkTimeout=10000
-validateDistributionUrl=true
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/flowable/src/main/java/com/ycl/controller/DynamicFlowController.java b/flowable/src/main/java/com/ycl/controller/DynamicFlowController.java
new file mode 100644
index 0000000..82ea0c1
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/DynamicFlowController.java
@@ -0,0 +1,208 @@
+package com.ycl.controller;
+
+
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.utils.StringUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.flowable.bpmn.BpmnAutoLayout;
+import org.flowable.bpmn.model.Process;
+import org.flowable.bpmn.model.*;
+import org.flowable.engine.HistoryService;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.repository.Deployment;
+import org.flowable.engine.runtime.Execution;
+import org.flowable.task.api.Task;
+import org.flowable.validation.ValidationError;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@Api(value = "鍔ㄦ�佹祦绋嬫帴鍙�")
+@Controller
+@RequiredArgsConstructor
+@RequestMapping("/dynamic/flow")
+public class DynamicFlowController {
+
+    private final RuntimeService runtimeService;
+
+    private final TaskService taskService;
+
+    private final RepositoryService repositoryService;
+
+    private final HistoryService historyService;
+
+
+    @ApiOperation("閬嶅巻娴佺▼淇℃伅")
+    @GetMapping(value = "/info/{processInstanceId}")
+    @ResponseBody
+    public AjaxResult remove(@PathVariable String processInstanceId) {
+        String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult().getProcessDefinitionId();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
+        Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
+        for (FlowElement flowElement : flowElements) {
+            if (flowElement instanceof UserTask) {
+                UserTask userTask = (UserTask) flowElement;
+                System.out.println(flowElement.getName());
+                System.out.println(flowElement.getId());
+                System.out.println(userTask.getAssignee());
+                String assigneeEl = userTask.getAssignee();
+                if (StringUtils.isBlank(assigneeEl)) {
+                    continue;
+                }
+                if (assigneeEl.startsWith("${") && assigneeEl.endsWith("}") && assigneeEl.length() > 3) {
+                    String assignee = assigneeEl.substring(2, assigneeEl.length() - 2);
+                    System.out.println("assignee:" + assignee);
+                }
+            }
+        }
+        return AjaxResult.success(flowElements);
+    }
+
+    @ApiOperation("鎾ら攢:寮哄埗缁撴潫涓�涓祦绋�")
+    @GetMapping(value = "/forceEnd/{taskId}")
+    @ResponseBody
+    public AjaxResult forceEnd(@PathVariable String taskId) {
+        Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
+        String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult().getProcessDefinitionId();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
+        // 瀵绘壘娴佺▼瀹炰緥褰撳墠浠诲姟鐨刟ctiveId
+        Execution execution = runtimeService.createExecutionQuery().executionId(t.getExecutionId()).singleResult();
+        String activityId = execution.getActivityId();
+        FlowNode currentNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
+        // 鍒涘缓缁撴潫鑺傜偣鍜岃繛鎺ョ嚎
+        EndEvent end = new EndEvent();
+        end.setName("寮哄埗缁撴潫");
+        end.setId("forceEnd");
+        List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
+        SequenceFlow newSequenceFlow = new SequenceFlow();
+        newSequenceFlow.setId("newFlow");
+        newSequenceFlow.setSourceFlowElement(currentNode);
+        newSequenceFlow.setTargetFlowElement(end);
+        newSequenceFlowList.add(newSequenceFlow);
+        // 澶囦唤鍘熸湁鏂瑰悜
+        List<SequenceFlow> dataflows = currentNode.getOutgoingFlows();
+        List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
+        oriSequenceFlows.addAll(dataflows);
+        // 娓呯┖鍘熸湁鏂瑰悜
+        currentNode.getOutgoingFlows().clear();
+        // 璁剧疆鏂版柟鍚�
+        currentNode.setOutgoingFlows(newSequenceFlowList);
+        // 瀹屾垚褰撳墠浠诲姟
+        taskService.addComment(taskId, t.getProcessInstanceId(), "comment", "鎾ら攢娴佺▼");
+        taskService.complete(taskId);
+        // 鎭㈠鍘熸湁鏂瑰悜
+        currentNode.setOutgoingFlows(oriSequenceFlows);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("椹冲洖鎴栬烦杞埌鎸囧畾鑺傜偣")
+    @GetMapping(value = "/jump/{taskId}/{sid}")
+    @ResponseBody
+    public AjaxResult jump(@PathVariable String taskId, @PathVariable String sid) {
+        Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
+        String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult().getProcessDefinitionId();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
+        // 瀵绘壘娴佺▼瀹炰緥褰撳墠浠诲姟鐨刟ctiveId
+        Execution execution = runtimeService.createExecutionQuery().executionId(t.getExecutionId()).singleResult();
+        String activityId = execution.getActivityId();
+        FlowNode currentNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
+        FlowNode targetNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sid);
+        // 鍒涘缓杩炴帴绾�
+        List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
+        SequenceFlow newSequenceFlow = new SequenceFlow();
+        newSequenceFlow.setId("newFlow");
+        newSequenceFlow.setSourceFlowElement(currentNode);
+        newSequenceFlow.setTargetFlowElement(targetNode);
+        newSequenceFlowList.add(newSequenceFlow);
+        // 澶囦唤鍘熸湁鏂瑰悜
+        List<SequenceFlow> dataflows = currentNode.getOutgoingFlows();
+        List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
+        oriSequenceFlows.addAll(dataflows);
+        // 娓呯┖鍘熸湁鏂瑰悜
+        currentNode.getOutgoingFlows().clear();
+        // 璁剧疆鏂版柟鍚�
+        currentNode.setOutgoingFlows(newSequenceFlowList);
+        // 瀹屾垚褰撳墠浠诲姟
+        taskService.addComment(taskId, t.getProcessInstanceId(), "comment", "璺宠浆鑺傜偣");
+        taskService.complete(taskId);
+        // 鎭㈠鍘熸湁鏂瑰悜
+        currentNode.setOutgoingFlows(oriSequenceFlows);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("鍔ㄦ�佸垱寤烘祦绋�")
+    @GetMapping(value = "/createProcess")
+    @ResponseBody
+    public AjaxResult createProcess() {
+        // 寮�濮嬭妭鐐圭殑灞炴��
+        StartEvent startEvent = new StartEvent();
+        startEvent.setId("start");
+        startEvent.setName("start");
+        // 鏅�歎serTask鑺傜偣
+        UserTask userTask = new UserTask();
+        userTask.setId("userTask");
+        userTask.setName("瀹℃壒浠诲姟");
+        // 缁撴潫鑺傜偣灞炴��
+        EndEvent endEvent = new EndEvent();
+        endEvent.setId("end");
+        endEvent.setName("end");
+        // 杩炵嚎淇℃伅
+        List<SequenceFlow> flows = new ArrayList<SequenceFlow>();
+        List<SequenceFlow> toEnd = new ArrayList<SequenceFlow>();
+        SequenceFlow s1 = new SequenceFlow();
+        s1.setId("flow1");
+        s1.setName("flow1");
+        s1.setSourceRef(startEvent.getId());
+        s1.setTargetRef(userTask.getId());
+        flows.add(s1);
+
+        SequenceFlow s2 = new SequenceFlow();
+        s2.setId("flow2");
+        s2.setName("flow2");
+        s2.setSourceRef(userTask.getId());
+        s2.setTargetRef(endEvent.getId());
+        toEnd.add(s2);
+        startEvent.setOutgoingFlows(flows);
+        userTask.setOutgoingFlows(toEnd);
+
+        // 缁欐祦绋嬪璞℃坊鍔犲厓绱�
+        Process process = new Process();
+        process.setId("dynamicProcess");
+        process.setName("鍔ㄦ�佹祦绋�");
+        process.addFlowElement(startEvent);
+        process.addFlowElement(s1);
+        process.addFlowElement(userTask);
+        process.addFlowElement(s2);
+        process.addFlowElement(endEvent);
+        // 鍒涘缓妯″瀷瀵硅薄
+        BpmnModel bpmnModel = new BpmnModel();
+        bpmnModel.addProcess(process);
+        // 娴佺▼鍥捐嚜鍔ㄥ竷灞�
+        new BpmnAutoLayout(bpmnModel).execute();
+
+        // 妯″瀷鍚堟硶鎬ф牎楠�
+        List<ValidationError> validationErrorList = repositoryService.validateProcess(bpmnModel);
+        if (validationErrorList.size() == 0) {
+            // 妯″瀷鍚堟硶灏遍儴缃叉祦绋�
+            Deployment deploy = repositoryService.createDeployment().category("dynamic")
+                    .key("dynamicProcess")
+                    .addBpmnModel("dynamicProcess.bpmn20.xml", bpmnModel)
+                    .deploy();
+            return AjaxResult.success("success");
+        } else {
+            return AjaxResult.error("fail");
+        }
+    }
+
+}
diff --git a/flowable/src/main/java/com/ycl/controller/FlowController.java b/flowable/src/main/java/com/ycl/controller/FlowController.java
new file mode 100644
index 0000000..428630f
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/FlowController.java
@@ -0,0 +1,223 @@
+package com.ycl.controller;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.page.TableDataInfo;
+import com.ycl.common.utils.StringUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.io.IOUtils;
+
+import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.editor.constants.ModelDataJsonConstants;
+import org.flowable.editor.language.json.converter.BpmnJsonConverter;
+import org.flowable.engine.ProcessEngineConfiguration;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.repository.Model;
+import org.flowable.engine.repository.ProcessDefinition;
+import org.flowable.engine.repository.ProcessDefinitionQuery;
+import org.flowable.image.ProcessDiagramGenerator;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import com.ycl.system.domain.Process;
+
+import javax.annotation.Resource;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.ZipInputStream;
+
+/**
+ * 娴佺▼绠$悊
+ */
+@Api(value = "閮ㄧ讲绠$悊鎺ュ彛")
+@Controller
+@RequiredArgsConstructor
+@RequestMapping("/flow/manage")
+public class FlowController extends BaseController {
+
+    private final RuntimeService runtimeService;
+
+    private final TaskService taskService;
+
+    private final RepositoryService repositoryService;
+
+    private final ProcessEngineConfiguration configuration;
+
+    private static final String prefix = "flowable/manage";
+
+    @GetMapping("")
+    public String processList()
+    {
+        return prefix + "/processList";
+    }
+
+    @GetMapping("deploy")
+    public String deploy()
+    {
+        return prefix + "/deployProcess";
+    }
+
+    @ApiOperation("涓婁紶涓�涓伐浣滄祦鏂囦欢")
+    @RequestMapping(value = "/uploadworkflow", method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxResult fileupload(@RequestParam MultipartFile uploadfile) {
+        try {
+            String filename = uploadfile.getOriginalFilename();
+            InputStream is = uploadfile.getInputStream();
+            if (filename.endsWith("zip")) {
+                repositoryService.createDeployment().name(filename).addZipInputStream(new ZipInputStream(is)).deploy();
+            } else if (filename.endsWith("bpmn") || filename.endsWith("xml")) {
+                repositoryService.createDeployment().name(filename).addInputStream(filename, is).deploy();
+            } else {
+                return AjaxResult.error("鏂囦欢鏍煎紡閿欒");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return AjaxResult.error("閮ㄧ讲澶辫触");
+        }
+        return AjaxResult.success("閮ㄧ讲鎴愬姛");
+    }
+
+    @ApiOperation("鏌ヨ宸查儴缃插伐浣滄祦鍒楄〃")
+    @RequestMapping(value = "/getprocesslists", method = RequestMethod.POST)
+    @ResponseBody
+    public TableDataInfo getlist(@RequestParam(required = false) String key, @RequestParam(required = false) String name,
+                                 @RequestParam(required = false) Boolean latest, Integer pageSize, Integer pageNum) {
+        ProcessDefinitionQuery queryCondition = repositoryService.createProcessDefinitionQuery();
+        if (StringUtils.isNotEmpty(key)) {
+            queryCondition.processDefinitionKey(key);
+        }
+        if (StringUtils.isNotEmpty(name)) {
+            queryCondition.processDefinitionName(name);
+        }
+        if (latest) {
+            queryCondition.latestVersion();
+        }
+        int total = queryCondition.list().size();
+        int start = (pageNum - 1) * pageSize;
+        List<ProcessDefinition> pageList = queryCondition.orderByDeploymentId().desc().listPage(start, pageSize);
+        List<Process> mylist = new ArrayList<Process>();
+        for (int i = 0; i < pageList.size(); i++) {
+            Process p = new Process();
+            p.setDeploymentId(pageList.get(i).getDeploymentId());
+            p.setId(pageList.get(i).getId());
+            p.setKey(pageList.get(i).getKey());
+            p.setName(pageList.get(i).getName());
+            p.setResourceName(pageList.get(i).getResourceName());
+            p.setDiagramresourceName(pageList.get(i).getDiagramResourceName());
+            p.setSuspended(pageList.get(i).isSuspended());
+            p.setVersion(pageList.get(i).getVersion());
+            mylist.add(p);
+        }
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(0);
+        rspData.setRows(mylist);
+        rspData.setTotal(total);
+        return rspData;
+    }
+
+    @ApiOperation("鍒犻櫎涓�娆¢儴缃茬殑宸ヤ綔娴�")
+    @RequestMapping(value = "/remove/{deploymentId}", method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxResult remove(@PathVariable String deploymentId) {
+        repositoryService.deleteDeployment(deploymentId, true);
+        return AjaxResult.success();
+    }
+
+
+    @ApiOperation("鏌ョ湅宸ヤ綔娴佸浘鐗�")
+    @RequestMapping(value = "/showresource", method = RequestMethod.GET)
+    public void showresource(@RequestParam("pdid") String pdid,
+                       HttpServletResponse response) throws Exception {
+        response.setContentType("image/jpeg;charset=UTF-8");
+        response.setHeader("Content-Disposition","inline;filename=process.jpg");
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(pdid);
+        ProcessDiagramGenerator diagramGenerator = configuration.getProcessDiagramGenerator();
+        InputStream is = diagramGenerator.generateDiagram(bpmnModel, "png",  "瀹嬩綋", "瀹嬩綋", "瀹嬩綋", configuration.getClassLoader(), true);
+        ServletOutputStream output = response.getOutputStream();
+        IOUtils.copy(is, output);
+    }
+
+    @ApiOperation("鏌ョ湅宸ヤ綔娴佸畾涔�")
+    @RequestMapping(value = "/showProcessDefinition/{pdid}/{resource}", method = RequestMethod.GET)
+    public void showProcessDefinition(@PathVariable("pdid") String pdid, @PathVariable(value="resource") String resource,
+                       HttpServletResponse response) throws Exception {
+        response.setContentType("application/xml");
+        response.setHeader("Content-Disposition","inline;filename=process.bpmn20.xml");
+        InputStream is = repositoryService.getResourceAsStream(pdid, resource);
+        ServletOutputStream output = response.getOutputStream();
+        IOUtils.copy(is, output);
+    }
+
+    @ApiOperation("灏嗘祦绋嬪畾涔夎浆涓烘ā鍨�")
+    @RequestMapping(value = "/exchangeProcessToModel/{pdid}", method = RequestMethod.GET)
+    @ResponseBody
+    public String exchangeProcessToModel(@PathVariable("pdid") String pdid, HttpServletResponse response) throws Exception {
+        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionId(pdid).singleResult();
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(definition.getId());
+        ObjectNode objectNode = new BpmnJsonConverter().convertToJson(bpmnModel);
+        Model modelData = repositoryService.newModel();
+        modelData.setKey(definition.getKey());
+        modelData.setName(definition.getName());
+        modelData.setCategory(definition.getCategory());
+        ObjectNode modelJson = new ObjectMapper().createObjectNode();
+        modelJson.put(ModelDataJsonConstants.MODEL_NAME, definition.getName());
+        modelJson.put(ModelDataJsonConstants.MODEL_DESCRIPTION, definition.getDescription());
+        List<Model> models = repositoryService.createModelQuery().modelKey(definition.getKey()).list();
+        if (models.size() > 0) {
+            Integer version = models.get(0).getVersion();
+            version++;
+            modelJson.put(ModelDataJsonConstants.MODEL_REVISION, version);
+            // 鍒犻櫎鏃фā鍨�
+            repositoryService.deleteModel(models.get(0).getId());
+            modelData.setVersion(version);
+        } else {
+            modelJson.put(ModelDataJsonConstants.MODEL_REVISION, 1);
+        }
+        modelData.setMetaInfo(modelJson.toString());
+        modelData.setDeploymentId(definition.getDeploymentId());
+        // 淇濆瓨鏂版ā鍨�
+        repositoryService.saveModel(modelData);
+        // 淇濆瓨妯″瀷json
+        repositoryService.addModelEditorSource(modelData.getId(), objectNode.toString().getBytes(StandardCharsets.UTF_8));
+        return objectNode.toString();
+    }
+
+    @ApiOperation("鎸傝捣涓�涓祦绋嬪畾涔�")
+    @RequestMapping(value = "/suspendProcessDefinition", method = RequestMethod.GET)
+    @ResponseBody
+    public AjaxResult suspendProcessDefinition(@RequestParam("pdid") String pdid, @RequestParam("flag") Boolean flag,
+                                               @RequestParam(value="date", required = false) String date) throws Exception {
+        if (StringUtils.isNotEmpty(date)) {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            repositoryService.suspendProcessDefinitionById(pdid, flag,  sdf.parse(date));
+        } else {
+            repositoryService.suspendProcessDefinitionById(pdid, flag, null);
+        }
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("婵�娲讳竴涓祦绋嬪畾涔�")
+    @RequestMapping(value = "/activateProcessDefinition", method = RequestMethod.GET)
+    @ResponseBody
+    public AjaxResult activateProcessDefinition(@RequestParam("pdid") String pdid, @RequestParam("flag") Boolean flag, @RequestParam(value="date", required = false) String date) throws Exception {
+        if (StringUtils.isNotEmpty(date)) {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            repositoryService.activateProcessDefinitionById(pdid, flag,  sdf.parse(date));
+        } else {
+            repositoryService.activateProcessDefinitionById(pdid, flag, null);
+        }
+        return AjaxResult.success();
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/controller/FlowDesignerController.java b/flowable/src/main/java/com/ycl/controller/FlowDesignerController.java
new file mode 100644
index 0000000..ba2d4b7
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/FlowDesignerController.java
@@ -0,0 +1,139 @@
+package com.ycl.controller;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.editor.constants.ModelDataJsonConstants;
+import org.flowable.editor.language.json.converter.BpmnJsonConverter;
+import org.flowable.engine.IdentityService;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.repository.Model;
+import org.flowable.validation.ProcessValidator;
+import org.flowable.validation.ProcessValidatorFactory;
+import org.flowable.validation.ValidationError;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Collections;
+import java.util.List;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/app/rest/")
+public class FlowDesignerController {
+
+    private final RepositoryService repositoryService;
+
+    private final IdentityService identityService;
+
+    private final RuntimeService runtimeService;
+
+    private final TaskService taskService;
+
+    private final ObjectMapper objectMapper;
+
+    /**
+     * 鑾峰緱
+     * @param modelId
+     * @return
+     */
+    @RequestMapping(value = "/models/{modelId}/editor/json", method = RequestMethod.GET, produces = "application/json")
+    public ObjectNode getModelJSON(@PathVariable String modelId) {
+        Model model = repositoryService.getModel(modelId);
+        ObjectNode modelNode = objectMapper.createObjectNode();
+        modelNode.put("modelId", model.getId());
+        modelNode.put("name", model.getName());
+        modelNode.put("key", model.getKey());
+        modelNode.put("description", JSONObject.parseObject(model.getMetaInfo()).getString("description"));
+        modelNode.putPOJO("lastUpdated", model.getLastUpdateTime());
+        byte[] modelEditorSource = repositoryService.getModelEditorSource(modelId);
+        if (null != modelEditorSource && modelEditorSource.length > 0) {
+            try {
+                ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(modelEditorSource);
+                editorJsonNode.put("modelType", "model");
+                modelNode.put("model", editorJsonNode);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+        } else {
+            ObjectNode editorJsonNode = objectMapper.createObjectNode();
+            editorJsonNode.put("id", "canvas");
+            editorJsonNode.put("resourceId", "canvas");
+            ObjectNode stencilSetNode = objectMapper.createObjectNode();
+            stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
+            editorJsonNode.put("modelType", "model");
+            modelNode.put("model", editorJsonNode);
+        }
+        return modelNode;
+    }
+
+    /**
+     * 淇濆瓨
+     * @param modelId
+     * @param values
+     */
+    @RequestMapping(value = "models/{modelId}/editor/json", method = RequestMethod.POST)
+    public void saveModel(@PathVariable String modelId, @RequestBody MultiValueMap<String, String> values) {
+
+        String json = values.getFirst("json_xml");
+        String name = values.getFirst("name");
+        String description = values.getFirst("description");
+        String key = values.getFirst("key");
+
+        Model modelData = repositoryService.getModel(modelId);
+        if (null == modelData) {
+            modelData = repositoryService.newModel();
+        }
+
+        ObjectNode modelNode = null;
+        try {
+            modelNode = (ObjectNode) new ObjectMapper().readTree(json);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        ObjectNode modelObjectNode = objectMapper.createObjectNode();
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
+        description = StringUtils.defaultString(description);
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
+        modelData.setMetaInfo(modelObjectNode.toString());
+        modelData.setName(name);
+        modelData.setKey(StringUtils.defaultString(key));
+        // 鏄剧ず鍙戝竷鎸夐挳
+        modelData.setDeploymentId(null);
+        repositoryService.saveModel(modelData);
+        try {
+            repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 鏍¢獙娴佺▼鍥�
+     */
+    @PostMapping(value = "/model/validate", consumes = MediaType.APPLICATION_JSON_VALUE)
+    public List<ValidationError> validate(@RequestBody JsonNode body) {
+        if (body != null && body.has("stencilset")) {
+            BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(body);
+            ProcessValidator validator = new ProcessValidatorFactory().createDefaultProcessValidator();
+            List<ValidationError> errors = validator.validate(bpmnModel);
+            return errors;
+        }
+        return Collections.emptyList();
+    }
+
+
+}
diff --git a/flowable/src/main/java/com/ycl/controller/FlowMonitorController.java b/flowable/src/main/java/com/ycl/controller/FlowMonitorController.java
new file mode 100644
index 0000000..eaa271f
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/FlowMonitorController.java
@@ -0,0 +1,403 @@
+package com.ycl.controller;
+
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.page.TableDataInfo;
+import com.ycl.common.utils.StringUtils;
+import com.ycl.common.utils.bean.BeanUtils;
+import com.ycl.system.domain.*;
+import com.ycl.mapper.ActRuExecutionMapper;
+import com.ycl.util.ActivitiTracingChart;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.bpmn.model.FlowElement;
+import org.flowable.engine.*;
+import org.flowable.engine.history.HistoricActivityInstance;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.history.HistoricProcessInstanceQuery;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.engine.runtime.ProcessInstanceQuery;
+import org.flowable.engine.task.Comment;
+import org.flowable.job.api.*;
+import org.flowable.task.api.Task;
+import org.flowable.variable.api.history.HistoricVariableInstance;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * 娴佺▼鐩戞帶
+ */
+@Api(value = "娴佺▼鐩戞帶鎺ュ彛")
+@Controller
+@RequiredArgsConstructor
+@RequestMapping("/flow/monitor")
+public class FlowMonitorController extends BaseController {
+
+    private final RuntimeService runtimeService;
+
+    private final TaskService taskService;
+
+    private final HistoryService historyService;
+
+    private final ManagementService managementService;
+
+    private final RepositoryService repositoryService;
+
+    private final ProcessEngineConfiguration configuration;
+
+    private final ActivitiTracingChart activitiTracingChart;
+
+    private final ActRuExecutionMapper actRuExecutionMapper;
+
+    private static final String prefix = "flowable/monitor";
+
+    @GetMapping("/instance")
+    public String processList() {
+        return prefix + "/processInstance";
+    }
+
+    @GetMapping("/history")
+    public String processHistory() {
+        return prefix + "/processHistory";
+    }
+
+    @GetMapping("/execution")
+    public String execution() {
+        return prefix + "/execution";
+    }
+
+    @GetMapping("/historyDetail")
+    public String historyDetail(String processInstanceId, ModelMap mmap) {
+        mmap.put("processInstanceId", processInstanceId);
+        return prefix + "/processHistoryDetail";
+    }
+
+    @GetMapping("/processVariablesDetail")
+    public String processVariablesDetail(String processInstanceId, ModelMap mmap) {
+        mmap.put("processInstanceId", processInstanceId);
+        return prefix + "/processVariablesDetail";
+    }
+
+    @ApiOperation("鏌ヨ鎵�鏈夋鍦ㄨ繍琛岀殑娴佺▼瀹炰緥鍒楄〃")
+    @RequestMapping(value = "/listProcess", method = RequestMethod.POST)
+    @ResponseBody
+    public TableDataInfo getlist(@RequestParam(required = false) String bussinesskey, @RequestParam(required = false) String name,
+                                 Integer pageSize, Integer pageNum) {
+        int start = (pageNum - 1) * pageSize;
+        ProcessInstanceQuery condition = runtimeService.createProcessInstanceQuery();
+        if (StringUtils.isNotEmpty(bussinesskey)) {
+            condition.processInstanceBusinessKey(bussinesskey);
+        }
+        if (StringUtils.isNotEmpty(name)) {
+            condition.processDefinitionName(name);
+        }
+        int total = condition.orderByProcessDefinitionId().desc().list().size();
+        List<ProcessInstance> processList = condition.orderByProcessDefinitionId().desc().listPage(start, pageSize);
+        List<FlowInfo> flows = new ArrayList<>();
+        processList.stream().forEach(p -> {
+            FlowInfo info = new FlowInfo();
+            info.setProcessInstanceId(p.getProcessInstanceId());
+            info.setBusinessKey(p.getBusinessKey());
+            info.setName(p.getProcessDefinitionName());
+            info.setStartTime(p.getStartTime());
+            info.setStartUserId(p.getStartUserId());
+            info.setSuspended(p.isSuspended());
+            info.setEnded(p.isEnded());
+            // 鏌ョ湅褰撳墠娲诲姩浠诲姟
+            List<Task> tasks =  taskService.createTaskQuery().processInstanceId(p.getProcessInstanceId()).list();
+            String taskName = "";
+            String assignee = "";
+            for (Task t : tasks) {
+                taskName += t.getName() + ",";
+                assignee += t.getAssignee() + ",";
+            }
+            taskName = taskName.substring(0, taskName.length() -1);
+            assignee = assignee.substring(0, assignee.length() -1);
+            info.setCurrentTask(taskName);
+            info.setAssignee(assignee);
+            flows.add(info);
+        });
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(0);
+        rspData.setRows(flows);
+        rspData.setTotal(total);
+        return rspData;
+    }
+
+    @ApiOperation("鏌ヨ鎵�鏈夋祦绋嬪疄渚嬪垪琛�-鍖呭惈鍦ㄨ繍琛屽拰宸茬粨鏉�")
+    @RequestMapping(value = "/listHistoryProcess", method = RequestMethod.POST)
+    @ResponseBody
+    public TableDataInfo listHistoryProcess(@RequestParam(required = false) String bussinesskey, @RequestParam(required = false) String name,
+                                            Integer pageSize, Integer pageNum) {
+        int start = (pageNum - 1) * pageSize;
+        HistoricProcessInstanceQuery condition = historyService.createHistoricProcessInstanceQuery();
+        if (StringUtils.isNotEmpty(bussinesskey)) {
+            condition.processInstanceBusinessKey(bussinesskey);
+        }
+        if (StringUtils.isNotEmpty(name)) {
+            condition.processDefinitionName(name);
+        }
+        int total = condition.orderByProcessInstanceStartTime().desc().list().size();
+        List<HistoricProcessInstance> processList = condition.orderByProcessInstanceStartTime().desc().listPage(start, pageSize);
+        List<FlowInfo> flows = new ArrayList<>();
+        processList.stream().forEach(p -> {
+            FlowInfo info = new FlowInfo();
+            info.setProcessInstanceId(p.getId());
+            info.setBusinessKey(p.getBusinessKey());
+            info.setName(p.getProcessDefinitionName());
+            info.setStartTime(p.getStartTime());
+            info.setEndTime(p.getEndTime());
+            info.setStartUserId(p.getStartUserId());
+            if (p.getEndTime() == null) {
+                info.setEnded(false);
+                // 鏌ョ湅褰撳墠娲诲姩浠诲姟
+                List<Task> tasks =  taskService.createTaskQuery().processInstanceId(p.getId()).list();
+                String taskName = "";
+                String assignee = "";
+                for (Task t : tasks) {
+                    taskName += t.getName() + ",";
+                    assignee += t.getAssignee() + ",";
+                }
+                taskName = taskName.substring(0, taskName.length() -1);
+                assignee = assignee.substring(0, assignee.length() -1);
+                info.setCurrentTask(taskName);
+                info.setAssignee(assignee);
+            } else {
+                info.setEnded(true);
+            }
+            flows.add(info);
+        });
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(0);
+        rspData.setRows(flows);
+        rspData.setTotal(total);
+        return rspData;
+    }
+
+    @ApiOperation("鏌ヨ涓�涓祦绋嬬殑娲诲姩鍘嗗彶")
+    @RequestMapping(value = "/history/{processInstanceId}", method = RequestMethod.POST)
+    @ResponseBody
+    public TableDataInfo history(@PathVariable String processInstanceId, Integer pageSize, Integer pageNum) {
+        int start = (pageNum - 1) * pageSize;
+        List<HistoricActivityInstance> history = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").orderByHistoricActivityInstanceStartTime().asc().listPage(start, pageSize);
+        int total = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").orderByHistoricActivityInstanceStartTime().asc().list().size();
+        List<TaskInfo> infos  = new ArrayList<>();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        history.stream().forEach(h->{
+            TaskInfo info = new TaskInfo();
+            info.setProcessInstanceId(h.getProcessInstanceId());
+            info.setStartTime(sdf.format(h.getStartTime()));
+            if (h.getEndTime() != null) {
+                info.setEndTime(sdf.format(h.getEndTime()));
+            }
+            info.setAssignee(h.getAssignee());
+            info.setTaskName(h.getActivityName());
+            List<Comment> comments = taskService.getTaskComments(h.getTaskId());
+            if (comments.size() > 0) {
+                info.setComment(comments.get(0).getFullMessage());
+            }
+            infos.add(info);
+        });
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(0);
+        rspData.setRows(infos);
+        rspData.setTotal(total);
+        return rspData;
+    }
+
+    @ApiOperation("鏌ヨ鎵�鏈夋鍦ㄨ繍琛岀殑鎵ц瀹炰緥鍒楄〃")
+    @RequestMapping(value = "/listExecutions", method = RequestMethod.POST)
+    @ResponseBody
+    public List<FlowInfo> listExecutions(@RequestParam(required = false) String name) {
+        List<ActRuExecution> executionList = actRuExecutionMapper.selectActRuExecutionListByProcessName(name);
+        List<FlowInfo> flows = new ArrayList<>();
+        executionList.stream().forEach(p -> {
+            FlowInfo info = new FlowInfo();
+            info.setProcessInstanceId(p.getProcInstId());
+            if (p.getSuspensionState() == 1L) {
+                info.setSuspended(false);
+            } else {
+                info.setSuspended(true);
+            }
+            if (p.getIsActive() == 0) {
+                info.setActive(false);
+            } else {
+                info.setActive(true);
+            }
+            if (p.getActId() != null) {
+                ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(p.getProcInstId()).singleResult();
+                BpmnModel bpmnModel = repositoryService.getBpmnModel(process.getProcessDefinitionId());
+                Map<String, FlowElement> nodes = bpmnModel.getMainProcess().getFlowElementMap();
+                info.setCurrentTask(nodes.get(p.getActId()).getName());
+                info.setName(process.getProcessDefinitionName());
+            } else {
+                ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(p.getProcInstId()).singleResult();
+                info.setStartTime(process.getStartTime());
+                info.setStartUserId(process.getStartUserId());
+                info.setName(process.getProcessDefinitionName());
+                List<Task> tasks =  taskService.createTaskQuery().processInstanceId(p.getProcInstId()).list();
+                String taskName = "";
+                for (Task t : tasks) {
+                    taskName += t.getName() + ",";
+                }
+                taskName = taskName.substring(0, taskName.length() -1);
+                info.setCurrentTask(taskName);
+            }
+            info.setStartTime(p.getStartTime());
+            info.setExecutionId(p.getId());
+            if (p.getParentId() == null) {
+                info.setParentExecutionId("0");
+            } else {
+                info.setParentExecutionId(p.getParentId());
+            }
+            flows.add(info);
+        });
+        return flows;
+    }
+
+    @ApiOperation("娴佺▼鍥捐繘搴﹁拷韪�")
+    @RequestMapping(value = {"/traceProcess/{processInstanceId}"}, method = RequestMethod.GET)
+    public void traceprocess(@PathVariable String processInstanceId, HttpServletResponse response) throws IOException {
+        response.setContentType("image/jpeg;charset=UTF-8");
+        response.setHeader("Content-Disposition", "inline; filename= trace.png");
+        activitiTracingChart.generateFlowChart(processInstanceId, response.getOutputStream());
+    }
+
+    @ApiOperation("鎸傝捣涓�涓祦绋嬪疄渚�")
+    @RequestMapping(value = "/suspend/{processInstanceId}", method = RequestMethod.GET)
+    @ResponseBody
+    public AjaxResult suspend(@PathVariable String processInstanceId) {
+        runtimeService.suspendProcessInstanceById(processInstanceId);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("鍞ら啋涓�涓寕璧风殑娴佺▼瀹炰緥")
+    @RequestMapping(value = "/run/{processInstanceId}", method = RequestMethod.GET)
+    @ResponseBody
+    public AjaxResult rerun(@PathVariable String processInstanceId) {
+        runtimeService.activateProcessInstanceById(processInstanceId);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("鏌ヨ涓�涓祦绋嬬殑鍙橀噺")
+    @RequestMapping(value = "/variables/{processInstanceId}", method = RequestMethod.POST)
+    @ResponseBody
+    public TableDataInfo variables(@PathVariable String processInstanceId, Integer pageSize, Integer pageNum) {
+        int start = (pageNum - 1) * pageSize;
+        List<HistoricVariableInstance> variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).orderByVariableName().asc().listPage(start, pageSize);
+        int total = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).orderByVariableName().asc().list().size();
+        List<VariableInfo> infos = new ArrayList<>();
+        variables.forEach(v->{
+            VariableInfo info = new VariableInfo();
+            BeanUtils.copyBeanProp(info, v);
+            if (v.getValue() != null) {
+                info.setValue(v.getValue().toString());
+            }
+            infos.add(info);
+        });
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(0);
+        rspData.setRows(infos);
+        rspData.setTotal(total);
+        return rspData;
+    }
+
+    @ApiOperation("鎸夌被鍨嬫煡璇㈡墍鏈夌殑浣滀笟鍒楄〃:瀹氭椂浣滀笟銆佸紓姝ヤ綔涓氥�佹寕璧蜂綔涓氥�佹浜′綔涓�")
+    @PostMapping(value = "/listJobs")
+    @ResponseBody
+    public TableDataInfo listJobs(@RequestParam(required = false) String processDefinitionId, @RequestParam(required = false) String startDate,
+                                  @RequestParam(required = false) String endDate,@RequestParam Integer type, Integer pageSize, Integer pageNum) throws Exception {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        int start = (pageNum - 1) * pageSize;
+        int total = 0;
+        List<Job> jobList = null;
+        ArrayList<DeadLetterJob> jobs = new ArrayList<>();
+        TableDataInfo rspData = new TableDataInfo();
+        if (type == 1) {
+            // 瀹氭椂浣滀笟
+            TimerJobQuery condition = managementService.createTimerJobQuery();
+            if (StringUtils.isNotEmpty(processDefinitionId)) {
+                condition.processDefinitionId(processDefinitionId);
+            }
+            if (StringUtils.isNotEmpty(startDate)) {
+                condition.duedateHigherThan(sdf.parse(startDate));
+            }
+            if (StringUtils.isNotEmpty(endDate)) {
+                condition.duedateLowerThan(sdf.parse(endDate));
+            }
+            total = condition.orderByJobDuedate().desc().list().size();
+            jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize);
+            rspData.setRows(jobList);
+        } else if (type == 2) {
+            // 寮傛浣滀笟
+            JobQuery condition = managementService.createJobQuery();
+            if (StringUtils.isNotEmpty(processDefinitionId)) {
+                condition.processDefinitionId(processDefinitionId);
+            }
+            if (StringUtils.isNotEmpty(startDate)) {
+                condition.duedateHigherThan(sdf.parse(startDate));
+            }
+            if (StringUtils.isNotEmpty(endDate)) {
+                condition.duedateLowerThan(sdf.parse(endDate));
+            }
+            total = condition.orderByJobDuedate().desc().list().size();
+            jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize);
+            rspData.setRows(jobList);
+        } else if (type == 3) {
+            // 鎸傝捣浣滀笟
+            SuspendedJobQuery condition = managementService.createSuspendedJobQuery();
+            if (StringUtils.isNotEmpty(processDefinitionId)) {
+                condition.processDefinitionId(processDefinitionId);
+            }
+            if (StringUtils.isNotEmpty(startDate)) {
+                condition.duedateHigherThan(sdf.parse(startDate));
+            }
+            if (StringUtils.isNotEmpty(endDate)) {
+                condition.duedateLowerThan(sdf.parse(endDate));
+            }
+            total = condition.orderByJobDuedate().desc().list().size();
+            jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize);
+            rspData.setRows(jobList);
+        } else if (type == 4) {
+            // 姝讳骸浣滀笟
+            DeadLetterJobQuery condition = managementService.createDeadLetterJobQuery();
+            if (StringUtils.isNotEmpty(processDefinitionId)) {
+                condition.processDefinitionId(processDefinitionId);
+            }
+            if (StringUtils.isNotEmpty(startDate)) {
+                condition.duedateHigherThan(sdf.parse(startDate));
+            }
+            if (StringUtils.isNotEmpty(endDate)) {
+                condition.duedateLowerThan(sdf.parse(endDate));
+            }
+            total = condition.orderByJobDuedate().desc().list().size();
+            jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize);
+
+            jobList.forEach(j->{
+                DeadLetterJob job = new DeadLetterJob();
+                job.setId(j.getId());
+                job.setDueDate(j.getDuedate());
+                job.setJobType(j.getJobType());
+                job.setExceptionMessage(j.getExceptionMessage());
+                job.setJobHandlerType(j.getJobHandlerType());
+                job.setProcessDefId(j.getProcessDefinitionId());
+                job.setProcessInstanceId(j.getProcessInstanceId());
+                job.setExecutionId(j.getExecutionId());
+                jobs.add(job);
+            });
+            rspData.setRows(jobs);
+        }
+        rspData.setCode(0);
+        rspData.setTotal(total);
+        return rspData;
+    }
+
+}
diff --git a/flowable/src/main/java/com/ycl/controller/LeaveapplyController.java b/flowable/src/main/java/com/ycl/controller/LeaveapplyController.java
new file mode 100644
index 0000000..3282bad
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/LeaveapplyController.java
@@ -0,0 +1,226 @@
+package com.ycl.controller;
+
+import com.ycl.common.annotation.Log;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.domain.entity.SysUser;
+import com.ycl.common.core.page.TableDataInfo;
+import com.ycl.common.enums.BusinessType;
+import com.ycl.common.utils.SecurityUtils;
+import com.ycl.common.utils.poi.ExcelUtil;
+import com.ycl.system.domain.Leaveapply;
+import com.ycl.service.ILeaveapplyService;
+import com.ycl.system.service.ISysUserService;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.task.api.Task;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 璇峰亣Controller
+ *
+ * @author shenzhanwang
+ * @date 2022-04-02
+ */
+@Controller
+@RequiredArgsConstructor
+@RequestMapping("/leaveapply")
+public class LeaveapplyController extends BaseController
+{
+    private static final String prefix = "flowable/leaveapply";
+
+    private final ILeaveapplyService leaveapplyService;
+
+    private final ISysUserService userService;
+
+    private final RuntimeService runtimeService;
+
+    private final TaskService taskService;
+
+    @GetMapping()
+    public String leaveapply()
+    {
+        return prefix + "/leaveapply";
+    }
+
+    /**
+     * 閮ㄩ棬棰嗗瀹℃壒
+     * @return
+     */
+    @ApiOperation("閮ㄩ棬棰嗗瀹℃壒")
+    @GetMapping("/deptleadercheck")
+    @ResponseBody
+    public AjaxResult deptleadercheck(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+
+    /**
+     * 浜轰簨瀹℃壒
+     * @return
+     */
+    @ApiOperation("浜轰簨瀹℃壒")
+    @GetMapping("/hrcheck")
+    @ResponseBody
+    public AjaxResult hrcheck(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+
+    /**
+     * 閿�鍋�
+     * @return
+     */
+    @ApiOperation("閿�鍋�")
+    @GetMapping("/destroyapply")
+    @ResponseBody
+    public AjaxResult destroyapply(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+
+
+    /**
+     * 璋冩暣鐢宠
+     * @return
+     */
+    @ApiOperation("璋冩暣鐢宠")
+    @GetMapping("/modifyapply")
+    @ResponseBody
+    public AjaxResult modifyapply(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+
+    /**
+     * 鍙戣捣璇峰亣鐢宠
+     * 椹冲洖鍚庝娇鐢�
+     * @return
+     */
+    @ApiOperation("鍙戣捣璇峰亣鐢宠-椹冲洖鍚庝娇鐢�")
+    @GetMapping("/addleave")
+    @ResponseBody
+    public AjaxResult addLeave(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+
+    /**
+     * 鏌ヨ璇峰亣鍒楄〃
+     */
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(Leaveapply leaveapply)
+    {
+        String username = getUsername();
+        leaveapply.setUserId(username);
+        startPage();
+        List<Leaveapply> list = leaveapplyService.selectLeaveapplyList(leaveapply);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭璇峰亣鍒楄〃
+     */
+    @Log(title = "璇峰亣", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    @ResponseBody
+    public AjaxResult export(Leaveapply leaveapply)
+    {
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+        String username = getUsername();
+        leaveapply.setUserId(username);
+        List<Leaveapply> list = leaveapplyService.selectLeaveapplyList(leaveapply);
+        ExcelUtil<Leaveapply> util = new ExcelUtil<Leaveapply>(Leaveapply.class);
+        return util.exportExcel(list, "璇峰亣鏁版嵁");
+    }
+
+    /**
+     * 褰撳墠鐧诲綍鐢ㄦ埛
+     */
+    @ApiOperation("褰撳墠鐧诲綍鐢ㄦ埛")
+    @GetMapping("/cuurentUser")
+    @ResponseBody
+    public AjaxResult cuurentUser()
+    {
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+        return AjaxResult.success(user);
+    }
+
+
+    /**
+     * 鍙戣捣璇峰亣娴佺▼
+     */
+    @Log(title = "璇峰亣", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(Leaveapply leaveapply)
+    {
+        leaveapply.setApplyTime(new Date());
+        return toAjax(leaveapplyService.insertLeaveapply(leaveapply));
+    }
+
+    @PostMapping("/update")
+    @ResponseBody
+    public AjaxResult update(Leaveapply leaveapply)
+    {
+        return toAjax(leaveapplyService.updateLeaveapply(leaveapply));
+    }
+
+    /**
+     * 鍒犻櫎璇峰亣
+     */
+    @Log(title = "璇峰亣", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(leaveapplyService.deleteLeaveapplyByIds(ids));
+    }
+
+}
diff --git a/flowable/src/main/java/com/ycl/controller/MeetingController.java b/flowable/src/main/java/com/ycl/controller/MeetingController.java
new file mode 100644
index 0000000..7326a04
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/MeetingController.java
@@ -0,0 +1,128 @@
+package com.ycl.controller;
+
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.page.TableDataInfo;
+import com.ycl.common.utils.poi.ExcelUtil;
+import com.ycl.system.domain.Meeting;
+import com.ycl.service.IMeetingService;
+import com.ycl.system.service.ISysUserService;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.task.api.Task;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
+
+@Controller
+@RequiredArgsConstructor
+@RequestMapping("/meeting")
+public class MeetingController extends BaseController {
+
+    private static final String prefix = "flowable/meeting";
+
+    private final RuntimeService runtimeService;
+
+    private final TaskService taskService;
+
+    private final ISysUserService userService;
+
+    private final IMeetingService meetingService;
+
+
+    /**
+     * 鏌ヨ浼氳鍒楄〃
+     */
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(Meeting meeting)
+    {
+        startPage();
+        List<Meeting> list = meetingService.selectMeetingList(meeting);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭浼氳鍒楄〃
+     */
+    @PostMapping("/export")
+    @ResponseBody
+    public AjaxResult export(Meeting meeting)
+    {
+        List<Meeting> list = meetingService.selectMeetingList(meeting);
+        ExcelUtil<Meeting> util = new ExcelUtil<Meeting>(Meeting.class);
+        return util.exportExcel(list, "浼氳鏁版嵁");
+    }
+
+
+    /**
+     * 鏂板淇濆瓨浼氳
+     */
+    @ApiOperation("鏂板淇濆瓨浼氳")
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(Meeting meeting)
+    {
+        return toAjax(meetingService.insertMeeting(meeting));
+    }
+
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult edit(Meeting meeting)
+    {
+        return toAjax(meetingService.updateMeeting(meeting));
+    }
+
+    /**
+     * 鍒犻櫎浼氳
+     */
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(meetingService.deleteMeetingByIds(ids));
+    }
+
+    /**
+     * 浼氳绛惧埌
+     */
+    @ApiOperation("浼氳绛惧埌")
+    @GetMapping("/signate")
+    @ResponseBody
+    public AjaxResult signate(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Meeting apply = meetingService.selectMeetingById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+
+    /**
+     * 濉啓浼氳绾
+     */
+    @ApiOperation("濉啓浼氳绾")
+    @GetMapping("/input")
+    @ResponseBody
+    public AjaxResult input(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Meeting apply = meetingService.selectMeetingById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/controller/ModelManageController.java b/flowable/src/main/java/com/ycl/controller/ModelManageController.java
new file mode 100644
index 0000000..d9c0959
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/ModelManageController.java
@@ -0,0 +1,161 @@
+package com.ycl.controller;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.page.TableDataInfo;
+import com.ycl.common.utils.StringUtils;
+import com.ycl.system.domain.ModelParam;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.apache.poi.util.IOUtils;
+import org.flowable.bpmn.converter.BpmnXMLConverter;
+import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.editor.constants.ModelDataJsonConstants;
+import org.flowable.editor.language.json.converter.BpmnJsonConverter;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.repository.Deployment;
+import org.flowable.engine.repository.Model;
+import org.flowable.engine.repository.ModelQuery;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+
+@Api(value = "妯″瀷绠$悊鎺ュ彛")
+@Controller
+@RequiredArgsConstructor
+@RequestMapping("/model/manage")
+public class ModelManageController extends BaseController {
+
+    private final RepositoryService repositoryService;
+
+    private final ObjectMapper objectMapper;
+
+    private static final String prefix = "flowable/manage";
+
+
+    @ApiOperation("鏌ヨ鎵�鏈夋ā鍨�")
+    @RequestMapping(value = "/modelLists", method = RequestMethod.POST)
+    @ResponseBody
+    public TableDataInfo modelLists(@RequestParam(required = false) String key, @RequestParam(required = false) String name,
+                                    Integer pageSize, Integer pageNum) {
+        ModelQuery query = repositoryService.createModelQuery();
+        if (StringUtils.isNotEmpty(key)) {
+            query.modelKey(key);
+        }
+        if (StringUtils.isNotEmpty(name)) {
+            query.modelName(name);
+        }
+        int start = (pageNum - 1) * pageSize;
+        List<Model> page = query.orderByCreateTime().desc().listPage(start, pageSize);
+        int total = repositoryService.createModelQuery().list().size();
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(0);
+        rspData.setRows(page);
+        rspData.setTotal(total);
+        return rspData;
+    }
+
+    /**
+     * 鏂板妯″瀷椤甸潰
+     * @return
+     */
+    @GetMapping("/add")
+    public String add()
+    {
+        return prefix + "/add";
+    }
+
+    /**
+     * 鏂板妯″瀷
+     */
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(ModelParam modelRequest) throws JsonProcessingException {
+        Model model = repositoryService.newModel();
+        model.setCategory(modelRequest.getCategory());
+        model.setKey(modelRequest.getKey());
+        ObjectNode modelNode = objectMapper.createObjectNode();
+        modelNode.put(ModelDataJsonConstants.MODEL_NAME, modelRequest.getName());
+        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, modelRequest.getDescription());
+        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, modelRequest.getVersion());
+        model.setMetaInfo(modelNode.toString());
+        model.setName(modelRequest.getName());
+        model.setVersion(modelRequest.getVersion());
+        ModelQuery modelQuery = repositoryService.createModelQuery();
+        List<Model> list = modelQuery.modelKey(modelRequest.getKey()).list();
+        if (list.size() > 0) {
+            return AjaxResult.error("妯″瀷鏍囪瘑涓嶈兘閲嶅");
+        } else {
+            // 淇濆瓨妯″瀷鍒癮ct_re_model琛�
+            repositoryService.saveModel(model);
+            HashMap<String, Object> content = new HashMap();
+            content.put("resourceId", model.getId());
+            HashMap<String, String> properties = new HashMap();
+            properties.put("process_id", modelRequest.getKey());
+            properties.put("name", modelRequest.getName());
+            properties.put("category", modelRequest.getCategory());
+            content.put("properties", properties);
+            HashMap<String, String> stencilset = new HashMap();
+            stencilset.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
+            content.put("stencilset", stencilset);
+            // 淇濆瓨妯″瀷鏂囦欢鍒癮ct_ge_bytearray琛�
+            repositoryService.addModelEditorSource(model.getId(), objectMapper.writeValueAsBytes(content));
+            return AjaxResult.success(model);
+        }
+    }
+
+    @RequestMapping("/deploy/{modelId}")
+    @ResponseBody
+    public AjaxResult modelDeployment(@PathVariable String modelId) {
+        try {
+            Model model = repositoryService.getModel(modelId);
+            byte[] modelData = repositoryService.getModelEditorSource(modelId);
+            JsonNode jsonNode = objectMapper.readTree(modelData);
+            BpmnModel bpmnModel = (new BpmnJsonConverter()).convertToBpmnModel(jsonNode);
+            Deployment deploy = repositoryService.createDeployment().category(model.getCategory())
+                    .name(model.getName()).key(model.getKey())
+                    .addBpmnModel(model.getKey() + ".bpmn20.xml", bpmnModel)
+                    .deploy();
+            model.setDeploymentId(deploy.getId());
+            repositoryService.saveModel(model);
+            return AjaxResult.success();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return AjaxResult.error("娴佺▼鍥句笉鍚堣鑼冿紝璇烽噸鏂拌璁�");
+        }
+    }
+
+    @PostMapping("/remove/{modelId}")
+    @ResponseBody
+    public AjaxResult removeModel(@PathVariable String modelId) {
+        repositoryService.deleteModel(modelId);
+        return AjaxResult.success("鍒犻櫎鎴愬姛");
+    }
+
+    @GetMapping("/export/{modelId}")
+    public void modelExport(@PathVariable String modelId, HttpServletResponse response) throws IOException {
+        byte[] modelData = repositoryService.getModelEditorSource(modelId);
+        JsonNode jsonNode = objectMapper.readTree(modelData);
+        BpmnModel bpmnModel = (new BpmnJsonConverter()).convertToBpmnModel(jsonNode);
+        byte[] xmlBytes = (new BpmnXMLConverter()).convertToXML(bpmnModel, "UTF-8");
+        ByteArrayInputStream in = new ByteArrayInputStream(xmlBytes);
+        String filename = bpmnModel.getMainProcess().getId() + ".bpmn20.xml";
+        response.setHeader("Content-Disposition","attachment;filename=" + filename);
+        response.setHeader("content-Type", "application/xml");
+        response.flushBuffer();
+        IOUtils.copy(in, response.getOutputStream());
+    }
+
+
+}
diff --git a/flowable/src/main/java/com/ycl/controller/PurchaseController.java b/flowable/src/main/java/com/ycl/controller/PurchaseController.java
new file mode 100644
index 0000000..558527f
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/PurchaseController.java
@@ -0,0 +1,217 @@
+package com.ycl.controller;
+
+import com.ycl.common.annotation.Log;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.page.TableDataInfo;
+import com.ycl.common.enums.BusinessType;
+import com.ycl.common.utils.poi.ExcelUtil;
+import com.ycl.system.domain.Purchase;
+import com.ycl.service.IPurchaseService;
+import com.ycl.system.service.ISysUserService;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.task.api.Task;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 閲囪喘Controller
+ *
+ * @author shenzhanwang
+ * @date 2022-05-28
+ */
+@Controller
+@RequiredArgsConstructor
+@RequestMapping("/purchase")
+public class PurchaseController extends BaseController
+{
+    private static final String prefix = "flowable/purchase";
+
+    private final IPurchaseService purchaseService;
+
+    private final ISysUserService userService;
+
+    private final RuntimeService runtimeService;
+
+    private final TaskService taskService;
+
+    @GetMapping()
+    public String purchase()
+    {
+        return prefix + "/purchase";
+    }
+
+    /**
+     * 鏌ヨ閲囪喘鍒楄〃
+     */
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(Purchase purchase)
+    {
+        startPage();
+        List<Purchase> list = purchaseService.selectPurchaseList(purchase);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭閲囪喘鍒楄〃
+     */
+    @PostMapping("/export")
+    @ResponseBody
+    public AjaxResult export(Purchase purchase)
+    {
+        List<Purchase> list = purchaseService.selectPurchaseList(purchase);
+        ExcelUtil<Purchase> util = new ExcelUtil<Purchase>(Purchase.class);
+        return util.exportExcel(list, "閲囪喘鏁版嵁");
+    }
+
+
+    /**
+     * 鏂板淇濆瓨閲囪喘
+     */
+    @ApiOperation("鏂板淇濆瓨閲囪喘")
+    @Log(title = "閲囪喘", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(Purchase purchase)
+    {
+        purchase.setApplytime(new Date());
+        return toAjax(purchaseService.insertPurchase(purchase));
+    }
+
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult edit(Purchase purchase)
+    {
+        return toAjax(purchaseService.updatePurchase(purchase));
+    }
+
+    /**
+     * 鍒犻櫎閲囪喘
+     */
+    @Log(title = "閲囪喘", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(purchaseService.deletePurchaseByIds(ids));
+    }
+
+    /**
+     * 閲囪喘缁忕悊瀹℃壒
+     */
+    @ApiOperation("閲囪喘缁忕悊瀹℃壒")
+    @GetMapping("/purchasemanager")
+    @ResponseBody
+    public AjaxResult purchasemanager(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+
+    /**
+     * 璐㈠姟瀹℃壒
+     */
+    @ApiOperation("璐㈠姟瀹℃壒")
+    @GetMapping("/finance")
+    @ResponseBody
+    public AjaxResult finance(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+
+    /**
+     * 鎬荤粡鐞嗗鎵�
+     */
+    @ApiOperation("鎬荤粡鐞嗗鎵�")
+    @GetMapping("/manager")
+    @ResponseBody
+    public AjaxResult manager(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+
+    /**
+     * 鍑虹撼浠樻
+     */
+    @ApiOperation("鍑虹撼浠樻")
+    @GetMapping("/pay")
+    @ResponseBody
+    public AjaxResult pay(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+
+    /**
+     * 鏀惰揣纭
+     */
+    @ApiOperation("鏀惰揣纭")
+    @GetMapping("/receiveitem")
+    @ResponseBody
+    public AjaxResult receiveitem(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+
+    /**
+     * 璋冩暣鐢宠
+     */
+    @ApiOperation("璋冩暣鐢宠")
+    @GetMapping("/updateapply")
+    @ResponseBody
+    public AjaxResult updateapply(String taskid)
+    {
+        Task t = taskService.createTaskQuery().taskId(taskid).singleResult();
+        String processId = t.getProcessInstanceId();
+        ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
+        if (p != null) {
+            Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey()));
+            return AjaxResult.success(apply);
+        }
+        return AjaxResult.error("娴佺▼涓嶅瓨鍦�");
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/controller/TaskController.java b/flowable/src/main/java/com/ycl/controller/TaskController.java
new file mode 100644
index 0000000..8746d9e
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/controller/TaskController.java
@@ -0,0 +1,208 @@
+package com.ycl.controller;
+
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.core.domain.entity.SysUser;
+import com.ycl.common.core.page.TableDataInfo;
+import com.ycl.common.utils.SecurityUtils;
+import com.ycl.common.utils.StringUtils;
+import com.ycl.system.domain.TaskInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.flowable.engine.FormService;
+import org.flowable.engine.HistoryService;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.history.HistoricActivityInstance;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.engine.task.Comment;
+import org.flowable.task.api.Task;
+import org.flowable.task.api.TaskQuery;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Api(value = "寰呭姙浠诲姟鎺ュ彛")
+@Controller
+@RequiredArgsConstructor
+@RequestMapping("/task/manage")
+public class TaskController extends BaseController {
+
+    private final RuntimeService runtimeService;
+
+    private final TaskService taskService;
+
+    private final FormService formService;
+
+    private final HistoryService historyService;
+
+    private static final String prefix = "flowable/task";
+
+    @GetMapping("/mytask")
+    public String mytasks()
+    {
+        return prefix + "/mytasks";
+    }
+
+    @GetMapping("/alltasks")
+    public String alltasks()
+    {
+        return prefix + "/alltasks";
+    }
+
+    /**
+     * 鏌ヨ鎴戠殑寰呭姙浠诲姟鍒楄〃
+     */
+    @ApiOperation("鏌ヨ鎴戠殑寰呭姙浠诲姟鍒楄〃")
+    @PostMapping("/mylist")
+    @ResponseBody
+    public TableDataInfo mylist(TaskInfo param)
+    {
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+        String username = getUsername();
+        TaskQuery condition = taskService.createTaskQuery().taskAssignee(username);
+        if (StringUtils.isNotEmpty(param.getTaskName())) {
+            condition.taskName(param.getTaskName());
+        }
+        if (StringUtils.isNotEmpty(param.getProcessName())) {
+            condition.processDefinitionName(param.getProcessName());
+        }
+        // 杩囨护鎺夋祦绋嬫寕璧风殑寰呭姙浠诲姟
+        int total = condition.active().orderByTaskCreateTime().desc().list().size();
+        int start = (param.getPageNum()-1) * param.getPageSize();
+        List<Task> taskList = condition.active().orderByTaskCreateTime().desc().listPage(start, param.getPageSize());
+        List<TaskInfo> tasks = new ArrayList<>();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        taskList.stream().forEach(a->{
+            ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(a.getProcessInstanceId()).singleResult();
+            TaskInfo info = new TaskInfo();
+            info.setAssignee(a.getAssignee());
+            info.setBusinessKey(process.getBusinessKey());
+            info.setCreateTime(sdf.format(a.getCreateTime()));
+            info.setTaskName(a.getName());
+            info.setExecutionId(a.getExecutionId());
+            info.setProcessInstanceId(a.getProcessInstanceId());
+            info.setProcessName(process.getProcessDefinitionName());
+            info.setStarter(process.getStartUserId());
+            info.setStartTime(sdf.format(process.getStartTime()));
+            info.setTaskId(a.getId());
+            String formKey = formService.getTaskFormData(a.getId()).getFormKey();
+            info.setFormKey(formKey);
+            tasks.add(info);
+        });
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(0);
+        rspData.setRows(tasks);
+        rspData.setTotal(total);
+        return rspData;
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈夊緟鍔炰换鍔″垪琛�
+     */
+    @ApiOperation("鏌ヨ鎵�鏈夊緟鍔炰换鍔″垪琛�")
+    @PostMapping("/alllist")
+    @ResponseBody
+    public TableDataInfo alllist(TaskInfo param)
+    {
+        TaskQuery condition = taskService.createTaskQuery();
+        if (StringUtils.isNotEmpty(param.getTaskName())) {
+            condition.taskName(param.getTaskName());
+        }
+        if (StringUtils.isNotEmpty(param.getProcessName())) {
+            condition.processDefinitionName(param.getProcessName());
+        }
+        int total = condition.active().orderByTaskCreateTime().desc().list().size();
+        int start = (param.getPageNum()-1) * param.getPageSize();
+        List<Task> taskList = condition.active().orderByTaskCreateTime().desc().listPage(start, param.getPageSize());
+        List<TaskInfo> tasks = new ArrayList<>();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        taskList.stream().forEach(a->{
+            ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(a.getProcessInstanceId()).singleResult();
+            TaskInfo info = new TaskInfo();
+            info.setAssignee(a.getAssignee());
+            info.setBusinessKey(process.getBusinessKey());
+            info.setCreateTime(sdf.format(a.getCreateTime()));
+            info.setTaskName(a.getName());
+            info.setExecutionId(a.getExecutionId());
+            info.setProcessInstanceId(a.getProcessInstanceId());
+            info.setProcessName(process.getProcessDefinitionName());
+            info.setStarter(process.getStartUserId());
+            info.setStartTime(sdf.format(process.getStartTime()));
+            info.setTaskId(a.getId());
+            String formKey = formService.getTaskFormData(a.getId()).getFormKey();
+            info.setFormKey(formKey);
+            tasks.add(info);
+        });
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(0);
+        rspData.setRows(tasks);
+        rspData.setTotal(total);
+        return rspData;
+    }
+
+    /**
+     * 鐢╰askid鏌ヨformkey
+     **/
+    @ApiOperation("鐢╰askid鏌ヨformkey")
+    @PostMapping("/forminfo/{taskId}")
+    @ResponseBody
+    public AjaxResult alllist(@PathVariable String taskId)
+    {
+        String formKey = formService.getTaskFormData(taskId).getFormKey();
+        return AjaxResult.success(formKey);
+    }
+
+    @ApiOperation("鍔炵悊涓�涓敤鎴蜂换鍔�")
+    @RequestMapping(value = "/completeTask/{taskId}", method = RequestMethod.POST)
+    @ResponseBody
+    public AjaxResult completeTask(@PathVariable("taskId") String taskId, @RequestBody(required=false) Map<String, Object> variables) {
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+        String username = getUsername();
+        taskService.setAssignee(taskId, username);
+        // 鏌ュ嚭娴佺▼瀹炰緥id
+        String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
+        if (variables == null) {
+            taskService.complete(taskId);
+        } else {
+            // 娣诲姞瀹℃壒鎰忚
+            if (variables.get("comment") != null) {
+                taskService.addComment(taskId, processInstanceId, (String) variables.get("comment"));
+                variables.remove("comment");
+            }
+            taskService.complete(taskId, variables);
+        }
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("浠诲姟鍔炵悊鏃堕棿杞�")
+    @RequestMapping(value = "/history/{taskId}", method = RequestMethod.GET)
+    @ResponseBody
+    public List<TaskInfo> history(@PathVariable String taskId) {
+        String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
+        List<HistoricActivityInstance> history = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").orderByHistoricActivityInstanceStartTime().asc().list();
+        List<TaskInfo> infos  = new ArrayList<>();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        history.stream().forEach(h->{
+            TaskInfo info = new TaskInfo();
+            info.setProcessInstanceId(h.getProcessInstanceId());
+            info.setStartTime(sdf.format(h.getStartTime()));
+            if (h.getEndTime() != null) {
+                info.setEndTime(sdf.format(h.getEndTime()));
+            }
+            info.setAssignee(h.getAssignee());
+            info.setTaskName(h.getActivityName());
+            List<Comment> comments = taskService.getTaskComments(h.getTaskId());
+            if (comments.size() > 0) {
+                info.setComment(comments.get(0).getFullMessage());
+            }
+            infos.add(info);
+        });
+        return infos;
+    }
+}
diff --git a/system/src/main/java/com/ycl/system/mapper/ActRuExecutionMapper.java b/flowable/src/main/java/com/ycl/mapper/ActRuExecutionMapper.java
similarity index 97%
rename from system/src/main/java/com/ycl/system/mapper/ActRuExecutionMapper.java
rename to flowable/src/main/java/com/ycl/mapper/ActRuExecutionMapper.java
index 3ecaced..e1ac6b7 100644
--- a/system/src/main/java/com/ycl/system/mapper/ActRuExecutionMapper.java
+++ b/flowable/src/main/java/com/ycl/mapper/ActRuExecutionMapper.java
@@ -1,4 +1,4 @@
-package com.ycl.system.mapper;
+package com.ycl.mapper;
 
 import java.util.List;
 import com.ycl.system.domain.ActRuExecution;
diff --git a/system/src/main/java/com/ycl/system/mapper/LeaveapplyMapper.java b/flowable/src/main/java/com/ycl/mapper/LeaveapplyMapper.java
similarity index 96%
rename from system/src/main/java/com/ycl/system/mapper/LeaveapplyMapper.java
rename to flowable/src/main/java/com/ycl/mapper/LeaveapplyMapper.java
index 442cc67..21946c5 100644
--- a/system/src/main/java/com/ycl/system/mapper/LeaveapplyMapper.java
+++ b/flowable/src/main/java/com/ycl/mapper/LeaveapplyMapper.java
@@ -1,4 +1,4 @@
-package com.ycl.system.mapper;
+package com.ycl.mapper;
 
 import java.util.List;
 import com.ycl.system.domain.Leaveapply;
diff --git a/system/src/main/java/com/ycl/system/mapper/MeetingMapper.java b/flowable/src/main/java/com/ycl/mapper/MeetingMapper.java
similarity index 96%
rename from system/src/main/java/com/ycl/system/mapper/MeetingMapper.java
rename to flowable/src/main/java/com/ycl/mapper/MeetingMapper.java
index f0ba6a4..5c1209d 100644
--- a/system/src/main/java/com/ycl/system/mapper/MeetingMapper.java
+++ b/flowable/src/main/java/com/ycl/mapper/MeetingMapper.java
@@ -1,4 +1,4 @@
-package com.ycl.system.mapper;
+package com.ycl.mapper;
 
 import java.util.List;
 import com.ycl.system.domain.Meeting;
diff --git a/system/src/main/java/com/ycl/system/mapper/PurchaseMapper.java b/flowable/src/main/java/com/ycl/mapper/PurchaseMapper.java
similarity index 96%
rename from system/src/main/java/com/ycl/system/mapper/PurchaseMapper.java
rename to flowable/src/main/java/com/ycl/mapper/PurchaseMapper.java
index e390398..54e0a7a 100644
--- a/system/src/main/java/com/ycl/system/mapper/PurchaseMapper.java
+++ b/flowable/src/main/java/com/ycl/mapper/PurchaseMapper.java
@@ -1,4 +1,4 @@
-package com.ycl.system.mapper;
+package com.ycl.mapper;
 
 import java.util.List;
 import com.ycl.system.domain.Purchase;
diff --git a/system/src/main/java/com/ycl/system/service/ILeaveapplyService.java b/flowable/src/main/java/com/ycl/service/ILeaveapplyService.java
similarity index 96%
rename from system/src/main/java/com/ycl/system/service/ILeaveapplyService.java
rename to flowable/src/main/java/com/ycl/service/ILeaveapplyService.java
index 50a76a3..85fe0dc 100644
--- a/system/src/main/java/com/ycl/system/service/ILeaveapplyService.java
+++ b/flowable/src/main/java/com/ycl/service/ILeaveapplyService.java
@@ -1,4 +1,4 @@
-package com.ycl.system.service;
+package com.ycl.service;
 
 import java.util.List;
 import com.ycl.system.domain.Leaveapply;
diff --git a/system/src/main/java/com/ycl/system/service/IMeetingService.java b/flowable/src/main/java/com/ycl/service/IMeetingService.java
similarity index 96%
rename from system/src/main/java/com/ycl/system/service/IMeetingService.java
rename to flowable/src/main/java/com/ycl/service/IMeetingService.java
index 3d12e1c..bef2b9e 100644
--- a/system/src/main/java/com/ycl/system/service/IMeetingService.java
+++ b/flowable/src/main/java/com/ycl/service/IMeetingService.java
@@ -1,4 +1,4 @@
-package com.ycl.system.service;
+package com.ycl.service;
 
 import java.util.List;
 import com.ycl.system.domain.Meeting;
diff --git a/system/src/main/java/com/ycl/system/service/IPurchaseService.java b/flowable/src/main/java/com/ycl/service/IPurchaseService.java
similarity index 89%
rename from system/src/main/java/com/ycl/system/service/IPurchaseService.java
rename to flowable/src/main/java/com/ycl/service/IPurchaseService.java
index f553b3b..7986e61 100644
--- a/system/src/main/java/com/ycl/system/service/IPurchaseService.java
+++ b/flowable/src/main/java/com/ycl/service/IPurchaseService.java
@@ -1,19 +1,19 @@
-package com.ycl.system.service;
+package com.ycl.service;
 
 import java.util.List;
 import com.ycl.system.domain.Purchase;
 
 /**
  * 閲囪喘Service鎺ュ彛
- * 
+ *
  * @author shenzhanwang
  * @date 2022-05-28
  */
-public interface IPurchaseService 
+public interface IPurchaseService
 {
     /**
      * 鏌ヨ閲囪喘
-     * 
+     *
      * @param id 閲囪喘涓婚敭
      * @return 閲囪喘
      */
@@ -21,7 +21,7 @@
 
     /**
      * 鏌ヨ閲囪喘鍒楄〃
-     * 
+     *
      * @param purchase 閲囪喘
      * @return 閲囪喘闆嗗悎
      */
@@ -29,7 +29,7 @@
 
     /**
      * 鏂板閲囪喘
-     * 
+     *
      * @param purchase 閲囪喘
      * @return 缁撴灉
      */
@@ -37,7 +37,7 @@
 
     /**
      * 淇敼閲囪喘
-     * 
+     *
      * @param purchase 閲囪喘
      * @return 缁撴灉
      */
@@ -45,7 +45,7 @@
 
     /**
      * 鎵归噺鍒犻櫎閲囪喘
-     * 
+     *
      * @param ids 闇�瑕佸垹闄ょ殑閲囪喘涓婚敭闆嗗悎
      * @return 缁撴灉
      */
@@ -53,7 +53,7 @@
 
     /**
      * 鍒犻櫎閲囪喘淇℃伅
-     * 
+     *
      * @param id 閲囪喘涓婚敭
      * @return 缁撴灉
      */
diff --git a/flowable/src/main/java/com/ycl/service/impl/LeaveapplyServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/LeaveapplyServiceImpl.java
new file mode 100644
index 0000000..9b77f5f
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/impl/LeaveapplyServiceImpl.java
@@ -0,0 +1,130 @@
+package com.ycl.service.impl;
+
+import com.ycl.common.core.text.Convert;
+import com.ycl.service.ILeaveapplyService;
+import com.ycl.system.domain.Leaveapply;
+import com.ycl.mapper.LeaveapplyMapper;
+import lombok.RequiredArgsConstructor;
+import org.flowable.engine.HistoryService;
+import org.flowable.engine.IdentityService;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.task.api.Task;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * 璇峰亣Service涓氬姟灞傚鐞�
+ *
+ * @author shenzhanwang
+ * @date 2022-04-02
+ */
+@Service
+@Transactional
+@RequiredArgsConstructor
+public class LeaveapplyServiceImpl implements ILeaveapplyService {
+
+    private final LeaveapplyMapper leaveapplyMapper;
+
+    private final RuntimeService runtimeService;
+
+    private final TaskService taskService;
+
+    private final IdentityService identityService;
+
+    private final HistoryService historyService;
+
+    /**
+     * 鏌ヨ璇峰亣
+     *
+     * @param id 璇峰亣涓婚敭
+     * @return 璇峰亣
+     */
+    @Override
+    public Leaveapply selectLeaveapplyById(Long id) {
+        return leaveapplyMapper.selectLeaveapplyById(id);
+    }
+
+    /**
+     * 鏌ヨ璇峰亣鍒楄〃
+     *
+     * @param leaveapply 璇峰亣
+     * @return 璇峰亣
+     */
+    @Override
+    public List<Leaveapply> selectLeaveapplyList(Leaveapply leaveapply) {
+        return leaveapplyMapper.selectLeaveapplyList(leaveapply);
+    }
+
+    /**
+     * 鏂板璇峰亣
+     *
+     * @param leaveapply 璇峰亣
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertLeaveapply(Leaveapply leaveapply) {
+        int rows = leaveapplyMapper.insertLeaveapply(leaveapply);
+        // 鍙戣捣璇峰亣娴佺▼
+        identityService.setAuthenticatedUserId(leaveapply.getUserId());
+        HashMap<String, Object> variables = new HashMap<>();
+        variables.put("applyuserid", leaveapply.getUserId());
+        variables.put("deptleader", leaveapply.getDeptleader());
+        runtimeService.startProcessInstanceByKey("leave", String.valueOf(leaveapply.getId()), variables);
+        // 鑷姩瀹屾垚绗竴涓换鍔�
+        Task autoTask = taskService.createTaskQuery().processDefinitionKey("leave").processInstanceBusinessKey(String.valueOf(leaveapply.getId())).singleResult();
+        taskService.complete(autoTask.getId());
+        return rows;
+    }
+
+    /**
+     * 淇敼璇峰亣
+     *
+     * @param leaveapply 璇峰亣
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateLeaveapply(Leaveapply leaveapply) {
+        return leaveapplyMapper.updateLeaveapply(leaveapply);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎璇峰亣
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑璇峰亣涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteLeaveapplyByIds(String ids) {
+        String[] keys = Convert.toStrArray(ids);
+        for (String key : keys) {
+            ProcessInstance process = runtimeService.createProcessInstanceQuery().processDefinitionKey("leave").processInstanceBusinessKey(key).singleResult();
+            if (process != null) {
+                runtimeService.deleteProcessInstance(process.getId(), "鍒犻櫎");
+            }
+            // 鍒犻櫎鍘嗗彶鏁版嵁
+            HistoricProcessInstance history = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("leave").processInstanceBusinessKey(key).singleResult();
+            if (history != null) {
+                historyService.deleteHistoricProcessInstance(history.getId());
+            }
+            leaveapplyMapper.deleteLeaveapplyById(Long.parseLong(key));
+        }
+        return keys.length;
+    }
+
+    /**
+     * 鍒犻櫎璇峰亣淇℃伅
+     *
+     * @param id 璇峰亣涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteLeaveapplyById(Long id) {
+        return leaveapplyMapper.deleteLeaveapplyById(id);
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/service/impl/MeetingServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/MeetingServiceImpl.java
new file mode 100644
index 0000000..98793b9
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/impl/MeetingServiceImpl.java
@@ -0,0 +1,131 @@
+package com.ycl.service.impl;
+
+import com.ycl.common.core.text.Convert;
+import com.ycl.service.IMeetingService;
+import com.ycl.system.domain.Meeting;
+import com.ycl.mapper.MeetingMapper;
+import com.ycl.mapper.PurchaseMapper;
+import lombok.RequiredArgsConstructor;
+import org.flowable.engine.HistoryService;
+import org.flowable.engine.IdentityService;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * 浼氳Service涓氬姟灞傚鐞�
+ *
+ * @author shenzhanwang
+ * @date 2022-05-30
+ */
+@Service
+@RequiredArgsConstructor
+@Transactional
+public class MeetingServiceImpl implements IMeetingService {
+
+    private final MeetingMapper meetingMapper;
+
+    private final PurchaseMapper purchaseMapper;
+
+    private final RuntimeService runtimeService;
+
+    private final TaskService taskService;
+
+    private final IdentityService identityService;
+
+    private final HistoryService historyService;
+
+    /**
+     * 鏌ヨ浼氳
+     *
+     * @param id 浼氳涓婚敭
+     * @return 浼氳
+     */
+    @Override
+    public Meeting selectMeetingById(Long id) {
+        return meetingMapper.selectMeetingById(id);
+    }
+
+    /**
+     * 鏌ヨ浼氳鍒楄〃
+     *
+     * @param meeting 浼氳
+     * @return 浼氳
+     */
+    @Override
+    public List<Meeting> selectMeetingList(Meeting meeting) {
+        return meetingMapper.selectMeetingList(meeting);
+    }
+
+    /**
+     * 鏂板浼氳
+     *
+     * @param meeting 浼氳
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertMeeting(Meeting meeting) {
+        int row = meetingMapper.insertMeeting(meeting);
+        // 鍚姩浼氳娴佺▼
+        identityService.setAuthenticatedUserId(meeting.getHost());
+        HashMap<String, Object> variables = new HashMap<>();
+        variables.put("host", meeting.getHost());
+        String[] person = meeting.getPeoplelist().split(",");
+        variables.put("people", Arrays.asList(person));
+        runtimeService.startProcessInstanceByKey("meeting", String.valueOf(meeting.getId()), variables);
+        return row;
+    }
+
+    /**
+     * 淇敼浼氳
+     *
+     * @param meeting 浼氳
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateMeeting(Meeting meeting) {
+        return meetingMapper.updateMeeting(meeting);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎浼氳
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑浼氳涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteMeetingByIds(String ids) {
+        String[] keys = Convert.toStrArray(ids);
+        for (String key : keys) {
+            ProcessInstance process = runtimeService.createProcessInstanceQuery().processDefinitionKey("meeting").processInstanceBusinessKey(key).singleResult();
+            if (process != null) {
+                runtimeService.deleteProcessInstance(process.getId(), "鍒犻櫎");
+            }
+            // 鍒犻櫎鍘嗗彶鏁版嵁
+            HistoricProcessInstance history = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("meeting").processInstanceBusinessKey(key).singleResult();
+            if (history != null) {
+                historyService.deleteHistoricProcessInstance(history.getId());
+            }
+            meetingMapper.deleteMeetingByIds(Convert.toStrArray(ids));
+        }
+        return keys.length;
+    }
+
+    /**
+     * 鍒犻櫎浼氳淇℃伅
+     *
+     * @param id 浼氳涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteMeetingById(Long id) {
+        return meetingMapper.deleteMeetingById(id);
+    }
+}
diff --git a/flowable/src/main/java/com/ycl/service/impl/PurchaseServiceImpl.java b/flowable/src/main/java/com/ycl/service/impl/PurchaseServiceImpl.java
new file mode 100644
index 0000000..f9987db
--- /dev/null
+++ b/flowable/src/main/java/com/ycl/service/impl/PurchaseServiceImpl.java
@@ -0,0 +1,130 @@
+package com.ycl.service.impl;
+
+import com.ycl.common.core.text.Convert;
+import com.ycl.service.IPurchaseService;
+import com.ycl.system.domain.Purchase;
+import com.ycl.mapper.PurchaseMapper;
+import lombok.RequiredArgsConstructor;
+import org.flowable.engine.HistoryService;
+import org.flowable.engine.IdentityService;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * 閲囪喘Service涓氬姟灞傚鐞�
+ *
+ * @author shenzhanwang
+ * @date 2022-05-28
+ */
+@Service
+@Transactional
+@RequiredArgsConstructor
+public class PurchaseServiceImpl implements IPurchaseService {
+
+    private final PurchaseMapper purchaseMapper;
+
+    private final RuntimeService runtimeService;
+
+    private final TaskService taskService;
+
+    private final IdentityService identityService;
+
+    private final HistoryService historyService;
+
+    /**
+     * 鏌ヨ閲囪喘
+     *
+     * @param id 閲囪喘涓婚敭
+     * @return 閲囪喘
+     */
+    @Override
+    public Purchase selectPurchaseById(Long id) {
+        return purchaseMapper.selectPurchaseById(id);
+    }
+
+    /**
+     * 鏌ヨ閲囪喘鍒楄〃
+     *
+     * @param purchase 閲囪喘
+     * @return 閲囪喘
+     */
+    @Override
+    public List<Purchase> selectPurchaseList(Purchase purchase) {
+        return purchaseMapper.selectPurchaseList(purchase);
+    }
+
+    /**
+     * 鏂板閲囪喘
+     *
+     * @param purchase 閲囪喘
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertPurchase(Purchase purchase) {
+        int row = purchaseMapper.insertPurchase(purchase);
+        // 鍚姩閲囪喘娴佺▼
+        identityService.setAuthenticatedUserId(purchase.getApplyer());
+        HashMap<String, Object> variables = new HashMap<>();
+        variables.put("starter", purchase.getApplyer());
+        variables.put("purchasemanager", purchase.getPurchasemanager());
+        variables.put("financeName", purchase.getFinanceName());
+        variables.put("pay", purchase.getPay());
+        variables.put("managerName", purchase.getManagerName());
+        variables.put("money", Double.parseDouble(purchase.getTotal()));
+        runtimeService.startProcessInstanceByKey("purchase", String.valueOf(purchase.getId()), variables);
+        return row;
+    }
+
+    /**
+     * 淇敼閲囪喘
+     *
+     * @param purchase 閲囪喘
+     * @return 缁撴灉
+     */
+    @Override
+    public int updatePurchase(Purchase purchase) {
+        return purchaseMapper.updatePurchase(purchase);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎閲囪喘
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑閲囪喘涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deletePurchaseByIds(String ids) {
+        String[] keys = Convert.toStrArray(ids);
+        for (String key : keys) {
+            ProcessInstance process = runtimeService.createProcessInstanceQuery().processDefinitionKey("purchase").processInstanceBusinessKey(key).singleResult();
+            if (process != null) {
+                runtimeService.deleteProcessInstance(process.getId(), "鍒犻櫎");
+            }
+            // 鍒犻櫎鍘嗗彶鏁版嵁
+            HistoricProcessInstance history = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("purchase").processInstanceBusinessKey(key).singleResult();
+            if (history != null) {
+                historyService.deleteHistoricProcessInstance(history.getId());
+            }
+            purchaseMapper.deletePurchaseByIds(Convert.toStrArray(ids));
+        }
+        return keys.length;
+    }
+
+    /**
+     * 鍒犻櫎閲囪喘淇℃伅
+     *
+     * @param id 閲囪喘涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deletePurchaseById(Long id) {
+        return purchaseMapper.deletePurchaseById(id);
+    }
+}
diff --git a/start/src/main/java/com/ycl/web/util/ActivitiTracingChart.java b/flowable/src/main/java/com/ycl/util/ActivitiTracingChart.java
similarity index 92%
rename from start/src/main/java/com/ycl/web/util/ActivitiTracingChart.java
rename to flowable/src/main/java/com/ycl/util/ActivitiTracingChart.java
index 080bd1f..bb40ff2 100644
--- a/start/src/main/java/com/ycl/web/util/ActivitiTracingChart.java
+++ b/flowable/src/main/java/com/ycl/util/ActivitiTracingChart.java
@@ -1,10 +1,7 @@
-package com.ycl.web.util;
+package com.ycl.util;
 
-import com.ycl.framework.web.domain.server.Sys;
 import org.apache.commons.lang3.StringUtils;
 import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.bpmn.model.FlowNode;
-import org.flowable.bpmn.model.SequenceFlow;
 import org.flowable.common.engine.impl.util.IoUtil;
 import org.flowable.engine.HistoryService;
 import org.flowable.engine.ProcessEngineConfiguration;
@@ -15,16 +12,13 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
-import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 /**
  * 娴佺▼杩借釜鍥�
diff --git a/system/src/main/resources/mapper/system/ActRuExecutionMapper.xml b/flowable/src/main/resources/mapper/ActRuExecutionMapper.xml
similarity index 99%
rename from system/src/main/resources/mapper/system/ActRuExecutionMapper.xml
rename to flowable/src/main/resources/mapper/ActRuExecutionMapper.xml
index d882dcf..cfab5de 100644
--- a/system/src/main/resources/mapper/system/ActRuExecutionMapper.xml
+++ b/flowable/src/main/resources/mapper/ActRuExecutionMapper.xml
@@ -2,7 +2,7 @@
 <!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ycl.system.mapper.ActRuExecutionMapper">
+<mapper namespace="com.ycl.mapper.ActRuExecutionMapper">
 
     <resultMap type="ActRuExecution" id="ActRuExecutionResult">
         <result property="id"    column="ID_"    />
diff --git a/system/src/main/resources/mapper/system/LeaveapplyMapper.xml b/flowable/src/main/resources/mapper/LeaveapplyMapper.xml
similarity index 98%
rename from system/src/main/resources/mapper/system/LeaveapplyMapper.xml
rename to flowable/src/main/resources/mapper/LeaveapplyMapper.xml
index acee100..9fb53f6 100644
--- a/system/src/main/resources/mapper/system/LeaveapplyMapper.xml
+++ b/flowable/src/main/resources/mapper/LeaveapplyMapper.xml
@@ -2,7 +2,7 @@
 <!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ycl.system.mapper.LeaveapplyMapper">
+<mapper namespace="com.ycl.mapper.LeaveapplyMapper">
 
     <resultMap type="Leaveapply" id="LeaveapplyResult">
         <result property="id"    column="id"    />
diff --git a/system/src/main/resources/mapper/system/MeetingMapper.xml b/flowable/src/main/resources/mapper/MeetingMapper.xml
similarity index 97%
rename from system/src/main/resources/mapper/system/MeetingMapper.xml
rename to flowable/src/main/resources/mapper/MeetingMapper.xml
index 3380442..617cf9a 100644
--- a/system/src/main/resources/mapper/system/MeetingMapper.xml
+++ b/flowable/src/main/resources/mapper/MeetingMapper.xml
@@ -2,7 +2,7 @@
 <!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ycl.system.mapper.MeetingMapper">
+<mapper namespace="com.ycl.mapper.MeetingMapper">
 
     <resultMap type="Meeting" id="MeetingResult">
         <result property="id"    column="id"    />
diff --git a/system/src/main/resources/mapper/system/PurchaseMapper.xml b/flowable/src/main/resources/mapper/PurchaseMapper.xml
similarity index 97%
rename from system/src/main/resources/mapper/system/PurchaseMapper.xml
rename to flowable/src/main/resources/mapper/PurchaseMapper.xml
index bada1c2..73097d8 100644
--- a/system/src/main/resources/mapper/system/PurchaseMapper.xml
+++ b/flowable/src/main/resources/mapper/PurchaseMapper.xml
@@ -2,7 +2,7 @@
 <!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.ycl.system.mapper.PurchaseMapper">
+<mapper namespace="com.ycl.mapper.PurchaseMapper">
 
     <resultMap type="Purchase" id="PurchaseResult">
         <result property="id"    column="id"    />

--
Gitblit v1.8.0