Merge remote-tracking branch 'refs/remotes/origin/REQ-2324' into feature/merged_all_req

# Conflicts:
#	inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/PendingMessagePushParam.java
#	msg-center-api/src/main/java/cn/axzo/msg/center/service/pending/request/PendingMessagePushRequest.java
#	msg-center-api/src/main/java/cn/axzo/msg/center/service/pending/response/PendingMessageResponse.java
This commit is contained in:
yangqicheng 2024-05-23 09:50:49 +08:00
commit f24683c368
19 changed files with 212 additions and 16 deletions

5
changelog/REQ-2324.md Normal file
View File

@ -0,0 +1,5 @@
# DDL
```mysql
ALTER TABLE todo
ADD support_batch_process VARCHAR(10) DEFAULT 'NO' NOT NULL COMMENT '是否支持批量处理. YES: 支持, NO: 不支持';
```

View File

@ -42,18 +42,19 @@ import cn.hutool.core.date.StopWatch;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @description
*
* @author cold_blade
* @date 2023/10/5
* @version 1.0
* @description
* @date 2023/10/5
*/
@Slf4j
@RestController
@ -194,6 +195,12 @@ public class PendingMessageNewController implements PendingMessageClient {
return CommonResponse.success(todoManager.completeBySubBizCode(param));
}
@Override
public CommonResponse<Boolean> rollbackTemplateCodeSubBizCode(@RequestBody @Valid CompletePendingBySubCodeRequest param) {
log.info("rollbackByTemplateCodeSubBizCode, request={}", JSON.toJSONString(param));
return CommonResponse.success(todoManager.rollbackBySubBizCode(param));
}
@Override
public CommonResponse<Boolean> revokeByTemplateCodeBizCode(CompletePendingMessageRequest param) {
log.info("revokeByTemplateCodeBizCode, request={}", JSON.toJSONString(param));
@ -230,6 +237,18 @@ public class PendingMessageNewController implements PendingMessageClient {
}
}
@Override
public CommonResponse<Boolean> batchSetProcessing(List<String> identityCodes) {
log.info("setProcessing, request={}", JSON.toJSONString(identityCodes));
Boolean result = null;
try {
result = todoManager.batchSetProcessing(identityCodes);
return CommonResponse.success(result);
} finally {
log.info("setProcessing. request={}, response={}", identityCodes, result);
}
}
@Override
public CommonResponse<Boolean> firePresetButtonPressed(PresetButtonPressedRequest req) {
log.info("firePresetButtonPressed, request={}", JSON.toJSONString(req));

View File

@ -1,10 +1,12 @@
package cn.axzo.msg.center.message.domain.dto;
import cn.axzo.msg.center.domain.entity.MessageBaseTemplate;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateRouterDTO.MessageRouteButtonDTO;
import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
import cn.axzo.msg.center.service.enums.BizDetailJumpStrategyEnum;
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
import cn.axzo.msg.center.service.enums.PushTerminalEnum;
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
import cn.axzo.msg.center.utils.JSONObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
@ -13,6 +15,7 @@ import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.collections.CollectionUtils;
import java.io.Serializable;
import java.util.List;
@ -97,6 +100,15 @@ public class MessageTemplateDTO implements Serializable {
private JSONObject pushData;
public boolean hasPresetButtons() {
List<MessageRouteButtonDTO> buttons = msgTemplateRouter.getRouteButtons();
if (CollectionUtils.isEmpty(buttons)) {
return false;
}
return buttons.stream()
.anyMatch(btn -> btn.getCategory() == RouterCategoryEnum.PRESET_BUTTON);
}
public boolean isCardJumpToBiz() {
if (msgTemplateRouter == null) {
return false;

View File

@ -12,6 +12,7 @@ import lombok.Setter;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* @description
@ -48,6 +49,10 @@ public class MessageGroupNodeStatisticParam implements Serializable {
* false:
*/
private Boolean withIdentify;
/**
* 项目部id列表
*/
private List<Long> workspaceIds;
public Long getPersonId() {
return getOperator().getId();

View File

@ -5,6 +5,7 @@ import cn.axzo.msg.center.api.custombutton.ProposedButtons;
import cn.axzo.msg.center.api.request.v3.PendingSendInfo;
import cn.axzo.msg.center.service.dto.PersonDTO;
import cn.axzo.msg.center.service.enums.OrganizationTypeEnum;
import cn.axzo.msg.center.service.enums.YesOrNo;
import cn.axzo.msg.center.service.pending.request.PendingMessagePushRequest;
import cn.axzo.msg.center.service.util.JSONUtils;
import com.alibaba.fastjson.JSON;
@ -79,6 +80,11 @@ public class PendingMessagePushParam extends PendingSendInfo implements Serializ
*/
private String routerParams;
/**
* 是否支持批量处理
*/
private YesOrNo supportBatchProcess;
/**
* 提前设定的按钮
*/

View File

@ -136,6 +136,8 @@ public class TodoRangeQueryService {
// 查询的待办类型: COPIED_TO_ME, EXECUTABLE
.eq(Todo::getType, request.determineToDoType())
.eq(Todo::getExecutorPersonId, request.getPersonId())
//判断是否支持批量过滤
.eq(request.getSupportBatchProcess() != null, Todo::getSupportBatchProcess, request.getSupportBatchProcess())
// like search
.and(StringUtils.isNotBlank(request.getTitle()), nested -> nested
.like(Todo::getTitle, request.getTitle())
@ -299,6 +301,7 @@ public class TodoRangeQueryService {
LambdaQueryWrapper<Todo> query = todoQuery(ouInfo)
.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))

View File

@ -17,6 +17,8 @@ import org.springframework.stereotype.Component;
import java.security.SecureRandom;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;
@ -95,10 +97,11 @@ public class NodeStatCache {
private static String buildCacheKey(MessageGroupNodeStatisticParam request) {
StringBuffer buf = new StringBuffer();
buf.append("msg-center:node-stat:v2");
buf.append("msg-center:node-stat:v3");
Consumer<Object> appender = value -> {
if (value != null)
if (value != null) {
buf.append(":").append(value);
}
};
appender.accept(request.getPersonId());
appender.accept(request.getOuId());
@ -112,6 +115,14 @@ public class NodeStatCache {
.sorted()
.forEach(appender);
}
List<Long> workspaceIds = request.getWorkspaceIds();
if (CollectionUtils.isNotEmpty(workspaceIds)) {
workspaceIds.stream()
.filter(Objects::nonNull)
.distinct()
.sorted()
.forEach(appender);
}
return buf.toString();
}

View File

@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapp
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import lombok.Getter;
import java.util.stream.Stream;
/**
* @author yanglin
*/
@ -41,6 +43,24 @@ class StateAdvanceBuilder {
return this;
}
StateAdvanceBuilder in(SFunction<Todo, ?> column, Object... values) {
query.in(column, values);
update.in(column, values);
boolean statePresent = Stream.of(values).anyMatch(v -> v instanceof PendingMessageStateEnum);
if (!statePresent)
noStateQuery.in(column, values);
return this;
}
StateAdvanceBuilder in(boolean condition, SFunction<Todo, ?> column, Object... values) {
query.in(condition, column, values);
update.in(condition, column, values);
boolean statePresent = Stream.of(values).anyMatch(v -> v instanceof PendingMessageStateEnum);
if (!statePresent)
noStateQuery.in(condition, column, values);
return this;
}
StateAdvanceBuilder set(SFunction<Todo, ?> column, Object val) {
update.set(column, val);
return this;

View File

@ -40,6 +40,16 @@ class TodoLogger {
logTodosUpdated(ctx, todos);
}
void logSetTodoProcessing(TodoRequestContext ctx, List<Todo> todos) {
ctx.addLogContent("state", PendingMessageStateEnum.PROCESSING);
logTodosUpdated(ctx, todos);
}
void logTodoRollback(TodoRequestContext ctx, List<Todo> todos) {
ctx.addLogContent("state", PendingMessageStateEnum.HAS_BEEN_SENT);
logTodosUpdated(ctx, todos);
}
void logTodoRevoked(TodoRequestContext ctx, List<Todo> todos) {
ctx.addLogContent("state", PendingMessageStateEnum.RETRACT);
logTodosUpdated(ctx, todos);

View File

@ -17,8 +17,10 @@ import cn.axzo.msg.center.message.service.todo.manage.event.NewTodoEvent;
import cn.axzo.msg.center.mq.MqMessageRecord;
import cn.axzo.msg.center.mq.MqMessageType;
import cn.axzo.msg.center.mq.MqProducer;
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
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.CompletePendingMessageByIdRequest;
import cn.axzo.msg.center.service.pending.request.CompletePendingMessageRequest;
@ -32,6 +34,7 @@ import cn.axzo.msg.center.service.util.JSONUtils;
import cn.axzo.msg.center.utils.DateFormatUtil;
import cn.axzo.msg.center.utils.QueryFormatter;
import cn.axzo.msg.center.utils.UUIDUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.google.common.base.Supplier;
@ -126,6 +129,13 @@ public class TodoManager {
log.warn("Found duplicated business. Found business={}, request={}", business, request, e);
}
}
//批量默认为false
YesOrNo supportBatchProcess = request.getSupportBatchProcess() == null ? YesOrNo.NO : request.getSupportBatchProcess();
//业务待办设置是否批量处理
if (template.getMsgCategory() == MessageCategoryEnum.BIZ_PENDING_MESSAGE
&& template.hasPresetButtons())
supportBatchProcess = YesOrNo.YES;
request.setSupportBatchProcess(supportBatchProcess);
List<Todo> todos = todoRecordBuilder.buildTodos(
request, ctx.getRequestNo(), ext, business);
todoDao.saveBatch(todos);
@ -262,6 +272,24 @@ public class TodoManager {
return true;
}
/**
* 恢复待办
*/
@Transactional(rollbackFor = Exception.class)
public boolean rollbackBySubBizCode(CompletePendingBySubCodeRequest request) {
TodoRequestContext ctx = TodoRequestContext.create("rollbackBySubBizCode", request);
StateAdvanceResult advanceResult = advanceState(ctx, execAdvanceBuilder()
.eq(Todo::getTemplateCode, request.getTemplateCode())
.eq(Todo::getBizCode, request.getBizCode())
.eq(Todo::getSubBizCode, request.getSubBizCode())
.set(Todo::getState, PendingMessageStateEnum.HAS_BEEN_SENT));
if (!advanceResult.isAdvanced()) {
return false;
}
todoLogger.logTodoRollback(ctx, advanceResult.getAdvancedTodos());
return true;
}
// !! revoke
/**
@ -354,6 +382,22 @@ public class TodoManager {
return updated;
}
/**
* 将待办设置为执行中
*/
@Transactional(rollbackFor = Exception.class)
public Boolean batchSetProcessing(List<String> identityCodes) {
log.info("batch set processing...,request:{}", JSONUtil.toJsonStr(identityCodes));
BizAssertions.assertTrue(CollectionUtils.isNotEmpty(identityCodes), "identityCodes列表不能为空");
Boolean updated = todoDao.batchSetExecutableProcessing(identityCodes);
if (updated) {
List<Todo> updatedTodos = todoDao.getByIdentityCodes(identityCodes);
TodoRequestContext ctx = TodoRequestContext.create("batchSetProcessing", identityCodes);
todoLogger.logSetTodoProcessing(ctx, updatedTodos);
}
return updated;
}
/**
* 更新待办的内容
*/
@ -531,7 +575,9 @@ public class TodoManager {
return new StateAdvanceBuilder(todoDao)
.set(Todo::getHideUntil, null)
.eq(Todo::getType, TodoType.EXECUTABLE)
.eq(Todo::getState, PendingMessageStateEnum.HAS_BEEN_SENT)
.in(Todo::getState,
PendingMessageStateEnum.HAS_BEEN_SENT,
PendingMessageStateEnum.PROCESSING)
.eq(Todo::getIsDelete, TableIsDeleteEnum.NORMAL.value);
}

View File

@ -108,6 +108,7 @@ class TodoRecordBuilder {
todo.setBizDesc(request.getBizDesc());
todo.setIsOuIdMigrated(YesOrNo.NO);
todo.setHideUntil(null);
todo.setSupportBatchProcess(request.getSupportBatchProcess());
todo.setState(request.determineTodoType() == TodoType.COPIED_TO_ME
? PendingMessageStateEnum.CREATED
: PendingMessageStateEnum.HAS_BEEN_SENT);

View File

@ -25,6 +25,7 @@ public enum PendingMessageStateEnum implements CodeDefinition<String> {
RETRACT(6, "已撤回"),
DELETED(7, "已删除"),
READ(8, "已读"),
PROCESSING(9, "处理中")
;
private final Integer deprecatedCode;

View File

@ -228,6 +228,15 @@ public interface PendingMessageClient {
@PostMapping(value = "/pending-message/complete/by-sub-biz-code", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Boolean> completeByTemplateCodeSubBizCode(@RequestBody @Valid CompletePendingBySubCodeRequest param);
/**
* 通过模版编号和业务编号和子业务编号恢复代办
*
* @param param
* @return
*/
@PostMapping(value = "/pending-message/rollback/by-sub-biz-code", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Boolean> rollbackTemplateCodeSubBizCode(@RequestBody @Valid CompletePendingBySubCodeRequest param);
/**
* 通过模版编号和业务编号撤销代办
*
@ -261,6 +270,12 @@ public interface PendingMessageClient {
@PostMapping(value = "/pending-message/update/setHide", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Boolean> setHide(@RequestBody @Valid SetHideRequest req);
/**
* 批量将待办设置为处理中
*/
@PostMapping(value = "/pending-message/update/batchSetProcessing", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Boolean> batchSetProcessing(@RequestBody @Valid List<String> identityCodes);
/**
* 通过BizCode获取最新代办
*

View File

@ -10,6 +10,7 @@ import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
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.enums.YesOrNo;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.Getter;
@ -136,6 +137,11 @@ public class PendingMessagePageRequest extends PageRequest implements Serializab
*/
private TodoQueryType queryType;
/**
* 是否支持批量处理
*/
private YesOrNo supportBatchProcess;
// !! 用于排查问题
private String analysisToken;
private String todoCode;

View File

@ -6,6 +6,7 @@ import cn.axzo.msg.center.service.enums.BizCategoryEnum;
import cn.axzo.msg.center.service.enums.BizFinalStateEnum;
import cn.axzo.msg.center.service.enums.OrganizationTypeEnum;
import cn.axzo.msg.center.service.enums.TodoType;
import cn.axzo.msg.center.service.enums.YesOrNo;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -131,6 +132,11 @@ public class PendingMessagePushRequest implements Serializable {
*/
private ProposedButtons proposedButtons;
/**
* 是否支持批量处理
*/
private YesOrNo supportBatchProcess;
@Override
public String toString() {
return JSON.toJSONString(this);

View File

@ -9,13 +9,13 @@ import lombok.Setter;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
/**
* @description
*
* @author cold_blade
* @date 2023/9/23
* @version 1.0
* @description
* @date 2023/9/23
*/
@Setter
@Getter
@ -49,6 +49,11 @@ public class PendingMessageStatisticRequest implements Serializable {
*/
private AppTerminalTypeEnum terminalType;
/**
* 项目部id列表
*/
private List<Long> workspaceIds;
@Override
public String toString() {
return JSON.toJSONString(this);

View File

@ -27,11 +27,10 @@ import java.util.Date;
import java.util.List;
/**
* @description
* 代办消息记录页面展示数模型
* @author cold_blade
* @date 2023/9/23
* @version 1.0
* @description 代办消息记录页面展示数模型
* @date 2023/9/23
*/
@Setter
@Getter
@ -219,13 +218,18 @@ public class PendingMessageResponse implements Serializable, TodoButtonProvider
/**
* 查询类型
* HAS_BEEN_SENT: 待处理
* COMPLETED: 已处理
* SEND_BY_ME: 我发起
* COPIED_TO_ME: 抄送我
* HAS_BEEN_SENT: 待处理
* COMPLETED: 已处理
* SEND_BY_ME: 我发起
* COPIED_TO_ME: 抄送我
*/
private TodoQueryType queryType;
/**
* 业务类型
*/
private BizCategoryEnum bizCategoryEnum;
/**
* 自定义按钮
*/

View File

@ -49,6 +49,13 @@ public class TodoDao extends ServiceImpl<TodoMapper, Todo> {
.list();
}
public List<Todo> getByIdentityCodes(List<String> identityCodes) {
return lambdaQuery()
.eq(Todo::getIdentityCode, identityCodes)
.eq(Todo::getIsDelete, TableIsDeleteEnum.NORMAL.value)
.list();
}
public Optional<Todo> getLatestByBiz(
@Nullable String templateCode, String bizCode, String subBizCode, TodoType todoType) {
if (StringUtils.isBlank(bizCode) && StringUtils.isBlank(subBizCode))
@ -98,6 +105,15 @@ public class TodoDao extends ServiceImpl<TodoMapper, Todo> {
return new SampleTodos(todos);
}
public Boolean batchSetExecutableProcessing(List<String> identityCodes) {
return lambdaUpdate()
.eq(Todo::getType, TodoType.EXECUTABLE)
.in(Todo::getIdentityCode, identityCodes)
.in(Todo::getState, PendingMessageStateEnum.HAS_BEEN_SENT, PendingMessageStateEnum.PROCESSING)
.set(Todo::getState, PendingMessageStateEnum.PROCESSING)
.update();
}
public boolean setExecutableHide(String subBizCode, Date expireTime) {
return lambdaUpdate()
.eq(Todo::getType, TodoType.EXECUTABLE)

View File

@ -147,6 +147,11 @@ public class Todo extends BaseEntityExt<Todo> {
*/
private YesOrNo isOuIdMigrated;
/**
* 是否支持批量处理
*/
private YesOrNo supportBatchProcess;
/**
* 保存额外的数据信息
*/