diff --git a/inside-notices/pom.xml b/inside-notices/pom.xml
index fc0a36ac..bbf4aa3b 100644
--- a/inside-notices/pom.xml
+++ b/inside-notices/pom.xml
@@ -110,6 +110,10 @@
1.0.0-SNAPSHOT
compile
+
+ cn.axzo.im.center
+ im-center-api
+
\ No newline at end of file
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/config/MessageSystemConfig.java b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/config/MessageSystemConfig.java
index 49f7041c..113845a8 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/config/MessageSystemConfig.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/config/MessageSystemConfig.java
@@ -24,4 +24,6 @@ public class MessageSystemConfig {
*/
@Value("${message.common.record.divide-days:-1}")
private Integer dataDivideDays;
+ @Value("${message.common.icon.orgIcon:https://axzo-pro.oss-cn-hangzhou.aliyuncs.com/rs_app/ic_org_icon.png}")
+ private String orgIcon;
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/MessageModuleService.java b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/MessageModuleService.java
index dd3a1d80..722352dc 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/MessageModuleService.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/MessageModuleService.java
@@ -6,6 +6,7 @@ import cn.axzo.msg.center.domain.dto.SearchModuleDTO;
import cn.axzo.msg.center.domain.dto.SyncModuleDataDTO;
import cn.axzo.msg.center.domain.dto.UpdateModuleDTO;
import cn.axzo.msg.center.domain.entity.MessageModule;
+import cn.axzo.msg.center.domain.enums.ModuleBizTypeEnum;
import cn.axzo.msg.center.domain.enums.UserTypeEnum;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -51,4 +52,12 @@ public interface MessageModuleService {
* @return 对应的模块列表
*/
List listByModuleName(String moduleName);
+
+ /**
+ * 通过bizType查询模块id列表
+ *
+ * @param bizType 业务类型
+ * @return 模块id列表
+ */
+ List listModuleIdByBizType(ModuleBizTypeEnum bizType);
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageModuleServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageModuleServiceImpl.java
index bd25ab5c..8c19edc4 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageModuleServiceImpl.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageModuleServiceImpl.java
@@ -3,7 +3,11 @@ package cn.axzo.msg.center.inside.notices.service.impl;
import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
import cn.axzo.msg.center.api.enums.ReceiveTypeEnum;
import cn.axzo.msg.center.dal.MessageModuleDao;
-import cn.axzo.msg.center.domain.dto.*;
+import cn.axzo.msg.center.domain.dto.CreateModuleDTO;
+import cn.axzo.msg.center.domain.dto.MsgModuleDTO;
+import cn.axzo.msg.center.domain.dto.SearchModuleDTO;
+import cn.axzo.msg.center.domain.dto.SyncModuleDataDTO;
+import cn.axzo.msg.center.domain.dto.UpdateModuleDTO;
import cn.axzo.msg.center.domain.entity.MessageModule;
import cn.axzo.msg.center.domain.enums.ModuleBizTypeEnum;
import cn.axzo.msg.center.domain.enums.UserTypeEnum;
@@ -20,7 +24,12 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -179,4 +188,19 @@ public class MessageModuleServiceImpl implements MessageModuleService {
.filter(e -> Objects.equals(e.getModuleName(), moduleName))
.collect(Collectors.toList());
}
+
+ @Override
+ public List listModuleIdByBizType(ModuleBizTypeEnum bizType) {
+ if (Objects.isNull(bizType)) {
+ log.info("bizType is null.");
+ return Collections.emptyList();
+ }
+ return messageModuleDao.lambdaQuery()
+ .eq(MessageModule::getBizType, bizType.getCode())
+ .eq(MessageModule::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .select(MessageModule::getId)
+ .list().stream()
+ .map(MessageModule::getId)
+ .collect(Collectors.toList());
+ }
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageRecordServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageRecordServiceImpl.java
index 807fd5a6..cbc4ce60 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageRecordServiceImpl.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageRecordServiceImpl.java
@@ -28,6 +28,7 @@ import cn.axzo.msg.center.domain.enums.*;
import cn.axzo.msg.center.domain.request.InsideCmsReadMsgReq;
import cn.axzo.msg.center.inside.notices.event.SendMessageEvent;
import cn.axzo.msg.center.inside.notices.service.MessageRecordService;
+import cn.axzo.msg.center.message.service.GeneralMessageMapperService;
import cn.azxo.framework.common.utils.LogUtil;
import cn.azxo.framework.common.utils.LogUtil.ErrorLevel;
import cn.azxo.framework.common.utils.LogUtil.ErrorType;
@@ -37,6 +38,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.springframework.beans.factory.annotation.Value;
@@ -84,6 +86,9 @@ public class MessageRecordServiceImpl implements MessageRecordService {
/*@Resource
private IdentityProfileService identityProfileService;*/
+ @Resource
+ private GeneralMessageMapperService generalMessageMapperService;
+
/**
* 新增推送消息接口
*
@@ -132,10 +137,11 @@ public class MessageRecordServiceImpl implements MessageRecordService {
List pushMessages = new ArrayList<>();
Lists.partition(Lists.newArrayList(message.getToId()), partitionSize).forEach(toIds -> {
- List messageRecords = saveBatch(basic, toIds, message.getToldIdPersonIdMap());
+ Map toIdRecordMap = Maps.newHashMap();
+ List messageRecords = saveBatch(basic, toIds, message.getToldIdPersonIdMap(), toIdRecordMap);
+ generalMessageMapperService.asyncBatchSendMessage(message, toIdRecordMap);
pushMessages.addAll(messageRecords);
});
-
if(pushAthena) {
asyncPushAthena(message, messageTemplate.getAudioFileName(), messageModule.getModuleName(), pushMessages);
}
@@ -158,7 +164,8 @@ public class MessageRecordServiceImpl implements MessageRecordService {
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
- public List saveBatch(MessageRecord basic, List toIds, Map toldIdPersonIdMap) {
+ public List saveBatch(MessageRecord basic, List toIds, Map toldIdPersonIdMap,
+ Map toIdRecordMap) {
if (CollectionUtils.isEmpty(toIds)) {
return Collections.emptyList();
}
@@ -172,6 +179,7 @@ public class MessageRecordServiceImpl implements MessageRecordService {
messageRecord.setToId(0L);
messageRecord.setPersonId(i);
pushMessages.add(messageRecord);
+ toIdRecordMap.put(i, messageRecord);
});
} else {
toIds.forEach(i -> {
@@ -183,6 +191,7 @@ public class MessageRecordServiceImpl implements MessageRecordService {
messageRecord.setPersonId(toldIdPersonIdMap.get(i));
}
pushMessages.add(messageRecord);
+ toIdRecordMap.put(i, messageRecord);
});
}
messageRecordDao.saveBatch(pushMessages);
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageRelationServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageRelationServiceImpl.java
index 9325d114..11180058 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageRelationServiceImpl.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/MessageRelationServiceImpl.java
@@ -24,7 +24,13 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -188,7 +194,8 @@ public class MessageRelationServiceImpl implements MessageRelationService {
}
return messageRelationDao.lambdaQuery()
.in(MessageRelation::getModuleId, moduleIds)
- .eq(MessageRelation::getIsDelete, 0)
+ .eq(MessageRelation::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .select(MessageRelation::getId)
.list().stream()
.map(MessageRelation::getId)
.collect(Collectors.toList());
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/RawMessageRecordServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/RawMessageRecordServiceImpl.java
index f6ece7fc..6e78ba58 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/RawMessageRecordServiceImpl.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/inside/notices/service/impl/RawMessageRecordServiceImpl.java
@@ -45,7 +45,6 @@ import java.util.function.Function;
import java.util.stream.Collectors;
/**
- * @description xxx
* @author cold_blade
* @date 2023/9/13
* @version 1.0
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/GeneralMessageController.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/GeneralMessageController.java
new file mode 100644
index 00000000..a921596a
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/GeneralMessageController.java
@@ -0,0 +1,53 @@
+package cn.axzo.msg.center.message.controller;
+
+import cn.axzo.msg.center.api.request.CmsMsgQueryReq;
+import cn.axzo.msg.center.api.response.MessageNewRes;
+import cn.axzo.msg.center.message.service.GeneralMessageOldService;
+import cn.axzo.msg.center.message.service.GeneralMessageService;
+import cn.axzo.msg.center.service.dto.PersonDTO;
+import cn.axzo.msg.center.service.general.client.GeneralMessageClient;
+import cn.axzo.msg.center.service.general.request.GeneralMessageOldDataStatisticRequest;
+import cn.axzo.msg.center.service.general.request.GeneralMessageSendRequest;
+import cn.axzo.msg.center.service.general.response.GeneralMessageOldDataStatisticResponse;
+import cn.azxo.framework.common.model.CommonResponse;
+import cn.azxo.framework.common.model.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/19
+ * @version 1.0
+ */
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+public class GeneralMessageController implements GeneralMessageClient {
+
+ private final GeneralMessageService generalMessageService;
+ private final GeneralMessageOldService generalMessageOldService;
+
+ @Override
+ public CommonResponse batchSend(GeneralMessageSendRequest request) {
+ generalMessageService.batchSendMessage(request);
+ return CommonResponse.success();
+ }
+
+ @Override
+ public CommonResponse statisticOldData(
+ GeneralMessageOldDataStatisticRequest request) {
+ return CommonResponse.success(generalMessageService.statisticOldData(request));
+ }
+
+ @Override
+ public CommonResponse countUnreadFromOldMessage(GeneralMessageOldDataStatisticRequest request) {
+ PersonDTO person = PersonDTO.from(request.getPersonId(), request.getIdentityId(), request.getIdentityType());
+ return CommonResponse.success(generalMessageOldService.countUnread(person));
+ }
+
+ @Override
+ public CommonResponse> pageQueryOldMessage(CmsMsgQueryReq request) {
+ return CommonResponse.success(generalMessageOldService.pageMsgInfo(request));
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageGroupController.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageGroupController.java
new file mode 100644
index 00000000..631c0490
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageGroupController.java
@@ -0,0 +1,56 @@
+package cn.axzo.msg.center.message.controller;
+
+import cn.axzo.msg.center.message.domain.param.MessageGroupNodeSaveOrUpdateParam;
+import cn.axzo.msg.center.message.service.MessageGroupNodeService;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
+import cn.axzo.msg.center.service.group.client.MessageGroupClient;
+import cn.axzo.msg.center.service.group.request.MessageGroupNodeAddRequest;
+import cn.axzo.msg.center.service.group.request.MessageGroupNodeUpdateRequest;
+import cn.axzo.msg.center.service.group.response.MessageGroupTreeNodeResponse;
+import cn.azxo.framework.common.model.CommonResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 消息分类管理
+ *
+ * @author cold_blade
+ * @date 2023/10/17
+ * @version 1.0
+ */
+@RestController
+@RequiredArgsConstructor
+public class MessageGroupController implements MessageGroupClient {
+
+ private final MessageGroupNodeService messageGroupNodeService;
+
+ @Override
+ public CommonResponse addNode(MessageGroupNodeAddRequest request) {
+ messageGroupNodeService.addGroupNode(MessageGroupNodeSaveOrUpdateParam.from(request));
+ return CommonResponse.success();
+ }
+
+ @Override
+ public CommonResponse updateNode(MessageGroupNodeUpdateRequest request) {
+ messageGroupNodeService.updateGroupNode(MessageGroupNodeSaveOrUpdateParam.from(request));
+ return CommonResponse.success();
+ }
+
+ @Override
+ public CommonResponse deleteNode(String nodeCode, Long operatorId) {
+ messageGroupNodeService.deleteGroupNode(operatorId, nodeCode);
+ return CommonResponse.success();
+ }
+
+ @Override
+ public CommonResponse> list(MessageCategoryEnum category) {
+ List groupTreeNodes = messageGroupNodeService.listGroupTree(category).stream()
+ .map(GroupTreeNodeDTO::toMessageGroupTreeNodeResponse)
+ .collect(Collectors.toList());
+ return CommonResponse.success(groupTreeNodes);
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java
index d8e9d4d0..c24681cd 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateController.java
@@ -1,14 +1,30 @@
package cn.axzo.msg.center.message.controller;
-import cn.axzo.msg.center.message.domain.param.MessageTemplateCreateParam;
+import cn.axzo.core.utils.converter.BeanConverter;
+import cn.axzo.msg.center.message.domain.param.MessageTemplateSaveOrUpdateParam;
+import cn.axzo.msg.center.message.domain.param.RelationTemplateMapInitParam;
+import cn.axzo.msg.center.message.domain.vo.RelationTemplateMapInitRequest;
import cn.axzo.msg.center.message.service.MessageTemplateNewService;
+import cn.axzo.msg.center.message.service.RelationTemplateMapService;
import cn.axzo.msg.center.service.template.client.MessageTemplateClient;
import cn.axzo.msg.center.service.template.request.MessageTemplateCreateRequest;
-import cn.axzo.msg.center.service.template.request.MessageTemplateMoveToRequest;
+import cn.axzo.msg.center.service.template.request.MessageTemplatePageRequest;
+import cn.axzo.msg.center.service.template.request.MessageTemplateUpdateRequest;
+import cn.axzo.msg.center.service.template.request.MessageTemplateUpdateStatusRequest;
+import cn.axzo.msg.center.service.template.response.MessageTemplateDetailResponse;
+import cn.axzo.msg.center.service.template.response.MessageTemplatePageResponse;
import cn.azxo.framework.common.model.CommonResponse;
+import cn.azxo.framework.common.model.Page;
import lombok.RequiredArgsConstructor;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
+import javax.validation.Valid;
+import java.util.Collection;
+import java.util.List;
+
/**
* 消息模板管理
*
@@ -21,17 +37,45 @@ import org.springframework.web.bind.annotation.RestController;
public class MessageTemplateController implements MessageTemplateClient {
private final MessageTemplateNewService messageTemplateNewService;
+ private final RelationTemplateMapService relationTemplateMapService;
@Override
- public CommonResponse addTemplate(MessageTemplateCreateRequest request) {
- MessageTemplateCreateParam param = MessageTemplateCreateParam.from(request);
- messageTemplateNewService.createTemplate(param);
- return CommonResponse.success(param.getTemplateCode());
+ public CommonResponse save(MessageTemplateCreateRequest request) {
+ return CommonResponse.success(
+ messageTemplateNewService.createTemplate(MessageTemplateSaveOrUpdateParam.from(request)));
}
@Override
- public CommonResponse batchMove(MessageTemplateMoveToRequest request) {
- // TODO: [cold_blade] [P2] 模板关联的批量移动
- return null;
+ public CommonResponse update(MessageTemplateUpdateRequest request) {
+ messageTemplateNewService.updateTemplate(MessageTemplateSaveOrUpdateParam.from(request));
+ return CommonResponse.success();
+ }
+
+ @Override
+ public CommonResponse detail(String templateCode) {
+ return CommonResponse.success(messageTemplateNewService.detail(templateCode));
+ }
+
+ @Override
+ public CommonResponse> page(MessageTemplatePageRequest request) {
+ return CommonResponse.success(messageTemplateNewService.page(request));
+ }
+
+ @Override
+ public CommonResponse> listByCodes(Collection templateCodes) {
+ return CommonResponse.success(messageTemplateNewService.listByCodes(templateCodes));
+ }
+
+ @Override
+ public CommonResponse updateStatus(MessageTemplateUpdateStatusRequest request) {
+ messageTemplateNewService.updateStatus(request.getOperatorId(), request.getTemplateCode(), request.getStatus());
+ return CommonResponse.success();
+ }
+
+ @PostMapping(value = "/message/template/relation/init", produces = {MediaType.APPLICATION_JSON_VALUE})
+ public CommonResponse initRelationTemplateMap(@RequestBody @Valid RelationTemplateMapInitRequest request) {
+ RelationTemplateMapInitParam param = BeanConverter.convert(request, RelationTemplateMapInitParam.class);
+ relationTemplateMapService.init(param);
+ return CommonResponse.success();
}
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateGroupRelationController.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateGroupRelationController.java
new file mode 100644
index 00000000..a72a10cd
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/MessageTemplateGroupRelationController.java
@@ -0,0 +1,62 @@
+package cn.axzo.msg.center.message.controller;
+
+import cn.axzo.msg.center.common.utils.PageHelperUtil;
+import cn.axzo.msg.center.message.service.MessageTemplateGroupService;
+import cn.axzo.msg.center.message.service.MessageTemplateNewService;
+import cn.axzo.msg.center.service.dto.MessageBaseTemplateDTO;
+import cn.axzo.msg.center.service.group.client.MessageTemplateGroupRelationClient;
+import cn.axzo.msg.center.service.group.request.MessageTemplateGroupRelationMoveRequest;
+import cn.axzo.msg.center.service.group.request.MessageTemplateGroupRelationPageRequest;
+import cn.axzo.msg.center.service.group.request.MessageTemplateGroupRelationRemoveRequest;
+import cn.axzo.msg.center.service.group.response.MessageTemplateGroupRelationResponse;
+import cn.axzo.msg.center.service.template.request.MessageTemplatePageRequest;
+import cn.azxo.framework.common.model.CommonResponse;
+import cn.azxo.framework.common.model.Page;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/17
+ * @version 1.0
+ */
+@RestController
+@RequiredArgsConstructor
+public class MessageTemplateGroupRelationController implements MessageTemplateGroupRelationClient {
+
+ private final MessageTemplateNewService messageTemplateNewService;
+ private final MessageTemplateGroupService messageTemplateGroupService;
+
+ @Override
+ public CommonResponse> page(MessageTemplateGroupRelationPageRequest request) {
+ MessageTemplatePageRequest pageRequest = new MessageTemplatePageRequest();
+ pageRequest.setPage(request.getPage());
+ pageRequest.setPageSize(request.getPageSize());
+ pageRequest.setTemplateName(request.getTemplateName());
+ pageRequest.setGroupNodeCode(request.getNodeCode());
+ Page result = messageTemplateNewService.pageBaseTemplate(pageRequest);
+ return CommonResponse.success(PageHelperUtil.convert(result, this::convert));
+ }
+
+ @Override
+ public CommonResponse move(MessageTemplateGroupRelationMoveRequest request) {
+ messageTemplateGroupService.move(request.getCurNodeCode(), request.getTargetNodeCode(),
+ request.getTemplateCodes());
+ return CommonResponse.success();
+ }
+
+ @Override
+ public CommonResponse remove(MessageTemplateGroupRelationRemoveRequest request) {
+ messageTemplateGroupService.remove(request.getCurNodeCode(), request.getTemplateCodes());
+ return CommonResponse.success();
+ }
+
+ private MessageTemplateGroupRelationResponse convert(MessageBaseTemplateDTO dto) {
+ MessageTemplateGroupRelationResponse response = new MessageTemplateGroupRelationResponse();
+ response.setTitle(dto.getTitle());
+ response.setTemplateCode(dto.getCode());
+ response.setTemplateName(dto.getName());
+ response.setCreateTimestamp(dto.getCreateTimestamp());
+ return response;
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PendingMessageNewController.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PendingMessageNewController.java
index 90d07020..f825ad98 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PendingMessageNewController.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/controller/PendingMessageNewController.java
@@ -1,6 +1,6 @@
package cn.axzo.msg.center.message.controller;
-import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeDTO;
+import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeStatisticDTO;
import cn.axzo.msg.center.message.domain.dto.PendingMessageDTO;
import cn.axzo.msg.center.message.domain.param.MessageGroupNodeStatisticParam;
import cn.axzo.msg.center.message.domain.param.PendingMessagePushParam;
@@ -36,10 +36,10 @@ public class PendingMessageNewController implements PendingMessageClient {
@Override
public CommonResponse> groupStatistic(MessageGroupNodeStatisticRequest request) {
- List groupNodes = pendingMessageNewService
+ List groupNodes = pendingMessageNewService
.groupStatistic(MessageGroupNodeStatisticParam.from(request));
return CommonResponse.success(groupNodes.stream()
- .map(MessageGroupNodeDTO::toResponse)
+ .map(MessageGroupNodeStatisticDTO::toResponse)
.collect(Collectors.toList())
);
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/GroupTreeNodePathDTO.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/GroupTreeNodePathDTO.java
new file mode 100644
index 00000000..3f0318a6
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/GroupTreeNodePathDTO.java
@@ -0,0 +1,68 @@
+package cn.axzo.msg.center.message.domain.dto;
+
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+import com.alibaba.fastjson.JSON;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+@Setter
+@Getter
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+public class GroupTreeNodePathDTO implements Serializable {
+
+ private static final long serialVersionUID = -6325338437781927201L;
+
+ private static final String NODE_NAME_PATH_SPLITER = "/";
+ private static final String NODE_CODE_PATH_SPLITER = ":";
+
+ /**
+ * 结点编码
+ */
+ private String nodeCode;
+ /**
+ * 结点名称格式的路径
+ */
+ private String nodeNamePath;
+ /**
+ * 结点编码格式的路径
+ */
+ private String nodeCodePath;
+
+ public static String parseLeafNodeCode(String nodeCodePath) {
+ if (StringUtils.isBlank(nodeCodePath)) {
+ return null;
+ }
+ String[] nodeCodes = nodeCodePath.split(NODE_CODE_PATH_SPLITER);
+ // 最后一个为叶节点的结点编码
+ return nodeCodes[nodeCodes.length - 1];
+ }
+
+ public static GroupTreeNodePathDTO of(String nodeCode, Collection nodes) {
+ String nodeNamePath = formatPath(GroupTreeNodeDTO::getNodeName, nodes, NODE_NAME_PATH_SPLITER);
+ String nodeCodePath = formatPath(GroupTreeNodeDTO::getNodeCode, nodes, NODE_CODE_PATH_SPLITER);
+ return new GroupTreeNodePathDTO(nodeCode, nodeNamePath, nodeCodePath);
+ }
+
+ private static String formatPath(Function pathFunc, Collection nodes,
+ String spliter) {
+ return nodes.stream().map(pathFunc).collect(Collectors.joining(spliter));
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeDTO.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeDTO.java
deleted file mode 100644
index 37bd6303..00000000
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeDTO.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package cn.axzo.msg.center.message.domain.dto;
-
-import cn.axzo.core.utils.converter.BeanConverter;
-import cn.axzo.msg.center.domain.entity.MessageGroupNode;
-import cn.axzo.msg.center.service.enums.MessageGroupNodeCategoryEnum;
-import cn.axzo.msg.center.service.pending.response.MessageGroupNodeResponse;
-import com.alibaba.fastjson.JSON;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-
-import java.io.Serializable;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @description
- * 消息分类结点DTO
- *
- * @author cold_blade
- * @date 2023/9/26
- * @version 1.0
- */
-@Setter
-@Getter
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class MessageGroupNodeDTO implements Serializable {
-
- private static final long serialVersionUID = 5171436359992401120L;
-
- /**
- * 结点类型
- * GENERAL_MESSAGE_CENTER: 消息中心
- * GENERAL_MESSAGE_MODULE: 消息模块
- * GENERAL_MESSAGE_CATEGORY: 消息分类
- * PENDING_MESSAGE_CENTER: 待办中心
- * PENDING_MESSAGE_MODULE: 待办模块
- * PENDING_MESSAGE_CATEGORY: 待办分类
- */
- private MessageGroupNodeCategoryEnum category;
- /**
- * 结点名称
- */
- private String nodeName;
- /**
- * 结点编码
- */
- private String nodeCode;
- /**
- * 父节点编码
- */
- private String parentNodeCode;
- /**
- * 结点对应的代办数量
- */
- private Integer pendingCount;
- /**
- * 子节点列表
- */
- private List children;
-
- public static MessageGroupNodeDTO from(MessageGroupNode groupNode) {
- return MessageGroupNodeDTO.builder()
- .category(groupNode.getCategory())
- .nodeName(groupNode.getName())
- .nodeCode(groupNode.getCode())
- .parentNodeCode(groupNode.getParentCode())
- .build();
- }
-
- public MessageGroupNodeResponse toResponse() {
- MessageGroupNodeResponse response = BeanConverter.convert(this, MessageGroupNodeResponse.class);
- List children = this.children.stream()
- .map(MessageGroupNodeDTO::toResponse).collect(Collectors.toList());
- response.setNodeChildren(children);
- return response;
- }
-
- @Override
- public String toString() {
- return JSON.toJSONString(this);
- }
-}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeStatisticDTO.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeStatisticDTO.java
new file mode 100644
index 00000000..9368d462
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageGroupNodeStatisticDTO.java
@@ -0,0 +1,81 @@
+package cn.axzo.msg.center.message.domain.dto;
+
+import cn.axzo.basics.common.model.IBaseTree;
+import cn.axzo.core.utils.converter.BeanConverter;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+import cn.axzo.msg.center.service.pending.response.MessageGroupNodeResponse;
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @description
+ * 消息分类结点DTO
+ *
+ * @author cold_blade
+ * @date 2023/9/26
+ * @version 1.0
+ */
+@Setter
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MessageGroupNodeStatisticDTO implements IBaseTree, Serializable {
+
+ private static final long serialVersionUID = 5171436359992401120L;
+
+ /**
+ * 树结点
+ */
+ private GroupTreeNodeDTO treeNode;
+ /**
+ * 子节点列表
+ */
+ private List nodeChildren;
+ /**
+ * 结点对应的代办数量
+ */
+ private Integer pendingCount;
+
+ public static MessageGroupNodeStatisticDTO of(GroupTreeNodeDTO groupNode) {
+ return MessageGroupNodeStatisticDTO.builder()
+ .treeNode(groupNode)
+ .build();
+ }
+
+ public MessageGroupNodeResponse toResponse() {
+ MessageGroupNodeResponse response = new MessageGroupNodeResponse();
+ response.setCategory(treeNode.getCategory());
+ response.setNodeCode(treeNode.getNodeCode());
+ response.setNodeName(treeNode.getNodeName());
+ response.setParentNodeCode(treeNode.getParentNodeCode());
+ response.setPendingCount(this.pendingCount);
+ List children = this.nodeChildren.stream()
+ .map(MessageGroupNodeStatisticDTO::toResponse).collect(Collectors.toList());
+ response.setNodeChildren(children);
+ return response;
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+
+ @Override
+ public String getNodeCode() {
+ return treeNode.getNodeCode();
+ }
+
+ @Override
+ public String getParentNodeCode() {
+ return treeNode.getParentNodeCode();
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageTemplateDTO.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageTemplateDTO.java
index 88fafc90..37e39d7e 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageTemplateDTO.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/MessageTemplateDTO.java
@@ -1,16 +1,23 @@
package cn.axzo.msg.center.message.domain.dto;
import cn.axzo.msg.center.domain.entity.MessageBaseTemplate;
+import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
+import cn.axzo.msg.center.service.enums.PushTerminalEnum;
+import cn.axzo.msg.center.utils.JSONObjectUtil;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
+import org.apache.commons.collections.CollectionUtils;
import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* @description
@@ -45,9 +52,9 @@ public class MessageTemplateDTO implements Serializable {
*/
private String content;
/**
- * 卡片信息,json字串
+ * 消息卡片信息标签列表
*/
- private String cardContent;
+ private List msgCardContentItems;
/**
* 所属消息类型
*/
@@ -60,6 +67,14 @@ public class MessageTemplateDTO implements Serializable {
* 模板路由信息
*/
private List routers;
+ /**
+ * 推送终端
+ */
+ private List pushTerminals;
+ /**
+ * APP最小版本支持,可不配
+ */
+ private String minAppVersion;
public static MessageTemplateDTO from(MessageBaseTemplate baseTemplate, List routers) {
return MessageTemplateDTO.builder()
@@ -67,13 +82,24 @@ public class MessageTemplateDTO implements Serializable {
.code(baseTemplate.getCode())
.title(baseTemplate.getTitle())
.content(baseTemplate.getContent())
- .cardContent(baseTemplate.getCardContent())
+ .msgCardContentItems(JSONObjectUtil.parseArray(baseTemplate.getCardContent(), MessageCardContentItemDTO.class))
.msgCategory(baseTemplate.getMsgCategory())
.icon(baseTemplate.getIcon())
.routers(routers)
+ .pushTerminals(JSON.parseArray(baseTemplate.getPushTerminal(), PushTerminalEnum.class))
+ .minAppVersion(baseTemplate.getMinAppVersion())
.build();
}
+ public Map toCardContentMap() {
+ if (CollectionUtils.isEmpty(msgCardContentItems)) {
+ return Collections.emptyMap();
+ }
+ Map map = new HashMap<>();
+ msgCardContentItems.forEach(e -> map.put(e.getLabel(), e.getValue()));
+ return map;
+ }
+
@Override
public String toString() {
return JSON.toJSONString(this);
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/PendingMessageDTO.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/PendingMessageDTO.java
index d073790c..cc0e4727 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/PendingMessageDTO.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/PendingMessageDTO.java
@@ -143,6 +143,7 @@ public class PendingMessageDTO implements Serializable {
.updateTimestamp(DateFormatUtil.toTimestamp(this.updateTime))
.routers(this.routers)
.routerParams(this.routerParams)
+ .bizExtParams("{}")
.build();
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/RawMessageRouterDTO.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/RawMessageRouterDTO.java
index 1c8ea27a..d478c6be 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/RawMessageRouterDTO.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/RawMessageRouterDTO.java
@@ -1,10 +1,15 @@
package cn.axzo.msg.center.message.domain.dto;
import cn.axzo.msg.center.domain.entity.MessageTemplateRouter;
+import cn.axzo.msg.center.service.dto.MessageRouterButtonDTO;
import cn.axzo.msg.center.service.dto.MessageRouterDTO;
+import cn.axzo.msg.center.service.dto.MessageRouterTerminalDTO;
+import cn.axzo.msg.center.service.enums.ButtonStyleEnum;
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
+import cn.axzo.msg.center.utils.MessageRouterUtil;
import com.alibaba.fastjson.JSON;
+import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
@@ -12,6 +17,8 @@ import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
/**
* @description
@@ -40,54 +47,96 @@ public class RawMessageRouterDTO implements Serializable {
*/
private RouterCategoryEnum category;
/**
- * 页面地址 OR API接口地址
+ * 路由终端
*/
- private String url;
- /**
- * 页面地址所属应用端(如果是API接口地址,请忽略改字段值)
- * WEB: web端页面
- * MINI_PROGRAM: 安心筑小程序端页面
- * IOS: 原生IOS端页面
- * ANDROID: 原生Android端页面
- * WEB_VIEW: H5页面
- * WECHAT_MINI_PROGRAM: 微信小程序页面
- */
- private TerminalTypeEnum terminalType;
+ private List terminals;
/**
* 模板编码
*/
private String templateCode;
+ /**
+ * 按钮样式配置
+ */
+ private List style;
- public static RawMessageRouterDTO from(MessageTemplateRouter msgTemplateRouter) {
+ public static RawMessageRouterDTO from(List msgTemplateRouters) {
+ MessageTemplateRouter router = msgTemplateRouters.get(0);
+ List terminals = msgTemplateRouters.stream()
+ .map(RawMessageRouterDTO::convert2Terminal)
+ .collect(Collectors.toList());
return RawMessageRouterDTO.builder()
- .desc(msgTemplateRouter.getName())
- .url(msgTemplateRouter.getUrl())
- .category(msgTemplateRouter.getCategory())
- .terminalType(msgTemplateRouter.getTerminalType())
- .templateCode(msgTemplateRouter.getTemplateCode())
+ .desc(router.getName())
+ .category(router.getCategory())
+ .templateCode(router.getTemplateCode())
+ .style(MessageRouterUtil.parseButtonStyle(router.getStyle()))
+ .terminals(terminals)
.build();
}
- public static RawMessageRouterDTO from(MessageRouterDTO router, String templateCode) {
+ public static RawMessageRouterDTO from(MessageRouterButtonDTO router, String templateCode) {
return RawMessageRouterDTO.builder()
.desc(router.getDesc())
- .url(router.getUrl())
.category(router.getCategory())
- .terminalType(router.getTerminalType())
+ .terminals(router.getTerminals())
+ .style(router.getStyle())
.templateCode(templateCode)
.build();
}
- public MessageTemplateRouter toMessageTemplateRouter() {
+ public MessageRouterButtonDTO toMessageRouterButton() {
+ return MessageRouterButtonDTO.builder()
+ .desc(this.desc)
+ .category(this.category)
+ .terminals(this.terminals)
+ .style(this.style)
+ .build();
+ }
+
+ public List toMessageTemplateRouters() {
+ return this.terminals.stream()
+ .map(this::convert)
+ .collect(Collectors.toList());
+ }
+
+ public MessageRouterDTO toMessageRouter(TerminalTypeEnum terminalType) {
+ MessageRouterTerminalDTO terminal = MessageRouterUtil.select(this, terminalType);
+ return MessageRouterDTO.builder()
+ .desc(this.desc)
+ .category(this.category)
+ .style(this.style)
+ .terminalType(terminal.getTerminalType())
+ .url(terminal.getUrl())
+ .build();
+ }
+
+ private MessageTemplateRouter convert(MessageRouterTerminalDTO terminal) {
MessageTemplateRouter router = new MessageTemplateRouter();
- router.setName(this.desc);
- router.setUrl(this.url);
- router.setCategory(this.category);
- router.setTerminalType(this.terminalType);
- router.setTemplateCode(this.templateCode);
+ router.setName(desc);
+ router.setCategory(category);
+ router.setTemplateCode(templateCode);
+ router.setStyle(JSON.toJSONString(style));
+ router.setUrl(terminal.getUrl());
+ router.setTerminalType(terminal.getTerminalType());
return router;
}
+ private static MessageRouterTerminalDTO convert2Terminal(MessageTemplateRouter router) {
+ return MessageRouterTerminalDTO.builder()
+ .url(router.getUrl())
+ .terminalType(router.getTerminalType())
+ .build();
+ }
+
+ public RawMessageRouterDTO deepClone() {
+ return RawMessageRouterDTO.builder()
+ .desc(this.desc)
+ .category(this.category)
+ .terminals(this.terminals.stream().map(MessageRouterTerminalDTO::deepClone).collect(Collectors.toList()))
+ .templateCode(this.templateCode)
+ .style(Lists.newArrayList(this.getStyle()))
+ .build();
+ }
+
@Override
public String toString() {
return JSON.toJSONString(this);
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/SendImMessageDTO.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/SendImMessageDTO.java
new file mode 100644
index 00000000..650088e9
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/dto/SendImMessageDTO.java
@@ -0,0 +1,47 @@
+package cn.axzo.msg.center.message.domain.dto;
+
+import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/25
+ * @version 1.0
+ */
+@Setter
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SendImMessageDTO implements Serializable {
+
+ private static final long serialVersionUID = 3385679937092148803L;
+
+ /**
+ * 自然人id
+ */
+ private Long personId;
+ /**
+ * im消息id
+ */
+ private String imMsgId;
+
+ public static SendImMessageDTO from(MessageDispatchResp resp) {
+ return SendImMessageDTO.builder()
+ .imMsgId(resp.getMsgid())
+ .personId(Long.parseLong(resp.getPersonId()))
+ .build();
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageGroupNodeSaveOrUpdateParam.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageGroupNodeSaveOrUpdateParam.java
new file mode 100644
index 00000000..161a68aa
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageGroupNodeSaveOrUpdateParam.java
@@ -0,0 +1,69 @@
+package cn.axzo.msg.center.message.domain.param;
+
+import cn.axzo.core.utils.converter.BeanConverter;
+import cn.axzo.msg.center.service.enums.MessageGroupNodeCategoryEnum;
+import cn.axzo.msg.center.service.group.request.MessageGroupNodeAddRequest;
+import cn.axzo.msg.center.service.group.request.MessageGroupNodeUpdateRequest;
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/17
+ * @version 1.0
+ */
+@Setter
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MessageGroupNodeSaveOrUpdateParam {
+
+ /**
+ * 操作者的自然人id
+ */
+ private Long operatorId;
+ /**
+ * 父节点编码
+ */
+ private String parentNodeCode;
+ /**
+ * 待添加结点名称
+ */
+ private String nodeName;
+ /**
+ * 待修改的结点编码
+ */
+ private String nodeCode;
+ /**
+ * 待添加结点类型
+ * GENERAL_MESSAGE_CENTER: 通知的业务中心
+ * GENERAL_MESSAGE_MODULE: 消息模块
+ * GENERAL_MESSAGE_CATEGORY: 消息分类
+ * PENDING_MESSAGE_CENTER: 待办的业务中心
+ * PENDING_MESSAGE_MODULE: 待办模块
+ * PENDING_MESSAGE_CATEGORY: 待办分类
+ */
+ private MessageGroupNodeCategoryEnum category;
+ /**
+ * 待添加结点图标
+ */
+ private String icon;
+
+ public static MessageGroupNodeSaveOrUpdateParam from(MessageGroupNodeAddRequest request) {
+ return BeanConverter.convert(request, MessageGroupNodeSaveOrUpdateParam.class);
+ }
+
+ public static MessageGroupNodeSaveOrUpdateParam from(MessageGroupNodeUpdateRequest request) {
+ return BeanConverter.convert(request, MessageGroupNodeSaveOrUpdateParam.class);
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageTemplateCreateParam.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageTemplateCreateParam.java
deleted file mode 100644
index f99c1cbe..00000000
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageTemplateCreateParam.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package cn.axzo.msg.center.message.domain.param;
-
-import cn.axzo.msg.center.service.dto.MessageRouterDTO;
-import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
-import cn.axzo.msg.center.service.template.request.MessageTemplateCreateRequest;
-import cn.axzo.msg.center.utils.UUIDUtil;
-import com.alibaba.fastjson.JSON;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * @description
- *
- * @author cold_blade
- * @date 2023/10/5
- * @version 1.0
- */
-@Setter
-@Getter
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class MessageTemplateCreateParam implements Serializable {
-
- private static final long serialVersionUID = 6657624182580261353L;
-
- /**
- * 模板名称
- */
- private String templateName;
- /**
- * 系统自动生成的模板code
- */
- private String templateCode;
- /**
- * 所属消息类型
- * GENERAL_MESSAGE: 普通消息
- * PENDING_MESSAGE: 待办消息
- */
- private MessageCategoryEnum msgCategory;
- /**
- * 模板标题
- */
- private String title;
- /**
- * 模板类容
- */
- private String content;
- /**
- * 卡片信息,json字串
- */
- private String cardContent;
- /**
- * 模板icon
- */
- private String icon;
- /**
- * 操作者自然人id
- */
- private Long operatorId;
- /**
- * 路由列表
- */
- private List routers;
-
- public static MessageTemplateCreateParam from(MessageTemplateCreateRequest request) {
- return MessageTemplateCreateParam.builder()
- .templateName(request.getTemplateName())
- .templateCode(UUIDUtil.uuidString())
- .msgCategory(request.getCategory())
- .title(request.getMsgTitle())
- .content(request.getMsgContent())
- .cardContent(request.getMsgCardInfo())
- .icon(request.getMsgIcon())
- .operatorId(request.getOperatorId())
- .routers(request.getRouters())
- .build();
- }
-
- @Override
- public String toString() {
- return JSON.toJSONString(this);
- }
-}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageTemplateSaveOrUpdateParam.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageTemplateSaveOrUpdateParam.java
new file mode 100644
index 00000000..baa17a8e
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/MessageTemplateSaveOrUpdateParam.java
@@ -0,0 +1,118 @@
+package cn.axzo.msg.center.message.domain.param;
+
+import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
+import cn.axzo.msg.center.service.dto.MessageRouterButtonDTO;
+import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
+import cn.axzo.msg.center.service.enums.PushTerminalEnum;
+import cn.axzo.msg.center.service.template.request.MessageTemplateCreateRequest;
+import cn.axzo.msg.center.service.template.request.MessageTemplateUpdateRequest;
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @description
+ *
+ * @author cold_blade
+ * @date 2023/10/5
+ * @version 1.0
+ */
+@Setter
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MessageTemplateSaveOrUpdateParam implements Serializable {
+
+ private static final long serialVersionUID = 6657624182580261353L;
+
+ /**
+ * 模板名称
+ */
+ private String templateName;
+ /**
+ * 模板编码
+ */
+ private String templateCode;
+ /**
+ * 消息分类树的叶结点的结点编码列表
+ */
+ private List leafGroupNodes;
+ /**
+ * 所属消息类型
+ * GENERAL_MESSAGE: 普通消息
+ * PENDING_MESSAGE: 待办消息
+ */
+ private MessageCategoryEnum msgCategory;
+ /**
+ * 模板标题
+ */
+ private String title;
+ /**
+ * 模板类容
+ */
+ private String content;
+ /**
+ * 消息卡片信息标签列表
+ */
+ private List msgCardContentItems;
+ /**
+ * 模板icon
+ */
+ private String icon;
+ /**
+ * 操作者自然人id
+ */
+ private Long operatorId;
+ /**
+ * 路由列表
+ */
+ private List routers;
+ /**
+ * 推送终端配置
+ * B_ENTERPRISE_APP: B-安心筑企业版
+ * C_WORKER_APP: C-安心筑工人版
+ */
+ private List pushTerminals;
+
+ public static MessageTemplateSaveOrUpdateParam from(MessageTemplateCreateRequest request) {
+ return MessageTemplateSaveOrUpdateParam.builder()
+ .templateName(request.getTemplateName())
+ .msgCategory(request.getCategory())
+ .leafGroupNodes(request.getLeafGroupNodes())
+ .title(request.getMsgTitle())
+ .content(request.getMsgContent())
+ .msgCardContentItems(request.getMsgCardContentItems())
+ .icon(request.getMsgIcon())
+ .operatorId(request.getOperatorId())
+ .routers(request.getRouters())
+ .pushTerminals(request.getPushTerminals())
+ .build();
+ }
+
+ public static MessageTemplateSaveOrUpdateParam from(MessageTemplateUpdateRequest request) {
+ return MessageTemplateSaveOrUpdateParam.builder()
+ .templateName(request.getTemplateName())
+ .templateCode(request.getTemplateCode())
+ .leafGroupNodes(request.getLeafGroupNodes())
+ .title(request.getMsgTitle())
+ .content(request.getMsgContent())
+ .msgCardContentItems(request.getMsgCardContentItems())
+ .icon(request.getMsgIcon())
+ .operatorId(request.getOperatorId())
+ .routers(request.getRouters())
+ .pushTerminals(request.getPushTerminals())
+ .build();
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/PendingMessagePushParam.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/PendingMessagePushParam.java
index 429b0a31..61f726f7 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/PendingMessagePushParam.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/PendingMessagePushParam.java
@@ -69,6 +69,10 @@ public class PendingMessagePushParam implements Serializable {
* 业务描述eg:流程结点描述
*/
private String bizDesc;
+ /**
+ * 业务扩展参数,JSON字符串格式
+ */
+ private String bizExtParams;
/**
* 路由参数(json string)
*/
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/RelationTemplateMapInitParam.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/RelationTemplateMapInitParam.java
new file mode 100644
index 00000000..cb1bca6a
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/param/RelationTemplateMapInitParam.java
@@ -0,0 +1,31 @@
+package cn.axzo.msg.center.message.domain.param;
+
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.Collection;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/27
+ * @version 1.0
+ */
+@Setter
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class RelationTemplateMapInitParam {
+
+ private Collection relationIds;
+ private String groupNodeCode;
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/vo/GeneralMessagePushVO.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/vo/GeneralMessagePushVO.java
new file mode 100644
index 00000000..5216d5b6
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/vo/GeneralMessagePushVO.java
@@ -0,0 +1,230 @@
+package cn.axzo.msg.center.message.domain.vo;
+
+import cn.axzo.msg.center.domain.entity.GeneralMessageRecord;
+import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
+import cn.axzo.msg.center.service.dto.MessageRouterButtonDTO;
+import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
+import com.alibaba.fastjson.JSON;
+import com.google.common.collect.Lists;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/19
+ * @version 1.0
+ */
+@Setter
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class GeneralMessagePushVO implements Serializable {
+
+ private static final long serialVersionUID = -9017550674630922381L;
+
+ /**
+ * 消息的唯一标识
+ */
+ private String identityCode;
+ /**
+ * 模板编码
+ */
+ private String templateCode;
+ /**
+ * 顶部图片 - 模板icon地址
+ */
+ private String cardBannerUrl;
+ /**
+ * 卡片标题标题 - 消息标题
+ */
+ private String cardTitle;
+ /**
+ * 详情按钮
+ */
+ private CardButton cardDetailButton;
+ /**
+ * 副标题 - 消息所属组织信息
+ */
+ private List subtitles;
+ /**
+ * 消息内容
+ */
+ private String cardContent;
+ /**
+ * 卡片信息
+ */
+ private List cardExtension;
+ /**
+ * 按钮操作区域
+ */
+ private List cardButtons;
+ /**
+ * 业务编码
+ */
+ private String bizCode;
+ /**
+ * 消息发送时间戳
+ */
+ private Long sendTimestamp;
+
+ public static GeneralMessagePushVO from(GeneralMessageRecord record, String templateIcon, String orgIcon,
+ List routerButtons,
+ List cardContentItems) {
+ CardButton cardDetailButton = CollectionUtils.isEmpty(routerButtons) ? null : routerButtons.stream()
+ .filter(e -> RouterCategoryEnum.DETAIL.equals(e.getCategory()))
+ .findFirst()
+ .map(CardButton::from)
+ .orElse(null);
+ List cardButtons = CollectionUtils.isEmpty(routerButtons) ? Collections.emptyList() :
+ routerButtons.stream()
+ .filter(e -> !RouterCategoryEnum.DETAIL.equals(e.getCategory()))
+ .filter(MessageRouterButtonDTO::isShowOnCard)
+ .map(CardButton::from)
+ .collect(Collectors.toList());
+ List cardExtension = CollectionUtils.isEmpty(cardContentItems) ? Collections.emptyList() :
+ cardContentItems.stream()
+ .map(CardExtensionItem::from)
+ .collect(Collectors.toList());
+ List subtitles = Collections.emptyList();
+ Optional subtitleOp = Subtitle.from(record, orgIcon);
+ if (subtitleOp.isPresent()) {
+ subtitles = Lists.newArrayList(subtitleOp.get());
+ }
+ return GeneralMessagePushVO.builder()
+ .identityCode(record.getIdentityCode())
+ .templateCode(record.getTemplateCode())
+ .cardBannerUrl(templateIcon)
+ .cardTitle(record.getTitle())
+ .cardDetailButton(cardDetailButton)
+ .subtitles(subtitles)
+ .cardContent(record.getContent())
+ .cardExtension(cardExtension)
+ .cardButtons(cardButtons)
+ .bizCode(record.getBizCode())
+ .sendTimestamp(record.getCreateAt().getTime())
+ .build();
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+
+ @Setter
+ @Getter
+ @Builder
+ @NoArgsConstructor
+ @AllArgsConstructor
+ static class Subtitle {
+
+ /**
+ * 图标 - 对应消息所属组织的图标
+ */
+ private String iconUrl;
+ /**
+ * 标题 - 对应消息所属组织的名称
+ */
+ private String title;
+
+ static Optional from(GeneralMessageRecord record, String orgIcon) {
+ if (StringUtils.isBlank(record.getOrgName())) {
+ return Optional.empty();
+ }
+ return Optional.of(Subtitle.builder()
+ .title(record.getOrgName())
+ .iconUrl(orgIcon)
+ .build());
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+ }
+
+ @Setter
+ @Getter
+ @Builder
+ @NoArgsConstructor
+ @AllArgsConstructor
+ static class CardButton {
+
+ /**
+ * 按钮标题
+ */
+ private String title;
+ /**
+ * 按钮操作类型: JUMP - 页面跳转, ACTION - 接口调用
+ */
+ private String action;
+ /**
+ * 按钮样式
+ */
+ private Boolean isHighlight;
+ /**
+ * 按钮点击后的跳转地址
+ */
+ private List actionPaths;
+
+ static CardButton from(MessageRouterButtonDTO routerButton) {
+ return CardButton.builder()
+ .title(routerButton.getDesc())
+ .action(routerButton.getCategory().name())
+ .isHighlight(routerButton.isHighlight())
+ .actionPaths(routerButton.getTerminals().stream()
+ .map(e -> new ButtonAction(e.getTerminalType().name(), e.getUrl()))
+ .collect(Collectors.toList())
+ ).build();
+ }
+
+ @Getter
+ @AllArgsConstructor
+ static class ButtonAction {
+
+ /**
+ * 平台
+ */
+ private String platform;
+ /**
+ * 跳转地址
+ */
+ private String url;
+ }
+ }
+
+ @Setter
+ @Getter
+ @Builder
+ @NoArgsConstructor
+ @AllArgsConstructor
+ static class CardExtensionItem {
+
+ private String title;
+
+ private String detail;
+
+ static CardExtensionItem from(MessageCardContentItemDTO cardContentItem) {
+ return CardExtensionItem.builder()
+ .title(cardContentItem.getLabel())
+ .detail(cardContentItem.getValue())
+ .build();
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/vo/RelationTemplateMapInitRequest.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/vo/RelationTemplateMapInitRequest.java
new file mode 100644
index 00000000..f8a49139
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/domain/vo/RelationTemplateMapInitRequest.java
@@ -0,0 +1,33 @@
+package cn.axzo.msg.center.message.domain.vo;
+
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import java.util.Collection;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/27
+ * @version 1.0
+ */
+@Setter
+@Getter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class RelationTemplateMapInitRequest {
+
+ private Collection relationIds;
+ @NotBlank(message = "groupNodeCode is required")
+ private String groupNodeCode;
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/GeneralMessageMapperService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/GeneralMessageMapperService.java
new file mode 100644
index 00000000..c30c5165
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/GeneralMessageMapperService.java
@@ -0,0 +1,25 @@
+package cn.axzo.msg.center.message.service;
+
+import cn.axzo.msg.center.api.request.GeneralMessageReq;
+import cn.axzo.msg.center.domain.entity.MessageRecord;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 新老版本消息映射的相关接口
+ *
+ * @author cold_blade
+ * @date 2023/10/23
+ * @version 1.0
+ */
+public interface GeneralMessageMapperService {
+
+ /**
+ * 异步批量发送消息
+ *
+ * @param request 发送消息时的请求参数
+ * @param toIdMessageRecordMap 接收者身份id与旧消息记录的映射关系
+ */
+ void asyncBatchSendMessage(GeneralMessageReq request, Map toIdMessageRecordMap);
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/GeneralMessageOldService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/GeneralMessageOldService.java
new file mode 100644
index 00000000..b4049ed6
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/GeneralMessageOldService.java
@@ -0,0 +1,46 @@
+package cn.axzo.msg.center.message.service;
+
+import cn.axzo.msg.center.api.request.CmsMsgQueryReq;
+import cn.axzo.msg.center.api.response.MessageNewRes;
+import cn.axzo.msg.center.service.dto.PersonDTO;
+import cn.azxo.framework.common.model.Page;
+
+import java.util.List;
+
+/**
+ * 旧普通消息的相关接口
+ *
+ * @author cold_blade
+ * @date 2023/10/24
+ * @version 1.0
+ */
+public interface GeneralMessageOldService {
+
+ /**
+ * 统计未读的消息数量
+ * 注: 该接口作为IM进入旧消息模块的入口,需要过滤双发至IM的消息
+ *
+ * @param person 身份信息
+ * @return 未读消息数量
+ */
+ int countUnread(PersonDTO person);
+
+ /**
+ * 统计未读的消息数量
+ * 注: 该接口作为IM进入旧消息模块的入口,需要过滤双发至IM的消息
+ *
+ * @param person 身份信息
+ * @param excludeMsgIds 待排除的消息记录id
+ * @return 未读消息数量
+ */
+ int countUnread(PersonDTO person, List excludeMsgIds);
+
+ /**
+ * 分页查询旧的普通消息记录
+ * 注: 该接口作为IM进入旧消息模块的入口,需要过滤双发至IM的消息
+ *
+ * @param request 分页查询参数
+ * @return 过滤后的旧的普通消息记录
+ */
+ Page pageMsgInfo(CmsMsgQueryReq request);
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/GeneralMessageService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/GeneralMessageService.java
new file mode 100644
index 00000000..eb2fa03a
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/GeneralMessageService.java
@@ -0,0 +1,32 @@
+package cn.axzo.msg.center.message.service;
+
+import cn.axzo.msg.center.message.domain.dto.SendImMessageDTO;
+import cn.axzo.msg.center.service.general.request.GeneralMessageOldDataStatisticRequest;
+import cn.axzo.msg.center.service.general.request.GeneralMessageSendRequest;
+import cn.axzo.msg.center.service.general.response.GeneralMessageOldDataStatisticResponse;
+
+import java.util.List;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/19
+ * @version 1.0
+ */
+public interface GeneralMessageService {
+
+ /**
+ * 发送消息
+ *
+ * @param request 消息所需参数
+ * @return 请求的唯一标识
+ */
+ List batchSendMessage(GeneralMessageSendRequest request);
+
+ /**
+ * 统计旧数据
+ *
+ * @param request 统计参数
+ * @return 旧数据的未读数以及最新一条消息
+ */
+ GeneralMessageOldDataStatisticResponse statisticOldData(GeneralMessageOldDataStatisticRequest request);
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupNodeService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupNodeService.java
new file mode 100644
index 00000000..3a328708
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupNodeService.java
@@ -0,0 +1,73 @@
+package cn.axzo.msg.center.message.service;
+
+import cn.axzo.msg.center.message.domain.param.MessageGroupNodeSaveOrUpdateParam;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * 消息分类结点管理
+ *
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+public interface MessageGroupNodeService {
+
+ /**
+ * 获取分类结点(叶结点)名称的路径
+ *
+ * @param groupNodeCodePaths 分类结点(叶结点)的编码列表
+ * @return 分类结点(叶结点)名称的路径
+ */
+ Map groupNodeNamePaths(Collection groupNodeCodePaths);
+
+ /**
+ * 获取分类结点(叶结点)编码的路径
+ *
+ * @param leafGroupNodeCodes 分类结点(叶结点)的编码列表
+ * @return 分类结点(叶结点)编码的路径
+ */
+ Map leafGroupNodeCodePaths(Collection leafGroupNodeCodes);
+
+ /**
+ * 根据结点编码查询结点信息
+ *
+ * @param rootNodeCode 结点编码
+ * @return 结点信息
+ */
+ Optional queryRootNode(String rootNodeCode);
+
+ /**
+ * 新增结点
+ *
+ * @param param 结点内容
+ */
+ void addGroupNode(MessageGroupNodeSaveOrUpdateParam param);
+
+ /**
+ * 编辑结点
+ *
+ * @param param 结点内容
+ */
+ void updateGroupNode(MessageGroupNodeSaveOrUpdateParam param);
+
+ /**
+ * 删除结点
+ *
+ * @param operatorId 操作人id
+ * @param nodeCode 待删除结点的编码
+ */
+ void deleteGroupNode(Long operatorId, String nodeCode);
+
+ /**
+ * 查询消息/待办 或者两者的分类树
+ * @param category 消息/待办
+ * @return 分类树列表
+ */
+ List listGroupTree(MessageCategoryEnum category);
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupService.java
deleted file mode 100644
index 66dabe02..00000000
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupService.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package cn.axzo.msg.center.message.service;
-
-import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeDTO;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * 消息分类管理
- *
- * @author cold_blade
- * @date 2023/9/20
- * @version 1.0
- */
-public interface MessageGroupService {
-
- /**
- * 通过结点编码查询结点信息
- *
- * @param nodeCode 结点编码
- * @return 结点信息
- */
- Optional queryByNodeCode(String nodeCode);
-
- /**
- * 查询指定结点的字节的信息
- *
- * @param nodeCode 指定结点编码
- * @return 子节点列表信息
- */
- List listChildren(String nodeCode);
-
- /**
- * 模板关联分类
- *
- * @param templateNode 模板编码
- * @param pathList 分类path列表
- */
- void templateGroup(String templateNode, Collection pathList);
-}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupTreeNodeCacheService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupTreeNodeCacheService.java
new file mode 100644
index 00000000..dca2c097
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageGroupTreeNodeCacheService.java
@@ -0,0 +1,53 @@
+package cn.axzo.msg.center.message.service;
+
+import cn.axzo.msg.center.message.domain.dto.GroupTreeNodePathDTO;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 消息分类树节点缓存管理
+ *
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+public interface MessageGroupTreeNodeCacheService {
+
+ /**
+ * 获取所有有效的分类结点树
+ *
+ * @return 树列表
+ */
+ List listAllGroupTree();
+
+ /**
+ * 获取指定结点所在的树的根节点
+ *
+ * @param rootNodeCode 结点编码
+ * @return 根节点
+ */
+ Optional queryRootNode(String rootNodeCode);
+
+ /**
+ * 根据结点编码查询结点信息
+ *
+ * @param groupNodeCode 结点编码
+ * @return 结点信息
+ */
+ Optional queryNode(String groupNodeCode);
+
+ /**
+ * 获取叶结点对应的树的路径
+ *
+ * @param leafNodeCode 叶结点编码
+ * @return 路径
+ */
+ Optional queryLeafNodePath(String leafNodeCode);
+
+ /**
+ * 刷新缓存
+ */
+ void refreshCache();
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageSendTwiceRecordService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageSendTwiceRecordService.java
new file mode 100644
index 00000000..144c6c4e
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageSendTwiceRecordService.java
@@ -0,0 +1,21 @@
+package cn.axzo.msg.center.message.service;
+
+import cn.axzo.msg.center.api.request.GeneralMessageReq;
+import cn.axzo.msg.center.service.dto.PersonDTO;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 双发消息记录service
+ *
+ * @author cold_blade
+ * @date 2023/10/23
+ * @version 1.0
+ */
+public interface MessageSendTwiceRecordService {
+
+ List listByPerson(Long personId);
+
+ void batchSave(Map msgRecordIdPersonIdMap);
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateGroupService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateGroupService.java
index f830e062..0cd3bf30 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateGroupService.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateGroupService.java
@@ -1,6 +1,8 @@
package cn.axzo.msg.center.message.service;
+import java.util.Collection;
import java.util.List;
+import java.util.Map;
/**
* 消息模板分类管理
@@ -18,4 +20,61 @@ public interface MessageTemplateGroupService {
* @return 模板编码列表
*/
List listMessageTemplateCodes(String groupNodeCode);
+
+ /**
+ * 模板关联分类
+ *
+ * @param templateNode 模板编码
+ * @param groupNodeCodes 分类结点编码列表
+ */
+ void templateGroup(String templateNode, Collection groupNodeCodes);
+
+ /**
+ * 模板关联分类
+ *
+ * @param templateGroupMap 模板编码与分类结点编码列表的map
+ */
+ void templateGroup(Map> templateGroupMap);
+
+ /**
+ * 更新模板的分类关系
+ *
+ * @param templateNode 模板编码
+ * @param groupNodeCodes 新的模板的分类结点编码
+ */
+ void updateTemplateGroup(String templateNode, Collection groupNodeCodes);
+
+ /**
+ * 解除模板关联的分类
+ *
+ * @param templateNode 模板编码
+ */
+ void deleteTemplateGroup(String templateNode);
+
+ /**
+ * 通过消息模板编码查询其关联的分类的path
+ *
+ * @param templateCodes 消息模板编码集合
+ * @return 模板编码与分类的path列表的映射关系
+ */
+ Map> listMessageTemplateGroupPaths(Collection templateCodes);
+
+ /**
+ * 解除模板与当前分类的关联关系
+ * 注:当模板只关联一个分类时,该关联关系不能解除
+ *
+ * @param curGroupNodeCode 当前分类结点的编码
+ * @param templateCodes 待解除关连关系的模板编码
+ */
+ void remove(String curGroupNodeCode, Collection templateCodes);
+
+ /**
+ * 解除模板与当前分类的关联关系
+ * 注:当模板只关联一个分类时,该关联关系不能解除
+ *
+ * @param srcGroupNodeCode 源分类结点的编码
+ * @param tgtGroupNodeCode 目标分类结点的编码
+ * @param templateCodes 待变更关连关系的模板编码
+ */
+ void move(String srcGroupNodeCode, String tgtGroupNodeCode, Collection templateCodes);
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateNewService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateNewService.java
index 6836bb14..74d94bf8 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateNewService.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateNewService.java
@@ -1,8 +1,15 @@
package cn.axzo.msg.center.message.service;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO;
-import cn.axzo.msg.center.message.domain.param.MessageTemplateCreateParam;
+import cn.axzo.msg.center.message.domain.param.MessageTemplateSaveOrUpdateParam;
+import cn.axzo.msg.center.service.dto.MessageBaseTemplateDTO;
+import cn.axzo.msg.center.service.enums.StatusEnum;
+import cn.axzo.msg.center.service.template.request.MessageTemplatePageRequest;
+import cn.axzo.msg.center.service.template.response.MessageTemplateDetailResponse;
+import cn.axzo.msg.center.service.template.response.MessageTemplatePageResponse;
+import cn.azxo.framework.common.model.Page;
+import java.util.Collection;
import java.util.List;
import java.util.Optional;
@@ -20,7 +27,31 @@ public interface MessageTemplateNewService {
*
* @param param 模板内容参数
*/
- void createTemplate(MessageTemplateCreateParam param);
+ String createTemplate(MessageTemplateSaveOrUpdateParam param);
+
+ /**
+ * 编辑模板
+ *
+ * @param param 模板内容参数
+ */
+ void updateTemplate(MessageTemplateSaveOrUpdateParam param);
+
+ /**
+ * 通过模板便阿门查询模板详情
+ *
+ * @param templateCode 模板编码
+ * @return 模板详情信息
+ */
+ MessageTemplateDetailResponse detail(String templateCode);
+
+ /**
+ * 更新模板状态
+ *
+ * @param operatorId 操作人id
+ * @param templateCode 模板编码
+ * @param status 新的模板状态
+ */
+ void updateStatus(Long operatorId, String templateCode, StatusEnum status);
/**
* 通过模板编码查询模板信息
@@ -37,4 +68,28 @@ public interface MessageTemplateNewService {
* @return 模板信息
*/
List listByTemplateCodes(List msgTemplateCodes);
+
+ /**
+ * 分页查询模板数据
+ *
+ * @param request 分页请求参数
+ * @return 模板数据列表
+ */
+ Page page(MessageTemplatePageRequest request);
+
+ /**
+ * 分页查询模板基础数据
+ *
+ * @param request 分页请求参数
+ * @return 模板数据列表
+ */
+ Page pageBaseTemplate(MessageTemplatePageRequest request);
+
+ /**
+ * 通过模板编码查询对应的模板
+ *
+ * @param templateCodes 模板编码集合
+ * @return 模板列表
+ */
+ List listByCodes(Collection templateCodes);
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateRouterService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateRouterService.java
index 915b43c1..51d71044 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateRouterService.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/MessageTemplateRouterService.java
@@ -1,6 +1,7 @@
package cn.axzo.msg.center.message.service;
import cn.axzo.msg.center.message.domain.dto.RawMessageRouterDTO;
+import cn.axzo.msg.center.service.dto.MessageRouterButtonDTO;
import java.util.List;
import java.util.Map;
@@ -30,6 +31,14 @@ public interface MessageTemplateRouterService {
*/
void batchInsert(List routers);
+ /**
+ * 更新模板的路由信息
+ *
+ * @param templateCode 模板编码
+ * @param routers 路由列表
+ */
+ void updateTemplateRoutes(String templateCode, List routers);
+
/**
* 根据消息模板编码查询配置的路由列表
*
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/PendingMessageNewService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/PendingMessageNewService.java
index df132a34..be931eef 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/PendingMessageNewService.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/PendingMessageNewService.java
@@ -1,12 +1,11 @@
package cn.axzo.msg.center.message.service;
-import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeDTO;
+import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeStatisticDTO;
import cn.axzo.msg.center.message.domain.dto.PendingMessageDTO;
import cn.axzo.msg.center.message.domain.param.MessageGroupNodeStatisticParam;
import cn.axzo.msg.center.message.domain.param.PendingMessagePushParam;
import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
import cn.axzo.msg.center.service.pending.request.PendingMessagePageRequest;
-import cn.axzo.msg.center.service.pending.request.PendingMessagePushRequest;
import cn.axzo.msg.center.service.pending.response.PendingMessageResponse;
import cn.azxo.framework.common.model.Page;
@@ -22,7 +21,7 @@ import java.util.Optional;
*/
public interface PendingMessageNewService {
- List groupStatistic(MessageGroupNodeStatisticParam param);
+ List groupStatistic(MessageGroupNodeStatisticParam param);
/**
* 代办列表分页查询
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/RelationTemplateMapService.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/RelationTemplateMapService.java
new file mode 100644
index 00000000..327b90ec
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/RelationTemplateMapService.java
@@ -0,0 +1,23 @@
+package cn.axzo.msg.center.message.service;
+
+import cn.axzo.msg.center.message.domain.param.RelationTemplateMapInitParam;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * 新老模板的关联关系service
+ *
+ * @author cold_blade
+ * @date 2023/10/23
+ * @version 1.0
+ */
+public interface RelationTemplateMapService {
+
+ Optional queryByRelationId(Long relationId);
+
+ void mapRelationAndTemplate(Map map);
+
+ void init(RelationTemplateMapInitParam param);
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/GeneralMessageMapperServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/GeneralMessageMapperServiceImpl.java
new file mode 100644
index 00000000..46288909
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/GeneralMessageMapperServiceImpl.java
@@ -0,0 +1,146 @@
+package cn.axzo.msg.center.message.service.impl;
+
+import cn.axzo.msg.center.api.enums.MsgTypeEnum;
+import cn.axzo.msg.center.api.request.GeneralMessageReq;
+import cn.axzo.msg.center.domain.entity.MessageRecord;
+import cn.axzo.msg.center.message.domain.dto.SendImMessageDTO;
+import cn.axzo.msg.center.message.service.GeneralMessageMapperService;
+import cn.axzo.msg.center.message.service.GeneralMessageService;
+import cn.axzo.msg.center.message.service.MessageSendTwiceRecordService;
+import cn.axzo.msg.center.message.service.RelationTemplateMapService;
+import cn.axzo.msg.center.service.dto.PersonDTO;
+import cn.axzo.msg.center.service.enums.IdentityTypeEnum;
+import cn.axzo.msg.center.service.enums.OrganizationTypeEnum;
+import cn.axzo.msg.center.service.general.request.GeneralMessageSendRequest;
+import cn.axzo.msg.center.utils.PersonIdentityUtil;
+import cn.hutool.core.map.MapUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import jodd.util.concurrent.ThreadFactoryBuilder;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/23
+ * @version 1.0
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GeneralMessageMapperServiceImpl implements GeneralMessageMapperService {
+
+ private final ThreadFactory asyncSendMsgThreadFactory = ThreadFactoryBuilder.create()
+ .setDaemon(true).setNameFormat("ASYNC_SEND_IM_MESSAGE_%d").get();
+ private final ExecutorService asyncSendMsgExecutorService = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<>(1024), asyncSendMsgThreadFactory);
+
+ private final GeneralMessageService generalMessageService;
+ private final RelationTemplateMapService relationTemplateMapService;
+ private final MessageSendTwiceRecordService messageSendTwiceRecordService;
+
+ @Override
+ public void asyncBatchSendMessage(GeneralMessageReq request, Map toIdMessageRecordMap) {
+ log.info("do some check before send im message. relationId:[{}]", request.getRelationId());
+ if (MsgTypeEnum.PENDING_MESSAGE.equals(request.getType())) {
+ log.info("pending message is not supported.");
+ return;
+ }
+ if (Objects.isNull(request.getRelationId())) {
+ log.info("relation id is null.");
+ return;
+ }
+ if (MapUtil.isEmpty(request.getToldIdPersonIdMap())) {
+ // 由于IM那边是根据personId来创建账户的,所以强依赖personId
+ log.info("toIdPersonIdMap is empty.");
+ return;
+ }
+ // 异步发送IM消息
+ log.info("start to async send im message. relationId:[{}]", request.getRelationId());
+ CompletableFuture.runAsync(() -> doBatchSendMessage(request, toIdMessageRecordMap),
+ asyncSendMsgExecutorService);
+ }
+
+ private void doBatchSendMessage(GeneralMessageReq request, Map toIdMessageRecordMap) {
+ String templateCode = relationTemplateMapService.queryByRelationId(request.getRelationId()).orElse(null);
+ if (StringUtils.isBlank(templateCode)) {
+ log.info("the relationId([{}]) is not map any new message template. ", request.getRelationId());
+ return;
+ }
+ log.info("start to send im message. relationId:[{}], templateCode:[{}]", request.getRelationId(), templateCode);
+ try {
+ // 发送IM消息
+ GeneralMessageSendRequest sendImMsgRequest = buildSendRequest(request, templateCode, toIdMessageRecordMap.keySet());
+ // IM消息的发送是基于personId+应用终端的(eg: 工人端/企业端)
+ List result = generalMessageService.batchSendMessage(sendImMsgRequest);
+ if (CollectionUtils.isEmpty(result)) {
+ log.info("there is not any person successfully send im message. relationId:[{}]", request.getRelationId());
+ return;
+ }
+ // 记录发送了IM消息的旧消息
+ recordSendImMessage(toIdMessageRecordMap, result, request.getToldIdPersonIdMap());
+ } catch (Exception e) {
+ log.warn("broke out some exception while sending im message. relationId:[{}]", request.getRelationId(), e);
+ }
+ }
+
+ private void recordSendImMessage(Map toIdMessageRecordMap, List sendImResult,
+ Map toIdPersonIdMap) {
+ // 成功发送了IM消息的personId集合
+ Set sucSendImMsgPersonIds = sendImResult.stream()
+ .map(SendImMessageDTO::getPersonId).collect(Collectors.toSet());
+ // 从入参中的toIdPersonIdMap中筛选发送成功的entry
+ Map subToIdPersonIdMap = toIdPersonIdMap.entrySet().stream()
+ // 过滤掉personId维度IM消息发送失败的entry
+ .filter(e -> sucSendImMsgPersonIds.contains(e.getValue()))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ Map msgRecordIdPersonIdMap = toIdMessageRecordMap.entrySet().stream()
+ .filter(e -> subToIdPersonIdMap.containsKey(e.getKey()))
+ .collect(Collectors.toMap(e -> e.getValue().getId(), e -> subToIdPersonIdMap.get(e.getKey())));
+ log.info("record message that has been send im message. msgIds:{}", msgRecordIdPersonIdMap.keySet());
+ // 双发记录
+ messageSendTwiceRecordService.batchSave(msgRecordIdPersonIdMap);
+ }
+
+ private GeneralMessageSendRequest buildSendRequest(GeneralMessageReq request, String templateCode,
+ Collection subReceiverIds) {
+ IdentityTypeEnum identityType = PersonIdentityUtil.toIdentityType(request.getReceiveType());
+ List receivers = subReceiverIds.stream()
+ .filter(request.getToldIdPersonIdMap()::containsKey)
+ .map(e -> PersonDTO.from(request.getToldIdPersonIdMap().get(e), e, identityType))
+ .collect(Collectors.toList());
+ OrganizationTypeEnum orgType = Objects.isNull(request.getTerminalType()) ? OrganizationTypeEnum.UNKNOWN :
+ OrganizationTypeEnum.valueOf(request.getTerminalType().name());
+ return GeneralMessageSendRequest.builder()
+ .templateCode(templateCode)
+ .receiver(receivers)
+ .orgType(orgType)
+ .orgName(request.getTerminalName())
+ .orgId(request.getTerminalId())
+ .bizCode(Optional.ofNullable(request.getBizId()).map(String::valueOf).orElse(""))
+ .routerParams(Optional.ofNullable(request.getRouterParams())
+ .map(v -> JSONObject.parseObject(JSON.toJSONString(v)))
+ .orElseGet(JSONObject::new))
+ .bizExtParams(Optional.ofNullable(request.getMsgParams())
+ .map(v -> JSONObject.parseObject(JSON.toJSONString(v)))
+ .orElseGet(JSONObject::new))
+ .build();
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/GeneralMessageOldServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/GeneralMessageOldServiceImpl.java
new file mode 100644
index 00000000..bd978636
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/GeneralMessageOldServiceImpl.java
@@ -0,0 +1,86 @@
+package cn.axzo.msg.center.message.service.impl;
+
+import cn.axzo.basics.common.util.AssertUtil;
+import cn.axzo.core.domain.PageResult;
+import cn.axzo.msg.center.api.enums.MsgStateEnum;
+import cn.axzo.msg.center.api.enums.MsgTypeEnum;
+import cn.axzo.msg.center.api.request.CmsMsgQueryReq;
+import cn.axzo.msg.center.api.response.MessageNewRes;
+import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
+import cn.axzo.msg.center.common.utils.PageHelperUtil;
+import cn.axzo.msg.center.dal.MessageRecordDao;
+import cn.axzo.msg.center.domain.entity.MessageRecord;
+import cn.axzo.msg.center.domain.enums.ModuleBizTypeEnum;
+import cn.axzo.msg.center.inside.notices.service.MessageCoreService;
+import cn.axzo.msg.center.inside.notices.service.MessageModuleService;
+import cn.axzo.msg.center.inside.notices.service.MessageRelationService;
+import cn.axzo.msg.center.message.service.GeneralMessageOldService;
+import cn.axzo.msg.center.message.service.MessageSendTwiceRecordService;
+import cn.axzo.msg.center.service.dto.PersonDTO;
+import cn.axzo.msg.center.utils.PersonIdentityUtil;
+import cn.azxo.framework.common.model.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/24
+ * @version 1.0
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GeneralMessageOldServiceImpl implements GeneralMessageOldService {
+
+ private final MessageRecordDao messageRecordDao;
+ private final MessageCoreService messageCoreService;
+ private final MessageModuleService messageModuleService;
+ private final MessageRelationService messageRelationService;
+ private final MessageSendTwiceRecordService messageSendTwiceRecordService;
+
+ @Override
+ public int countUnread(PersonDTO person) {
+ AssertUtil.isTrue(Objects.nonNull(person) && person.isValid(),
+ "session 异常, 无法执行消息统计查询!, person : " + person);
+ List sendTwiceMsgIds = messageSendTwiceRecordService.listByPerson(person.getId());
+ return countUnread(person, sendTwiceMsgIds);
+ }
+
+ @Override
+ public int countUnread(PersonDTO person, List excludeMsgIds) {
+ List moduleIds = messageModuleService.listModuleIdByBizType(ModuleBizTypeEnum.CONSTRUCTION);
+ List relationIds = messageRelationService.listRelationIds(moduleIds);
+ if (CollectionUtils.isEmpty(relationIds)) {
+ log.info("the is not any valid relation id.");
+ return 0;
+ }
+ return messageRecordDao.lambdaQuery()
+ .eq(MessageRecord::getType, MsgTypeEnum.GENERAL_MESSAGE)
+ .in(MessageRecord::getState, MsgStateEnum.unreadStates())
+ .eq(MessageRecord::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .eq(MessageRecord::getToId, person.getIdentity().getId())
+ .eq(MessageRecord::getReceiveType, PersonIdentityUtil.toReceiveType(person.getIdentity().getType()))
+ .in(MessageRecord::getRelationId, relationIds)
+ // 排除双发记录表中的数据
+ .notIn(CollectionUtils.isNotEmpty(excludeMsgIds), MessageRecord::getId, excludeMsgIds)
+ .count();
+ }
+
+ @Override
+ public Page pageMsgInfo(CmsMsgQueryReq request) {
+ log.info("start to page query general message. request:{}", request);
+ if (CollectionUtils.isEmpty(request.getExcludeMsgIds())) {
+ request.setExcludeMsgIds(messageSendTwiceRecordService.listByPerson(request.getPersonId()));
+ }
+ PageResult result = messageCoreService.listMsgInfo(request);
+ if (CollectionUtils.isEmpty(result.getData())) {
+ return PageHelperUtil.emptyPage(request.getPage(), request.getPageSize());
+ }
+ return Page.toPage(request.getPage(), request.getPageSize(), result.getTotalCount(), result.getData());
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/GeneralMessageServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/GeneralMessageServiceImpl.java
new file mode 100644
index 00000000..0ab4e86a
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/GeneralMessageServiceImpl.java
@@ -0,0 +1,232 @@
+package cn.axzo.msg.center.message.service.impl;
+
+import cn.axzo.framework.domain.web.result.ApiResult;
+import cn.axzo.im.center.api.feign.MessageApi;
+import cn.axzo.im.center.api.vo.req.MessageInfo;
+import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
+import cn.axzo.im.center.common.enums.AppTypeEnum;
+import cn.axzo.msg.center.api.request.CmsMsgQueryReq;
+import cn.axzo.msg.center.api.response.MessageNewRes;
+import cn.axzo.msg.center.common.exception.ServiceException;
+import cn.axzo.msg.center.common.utils.PlaceholderResolver;
+import cn.axzo.msg.center.dal.GeneralMessageRecordDao;
+import cn.axzo.msg.center.domain.entity.GeneralMessageRecord;
+import cn.axzo.msg.center.domain.enums.UserTypeEnum;
+import cn.axzo.msg.center.inside.notices.config.MessageSystemConfig;
+import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO;
+import cn.axzo.msg.center.message.domain.dto.RawMessageRouterDTO;
+import cn.axzo.msg.center.message.domain.dto.SendImMessageDTO;
+import cn.axzo.msg.center.message.domain.vo.GeneralMessagePushVO;
+import cn.axzo.msg.center.message.service.GeneralMessageOldService;
+import cn.axzo.msg.center.message.service.GeneralMessageService;
+import cn.axzo.msg.center.message.service.MessageSendTwiceRecordService;
+import cn.axzo.msg.center.message.service.MessageTemplateNewService;
+import cn.axzo.msg.center.service.dto.IdentityDTO;
+import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
+import cn.axzo.msg.center.service.dto.MessageRouterButtonDTO;
+import cn.axzo.msg.center.service.dto.PersonDTO;
+import cn.axzo.msg.center.service.enums.GeneralMessageStateEnum;
+import cn.axzo.msg.center.service.enums.IdentityTypeEnum;
+import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
+import cn.axzo.msg.center.service.enums.PushTerminalEnum;
+import cn.axzo.msg.center.service.general.request.GeneralMessageOldDataStatisticRequest;
+import cn.axzo.msg.center.service.general.request.GeneralMessageSendRequest;
+import cn.axzo.msg.center.service.general.response.GeneralMessageOldDataStatisticResponse;
+import cn.axzo.msg.center.utils.MessageRouterUtil;
+import cn.axzo.msg.center.utils.PersonIdentityUtil;
+import cn.axzo.msg.center.utils.UUIDUtil;
+import cn.azxo.framework.common.model.Page;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/19
+ * @version 1.0
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GeneralMessageServiceImpl implements GeneralMessageService {
+
+ private static final PersonDTO SYSTEM_SENDER = PersonDTO.builder()
+ .id(0L)
+ .identity(IdentityDTO.builder().id(0L).type(IdentityTypeEnum.NOT_SUPPORT).build())
+ .build();
+
+ private static final ImmutableMap PUSH_TERMINAL_APP_MAP = ImmutableMap.of(
+ PushTerminalEnum.B_ENTERPRISE_APP, AppTypeEnum.CMP,
+ PushTerminalEnum.C_WORKER_APP, AppTypeEnum.CM
+ );
+
+ private final MessageApi messageApi;
+ private final MessageSystemConfig messageSystemConfig;
+ private final GeneralMessageRecordDao generalMessageRecordDao;
+ private final GeneralMessageOldService generalMessageOldService;
+ private final MessageTemplateNewService messageTemplateNewService;
+ private final MessageSendTwiceRecordService messageSendTwiceRecordService;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
+ public List batchSendMessage(GeneralMessageSendRequest request) {
+ // 查询模板基础信息
+ MessageTemplateDTO template = messageTemplateNewService.queryByTemplateCode(request.getTemplateCode())
+ .orElseThrow(() -> new ServiceException("未查询到对应的模板"));
+ // 构建消息记录并存储
+ List messageRecords = buildMessageRecord(request, template);
+ generalMessageRecordDao.saveBatch(messageRecords);
+ // 发送IM消息
+ return pushImMessage(messageRecords, template);
+ }
+
+ @Override
+ public GeneralMessageOldDataStatisticResponse statisticOldData(GeneralMessageOldDataStatisticRequest request) {
+ // 查询双发的消息记录
+ List sendTwiceMsgIds = messageSendTwiceRecordService.listByPerson(request.getPersonId());
+ // 分页查询最新一条数据
+ Page result = generalMessageOldService.pageMsgInfo(build(request, sendTwiceMsgIds));
+ // 统计旧的未读普通消息数量
+ int count = generalMessageOldService.countUnread(PersonDTO.from(request.getPersonId(), request.getIdentityId(),
+ request.getIdentityType()), sendTwiceMsgIds);
+ // 编排组合成界面展示的数据结构
+ MessageNewRes msg = CollectionUtils.isNotEmpty(result.getList()) ? result.getList().get(0) : null;
+ return GeneralMessageOldDataStatisticResponse.builder()
+ .unreadCount(count)
+ .latestMsgSendTimestamp(Optional.ofNullable(msg).map(v -> v.getCreateAt().getTime()).orElse(null))
+ .latestMsgContent(Optional.ofNullable(msg).map(MessageNewRes::getContent).orElse(null))
+ .build();
+ }
+
+ private List buildMessageRecord(GeneralMessageSendRequest request, MessageTemplateDTO template) {
+ return request.getReceiver().stream()
+ .map(e -> buildMessageRecord(request, e, template))
+ .collect(Collectors.toList());
+ }
+
+ private GeneralMessageRecord buildMessageRecord(GeneralMessageSendRequest request, PersonDTO receiver,
+ MessageTemplateDTO template) {
+ PersonDTO sender = Objects.isNull(request.getSender()) ? SYSTEM_SENDER : request.getSender();
+ return GeneralMessageRecord.builder()
+ .identityCode(UUIDUtil.uuidString())
+ .senderPersonId(sender.getId())
+ .senderId(sender.getIdentity().getId())
+ .senderType(sender.getIdentity().getType())
+ .receiverPersonId(receiver.getId())
+ .receiverId(receiver.getIdentity().getId())
+ .receiverType(receiver.getIdentity().getType())
+ .templateCode(template.getCode())
+ .title(parseString(template.getTitle(), request.getBizExtParams()))
+ .content(parseString(template.getContent(), request.getBizExtParams()))
+ .orgType(request.getOrgType())
+ .orgId(request.getOrgId())
+ .orgName(request.getOrgName())
+ .state(GeneralMessageStateEnum.HAS_BEEN_SENT)
+ .bizCode(request.getBizCode())
+ .routerParams(request.getRouterParams())
+ .bizExtParams(request.getBizExtParams())
+ .build();
+ }
+
+ private List pushImMessage(List messageRecords, MessageTemplateDTO template) {
+ if (CollectionUtils.isEmpty(template.getPushTerminals())) {
+ // 模板未配置任何推送终端
+ return Collections.emptyList();
+ }
+ GeneralMessageRecord record = messageRecords.get(0);
+ List appTypes = template.getPushTerminals().stream()
+ .map(PUSH_TERMINAL_APP_MAP::get).collect(Collectors.toList());
+ GeneralMessagePushVO message = convert(record, template);
+ MessageInfo msgInfo = new MessageInfo();
+ msgInfo.setAppTypeList(appTypes);
+ msgInfo.setToPersonIdList(Sets.newHashSet(messageRecords.stream()
+ .map(e -> String.valueOf(e.getReceiverPersonId()))
+ .collect(Collectors.toSet())));
+ msgInfo.setMsgHeader(record.getTitle());
+ msgInfo.setMsgContent(record.getContent());
+ msgInfo.setMsgTemplateId(record.getTemplateCode());
+ msgInfo.setMsgTemplateContent(JSON.toJSONString(message));
+ // 扩展信息
+ Map ext = new HashMap<>();
+ ext.put("minAppVersion", template.getMinAppVersion());
+ if (Objects.nonNull(record.getOrgId()) && record.getOrgId() > 0L) {
+ ext.put("workspaceId", record.getOrgId().toString());
+ }
+ msgInfo.setExtendsInfo(ext);
+
+ ApiResult> result = messageApi.sendMessage(msgInfo);
+ if (result.isError() || CollectionUtils.isEmpty(result.getData())) {
+ log.warn("failed to batch send im message. result:{}", result);
+ return Collections.emptyList();
+ }
+ return result.getData().stream()
+ .map(SendImMessageDTO::from)
+ .collect(Collectors.toList());
+ }
+
+ private GeneralMessagePushVO convert(GeneralMessageRecord record, MessageTemplateDTO template) {
+ // 对应模板的路由列表
+ List rawRouters = template.getRouters();
+ // 解析路由地址
+ List routers = rawRouters.stream()
+ .map(e -> MessageRouterUtil.parseAndConcatRouteUrl(e, record.getRouterParams()))
+ .collect(Collectors.toList());
+ // 转化成客户端展示的数据模型
+ List routerButtons = routers.stream()
+ .map(RawMessageRouterDTO::toMessageRouterButton)
+ .collect(Collectors.toList());
+ // 获取模板卡片信息
+ List rawCardContentItems = template.getMsgCardContentItems();
+ List cardContentItems = rawCardContentItems;
+ if (CollectionUtils.isNotEmpty(rawCardContentItems) && Objects.nonNull(record.getBizExtParams())
+ && !record.getBizExtParams().isEmpty()) {
+ // 克隆,避免修改入参
+ cardContentItems = cardContentItems.stream()
+ .map(MessageCardContentItemDTO::deepClone)
+ .collect(Collectors.toList());
+ cardContentItems.forEach(e -> {
+ String value = PlaceholderResolver.getDefaultResolver()
+ .resolveByMap(e.getValue(), record.getBizExtParams());
+ e.setValue(value);
+ });
+ }
+ return GeneralMessagePushVO.from(record, template.getIcon(), messageSystemConfig.getOrgIcon(), routerButtons, cardContentItems);
+ }
+
+ private String parseString(String string, JSONObject params) {
+ if (Objects.isNull(params)) {
+ return string;
+ }
+ return PlaceholderResolver.getDefaultResolver().resolveByMap(string, params);
+ }
+
+ private CmsMsgQueryReq build(GeneralMessageOldDataStatisticRequest request, List excludeMsgIds) {
+ UserTypeEnum userType = PersonIdentityUtil.toUserType(request.getIdentityType());
+ CmsMsgQueryReq req = new CmsMsgQueryReq();
+ req.setMsgType(MessageCategoryEnum.GENERAL_MESSAGE.getCode());
+ // 这里查询消息中心全部状态的数据
+ req.setMsgStatus(0);
+ req.setPage(1L);
+ req.setPageSize(1L);
+ req.setPersonId(request.getPersonId());
+ req.setIdentityId(request.getIdentityId());
+ req.setUserType(userType.getValue());
+ req.setExcludeMsgIds(excludeMsgIds);
+ return req;
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupNodeServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupNodeServiceImpl.java
new file mode 100644
index 00000000..97680abd
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupNodeServiceImpl.java
@@ -0,0 +1,168 @@
+package cn.axzo.msg.center.message.service.impl;
+
+import cn.axzo.basics.common.util.AssertUtil;
+import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
+import cn.axzo.msg.center.common.exception.ServiceException;
+import cn.axzo.msg.center.dal.MessageGroupNodeDao;
+import cn.axzo.msg.center.dal.MessageTemplateGroupDao;
+import cn.axzo.msg.center.domain.entity.MessageGroupNode;
+import cn.axzo.msg.center.domain.entity.MessageTemplateGroup;
+import cn.axzo.msg.center.message.domain.dto.GroupTreeNodePathDTO;
+import cn.axzo.msg.center.message.domain.param.MessageGroupNodeSaveOrUpdateParam;
+import cn.axzo.msg.center.message.service.MessageGroupNodeService;
+import cn.axzo.msg.center.message.service.MessageGroupTreeNodeCacheService;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
+import cn.axzo.msg.center.utils.TreeHelperUtil;
+import cn.axzo.msg.center.utils.UUIDUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class MessageGroupNodeServiceImpl implements MessageGroupNodeService {
+
+ private final MessageGroupNodeDao messageGroupNodeDao;
+ private final MessageTemplateGroupDao messageTemplateGroupDao;
+ private final MessageGroupTreeNodeCacheService messageGroupTreeNodeCacheService;
+
+ @Override
+ public Map groupNodeNamePaths(Collection groupNodeCodePaths) {
+ if (CollectionUtils.isEmpty(groupNodeCodePaths)) {
+ log.info("leafGroupNodeCodes is empty.");
+ return Collections.emptyMap();
+ }
+ return groupNodeCodePaths.stream()
+ .map(GroupTreeNodePathDTO::parseLeafNodeCode)
+ .map(messageGroupTreeNodeCacheService::queryLeafNodePath)
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(Collectors.toMap(GroupTreeNodePathDTO::getNodeCodePath,
+ GroupTreeNodePathDTO::getNodeNamePath, (cur, pre) -> cur));
+ }
+
+ @Override
+ public Map leafGroupNodeCodePaths(Collection leafGroupNodeCodes) {
+ if (CollectionUtils.isEmpty(leafGroupNodeCodes)) {
+ log.info("leafGroupNodeCodes is empty.");
+ return Collections.emptyMap();
+ }
+ return leafGroupNodeCodes.stream()
+ .map(messageGroupTreeNodeCacheService::queryLeafNodePath)
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(Collectors.toMap(GroupTreeNodePathDTO::getNodeCode,
+ GroupTreeNodePathDTO::getNodeCodePath, (cur, pre) -> cur));
+ }
+
+ @Override
+ public Optional queryRootNode(String rootNodeCode) {
+ return messageGroupTreeNodeCacheService.queryRootNode(rootNodeCode);
+ }
+
+ @Override
+ public void addGroupNode(MessageGroupNodeSaveOrUpdateParam param) {
+ GroupTreeNodeDTO parent = StringUtils.isBlank(param.getParentNodeCode()) ? null :
+ messageGroupTreeNodeCacheService.queryNode(param.getParentNodeCode())
+ .orElseThrow(() -> new ServiceException("parentNodeCode is invalid"));
+ // 合法性校验
+ checkCreateRule(parent, param);
+ // 存储
+ messageGroupNodeDao.save(convert(param));
+ // 刷新缓存
+ messageGroupTreeNodeCacheService.refreshCache();
+ }
+
+ @Override
+ public void updateGroupNode(MessageGroupNodeSaveOrUpdateParam param) {
+ boolean updateResult = messageGroupNodeDao.lambdaUpdate()
+ .eq(MessageGroupNode::getCode, param.getNodeCode())
+ .eq(MessageGroupNode::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .set(StringUtils.isNotBlank(param.getNodeName()), MessageGroupNode::getName, param.getNodeName())
+ .set(StringUtils.isNotBlank(param.getIcon()), MessageGroupNode::getIcon, param.getIcon())
+ .set(MessageGroupNode::getUpdaterId, param.getOperatorId())
+ .update();
+ if (updateResult) {
+ // 刷新缓存
+ messageGroupTreeNodeCacheService.refreshCache();
+ }
+ }
+
+ @Override
+ public void deleteGroupNode(Long operatorId, String nodeCode) {
+ if (Objects.isNull(operatorId) || StringUtils.isBlank(nodeCode)) {
+ log.info("the param is invalid. operatorId:[{}], nodeCode:[{}]", operatorId, nodeCode);
+ return;
+ }
+ // 合法性校验
+ checkDeleteRule(nodeCode);
+ // 删除结点
+ boolean removeResult = messageGroupNodeDao.lambdaUpdate()
+ .eq(MessageGroupNode::getCode, nodeCode)
+ .remove();
+ if (removeResult) {
+ // 刷新缓存
+ messageGroupTreeNodeCacheService.refreshCache();
+ }
+ }
+
+ @Override
+ public List listGroupTree(MessageCategoryEnum category) {
+ return messageGroupTreeNodeCacheService.listAllGroupTree().stream()
+ // 查询消息/待办 OR 两者的分类树
+ .filter(e -> Objects.isNull(category)
+ || Objects.equals(e.getCategory().getMsgCategory(), category))
+ .collect(Collectors.toList());
+ }
+
+ private MessageGroupNode convert(MessageGroupNodeSaveOrUpdateParam param) {
+ MessageGroupNode groupNode = new MessageGroupNode();
+ groupNode.setCode(UUIDUtil.uuidString());
+ groupNode.setName(param.getNodeName());
+ groupNode.setIcon(param.getIcon());
+ groupNode.setCategory(param.getCategory());
+ groupNode.setParentCode(param.getParentNodeCode());
+ groupNode.setCreatorId(param.getOperatorId());
+ groupNode.setUpdaterId(param.getOperatorId());
+ if (TreeHelperUtil.isLeafNodeCategory(param.getCategory())) {
+ groupNode.setIsLeaf(1);
+ }
+ return groupNode;
+ }
+
+ private void checkCreateRule(GroupTreeNodeDTO parent, MessageGroupNodeSaveOrUpdateParam param) {
+ if (Objects.nonNull(parent)) {
+ AssertUtil.isTrue(parent.getCategory().getLevel() < param.getCategory().getLevel(), "父节点的类型非法");
+ }
+ }
+
+ private void checkDeleteRule(String nodeCode) {
+ GroupTreeNodeDTO node = messageGroupTreeNodeCacheService.queryNode(nodeCode)
+ .orElseThrow(() -> new ServiceException(String.format("未找到指定的结点[%s]", nodeCode)));
+ // TODO: [cold_blade] [P2] 异常处理需要检查
+ AssertUtil.isEmpty(node.getNodeChildren(), "删除失败!删除前请删除子级!");
+ // 校验其结点是否被模板关联
+ int cnt = messageTemplateGroupDao.lambdaQuery()
+ .like(MessageTemplateGroup::getPath, nodeCode)
+ .eq(MessageTemplateGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .count();
+ AssertUtil.isTrue(cnt == 0, "删除失败!删除前请先转移消息模版!");
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupServiceImpl.java
deleted file mode 100644
index 0ca69898..00000000
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupServiceImpl.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package cn.axzo.msg.center.message.service.impl;
-
-import cn.axzo.msg.center.dal.MessageGroupNodeDao;
-import cn.axzo.msg.center.dal.MessageTemplateGroupDao;
-import cn.axzo.msg.center.domain.entity.MessageGroupNode;
-import cn.axzo.msg.center.domain.entity.MessageTemplateGroup;
-import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeDTO;
-import cn.axzo.msg.center.message.service.MessageGroupService;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.stereotype.Service;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-/**
- * @author cold_blade
- * @date 2023/10/6
- * @version 1.0
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class MessageGroupServiceImpl implements MessageGroupService {
-
- private final MessageGroupNodeDao messageGroupNodeDao;
- private final MessageTemplateGroupDao messageTemplateGroupDao;
-
- @Override
- public Optional queryByNodeCode(String nodeCode) {
- if (StringUtils.isBlank(nodeCode)) {
- return Optional.empty();
- }
- MessageGroupNode groupNode = messageGroupNodeDao.lambdaQuery()
- .eq(MessageGroupNode::getCode, nodeCode)
- .eq(MessageGroupNode::getIsDelete, 0)
- .one();
- return Optional.ofNullable(groupNode).map(MessageGroupNodeDTO::from);
- }
-
- @Override
- public List listChildren(String nodeCode) {
- return messageGroupNodeDao.lambdaQuery()
- .eq(MessageGroupNode::getParentCode, nodeCode)
- .eq(MessageGroupNode::getIsDelete, 0)
- .list().stream()
- .map(MessageGroupNodeDTO::from)
- .collect(Collectors.toList());
- }
-
- @Override
- public void templateGroup(String templateNode, Collection pathList) {
- if (StringUtils.isBlank(templateNode)
- || CollectionUtils.isEmpty(pathList)) {
- return;
- }
- List rows = pathList.stream()
- .map(e -> {
- MessageTemplateGroup group = new MessageTemplateGroup();
- group.setTemplateCode(templateNode);
- group.setPath(e);
- return group;
- }).collect(Collectors.toList());
- messageTemplateGroupDao.saveBatch(rows);
- }
-}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupTreeNodeCacheServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupTreeNodeCacheServiceImpl.java
new file mode 100644
index 00000000..fa06350e
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageGroupTreeNodeCacheServiceImpl.java
@@ -0,0 +1,193 @@
+package cn.axzo.msg.center.message.service.impl;
+
+import cn.axzo.basics.common.util.TreeUtil;
+import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
+import cn.axzo.msg.center.common.redis.RedisUtil;
+import cn.axzo.msg.center.dal.MessageGroupNodeDao;
+import cn.axzo.msg.center.domain.entity.MessageGroupNode;
+import cn.axzo.msg.center.message.domain.dto.GroupTreeNodePathDTO;
+import cn.axzo.msg.center.message.service.MessageGroupTreeNodeCacheService;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.compress.utils.Lists;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @author cold_blade
+ * @date 2023/10/14
+ * @version 1.0
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class MessageGroupTreeNodeCacheServiceImpl implements MessageGroupTreeNodeCacheService {
+
+ private static final String CACHE_KEY = "msg-center:message:group:cache-key";
+ private static final String CACHE_VALUE = "msg-center:message:group:cache-val";
+ private static final long CACHE_KEY_TIMEOUT_DAYS = 1;
+
+ private final RedisUtil redisUtil;
+ private final MessageGroupNodeDao messageGroupNodeDao;
+
+ private List allGroupTreesCache = Collections.emptyList();
+ private List leafTreeNodePathsCache = Collections.emptyList();
+
+ @Override
+ public List listAllGroupTree() {
+ return getAllGroupTreesCache();
+ }
+
+ @Override
+ public Optional queryRootNode(String rootNodeCode) {
+ if (StringUtils.isBlank(rootNodeCode)) {
+ log.info("rootNodeCode is blank.");
+ return Optional.empty();
+ }
+ return getAllGroupTreesCache().stream()
+ .filter(e -> Objects.equals(e.getNodeCode(), rootNodeCode))
+ .findFirst();
+ }
+
+ @Override
+ public Optional queryNode(String groupNodeCode) {
+ if (StringUtils.isBlank(groupNodeCode)) {
+ log.info("groupNodeCode is blank.");
+ return Optional.empty();
+ }
+ return getAllGroupTreesCache().stream()
+ .map(e -> findTreeNode(e, groupNodeCode))
+ .filter(Objects::nonNull)
+ .findFirst();
+ }
+
+ @Override
+ public Optional queryLeafNodePath(String leafNodeCode) {
+ if (StringUtils.isBlank(leafNodeCode)) {
+ log.info("leafNodeCode is blank.");
+ return Optional.empty();
+ }
+ return getLeafTreeNodePathsCache().stream()
+ .filter(e -> Objects.equals(e.getNodeCode(), leafNodeCode))
+ .findFirst();
+ }
+
+ @Override
+ public synchronized void refreshCache() {
+ // 清除redis中的缓存标识
+ redisUtil.getKeyOps().delete(CACHE_KEY);
+ // 本地缓存初始化并更新redis中的缓存标识
+ initialize(true);
+ }
+
+ private GroupTreeNodeDTO findTreeNode(GroupTreeNodeDTO root, String treeNodeCode) {
+ if (Objects.equals(root.getNodeCode(), treeNodeCode)) {
+ return root;
+ }
+ LinkedList queue = new LinkedList<>(root.getNodeChildren());
+ while (!queue.isEmpty()) {
+ GroupTreeNodeDTO node = queue.pop();
+ Optional childOp = node.getChild(treeNodeCode);
+ if (childOp.isPresent()) {
+ return childOp.get();
+ }
+ queue.addAll(node.getNodeChildren());
+ }
+ return null;
+ }
+
+ private List getAllGroupTreesCache() {
+ if (redisUtil.getKeyOps().hasKey(CACHE_KEY)) {
+ // 其它结点进行了本地缓存,但是当前服务进程还未进行缓存
+ if (CollectionUtils.isEmpty(allGroupTreesCache)) {
+ // 本地缓存初始化,不更新redis中的缓存标识
+ initialize(false);
+ }
+ } else {
+ // 本地缓存初始化并更新redis中的缓存标识
+ initialize(true);
+ }
+ return this.allGroupTreesCache;
+ }
+
+ private List getLeafTreeNodePathsCache() {
+ if (redisUtil.getKeyOps().hasKey(CACHE_KEY)) {
+ // 其它结点进行了本地缓存,但是当前服务进程还未进行缓存
+ if (leafTreeNodePathsCache.isEmpty()) {
+ // 本地缓存初始化,不更新redis中的缓存标识
+ initialize(false);
+ }
+ } else {
+ // 本地缓存初始化并更新redis中的缓存标识
+ initialize(true);
+ }
+ return leafTreeNodePathsCache;
+ }
+
+ private synchronized void initialize(boolean refreshCache) {
+ List groupNodes = listAllValidNodesFromDB();
+ allGroupTreesCache = TreeUtil.buildTree(groupNodes);
+ leafTreeNodePathsCache = allGroupTreesCache.stream()
+ .flatMap(e -> parseRootNode(e).stream())
+ .collect(Collectors.toList());
+ if (refreshCache) {
+ redisUtil.getStringOps().setIfAbsent(CACHE_KEY, CACHE_VALUE, CACHE_KEY_TIMEOUT_DAYS, TimeUnit.DAYS);
+ }
+ }
+
+ private List listAllValidNodesFromDB() {
+ return messageGroupNodeDao.lambdaQuery()
+ .eq(MessageGroupNode::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .list().stream()
+ .map(this::convert)
+ .collect(Collectors.toList());
+ }
+
+ private GroupTreeNodeDTO convert(MessageGroupNode groupNode) {
+ return GroupTreeNodeDTO.builder()
+ .nodeName(groupNode.getName())
+ .nodeCode(groupNode.getCode())
+ .category(groupNode.getCategory())
+ .parentNodeCode(groupNode.getParentCode())
+ .isLeaf(groupNode.getIsLeaf())
+ .status(groupNode.getStatus())
+ .build();
+ }
+
+ private List parseRootNode(GroupTreeNodeDTO root) {
+ List paths = Lists.newArrayList();
+ LinkedList pathNodeStack = new LinkedList<>();
+ LinkedList stack = new LinkedList<>();
+ stack.push(root);
+ while (!stack.isEmpty()) {
+ GroupTreeNodeDTO node = stack.pop();
+ pathNodeStack.push(node);
+ if (CollectionUtils.isEmpty(node.getNodeChildren())) {
+ // 当前结点为树的叶结点(逻辑上的,有可能不是业务维度的叶结点)
+ paths.add(GroupTreeNodePathDTO.of(node.getNodeCode(), reverseStack(pathNodeStack)));
+ pathNodeStack.pop();
+ } else {
+ stack.addAll(node.getNodeChildren());
+ }
+ }
+ return paths;
+ }
+
+ private List reverseStack(LinkedList pathNodeStack) {
+ List list = Lists.newArrayList();
+ for (GroupTreeNodeDTO node : pathNodeStack) {
+ list.add(0, node);
+ }
+ return list;
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageSendTwiceRecordServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageSendTwiceRecordServiceImpl.java
new file mode 100644
index 00000000..05c66a8a
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageSendTwiceRecordServiceImpl.java
@@ -0,0 +1,60 @@
+package cn.axzo.msg.center.message.service.impl;
+
+import cn.axzo.msg.center.dal.MessageSendTwiceRecordDao;
+import cn.axzo.msg.center.domain.entity.MessageSendTwiceRecord;
+import cn.axzo.msg.center.message.service.MessageSendTwiceRecordService;
+import cn.hutool.core.map.MapUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @description xxx
+ * @author cold_blade
+ * @date 2023/10/23
+ * @version 1.0
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class MessageSendTwiceRecordServiceImpl implements MessageSendTwiceRecordService {
+
+ private final MessageSendTwiceRecordDao messageSendTwiceRecordDao;
+
+ @Override
+ public List listByPerson(Long personId) {
+ if (Objects.isNull(personId)) {
+ log.info("personId is null.");
+ return Collections.emptyList();
+ }
+ return messageSendTwiceRecordDao.lambdaQuery()
+ .eq(MessageSendTwiceRecord::getReceiverPersonId, personId)
+ .last("LIMIT 500")
+ .orderByDesc(MessageSendTwiceRecord::getId)
+ .select(MessageSendTwiceRecord::getOriginalMsgId)
+ .list().stream()
+ .map(MessageSendTwiceRecord::getOriginalMsgId)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void batchSave(Map msgRecordIdPersonIdMap) {
+ if (MapUtil.isEmpty(msgRecordIdPersonIdMap)) {
+ return;
+ }
+ List records = msgRecordIdPersonIdMap.entrySet().stream()
+ .map(e -> {
+ MessageSendTwiceRecord record = new MessageSendTwiceRecord();
+ record.setReceiverPersonId(e.getValue());
+ record.setOriginalMsgId(e.getKey());
+ return record;
+ }).collect(Collectors.toList());
+ messageSendTwiceRecordDao.saveBatch(records);
+ }
+}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateGroupServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateGroupServiceImpl.java
index cfcd1b34..d7d1045d 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateGroupServiceImpl.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateGroupServiceImpl.java
@@ -1,15 +1,26 @@
package cn.axzo.msg.center.message.service.impl;
+import cn.axzo.basics.common.util.AssertUtil;
+import cn.axzo.framework.core.util.MapUtil;
+import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
import cn.axzo.msg.center.dal.MessageTemplateGroupDao;
import cn.axzo.msg.center.domain.entity.MessageTemplateGroup;
+import cn.axzo.msg.center.message.service.MessageGroupNodeService;
import cn.axzo.msg.center.message.service.MessageTemplateGroupService;
+import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
import java.util.stream.Collectors;
/**
@@ -22,6 +33,7 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class MessageTemplateGroupServiceImpl implements MessageTemplateGroupService {
+ private final MessageGroupNodeService messageGroupNodeService;
private final MessageTemplateGroupDao messageTemplateGroupDao;
@Override
@@ -37,4 +49,138 @@ public class MessageTemplateGroupServiceImpl implements MessageTemplateGroupServ
.map(MessageTemplateGroup::getTemplateCode)
.collect(Collectors.toList());
}
+
+ @Override
+ public void templateGroup(String templateNode, Collection groupNodeCodes) {
+ if (StringUtils.isBlank(templateNode)
+ || CollectionUtils.isEmpty(groupNodeCodes)) {
+ log.info("the param is invalid. templateNode:[{}], groupNodeCodes:{}", templateNode, groupNodeCodes);
+ return;
+ }
+ Map pathMap = messageGroupNodeService.leafGroupNodeCodePaths(groupNodeCodes);
+ List rows = groupNodeCodes.stream()
+ .filter(pathMap::containsKey)
+ .map(e -> {
+ MessageTemplateGroup group = new MessageTemplateGroup();
+ group.setTemplateCode(templateNode);
+ group.setPath(pathMap.get(e));
+ return group;
+ }).collect(Collectors.toList());
+ messageTemplateGroupDao.saveBatch(rows);
+ }
+
+ @Override
+ public void templateGroup(Map> templateGroupMap) {
+ if (MapUtil.isEmpty(templateGroupMap)) {
+ log.info("the templateGroupMap is empty.");
+ return;
+ }
+ Set groupNodes = templateGroupMap.values().stream()
+ .flatMap(Collection::stream)
+ .collect(Collectors.toSet());
+ Map pathMap = messageGroupNodeService.leafGroupNodeCodePaths(groupNodes);
+ List rows = templateGroupMap.entrySet().stream()
+ .flatMap(e -> e.getValue().stream()
+ .filter(pathMap::containsKey)
+ .map(nodeCode -> {
+ MessageTemplateGroup group = new MessageTemplateGroup();
+ group.setTemplateCode(e.getKey());
+ group.setPath(pathMap.get(nodeCode));
+ return group;
+ })
+ ).collect(Collectors.toList());
+ messageTemplateGroupDao.saveBatch(rows);
+ }
+
+ @Override
+ public void updateTemplateGroup(String templateNode, Collection groupNodeCodes) {
+ // 先解除之前的关联关系
+ deleteTemplateGroup(templateNode);
+ // 构建新的关联关系
+ templateGroup(templateNode, groupNodeCodes);
+ }
+
+ @Override
+ public void deleteTemplateGroup(String templateNode) {
+ if (StringUtils.isBlank(templateNode)) {
+ log.info("the templateNode is blank.");
+ return;
+ }
+ messageTemplateGroupDao.lambdaUpdate()
+ .eq(MessageTemplateGroup::getTemplateCode, templateNode)
+ .remove();
+ }
+
+ @Override
+ public Map> listMessageTemplateGroupPaths(Collection templateCodes) {
+ if (CollectionUtils.isEmpty(templateCodes)) {
+ return Collections.emptyMap();
+ }
+ return messageTemplateGroupDao.lambdaQuery()
+ .in(MessageTemplateGroup::getTemplateCode, templateCodes)
+ .eq(MessageTemplateGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .list().stream()
+ .collect(Collectors.groupingBy(MessageTemplateGroup::getTemplateCode,
+ Collectors.mapping(MessageTemplateGroup::getPath, Collectors.toList())));
+ }
+
+ @Override
+ public void remove(String curGroupNodeCode, Collection templateCodes) {
+ // 参数校验
+ AssertUtil.isTrue(StringUtils.isNotBlank(curGroupNodeCode), "curGroupNodeCode can not be blank");
+ AssertUtil.notEmpty(templateCodes, "templateCodes can not be empty");
+ // 通过分类结点编码获取其对应的结点编码的路径
+ Map nodeCodePathMap = messageGroupNodeService
+ .leafGroupNodeCodePaths(Lists.newArrayList(curGroupNodeCode));
+ // 通过能否成功获取到其树路径来校验其有效性
+ AssertUtil.isFalse(nodeCodePathMap.isEmpty(), "curGroupNodeCode is invalid");
+ // 统计指定的模板编码关联的分类数量
+ Map templateCodeList = messageTemplateGroupDao.lambdaQuery()
+ .in(MessageTemplateGroup::getTemplateCode, templateCodes)
+ .eq(MessageTemplateGroup::getPath, nodeCodePathMap.get(curGroupNodeCode))
+ .eq(MessageTemplateGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ // 这里仅查询模板编码字段即可
+ .select(MessageTemplateGroup::getTemplateCode)
+ .list().stream()
+ .map(MessageTemplateGroup::getTemplateCode)
+ // 内存中来做groupingBy操作
+ .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
+ // 筛选出仅关联了一个分类的模板编码
+ List onlyContainsOneTemplateCodes = templateCodeList.entrySet().stream()
+ .filter(e -> Objects.equals(e.getValue(), 1L))
+ .map(Map.Entry::getKey)
+ .collect(Collectors.toList());
+ AssertUtil.isEmpty(onlyContainsOneTemplateCodes, removeErrorStr(onlyContainsOneTemplateCodes));
+ // 解除关联关系
+ messageTemplateGroupDao.lambdaUpdate()
+ .in(MessageTemplateGroup::getTemplateCode, templateCodes)
+ .eq(MessageTemplateGroup::getPath, nodeCodePathMap.get(curGroupNodeCode))
+ .remove();
+ }
+
+ @Override
+ public void move(String srcGroupNodeCode, String tgtGroupNodeCode, Collection templateCodes) {
+ // 参数校验
+ AssertUtil.isTrue(StringUtils.isNotBlank(srcGroupNodeCode), "srcGroupNodeCode can not be blank");
+ AssertUtil.isTrue(StringUtils.isNotBlank(tgtGroupNodeCode), "tgtGroupNodeCode can not be blank");
+ AssertUtil.notEmpty(templateCodes, "templateCodes can not be empty");
+ // 通过分类结点编码获取其对应的结点编码的路径
+ Map nodeCodePathMap = messageGroupNodeService
+ .leafGroupNodeCodePaths(Lists.newArrayList(srcGroupNodeCode, tgtGroupNodeCode));
+ // 通过能否成功获取到其树路径来校验其有效性
+ AssertUtil.isTrue(StringUtils.isNotBlank(nodeCodePathMap.get(srcGroupNodeCode)), "srcGroupNodeCode is invalid");
+ AssertUtil.isTrue(StringUtils.isNotBlank(nodeCodePathMap.get(tgtGroupNodeCode)), "tgtGroupNodeCode is invalid");
+ // 更新分类路径与模板编码的映射关系
+ messageTemplateGroupDao.lambdaUpdate()
+ .eq(MessageTemplateGroup::getPath, nodeCodePathMap.get(srcGroupNodeCode))
+ .in(MessageTemplateGroup::getTemplateCode, templateCodes)
+ .eq(MessageTemplateGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .set(MessageTemplateGroup::getPath, nodeCodePathMap.get(tgtGroupNodeCode))
+ .update();
+ }
+
+ private String removeErrorStr(List onlyContainsOneTemplateCodes) {
+ return String.format("模板:%s。解除关联后,将无关联分类!本次操作无效!",
+ String.join("、", onlyContainsOneTemplateCodes));
+ }
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java
index 5a149989..5191441d 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateNewServiceImpl.java
@@ -1,19 +1,42 @@
package cn.axzo.msg.center.message.service.impl;
-import cn.axzo.core.utils.converter.BeanConverter;
+import cn.axzo.basics.common.util.AssertUtil;
+import cn.axzo.msg.center.common.enums.ServiceErrorCodeEnum;
+import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
+import cn.axzo.msg.center.common.redis.RedisUtil;
+import cn.axzo.msg.center.common.utils.PageHelperUtil;
import cn.axzo.msg.center.dal.MessageBaseTemplateDao;
import cn.axzo.msg.center.domain.entity.MessageBaseTemplate;
+import cn.axzo.msg.center.message.domain.dto.GroupTreeNodePathDTO;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO;
import cn.axzo.msg.center.message.domain.dto.RawMessageRouterDTO;
-import cn.axzo.msg.center.message.domain.param.MessageTemplateCreateParam;
+import cn.axzo.msg.center.message.domain.param.MessageTemplateSaveOrUpdateParam;
+import cn.axzo.msg.center.message.service.MessageGroupNodeService;
+import cn.axzo.msg.center.message.service.MessageTemplateGroupService;
import cn.axzo.msg.center.message.service.MessageTemplateNewService;
import cn.axzo.msg.center.message.service.MessageTemplateRouterService;
+import cn.axzo.msg.center.service.dto.MessageBaseTemplateDTO;
+import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
+import cn.axzo.msg.center.service.dto.MessageRouterButtonDTO;
+import cn.axzo.msg.center.service.enums.PushTerminalEnum;
+import cn.axzo.msg.center.service.enums.StatusEnum;
+import cn.axzo.msg.center.service.template.request.MessageTemplatePageRequest;
+import cn.axzo.msg.center.service.template.response.MessageTemplateDetailResponse;
+import cn.axzo.msg.center.service.template.response.MessageTemplatePageResponse;
+import cn.axzo.msg.center.utils.JSONObjectUtil;
+import cn.axzo.msg.center.utils.UUIDUtil;
+import cn.azxo.framework.common.model.Page;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -33,19 +56,73 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class MessageTemplateNewServiceImpl implements MessageTemplateNewService {
+ private static final String SAVE_TEMPLATE_MUTEX_KEY = "msg-center:template:save:%s";
+ private static final long TRY_LOCK_TIMEOUT_MILLS = 1000;
+ private static final int RETRY_CNT_MAX = 3;
+
+ private static final int MAX_NUM_ONCE_QUERY = 1000;
+
+ private final RedisUtil redisUtil;
private final MessageBaseTemplateDao messageBaseTemplateDao;
+ private final MessageGroupNodeService messageGroupNodeService;
+ private final MessageTemplateGroupService messageTemplateGroupService;
private final MessageTemplateRouterService messageTemplateRouterService;
@Override
- public void createTemplate(MessageTemplateCreateParam param) {
- // TODO: [cold_blade] [P2] 模板与分类的关系
- messageBaseTemplateDao.save(convert(param));
- if (CollectionUtils.isNotEmpty(param.getRouters())) {
- List routers = param.getRouters().stream()
- .map(e -> RawMessageRouterDTO.from(e, param.getTemplateCode()))
- .collect(Collectors.toList());
- messageTemplateRouterService.batchInsert(routers);
+ @Transactional(rollbackFor = Exception.class)
+ public String createTemplate(MessageTemplateSaveOrUpdateParam param) {
+ // 创建模板基础数据
+ String templateCode = saveTemplate(param);
+ // 创建模板的路由数据
+ saveTemplateRouters(param, templateCode);
+ // 创建模板与分类的关联关系数据
+ messageTemplateGroupService.templateGroup(templateCode, param.getLeafGroupNodes());
+ return templateCode;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateTemplate(MessageTemplateSaveOrUpdateParam param) {
+ // 更新模板基础数据
+ updateBaseTemplate(param);
+ // 更新模板分类信息
+ updateTemplateGroupRelation(param);
+ // 更新模板路由信息
+ updateTemplateRouters(param);
+ }
+
+ @Override
+ public MessageTemplateDetailResponse detail(String templateCode) {
+ if (StringUtils.isBlank(templateCode)) {
+ return null;
}
+ MessageBaseTemplate baseTemplate = messageBaseTemplateDao.lambdaQuery()
+ .eq(MessageBaseTemplate::getCode, templateCode)
+ .eq(MessageBaseTemplate::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .one();
+ if (Objects.isNull(baseTemplate)) {
+ log.info("there is not any template match the templateCode:[{}]", templateCode);
+ return null;
+ }
+ // 获取模板关联分类的path列表
+ List groupNodePaths = messageTemplateGroupService.listMessageTemplateGroupPaths(
+ Lists.newArrayList(templateCode)).getOrDefault(templateCode, Collections.emptyList());
+ List routers = messageTemplateRouterService.queryByTemplateCode(templateCode);
+ return convert(baseTemplate, groupNodePaths, routers);
+ }
+
+ @Override
+ public void updateStatus(Long operatorId, String templateCode, StatusEnum status) {
+ if (Objects.isNull(operatorId) || StringUtils.isBlank(templateCode) || Objects.isNull(status)) {
+ log.info("the param is invalid. operatorId:[{}], code:[{}], status:[{}]", operatorId, templateCode, status);
+ return;
+ }
+ messageBaseTemplateDao.lambdaUpdate()
+ .eq(MessageBaseTemplate::getCode, templateCode)
+ .eq(MessageBaseTemplate::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .set(MessageBaseTemplate::getStatus, status)
+ .set(MessageBaseTemplate::getUpdaterId, operatorId)
+ .update();
}
@Override
@@ -87,12 +164,256 @@ public class MessageTemplateNewServiceImpl implements MessageTemplateNewService
.collect(Collectors.toList());
}
- private MessageBaseTemplate convert(MessageTemplateCreateParam param) {
- MessageBaseTemplate template = BeanConverter.convert(param, MessageBaseTemplate.class);
+ @Override
+ public Page page(MessageTemplatePageRequest request) {
+ List templateCodes = Lists.newArrayList();
+ if (StringUtils.isNotBlank(request.getGroupNodeCode())) {
+ templateCodes = messageTemplateGroupService.listMessageTemplateCodes(request.getGroupNodeCode());
+ if (CollectionUtils.isEmpty(templateCodes)) {
+ // 入参中的分类没有关联任何模板,直接返回查询结果
+ return PageHelperUtil.emptyPage(request.getPage(), request.getPageSize());
+ }
+ }
+ if (StringUtils.isNotBlank(request.getTemplateCode())) {
+ if (CollectionUtils.isNotEmpty(templateCodes)
+ && !templateCodes.contains(request.getTemplateCode())) {
+ // 分页查询的入参中没指定的模板编码与分类映射的模板编码无交集
+ return PageHelperUtil.emptyPage(request.getPage(), request.getPageSize());
+ }
+ // 取两者的交集
+ templateCodes = Lists.newArrayList(request.getTemplateCode());
+ }
+ IPage pageRequest = request.toPage();
+ IPage result = messageBaseTemplateDao.lambdaQuery()
+ .like(StringUtils.isNotBlank(request.getTemplateName()),
+ MessageBaseTemplate::getName, request.getTemplateName())
+ .in(CollectionUtils.isNotEmpty(templateCodes),
+ MessageBaseTemplate::getCode, request.getTemplateCode())
+ .eq(Objects.nonNull(request.getCategory()), MessageBaseTemplate::getMsgCategory, request.getCategory())
+ .eq(Objects.nonNull(request.getStatus()), MessageBaseTemplate::getStatus, request.getStatus())
+ .page(pageRequest);
+ if (CollectionUtils.isEmpty(result.getRecords())) {
+ return PageHelperUtil.emptyPage(request.getPage(), request.getPageSize());
+ }
+ templateCodes = result.getRecords().stream().map(MessageBaseTemplate::getCode).collect(Collectors.toList());
+ Map> groupNodePaths = messageTemplateGroupService
+ .listMessageTemplateGroupPaths(templateCodes);
+ Map codeNameMap = messageGroupNodeService.groupNodeNamePaths(groupNodePaths.values().stream()
+ .flatMap(Collection::stream).collect(Collectors.toList()));
+ List records = result.getRecords().stream()
+ .map(e -> convert(e, groupNodePaths, codeNameMap))
+ .collect(Collectors.toList());
+ return Page.toPage(request.getPage(), request.getPageSize(), result.getTotal(), records);
+ }
+
+ @Override
+ public Page pageBaseTemplate(MessageTemplatePageRequest request) {
+ List templateCodes = Lists.newArrayList();
+ if (StringUtils.isNotBlank(request.getGroupNodeCode())) {
+ templateCodes = messageTemplateGroupService.listMessageTemplateCodes(request.getGroupNodeCode());
+ if (CollectionUtils.isEmpty(templateCodes)) {
+ // 入参中的分类没有关联任何模板,直接返回查询结果
+ return PageHelperUtil.emptyPage(request.getPage(), request.getPageSize());
+ }
+ }
+ if (StringUtils.isNotBlank(request.getTemplateCode())) {
+ if (CollectionUtils.isNotEmpty(templateCodes)
+ && !templateCodes.contains(request.getTemplateCode())) {
+ // 分页查询的入参中没指定的模板编码与分类映射的模板编码无交集
+ return PageHelperUtil.emptyPage(request.getPage(), request.getPageSize());
+ }
+ // 取两者的交集
+ templateCodes = Lists.newArrayList(request.getTemplateCode());
+ }
+ IPage pageRequest = request.toPage();
+ IPage result = messageBaseTemplateDao.lambdaQuery()
+ .like(StringUtils.isNotBlank(request.getTemplateName()),
+ MessageBaseTemplate::getName, request.getTemplateName())
+ .in(CollectionUtils.isNotEmpty(templateCodes),
+ MessageBaseTemplate::getCode, request.getTemplateCode())
+ .eq(Objects.nonNull(request.getCategory()), MessageBaseTemplate::getMsgCategory, request.getCategory())
+ .eq(Objects.nonNull(request.getStatus()), MessageBaseTemplate::getStatus, request.getStatus())
+ .page(pageRequest);
+ if (CollectionUtils.isEmpty(result.getRecords())) {
+ return PageHelperUtil.emptyPage(request.getPage(), request.getPageSize());
+ }
+ List records = result.getRecords().stream()
+ .map(this::convert)
+ .collect(Collectors.toList());
+ return Page.toPage(request.getPage(), request.getPageSize(), result.getTotal(), records);
+ }
+
+ @Override
+ public List listByCodes(Collection templateCodes) {
+ if (CollectionUtils.isEmpty(templateCodes)) {
+ log.info("the templateCodes is empty.");
+ return Collections.emptyList();
+ }
+ AssertUtil.isTrue(templateCodes.size() <= MAX_NUM_ONCE_QUERY, "the collection of templateCodes is too large");
+ // 查询模板基础数据
+ List records = messageBaseTemplateDao.lambdaQuery()
+ .in(MessageBaseTemplate::getCode, templateCodes)
+ .eq(MessageBaseTemplate::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .list();
+ // 查询模板的分类结点编码path
+ templateCodes = records.stream().map(MessageBaseTemplate::getCode).collect(Collectors.toList());
+ Map> groupNodePaths = messageTemplateGroupService
+ .listMessageTemplateGroupPaths(templateCodes);
+ // 将模板分类结点编码path转化为分类名称path
+ Map codeNameMap = messageGroupNodeService.groupNodeNamePaths(groupNodePaths.values().stream()
+ .flatMap(Collection::stream).collect(Collectors.toList()));
+ // 转化为页面展示的数据模型
+ return records.stream()
+ .map(e -> convert(e, groupNodePaths, codeNameMap))
+ .collect(Collectors.toList());
+ }
+
+ private String saveTemplate(MessageTemplateSaveOrUpdateParam param) {
+ String templateCode = UUIDUtil.uuidString();
+ MessageBaseTemplate template = convert(param);
+ boolean result = doSaveTemplate(template, templateCode);
+ int retryCnt = 0;
+ while (!result && retryCnt++ < RETRY_CNT_MAX) {
+ // 默认重试{@cod RETRY_CNT_MAX}次,若{@code RETRY_CNT_MAX}次后依然失败就报错
+ templateCode = UUIDUtil.uuidString();
+ result = doSaveTemplate(template, templateCode);
+ }
+ AssertUtil.isTrue(result, ServiceErrorCodeEnum.SYSTEM_BUSY.getDesc());
+ return templateCode;
+ }
+
+ private boolean doSaveTemplate(MessageBaseTemplate template, String templateCode) {
+ String requestId = UUIDUtil.uuidRawString();
+ try {
+ String opKey = String.format(SAVE_TEMPLATE_MUTEX_KEY, templateCode);
+ boolean lockResult = redisUtil.getLockOps().getLockUntilTimeout(opKey, requestId, TRY_LOCK_TIMEOUT_MILLS);
+ AssertUtil.isTrue(lockResult, ServiceErrorCodeEnum.SYSTEM_BUSY.getDesc());
+ if (isTemplateExist(templateCode)) {
+ return false;
+ }
+ template.setCode(templateCode);
+ messageBaseTemplateDao.save(template);
+ return true;
+ } finally {
+ redisUtil.getLockOps().releaseLock(SAVE_TEMPLATE_MUTEX_KEY, requestId);
+ }
+ }
+
+ private boolean isTemplateExist(String templateCode) {
+ return messageBaseTemplateDao.lambdaQuery()
+ .eq(MessageBaseTemplate::getCode, templateCode)
+ .eq(MessageBaseTemplate::getIsDelete, 0)
+ .count() > 0;
+ }
+
+ private MessageBaseTemplate convert(MessageTemplateSaveOrUpdateParam param) {
+ MessageBaseTemplate template = new MessageBaseTemplate();
template.setName(param.getTemplateName());
- template.setCode(param.getTemplateCode());
+ template.setMsgCategory(param.getMsgCategory());
+ template.setTitle(param.getTitle());
+ template.setContent(param.getContent());
+ template.setCardContent(JSONObjectUtil.toJSONString(param.getMsgCardContentItems()));
+ template.setIcon(param.getIcon());
+ template.setPushTerminal(JSONObjectUtil.toJSONString(param.getPushTerminals()));
template.setCreatorId(param.getOperatorId());
template.setUpdaterId(param.getOperatorId());
return template;
}
+
+ private void saveTemplateRouters(MessageTemplateSaveOrUpdateParam param, String templateCode) {
+ if (CollectionUtils.isEmpty(param.getRouters())) {
+ return;
+ }
+ List routers = param.getRouters().stream()
+ .map(e -> RawMessageRouterDTO.from(e, templateCode))
+ .collect(Collectors.toList());
+ messageTemplateRouterService.batchInsert(routers);
+ }
+
+ private void updateBaseTemplate(MessageTemplateSaveOrUpdateParam param) {
+ messageBaseTemplateDao.lambdaUpdate()
+ .eq(MessageBaseTemplate::getCode, param.getTemplateCode())
+ .eq(MessageBaseTemplate::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .set(MessageBaseTemplate::getUpdaterId, param.getOperatorId())
+ .set(StringUtils.isNotBlank(param.getTemplateName()), MessageBaseTemplate::getName,
+ param.getTemplateName())
+ .set(CollectionUtils.isNotEmpty(param.getPushTerminals()), MessageBaseTemplate::getPushTerminal,
+ JSON.toJSONString(param.getPushTerminals()))
+ .set(StringUtils.isNotBlank(param.getTitle()), MessageBaseTemplate::getTitle, param.getTitle())
+ .set(CollectionUtils.isNotEmpty(param.getMsgCardContentItems()), MessageBaseTemplate::getCardContent,
+ JSONObjectUtil.toJSONString(param.getMsgCardContentItems()))
+ .set(StringUtils.isNotBlank(param.getContent()), MessageBaseTemplate::getContent, param.getContent())
+ .set(StringUtils.isNotBlank(param.getIcon()), MessageBaseTemplate::getIcon, param.getIcon())
+ .update();
+ }
+
+ private void updateTemplateGroupRelation(MessageTemplateSaveOrUpdateParam param) {
+ if (CollectionUtils.isEmpty(param.getLeafGroupNodes())) {
+ return;
+ }
+ messageTemplateGroupService.updateTemplateGroup(param.getTemplateCode(), param.getLeafGroupNodes());
+ }
+
+ private void updateTemplateRouters(MessageTemplateSaveOrUpdateParam param) {
+ if (CollectionUtils.isEmpty(param.getRouters())) {
+ return;
+ }
+ messageTemplateRouterService.updateTemplateRoutes(param.getTemplateCode(), param.getRouters());
+ }
+
+ private MessageBaseTemplateDTO convert(MessageBaseTemplate record) {
+ return MessageBaseTemplateDTO.builder()
+ .name(record.getName())
+ .code(record.getCode())
+ .msgCategory(record.getMsgCategory())
+ .title(record.getTitle())
+ .content(record.getContent())
+ .cardContentItems(JSONObjectUtil.parseArray(record.getCardContent(), MessageCardContentItemDTO.class))
+ .icon(record.getIcon())
+ .pushTerminals(JSON.parseArray(record.getPushTerminal(), PushTerminalEnum.class))
+ .createTimestamp(record.getCreateAt().getTime())
+ .build();
+ }
+
+ private MessageTemplatePageResponse convert(MessageBaseTemplate record, Map> groupNodePaths,
+ Map codeNameMap) {
+ MessageTemplatePageResponse response = new MessageTemplatePageResponse();
+ response.setTemplateName(record.getName());
+ response.setTemplateCode(record.getCode());
+ response.setTitle(record.getTitle());
+ response.setContent(record.getContent());
+ response.setCategory(record.getMsgCategory());
+ response.setStatus(record.getStatus());
+ List nodeNamePaths = groupNodePaths.getOrDefault(record.getCode(), Collections.emptyList()).stream()
+ .filter(codeNameMap::containsKey)
+ .map(codeNameMap::get)
+ .collect(Collectors.toList());
+ response.setGroupNodeNamePaths(nodeNamePaths);
+ return response;
+ }
+
+ private MessageTemplateDetailResponse convert(MessageBaseTemplate record, List groupNodePaths,
+ List routers) {
+ // 将path解析中解析出分类结点(路径叶结点)的编码
+ List groupNodeCodes = groupNodePaths.stream()
+ .map(GroupTreeNodePathDTO::parseLeafNodeCode)
+ .collect(Collectors.toList());
+ // 转化为页面相关的数据模型
+ List routerButtons = routers.stream()
+ .map(RawMessageRouterDTO::toMessageRouterButton)
+ .collect(Collectors.toList());
+ return MessageTemplateDetailResponse.builder()
+ .templateName(record.getName())
+ .category(record.getMsgCategory())
+ .leafGroupNodes(groupNodeCodes)
+ .pushTerminals(JSON.parseArray(record.getPushTerminal(), PushTerminalEnum.class))
+ .msgTitle(record.getTitle())
+ .msgContent(record.getContent())
+ .cardContentItems(JSONObjectUtil.parseArray(record.getCardContent(), MessageCardContentItemDTO.class))
+ .msgIcon(record.getIcon())
+ .routers(routerButtons)
+ .createTimestamp(record.getCreateAt().getTime())
+ .updateTimestamp(record.getUpdateAt().getTime())
+ .build();
+ }
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateRouterServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateRouterServiceImpl.java
index 8a0ca09d..bab7e237 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateRouterServiceImpl.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/MessageTemplateRouterServiceImpl.java
@@ -4,6 +4,7 @@ import cn.axzo.msg.center.dal.MessageTemplateRouterDao;
import cn.axzo.msg.center.domain.entity.MessageTemplateRouter;
import cn.axzo.msg.center.message.domain.dto.RawMessageRouterDTO;
import cn.axzo.msg.center.message.service.MessageTemplateRouterService;
+import cn.axzo.msg.center.service.dto.MessageRouterButtonDTO;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -36,9 +37,7 @@ public class MessageTemplateRouterServiceImpl implements MessageTemplateRouterSe
log.warn("the template code is blank.");
return Collections.emptyList();
}
- return messageTemplateRouterDao.listByTemplateCode(Lists.newArrayList(templateCode)).stream()
- .map(RawMessageRouterDTO::from)
- .collect(Collectors.toList());
+ return listByTemplateCodes(Lists.newArrayList(templateCode));
}
@Override
@@ -47,18 +46,49 @@ public class MessageTemplateRouterServiceImpl implements MessageTemplateRouterSe
return;
}
List messageTemplateRouters = routers.stream()
- .map(RawMessageRouterDTO::toMessageTemplateRouter)
+ .flatMap(e -> e.toMessageTemplateRouters().stream())
.collect(Collectors.toList());
messageTemplateRouterDao.saveBatch(messageTemplateRouters);
}
+ @Override
+ public void updateTemplateRoutes(String templateCode, List routers) {
+ if (StringUtils.isBlank(templateCode)
+ || CollectionUtils.isEmpty(routers)) {
+ log.info("the param is invalid. templateCode:[{}], routers:{}", templateCode, routers);
+ return;
+ }
+ // 移除之前的路由信息
+ messageTemplateRouterDao.lambdaUpdate()
+ .eq(MessageTemplateRouter::getTemplateCode, templateCode)
+ .remove();
+ // 创建信息的路由信息
+ List newRouters = routers.stream()
+ .map(e -> RawMessageRouterDTO.from(e, templateCode))
+ .collect(Collectors.toList());
+ batchInsert(newRouters);
+ }
+
@Override
public Map> groupByTemplateCode(List templateCodes) {
if (CollectionUtils.isEmpty(templateCodes)) {
return Collections.emptyMap();
}
- return messageTemplateRouterDao.listByTemplateCode(templateCodes).stream()
- .map(RawMessageRouterDTO::from)
+ return listByTemplateCodes(templateCodes).stream()
.collect(Collectors.groupingBy(RawMessageRouterDTO::getTemplateCode));
}
+
+ private List listByTemplateCodes(List templateCodes) {
+ // 根据模板编码进行分组
+ Map> routers = messageTemplateRouterDao
+ .listByTemplateCode(templateCodes).stream()
+ .collect(Collectors.groupingBy(MessageTemplateRouter::getTemplateCode));
+ return routers.values().stream()
+ .flatMap(e -> {
+ // 模板路由的按钮维度
+ Map> btnMap = e.stream()
+ .collect(Collectors.groupingBy(MessageTemplateRouter::getName));
+ return btnMap.values().stream().map(RawMessageRouterDTO::from);
+ }).collect(Collectors.toList());
+ }
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/PendingMessageNewServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/PendingMessageNewServiceImpl.java
index 079a52d6..7253c6b6 100644
--- a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/PendingMessageNewServiceImpl.java
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/PendingMessageNewServiceImpl.java
@@ -1,21 +1,21 @@
package cn.axzo.msg.center.message.service.impl;
-import cn.axzo.core.utils.converter.BeanConverter;
import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
import cn.axzo.msg.center.common.exception.ServiceException;
import cn.axzo.msg.center.common.utils.PlaceholderResolver;
import cn.axzo.msg.center.dal.PendingMessageRecordDao;
import cn.axzo.msg.center.domain.entity.PendingMessageRecord;
-import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeDTO;
+import cn.axzo.msg.center.message.domain.dto.MessageGroupNodeStatisticDTO;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO;
import cn.axzo.msg.center.message.domain.dto.PendingMessageDTO;
import cn.axzo.msg.center.message.domain.dto.RawMessageRouterDTO;
import cn.axzo.msg.center.message.domain.param.MessageGroupNodeStatisticParam;
import cn.axzo.msg.center.message.domain.param.PendingMessagePushParam;
-import cn.axzo.msg.center.message.service.MessageGroupService;
+import cn.axzo.msg.center.message.service.MessageGroupNodeService;
import cn.axzo.msg.center.message.service.MessageTemplateGroupService;
import cn.axzo.msg.center.message.service.MessageTemplateNewService;
import cn.axzo.msg.center.message.service.PendingMessageNewService;
+import cn.axzo.msg.center.service.dto.GroupTreeNodeDTO;
import cn.axzo.msg.center.service.dto.IdentityDTO;
import cn.axzo.msg.center.service.dto.MessageRouterDTO;
import cn.axzo.msg.center.service.dto.PersonDTO;
@@ -27,11 +27,14 @@ import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
import cn.axzo.msg.center.service.pending.request.PendingMessagePageRequest;
import cn.axzo.msg.center.service.pending.response.PendingMessageResponse;
+import cn.axzo.msg.center.utils.JSONObjectUtil;
import cn.axzo.msg.center.utils.MessageRouterUtil;
import cn.axzo.msg.center.utils.OrderFieldParseUtil;
+import cn.axzo.msg.center.utils.TreeHelperUtil;
import cn.axzo.msg.center.utils.UUIDUtil;
import cn.azxo.framework.common.model.Page;
import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
@@ -44,10 +47,10 @@ import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.Stack;
import java.util.stream.Collectors;
/**
@@ -62,13 +65,13 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class PendingMessageNewServiceImpl implements PendingMessageNewService {
- private final MessageGroupService messageGroupService;
private final PendingMessageRecordDao pendingMessageRecordDao;
+ private final MessageGroupNodeService messageGroupNodeService;
private final MessageTemplateNewService messageTemplateNewService;
private final MessageTemplateGroupService messageTemplateGroupService;
@Override
- public List groupStatistic(MessageGroupNodeStatisticParam param) {
+ public List groupStatistic(MessageGroupNodeStatisticParam param) {
return param.getGroupNodeCodes().stream()
.flatMap(e -> statistic(e, param).stream())
.collect(Collectors.toList());
@@ -169,19 +172,20 @@ public class PendingMessageNewServiceImpl implements PendingMessageNewService {
.findFirst()
.map(MessageTemplateDTO::getRouters)
.orElseGet(Collections::emptyList);
- rawRouters = MessageRouterUtil.selectRouter(rawRouters, terminalType);
- List routers = rawRouters.stream().map(e -> {
- MessageRouterDTO router = BeanConverter.convert(e, MessageRouterDTO.class);
- // 视情况替换原始URL中的参数变量
- MessageRouterUtil.parseRouteUrl(router, pendingMessageRecord.getRouterParams());
- return router;
- }).collect(Collectors.toList());
+ List routers = rawRouters.stream()
+ .map(e -> {
+ MessageRouterDTO router = e.toMessageRouter(terminalType);
+ // 视情况替换原始URL中的参数变量
+ MessageRouterUtil.parseRouteUrl(router, pendingMessageRecord.getRouterParams());
+ return router;
+ })
+ .collect(Collectors.toList());
pendingMessage.setRouters(routers);
// 获取模板卡片信息
String cardContent = messageTemplates.stream()
.filter(e -> Objects.equals(e.getCode(), pendingMessageRecord.getTemplateCode()))
.findFirst()
- .map(MessageTemplateDTO::getCardContent)
+ .map(e -> JSON.toJSONString(e.toCardContentMap()))
.orElse(null);
if (StringUtils.isNotBlank(cardContent) && StringUtils.isNotBlank(pendingMessageRecord.getRouterParams())) {
cardContent = PlaceholderResolver.getDefaultResolver()
@@ -191,26 +195,23 @@ public class PendingMessageNewServiceImpl implements PendingMessageNewService {
return pendingMessage;
}
- private List statistic(String rootNodeCode, MessageGroupNodeStatisticParam param) {
- MessageGroupNodeDTO groupNode = messageGroupService.queryByNodeCode(rootNodeCode)
+ private List statistic(String rootNodeCode, MessageGroupNodeStatisticParam param) {
+ GroupTreeNodeDTO rootNode = messageGroupNodeService.queryRootNode(rootNodeCode)
.orElseThrow(() -> new ServiceException("groupNodeCode is invalid."));
- MessageGroupNodeDTO root = groupNode;
- Stack stack = new Stack<>();
- stack.push(groupNode);
- List children;
+ MessageGroupNodeStatisticDTO rootWrapper = TreeHelperUtil.wrapper(rootNode, MessageGroupNodeStatisticDTO::of);
+ LinkedList stack = new LinkedList<>();
+ stack.push(rootWrapper);
+ MessageGroupNodeStatisticDTO wrapper;
while (!stack.isEmpty()) {
- // TODO: [cold_blade] [P3] 优化树形分类结点的统计效率
- groupNode = stack.pop();
- statistic(groupNode, param);
- children = messageGroupService.listChildren(groupNode.getNodeCode());
- groupNode.setChildren(children);
- children.forEach(stack::push);
+ wrapper = stack.pop();
+ statistic(wrapper, param);
+ stack.addAll(wrapper.getNodeChildren());
}
// 外部传的是根节点,但是前端希望只返回根节点的字节的
- return root.getChildren();
+ return rootWrapper.getNodeChildren();
}
- private void statistic(MessageGroupNodeDTO groupNode, MessageGroupNodeStatisticParam param) {
+ private void statistic(MessageGroupNodeStatisticDTO groupNode, MessageGroupNodeStatisticParam param) {
List templateCodes = messageTemplateGroupService.listMessageTemplateCodes(groupNode.getNodeCode());
if (CollectionUtils.isEmpty(templateCodes)) {
groupNode.setPendingCount(0);
@@ -282,10 +283,7 @@ public class PendingMessageNewServiceImpl implements PendingMessageNewService {
record.setOrgId(param.getOrgId());
record.setOrgName(param.getOrgName());
// 构建业务类信息
- record.setBizCode(param.getBizCode());
- record.setSubBizCode(param.getSubBizCode());
- record.setBizDesc(param.getBizDesc());
- record.setBizCategory(param.getBizCategory());
+ buildBusinessInfo(record, param);
return record;
}
@@ -299,17 +297,28 @@ public class PendingMessageNewServiceImpl implements PendingMessageNewService {
}
private void buildTemplateInfo(PendingMessageRecord record, MessageTemplateDTO msgTemplate, String routeParam) {
- String title = msgTemplate.getTitle();
- String content = msgTemplate.getContent();
- if (StringUtils.isNotBlank(routeParam)) {
- title = PlaceholderResolver
- .getDefaultResolver().resolveByMap(title, JSON.parseObject(routeParam));
- content = PlaceholderResolver
- .getDefaultResolver().resolveByMap(content, JSON.parseObject(routeParam));
- }
+ // TODO:[cold_blade] [P3] 后续其它业务对接的时候,需要明确业务扩展字段和路由参数的分界
+ JSONObject routerParamObj = JSONObjectUtil.parseObject(routeParam);
+ String title = PlaceholderResolver
+ .getDefaultResolver().resolveByMap(msgTemplate.getTitle(), routerParamObj);
+ String content = PlaceholderResolver
+ .getDefaultResolver().resolveByMap(msgTemplate.getContent(), routerParamObj);
record.setTitle(title);
record.setContent(content);
record.setTemplateCode(msgTemplate.getCode());
- record.setRouterParams(routeParam);
+ record.setRouterParams(routerParamObj.toJSONString());
+ }
+
+ private void buildBusinessInfo(PendingMessageRecord record, PendingMessagePushParam param) {
+ record.setBizCode(param.getBizCode());
+ record.setSubBizCode(param.getSubBizCode());
+ record.setBizDesc(param.getBizDesc());
+ record.setBizCategory(param.getBizCategory());
+ record.setBizExtParam(JSONObjectUtil.checkAndReturn(param.getBizExtParams()));
+ }
+
+ private static class GroupTreeNodeWrapper {
+ private GroupTreeNodeDTO treeNode;
+ private int pendingCnt;
}
}
diff --git a/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/RelationTemplateMapServiceImpl.java b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/RelationTemplateMapServiceImpl.java
new file mode 100644
index 00000000..381a60ec
--- /dev/null
+++ b/inside-notices/src/main/java/cn/axzo/msg/center/message/service/impl/RelationTemplateMapServiceImpl.java
@@ -0,0 +1,212 @@
+package cn.axzo.msg.center.message.service.impl;
+
+import cn.axzo.msg.center.common.enums.TableIsDeleteEnum;
+import cn.axzo.msg.center.dal.MessageBaseTemplateDao;
+import cn.axzo.msg.center.dal.RelationTemplateMapDao;
+import cn.axzo.msg.center.domain.entity.MessageBaseTemplate;
+import cn.axzo.msg.center.domain.entity.MessageRelation;
+import cn.axzo.msg.center.domain.entity.MessageRouter;
+import cn.axzo.msg.center.domain.entity.MessageTemplate;
+import cn.axzo.msg.center.domain.entity.RelationTemplateMap;
+import cn.axzo.msg.center.inside.notices.service.MessageRelationService;
+import cn.axzo.msg.center.inside.notices.service.MessageRouterService;
+import cn.axzo.msg.center.inside.notices.service.MessageTemplateService;
+import cn.axzo.msg.center.message.domain.dto.RawMessageRouterDTO;
+import cn.axzo.msg.center.message.domain.param.RelationTemplateMapInitParam;
+import cn.axzo.msg.center.message.service.MessageTemplateGroupService;
+import cn.axzo.msg.center.message.service.MessageTemplateRouterService;
+import cn.axzo.msg.center.message.service.RelationTemplateMapService;
+import cn.axzo.msg.center.service.dto.MessageRouterButtonDTO;
+import cn.axzo.msg.center.service.dto.MessageRouterTerminalDTO;
+import cn.axzo.msg.center.service.enums.ButtonStyleEnum;
+import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
+import cn.axzo.msg.center.service.enums.PushTerminalEnum;
+import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
+import cn.axzo.msg.center.service.enums.TerminalTypeEnum;
+import cn.axzo.msg.center.utils.JSONObjectUtil;
+import cn.axzo.msg.center.utils.UUIDUtil;
+import com.google.common.collect.Lists;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 新老模板映射关系service
+ *
+ * @author cold_blade
+ * @date 2023/10/23
+ * @version 1.0
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class RelationTemplateMapServiceImpl implements RelationTemplateMapService {
+
+ private final MessageRouterService messageRouterService;
+ private final MessageRelationService messageRelationService;
+ private final MessageTemplateService messageTemplateService;
+ private final RelationTemplateMapDao relationTemplateMapDao;
+ private final MessageBaseTemplateDao messageBaseTemplateDao;
+ private final MessageTemplateGroupService messageTemplateGroupService;
+ private final MessageTemplateRouterService messageTemplateRouterService;
+
+ @Override
+ public Optional queryByRelationId(Long relationId) {
+ if (Objects.isNull(relationId)) {
+ log.info("relationId is null");
+ return Optional.empty();
+ }
+ return Optional.ofNullable(relationTemplateMapDao.lambdaQuery()
+ .eq(RelationTemplateMap::getOriginalRelationId, relationId)
+ .eq(RelationTemplateMap::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .one()
+ ).map(RelationTemplateMap::getTemplateCode);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void mapRelationAndTemplate(Map map) {
+ if (Objects.isNull(map) || map.isEmpty()) {
+ return;
+ }
+ relationTemplateMapDao.lambdaUpdate()
+ .in(RelationTemplateMap::getOriginalRelationId, map.keySet())
+ .eq(RelationTemplateMap::getIsDelete, TableIsDeleteEnum.NORMAL.value)
+ .remove();
+ List rows = map.entrySet().stream()
+ .map(e -> {
+ RelationTemplateMap row = new RelationTemplateMap();
+ row.setOriginalRelationId(e.getKey());
+ row.setTemplateCode(e.getValue());
+ return row;
+ }).collect(Collectors.toList());
+ relationTemplateMapDao.saveBatch(rows);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void init(RelationTemplateMapInitParam param) {
+ List allRelations = messageRelationService.getAllRelations();
+ if (CollectionUtils.isNotEmpty(param.getRelationIds())) {
+ // 指定了需要创建并关联的relationId
+ allRelations = allRelations.stream()
+ .filter(e -> param.getRelationIds().contains(e.getId()))
+ .collect(Collectors.toList());
+ }
+ // relationId与templateId的map
+ Map relationIdTemplateIdMap = allRelations.stream()
+ .collect(Collectors.toMap(MessageRelation::getId, MessageRelation::getTemplateId));
+ // 获取已经建立关联关系的relationId集合
+ Set mappedRelationIds = getAllOriginalRelationIds();
+ // 过滤掉已经建立关联关系的relationId
+ relationIdTemplateIdMap = relationIdTemplateIdMap.entrySet().stream()
+ .filter(e -> !mappedRelationIds.contains(e.getKey()))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ // 获取生效中的模板
+ Map messageTemplates = messageTemplateService.getAllTemplates().stream()
+ .collect(Collectors.toMap(MessageTemplate::getId, Function.identity()));
+ // 过滤掉relationId对应的消息模板已经删除的场景
+ relationIdTemplateIdMap = relationIdTemplateIdMap.entrySet().stream()
+ .filter(e -> messageTemplates.containsKey(e.getValue()))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ // 获取真实有效且待建立关联关系的relationId对应的消息模板路由
+ Map> messageRouters = messageRouterService.getRouterMapByRelationIds(
+ Lists.newArrayList(relationIdTemplateIdMap.keySet())).stream()
+ .collect(Collectors.groupingBy(MessageRouter::getRelationId));
+ // 转化为新模板的数据模型wrapper
+ List