xiangpei
2025-01-20 1045f256c2d9477b177dec61246bc0d174133f97
flowable/src/main/java/com/ycl/service/impl/FlowTaskServiceImpl.java
@@ -4,9 +4,12 @@
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ycl.common.constant.ProcessConstants;
import com.ycl.common.core.domain.AjaxResult;
import com.ycl.common.core.domain.entity.SysDept;
import com.ycl.common.core.domain.entity.SysDictData;
import com.ycl.common.core.domain.entity.SysRole;
import com.ycl.common.core.domain.entity.SysUser;
import com.ycl.common.enums.FlowComment;
@@ -16,18 +19,22 @@
import com.ycl.domain.dto.FlowNextDto;
import com.ycl.domain.dto.FlowTaskDto;
import com.ycl.domain.dto.FlowViewerDto;
import com.ycl.domain.entity.ProcessCoding;
import com.ycl.domain.entity.SysForm;
import com.ycl.domain.vo.FlowQueryVo;
import com.ycl.domain.vo.FlowTaskVo;
import com.ycl.domain.vo.FormDetailVO;
import com.ycl.factory.FlowServiceFactory;
import com.ycl.flow.CustomProcessDiagramGenerator;
import com.ycl.flow.FindNextNodeUtil;
import com.ycl.flow.FlowableUtils;
import com.ycl.mapper.ProcessCodingMapper;
import com.ycl.service.ProcessLogService;
import com.ycl.service.IFlowTaskService;
import com.ycl.service.ISysDeployFormService;
import com.ycl.service.ISysFormService;
import com.ycl.system.service.ISysRoleService;
import com.ycl.system.service.ISysUserService;
import com.ycl.service.common.TaskCommonService;
import com.ycl.system.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
@@ -57,7 +64,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
@@ -66,6 +72,9 @@
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static com.ycl.common.constant.ProcessOverTimeConstants.RED;
import static com.ycl.common.constant.ProcessOverTimeConstants.YELLOW;
/**
 * @author Tony
@@ -78,8 +87,13 @@
    private final ISysUserService sysUserService;
    private final ISysRoleService sysRoleService;
    private final ISysDeptService sysDeptService;
    private final ISysDictTypeService sysDictDService;
    private final ISysDeployFormService sysInstanceFormService;
    private final ISysFormService sysFormService;
    private final TaskCommonService taskCommonService;
    private final ProcessCodingMapper processCodingMapper;
    private final ProcessLogService processLogService;
    /**
     * 完成审核任务
@@ -108,19 +122,41 @@
    /**
     * 完成表单提交任务/普通任务
     *
     * @param taskId  任务id
     * @param variables  表单数据
     * @param taskId    任务id
     * @param variables 表单数据
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult completeSubmitForm(String taskId, Map<String, Object> variables) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (Objects.isNull(task)) {
            return AjaxResult.error("任务不存在");
        }
//        variables.put(taskId + "formJson", variables.get("formJson"));
        Map<String, Object> processVariables = new HashMap<>();
        //查出字典中需要注入的字段信息
        List<String> dictList = sysDictDService.selectDictDataByType("flow_variables").stream().map(SysDictData::getDictValue).collect(Collectors.toList());
        Map<String, Object> newV = new HashMap<>(2);
        if (!org.springframework.util.CollectionUtils.isEmpty(variables)) {
            for (String key : variables.keySet()) {
                newV.put(task.getTaskDefinitionKey() + "&" + key, variables.get(key));
                //字典里有就放入流程变量中
                if (!CollectionUtils.isEmpty(dictList) && dictList.contains(key)) {
                    processVariables.put(key,variables.get(key));
                }
            }
        }
        //添加流程变量
        if(!processVariables.isEmpty()) taskService.setVariables(taskId,processVariables);
        taskService.addComment(taskId, task.getProcessInstanceId(), FlowComment.SUBMIT.getType(), "完成提交");
        taskService.complete(taskId, variables);
        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            taskService.resolveTask(taskId, newV);
        } else {
            // 先让当前用户认领这个任务
            taskService.claim(taskId, SecurityUtils.getUserId() + "");
            taskService.complete(taskId, newV);
        }
        return AjaxResult.success("提交成功");
    }
@@ -291,7 +327,6 @@
        if (!isSequential) {
            throw new CustomException("当前节点相对于目标节点,不属于串行关系,无法回退");
        }
        // 获取所有正常进行的任务节点 Key,这些任务不能直接使用,需要找出其中需要撤回的任务
        List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
@@ -765,7 +800,7 @@
     * @return
     */
    @Override
    public AjaxResult flowRecord(String procInsId, String deployId) {
    public AjaxResult flowRecord(String procInsId) {
        Map<String, Object> map = new HashMap<String, Object>();
        if (StringUtils.isNotBlank(procInsId)) {
            List<HistoricActivityInstance> list = historyService
@@ -773,6 +808,10 @@
                    .processInstanceId(procInsId)
                    .orderByHistoricActivityInstanceStartTime()
                    .desc().list();
            //扩展 获取这个流程实例的监控信息 key:TaskId value:实体类
            Map<String, ProcessCoding> processCodingMap = processCodingMapper.selectList(new QueryWrapper<ProcessCoding>().eq("process_ins_id", procInsId))
                    .stream()
                    .collect(Collectors.toMap(ProcessCoding::getTaskId, Function.identity()));
            List<FlowTaskDto> hisFlowList = new ArrayList<>();
            for (HistoricActivityInstance histIns : list) {
                // 展示开始节点
@@ -815,8 +854,14 @@
                                stringBuilder.append(sysUser.getNickName()).append(",");
                            }
                            if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                                SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId()));
                                stringBuilder.append(sysRole.getRoleName()).append(",");
                                if (identityLink.getGroupId().contains("dept")) {
                                    SysDept sysDept = sysDeptService.selectDeptById(Long.parseLong(identityLink.getGroupId().split(":")[1]));
                                    stringBuilder.append(sysDept.getDeptName()).append(",");
                                } else {
                                    SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId()));
                                    stringBuilder.append(sysRole.getRoleName()).append(",");
                                }
                            }
                        }
                    }
