Merge branch 'feature/REQ-3045' into dev

This commit is contained in:
xudawei 2024-10-08 15:46:44 +08:00
commit 44a8f16042
32 changed files with 2139 additions and 31 deletions

View File

@ -0,0 +1,117 @@
package cn.axzo.msg.center.message.controller;
import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.msg.center.message.domain.param.MessageTemplateSaveOrUpdateParam;
import cn.axzo.msg.center.message.domain.param.MessageTemplateV3SaveOrUpdateParam;
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.MessageTemplateNewSyncService;
import cn.axzo.msg.center.message.service.MessageTemplateV3Service;
import cn.axzo.msg.center.message.service.RelationTemplateMapService;
import cn.axzo.msg.center.service.template.client.MessageTemplateV3Client;
import cn.axzo.msg.center.service.template.request.MessageTemplateV3CreateRequest;
import cn.axzo.msg.center.service.template.request.MessageTemplatePageRequest;
import cn.axzo.msg.center.service.template.request.MessageTemplateSyncDto;
import cn.axzo.msg.center.service.template.request.MessageTemplateSyncQueryRequest;
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.MessageDetailStyle;
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 cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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;
/**
* 消息模板管理
*
* @author cold_blade
* @date 2023/10/5
* @version 1.0
*/
@Slf4j
@RestController
@RequiredArgsConstructor
public class MessageTemplateV3Controller implements MessageTemplateV3Client {
private final MessageTemplateNewService messageTemplateNewService;
private final RelationTemplateMapService relationTemplateMapService;
private final MessageTemplateNewSyncService messageTemplateNewSyncService;
private final MessageTemplateV3Service messageTemplateV3Service;
@Override
public CommonResponse<String> save(MessageTemplateV3CreateRequest request) {
return CommonResponse.success(
messageTemplateV3Service.createTemplate(MessageTemplateV3SaveOrUpdateParam.from(request)));
}
@Override
public CommonResponse<Void> update(MessageTemplateUpdateRequest request) {
messageTemplateNewService.updateTemplate(MessageTemplateSaveOrUpdateParam.from(request));
return CommonResponse.success();
}
@Override
public CommonResponse<MessageTemplateDetailResponse> detail(String templateCode) {
return CommonResponse.success(messageTemplateNewService.detail(templateCode));
}
@Override
public CommonResponse<Page<MessageTemplatePageResponse>> page(MessageTemplatePageRequest request) {
return CommonResponse.success(messageTemplateNewService.page(request));
}
@Override
public CommonResponse<List<MessageTemplatePageResponse>> listByCodes(Collection<String> templateCodes) {
return CommonResponse.success(messageTemplateNewService.listByCodes(templateCodes));
}
@Override
public CommonResponse<Void> updateStatus(MessageTemplateUpdateStatusRequest request) {
messageTemplateNewService.updateStatus(request.getOperatorId(), request.getTemplateCode(), request.getStatus());
return CommonResponse.success();
}
@Override
public CommonResponse<MessageTemplateSyncDto> getSyncMessageTemplate(
MessageTemplateSyncQueryRequest request) {
MessageTemplateDetailResponse detail = messageTemplateNewService.querySyncMessageTemplate(request.getTemplateCode());
AssertUtil.notNull(detail, "消息模板不存在");
MessageTemplateSyncDto result = BeanUtil.copyProperties(detail, MessageTemplateSyncDto.class);
result.setTemplateCode(request.getTemplateCode());
result.setEnv(request.getEnv());
return CommonResponse.success(result);
}
@Override
public CommonResponse<List<MessageDetailStyle>> listTemplateDetailStyles() {
List<MessageDetailStyle> styles = messageTemplateNewService.listTemplateDetailStyles();
return CommonResponse.success(styles);
}
@Override
public CommonResponse<Void> syncTemplate(MessageTemplateSyncDto param) {
log.info("syncTemplate param= [{}]", JSONUtil.toJsonStr(param));
messageTemplateNewSyncService.syncTemplate(param);
return CommonResponse.success();
}
@PostMapping(value = "/message/template/relation/init", produces = {MediaType.APPLICATION_JSON_VALUE})
public CommonResponse<Void> initRelationTemplateMap(@RequestBody @Valid RelationTemplateMapInitRequest request) {
RelationTemplateMapInitParam param = request.toInitParam();
relationTemplateMapService.init(param);
return CommonResponse.success();
}
}

View File

