Merge branch 'feature/REQ-3502'
This commit is contained in:
commit
40754a7bd0
@ -21,6 +21,10 @@
|
|||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.axzo.workflow</groupId>
|
||||||
|
<artifactId>workflow-engine-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.axzo.org</groupId>
|
<groupId>cn.axzo.org</groupId>
|
||||||
<artifactId>org-api</artifactId>
|
<artifactId>org-api</artifactId>
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
package cn.axzo.msg.center.event.card;
|
|
||||||
|
|
||||||
import cn.axzo.framework.rocketmq.Event;
|
|
||||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
|
||||||
import cn.axzo.framework.rocketmq.EventHandler;
|
|
||||||
import cn.axzo.msg.center.api.mq.CardPresetButtonPressedMessage;
|
|
||||||
import cn.axzo.msg.center.message.service.todo.TodoWithCardWrapper;
|
|
||||||
import cn.axzo.msg.center.message.service.todo.manage.TodoManager;
|
|
||||||
import cn.axzo.msg.center.notices.common.constans.CommonConstants;
|
|
||||||
import cn.axzo.msg.center.service.enums.MqMessageType;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author xudawei@axzo.cn
|
|
||||||
* @date 2024/11/07
|
|
||||||
* @desc 卡片预设MQ消费
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class CardChangeStateSyncTodoEventHandler implements EventHandler, InitializingBean {
|
|
||||||
|
|
||||||
private final EventConsumer eventConsumer;
|
|
||||||
|
|
||||||
private final TodoWithCardWrapper todoWithCardWrapper;
|
|
||||||
|
|
||||||
private final TodoManager todoManager;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(Event event, EventConsumer.Context context) {
|
|
||||||
if (!MqMessageType.CARD_PRESET_BUTTON_PRESSED.getEventName().equalsIgnoreCase(event.getEventCode().getName())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("CardChangeStateSyncTodoEventHandler-start - handle mq event, event={}", JSON.toJSONString(event));
|
|
||||||
try {
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
handleMqMessage(event);
|
|
||||||
long end = System.currentTimeMillis();
|
|
||||||
log.warn("CardChangeStateSyncTodoEventHandler-handle mq event, used={}ms, event={}", end - start, JSON.toJSONString(event));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("CardChangeStateSyncTodoEventHandler-error - handle mq event, event={}", JSON.toJSONString(event), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 业务逻辑
|
|
||||||
*/
|
|
||||||
private void handleMqMessage(Event event) {
|
|
||||||
//解析数据
|
|
||||||
CardPresetButtonPressedMessage payload = event.normalizedData(CardPresetButtonPressedMessage.class);
|
|
||||||
if (Objects.isNull(payload)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Objects.isNull(payload.getCardInfo())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!CommonConstants.TODO_SYSN_CARD_APP_CODE.equalsIgnoreCase(payload.getCardInfo().getAppCode())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Long operatorId = Objects.nonNull(payload.getOperatorId()) ? payload.getOperatorId() : 0L;
|
|
||||||
todoWithCardWrapper.fireTodoWhenPresetButtonPressedByCard(todoManager, payload.getPresetButtonType(), payload.getCardInfo(), operatorId);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() {
|
|
||||||
Event.EventCode eventCode = new Event.EventCode(MqMessageType.CARD_PRESET_BUTTON_PRESSED.getEventModel(), MqMessageType.CARD_PRESET_BUTTON_PRESSED.getEventName());
|
|
||||||
eventConsumer.registerHandler(eventCode, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -135,6 +135,12 @@ public class PushYouMengMessageHandler implements EventHandler, InitializingBean
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MessageHistoryUpdatedPayload.MsgBody msgBody = messageBody.resolveMsgBody();
|
||||||
|
if (msgBody == null) {
|
||||||
|
log.warn("push-handler, 模板code:{}, msgBody为空 [不是普通消息], event: {}", card.getTemplateCode(), event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
youMengMessageService.sendPushMessage(MsgBody4Guest.builder()
|
youMengMessageService.sendPushMessage(MsgBody4Guest.builder()
|
||||||
.ty(0)
|
.ty(0)
|
||||||
.f("0")
|
.f("0")
|
||||||
|
|||||||
@ -34,9 +34,9 @@ public class DiagnosisProps implements EnvironmentAware {
|
|||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
public static class RowCount {
|
public static class RowCount {
|
||||||
private int warningThreshold = 6000;
|
private int warningThreshold = 1500;
|
||||||
private boolean enable = true;
|
private boolean enable = true;
|
||||||
private int periodMaxWarnTimes = 3;
|
private int periodMaxWarnTimes = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For test purpose
|
* For test purpose
|
||||||
|
|||||||
@ -173,6 +173,15 @@ public class PendingMessageBizConfig {
|
|||||||
@Getter
|
@Getter
|
||||||
private int todoTitleSearchMaxSize = 5000;
|
private int todoTitleSearchMaxSize = 5000;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private boolean enableTodoLog = true;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private String workflowIMChannelAppMinVersionCmp = "";
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private String workflowIMChannelAppMinVersionCm = "";
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private boolean requestReplayWindowEnabled = true;
|
private boolean requestReplayWindowEnabled = true;
|
||||||
|
|
||||||
|
|||||||
@ -302,15 +302,9 @@ public class PendingMessageNewController implements PendingMessageClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public CommonResponse<Boolean> setHide(SetHideRequest req) {
|
public CommonResponse<Boolean> setHide(SetHideRequest req) {
|
||||||
log.info("setHide, request={}", JSON.toJSONString(req));
|
return CommonResponse.success(true);
|
||||||
Boolean response = null;
|
|
||||||
try {
|
|
||||||
response = todoManager.setHide(req);
|
|
||||||
return CommonResponse.success(response);
|
|
||||||
} finally {
|
|
||||||
log.info("setHide. request={}, response={}", req, response);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import cn.axzo.msg.center.service.domain.UrlConfig;
|
|||||||
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
|
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
|
||||||
import cn.axzo.msg.center.service.enums.RouterButtonSourceEnum;
|
import cn.axzo.msg.center.service.enums.RouterButtonSourceEnum;
|
||||||
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
|
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
|
||||||
|
import cn.axzo.msg.center.service.enums.WebPageOpenStrategy;
|
||||||
import cn.axzo.msg.center.service.pending.client.WorkflowButtonSyncClient;
|
import cn.axzo.msg.center.service.pending.client.WorkflowButtonSyncClient;
|
||||||
import cn.axzo.msg.center.service.pending.request.WorkflowSyncButtonsRequest;
|
import cn.axzo.msg.center.service.pending.request.WorkflowSyncButtonsRequest;
|
||||||
import cn.axzo.msg.center.service.pending.request.WorkflowSyncButtonsRequest.WorkflowButton;
|
import cn.axzo.msg.center.service.pending.request.WorkflowSyncButtonsRequest.WorkflowButton;
|
||||||
@ -96,12 +97,14 @@ public class WorkflowButtonSyncClientController implements WorkflowButtonSyncCli
|
|||||||
if (button.getCategory() == RouterCategoryEnum.JUMP) {
|
if (button.getCategory() == RouterCategoryEnum.JUMP) {
|
||||||
UrlConfig urlConfig = new UrlConfig();
|
UrlConfig urlConfig = new UrlConfig();
|
||||||
urlConfig.setDefaultUrl(workflowButton.getUrl());
|
urlConfig.setDefaultUrl(workflowButton.getUrl());
|
||||||
|
urlConfig.setWebOpenStrategy(WebPageOpenStrategy.DRAWER);
|
||||||
update.setUrlConfig(urlConfig);
|
update.setUrlConfig(urlConfig);
|
||||||
update.setApiUrl("");
|
update.setApiUrl("");
|
||||||
} else {
|
} else {
|
||||||
String apiUrl = workflowButton.getUrl();
|
String apiUrl = workflowButton.getUrl();
|
||||||
if (apiUrl == null) apiUrl = "";
|
if (apiUrl == null) apiUrl = "";
|
||||||
update.setApiUrl(apiUrl);
|
update.setApiUrl(apiUrl);
|
||||||
|
update.setUrlConfig(new UrlConfig());
|
||||||
}
|
}
|
||||||
messageTemplateButtonV3Dao.updateById(update);
|
messageTemplateButtonV3Dao.updateById(update);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -175,18 +175,6 @@ public class MessageTemplateV3SaveOrUpdateParam implements Serializable {
|
|||||||
* 校验
|
* 校验
|
||||||
*/
|
*/
|
||||||
public void checkCreate() {
|
public void checkCreate() {
|
||||||
//1 流程待办,暂不能使用IM通道
|
|
||||||
switch (this.getMsgCategory()) {
|
|
||||||
case GENERAL_MESSAGE:
|
|
||||||
break;
|
|
||||||
case IM_MESSAGE_CARD:
|
|
||||||
break;
|
|
||||||
case BIZ_PENDING_MESSAGE:
|
|
||||||
break;
|
|
||||||
case APPROVAL_PENDING_MESSAGE:
|
|
||||||
boolean contains = CollectionUtils.isNotEmpty(this.getChannels()) && this.getChannels().contains(MessageChannel.IM);
|
|
||||||
BizAssertions.assertFalse(contains, "审批待办,暂不能使用IM通道");
|
|
||||||
}
|
|
||||||
//2 同一个预设按钮类型,只能有一个
|
//2 同一个预设按钮类型,只能有一个
|
||||||
if (CollectionUtils.isNotEmpty(this.getButtons())) {
|
if (CollectionUtils.isNotEmpty(this.getButtons())) {
|
||||||
Map<String, Set<PresetButtonType>> collect = this.getButtons().stream()
|
Map<String, Set<PresetButtonType>> collect = this.getButtons().stream()
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import cn.axzo.msg.center.service.domain.UrlConfig;
|
|||||||
import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
|
import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
|
||||||
import cn.axzo.msg.center.service.enums.ButtonStyleEnum;
|
import cn.axzo.msg.center.service.enums.ButtonStyleEnum;
|
||||||
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
||||||
|
import cn.axzo.msg.center.service.enums.RouterButtonSourceEnum;
|
||||||
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
|
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
|
||||||
import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
|
import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
|
||||||
import cn.axzo.msg.center.service.pending.card.domain.CardElementConfig;
|
import cn.axzo.msg.center.service.pending.card.domain.CardElementConfig;
|
||||||
@ -89,6 +90,12 @@ public class GeneralMessagePushVO implements Serializable {
|
|||||||
* 业务编码
|
* 业务编码
|
||||||
*/
|
*/
|
||||||
private String bizCode;
|
private String bizCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子业务编码
|
||||||
|
*/
|
||||||
|
private String subBizCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息发送时间戳
|
* 消息发送时间戳
|
||||||
*/
|
*/
|
||||||
@ -111,6 +118,8 @@ public class GeneralMessagePushVO implements Serializable {
|
|||||||
|
|
||||||
private Map<String, Object> debugInfo;
|
private Map<String, Object> debugInfo;
|
||||||
|
|
||||||
|
private Map<String, Object> extInfo;
|
||||||
|
|
||||||
public void addDebugInfo(String name, Object value) {
|
public void addDebugInfo(String name, Object value) {
|
||||||
if (debugInfo == null)
|
if (debugInfo == null)
|
||||||
debugInfo = new HashMap<>();
|
debugInfo = new HashMap<>();
|
||||||
@ -236,6 +245,11 @@ public class GeneralMessagePushVO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private UrlConfig urlConfig;
|
private UrlConfig urlConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按钮来源
|
||||||
|
*/
|
||||||
|
private RouterButtonSourceEnum source;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用api的地址. action=ACTION时, 消费这个字段
|
* 调用api的地址. action=ACTION时, 消费这个字段
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.card;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
public class CardExtInfo {
|
||||||
|
|
||||||
|
private final JSONObject extInfo;
|
||||||
|
|
||||||
|
public CardExtInfo(JSONObject bizParam) {
|
||||||
|
JSONObject extInfo = bizParam.getJSONObject("extInfo");
|
||||||
|
if (extInfo == null) {
|
||||||
|
extInfo = new JSONObject();
|
||||||
|
bizParam.put("extInfo", extInfo);
|
||||||
|
}
|
||||||
|
this.extInfo = extInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addExtInfo(String key, Object value) {
|
||||||
|
extInfo.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JSONObject getJsonObject() {
|
||||||
|
return extInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -135,7 +135,7 @@ public class CardManager {
|
|||||||
if (cardProps.isDeleteCardsWhenSendFail()) {
|
if (cardProps.isDeleteCardsWhenSendFail()) {
|
||||||
cardSupport.deleteCardIdempotent(request);
|
cardSupport.deleteCardIdempotent(request);
|
||||||
cardDao.deleteCards(sendModel.getCards());
|
cardDao.deleteCards(sendModel.getCards());
|
||||||
sendLogger.reloadAndLogCards("send:fail:deleteCards");
|
sendLogger.reloadAndLogCards("send:fail:deleteCards", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
throw MiscUtils.wrapException(e);
|
throw MiscUtils.wrapException(e);
|
||||||
@ -152,11 +152,9 @@ public class CardManager {
|
|||||||
public void updateState(CardUpdateStateRequest request) {
|
public void updateState(CardUpdateStateRequest request) {
|
||||||
request.validate();
|
request.validate();
|
||||||
TemplateModelV3 templateModel = cardSupport.ensureImChannelPresent(request.getTemplateCode());
|
TemplateModelV3 templateModel = cardSupport.ensureImChannelPresent(request.getTemplateCode());
|
||||||
boolean updated = false;
|
|
||||||
// 不要放到for里面去了
|
// 不要放到for里面去了
|
||||||
CardRequestContext<CardUpdateStateRequest> requestContext = CardRequestContext.create(request);
|
CardRequestContext<CardUpdateStateRequest> requestContext = CardRequestContext.create(request);
|
||||||
for (List<Card> cards : cardsCursor(request)) {
|
for (List<Card> cards : cardsCursor(request)) {
|
||||||
updated = true;
|
|
||||||
UpdateExecutor executor = new UpdateExecutor(requestContext, "updateState", templateModel, cards);
|
UpdateExecutor executor = new UpdateExecutor(requestContext, "updateState", templateModel, cards);
|
||||||
executor.update(card -> {
|
executor.update(card -> {
|
||||||
Card update = executor.createUpdate(card);
|
Card update = executor.createUpdate(card);
|
||||||
@ -165,10 +163,9 @@ public class CardManager {
|
|||||||
update.setBizState(request.getBizState());
|
update.setBizState(request.getBizState());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
BizAssertions.assertTrue(updated, "未找到任何需要更新的卡片, request={}", request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setActionPerformed(SetActionPerformedRequest request) {
|
public void setActionPerformed(SetActionPerformedRequest request) {
|
||||||
TemplateModelV3 templateModel = cardSupport.ensureImChannelPresent(request.getTemplateCode());
|
TemplateModelV3 templateModel = cardSupport.ensureImChannelPresent(request.getTemplateCode());
|
||||||
MessageTemplateButtonV3 button = templateModel.findButton(request.getButtonCode()).orElse(null);
|
MessageTemplateButtonV3 button = templateModel.findButton(request.getButtonCode()).orElse(null);
|
||||||
BizAssertions.assertNotNull(button, "找不到对应的按钮. buttonCode={}", request.getButtonCode());
|
BizAssertions.assertNotNull(button, "找不到对应的按钮. buttonCode={}", request.getButtonCode());
|
||||||
@ -194,11 +191,15 @@ public class CardManager {
|
|||||||
"卡片已是终状态, 无法'{}'", request.getPresetButtonType().getDesc());
|
"卡片已是终状态, 无法'{}'", request.getPresetButtonType().getDesc());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void firePresetButtonPressed(CardUpdatePresetButtonRequest request) {
|
public boolean firePresetButtonPressed(CardUpdatePresetButtonRequest request) {
|
||||||
TemplateModelV3 templateModel = cardSupport.ensureImChannelPresent(request.getTemplateCode());
|
TemplateModelV3 templateModel = cardSupport.ensureImChannelPresent(request.getTemplateCode());
|
||||||
CardRequestContext<CardUpdatePresetButtonRequest> requestContext = CardRequestContext.create(request);
|
CardRequestContext<CardUpdatePresetButtonRequest> requestContext = CardRequestContext.create(request);
|
||||||
for (List<Card> cards : cardsCursor(request))
|
boolean updated = false;
|
||||||
firePresetButtonPressedImpl(request, requestContext, templateModel, cards);
|
for (List<Card> cards : cardsCursor(request)) {
|
||||||
|
UpdateStateResult result = firePresetButtonPressedImpl(request, requestContext, templateModel, cards);
|
||||||
|
updated = result == UpdateStateResult.UPDATED || updated;
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UpdateStateResult firePresetButtonPressedImpl(
|
private UpdateStateResult firePresetButtonPressedImpl(
|
||||||
@ -214,8 +215,10 @@ public class CardManager {
|
|||||||
UpdateStateResult result = executor.update(new SetActionPerformedBuilder(
|
UpdateStateResult result = executor.update(new SetActionPerformedBuilder(
|
||||||
executor, button, CardBizState.fromPresetButton(request.getPresetButtonType())));
|
executor, button, CardBizState.fromPresetButton(request.getPresetButtonType())));
|
||||||
if (result == UpdateStateResult.UPDATED) {
|
if (result == UpdateStateResult.UPDATED) {
|
||||||
cardBroadcaster.firePresetButtonPressed(executor.updatedCards, request);
|
cardBroadcaster.firePresetButtonPressed(executor.updatedCards, request, requestContext);
|
||||||
executor.updateCardLogger.reloadAndLogCards("presetButtonPressed:mq:success");
|
executor.updateCardLogger.reloadAndLogCards("presetButtonPressed:mq:success");
|
||||||
|
} else {
|
||||||
|
executor.updateCardLogger.reloadAndLogCards("presetButtonPressed:cardNoUpdate");
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -251,7 +254,7 @@ public class CardManager {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rebuildCardContent(TemplateModelV3 templateModel, List<Card> cards) {
|
void rebuildCardContent(TemplateModelV3 templateModel, List<Card> cards) {
|
||||||
ArrayList<Card> updates = new ArrayList<>();
|
ArrayList<Card> updates = new ArrayList<>();
|
||||||
for (Card card : cardDao.reloadCards(cards)) {
|
for (Card card : cardDao.reloadCards(cards)) {
|
||||||
Card update = new Card();
|
Card update = new Card();
|
||||||
@ -261,9 +264,6 @@ public class CardManager {
|
|||||||
BizAssertions.assertTrue(cardTemplate.isUpdatable(),
|
BizAssertions.assertTrue(cardTemplate.isUpdatable(),
|
||||||
"模板不支持更新, templateCode={}", card.getTemplateCode());
|
"模板不支持更新, templateCode={}", card.getTemplateCode());
|
||||||
GeneralMessagePushVO cardContent = cardParser.parseCardContent(cardTemplate, card);
|
GeneralMessagePushVO cardContent = cardParser.parseCardContent(cardTemplate, card);
|
||||||
// 保留原来的title和content, 避免模版变了但缺少bizParam导致数据不完整
|
|
||||||
cardContent.setCardTitle(card.getTitle());
|
|
||||||
cardContent.setCardContent(card.getContent());
|
|
||||||
cardContent.addDebugInfo("bizCode", card.getBizCode());
|
cardContent.addDebugInfo("bizCode", card.getBizCode());
|
||||||
cardContent.addDebugInfo("subBizCode", card.getSubBizCode());
|
cardContent.addDebugInfo("subBizCode", card.getSubBizCode());
|
||||||
update.setCardContent(cardContent);
|
update.setCardContent(cardContent);
|
||||||
@ -301,6 +301,7 @@ public class CardManager {
|
|||||||
private class UpdateExecutor {
|
private class UpdateExecutor {
|
||||||
|
|
||||||
final CardLogger updateCardLogger;
|
final CardLogger updateCardLogger;
|
||||||
|
final CardRequestContext<?> requestContext;
|
||||||
final TemplateModelV3 templateModel;
|
final TemplateModelV3 templateModel;
|
||||||
final String operation;
|
final String operation;
|
||||||
final List<Card> cards;
|
final List<Card> cards;
|
||||||
@ -310,6 +311,7 @@ public class CardManager {
|
|||||||
UpdateExecutor(CardRequestContext<?> requestContext, String operation,
|
UpdateExecutor(CardRequestContext<?> requestContext, String operation,
|
||||||
TemplateModelV3 templateModel, List<Card> cards) {
|
TemplateModelV3 templateModel, List<Card> cards) {
|
||||||
this.updateCardLogger = cardLoggers.createLogger(requestContext);
|
this.updateCardLogger = cardLoggers.createLogger(requestContext);
|
||||||
|
this.requestContext = requestContext;
|
||||||
this.templateModel = templateModel;
|
this.templateModel = templateModel;
|
||||||
this.operation = operation;
|
this.operation = operation;
|
||||||
this.cards = cards;
|
this.cards = cards;
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import cn.axzo.msg.center.inside.notices.config.MessageSystemConfig;
|
|||||||
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
|
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
|
||||||
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO.CardButton;
|
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO.CardButton;
|
||||||
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO.CardExtensionItem;
|
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO.CardExtensionItem;
|
||||||
|
import cn.axzo.msg.center.message.service.card.interceptor.CardButtonInterceptor;
|
||||||
|
import cn.axzo.msg.center.message.service.card.interceptor.CardButtonInterceptorFactory;
|
||||||
import cn.axzo.msg.center.message.service.impl.v3.AppLink;
|
import cn.axzo.msg.center.message.service.impl.v3.AppLink;
|
||||||
import cn.axzo.msg.center.message.service.impl.v3.NativeAppLinkUrlConfigVisitor;
|
import cn.axzo.msg.center.message.service.impl.v3.NativeAppLinkUrlConfigVisitor;
|
||||||
import cn.axzo.msg.center.message.service.impl.v3.V3ExtPopulator;
|
import cn.axzo.msg.center.message.service.impl.v3.V3ExtPopulator;
|
||||||
@ -12,8 +14,8 @@ import cn.axzo.msg.center.service.domain.UrlConfigWalker;
|
|||||||
import cn.axzo.msg.center.service.enums.ButtonStyleEnum;
|
import cn.axzo.msg.center.service.enums.ButtonStyleEnum;
|
||||||
import cn.axzo.msg.center.service.enums.CardState;
|
import cn.axzo.msg.center.service.enums.CardState;
|
||||||
import cn.axzo.msg.center.service.enums.KVContentType;
|
import cn.axzo.msg.center.service.enums.KVContentType;
|
||||||
|
import cn.axzo.msg.center.service.enums.RouterButtonSourceEnum;
|
||||||
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
|
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
|
||||||
import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
|
|
||||||
import cn.axzo.msg.center.service.pending.card.domain.CardButtonStates;
|
import cn.axzo.msg.center.service.pending.card.domain.CardButtonStates;
|
||||||
import cn.axzo.msg.center.service.pending.card.domain.CardElementConfig;
|
import cn.axzo.msg.center.service.pending.card.domain.CardElementConfig;
|
||||||
import cn.axzo.msg.center.service.pending.request.CardContent;
|
import cn.axzo.msg.center.service.pending.request.CardContent;
|
||||||
@ -25,8 +27,9 @@ import cn.axzo.msg.center.service.pending.response.v3.model.ParsedGroupV3;
|
|||||||
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedKV;
|
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedKV;
|
||||||
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedTemplateV3;
|
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedTemplateV3;
|
||||||
import cn.axzo.msg.center.service.pending.response.v3.model.PersonInfo;
|
import cn.axzo.msg.center.service.pending.response.v3.model.PersonInfo;
|
||||||
import lombok.RequiredArgsConstructor;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -38,12 +41,23 @@ import java.util.List;
|
|||||||
* @author yanglin
|
* @author yanglin
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
|
||||||
class CardParser {
|
class CardParser {
|
||||||
|
|
||||||
private final MessageSystemConfig messageSystemConfig;
|
private final MessageSystemConfig messageSystemConfig;
|
||||||
private final V3ExtPopulator v3ExtPopulator;
|
private final V3ExtPopulator v3ExtPopulator;
|
||||||
private final CardProps cardProps;
|
private final CardProps cardProps;
|
||||||
|
private final CardButtonInterceptorFactory[] interceptorFactories;
|
||||||
|
|
||||||
|
CardParser(MessageSystemConfig messageSystemConfig,
|
||||||
|
V3ExtPopulator v3ExtPopulator,
|
||||||
|
CardProps cardProps,
|
||||||
|
ObjectProvider<CardButtonInterceptorFactory[]> interceptorFactoryProvider) {
|
||||||
|
this.messageSystemConfig = messageSystemConfig;
|
||||||
|
this.v3ExtPopulator = v3ExtPopulator;
|
||||||
|
this.cardProps = cardProps;
|
||||||
|
this.interceptorFactories = interceptorFactoryProvider
|
||||||
|
.getIfAvailable(() -> new CardButtonInterceptorFactory[0]);
|
||||||
|
}
|
||||||
|
|
||||||
GeneralMessagePushVO parseCardContent(CardTemplate cardTemplate, CardContent card) {
|
GeneralMessagePushVO parseCardContent(CardTemplate cardTemplate, CardContent card) {
|
||||||
ParsedTemplateV3 template = cardTemplate.getTemplate();
|
ParsedTemplateV3 template = cardTemplate.getTemplate();
|
||||||
@ -55,6 +69,8 @@ class CardParser {
|
|||||||
super.addDebugInfo(name, value);
|
super.addDebugInfo(name, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
bizBody.setBizCode(card.getBizCode());
|
||||||
|
bizBody.setSubBizCode(card.getSubBizCode());
|
||||||
bizBody.setCardStyleCode(template.getCardStyleCode());
|
bizBody.setCardStyleCode(template.getCardStyleCode());
|
||||||
bizBody.setTemplateCode(template.getCode());
|
bizBody.setTemplateCode(template.getCode());
|
||||||
bizBody.setCardBannerUrl(template.getIcon());
|
bizBody.setCardBannerUrl(template.getIcon());
|
||||||
@ -76,6 +92,7 @@ class CardParser {
|
|||||||
bizBody.addDebugInfo("bizState", stateInfo.getBizState());
|
bizBody.addDebugInfo("bizState", stateInfo.getBizState());
|
||||||
bizBody.addDebugInfo("cardState", stateInfo.getCardState());
|
bizBody.addDebugInfo("cardState", stateInfo.getCardState());
|
||||||
bizBody.addDebugInfo("isUpdatable", cardTemplate.isUpdatable());
|
bizBody.addDebugInfo("isUpdatable", cardTemplate.isUpdatable());
|
||||||
|
CardButtonInterceptor buttonInterceptor = getButtonInterceptor(card);
|
||||||
ParsedModelV3Walker.walkDown(cardTemplate.getParsedModel(), new ParsedModel3Visitor() {
|
ParsedModelV3Walker.walkDown(cardTemplate.getParsedModel(), new ParsedModel3Visitor() {
|
||||||
@Override
|
@Override
|
||||||
public void visitTemplateCardUrlConfig(UrlConfig urlConfig) {
|
public void visitTemplateCardUrlConfig(UrlConfig urlConfig) {
|
||||||
@ -113,16 +130,25 @@ class CardParser {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visitButton(ParsedButtonV3 button) {
|
public void visitButton(ParsedButtonV3 button) {
|
||||||
List<ButtonStyleEnum> styles = button.parseStyle();
|
if (bizBody.getCardButtons() != null
|
||||||
if (!styles.contains(ButtonStyleEnum.OVER_CARD))
|
&& bizBody.getCardButtons().size() >= cardProps.getMaxSendingCardButtonsCount())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
boolean isActionPerformed = CardButtonStates
|
Boolean isVisibleOnCard = buttonInterceptor
|
||||||
.create(card.getButtonStates())
|
.isVisibleOnCard(button)
|
||||||
.isButtonActionPerformed(button);
|
.orElse(() -> button.getStyles().contains(ButtonStyleEnum.OVER_CARD));
|
||||||
|
if (!isVisibleOnCard) return;
|
||||||
|
|
||||||
|
boolean isPerformActionAvailable = buttonInterceptor
|
||||||
|
.isPerformActionAvailable(button)
|
||||||
|
.orElse(button.isPerformActionAvailable());
|
||||||
|
Boolean isActionPerformed = buttonInterceptor
|
||||||
|
.isActionPerformed(button)
|
||||||
|
.orElse(CardButtonStates
|
||||||
|
.create(card.getButtonStates())
|
||||||
|
.isButtonActionPerformed(button));
|
||||||
if (card.getStateInfo().getCardState() == CardState.COMPLETED
|
if (card.getStateInfo().getCardState() == CardState.COMPLETED
|
||||||
&& button.isPerformActionAvailable()
|
&& isPerformActionAvailable
|
||||||
&& !isActionPerformed)
|
&& !isActionPerformed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -131,21 +157,23 @@ class CardParser {
|
|||||||
CardButton imButton = new CardButton();
|
CardButton imButton = new CardButton();
|
||||||
bizBody.getCardButtons().add(imButton);
|
bizBody.getCardButtons().add(imButton);
|
||||||
|
|
||||||
imButton.setTitle(isActionPerformed ? button.getActionPerformedName() : button.getName());
|
String actionPerformed = buttonInterceptor
|
||||||
|
.getActionPerformedName(button)
|
||||||
|
.orElse(button.getActionPerformedName());
|
||||||
|
imButton.setSource(button.getSource());
|
||||||
|
imButton.setTitle(isActionPerformed ? actionPerformed : button.getName());
|
||||||
imButton.setAction(button.getCategory().name());
|
imButton.setAction(button.getCategory().name());
|
||||||
imButton.setIsHighlight(styles.contains(ButtonStyleEnum.HIGH_LIGHT));
|
imButton.setIsHighlight(button.getStyles().contains(ButtonStyleEnum.HIGH_LIGHT));
|
||||||
imButton.setExecutorShow(button.getExecutorShow());
|
imButton.setSenderShow(buttonInterceptor.isSenderShow(button).orElse(false));
|
||||||
|
imButton.setExecutorShow(buttonInterceptor.isExecutorShow(button).orElse(button.getExecutorShow()));
|
||||||
imButton.setActionPerformed(isActionPerformed);
|
imButton.setActionPerformed(isActionPerformed);
|
||||||
|
boolean isSystemButton = button.getSource() == RouterButtonSourceEnum.SYSTEM;
|
||||||
if (button.getUrlConfig().hasUrl())
|
if (button.getUrlConfig().hasUrl())
|
||||||
imButton.setUrlConfig(button.getUrlConfig());
|
imButton.setUrlConfig(button.getUrlConfig());
|
||||||
imButton.setButtonCode(button.getCode());
|
imButton.setButtonCode(button.getCode());
|
||||||
imButton.setPresetButtonType(button.getPresetButtonType());
|
imButton.setPresetButtonType(button.getPresetButtonType());
|
||||||
imButton.setApiUrl(button.getApiUrl());
|
|
||||||
|
|
||||||
if (RouterCategoryEnum.ACTION.equals(button.getCategory())) {
|
if (button.getUrlConfig().hasUrl() && !isSystemButton) {
|
||||||
AppLink appLink = new AppLink(TerminalTypeEnum.WEB_VIEW.name(), button.getApiUrl());
|
|
||||||
imButton.setActionPaths(Collections.singletonList(appLink));
|
|
||||||
} else if (button.getUrlConfig().hasUrl()) {
|
|
||||||
imButton.setActionPaths(getNativeAppLinks(button.getUrlConfig()));
|
imButton.setActionPaths(getNativeAppLinks(button.getUrlConfig()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,6 +188,9 @@ class CardParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
JSONObject extInfo = new CardExtInfo(card.getBizParam()).getJsonObject();
|
||||||
|
if (!extInfo.isEmpty())
|
||||||
|
bizBody.setExtInfo(extInfo);
|
||||||
return bizBody;
|
return bizBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,4 +201,13 @@ class CardParser {
|
|||||||
return visitor.getLinks();
|
return visitor.getLinks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CardButtonInterceptor getButtonInterceptor(CardContent card) {
|
||||||
|
for (CardButtonInterceptorFactory factory : interceptorFactories) {
|
||||||
|
CardButtonInterceptor interceptor = factory.create(card);
|
||||||
|
if (interceptor != null)
|
||||||
|
return interceptor;
|
||||||
|
}
|
||||||
|
return CardButtonInterceptor.NOT_SURE;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -22,6 +22,8 @@ public class CardProps {
|
|||||||
private boolean deleteCardsWhenSendFail = true;
|
private boolean deleteCardsWhenSendFail = true;
|
||||||
private boolean enableCardIdempotent = true;
|
private boolean enableCardIdempotent = true;
|
||||||
private int updateCardBatchSize = 200;
|
private int updateCardBatchSize = 200;
|
||||||
|
// IM最多显示3个, 可能会存在仅发起人可见的按钮1个, 3 + 1 = 4, 避免消息超长
|
||||||
|
private int maxSendingCardButtonsCount = 4;
|
||||||
private Set<String> idempotentFreeTemplateCodes = new HashSet<>();
|
private Set<String> idempotentFreeTemplateCodes = new HashSet<>();
|
||||||
|
|
||||||
boolean isIdempotentFree(String templateCode) {
|
boolean isIdempotentFree(String templateCode) {
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package cn.axzo.msg.center.message.service.card;
|
package cn.axzo.msg.center.message.service.card;
|
||||||
|
|
||||||
import cn.axzo.basics.common.exception.ServiceException;
|
|
||||||
import cn.axzo.framework.jackson.utility.JSON;
|
import cn.axzo.framework.jackson.utility.JSON;
|
||||||
import cn.axzo.im.center.api.vo.PersonAccountAttribute;
|
import cn.axzo.im.center.api.vo.PersonAccountAttribute;
|
||||||
import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam;
|
import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam;
|
||||||
@ -11,10 +10,12 @@ import cn.axzo.msg.center.common.utils.BizAssertions;
|
|||||||
import cn.axzo.msg.center.dal.CardIdempotentDao;
|
import cn.axzo.msg.center.dal.CardIdempotentDao;
|
||||||
import cn.axzo.msg.center.domain.entity.Card;
|
import cn.axzo.msg.center.domain.entity.Card;
|
||||||
import cn.axzo.msg.center.domain.entity.CardIdempotent;
|
import cn.axzo.msg.center.domain.entity.CardIdempotent;
|
||||||
|
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
|
||||||
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
|
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
|
||||||
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
|
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
|
||||||
import cn.axzo.msg.center.message.service.card.domain.CardGroup;
|
import cn.axzo.msg.center.message.service.card.domain.CardGroup;
|
||||||
import cn.axzo.msg.center.message.service.card.domain.CardSendModel;
|
import cn.axzo.msg.center.message.service.card.domain.CardSendModel;
|
||||||
|
import cn.axzo.msg.center.message.service.card.exception.CardIdempotentException;
|
||||||
import cn.axzo.msg.center.message.service.impl.v3.ModelV3Parser;
|
import cn.axzo.msg.center.message.service.impl.v3.ModelV3Parser;
|
||||||
import cn.axzo.msg.center.message.service.impl.v3.ModelV3Service;
|
import cn.axzo.msg.center.message.service.impl.v3.ModelV3Service;
|
||||||
import cn.axzo.msg.center.message.service.impl.v3.UrlParser;
|
import cn.axzo.msg.center.message.service.impl.v3.UrlParser;
|
||||||
@ -23,6 +24,7 @@ import cn.axzo.msg.center.nimpush.device.PushDeviceSnapshots;
|
|||||||
import cn.axzo.msg.center.push.PushData;
|
import cn.axzo.msg.center.push.PushData;
|
||||||
import cn.axzo.msg.center.service.domain.card.AppVersionConfig;
|
import cn.axzo.msg.center.service.domain.card.AppVersionConfig;
|
||||||
import cn.axzo.msg.center.service.dto.PeerPerson;
|
import cn.axzo.msg.center.service.dto.PeerPerson;
|
||||||
|
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
|
||||||
import cn.axzo.msg.center.service.enums.MessageChannel;
|
import cn.axzo.msg.center.service.enums.MessageChannel;
|
||||||
import cn.axzo.msg.center.service.pending.request.CardContent;
|
import cn.axzo.msg.center.service.pending.request.CardContent;
|
||||||
import cn.axzo.msg.center.service.pending.request.CardSendRequest;
|
import cn.axzo.msg.center.service.pending.request.CardSendRequest;
|
||||||
@ -60,6 +62,7 @@ public class CardSupport {
|
|||||||
private final NimPushService nimPushService;
|
private final NimPushService nimPushService;
|
||||||
private final CardIdempotentDao cardIdempotentDao;
|
private final CardIdempotentDao cardIdempotentDao;
|
||||||
private final CardProps cardProps;
|
private final CardProps cardProps;
|
||||||
|
private final PendingMessageBizConfig cfg;
|
||||||
|
|
||||||
public static String getBizIdPrefix(String templateCode) {
|
public static String getBizIdPrefix(String templateCode) {
|
||||||
return IdBuilder.builder()
|
return IdBuilder.builder()
|
||||||
@ -82,7 +85,7 @@ public class CardSupport {
|
|||||||
cardIdempotentDao.save(idempotent);
|
cardIdempotentDao.save(idempotent);
|
||||||
} catch (DuplicateKeyException e) {
|
} catch (DuplicateKeyException e) {
|
||||||
log.warn("重复创建卡片, request={}", request);
|
log.warn("重复创建卡片, request={}", request);
|
||||||
throw new ServiceException(403, String.format("重复创建卡片: %s", idempotent));
|
throw new CardIdempotentException(403, String.format("重复创建卡片: %s", idempotent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,15 +181,22 @@ public class CardSupport {
|
|||||||
|
|
||||||
private String determineMinAppVersion(ParsedModelV3 model,
|
private String determineMinAppVersion(ParsedModelV3 model,
|
||||||
AppTypeEnum appType) {
|
AppTypeEnum appType) {
|
||||||
Ref<String> minVersion = Ref.create("");
|
Ref<String> ref = Ref.create("");
|
||||||
ParsedModelV3Walker.walkDown(model, new ParsedModel3Visitor() {
|
ParsedModelV3Walker.walkDown(model, new ParsedModel3Visitor() {
|
||||||
@Override
|
@Override
|
||||||
public void visitAppVersionConfig(AppVersionConfig cfg) {
|
public void visitAppVersionConfig(AppVersionConfig cfg) {
|
||||||
if (cfg.getAppType() == appType)
|
if (cfg.getAppType() == appType)
|
||||||
minVersion.set(cfg.getMinVersion());
|
ref.set(cfg.getMinVersion());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return minVersion.get();
|
String minVersion = ref.get();
|
||||||
|
if (StringUtils.isBlank(minVersion)
|
||||||
|
&& model.getTemplate().getMsgCategory() == MessageCategoryEnum.APPROVAL_PENDING_MESSAGE) {
|
||||||
|
return appType == AppTypeEnum.CMP
|
||||||
|
? cfg.getWorkflowIMChannelAppMinVersionCmp()
|
||||||
|
: cfg.getWorkflowIMChannelAppMinVersionCm();
|
||||||
|
}
|
||||||
|
return minVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateModelV3 ensureImChannelPresent(String templateCode) {
|
TemplateModelV3 ensureImChannelPresent(String templateCode) {
|
||||||
|
|||||||
@ -5,10 +5,12 @@ import cn.axzo.msg.center.api.mq.CardInfo;
|
|||||||
import cn.axzo.msg.center.api.mq.CardPresetButtonPressedMessage;
|
import cn.axzo.msg.center.api.mq.CardPresetButtonPressedMessage;
|
||||||
import cn.axzo.msg.center.dal.CardDao;
|
import cn.axzo.msg.center.dal.CardDao;
|
||||||
import cn.axzo.msg.center.domain.entity.Card;
|
import cn.axzo.msg.center.domain.entity.Card;
|
||||||
|
import cn.axzo.msg.center.message.service.card.CardRequestContext;
|
||||||
import cn.axzo.msg.center.mq.MqMessageRecord;
|
import cn.axzo.msg.center.mq.MqMessageRecord;
|
||||||
import cn.axzo.msg.center.mq.MqProducer;
|
import cn.axzo.msg.center.mq.MqProducer;
|
||||||
import cn.axzo.msg.center.service.enums.MqMessageType;
|
import cn.axzo.msg.center.service.enums.MqMessageType;
|
||||||
import cn.axzo.msg.center.service.pending.request.CardPresetButtonRequest;
|
import cn.axzo.msg.center.service.pending.request.CardPresetButtonRequest;
|
||||||
|
import cn.axzo.msg.center.service.util.IdBuilder;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -24,18 +26,25 @@ public class CardBroadcaster {
|
|||||||
private final CardDao cardDao;
|
private final CardDao cardDao;
|
||||||
private final MqProducer mqProducer;
|
private final MqProducer mqProducer;
|
||||||
|
|
||||||
public void firePresetButtonPressed(List<Card> cards, CardPresetButtonRequest request) {
|
public void firePresetButtonPressed(List<Card> cards,
|
||||||
|
CardPresetButtonRequest request,
|
||||||
|
CardRequestContext<?> requestContext) {
|
||||||
for (Card card : cardDao.reloadCards(cards)) {
|
for (Card card : cardDao.reloadCards(cards)) {
|
||||||
CardPresetButtonPressedMessage message = new CardPresetButtonPressedMessage();
|
CardPresetButtonPressedMessage message = new CardPresetButtonPressedMessage();
|
||||||
message.setPresetButtonType(request.getPresetButtonType());
|
message.setPresetButtonType(request.getPresetButtonType());
|
||||||
message.setOperatorId(request.getOperatorId());
|
message.setOperatorId(request.getOperatorId());
|
||||||
message.setOperatorName(request.getOperatorName());
|
message.setOperatorName(request.getOperatorName());
|
||||||
message.setCardInfo(BeanMapper.copyBean(card, CardInfo.class));
|
message.setCardInfo(BeanMapper.copyBean(card, CardInfo.class));
|
||||||
|
message.setBatchNo(requestContext.getBatchNo());
|
||||||
mqProducer.send(MqMessageRecord
|
mqProducer.send(MqMessageRecord
|
||||||
.builder(MqMessageType.CARD_PRESET_BUTTON_PRESSED, message)
|
.builder(MqMessageType.CARD_PRESET_BUTTON_PRESSED, message)
|
||||||
.messageKey(card.getId())
|
.messageKey(card.getIdentityCode())
|
||||||
.operatorId(request.getOperatorId())
|
.operatorId(request.getOperatorId())
|
||||||
.shardingKey(card.getTemplateCode())
|
.shardingKey(IdBuilder.builder()
|
||||||
|
.append(card.getTemplateCode())
|
||||||
|
.append(card.getBizCode())
|
||||||
|
.append(card.getSubBizCode())
|
||||||
|
.build())
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.card.exception;
|
||||||
|
|
||||||
|
import cn.axzo.basics.common.exception.ServiceException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
public class CardIdempotentException extends ServiceException {
|
||||||
|
|
||||||
|
public CardIdempotentException(Integer code, String msg) {
|
||||||
|
super(code, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CardIdempotentException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.card.interceptor;
|
||||||
|
|
||||||
|
import cn.axzo.msg.center.service.ButtonV3;
|
||||||
|
import cn.axzo.msg.center.utils.desision.DecisionValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
public interface CardButtonInterceptor {
|
||||||
|
|
||||||
|
default DecisionValue<Boolean> isPerformActionAvailable(ButtonV3 button) {
|
||||||
|
return DecisionValue.notSure();
|
||||||
|
}
|
||||||
|
|
||||||
|
default DecisionValue<Boolean> isActionPerformed(ButtonV3 button) {
|
||||||
|
return DecisionValue.notSure();
|
||||||
|
}
|
||||||
|
|
||||||
|
default DecisionValue<String> getActionPerformedName(ButtonV3 button) {
|
||||||
|
return DecisionValue.notSure();
|
||||||
|
}
|
||||||
|
|
||||||
|
default DecisionValue<Boolean> isVisibleOnCard(ButtonV3 button) {
|
||||||
|
return DecisionValue.notSure();
|
||||||
|
}
|
||||||
|
|
||||||
|
default DecisionValue<Boolean> isSenderShow(ButtonV3 button) {
|
||||||
|
return DecisionValue.notSure();
|
||||||
|
}
|
||||||
|
|
||||||
|
default DecisionValue<Boolean> isExecutorShow(ButtonV3 button) {
|
||||||
|
return DecisionValue.notSure();
|
||||||
|
}
|
||||||
|
|
||||||
|
CardButtonInterceptor NOT_SURE = new CardButtonInterceptor() {};
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.card.interceptor;
|
||||||
|
|
||||||
|
import cn.axzo.msg.center.service.pending.request.CardContent;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
public interface CardButtonInterceptorFactory {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
CardButtonInterceptor create(CardContent card);
|
||||||
|
|
||||||
|
}
|
||||||
@ -6,7 +6,9 @@ import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yanglin
|
* @author yanglin
|
||||||
@ -15,6 +17,7 @@ import java.util.List;
|
|||||||
public class NativeAppLinkUrlConfigVisitor implements UrlConfigVisitor {
|
public class NativeAppLinkUrlConfigVisitor implements UrlConfigVisitor {
|
||||||
|
|
||||||
private final List<AppLink> links = new ArrayList<>();
|
private final List<AppLink> links = new ArrayList<>();
|
||||||
|
private final Set<TerminalTypeEnum> terminals = new HashSet<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitAppManagerAndroid(AppUrl android) {
|
public void visitAppManagerAndroid(AppUrl android) {
|
||||||
@ -41,7 +44,9 @@ public class NativeAppLinkUrlConfigVisitor implements UrlConfigVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addLink(AppLink link) {
|
private void addLink(AppLink link) {
|
||||||
if (!links.contains(link))
|
if (!terminals.contains(link.getPlatform())) {
|
||||||
links.add(link);
|
links.add(link);
|
||||||
|
terminals.add(link.getPlatform());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ public class ModelV2PropsPopulator implements ParsedModel3Visitor {
|
|||||||
buttonV2.setDesc(buttonV3.getName());
|
buttonV2.setDesc(buttonV3.getName());
|
||||||
buttonV2.setCategory(buttonV3.getCategory());
|
buttonV2.setCategory(buttonV3.getCategory());
|
||||||
buttonV2.setPresetButtonType(buttonV3.getPresetButtonType());
|
buttonV2.setPresetButtonType(buttonV3.getPresetButtonType());
|
||||||
buttonV2.setStyle(buttonV3.parseStyle());
|
buttonV2.setStyle(buttonV3.getStyles());
|
||||||
buttonV2.setExecutorShow(buttonV3.getExecutorShow());
|
buttonV2.setExecutorShow(buttonV3.getExecutorShow());
|
||||||
buttonV2.setPendingShow(buttonV3.getPendingShow());
|
buttonV2.setPendingShow(buttonV3.getPendingShow());
|
||||||
buttonV2.setKey(buttonV3.getCode());
|
buttonV2.setKey(buttonV3.getCode());
|
||||||
|
|||||||
@ -1,324 +0,0 @@
|
|||||||
package cn.axzo.msg.center.message.service.todo;
|
|
||||||
|
|
||||||
import cn.axzo.basics.common.exception.ServiceException;
|
|
||||||
import cn.axzo.msg.center.api.mq.CardInfo;
|
|
||||||
import cn.axzo.msg.center.dal.TodoDao;
|
|
||||||
import cn.axzo.msg.center.domain.entity.Todo;
|
|
||||||
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
|
|
||||||
import cn.axzo.msg.center.message.domain.param.PendingMessagePushParam;
|
|
||||||
import cn.axzo.msg.center.message.service.card.CardManager;
|
|
||||||
import cn.axzo.msg.center.message.service.impl.v3.ModelV3Service;
|
|
||||||
import cn.axzo.msg.center.message.service.todo.manage.TodoLogger;
|
|
||||||
import cn.axzo.msg.center.message.service.todo.manage.TodoManager;
|
|
||||||
import cn.axzo.msg.center.message.service.todo.manage.TodoRequestContext;
|
|
||||||
import cn.axzo.msg.center.notices.common.constans.CommonConstants;
|
|
||||||
import cn.axzo.msg.center.service.dto.PeerPerson;
|
|
||||||
import cn.axzo.msg.center.service.dto.PersonDTO;
|
|
||||||
import cn.axzo.msg.center.service.enums.CardBizState;
|
|
||||||
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
|
||||||
import cn.axzo.msg.center.service.pending.request.CardSendRequest;
|
|
||||||
import cn.axzo.msg.center.service.pending.request.CardUpdatePresetButtonRequest;
|
|
||||||
import cn.axzo.msg.center.service.pending.request.CardUpdateStateRequest;
|
|
||||||
import cn.axzo.msg.center.service.pending.request.PresetButtonPressedRequest;
|
|
||||||
import cn.axzo.msg.center.service.util.IdBuilder;
|
|
||||||
import com.alibaba.excel.util.StringUtils;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.google.common.base.Throwables;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author xudawei@axzo.cn
|
|
||||||
* @date 2024/12/12
|
|
||||||
* @desc 待办与卡片关联包装
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class TodoWithCardWrapper {
|
|
||||||
|
|
||||||
private final CardManager cardManager;
|
|
||||||
|
|
||||||
private final TodoLogger todoLogger;
|
|
||||||
|
|
||||||
private final TodoDao todoDao;
|
|
||||||
|
|
||||||
private final ModelV3Service modelV3Service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 卡片预设按钮,同步待办
|
|
||||||
* 注:卡片预设同步待办状态
|
|
||||||
* @param presetButtonType 预设类型
|
|
||||||
* @param cardInfo 卡片
|
|
||||||
*/
|
|
||||||
public void fireTodoWhenPresetButtonPressedByCard(TodoManager todoManager, PresetButtonType presetButtonType, CardInfo cardInfo, Long operatorId) {
|
|
||||||
if (Objects.isNull(presetButtonType) || Objects.isNull(cardInfo)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (StringUtils.isBlank(cardInfo.getTemplateCode()) || StringUtils.isBlank(cardInfo.getBizCode())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("TodoWithCardWrapper#fireTodoWhenPresetButtonPressedByCard start,presetButtonType:{},cardInfo:{}", presetButtonType, JSON.toJSONString(cardInfo));
|
|
||||||
TodoRequestContext ctx = TodoRequestContext.create("cardPresetTodo", cardInfo);
|
|
||||||
ctx.addLogContent("presetButtonType", presetButtonType);
|
|
||||||
ctx.addLogContent("operatorId", operatorId);
|
|
||||||
//1 查询待办(Todo对象),根据templateCode/bizCode/subBizCode/receiverPresonId/receiverOuId/receiverWorkspaceId 理论上只能查询一条[待办]记录
|
|
||||||
List<Todo> todoList = todoDao.findByCondition(cardInfo.getTemplateCode(), cardInfo.getBizCode(), cardInfo.getSubBizCode(), cardInfo.getReceiverPersonId(), cardInfo.getReceiverOuId(), cardInfo.getReceiverWorkspaceId());
|
|
||||||
try {
|
|
||||||
if (CollectionUtils.isEmpty(todoList)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//2 同步待办预设状态,
|
|
||||||
for (Todo todo : todoList) {
|
|
||||||
PresetButtonPressedRequest presetButtonPressedRequest = this.buildPresetButtonPressedRequest(todo.getIdentityCode(), presetButtonType, operatorId);
|
|
||||||
todoManager.firePresetButtonPressed( presetButtonPressedRequest, false);
|
|
||||||
|
|
||||||
ctx.addLogContent("fireTodoWhenPresetButtonPressedByCard", "success");
|
|
||||||
todoLogger.logTodosUpdated(ctx, Collections.singletonList(todo));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("TodoWithCardWrapper#fireTodoWhenPresetButtonPressedByCard exception,presetButtonType:{},cardInfo:{}", presetButtonType, JSON.toJSONString(cardInfo),e);
|
|
||||||
ctx.addLogContent("exception", Throwables.getStackTraceAsString(e));
|
|
||||||
todoLogger.logTodosUpdated(ctx, todoList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建预设按钮对象
|
|
||||||
*/
|
|
||||||
private PresetButtonPressedRequest buildPresetButtonPressedRequest(String identityCode, PresetButtonType presetButtonType, Long operatorId) {
|
|
||||||
return PresetButtonPressedRequest.builder()
|
|
||||||
.identityCode(identityCode)
|
|
||||||
.presetButtonType(presetButtonType)
|
|
||||||
.operatorId(operatorId)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 点击预设按钮-同步卡片
|
|
||||||
* 注:待办预设同步卡片状态
|
|
||||||
*/
|
|
||||||
public void fireCardWhenPresetButtonPressedByTodo(PresetButtonPressedRequest request, Todo todo, boolean isSyncCard) {
|
|
||||||
//是否同步卡片信息,true:同步;false:不同步
|
|
||||||
if (!isSyncCard) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
log.info("TodoWithCardWrapper#fireCardWhenPresetButtonPressedByTodo start,request:{},todo:{}", JSON.toJSONString(request), JSON.toJSONString(todo));
|
|
||||||
TodoRequestContext ctx = TodoRequestContext.create("todoPresetCard", request);
|
|
||||||
|
|
||||||
|
|
||||||
if (!this.isContainImChannel(todo.getTemplateCode())) {
|
|
||||||
log.info("fireCardWhenPresetButtonPressedByTodo#notContainImChannel,templateCode:{}", todo.getTemplateCode());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
log.info("fireCardWhenPresetButtonPressedByTodo#isContainImChannel,templateCode:{}", todo.getTemplateCode());
|
|
||||||
try {
|
|
||||||
//1 构建对象
|
|
||||||
CardUpdatePresetButtonRequest cardRequest = this.buildCardUpdatePresetButtonRequest(request, todo);
|
|
||||||
//2 同步卡片
|
|
||||||
cardManager.firePresetButtonPressed(cardRequest);
|
|
||||||
|
|
||||||
ctx.addLogContent("fireCardWhenPresetButtonPressedByTodo", "success");
|
|
||||||
todoLogger.logTodosUpdated(ctx, Collections.singletonList(todo));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("TodoWithCardWrapper#fireCardWhenPresetButtonPressedByTodo exception,request:{},todo:{}", JSON.toJSONString(request), JSON.toJSONString(todo),e);
|
|
||||||
ctx.addLogContent("exception", Throwables.getStackTraceAsString(e));
|
|
||||||
todoLogger.logTodosUpdated(ctx, Collections.singletonList(todo));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建对象
|
|
||||||
*/
|
|
||||||
private CardUpdatePresetButtonRequest buildCardUpdatePresetButtonRequest(PresetButtonPressedRequest request, Todo todo) {
|
|
||||||
CardUpdatePresetButtonRequest cardRequest = new CardUpdatePresetButtonRequest();
|
|
||||||
cardRequest.setAppCode(CommonConstants.TODO_SYSN_CARD_APP_CODE);
|
|
||||||
cardRequest.setTemplateCode(todo.getTemplateCode());
|
|
||||||
cardRequest.setBizCode(todo.getBizCode());
|
|
||||||
cardRequest.setSubBizCode(todo.getSubBizCode());
|
|
||||||
cardRequest.setReceivers(Sets.newHashSet(
|
|
||||||
PeerPerson.newPeerPerson(todo.getExecutorPersonId()
|
|
||||||
, todo.getOuId()
|
|
||||||
, todo.getReceiverWorkspaceId())));
|
|
||||||
|
|
||||||
cardRequest.setPresetButtonType(request.getPresetButtonType());
|
|
||||||
cardRequest.setOperatorId(request.getOperatorId());
|
|
||||||
return cardRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送卡片信息
|
|
||||||
*/
|
|
||||||
public void send(PendingMessagePushParam param,List<Todo> todos) {
|
|
||||||
log.info("TodoWithCardWrapper#send start,param:{}", JSON.toJSONString(param));
|
|
||||||
TodoRequestContext ctx = TodoRequestContext.create("todoSyncCardSend", param);
|
|
||||||
if (!this.isContainImChannel(param.getTemplateCode())) {
|
|
||||||
log.info("send#notContainImChannel,templateCode:{}", param.getTemplateCode());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
log.info("send#isContainImChannel,templateCode:{}", param.getTemplateCode());
|
|
||||||
try {
|
|
||||||
//1 构建对象
|
|
||||||
CardSendRequest cardSendRequest = this.buildCardSendRequest(param);
|
|
||||||
ctx.addLogContent(JSON.toJSONString(cardSendRequest));
|
|
||||||
//2 发送
|
|
||||||
cardManager.send(cardSendRequest);
|
|
||||||
|
|
||||||
ctx.addLogContent("sendCard", "success");
|
|
||||||
todoLogger.logTodosUpdated(ctx, todos);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("TodoWithCardWrapper#send,param:{}", JSON.toJSONString(param), e);
|
|
||||||
ctx.addLogContent("exception", Throwables.getStackTraceAsString(e));
|
|
||||||
todoLogger.logTodosUpdated(ctx, todos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否包含IM通道
|
|
||||||
*/
|
|
||||||
private boolean isContainImChannel(String templateCode) {
|
|
||||||
TemplateModelV3 templateModel = modelV3Service.findEnabledByCode(templateCode)
|
|
||||||
.orElseThrow(() -> new ServiceException(
|
|
||||||
String.format("Can't find template. templateCode=%s", templateCode)));
|
|
||||||
return templateModel.getTemplate().isContainImChannel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 卡片更新状态-完成
|
|
||||||
*/
|
|
||||||
public void cardCompleteStateByTodoList(List<Todo> todoList) {
|
|
||||||
this.cardUpdateStateByTodoList(todoList,CardBizState.END, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 卡片更新状态-回滚
|
|
||||||
* 暂时不需要
|
|
||||||
*/
|
|
||||||
public void cardRollbackStateByTodoList(List<Todo> todoList) {
|
|
||||||
this.cardUpdateStateByTodoList(todoList, CardBizState.ABORTED, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 卡片更新状态-撤销
|
|
||||||
*/
|
|
||||||
public void cardRevokeStateByTodoList(List<Todo> todoList) {
|
|
||||||
this.cardUpdateStateByTodoList(todoList, CardBizState.REVOKED, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 卡片更新状态-执行中
|
|
||||||
*/
|
|
||||||
public void cardProcessingStateByTodoList(List<Todo> todoList) {
|
|
||||||
this.cardUpdateStateByTodoList(todoList, CardBizState.PENDING, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 卡片更新完成状态
|
|
||||||
*/
|
|
||||||
private void cardUpdateStateByTodoList(List<Todo> todoList, CardBizState bizState, boolean setCardCompleted) {
|
|
||||||
log.info("TodoWithCardWrapper#cardUpdateStateByTodoList start,todoList:{},bizState:{},setCardCompleted:{}", JSON.toJSONString(todoList), bizState, setCardCompleted);
|
|
||||||
if (CollectionUtils.isEmpty(todoList)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TodoRequestContext ctx = TodoRequestContext.create("todoSyncCardState", todoList);
|
|
||||||
ctx.addLogContent("bizState", bizState);
|
|
||||||
ctx.addLogContent("cardState", bizState);
|
|
||||||
ctx.addLogContent("setCardCompleted", setCardCompleted);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Set<String> codes = todoList.stream().map(Todo::getTemplateCode).collect(Collectors.toSet());
|
|
||||||
List<TemplateModelV3> byCodes = modelV3Service.getByCodes(new ArrayList<>(codes));
|
|
||||||
Map<String, TemplateModelV3> modelV3Map = byCodes.stream().collect(Collectors.toMap(TemplateModelV3::getTemplateCode, Function.identity()));
|
|
||||||
|
|
||||||
for (Todo todo : todoList) {
|
|
||||||
TemplateModelV3 templateModelV3 = modelV3Map.get(todo.getTemplateCode());
|
|
||||||
if (Objects.isNull(templateModelV3) || Objects.isNull(templateModelV3.getTemplate())
|
|
||||||
|| StringUtils.isBlank(templateModelV3.getTemplate().getCode()) ||!templateModelV3.getTemplate().isContainImChannel()) {
|
|
||||||
log.info("cardUpdateStateByTodoList#notContainImChannel,templateModelV3:{}", JSON.toJSONString(templateModelV3));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
log.info("cardUpdateStateByTodoList#isContainImChannel,templateModelV3:{}", JSON.toJSONString(templateModelV3));
|
|
||||||
//1 构建对象
|
|
||||||
CardUpdateStateRequest updateStateRequest = this.buildCardUpdateStateRequest(todo, bizState, setCardCompleted);
|
|
||||||
//2 更新状态
|
|
||||||
cardManager.updateState(updateStateRequest);
|
|
||||||
ctx.addLogContent("cardUpdateStateByTodoList", "success");
|
|
||||||
todoLogger.logTodosUpdated(ctx, Collections.singletonList(todo));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("TodoWithCardWrapper#cardCompleteState,todoList:{}", JSON.toJSONString(todoList), e);
|
|
||||||
ctx.addLogContent("exception", Throwables.getStackTraceAsString(e));
|
|
||||||
todoLogger.logTodosUpdated(ctx, todoList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建卡片状态更新对象
|
|
||||||
*/
|
|
||||||
private CardUpdateStateRequest buildCardUpdateStateRequest(Todo todo, CardBizState bizState, boolean setCardCompleted) {
|
|
||||||
CardUpdateStateRequest updateStateRequest = new CardUpdateStateRequest();
|
|
||||||
|
|
||||||
updateStateRequest.setBizState(bizState);
|
|
||||||
updateStateRequest.setCardCompleted(setCardCompleted);
|
|
||||||
|
|
||||||
updateStateRequest.setAppCode(CommonConstants.TODO_SYSN_CARD_APP_CODE);
|
|
||||||
updateStateRequest.setTemplateCode(todo.getTemplateCode());
|
|
||||||
updateStateRequest.setBizCode(todo.getBizCode());
|
|
||||||
updateStateRequest.setSubBizCode(todo.getSubBizCode());
|
|
||||||
updateStateRequest.setReceivers(Sets.newHashSet(PeerPerson.newPeerPerson(todo.getExecutorPersonId(), todo.getOuId(), todo.getReceiverWorkspaceId())));//TODO
|
|
||||||
return updateStateRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建对象
|
|
||||||
*/
|
|
||||||
private CardSendRequest buildCardSendRequest(PendingMessagePushParam param) {
|
|
||||||
CardSendRequest sendRequest = new CardSendRequest();
|
|
||||||
sendRequest.setAppCode(CommonConstants.TODO_SYSN_CARD_APP_CODE);
|
|
||||||
sendRequest.setTemplateCode(param.getTemplateCode());
|
|
||||||
sendRequest.setBizCode(param.getBizCode());
|
|
||||||
sendRequest.setSubBizCode(param.getSubBizCode());
|
|
||||||
if (Objects.nonNull(param.getPromoter()) && Objects.nonNull(param.getPromoter().getId())) {
|
|
||||||
sendRequest.setSender(PeerPerson.newPeerPerson(param.getPromoter().getId()
|
|
||||||
, Objects.nonNull(param.getPromoterOuId()) ? param.getPromoterOuId() : null
|
|
||||||
, Objects.nonNull(param.getPromoterWorkspaceId()) ? param.getPromoterWorkspaceId() : null));
|
|
||||||
}
|
|
||||||
|
|
||||||
sendRequest.setReceivers(this.buildReceivers(param.getExecutor(), param.getOuId(), param.getWorkspaceId()));
|
|
||||||
if (StringUtils.isNotBlank(param.getBizExtParams())) {
|
|
||||||
sendRequest.setBizParam(JSON.parseObject(param.getBizExtParams()));
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotBlank(param.getRouterParams())) {
|
|
||||||
sendRequest.setRouterParam(JSON.parseObject(param.getRouterParams()));
|
|
||||||
}
|
|
||||||
|
|
||||||
sendRequest.setIdempotentCode(IdBuilder.builder()
|
|
||||||
.append(param.getBizCode())
|
|
||||||
.append(param.getSubBizCode())
|
|
||||||
.build());
|
|
||||||
|
|
||||||
return sendRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<PeerPerson> buildReceivers(List<PersonDTO> personDTOS, Long ouId, Long workspaceId) {
|
|
||||||
if (CollectionUtils.isEmpty(personDTOS)) {
|
|
||||||
return Sets.newHashSet();
|
|
||||||
}
|
|
||||||
return personDTOS.stream().map(item -> PeerPerson.newPeerPerson(item.getId(), ouId, workspaceId)).collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.todo.card;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
|
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||||
|
import cn.axzo.msg.center.api.mq.CardPresetButtonPressedMessage;
|
||||||
|
import cn.axzo.msg.center.mq.ConsumerIsolation;
|
||||||
|
import cn.axzo.msg.center.mq.IsolationMQListener;
|
||||||
|
import cn.axzo.msg.center.mq.RocketMQConfig;
|
||||||
|
import cn.axzo.msg.center.service.enums.MqMessageType;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||||
|
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RocketMQMessageListener(
|
||||||
|
consumeThreadMax = 2,
|
||||||
|
maxReconsumeTimes = 3,
|
||||||
|
consumeMode = ConsumeMode.ORDERLY,
|
||||||
|
nameServer = "${rocketmq.name-server}",
|
||||||
|
topic = RocketMQConfig.MSG_CENTER_TOPIC,
|
||||||
|
consumerGroup = "GID_topic_card_preset_button_sync_todo_${spring.profiles.active}"
|
||||||
|
)
|
||||||
|
public class CardPresetButtonSyncTodoListener extends IsolationMQListener {
|
||||||
|
|
||||||
|
private final TodoSyncCardService todoSyncCardService;
|
||||||
|
|
||||||
|
CardPresetButtonSyncTodoListener(TodoSyncCardService todoSyncCardService) {
|
||||||
|
super(ConsumerIsolation.CARD_PRESET_BUTTON_CLICKED_SYNC_TODO,
|
||||||
|
MqMessageType.CARD_PRESET_BUTTON_PRESSED);
|
||||||
|
this.todoSyncCardService = todoSyncCardService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEventImpl(Event event, EventConsumer.Context context) {
|
||||||
|
CardPresetButtonPressedMessage message = event.normalizedData(CardPresetButtonPressedMessage.class);
|
||||||
|
log.info("received CardPresetButtonPressedMessage: {}", message);
|
||||||
|
todoSyncCardService.syncCardPresetButtonPressed(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.todo.card;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
|
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||||
|
import cn.axzo.msg.center.api.mq.PresetButtonPressedMessage;
|
||||||
|
import cn.axzo.msg.center.mq.ConsumerIsolation;
|
||||||
|
import cn.axzo.msg.center.mq.IsolationMQListener;
|
||||||
|
import cn.axzo.msg.center.mq.RocketMQConfig;
|
||||||
|
import cn.axzo.msg.center.service.enums.MqMessageType;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||||
|
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RocketMQMessageListener(
|
||||||
|
consumeThreadMax = 2,
|
||||||
|
maxReconsumeTimes = 3,
|
||||||
|
consumeMode = ConsumeMode.ORDERLY,
|
||||||
|
nameServer = "${rocketmq.name-server}",
|
||||||
|
topic = RocketMQConfig.MSG_CENTER_TOPIC,
|
||||||
|
consumerGroup = "GID_topic_todo_preset_button_sync_card_${spring.profiles.active}"
|
||||||
|
)
|
||||||
|
public class TodoPresetButtonSyncCardListener extends IsolationMQListener {
|
||||||
|
|
||||||
|
private final TodoSyncCardService todoSyncCardService;
|
||||||
|
|
||||||
|
TodoPresetButtonSyncCardListener(TodoSyncCardService todoSyncCardService) {
|
||||||
|
super(ConsumerIsolation.TODO_PRESET_BUTTON_CLICKED_SYNC_CARD,
|
||||||
|
MqMessageType.TODO_PRESET_BUTTON_PRESSED);
|
||||||
|
this.todoSyncCardService = todoSyncCardService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEventImpl(Event event, EventConsumer.Context context) {
|
||||||
|
PresetButtonPressedMessage message = event.normalizedData(PresetButtonPressedMessage.class);
|
||||||
|
log.info("received PresetButtonPressedMessage: {}", message);
|
||||||
|
todoSyncCardService.syncTodoPresetButtonPressed(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.todo.card;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
|
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||||
|
import cn.axzo.msg.center.api.mq.TodoUpdateMessage;
|
||||||
|
import cn.axzo.msg.center.mq.ConsumerIsolation;
|
||||||
|
import cn.axzo.msg.center.mq.IsolationMQListener;
|
||||||
|
import cn.axzo.msg.center.mq.RocketMQConfig;
|
||||||
|
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
|
||||||
|
import cn.axzo.msg.center.service.enums.MqMessageType;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||||
|
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RocketMQMessageListener(
|
||||||
|
consumeThreadMax = 2,
|
||||||
|
maxReconsumeTimes = 3,
|
||||||
|
consumeMode = ConsumeMode.ORDERLY,
|
||||||
|
nameServer = "${rocketmq.name-server}",
|
||||||
|
topic = RocketMQConfig.MSG_CENTER_TOPIC,
|
||||||
|
consumerGroup = "GID_topic_todo_sync_card_biz_${spring.profiles.active}"
|
||||||
|
)
|
||||||
|
class TodoSyncCardBizListener extends IsolationMQListener {
|
||||||
|
|
||||||
|
private final TodoSyncCardService todoSyncCardService;
|
||||||
|
|
||||||
|
TodoSyncCardBizListener(TodoSyncCardService todoSyncCardService) {
|
||||||
|
super(ConsumerIsolation.TODO_SYNC_CARD_BIZ, MqMessageType.TODO_STATE_UPDATE);
|
||||||
|
this.todoSyncCardService = todoSyncCardService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEventImpl(Event event, EventConsumer.Context context) {
|
||||||
|
TodoUpdateMessage message;
|
||||||
|
try {
|
||||||
|
message = event.normalizedData(TodoUpdateMessage.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("parse message error. event={}", event, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (message.getUpdatedTodo().getBizCategory() == BizCategoryEnum.OTHER)
|
||||||
|
todoSyncCardService.onMessage(event, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.todo.card;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
|
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||||
|
import cn.axzo.msg.center.api.mq.TodoUpdateMessage;
|
||||||
|
import cn.axzo.msg.center.mq.ConsumerIsolation;
|
||||||
|
import cn.axzo.msg.center.mq.IsolationMQListener;
|
||||||
|
import cn.axzo.msg.center.mq.RocketMQConfig;
|
||||||
|
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
|
||||||
|
import cn.axzo.msg.center.service.enums.MqMessageType;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||||
|
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RocketMQMessageListener(
|
||||||
|
consumeThreadMax = 2,
|
||||||
|
maxReconsumeTimes = 3,
|
||||||
|
consumeMode = ConsumeMode.ORDERLY,
|
||||||
|
nameServer = "${rocketmq.name-server}",
|
||||||
|
topic = RocketMQConfig.MSG_CENTER_TOPIC,
|
||||||
|
consumerGroup = "GID_topic_todo_sync_card_flow_${spring.profiles.active}"
|
||||||
|
)
|
||||||
|
class TodoSyncCardFlowListener extends IsolationMQListener {
|
||||||
|
|
||||||
|
private final TodoSyncCardService todoSyncCardService;
|
||||||
|
|
||||||
|
TodoSyncCardFlowListener(TodoSyncCardService todoSyncCardService) {
|
||||||
|
super(ConsumerIsolation.TODO_SYNC_CARD_FLOW, MqMessageType.TODO_STATE_UPDATE);
|
||||||
|
this.todoSyncCardService = todoSyncCardService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEventImpl(Event event, EventConsumer.Context context) {
|
||||||
|
TodoUpdateMessage message;
|
||||||
|
try {
|
||||||
|
message = event.normalizedData(TodoUpdateMessage.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("parse message error. event={}", event, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (message.getUpdatedTodo().getBizCategory() == BizCategoryEnum.FLOW)
|
||||||
|
todoSyncCardService.onMessage(event, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,318 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.todo.card;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
|
import cn.axzo.msg.center.api.mq.CardPresetButtonPressedMessage;
|
||||||
|
import cn.axzo.msg.center.api.mq.PresetButtonPressedMessage;
|
||||||
|
import cn.axzo.msg.center.api.mq.TodoUpdateMessage;
|
||||||
|
import cn.axzo.msg.center.dal.MessageTemplateV3Dao;
|
||||||
|
import cn.axzo.msg.center.dal.TodoBusinessDao;
|
||||||
|
import cn.axzo.msg.center.dal.TodoDao;
|
||||||
|
import cn.axzo.msg.center.domain.entity.MessageTemplateV3;
|
||||||
|
import cn.axzo.msg.center.domain.entity.Todo;
|
||||||
|
import cn.axzo.msg.center.domain.entity.TodoBusiness;
|
||||||
|
import cn.axzo.msg.center.message.service.card.CardExtInfo;
|
||||||
|
import cn.axzo.msg.center.message.service.card.CardManager;
|
||||||
|
import cn.axzo.msg.center.message.service.card.exception.CardIdempotentException;
|
||||||
|
import cn.axzo.msg.center.message.service.todo.manage.TodoLogger;
|
||||||
|
import cn.axzo.msg.center.message.service.todo.manage.TodoManager;
|
||||||
|
import cn.axzo.msg.center.message.service.todo.manage.TodoRequestContext;
|
||||||
|
import cn.axzo.msg.center.service.dto.PeerPerson;
|
||||||
|
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
|
||||||
|
import cn.axzo.msg.center.service.enums.BizFinalStateEnum;
|
||||||
|
import cn.axzo.msg.center.service.enums.CardBizState;
|
||||||
|
import cn.axzo.msg.center.service.enums.CodeDefinition;
|
||||||
|
import cn.axzo.msg.center.service.enums.MessageChannel;
|
||||||
|
import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
|
||||||
|
import cn.axzo.msg.center.service.pending.request.CardSendRequest;
|
||||||
|
import cn.axzo.msg.center.service.pending.request.CardUpdatePresetButtonRequest;
|
||||||
|
import cn.axzo.msg.center.service.pending.request.CardUpdateStateRequest;
|
||||||
|
import cn.axzo.msg.center.service.pending.request.PresetButtonPressedRequest;
|
||||||
|
import cn.axzo.msg.center.service.pending.response.CardSendResponse;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class TodoSyncCardService {
|
||||||
|
|
||||||
|
private static final ThreadLocal<TodoUpdateMessage> TODO_MESSAGE = new ThreadLocal<>();
|
||||||
|
|
||||||
|
private static final String APP_CODE = "msg-center:todo";
|
||||||
|
private static final String TODO_IDENTITY_CODE_BIZ_PARAM_KEY = "todoIdentityCode";
|
||||||
|
private static final String TODO_TYPE_BIZ_PARAM_KEY = "todoType";
|
||||||
|
private static final String TODO_CATEGORY_BIZ_PARAM_KEY = "todoCategory";
|
||||||
|
private static final String TODO_EXECUTOR_WORKSPACE_ID_BIZ_PARAM_KEY = "todoExecutorWorkspaceId";
|
||||||
|
private static final String TODO_PROMOTER_WORKSPACE_ID_BIZ_PARAM_KEY = "todoPromoterWorkspaceId";
|
||||||
|
|
||||||
|
private final TodoDao todoDao;
|
||||||
|
private final TodoBusinessDao todoBusinessDao;
|
||||||
|
private final CardManager cardManager;
|
||||||
|
private final TodoLogger todoLogger;
|
||||||
|
private final MessageTemplateV3Dao messageTemplateV3Dao;
|
||||||
|
private final TodoManager todoManager;
|
||||||
|
private final TransactionTemplate transactionTemplate;
|
||||||
|
|
||||||
|
void onMessage(Event event, TodoUpdateMessage message) {
|
||||||
|
log.info("received TodoUpdateMessage: {}", message);
|
||||||
|
try {
|
||||||
|
TODO_MESSAGE.set(message);
|
||||||
|
sync(event, message);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("onMessage error, message={}", message, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
TODO_MESSAGE.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<TodoUpdateMessage> getTodoUpdateMessage() {
|
||||||
|
return Optional.ofNullable(TODO_MESSAGE.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sync(Event event, TodoUpdateMessage message) {
|
||||||
|
if (!message.isUpdateCard()) {
|
||||||
|
log.warn("not update card, message={}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Todo todo = todoDao.findTodoByCode(message.getUpdatedTodo().getIdentityCode())
|
||||||
|
.orElse(null);
|
||||||
|
if (todo == null) {
|
||||||
|
log.warn("[sync] todo not found, message={}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MessageTemplateV3 template = messageTemplateV3Dao
|
||||||
|
.findByCode(todo.getTemplateCode())
|
||||||
|
.orElse(null);
|
||||||
|
if (template == null) {
|
||||||
|
log.warn("template not found, message={}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!template.determineChannels().contains(MessageChannel.IM)) {
|
||||||
|
log.warn("template not support IM, message={}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TodoBusiness business = todoBusinessDao.getBusinesses(todo).findBusiness(todo).orElse(null);
|
||||||
|
if (business == null) {
|
||||||
|
log.warn("business not found, message={}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (todo.getState() == PendingMessageStateEnum.HAS_BEEN_SENT
|
||||||
|
|| (todo.getState() == PendingMessageStateEnum.CREATED && business.getBizFinalState() == null))
|
||||||
|
sendCard(event, business, todo);
|
||||||
|
else if (!TodoManager.OP_FIRE_PRESET_BUTTON_PRESSED.equals(message.getOperation()))
|
||||||
|
updateCardState(event, business, todo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendCard(Event event, TodoBusiness business, Todo todo) {
|
||||||
|
CardSendRequest request = new CardSendRequest();
|
||||||
|
request.setAppCode(APP_CODE);
|
||||||
|
request.setTemplateCode(todo.getTemplateCode());
|
||||||
|
request.setBizCode(todo.getBizCode());
|
||||||
|
request.setIdempotentCode(todo.getIdentityCode());
|
||||||
|
request.setSubBizCode(todo.getSubBizCode());
|
||||||
|
Long promoterPersonId = business.getPromoterPersonId();
|
||||||
|
if (promoterPersonId == null) promoterPersonId = 0L;
|
||||||
|
Long ouId = business.getOuId();
|
||||||
|
if (ouId == null) ouId = 0L;
|
||||||
|
request.setSender(PeerPerson.create(promoterPersonId, ouId, business.getOrgId()));
|
||||||
|
request.setReceivers(Sets.newHashSet(PeerPerson.create(
|
||||||
|
todo.getExecutorPersonId(), todo.getOuId(), todo.getOrgId())));
|
||||||
|
JSONObject bizParam = todo.bizParam();
|
||||||
|
CardExtInfo cardExtInfo = new CardExtInfo(bizParam);
|
||||||
|
cardExtInfo.addExtInfo(TODO_IDENTITY_CODE_BIZ_PARAM_KEY, todo.getIdentityCode());
|
||||||
|
cardExtInfo.addExtInfo(TODO_TYPE_BIZ_PARAM_KEY, todo.getType().getCode());
|
||||||
|
cardExtInfo.addExtInfo(TODO_CATEGORY_BIZ_PARAM_KEY, business.getBizCategory().getCode());
|
||||||
|
cardExtInfo.addExtInfo(TODO_EXECUTOR_WORKSPACE_ID_BIZ_PARAM_KEY, todo.getReceiverWorkspaceId());
|
||||||
|
cardExtInfo.addExtInfo(TODO_PROMOTER_WORKSPACE_ID_BIZ_PARAM_KEY, business.getOrgId());
|
||||||
|
request.setBizParam(bizParam);
|
||||||
|
request.setRouterParam(todo.routerParam());
|
||||||
|
request.setReturnCards(true);
|
||||||
|
TodoRequestContext ctx = TodoRequestContext
|
||||||
|
.create("sendCard", event)
|
||||||
|
.addLogContent("sendCardRequest", request);
|
||||||
|
try {
|
||||||
|
log.info("sendCard: todo={}", todo);
|
||||||
|
CardSendResponse response = cardManager.send(request);
|
||||||
|
ctx.addLogContent("sendCardResponse", response);
|
||||||
|
todoLogger.logTodoUpdated(ctx, todo);
|
||||||
|
log.info("sendCard: success, todo={}", todo);
|
||||||
|
} catch (CardIdempotentException ignored) {
|
||||||
|
log.warn("sendCard: idempotent, todo={}", todo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("sendCard: error, todo={}", todo, e);
|
||||||
|
todoLogger.logTodoUpdated(ctx.copy().addLogContent("exception", e), todo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCardState(Event event, TodoBusiness business, Todo todo) {
|
||||||
|
TodoCardUpdateStateRequest request = new TodoCardUpdateStateRequest();
|
||||||
|
request.setTodo(todo);
|
||||||
|
request.setTodoBusiness(business);
|
||||||
|
request.setAppCode(APP_CODE);
|
||||||
|
request.setTemplateCode(todo.getTemplateCode());
|
||||||
|
request.setBizCode(todo.getBizCode());
|
||||||
|
request.setSubBizCode(todo.getSubBizCode());
|
||||||
|
request.setReceivers(Sets.newHashSet(PeerPerson.create(
|
||||||
|
todo.getExecutorPersonId(), todo.getOuId(), todo.getOrgId())));
|
||||||
|
if (todo.getState() != PendingMessageStateEnum.PROCESSING) {
|
||||||
|
request.setBizState(business.getBizCategory() == BizCategoryEnum.FLOW
|
||||||
|
? determineCardBizStateForFlowTodo(business)
|
||||||
|
: determineCardBizStateForBizTodo(todo));
|
||||||
|
}
|
||||||
|
request.setCardCompleted(todo.getState() == PendingMessageStateEnum.COMPLETED);
|
||||||
|
TodoRequestContext ctx = TodoRequestContext
|
||||||
|
.create("updateCardState", event)
|
||||||
|
.addLogContent("updateCardStateRequest", request)
|
||||||
|
.addLogContent("todo", todo);
|
||||||
|
if (request.isValid()) {
|
||||||
|
try {
|
||||||
|
cardManager.updateState(request);
|
||||||
|
todoLogger.logTodoUpdated(ctx.copy().addLogContent("updateCardStateResult", "success"), todo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("updateCardState: error, todo={}", todo, e);
|
||||||
|
todoLogger.logTodoUpdated(ctx.copy().addLogContent("exception", e), todo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info("updateCardState: invalid request, todo={}", todo);
|
||||||
|
todoLogger.logTodoUpdated(ctx.copy().addLogContent("updateCardStateResult", "invalid update card state request"), todo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void syncCardPresetButtonPressed(CardPresetButtonPressedMessage message) {
|
||||||
|
log.info("onCardPresetButtonPressed: {}", message);
|
||||||
|
if (!APP_CODE.equals(message.getCardInfo().getAppCode())) {
|
||||||
|
log.info("[syncCardPresetButtonPressed] onCardPresetButtonPressed: not msg-center:todo, message={}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String identityCode = new CardExtInfo(message.getCardInfo().determineBizParam())
|
||||||
|
.getJsonObject().getString(TODO_IDENTITY_CODE_BIZ_PARAM_KEY);
|
||||||
|
if (StringUtils.isBlank(identityCode)) {
|
||||||
|
log.warn("[syncCardPresetButtonPressed] onCardPresetButtonPressed: identityCode is blank, message={}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Todo todo = todoDao.findTodoByCode(identityCode).orElse(null);
|
||||||
|
if (todo == null) {
|
||||||
|
log.info("[syncCardPresetButtonPressed] onCardPresetButtonPressed: todo not found, message={}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PresetButtonPressedRequest request = new PresetButtonPressedRequest();
|
||||||
|
request.setIdentityCode(identityCode);
|
||||||
|
request.setPresetButtonType(message.getPresetButtonType());
|
||||||
|
request.setOperatorId(message.getOperatorId());
|
||||||
|
request.setOperatorName(message.getOperatorName());
|
||||||
|
TodoRequestContext ctx = TodoRequestContext.create(
|
||||||
|
"syncCardPresetButtonPressed:finished", message.getBatchNo(), message);
|
||||||
|
try {
|
||||||
|
execTransactional(() -> {
|
||||||
|
if (todoManager.firePresetButtonPressed(request, false))
|
||||||
|
todoLogger.logTodoUpdated(ctx, todo);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("[syncCardPresetButtonPressed] onCardPresetButtonPressed: error, message={}", message, e);
|
||||||
|
todoLogger.logTodoUpdated(ctx.copy().addLogContent("exception", e), todo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void syncTodoPresetButtonPressed(PresetButtonPressedMessage message) {
|
||||||
|
Todo todo = todoDao.findTodoByCode(message.getTodoInfo().getIdentityCode()).orElse(null);
|
||||||
|
if (todo == null) {
|
||||||
|
log.warn("[syncTodoPresetButtonPressed] todo not found, message={}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MessageTemplateV3 template = messageTemplateV3Dao
|
||||||
|
.findByCode(todo.getTemplateCode())
|
||||||
|
.orElse(null);
|
||||||
|
if (template == null) {
|
||||||
|
log.warn("[syncTodoPresetButtonPressed] template not found, message={}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!template.determineChannels().contains(MessageChannel.IM)) {
|
||||||
|
log.warn("[syncTodoPresetButtonPressed] template not support IM, message={}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CardUpdatePresetButtonRequest request = new CardUpdatePresetButtonRequest();
|
||||||
|
request.setAppCode(APP_CODE);
|
||||||
|
request.setTemplateCode(todo.getTemplateCode());
|
||||||
|
request.setBizCode(todo.getBizCode());
|
||||||
|
request.setSubBizCode(todo.getSubBizCode());
|
||||||
|
request.setReceivers(Sets.newHashSet(PeerPerson.create(
|
||||||
|
todo.getExecutorPersonId(), todo.getOuId(), todo.getReceiverWorkspaceId())));
|
||||||
|
request.setPresetButtonType(message.getPresetButtonType());
|
||||||
|
request.setOperatorId(0L);
|
||||||
|
request.setOperatorName("");
|
||||||
|
TodoRequestContext ctx = TodoRequestContext.create("syncTodoPresetButtonPressed:finished", message);
|
||||||
|
try {
|
||||||
|
execTransactional(() -> {
|
||||||
|
if (cardManager.firePresetButtonPressed(request))
|
||||||
|
todoLogger.logTodoUpdated(ctx, todo);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("[syncTodoPresetButtonPressed] error, message={}", message, e);
|
||||||
|
todoLogger.logTodoUpdated(ctx.copy().addLogContent("exception", e), todo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CardBizState determineCardBizStateForBizTodo(Todo todo) {
|
||||||
|
if (todo.getState() == PendingMessageStateEnum.COMPLETED)
|
||||||
|
return CardBizState.COMPLETED;
|
||||||
|
if (todo.getState() == PendingMessageStateEnum.PROCESSING)
|
||||||
|
return CardBizState.PROCESSING;
|
||||||
|
if (todo.getState() == PendingMessageStateEnum.RETRACT)
|
||||||
|
return CardBizState.REVOKED;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CardBizState determineCardBizStateForFlowTodo(TodoBusiness business) {
|
||||||
|
if (business.getBizFinalState() == BizFinalStateEnum.COMPLETED)
|
||||||
|
return CardBizState.COMPLETED;
|
||||||
|
if (business.getBizFinalState() == BizFinalStateEnum.RETRACT)
|
||||||
|
return CardBizState.REVOKED;
|
||||||
|
if (business.getBizFinalState() == BizFinalStateEnum.PASSED)
|
||||||
|
return CardBizState.AGREED;
|
||||||
|
if (business.getBizFinalState() == BizFinalStateEnum.REJECTED)
|
||||||
|
return CardBizState.REJECTED;
|
||||||
|
if (business.getBizFinalState() == BizFinalStateEnum.ABORTED)
|
||||||
|
return CardBizState.ABORTED;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<BizCategoryEnum> findTodoBizCategory(JSONObject bizParam) {
|
||||||
|
if (bizParam == null)
|
||||||
|
return Optional.empty();
|
||||||
|
String category = new CardExtInfo(bizParam)
|
||||||
|
.getJsonObject().getString(TODO_CATEGORY_BIZ_PARAM_KEY);
|
||||||
|
return CodeDefinition.findByCode(BizCategoryEnum.class, category);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<String> findTodoIdentityCode(JSONObject bizParam) {
|
||||||
|
if (bizParam == null)
|
||||||
|
return Optional.empty();
|
||||||
|
String identityCode = new CardExtInfo(bizParam)
|
||||||
|
.getJsonObject().getString(TODO_IDENTITY_CODE_BIZ_PARAM_KEY);
|
||||||
|
return Optional.ofNullable(identityCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
private static class TodoCardUpdateStateRequest extends CardUpdateStateRequest {
|
||||||
|
private TodoBusiness todoBusiness;
|
||||||
|
private Todo todo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void execTransactional(Runnable runnable) {
|
||||||
|
transactionTemplate.executeWithoutResult(unused -> runnable.run());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,147 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.todo.card.workflow;
|
||||||
|
|
||||||
|
import cn.axzo.msg.center.domain.entity.Todo;
|
||||||
|
import cn.axzo.msg.center.message.service.card.interceptor.CardButtonInterceptor;
|
||||||
|
import cn.axzo.msg.center.service.ButtonV3;
|
||||||
|
import cn.axzo.msg.center.service.enums.BizFinalStateEnum;
|
||||||
|
import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
|
||||||
|
import cn.axzo.msg.center.service.enums.RouterButtonSourceEnum;
|
||||||
|
import cn.axzo.msg.center.utils.desision.DecisionValue;
|
||||||
|
import cn.axzo.workflow.common.enums.BpmnProcessTaskResultEnum;
|
||||||
|
import cn.axzo.workflow.common.enums.ButtonVisibleScopeEnum;
|
||||||
|
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo;
|
||||||
|
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskButtonVo;
|
||||||
|
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskButtonVo.BpmnButtonMetaInfoWithVisibleScope;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
class WorkflowTodoCardButtonInterceptor implements CardButtonInterceptor {
|
||||||
|
|
||||||
|
private final static Set<String> SYSTEM_BUTTONS_SENDER_SHOW = Sets.newHashSet(
|
||||||
|
BizFinalStateEnum.RETRACT.getButtonCode());
|
||||||
|
private final static Set<String> SYSTEM_BUTTONS_EXECUTOR_SHOW = Sets.newHashSet(
|
||||||
|
BizFinalStateEnum.PASSED.getButtonCode(),
|
||||||
|
BizFinalStateEnum.REJECTED.getButtonCode());
|
||||||
|
|
||||||
|
private final Todo todo;
|
||||||
|
private final BpmnTaskButtonVo taskInfo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecisionValue<Boolean> isPerformActionAvailable(ButtonV3 button) {
|
||||||
|
BizFinalStateEnum btnBizState = findButtonClickState(button).orElse(null);
|
||||||
|
return DecisionValue.decide(btnBizState != null && btnBizState.isButtonPerformActionAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecisionValue<Boolean> isActionPerformed(ButtonV3 button) {
|
||||||
|
return DecisionValue.decide(isSystemButtonActionPerformed(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSystemButtonActionPerformed(ButtonV3 button) {
|
||||||
|
return isExecutorActionPerformed(button) || isSenderActionPerformed(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isExecutorActionPerformed(ButtonV3 button) {
|
||||||
|
BizFinalStateEnum btnBizState = findButtonClickState(button).orElse(null);
|
||||||
|
if (btnBizState == null)
|
||||||
|
return false;
|
||||||
|
if (btnBizState == BizFinalStateEnum.PASSED
|
||||||
|
&& taskInfo.getExecutorTaskResult() == BpmnProcessTaskResultEnum.APPROVED)
|
||||||
|
return true;
|
||||||
|
return btnBizState == BizFinalStateEnum.REJECTED
|
||||||
|
&& taskInfo.getExecutorTaskResult() == BpmnProcessTaskResultEnum.REJECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSenderActionPerformed(ButtonV3 button) {
|
||||||
|
BizFinalStateEnum btnBizState = findButtonClickState(button).orElse(null);
|
||||||
|
if (btnBizState == null)
|
||||||
|
return false;
|
||||||
|
return btnBizState == BizFinalStateEnum.RETRACT
|
||||||
|
&& taskInfo.getInitiatorTaskResult() == BpmnProcessTaskResultEnum.CANCELED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecisionValue<String> getActionPerformedName(ButtonV3 button) {
|
||||||
|
BizFinalStateEnum btnBizState = findButtonClickState(button).orElse(null);
|
||||||
|
return btnBizState == null
|
||||||
|
? DecisionValue.notSure()
|
||||||
|
: DecisionValue.decide(btnBizState.getActionPerformedName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecisionValue<Boolean> isVisibleOnCard(ButtonV3 button) {
|
||||||
|
// 进行中隐藏所有按钮
|
||||||
|
if (todo.getState() == PendingMessageStateEnum.PROCESSING)
|
||||||
|
return DecisionValue.decide(false);
|
||||||
|
// 显示失效按钮
|
||||||
|
if (isSystemButtonActionPerformed(button))
|
||||||
|
return DecisionValue.notSure();
|
||||||
|
if (getWorkflowHideButtonKeys().contains(button.getCode()))
|
||||||
|
return DecisionValue.decide(false);
|
||||||
|
if (button.getSource() == RouterButtonSourceEnum.CUSTOM)
|
||||||
|
return DecisionValue.notSure();
|
||||||
|
BpmnButtonMetaInfoWithVisibleScope workflowButton = findWorkflowButton(button).orElse(null);
|
||||||
|
// 如果找不到流程按钮, 说明不需要显示按钮,否则是否显示由待办模版控制
|
||||||
|
return workflowButton == null ? DecisionValue.decide(false) : DecisionValue.notSure();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecisionValue<Boolean> isSenderShow(ButtonV3 button) {
|
||||||
|
if (button.getSource() == RouterButtonSourceEnum.CUSTOM)
|
||||||
|
return DecisionValue.decide(false);
|
||||||
|
return DecisionValue.decide(SYSTEM_BUTTONS_SENDER_SHOW.contains(button.getCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecisionValue<Boolean> isExecutorShow(ButtonV3 button) {
|
||||||
|
if (button.getSource() == RouterButtonSourceEnum.CUSTOM)
|
||||||
|
return DecisionValue.notSure();
|
||||||
|
if (SYSTEM_BUTTONS_EXECUTOR_SHOW.contains(button.getCode()))
|
||||||
|
return DecisionValue.decide(true);
|
||||||
|
BpmnButtonMetaInfoWithVisibleScope workflowButton = findWorkflowButton(button).orElse(null);
|
||||||
|
if (workflowButton == null)
|
||||||
|
return DecisionValue.notSure();
|
||||||
|
List<ButtonVisibleScopeEnum> scopes = workflowButton.getVisibleScopes();
|
||||||
|
return DecisionValue.decide(scopes != null
|
||||||
|
&& scopes.contains(ButtonVisibleScopeEnum.EXECUTOR)
|
||||||
|
&& !scopes.contains(ButtonVisibleScopeEnum.INITIATOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<BizFinalStateEnum> findButtonClickState(ButtonV3 button) {
|
||||||
|
if (button.getSource() == RouterButtonSourceEnum.CUSTOM)
|
||||||
|
return Optional.empty();
|
||||||
|
return BizFinalStateEnum.findButtonClickedState(button.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<BpmnButtonMetaInfoWithVisibleScope> findWorkflowButton(ButtonV3 button) {
|
||||||
|
List<BpmnButtonMetaInfoWithVisibleScope> workflowButtons = this.taskInfo.getButtons();
|
||||||
|
if (workflowButtons == null)
|
||||||
|
workflowButtons = Collections.emptyList();
|
||||||
|
return workflowButtons.stream()
|
||||||
|
.filter(workflowButton -> workflowButton.getBtnKey().equals(button.getCode()))
|
||||||
|
.findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getWorkflowHideButtonKeys() {
|
||||||
|
List<BpmnButtonMetaInfo> workflowHiddenButtons = taskInfo.getCustomHiddenButtons();
|
||||||
|
if (workflowHiddenButtons == null)
|
||||||
|
workflowHiddenButtons = Collections.emptyList();
|
||||||
|
return workflowHiddenButtons.stream()
|
||||||
|
.map(BpmnButtonMetaInfo::getBtnKey)
|
||||||
|
.collect(toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.todo.card.workflow;
|
||||||
|
|
||||||
|
import cn.axzo.msg.center.api.mq.TodoUpdateMessage;
|
||||||
|
import cn.axzo.msg.center.common.utils.BizAssertions;
|
||||||
|
import cn.axzo.msg.center.dal.TodoBusinessDao;
|
||||||
|
import cn.axzo.msg.center.dal.TodoDao;
|
||||||
|
import cn.axzo.msg.center.domain.entity.Todo;
|
||||||
|
import cn.axzo.msg.center.domain.entity.TodoBusiness;
|
||||||
|
import cn.axzo.msg.center.message.service.card.interceptor.CardButtonInterceptor;
|
||||||
|
import cn.axzo.msg.center.message.service.card.interceptor.CardButtonInterceptorFactory;
|
||||||
|
import cn.axzo.msg.center.message.service.todo.card.TodoSyncCardService;
|
||||||
|
import cn.axzo.msg.center.message.service.todo.manage.TodoLogger;
|
||||||
|
import cn.axzo.msg.center.message.service.todo.manage.TodoRequestContext;
|
||||||
|
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
|
||||||
|
import cn.axzo.msg.center.service.pending.request.CardContent;
|
||||||
|
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskButtonSearchDTO;
|
||||||
|
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskButtonVo;
|
||||||
|
import cn.axzo.workflow.starter.api.WorkflowCoreService;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
class WorkflowTodoCardButtonInterceptorFactory implements CardButtonInterceptorFactory {
|
||||||
|
|
||||||
|
private final TodoBusinessDao todoBusinessDao;
|
||||||
|
private final TodoDao todoDao;
|
||||||
|
private final WorkflowCoreService workflowCoreService;
|
||||||
|
private final TodoLogger todoLogger;
|
||||||
|
|
||||||
|
@Override @Nullable
|
||||||
|
public CardButtonInterceptor create(CardContent card) {
|
||||||
|
BizCategoryEnum category = TodoSyncCardService.findTodoBizCategory(card.getBizParam()).orElse(null);
|
||||||
|
if (category != BizCategoryEnum.FLOW)
|
||||||
|
return null;
|
||||||
|
String identityCode = TodoSyncCardService.findTodoIdentityCode(card.getBizParam()).orElse(null);
|
||||||
|
if (identityCode == null)
|
||||||
|
return null;
|
||||||
|
Todo todo = todoDao.findTodoByCode(identityCode).orElse(null);
|
||||||
|
if (todo == null) {
|
||||||
|
log.warn("todo not found. identityCode={}", card.getBizParam());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BpmnTaskButtonVo taskInfo = fetchWorkflowButtons(todo);
|
||||||
|
log.info("fetchWorkflowButtons, todoIdentityCode={}, workflowTaskInfo: {}",
|
||||||
|
todo.getIdentityCode(), JSON.toJSONString(taskInfo));
|
||||||
|
String contextName = "syncWorkflowButtons";
|
||||||
|
TodoUpdateMessage todoMessage = TodoSyncCardService.getTodoUpdateMessage().orElse(null);
|
||||||
|
if (todoMessage != null)
|
||||||
|
contextName += ":" + todoMessage.getOperation();
|
||||||
|
TodoRequestContext ctx = TodoRequestContext.create(contextName, card)
|
||||||
|
.addLogContent("workflowTaskInfo", taskInfo);
|
||||||
|
todoLogger.logTodoUpdated(ctx, todo);
|
||||||
|
return new WorkflowTodoCardButtonInterceptor(todo, taskInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
BpmnTaskButtonVo fetchWorkflowButtons(Todo todo) {
|
||||||
|
TodoBusiness business = todoBusinessDao.getBusinesses(todo).findBusiness(todo).orElse(null);
|
||||||
|
BizAssertions.assertNotNull(business, "todo business not found. todoIdentityCode={}", todo.getIdentityCode());
|
||||||
|
BpmnTaskButtonSearchDTO workflowRequest = new BpmnTaskButtonSearchDTO();
|
||||||
|
workflowRequest.setProcessInstanceId(todo.getBizCode());
|
||||||
|
workflowRequest.setTaskId(todo.getSubBizCode());
|
||||||
|
workflowRequest.setInitiatorPersonId(business.getPromoterPersonId());
|
||||||
|
workflowRequest.setExecutorPersonId(todo.getExecutorPersonId());
|
||||||
|
return workflowCoreService.findProcessSingleTaskButtons(workflowRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,10 +2,12 @@ package cn.axzo.msg.center.message.service.todo.manage;
|
|||||||
|
|
||||||
import cn.axzo.msg.center.dal.TodoBusinessDao;
|
import cn.axzo.msg.center.dal.TodoBusinessDao;
|
||||||
import cn.axzo.msg.center.dal.TodoBusinesses;
|
import cn.axzo.msg.center.dal.TodoBusinesses;
|
||||||
|
import cn.axzo.msg.center.dal.TodoDao;
|
||||||
import cn.axzo.msg.center.dal.TodoLogDao;
|
import cn.axzo.msg.center.dal.TodoLogDao;
|
||||||
import cn.axzo.msg.center.domain.entity.Todo;
|
import cn.axzo.msg.center.domain.entity.Todo;
|
||||||
import cn.axzo.msg.center.domain.entity.TodoBusiness;
|
import cn.axzo.msg.center.domain.entity.TodoBusiness;
|
||||||
import cn.axzo.msg.center.domain.entity.TodoLog;
|
import cn.axzo.msg.center.domain.entity.TodoLog;
|
||||||
|
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
|
||||||
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
|
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
|
||||||
import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
|
import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
|
||||||
import cn.axzo.msg.center.service.enums.TodoLogType;
|
import cn.axzo.msg.center.service.enums.TodoLogType;
|
||||||
@ -18,6 +20,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yanglin
|
* @author yanglin
|
||||||
*/
|
*/
|
||||||
@ -27,8 +31,11 @@ public class TodoLogger {
|
|||||||
|
|
||||||
private final TodoLogDao todoLogDao;
|
private final TodoLogDao todoLogDao;
|
||||||
private final TodoBusinessDao todoBusinessDao;
|
private final TodoBusinessDao todoBusinessDao;
|
||||||
|
private final TodoDao todoDao;
|
||||||
|
private final PendingMessageBizConfig cfg;
|
||||||
|
|
||||||
void logBusinessUpdated(TodoRequestContext ctx, TodoBusiness business) {
|
void logBusinessUpdated(TodoRequestContext ctx, TodoBusiness business) {
|
||||||
|
if (!cfg.isEnableTodoLog()) return;
|
||||||
TodoLog log = createBusinessLog(ctx, business);
|
TodoLog log = createBusinessLog(ctx, business);
|
||||||
log.setContext(ctx.getName());
|
log.setContext(ctx.getName());
|
||||||
log.addLogContents(ctx.getLogContents());
|
log.addLogContents(ctx.getLogContents());
|
||||||
@ -55,16 +62,20 @@ public class TodoLogger {
|
|||||||
logTodosUpdated(ctx, todos);
|
logTodosUpdated(ctx, todos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void logTodoUpdated(TodoRequestContext ctx, Todo todo) {
|
public void logTodoUpdated(TodoRequestContext ctx, Todo todo) {
|
||||||
logTodosUpdated(ctx, Collections.singletonList(todo));
|
logTodosUpdated(ctx, Collections.singletonList(todo));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void logTodosUpdated(TodoRequestContext ctx, List<Todo> todos) {
|
public void logTodosUpdated(TodoRequestContext ctx, List<Todo> todos) {
|
||||||
if (CollectionUtils.isEmpty(todos))
|
if (!cfg.isEnableTodoLog()) return;
|
||||||
return;
|
if (CollectionUtils.isEmpty(todos)) return;
|
||||||
TodoBusinesses businesses = todoBusinessDao.getBusinesses(todos);
|
TodoBusinesses businesses = todoBusinessDao.getBusinesses(todos);
|
||||||
ArrayList<TodoLog> logs = new ArrayList<>();
|
ArrayList<TodoLog> logs = new ArrayList<>();
|
||||||
for (Todo todo : todos) {
|
List<String> todoCodes = todos.stream()
|
||||||
|
.map(Todo::getIdentityCode)
|
||||||
|
.distinct().collect(toList());
|
||||||
|
// reload to get the up-to-date update time
|
||||||
|
for (Todo todo : todoDao.getByCodes(todoCodes)) {
|
||||||
logs.add(createTodoLog(ctx, businesses, todo)
|
logs.add(createTodoLog(ctx, businesses, todo)
|
||||||
.addLogContents(ctx.getLogContents()));
|
.addLogContents(ctx.getLogContents()));
|
||||||
}
|
}
|
||||||
@ -101,6 +112,8 @@ public class TodoLogger {
|
|||||||
log.setSubBizCode(todo.getSubBizCode());
|
log.setSubBizCode(todo.getSubBizCode());
|
||||||
log.setRequestNo(ctx.getRequestNo());
|
log.setRequestNo(ctx.getRequestNo());
|
||||||
log.setContext(ctx.getName());
|
log.setContext(ctx.getName());
|
||||||
|
log.addLogContent("todoState", todo.getState());
|
||||||
|
log.addLogContent("todoUpdateTime", todo.getUpdateAt().getTime());
|
||||||
String category = businesses.findBusiness(todo)
|
String category = businesses.findBusiness(todo)
|
||||||
.map(TodoBusiness::getBizCategory)
|
.map(TodoBusiness::getBizCategory)
|
||||||
.map(Enum::name)
|
.map(Enum::name)
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import cn.axzo.msg.center.message.domain.param.PendingMessagePushParam;
|
|||||||
import cn.axzo.msg.center.message.service.impl.v3.ModelV3Service;
|
import cn.axzo.msg.center.message.service.impl.v3.ModelV3Service;
|
||||||
import cn.axzo.msg.center.message.service.replay.RequestInfo;
|
import cn.axzo.msg.center.message.service.replay.RequestInfo;
|
||||||
import cn.axzo.msg.center.message.service.replay.RequestReplayService;
|
import cn.axzo.msg.center.message.service.replay.RequestReplayService;
|
||||||
import cn.axzo.msg.center.message.service.todo.TodoWithCardWrapper;
|
|
||||||
import cn.axzo.msg.center.message.service.todo.manage.broadcast.TodoBroadcaster;
|
import cn.axzo.msg.center.message.service.todo.manage.broadcast.TodoBroadcaster;
|
||||||
import cn.axzo.msg.center.message.service.todo.manage.broadcast.TodoMqBroadcaster;
|
import cn.axzo.msg.center.message.service.todo.manage.broadcast.TodoMqBroadcaster;
|
||||||
import cn.axzo.msg.center.message.service.todo.manage.event.HandoverEvent;
|
import cn.axzo.msg.center.message.service.todo.manage.event.HandoverEvent;
|
||||||
@ -42,13 +41,12 @@ import cn.axzo.msg.center.service.pending.request.CompletePendingMessageRequest;
|
|||||||
import cn.axzo.msg.center.service.pending.request.PresetButtonPressedRequest;
|
import cn.axzo.msg.center.service.pending.request.PresetButtonPressedRequest;
|
||||||
import cn.axzo.msg.center.service.pending.request.RevokeByTemplateCodeRequest;
|
import cn.axzo.msg.center.service.pending.request.RevokeByTemplateCodeRequest;
|
||||||
import cn.axzo.msg.center.service.pending.request.RevokePendingMessageByIdRequest;
|
import cn.axzo.msg.center.service.pending.request.RevokePendingMessageByIdRequest;
|
||||||
import cn.axzo.msg.center.service.pending.request.SetHideRequest;
|
|
||||||
import cn.axzo.msg.center.service.pending.request.TodoHandoverRequest;
|
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.UpdateBusinessFinalBizStateRequest;
|
||||||
import cn.axzo.msg.center.service.pending.request.UpdatePendingMessageByIdRequest;
|
import cn.axzo.msg.center.service.pending.request.UpdatePendingMessageByIdRequest;
|
||||||
import cn.axzo.msg.center.service.pending.response.PushPendingMessageDTO;
|
import cn.axzo.msg.center.service.pending.response.PushPendingMessageDTO;
|
||||||
|
import cn.axzo.msg.center.service.util.IdBuilder;
|
||||||
import cn.axzo.msg.center.service.util.JSONUtils;
|
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.QueryFormatter;
|
||||||
import cn.axzo.msg.center.utils.UUIDUtil;
|
import cn.axzo.msg.center.utils.UUIDUtil;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
@ -62,7 +60,6 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.joda.time.DateTime;
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.dao.DuplicateKeyException;
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
@ -72,7 +69,6 @@ import org.springframework.transaction.support.TransactionTemplate;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -91,6 +87,8 @@ import static java.util.stream.Collectors.toSet;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class TodoManager {
|
public class TodoManager {
|
||||||
|
|
||||||
|
public static final String OP_FIRE_PRESET_BUTTON_PRESSED = "firePresetButtonPressed";
|
||||||
|
|
||||||
private final TodoBusinessDao todoBusinessDao;
|
private final TodoBusinessDao todoBusinessDao;
|
||||||
private final TodoDao todoDao;
|
private final TodoDao todoDao;
|
||||||
private final TodoRecordBuilder todoRecordBuilder;
|
private final TodoRecordBuilder todoRecordBuilder;
|
||||||
@ -103,7 +101,6 @@ public class TodoManager {
|
|||||||
private final ApplicationContext applicationContext;
|
private final ApplicationContext applicationContext;
|
||||||
private final TodoBroadcaster todoBroadcaster;
|
private final TodoBroadcaster todoBroadcaster;
|
||||||
private final TransactionTemplate transactionTemplate;
|
private final TransactionTemplate transactionTemplate;
|
||||||
private final TodoWithCardWrapper todoWithCardWrapper;
|
|
||||||
private final RequestReplayService requestReplayService;
|
private final RequestReplayService requestReplayService;
|
||||||
|
|
||||||
public List<PushPendingMessageDTO> send(PendingMessagePushParam request) {
|
public List<PushPendingMessageDTO> send(PendingMessagePushParam request) {
|
||||||
@ -184,7 +181,7 @@ public class TodoManager {
|
|||||||
if (StringUtils.isBlank(business.getSampleTodoCode())
|
if (StringUtils.isBlank(business.getSampleTodoCode())
|
||||||
&& request.determineTodoType() == TodoType.EXECUTABLE)
|
&& request.determineTodoType() == TodoType.EXECUTABLE)
|
||||||
todoBusinessDao.updateSampleTodCode(business.getId(), sample.getIdentityCode());
|
todoBusinessDao.updateSampleTodCode(business.getId(), sample.getIdentityCode());
|
||||||
todoBroadcaster.fireTodoUpdates("send", todos);
|
todoBroadcaster.fireTodoUpdates("send", todos, true);
|
||||||
// 记录日志
|
// 记录日志
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
ctx.addLogContent("templateTitle", templateModel.getTemplate().getTitle())
|
ctx.addLogContent("templateTitle", templateModel.getTemplate().getTitle())
|
||||||
@ -200,7 +197,6 @@ public class TodoManager {
|
|||||||
todoLogger.logBusinessUpdated(ctx, business);
|
todoLogger.logBusinessUpdated(ctx, business);
|
||||||
todoLogger.logTodosUpdated(ctx, todos);
|
todoLogger.logTodosUpdated(ctx, todos);
|
||||||
applicationContext.publishEvent(new NewTodoEvent(this, templateModel, todos));
|
applicationContext.publishEvent(new NewTodoEvent(this, templateModel, todos));
|
||||||
todoWithCardWrapper.send(request, todos);
|
|
||||||
|
|
||||||
return todos.stream()
|
return todos.stream()
|
||||||
.map(todo -> new PushPendingMessageDTO(
|
.map(todo -> new PushPendingMessageDTO(
|
||||||
@ -264,8 +260,8 @@ public class TodoManager {
|
|||||||
destTodo.setExecutorName(request.determineToPersonName());
|
destTodo.setExecutorName(request.determineToPersonName());
|
||||||
}
|
}
|
||||||
todoDao.saveBatch(destTodos);
|
todoDao.saveBatch(destTodos);
|
||||||
todoBroadcaster.fireTodoUpdates("handover", srcTodos);
|
todoBroadcaster.fireTodoUpdates("handover", srcTodos, true);
|
||||||
todoBroadcaster.fireTodoUpdates("handover", destTodos);
|
todoBroadcaster.fireTodoUpdates("handover", destTodos, true);
|
||||||
// build handover mappings
|
// build handover mappings
|
||||||
List<TodoHandoverMapping> mappings = new ArrayList<>();
|
List<TodoHandoverMapping> mappings = new ArrayList<>();
|
||||||
for (int i = 0; i < srcTodos.size(); i++) {
|
for (int i = 0; i < srcTodos.size(); i++) {
|
||||||
@ -299,7 +295,6 @@ public class TodoManager {
|
|||||||
if (!advanceResult.isAdvanced())
|
if (!advanceResult.isAdvanced())
|
||||||
return false;
|
return false;
|
||||||
todoLogger.logTodoCompleted(ctx, advanceResult.getAdvancedTodos());
|
todoLogger.logTodoCompleted(ctx, advanceResult.getAdvancedTodos());
|
||||||
todoWithCardWrapper.cardCompleteStateByTodoList(advanceResult.getAdvancedTodos());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +305,9 @@ public class TodoManager {
|
|||||||
public boolean completeById(CompletePendingMessageByIdRequest request) {
|
public boolean completeById(CompletePendingMessageByIdRequest request) {
|
||||||
Set<Long> ids = request.determineIds();
|
Set<Long> ids = request.determineIds();
|
||||||
BizAssertions.assertNotEmpty(ids, "待办id不能为空");
|
BizAssertions.assertNotEmpty(ids, "待办id不能为空");
|
||||||
TodoRequestContext ctx = TodoRequestContext.create("completeById", request);
|
TodoRequestContext ctx = TodoRequestContext
|
||||||
|
.create("completeById", request)
|
||||||
|
.delayBroadcast(true);
|
||||||
StateAdvanceResult advanceResult = advanceState(ctx, execAdvanceBuilder()
|
StateAdvanceResult advanceResult = advanceState(ctx, execAdvanceBuilder()
|
||||||
.in(Todo::getId, ids.toArray(new Object[0]))
|
.in(Todo::getId, ids.toArray(new Object[0]))
|
||||||
.set(Todo::getState, PendingMessageStateEnum.COMPLETED));
|
.set(Todo::getState, PendingMessageStateEnum.COMPLETED));
|
||||||
@ -324,10 +321,12 @@ public class TodoManager {
|
|||||||
"businessUpdated", businessUpdated);
|
"businessUpdated", businessUpdated);
|
||||||
todoLogger.logBusinessUpdated(ctx, advanceResult.getBusiness());
|
todoLogger.logBusinessUpdated(ctx, advanceResult.getBusiness());
|
||||||
}
|
}
|
||||||
if (advanceResult.isAdvanced()) {
|
if (advanceResult.isAdvanced())
|
||||||
todoLogger.logTodoCompleted(ctx, advanceResult.getAdvancedTodos());
|
todoLogger.logTodoCompleted(ctx, advanceResult.getAdvancedTodos());
|
||||||
todoWithCardWrapper.cardCompleteStateByTodoList(advanceResult.getAdvancedTodos());
|
if (businessUpdated)
|
||||||
}
|
todoBroadcaster.fireTodoUpdates("completeById", advanceResult.getBusinessId(), true);
|
||||||
|
else
|
||||||
|
advanceResult.broadcast();
|
||||||
|
|
||||||
return advanceResult.isAdvanced() || businessUpdated;
|
return advanceResult.isAdvanced() || businessUpdated;
|
||||||
}
|
}
|
||||||
@ -354,12 +353,13 @@ public class TodoManager {
|
|||||||
"businessUpdated", businessUpdated);
|
"businessUpdated", businessUpdated);
|
||||||
todoLogger.logBusinessUpdated(ctx, advanceResult.getBusiness());
|
todoLogger.logBusinessUpdated(ctx, advanceResult.getBusiness());
|
||||||
}
|
}
|
||||||
if (advanceResult.isAdvanced()) {
|
if (advanceResult.isAdvanced())
|
||||||
todoLogger.logTodoCompleted(ctx, advanceResult.getAdvancedTodos());
|
todoLogger.logTodoCompleted(ctx, advanceResult.getAdvancedTodos());
|
||||||
todoWithCardWrapper.cardCompleteStateByTodoList(advanceResult.getAdvancedTodos());
|
if (businessUpdated)
|
||||||
}
|
todoBroadcaster.fireTodoUpdates("completeByBizCode", advanceResult.getBusinessId(), true);
|
||||||
|
else
|
||||||
|
advanceResult.broadcast();
|
||||||
|
|
||||||
advanceResult.broadcast();
|
|
||||||
return advanceResult.isAdvanced() || businessUpdated;
|
return advanceResult.isAdvanced() || businessUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,8 +398,7 @@ public class TodoManager {
|
|||||||
TodoRequestContext ctx = TodoRequestContext.create("updateBusinessFinalBizState", request)
|
TodoRequestContext ctx = TodoRequestContext.create("updateBusinessFinalBizState", request)
|
||||||
.addLogContent("updated", updated);
|
.addLogContent("updated", updated);
|
||||||
todoLogger.logBusinessUpdated(ctx, business);
|
todoLogger.logBusinessUpdated(ctx, business);
|
||||||
List<Todo> todos = todoDao.getByBusinessIds(Collections.singletonList(business.getId()));
|
todoBroadcaster.fireTodoUpdates("updateBusinessFinalBizState", business.getId(), true);
|
||||||
todoBroadcaster.fireTodoUpdates("updateBusinessFinalBizState", todos);
|
|
||||||
}
|
}
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
@ -418,7 +417,6 @@ public class TodoManager {
|
|||||||
if (!advanceResult.isAdvanced())
|
if (!advanceResult.isAdvanced())
|
||||||
return false;
|
return false;
|
||||||
todoLogger.logTodoCompleted(ctx, advanceResult.getAdvancedTodos());
|
todoLogger.logTodoCompleted(ctx, advanceResult.getAdvancedTodos());
|
||||||
todoWithCardWrapper.cardCompleteStateByTodoList(advanceResult.getAdvancedTodos());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,8 +435,7 @@ public class TodoManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
todoLogger.logTodoRollback(ctx, advanceResult.getAdvancedTodos());
|
todoLogger.logTodoRollback(ctx, advanceResult.getAdvancedTodos());
|
||||||
todoBroadcaster.fireTodoUpdates("rollbackBySubBizCode", advanceResult.getAdvancedTodos());
|
todoBroadcaster.fireTodoUpdates("rollbackBySubBizCode", advanceResult.getAdvancedTodos(), true);
|
||||||
// todoWithCardWrapper.cardRollbackStateByTodoList(advanceResult.getAdvancedTodos());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +455,6 @@ public class TodoManager {
|
|||||||
if (!advanceResult.isAdvanced())
|
if (!advanceResult.isAdvanced())
|
||||||
return false;
|
return false;
|
||||||
todoLogger.logTodoRevoked(ctx, advanceResult.getAdvancedTodos());
|
todoLogger.logTodoRevoked(ctx, advanceResult.getAdvancedTodos());
|
||||||
todoWithCardWrapper.cardRevokeStateByTodoList(advanceResult.getAdvancedTodos());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,7 +470,6 @@ public class TodoManager {
|
|||||||
if (!advanceResult.isAdvanced())
|
if (!advanceResult.isAdvanced())
|
||||||
return false;
|
return false;
|
||||||
todoLogger.logTodoRevoked(ctx, advanceResult.getAdvancedTodos());
|
todoLogger.logTodoRevoked(ctx, advanceResult.getAdvancedTodos());
|
||||||
todoWithCardWrapper.cardRevokeStateByTodoList(advanceResult.getAdvancedTodos());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,7 +485,6 @@ public class TodoManager {
|
|||||||
if (!advanceResult.isAdvanced())
|
if (!advanceResult.isAdvanced())
|
||||||
return false;
|
return false;
|
||||||
todoLogger.logTodoRevoked(ctx, advanceResult.getAdvancedTodos());
|
todoLogger.logTodoRevoked(ctx, advanceResult.getAdvancedTodos());
|
||||||
todoWithCardWrapper.cardRevokeStateByTodoList(advanceResult.getAdvancedTodos());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,7 +501,6 @@ public class TodoManager {
|
|||||||
if (!advanceResult.isAdvanced())
|
if (!advanceResult.isAdvanced())
|
||||||
return false;
|
return false;
|
||||||
todoLogger.logTodoRevoked(ctx, advanceResult.getAdvancedTodos());
|
todoLogger.logTodoRevoked(ctx, advanceResult.getAdvancedTodos());
|
||||||
todoWithCardWrapper.cardRevokeStateByTodoList(advanceResult.getAdvancedTodos());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,37 +513,11 @@ public class TodoManager {
|
|||||||
if (!advanceResult.isAdvanced())
|
if (!advanceResult.isAdvanced())
|
||||||
return false;
|
return false;
|
||||||
todoLogger.logTodoRevoked(ctx, advanceResult.getAdvancedTodos());
|
todoLogger.logTodoRevoked(ctx, advanceResult.getAdvancedTodos());
|
||||||
todoWithCardWrapper.cardRevokeStateByTodoList(advanceResult.getAdvancedTodos());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// !! update
|
// !! update
|
||||||
|
|
||||||
/**
|
|
||||||
* 将待办设置为隐藏, 隐藏有时间期限
|
|
||||||
*/
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public boolean setHide(SetHideRequest request) {
|
|
||||||
BizAssertions.assertTrue(StringUtils.isNotBlank(request.getSubBizCode()), "subBizCode不能为空");
|
|
||||||
List<Todo> todos = todoDao.getBySubBizCode(request.getSubBizCode());
|
|
||||||
if (todos.isEmpty())
|
|
||||||
return false;
|
|
||||||
int seconds = request.getHideSeconds() == null
|
|
||||||
? cfg.getPendingSetHideSeconds() : request.getHideSeconds();
|
|
||||||
Date expireTime = DateTime.now().plusSeconds(seconds).toDate();
|
|
||||||
boolean updated = todoDao.setExecutableHide(request.getSubBizCode(), expireTime);
|
|
||||||
if (updated) {
|
|
||||||
List<Todo> updatedTodos = todos.stream()
|
|
||||||
.filter(todo -> todo.getState() == PendingMessageStateEnum.HAS_BEEN_SENT)
|
|
||||||
.collect(toList());
|
|
||||||
TodoRequestContext ctx = TodoRequestContext.create("setHide", request)
|
|
||||||
.addLogContent("expiredTime", expireTime.getTime())
|
|
||||||
.addLogContent("readableExpiredTime", DateFormatUtil.toReadableString(expireTime));
|
|
||||||
todoLogger.logTodosUpdated(ctx, updatedTodos);
|
|
||||||
}
|
|
||||||
return updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将待办设置为执行中
|
* 将待办设置为执行中
|
||||||
*/
|
*/
|
||||||
@ -571,8 +538,7 @@ public class TodoManager {
|
|||||||
request.put("subBizCodes", subBizCodes);
|
request.put("subBizCodes", subBizCodes);
|
||||||
TodoRequestContext ctx = TodoRequestContext.create("batchSetProcessing", request);
|
TodoRequestContext ctx = TodoRequestContext.create("batchSetProcessing", request);
|
||||||
todoLogger.logSetTodoProcessing(ctx, todos);
|
todoLogger.logSetTodoProcessing(ctx, todos);
|
||||||
todoBroadcaster.fireTodoUpdates("batchSetProcessing", todos);
|
todoBroadcaster.fireTodoUpdates("batchSetProcessing", todos, true);
|
||||||
todoWithCardWrapper.cardProcessingStateByTodoList(todos);
|
|
||||||
}
|
}
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
@ -609,7 +575,7 @@ public class TodoManager {
|
|||||||
.addLogContent("updatedRouterParam", routerParam)
|
.addLogContent("updatedRouterParam", routerParam)
|
||||||
.addLogContent("updatedTemplateCode", request.getTemplateCode());
|
.addLogContent("updatedTemplateCode", request.getTemplateCode());
|
||||||
todoLogger.logBusinessUpdated(ctx, business);
|
todoLogger.logBusinessUpdated(ctx, business);
|
||||||
//TODO todoWithCardWrapper.send
|
todoBroadcaster.fireTodoUpdates("updateBusinessById", business.getId(), true);
|
||||||
}
|
}
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
@ -620,31 +586,23 @@ public class TodoManager {
|
|||||||
* 点击预设按钮
|
* 点击预设按钮
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public boolean firePresetButtonPressed(PresetButtonPressedRequest request, boolean isSyncCard) {
|
public boolean firePresetButtonPressed(PresetButtonPressedRequest request, boolean syncCardState) {
|
||||||
Todo todo = todoDao.findTodoByCode(request.getIdentityCode()).orElse(null);
|
Todo todo = todoDao.findTodoByCode(request.getIdentityCode()).orElse(null);
|
||||||
if (todo == null)
|
if (todo == null)
|
||||||
return false;
|
return false;
|
||||||
TodoRequestContext ctx = TodoRequestContext.create("firePresetButtonPressed", request)
|
TodoRequestContext ctx = TodoRequestContext.create(OP_FIRE_PRESET_BUTTON_PRESSED, request)
|
||||||
.addLogContent("presetButtonType", request.getPresetButtonType());
|
.addLogContent("presetButtonType", request.getPresetButtonType())
|
||||||
|
.addLogContent("syncCardState", syncCardState);
|
||||||
|
if (!syncCardState)
|
||||||
|
ctx.disableUpdateCard();
|
||||||
StateAdvanceResult advanceResult = advanceState(ctx, execAdvanceBuilder()
|
StateAdvanceResult advanceResult = advanceState(ctx, execAdvanceBuilder()
|
||||||
.eq(Todo::getIdentityCode, request.getIdentityCode())
|
.eq(Todo::getIdentityCode, request.getIdentityCode())
|
||||||
.set(Todo::getState, PendingMessageStateEnum.COMPLETED));
|
.set(Todo::getState, PendingMessageStateEnum.COMPLETED));
|
||||||
// isExecCompleted 可以排除是抄送待办的情况
|
if (advanceResult.isAdvanced()) {
|
||||||
boolean isAdvancedOrCompleted = advanceResult.isAdvanced() || todo.isExecCompleted();
|
|
||||||
// 支持重复发mq消息
|
|
||||||
if (isAdvancedOrCompleted) {
|
|
||||||
sendMqMessageOnPresetButtonPressed(ctx, request, todo);
|
sendMqMessageOnPresetButtonPressed(ctx, request, todo);
|
||||||
todoBroadcaster.fireTodoUpdates("presetButtonPressed", todo);
|
|
||||||
todoWithCardWrapper.fireCardWhenPresetButtonPressedByTodo(request, todo, isSyncCard);
|
|
||||||
|
|
||||||
// 如果不是重复发送, 就只记一条日志. 如果是重复发送, 就单独记录一条日志
|
|
||||||
if (!advanceResult.isAdvanced())
|
|
||||||
todoLogger.logTodoUpdated(ctx, todo);
|
|
||||||
}
|
|
||||||
// 如果不是重复发送, 就只记一条日志. 所以这个记录日志不能提前
|
|
||||||
if (advanceResult.isAdvanced())
|
|
||||||
todoLogger.logTodoCompleted(ctx, advanceResult.getAdvancedTodos());
|
todoLogger.logTodoCompleted(ctx, advanceResult.getAdvancedTodos());
|
||||||
return isAdvancedOrCompleted;
|
}
|
||||||
|
return advanceResult.isAdvanced();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -662,9 +620,13 @@ public class TodoManager {
|
|||||||
try {
|
try {
|
||||||
mqProducer.send(MqMessageRecord
|
mqProducer.send(MqMessageRecord
|
||||||
.builder(MqMessageType.TODO_PRESET_BUTTON_PRESSED, message)
|
.builder(MqMessageType.TODO_PRESET_BUTTON_PRESSED, message)
|
||||||
.messageKey(todo.getId())
|
.messageKey(todo.getIdentityCode())
|
||||||
.operatorId(request.getOperatorId())
|
.operatorId(request.getOperatorId())
|
||||||
.shardingKey(todo.getTemplateCode())
|
.shardingKey(IdBuilder.builder()
|
||||||
|
.append(todo.getTemplateCode())
|
||||||
|
.append(todo.getBizCode())
|
||||||
|
.append(todo.getSubBizCode())
|
||||||
|
.build())
|
||||||
.build());
|
.build());
|
||||||
ctx.addLogContent("sendMqMessage", ImmutableMap.of("isSuccess", "true"));
|
ctx.addLogContent("sendMqMessage", ImmutableMap.of("isSuccess", "true"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -692,6 +654,7 @@ public class TodoManager {
|
|||||||
return false;
|
return false;
|
||||||
ImmutableMap<String, Object> request = ImmutableMap.of("personId", personId, "identityCode", identityCode);
|
ImmutableMap<String, Object> request = ImmutableMap.of("personId", personId, "identityCode", identityCode);
|
||||||
TodoRequestContext ctx = TodoRequestContext.create("setCopiedToMeRead", request)
|
TodoRequestContext ctx = TodoRequestContext.create("setCopiedToMeRead", request)
|
||||||
|
.disableUpdateCard()
|
||||||
.addLogContent("state", PendingMessageStateEnum.READ)
|
.addLogContent("state", PendingMessageStateEnum.READ)
|
||||||
.addLogContent("isSetAllRead", StringUtils.isBlank(identityCode));
|
.addLogContent("isSetAllRead", StringUtils.isBlank(identityCode));
|
||||||
StateAdvanceResult advanceResult = advanceState(ctx, copiedAdvanceBuilder()
|
StateAdvanceResult advanceResult = advanceState(ctx, copiedAdvanceBuilder()
|
||||||
@ -724,7 +687,7 @@ public class TodoManager {
|
|||||||
"currentStateSample", noStateBusinessTodos.sampleTodo());
|
"currentStateSample", noStateBusinessTodos.sampleTodo());
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
if (cfg.isLogAdvanceTodoStateFail())
|
if (cfg.isLogAdvanceTodoStateFail())
|
||||||
todoLogger.logTodosUpdated(ctx, noStateBusinessTodos.todos);
|
todoLogger.logTodosUpdated(ctx.copy(String.format("%s:fail", ctx.getName())), noStateBusinessTodos.todos);
|
||||||
// throw an error? dunno
|
// throw an error? dunno
|
||||||
log.warn("尝试推进待办状态, 但是 {}. ctx={}, query={}, currentStateSample={}",
|
log.warn("尝试推进待办状态, 但是 {}. ctx={}, query={}, currentStateSample={}",
|
||||||
failReason, ctx, QueryFormatter.format(builder.getQuery()), noStateBusinessTodos.sampleTodo());
|
failReason, ctx, QueryFormatter.format(builder.getQuery()), noStateBusinessTodos.sampleTodo());
|
||||||
@ -745,7 +708,7 @@ public class TodoManager {
|
|||||||
broadcastHandler = () -> {
|
broadcastHandler = () -> {
|
||||||
if (!updatedTodoIds.isEmpty()) {
|
if (!updatedTodoIds.isEmpty()) {
|
||||||
List<Todo> updatedTodos = todoDao.listByIds(updatedTodoIds);
|
List<Todo> updatedTodos = todoDao.listByIds(updatedTodoIds);
|
||||||
todoBroadcaster.fireTodoUpdates(ctx.getName(), updatedTodos);
|
todoBroadcaster.fireTodoUpdates(ctx.getName(), updatedTodos, ctx.isUpdateCard());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!ctx.isDelayBroadcast())
|
if (!ctx.isDelayBroadcast())
|
||||||
|
|||||||
@ -3,7 +3,9 @@ package cn.axzo.msg.center.message.service.todo.manage;
|
|||||||
import cn.axzo.msg.center.common.utils.BizAssertions;
|
import cn.axzo.msg.center.common.utils.BizAssertions;
|
||||||
import cn.axzo.msg.center.utils.UUIDUtil;
|
import cn.axzo.msg.center.utils.UUIDUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.google.common.base.Throwables;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@ -18,6 +20,7 @@ public class TodoRequestContext {
|
|||||||
private final String requestNo;
|
private final String requestNo;
|
||||||
private final Map<String, Object> logContents = new LinkedHashMap<>();
|
private final Map<String, Object> logContents = new LinkedHashMap<>();
|
||||||
private boolean delayBroadcast = false;
|
private boolean delayBroadcast = false;
|
||||||
|
private boolean updateCard = true;
|
||||||
|
|
||||||
private TodoRequestContext(String name, String requestNo, Object request) {
|
private TodoRequestContext(String name, String requestNo, Object request) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@ -35,7 +38,8 @@ public class TodoRequestContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static TodoRequestContext create(String name, String requestNo, Object request) {
|
public static TodoRequestContext create(String name, String requestNo, Object request) {
|
||||||
return new TodoRequestContext(name, requestNo, request);
|
String finalRequestNo = StringUtils.isBlank(requestNo) ? UUIDUtil.uuidString() : requestNo;
|
||||||
|
return new TodoRequestContext(name, finalRequestNo, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TodoRequestContext addLogContent(String name, Object... fields) {
|
public TodoRequestContext addLogContent(String name, Object... fields) {
|
||||||
@ -53,15 +57,28 @@ public class TodoRequestContext {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TodoRequestContext disableUpdateCard() {
|
||||||
|
this.updateCard = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public TodoRequestContext addLogContent(String name, Object value) {
|
public TodoRequestContext addLogContent(String name, Object value) {
|
||||||
if (name == null || value == null)
|
if (name == null || value == null)
|
||||||
return this;
|
return this;
|
||||||
if (!logContents.containsKey(name))
|
if (!logContents.containsKey(name)) {
|
||||||
logContents.put(name, value);
|
if (value instanceof Throwable)
|
||||||
|
logContents.put(name, Throwables.getStackTraceAsString((Throwable) value));
|
||||||
|
else
|
||||||
|
logContents.put(name, value);
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TodoRequestContext copy() {
|
public TodoRequestContext copy() {
|
||||||
|
return copy(this.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TodoRequestContext copy(String name) {
|
||||||
TodoRequestContext copy = new TodoRequestContext(name, requestNo);
|
TodoRequestContext copy = new TodoRequestContext(name, requestNo);
|
||||||
copy.logContents.putAll(logContents);
|
copy.logContents.putAll(logContents);
|
||||||
return copy;
|
return copy;
|
||||||
|
|||||||
@ -26,11 +26,16 @@ public class TodoBroadcaster {
|
|||||||
private final TodoPullBroadcaster todoPullBroadcaster;
|
private final TodoPullBroadcaster todoPullBroadcaster;
|
||||||
private final TodoDao todoDao;
|
private final TodoDao todoDao;
|
||||||
|
|
||||||
public void fireTodoUpdates(String operation, Todo todo) {
|
public void fireTodoUpdates(String operation, Long businessId, boolean updateCard) {
|
||||||
fireTodoUpdates(operation, Collections.singletonList(todo));
|
List<Todo> todos = todoDao.getByBusinessIds(Collections.singletonList(businessId));
|
||||||
|
fireTodoUpdates(operation, todos, updateCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fireTodoUpdates(String operation, List<Todo> todos) {
|
public void fireTodoUpdates(String operation, Todo todo, boolean updateCard) {
|
||||||
|
fireTodoUpdates(operation, Collections.singletonList(todo), updateCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fireTodoUpdates(String operation, List<Todo> todos, boolean updateCard) {
|
||||||
if (CollectionUtils.isEmpty(todos))
|
if (CollectionUtils.isEmpty(todos))
|
||||||
return;
|
return;
|
||||||
List<Long> todoIds = todos.stream()
|
List<Long> todoIds = todos.stream()
|
||||||
@ -42,8 +47,8 @@ public class TodoBroadcaster {
|
|||||||
log.warn("发送待办通知时, 查询不到最新的待办信息. todoIds={}", JSON.toJSONString(todoIds));
|
log.warn("发送待办通知时, 查询不到最新的待办信息. todoIds={}", JSON.toJSONString(todoIds));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
todoMqBroadcaster.fireTodoUpdated(operation, todos);
|
todoMqBroadcaster.fireTodoUpdated(operation, upToDateTodos, updateCard);
|
||||||
todoPullBroadcaster.fireTodoChanged(todos);
|
todoPullBroadcaster.fireTodoChanged(upToDateTodos);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -11,6 +11,7 @@ import cn.axzo.msg.center.message.service.todo.manage.TodoExt;
|
|||||||
import cn.axzo.msg.center.mq.MqMessageRecord;
|
import cn.axzo.msg.center.mq.MqMessageRecord;
|
||||||
import cn.axzo.msg.center.mq.MqProducer;
|
import cn.axzo.msg.center.mq.MqProducer;
|
||||||
import cn.axzo.msg.center.service.enums.MqMessageType;
|
import cn.axzo.msg.center.service.enums.MqMessageType;
|
||||||
|
import cn.axzo.msg.center.service.util.IdBuilder;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -26,20 +27,25 @@ public class TodoMqBroadcaster {
|
|||||||
private final MqProducer mqProducer;
|
private final MqProducer mqProducer;
|
||||||
private final TodoBusinessDao todoBusinessDao;
|
private final TodoBusinessDao todoBusinessDao;
|
||||||
|
|
||||||
public void fireTodoUpdated(String operation, List<Todo> todos) {
|
public void fireTodoUpdated(String operation, List<Todo> todos, boolean updateCard) {
|
||||||
TodoBusinesses businesses = todoBusinessDao.getBusinesses(todos);
|
TodoBusinesses businesses = todoBusinessDao.getBusinesses(todos);
|
||||||
for (Todo todo : todos)
|
for (Todo todo : todos)
|
||||||
fireTodoUpdated(operation, businesses, todo);
|
fireTodoUpdated(operation, businesses, todo, updateCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireTodoUpdated(String operation, TodoBusinesses businesses, Todo todo) {
|
private void fireTodoUpdated(String operation, TodoBusinesses businesses, Todo todo, boolean updateCard) {
|
||||||
TodoUpdateMessage message = new TodoUpdateMessage();
|
TodoUpdateMessage message = new TodoUpdateMessage();
|
||||||
message.setOperation(operation);
|
message.setOperation(operation);
|
||||||
message.setUpdatedTodo(createTodoInfo(businesses, todo));
|
message.setUpdatedTodo(createTodoInfo(businesses, todo));
|
||||||
|
message.setUpdateCard(updateCard);
|
||||||
mqProducer.send(MqMessageRecord
|
mqProducer.send(MqMessageRecord
|
||||||
.builder(MqMessageType.TODO_STATE_UPDATE, message)
|
.builder(MqMessageType.TODO_STATE_UPDATE, message)
|
||||||
.messageKey(todo.getId())
|
.messageKey(todo.getIdentityCode())
|
||||||
.shardingKey(todo.getTemplateCode())
|
.shardingKey(IdBuilder.builder()
|
||||||
|
.append(todo.getTemplateCode())
|
||||||
|
.append(todo.getBizCode())
|
||||||
|
.append(todo.getSubBizCode())
|
||||||
|
.build())
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import org.apache.ibatis.plugin.Interceptor;
|
|||||||
import org.apache.ibatis.plugin.Intercepts;
|
import org.apache.ibatis.plugin.Intercepts;
|
||||||
import org.apache.ibatis.plugin.Invocation;
|
import org.apache.ibatis.plugin.Invocation;
|
||||||
import org.apache.ibatis.plugin.Signature;
|
import org.apache.ibatis.plugin.Signature;
|
||||||
|
import org.apache.ibatis.reflection.DefaultReflectorFactory;
|
||||||
import org.apache.ibatis.reflection.MetaObject;
|
import org.apache.ibatis.reflection.MetaObject;
|
||||||
import org.apache.ibatis.reflection.SystemMetaObject;
|
import org.apache.ibatis.reflection.SystemMetaObject;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
@ -36,12 +37,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
args = {Connection.class, Integer.class})})
|
args = {Connection.class, Integer.class})})
|
||||||
public class BeautifulPaginationInterceptor implements Interceptor, Ordered {
|
public class BeautifulPaginationInterceptor implements Interceptor, Ordered {
|
||||||
|
|
||||||
|
private static final DefaultReflectorFactory REFLECTOR_FACTORY = new DefaultReflectorFactory();
|
||||||
private final PaginationInterceptor delegate = new CustomPaginationInterceptor();
|
private final PaginationInterceptor delegate = new CustomPaginationInterceptor();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object intercept(Invocation invocation) throws Throwable {
|
public Object intercept(Invocation invocation) throws Throwable {
|
||||||
StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
|
StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
|
||||||
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
|
MetaObject metaObject = systemMetaForObject(statementHandler);
|
||||||
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
|
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
|
||||||
if (SqlCommandType.SELECT != mappedStatement.getSqlCommandType()
|
if (SqlCommandType.SELECT != mappedStatement.getSqlCommandType()
|
||||||
|| StatementType.CALLABLE == mappedStatement.getStatementType()) {
|
|| StatementType.CALLABLE == mappedStatement.getStatementType()) {
|
||||||
@ -70,7 +72,7 @@ public class BeautifulPaginationInterceptor implements Interceptor, Ordered {
|
|||||||
private static String tryBuildSql(Invocation invocation) {
|
private static String tryBuildSql(Invocation invocation) {
|
||||||
Connection connection = (Connection) (invocation.getArgs()[0]);
|
Connection connection = (Connection) (invocation.getArgs()[0]);
|
||||||
StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
|
StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
|
||||||
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
|
MetaObject metaObject = systemMetaForObject(statementHandler);
|
||||||
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
|
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
|
||||||
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
|
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
|
||||||
try (PreparedStatement statement = connection.prepareStatement(boundSql.getSql())) {
|
try (PreparedStatement statement = connection.prepareStatement(boundSql.getSql())) {
|
||||||
@ -86,6 +88,13 @@ public class BeautifulPaginationInterceptor implements Interceptor, Ordered {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MetaObject systemMetaForObject(Object object) {
|
||||||
|
return MetaObject.forObject(object,
|
||||||
|
SystemMetaObject.DEFAULT_OBJECT_FACTORY,
|
||||||
|
SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
|
||||||
|
REFLECTOR_FACTORY);
|
||||||
|
}
|
||||||
|
|
||||||
private static class CustomPaginationInterceptor extends PaginationInterceptor {
|
private static class CustomPaginationInterceptor extends PaginationInterceptor {
|
||||||
|
|
||||||
public CustomPaginationInterceptor() {
|
public CustomPaginationInterceptor() {
|
||||||
|
|||||||
@ -63,7 +63,7 @@ public class ProxyStatement extends StatementWrapper {
|
|||||||
|
|
||||||
private boolean canWarnPeriodically() {
|
private boolean canWarnPeriodically() {
|
||||||
int maxWarnTimes = props.getRowCount().getPeriodMaxWarnTimes();
|
int maxWarnTimes = props.getRowCount().getPeriodMaxWarnTimes();
|
||||||
return rowCount % 2000 == 0 && periodWarnTimes <= maxWarnTimes;
|
return rowCount % 100 == 0 && periodWarnTimes <= maxWarnTimes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
package cn.axzo.msg.center.mq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
public enum ConsumerIsolation {
|
||||||
|
|
||||||
|
TODO_SYNC_CARD_BIZ,
|
||||||
|
TODO_SYNC_CARD_FLOW,
|
||||||
|
TODO_PRESET_BUTTON_CLICKED_SYNC_CARD,
|
||||||
|
CARD_PRESET_BUTTON_CLICKED_SYNC_TODO
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private static final ThreadLocal<ConsumerIsolation> INSTANCE = new ThreadLocal<>();
|
||||||
|
|
||||||
|
public static void setIsolation(ConsumerIsolation isolation) {
|
||||||
|
INSTANCE.set(isolation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConsumerIsolation getIsolation() {
|
||||||
|
return INSTANCE.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearIsolation() {
|
||||||
|
INSTANCE.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
package cn.axzo.msg.center.mq;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.BaseListener;
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
|
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||||
|
import cn.axzo.framework.rocketmq.EventHandler;
|
||||||
|
import cn.axzo.msg.center.service.enums.MqMessageType;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.rocketmq.common.message.MessageExt;
|
||||||
|
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
public abstract class IsolationMQListener extends BaseListener
|
||||||
|
implements RocketMQListener<MessageExt>, EventHandler, InitializingBean {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EventConsumer eventConsumer;
|
||||||
|
private final ConsumerIsolation isolation;
|
||||||
|
private final Event.EventCode eventCode;
|
||||||
|
|
||||||
|
protected IsolationMQListener(ConsumerIsolation isolation, MqMessageType mqMessageType) {
|
||||||
|
this(isolation, mqMessageType.getEventCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IsolationMQListener(ConsumerIsolation isolation, Event.EventCode eventCode) {
|
||||||
|
this.isolation = isolation;
|
||||||
|
this.eventCode = eventCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(MessageExt message) {
|
||||||
|
ConsumerIsolation.setIsolation(isolation);
|
||||||
|
try {
|
||||||
|
super.onEvent(message, eventConsumer);
|
||||||
|
} finally {
|
||||||
|
ConsumerIsolation.clearIsolation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void onEvent(Event event, EventConsumer.Context context) {
|
||||||
|
if (ConsumerIsolation.getIsolation() == isolation)
|
||||||
|
onEventImpl(event, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
eventConsumer.registerHandler(eventCode, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void onEventImpl(Event event, EventConsumer.Context context);
|
||||||
|
}
|
||||||
@ -11,7 +11,6 @@ import cn.axzo.framework.rocketmq.RocketMQEventProducer.RocketMQMessageMeta;
|
|||||||
import cn.axzo.framework.rocketmq.utils.TraceUtils;
|
import cn.axzo.framework.rocketmq.utils.TraceUtils;
|
||||||
import cn.axzo.msg.center.api.mq.MqMessage;
|
import cn.axzo.msg.center.api.mq.MqMessage;
|
||||||
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
|
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -41,8 +40,9 @@ import java.util.function.Consumer;
|
|||||||
public class RocketMQConfig {
|
public class RocketMQConfig {
|
||||||
|
|
||||||
public static final String APP_NAME = "MSG-CENTER";
|
public static final String APP_NAME = "MSG-CENTER";
|
||||||
|
public static final String MSG_CENTER_TOPIC = "topic_msg_center_${spring.profiles.active}";
|
||||||
|
|
||||||
@Value("topic_msg_center_${spring.profiles.active}")
|
@Value(MSG_CENTER_TOPIC)
|
||||||
private String topic;
|
private String topic;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ -126,7 +126,7 @@ public class RocketMQConfig {
|
|||||||
eventConsumer.onEvent(value, EventConsumer.Context.builder()
|
eventConsumer.onEvent(value, EventConsumer.Context.builder()
|
||||||
.msgId(message.getMsgId())
|
.msgId(message.getMsgId())
|
||||||
.ext(ImmutableMap.of("topic", topic))
|
.ext(ImmutableMap.of("topic", topic))
|
||||||
.headers(Maps.transformValues(headers, header -> Optional.ofNullable(header).map(String::getBytes).orElse(new byte[] {})))
|
.headers(Maps.transformValues(headers, header -> Optional.ofNullable(header).map(String::getBytes).orElse(new byte[]{})))
|
||||||
.lagSupplier(() -> partitionLag)
|
.lagSupplier(() -> partitionLag)
|
||||||
.maxAllowElapsedMillis(cfg.getMsgCenterMqSelfConsumeMaxExecMs())
|
.maxAllowElapsedMillis(cfg.getMsgCenterMqSelfConsumeMaxExecMs())
|
||||||
.build());
|
.build());
|
||||||
@ -140,26 +140,4 @@ public class RocketMQConfig {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 卡片变更,同步状态至待办TODO
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RocketMQMessageListener(topic = "topic_msg_center_${spring.profiles.active}",
|
|
||||||
consumerGroup = "GID_topic_card_change_state_sync_todo_${spring.application.name}_${spring.profiles.active}",
|
|
||||||
consumeMode = ConsumeMode.ORDERLY,
|
|
||||||
nameServer = "${rocketmq.name-server}"
|
|
||||||
)
|
|
||||||
public static class CardChangeStateSyncTodoListener extends BaseListener implements RocketMQListener<MessageExt> {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private EventConsumer eventConsumer;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMessage(MessageExt message) {
|
|
||||||
log.info("CardChangeStateSyncTodoListener onMessage,message:{}", JSON.toJSONString(message));
|
|
||||||
super.onEvent(message, eventConsumer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package cn.axzo.msg.center.utils.desision;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
public enum Decision {
|
||||||
|
NOT_SURE, DECIDED
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package cn.axzo.msg.center.utils.desision;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class DecisionValue<T> {
|
||||||
|
|
||||||
|
private static final DecisionValue<?> NOT_SURE = new DecisionValue<>(Decision.NOT_SURE, null);
|
||||||
|
|
||||||
|
private final Decision decision;
|
||||||
|
@Getter private final T value;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> DecisionValue<T> notSure() {
|
||||||
|
return (DecisionValue<T>) NOT_SURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> DecisionValue<T> decide(T value) {
|
||||||
|
return new DecisionValue<>(Decision.DECIDED, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T orElse(Supplier<T> supplier) {
|
||||||
|
return isDecided() ? value : supplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T orElse(T value) {
|
||||||
|
return isDecided() ? this.value : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDecided() {
|
||||||
|
return decision == Decision.DECIDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -148,4 +148,9 @@ public class CardInfo {
|
|||||||
*/
|
*/
|
||||||
private String subtitle;
|
private String subtitle;
|
||||||
|
|
||||||
|
public JSONObject determineBizParam() {
|
||||||
|
if (bizParam == null)
|
||||||
|
bizParam = new JSONObject();
|
||||||
|
return bizParam;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,4 +30,5 @@ public class CardPresetButtonPressedMessage extends MqMessage implements Seriali
|
|||||||
*/
|
*/
|
||||||
private CardInfo cardInfo;
|
private CardInfo cardInfo;
|
||||||
|
|
||||||
|
private String batchNo;
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package cn.axzo.msg.center.api.mq;
|
package cn.axzo.msg.center.api.mq;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ import lombok.EqualsAndHashCode;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class TodoUpdateMessage extends MqMessage {
|
public class TodoUpdateMessage extends MqMessage {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 什么操作导致这次变化
|
* 什么操作导致这次变化
|
||||||
*/
|
*/
|
||||||
@ -17,4 +19,15 @@ public class TodoUpdateMessage extends MqMessage {
|
|||||||
* 待办信息
|
* 待办信息
|
||||||
*/
|
*/
|
||||||
private TodoInfo updatedTodo;
|
private TodoInfo updatedTodo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否需要更新卡片
|
||||||
|
*/
|
||||||
|
private boolean updateCard;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JSON.toJSONString(this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,12 +1,17 @@
|
|||||||
package cn.axzo.msg.center.service;
|
package cn.axzo.msg.center.service;
|
||||||
|
|
||||||
|
import cn.axzo.msg.center.service.enums.ButtonStyleEnum;
|
||||||
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
||||||
|
import cn.axzo.msg.center.service.enums.RouterButtonSourceEnum;
|
||||||
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
|
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
|
||||||
|
import cn.axzo.msg.center.service.pending.response.MessageButton;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yanglin
|
* @author yanglin
|
||||||
*/
|
*/
|
||||||
public interface ButtonV3 {
|
public interface ButtonV3 extends MessageButton {
|
||||||
|
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
@ -22,14 +27,14 @@ public interface ButtonV3 {
|
|||||||
|
|
||||||
RouterCategoryEnum getCategory();
|
RouterCategoryEnum getCategory();
|
||||||
|
|
||||||
|
RouterButtonSourceEnum getSource();
|
||||||
|
|
||||||
|
List<ButtonStyleEnum> getStyles();
|
||||||
|
|
||||||
default boolean determineIsPendingShow() {
|
default boolean determineIsPendingShow() {
|
||||||
return getPendingShow() != null && getPendingShow();
|
return getPendingShow() != null && getPendingShow();
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean determineIsExecutorShow() {
|
|
||||||
return getExecutorShow() != null && getExecutorShow();
|
|
||||||
}
|
|
||||||
|
|
||||||
default boolean isPerformActionAvailable() {
|
default boolean isPerformActionAvailable() {
|
||||||
return determineIsPendingShow() || getCategory() == RouterCategoryEnum.PRESET_BUTTON;
|
return determineIsPendingShow() || getCategory() == RouterCategoryEnum.PRESET_BUTTON;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package cn.axzo.msg.center.service.domain;
|
package cn.axzo.msg.center.service.domain;
|
||||||
|
|
||||||
|
import cn.axzo.framework.jackson.utility.JSON;
|
||||||
import cn.axzo.msg.center.service.domain.url.AppUrl;
|
import cn.axzo.msg.center.service.domain.url.AppUrl;
|
||||||
import cn.axzo.msg.center.service.domain.url.WebUrl;
|
import cn.axzo.msg.center.service.domain.url.WebUrl;
|
||||||
import cn.axzo.msg.center.service.enums.WebPageOpenStrategy;
|
import cn.axzo.msg.center.service.enums.WebPageOpenStrategy;
|
||||||
@ -17,6 +18,8 @@ import lombok.Setter;
|
|||||||
@Getter
|
@Getter
|
||||||
public class UrlConfig {
|
public class UrlConfig {
|
||||||
|
|
||||||
|
private String sameUrlForAllPlatforms;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PC(OMS)
|
* PC(OMS)
|
||||||
*/
|
*/
|
||||||
@ -129,4 +132,14 @@ public class UrlConfig {
|
|||||||
getOrCreateAppWorker().setIos(appUrl);
|
getOrCreateAppWorker().setIos(appUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setWebOpenStrategy(WebPageOpenStrategy openStrategy) {
|
||||||
|
if (pcCms != null) pcCms.setOpenStrategy(openStrategy);
|
||||||
|
if (pcOms != null) pcOms.setOpenStrategy(openStrategy);
|
||||||
|
if (pcGaGeneral != null) pcGaGeneral.setOpenStrategy(openStrategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UrlConfig copy() {
|
||||||
|
return JSON.parseObject(JSON.toJSONString(this), UrlConfig.class);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ public class PeerPerson {
|
|||||||
return person;
|
return person;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PeerPerson newPeerPerson(Long personId, Long ouId, Long workspaceId) {
|
public static PeerPerson create(Long personId, Long ouId, Long workspaceId) {
|
||||||
PeerPerson person = new PeerPerson();
|
PeerPerson person = new PeerPerson();
|
||||||
person.setPersonId(personId);
|
person.setPersonId(personId);
|
||||||
person.setOuId(ouId);
|
person.setOuId(ouId);
|
||||||
|
|||||||
@ -13,10 +13,15 @@ import lombok.Getter;
|
|||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public enum BizCategoryEnum {
|
public enum BizCategoryEnum implements CodeDefinition<String> {
|
||||||
|
|
||||||
FLOW("流程"), OTHER("其它"),
|
FLOW("流程"), OTHER("其它"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String desc;
|
private final String desc;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCode() {
|
||||||
|
return name();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,14 +3,15 @@ package cn.axzo.msg.center.service.enums;
|
|||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description
|
|
||||||
* 业务终态的状态枚举,包含审批流的相关状态
|
|
||||||
*
|
|
||||||
* @author cold_blade
|
* @author cold_blade
|
||||||
* @date 2023/11/7
|
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
|
* @description 业务终态的状态枚举,包含审批流的相关状态
|
||||||
|
* @date 2023/11/7
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
@ -19,28 +20,42 @@ public enum BizFinalStateEnum implements CodeDefinition<String> {
|
|||||||
/**
|
/**
|
||||||
* 已处理
|
* 已处理
|
||||||
*/
|
*/
|
||||||
COMPLETED("https://static.axzo.cn/fe-static/uni-icon/public/seal-1%23_%241699341908382.png"),
|
COMPLETED("", "", "https://static.axzo.cn/fe-static/uni-icon/public/seal-1%23_%241699341908382.png"),
|
||||||
/**
|
/**
|
||||||
* 已撤销
|
* 已撤销
|
||||||
*/
|
*/
|
||||||
RETRACT("https://static.axzo.cn/fe-static/uni-icon/native/%E5%8E%9F%E7%A8%BF%23_%241711338477975.png"),
|
RETRACT("BPMN_REVOCATION", "已撤销", "https://static.axzo.cn/fe-static/uni-icon/native/%E5%8E%9F%E7%A8%BF%23_%241711338477975.png"),
|
||||||
/**
|
/**
|
||||||
* 已通过
|
* 已通过
|
||||||
*/
|
*/
|
||||||
PASSED("https://static.axzo.cn/fe-static/uni-icon/public/seal-4%23_%241699341908374.png"),
|
PASSED("BPMN_APPROVE", "已同意", "https://static.axzo.cn/fe-static/uni-icon/public/seal-4%23_%241699341908374.png"),
|
||||||
/**
|
/**
|
||||||
* 已拒绝
|
* 已拒绝
|
||||||
*/
|
*/
|
||||||
REJECTED("https://static.axzo.cn/fe-static/uni-icon/public/seal-2%23_%241699341908381.png"),
|
REJECTED("BPMN_REJECT", "已驳回", "https://static.axzo.cn/fe-static/uni-icon/public/seal-2%23_%241699341908381.png"),
|
||||||
/**
|
/**
|
||||||
* 已终止
|
* 已终止
|
||||||
*/
|
*/
|
||||||
ABORTED("https://axzo-public.oss-cn-chengdu.aliyuncs.com/%E5%8D%B0%E7%AB%A0-%E8%AF%A6%E6%83%85end.png");
|
ABORTED("", "", "https://axzo-public.oss-cn-chengdu.aliyuncs.com/%E5%8D%B0%E7%AB%A0-%E8%AF%A6%E6%83%85end.png");
|
||||||
|
|
||||||
|
private final String buttonCode;
|
||||||
|
private final String actionPerformedName;
|
||||||
private final String icon;
|
private final String icon;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCode() {
|
public String getCode() {
|
||||||
return name();
|
return name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<BizFinalStateEnum> findButtonClickedState(String buttonCode) {
|
||||||
|
for (BizFinalStateEnum value : values()) {
|
||||||
|
if (value.buttonCode.equals(buttonCode))
|
||||||
|
return Optional.of(value);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isButtonPerformActionAvailable() {
|
||||||
|
return StringUtils.isNotBlank(actionPerformedName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ public enum CardBizState implements CodeDefinition<String> {
|
|||||||
ABORTED("已中止", true, "https://axzo-public.oss-cn-chengdu.aliyuncs.com/msg-center/todo_card_state/card_biz_state_aborted_20241220.png"),
|
ABORTED("已中止", true, "https://axzo-public.oss-cn-chengdu.aliyuncs.com/msg-center/todo_card_state/card_biz_state_aborted_20241220.png"),
|
||||||
COMPLETED("已处理", true, "https://axzo-public.oss-cn-chengdu.aliyuncs.com/msg-center/todo_card_state/card_biz_state_completed_20241220.png"),
|
COMPLETED("已处理", true, "https://axzo-public.oss-cn-chengdu.aliyuncs.com/msg-center/todo_card_state/card_biz_state_completed_20241220.png"),
|
||||||
END("已完结", true, "https://axzo-public.oss-cn-chengdu.aliyuncs.com/msg-center/todo_card_state/card_biz_state_end_20241220.png"),
|
END("已完结", true, "https://axzo-public.oss-cn-chengdu.aliyuncs.com/msg-center/todo_card_state/card_biz_state_end_20241220.png"),
|
||||||
IN_PROGRESS("进行中", false, "https://axzo-public.oss-cn-chengdu.aliyuncs.com/msg-center/todo_card_state/card_biz_state_inprogress_20241220.png")
|
PROCESSING("进行中", false, "https://axzo-public.oss-cn-chengdu.aliyuncs.com/msg-center/todo_card_state/card_biz_state_inprogress_20241220.png")
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@ -11,15 +11,14 @@ import lombok.RequiredArgsConstructor;
|
|||||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public enum CardState implements CodeDefinition<String> {
|
public enum CardState implements CodeDefinition<String> {
|
||||||
|
|
||||||
CREATED("待处理"),
|
CREATED("未发送"),
|
||||||
SEND_SUCCESS("发送成功"),
|
SEND_SUCCESS("已发送"),
|
||||||
COMPLETED("已完成"),
|
COMPLETED("已处理"),
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCode() {
|
public String getCode() {
|
||||||
return name();
|
return name();
|
||||||
|
|||||||
@ -19,11 +19,9 @@ import java.util.Objects;
|
|||||||
public enum PendingMessageStateEnum implements CodeDefinition<String> {
|
public enum PendingMessageStateEnum implements CodeDefinition<String> {
|
||||||
|
|
||||||
CREATED(0, "创建"),
|
CREATED(0, "创建"),
|
||||||
UNSENT(1, "未发送"),
|
|
||||||
HAS_BEEN_SENT(2, "代办"),
|
HAS_BEEN_SENT(2, "代办"),
|
||||||
COMPLETED(5, "已办"),
|
COMPLETED(5, "已办"),
|
||||||
RETRACT(6, "已撤回"),
|
RETRACT(6, "已撤回"),
|
||||||
DELETED(7, "已删除"),
|
|
||||||
READ(8, "已读"),
|
READ(8, "已读"),
|
||||||
PROCESSING(9, "处理中")
|
PROCESSING(9, "处理中")
|
||||||
;
|
;
|
||||||
|
|||||||
@ -11,6 +11,10 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface CardContent {
|
public interface CardContent {
|
||||||
|
|
||||||
|
String getBizCode();
|
||||||
|
|
||||||
|
String getSubBizCode();
|
||||||
|
|
||||||
String getTemplateCode();
|
String getTemplateCode();
|
||||||
|
|
||||||
CardStateInfo getStateInfo();
|
CardStateInfo getStateInfo();
|
||||||
|
|||||||
@ -24,16 +24,18 @@ public class CardUpdateStateRequest extends CardUpdateRequest {
|
|||||||
private Boolean cardCompleted;
|
private Boolean cardCompleted;
|
||||||
|
|
||||||
public void validate() {
|
public void validate() {
|
||||||
if (!determineIsCardCompleted() && bizState == null)
|
if (!isValid()) throw new ServiceException("cardCompleted 和 bizState 不能同时为空");
|
||||||
throw new ServiceException("cardCompleted 和 bizState 不能同时为空");
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return determineIsCardCompleted() || bizState != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean determineIsCardCompleted() {
|
public boolean determineIsCardCompleted() {
|
||||||
return cardCompleted != null && cardCompleted;
|
return cardCompleted != null && cardCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override public String toString() {
|
||||||
public String toString() {
|
|
||||||
return JSON.toJSONString(this);
|
return JSON.toJSONString(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,18 +0,0 @@
|
|||||||
package cn.axzo.msg.center.service.pending.response;
|
|
||||||
|
|
||||||
import cn.axzo.msg.center.api.custombutton.ProposedButtons;
|
|
||||||
import cn.axzo.msg.center.service.dto.ButtonRouterDTO;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author yanglin
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public interface TodoButtonProvider {
|
|
||||||
|
|
||||||
List<ButtonRouterDTO> getButtonRouters();
|
|
||||||
|
|
||||||
ProposedButtons getProposedButtons();
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -15,6 +15,7 @@ import cn.axzo.msg.center.service.pending.response.v3.model.ParsedTemplateV3;
|
|||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yanglin
|
* @author yanglin
|
||||||
@ -40,7 +41,9 @@ public class ParsedModelV3Walker {
|
|||||||
}
|
}
|
||||||
for (ParsedGroupV3 group : new ArrayList<>(model.determineGroups()))
|
for (ParsedGroupV3 group : new ArrayList<>(model.determineGroups()))
|
||||||
visitGroup(visitor, group);
|
visitGroup(visitor, group);
|
||||||
for (ParsedButtonV3 button : new ArrayList<>(model.determineButtons()))
|
ArrayList<ParsedButtonV3> buttons = new ArrayList<>(model.determineButtons());
|
||||||
|
buttons.sort(Comparator.comparingInt(ParsedButtonV3::determinePriority));
|
||||||
|
for (ParsedButtonV3 button : buttons)
|
||||||
visitButton(visitor, button);
|
visitButton(visitor, button);
|
||||||
if (template != null)
|
if (template != null)
|
||||||
visitor.exitTemplate(template);
|
visitor.exitTemplate(template);
|
||||||
|
|||||||
@ -103,13 +103,8 @@ public class ParsedButtonV3 implements MessageButton, ButtonV3 {
|
|||||||
return priority == null ? Integer.MAX_VALUE : priority;
|
return priority == null ? Integer.MAX_VALUE : priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ButtonStyleEnum> parseStyle() {
|
|
||||||
if (style == null) return Collections.emptyList();
|
|
||||||
return JSON.parseArray(style.toJSONString(), ButtonStyleEnum.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasStyle(ButtonStyleEnum style) {
|
public boolean hasStyle(ButtonStyleEnum style) {
|
||||||
return parseStyle().contains(style);
|
return getStyles().contains(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -126,4 +121,10 @@ public class ParsedButtonV3 implements MessageButton, ButtonV3 {
|
|||||||
public PresetButtonType getPresetBtnType() {
|
public PresetButtonType getPresetBtnType() {
|
||||||
return presetButtonType;
|
return presetButtonType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ButtonStyleEnum> getStyles() {
|
||||||
|
if (style == null) return Collections.emptyList();
|
||||||
|
return JSON.parseArray(style.toJSONString(), ButtonStyleEnum.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -45,4 +45,8 @@ public class IdBuilder {
|
|||||||
return buf.stream().map(String::valueOf).collect(joining(":"));
|
return buf.stream().map(String::valueOf).collect(joining(":"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -21,6 +21,10 @@ import java.util.Objects;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class BizAssertions {
|
public class BizAssertions {
|
||||||
|
|
||||||
|
public static ServiceException fail(String message, Object... args) {
|
||||||
|
return new ServiceException(MessageFormatter.arrayFormat(message, args).getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 断言为NULL
|
* 断言为NULL
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -17,9 +17,7 @@ import org.springframework.stereotype.Component;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -157,24 +155,4 @@ public class TodoDao extends ServiceImpl<TodoMapper, Todo> {
|
|||||||
.set(Todo::getState, PendingMessageStateEnum.PROCESSING)
|
.set(Todo::getState, PendingMessageStateEnum.PROCESSING)
|
||||||
.update();
|
.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setExecutableHide(String subBizCode, Date expireTime) {
|
|
||||||
return lambdaUpdate()
|
|
||||||
.eq(Todo::getType, TodoType.EXECUTABLE)
|
|
||||||
.eq(Todo::getSubBizCode, subBizCode)
|
|
||||||
.eq(Todo::getState, PendingMessageStateEnum.HAS_BEEN_SENT)
|
|
||||||
.set(Todo::getHideUntil, expireTime)
|
|
||||||
.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Todo> findByCondition(String templateCode, String bizCode, String subBizCode, Long executorPersonId, Long ouId, Long workspaceId) {
|
|
||||||
return lambdaQuery()
|
|
||||||
.eq(StringUtils.isNotBlank(templateCode), Todo::getTemplateCode, templateCode)
|
|
||||||
.eq(StringUtils.isNotBlank(bizCode), Todo::getBizCode, bizCode)
|
|
||||||
.eq(StringUtils.isNotBlank(subBizCode), Todo::getSubBizCode, subBizCode)
|
|
||||||
.eq(Objects.nonNull(executorPersonId), Todo::getExecutorPersonId, executorPersonId)
|
|
||||||
.eq(Objects.nonNull(ouId), Todo::getOuId, ouId)
|
|
||||||
.eq(Objects.nonNull(workspaceId), Todo::getReceiverWorkspaceId, workspaceId)
|
|
||||||
.list();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -3,6 +3,7 @@ package cn.axzo.msg.center.domain.entity;
|
|||||||
import cn.axzo.msg.center.domain.utils.IgnorePropsJsonTypeHandler;
|
import cn.axzo.msg.center.domain.utils.IgnorePropsJsonTypeHandler;
|
||||||
import cn.axzo.msg.center.service.ButtonV3;
|
import cn.axzo.msg.center.service.ButtonV3;
|
||||||
import cn.axzo.msg.center.service.domain.UrlConfig;
|
import cn.axzo.msg.center.service.domain.UrlConfig;
|
||||||
|
import cn.axzo.msg.center.service.enums.ButtonStyleEnum;
|
||||||
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
||||||
import cn.axzo.msg.center.service.enums.RouterButtonSourceEnum;
|
import cn.axzo.msg.center.service.enums.RouterButtonSourceEnum;
|
||||||
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
|
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
|
||||||
@ -14,6 +15,9 @@ import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yanglin
|
* @author yanglin
|
||||||
*/
|
*/
|
||||||
@ -102,6 +106,17 @@ public class MessageTemplateButtonV3 extends BaseEntityWithOperator<MessageTempl
|
|||||||
return recordExt;
|
return recordExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ButtonStyleEnum> getStyles() {
|
||||||
|
if (style == null) return Collections.emptyList();
|
||||||
|
return JSON.parseArray(style.toJSONString(), ButtonStyleEnum.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String key() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
public static class RecordExt {
|
public static class RecordExt {
|
||||||
|
|||||||
@ -182,20 +182,17 @@ public class Todo extends BaseEntityExt<Todo> implements MessageEntity {
|
|||||||
return orgId;
|
return orgId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行待办是否已经完成(处理)
|
|
||||||
*/
|
|
||||||
public boolean isExecCompleted() {
|
|
||||||
return type == TodoType.EXECUTABLE && state == PendingMessageStateEnum.COMPLETED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject bizParam() {
|
public JSONObject bizParam() {
|
||||||
return bizExtParam == null ? new JSONObject() : bizExtParam;
|
if (bizExtParam == null)
|
||||||
|
bizExtParam = new JSONObject();
|
||||||
|
return bizExtParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject routerParam() {
|
public JSONObject routerParam() {
|
||||||
return routerParams == null ? new JSONObject() : routerParams;
|
if (routerParams == null)
|
||||||
|
routerParams = new JSONObject();
|
||||||
|
return routerParams;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,6 +60,7 @@ public class MnsLimiter {
|
|||||||
error = String.format("验证码短信: 每 %s 分钟发送给同一个手机号的重复内容不能超过 %s 条。 请勿重试发送!!",
|
error = String.format("验证码短信: 每 %s 分钟发送给同一个手机号的重复内容不能超过 %s 条。 请勿重试发送!!",
|
||||||
props.getVerifyCodeLimitWindowMinutes(), limitCount);
|
props.getVerifyCodeLimitWindowMinutes(), limitCount);
|
||||||
}
|
}
|
||||||
|
error += " [" + request.getPhoneNo() + "]";
|
||||||
if (alreadySendCount + 1 > limitCount) {
|
if (alreadySendCount + 1 > limitCount) {
|
||||||
log.warn("mns rate limited, {}, request={}", error, request);
|
log.warn("mns rate limited, {}, request={}", error, request);
|
||||||
throw new ServiceException(ReturnCodeEnum.FAIL.getCode(), error);
|
throw new ServiceException(ReturnCodeEnum.FAIL.getCode(), error);
|
||||||
|
|||||||
6
pom.xml
6
pom.xml
@ -42,6 +42,7 @@
|
|||||||
<feign-httpclient.version>11.8</feign-httpclient.version>
|
<feign-httpclient.version>11.8</feign-httpclient.version>
|
||||||
<jetbrains.version>26.0.0</jetbrains.version>
|
<jetbrains.version>26.0.0</jetbrains.version>
|
||||||
<epic.version>1.0.0-SNAPSHOT</epic.version>
|
<epic.version>1.0.0-SNAPSHOT</epic.version>
|
||||||
|
<workflow.version>1.5.2-SNAPSHOT</workflow.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
@ -106,6 +107,11 @@
|
|||||||
<artifactId>msg-center-api-v2</artifactId>
|
<artifactId>msg-center-api-v2</artifactId>
|
||||||
<version>${msg-center-api-v2-version}</version>
|
<version>${msg-center-api-v2-version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.axzo.workflow</groupId>
|
||||||
|
<artifactId>workflow-engine-spring-boot-starter</artifactId>
|
||||||
|
<version>${workflow.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,34 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.card;
|
||||||
|
|
||||||
|
import cn.axzo.msg.center.MsgCenterApplication;
|
||||||
|
import cn.axzo.msg.center.common.utils.BizAssertions;
|
||||||
|
import cn.axzo.msg.center.dal.CardDao;
|
||||||
|
import cn.axzo.msg.center.domain.entity.Card;
|
||||||
|
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
@SpringBootTest(classes = MsgCenterApplication.class)
|
||||||
|
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||||
|
class CardManagerTest {
|
||||||
|
|
||||||
|
private final CardManager cardManager;
|
||||||
|
private final CardSupport cardSupport;
|
||||||
|
private final CardDao cardDao;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rebuildCardContent() {
|
||||||
|
TemplateModelV3 templateModel = cardSupport.ensureImChannelPresent("8733f93de8db49699a78eda5a342763c");
|
||||||
|
Card card = cardDao.findCardByBizMessageId("c0d696b2178f442f9488cfc74c518042").orElse(null);
|
||||||
|
BizAssertions.assertNotNull(card, "card not found");
|
||||||
|
cardManager.rebuildCardContent(templateModel, Collections.singletonList(card));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package cn.axzo.msg.center.message.service.todo.card;
|
||||||
|
|
||||||
|
import cn.axzo.msg.center.MsgCenterApplication;
|
||||||
|
import cn.axzo.msg.center.api.mq.CardPresetButtonPressedMessage;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
@SpringBootTest(classes = MsgCenterApplication.class)
|
||||||
|
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||||
|
class TodoSyncCardServiceTest {
|
||||||
|
|
||||||
|
private final TodoSyncCardService todoSyncCardService;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void syncCardPresetButtonPressed() {
|
||||||
|
String json = "{\"cardInfo\": {\"appCode\": \"msg-center:todo\", \"batchNo\": \"fd301a68203a430cbc6e6928c0164fe5\", \"bizCode\": \"test-14\", \"bizMessageId\": \"2e1119e4a96345049870558d53939700\", \"bizParam\": {\"assistLogName\": \"测试\", \"extInfo\": {\"todoType\": \"EXECUTABLE\", \"todoCategory\": \"OTHER\", \"todoPromoterWorkspaceId\": 0, \"todoIdentityCode\": \"80978834809443febcf579b0eecf560b\", \"todoExecutorWorkspaceId\": 0}}, \"buttonStates\": [{\"buttonCode\": \"f6a77000fc50487ab9be215201bf233a\", \"isActionPerformed\": true}], \"cardContent\": {\"bizCode\": \"test-14\", \"cardStyleCode\": \"common_style_001\", \"updateTime\": 1737025348622, \"cardContent\": \"系统提示,无需关注\", \"debugInfo\": {\"isUpdatable\": true, \"bizCode\": \"test-14\", \"bizState\": \"AGREED\", \"subBizCode\": \"aaaa\", \"cardState\": \"COMPLETED\"}, \"templateCode\": \"7aceab1f31ec4570a98cdaf7f8940c61\", \"sendTimestamp\": 1737025348622, \"cardTitle\": \"系统提示\", \"extInfo\": {\"todoType\": \"EXECUTABLE\", \"todoCategory\": \"OTHER\", \"todoPromoterWorkspaceId\": 0, \"todoIdentityCode\": \"80978834809443febcf579b0eecf560b\", \"todoExecutorWorkspaceId\": 0}, \"cardBannerUrl\": \"\", \"subBizCode\": \"aaaa\", \"stateImage\": \"https://axzo-public.oss-cn-chengdu.aliyuncs.com/msg-center/todo_card_state/card_biz_state_agreed_20241220.png\", \"cardButtons\": [{\"presetButtonType\": \"AGREE\", \"actionPerformed\": true, \"senderShow\": false, \"buttonCode\": \"f6a77000fc50487ab9be215201bf233a\", \"isHighlight\": true, \"action\": \"PRESET_BUTTON\", \"source\": \"CUSTOM\", \"title\": \"已同意\", \"executorShow\": true}]}, \"content\": \"系统提示,无需关注\", \"id\": 167756, \"identityCode\": \"726de22e936c4f3bb640693e5f2c0968\", \"imTaskId\": 756527, \"isSenderRobot\": \"YES\", \"receiverAppType\": \"CMP\", \"receiverOuId\": 10616, \"receiverPersonId\": 9000399522, \"receiverWorkspaceId\": 0, \"routerParam\": {}, \"senderAppType\": \"SYSTEM\", \"senderOuId\": 0, \"senderPersonId\": 6678911, \"senderWorkspaceId\": 0, \"state\": null, \"subBizCode\": \"aaaa\", \"subtitle\": \"\", \"templateCode\": \"7aceab1f31ec4570a98cdaf7f8940c61\", \"title\": \"系统提示\"}, \"messageId\": \"490ddb1e-5879-4088-bbda-7ca8f15bd4f2\", \"messageSendTime\": 1737025348697, \"messageSendTimeStr\": \"2025-01-16 19:02:28\", \"operatorId\": 9000399522, \"operatorName\": \"罗福\", \"presetButtonType\": \"AGREE\"}";
|
||||||
|
CardPresetButtonPressedMessage message = JSON.parseObject(json, CardPresetButtonPressedMessage.class);
|
||||||
|
todoSyncCardService.syncCardPresetButtonPressed(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user