@@ -825,6 +870,23 @@
                    }
                    flowTask.setDuration(histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null : getDate(histIns.getDurationInMillis()));
                    //扩展 判断是否超时
                    ProcessCoding processCoding = processCodingMap.get(histIns.getTaskId());
                    if (processCoding != null) {
                        //通过耗时判断是否是代办节点
                        //如果任务是代办节点
                        if (flowTask.getDuration() == null) {
                            if (RED.equals(processCoding.getStatus()) || YELLOW.equals(processCoding.getStatus())) {
                                flowTask.setOvertime(processCoding.getStatus());
                            }
                        } else {
                            //如果任务节点属于历史节点
                            if (RED.equals(processCoding.getStatus())) {
                                flowTask.setOvertime(processCoding.getStatus());
                            }
                            ;
                        }
                    }
                    // 获取意见评论内容
                    List<Comment> commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId());
                    commentList.forEach(comment -> {
@@ -837,14 +899,14 @@
            }
            map.put("flowList", hisFlowList);
        }
        // 第一次申请获取初始化表单
        if (StringUtils.isNotBlank(deployId)) {
            SysForm sysForm = sysInstanceFormService.selectSysDeployFormByDeployId(deployId);
            if (Objects.isNull(sysForm)) {
                return AjaxResult.error("请先配置流程表单");
            }
            map.put("formData", JSONObject.parseObject(sysForm.getFormContent()));
        }
//        // 第一次申请获取初始化表单
//        if (StringUtils.isNotBlank(deployId)) {
//            SysForm sysForm = sysInstanceFormService.selectSysDeployFormByDeployId(deployId);
//            if (Objects.isNull(sysForm)) {
//                return AjaxResult.error("请先配置流程表单");
//            }
//            map.put("formData", JSONObject.parseObject(sysForm.getFormContent()));
//        }
        return AjaxResult.success(map);
    }