@ -0,0 +1,179 @@
package cn.axzo.msg.center.message.domain.param;
import cn.axzo.msg.center.common.exception.ServiceException;
import cn.axzo.msg.center.service.dto.MessageButtonRouteStrategyDTO;
import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
import cn.axzo.msg.center.service.dto.MessageDetailRouteStrategyDTO;
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
import cn.axzo.msg.center.service.enums.PushTerminalEnum;
import cn.axzo.msg.center.service.template.request.MessageTemplateGroupV3CreateRequest;
import cn.axzo.msg.center.service.template.request.MessageTemplateV3CreateRequest;
import cn.axzo.msg.center.service.template.request.MessageTemplateSyncDto;
import cn.axzo.msg.center.service.template.request.MessageTemplateUpdateRequest;
import cn.axzo.msg.center.utils.MessageTemplateCategoryUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
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 MessageTemplateV3SaveOrUpdateParam implements Serializable {
private static final long serialVersionUID = 6657624182580261353L;
/**
* 模板编码
*/
private String templateCode;
/**
* 操作者的自然人id
*/
private Long operatorId;
/**
* 操作者的自然人姓名
*/
private String operatorName;
/**
* 模板名称
*/
private String templateName;
/**
* 消息类型
* GENERAL_MESSAGE: 通知
* BIZ_PENDING_MESSAGE: 业务待办
* APPROVAL_PENDING_MESSAGE: 审批待办
*/
private MessageCategoryEnum msgCategory;
/**
* 消息分类树的叶结点的结点编码列表
*/
private List<String> leafGroupNodes;
/**
* 推送终端配置
* B_ENTERPRISE_APP: B-安心筑企业版
* C_WORKER_APP: C-安心筑工人版
*/
private List<PushTerminalEnum> pushTerminals;
/**
* 该模板最低支持的APP版本号
*/
private String minAppVersion;
/**
* 消息标题
*/
private String title;
/**
* 消息内容
*/
private String content;
/**
* 消息图标
*/
private String icon;
/**
* 消息卡片信息标签列表可为空
*/
private List<MessageTemplateGroupV3CreateRequest> messageTemplateGroups;
/**
* 业务详情展示策略
*/
private MessageDetailRouteStrategyDTO bizDetailShowStrategy;
/**
* 路由策略列表
*/
private List<MessageButtonRouteStrategyDTO> routers;
/**
* 待办样式, BIZ_COMMON: 业务待办能用, FLOW_COMMON: 审批待办能用, 其它动态配置的
*/
private String detailStyleCode;
private JSONObject pushData;
public static MessageTemplateV3SaveOrUpdateParam from(MessageTemplateV3CreateRequest request) {
MessageCategoryEnum category = MessageTemplateCategoryUtil
.checkAndReturnSubCategory(request.getCategory(), request.getSubCategory())
.orElseThrow(() -> new ServiceException("无效的参数"));
return MessageTemplateV3SaveOrUpdateParam.builder()
.templateName(request.getTemplateName())
.detailStyleCode(request.getDetailStyleCode())
.operatorId(request.getOperatorId())
.operatorName(request.getOperatorName())
.msgCategory(category)
.leafGroupNodes(request.getLeafGroupNodes())
.title(request.getMsgTitle())
.content(request.getMsgContent())
.messageTemplateGroups(request.getMessageTemplateGroups())
.icon(request.getMsgIcon())
.minAppVersion(request.getMinAppVersion())
.operatorId(request.getOperatorId())
.routers(request.getRouters())
.pushTerminals(request.getPushTerminals())
.bizDetailShowStrategy(request.getDetailStrategy())
.pushData(request.getPushData())
.build();
}
public static MessageTemplateV3SaveOrUpdateParam from(MessageTemplateUpdateRequest request) {
return MessageTemplateV3SaveOrUpdateParam.builder()
.templateName(request.getTemplateName())
.detailStyleCode(request.getDetailStyleCode())
.operatorName(request.getOperatorName())
.templateCode(request.getTemplateCode())
.leafGroupNodes(request.getLeafGroupNodes())
.title(request.getMsgTitle())
.content(request.getMsgContent())
// .msgCardContentItems(request.getMsgCardContentItems())
.minAppVersion(request.getMinAppVersion())
.icon(request.getMsgIcon())
.operatorId(request.getOperatorId())
.operatorName(request.getOperatorName())
.routers(request.getRouters())
.pushTerminals(request.getPushTerminals())
.bizDetailShowStrategy(request.getDetailStrategy())
.pushData(request.getPushData())
.build();
}
public static MessageTemplateV3SaveOrUpdateParam fromSync(MessageTemplateSyncDto request) {
MessageCategoryEnum category = MessageTemplateCategoryUtil
.checkAndReturnSubCategory(request.getCategory(), request.getSubCategory())
.orElseThrow(() -> new ServiceException("无效的参数"));
return MessageTemplateV3SaveOrUpdateParam.builder()
.templateName(request.getTemplateName())
.msgCategory(category)
.leafGroupNodes(request.getLeafGroupNodes())
.title(request.getMsgTitle())
.content(request.getMsgContent())
// .msgCardContentItems(request.getCardContentItems())
.icon(request.getMsgIcon())
.minAppVersion(request.getMinAppVersion())
.operatorId(request.getOperatorId())
.routers(request.getRouters())
.pushTerminals(request.getPushTerminals())
.bizDetailShowStrategy(request.getDetailStrategy())
.build();
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}

View File

@ -0,0 +1,95 @@
package cn.axzo.msg.center.message.service;
import cn.axzo.msg.center.service.template.request.MessageTemplateGroupV3CreateRequest;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 消息模板分类管理
*
* @author cold_blade
* @date 2023/10/5
* @version 1.0
*/
public interface MessageTemplateGroupV3Service {
/**
* 通过分组结点编码路径查询关联的模板编码列表
*
* @param leafNodePathCodes 分组结点编码路径列表
* @return 模板编码列表
*/
List<String> listMessageTemplateCodes(Collection<String> leafNodePathCodes);
/**
* 通过分组结点编码路径查询关联的模板编码列表
*
* @param leafNodePathCodes 分组结点编码路径列表
* @return 模板编码列表
*/
Map<String, List<String>> groupingByMessageTemplateCodes(Collection<String> leafNodePathCodes);
/**
* 模板关联分类
*
* @param templateNode 模板编码
* @param groupNodeCodes 分类结点编码列表
*/
void templateGroup(String templateNode, Collection<String> groupNodeCodes);
/**
* 模板关联分类
*
* @param templateGroupMap 模板编码与分类结点编码列表的map
*/
void templateGroup(Map<String, List<String>> templateGroupMap);
/**
* 保存模版分组
*/
void saveTemplateGroup(String messageTemplateCode, List<MessageTemplateGroupV3CreateRequest> groupV3List);
/**
* 更新模板的分类关系
*
* @param templateNode 模板编码
* @param groupNodeCodes 新的模板的分类结点编码
*/
void updateTemplateGroup(String templateNode, Collection<String> groupNodeCodes);
/**
* 解除模板关联的分类
*
* @param templateNode 模板编码
*/
void deleteTemplateGroup(String templateNode);
/**
* 通过消息模板编码查询其关联的分类的path
*
* @param templateCodes 消息模板编码集合
* @return 模板编码与分类的path列表的映射关系
*/
Map<String, List<String>> listMessageTemplateGroupPaths(Collection<String> templateCodes);
/**
* 解除模板与当前分类的关联关系
* 当模板只关联一个分类时该关联关系不能解除
*
* @param curGroupNodeCode 当前分类结点的编码
* @param templateCodes 待解除关连关系的模板编码
*/
void remove(String curGroupNodeCode, Collection<String> templateCodes);
/**
* 解除模板与当前分类的关联关系
* 当模板只关联一个分类时该关联关系不能解除
*
* @param srcGroupNodeCode 源分类结点的编码
* @param tgtGroupNodeCode 目标分类结点的编码
* @param templateCodes 待变更关连关系的模板编码
*/
void move(String srcGroupNodeCode, String tgtGroupNodeCode, Collection<String> templateCodes);
}

View File

@ -0,0 +1,118 @@
package cn.axzo.msg.center.message.service;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateDTO;
import cn.axzo.msg.center.message.domain.param.MessageTemplateSaveOrUpdateParam;
import cn.axzo.msg.center.message.domain.param.MessageTemplateV3SaveOrUpdateParam;
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.MessageDetailStyle;
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;
/**
* @description
* 消息模板管理
* @author cold_blade
* @date 2023/10/5
* @version 1.0
*/
public interface MessageTemplateV3Service {
/**
* 创建模板
*
* @param param 模板内容参数
*/
String createTemplate(MessageTemplateV3SaveOrUpdateParam param);
/**
* 编辑模板
*
* @param param 模板内容参数
*/
void updateTemplate(MessageTemplateV3SaveOrUpdateParam param);
/**
* 通过模板便阿门查询模板详情
*
* @param templateCode 模板编码
* @return 模板详情信息
*/
MessageTemplateDetailResponse detail(String templateCode);
/**
* 更新模板状态
*
* @param operatorId 操作人id
* @param templateCode 模板编码
* @param status 新的模板状态
*/
void updateStatus(Long operatorId, String templateCode, StatusEnum status);
/**
* 通过模板编码查询模板信息
*
* @param msgTemplateCode 模板编码
* @return 模板信息
*/
Optional<MessageTemplateDTO> queryEnableTemplateByCode(String msgTemplateCode);
/**
* 通过模板编码查询模板信息
*
* @param msgTemplateCodes 模板编码列表
* @return 模板信息
*/
List<MessageTemplateDTO> listByTemplateCodes(List<String> msgTemplateCodes);
/**
* 分页查询模板数据
*
* @param request 分页请求参数
* @return 模板数据列表
*/
Page<MessageTemplatePageResponse> page(MessageTemplatePageRequest request);
/**
* 分页查询模板基础数据
*
* @param request 分页请求参数
* @return 模板数据列表
*/
Page<MessageBaseTemplateDTO> pageBaseTemplate(MessageTemplatePageRequest request);
/**
* 通过模板编码查询对应的模板
*
* @param templateCodes 模板编码集合
* @return 模板列表
*/
List<MessageTemplatePageResponse> listByCodes(Collection<String> templateCodes);
/**
* 通过模板id获取对应的模板编码
*
* @param ids 模板id列表
* @return 模板编码列表
*/
List<String> listTemplateCodesByIds(Collection<Long> ids);
/**
* 查询需要同步的模板
* @param templateCode
* @return
*/
MessageTemplateDetailResponse querySyncMessageTemplate(String templateCode);
/**
* 获取所有消息样式
* @return
*/
List<MessageDetailStyle> listTemplateDetailStyles();
}

View File

@ -0,0 +1,239 @@
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.dal.MessageTemplateGroupV3Dao;
import cn.axzo.msg.center.domain.entity.MessageTemplateGroup;
import cn.axzo.msg.center.domain.entity.MessageTemplateGroupV3;
import cn.axzo.msg.center.message.service.MessageGroupNodeService;
import cn.axzo.msg.center.message.service.MessageTemplateGroupService;
import cn.axzo.msg.center.message.service.MessageTemplateGroupV3Service;
import cn.axzo.msg.center.service.template.request.MessageTemplateGroupV3CreateRequest;
import cn.hutool.core.bean.BeanUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
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;
/**
* @author cold_blade
* @date 2023/10/5
* @version 1.0
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class MessageTemplateGroupV3ServiceImpl implements MessageTemplateGroupV3Service {
private final MessageGroupNodeService messageGroupNodeService;
private final MessageTemplateGroupDao messageTemplateGroupDao;
private final MessageTemplateGroupV3Dao messageTemplateGroupV3Dao;
@Override
public List<String> listMessageTemplateCodes(Collection<String> leafNodePathCodes) {
if (CollectionUtils.isEmpty(leafNodePathCodes)) {
log.info("leafNodePathCodes is empty.");
return Collections.emptyList();
}
return messageTemplateGroupDao.lambdaQuery()
.in(MessageTemplateGroup::getPath, leafNodePathCodes)
.eq(MessageTemplateGroup::getIsDelete, 0)
.list().stream()
.map(MessageTemplateGroup::getTemplateCode)
.collect(Collectors.toList());
}
@Override
public Map<String, List<String>> groupingByMessageTemplateCodes(Collection<String> leafNodePathCodes) {
if (CollectionUtils.isEmpty(leafNodePathCodes)) {
log.info("leafNodePathCodes is empty.");
return Collections.emptyMap();
}
Map<String, List<MessageTemplateGroup>> groupingBy = messageTemplateGroupDao.lambdaQuery()
.in(MessageTemplateGroup::getPath, leafNodePathCodes)
.select(MessageTemplateGroup::getPath, MessageTemplateGroup::getTemplateCode)
.list().stream()
.collect(Collectors.groupingBy(MessageTemplateGroup::getTemplateCode));
final Map<String, List<String>> result = Maps.newHashMap();
groupingBy.forEach((key, value) -> {
List<String> paths = value.stream().map(MessageTemplateGroup::getPath).collect(Collectors.toList());
result.put(key, paths);
});
return result;
}
@Override
public void templateGroup(String templateNode, Collection<String> groupNodeCodes) {
if (StringUtils.isBlank(templateNode)
|| CollectionUtils.isEmpty(groupNodeCodes)) {
log.info("the param is invalid. templateNode:[{}], groupNodeCodes:{}", templateNode, groupNodeCodes);
return;
}
Map<String, String> pathMap = messageGroupNodeService.leafGroupNodeCodePaths(groupNodeCodes);
List<MessageTemplateGroup> 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<String, List<String>> templateGroupMap) {
if (MapUtil.isEmpty(templateGroupMap)) {
log.info("the templateGroupMap is empty.");
return;
}
Set<String> groupNodes = templateGroupMap.values().stream()
.flatMap(Collection::stream)
.collect(Collectors.toSet());
Map<String, String> pathMap = messageGroupNodeService.leafGroupNodeCodePaths(groupNodes);
List<MessageTemplateGroup> 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 saveTemplateGroup(String messageTemplateCode, List<MessageTemplateGroupV3CreateRequest> groupV3List) {
if (CollectionUtils.isEmpty(groupV3List)) {
log.info("groupV3List is empty.");
return;
}
List<MessageTemplateGroupV3> templateGroupV3List = groupV3List.stream().map(item -> {
MessageTemplateGroupV3 messageTemplateGroupV3 = BeanUtil.copyProperties(item, MessageTemplateGroupV3.class);
messageTemplateGroupV3.setTemplateCode(messageTemplateCode);
return messageTemplateGroupV3;
}).collect(Collectors.toList());
messageTemplateGroupV3Dao.saveBatch(templateGroupV3List);
}
@Override
public void updateTemplateGroup(String templateNode, Collection<String> 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<String, List<String>> listMessageTemplateGroupPaths(Collection<String> 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<String> templateCodes) {
// 参数校验
AssertUtil.isTrue(StringUtils.isNotBlank(curGroupNodeCode), "curGroupNodeCode can not be blank");
AssertUtil.notEmpty(templateCodes, "templateCodes can not be empty");
// 通过分类结点编码获取其对应的结点编码的路径
Map<String, String> nodeCodePathMap = messageGroupNodeService
.leafGroupNodeCodePaths(Lists.newArrayList(curGroupNodeCode));
// 通过能否成功获取到其树路径来校验其有效性
AssertUtil.isFalse(nodeCodePathMap.isEmpty(), "curGroupNodeCode is invalid");
// 统计指定的模板编码关联的分类数量
Map<String, Long> templateCodeList = messageTemplateGroupDao.lambdaQuery()
.in(MessageTemplateGroup::getTemplateCode, templateCodes)
.eq(MessageTemplateGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value)
// 这里仅查询模板编码字段即可
.select(MessageTemplateGroup::getTemplateCode)
.list().stream()
.map(MessageTemplateGroup::getTemplateCode)
// 内存中来做groupingBy操作
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
// 筛选出仅关联了一个分类的模板编码
List<String> 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<String> 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<String, String> 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");
// 获取已经存在目标分类与模板关联关系的模板编码列表
List<String> existTgtRelationTemplates = messageTemplateGroupDao.lambdaQuery()
.eq(MessageTemplateGroup::getPath, nodeCodePathMap.get(tgtGroupNodeCode))
.in(MessageTemplateGroup::getTemplateCode, templateCodes)
.select(MessageTemplateGroup::getTemplateCode)
.list().stream().map(MessageTemplateGroup::getTemplateCode).collect(Collectors.toList());
templateCodes = templateCodes.stream()
// 过滤掉已经存在目标分类与模板关联关系存在的模板编码
.filter(e -> !existTgtRelationTemplates.contains(e))
.collect(Collectors.toList());
if (templateCodes.isEmpty()) {
log.info("目标分类与模板的关联关系已存在. existTgtRelationTemplates:{}", existTgtRelationTemplates);
return;
}
// 更新分类路径与模板编码的映射关系
messageTemplateGroupDao.lambdaUpdate()
.eq(MessageTemplateGroup::getPath, nodeCodePathMap.get(srcGroupNodeCode))
.in(MessageTemplateGroup::getTemplateCode, templateCodes)
.set(MessageTemplateGroup::getPath, nodeCodePathMap.get(tgtGroupNodeCode))
.update();
}
private String removeErrorStr(List<String> onlyContainsOneTemplateCodes) {
return String.format("模板:%s。解除关联后将无关联分类本次操作无效",
String.join("", onlyContainsOneTemplateCodes));
}
}

View File

@ -0,0 +1,540 @@
package cn.axzo.msg.center.message.service.impl;
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.dal.MessageTemplateGroupV3Dao;
import cn.axzo.msg.center.dal.MessageTemplateV3Dao;
import cn.axzo.msg.center.domain.entity.MessageBaseTemplate;
import cn.axzo.msg.center.domain.entity.MessageTemplateV3;
import cn.axzo.msg.center.inside.notices.config.DetailStyleInfo;
import cn.axzo.msg.center.inside.notices.config.PendingMessageBizConfig;
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.MessageTemplateRouterDTO;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateRouterDTO.MessageRouteButtonDTO;
import cn.axzo.msg.center.message.domain.dto.MessageTemplateRouterDTO.MessageRouteDetailDTO;
import cn.axzo.msg.center.message.domain.param.MessageTemplateSaveOrUpdateParam;
import cn.axzo.msg.center.message.domain.param.MessageTemplateV3SaveOrUpdateParam;
import cn.axzo.msg.center.message.service.MessageGroupNodeService;
import cn.axzo.msg.center.message.service.MessageTemplateGroupService;
import cn.axzo.msg.center.message.service.MessageTemplateGroupV3Service;
import cn.axzo.msg.center.message.service.MessageTemplateNewService;
import cn.axzo.msg.center.message.service.MessageTemplateRouterService;
import cn.axzo.msg.center.message.service.MessageTemplateV3Service;
import cn.axzo.msg.center.message.service.group.GroupTemplateService;
import cn.axzo.msg.center.service.dto.MessageBaseTemplateDTO;
import cn.axzo.msg.center.service.dto.MessageButtonRouteStrategyDTO;
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.service.enums.StatusEnum;
import cn.axzo.msg.center.service.template.request.MessageTemplatePageRequest;
import cn.axzo.msg.center.service.template.response.MessageDetailStyle;
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.MessageRouterUtil;
import cn.axzo.msg.center.utils.MessageTemplateCategoryUtil;
import cn.axzo.msg.center.utils.UUIDUtil;
import cn.azxo.framework.common.model.Page;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
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.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
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;
/**
* @description
*
* @author cold_blade
* @date 2023/10/5
* @version 1.0
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class MessageTemplateV3ServiceImpl implements MessageTemplateV3Service {
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;
private final PendingMessageBizConfig pendingBizConfig;
private final GroupTemplateService groupTemplateService;
private final MessageTemplateV3Dao messageTemplateV3Dao;
private final MessageTemplateGroupV3Service messageTemplateGroupV3Service;
@Override
@Transactional(rollbackFor = Exception.class)
public String createTemplate(MessageTemplateV3SaveOrUpdateParam param) {
// 创建模板基础数据
String templateCode = saveTemplate(param);
// 创建模板的路由数据
// saveTemplateRouters(param, templateCode);
// 创建模板与分类的关联关系数据
messageTemplateGroupV3Service.saveTemplateGroup(templateCode,param.getMessageTemplateGroups());
return templateCode;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateTemplate(MessageTemplateV3SaveOrUpdateParam 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<String> groupNodePaths = messageTemplateGroupService.listMessageTemplateGroupPaths(
Lists.newArrayList(templateCode)).getOrDefault(templateCode, Collections.emptyList());
// 获取模板配置的路由信息
MessageTemplateRouterDTO msgTemplateRouter = messageTemplateRouterService.queryByTemplateCode(templateCode)
.orElse(null);
return convert(baseTemplate, groupNodePaths, msgTemplateRouter);
}
@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
public Optional<MessageTemplateDTO> queryEnableTemplateByCode(String msgTemplateCode) {
if (StringUtils.isBlank(msgTemplateCode)) {
log.info("msgTemplateCode is blank.");
return Optional.empty();
}
MessageBaseTemplate msgBaseTemplate = messageBaseTemplateDao.lambdaQuery()
.eq(MessageBaseTemplate::getCode, msgTemplateCode)
.eq(MessageBaseTemplate::getIsDelete, 0)
.eq(MessageBaseTemplate::getStatus, StatusEnum.ENABLE)
.one();
if (Objects.isNull(msgBaseTemplate)) {
log.info("not find the [{}] template.", msgTemplateCode);
return Optional.empty();
}
// 获取模板的路由配置信息
MessageTemplateRouterDTO msgTemplateRouter = messageTemplateRouterService.queryByTemplateCode(msgTemplateCode)
.orElse(null);
return Optional.of(MessageTemplateDTO.from(msgBaseTemplate, msgTemplateRouter));
}
@Override
public List<MessageTemplateDTO> listByTemplateCodes(List<String> msgTemplateCodes) {
if (CollectionUtils.isEmpty(msgTemplateCodes)) {
log.info("msgTemplateCodes is empty.");
return Collections.emptyList();
}
List<MessageBaseTemplate> msgBaseTemplates = messageBaseTemplateDao.lambdaQuery()
.in(MessageBaseTemplate::getCode, msgTemplateCodes)
.eq(MessageBaseTemplate::getIsDelete, 0)
.list();
if (Objects.isNull(msgBaseTemplates)) {
log.info("not find the [{}] templates.", msgTemplateCodes);
return Collections.emptyList();
}
Map<String, MessageTemplateRouterDTO> templateRouterMap = messageTemplateRouterService
.groupByTemplateCode(msgTemplateCodes);
return msgBaseTemplates.stream()
.map(e -> MessageTemplateDTO.from(e, templateRouterMap.get(e.getCode())))
.collect(Collectors.toList());
}
@Override
public Page<MessageTemplatePageResponse> page(MessageTemplatePageRequest request) {
IPage<MessageBaseTemplate> result = pageQueryBaseTemplate(request);
if (Objects.isNull(result)
|| CollectionUtils.isEmpty(result.getRecords())) {
return PageHelperUtil.emptyPage(request.getPage(), request.getPageSize());
}
List<String> templateCodes = result.getRecords().stream()
.map(MessageBaseTemplate::getCode)
.collect(Collectors.toList());
Map<String, List<String>> groupNodePaths = messageTemplateGroupService
.listMessageTemplateGroupPaths(templateCodes);
Map<String, String> codeNameMap = messageGroupNodeService.groupNodeNamePaths(groupNodePaths.values().stream()
.flatMap(Collection::stream).collect(Collectors.toList()));
List<MessageTemplatePageResponse> 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<MessageBaseTemplateDTO> pageBaseTemplate(MessageTemplatePageRequest request) {
IPage<MessageBaseTemplate> result = pageQueryBaseTemplate(request);
if (Objects.isNull(result)
|| CollectionUtils.isEmpty(result.getRecords())) {
return PageHelperUtil.emptyPage(request.getPage(), request.getPageSize());
}
List<MessageBaseTemplateDTO> records = result.getRecords().stream()
.map(this::convert)
.collect(Collectors.toList());
return Page.toPage(request.getPage(), request.getPageSize(), result.getTotal(), records);
}
@Override
public List<MessageTemplatePageResponse> listByCodes(Collection<String> 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<MessageBaseTemplate> 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<String, List<String>> groupNodePaths = messageTemplateGroupService
.listMessageTemplateGroupPaths(templateCodes);
// 将模板分类结点编码path转化为分类名称path
Map<String, String> codeNameMap = messageGroupNodeService.groupNodeNamePaths(groupNodePaths.values().stream()
.flatMap(Collection::stream).collect(Collectors.toList()));
// 转化为页面展示的数据模型
return records.stream()
.map(e -> convert(e, groupNodePaths, codeNameMap))
.collect(Collectors.toList());
}
@Override
public List<String> listTemplateCodesByIds(Collection<Long> ids) {
if (CollectionUtils.isEmpty(ids)) {
log.info("ids is empty.");
return Collections.emptyList();
}
return messageBaseTemplateDao.lambdaQuery()
.in(MessageBaseTemplate::getId, ids)
.select(MessageBaseTemplate::getCode)
.list().stream()
.map(MessageBaseTemplate::getCode)
.collect(Collectors.toList());
}
@Override
public MessageTemplateDetailResponse querySyncMessageTemplate(String templateCode) {
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;
}
// 获取模板配置的路由信息
MessageTemplateRouterDTO msgTemplateRouter = messageTemplateRouterService.queryByTemplateCode(templateCode)
.orElse(null);
return convert(baseTemplate, null, msgTemplateRouter);
}
@Override
public List<MessageDetailStyle> listTemplateDetailStyles() {
return new ArrayList<>(pendingBizConfig.getMessageDetailStyles());
}
private String saveTemplate(MessageTemplateV3SaveOrUpdateParam param) {
String templateCode = UUIDUtil.uuidString();
MessageTemplateV3 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;
}
public boolean doSaveTemplate(MessageTemplateV3 template, String templateCode) {
String opKey = String.format(SAVE_TEMPLATE_MUTEX_KEY, templateCode);
String requestId = UUIDUtil.uuidRawString();
try {
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);
messageTemplateV3Dao.save(template);
return true;
} finally {
redisUtil.getLockOps().releaseLock(opKey, requestId);
}
}
private boolean isTemplateExist(String templateCode) {
return messageBaseTemplateDao.lambdaQuery()
.eq(MessageBaseTemplate::getCode, templateCode)
.eq(MessageBaseTemplate::getIsDelete, 0)
.count() > 0;
}
private MessageTemplateV3 convert(MessageTemplateV3SaveOrUpdateParam param) {
MessageTemplateV3 template = new MessageTemplateV3();
template.setName(param.getTemplateName());
template.setMsgCategory(param.getMsgCategory());
template.setTitle(param.getTitle());
template.setContent(param.getContent());
template.setDetailStyleCode(param.getDetailStyleCode());
// template.setCardContent(JSONObjectUtil.toJSONString(param.getMsgCardContentItems()));
template.setIcon(param.getIcon());
template.setPushTerminal(JSONObjectUtil.toJSONString(param.getPushTerminals()));
template.setMinAppVersion(param.getMinAppVersion());
// template.setCreatorId(param.getOperatorId());
// template.setUpdaterId(param.getOperatorId());
template.setCreatePersonId(param.getOperatorId());
template.setCreatePersonName(param.getOperatorName());
template.setUpdatePersonId(param.getOperatorId());
template.setUpdatePersonName(param.getOperatorName());
template.setPushData(param.getPushData());
return template;
}
public void saveTemplateRouters(MessageTemplateV3SaveOrUpdateParam param, String templateCode) {
MessageTemplateRouterDTO templateRouter = buildTemplateRouter(param, templateCode);
if (templateRouter.isValid()) {
// 模板配置了路由的场景
messageTemplateRouterService.saveOrUpdate(templateRouter, false, templateCode);
}
}
private void updateBaseTemplate(MessageTemplateV3SaveOrUpdateParam param) {
JSONObject pushData = param.getPushData();
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(MessageBaseTemplate::getPushTerminal, JSON.toJSONString(param.getPushTerminals()))
.set(StringUtils.isNotBlank(param.getTitle()), MessageBaseTemplate::getTitle, param.getTitle())
// .set(MessageBaseTemplate::getCardContent, JSONObjectUtil.toJSONString(param.getMsgCardContentItems()))
.set(MessageBaseTemplate::getContent, param.getContent())
.set(StringUtils.isNotBlank(param.getDetailStyleCode()),
MessageBaseTemplate::getDetailStyleCode, param.getDetailStyleCode())
.set(MessageBaseTemplate::getUpdatePersonId, param.getOperatorId())
.set(MessageBaseTemplate::getUpdatePersonName, param.getOperatorName())
.set(MessageBaseTemplate::getIcon, param.getIcon())
.set(MessageBaseTemplate::getMinAppVersion, param.getMinAppVersion())
.set(Objects.nonNull(pushData), MessageBaseTemplate::getPushData,
pushData == null ? null : pushData.toJSONString())
.update();
}
private void updateTemplateGroupRelation(MessageTemplateV3SaveOrUpdateParam param) {
if (CollectionUtils.isEmpty(param.getLeafGroupNodes())) {
messageTemplateGroupService.deleteTemplateGroup(param.getTemplateCode());
return;
}
messageTemplateGroupService.updateTemplateGroup(param.getTemplateCode(), param.getLeafGroupNodes());
}
private void updateTemplateRouters(MessageTemplateV3SaveOrUpdateParam param) {
MessageTemplateRouterDTO templateRouter = buildTemplateRouter(param, param.getTemplateCode());
boolean isCleanOldFlag = Objects.isNull(param.getBizDetailShowStrategy())
|| CollectionUtils.isEmpty(param.getBizDetailShowStrategy().getTerminals())
|| CollectionUtils.isEmpty(param.getRouters());
if (templateRouter.isValid() || isCleanOldFlag) {
// 模板修改了路由的场景
messageTemplateRouterService.saveOrUpdate(templateRouter, true, param.getTemplateCode());
}
}
private IPage<MessageBaseTemplate> pageQueryBaseTemplate(MessageTemplatePageRequest request) {
List<String> templateCodes = Lists.newArrayList();
if (StringUtils.isNotBlank(request.getGroupNodeCode())) {
templateCodes = groupTemplateService.collectTemplateCodes(request.getGroupNodeCode());
if (CollectionUtils.isEmpty(templateCodes)) {
// 入参中的分类没有关联任何模板,直接返回查询结果
return null;
}
}
if (StringUtils.isNotBlank(request.getTemplateCode())) {
if (CollectionUtils.isNotEmpty(templateCodes)
&& !templateCodes.contains(request.getTemplateCode())) {
// 分页查询的入参中没指定的模板编码与分类映射的模板编码无交集
return null;
}
// 取两者的交集
templateCodes = Lists.newArrayList(request.getTemplateCode());
}
IPage<MessageBaseTemplate> pageRequest = request.toPage();
String title = request.getTitle();
if (title != null) {
title = title.trim();
}
String content = request.getContent();
if (content != null) {
content = content.trim();
}
return messageBaseTemplateDao.lambdaQuery()
.like(StringUtils.isNotBlank(title), MessageBaseTemplate::getTitle, title)
.like(StringUtils.isNotBlank(content), MessageBaseTemplate::getContent, content)
.apply(BooleanUtils.isFalse(request.pushSwitchOn), "(json_extract(push_data, '$.switchOn') is null or json_extract(push_data, '$.switchOn') = false)")
.apply(BooleanUtils.isTrue(request.pushSwitchOn), "json_extract(push_data, '$.switchOn') = true")
.like(StringUtils.isNotBlank(request.getTemplateName()),
MessageBaseTemplate::getName, request.getTemplateName())
.in(CollectionUtils.isNotEmpty(templateCodes), MessageBaseTemplate::getCode, templateCodes)
.in(CollectionUtils.isNotEmpty(request.getCategories()), MessageBaseTemplate::getMsgCategory,
request.getCategories())
.eq(Objects.nonNull(request.getStatus()), MessageBaseTemplate::getStatus, request.getStatus())
.orderByDesc(MessageBaseTemplate::getCreateAt)
.page(pageRequest);
}
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<String, List<String>> groupNodePaths,
Map<String, String> codeNameMap) {
MessageDetailStyle styleType = pendingBizConfig
.findMessageDetailType(record.getDetailStyleCode())
.orElse(null);
MessageTemplatePageResponse response = new MessageTemplatePageResponse();
if (styleType != null) {
response.setStyleType(styleType);
} else if (record.getMsgCategory() == MessageCategoryEnum.BIZ_PENDING_MESSAGE) {
response.setStyleType(new MessageDetailStyle(
DetailStyleInfo.BIZ_COMMON_CODE, MessageCategoryEnum.BIZ_PENDING_MESSAGE, "业务待办能用", null));
} else if (record.getMsgCategory() == MessageCategoryEnum.APPROVAL_PENDING_MESSAGE) {
response.setStyleType(new MessageDetailStyle(
DetailStyleInfo.FLOW_COMMON_CODE, MessageCategoryEnum.APPROVAL_PENDING_MESSAGE, "审批待办能用", null));
}
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<String> nodeNamePaths = groupNodePaths.getOrDefault(record.getCode(), Collections.emptyList()).stream()
.filter(codeNameMap::containsKey)
.map(codeNameMap::get)
.collect(Collectors.toList());
response.setGroupNodeNamePaths(nodeNamePaths);
response.setCreatePersonId(record.getCreatePersonId());
response.setCreatePersonName(record.getCreatePersonName());
response.setUpdatePersonId(record.getUpdatePersonId());
response.setUpdatePersonName(record.getUpdatePersonName());
response.setPushData(record.getPushData());
return response;
}
private MessageTemplateDetailResponse convert(MessageBaseTemplate record, List<String> groupNodePaths,
MessageTemplateRouterDTO msgTemplateRouter) {
List<String> groupNodeCodes = Lists.newArrayList();
if (CollUtil.isNotEmpty(groupNodePaths)) {
// 将path解析中解析出分类结点路径叶结点的编码
groupNodeCodes = groupNodePaths.stream()
.map(GroupTreeNodePathDTO::parseLeafNodeCode)
.collect(Collectors.toList());
}
MessageDetailStyle styleType = pendingBizConfig
.findMessageDetailType(record.getDetailStyleCode())
.orElse(null);
return MessageTemplateDetailResponse.builder()
.templateName(record.getName())
.detailStyle(styleType)
.category(MessageTemplateCategoryUtil.parentCategory(record.getMsgCategory()))
.subCategory(MessageTemplateCategoryUtil.parseAndReturnSubCategory(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())
.detailStrategy(MessageRouterUtil.fetchBizDetailShowStrategy(msgTemplateRouter).orElse(null))
.routers(MessageRouterUtil.fetchMessageRouterButtonStrategies(msgTemplateRouter))
.minAppVersion(record.getMinAppVersion())
.createTimestamp(record.getCreateAt().getTime())
.updateTimestamp(record.getUpdateAt().getTime())
.createPersonId(record.getCreatePersonId())
.createPersonName(record.getCreatePersonName())
.updatePersonId(record.getUpdatePersonId())
.updatePersonName(record.getUpdatePersonName())
.pushData(record.getPushData())
.build();
}
private MessageTemplateRouterDTO buildTemplateRouter(MessageTemplateV3SaveOrUpdateParam param, String templateCode) {
MessageTemplateRouterDTO templateRouter = MessageTemplateRouterDTO.builder().build();
if (Objects.nonNull(param.getBizDetailShowStrategy())
&& CollectionUtils.isNotEmpty(param.getBizDetailShowStrategy().getTerminals())) {
MessageRouteDetailDTO detailRouter = MessageRouteDetailDTO.from(param.getBizDetailShowStrategy(), templateCode);
templateRouter.setRouteDetail(detailRouter);
}
if (CollectionUtils.isNotEmpty(param.getRouters())) {
List<MessageRouteButtonDTO> btnRouters = param.getRouters().stream()
.filter(MessageButtonRouteStrategyDTO::isValid)
.map(e -> MessageRouteButtonDTO.from(e, templateCode))
.collect(Collectors.toList());
templateRouter.setRouteButtons(btnRouters);
}
return templateRouter;
}
}

View File

@ -0,0 +1,18 @@
package cn.axzo.msg.center.service.domain;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class CardUrlConfig {
/**
* 链接配置
*/
private UrlConfig urlConfig;
}

