Merge branch 'master' into feature/REQ-3284

# Conflicts:
#	inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/config/PendingMessageBizConfig.java
This commit is contained in:
yanglin 2024-11-27 18:09:45 +08:00
commit 9676faf898
25 changed files with 532 additions and 25 deletions

View File

@ -170,6 +170,9 @@ public class PendingMessageBizConfig {
@Getter
private PushChannel pushChannel = PushChannel.NIM;
@Getter
private int todoTitleSearchMaxSize = 5000;
public boolean determineOldMsgStatCacheOn() {
return isOldMsgStatCacheOn();
}

View File

@ -71,6 +71,7 @@ public class MessageTemplateParserV3 {
@Override
public void visitTemplateCardUrlConfig(UrlConfig urlConfig) {
if (!urlConfig.hasUrl()) return;
CardButton cardDetailButton = new CardButton();
cardDetailButton.setTitle("详情");
cardDetailButton.setAction(RouterCategoryEnum.JUMP.name());

View File

@ -6,15 +6,19 @@ import cn.axzo.msg.center.message.service.todo.TodoRangeQueryService;
import cn.axzo.msg.center.message.service.todo.TodoSimpleQueryService;
import cn.axzo.msg.center.message.service.todo.TodoWorkerQueryService;
import cn.axzo.msg.center.message.service.todo.manage.TodoManager;
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
import cn.axzo.msg.center.service.enums.TodoQueryType;
import cn.axzo.msg.center.service.enums.TodoType;
import cn.axzo.msg.center.service.pending.ModelVersion;
import cn.axzo.msg.center.service.pending.client.PendingMessageClient;
import cn.axzo.msg.center.service.pending.request.CompletePendingBySubCodeRequest;
import cn.axzo.msg.center.service.pending.request.CompletePendingMessageByCodesRequest;
import cn.axzo.msg.center.service.pending.request.CompletePendingMessageByIdRequest;
import cn.axzo.msg.center.service.pending.request.CompletePendingMessageRequest;
import cn.axzo.msg.center.service.pending.request.GetPendingTodosRequest;
import cn.axzo.msg.center.service.pending.request.GetTodoCountRequest;
import cn.axzo.msg.center.service.pending.request.GetTodoPageRequest;
import cn.axzo.msg.center.service.pending.request.GetTodoRequest;
import cn.axzo.msg.center.service.pending.request.PendingMessageByBizCodeRequest;
import cn.axzo.msg.center.service.pending.request.PendingMessageCountUncompletedRequest;
@ -35,6 +39,7 @@ import cn.axzo.msg.center.service.pending.request.TodoHandoverRequest;
import cn.axzo.msg.center.service.pending.request.UpdateBusinessFinalBizStateRequest;
import cn.axzo.msg.center.service.pending.request.UpdatePendingMessageByIdRequest;
import cn.axzo.msg.center.service.pending.response.AnalysisPage;
import cn.axzo.msg.center.service.pending.response.PendingMessageCountDTO;
import cn.axzo.msg.center.service.pending.response.PendingMessageIterateResponse;
import cn.axzo.msg.center.service.pending.response.PendingMessageResponse;
import cn.axzo.msg.center.service.pending.response.PendingMessageSimpleDTO;
@ -54,6 +59,7 @@ import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
@ -217,6 +223,12 @@ public class PendingMessageNewController implements PendingMessageClient {
return CommonResponse.success(todoManager.completeByBizCode(param));
}
@Override
public CommonResponse<Boolean> completeByIdentityCodes(CompletePendingMessageByCodesRequest param) {
log.info("completeByCodes, request={}", JSON.toJSONString(param));
return CommonResponse.success(todoManager.batchCompleteByIdentityCodes(param));
}
@Override
public CommonResponse<Boolean> updateBusinessFinalBizState(UpdateBusinessFinalBizStateRequest param) {
log.info("updateBusinessFinalBizState, request={}", JSON.toJSONString(param));
@ -266,11 +278,22 @@ public class PendingMessageNewController implements PendingMessageClient {
}
@Override
public CommonResponse<List<PendingMessageSimpleDTO>> getTodosSimple(GetTodoRequest request) {
public CommonResponse<List<PendingMessageSimpleDTO>> getTodosSimple(@RequestBody GetTodoRequest request) {
log.info("getTodos, request={}", JSON.toJSONString(request));
return CommonResponse.success(todoSimpleQueryService.getTodosSimple(request));
}
@Override
public CommonResponse<Map<BizCategoryEnum, PendingMessageCountDTO>> getTodosSimpleCount(GetTodoCountRequest request) {
return CommonResponse.success(todoSimpleQueryService.getTodosSimpleCount(request));
}
@Override
public CommonResponse<Page<PendingMessageSimpleDTO>> getTodosSimplePage(@RequestBody GetTodoPageRequest request) {
log.info("getTodos page, request={}", JSON.toJSONString(request));
return CommonResponse.success(todoSimpleQueryService.getTodosSimplePage(request));
}
@Override
public CommonResponse<Boolean> setHide(SetHideRequest req) {
log.info("setHide, request={}", JSON.toJSONString(req));

View File

@ -45,6 +45,10 @@ public class WorkflowButtonSyncClientController implements WorkflowButtonSyncCli
request.getButtons().stream()
.collect(toMap(WorkflowButton::getCode, identity(),
(oldValue, newValue) -> oldValue));
Map<String, WorkflowButton> name2FlowButton =
request.getButtons().stream()
.collect(toMap(WorkflowButton::getName, identity(),
(oldValue, newValue) -> oldValue));
List<MessageTemplateButtonV3> buttons =
messageTemplateButtonV3Dao.lambdaQuery().list();
@ -56,10 +60,9 @@ public class WorkflowButtonSyncClientController implements WorkflowButtonSyncCli
semaphore.acquire();
tasks.runAsync(() -> {
try {
sync(code2Template, code2FlowButton, button);
sync(code2Template, code2FlowButton, name2FlowButton, button);
} catch (Exception e) {
log.warn("sync button error, button={}", button, e);
throw new RuntimeException(e);
} finally {
semaphore.release();
}
@ -72,6 +75,7 @@ public class WorkflowButtonSyncClientController implements WorkflowButtonSyncCli
private void sync(Map<String, MessageTemplateV3> code2Template,
Map<String, WorkflowButton> code2FlowButton,
Map<String, WorkflowButton> name2FlowButton,
MessageTemplateButtonV3 button) {
if (button.getSource() != RouterButtonSourceEnum.SYSTEM)
return;
@ -79,9 +83,14 @@ public class WorkflowButtonSyncClientController implements WorkflowButtonSyncCli
if (template.getMsgCategory() != MessageCategoryEnum.APPROVAL_PENDING_MESSAGE)
return;
WorkflowButton workflowButton = code2FlowButton.get(button.getCode());
if (workflowButton == null) return;
MessageTemplateButtonV3 update = new MessageTemplateButtonV3();
WorkflowButton workflowButton = code2FlowButton.get(button.getCode());
if (workflowButton == null) {
workflowButton = name2FlowButton.get(button.getName());
if (workflowButton != null)
update.setCode(workflowButton.getCode());
}
if (workflowButton == null) return;
update.setId(button.getId());
update.setCategory(workflowButton.getCategory());
if (button.getCategory() == RouterCategoryEnum.JUMP) {

View File

@ -1,6 +1,7 @@
package cn.axzo.msg.center.message.service.impl.v3;
import cn.axzo.msg.center.domain.entity.MessageEntity;
import cn.axzo.msg.center.domain.entity.MessageTemplateButtonV3;
import cn.axzo.msg.center.domain.entity.MessageTemplateGroupV3;
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
@ -31,6 +32,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.jetbrains.annotations.Nullable;
@ -183,6 +185,12 @@ public class ModelV3Parser {
parsedModel.setTemplate(JSON.parseObject(JSON.toJSONString(templateModel.getTemplate()), ParsedTemplateV3.class));
parsedModel.setGroups(deepCopyGroups(templateModel.getGroups()));
parsedModel.setButtons(JSON.parseArray(JSON.toJSONString(templateModel.getButtons()), ParsedButtonV3.class));
if (CollectionUtils.isNotEmpty(templateModel.getButtons())) {
for (int i = 0; i < templateModel.getButtons().size(); i++) {
MessageTemplateButtonV3 button = templateModel.getButtons().get(i);
parsedModel.getButtons().get(i).setPresetButtonType(button.getPresetBtnType());
}
}
return parsedModel;
}

View File

@ -88,7 +88,7 @@ public class ModelV2PropsPopulator implements ParsedModel3Visitor {
ButtonRouterDTO buttonV2 = new ButtonRouterDTO();
buttonV2.setDesc(buttonV3.getName());
buttonV2.setCategory(buttonV3.getCategory());
buttonV2.setPresetButtonType(buttonV3.getPresetBtnType());
buttonV2.setPresetButtonType(buttonV3.getPresetButtonType());
buttonV2.setStyle(buttonV3.parseStyle());
buttonV2.setExecutorShow(buttonV3.getExecutorShow());
buttonV2.setPendingShow(buttonV3.getPendingShow());

View File

@ -13,6 +13,7 @@ import cn.axzo.msg.center.domain.entity.PendingRecordAdapter;
import cn.axzo.msg.center.domain.entity.Todo;
import cn.axzo.msg.center.domain.entity.TodoBusiness;
import cn.axzo.msg.center.domain.persistence.BaseEntityExt;
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
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;
@ -94,6 +95,7 @@ public class TodoRangeQueryService {
private final TodoTerminalHelper todoTerminalHelper;
private final AnalysisHelper analysisHelper;
private final ModelV3ExtPopulator modelV3ExtPopulator;
private final PendingMessageBizConfig cfg;
// !! page query
@ -170,7 +172,11 @@ public class TodoRangeQueryService {
// 模糊匹配发起人title
Collection<Long> businessIds = StringUtils.isBlank(request.getTitle())
? Collections.emptyList()
: todoBusinessMapper.selectList(businessQuery(request.getTitle(), false))
: todoBusinessMapper.selectList(
businessQuery(request.getTitle(), false)
.select(TodoBusiness::getId)
.orderByDesc(TodoBusiness::getId)
.last("LIMIT " + cfg.getTodoTitleSearchMaxSize()))
.stream()
.map(BaseEntityExt::getId)
.collect(toSet());

View File

@ -1,5 +1,7 @@
package cn.axzo.msg.center.message.service.todo;
import cn.axzo.framework.domain.web.result.ApiListResult;
import cn.axzo.maokai.api.vo.response.tree.ValueNode;
import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
import cn.axzo.msg.center.common.utils.BizAssertions;
import cn.axzo.msg.center.dal.TodoBusinessDao;
@ -8,15 +10,27 @@ import cn.axzo.msg.center.domain.entity.PendingRecordAdapter;
import cn.axzo.msg.center.domain.entity.Todo;
import cn.axzo.msg.center.domain.entity.TodoBusiness;
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
import cn.axzo.msg.center.message.service.group.GroupTemplateService;
import cn.axzo.msg.center.message.service.group.NodeWrapper;
import cn.axzo.msg.center.message.service.impl.v3.ModelV3ExtPopulator;
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
import cn.axzo.msg.center.service.enums.TodoQueryType;
import cn.axzo.msg.center.service.enums.TodoType;
import cn.axzo.msg.center.service.pending.request.GetTodoCountRequest;
import cn.axzo.msg.center.service.pending.request.GetTodoPageRequest;
import cn.axzo.msg.center.service.pending.request.GetTodoRequest;
import cn.axzo.msg.center.service.pending.request.PendingMessageByBizCodeRequest;
import cn.axzo.msg.center.service.pending.request.PendingMessageDetailRequestV3;
import cn.axzo.msg.center.service.pending.request.PendingMessageQueryRequest;
import cn.axzo.msg.center.service.pending.response.PendingMessageCountDTO;
import cn.axzo.msg.center.service.pending.response.PendingMessageResponse;
import cn.axzo.msg.center.service.pending.response.PendingMessageSimpleDTO;
import cn.azxo.framework.common.model.Page;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
@ -25,8 +39,12 @@ import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.groupingBy;
@ -45,6 +63,7 @@ public class TodoSimpleQueryService {
private final TodoRespBuilder todoRespBuilder;
private final PendingMessageBizConfig cfg;
private final ModelV3ExtPopulator modelV3ExtPopulator;
private final GroupTemplateService groupTemplateService;
public PendingMessageResponse query(PendingMessageQueryRequest req) {
// 虽然通过code可以查询到唯一的记录, 把一些事情交给数据库去库, 成本不高
@ -138,8 +157,120 @@ public class TodoSimpleQueryService {
.in(CollectionUtils.isNotEmpty(executor.getPersonIds()), Todo::getExecutorPersonId, executor.getPersonIds());
}
})
.exists(request.getBizCategory() != null, String.format("select id from todo_business as b where b.id=todo_business_id and b.biz_category = '%s'", request.getBizCategory() == null ? "" : request.getBizCategory().name()))
.last("LIMIT " + cfg.getGetTodoSimpleSize())
.list();
return todoRespBuilder.buildTodosSimple(todos);
}
public Map<BizCategoryEnum, PendingMessageCountDTO> getTodosSimpleCount(GetTodoCountRequest request) {
Map<BizCategoryEnum, PendingMessageCountDTO> resultMap = new EnumMap<>(BizCategoryEnum.class);
BizCategoryEnum[] values;
if (request.getBizCategory() == null) {
values = BizCategoryEnum.values();
} else {
values = new BizCategoryEnum[]{request.getBizCategory()};
}
for (BizCategoryEnum bizCategory : values) {
List<Todo> todos = todoDao.lambdaQuery()
.in(CollectionUtils.isNotEmpty(request.getIdentityCodes()), Todo::getIdentityCode, request.getIdentityCodes())
.in(CollectionUtils.isNotEmpty(request.getTemplateCodes()), Todo::getTemplateCode, request.getTemplateCodes())
.in(CollectionUtils.isNotEmpty(request.getBizCodes()), Todo::getBizCode, request.getBizCodes())
.eq(Todo::getState, PendingMessageStateEnum.HAS_BEEN_SENT)
.and(CollectionUtils.isNotEmpty(request.getExecutors()), wrapper -> {
for (GetTodoCountRequest.Executor executor : request.getExecutors()) {
wrapper.or()
.eq(executor.getOuId() != null, Todo::getOuId, executor.getOuId())
.eq(executor.getWorkspaceId() != null, Todo::getOrgId, executor.getWorkspaceId())
.in(CollectionUtils.isNotEmpty(executor.getPersonIds()), Todo::getExecutorPersonId, executor.getPersonIds());
}
})
.exists(String.format("select id from todo_business as b where b.id=todo_business_id and b.biz_category = '%s'", bizCategory.name()))
.select(Todo::getId, Todo::getIdentityCode, Todo::getOuId, Todo::getExecutorPersonId, Todo::getOrgId, Todo::getState, Todo::getTodoBusinessId, Todo::getTemplateCode)
.list();
if (todos == null) {
todos = Collections.emptyList();
}
List<PendingMessageCountDTO.SinglePendingDto> pendingDtos = todos.stream()
.map(todo -> PendingMessageCountDTO.SinglePendingDto.builder()
.identityCode(todo.getIdentityCode())
.templateCode(todo.getTemplateCode())
.executePersonId(todo.getExecutorPersonId())
.ouId(todo.getOuId())
.workspaceId(todo.getOrgId())
.build())
.collect(toList());
PendingMessageCountDTO dto = PendingMessageCountDTO.builder().count(pendingDtos.size()).dtos(pendingDtos).build();
resultMap.put(bizCategory, dto);
}
return resultMap;
}
public Page<PendingMessageSimpleDTO> getTodosSimplePage(GetTodoPageRequest request) {
List<String> groupTempCodes = null;
if (!request.determineGroupNodeCodes().isEmpty()) {
groupTempCodes = groupTemplateService.collectTemplateCodes(request.determineGroupNodeCodes());
} else if (request.getAppTerminalType() != null) {
List<ValueNode<NodeWrapper>> nodes = groupTemplateService.getTodoGroups(request.getAppTerminalType());
groupTempCodes = groupTemplateService.collectTemplateCodes(nodes);
}
List<String> valuableTempCodes = new ArrayList<>();
if (CollectionUtils.isNotEmpty(groupTempCodes)) {
if (CollectionUtils.isNotEmpty(request.getTemplateCodes())) {
valuableTempCodes.addAll(request.getTemplateCodes().stream()
.filter(groupTempCodes::contains)
.collect(Collectors.toList()));
} else {
valuableTempCodes.addAll(groupTempCodes);
}
} else if (CollectionUtils.isNotEmpty(request.getTemplateCodes())) {
valuableTempCodes.addAll(request.getTemplateCodes());
}
IPage<Todo> page = todoDao.lambdaQuery()
.in(CollectionUtils.isNotEmpty(request.getIdentityCodes()), Todo::getIdentityCode, request.getIdentityCodes())
.in(CollectionUtils.isNotEmpty(valuableTempCodes), Todo::getTemplateCode, valuableTempCodes)
.in(CollectionUtils.isNotEmpty(request.getBizCodes()), Todo::getBizCode, request.getBizCodes())
.in(CollectionUtils.isNotEmpty(request.getStates()), Todo::getState, request.getStates())
.likeRight(StringUtils.isNotBlank(request.getTitleLike()), Todo::getTitle, request.getTitleLike())
.and(CollectionUtils.isNotEmpty(request.getExecutors()), wrapper -> {
for (GetTodoPageRequest.Executor executor : request.getExecutors()) {
wrapper.or()
.eq(executor.getOuId() != null, Todo::getOuId, executor.getOuId())
.eq(executor.getWorkspaceId() != null, Todo::getOrgId, executor.getWorkspaceId())
.in(CollectionUtils.isNotEmpty(executor.getPersonIds()), Todo::getExecutorPersonId, executor.getPersonIds());
}
})
.exists(request.getBizCategory() != null, String.format("select id from todo_business as b where b.id=todo_business_id and b.biz_category = '%s'", request.getBizCategory() == null ? "" : request.getBizCategory().name()))
.page(request.toPage());
List<PendingMessageSimpleDTO> messageSimpleDTOS = todoRespBuilder.buildTodosSimple(page.getRecords());
return Page.toPage(page.getCurrent(), page.getSize(), page.getTotal(), messageSimpleDTOS);
}
/**
* 常用的RPC请求返回值解析如果 被请求方 返回非200会抛出异常
*
* @param supplier ApiListResult类型的RPC接口
* @param operationType 接口方法描述
* @param param 接口入参
* @return 接口返回值
*/
public static <T> List<T> rpcApiListResultProcessor(Supplier<ApiListResult<T>> supplier, String operationType, Object... param) {
log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param));
ApiListResult<T> result = printLatency(supplier, operationType);
log.info(operationType + "-Result: " + JSONUtil.toJsonStr(result));
Assert.notNull(result, "服务调用异常");
Assert.isTrue(result.isSuccess(), "服务调用异常:" + result.getMsg());
return result.getData();
}
public static <R> R printLatency(Supplier<R> function, String optType) {
StopWatch stopWatch = new StopWatch(optType);
stopWatch.start(optType);
R r = function.get();
stopWatch.stop();
log.info(stopWatch.shortSummary(TimeUnit.MILLISECONDS));
return r;
}
}

View File

@ -4,6 +4,7 @@ import cn.axzo.msg.center.domain.entity.Todo;
import cn.axzo.msg.center.domain.entity.TodoBusiness;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import java.util.List;
@ -17,6 +18,14 @@ class StateAdvanceResult {
private final TodoBusiness business;
private final List<Todo> advancedTodos;
@Setter
private Runnable broadcastHandler;
public void broadcast() {
if (broadcastHandler != null)
broadcastHandler.run();
}
Long getBusinessId() {
return business == null ? 0L : business.getId();
}

View File

@ -3,6 +3,7 @@ package cn.axzo.msg.center.message.service.todo.manage;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.framework.jackson.utility.JSON;
import cn.axzo.framework.rocketmq.utils.TraceUtils;
import cn.axzo.msg.center.api.mq.PresetButtonPressedMessage;
import cn.axzo.msg.center.common.utils.BizAssertions;
@ -31,6 +32,7 @@ import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
import cn.axzo.msg.center.service.enums.TodoType;
import cn.axzo.msg.center.service.enums.YesOrNo;
import cn.axzo.msg.center.service.pending.request.CompletePendingBySubCodeRequest;
import cn.axzo.msg.center.service.pending.request.CompletePendingMessageByCodesRequest;
import cn.axzo.msg.center.service.pending.request.CompletePendingMessageByIdRequest;
import cn.axzo.msg.center.service.pending.request.CompletePendingMessageRequest;
import cn.axzo.msg.center.service.pending.request.PresetButtonPressedRequest;
@ -69,8 +71,10 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
@ -195,7 +199,7 @@ public class TodoManager {
*/
@Transactional(rollbackFor = Exception.class)
public Integer handover(TodoHandoverRequest request) {
BizAssertions.assertNotBlank(request.getFromPersonName(), "交接来源人自然人姓名不能为空");
// BizAssertions.assertNotBlank(request.getFromPersonName(), "交接来源人自然人姓名不能为空");
BizAssertions.assertNotEmpty(request.getTodoIdentityCodes(), "需要转交的待办编码不能为空");
List<Todo> candidates = todoDao.getByCodes(request.getTodoIdentityCodes());
// 只处理未完成的
@ -232,7 +236,12 @@ public class TodoManager {
// 身份id设置为0, 去身份
destTodo.setExecutorId(0L);
destTodo.setExecutorType(IdentityTypeEnum.NOT_SUPPORT);
if (request.getToOuId() != null && request.getToOuId() > 0) {
destTodo.setOuId(request.getToOuId());
}
if (request.getToWorkspaceId() != null && request.getToWorkspaceId() > 0) {
destTodo.setOrgId(request.getToWorkspaceId());
}
destTodo.setExecutorPersonId(request.getToPersonId());
destTodo.setExecutorName(request.determineToPersonName());
}
@ -306,7 +315,9 @@ public class TodoManager {
*/
@Transactional(rollbackFor = Exception.class)
public boolean completeByBizCode(CompletePendingMessageRequest request) {
TodoRequestContext ctx = TodoRequestContext.create("completeByBizCode", request);
TodoRequestContext ctx = TodoRequestContext
.create("completeByBizCode", request)
.delayBroadcast(true);
StateAdvanceResult advanceResult = advanceState(ctx, execAdvanceBuilder()
.eq(Todo::getTemplateCode, request.getTemplateCode())
.eq(Todo::getBizCode, request.getBizCode())
@ -323,9 +334,33 @@ public class TodoManager {
}
if (advanceResult.isAdvanced())
todoLogger.logTodoCompleted(ctx, advanceResult.getAdvancedTodos());
advanceResult.broadcast();
return advanceResult.isAdvanced() || businessUpdated;
}
@Transactional(rollbackFor = Exception.class)
public boolean batchCompleteByIdentityCodes(CompletePendingMessageByCodesRequest request) {
log.info("batchCompleteByIdentityCodes param:{}", JSON.toJSONString(request));
if (CollectionUtils.isEmpty(request.getIdentityCodes())) {
return true;
}
List<Todo> todos = todoDao.getByIdentityCodes(request.getIdentityCodes());
if (CollectionUtils.isEmpty(todos)) {
return true;
}
Map<Long, List<Todo>> businessTodoMap = todos.stream().collect(Collectors.groupingBy(Todo::getTodoBusinessId));
boolean result = false;
for (List<Todo> todoValues : businessTodoMap.values()) {
CompletePendingMessageRequest singleRequest = new CompletePendingMessageRequest();
singleRequest.setBizCode(todoValues.get(0).getBizCode());
singleRequest.setTemplateCode(todoValues.get(0).getTemplateCode());
singleRequest.setFinalStatus(request.getFinalStatus());
singleRequest.setBizFinalStateEnum(request.getBizFinalStateEnum());
result = this.completeByBizCode(singleRequest) || result;
}
return result;
}
@Transactional
public boolean updateBusinessFinalBizState(UpdateBusinessFinalBizStateRequest request) {
TodoBusiness business = todoBusinessDao
@ -338,6 +373,8 @@ public class TodoManager {
TodoRequestContext ctx = TodoRequestContext.create("updateBusinessFinalBizState", request)
.addLogContent("updated", updated);
todoLogger.logBusinessUpdated(ctx, business);
List<Todo> todos = todoDao.getByBusinessIds(Collections.singletonList(business.getId()));
todoBroadcaster.fireTodoUpdates("updateBusinessFinalBizState", todos);
}
return updated;
}
@ -488,7 +525,7 @@ public class TodoManager {
@Transactional(rollbackFor = Exception.class)
public Boolean batchSetProcessing(List<String> identityCodes, List<String> subBizCodes) {
BizAssertions.assertTrue(
CollectionUtils.isNotEmpty(identityCodes) || CollectionUtils.isNotEmpty(subBizCodes) ,
CollectionUtils.isNotEmpty(identityCodes) || CollectionUtils.isNotEmpty(subBizCodes),
"identityCodes或subBizCodes列表不能为空");
List<Todo> todos;
if (CollectionUtils.isNotEmpty(identityCodes))
@ -663,19 +700,27 @@ public class TodoManager {
return new StateAdvanceResult(false, noStateTodos.business, Collections.emptyList());
}
boolean updated = builder.getUpdate().update();
Runnable broadcastHandler = null;
if (updated) {
ctx.addLogContent("stateAdvanced", true);
Set<Long> updatedTodoIds = advanceTodos.todos.stream()
.map(BaseEntityExt::getId)
.collect(toSet());
broadcastHandler = () -> {
if (!updatedTodoIds.isEmpty()) {
List<Todo> updatedTodos = todoDao.listByIds(updatedTodoIds);
todoBroadcaster.fireTodoUpdates(ctx.getName(), updatedTodos);
}
};
if (!ctx.isDelayBroadcast())
broadcastHandler.run();
} else {
advanceFailLogger.get();
}
return new StateAdvanceResult(updated, advanceTodos.business, advanceTodos.todos);
StateAdvanceResult result = new StateAdvanceResult(updated, advanceTodos.business, advanceTodos.todos);
if (ctx.isDelayBroadcast())
result.setBroadcastHandler(broadcastHandler);
return result;
}
private StateAdvanceBuilder execAdvanceBuilder() {

View File

@ -17,6 +17,7 @@ public class TodoRequestContext {
private final String name;
private final String requestNo;
private final Map<String, Object> logContents = new LinkedHashMap<>();
private boolean delayBroadcast = false;
private TodoRequestContext(String name, String requestNo, Object request) {
this.name = name;
@ -47,6 +48,11 @@ public class TodoRequestContext {
return this;
}
public TodoRequestContext delayBroadcast(boolean delayBroadcast) {
this.delayBroadcast = delayBroadcast;
return this;
}
public TodoRequestContext addLogContent(String name, Object value) {
if (name == null || value == null)
return this;

View File

@ -0,0 +1,32 @@
package cn.axzo.msg.center.service.enums;
import lombok.Getter;
@Getter
public enum SimplePageQueryStateEnum {
/**
* 已处理
*/
COMPLETED(1, "已处理"),
/**
* 已终止
*/
ABORTED(2, "已终止"),
/**
* 已撤销
*/
RETRACT(3, "已撤销"),
/**
* 待处理
*/
HAS_BEEN_SENT(4, "待处理");
private final int code;
private final String desc;
SimplePageQueryStateEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
}

View File

@ -1,11 +1,15 @@
package cn.axzo.msg.center.service.pending.client;
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
import cn.axzo.msg.center.service.enums.TodoQueryType;
import cn.axzo.msg.center.service.pending.request.CompletePendingBySubCodeRequest;
import cn.axzo.msg.center.service.pending.request.CompletePendingMessageByCodesRequest;
import cn.axzo.msg.center.service.pending.request.CompletePendingMessageByIdRequest;
import cn.axzo.msg.center.service.pending.request.CompletePendingMessageRequest;
import cn.axzo.msg.center.service.pending.request.GetPendingTodosRequest;
import cn.axzo.msg.center.service.pending.request.GetTodoCountRequest;
import cn.axzo.msg.center.service.pending.request.GetTodoPageRequest;
import cn.axzo.msg.center.service.pending.request.GetTodoRequest;
import cn.axzo.msg.center.service.pending.request.PendingMessageByBizCodeRequest;
import cn.axzo.msg.center.service.pending.request.PendingMessageCountUncompletedRequest;
@ -26,6 +30,7 @@ import cn.axzo.msg.center.service.pending.request.TodoHandoverRequest;
import cn.axzo.msg.center.service.pending.request.UpdateBusinessFinalBizStateRequest;
import cn.axzo.msg.center.service.pending.request.UpdatePendingMessageByIdRequest;
import cn.axzo.msg.center.service.pending.response.AnalysisPage;
import cn.axzo.msg.center.service.pending.response.PendingMessageCountDTO;
import cn.axzo.msg.center.service.pending.response.PendingMessageIterateResponse;
import cn.axzo.msg.center.service.pending.response.PendingMessageResponse;
import cn.axzo.msg.center.service.pending.response.PendingMessageSimpleDTO;
@ -44,6 +49,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
/**
* 代办消息模块管理
@ -237,6 +243,15 @@ public interface PendingMessageClient {
@PostMapping(value = "/pending-message/complete/by-biz-code", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Boolean> completeByTemplateCodeBizCode(@RequestBody @Valid CompletePendingMessageRequest param);
/**
* 通过IdentityCode 批量更新
*
* @param param
* @return
*/
@PostMapping(value = "/pending-message/complete/by-identity-codes", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Boolean> completeByIdentityCodes(@RequestBody @Valid CompletePendingMessageByCodesRequest param);
@PostMapping(value = "/pending-message/update-business-final-biz-state",
produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Boolean> updateBusinessFinalBizState(@RequestBody @Valid UpdateBusinessFinalBizStateRequest param);
@ -332,4 +347,10 @@ public interface PendingMessageClient {
@PostMapping(value = "/pending-message/record/get-todos-simple", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<List<PendingMessageSimpleDTO>> getTodosSimple(@RequestBody @Valid GetTodoRequest request);
@PostMapping(value = "/pending-message/record/get-todos-simple/count", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Map<BizCategoryEnum, PendingMessageCountDTO>> getTodosSimpleCount(@RequestBody @Valid GetTodoCountRequest request);
@PostMapping(value = "/pending-message/record/get-todos-simple/page", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Page<PendingMessageSimpleDTO>> getTodosSimplePage(@RequestBody @Valid GetTodoPageRequest request);
}

View File

@ -0,0 +1,40 @@
package cn.axzo.msg.center.service.pending.request;
import cn.axzo.msg.center.service.enums.BizFinalStateEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.validation.constraints.NotEmpty;
import java.util.List;
@Data
@Slf4j
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CompletePendingMessageByCodesRequest {
/**
* 待办IdentityCode列表
*/
@NotEmpty
private List<String> identityCodes;
/**
* 整个流程是否完结审批待办完结后传true
*/
private Boolean finalStatus;
/**
* 业务终态的状态枚举
*/
private BizFinalStateEnum bizFinalStateEnum;
public boolean determineUpdateFinalBizState() {
return finalStatus != null && finalStatus && bizFinalStateEnum != null;
}
}

View File

@ -0,0 +1,32 @@
package cn.axzo.msg.center.service.pending.request;
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
import com.alibaba.fastjson.JSON;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Set;
@Setter
@Getter
public class GetTodoCountRequest {
private BizCategoryEnum bizCategory;
private Set<String> identityCodes;
private Set<String> templateCodes;
private Set<String> bizCodes;
private List<Executor> executors;
@Setter
@Getter
public static class Executor {
private Long ouId;
private Long workspaceId;
private List<Long> personIds;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}

View File

@ -0,0 +1,71 @@
package cn.axzo.msg.center.service.pending.request;
import cn.axzo.basics.common.page.PageRequest;
import cn.axzo.maokai.common.enums.OrgUserStatusEnum;
import cn.axzo.msg.center.service.enums.AppTerminalTypeEnum;
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import javax.validation.constraints.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GetTodoPageRequest extends PageRequest {
private TerminalTypeEnum terminalType;
private AppTerminalTypeEnum appTerminalType;
private String titleLike;
private BizCategoryEnum bizCategory;
private Set<String> identityCodes;
private Set<String> templateCodes;
private Set<String> bizCodes;
private Set<PendingMessageStateEnum> states;
private List<GetTodoPageRequest.Executor> executors;
/**
* 代办消息的分类结点编码, 单个节点. groupNodeCodes的优先级高于groupNodeCode
*/
private String groupNodeCode;
/**
* 代办消息的分类结点编码, 支持多个节点. groupNodeCodes的优先级高于groupNodeCode
*/
private Collection<String> groupNodeCodes;
@NotNull
public Collection<String> determineGroupNodeCodes() {
if (CollectionUtils.isNotEmpty(groupNodeCodes)) {
return groupNodeCodes;
}
if (StringUtils.isNotBlank(groupNodeCode)) {
return Collections.singletonList(groupNodeCode);
}
return Collections.emptyList();
}
@Setter
@Getter
public static class Executor {
private Long ouId;
private Long workspaceId;
private List<Long> personIds;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}

View File

@ -1,5 +1,6 @@
package cn.axzo.msg.center.service.pending.request;
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
import com.alibaba.fastjson.JSON;
import lombok.Getter;
@ -14,6 +15,7 @@ import java.util.Set;
@Setter
@Getter
public class GetTodoRequest {
private BizCategoryEnum bizCategory;
private Set<String> identityCodes;
private Set<String> templateCodes;
private Set<String> bizCodes;

View File

@ -157,6 +157,13 @@ public class PendingMessagePageRequest extends PageRequest implements ClientRequ
private String analysisToken;
private AnalysisInfo a = new AnalysisInfo();
@SuppressWarnings({"unused", "log purpose"})
public String getSearchByTitle() {
if (StringUtils.isBlank(title))
return null;
return "yes_search_by_title";
}
public boolean determineQueryTemplateTerminals() {
return queryTemplateTerminals != null && queryTemplateTerminals;
}

View File

@ -3,7 +3,6 @@ package cn.axzo.msg.center.service.pending.request;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@ -17,19 +16,19 @@ public class TodoHandoverRequest {
/**
* 交接来源自然人id
*/
@NotNull(message = "fromPersonId is required")
@Deprecated
private Long fromPersonId;
/**
* 交接来源人自然人姓名
*/
@NotBlank(message = "fromPersonName is required")
@Deprecated
private String fromPersonName;
/**
* 交接来源单位id
*/
@NotNull(message = "fromOuId is required")
@Deprecated
private Long fromOuId;
/**
@ -46,9 +45,18 @@ public class TodoHandoverRequest {
/**
* 交接目标单位id
*/
@NotNull(message = "toOuId is required")
private Long toOuId;
/**
* 交接工作台id
*/
private Long toWorkspaceId;
/**
* 操作人id
*/
private String operatePersonId;
/**
* 需要转交的待办编码
*/

View File

@ -20,6 +20,7 @@ public class WorkflowSyncButtonsRequest {
@Setter
@Getter
public static class WorkflowButton {
private String name;
private String code;
private RouterCategoryEnum category;
private String url;

View File

@ -0,0 +1,32 @@
package cn.axzo.msg.center.service.pending.response;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class PendingMessageCountDTO {
private Integer count = 0;
private List<SinglePendingDto> dtos = new ArrayList<>();
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public static final class SinglePendingDto {
private String identityCode;
private String templateCode;
private Long executePersonId;
private Long ouId;
private Long workspaceId;
}
}

View File

@ -133,4 +133,10 @@ public class PendingMessageSimpleDTO {
* 最终失败原因
*/
private String failCause;
/**
* 发起时间
*/
private Date createAt;
}

View File

@ -39,7 +39,7 @@ public class ParsedButtonV3 implements MessageButton {
/**
* 预设按钮类型
*/
private PresetButtonType presetBtnType;
private PresetButtonType presetButtonType;
/**
* 按钮来源

View File

@ -40,6 +40,15 @@ public class TodoDao extends ServiceImpl<TodoMapper, Todo> {
.list();
}
public List<Todo> getByBusinessIds(List<Long> businessIds) {
if (CollectionUtils.isEmpty(businessIds))
return Collections.emptyList();
return lambdaQuery()
.in(Todo::getTodoBusinessId, businessIds)
.eq(Todo::getIsDelete, TableIsDeleteEnum.NORMAL.value)
.list();
}
public List<Todo> getToBeDone(Long personId, @Nullable Long ouId) {
return lambdaQuery()
.eq(Todo::getExecutorPersonId, personId)
@ -81,7 +90,7 @@ public class TodoDao extends ServiceImpl<TodoMapper, Todo> {
public List<Todo> getByIdentityCodes(List<String> identityCodes) {
return lambdaQuery()
.eq(Todo::getIdentityCode, identityCodes)
.in(Todo::getIdentityCode, identityCodes)
.eq(Todo::getIsDelete, TableIsDeleteEnum.NORMAL.value)
.list();
}

View File

@ -134,7 +134,12 @@ public class AliYunSmsClientImpl implements AliYunSmsClient {
log.info("[mns <- aliyun]AliyunSmsService.sendSms response is {}", JSON.toJSONString(aliyunRequest));
SendSmsResponse response;
try {
response = client.sendSms(aliyunRequest);
RuntimeOptions options = new RuntimeOptions();
options.autoretry = true;
options.backoffPolicy = "yes";
// 每次重试间隔2秒
options.backoffPeriod = 2000;
response = client.sendSmsWithOptions(aliyunRequest, options);
log.info("[mns <- aliyun]AliyunSmsService.sendSms response is {}", JSON.toJSONString(response));
} catch (Exception e) {
LogUtil.error("[mns <- aliyun]AliyunSmsService.sendSms is fail", e);