@@ -1070,6 +1132,7 @@
    @Override
    public AjaxResult flowXmlAndNode(String procInsId, String deployId) {
        try {
            List<FlowViewerDto> flowViewerList = new ArrayList<>();
            // 获取已经完成的节点
            List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
@@ -1077,11 +1140,22 @@
                    .finished()
                    .list();
            //扩展 获取这个流程实例的监控信息 key:TaskId value:实体类
            Map<String, ProcessCoding> processCodingMap = processCodingMapper
                    .selectList(new QueryWrapper<ProcessCoding>().eq("process_ins_id", procInsId))
                    .stream()
                    .collect(Collectors.toMap(ProcessCoding::getTaskId, Function.identity()));
            // 保存已经完成的流程节点编号
            listFinished.forEach(s -> {
                FlowViewerDto flowViewerDto = new FlowViewerDto();
                flowViewerDto.setKey(s.getActivityId());
                flowViewerDto.setCompleted(true);
                //扩展内容 不反overtime前端默认是绿色
                ProcessCoding processCoding = processCodingMap.get(s.getTaskId());
                //如果有监控数据, 历史节点只判断红码
                if (processCoding != null && RED.equals(processCoding.getStatus())) {
                    flowViewerDto.setOvertime(processCoding.getStatus());
                }
                // 退回节点不进行展示
                if (StringUtils.isBlank(s.getDeleteReason())) {
                    flowViewerList.add(flowViewerDto);
@@ -1093,7 +1167,6 @@
                    .processInstanceId(procInsId)
                    .unfinished()
                    .list();
            // 保存需要代办的节点编号
            listUnFinished.forEach(s -> {
                // 删除已退回节点
@@ -1101,6 +1174,12 @@
                FlowViewerDto flowViewerDto = new FlowViewerDto();
                flowViewerDto.setKey(s.getActivityId());
                flowViewerDto.setCompleted(false);
                // 扩展内容 代办的通过当前时间作为endTime
                ProcessCoding processCoding = processCodingMap.get(s.getTaskId());
                //如果有监控数据 不反的话前端默认是进行中(蓝色)
                if (processCoding != null && (RED.equals(processCoding.getStatus()) || YELLOW.equals(processCoding.getStatus()))) {
                    flowViewerDto.setOvertime(processCoding.getStatus());
                }
                flowViewerList.add(flowViewerDto);
            });
            Map<String, Object> result = new HashMap();
@@ -1112,6 +1191,7 @@
            result.put("xmlData", xmlData);
            return AjaxResult.success(result);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("高亮历史任务失败");
        }
    }
@@ -1133,41 +1213,124 @@
        } else {
            parameters = taskService.getVariables(taskId);
        }
        List<FormDetailVO> beforeNodes = this.getBeforeNodeForm(parameters, task.getFormKey(), task.getName(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), Boolean.FALSE);
        return AjaxResult.success(beforeNodes);
    }
        JSONObject oldVariables = JSONObject.parseObject(JSON.toJSONString(parameters.get("formJson")));
        if (Objects.isNull(oldVariables)) {
            // 如果是空的,直接使用主表单
            String deploymentId = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult().getDeploymentId();
            return this.flowFormData(deploymentId);
    @Override
    public AjaxResult detail(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        // 流程变量
        Map<String, Object> parameters = new HashMap<>();
        if (Objects.isNull(task)) {
            // 如果为空,可能是任务已经结束
            HistoricTaskInstance hisTask = historyService.createHistoricTaskInstanceQuery().taskId(taskId).includeProcessVariables().singleResult();
            if (Objects.isNull(hisTask)) {
                throw new RuntimeException("该任务不存在");
            }
            parameters = hisTask.getProcessVariables();
            List<FormDetailVO> beforeNodes = this.getBeforeNodeForm(parameters, hisTask.getFormKey(), hisTask.getName(), hisTask.getProcessDefinitionId(), hisTask.getTaskDefinitionKey(), Boolean.TRUE);
            return AjaxResult.success(beforeNodes);
        } else {
            parameters = taskService.getVariables(taskId);
            List<FormDetailVO> beforeNodes = this.getBeforeNodeForm(parameters, task.getFormKey(), task.getName(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), Boolean.TRUE);
            return AjaxResult.success(beforeNodes);
        }
        List<JSONObject> oldFields = JSON.parseObject(JSON.toJSONString(oldVariables.get("widgetList")), new TypeReference<List<JSONObject>>() {
        });
        // 设置已填写的表单为禁用状态
        for (JSONObject oldField : oldFields) {
            JSONObject options = oldField.getJSONObject("options");
            options.put("disabled", true);
    }
    /**
     * 获取当前节点和上一节点的表单内容
     *
     * @param parameters    根据任务查找出来的参数
     * @param formKey       task自身关联的表单id
     * @param taskName      task自身的任务名
     * @param processDefId  流程定义id
     * @param processDefKey 流程实例id
     * @return
     */
    private List<FormDetailVO> getBeforeNodeForm(Map<String, Object> parameters, String formKey, String taskName, String processDefId, String processDefKey, Boolean currentNeedData) {
        if (!parameters.keySet().stream().anyMatch(key -> key.contains(ProcessConstants.TASK_FORM_KEY))) {
            FormDetailVO formDetailVO = new FormDetailVO();
            formDetailVO.setBeforeNodeName(taskName);
            formDetailVO.setCurrent(Boolean.TRUE);
            // 如果是空的,使用formId去查
            if (StringUtils.isNotBlank(formKey)) {
                SysForm sysForm = sysFormService.selectSysFormById(Long.parseLong(formKey));
                if (Objects.isNull(sysForm)) {
                    throw new RuntimeException("该流程绑定的表单不存在或已被删除");
                }
                Map<String, Object> data = new HashMap<>(1);
                data.put(ProcessConstants.TASK_FORM_KEY, JSONObject.parseObject(sysForm.getFormContent()));
                formDetailVO.setFormJsonObj(data);
                return Arrays.asList(formDetailVO);
            } else {
                return Arrays.asList(formDetailVO);
            }
        }
        // TODO 暂时只处理用户任务上的表单
        if (StringUtils.isNotBlank(task.getFormKey())) {
            SysForm sysForm = sysFormService.selectSysFormById(Long.parseLong(task.getFormKey()));
            JSONObject data = JSONObject.parseObject(sysForm.getFormContent());
            List<JSONObject> newFields = JSON.parseObject(JSON.toJSONString(data.get("widgetList")), new TypeReference<List<JSONObject>>() {
            });
            // 表单回显时 加入子表单信息到流程变量中
            for (JSONObject newField : newFields) {
                String key = newField.getString("id");
                // 处理图片上传组件回显问题
                if ("picture-upload".equals(newField.getString("type"))) {
                    parameters.put(key, new ArrayList<>());
                } else {
                    parameters.put(key, null);
        // 这里只需要查自身以及上一个节点(如果并行的有多个)的表单数据
        List<FormDetailVO> beforeNodes = taskCommonService.getBeforeNodeDefInfo(processDefId, processDefKey, sysFormService, Boolean.TRUE);
        List<String> beforeNodeDefIds = beforeNodes.stream().filter(item -> !item.getCurrent() || currentNeedData).map(FormDetailVO::getBeforeNodeDefId).collect(Collectors.toList());
        // 处理每个表单的数据
        for (FormDetailVO formDetailVO : beforeNodes) {
            if (formDetailVO.getCurrent() && !currentNeedData) {
                continue;  // 跳过当前节点,因为当前节点在获取前置节点时已经设置过了(但表单数据没有给)
            }
            Map<String, Object> newP = new HashMap<>();
            if (CollectionUtils.isNotEmpty(beforeNodeDefIds)) {
                for (String key : parameters.keySet()) {
                    // 过滤拿到目标表单数据,将目标表单数据放到新map中
                    if (key.startsWith(formDetailVO.getBeforeNodeDefId())) {
                        if (key.contains(ProcessConstants.TASK_FORM_KEY)) {
                            newP.put(key, parameters.get(key));
                        } else {
                            newP.put(key.split("&")[1], parameters.get(key));
                        }
                    }
                }
            }
            oldFields.addAll(newFields);
            Object form = newP.get(formDetailVO.getBeforeNodeDefId() + "&" + ProcessConstants.TASK_FORM_KEY);
            if (Objects.nonNull(form)) {
                JSONObject formJson = JSONObject.parseObject(JSON.toJSONString(form));
                List<JSONObject> oldFields = JSON.parseObject(JSON.toJSONString(formJson.get(ProcessConstants.WIDGET_LIST)), new TypeReference<List<JSONObject>>() {
                });
                if(CollectionUtils.isNotEmpty(oldFields)) {
                    // 设置已填写的表单为禁用状态
                    for (JSONObject oldField : oldFields) {
                        JSONObject options = oldField.getJSONObject("options");
                        options.put("disabled", true);
                    }
                    formJson.put(ProcessConstants.WIDGET_LIST, oldFields);
                    newP.put(ProcessConstants.TASK_FORM_KEY, formJson);
                    newP.remove(formDetailVO.getBeforeNodeDefId() + "&" + ProcessConstants.TASK_FORM_KEY);
                    formDetailVO.setFormJsonObj(newP);
                }
                // TODO 暂时只处理用户任务上的表单
//                if (StringUtils.isNotBlank(task.getFormKey())) {
//                    SysForm sysForm = sysFormService.selectSysFormById(Long.parseLong(task.getFormKey()));
//                    JSONObject data = JSONObject.parseObject(sysForm.getFormContent());
//                    List<JSONObject> newFields = JSON.parseObject(JSON.toJSONString(data.get(ProcessConstants.WIDGET_LIST)), new TypeReference<List<JSONObject>>() {
//                    });
//                    // 表单回显时 加入子表单信息到流程变量中
//                    for (JSONObject newField : newFields) {
//                        String key = newField.getString("id");
//                        // 处理图片上传组件回显问题
//                        if ("picture-upload".equals(newField.getString("type"))) {
//                            parameters.put(key, new ArrayList<>());
//                        } else {
//                            parameters.put(key, null);
//                        }
//                    }
//                    oldFields.addAll(newFields);
//                }
            }
        }
        oldVariables.put("widgetList", oldFields);
        parameters.put("formJson", oldVariables);
        return AjaxResult.success(parameters);
        return beforeNodes;
    }
    /**