fuliqi
2024-11-22 0526c88cd7082090fe658fd536562185527ba48a
Merge remote-tracking branch 'origin/master'
13个文件已添加
12 文件已重命名
2个文件已删除
2383 ■■■■■ 已修改文件
flowable/gradle/wrapper/gradle-wrapper.jar 补丁 | 查看 | 原始文档 | blame | 历史
flowable/gradle/wrapper/gradle-wrapper.properties 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/controller/DynamicFlowController.java 208 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/controller/FlowController.java 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/controller/FlowDesignerController.java 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/controller/FlowMonitorController.java 403 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/controller/LeaveapplyController.java 226 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/controller/MeetingController.java 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/controller/ModelManageController.java 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/controller/PurchaseController.java 217 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/controller/TaskController.java 208 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/mapper/ActRuExecutionMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/mapper/LeaveapplyMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/mapper/MeetingMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/mapper/PurchaseMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/service/ILeaveapplyService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/service/IMeetingService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/service/IPurchaseService.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/service/impl/LeaveapplyServiceImpl.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/service/impl/MeetingServiceImpl.java 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/service/impl/PurchaseServiceImpl.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/java/com/ycl/util/ActivitiTracingChart.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/resources/mapper/ActRuExecutionMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/resources/mapper/LeaveapplyMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/resources/mapper/MeetingMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/src/main/resources/mapper/PurchaseMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
system/src/main/java/com/ycl/system/domain/base/AbsEntityOnlyIdAndDeleted.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
flowable/gradle/wrapper/gradle-wrapper.jar
Binary files differ
flowable/gradle/wrapper/gradle-wrapper.properties
File was deleted
flowable/src/main/java/com/ycl/controller/DynamicFlowController.java
New file
@@ -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);
        // 寻找流程实例当前任务的activeId
        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);
        // 寻找流程实例当前任务的activeId
        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");
        // 普通UserTask节点
        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");
        }
    }
}
flowable/src/main/java/com/ycl/controller/FlowController.java
New file
@@ -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();
    }
}
flowable/src/main/java/com/ycl/controller/FlowDesignerController.java
New file
@@ -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();
    }
}
flowable/src/main/java/com/ycl/controller/FlowMonitorController.java
New file
@@ -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;
    }
}
flowable/src/main/java/com/ycl/controller/LeaveapplyController.java
New file
@@ -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));
    }
}
flowable/src/main/java/com/ycl/controller/MeetingController.java
New file
@@ -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("流程不存在");
    }
}
flowable/src/main/java/com/ycl/controller/ModelManageController.java
New file
@@ -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 {
            // 保存模型到act_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);
            // 保存模型文件到act_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());
    }
}
flowable/src/main/java/com/ycl/controller/PurchaseController.java
New file
@@ -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("流程不存在");
    }
}
flowable/src/main/java/com/ycl/controller/TaskController.java
New file
@@ -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;
    }
    /**
     * 用taskid查询formkey
     **/
    @ApiOperation("用taskid查询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;
    }
}
flowable/src/main/java/com/ycl/mapper/ActRuExecutionMapper.java
File was renamed from system/src/main/java/com/ycl/system/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;
flowable/src/main/java/com/ycl/mapper/LeaveapplyMapper.java
File was renamed from system/src/main/java/com/ycl/system/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;
flowable/src/main/java/com/ycl/mapper/MeetingMapper.java
File was renamed from system/src/main/java/com/ycl/system/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;
flowable/src/main/java/com/ycl/mapper/PurchaseMapper.java
File was renamed from system/src/main/java/com/ycl/system/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;
flowable/src/main/java/com/ycl/service/ILeaveapplyService.java
File was renamed from system/src/main/java/com/ycl/system/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;
flowable/src/main/java/com/ycl/service/IMeetingService.java
File was renamed from system/src/main/java/com/ycl/system/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;
flowable/src/main/java/com/ycl/service/IPurchaseService.java
File was renamed from system/src/main/java/com/ycl/system/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 结果
     */
flowable/src/main/java/com/ycl/service/impl/LeaveapplyServiceImpl.java
New file
@@ -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);
    }
}
flowable/src/main/java/com/ycl/service/impl/MeetingServiceImpl.java
New file
@@ -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);
    }
}
flowable/src/main/java/com/ycl/service/impl/PurchaseServiceImpl.java
New file
@@ -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);
    }
}
flowable/src/main/java/com/ycl/util/ActivitiTracingChart.java
File was renamed from start/src/main/java/com/ycl/web/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;
/**
 * 流程追踪图
flowable/src/main/resources/mapper/ActRuExecutionMapper.xml
File was renamed from system/src/main/resources/mapper/system/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_"    />
flowable/src/main/resources/mapper/LeaveapplyMapper.xml
File was renamed from system/src/main/resources/mapper/system/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"    />
flowable/src/main/resources/mapper/MeetingMapper.xml
File was renamed from system/src/main/resources/mapper/system/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"    />
flowable/src/main/resources/mapper/PurchaseMapper.xml
File was renamed from system/src/main/resources/mapper/system/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"    />
system/src/main/java/com/ycl/system/domain/base/AbsEntityOnlyIdAndDeleted.java
New file
@@ -0,0 +1,26 @@
package com.ycl.system.domain.base;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.util.Date;
/**
 * @author xp
 * @date 2022/11/29
 */
@Data
public abstract class AbsEntityOnlyIdAndDeleted {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Integer id;
    @TableField(value = "deleted", fill = FieldFill.INSERT)
    private Integer deleted;
}