|
|
|
|
@ -15,6 +15,7 @@ import cn.axzo.msg.center.domain.entity.TodoBusiness;
|
|
|
|
|
import cn.axzo.msg.center.domain.persistence.BaseEntityExt;
|
|
|
|
|
import cn.axzo.msg.center.message.domain.param.MessageGroupNodeStatisticParam;
|
|
|
|
|
import cn.axzo.msg.center.message.service.group.GroupTemplateService;
|
|
|
|
|
import cn.axzo.msg.center.message.service.group.GroupTemplates;
|
|
|
|
|
import cn.axzo.msg.center.message.service.group.NodeWrapper;
|
|
|
|
|
import cn.axzo.msg.center.message.service.impl.PendingMessageNewServiceImpl;
|
|
|
|
|
import cn.axzo.msg.center.message.service.todo.cache.NodeStatCache;
|
|
|
|
|
@ -39,6 +40,7 @@ import cn.axzo.msg.center.service.pending.response.PendingMessageStatisticRespon
|
|
|
|
|
import cn.axzo.msg.center.service.pending.response.PersonTodoToBeDoneStatResponse;
|
|
|
|
|
import cn.axzo.msg.center.utils.DateFormatUtil;
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
@ -49,14 +51,12 @@ import org.springframework.stereotype.Component;
|
|
|
|
|
|
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
|
|
import java.util.concurrent.ForkJoinPool;
|
|
|
|
|
import java.util.function.Function;
|
|
|
|
|
import java.util.function.Supplier;
|
|
|
|
|
|
|
|
|
|
import static cn.axzo.msg.center.inside.notices.utils.Queries.query;
|
|
|
|
|
@ -81,7 +81,6 @@ public class TodoRangeQueryService {
|
|
|
|
|
private final AnalysisConfig analysisConfig;
|
|
|
|
|
private final GroupTemplateService groupTemplateService;
|
|
|
|
|
private final NodeStatCache nodeStatCache;
|
|
|
|
|
private final ForkJoinPool statExecutor = new ForkJoinPool(80);
|
|
|
|
|
private final TodoTerminalHelper todoTerminalHelper;
|
|
|
|
|
private final AnalysisHelper analysisHelper;
|
|
|
|
|
|
|
|
|
|
@ -144,8 +143,8 @@ public class TodoRangeQueryService {
|
|
|
|
|
.collect(toSet());
|
|
|
|
|
CopiedToMeParam copiedToMeParam = request.getCopiedToMeParam();
|
|
|
|
|
Ref<List<Long>> ouCollector = Ref.create();
|
|
|
|
|
OuInfo ouInfo = OuInfo.create(request.getOuId(), request.getAppTerminalType(), request.determineToDoType());
|
|
|
|
|
LambdaQueryWrapper<Todo> query = todoQuery(ouInfo, ouCollector)
|
|
|
|
|
OuInfo ouInfo = new OuInfo(request.getOuId(), request.getAppTerminalType());
|
|
|
|
|
LambdaQueryWrapper<Todo> query = todoQuery(query(Todo.class), ouInfo, ouCollector)
|
|
|
|
|
// 查询的待办类型: COPIED_TO_ME, EXECUTABLE
|
|
|
|
|
.eq(Todo::getType, request.determineToDoType())
|
|
|
|
|
.eq(Todo::getExecutorPersonId, request.getPersonId())
|
|
|
|
|
@ -227,7 +226,7 @@ public class TodoRangeQueryService {
|
|
|
|
|
// 如果没有传端就查询所有端的待办, 用于待办转交
|
|
|
|
|
if (request.getAppTerminalType() == null)
|
|
|
|
|
nodes = groupTemplateService.getTodoGroups(AppTerminalTypeEnum.allTerminals());
|
|
|
|
|
else
|
|
|
|
|
else
|
|
|
|
|
// 获取可见的模版时, 不用定位到叶子节点
|
|
|
|
|
nodes = groupTemplateService.getTodoGroups(request.getAppTerminalType());
|
|
|
|
|
return groupTemplateService.collectTemplateCodes(nodes);
|
|
|
|
|
@ -256,40 +255,26 @@ public class TodoRangeQueryService {
|
|
|
|
|
|
|
|
|
|
private PendingMessageStatisticResponseV2 countStatGroupedImpl(MessageGroupNodeStatisticParam request) {
|
|
|
|
|
List<ValueNode<NodeWrapper>> nodes = determineStatNodes(request);
|
|
|
|
|
Function<ValueNode<NodeWrapper>, GroupStat> nodeStatFun = valueNode -> {
|
|
|
|
|
int executableCount = countStatByNode(request, valueNode, TodoType.EXECUTABLE);
|
|
|
|
|
int copiedToMeCount = countStatByNode(request, valueNode, TodoType.COPIED_TO_ME);
|
|
|
|
|
GroupStat groupStat = new GroupStat();
|
|
|
|
|
MessageGroupNode node = valueNode.getValue().unwrap();
|
|
|
|
|
groupStat.setGroupCode(node.getCode());
|
|
|
|
|
groupStat.setGroupName(node.getName());
|
|
|
|
|
groupStat.setGroupIcon(node.getIcon());
|
|
|
|
|
groupStat.setStat(new Stat(executableCount, copiedToMeCount));
|
|
|
|
|
return groupStat;
|
|
|
|
|
};
|
|
|
|
|
try {
|
|
|
|
|
LeafNodeStats nodeStats = countStatByNodes(request, nodes);
|
|
|
|
|
List<GroupStat> stats = new ArrayList<>();
|
|
|
|
|
for (ValueNode<NodeWrapper> valueNode : nodes) {
|
|
|
|
|
GroupStat groupStat = new GroupStat();
|
|
|
|
|
stats.add(groupStat);
|
|
|
|
|
MessageGroupNode node = valueNode.getValue().unwrap();
|
|
|
|
|
groupStat.setGroupCode(node.getCode());
|
|
|
|
|
groupStat.setGroupName(node.getName());
|
|
|
|
|
groupStat.setGroupIcon(node.getIcon());
|
|
|
|
|
groupStat.setStat(new Stat(
|
|
|
|
|
nodeStats.getCount(valueNode, TodoType.EXECUTABLE),
|
|
|
|
|
nodeStats.getCount(valueNode, TodoType.COPIED_TO_ME)));
|
|
|
|
|
}
|
|
|
|
|
PendingMessageStatisticResponseV2 resp = new PendingMessageStatisticResponseV2();
|
|
|
|
|
// 先提交任务
|
|
|
|
|
CompletableFuture<Integer> uniqueExecutableCountFuture = CompletableFuture.supplyAsync(
|
|
|
|
|
() -> countStatByNodes(request, nodes, TodoType.EXECUTABLE), statExecutor);
|
|
|
|
|
CompletableFuture<Integer> uniqueCopiedToMeCountFuture = CompletableFuture.supplyAsync(
|
|
|
|
|
() -> countStatByNodes(request, nodes, TodoType.COPIED_TO_ME), statExecutor);
|
|
|
|
|
// 用一个偏大的线程池, IO密集型任务, commonPool不够用
|
|
|
|
|
// 提交任务并获取结果
|
|
|
|
|
List<GroupStat> stats = statExecutor
|
|
|
|
|
.submit(() -> nodes
|
|
|
|
|
.parallelStream()
|
|
|
|
|
.map(nodeStatFun)
|
|
|
|
|
.collect(toList()))
|
|
|
|
|
.get();
|
|
|
|
|
resp.addGroupStats(stats);
|
|
|
|
|
// 一个端可能会有重复分类
|
|
|
|
|
resp.setTotalStat();
|
|
|
|
|
CompletableFuture.allOf(uniqueExecutableCountFuture, uniqueCopiedToMeCountFuture).join();
|
|
|
|
|
// 一个端不包含重复分类
|
|
|
|
|
int uniqueExecutableCount = uniqueExecutableCountFuture.get();
|
|
|
|
|
int uniqueCopiedToMeCount = uniqueCopiedToMeCountFuture.get();
|
|
|
|
|
resp.setUniqueTotalStat(new Stat(uniqueExecutableCount, uniqueCopiedToMeCount));
|
|
|
|
|
// 为了性能, 不做去重的统计了
|
|
|
|
|
resp.setUniqueTotalStat(new Stat(-1, -1));
|
|
|
|
|
return resp;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.warn("分类统计异常, request={}", request, e);
|
|
|
|
|
@ -303,32 +288,30 @@ public class TodoRangeQueryService {
|
|
|
|
|
public Integer countStat(MessageGroupNodeStatisticParam request) {
|
|
|
|
|
PendingMessageStatisticResponseV2 nodeStat = nodeStatCache
|
|
|
|
|
.getCacheResponseOrReload(request, () -> countStatGroupedImpl(request));
|
|
|
|
|
Stat totalStat = nodeStat.getUniqueTotalStat();
|
|
|
|
|
Stat totalStat = nodeStat.getTotalStat();
|
|
|
|
|
return totalStat == null ? 0 : totalStat.getPendingCount();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int countStatByNode(MessageGroupNodeStatisticParam request,
|
|
|
|
|
ValueNode<NodeWrapper> node, TodoType todoType) {
|
|
|
|
|
return countStatByNodes(request, Collections.singletonList(node), todoType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int countStatByNodes(MessageGroupNodeStatisticParam request,
|
|
|
|
|
List<ValueNode<NodeWrapper>> nodes, TodoType todoType) {
|
|
|
|
|
private LeafNodeStats countStatByNodes(MessageGroupNodeStatisticParam request, List<ValueNode<NodeWrapper>> nodes) {
|
|
|
|
|
List<String> templateCodes = groupTemplateService.collectTemplateCodes(nodes);
|
|
|
|
|
GroupTemplates groupTemplates = groupTemplateService.collectTemplates(nodes);
|
|
|
|
|
if (CollectionUtils.isEmpty(templateCodes))
|
|
|
|
|
return 0;
|
|
|
|
|
OuInfo ouInfo = OuInfo.create(request.getOuId(), request.getTerminalType(), todoType);
|
|
|
|
|
LambdaQueryWrapper<Todo> query = todoQuery(ouInfo)
|
|
|
|
|
return new LeafNodeStats(Collections.emptyList(), groupTemplates);
|
|
|
|
|
LambdaQueryWrapper<Todo> query = new QueryWrapper<Todo>()
|
|
|
|
|
// 1. group by bellow
|
|
|
|
|
.select("COUNT(*) AS count, template_code, type")
|
|
|
|
|
.lambda();
|
|
|
|
|
OuInfo ouInfo = new OuInfo(request.getOuId(), request.getTerminalType());
|
|
|
|
|
//noinspection unchecked
|
|
|
|
|
List<Todo> stats = todoDao.list(todoQuery(query, ouInfo, null)
|
|
|
|
|
.in(Todo::getTemplateCode, templateCodes)
|
|
|
|
|
.eq(Todo::getExecutorPersonId, request.getPersonId())
|
|
|
|
|
.in(CollectionUtils.isNotEmpty(request.getWorkspaceIds()), Todo::getOrgId, request.getWorkspaceIds())
|
|
|
|
|
.and(todoType == TodoType.EXECUTABLE, nested -> nested
|
|
|
|
|
.eq(Todo::getType, TodoType.EXECUTABLE)
|
|
|
|
|
.eq(Todo::getState, PendingMessageStateEnum.HAS_BEEN_SENT))
|
|
|
|
|
.and(todoType == TodoType.COPIED_TO_ME, nested -> nested
|
|
|
|
|
.eq(Todo::getType, TodoType.COPIED_TO_ME)
|
|
|
|
|
.eq(Todo::getState, PendingMessageStateEnum.CREATED));
|
|
|
|
|
return todoDao.count(query);
|
|
|
|
|
.in(Todo::getType, TodoType.EXECUTABLE, TodoType.COPIED_TO_ME)
|
|
|
|
|
.in(Todo::getState, PendingMessageStateEnum.HAS_BEEN_SENT, PendingMessageStateEnum.CREATED)
|
|
|
|
|
// 2. group by here
|
|
|
|
|
.groupBy(Todo::getTemplateCode, Todo::getType));
|
|
|
|
|
return new LeafNodeStats(stats, groupTemplates);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<ValueNode<NodeWrapper>> determineStatNodes(MessageGroupNodeStatisticParam request) {
|
|
|
|
|
@ -358,11 +341,8 @@ public class TodoRangeQueryService {
|
|
|
|
|
.likeRight(matchBusinessTitle, TodoBusiness::getTitle, title));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private LambdaQueryWrapper<Todo> todoQuery(OuInfo info) {
|
|
|
|
|
return todoQuery(info, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private LambdaQueryWrapper<Todo> todoQuery(OuInfo info, @Nullable Ref<List<Long>> ouCollector) {
|
|
|
|
|
private LambdaQueryWrapper<Todo> todoQuery(LambdaQueryWrapper<Todo> query,
|
|
|
|
|
OuInfo info, @Nullable Ref<List<Long>> ouCollector) {
|
|
|
|
|
List<Long> ouIds = Collections.emptyList();
|
|
|
|
|
// 工人端不通过ou做查询
|
|
|
|
|
if (info.terminalType != AppTerminalTypeEnum.C_WORKER_APP) {
|
|
|
|
|
@ -372,7 +352,7 @@ public class TodoRangeQueryService {
|
|
|
|
|
}
|
|
|
|
|
// 1. 查询 ouId = 0 的数据
|
|
|
|
|
// 2. 查询ouId下面所有的平台班组id当成ouId
|
|
|
|
|
return query(Todo.class)
|
|
|
|
|
return query
|
|
|
|
|
.eq(Todo::getIsDelete, TableIsDeleteEnum.NORMAL.value)
|
|
|
|
|
.in(CollectionUtils.isNotEmpty(ouIds), Todo::getOuId, ouIds);
|
|
|
|
|
}
|
|
|
|
|
@ -381,11 +361,6 @@ public class TodoRangeQueryService {
|
|
|
|
|
private static class OuInfo {
|
|
|
|
|
final Long ouId;
|
|
|
|
|
final AppTerminalTypeEnum terminalType;
|
|
|
|
|
final boolean includeZeroOuId;
|
|
|
|
|
|
|
|
|
|
static OuInfo create(Long ouId, AppTerminalTypeEnum terminalType, TodoType todoType) {
|
|
|
|
|
return new OuInfo(ouId, terminalType, todoType == TodoType.EXECUTABLE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|