View File

@ -0,0 +1,25 @@
package cn.axzo.msg.center.service.domain;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* @author yanglin
*/
@Setter
@Getter
public class GroupConfig {
/**
* key/value的配置
*/
private List<KVConfig> keyValues;
/**
* 详情的配置
*/
private UrlConfig detail;
}

View File

@ -0,0 +1,33 @@
package cn.axzo.msg.center.service.domain;
import cn.axzo.msg.center.service.enums.KVContentType;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class KVConfig {
/**
* 内容的类型. TEXT: 文本, PHONE: 手机号, ATTACHMENT: 附件, PERSON_ID: 自然人ID
*/
private KVContentType contentType;
/**
* : 项目
*/
private String key;
/**
* : ${workspaceId}
*/
private String value;
/**
* 是否显示在卡片上
*/
private boolean displayOnCard;
}

View File

@ -0,0 +1,24 @@
package cn.axzo.msg.center.service.domain;
import cn.axzo.msg.center.service.domain.url.AppUrl;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class MobileUrlConfig {
/**
* ios的url配置
*/
private AppUrl ios;
/**
* android的url配置
*/
private AppUrl android;
}

View File

@ -0,0 +1,39 @@
package cn.axzo.msg.center.service.domain;
import cn.axzo.msg.center.service.domain.url.WebUrl;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class UrlConfig {
/**
* PC(OMS)
*/
private WebUrl pcOms;
/**
* PC(CMS)
*/
private WebUrl pcCms;
/**
* 监管平台
*/
private WebUrl pcGaGeneral;
/**
* APP(工人端)
*/
private MobileUrlConfig appWorker;
/**
* APP(管理端)
*/
private MobileUrlConfig appManager;
}

