package com.ycl.service.impl;
|
|
|
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
import com.ycl.common.base.Result;
|
import com.ycl.common.constant.ProcessOverTimeConstants;
|
import com.ycl.common.core.domain.BaseEntity;
|
import com.ycl.common.core.domain.entity.SysDept;
|
import com.ycl.common.core.domain.entity.SysRole;
|
import com.ycl.common.core.domain.entity.SysUser;
|
import com.ycl.common.enums.business.*;
|
import com.ycl.common.utils.SecurityUtils;
|
import com.ycl.domain.entity.ProcessCoding;
|
import com.ycl.domain.entity.ProcessLog;
|
import com.ycl.domain.entity.ProjectInfo;
|
import com.ycl.domain.entity.ProjectProcess;
|
import com.ycl.domain.form.ProjectProgressStatisticsForm;
|
import com.ycl.domain.query.WaitTodoQuery;
|
import com.ycl.domain.vo.*;
|
import com.ycl.factory.FlowServiceFactory;
|
import com.ycl.mapper.ProcessCodingMapper;
|
import com.ycl.mapper.ProcessLogMapper;
|
import com.ycl.mapper.ProjectInfoMapper;
|
import com.ycl.service.IndexHomeService;
|
import com.ycl.service.ProjectProcessService;
|
import com.ycl.service.common.TaskCommonService;
|
import com.ycl.system.mapper.SysDeptMapper;
|
import com.ycl.system.service.ISysDeptService;
|
import com.ycl.system.service.ISysRoleService;
|
import com.ycl.system.service.ISysUserService;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.lang3.StringUtils;
|
import org.flowable.bpmn.model.BpmnModel;
|
import org.flowable.bpmn.model.Process;
|
import org.flowable.bpmn.model.UserTask;
|
import org.flowable.engine.history.HistoricProcessInstance;
|
import org.flowable.engine.runtime.ProcessInstance;
|
import org.flowable.identitylink.api.IdentityLink;
|
import org.flowable.identitylink.api.IdentityLinkInfo;
|
import org.flowable.task.api.Task;
|
import org.flowable.task.api.TaskQuery;
|
import org.flowable.task.api.history.HistoricTaskInstance;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.CollectionUtils;
|
|
import java.text.DecimalFormat;
|
import java.time.LocalDate;
|
import java.time.ZoneId;
|
import java.time.temporal.TemporalAdjusters;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* nongtou-project-java
|
* 首页实现类
|
*
|
* @author : zxl
|
* @date : 2025-11-26 16:51
|
**/
|
@Service
|
@RequiredArgsConstructor
|
@Slf4j
|
public class IndexHomeServiceImpl extends FlowServiceFactory implements IndexHomeService {
|
|
private final SysDeptMapper sysDeptMapper;
|
private final ProjectInfoMapper projectInfoMapper;
|
|
private final ProjectProcessService projectProcessService;
|
|
private final ProcessLogMapper processLogMapper;
|
|
private final ProcessCodingMapper processCodingMapper;
|
|
private final ISysUserService sysUserService;
|
|
private final ISysDeptService sysDeptService;
|
|
private final ISysRoleService sysRoleService;
|
|
private final TaskCommonService taskCommonService;
|
|
|
@Override
|
public Result projectCodingStatusCount() {
|
//权限控制
|
List<ProjectInfo> loginUserOwnProjectInfo = getLoginUserOwnProjectInfo();
|
|
Map<String,Integer> map = new HashMap<>();
|
map.put(ProcessOverTimeConstants.GREEN,0);
|
map.put(ProcessOverTimeConstants.YELLOW,0);
|
map.put(ProcessOverTimeConstants.RED,0);
|
map.put("total",0);
|
if (CollectionUtils.isEmpty(loginUserOwnProjectInfo)) {
|
|
//返回默认值
|
return Result.ok().data(map);
|
}
|
|
Map<String, List<ProjectInfo>> collect = loginUserOwnProjectInfo.stream()
|
.filter(project -> project.getCoding() != null) // 过滤coding为null的情况
|
.collect(Collectors.groupingBy(ProjectInfo::getCoding));
|
|
if (collect.containsKey(ProcessOverTimeConstants.GREEN)) {
|
map.put(ProcessOverTimeConstants.GREEN, collect.get(ProcessOverTimeConstants.GREEN).size());
|
}
|
if (collect.containsKey(ProcessOverTimeConstants.YELLOW)) {
|
map.put(ProcessOverTimeConstants.YELLOW, collect.get(ProcessOverTimeConstants.YELLOW).size());
|
}
|
if (collect.containsKey(ProcessOverTimeConstants.RED)) {
|
map.put(ProcessOverTimeConstants.RED, collect.get(ProcessOverTimeConstants.RED).size());
|
}
|
|
map.put("total", loginUserOwnProjectInfo.size());
|
return Result.ok().data(map);
|
}
|
|
@Override
|
public Result projectStageCount() {
|
List<ProjectVO> projectVOS = projectInfoMapper.homeCount(new BaseEntity());
|
int reserve = 0;
|
int previous = 0;
|
int implement = 0;
|
int finish = 0;
|
for (ProjectVO projectVO : projectVOS) {
|
if (ProjectCategoryEnum.RESERVE.getDesc().equals(ProjectCategoryEnum.getPhaseByProjectStatus(projectVO.getProjectPhase()))) {
|
reserve+=1;
|
} else if (ProjectCategoryEnum.PREVIOUS.getDesc().equals(ProjectCategoryEnum.getPhaseByProjectStatus(projectVO.getProjectPhase()))) {
|
previous+=1;
|
} else if (ProjectCategoryEnum.IMPLEMENT.getDesc().equals(ProjectCategoryEnum.getPhaseByProjectStatus(projectVO.getProjectPhase()))) {
|
implement+=1;
|
} else if (ProjectCategoryEnum.FINISH.getDesc().equals(ProjectCategoryEnum.getPhaseByProjectStatus(projectVO.getProjectPhase()))) {
|
finish+=1;
|
}
|
}
|
|
|
Map<String,Object> map = new HashMap<>();
|
Integer[] yData = new Integer[]{
|
projectVOS.size(),
|
reserve,
|
previous,
|
implement,
|
finish
|
};
|
String[] xData = new String[]{
|
"在库", "储备","前期","实施","竣工"
|
};
|
map.put("xData",xData);
|
map.put("yData",yData);
|
return Result.ok().data(map);
|
}
|
|
@Override
|
public List<ProjectInfo> getLoginUserOwnProjectInfo(){
|
//权限控制
|
Long userId = SecurityUtils.getUserId();
|
List<ProjectInfo> list;
|
if (SecurityUtils.isAdmin(userId)){
|
//查询全部
|
list = new LambdaQueryChainWrapper<>(projectInfoMapper)
|
.eq(ProjectInfo::getDeleted, Boolean.FALSE)
|
.eq(ProjectInfo::getUsedStatus, 2)//审核通过
|
.orderBy(true, true, ProjectInfo::getId)
|
.list();
|
}else{
|
String ancestors = sysDeptMapper.selectAncestors(userId);
|
String[] ancestorArr = ancestors.split(",");
|
List<String> ancestorList = Arrays.stream(ancestorArr).collect(Collectors.toList());
|
ancestorList.add(SecurityUtils.getDeptId() + "");
|
//获得本单位以及其子单位deptId;
|
list = new LambdaQueryChainWrapper<>(projectInfoMapper)
|
.eq(ProjectInfo::getDeleted, Boolean.FALSE)
|
.eq(ProjectInfo::getUsedStatus, 2) //审核通过
|
.in(ProjectInfo::getProjectOwnerUnit, ancestorList)
|
.orderBy(true, true, ProjectInfo::getId)
|
.list();
|
}
|
return list;
|
}
|
|
@Override
|
public Result projectTaskStatus(ProjectProgressStatisticsForm form) {
|
//获得是项目
|
List<ProjectInfo> loginUserOwnProjectInfo = getLoginUserOwnProjectInfo();
|
|
|
if (CollectionUtils.isEmpty(loginUserOwnProjectInfo)) {
|
return Result.ok().data(loginUserOwnProjectInfo);
|
}
|
Map<String, String> projectMap = loginUserOwnProjectInfo.stream()
|
.collect(Collectors.toMap(
|
projectInfo -> String.valueOf(projectInfo.getId()), // key: 项目ID
|
ProjectInfo::getProjectName, // value: 项目对象本身
|
(existing, replacement) -> existing // 处理重复ID的冲突策略(保留原有值)
|
));
|
|
|
|
//获得项目ids
|
List<Long> ids = loginUserOwnProjectInfo.stream().map(ProjectInfo::getId).collect(Collectors.toList());
|
|
|
//更具项目ids获得所有对应流程信息 ProjectProcess 流程定义ID processDefId;流程实例id processInsId;
|
List<ProjectProcess> projectProcessList = new LambdaQueryChainWrapper<>(projectProcessService.getBaseMapper())
|
.eq(ProjectProcess::getDeleted, Boolean.FALSE)
|
.in(ProjectProcess::getProjectId, ids).list();
|
|
Date statisticsTime = form.getStartTime();
|
if (statisticsTime == null) {
|
statisticsTime = new Date(); // 如果未传入时间,默认使用当前时间
|
}
|
LocalDate statisticsLocalDate = statisticsTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
LocalDate firstDayOfMonth = statisticsLocalDate.with(TemporalAdjusters.firstDayOfMonth());
|
LocalDate lastDayOfMonth = statisticsLocalDate.with(TemporalAdjusters.lastDayOfMonth());
|
|
Date monthStart = Date.from(firstDayOfMonth.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
Date monthEnd = Date.from(lastDayOfMonth.atTime(23, 59, 59).atZone(ZoneId.systemDefault()).toInstant());
|
|
// 存储每个流程实例的统计结果
|
List<Map<String, Object>> processStatisticsList = new ArrayList<>();
|
|
// 获得流程日志表中 任务信息 按流程实列id分组
|
Map<String, List<ProcessLog>> groupMap = new LambdaQueryChainWrapper<>(processLogMapper)
|
.eq(ProcessLog::getDeleted, Boolean.FALSE)
|
.in(ProcessLog::getProjectId, ids).list()
|
.stream().collect(Collectors.groupingBy(ProcessLog::getProcessInsId));
|
|
|
for (ProjectProcess projectProcess : projectProcessList) {
|
|
String processInstanceId = projectProcess.getProcessInsId();
|
if (processInstanceId == null) {
|
continue;
|
}
|
|
// 单个流程的统计结果
|
Map<String, Object> processResult = new HashMap<>();
|
processResult.put("id",projectProcess.getProjectId());
|
processResult.put("projectName", projectMap.get(projectProcess.getProjectId()));
|
|
int completedCount = 0; // 已完成任务数
|
int inProgressCount = 0; // 进行中任务数
|
int notStartedCount = 0; // 未开始任务数
|
|
try {
|
// 1. 获取该流程实例的所有已完成任务
|
List<HistoricTaskInstance> completedTasks = historyService.createHistoricTaskInstanceQuery()
|
.processInstanceId(processInstanceId)
|
.finished()
|
.list();
|
// 去重历史信息 排除相同的任务key保留最新的任务
|
completedTasks = projectProcessService.distinctHisTask(completedTasks);
|
// 需要排除已完成任务中被驳回的任务数
|
List<ProcessLog> taskLogs = groupMap.get(projectProcess.getProcessInsId());
|
if ("144".equals(projectProcess.getProjectId())) {
|
for (ProcessLog processLog : taskLogs) {
|
System.out.println("打印信息");
|
System.out.println(processLog.toString());
|
}
|
}
|
if (!CollectionUtils.isEmpty(taskLogs)) {
|
//排除掉所有被驳回的任务
|
// 获取所有被驳回任务的ID列表
|
List<String> rejectedTaskIds = taskLogs.stream()
|
.filter(log -> {
|
// 判断是否为驳回类型的日志(根据你的枚举值调整)
|
return ProcessLogEventTypeEnum.REJECT.equals(log.getEventType());
|
})
|
.map(ProcessLog::getTaskId) // 假设日志中有taskId字段关联任务
|
.filter(Objects::nonNull) // 过滤掉null的taskId
|
.collect(Collectors.toList());
|
|
// 排除被驳回的任务,生成新的已完成任务集合
|
|
// 将过滤后的集合赋值给原变量
|
completedTasks = completedTasks.stream()
|
.filter(task -> !rejectedTaskIds.contains(task.getId())) //保留不包含驳回的taskId
|
.collect(Collectors.toList());
|
}
|
|
|
// 本月最后一天完成的 属于已完成 after 之后 before 之前
|
for (HistoricTaskInstance task : completedTasks) {
|
Date completionTime = task.getEndTime();
|
if (completionTime != null &&
|
completionTime.before(monthEnd)) {
|
completedCount++;
|
}
|
}
|
// 获得上一步未覆盖到查询条件的元素 完成时间是在本月之后
|
List<HistoricTaskInstance> excessCompletedTasks = completedTasks.stream().filter(
|
task -> { Date endTime = task.getEndTime();
|
return endTime != null && endTime.after(monthEnd);
|
}).collect(Collectors.toList());
|
|
// 循环完成时间是在本月之后的
|
for (HistoricTaskInstance task : excessCompletedTasks) {
|
Date createTime = task.getCreateTime();
|
Date endTime = task.getEndTime();
|
|
// 本月创建,完成在本月之后 属于进行中
|
if (createTime != null && endTime != null) {
|
if (createTime.before(monthEnd) && createTime.after(monthStart) && endTime.after(monthEnd)) {
|
inProgressCount++;
|
}
|
}
|
|
|
}
|
// 2. 获取该流程实例的所有进行中任务
|
List<Task> activeTasks = taskService.createTaskQuery()
|
.processInstanceId(processInstanceId)
|
.active()
|
.list();
|
for (Task task : activeTasks) {
|
Date createTime = task.getCreateTime();
|
// 进行中的任务 判断创建时间是否在下个月之前 如果是本月则加1
|
if (createTime != null && createTime.before(monthEnd)) {
|
inProgressCount++;
|
}
|
|
}
|
|
|
|
|
// 5. 统计未开始任务(获取流程定义的总任务数 - 已统计的任务数)
|
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
.processInstanceId(processInstanceId)
|
.singleResult();
|
|
if (processInstance != null) {
|
BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
|
Process mainProcess = bpmnModel.getMainProcess();
|
List<UserTask> userTasks = mainProcess.findFlowElementsOfType(UserTask.class);
|
int totalUserTaskCount = userTasks.size();
|
|
// 未开始任务数 = 总任务数 - 已完成 - 进行中
|
notStartedCount = totalUserTaskCount - completedCount - inProgressCount;
|
|
// 确保未开始任务数不为负数
|
if (notStartedCount < 0) {
|
notStartedCount = 0;
|
}
|
}
|
} catch (Exception e) {
|
// 异常处理
|
notStartedCount = 0;
|
}
|
|
// 设置当前流程的统计结果
|
int totalTasks = completedCount + inProgressCount + notStartedCount;
|
|
double completedPercent = totalTasks == 0 ? 0 : (completedCount * 100.0 / totalTasks);
|
double inProgressPercent = totalTasks == 0 ? 0 : (inProgressCount * 100.0 / totalTasks);
|
double notStartedPercent = totalTasks == 0 ? 0 : (notStartedCount * 100.0 / totalTasks);
|
//四舍五入
|
completedPercent = Math.round(completedPercent * 10) / 10.0;
|
inProgressPercent = Math.round(inProgressPercent * 10) / 10.0;
|
notStartedPercent = Math.round(notStartedPercent * 10) / 10.0;
|
//保留一位
|
DecimalFormat df = new DecimalFormat("#.#");
|
|
// 格式化结果(可选:保留为字符串或转换为Double)
|
String completedFormatted = df.format(completedPercent);
|
String inProgressFormatted = df.format(inProgressPercent);
|
String notStartedFormatted = df.format(notStartedPercent);
|
|
processResult.put("completed", completedFormatted);
|
processResult.put("co", completedCount);
|
processResult.put("co2", inProgressCount);
|
processResult.put("co3", notStartedCount);
|
processResult.put("inProgress", inProgressFormatted);
|
processResult.put("notStarted", notStartedFormatted);
|
processResult.put("totalTasks",totalTasks) ;
|
|
// 添加到结果列表
|
processStatisticsList.add(processResult);
|
}
|
|
return Result.ok().data(processStatisticsList);
|
}
|
|
@Override
|
public Result projectFundingStatus( ) {
|
List<ProjectInvestmentFundingVO> projectInfoAndFunding = projectInfoMapper.getProjectInfoAndFunding(new BaseEntity());
|
//排除空数据
|
projectInfoAndFunding = projectInfoAndFunding.stream().filter(Objects::nonNull).collect(Collectors.toList());
|
|
return Result.ok().data(projectInfoAndFunding);
|
}
|
@Override
|
public int countWaitTask() {
|
Long userId = SecurityUtils.getUserId();
|
List<ProjectInfo> loginUserOwnProjectInfo = getLoginUserOwnProjectInfo();
|
if (CollectionUtils.isEmpty(loginUserOwnProjectInfo)) {
|
return 0;
|
}
|
List<Long> ids = loginUserOwnProjectInfo.stream()
|
.filter(Objects::nonNull)
|
.map(ProjectInfo::getId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toList());
|
if (CollectionUtils.isEmpty(ids)) {
|
return 0;
|
}
|
List<ProjectProcess> projectProcessList = new LambdaQueryChainWrapper<>(projectProcessService.getBaseMapper())
|
.eq(ProjectProcess::getDeleted, Boolean.FALSE)
|
.in(ProjectProcess::getProjectId, ids)
|
.list();
|
if (CollectionUtils.isEmpty(projectProcessList)) {
|
return 0;
|
}
|
List<String> targetProcessInsIds = projectProcessList.stream()
|
.filter(Objects::nonNull) // 过滤null的ProjectProcess对象
|
.map(ProjectProcess::getProcessInsId)
|
.filter(defId -> defId != null && !defId.trim().isEmpty()) // 先判null再trim,修复风险3
|
.distinct()
|
.collect(Collectors.toList());
|
if (CollectionUtils.isEmpty(targetProcessInsIds)) {
|
return 0;
|
}
|
|
List<Task> allRunningTasks = taskService.createTaskQuery().active().list();
|
if (CollectionUtils.isEmpty(allRunningTasks)) {
|
return 0;
|
}
|
List<Task> targetRunningTasks = allRunningTasks.stream()
|
.filter(Objects::nonNull)
|
.filter(task -> {
|
// 先判null,再匹配,修复风险1
|
String processInsId = task.getProcessInstanceId();
|
return processInsId != null && targetProcessInsIds.contains(processInsId);
|
})
|
.filter(task -> {
|
String assignee = task.getAssignee();
|
return assignee == null || userId.toString().equals(assignee);//排除领取人
|
})
|
.collect(Collectors.toList());
|
|
|
return targetRunningTasks.size();
|
}
|
|
@Override
|
public Result projectAdvanceCheckPoint() {
|
List<ProjectInfo> loginUserOwnProjectInfo = getLoginUserOwnProjectInfo();
|
if (CollectionUtils.isEmpty(loginUserOwnProjectInfo)) {
|
return Result.ok().data(loginUserOwnProjectInfo);
|
}
|
//获得项目ids
|
List<Long> ids = loginUserOwnProjectInfo.stream().map(ProjectInfo::getId).collect(Collectors.toList());
|
List<ProjectProcess> projectProcessList = new LambdaQueryChainWrapper<>(projectProcessService.getBaseMapper())
|
.eq(ProjectProcess::getDeleted, Boolean.FALSE)
|
.in(ProjectProcess::getProjectId, ids).list();
|
Long userId = SecurityUtils.getUserId();
|
//流程实例id集合
|
List<String> targetProcessInsIds = projectProcessList.stream()
|
.map(ProjectProcess::getProcessInsId)
|
.distinct()
|
.filter(defId -> defId != null && !defId.trim().isEmpty())
|
.collect(Collectors.toList());
|
//组装项目流程信息 项目id为key
|
Map<String,CheckPointVO> map = new HashMap<>();
|
for (ProjectInfo projectInfo : loginUserOwnProjectInfo){
|
CheckPointVO checkPointVO = new CheckPointVO();
|
checkPointVO.setId(projectInfo.getId());
|
checkPointVO.setProjectName(projectInfo.getProjectName());
|
map.put(String.valueOf(projectInfo.getId()),checkPointVO);
|
}
|
//组装流程信息
|
for (ProjectProcess projectProcess : projectProcessList) {
|
|
CheckPointVO checkPointVO = map.get(projectProcess.getProjectId());
|
checkPointVO.setProcessDefinitionId(projectProcess.getProcessDefId());
|
checkPointVO.setProcessInstanceId(projectProcess.getProcessInsId());
|
|
//获得流程部署id
|
ProcessInstance process = runtimeService.createProcessInstanceQuery()
|
.processInstanceId(projectProcess.getProcessInsId()).singleResult();
|
if (Objects.nonNull(process)) {
|
checkPointVO.setDeployId(process.getDeploymentId()); // 运行中流程直接取部署ID
|
checkPointVO.setProcessName(process.getProcessDefinitionName());
|
} else {
|
// 2. 运行中流程不存在(已结束),查历史流程实例
|
HistoricProcessInstance hisProcess = historyService.createHistoricProcessInstanceQuery()
|
.processInstanceId(projectProcess.getProcessInsId()).singleResult();
|
// 历史流程取部署ID
|
checkPointVO.setDeployId(hisProcess.getDeploymentId());
|
checkPointVO.setProcessName(hisProcess.getProcessDefinitionName());
|
}
|
map.put(projectProcess.getProjectId(),checkPointVO);
|
}
|
// 转换为list后按 流程实例id分组
|
List<CheckPointVO> checkPointList = map.values().stream()
|
.collect(Collectors.toList());
|
// 获得组装好的 流程map 键为流程实例id,
|
Map<String, CheckPointVO> processInfoMap = checkPointList.stream()
|
.filter(Objects::nonNull) // 避免null元素导致异常(可选,按需保留)
|
.filter(vo -> vo.getProcessInstanceId() != null) // 过滤流程定义ID为null的无效数据
|
.collect(Collectors.toMap(
|
CheckPointVO::getProcessInstanceId, // key:流程定义ID(替换为你的实际方法名)
|
vo -> vo, // value:原始CheckPointVO对象
|
(oldVal, newVal) -> newVal // 冲突策略:存在重复ID时保留后者(按需调整)
|
));
|
|
|
List<Task> allRunningTasks = taskService.createTaskQuery().active().list();
|
|
List<Task> targetRunningTasks = allRunningTasks.stream()
|
// 关键匹配:任务的流程定义ID 存在于 projectProcessList 的流程定义ID列表中
|
.filter(task -> targetProcessInsIds.contains(task.getProcessInstanceId()))
|
.filter(task -> {
|
String assignee = task.getAssignee();
|
log.info("assignee:{}",assignee);
|
return assignee == null || userId.toString().equals(assignee);
|
})
|
.collect(Collectors.toList());
|
|
List<TaskInfoVo> list = new ArrayList<>();
|
// 按流程实例id分组
|
if (!CollectionUtils.isEmpty(targetRunningTasks)){
|
|
//查询到所有
|
List<String> taskIds = targetRunningTasks.stream().map(Task::getId).collect(Collectors.toList());
|
// 任务运行时不在 list中,可能任务没有设置超时时间
|
List<ProcessCoding> processCodingList = new LambdaQueryChainWrapper<>(processCodingMapper)
|
.eq(ProcessCoding::getDeleted, Boolean.FALSE)
|
.in(ProcessCoding::getTaskId, taskIds)
|
.list();
|
log.info("processCodingList.size():{}", processCodingList.size()); // 看日志是否为0
|
Map<String, ProcessCoding> processCodingMap = new HashMap<>();
|
//按taskId转换为map方面下面获取
|
if (!CollectionUtils.isEmpty(processCodingList)){
|
processCodingMap = processCodingList.stream()
|
.filter(Objects::nonNull) // 避免null元素导致NPE(可选保留)
|
.filter(vo -> vo.getTaskId() != null) // 过滤taskId为null的无效数据
|
.collect(Collectors.toMap(
|
ProcessCoding::getTaskId, // key:仍为taskId
|
vo -> vo, // value:原始ProcessCoding对象
|
// 冲突策略:比较创建时间,保留更新的那个
|
(oldVal, newVal) -> {
|
// 获取两者创建时间(根据实际方法名调整,如getGmtCreate()
|
Date oldCreateTime = oldVal.getGmtCreate();
|
Date newCreateTime = newVal.getGmtCreate();
|
|
// 处理创建时间为null的情况(优先级:有时间>无时间,都无则保留后者)
|
if (oldCreateTime == null) return newVal;
|
if (newCreateTime == null) return oldVal;
|
|
// 比较时间戳,返回更大的(更新的)对象
|
return newCreateTime.getTime() > oldCreateTime.getTime() ? newVal : oldVal;
|
}
|
));
|
}
|
for (Task task : targetRunningTasks) {
|
|
TaskInfoVo taskVo = new TaskInfoVo();
|
|
taskVo.setId(task.getId());
|
taskVo.setTaskName(task.getName());
|
taskVo.setStartTime(task.getCreateTime());
|
taskVo.setEndTime(task.getDueDate());
|
// taskVo.setTaskType();
|
|
List<Long> handlerIds = new ArrayList<>(2);
|
List<String> handlerNames = new ArrayList<>(2);
|
List<Long> handlerUnitIds = new ArrayList<>(2);
|
List<String> handlerUnitNames = new ArrayList<>(2);
|
List<String> promoterNames = new ArrayList<>(2);
|
List<String> promoterUnitNames = new ArrayList<>(2);
|
CustomerTaskVO customerTaskVO = new CustomerTaskVO();
|
customerTaskVO.setHandlerId(handlerIds);
|
customerTaskVO.setHandlerName(handlerNames);
|
customerTaskVO.setHandlerUnitId(handlerUnitIds);
|
customerTaskVO.setHandlerUnitName(handlerUnitNames);
|
customerTaskVO.setPromoterName(promoterNames);
|
customerTaskVO.setPromoterUnitName(promoterUnitNames);
|
|
// 流程处理人信息
|
List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(task.getId());
|
for (IdentityLinkInfo identityLink : identityLinksForTask) {
|
// 绑定的是用户,查出用户姓名、部门
|
if (StringUtils.isNotBlank(identityLink.getUserId())) {
|
// 处理变量表达式,运行中的任务无需再处理表达式了,flowable已经自动根据变量设置了
|
customerTaskVO.setHandlerType(HandlerTypeEnum.USER);
|
SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId()));
|
if (Objects.nonNull(sysUser)) {
|
customerTaskVO.getHandlerId().add(sysUser.getUserId());
|
customerTaskVO.getHandlerName().add(this.getUserShowName(sysUser));
|
if (Objects.nonNull(sysUser.getDept())) {
|
customerTaskVO.getHandlerUnitId().add(sysUser.getDept().getDeptId());
|
customerTaskVO.getHandlerUnitName().add(sysUser.getDept().getDeptName());
|
customerTaskVO.getPromoterName().add(this.getUserShowName(sysUser));
|
String[] str = sysUser.getDept().getAncestors().split(",");
|
if (str.length >= 4){
|
customerTaskVO.getPromoterUnitName().add(sysUser.getDept().getParentName() +"-"+sysUser.getDept().getDeptName());
|
}else {
|
customerTaskVO.getPromoterUnitName().add(sysUser.getDept().getDeptName());
|
}
|
|
}
|
}
|
// 绑定的是角色或者部门
|
} else if (StringUtils.isNotBlank(identityLink.getGroupId())) {
|
if (identityLink.getGroupId().startsWith("dept")) { // 部门的id是加了前缀的如:dept:1
|
customerTaskVO.setHandlerType(HandlerTypeEnum.DEPT);
|
String[] split = identityLink.getGroupId().split(":");
|
if (split.length > 1) {
|
// 部门
|
SysDept dept = sysDeptService.selectDeptById(Long.parseLong(split[1]));
|
if (Objects.nonNull(dept)) {
|
customerTaskVO.getHandlerUnitId().add(dept.getDeptId());
|
customerTaskVO.getHandlerUnitName().add(dept.getDeptName());
|
customerTaskVO.getPromoterName().add(this.getDeptLeaderShowName(dept));
|
customerTaskVO.getPromoterUnitName().add(this.setDeptNameWithParentName(dept));
|
}
|
}
|
} else {
|
customerTaskVO.setHandlerType(HandlerTypeEnum.ROLE);
|
SysRole role = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId()));
|
if (Objects.nonNull(role)) {
|
customerTaskVO.getHandlerUnitId().add(Long.parseLong(identityLink.getGroupId()));
|
customerTaskVO.getHandlerUnitName().add(role.getRoleName());
|
}
|
}
|
}
|
this.distinctVo(customerTaskVO);
|
}
|
taskVo.setCustomerTaskInfo(customerTaskVO);
|
|
//组装任务信息
|
CheckPointVO checkPointVO = processInfoMap.get(task.getProcessInstanceId());
|
if (checkPointVO != null) {
|
taskVo.setCheckPointInfo(checkPointVO);
|
}
|
//超时时间和次数在 processCodingList中 这里需要更具taskId来获得对应信息
|
ProcessCoding processCoding = processCodingMap.get(task.getId());
|
//设置超时信息
|
if (processCoding != null) {
|
|
String overTimeTotalStr = processCoding.getOverTimeTotal();
|
long overTimeTotal = 0L;
|
if (StringUtils.isNotBlank(overTimeTotalStr)) {
|
try {
|
overTimeTotal = Long.parseLong(overTimeTotalStr.trim());
|
} catch (NumberFormatException e) {
|
|
}
|
}
|
String overTimeDesc = convertHoursToDayHourStr(overTimeTotal);
|
taskVo.setTotalOverTime(overTimeDesc);
|
|
// 2. 提取红码阈值 如: 0-22 天-小时 并转换为小时
|
String redTimeStr = processCoding.getRedTime();
|
Long redTimeSec = getTime(redTimeStr);
|
Double redTimeHour = null;
|
if (redTimeSec != null && redTimeSec > 0) {
|
redTimeHour = redTimeSec / 3600.0;
|
}
|
long overTimeCount = 0L;
|
// 判断超时次数
|
if (overTimeTotal > 0 && redTimeHour != null && redTimeHour > 0) {
|
overTimeCount = (long) (overTimeTotal / redTimeHour);
|
}
|
|
|
taskVo.setOverTimeCount(overTimeCount);
|
}else {
|
//为null 说明未配置超时时间 默认未超时
|
taskVo.setOverTimeCount(0L);
|
taskVo.setTotalOverTime("0小时");
|
}
|
list.add(taskVo);
|
}
|
|
|
}
|
|
return Result.ok().data(list);
|
}
|
|
public HashMap<String,Object> buildEmptyResultMap(){
|
HashMap<String,Object> map = new HashMap<>();
|
map.put("data", new ArrayList<>());
|
map.put("total", 0L);
|
return map;
|
}
|
@Override
|
public Result getWaitTaskList(WaitTodoQuery baseQuery) {
|
int pageNum = (int) baseQuery.getCurrentPage();
|
int pageSize = (int) baseQuery.getPageSize();
|
Long userId = SecurityUtils.getUserId(); // 当前用户ID
|
boolean isAdmin = SecurityUtils.getLoginUser().getUser().isAdmin(); // 是否管理员
|
List<String> userGroups = taskCommonService.getCurrentUserGroups(); // 当前用户所属组
|
List<ProjectInfo> targetProjectList = new ArrayList<>();
|
String queryProjectId = baseQuery.getProjectId();
|
|
if ("all".equals(queryProjectId) || StringUtils.isBlank(queryProjectId)){
|
// 查询全部
|
targetProjectList = getLoginUserOwnProjectInfo();
|
}else{
|
try {
|
Long projectId = Long.parseLong(queryProjectId);
|
// ① 查询该项目基础信息(替换为实际查询方法)
|
ProjectInfo projectInfo = projectInfoMapper.selectById(projectId);
|
if (projectInfo == null) {
|
// 项目不存在,返回空数据
|
return Result.ok().data(buildEmptyResultMap());
|
}
|
targetProjectList.add(projectInfo);
|
} catch (NumberFormatException e) {
|
// 项目ID格式错误,返回空数据
|
return Result.ok().data(buildEmptyResultMap());
|
}
|
}
|
|
List<Long> projectIds = targetProjectList.stream().map(ProjectInfo::getId).collect(Collectors.toList());
|
|
List<ProjectProcess> projectProcessList = new LambdaQueryChainWrapper<>(projectProcessService.getBaseMapper())
|
.eq(ProjectProcess::getDeleted, Boolean.FALSE)
|
.in(ProjectProcess::getProjectId, projectIds).list();
|
// 4. 提取有效的流程实例ID(去重+非空过滤)
|
List<String> targetProcessInsIds = projectProcessList.stream()
|
.map(ProjectProcess::getProcessInsId)
|
.distinct()
|
.filter(defId -> defId != null && !defId.trim().isEmpty())
|
.collect(Collectors.toList());
|
|
if (CollectionUtils.isEmpty(targetProcessInsIds)) {
|
return Result.ok().data(new HashMap<String, Object>() {{
|
put("data", new ArrayList<>());
|
put("total", 0L);
|
}});
|
}
|
|
// 5. 构建processInfoMap(核心:项目ID→CheckPointVO,再关联流程信息)
|
Map<String, CheckPointVO> map = new HashMap<>();
|
// 先填充项目基础信息
|
for (ProjectInfo projectInfo : targetProjectList) {
|
CheckPointVO checkPointVO = new CheckPointVO();
|
checkPointVO.setId(projectInfo.getId());
|
checkPointVO.setProjectName(projectInfo.getProjectName());
|
map.put(String.valueOf(projectInfo.getId()), checkPointVO);
|
}
|
// 再填充流程信息(部署ID、流程名称等)
|
for (ProjectProcess projectProcess : projectProcessList) {
|
CheckPointVO checkPointVO = map.get(projectProcess.getProjectId().toString()); // 修复:projectId是Long,需转字符串
|
if (checkPointVO == null) {
|
continue; // 无匹配项目,跳过
|
}
|
checkPointVO.setProcessDefinitionId(projectProcess.getProcessDefId());
|
checkPointVO.setProcessInstanceId(projectProcess.getProcessInsId());
|
|
// 获得流程部署id和流程名称(兼容运行中/已结束流程)
|
ProcessInstance process = runtimeService.createProcessInstanceQuery()
|
.processInstanceId(projectProcess.getProcessInsId()).singleResult();
|
if (Objects.nonNull(process)) {
|
checkPointVO.setDeployId(process.getDeploymentId());
|
checkPointVO.setProcessName(process.getProcessDefinitionName());
|
} else {
|
HistoricProcessInstance hisProcess = historyService.createHistoricProcessInstanceQuery()
|
.processInstanceId(projectProcess.getProcessInsId()).singleResult();
|
if (Objects.nonNull(hisProcess)) { // 避免历史流程为null的NPE
|
checkPointVO.setDeployId(hisProcess.getDeploymentId());
|
checkPointVO.setProcessName(hisProcess.getProcessDefinitionName());
|
}
|
}
|
map.put(projectProcess.getProjectId().toString(), checkPointVO); // 修复:projectId转字符串
|
}
|
Map<String, CheckPointVO> processInfoMap = map.values().stream()
|
.filter(Objects::nonNull)
|
.filter(vo -> vo.getProcessInstanceId() != null)
|
.collect(Collectors.toMap(
|
CheckPointVO::getProcessInstanceId,
|
vo -> vo,
|
(oldVal, newVal) -> newVal // 重复流程实例ID保留后者
|
));
|
|
TaskQuery query = getTaskService().createTaskQuery()
|
.active() // 未完成、未挂起的活跃任务
|
.processInstanceIdIn(targetProcessInsIds); // 仅查项目关联的流程实例任务
|
|
// 权限过滤:非管理员仅查自己有权限的任务(已领取+候选)
|
if (!isAdmin) {
|
query.or()
|
.taskAssignee(userId+"") // 自己已领取的任务
|
.taskCandidateUser(userId+"") // 自己是候选用户的任务
|
.taskCandidateGroupIn(userGroups) // 自己在候选组的任务
|
.endOr();
|
}
|
|
query.orderByTaskCreateTime().desc();
|
List<Task> allTaskList = query.list();
|
// 排除领取人问题
|
allTaskList = allTaskList.stream()
|
.filter(Objects::nonNull) // 空任务防护
|
.filter(task -> {
|
String assignee = task.getAssignee();
|
return assignee == null || userId.toString().equals(assignee);
|
})
|
.collect(Collectors.toList());
|
// 任务去重
|
Set<String> taskIdSet = new HashSet<>();
|
List<Task> distinctAllTaskList = new ArrayList<>();
|
for (Task task : allTaskList) {
|
if (!taskIdSet.contains(task.getId())) {
|
taskIdSet.add(task.getId());
|
distinctAllTaskList.add(task);
|
}
|
}
|
|
// ========== 修复点1:提前查询任务状态,过滤已完成任务(分页前执行) ==========
|
// 查询任务状态
|
final HashMap<String, ProcessLog> taskInfoMap = new HashMap<>();
|
|
List<String> allTaskIds = distinctAllTaskList.stream().map(Task::getId).collect(Collectors.toList());
|
if (!CollectionUtils.isEmpty(allTaskIds)) {
|
// 2. 不再重新赋值,而是先查询出结果,再放入已初始化的map中
|
List<ProcessLog> processLogs = new LambdaQueryChainWrapper<>(processLogMapper)
|
.eq(ProcessLog::getDeleted, Boolean.FALSE)
|
.in(ProcessLog::getTaskId, allTaskIds)
|
.list();
|
|
// 3. 填充数据到taskInfoMap,引用未改变
|
Map<String, ProcessLog> tempMap = processLogs.stream()
|
.filter(processLog -> processLog.getTaskId() != null && processLog.getGmtCreate() != null)
|
.collect(Collectors.toMap(
|
ProcessLog::getTaskId,
|
processLog -> processLog,
|
(existing, replacement) -> replacement.getGmtCreate().after(existing.getGmtCreate()) ? replacement : existing,
|
HashMap::new
|
));
|
taskInfoMap.putAll(tempMap);
|
}
|
|
// 过滤已完成任务,得到有效任务列表(分页的依据)
|
List<Task> validTaskList = distinctAllTaskList.stream()
|
.filter(task -> {
|
ProcessLog processLog = taskInfoMap.get(task.getId());
|
// 未查询到日志 → 待完成;日志状态不是FINISHED → 有效
|
return processLog == null || !ProcessLogEventTypeEnum.FINISHED.getDesc().equals(processLog.getEventType().getDesc());
|
})
|
.collect(Collectors.toList());
|
|
// 有效数据总条数
|
long validTotal = validTaskList.size();
|
System.out.println("有效任务总数(排除已完成):" + validTotal);
|
|
// ========== 修复点2:分页合法性校验 ==========
|
// 计算最大有效页码
|
int maxPageNum = (int) (validTotal % pageSize == 0 ? validTotal / pageSize : (validTotal / pageSize) + 1);
|
// 若总条数为0,直接返回空数据
|
if (validTotal == 0) {
|
return Result.ok().data(new HashMap<String, Object>() {{
|
put("data", new ArrayList<>());
|
put("total", 0L);
|
}});
|
}
|
// 若请求页码超过最大页码,默认返回最后一页
|
if (pageNum > maxPageNum) {
|
pageNum = maxPageNum;
|
}
|
|
// ========== 修复点3:优化内存分页 ==========
|
int startIndex = (pageNum - 1) * pageSize;
|
int endIndex = Math.min(startIndex + pageSize, validTaskList.size());
|
// 转为新列表,避免subList视图的风险
|
List<Task> pageTaskList = new ArrayList<>(validTaskList.subList(startIndex, endIndex));
|
|
// 组装返回VO
|
List<TaskInfoVo> taskInfoVoList = new ArrayList<>();
|
for (Task task : pageTaskList) {
|
TaskInfoVo taskVo = new TaskInfoVo();
|
taskVo.setId(task.getId());
|
taskVo.setTaskName(task.getName());
|
taskVo.setStartTime(task.getCreateTime());
|
taskVo.setEndTime(task.getDueDate());
|
// 填充任务状态字段
|
taskVo.setTaskType("待完成");
|
ProcessLog processLog = taskInfoMap.get(task.getId());
|
if (Objects.nonNull(processLog)) {
|
taskVo.setTaskType(processLog.getEventType().getDesc());
|
}
|
|
CheckPointVO checkPointVO = processInfoMap.get(task.getProcessInstanceId());
|
if (checkPointVO != null) {
|
taskVo.setCheckPointInfo(checkPointVO);
|
}
|
|
taskInfoVoList.add(taskVo);
|
}
|
return Result.ok().data(taskInfoVoList).total(validTotal);
|
}
|
|
|
|
private String convertHoursToDayHourStr(long totalHours) {
|
if (totalHours < 0) {
|
return "0小时"; // 防御性处理负数场景
|
}
|
long days = totalHours / 24; // 计算天数
|
long hours = totalHours % 24; // 计算剩余小时数
|
|
StringBuilder sb = new StringBuilder();
|
if (days > 0) {
|
sb.append(days).append("天");
|
}
|
// 小时数无论是否为0,都展示(也可根据业务调整:如0小时时不展示)
|
if (hours > 0 || days == 0) {
|
sb.append(hours).append("小时");
|
}
|
return sb.toString();
|
}
|
// 对部门负责人集合信息进行去重
|
private void distinctVo(CustomerTaskVO vo) {
|
vo.setHandlerId(vo.getHandlerId().stream().distinct().collect(Collectors.toList()));
|
vo.setHandlerName(vo.getHandlerName().stream().distinct().collect(Collectors.toList()));
|
vo.setHandlerUnitId(vo.getHandlerUnitId().stream().distinct().collect(Collectors.toList()));
|
vo.setHandlerUnitName(vo.getHandlerUnitName().stream().distinct().collect(Collectors.toList()));
|
}
|
//拼接用户昵称以及电话
|
private String getUserShowName(SysUser user) {
|
return user.getNickName() + (StringUtils.isNotBlank(user.getPhonenumber()) ? "(" + user.getPhonenumber() + ")" : "");
|
}
|
//拼接部门负责人以及电话
|
private String getDeptLeaderShowName(SysDept dept) {
|
return dept.getLeader() + (StringUtils.isNotBlank(dept.getPhone()) ? "(" + dept.getPhone() + ")" : "");
|
}
|
//拼接上级部门以及本部门名称
|
private String setDeptNameWithParentName(SysDept dept) {
|
String[] str = dept.getAncestors().split(",");
|
if (str.length >= 4){
|
return dept.getParentName() + " / " + dept.getDeptName();
|
}else {
|
return dept.getDeptName();
|
}
|
}
|
private Long getTime(String timeStr) {
|
Long time = null;
|
if (StringUtils.isNotBlank(timeStr)) {
|
String[] timeArr = timeStr.split("-");
|
// 解析天数和小时数
|
int days = Integer.parseInt(timeArr[0]);
|
int hours = 0;
|
if (timeArr.length > 1) {
|
hours = Integer.parseInt(timeArr[1]);
|
}
|
time = (days * 24L + hours) * 3600L;
|
// //分-秒
|
// time= (days * 60L) + hours;
|
}
|
return time;
|
}
|
|
@Override
|
public Result getProjectList(){
|
List<ProjectInfo> loginUserOwnProjectInfo = getLoginUserOwnProjectInfo();
|
return Result.ok().data(loginUserOwnProjectInfo);
|
}
|
|
@Override
|
public Result getProjectSelectList() {
|
List<ProjectInfo> loginUserOwnProjectInfo = getLoginUserOwnProjectInfo();
|
if (CollectionUtils.isEmpty(loginUserOwnProjectInfo)) {
|
return Result.ok().data(loginUserOwnProjectInfo);
|
}
|
|
Map<String, String> projectMap = loginUserOwnProjectInfo.stream()
|
.collect(Collectors.toMap(
|
projectInfo -> String.valueOf(projectInfo.getId()), // key: 项目ID
|
ProjectInfo::getProjectName, // value: 项目对象本身
|
(existing, replacement) -> existing, // 处理重复ID的冲突策略(保留原有值)
|
LinkedHashMap::new
|
));
|
return Result.ok().data(projectMap);
|
}
|
|
|
}
|