REQ-3281: 发送卡片消息
This commit is contained in:
parent
9da3f9b325
commit
8132bfee23
@ -11,8 +11,8 @@ import cn.axzo.msg.center.domain.entity.MessageRecordV3;
|
||||
import cn.axzo.msg.center.domain.enums.NativeTypeEnum;
|
||||
import cn.axzo.msg.center.event.payload.MessageHistoryUpdatedPayload;
|
||||
import cn.axzo.msg.center.inside.notices.service.IYouMengMessageService;
|
||||
import cn.axzo.msg.center.inside.notices.service.impl.v3.msg.TemplateMessage;
|
||||
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
|
||||
import cn.axzo.msg.center.message.service.card.CardSupport;
|
||||
import cn.axzo.msg.center.message.service.impl.v3.AppLink;
|
||||
import cn.axzo.msg.center.message.service.impl.v3.ModelV3Service;
|
||||
import cn.axzo.msg.center.nimpush.PushChannel;
|
||||
@ -89,7 +89,7 @@ public class PushYouMengMessageHandler implements EventHandler, InitializingBean
|
||||
return;
|
||||
}
|
||||
|
||||
if (!payload.getNewMessageHistory().getBizId().startsWith(TemplateMessage.BIZ_ID_PREFIX)) {
|
||||
if (!payload.getNewMessageHistory().getBizId().startsWith(CardSupport.BIZ_ID_PREFIX)) {
|
||||
log.info("push-handler 非msg-center的消息");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import cn.axzo.msg.center.dal.MessageBaseTemplateDao;
|
||||
import cn.axzo.msg.center.domain.entity.MessageBaseTemplate;
|
||||
import cn.axzo.msg.center.im.service.IMService;
|
||||
import cn.axzo.msg.center.inside.notices.config.ImMessageProps;
|
||||
import cn.axzo.msg.center.inside.notices.service.impl.v3.msg.TemplateMessage;
|
||||
import cn.axzo.msg.center.message.service.card.CardSupport;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -46,7 +46,7 @@ public class IMServiceImpl implements IMService {
|
||||
.update();
|
||||
BizAssertions.assertTrue(templateUpdated, "未找到对应的模版或者模版已经删除");
|
||||
UpdateTemplateSendPriorityRequest updatePriorityRequest = new UpdateTemplateSendPriorityRequest();
|
||||
updatePriorityRequest.setBizIdPrefix(TemplateMessage.getBizIdPrefix(request.getTemplateCode()));
|
||||
updatePriorityRequest.setBizIdPrefix(CardSupport.getBizIdPrefix(request.getTemplateCode()));
|
||||
updatePriorityRequest.setSendPriority(request.getSendPriority());
|
||||
updatePriorityRequest.setToken(imProps.getControllerToken());
|
||||
Boolean imMessageUpdated = messageController.updateSendPriority(updatePriorityRequest).getData();
|
||||
|
||||
@ -0,0 +1,92 @@
|
||||
package cn.axzo.msg.center.inside.notices.service.impl.v3.msg;
|
||||
|
||||
import cn.axzo.msg.center.api.request.v4.MessageSendBasicInfoV4;
|
||||
import cn.axzo.msg.center.api.response.v3.MessageSendResultV3;
|
||||
import cn.axzo.msg.center.api.response.v3.TemplateSendResultV3;
|
||||
import cn.axzo.msg.center.inside.notices.service.impl.v3.EventMappingProcessor;
|
||||
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
|
||||
import cn.axzo.msg.center.message.service.card.CardManager;
|
||||
import cn.axzo.msg.center.service.dto.PeerPerson;
|
||||
import cn.axzo.msg.center.service.dto.PersonV3DTO;
|
||||
import cn.axzo.msg.center.service.enums.Channel;
|
||||
import cn.axzo.msg.center.service.pending.request.CardSendRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@Scope("prototype")
|
||||
@RequiredArgsConstructor
|
||||
public class CardMappingProcessor implements EventMappingProcessor {
|
||||
|
||||
private final CardManager cardManager;
|
||||
|
||||
@Setter
|
||||
private MessageSendBasicInfoV4 sendBasicInfo;
|
||||
@Setter
|
||||
private Channel channel;
|
||||
@Setter
|
||||
private TemplateModelV3 templateModel;
|
||||
|
||||
@Override
|
||||
public void saveRecords() {
|
||||
// NOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeAsyncSend() {
|
||||
PeerPerson cardSender = new PeerPerson();
|
||||
cardSender.setOuId(sendBasicInfo.getSenderOuId());
|
||||
cardSender.setWorkspaceId(sendBasicInfo.getSenderWorkspaceId());
|
||||
PersonV3DTO eventSender = sendBasicInfo.getSender();
|
||||
if (eventSender != null)
|
||||
cardSender.setPersonId(eventSender.getId());
|
||||
|
||||
Set<PeerPerson> cardReceivers = new HashSet<>();
|
||||
for (PersonV3DTO eventReceiver : sendBasicInfo.receivers()) {
|
||||
PersonV3DTO.ReceiveModel receiveModel = eventReceiver.getImReceiveModel();
|
||||
PeerPerson cardReceiver = new PeerPerson();
|
||||
cardReceiver.setPersonId(eventReceiver.getId());
|
||||
cardReceiver.setOuId(receiveModel == null
|
||||
? sendBasicInfo.getReceiversOuId()
|
||||
: receiveModel.getOuId());
|
||||
cardReceiver.setWorkspaceId(receiveModel == null
|
||||
? sendBasicInfo.getReceiversWorkspaceId()
|
||||
: receiveModel.getWorkspaceId());
|
||||
cardReceivers.add(cardReceiver);
|
||||
}
|
||||
|
||||
CardSendRequest cardRequest = new CardSendRequest();
|
||||
cardRequest.setAppCode("msg-center");
|
||||
cardRequest.setTemplateCode(templateModel.getTemplateCode());
|
||||
cardRequest.setBizCode(sendBasicInfo.getBizCode());
|
||||
cardRequest.setSubBizCode(null);
|
||||
cardRequest.setSender(cardSender);
|
||||
cardRequest.setReceivers(cardReceivers);
|
||||
cardRequest.setBizParam(sendBasicInfo.getBizExtParams());
|
||||
cardRequest.setRouterParam(sendBasicInfo.getRouterParams());
|
||||
cardRequest.setSubtitle(sendBasicInfo.getSubtitle());
|
||||
cardManager.send(cardRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateSendResultV3 buildTemplateSendResult() {
|
||||
TemplateSendResultV3 templateResult = new TemplateSendResultV3(
|
||||
templateModel.getTemplateCode(), channel.getCode());
|
||||
for (PersonV3DTO receiver : sendBasicInfo.receivers()) {
|
||||
templateResult.addResult(new MessageSendResultV3(
|
||||
receiver.getId(), 0L));
|
||||
}
|
||||
return templateResult;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,105 +0,0 @@
|
||||
package cn.axzo.msg.center.inside.notices.service.impl.v3.msg;
|
||||
|
||||
import cn.axzo.framework.domain.ServiceException;
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.im.center.api.feign.MessageApi;
|
||||
import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam;
|
||||
import cn.axzo.im.center.api.vo.resp.MessageTaskResp;
|
||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||
import cn.axzo.msg.center.api.response.v3.MessageSendResultV3;
|
||||
import cn.axzo.msg.center.api.response.v3.TemplateSendResultV3;
|
||||
import cn.axzo.msg.center.common.utils.BizAssertions;
|
||||
import cn.axzo.msg.center.dal.MessageRecordV3Dao;
|
||||
import cn.axzo.msg.center.domain.entity.MessageRecordV3;
|
||||
import cn.axzo.msg.center.domain.entity.MessageTemplateV3;
|
||||
import cn.axzo.msg.center.inside.notices.service.impl.v3.EventMappingProcessor;
|
||||
import cn.axzo.msg.center.nimpush.device.PushDeviceService;
|
||||
import cn.axzo.msg.center.nimpush.device.PushDeviceSnapshots;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@Scope("prototype")
|
||||
@RequiredArgsConstructor
|
||||
public class MessageMappingProcessor implements EventMappingProcessor {
|
||||
|
||||
private final MessageRecordV3Dao messageRecordV3Dao;
|
||||
private final TerminalAppMapping terminalAppMapping;
|
||||
private final MessageTemplateParserV3 templateParser;
|
||||
private final MessageApi messageApi;
|
||||
private final PushDeviceService pushDeviceService;
|
||||
|
||||
/**
|
||||
* Scope("prototype") -> we're good
|
||||
*/
|
||||
@Setter
|
||||
private TemplateMessage template;
|
||||
|
||||
@Override
|
||||
public void saveRecords() {
|
||||
messageRecordV3Dao.saveBatch(template.getMessageRecords());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeAsyncSend() {
|
||||
List<AppTypeEnum> appTypes = terminalAppMapping
|
||||
.toImTypes(getTemplate().determinePushTerminals());
|
||||
BizAssertions.assertNotEmpty(appTypes, "发送IM消息, 消息模版没有配置IM发送终端, templateCode={}, templateName={}",
|
||||
getTemplate().getCode(), getTemplate().getName());
|
||||
String cmTaskId = null;
|
||||
String cmpTaskId = null;
|
||||
PushDeviceSnapshots deviceSnapshots = pushDeviceService.createDeviceSnapshots();
|
||||
try {
|
||||
for (AppTypeEnum appType : appTypes) {
|
||||
String taskId = sendImpl(deviceSnapshots, appType);
|
||||
if (appType == AppTypeEnum.CM)
|
||||
cmTaskId = taskId;
|
||||
else if (appType == AppTypeEnum.CMP)
|
||||
cmpTaskId = taskId;
|
||||
}
|
||||
messageRecordV3Dao.setSendSuccess(template.getMessageIds(), cmTaskId, cmpTaskId);
|
||||
} catch (Exception e) {
|
||||
messageRecordV3Dao.batchSetSendFailed(template.getMessageIds(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String sendImpl(PushDeviceSnapshots deviceCache, AppTypeEnum appType) {
|
||||
SendTemplateMessageParam request = template.buildImRequest(templateParser, deviceCache, appType);
|
||||
ApiResult<MessageTaskResp> apiResult = messageApi.sendTemplateMessageAsync(request);
|
||||
log.info("sending im message result, req={}, resp={}",
|
||||
JSON.toJSONString(request), JSON.toJSONString(apiResult));
|
||||
if (apiResult.isSuccess()) {
|
||||
return apiResult.getData().getId() + "";
|
||||
} else {
|
||||
log.warn("sending im message fail, req={}, resp={}",
|
||||
JSON.toJSONString(request), JSON.toJSONString(apiResult));
|
||||
throw new ServiceException(apiResult.getMsg());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateSendResultV3 buildTemplateSendResult() {
|
||||
TemplateSendResultV3 templateResult = new TemplateSendResultV3(
|
||||
template.getTemplateCode(), template.getChannel().name());
|
||||
for (MessageRecordV3 message : template.getMessageRecords()) {
|
||||
templateResult.addResult(new MessageSendResultV3(
|
||||
message.getReceiverPersonId(), message.getId()));
|
||||
}
|
||||
return templateResult;
|
||||
}
|
||||
|
||||
private MessageTemplateV3 getTemplate() {
|
||||
return template.getTemplateModel().getTemplate();
|
||||
}
|
||||
|
||||
}
|
||||
@ -141,31 +141,31 @@ public class MessageTemplateParserV3 {
|
||||
return im;
|
||||
}
|
||||
|
||||
private static ParsedUrlForCms parseUrlForCms(UrlConfig urlConfig) {
|
||||
if (urlConfig == null) return null;
|
||||
ParsedUrlForCms urlForCms = new ParsedUrlForCms();
|
||||
UrlConfigWalker.walkDown(urlConfig, new UrlConfigVisitor() {
|
||||
|
||||
@Override
|
||||
public void visitPcCms(WebUrl pcCms) {
|
||||
urlForCms.setUrl(pcCms.getUrl());
|
||||
urlForCms.setOpenStrategy(pcCms.getOpenStrategy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAppManager(MobileUrlConfig appManager) {
|
||||
urlForCms.setHasManagerAppUrl(appManager.hasUrl());
|
||||
}
|
||||
|
||||
});
|
||||
return urlForCms;
|
||||
}
|
||||
|
||||
private List<AppLink> getNativeAppLinks(UrlConfig urlConfig) {
|
||||
if (urlConfig == null) return Collections.emptyList();
|
||||
NativeAppLinkUrlConfigVisitor visitor = new NativeAppLinkUrlConfigVisitor();
|
||||
UrlConfigWalker.walkDown(urlConfig, visitor);
|
||||
return visitor.getLinks();
|
||||
}
|
||||
//private static ParsedUrlForCms parseUrlForCms(UrlConfig urlConfig) {
|
||||
// if (urlConfig == null) return null;
|
||||
// ParsedUrlForCms urlForCms = new ParsedUrlForCms();
|
||||
// UrlConfigWalker.walkDown(urlConfig, new UrlConfigVisitor() {
|
||||
//
|
||||
// @Override
|
||||
// public void visitPcCms(WebUrl pcCms) {
|
||||
// urlForCms.setUrl(pcCms.getUrl());
|
||||
// urlForCms.setOpenStrategy(pcCms.getOpenStrategy());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitAppManager(MobileUrlConfig appManager) {
|
||||
// urlForCms.setHasManagerAppUrl(appManager.hasUrl());
|
||||
// }
|
||||
//
|
||||
// });
|
||||
// return urlForCms;
|
||||
//}
|
||||
//
|
||||
//private List<AppLink> getNativeAppLinks(UrlConfig urlConfig) {
|
||||
// if (urlConfig == null) return Collections.emptyList();
|
||||
// NativeAppLinkUrlConfigVisitor visitor = new NativeAppLinkUrlConfigVisitor();
|
||||
// UrlConfigWalker.walkDown(urlConfig, visitor);
|
||||
// return visitor.getLinks();
|
||||
//}
|
||||
|
||||
}
|
||||
@ -16,6 +16,7 @@ import cn.axzo.msg.center.common.utils.PlaceholderResolver;
|
||||
import cn.axzo.msg.center.domain.entity.MessageRecordV3;
|
||||
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
|
||||
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
|
||||
import cn.axzo.msg.center.message.service.card.CardSupport;
|
||||
import cn.axzo.msg.center.message.service.impl.v3.ModelV3Parser;
|
||||
import cn.axzo.msg.center.message.service.impl.v3.UrlParser;
|
||||
import cn.axzo.msg.center.nimpush.NimPushService;
|
||||
@ -55,8 +56,6 @@ import static java.util.stream.Collectors.toSet;
|
||||
@RequiredArgsConstructor
|
||||
public class TemplateMessage {
|
||||
|
||||
public static final String BIZ_ID_PREFIX = "msg-center";
|
||||
|
||||
private final MessageSendRequestV4 req;
|
||||
private final String batchNo;
|
||||
@Getter
|
||||
@ -127,25 +126,21 @@ public class TemplateMessage {
|
||||
return records;
|
||||
}
|
||||
|
||||
public static String getBizIdPrefix(String templateCode) {
|
||||
return String.format("%s:%s", BIZ_ID_PREFIX, templateCode);
|
||||
}
|
||||
|
||||
SendTemplateMessageParam buildImRequest(MessageTemplateParserV3 templateParser,
|
||||
PushDeviceSnapshots deviceCache,
|
||||
PushDeviceSnapshots deviceSnapshots,
|
||||
AppTypeEnum appType) {
|
||||
MessageRecordV3 sample = getMessageRecords().get(0);
|
||||
GeneralMessagePushVO sendVo = templateParser.parse(sample, templateModel);
|
||||
|
||||
MessageSendBasicInfoV4 sendBasicInfo = req.getSendBasicInfo();
|
||||
SendTemplateMessageParam imReq = new SendTemplateMessageParam();
|
||||
imReq.setBizId(String.format("%s:%s", getBizIdPrefix(getTemplateCode()), sendBasicInfo.determineBizCode()));
|
||||
imReq.setSendPriority(templateModel.getTemplate().determineImSendPriority());
|
||||
imReq.setMsgHeader(parseTitle());
|
||||
imReq.setMsgContent(parseContent());
|
||||
imReq.setMsgTemplateId(getTemplateCode());
|
||||
imReq.setMsgTemplateContent(JSON.toJSONString(sendVo));
|
||||
imReq.setExcludePushPayloads(new ArrayList<>());
|
||||
SendTemplateMessageParam imRequest = new SendTemplateMessageParam();
|
||||
imRequest.setBizId(String.format("%s:%s", CardSupport.getBizIdPrefix(getTemplateCode()), sendBasicInfo.determineBizCode()));
|
||||
imRequest.setSendPriority(templateModel.getTemplate().determineImSendPriority());
|
||||
imRequest.setMsgHeader(parseTitle());
|
||||
imRequest.setMsgContent(parseContent());
|
||||
imRequest.setMsgTemplateId(getTemplateCode());
|
||||
imRequest.setMsgTemplateContent(JSON.toJSONString(sendVo));
|
||||
imRequest.setExcludePushPayloads(new ArrayList<>());
|
||||
// 接收人
|
||||
ArrayList<PersonAccountAttribute> receivers = new ArrayList<>();
|
||||
Set<Long> cmUnique = new HashSet<>();
|
||||
@ -155,7 +150,6 @@ public class TemplateMessage {
|
||||
boolean pushable = pushData.determinePushable(log, getTemplateCode());
|
||||
|
||||
// 扩展信息
|
||||
JSONObject ext = new JSONObject();
|
||||
for (PersonV3DTO receiver : sendBasicInfo.receivers()) {
|
||||
PersonV3DTO.ReceiveModel imReceiveModel = receiver.getImReceiveModel();
|
||||
Long ouId = imReceiveModel == null ? sendBasicInfo.determineReceiversOuId() : imReceiveModel.getOuId();
|
||||
@ -167,13 +161,13 @@ public class TemplateMessage {
|
||||
}
|
||||
|
||||
boolean excludePayload = pushable &&
|
||||
!deviceCache.getDevice(receiver.getId())
|
||||
!deviceSnapshots.getDevice(receiver.getId())
|
||||
.shouldPush(appType, PushChannel.NIM);
|
||||
if (excludePayload) {
|
||||
ExcludePushPayload excludePush = new ExcludePushPayload();
|
||||
excludePush.setPersonId(receiver.getId() + "");
|
||||
excludePush.setAppType(appType);
|
||||
imReq.getExcludePushPayloads().add(excludePush);
|
||||
imRequest.getExcludePushPayloads().add(excludePush);
|
||||
}
|
||||
|
||||
PersonAccountAttribute receiverAccount = new PersonAccountAttribute();
|
||||
@ -186,7 +180,8 @@ public class TemplateMessage {
|
||||
else if (appType == AppTypeEnum.CMP)
|
||||
cmpUnique.add(new OuAndPerson(ouId, receiver.getId()));
|
||||
}
|
||||
imReq.setReceivePersons(receivers);
|
||||
imRequest.setReceivePersons(receivers);
|
||||
JSONObject ext = new JSONObject();
|
||||
ext.put("minAppVersion", templateModel.getTemplate().getMinAppVersion());
|
||||
if (sample.getReceiverWorkspaceId() != null) {
|
||||
ext.put("workspaceId", String.valueOf(sample.getReceiverWorkspaceId()));
|
||||
@ -194,13 +189,13 @@ public class TemplateMessage {
|
||||
if (sample.getReceiverOuId() != null) {
|
||||
ext.put("ouId", String.valueOf(sample.getReceiverOuId()));
|
||||
}
|
||||
imReq.setExt(ext);
|
||||
imRequest.setExt(ext);
|
||||
if (pushable) {
|
||||
imReq.setPayload(buildPayload(sample, appType));
|
||||
imRequest.setPayload(buildPayload(sample, appType));
|
||||
if (StringUtils.isNotBlank(pushData.getVoiceFile()))
|
||||
ext.put(Intent.INTENT_SOUND, pushData.getVoiceFile());
|
||||
}
|
||||
return imReq;
|
||||
return imRequest;
|
||||
}
|
||||
|
||||
private String buildPayload(MessageRecordV3 sample, AppTypeEnum appType) {
|
||||
|
||||
@ -8,8 +8,7 @@ import cn.axzo.msg.center.api.response.v3.MessageSendRespV3;
|
||||
import cn.axzo.msg.center.common.utils.BizAssertions;
|
||||
import cn.axzo.msg.center.inside.notices.service.MessageServiceV4;
|
||||
import cn.axzo.msg.center.inside.notices.service.impl.v3.EventMappingProcessor;
|
||||
import cn.axzo.msg.center.inside.notices.service.impl.v3.msg.MessageMappingProcessor;
|
||||
import cn.axzo.msg.center.inside.notices.service.impl.v3.msg.TemplateMessage;
|
||||
import cn.axzo.msg.center.inside.notices.service.impl.v3.msg.CardMappingProcessor;
|
||||
import cn.axzo.msg.center.inside.notices.service.impl.v3.todo.TodoMappingProcessor;
|
||||
import cn.axzo.msg.center.inside.notices.utils.FunctionalTransactionTemplate;
|
||||
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
|
||||
@ -55,9 +54,10 @@ public class MessageServiceV4Impl implements MessageServiceV4 {
|
||||
"未查询到对应的模板, templateCode=%s", templateCode)));
|
||||
if (info.getChannel() == Channel.NOTIFICATION) {
|
||||
// @Scope("prototype") -> we're good
|
||||
MessageMappingProcessor imProcessor = beanFactory.getBean(MessageMappingProcessor.class);
|
||||
imProcessor.setTemplate(new TemplateMessage(
|
||||
request, sendRequestNo, info.getChannel(), templateModel, beanFactory));
|
||||
CardMappingProcessor imProcessor = beanFactory.getBean(CardMappingProcessor.class);
|
||||
imProcessor.setSendBasicInfo(sendBasicInfo);
|
||||
imProcessor.setChannel(info.getChannel());
|
||||
imProcessor.setTemplateModel(templateModel);
|
||||
processors.add(imProcessor);
|
||||
} else if (info.getChannel() == Channel.PENDING) {
|
||||
// @Scope("prototype") -> we're good
|
||||
|
||||
@ -5,6 +5,7 @@ import cn.axzo.msg.center.domain.entity.MessageTemplateButtonV3;
|
||||
import cn.axzo.msg.center.domain.entity.MessageTemplateGroupV3;
|
||||
import cn.axzo.msg.center.domain.entity.MessageTemplateV3;
|
||||
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
|
||||
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
||||
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -12,6 +13,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
@ -38,4 +40,10 @@ public class TemplateModelV3 {
|
||||
.anyMatch(btn -> btn.getCategory() == RouterCategoryEnum.PRESET_BUTTON);
|
||||
}
|
||||
|
||||
public Optional<MessageTemplateButtonV3> findPresetButton(PresetButtonType type) {
|
||||
return buttons.stream()
|
||||
.filter(btn -> btn.getPresetBtnType() == type)
|
||||
.findFirst();
|
||||
|
||||
}
|
||||
}
|
||||
@ -3,9 +3,11 @@ package cn.axzo.msg.center.message.domain.vo;
|
||||
import cn.axzo.msg.center.domain.entity.GeneralMessageRecord;
|
||||
import cn.axzo.msg.center.message.domain.dto.MessageTemplateRouterDTO;
|
||||
import cn.axzo.msg.center.message.service.impl.v3.AppLink;
|
||||
import cn.axzo.msg.center.service.domain.UrlConfig;
|
||||
import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
|
||||
import cn.axzo.msg.center.service.enums.ButtonStyleEnum;
|
||||
import cn.axzo.msg.center.service.enums.CardState;
|
||||
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
||||
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.CardElementConfig;
|
||||
@ -21,7 +23,6 @@ import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -42,6 +43,11 @@ public class GeneralMessagePushVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -9017550674630922381L;
|
||||
|
||||
/**
|
||||
* 样式编码
|
||||
*/
|
||||
private String cardStyleCode;
|
||||
|
||||
/**
|
||||
* 消息的唯一标识
|
||||
*/
|
||||
@ -102,10 +108,15 @@ public class GeneralMessagePushVO implements Serializable {
|
||||
*/
|
||||
private String stateImage;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Long updateTime;
|
||||
|
||||
/**
|
||||
* 卡片元素
|
||||
*/
|
||||
private List<CardElementConfig> cardElements = new ArrayList<>();
|
||||
private List<CardElementConfig> cardElements;
|
||||
|
||||
public static GeneralMessagePushVO from(GeneralMessageRecord record, String templateIcon, String orgIcon,
|
||||
MessageTemplateRouterDTO msgTemplateRouter,
|
||||
@ -225,6 +236,11 @@ public class GeneralMessagePushVO implements Serializable {
|
||||
*/
|
||||
private List<AppLink> actionPaths;
|
||||
|
||||
/**
|
||||
* 各个端的url配置
|
||||
*/
|
||||
private UrlConfig urlConfig;
|
||||
|
||||
/**
|
||||
* 专门给cms的路由信息
|
||||
*/
|
||||
@ -240,6 +256,16 @@ public class GeneralMessagePushVO implements Serializable {
|
||||
*/
|
||||
private Boolean actionPerformed;
|
||||
|
||||
/**
|
||||
* 预设按钮类型. AGREE: 同意, REJECT: 驳回, REVOKE: 撤销
|
||||
*/
|
||||
private PresetButtonType presetButtonType;
|
||||
|
||||
/**
|
||||
* 按钮编码
|
||||
*/
|
||||
private String buttonCode;
|
||||
|
||||
static CardButton from(MessageTemplateRouterDTO.MessageRouteDetailDTO routeDetail) {
|
||||
return CardButton.builder()
|
||||
.title(routeDetail.getName())
|
||||
|
||||
@ -2,9 +2,8 @@ package cn.axzo.msg.center.message.service.card;
|
||||
|
||||
import cn.axzo.msg.center.service.pending.card.CardClient;
|
||||
import cn.axzo.msg.center.service.pending.request.CardSendRequest;
|
||||
import cn.axzo.msg.center.service.pending.request.CardUpdateRequest;
|
||||
import cn.axzo.msg.center.service.pending.response.CardSendResponse;
|
||||
import cn.axzo.msg.center.service.pending.response.CardUpdateResponse;
|
||||
import cn.axzo.msg.center.service.pending.request.CardUpdateStateRequest;
|
||||
import cn.axzo.msg.center.service.pending.request.CardPresetButtonPressedRequest;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -21,13 +20,22 @@ public class CardController implements CardClient {
|
||||
private final CardManager cardManager;
|
||||
|
||||
@Override
|
||||
public CommonResponse<CardSendResponse> send(CardSendRequest request) {
|
||||
return CommonResponse.success(cardManager.send(request));
|
||||
public CommonResponse<Void> send(CardSendRequest request) {
|
||||
cardManager.send(request);
|
||||
return CommonResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<CardUpdateResponse> update(CardUpdateRequest request) {
|
||||
return CommonResponse.success(cardManager.update(request));
|
||||
public CommonResponse<Void> updateState(CardUpdateStateRequest request) {
|
||||
cardManager.updateState(request);
|
||||
return CommonResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Void>
|
||||
firePresetButtonPressed(CardPresetButtonPressedRequest request) {
|
||||
cardManager.firePresetButtonPressed(request);
|
||||
return CommonResponse.success();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,10 +1,49 @@
|
||||
package cn.axzo.msg.center.message.service.card;
|
||||
|
||||
import cn.axzo.msg.center.dal.CardDao;
|
||||
import cn.axzo.msg.center.dal.CardLogDao;
|
||||
import cn.axzo.msg.center.domain.entity.Card;
|
||||
import cn.axzo.msg.center.domain.entity.CardLog;
|
||||
import com.google.common.base.Throwables;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
class CardLogger {
|
||||
|
||||
private final CardDao cardDao;
|
||||
private final CardLogDao cardLogDao;
|
||||
|
||||
void reloadAndLogCards(String context, Object request, List<Card> cards) {
|
||||
reloadAndLogCards(context, request, cards, null);
|
||||
}
|
||||
|
||||
void reloadAndLogCards(String context, Object request, List<Card> cards, Exception e) {
|
||||
ArrayList<CardLog> logs = new ArrayList<>();
|
||||
for (Card card : cardDao.reloadCards(cards)) {
|
||||
CardLog log = new CardLog();
|
||||
logs.add(log);
|
||||
log.setIdentityCode(card.getIdentityCode());
|
||||
log.setTemplateCode(card.getTemplateCode());
|
||||
log.setBizMessageId(card.getBizMessageId());
|
||||
log.setBizCode(card.getBizCode());
|
||||
log.setSubBizCode(card.getSubBizCode());
|
||||
log.setContext(context);
|
||||
log.setBatchNo(card.getBatchNo());
|
||||
log.setCardContent(card.getCardContent());
|
||||
log.addLogContent("request", request);
|
||||
log.addLogContent("state", card.getState());
|
||||
if (e != null)
|
||||
log.addLogContent("exception", Throwables.getStackTraceAsString(e));
|
||||
}
|
||||
cardLogDao.saveBatch(logs);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,20 +1,40 @@
|
||||
package cn.axzo.msg.center.message.service.card;
|
||||
|
||||
import cn.axzo.msg.center.api.MessageApi;
|
||||
import cn.axzo.framework.jackson.utility.JSON;
|
||||
import cn.axzo.im.center.api.feign.MessageApi;
|
||||
import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam;
|
||||
import cn.axzo.im.center.api.vo.req.UpdateMessageRequest;
|
||||
import cn.axzo.im.center.api.vo.resp.MessageTaskResp;
|
||||
import cn.axzo.maokai.api.util.Ref;
|
||||
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.domain.entity.MessageTemplateButtonV3;
|
||||
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
|
||||
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.UrlParser;
|
||||
import cn.axzo.msg.center.message.service.card.broadcast.CardBroadcaster;
|
||||
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.nimpush.device.PushDeviceService;
|
||||
import cn.axzo.msg.center.nimpush.device.PushDeviceSnapshots;
|
||||
import cn.axzo.msg.center.service.dto.PeerPerson;
|
||||
import cn.axzo.msg.center.service.pending.card.domain.CardButtonStates;
|
||||
import cn.axzo.msg.center.service.pending.request.CardPresetButtonPressedRequest;
|
||||
import cn.axzo.msg.center.service.pending.request.CardPresetButtonRequest;
|
||||
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.CardUpdateRequest;
|
||||
import cn.axzo.msg.center.service.pending.response.CardSendResponse;
|
||||
import cn.axzo.msg.center.service.pending.response.CardUpdateResponse;
|
||||
import cn.axzo.msg.center.service.pending.request.CardUpdateStateRequest;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedModelV3;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
@ -24,28 +44,168 @@ import org.springframework.stereotype.Component;
|
||||
@RequiredArgsConstructor
|
||||
public class CardManager {
|
||||
|
||||
private final ModelV3Service modelV3Service;
|
||||
private final ModelV3Parser modelV3Parser;
|
||||
private final TransactionTemplate transactionTemplate;
|
||||
private final CardSupport cardSupport;
|
||||
private final CardDao cardDao;
|
||||
private final CardLogger cardLogger;
|
||||
private final MessageApi messageApi;
|
||||
private final PushDeviceService pushDeviceService;
|
||||
private final CardParser cardParser;
|
||||
private final CardBroadcaster cardBroadcaster;
|
||||
|
||||
public CardSendResponse send(CardSendRequest request) {
|
||||
return null;
|
||||
public void send(CardSendRequest request) {
|
||||
// 校验参数
|
||||
BizAssertions.assertNotNull(request.getSender(), "发送人不能为空");
|
||||
BizAssertions.assertNotEmpty(request.getReceivers(), "接收人不能为空");
|
||||
ParsedModelV3 parsedModel = cardSupport.parseModel(
|
||||
cardSupport.getTemplateModelOrThrow(request.getTemplateCode()), request);
|
||||
// 主要逻辑
|
||||
CardSendModel sendModel = new CardSendModel(request, parsedModel);
|
||||
cardSupport.buildCardsForSend(sendModel);
|
||||
execTransactional(() -> {
|
||||
cardDao.saveBatch(sendModel.getCards());
|
||||
cardLogger.reloadAndLogCards("send:enqueue", request, sendModel.getCards());
|
||||
});
|
||||
PushDeviceSnapshots deviceSnapshots = pushDeviceService.createDeviceSnapshots();
|
||||
String imSenderAccount = BizAssertions.assertResponse(
|
||||
messageApi.findTemplateRobotImAccount(parsedModel.getTemplateCode()));
|
||||
for (CardGroup group : sendModel.getCardGroups()) {
|
||||
SendTemplateMessageParam imRequest = cardSupport.buildImSendRequest(
|
||||
sendModel, group, deviceSnapshots, imSenderAccount);
|
||||
try {
|
||||
MessageTaskResp imResponse = BizAssertions.assertResponse(
|
||||
messageApi.sendTemplateMessageAsync(imRequest));
|
||||
execTransactional(() -> {
|
||||
cardDao.setSendSuccess(sendModel.getCards(), imResponse);
|
||||
cardLogger.reloadAndLogCards("send:success", request, sendModel.getCards());
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.warn("发送IM消息失败, request={}", request, e);
|
||||
cardLogger.reloadAndLogCards("send:fail", request, sendModel.getCards(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CardUpdateResponse update(CardUpdateRequest request) {
|
||||
return null;
|
||||
public void updateState(CardUpdateStateRequest request) {
|
||||
TemplateModelV3 templateModel = cardSupport.getTemplateModelOrThrow(request.getTemplateCode());
|
||||
Supplier<List<Card>> cursor = cardsCursor(request);
|
||||
boolean updated = false;
|
||||
for (List<Card> cards = cursor.get(); !cards.isEmpty(); cards = cursor.get()) {
|
||||
updated = true;
|
||||
List<Card> finalCards = cards;
|
||||
execTransactional(() -> {
|
||||
cardDao.updateStates(finalCards, request.getCardState());
|
||||
rebuildCardContent(templateModel, finalCards);
|
||||
cardLogger.reloadAndLogCards("updateState:enqueue", request, finalCards);
|
||||
});
|
||||
updateMessages("updateState", request, cards);
|
||||
}
|
||||
BizAssertions.assertTrue(updated, "未找到任何需要更新的卡片, request={}", request);
|
||||
}
|
||||
|
||||
private ParsedModelV3 parseModel(String templateCode,
|
||||
JSONObject bizParam,
|
||||
JSONObject routerParam) {
|
||||
TemplateModelV3 model = modelV3Service
|
||||
.findEnabledByCode(templateCode)
|
||||
.orElse(null);
|
||||
BizAssertions.assertNotNull(model, "模板不存在或已下线 {} ", templateCode);
|
||||
return modelV3Parser.parseModel(model, bizParam, new UrlParser(routerParam));
|
||||
void firePresetButtonPressed(CardPresetButtonPressedRequest request) {
|
||||
Card requestCard = cardDao.findCardByBizMessageId(request.getBizMessageId()).orElse(null);
|
||||
BizAssertions.assertNotNull(requestCard, "找不到对应的卡片, bizMessageId={}", request.getBizMessageId());
|
||||
List<Card> cards = cardDao.collectPersonCards(request.getBizMessageId());
|
||||
TemplateModelV3 templateModel = cardSupport.getTemplateModelOrThrow(requestCard.getTemplateCode());
|
||||
firePresetButtonPressedImpl(request, templateModel, cards);
|
||||
}
|
||||
|
||||
public void firePresetButtonPressed(CardUpdatePresetButtonRequest request) {
|
||||
TemplateModelV3 templateModel = cardSupport.getTemplateModelOrThrow(request.getTemplateCode());
|
||||
Supplier<List<Card>> cursor = cardsCursor(request);
|
||||
for (List<Card> cards = cursor.get(); !cards.isEmpty(); cards = cursor.get())
|
||||
firePresetButtonPressedImpl(request, templateModel, cards);
|
||||
}
|
||||
|
||||
private void firePresetButtonPressedImpl(
|
||||
CardPresetButtonRequest request, TemplateModelV3 templateModel, List<Card> cards) {
|
||||
MessageTemplateButtonV3 button = templateModel.findPresetButton(request.getPresetButtonType()).orElse(null);
|
||||
BizAssertions.assertNotNull(button, "找不到对应的预设按钮, request={}", JSON.toJSONString(request));
|
||||
ArrayList<Card> updates = new ArrayList<>();
|
||||
for (Card card : cards) {
|
||||
CardButtonStates buttonStates = CardButtonStates.create(card.getButtonStates());
|
||||
//noinspection DataFlowIssue
|
||||
buttonStates.setActionPerformed(button.getCode());
|
||||
Card update = new Card();
|
||||
update.setId(card.getId());
|
||||
update.setButtonStates(buttonStates.getStates());
|
||||
updates.add(update);
|
||||
}
|
||||
execTransactional(() -> {
|
||||
cardDao.updateBatchById(updates);
|
||||
rebuildCardContent(templateModel, cards);
|
||||
cardLogger.reloadAndLogCards("presetButtonPressed:enqueue", request, cards);
|
||||
});
|
||||
if (updateMessages("presetButtonPressed", request, cards)) {
|
||||
cardBroadcaster.firePresetButtonPressed(
|
||||
cards, request.getOperatorId(), request.getPresetButtonType());
|
||||
cardLogger.reloadAndLogCards("presetButtonPressed:mq:success", request, cards);
|
||||
}
|
||||
}
|
||||
|
||||
private Supplier<List<Card>> cardsCursor(CardUpdateRequest request) {
|
||||
Ref<Long> maxId = Ref.create(0L);
|
||||
return () -> {
|
||||
List<Card> cards = cardDao.lambdaQuery()
|
||||
.eq(Card::getAppCode, request.getAppCode())
|
||||
.eq(Card::getTemplateCode, request.getTemplateCode())
|
||||
.eq(Card::getBizCode, request.getBizCode())
|
||||
.eq(StringUtils.isNotBlank(request.getSubBizCode()), Card::getSubBizCode, request.getSubBizCode())
|
||||
.nested(CollectionUtils.isNotEmpty(request.getReceivers()), nested -> {
|
||||
for (PeerPerson receiver : request.getReceivers()) {
|
||||
nested.or().eq(Card::getReceiverPersonId, receiver.getPersonId())
|
||||
// 有可能不区分ouId和workspaceId更新人所有ou和workspace的卡片
|
||||
.eq(receiver.getOuId() != null, Card::getReceiverOuId, receiver.getOuId())
|
||||
.eq(receiver.getWorkspaceId() != null, Card::getReceiverWorkspaceId, receiver.getWorkspaceId());
|
||||
}
|
||||
})
|
||||
.gt(Card::getId, maxId.get())
|
||||
.orderByAsc(Card::getId)
|
||||
.last("LIMIT 500")
|
||||
.list();
|
||||
if (!cards.isEmpty())
|
||||
maxId.set(cards.get(cards.size() - 1).getId());
|
||||
return cards;
|
||||
};
|
||||
}
|
||||
|
||||
private void rebuildCardContent(TemplateModelV3 templateModel, List<Card> cards) {
|
||||
ArrayList<Card> updates = new ArrayList<>();
|
||||
for (Card card : cardDao.reloadCards(cards)) {
|
||||
Card update = new Card();
|
||||
update.setId(card.getId());
|
||||
// 每个消息独立解析, 因为每个卡片的状态和按钮可能已经存在差异了
|
||||
CardTemplate cardTemplate = CardTemplate.wrap(cardSupport.parseModel(templateModel, card));
|
||||
BizAssertions.assertTrue(cardTemplate.isUpdatable(),
|
||||
"模板不支持更新, templateCode={}", card.getTemplateCode());
|
||||
update.setCardContent(cardParser.parseCardContent(cardTemplate, card));
|
||||
updates.add(update);
|
||||
}
|
||||
cardDao.updateBatchById(updates);
|
||||
}
|
||||
|
||||
private boolean updateMessages(String operation, Object request, List<Card> cards) {
|
||||
UpdateMessageRequest imRequest = new UpdateMessageRequest();
|
||||
for (Card card : cardDao.reloadCards(cards)) {
|
||||
UpdateMessageRequest.Update update = new UpdateMessageRequest.Update();
|
||||
update.setBizMessageId(card.getBizMessageId());
|
||||
update.setMsgTemplateContent(JSON.toJSONString(card.getCardContent()));
|
||||
imRequest.addUpdate(update);
|
||||
}
|
||||
try {
|
||||
BizAssertions.assertResponse(messageApi.updateMessage(imRequest));
|
||||
cardLogger.reloadAndLogCards(String.format("%s:success", operation), request, cards);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.warn("更新IM消息失败, operation={}, request={}", operation, JSON.toJSONString(request), e);
|
||||
cardLogger.reloadAndLogCards(String.format("%s:fail", operation), request, cards, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void execTransactional(Runnable runnable) {
|
||||
transactionTemplate.executeWithoutResult(unused -> runnable.run());
|
||||
}
|
||||
|
||||
}
|
||||
@ -3,6 +3,7 @@ package cn.axzo.msg.center.message.service.card;
|
||||
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.CardButton;
|
||||
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO.CardExtensionItem;
|
||||
import cn.axzo.msg.center.message.domain.vo.ParsedUrlForCms;
|
||||
import cn.axzo.msg.center.message.service.impl.v3.AppLink;
|
||||
import cn.axzo.msg.center.message.service.impl.v3.NativeAppLinkUrlConfigVisitor;
|
||||
@ -17,13 +18,13 @@ import cn.axzo.msg.center.service.enums.CardState;
|
||||
import cn.axzo.msg.center.service.enums.KVContentType;
|
||||
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.CardElementConfig;
|
||||
import cn.axzo.msg.center.service.pending.request.CardContent;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.ParsedModel3Visitor;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.ParsedModelV3Walker;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedButtonV3;
|
||||
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.ParsedModelV3;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedTemplateV3;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.model.PersonInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -45,28 +46,30 @@ class CardParser {
|
||||
private final MessageSystemConfig messageSystemConfig;
|
||||
private final V3ExtPopulator v3ExtPopulator;
|
||||
|
||||
GeneralMessagePushVO parseCardContent(ParsedModelV3 model,
|
||||
CardContent card) {
|
||||
ParsedTemplateV3 template = model.getTemplate();
|
||||
GeneralMessagePushVO parseCardContent(CardTemplate cardTemplate, CardContent card) {
|
||||
ParsedTemplateV3 template = cardTemplate.getTemplate();
|
||||
GeneralMessagePushVO im = new GeneralMessagePushVO();
|
||||
// 这个字段好像没有业务含义
|
||||
im.setIdentityCode("");
|
||||
im.setCardStyleCode(template.getCardStyleCode());
|
||||
im.setBizCode("");
|
||||
im.setTemplateCode(template.getCode());
|
||||
im.setCardBannerUrl(template.getIcon());
|
||||
im.setCardTitle(template.getTitle());
|
||||
im.setCardContent(template.getContent());
|
||||
im.setSendTimestamp(new Date().getTime());
|
||||
//im.setCardState();
|
||||
//im.setStateImage();
|
||||
//im.setCardElements();
|
||||
// 取当前时间即可, 数据库存的更新时间肯定晚于等于这个时间, 因此不会存在更新丢失
|
||||
im.setUpdateTime(System.currentTimeMillis());
|
||||
if (cardTemplate.isUpdatable())
|
||||
im.setCardState(card.getState());
|
||||
im.setStateImage(cardTemplate.determineStateImage(card.getState()));
|
||||
if (StringUtils.isNotBlank(card.getSubtitle())) {
|
||||
GeneralMessagePushVO.Subtitle subtitle = new GeneralMessagePushVO.Subtitle();
|
||||
subtitle.setIconUrl(messageSystemConfig.getOrgIcon());
|
||||
subtitle.setTitle(card.getSubtitle());
|
||||
im.setSubtitles(Collections.singletonList(subtitle));
|
||||
}
|
||||
ParsedModelV3Walker.walkDown(model, new ParsedModel3Visitor() {
|
||||
ParsedModelV3Walker.walkDown(cardTemplate.getParsedModel(), new ParsedModel3Visitor() {
|
||||
@Override
|
||||
public void visitTemplateCardUrlConfig(UrlConfig urlConfig) {
|
||||
if (!urlConfig.hasUrl()) return;
|
||||
@ -75,6 +78,7 @@ class CardParser {
|
||||
cardDetailButton.setAction(RouterCategoryEnum.JUMP.name());
|
||||
cardDetailButton.setIsHighlight(false);
|
||||
cardDetailButton.setActionPaths(getNativeAppLinks(urlConfig));
|
||||
cardDetailButton.setUrlConfig(urlConfig);
|
||||
im.setCardDetailButton(cardDetailButton);
|
||||
|
||||
im.setCardUrlForCms(parseUrlForCms(urlConfig));
|
||||
@ -82,15 +86,15 @@ class CardParser {
|
||||
|
||||
@Override
|
||||
public void visitGroupKeyValue(ParsedGroupV3 group, ParsedKV kv) {
|
||||
if (!kv.isDisplayOnCard())
|
||||
return;
|
||||
GeneralMessagePushVO.CardExtensionItem item = new GeneralMessagePushVO.CardExtensionItem(kv.getKey(), kv.getValue());
|
||||
if (!kv.isDisplayOnCard()) return;
|
||||
if (StringUtils.isBlank(kv.getValue())) return;
|
||||
CardExtensionItem item = new CardExtensionItem(kv.getKey(), kv.getValue());
|
||||
// IM人员: 张三(130****5556)
|
||||
if (kv.getContentType() == KVContentType.PERSON_ID) {
|
||||
v3ExtPopulator.populatePersonKV(kv);
|
||||
PersonInfo person = kv.getPersonInfo();
|
||||
if (person != null) {
|
||||
item = new GeneralMessagePushVO.CardExtensionItem(kv.getKey(), person.getPlainPersonInfo());
|
||||
item = new CardExtensionItem(kv.getKey(), person.getPlainPersonInfo());
|
||||
}
|
||||
}
|
||||
if (im.getCardExtension() == null)
|
||||
@ -103,7 +107,8 @@ class CardParser {
|
||||
List<ButtonStyleEnum> styles = button.parseStyle();
|
||||
if (!styles.contains(ButtonStyleEnum.OVER_CARD))
|
||||
return;
|
||||
if (card.getCardState() != CardState.PENDING && button.determinePendingShow())
|
||||
if (card.getState() != CardState.PENDING
|
||||
&& button.determinePendingShow())
|
||||
return;
|
||||
if (im.getCardButtons() == null)
|
||||
im.setCardButtons(new ArrayList<>());
|
||||
@ -117,6 +122,9 @@ class CardParser {
|
||||
imButton.setIsOverCard(styles.contains(ButtonStyleEnum.OVER_CARD));
|
||||
imButton.setExecutorShow(button.getExecutorShow());
|
||||
imButton.setActionPerformed(card.isButtonActionPerformed(button.getCode()));
|
||||
imButton.setUrlConfig(button.getUrlConfig());
|
||||
imButton.setButtonCode(button.getCode());
|
||||
imButton.setPresetButtonType(button.getPresetButtonType());
|
||||
|
||||
if (RouterCategoryEnum.ACTION.equals(button.getCategory())) {
|
||||
AppLink appLink = new AppLink(TerminalTypeEnum.WEB_VIEW.name(), button.getApiUrl());
|
||||
@ -130,6 +138,25 @@ class CardParser {
|
||||
imButton.setUrlInfoForCms(parseUrlForCms(button.getUrlConfig()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCardElement(CardElementConfig cfg) {
|
||||
addCardElement(cfg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCardExtField(CardElementConfig cfg) {
|
||||
addCardElement(cfg);
|
||||
}
|
||||
|
||||
private void addCardElement(CardElementConfig cfg) {
|
||||
if (StringUtils.isBlank(cfg.getValue()))
|
||||
return;
|
||||
if (im.getCardElements() == null)
|
||||
im.setCardElements(new ArrayList<>());
|
||||
im.getCardElements().add(cfg);
|
||||
}
|
||||
|
||||
});
|
||||
if (im.getCardUrlForCms() == null) {
|
||||
ParsedUrlForCms cardUrlForCms = new ParsedUrlForCms();
|
||||
|
||||
@ -1,74 +1,174 @@
|
||||
package cn.axzo.msg.center.message.service.card;
|
||||
|
||||
import cn.axzo.im.center.api.vo.PersonAccountAttribute;
|
||||
import cn.axzo.framework.jackson.utility.JSON;
|
||||
import cn.axzo.im.center.api.vo.ApiChannel;
|
||||
import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam;
|
||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||
import cn.axzo.im.center.common.enums.YesOrNo;
|
||||
import cn.axzo.maokai.api.util.Ref;
|
||||
import cn.axzo.msg.center.common.utils.BizAssertions;
|
||||
import cn.axzo.msg.center.domain.entity.Card;
|
||||
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
|
||||
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
|
||||
import cn.axzo.msg.center.message.service.card.domain.CardsForSend;
|
||||
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.impl.v3.ModelV3Parser;
|
||||
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.nimpush.NimPushService;
|
||||
import cn.axzo.msg.center.nimpush.PushPeer;
|
||||
import cn.axzo.msg.center.nimpush.device.PushDeviceSnapshots;
|
||||
import cn.axzo.msg.center.nimpush.payload.intent.Intent;
|
||||
import cn.axzo.msg.center.push.PushData;
|
||||
import cn.axzo.msg.center.service.domain.card.AppVersionConfig;
|
||||
import cn.axzo.msg.center.service.dto.PeerPerson;
|
||||
import cn.axzo.msg.center.service.enums.CardSendState;
|
||||
import cn.axzo.msg.center.service.enums.CardState;
|
||||
import cn.axzo.msg.center.service.enums.YesOrNo;
|
||||
import cn.axzo.msg.center.service.pending.request.CardSendRequest;
|
||||
import cn.axzo.msg.center.service.enums.MessageChannel;
|
||||
import cn.axzo.msg.center.service.pending.request.CardContent;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.ParsedModel3Visitor;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.ParsedModelV3Walker;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedModelV3;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedTemplateV3;
|
||||
import cn.axzo.msg.center.utils.UUIDUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
class CardSupport {
|
||||
public class CardSupport {
|
||||
|
||||
public static final String BIZ_ID_PREFIX = "msg-center";
|
||||
|
||||
private final ModelV3Service modelV3Service;
|
||||
private final ModelV3Parser modelV3Parser;
|
||||
private final CardParser cardParser;
|
||||
private final NimPushService nimPushService;
|
||||
|
||||
CardsForSend buildCards(CardSendRequest request, ParsedModelV3 model) {
|
||||
ArrayList<Card> cards = new ArrayList<>();
|
||||
HashSet<PersonAccountAttribute> accounts = new HashSet<>();
|
||||
public static String getBizIdPrefix(String templateCode) {
|
||||
return String.format("%s:%s", BIZ_ID_PREFIX, templateCode);
|
||||
}
|
||||
|
||||
void buildCardsForSend(CardSendModel sendModel) {
|
||||
String batchNo = UUIDUtil.uuidString();
|
||||
ParsedTemplateV3 template = model.getTemplate();
|
||||
GeneralMessagePushVO cardContent = cardParser.parseCardContent(model, request);
|
||||
for (PeerPerson person : request.getReceivers()) {
|
||||
PersonAccountAttribute account = new PersonAccountAttribute();
|
||||
if (accounts.contains(account)) continue;
|
||||
accounts.add(account);
|
||||
Card card = new Card();
|
||||
cards.add(card);
|
||||
card.setBatchNo(batchNo);
|
||||
//todo
|
||||
card.setImInitTaskId(0L);
|
||||
card.setIdentityCode(UUIDUtil.uuidString());
|
||||
card.setBizCode(request.getBizCode());
|
||||
card.setSubBizCode(request.getSubBizCode());
|
||||
card.setTemplateCode(request.getTemplateCode());
|
||||
card.setSendState(CardSendState.INIT_SEND_QUEUED);
|
||||
card.setCardState(CardState.PENDING);
|
||||
card.setTitle(template.getTitle());
|
||||
card.setContent(template.getContent());
|
||||
card.setCardContent(cardContent);
|
||||
card.setBizParam(request.getBizParam());
|
||||
card.setRouterParam(request.getRouterParam());
|
||||
card.setSenderAppType(AppTypeEnum.SYSTEM);
|
||||
card.setIsSenderRobot(YesOrNo.YES);
|
||||
card.setReceiverAppTypes(template.parsePushAppTypes());
|
||||
card.setSenderPersonId(request.getSender().getPersonId());
|
||||
card.setSenderOuId(request.getSender().getOuId());
|
||||
card.setSenderWorkspaceId(request.getSender().getWorkspaceId());
|
||||
card.setReceiverPersonId(person.getPersonId());
|
||||
card.setReceiverOuId(person.getOuId());
|
||||
card.setReceiverWorkspaceId(person.getWorkspaceId());
|
||||
//card.setButtonStates();
|
||||
//card.setStateImage(request.getStateImage());
|
||||
card.setSubtitle(request.getSubtitle());
|
||||
//card.setUpdatable();
|
||||
GeneralMessagePushVO cardContent = cardParser.parseCardContent(
|
||||
sendModel.cardTemplate(), sendModel.getRequest());
|
||||
sendModel.setCardContent(cardContent);
|
||||
for (PeerPerson person : sendModel.getRequest().getReceivers()) {
|
||||
for (AppTypeEnum appType : sendModel.cardTemplate().ensureAppTypesPresent()) {
|
||||
Card card = new Card();
|
||||
sendModel.addCard(card);
|
||||
card.setBatchNo(batchNo);
|
||||
card.setAppCode(sendModel.getRequest().getAppCode());
|
||||
card.setImTaskId(0L);
|
||||
card.setBizMessageId("");
|
||||
card.setIdentityCode(UUIDUtil.uuidString());
|
||||
card.setBizCode(sendModel.getRequest().determineBizCode());
|
||||
card.setSubBizCode(sendModel.getRequest().getSubBizCode());
|
||||
card.setTemplateCode(sendModel.getRequest().getTemplateCode());
|
||||
card.setState(CardState.PENDING);
|
||||
card.setTitle(sendModel.getParsedModel().getTemplate().getTitle());
|
||||
card.setContent(sendModel.getParsedModel().getTemplate().getContent());
|
||||
card.setCardContent(cardContent);
|
||||
card.setBizParam(sendModel.getRequest().getBizParam());
|
||||
card.setRouterParam(sendModel.getRequest().getRouterParam());
|
||||
card.setSenderAppType(AppTypeEnum.SYSTEM);
|
||||
card.setIsSenderRobot(YesOrNo.YES);
|
||||
card.setReceiverAppType(appType);
|
||||
card.setSenderPersonId(sendModel.getRequest().getSender().getPersonId());
|
||||
card.setSenderOuId(sendModel.getRequest().getSender().getOuId());
|
||||
card.setSenderWorkspaceId(sendModel.getRequest().getSender().getWorkspaceId());
|
||||
card.setReceiverPersonId(person.getPersonId());
|
||||
card.setReceiverOuId(person.getOuId());
|
||||
card.setReceiverWorkspaceId(person.getWorkspaceId());
|
||||
card.setSubtitle(sendModel.getRequest().getSubtitle());
|
||||
card.setButtonStates(new ArrayList<>());
|
||||
card.setUpdatable(sendModel.cardTemplate().isUpdatable() ? YesOrNo.YES : YesOrNo.NO);
|
||||
}
|
||||
}
|
||||
return new CardsForSend(cards, cardContent);
|
||||
}
|
||||
|
||||
SendTemplateMessageParam buildImSendRequest(CardSendModel sendModel,
|
||||
CardGroup group,
|
||||
PushDeviceSnapshots deviceSnapshots,
|
||||
String imSenderAccount) {
|
||||
ParsedTemplateV3 template = sendModel.getParsedModel().getTemplate();
|
||||
Supplier<String> payloadBuilder = () -> {
|
||||
PushPeer peer = new PushPeer();
|
||||
peer.setSenderImAccount(imSenderAccount);
|
||||
peer.setOuId(group.getGroupKey().getOuId());
|
||||
peer.setWorkspaceId(group.getGroupKey().getWorkspaceId());
|
||||
peer.setAppType(group.getGroupKey().getAppType());
|
||||
peer.setApiChannel(ApiChannel.COMMON_MESSAGE);
|
||||
return nimPushService.buildPayloadString(sendModel.getParsedModel(), peer);
|
||||
};
|
||||
Supplier<JSONObject> extBuilder = () -> {
|
||||
JSONObject ext = new JSONObject();
|
||||
ext.put("minAppVersion", determineMinAppVersion(
|
||||
sendModel.getParsedModel(), group.getGroupKey().getAppType()));
|
||||
if (group.getGroupKey().getOuId() != null)
|
||||
ext.put("ouId", String.valueOf(group.getGroupKey().getOuId()));
|
||||
if (group.getGroupKey().getWorkspaceId() != null)
|
||||
ext.put("workspaceId", String.valueOf(group.getGroupKey().getWorkspaceId()));
|
||||
return ext;
|
||||
};
|
||||
PushData pushData = template.parsePushData();
|
||||
SendTemplateMessageParam imRequest = new SendTemplateMessageParam();
|
||||
imRequest.setSender(null);
|
||||
imRequest.setMsgHeader(template.getTitle());
|
||||
imRequest.setMsgContent(template.getContent());
|
||||
imRequest.setMsgTemplateId(template.getCode());
|
||||
imRequest.setSendPriority(template.determineImSendPriority());
|
||||
imRequest.setMsgTemplateContent(JSON.toJSONString(sendModel.getCardContent()));
|
||||
imRequest.setBizId(String.format("%s:%s", getBizIdPrefix(
|
||||
template.getCode()), sendModel.getRequest().determineBizCode()));
|
||||
imRequest.setReceivePersons(group.buildReceiverAccounts());
|
||||
imRequest.setExt(extBuilder.get());
|
||||
imRequest.setUpdatable(sendModel.cardTemplate().isUpdatable());
|
||||
if (pushData.determinePushable(log, template.getCode())) {
|
||||
imRequest.setPayload(payloadBuilder.get());
|
||||
imRequest.setExcludePushPayloads(group.buildNimPushExcludes(deviceSnapshots));
|
||||
if (StringUtils.isNotBlank(pushData.getVoiceFile()))
|
||||
imRequest.getExt().put(Intent.INTENT_SOUND, pushData.getVoiceFile());
|
||||
}
|
||||
return imRequest;
|
||||
}
|
||||
|
||||
private String determineMinAppVersion(ParsedModelV3 model,
|
||||
AppTypeEnum appType) {
|
||||
Ref<String> minVersion = Ref.create("");
|
||||
ParsedModelV3Walker.walkDown(model, new ParsedModel3Visitor() {
|
||||
@Override
|
||||
public void visitAppVersionConfig(AppVersionConfig cfg) {
|
||||
if (cfg.getAppType() == appType)
|
||||
minVersion.set(cfg.getMinVersion());
|
||||
}
|
||||
});
|
||||
return minVersion.get();
|
||||
}
|
||||
|
||||
TemplateModelV3 getTemplateModelOrThrow(String templateCode) {
|
||||
TemplateModelV3 templateModel = modelV3Service
|
||||
.findEnabledByCode(templateCode).orElse(null);
|
||||
BizAssertions.assertNotNull(templateModel, "模板不存在或已下线 {} ", templateCode);
|
||||
return templateModel;
|
||||
}
|
||||
|
||||
ParsedModelV3 parseModel(TemplateModelV3 model, CardContent card) {
|
||||
List<MessageChannel> channels = model.getTemplate().determineChannels();
|
||||
BizAssertions.assertTrue(channels.contains(MessageChannel.IM), "模版未配置IM通道 {} ",
|
||||
model.getTemplateCode());
|
||||
return modelV3Parser.parseModel(model, card.getBizParam(), new UrlParser(card.getRouterParam()));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package cn.axzo.msg.center.message.service.card;
|
||||
|
||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||
import cn.axzo.msg.center.common.utils.BizAssertions;
|
||||
import cn.axzo.msg.center.service.domain.card.StateImageConfig;
|
||||
import cn.axzo.msg.center.service.enums.CardState;
|
||||
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedModelV3;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedTemplateV3;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CardTemplate {
|
||||
|
||||
private final ParsedModelV3 parsedModel;
|
||||
|
||||
public static CardTemplate wrap(ParsedModelV3 parsedModel) {
|
||||
return new CardTemplate(parsedModel);
|
||||
}
|
||||
|
||||
public List<AppTypeEnum> ensureAppTypesPresent() {
|
||||
List<AppTypeEnum> appTypes = parsedModel.getTemplate().parsePushAppTypes();
|
||||
BizAssertions.assertNotEmpty(appTypes,
|
||||
"发送IM消息, 消息模版没有配置IM发送终端, templateCode={}", parsedModel.getTemplateCode());
|
||||
return appTypes;
|
||||
}
|
||||
|
||||
public boolean isUpdatable() {
|
||||
return getTemplate().getMsgCategory() != MessageCategoryEnum.GENERAL_MESSAGE;
|
||||
}
|
||||
|
||||
public String determineStateImage(CardState state) {
|
||||
List<StateImageConfig> images = getTemplate().getStateImageConfigs();
|
||||
if (images == null) return null;
|
||||
return images.stream()
|
||||
.filter(config -> config.getCardState() == state)
|
||||
.findFirst()
|
||||
.map(StateImageConfig::determineImageUrl)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public ParsedTemplateV3 getTemplate() {
|
||||
return parsedModel.getTemplate();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package cn.axzo.msg.center.message.service.card.broadcast;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
import cn.axzo.msg.center.api.mq.CardInfo;
|
||||
import cn.axzo.msg.center.api.mq.CardPresetButtonPressedMessage;
|
||||
import cn.axzo.msg.center.dal.CardDao;
|
||||
import cn.axzo.msg.center.domain.entity.Card;
|
||||
import cn.axzo.msg.center.mq.MqMessageRecord;
|
||||
import cn.axzo.msg.center.mq.MqProducer;
|
||||
import cn.axzo.msg.center.service.enums.MqMessageType;
|
||||
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CardBroadcaster {
|
||||
|
||||
private final CardDao cardDao;
|
||||
private final MqProducer mqProducer;
|
||||
|
||||
public void firePresetButtonPressed(
|
||||
List<Card> cards, Long operatorId, PresetButtonType presetButtonType) {
|
||||
for (Card card : cardDao.reloadCards(cards)) {
|
||||
CardPresetButtonPressedMessage message = new CardPresetButtonPressedMessage();
|
||||
message.setPresetButtonType(presetButtonType);
|
||||
message.setCardInfo(BeanMapper.copyBean(card, CardInfo.class));
|
||||
mqProducer.send(MqMessageRecord
|
||||
.builder(MqMessageType.CARD_PRESET_BUTTON_PRESSED, message)
|
||||
.messageKey(card.getId())
|
||||
.operatorId(operatorId)
|
||||
.shardingKey(card.getTemplateCode())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package cn.axzo.msg.center.message.service.card.domain;
|
||||
|
||||
import cn.axzo.im.center.api.vo.PersonAccountAttribute;
|
||||
import cn.axzo.im.center.api.vo.req.ExcludePushPayload;
|
||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||
import cn.axzo.msg.center.domain.entity.Card;
|
||||
import cn.axzo.msg.center.nimpush.PushChannel;
|
||||
import cn.axzo.msg.center.nimpush.device.PushDevice;
|
||||
import cn.axzo.msg.center.nimpush.device.PushDeviceSnapshots;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class CardGroup {
|
||||
|
||||
private final CardGroupKey groupKey;
|
||||
private final List<Card> cards = new ArrayList<>();
|
||||
|
||||
public void addCard(Card card) {
|
||||
cards.add(card);
|
||||
}
|
||||
|
||||
public List<PersonAccountAttribute> buildReceiverAccounts() {
|
||||
return getCards().stream().map(card -> {
|
||||
PersonAccountAttribute account = new PersonAccountAttribute();
|
||||
account.setPersonId(card.getReceiverPersonId() + "");
|
||||
account.setOuId(card.getReceiverOuId());
|
||||
account.setWorkspaceId(card.getReceiverWorkspaceId());
|
||||
account.setAppType(groupKey.getAppType());
|
||||
return account;
|
||||
}).collect(toList());
|
||||
}
|
||||
|
||||
public List<ExcludePushPayload> buildNimPushExcludes(PushDeviceSnapshots deviceSnapshots) {
|
||||
AppTypeEnum appType = groupKey.getAppType();
|
||||
return getCards().stream().map(Card::getReceiverPersonId)
|
||||
.filter(personId -> {
|
||||
PushDevice device = deviceSnapshots.getDevice(personId);
|
||||
return device.shouldPush(appType, PushChannel.NIM);
|
||||
})
|
||||
.map(personId -> {
|
||||
ExcludePushPayload exclude = new ExcludePushPayload();
|
||||
exclude.setPersonId(personId + "");
|
||||
exclude.setAppType(appType);
|
||||
return exclude;
|
||||
})
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package cn.axzo.msg.center.message.service.card.domain;
|
||||
|
||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@RequiredArgsConstructor
|
||||
public class CardGroupKey {
|
||||
private final Long ouId;
|
||||
private final Long workspaceId;
|
||||
private final AppTypeEnum appType;
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package cn.axzo.msg.center.message.service.card.domain;
|
||||
|
||||
import cn.axzo.msg.center.domain.entity.Card;
|
||||
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
|
||||
import cn.axzo.msg.center.message.service.card.CardTemplate;
|
||||
import cn.axzo.msg.center.service.pending.request.CardSendRequest;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.model.ParsedModelV3;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class CardSendModel {
|
||||
|
||||
private final CardSendRequest request;
|
||||
private final ParsedModelV3 parsedModel;
|
||||
private final List<Card> cards = new ArrayList<>();
|
||||
|
||||
private GeneralMessagePushVO cardContent;
|
||||
|
||||
public CardTemplate cardTemplate() {
|
||||
return CardTemplate.wrap(parsedModel);
|
||||
}
|
||||
|
||||
public void addCard(Card card) {
|
||||
cards.add(card);
|
||||
}
|
||||
|
||||
public Collection<CardGroup> getCardGroups() {
|
||||
HashMap<CardGroupKey, CardGroup> groups = new HashMap<>();
|
||||
for (Card card : cards) {
|
||||
CardGroupKey key = new CardGroupKey(
|
||||
card.getReceiverOuId(),
|
||||
card.getReceiverWorkspaceId(),
|
||||
card.getReceiverAppType());
|
||||
groups.computeIfAbsent(key, CardGroup::new)
|
||||
.addCard(card);
|
||||
}
|
||||
return groups.values();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
package cn.axzo.msg.center.message.service.card.domain;
|
||||
|
||||
import cn.axzo.msg.center.domain.entity.Card;
|
||||
import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class CardsForSend {
|
||||
private final List<Card> cards;
|
||||
private final GeneralMessagePushVO cardContent;
|
||||
}
|
||||
@ -4,6 +4,7 @@ import cn.axzo.msg.center.domain.entity.MessageEntity;
|
||||
import cn.axzo.msg.center.domain.entity.MessageTemplateButtonV3;
|
||||
import cn.axzo.msg.center.domain.entity.MessageTemplateGroupV3;
|
||||
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
|
||||
import cn.axzo.msg.center.inside.notices.utils.FunctionalTransactionTemplate;
|
||||
import cn.axzo.msg.center.message.domain.dto.TemplateModelV3;
|
||||
import cn.axzo.msg.center.service.domain.UrlConfig;
|
||||
import cn.axzo.msg.center.service.domain.UrlConfigVisitor;
|
||||
@ -13,6 +14,7 @@ import cn.axzo.msg.center.service.domain.url.WebUrl;
|
||||
import cn.axzo.msg.center.service.enums.GroupType;
|
||||
import cn.axzo.msg.center.service.enums.KVContentType;
|
||||
import cn.axzo.msg.center.service.pending.ClientRequest;
|
||||
import cn.axzo.msg.center.service.pending.card.domain.CardElementConfig;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.ParsedModel3Visitor;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.ParsedModelV3Walker;
|
||||
import cn.axzo.msg.center.service.pending.response.v3.model.ComponentWorkerGroup;
|
||||
@ -36,6 +38,7 @@ import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -54,6 +57,8 @@ public class ModelV3Parser {
|
||||
private static final String CUSTOMER_PERSON_ID = "customerPersonId";
|
||||
|
||||
private final PendingMessageBizConfig cfg;
|
||||
private final ResourcePatternResolver resourcePatternResolver;
|
||||
private final FunctionalTransactionTemplate functionalTransactionTemplate;
|
||||
|
||||
public ParsedModelV3 parseModelForTodo(TemplateModelV3 templateModel,
|
||||
MessageEntity entity,
|
||||
@ -99,8 +104,8 @@ public class ModelV3Parser {
|
||||
|
||||
@Override
|
||||
public void visitTemplate(ParsedTemplateV3 template) {
|
||||
template.setTitle(getDefaultResolver().resolveByMap(template.getTitle(), bizParam));
|
||||
template.setContent(getDefaultResolver().resolveByMap(template.getContent(), bizParam));
|
||||
template.setTitle(resolveBizParam(template.getTitle()));
|
||||
template.setContent(resolveBizParam(template.getContent()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -126,7 +131,7 @@ public class ModelV3Parser {
|
||||
|
||||
@Override
|
||||
public void visitGroupKeyValue(ParsedGroupV3 group, ParsedKV kv) {
|
||||
kv.setValue(getDefaultResolver().resolveByMap(kv.getValue(), bizParam));
|
||||
kv.setValue(resolveBizParam(kv.getValue()));
|
||||
|
||||
if (kv.getContentType() == KVContentType.PERSON_ID
|
||||
&& StringUtils.isNotBlank(kv.getValue())
|
||||
@ -175,11 +180,25 @@ public class ModelV3Parser {
|
||||
urlParser.parseUrlConfig(urlConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCardExtField(CardElementConfig cfg) {
|
||||
cfg.setValue(resolveBizParam(cfg.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCardElement(CardElementConfig cfg) {
|
||||
cfg.setValue(resolveBizParam(cfg.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitModel(ParsedModelV3 model) {
|
||||
model.removeEmptyKVGroups();
|
||||
}
|
||||
|
||||
private String resolveBizParam(String template) {
|
||||
return getDefaultResolver().resolveByMap(template, bizParam);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return parsedModel;
|
||||
|
||||
@ -0,0 +1,152 @@
|
||||
package cn.axzo.msg.center.api.mq;
|
||||
|
||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||
import cn.axzo.im.center.common.enums.YesOrNo;
|
||||
import cn.axzo.msg.center.service.enums.CardState;
|
||||
import cn.axzo.msg.center.service.pending.card.domain.CardButtonState;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CardInfo {
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 请求批次号
|
||||
*/
|
||||
private String batchNo;
|
||||
|
||||
/**
|
||||
* 调用方标识
|
||||
*/
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* IM任务id
|
||||
*/
|
||||
private Long imTaskId;
|
||||
|
||||
/**
|
||||
* 业务消息ID
|
||||
*/
|
||||
private String bizMessageId;
|
||||
|
||||
/**
|
||||
* 卡片编码
|
||||
*/
|
||||
private String identityCode;
|
||||
|
||||
/**
|
||||
* 业务编码
|
||||
*/
|
||||
private String bizCode;
|
||||
|
||||
/**
|
||||
* 流程类代办的流程结点编码
|
||||
*/
|
||||
private String subBizCode;
|
||||
|
||||
/**
|
||||
* 卡片模版编码
|
||||
*/
|
||||
private String templateCode;
|
||||
|
||||
/**
|
||||
* 卡片状态. PENDING: 待处理, AGREED: 已同意, REJECTED: 已拒绝, REVOKED: 已撤销, ABORTED: 已中止, COMPLETED: 已处理, END: 已完结, IN_PROGRESS: 进行中
|
||||
*/
|
||||
private CardState state;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* IM卡片信息 (解析后)
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private Object cardContent;
|
||||
|
||||
/**
|
||||
* 业务扩展参数
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private JSONObject bizParam;
|
||||
|
||||
/**
|
||||
* 路由扩展参数
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private JSONObject routerParam;
|
||||
|
||||
/**
|
||||
* 发送者的端
|
||||
*/
|
||||
private AppTypeEnum senderAppType;
|
||||
|
||||
/**
|
||||
* 接收的端
|
||||
*/
|
||||
private AppTypeEnum receiverAppType;
|
||||
|
||||
/**
|
||||
* 发送人是否为机器人. YES: 是, NO: 否
|
||||
*/
|
||||
private YesOrNo isSenderRobot;
|
||||
|
||||
/**
|
||||
* 发起者的自然人ID
|
||||
*/
|
||||
private Long senderPersonId;
|
||||
|
||||
/**
|
||||
* 发起人的单位id
|
||||
*/
|
||||
private Long senderOuId;
|
||||
|
||||
/**
|
||||
* 发起者项目id
|
||||
*/
|
||||
private Long senderWorkspaceId;
|
||||
|
||||
/**
|
||||
* 接收人自然人id
|
||||
*/
|
||||
private Long receiverPersonId;
|
||||
|
||||
/**
|
||||
* 接收人单位id
|
||||
*/
|
||||
private Long receiverOuId;
|
||||
|
||||
/**
|
||||
* 接收人项目id
|
||||
*/
|
||||
private Long receiverWorkspaceId;
|
||||
|
||||
/**
|
||||
* 按钮状态
|
||||
*/
|
||||
private List<CardButtonState> buttonStates;
|
||||
|
||||
/**
|
||||
* 副标题
|
||||
*/
|
||||
private String subtitle;
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package cn.axzo.msg.center.api.mq;
|
||||
|
||||
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class CardPresetButtonPressedMessage extends MqMessage implements Serializable {
|
||||
|
||||
/**
|
||||
* 预设按钮类型
|
||||
* AGREE: 同意
|
||||
* REJECT: 驳回
|
||||
* REVOKE: 撤销
|
||||
*/
|
||||
private PresetButtonType presetButtonType;
|
||||
|
||||
/**
|
||||
* 待办信息
|
||||
*/
|
||||
private CardInfo cardInfo;
|
||||
|
||||
}
|
||||
@ -24,16 +24,16 @@ public class PeerPerson {
|
||||
/**
|
||||
* 自然人id
|
||||
*/
|
||||
private Long personId;
|
||||
private Long personId = 0L;
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
private Long ouId;
|
||||
private Long ouId = 0L;
|
||||
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
private Long workspaceId;
|
||||
private Long workspaceId = 0L;
|
||||
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
package cn.axzo.msg.center.service.enums;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public enum CardSendState implements CodeDefinition<String> {
|
||||
|
||||
INIT_SEND_QUEUED("准备发送"),
|
||||
INIT_SEND_SUCCESS("首次发送成功"),
|
||||
INIT_SEND_FAIL("首次发送失败"),
|
||||
UPDATE_SEND_SUCCESS("更新发送成功"),
|
||||
UPDATE_SEND_FAIL("更新发送失败"),
|
||||
|
||||
;
|
||||
|
||||
private final String description;
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return name();
|
||||
}
|
||||
|
||||
}
|
||||
@ -14,9 +14,11 @@ import org.apache.commons.lang3.StringUtils;
|
||||
public enum MqMessageType {
|
||||
|
||||
OLD_MSG_SEND("old-msg", "old-msg-send", "发送旧消息"),
|
||||
TODO_PRESET_BUTTON_PRESSED("todo", "todo-preset-button-pressed", "预设按钮被点击"),
|
||||
TODO_PRESET_BUTTON_PRESSED("todo", "todo-preset-button-pressed", "待定预设按钮被点击"),
|
||||
TODO_TEST_MESSAGE("todo", "test-message", "测试消息"),
|
||||
TODO_STATE_UPDATE("todo", "todo-state-update", "待办状态变更(创建)");
|
||||
TODO_STATE_UPDATE("todo", "todo-state-update", "待办状态变更(创建)"),
|
||||
CARD_PRESET_BUTTON_PRESSED("card", "card-preset-button-pressed", "卡片预设按钮被点击"),
|
||||
;
|
||||
|
||||
private final String eventModel;
|
||||
private final String eventName;
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package cn.axzo.msg.center.service.pending.card;
|
||||
|
||||
import cn.axzo.msg.center.service.pending.request.CardSendRequest;
|
||||
import cn.axzo.msg.center.service.pending.request.CardUpdateRequest;
|
||||
import cn.axzo.msg.center.service.pending.response.CardSendResponse;
|
||||
import cn.axzo.msg.center.service.pending.response.CardUpdateResponse;
|
||||
import cn.axzo.msg.center.service.pending.request.CardUpdateStateRequest;
|
||||
import cn.axzo.msg.center.service.pending.request.CardPresetButtonPressedRequest;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.http.MediaType;
|
||||
@ -20,11 +19,19 @@ import javax.validation.Valid;
|
||||
@FeignClient(value = "msg-center", url = "${server.serviceUrl:http://msg-center:8080}")
|
||||
public interface CardClient {
|
||||
|
||||
@PostMapping(value = "/card/send", produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||
CommonResponse<CardSendResponse> send(@RequestBody @Valid CardSendRequest request);
|
||||
@PostMapping(value = "/card/send",
|
||||
produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||
CommonResponse<Void> send(
|
||||
@RequestBody @Valid CardSendRequest request);
|
||||
|
||||
@PostMapping(value = "/card/updateState",
|
||||
produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||
CommonResponse<Void> updateState(
|
||||
@RequestBody @Valid CardUpdateStateRequest request);
|
||||
|
||||
@PostMapping(value = "/card/update", produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||
CommonResponse<CardUpdateResponse> update(@RequestBody @Valid CardUpdateRequest request);
|
||||
@PostMapping(value = "/card/firePresetButtonPressed",
|
||||
produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||
CommonResponse<Void> firePresetButtonPressed(
|
||||
@RequestBody @Valid CardPresetButtonPressedRequest request);
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package cn.axzo.msg.center.domain.entity;
|
||||
package cn.axzo.msg.center.service.pending.card.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -0,0 +1,42 @@
|
||||
package cn.axzo.msg.center.service.pending.card.domain;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CardButtonStates {
|
||||
|
||||
private final List<CardButtonState> states;
|
||||
|
||||
public static CardButtonStates create(List<CardButtonState> buttonStates) {
|
||||
return new CardButtonStates(new ArrayList<>(
|
||||
buttonStates == null ? Collections.emptyList(): buttonStates));
|
||||
}
|
||||
|
||||
public void setActionPerformed(String buttonCode) {
|
||||
states.removeIf(s -> s.getButtonCode().equals(buttonCode));
|
||||
CardButtonState state = new CardButtonState();
|
||||
state.setButtonCode(buttonCode);
|
||||
state.setIsActionPerformed(true);
|
||||
states.add(state);
|
||||
}
|
||||
|
||||
public boolean isButtonActionPerformed(String buttonCode) {
|
||||
return states.stream()
|
||||
.anyMatch(state -> {
|
||||
boolean isTheButton = state.getButtonCode().equals(buttonCode);
|
||||
boolean actionPerformed = state.determineIsActionPerformed();
|
||||
return isTheButton && actionPerformed;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,16 +1,27 @@
|
||||
package cn.axzo.msg.center.service.pending.request;
|
||||
|
||||
import cn.axzo.msg.center.service.enums.CardState;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public interface CardContent {
|
||||
|
||||
CardState getCardState();
|
||||
String getTemplateCode();
|
||||
|
||||
CardState getState();
|
||||
|
||||
boolean isButtonActionPerformed(String buttonCode);
|
||||
|
||||
String getSubtitle();
|
||||
|
||||
@NotNull
|
||||
JSONObject getBizParam();
|
||||
|
||||
@NotNull
|
||||
JSONObject getRouterParam();
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package cn.axzo.msg.center.service.pending.request;
|
||||
|
||||
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CardPresetButtonPressedRequest implements CardPresetButtonRequest {
|
||||
|
||||
/**
|
||||
* 业务消息id
|
||||
*/
|
||||
@NotBlank
|
||||
private String bizMessageId;
|
||||
|
||||
/**
|
||||
* 预设按钮类型
|
||||
* AGREE: 同意
|
||||
* REJECT: 驳回
|
||||
* REVOKE: 撤销
|
||||
*/
|
||||
@NotNull
|
||||
private PresetButtonType presetButtonType;
|
||||
|
||||
private Long operatorId;
|
||||
|
||||
private Long operatorName;
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package cn.axzo.msg.center.service.pending.request;
|
||||
|
||||
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public interface CardPresetButtonRequest {
|
||||
|
||||
PresetButtonType getPresetButtonType();
|
||||
|
||||
Long getOperatorId();
|
||||
|
||||
}
|
||||
@ -19,6 +19,12 @@ import java.util.Set;
|
||||
@Getter
|
||||
public class CardSendRequest implements CardContent {
|
||||
|
||||
/**
|
||||
* 调用方应用编码或场景编码, 保证这个场景下bizCode唯一
|
||||
*/
|
||||
@NotBlank(message = "应用编码不能为空")
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 模版编码
|
||||
*/
|
||||
@ -64,7 +70,7 @@ public class CardSendRequest implements CardContent {
|
||||
private String subtitle;
|
||||
|
||||
@Override
|
||||
public CardState getCardState() {
|
||||
public CardState getState() {
|
||||
return CardState.PENDING;
|
||||
}
|
||||
|
||||
@ -73,4 +79,18 @@ public class CardSendRequest implements CardContent {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getBizParam() {
|
||||
return bizParam == null ? new JSONObject() : bizParam;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getRouterParam() {
|
||||
return routerParam == null ? new JSONObject() : routerParam;
|
||||
}
|
||||
|
||||
public String determineBizCode() {
|
||||
return bizCode == null ? "" : bizCode;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package cn.axzo.msg.center.service.pending.request;
|
||||
|
||||
import cn.axzo.msg.center.service.enums.PresetButtonType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CardUpdatePresetButtonRequest extends CardUpdateRequest implements CardPresetButtonRequest {
|
||||
|
||||
/**
|
||||
* 预设按钮类型
|
||||
* AGREE: 同意
|
||||
* REJECT: 驳回
|
||||
* REVOKE: 撤销
|
||||
*/
|
||||
@NotNull
|
||||
private PresetButtonType presetButtonType;
|
||||
|
||||
private Long operatorId;
|
||||
|
||||
}
|
||||
@ -1,12 +1,46 @@
|
||||
package cn.axzo.msg.center.service.pending.request;
|
||||
|
||||
import cn.axzo.msg.center.service.dto.PeerPerson;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CardUpdateRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用方应用编码或场景编码, 保证这个场景下bizCode唯一
|
||||
*/
|
||||
@NotBlank(message = "应用编码不能为空")
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 模版编码
|
||||
*/
|
||||
@NotBlank(message = "模版编码不能为空")
|
||||
private String templateCode;
|
||||
|
||||
/**
|
||||
* 业务编码
|
||||
*/
|
||||
@NotBlank(message = "业务编码不能为空")
|
||||
private String bizCode;
|
||||
|
||||
/**
|
||||
* 子业务编码
|
||||
*/
|
||||
private String subBizCode;
|
||||
|
||||
/**
|
||||
* 接收人, 可选
|
||||
*/
|
||||
private Set<PeerPerson> receivers = new HashSet<>();
|
||||
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package cn.axzo.msg.center.service.pending.request;
|
||||
|
||||
import cn.axzo.msg.center.service.enums.CardState;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CardUpdateStateRequest extends CardUpdateRequest {
|
||||
|
||||
/**
|
||||
* 卡片状态
|
||||
*/
|
||||
@NotNull(message = "卡片状态不能为空")
|
||||
private CardState cardState;
|
||||
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
package cn.axzo.msg.center.service.pending.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CardSendResponse {
|
||||
}
|
||||
@ -8,5 +8,5 @@ import lombok.Setter;
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CardUpdateResponse {
|
||||
public class ImPresetButtonPressedResponse {
|
||||
}
|
||||
@ -1,13 +1,14 @@
|
||||
package cn.axzo.msg.center.service.pending.response.v3.model;
|
||||
|
||||
import cn.axzo.im.center.api.feign.SendPriority;
|
||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||
import cn.axzo.msg.center.push.PushData;
|
||||
import cn.axzo.msg.center.service.domain.CardUrlConfig;
|
||||
import cn.axzo.msg.center.service.domain.card.AppVersionConfig;
|
||||
import cn.axzo.msg.center.service.domain.card.StateImageConfig;
|
||||
import cn.axzo.msg.center.service.enums.CardState;
|
||||
import cn.axzo.msg.center.service.enums.CardUrlOpenStrategy;
|
||||
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
|
||||
import cn.axzo.msg.center.service.enums.MessageChannel;
|
||||
import cn.axzo.msg.center.service.enums.StatusEnum;
|
||||
import cn.axzo.msg.center.service.enums.YesOrNo;
|
||||
import cn.axzo.msg.center.service.pending.card.domain.CardElementConfig;
|
||||
@ -129,13 +130,10 @@ public class ParsedTemplateV3 {
|
||||
*/
|
||||
private List<StateImageConfig> stateImageConfigs;
|
||||
|
||||
public String determineStateImage(CardState state) {
|
||||
return stateImageConfigs.stream()
|
||||
.filter(config -> config.getCardState() == state)
|
||||
.findFirst()
|
||||
.map(StateImageConfig::determineImageUrl)
|
||||
.orElse(null);
|
||||
}
|
||||
/**
|
||||
* 通道
|
||||
*/
|
||||
private List<MessageChannel> channels;
|
||||
|
||||
public List<AppTypeEnum> parsePushAppTypes() {
|
||||
if (StringUtils.isBlank(pushTerminal))
|
||||
@ -157,6 +155,10 @@ public class ParsedTemplateV3 {
|
||||
return cardUrl;
|
||||
}
|
||||
|
||||
public Integer determineImSendPriority() {
|
||||
return imSendPriority == null ? SendPriority.TEMPLATE_MESSAGE.getPriority() : imSendPriority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
|
||||
@ -1,10 +1,23 @@
|
||||
package cn.axzo.msg.center.dal;
|
||||
|
||||
import cn.axzo.im.center.api.vo.resp.MessageTaskResp;
|
||||
import cn.axzo.im.center.api.vo.resp.UpdatableMessageSendResult;
|
||||
import cn.axzo.msg.center.dal.mapper.CardMapper;
|
||||
import cn.axzo.msg.center.domain.entity.Card;
|
||||
import cn.axzo.msg.center.domain.persistence.BaseEntityExt;
|
||||
import cn.axzo.msg.center.service.enums.CardState;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
@ -12,4 +25,58 @@ import org.springframework.stereotype.Component;
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CardDao extends ServiceImpl<CardMapper, Card> {
|
||||
|
||||
public void updateStates(List<Card> cards, CardState state) {
|
||||
List<Long> cardIds = cards.stream()
|
||||
.map(BaseEntityExt::getId)
|
||||
.collect(Collectors.toList());
|
||||
lambdaUpdate()
|
||||
.in(Card::getId, cardIds)
|
||||
.set(Card::getState, state)
|
||||
.update();
|
||||
}
|
||||
|
||||
public List<Card> collectPersonCards(String oneOfBizMessageId) {
|
||||
Card card = findCardByBizMessageId(oneOfBizMessageId).orElse(null);
|
||||
if (card == null) return Collections.emptyList();
|
||||
return lambdaQuery()
|
||||
.eq(Card::getAppCode, card.getAppCode())
|
||||
.eq(Card::getTemplateCode, card.getTemplateCode())
|
||||
.eq(Card::getBizCode, card.getBizCode())
|
||||
.eq(Card::getSubBizCode, card.getSubBizCode())
|
||||
.eq(Card::getReceiverOuId, card.getReceiverOuId())
|
||||
.eq(Card::getReceiverWorkspaceId, card.getReceiverWorkspaceId())
|
||||
.eq(Card::getReceiverPersonId, card.getReceiverPersonId())
|
||||
.list();
|
||||
}
|
||||
|
||||
public Optional<Card> findCardByBizMessageId(String bizMessageId) {
|
||||
return Optional.ofNullable(lambdaQuery()
|
||||
.eq(Card::getBizMessageId, bizMessageId)
|
||||
.one());
|
||||
}
|
||||
|
||||
public List<Card> reloadCards(List<Card> cards) {
|
||||
List<Long> cardIds = cards.stream().map(BaseEntityExt::getId).collect(toList());
|
||||
return listByIds(cardIds);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void setSendSuccess(List<Card> cards, MessageTaskResp imResponse) {
|
||||
ArrayList<Card> updates = new ArrayList<>();
|
||||
List<UpdatableMessageSendResult> sendResults = imResponse.getUpdatableMessageSendResults();
|
||||
for (int i = 0; i < cards.size(); i++) {
|
||||
Card card = cards.get(i);
|
||||
Card update = new Card();
|
||||
update.setId(card.getId());
|
||||
update.setImTaskId(imResponse.getId());
|
||||
if (sendResults != null && i < sendResults.size()) {
|
||||
UpdatableMessageSendResult sendResult = sendResults.get(i);
|
||||
update.setBizMessageId(sendResult.getBizMessageId());
|
||||
}
|
||||
updates.add(update);
|
||||
}
|
||||
updateBatchById(updates);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package cn.axzo.msg.center.dal;
|
||||
|
||||
import cn.axzo.msg.center.dal.mapper.CardMessageMapper;
|
||||
import cn.axzo.msg.center.domain.entity.CardMessage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CardMessageDao extends ServiceImpl<CardMessageMapper, CardMessage> {
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
package cn.axzo.msg.center.dal.mapper;
|
||||
|
||||
import cn.axzo.msg.center.domain.entity.CardMessage;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public interface CardMessageMapper extends BaseMapper<CardMessage> {
|
||||
}
|
||||
@ -2,11 +2,12 @@ package cn.axzo.msg.center.domain.entity;
|
||||
|
||||
import cn.axzo.foundation.dao.support.mysql.type.BaseListTypeHandler;
|
||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||
import cn.axzo.im.center.common.enums.YesOrNo;
|
||||
import cn.axzo.msg.center.domain.persistence.BaseEntityExt;
|
||||
import cn.axzo.msg.center.domain.utils.IgnorePropsJsonTypeHandler;
|
||||
import cn.axzo.msg.center.service.enums.CardSendState;
|
||||
import cn.axzo.msg.center.service.enums.CardState;
|
||||
import cn.axzo.msg.center.service.enums.YesOrNo;
|
||||
import cn.axzo.msg.center.service.pending.card.domain.CardButtonState;
|
||||
import cn.axzo.msg.center.service.pending.card.domain.CardButtonStates;
|
||||
import cn.axzo.msg.center.service.pending.request.CardContent;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
@ -32,10 +33,20 @@ public class Card extends BaseEntityExt<Card> implements CardContent {
|
||||
*/
|
||||
private String batchNo;
|
||||
|
||||
/**
|
||||
* 调用方标识
|
||||
*/
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* IM任务id
|
||||
*/
|
||||
private Long imInitTaskId;
|
||||
private Long imTaskId;
|
||||
|
||||
/**
|
||||
* 业务消息ID
|
||||
*/
|
||||
private String bizMessageId;
|
||||
|
||||
/**
|
||||
* 卡片编码
|
||||
@ -57,15 +68,10 @@ public class Card extends BaseEntityExt<Card> implements CardContent {
|
||||
*/
|
||||
private String templateCode;
|
||||
|
||||
/**
|
||||
* 卡片发送状态. INIT_SEND_QUEUED: 准备发送; INIT_SEND_SUCCESS: 首次发送成功; INIT_SEND_FAIL: 首次发送成功; UPDATE_SEND_SUCCESS: 更新发送成功; UPDATE_SEND_FAIL: 更新发送失败;
|
||||
*/
|
||||
private CardSendState sendState;
|
||||
|
||||
/**
|
||||
* 卡片状态. PENDING: 待处理, AGREED: 已同意, REJECTED: 已拒绝, REVOKED: 已撤销, ABORTED: 已中止, COMPLETED: 已处理, END: 已完结, IN_PROGRESS: 进行中
|
||||
*/
|
||||
private CardState cardState;
|
||||
private CardState state;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
@ -103,8 +109,7 @@ public class Card extends BaseEntityExt<Card> implements CardContent {
|
||||
/**
|
||||
* 接收的端
|
||||
*/
|
||||
@TableField(typeHandler = AppTypeHandler.class)
|
||||
private List<AppTypeEnum> receiverAppTypes;
|
||||
private AppTypeEnum receiverAppType;
|
||||
|
||||
/**
|
||||
* 发送人是否为机器人. YES: 是, NO: 否
|
||||
@ -147,11 +152,6 @@ public class Card extends BaseEntityExt<Card> implements CardContent {
|
||||
@TableField(typeHandler = CardButtonStateHandler.class)
|
||||
private List<CardButtonState> buttonStates;
|
||||
|
||||
/**
|
||||
* 状态戳
|
||||
*/
|
||||
private String stateImage;
|
||||
|
||||
/**
|
||||
* 副标题
|
||||
*/
|
||||
@ -170,12 +170,17 @@ public class Card extends BaseEntityExt<Card> implements CardContent {
|
||||
|
||||
@Override
|
||||
public boolean isButtonActionPerformed(String buttonCode) {
|
||||
return buttonStates.stream()
|
||||
.anyMatch(state -> {
|
||||
boolean isTheButton = state.getButtonCode().equals(buttonCode);
|
||||
boolean actionPerformed = state.determineIsActionPerformed();
|
||||
return isTheButton && actionPerformed;
|
||||
});
|
||||
return CardButtonStates.create(buttonStates).isButtonActionPerformed(buttonCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getBizParam() {
|
||||
return bizParam;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getRouterParam() {
|
||||
return routerParam;
|
||||
}
|
||||
|
||||
@Setter
|
||||
@ -184,8 +189,6 @@ public class Card extends BaseEntityExt<Card> implements CardContent {
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
public static class AppTypeHandler
|
||||
extends BaseListTypeHandler<AppTypeEnum> {}
|
||||
public static class CardButtonStateHandler
|
||||
extends BaseListTypeHandler<CardButtonState> {}
|
||||
// @formatter:on
|
||||
|
||||
@ -2,6 +2,7 @@ package cn.axzo.msg.center.domain.entity;
|
||||
|
||||
import cn.axzo.msg.center.domain.persistence.BaseEntityExt;
|
||||
import cn.axzo.msg.center.domain.utils.IgnorePropsJsonTypeHandler;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
@ -22,6 +23,11 @@ public class CardLog extends BaseEntityExt<CardLog> {
|
||||
*/
|
||||
private String identityCode;
|
||||
|
||||
/**
|
||||
* 业务消息ID
|
||||
*/
|
||||
private String bizMessageId;
|
||||
|
||||
/**
|
||||
* 模版编码
|
||||
*/
|
||||
@ -57,7 +63,7 @@ public class CardLog extends BaseEntityExt<CardLog> {
|
||||
* 日志内容
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private Object logContent;
|
||||
private JSONObject logContent;
|
||||
|
||||
/**
|
||||
* 扩展字段
|
||||
@ -65,6 +71,12 @@ public class CardLog extends BaseEntityExt<CardLog> {
|
||||
@TableField(typeHandler = IgnorePropsJsonTypeHandler.class)
|
||||
private Card.RecordExt recordExt;
|
||||
|
||||
public void addLogContent(String name, Object value) {
|
||||
if (logContent == null)
|
||||
logContent = new JSONObject();
|
||||
logContent.put(name, value);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class RecordExt {
|
||||
|
||||
@ -1,78 +0,0 @@
|
||||
package cn.axzo.msg.center.domain.entity;
|
||||
|
||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||
import cn.axzo.msg.center.domain.persistence.BaseEntityExt;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@Accessors(chain = true)
|
||||
@TableName(value = "card_message", autoResultMap = true)
|
||||
public class CardMessage extends BaseEntityExt<CardMessage> {
|
||||
|
||||
/**
|
||||
* 卡片id
|
||||
*/
|
||||
private Long cardId;
|
||||
|
||||
/**
|
||||
* 消息业务id
|
||||
*/
|
||||
private String bizMessageId;
|
||||
|
||||
/**
|
||||
* 业务编码
|
||||
*/
|
||||
private String bizCode;
|
||||
|
||||
/**
|
||||
* 消息卡片id
|
||||
*/
|
||||
private String cardIdentityCode;
|
||||
|
||||
/**
|
||||
* 样式模版code
|
||||
*/
|
||||
private String templateCode;
|
||||
|
||||
/**
|
||||
* 发起者的自然人ID
|
||||
*/
|
||||
private Long senderPersonId;
|
||||
|
||||
/**
|
||||
* 发送者单位id
|
||||
*/
|
||||
private Long senderOuId;
|
||||
|
||||
/**
|
||||
* 发送者项目id
|
||||
*/
|
||||
private Long senderWorkspaceId;
|
||||
|
||||
/**
|
||||
* 接收人自然人id
|
||||
*/
|
||||
private Long receiverPersonId;
|
||||
|
||||
/**
|
||||
* 接收者单位id
|
||||
*/
|
||||
private Long receiveOuId;
|
||||
|
||||
/**
|
||||
* 接收者项目id
|
||||
*/
|
||||
private Long receiveWorkspaceId;
|
||||
|
||||
/**
|
||||
* 终端类型. CM: 工人端, CMP: 管理端
|
||||
*/
|
||||
private AppTypeEnum appType;
|
||||
}
|
||||
@ -148,6 +148,10 @@ public class MessageTemplateV3 extends BaseEntityWithOperator<MessageTemplateV3>
|
||||
@TableField(typeHandler = IgnorePropsJsonTypeHandler.class)
|
||||
private RecordExt recordExt;
|
||||
|
||||
public List<MessageChannel> determineChannels() {
|
||||
return channels == null ? Collections.emptyList() : channels;
|
||||
}
|
||||
|
||||
public PushData parsePushData() {
|
||||
JSONObject pushData = this.pushData;
|
||||
if (pushData == null)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user