View File

@ -0,0 +1,18 @@
package cn.axzo.msg.center.service.domain.url;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class AppUrl {
/**
* url地址
*/
private String url;
}

View File

@ -0,0 +1,24 @@
package cn.axzo.msg.center.service.domain.url;
import cn.axzo.msg.center.service.enums.WebPageOpenStrategy;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class WebUrl {
/**
* 网页打开方式. NEW_PAGE: 新页面打开, CURRENT_PAGE: 当前页面打开, DRAWER: 抽屉
*/
private WebPageOpenStrategy openStrategy;
/**
* url地址
*/
private String url;
}

View File

@ -0,0 +1,21 @@
package cn.axzo.msg.center.service.enums;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author yanglin
*/
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum CardUrlOpenStrategy {
NONE("无跳转"),
OPEN_TODO_DETAIL("打开待办详情"),
OPEN_CUSTOM_PAGE("打开指定页面")
;
private final String desc;
}

View File

@ -0,0 +1,20 @@
package cn.axzo.msg.center.service.enums;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author yanglin
*/
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum GroupType {
KV_VALUES("键值信息"),
COMPONENT_WORKER("工人卡片")
;
private final String desc;
}

View File

@ -0,0 +1,22 @@
package cn.axzo.msg.center.service.enums;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author yanglin
*/
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum KVContentType {
TEXT("文本"),
PHONE("手机号"),
ATTACHMENT("附件"),
PERSON_ID("自然人ID")
;
private final String desc;
}

View File

@ -22,6 +22,7 @@ public enum RouterCategoryEnum {
/**
* 接口调用
*/
@Deprecated
ACTION("接口调用"),
/**
* 预设按钮

View File

@ -0,0 +1,21 @@
package cn.axzo.msg.center.service.enums;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author yanglin
*/
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum WebPageOpenStrategy {
NEW_PAGE("新页面打开"),
CURRENT_PAGE("当前页面打开"),
DRAWER("抽屉")
;
private final String desc;
}

View File

@ -0,0 +1,103 @@
package cn.axzo.msg.center.service.template.client;
import cn.axzo.msg.center.service.template.request.MessageTemplateV3CreateRequest;
import cn.axzo.msg.center.service.template.request.MessageTemplatePageRequest;
import cn.axzo.msg.center.service.template.request.MessageTemplateSyncDto;
import cn.axzo.msg.center.service.template.request.MessageTemplateSyncQueryRequest;
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.MessageDetailStyle;
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 org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
/**
* 消息模板管理
*/
@Component
@FeignClient(value = "msg-center", url = "${server.serviceUrl:http://msg-center:8080}")
public interface MessageTemplateV3Client {
/**
* 添加消息模板
*
* @param request 模板数据模型
* @return 模板编码
*/
@PostMapping(value = "/message/template/add", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<String> save(@RequestBody @Valid MessageTemplateV3CreateRequest request);
/**
* 编辑消息模板
*
* @param request 模板数据模型
*/
@PostMapping(value = "/message/template/update", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Void> update(@RequestBody @Valid MessageTemplateUpdateRequest request);
/**
* 消息模板详情
*
* @param templateCode 消息模板编码
* @return 消息模板详情
*/
@PostMapping(value = "/message/template/detail", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<MessageTemplateDetailResponse> detail(@RequestParam("templateCode") String templateCode);
/**
* 分页查询模板
*
* @param request 分页查询参数
* @return 模板列表
*/
@PostMapping(value = "/message/template/page", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Page<MessageTemplatePageResponse>> page(@RequestBody MessageTemplatePageRequest request);
/**
* 通过模板编码查询对应的模板
*
* @param templateCodes 模板编码集合
* @return 模板列表
*/
@PostMapping(value = "/message/template/list", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<List<MessageTemplatePageResponse>> listByCodes(@RequestParam("templateCodes") Collection<String> templateCodes);
/**
* 启用/禁用消息模板
*
* @param request 模板状态
*/
@PostMapping(value = "/message/template/update-status", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Void> updateStatus(@RequestBody @Valid MessageTemplateUpdateStatusRequest request);
/**
* 查询消息模板
*/
@PostMapping(value = "/message/template/sync/get", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<MessageTemplateSyncDto> getSyncMessageTemplate(@RequestBody @Valid MessageTemplateSyncQueryRequest request);
/**
* 同步消息模板
* req-1896 说明仅pre环境能同步
*/
@PostMapping(value = "/message/template/sync", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<Void> syncTemplate(@RequestBody @Valid MessageTemplateSyncDto request);
/**
* 获取所有消息样式
*/
@GetMapping(value = "/message/template/list-template-detail-styles", produces = {MediaType.APPLICATION_JSON_VALUE})
CommonResponse<List<MessageDetailStyle>> listTemplateDetailStyles();
}

View File

@ -0,0 +1,39 @@
package cn.axzo.msg.center.service.template.request;
import cn.axzo.msg.center.service.domain.GroupConfig;
import cn.axzo.msg.center.service.enums.GroupType;
import lombok.Data;
import java.util.List;
/**
* @description
*
* @author cold_blade
* @date 2023/9/26
* @version 1.0
*/
@Data
public class MessageTemplateGroupV3CreateRequest {
/**
* 分组名称, 公共组件时为空
*/
private String name;
/**
* 分组类型. KV_VALUES: 卡片信息; COMPONENT_WORKER:工人卡片
*/
private GroupType groupType;
/**
* 排列顺序
*/
private Integer sortOrder;
/**
* 分组配置
*/
private GroupConfig groupConfig;
}

View File

@ -0,0 +1,113 @@
package cn.axzo.msg.center.service.template.request;
import cn.axzo.msg.center.service.dto.MessageButtonRouteStrategyDTO;
import cn.axzo.msg.center.service.dto.MessageCardContentItemDTO;
import cn.axzo.msg.center.service.dto.MessageDetailRouteStrategyDTO;
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
import cn.axzo.msg.center.service.enums.MessageGroupCategoryEnum;
import cn.axzo.msg.center.service.enums.PushTerminalEnum;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;
/**
* @description
*
* @author cold_blade
* @date 2023/9/26
* @version 1.0
*/
@Setter
@Getter
public class MessageTemplateV3CreateRequest implements Serializable {
private static final long serialVersionUID = -2894419272913799317L;
/**
* 操作者的自然人id
*/
@NotNull(message = "operatorId is required")
private Long operatorId;
/**
* 操作人人姓名
*/
private String operatorName;
/**
* 模板名称
*/
@NotBlank(message = "templateName is required")
private String templateName;
/**
* 消息类型
* NOTIFICATION: 通知
* PENDING: 待办
*/
@NotNull(message = "category is required")
private MessageGroupCategoryEnum category;
/**
* 消息类型
* BIZ_PENDING_MESSAGE: 业务待办
* APPROVAL_PENDING_MESSAGE: 审批待办
*/
private MessageCategoryEnum subCategory;
/**
* 消息分类树的叶结点的结点编码列表
*/
@NotEmpty(message = "leafGroupNodes is required")
private List<String> leafGroupNodes;
/**
* 推送终端配置
* B_ENTERPRISE_APP: B-安心筑企业版
* C_WORKER_APP: C-安心筑工人版
*/
private List<PushTerminalEnum> pushTerminals;
/**
* 该模板最低支持的APP版本号
*/
private String minAppVersion;
/**
* 消息标题
*/
@NotBlank(message = "msgTitle is required")
private String msgTitle;
/**
* 消息内容
*/
@NotBlank(message = "msgContent is required")
private String msgContent;
/**
* 消息图标
*/
private String msgIcon;
/**
* 消息卡片信息标签列表可为空
*/
private List<MessageTemplateGroupV3CreateRequest> messageTemplateGroups;
/**
* 详情展示策略
*/
private MessageDetailRouteStrategyDTO detailStrategy;
/**
* 路由策略列表
*/
private List<MessageButtonRouteStrategyDTO> routers;
/**
* 待办样式, BIZ_COMMON: 业务待办能用, FLOW_COMMON: 审批待办能用, 其它动态配置的
*/
private String detailStyleCode;
private JSONObject pushData;
@Override
public String toString() {
return JSON.toJSONString(this);
}
}

View File

@ -0,0 +1,15 @@
package cn.axzo.msg.center.dal;
import cn.axzo.msg.center.dal.mapper.MessageTemplateButtonV3Mapper;
import cn.axzo.msg.center.domain.entity.MessageTemplateButtonV3;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author yanglin
*/
@Slf4j
@Component
public class MessageTemplateButtonV3Dao extends ServiceImpl<MessageTemplateButtonV3Mapper, MessageTemplateButtonV3> {
}

View File

@ -0,0 +1,15 @@
package cn.axzo.msg.center.dal;
import cn.axzo.msg.center.dal.mapper.MessageTemplateGroupV3Mapper;
import cn.axzo.msg.center.domain.entity.MessageTemplateGroupV3;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author yanglin
*/
@Slf4j
@Component
public class MessageTemplateGroupV3Dao extends ServiceImpl<MessageTemplateGroupV3Mapper, MessageTemplateGroupV3> {
}

View File

@ -0,0 +1,15 @@
package cn.axzo.msg.center.dal;
import cn.axzo.msg.center.dal.mapper.MessageTemplateV3Mapper;
import cn.axzo.msg.center.domain.entity.MessageTemplateV3;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author yanglin
*/
@Slf4j
@Component
public class MessageTemplateV3Dao extends ServiceImpl<MessageTemplateV3Mapper, MessageTemplateV3> {
}

View File

@ -0,0 +1,12 @@
package cn.axzo.msg.center.dal.mapper;
import cn.axzo.msg.center.domain.entity.MessageTemplateButtonV3;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author yanglin
*/
@Mapper
public interface MessageTemplateButtonV3Mapper extends BaseMapper<MessageTemplateButtonV3> {
}

View File

@ -0,0 +1,12 @@
package cn.axzo.msg.center.dal.mapper;
import cn.axzo.msg.center.domain.entity.MessageTemplateGroupV3;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author yanglin
*/
@Mapper
public interface MessageTemplateGroupV3Mapper extends BaseMapper<MessageTemplateGroupV3> {
}

View File

@ -0,0 +1,12 @@
package cn.axzo.msg.center.dal.mapper;
import cn.axzo.msg.center.domain.entity.MessageTemplateV3;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author yanglin
*/
@Mapper
public interface MessageTemplateV3Mapper extends BaseMapper<MessageTemplateV3> {
}

View File

@ -0,0 +1,31 @@
package cn.axzo.msg.center.domain.entity;
import cn.axzo.msg.center.domain.persistence.BaseEntityExt;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
/**
* @author yanglin
*/
@Data
public abstract class BaseEntityWithOperator<T extends Model<T>> extends BaseEntityExt<T> {
/**
* 创建人id
*/
private Long createPersonId;
/**
* 创建人姓名
*/
private String createPersonName;
/**
* 更新人id
*/
private Long updatePersonId;
/**
* 更新人姓名
*/
private String updatePersonName;
}

View File

@ -0,0 +1,74 @@
package cn.axzo.msg.center.domain.entity;
import cn.axzo.msg.center.service.domain.UrlConfig;
import cn.axzo.msg.center.service.enums.PresetButtonType;
import cn.axzo.msg.center.service.enums.RouterButtonSourceEnum;
import cn.axzo.msg.center.service.enums.RouterCategoryEnum;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
@TableName(value = "message_template_button_v3", autoResultMap = true)
public class MessageTemplateButtonV3 extends BaseEntityWithOperator<MessageTemplateButtonV3> {
/**
* 按钮名称
*/
private String name;
/**
* 模板code
*/
private String templateCode;
/**
* 预设按钮类型
*/
private PresetButtonType presetBtnCode;
/**
* 按钮来源
*/
private RouterButtonSourceEnum source;
/**
* 路由类型
*/
private RouterCategoryEnum category;
/**
* 按钮链接配置
*/
@TableField(typeHandler = FastjsonTypeHandler.class)
private UrlConfig urlConfig;
/**
* 按钮style配置
*/
@TableField(typeHandler = FastjsonTypeHandler.class)
private JSONArray style;
/**
* 执行人可见true 不可见false
*/
private Boolean executorShow;
/**
* 待办状态可见可见true 不可见false
*/
private Boolean pendingShow;
/**
* 按钮优先级数值越大优先级越低
*/
private Integer priority;
}

View File

@ -0,0 +1,45 @@
package cn.axzo.msg.center.domain.entity;
import cn.axzo.msg.center.service.domain.GroupConfig;
import cn.axzo.msg.center.service.enums.GroupType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
@TableName(value = "message_template_group_v3", autoResultMap = true)
public class MessageTemplateGroupV3 extends BaseEntityWithOperator<MessageTemplateGroupV3> {
/**
* 分组名称, 公共组件时为空
*/
private String name;
/**
* 模板code
*/
private String templateCode;
/**
* 分组类型. KV_VALUES: 键值信息; COMPONENT_WORKER:工人卡片
*/
private GroupType groupType;
/**
* 排列顺序
*/
private Integer sortOrder;
/**
* 分组配置
*/
@TableField(typeHandler = FastjsonTypeHandler.class)
private GroupConfig groupConfig;
}

View File

@ -0,0 +1,99 @@
package cn.axzo.msg.center.domain.entity;
import cn.axzo.msg.center.service.domain.CardUrlConfig;
import cn.axzo.msg.center.service.enums.CardUrlOpenStrategy;
import cn.axzo.msg.center.service.enums.MessageCategoryEnum;
import cn.axzo.msg.center.service.enums.StatusEnum;
import cn.axzo.msg.center.service.enums.YesOrNo;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
@TableName(value = "message_template_v3", autoResultMap = true)
public class MessageTemplateV3 extends BaseEntityWithOperator<MessageTemplateV3> {
/**
* 模板名称
*/
private String name;
/**
* 系统自动生成的模板code
*/
private String code;
/**
* 所属消息类型
*/
private MessageCategoryEnum msgCategory;
/**
* 模板标题
*/
private String title;
/**
* 模板类容
*/
private String content;
/**
* 消息详情样式. BIZ_COMMON: 业务待办能用, FLOW_COMMON: 审批待办能用, 其它动态配置的
*/
private String detailStyleCode;
/**
* 模板icon
*/
private String icon;
/**
* APP最小版本支持可不配
*/
private String minAppVersion;
/**
* 模板状态
*/
private StatusEnum status;
/**
* 推送终端配置 JSON字串
*/
private String pushTerminal;
/**
* 卡片跳转方式. NONE: 无跳转, OPEN_TODO_DETAIL: 打开待办详情, OPEN_CUSTOM_PAGE: 打开指定页面
*/
private CardUrlOpenStrategy cardUrlOpenStrategy;
/**
* 卡片跳转配置. 在links的基础上再包一层, 避免以后卡片增加自己的配置
*/
@TableField(typeHandler = FastjsonTypeHandler.class)
private CardUrlConfig cardUrConfig;
/**
* IM发送优先级
*/
private Integer imSendPriority;
/**
* push配置
*/
@TableField(typeHandler = FastjsonTypeHandler.class)
private JSONObject pushData;
/**
* 是否显示在列表中. YES: , NO:
*/
private YesOrNo displayOnList;
}

View File

@ -1,31 +0,0 @@
package cn.axzo.msg.center.api;
import cn.axzo.msg.center.MsgCenterApplication;
import cn.axzo.msg.center.api.request.v4.MessageSendRequestV4;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Commit;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author yanglin
*/
@SpringBootTest(classes = MsgCenterApplication.class)
@RequiredArgsConstructor(onConstructor_ = @Autowired)
class MessageAPIV4Test {
private final MessageAPIV4 messageAPIV4;
@Test @Transactional @Commit
void exec() {
String json = "{\"eventMappingCode\":\"gaia_projectComplete_closeOrCancel_workpoint\",\"sendBasicInfo\":{\"bizCode\":\"421\",\"bizExtParams\":{\"reason\":\"记工单关联的部分工程已完结\",\"count\":\"1 单\",\"type\":\"系统自动撤销记工单\"},\"receivers\":[{\"id\":2810}],\"receiversOrgType\":\"PROJECT\",\"receiversOuId\":6458,\"receiversWorkspaceId\":326,\"routerParams\":{\"projectId\":421,\"workspaceId\":326}},\"templates\":[{\"channel\":\"NOTIFICATION\",\"templateCodes\":[\"75d88ddae7914c7089b67d944357fa1c\"]}]}";
MessageSendRequestV4 request = JSON.parseObject(json, MessageSendRequestV4.class);;
messageAPIV4.send(request);
}
}