Merge branch 'feature-REQ/2129' into 'master'
Feature req/2129 See merge request universal/infrastructure/backend/nanopart!24
This commit is contained in:
commit
ce65586d7b
@ -96,6 +96,33 @@
|
||||
<artifactId>black-list-service</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.nanopart</groupId>
|
||||
<artifactId>op-api</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.nanopart</groupId>
|
||||
<artifactId>op-server</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.im.center</groupId>
|
||||
<artifactId>im-center-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.basics</groupId>
|
||||
<artifactId>basics-profiles-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework.rocketmq</groupId>
|
||||
<artifactId>axzo-common-rocketmq</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -1,17 +1,20 @@
|
||||
package cn.axzo.nanopart;
|
||||
|
||||
import cn.axzo.nanopart.config.RocketMQEventConfiguration;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@MapperScan(value = {"cn.axzo.**.mapper"})
|
||||
@SpringBootApplication
|
||||
@EnableFeignClients(basePackages = {
|
||||
"cn.axzo.nanopart.api"
|
||||
"cn.axzo"
|
||||
})
|
||||
@EnableAspectJAutoProxy()
|
||||
@Import(RocketMQEventConfiguration.class)
|
||||
public class NanopartApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(NanopartApplication.class, args);
|
||||
|
||||
@ -0,0 +1,138 @@
|
||||
package cn.axzo.nanopart.config;
|
||||
|
||||
import cn.azxo.framework.common.constatns.Constants;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
import feign.Target.HardCodedTarget;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author liuyang
|
||||
* @date 2020/10/24
|
||||
**/
|
||||
@Component
|
||||
@Slf4j
|
||||
@Profile({"dev", "test", "local", "pre"})
|
||||
public class FeignConfig implements RequestInterceptor, EnvironmentAware {
|
||||
private Environment environment;
|
||||
@Value("${maokaiEnvUrl:http://dev-app.axzo.cn/maokai}")
|
||||
private String maokaiEnvUrl;
|
||||
@Value("${apolloEnvUrl:http://dev-app.axzo.cn/apollo}")
|
||||
private String apolloEnvUrl;
|
||||
@Value("${mnsEnvUrl:http://dev-app.axzo.cn/mns}")
|
||||
private String mnsEnvUrl;
|
||||
@Value("${pudgeEnvUrl:http://dev-app.axzo.cn/pudge}")
|
||||
private String pudgeEnvUrl;
|
||||
@Value("${outmanEnvUrl:http://dev-app.axzo.cn/outman}")
|
||||
private String outmanEnvUrl;
|
||||
@Value("${thronesEnvUrl:http://dev-app.axzo.cn/thrones}")
|
||||
private String thronesEnvUrl;
|
||||
@Value("${workspaceEnvUrl:http://dev-app.axzo.cn/workspace}")
|
||||
private String workspaceEnvUrl;
|
||||
@Value("${thirdPartUrl:http://dev-app.axzo.cn/thirdParty}")
|
||||
private String thirdPartUrl;
|
||||
@Value("${nanopartUrl:http://dev-app.axzo.cn/nanopart}")
|
||||
private String nanopartUrl;
|
||||
@Value("${tyrEnvUrl:http://dev-app.axzo.cn/tyr}")
|
||||
private String tyrEnvUrl;
|
||||
@Value("${plutoEnvUrl:http://dev-app.axzo.cn/pluto}")
|
||||
private String plutoUrl;
|
||||
@Value("${sennaEnvUrl:http://dev-app.axzo.cn/senna}")
|
||||
private String sennaEnvUrl;
|
||||
@Value("${workflowEngineEnvUrl:http://dev-app.axzo.cn/workflow-engine}")
|
||||
private String workflowEngineEnvUrl;
|
||||
@Value("${msgCenterEngineEnvUrl:http://dev-app.axzo.cn/msg-center}")
|
||||
private String msgCenterEngineEnvUrl;
|
||||
@Value("${imCenterEnvUrl:http://dev-app.axzo.cn/im-center}")
|
||||
private String imCenterEnvUrl;
|
||||
@Value("${msgCenterEngineEnvUrl:http://dev-app.axzo.cn/braum}")
|
||||
private String braumEnvUrl;
|
||||
@Value("${labourEnvUrl:http://dev-app.axzo.cn/labour}")
|
||||
private String labourEvnUrl;
|
||||
@Value("${epicEnvUrl:http://dev-app.axzo.cn/epic}")
|
||||
private String epicEnvUrl;
|
||||
@Value("${karmaEnvUrl:http://dev-app.axzo.cn/karma}")
|
||||
private String karmaEnvUrl;
|
||||
@Value("${dataCollectionUrl:http://dev-app.axzo.cn/dataCollection}")
|
||||
private String dataCollectionUrl;
|
||||
@Value("${attendanceUrl:http://dev-app.axzo.cn/attendance}")
|
||||
private String attendanceApi;
|
||||
private static String POD_NAMESPACE;
|
||||
|
||||
static {
|
||||
Map<String, String> env = System.getenv();
|
||||
if (env != null) {
|
||||
POD_NAMESPACE = env.get("MY_POD_NAMESPACE");
|
||||
}
|
||||
log.info("init FeignConfig, POD_NAMESPACE value is {}", POD_NAMESPACE);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void apply(RequestTemplate requestTemplate) {
|
||||
if (POD_NAMESPACE == null) {
|
||||
HardCodedTarget target = (HardCodedTarget) requestTemplate.feignTarget();
|
||||
String url = requestTemplate.feignTarget().url();
|
||||
// 如需修改微服务地址,建议通过外部化参数来调整
|
||||
url = url.replace("http://maokai:8080", maokaiEnvUrl);
|
||||
url = url.replace("http://apollo:11000", apolloEnvUrl);
|
||||
url = url.replace("http://mns:8989", mnsEnvUrl);
|
||||
url = url.replace("http://pudge:10099", pudgeEnvUrl);
|
||||
url = url.replace("http://outman:8989", outmanEnvUrl);
|
||||
url = url.replace("http://thrones", thronesEnvUrl);
|
||||
url = url.replace("http://workspace:8080", workspaceEnvUrl);
|
||||
url = url.replace("http://third-party:11000", thirdPartUrl);
|
||||
url = url.replace("http://nanopart:8080", nanopartUrl);
|
||||
url = url.replace("http://tyr:8080", tyrEnvUrl);
|
||||
url = url.replace("http://pluto:8080", plutoUrl);
|
||||
url = url.replace("http://senna:8080", sennaEnvUrl);
|
||||
url = url.replace("http://workflow-engine:8080", workflowEngineEnvUrl);
|
||||
url = url.replace("http://msg-center:8080", msgCenterEngineEnvUrl);
|
||||
url = url.replace("http://im-center:8080", imCenterEnvUrl);
|
||||
url = url.replace("http://braum:8080", braumEnvUrl);
|
||||
url = url.replace("http://labour:8080", labourEvnUrl);
|
||||
url = url.replace("http://epic:8080", epicEnvUrl);
|
||||
url = url.replace("http://karma:8080", karmaEnvUrl);
|
||||
url = url.replace("http://data-collection:21200", dataCollectionUrl);
|
||||
url = url.replace("http://attendance:8080", attendanceApi);
|
||||
String profile = environment.getProperty("spring.profiles.active");
|
||||
if(Objects.equals(profile, "test") && url.contains("dev-app.axzo.cn")) {
|
||||
url = url.replace("dev-app", "test-api");
|
||||
}
|
||||
if(Objects.equals(profile, "pre") && url.contains("dev-app.axzo.cn")) {
|
||||
url = url.replace("dev-app", "pre-api");
|
||||
}
|
||||
if(Objects.equals(profile, "live") && url.contains("dev-app.axzo.cn")) {
|
||||
url = url.replace("dev-app", "live-api");
|
||||
}
|
||||
requestTemplate.target(url);
|
||||
Field field = ReflectUtil.getField(target.getClass(), "url");
|
||||
field.setAccessible(true);
|
||||
field.set(target, url);
|
||||
}
|
||||
requestTemplate.header(Constants.CTX_LOG_ID_MDC, MDC.get(Constants.CTX_LOG_ID_MDC));
|
||||
requestTemplate.header("X-SERVER-NAME", environment.getProperty("spring.application.name"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@code Environment} that this component runs in.
|
||||
*
|
||||
* @param environment
|
||||
*/
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package cn.axzo.nanopart.config;
|
||||
|
||||
import cn.axzo.framework.rocketmq.BaseListener;
|
||||
import cn.axzo.framework.rocketmq.DefaultEventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandlerRepository;
|
||||
import cn.axzo.framework.rocketmq.EventProducer;
|
||||
import cn.axzo.framework.rocketmq.RocketMQEventProducer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @Author: liyong.tian
|
||||
* @Date: 2023/7/25 14:43
|
||||
* @Description:
|
||||
*/
|
||||
@Slf4j
|
||||
public class RocketMQEventConfiguration {
|
||||
|
||||
@Value("${spring.application.name}")
|
||||
private String appName;
|
||||
|
||||
@Value("${topic}")
|
||||
private String topic;
|
||||
|
||||
@Bean
|
||||
public RocketMQTemplate ser(){
|
||||
return new RocketMQTemplate();
|
||||
}
|
||||
@Bean
|
||||
EventProducer eventProducer(RocketMQTemplate rocketMQTemplate) {
|
||||
return new RocketMQEventProducer(rocketMQTemplate,
|
||||
"nanopart",
|
||||
appName,
|
||||
EventProducer.Context.<RocketMQEventProducer.RocketMQMessageMeta>builder()
|
||||
.meta(RocketMQEventProducer.RocketMQMessageMeta.builder()
|
||||
.topic(topic)
|
||||
.build())
|
||||
.build(),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@Bean
|
||||
EventConsumer eventConsumer(EventHandlerRepository eventHandlerRepository) {
|
||||
Consumer<EventConsumer.EventWrapper> callback = (eventWrapper) -> {
|
||||
if (eventWrapper.isHandled()) {
|
||||
// 只收集被App真正消费的消息.
|
||||
//String topic = (String) eventWrapper.getExt().get(EVENT_TOPIC_KEY);
|
||||
|
||||
}
|
||||
};
|
||||
return new DefaultEventConsumer(appName, eventHandlerRepository, callback);
|
||||
}
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RocketMQMessageListener(topic = "topic_im_center_${spring.profiles.active}",
|
||||
consumerGroup = "GID_topic_im_center_${spring.application.name}_${spring.profiles.active}",
|
||||
consumeMode = ConsumeMode.ORDERLY,
|
||||
nameServer = "${rocketmq.name-server}"
|
||||
)
|
||||
public static class DefaultListener extends BaseListener implements RocketMQListener<MessageExt> {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
|
||||
@Override
|
||||
public void onMessage(MessageExt message) {
|
||||
super.onEvent(message, eventConsumer);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
EventHandlerRepository eventHandlerRepository() {
|
||||
return new EventHandlerRepository((ex, logText) -> {
|
||||
log.warn("MQ, handle warning {}", logText, ex);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package cn.axzo.nanopart.config;
|
||||
|
||||
import cn.azxo.framework.common.logger.JobLoggerTemplate;
|
||||
import cn.azxo.framework.common.service.JobParamResolver;
|
||||
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* xxl-job config
|
||||
*
|
||||
* @author xuxueli 2017-04-28
|
||||
*/
|
||||
@Configuration
|
||||
public class XxlJobConfig {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
|
||||
|
||||
// @Value("http://dev-xxl-job.axzo.cn/xxl-job-admin")
|
||||
@Value("${xxl.job.admin.addresses}")
|
||||
private String adminAddresses;
|
||||
|
||||
@Value("${xxl.job.executor.appname}")
|
||||
private String appName;
|
||||
|
||||
@Value("")
|
||||
private String ip;
|
||||
|
||||
@Value("${xxl.job.executor.port}")
|
||||
private int port;
|
||||
|
||||
// @Value("${xxl.job.accessToken}")
|
||||
@Value("")
|
||||
private String accessToken;
|
||||
|
||||
@Value("")
|
||||
private String logPath;
|
||||
|
||||
@Value("-1")
|
||||
private int logRetentionDays;
|
||||
|
||||
@Bean
|
||||
public XxlJobSpringExecutor xxlJobExecutor() {
|
||||
logger.info(">>>>>>>>>>> xxl-job config init.");
|
||||
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
|
||||
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
|
||||
xxlJobSpringExecutor.setAppname(appName);
|
||||
xxlJobSpringExecutor.setIp(ip);
|
||||
xxlJobSpringExecutor.setPort(port);
|
||||
xxlJobSpringExecutor.setAccessToken(accessToken);
|
||||
xxlJobSpringExecutor.setLogPath(logPath);
|
||||
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
|
||||
|
||||
return xxlJobSpringExecutor;
|
||||
}
|
||||
|
||||
@Bean("jobParamResolver")
|
||||
public JobParamResolver jobParamResolver() {
|
||||
return new JobParamResolver();
|
||||
}
|
||||
|
||||
@Bean("jobLoggerTemplate")
|
||||
public JobLoggerTemplate jobLoggerTemplate() {
|
||||
return new JobLoggerTemplate();
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package cn.axzo.nanopart.config.exception;
|
||||
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.pokonyan.exception.BusinessException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@ -41,6 +42,12 @@ public class ExceptionAdviceHandler {
|
||||
return ApiResult.err(e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(BusinessException.class)
|
||||
public ApiResult<Void> businessExceptionHandler(BusinessException e){
|
||||
log.warn("业务异常", e);
|
||||
return ApiResult.err(e.getErrorMsg());
|
||||
}
|
||||
|
||||
@ExceptionHandler(BindException.class)
|
||||
public ApiResult<Void> bindExceptionHandler(BindException e) {
|
||||
log.warn("业务异常", e);
|
||||
|
||||
1
op/README.md
Normal file
1
op/README.md
Normal file
@ -0,0 +1 @@
|
||||
# 项目介绍
|
||||
2
op/RELEASE.md
Normal file
2
op/RELEASE.md
Normal file
@ -0,0 +1,2 @@
|
||||
# 发布记录
|
||||
|
||||
38
op/op-api/pom.xml
Normal file
38
op/op-api/pom.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>op</artifactId>
|
||||
<groupId>cn.axzo.nanopart</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>op-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>op-api</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-common-domain</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.basics</groupId>
|
||||
<artifactId>basics-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.basics</groupId>
|
||||
<artifactId>basics-profiles-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
342
op/op-api/src/main/java/cn/axzo/op/api/OpMessageConfigApi.java
Normal file
342
op/op-api/src/main/java/cn/axzo/op/api/OpMessageConfigApi.java
Normal file
@ -0,0 +1,342 @@
|
||||
package cn.axzo.op.api;
|
||||
|
||||
import cn.axzo.framework.domain.web.result.ApiPageResult;
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@FeignClient(name = "nanopart", url = "${axzo.service.nanopart:http://nanopart:8080}")
|
||||
public interface OpMessageConfigApi {
|
||||
|
||||
@PostMapping("/api/op-message-config/page")
|
||||
ApiPageResult<OpMessageConfigResp> page(@RequestBody PageOpMessageConfigReq req);
|
||||
|
||||
@PostMapping("/api/op-message-config/create")
|
||||
ApiResult<OpMessageConfigBaseResp> create(@Valid @RequestBody CreateOpMessageConfigParam req);
|
||||
|
||||
@PostMapping("/api/op-message-config/delete")
|
||||
ApiResult<Void> delete(@Valid @RequestBody DeleteOpMessageConfigParam param);
|
||||
|
||||
@PostMapping("/api/op-message-config/update")
|
||||
ApiResult<OpMessageConfigBaseResp> update(@Valid @RequestBody UpdateOpMessageConfigParam param);
|
||||
|
||||
@PostMapping("/api/op-message-config/draft/save")
|
||||
ApiResult<OpMessageConfigBaseResp> saveDraft(@Valid @RequestBody SaveDraftOpMessageConfigParam req);
|
||||
|
||||
@PostMapping("/api/op-message-config/draft/submit")
|
||||
ApiResult<OpMessageConfigBaseResp> submitDraft(@Valid @RequestBody SaveDraftOpMessageConfigParam req);
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class UpdateOpMessageConfigParam {
|
||||
|
||||
@NotNull(message = "id不能为空")
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String sendImAccount;
|
||||
|
||||
private JSONObject receiveData;
|
||||
|
||||
private ActionEnum action;
|
||||
|
||||
private String title;
|
||||
|
||||
private String content;
|
||||
|
||||
private String contentType;
|
||||
|
||||
private String coverImg;
|
||||
|
||||
private JSONObject jumpData;
|
||||
|
||||
private JSONObject pushData;
|
||||
|
||||
private JSONObject ext;
|
||||
|
||||
private Date planStartTime;
|
||||
|
||||
@NotNull(message = "operatePersonId不能为空")
|
||||
private Long operatePersonId;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
enum ActionEnum {
|
||||
SUBMIT_DRAFT
|
||||
}
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class DeleteOpMessageConfigParam {
|
||||
|
||||
@NotNull(message = "id不能为空")
|
||||
private Long id;
|
||||
|
||||
@NotNull(message = "operatePersonId不能为空")
|
||||
private Long operatePersonId;
|
||||
}
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class CreateOpMessageConfigParam {
|
||||
private String name;
|
||||
|
||||
private String sendImAccount;
|
||||
|
||||
private JSONObject receiveData;
|
||||
|
||||
private Status status;
|
||||
|
||||
private String title;
|
||||
|
||||
private String content;
|
||||
|
||||
private String contentType;
|
||||
|
||||
private String coverImg;
|
||||
|
||||
private JSONObject jumpData;
|
||||
|
||||
private JSONObject pushData;
|
||||
|
||||
private JSONObject ext;
|
||||
|
||||
private Date planStartTime;
|
||||
|
||||
@NotNull(message = "operatePersonId不能为空")
|
||||
private Long operatePersonId;
|
||||
}
|
||||
|
||||
@SuperBuilder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ListOpMessageConfigReq {
|
||||
|
||||
private List<Long> ids;
|
||||
|
||||
private Date planStartTimeLE;
|
||||
|
||||
private List<String> statuses;
|
||||
|
||||
private String nameLike;
|
||||
|
||||
private String sendImAccount;
|
||||
|
||||
private String sendImAccountLike;
|
||||
|
||||
private String contentType;
|
||||
|
||||
private List<String> receivePlatforms;
|
||||
|
||||
/**
|
||||
* 返回发送的信息:
|
||||
* IM机器人账号:返回头像、名字等信息
|
||||
* 账号有机器人和系统人员信息,查询的接口不同
|
||||
*/
|
||||
private boolean needSendUserInfo;
|
||||
|
||||
/**
|
||||
* 返回创建人的信息
|
||||
*/
|
||||
private boolean needCreatePersonInfo;
|
||||
|
||||
/**
|
||||
* 返回提交审核人的信息
|
||||
*/
|
||||
private boolean needSubmitPersonInfo;
|
||||
}
|
||||
|
||||
@SuperBuilder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class PageOpMessageConfigReq extends ListOpMessageConfigReq {
|
||||
Integer page;
|
||||
|
||||
Integer pageSize;
|
||||
|
||||
/**
|
||||
* 排序:使用示例,createTime__DESC
|
||||
*/
|
||||
List<String> sort;
|
||||
}
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class OpMessageConfigResp extends OpMessageConfigBaseResp {
|
||||
private SendUserInfo sendUserInfo;
|
||||
|
||||
private PersonProfileDto createPersonProfile;
|
||||
|
||||
private PersonProfileDto submitPersonProfile;
|
||||
}
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class PersonProfileDto {
|
||||
|
||||
private String phone;
|
||||
private String realName;
|
||||
}
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class OpMessageConfigBaseResp {
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* im-center服务im_message_task的id
|
||||
*/
|
||||
private Long imMessageTaskId;
|
||||
|
||||
/**
|
||||
* 消息名字
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 发送者的三方平台账号id
|
||||
*/
|
||||
private String sendImAccount;
|
||||
|
||||
/**
|
||||
* 消息接收配置
|
||||
*/
|
||||
private JSONObject receiveData;
|
||||
|
||||
private String status;
|
||||
|
||||
private String title;
|
||||
|
||||
private String content;
|
||||
|
||||
private String contentType;
|
||||
|
||||
private String coverImg;
|
||||
|
||||
private JSONObject jumpData;
|
||||
|
||||
private JSONObject pushData;
|
||||
|
||||
private JSONObject ext;
|
||||
|
||||
private Date planStartTime;
|
||||
|
||||
private Date startedTime;
|
||||
|
||||
private Date finishedTime;
|
||||
|
||||
private Integer isDelete;
|
||||
|
||||
private Date createAt;
|
||||
|
||||
private Date updateAt;
|
||||
|
||||
private Long createPersonId;
|
||||
|
||||
/**
|
||||
* 删除人id
|
||||
*/
|
||||
private Long deletePersonId;
|
||||
|
||||
/**
|
||||
* 更新人id
|
||||
*/
|
||||
private Long updatePersonId;
|
||||
|
||||
private Date submitTime;
|
||||
}
|
||||
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class SendUserInfo {
|
||||
|
||||
/**
|
||||
* im账号
|
||||
*/
|
||||
private String imAccount;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
private String nickName;
|
||||
|
||||
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
private String headImageUrl;
|
||||
}
|
||||
|
||||
enum Status {
|
||||
DRAFT,
|
||||
PENDING,
|
||||
RUNNING,
|
||||
COMPLETED,
|
||||
;
|
||||
}
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class SaveDraftOpMessageConfigParam {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String sendImAccount;
|
||||
|
||||
private JSONObject receiveData;
|
||||
|
||||
private String title;
|
||||
|
||||
private String content;
|
||||
|
||||
private String contentType;
|
||||
|
||||
private String coverImg;
|
||||
|
||||
private JSONObject jumpData;
|
||||
|
||||
private JSONObject pushData;
|
||||
|
||||
private JSONObject ext;
|
||||
|
||||
private Date planStartTime;
|
||||
|
||||
@NotNull(message = "operatePersonId不能为空")
|
||||
private Long operatePersonId;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package cn.axzo.op.api.config;
|
||||
|
||||
import cn.axzo.op.api.constant.NanopartConstant;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@EnableFeignClients(NanopartConstant.BASIC_FEIGN_PACKAGE)
|
||||
public class NanopartApiAutoConfiguration {
|
||||
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package cn.axzo.op.api.constant;
|
||||
|
||||
/**
|
||||
* @author: chenwenjian
|
||||
* @date: 2023/8/14 9:38
|
||||
* @description:
|
||||
* @modifiedBy:
|
||||
* @version: 1.0
|
||||
*/
|
||||
public class NanopartConstant {
|
||||
|
||||
public static final String BASIC_FEIGN_PACKAGE = "cn.axzo";
|
||||
}
|
||||
2
op/op-api/src/main/resources/META-INF/spring.factories
Normal file
2
op/op-api/src/main/resources/META-INF/spring.factories
Normal file
@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.axzo.nanopart.api.config.NanopartApiAutoConfiguration
|
||||
99
op/op-server/pom.xml
Normal file
99
op/op-server/pom.xml
Normal file
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>cn.axzo.nanopart</groupId>
|
||||
<artifactId>op</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>op-server</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>op-server</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-web-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-spring-cloud-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-consumer-spring-cloud-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-processor-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!--mybatis-plus-->
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-mybatisplus-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- swagger-yapi -->
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-swagger-yapi-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.basics</groupId>
|
||||
<artifactId>basics-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-logger-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.nanopart</groupId>
|
||||
<artifactId>op-api</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.pokonyan</groupId>
|
||||
<artifactId>pokonyan</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.im.center</groupId>
|
||||
<artifactId>im-center-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.basics</groupId>
|
||||
<artifactId>basics-profiles-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework.rocketmq</groupId>
|
||||
<artifactId>axzo-common-rocketmq</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.msgcenter</groupId>
|
||||
<artifactId>msg-center-api</artifactId>
|
||||
<version>1.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -0,0 +1,20 @@
|
||||
package cn.axzo.nanopart.server.config;
|
||||
|
||||
import cn.axzo.pokonyan.exception.ResultCode;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum BizResultCode implements ResultCode {
|
||||
|
||||
OP_MESSAGE_CONFIG_NOT_FOUND("100", "运营消息配置不存在"),
|
||||
DELETE_OP_MESSAGE_CONFIG_STATUS_ERROR("101", "删除运营消息配置失败,状态异常"),
|
||||
UPDATE_OP_MESSAGE_CONFIG_STATUS_ERROR("102", "更新运营消息配置失败,状态异常"),
|
||||
OP_MESSAGE_CONFIG_ID_NOT_NULL("103", "id不能为空"),
|
||||
OP_MESSAGE_CONFIG_STATUS_ERROR("104", "操作运营消息配置失败,状态异常"),;
|
||||
|
||||
|
||||
private String errorCode;
|
||||
private String errorMessage;
|
||||
}
|
||||
@ -0,0 +1,152 @@
|
||||
package cn.axzo.nanopart.server.controller;
|
||||
|
||||
import cn.axzo.framework.domain.web.result.ApiPageResult;
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.nanopart.server.domain.OpMessageConfig;
|
||||
import cn.axzo.nanopart.server.service.OpMessageConfigService;
|
||||
import cn.axzo.op.api.OpMessageConfigApi;
|
||||
import cn.axzo.pokonyan.exception.Aassert;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static cn.axzo.nanopart.server.config.BizResultCode.OP_MESSAGE_CONFIG_ID_NOT_NULL;
|
||||
|
||||
@RestController
|
||||
public class OpMessageConfigController implements OpMessageConfigApi {
|
||||
|
||||
|
||||
@Autowired
|
||||
private OpMessageConfigService opMessageConfigService;
|
||||
|
||||
@Override
|
||||
public ApiPageResult<OpMessageConfigResp> page(PageOpMessageConfigReq param) {
|
||||
OpMessageConfigService.PageOpMessageConfigParam pageOpMessageConfigParam = OpMessageConfigService.PageOpMessageConfigParam.builder().build();
|
||||
BeanUtils.copyProperties(param, pageOpMessageConfigParam);
|
||||
|
||||
Page<OpMessageConfigService.OpMessageConfigDTO> page = opMessageConfigService.page(pageOpMessageConfigParam);
|
||||
|
||||
return ApiPageResult.ok(page.convert(record -> {
|
||||
OpMessageConfigResp opMessageConfigResp = OpMessageConfigResp.builder().build();
|
||||
BeanUtils.copyProperties(record, opMessageConfigResp);
|
||||
opMessageConfigResp.setStatus(record.getStatus().name());
|
||||
|
||||
if (record.getSendUserInfo() != null) {
|
||||
SendUserInfo sendUserInfo = SendUserInfo.builder().build();
|
||||
BeanUtils.copyProperties(record.getSendUserInfo(), sendUserInfo);
|
||||
opMessageConfigResp.setSendUserInfo(sendUserInfo);
|
||||
}
|
||||
|
||||
if (record.getCreatePersonProfile() != null) {
|
||||
PersonProfileDto createPersonProfile = PersonProfileDto.builder().build();
|
||||
BeanUtils.copyProperties(record.getCreatePersonProfile(), createPersonProfile);
|
||||
opMessageConfigResp.setCreatePersonProfile(createPersonProfile);
|
||||
}
|
||||
|
||||
if (record.getSubmitPersonProfile() != null) {
|
||||
PersonProfileDto submitPersonProfile = PersonProfileDto.builder().build();
|
||||
BeanUtils.copyProperties(record.getSubmitPersonProfile(), submitPersonProfile);
|
||||
opMessageConfigResp.setSubmitPersonProfile(submitPersonProfile);
|
||||
}
|
||||
|
||||
return opMessageConfigResp;
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<OpMessageConfigBaseResp> create(CreateOpMessageConfigParam param) {
|
||||
OpMessageConfigService.CreateOpMessageConfigParam createOpMessageConfigParam = OpMessageConfigService.CreateOpMessageConfigParam.builder().build();
|
||||
BeanUtils.copyProperties(param, createOpMessageConfigParam);
|
||||
// 默认状态为待执行,创建人就是提交审核人
|
||||
createOpMessageConfigParam.setSubmitPersonId(param.getOperatePersonId());
|
||||
createOpMessageConfigParam.setCreatePersonId(param.getOperatePersonId());
|
||||
createOpMessageConfigParam.setStatus(OpMessageConfig.Status.PENDING);
|
||||
createOpMessageConfigParam.setPlanStartTime(resolvePlanStartTime(param.getReceiveData(), param.getPlanStartTime()));
|
||||
|
||||
OpMessageConfig opMessageConfig = opMessageConfigService.create(createOpMessageConfigParam);
|
||||
return ApiResult.ok(to(opMessageConfig));
|
||||
}
|
||||
|
||||
private Date resolvePlanStartTime(JSONObject receiveData, Date planStartTime) {
|
||||
if (planStartTime != null) {
|
||||
return planStartTime;
|
||||
}
|
||||
if (receiveData == null) {
|
||||
return null;
|
||||
}
|
||||
if (receiveData.toJavaObject(OpMessageConfig.ReceiveData.class).isNowStrategy()) {
|
||||
return new Date();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> delete(DeleteOpMessageConfigParam param) {
|
||||
OpMessageConfigService.DeleteOpMessageConfigParam deleteOpMessageConfigParam = OpMessageConfigService.DeleteOpMessageConfigParam.builder()
|
||||
.id(param.getId())
|
||||
.deletePersonId(param.getOperatePersonId())
|
||||
.build();
|
||||
opMessageConfigService.delete(deleteOpMessageConfigParam);
|
||||
return ApiResult.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<OpMessageConfigBaseResp> update(UpdateOpMessageConfigParam param) {
|
||||
OpMessageConfigService.UpdateOpMessageConfigParam updateOpMessageConfigParam = OpMessageConfigService.UpdateOpMessageConfigParam.builder().build();
|
||||
BeanUtils.copyProperties(param, updateOpMessageConfigParam);
|
||||
updateOpMessageConfigParam.setUpdatePersonId(param.getOperatePersonId());
|
||||
updateOpMessageConfigParam.setPlanStartTime(resolvePlanStartTime(param.getReceiveData(), param.getPlanStartTime()));
|
||||
|
||||
OpMessageConfig opMessageConfig = opMessageConfigService.update(updateOpMessageConfigParam);
|
||||
return ApiResult.ok(to(opMessageConfig));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<OpMessageConfigBaseResp> saveDraft(SaveDraftOpMessageConfigParam req) {
|
||||
|
||||
if (req.getId() == null) {
|
||||
OpMessageConfigService.CreateOpMessageConfigParam createOpMessageConfigParam = OpMessageConfigService.CreateOpMessageConfigParam.builder().build();
|
||||
BeanUtils.copyProperties(req, createOpMessageConfigParam);
|
||||
createOpMessageConfigParam.setStatus(OpMessageConfig.Status.DRAFT);
|
||||
createOpMessageConfigParam.setCreatePersonId(req.getOperatePersonId());
|
||||
|
||||
OpMessageConfig opMessageConfig = opMessageConfigService.create(createOpMessageConfigParam);
|
||||
return ApiResult.ok(to(opMessageConfig));
|
||||
}
|
||||
|
||||
OpMessageConfigService.UpdateOpMessageConfigParam updateOpMessageConfigParam = OpMessageConfigService.UpdateOpMessageConfigParam.builder().build();
|
||||
BeanUtils.copyProperties(req, updateOpMessageConfigParam);
|
||||
updateOpMessageConfigParam.setUpdatePersonId(req.getOperatePersonId());
|
||||
updateOpMessageConfigParam.setPlanStartTime(resolvePlanStartTime(req.getReceiveData(), req.getPlanStartTime()));
|
||||
|
||||
OpMessageConfig opMessageConfig = opMessageConfigService.update(updateOpMessageConfigParam);
|
||||
return ApiResult.ok(to(opMessageConfig));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<OpMessageConfigBaseResp> submitDraft(SaveDraftOpMessageConfigParam req) {
|
||||
Aassert.notNull(req.getId(), OP_MESSAGE_CONFIG_ID_NOT_NULL);
|
||||
|
||||
OpMessageConfigService.UpdateOpMessageConfigParam updateOpMessageConfigParam = OpMessageConfigService.UpdateOpMessageConfigParam.builder().build();
|
||||
BeanUtils.copyProperties(req, updateOpMessageConfigParam);
|
||||
updateOpMessageConfigParam.setAction(OpMessageConfig.ActionEnum.SUBMIT_DRAFT);
|
||||
updateOpMessageConfigParam.setUpdatePersonId(req.getOperatePersonId());
|
||||
updateOpMessageConfigParam.setSubmitPersonId(req.getOperatePersonId());
|
||||
updateOpMessageConfigParam.setSubmitTime(new Date());
|
||||
updateOpMessageConfigParam.setPlanStartTime(resolvePlanStartTime(req.getReceiveData(), req.getPlanStartTime()));
|
||||
|
||||
OpMessageConfig opMessageConfig = opMessageConfigService.update(updateOpMessageConfigParam);
|
||||
return ApiResult.ok(to(opMessageConfig));
|
||||
}
|
||||
|
||||
public OpMessageConfigBaseResp to(OpMessageConfig opMessageConfig) {
|
||||
OpMessageConfigBaseResp opMessageConfigResp = OpMessageConfigBaseResp.builder().build();;
|
||||
BeanUtils.copyProperties(opMessageConfig, opMessageConfigResp);
|
||||
opMessageConfigResp.setStatus(opMessageConfig.getStatus().name());
|
||||
return opMessageConfigResp;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package cn.axzo.nanopart.server.controller;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.nanopart.server.event.outer.PushYouMengMessageHandler;
|
||||
import cn.axzo.nanopart.server.xxljob.SendMessageJob;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/private")
|
||||
public class PrivateController {
|
||||
|
||||
@Autowired
|
||||
private SendMessageJob sendMessageJob;
|
||||
@Autowired
|
||||
private PushYouMengMessageHandler pushYouMengMessageHandler;
|
||||
|
||||
@PostMapping("/send-message/job/run")
|
||||
public Object runSendMessage(@RequestBody SendMessageJob.SendMessageParam param) throws Exception {
|
||||
return sendMessageJob.execute(JSONObject.toJSONString(param));
|
||||
}
|
||||
|
||||
@PostMapping("/you-meng/push")
|
||||
public Object pushYouMeng(@RequestBody Event param) throws Exception {
|
||||
pushYouMengMessageHandler.onEvent(param, null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,312 @@
|
||||
package cn.axzo.nanopart.server.domain;
|
||||
|
||||
import cn.axzo.nanopart.server.config.BizResultCode;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName(value = "`op_message_config`", autoResultMap = true)
|
||||
public class OpMessageConfig {
|
||||
|
||||
private static final Set<Status> CAN_DELETE_STATUSES = Sets.newHashSet(
|
||||
Status.DRAFT,
|
||||
Status.PENDING
|
||||
);
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* im-center服务im_message_task的id
|
||||
*/
|
||||
@TableField(value = "im_message_task_id")
|
||||
private Long imMessageTaskId;
|
||||
|
||||
/**
|
||||
* 消息名字
|
||||
*/
|
||||
@TableField(value = "name")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 发送者的三方平台账号id
|
||||
*/
|
||||
@TableField(value = "send_im_account")
|
||||
private String sendImAccount;
|
||||
|
||||
/**
|
||||
* 消息接收配置
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private JSONObject receiveData;
|
||||
|
||||
private Status status;
|
||||
|
||||
@TableField(value = "title")
|
||||
private String title;
|
||||
|
||||
@TableField(value = "content")
|
||||
private String content;
|
||||
|
||||
@TableField(value = "content_type")
|
||||
private String contentType;
|
||||
|
||||
@TableField(value = "cover_img")
|
||||
private String coverImg;
|
||||
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private JSONObject jumpData;
|
||||
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private JSONObject pushData;
|
||||
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private JSONObject ext;
|
||||
|
||||
@TableField
|
||||
private Date planStartTime;
|
||||
|
||||
@TableField
|
||||
private Date startedTime;
|
||||
|
||||
@TableField
|
||||
private Date finishedTime;
|
||||
|
||||
@TableField
|
||||
private Integer isDelete;
|
||||
|
||||
@TableField
|
||||
private Date createAt;
|
||||
|
||||
@TableField
|
||||
private Date submitTime;
|
||||
|
||||
@TableField
|
||||
private Date updateAt;
|
||||
|
||||
/**
|
||||
* 创建人id
|
||||
*/
|
||||
@TableField
|
||||
private Long createPersonId;
|
||||
|
||||
/**
|
||||
* 删除人id
|
||||
*/
|
||||
@TableField
|
||||
private Long deletePersonId;
|
||||
|
||||
/**
|
||||
* 更新人id
|
||||
*/
|
||||
@TableField
|
||||
private Long updatePersonId;
|
||||
|
||||
/**
|
||||
* 提交审核人
|
||||
*/
|
||||
@TableField
|
||||
private Long submitPersonId;
|
||||
|
||||
public enum Status {
|
||||
DRAFT,
|
||||
PENDING,
|
||||
RUNNING,
|
||||
COMPLETED,
|
||||
;
|
||||
}
|
||||
|
||||
public boolean canDelete() {
|
||||
return CAN_DELETE_STATUSES.contains(this.getStatus());
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ActionEnum {
|
||||
SUBMIT_DRAFT,
|
||||
RUN,
|
||||
COMPLETE
|
||||
;
|
||||
|
||||
private static final Table<Status, ActionEnum, Status> STATUS_FLOWS = HashBasedTable.create();
|
||||
|
||||
static {
|
||||
STATUS_FLOWS.put(Status.DRAFT, SUBMIT_DRAFT, Status.PENDING);
|
||||
STATUS_FLOWS.put(Status.PENDING, RUN, Status.RUNNING);
|
||||
STATUS_FLOWS.put(Status.RUNNING, COMPLETE, Status.COMPLETED);
|
||||
}
|
||||
|
||||
public Status getNextStatus(Status oldStatus) {
|
||||
return Optional.ofNullable(STATUS_FLOWS.get(oldStatus, this)).orElseThrow(BizResultCode.OP_MESSAGE_CONFIG_STATUS_ERROR::toException);
|
||||
}
|
||||
}
|
||||
|
||||
public ReceiveData resolveReceiveData() {
|
||||
JSONObject receiveData = Optional.ofNullable(this.getReceiveData()).orElseGet(JSONObject::new);
|
||||
return JSONObject.toJavaObject(receiveData, ReceiveData.class);
|
||||
}
|
||||
|
||||
public JumpData resolveJumpData() {
|
||||
JSONObject jumpData = Optional.ofNullable(this.getJumpData()).orElseGet(JSONObject::new);
|
||||
return JSONObject.toJavaObject(jumpData, JumpData.class);
|
||||
}
|
||||
|
||||
public PushData resolvePushData() {
|
||||
JSONObject pushData = Optional.ofNullable(this.getPushData()).orElseGet(JSONObject::new);
|
||||
return JSONObject.toJavaObject(pushData, PushData.class);
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ReceiveData {
|
||||
|
||||
private List<Person> persons;
|
||||
|
||||
/**
|
||||
* 推送时间策略:now(立即发送)、specifyTime(指定时间)
|
||||
*/
|
||||
private String strategy;
|
||||
|
||||
private String fileName;
|
||||
|
||||
private String fileKey;
|
||||
|
||||
/**
|
||||
* 接收的类型:all(全部员工)、import(导入名单)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 接收渠道平台:CMP(B端: APP(管理端)+ CMS)、CM(C端:APP(工人端))
|
||||
*/
|
||||
private List<String> platforms;
|
||||
|
||||
public boolean isNowStrategy() {
|
||||
return Objects.equals("now", this.getStrategy());
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Person {
|
||||
|
||||
private Long ouId;
|
||||
|
||||
private Long personId;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ReceiveType {
|
||||
ALL("all", "全部员工"),
|
||||
IMPORT("import", "导入名单");
|
||||
|
||||
private String code;
|
||||
|
||||
private String desc;
|
||||
|
||||
public static ReceiveType of(String typeCode) {
|
||||
if (StringUtils.isBlank(typeCode)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Arrays.stream(values())
|
||||
.filter(e -> Objects.equals(e.getCode(), typeCode))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class JumpData {
|
||||
private boolean switchOn;
|
||||
|
||||
private List<Platform> platforms;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class Platform {
|
||||
|
||||
private JumpPlatform platform;
|
||||
|
||||
private String url;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum JumpPlatform {
|
||||
PC,
|
||||
CM_IOS,
|
||||
CM_ANDROID,
|
||||
CMP_IOS,
|
||||
CMP_ANDROID
|
||||
;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class PushData {
|
||||
|
||||
private boolean switchOn;
|
||||
|
||||
/**
|
||||
* 声音文件
|
||||
*/
|
||||
private String voiceFile;
|
||||
|
||||
private String voiceFileName;
|
||||
|
||||
/**
|
||||
* 提醒方式:voice(声音)、vibrate(震动)
|
||||
*/
|
||||
private String ability;
|
||||
|
||||
/**
|
||||
* push类型:system(系统消息)、op(运营消息)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 声音类型:custom(自定义)、system(系统
|
||||
*/
|
||||
private String voiceType;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package cn.axzo.nanopart.server.event.outer;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @Classname EventTypeEnum
|
||||
* @Date 2021/2/7 6:05 下午
|
||||
* @Created by lilong
|
||||
*/
|
||||
@Getter
|
||||
public enum EventTypeEnum {
|
||||
|
||||
MESSAGE_HISTORY_UPDATED("message-history", "message-history-updated", "发送记录修改")
|
||||
;
|
||||
|
||||
EventTypeEnum(String model, String name, String desc) {
|
||||
this.eventCode = Event.EventCode.builder()
|
||||
.module(model)
|
||||
.name(name)
|
||||
.build();
|
||||
this.model = model;
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
private String model;
|
||||
private String name;
|
||||
private String desc;
|
||||
private Event.EventCode eventCode;
|
||||
}
|
||||
@ -0,0 +1,184 @@
|
||||
package cn.axzo.nanopart.server.event.outer;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
import cn.axzo.msg.center.api.MessagePushApi;
|
||||
import cn.axzo.msg.center.api.request.MsgBody4Guest;
|
||||
import cn.axzo.nanopart.server.domain.OpMessageConfig;
|
||||
import cn.axzo.nanopart.server.event.payload.MessageHistoryUpdatedPayload;
|
||||
import cn.axzo.nanopart.server.service.OpMessageConfigService;
|
||||
import cn.axzo.nanopart.server.xxljob.SendMessageJob;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.collect.Lists;
|
||||
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.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.nanopart.server.event.payload.MessageHistoryUpdatedPayload.PLATFORM_ROUTER_TYPE;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PushYouMengMessageHandler implements EventHandler, InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
@Autowired
|
||||
private OpMessageConfigService opMessageConfigService;
|
||||
@Autowired
|
||||
private MessagePushApi messagePushApi;
|
||||
|
||||
/**
|
||||
* 按照这个顺序解析routerType
|
||||
*/
|
||||
private static final List<String> ROUTER_TYPE_SORTED = Lists.newArrayList(
|
||||
MessageHistoryUpdatedPayload.IOS_PLATFORM,
|
||||
MessageHistoryUpdatedPayload.ANDROID_PLATFORM,
|
||||
MessageHistoryUpdatedPayload.WEBVIEW_PLATFORM,
|
||||
MessageHistoryUpdatedPayload.MINI_PROGRAM_PLATFORM,
|
||||
MessageHistoryUpdatedPayload.WECHAT_MINI_PROGRAM_PLATFORM);
|
||||
|
||||
/**
|
||||
* 按照这个顺序解析IOS的url
|
||||
*/
|
||||
private static final List<String> IOS_URL_SORTED = Lists.newArrayList(
|
||||
MessageHistoryUpdatedPayload.IOS_PLATFORM,
|
||||
MessageHistoryUpdatedPayload.WEBVIEW_PLATFORM,
|
||||
MessageHistoryUpdatedPayload.MINI_PROGRAM_PLATFORM,
|
||||
MessageHistoryUpdatedPayload.WECHAT_MINI_PROGRAM_PLATFORM);
|
||||
|
||||
/**
|
||||
* 按照这个顺序解析ANDROID的url
|
||||
*/
|
||||
private static final List<String> ANDROID_URL_SORTED = Lists.newArrayList(
|
||||
MessageHistoryUpdatedPayload.ANDROID_PLATFORM,
|
||||
MessageHistoryUpdatedPayload.WEBVIEW_PLATFORM,
|
||||
MessageHistoryUpdatedPayload.MINI_PROGRAM_PLATFORM,
|
||||
MessageHistoryUpdatedPayload.WECHAT_MINI_PROGRAM_PLATFORM);
|
||||
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event, EventConsumer.Context context) {
|
||||
log.info("begin push-handler rocketmq event: {}", event);
|
||||
MessageHistoryUpdatedPayload payload = event.normalizedData(MessageHistoryUpdatedPayload.class);
|
||||
if (Objects.isNull(payload) || StringUtils.isBlank(payload.getNewMessageHistory().getBizId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!payload.getNewMessageHistory().getBizId().startsWith(SendMessageJob.BIZ_ID_PREFIX)) {
|
||||
log.info("push-handler 非op-message的消息");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!payload.isSuccess()) {
|
||||
log.info("push-handler is not success");
|
||||
return;
|
||||
}
|
||||
|
||||
if (payload.getNewMessageHistory().getImMessageTaskId() == null) {
|
||||
log.info("push-handler imMessageTaskId is null");
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<OpMessageConfigService.OpMessageConfigDTO> opMessageConfigDTO = opMessageConfigService.page(OpMessageConfigService.PageOpMessageConfigParam.builder()
|
||||
.imMessageTaskId(payload.getNewMessageHistory().getImMessageTaskId())
|
||||
.build())
|
||||
.getRecords()
|
||||
.stream()
|
||||
.findFirst();
|
||||
if (!opMessageConfigDTO.isPresent()) {
|
||||
log.info("push-handler imMessageTaskId is not found,{}", payload.getNewMessageHistory().getImMessageTaskId());
|
||||
return;
|
||||
}
|
||||
|
||||
if (opMessageConfigDTO.get().getPushData() == null) {
|
||||
log.info("push-handler, opMessageConfig:{},未配置push信息", opMessageConfigDTO.get().getId());
|
||||
return;
|
||||
}
|
||||
OpMessageConfig.PushData pushData = opMessageConfigDTO.get().getPushData().toJavaObject(OpMessageConfig.PushData.class);
|
||||
|
||||
if (BooleanUtils.isNotTrue(pushData.isSwitchOn())) {
|
||||
log.info("push-handler, opMessageConfig:{},push开关未打开", opMessageConfigDTO.get().getId());
|
||||
return;
|
||||
}
|
||||
|
||||
MessageHistoryUpdatedPayload.MessageHistory newMessageHistory = payload.getNewMessageHistory();
|
||||
MessageHistoryUpdatedPayload.MessageBody messageBody = newMessageHistory.resolveMessageBody();
|
||||
messagePushApi.sendPushMessage(MsgBody4Guest.builder()
|
||||
.ty(0)
|
||||
.f("0")
|
||||
.appClient(newMessageHistory.getAppType())
|
||||
.m(messageBody.getMsgContent())
|
||||
.m3(newMessageHistory.getReceivePersonId())
|
||||
.m2(resolveM2(messageBody, pushData))
|
||||
// 为了兼容老版本,保证老版本的工人端能收到push,所以新的push都alias都是person
|
||||
.t("not_identity" + newMessageHistory.getReceivePersonId())
|
||||
.ouId(newMessageHistory.getReceiveOuId())
|
||||
.pushType(pushData.getType())
|
||||
.build());
|
||||
|
||||
log.info("end push-handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
private String resolveM2(MessageHistoryUpdatedPayload.MessageBody messageBody,
|
||||
OpMessageConfig.PushData pushData) {
|
||||
JSONObject jsonObject = new JSONObject()
|
||||
.fluentPut("t", messageBody.getMsgHeader())
|
||||
.fluentPut("type", 0);
|
||||
if (StringUtils.isNotBlank(pushData.getVoiceFile())) {
|
||||
jsonObject.fluentPut("audio", pushData.getVoiceFile());
|
||||
}
|
||||
MessageHistoryUpdatedPayload.CardDetailButton cardDetailButton = messageBody.resolveMsgBody().getCardDetailButton();
|
||||
if (cardDetailButton != null && CollectionUtils.isNotEmpty(cardDetailButton.getActionPaths())) {
|
||||
resolveRouter(jsonObject, cardDetailButton.getActionPaths());
|
||||
}
|
||||
return jsonObject.toJSONString();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param jsonObject
|
||||
* @param actionPaths
|
||||
*/
|
||||
private void resolveRouter(JSONObject jsonObject, List<MessageHistoryUpdatedPayload.ActionPath> actionPaths) {
|
||||
|
||||
Map<String, MessageHistoryUpdatedPayload.ActionPath> actionPathMap = actionPaths.stream()
|
||||
.collect(Collectors.toMap(MessageHistoryUpdatedPayload.ActionPath::getPlatform, Function.identity()));
|
||||
Optional<MessageHistoryUpdatedPayload.ActionPath> routerType = ROUTER_TYPE_SORTED.stream()
|
||||
.map(actionPathMap::get)
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst();
|
||||
routerType.ifPresent(actionPath -> jsonObject.fluentPut("rt", PLATFORM_ROUTER_TYPE.get(actionPath.getPlatform())));
|
||||
|
||||
Optional<MessageHistoryUpdatedPayload.ActionPath> ios = IOS_URL_SORTED.stream()
|
||||
.map(actionPathMap::get)
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst();
|
||||
// IOS的跳转URL
|
||||
ios.ifPresent(actionPath -> jsonObject.fluentPut("ir", actionPath.getUrl()));
|
||||
|
||||
Optional<MessageHistoryUpdatedPayload.ActionPath> android = ANDROID_URL_SORTED.stream()
|
||||
.map(actionPathMap::get)
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst();
|
||||
// ANDROID的跳转URL
|
||||
android.ifPresent(actionPath -> jsonObject.fluentPut("ar", actionPath.getUrl()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
eventConsumer.registerHandler(EventTypeEnum.MESSAGE_HISTORY_UPDATED.getEventCode(), this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,176 @@
|
||||
package cn.axzo.nanopart.server.event.payload;
|
||||
|
||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MessageHistoryUpdatedPayload implements Serializable {
|
||||
|
||||
public static final String IOS_PLATFORM = "IOS";
|
||||
public static final String ANDROID_PLATFORM = "ANDROID";
|
||||
public static final String WEBVIEW_PLATFORM = "WEBVIEW";
|
||||
public static final String MINI_PROGRAM_PLATFORM = "MINI_PROGRAM";
|
||||
public static final String WECHAT_MINI_PROGRAM_PLATFORM = "WECHAT_MINI_PROGRAM";
|
||||
|
||||
public static final Map<String, Integer> PLATFORM_ROUTER_TYPE = Maps.newHashMap();
|
||||
static {
|
||||
PLATFORM_ROUTER_TYPE.put(IOS_PLATFORM, 2);
|
||||
PLATFORM_ROUTER_TYPE.put(ANDROID_PLATFORM, 2);
|
||||
PLATFORM_ROUTER_TYPE.put(WEBVIEW_PLATFORM, 3);
|
||||
PLATFORM_ROUTER_TYPE.put(MINI_PROGRAM_PLATFORM, 1);
|
||||
PLATFORM_ROUTER_TYPE.put(WECHAT_MINI_PROGRAM_PLATFORM, 5);
|
||||
}
|
||||
|
||||
private MessageHistory newMessageHistory;
|
||||
private MessageHistory oldMessageHistory;
|
||||
|
||||
public boolean isSuccess() {
|
||||
return !Objects.equals(newMessageHistory.getStatus(), oldMessageHistory.getStatus())
|
||||
&& Objects.equals(newMessageHistory.getStatus(), MessageHistory.Status.SUCCEED.name());
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class MessageHistory implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 上游业务请求ID
|
||||
*/
|
||||
private String bizId;
|
||||
|
||||
/**
|
||||
* 普通用户,通过appType包装
|
||||
* 包装以后进行账户注册
|
||||
*/
|
||||
private String messageId;
|
||||
|
||||
/**
|
||||
* 发送者IM账户
|
||||
*/
|
||||
private String fromAccount;
|
||||
|
||||
/**
|
||||
* 发送者IM账户
|
||||
*/
|
||||
private String toAccount;
|
||||
|
||||
/**
|
||||
* 终端类型
|
||||
*
|
||||
* @see AppTypeEnum
|
||||
*/
|
||||
private String appType;
|
||||
|
||||
/**
|
||||
* channel 网易云信
|
||||
*/
|
||||
private String channel;
|
||||
|
||||
private String messageBody;
|
||||
|
||||
private String result;
|
||||
|
||||
private Long imMessageTaskId;
|
||||
|
||||
private String receivePersonId;
|
||||
|
||||
private Long receiveOuId;
|
||||
|
||||
private String status;
|
||||
|
||||
private Integer isDelete;
|
||||
|
||||
private Date createAt;
|
||||
|
||||
private Date updateAt;
|
||||
|
||||
public enum Status {
|
||||
PENDING,
|
||||
SUCCEED,
|
||||
FAILED,
|
||||
;
|
||||
}
|
||||
|
||||
public MessageBody resolveMessageBody() {
|
||||
return JSONObject.parseObject(messageBody, MessageBody.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class MessageBody {
|
||||
|
||||
/**
|
||||
* 模板消息:Template、聊天消息:Chat、通知消息:Notify
|
||||
*/
|
||||
private String msgType;
|
||||
|
||||
/**
|
||||
* 消息标题
|
||||
*/
|
||||
private String msgHeader;
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
private String msgContent;
|
||||
|
||||
/**
|
||||
* 消息通知结构体
|
||||
*/
|
||||
private String msgBody;
|
||||
|
||||
public MsgBody resolveMsgBody() {
|
||||
return JSONObject.parseObject(msgBody, MsgBody.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class MsgBody {
|
||||
private CardDetailButton cardDetailButton;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class CardDetailButton {
|
||||
private List<ActionPath> actionPaths;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ActionPath {
|
||||
private String platform;
|
||||
|
||||
private String url;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package cn.axzo.nanopart.server.mapper;
|
||||
|
||||
import cn.axzo.nanopart.server.domain.OpMessageConfig;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface OpMessageConfigMapper extends BaseMapper<OpMessageConfig> {
|
||||
}
|
||||
@ -0,0 +1,281 @@
|
||||
package cn.axzo.nanopart.server.service;
|
||||
|
||||
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||
import cn.axzo.im.center.api.feign.RobotInfoApi;
|
||||
import cn.axzo.nanopart.server.domain.OpMessageConfig;
|
||||
import cn.axzo.pokonyan.dao.mysql.QueryWrapperHelper;
|
||||
import cn.axzo.pokonyan.dao.page.IPageParam;
|
||||
import cn.axzo.pokonyan.dao.wrapper.CriteriaField;
|
||||
import cn.axzo.pokonyan.dao.wrapper.Operator;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public interface OpMessageConfigService extends IService<OpMessageConfig> {
|
||||
|
||||
Page<OpMessageConfigDTO> page(PageOpMessageConfigParam param);
|
||||
|
||||
OpMessageConfig create(CreateOpMessageConfigParam param);
|
||||
|
||||
OpMessageConfig update(UpdateOpMessageConfigParam param);
|
||||
|
||||
void delete(DeleteOpMessageConfigParam param);
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class DeleteOpMessageConfigParam {
|
||||
private Long id;
|
||||
|
||||
private Long deletePersonId;
|
||||
}
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class UpdateOpMessageConfigParam {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String sendImAccount;
|
||||
|
||||
private JSONObject receiveData;
|
||||
|
||||
private String title;
|
||||
|
||||
private String content;
|
||||
|
||||
private String contentType;
|
||||
|
||||
private String coverImg;
|
||||
|
||||
private JSONObject jumpData;
|
||||
|
||||
private JSONObject pushData;
|
||||
|
||||
private JSONObject ext;
|
||||
|
||||
private Date planStartTime;
|
||||
|
||||
private Long updatePersonId;
|
||||
|
||||
private Long submitPersonId;
|
||||
|
||||
private OpMessageConfig.ActionEnum action;
|
||||
|
||||
private Date submitTime;
|
||||
|
||||
private Long imMessageTaskId;
|
||||
|
||||
private Date startedTime;
|
||||
|
||||
private Date finishedTime;
|
||||
|
||||
public OpMessageConfig to() {
|
||||
OpMessageConfig opMessageConfig = OpMessageConfig.builder().build();
|
||||
BeanUtils.copyProperties(this, opMessageConfig);
|
||||
return opMessageConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class CreateOpMessageConfigParam {
|
||||
private String name;
|
||||
|
||||
private String sendImAccount;
|
||||
|
||||
private JSONObject receiveData;
|
||||
|
||||
private OpMessageConfig.Status status;
|
||||
|
||||
private String title;
|
||||
|
||||
private String content;
|
||||
|
||||
private String contentType;
|
||||
|
||||
private String coverImg;
|
||||
|
||||
private JSONObject jumpData;
|
||||
|
||||
private JSONObject pushData;
|
||||
|
||||
private JSONObject ext;
|
||||
|
||||
private Date planStartTime;
|
||||
|
||||
private Long createPersonId;
|
||||
|
||||
private Long submitPersonId;
|
||||
|
||||
public OpMessageConfig to() {
|
||||
OpMessageConfig opMessageConfig = OpMessageConfig.builder().build();
|
||||
BeanUtils.copyProperties(this, opMessageConfig);
|
||||
opMessageConfig.setSubmitTime(new Date());
|
||||
return opMessageConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@SuperBuilder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ListOpMessageConfigParam {
|
||||
|
||||
@CriteriaField(field = "id", operator = Operator.IN)
|
||||
private List<Long> ids;
|
||||
|
||||
@CriteriaField(field = "name", operator = Operator.LIKE)
|
||||
private String nameLike;
|
||||
|
||||
@CriteriaField(field = "sendImAccount", operator = Operator.EQ)
|
||||
private String sendImAccount;
|
||||
|
||||
@CriteriaField(field = "sendImAccount", operator = Operator.LIKE)
|
||||
private String sendImAccountLike;
|
||||
|
||||
@CriteriaField(field = "planStartTime", operator = Operator.LE)
|
||||
private Date planStartTimeLE;
|
||||
|
||||
@CriteriaField(field = "status", operator = Operator.IN)
|
||||
private List<String> statuses;
|
||||
|
||||
@CriteriaField(field = "contentType", operator = Operator.EQ)
|
||||
private String contentType;
|
||||
|
||||
@CriteriaField(field = "imMessageTaskId", operator = Operator.EQ)
|
||||
private Long imMessageTaskId;
|
||||
|
||||
@CriteriaField(ignore = true)
|
||||
private List<String> receivePlatforms;;
|
||||
|
||||
/**
|
||||
* 返回发送的信息:
|
||||
* IM机器人账号:返回头像、名字等信息
|
||||
* 账号有机器人和系统人员信息,查询的接口不同
|
||||
*/
|
||||
@CriteriaField(ignore = true)
|
||||
private boolean needSendUserInfo;
|
||||
|
||||
/**
|
||||
* 返回创建人的信息
|
||||
*/
|
||||
@CriteriaField(ignore = true)
|
||||
private boolean needCreatePersonInfo;
|
||||
|
||||
/**
|
||||
* 返回提交审核人的信息
|
||||
*/
|
||||
@CriteriaField(ignore = true)
|
||||
private boolean needSubmitPersonInfo;
|
||||
}
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class SendUserInfo {
|
||||
|
||||
/**
|
||||
* im账号
|
||||
*/
|
||||
private String imAccount;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
private String nickName;
|
||||
|
||||
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
private String headImageUrl;
|
||||
|
||||
public static SendUserInfo from(RobotInfoApi.RobotInfoDTO robotInfoDTO) {
|
||||
return SendUserInfo.builder()
|
||||
.imAccount(robotInfoDTO.getImAccount())
|
||||
.nickName(robotInfoDTO.getNickName())
|
||||
.headImageUrl(robotInfoDTO.getHeadImageUrl())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@SuperBuilder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class PageOpMessageConfigParam extends ListOpMessageConfigParam implements IPageParam {
|
||||
@CriteriaField(ignore = true)
|
||||
Integer page;
|
||||
|
||||
@CriteriaField(ignore = true)
|
||||
Integer pageSize;
|
||||
|
||||
/**
|
||||
* 排序:使用示例,createTime__DESC
|
||||
*/
|
||||
@CriteriaField(ignore = true)
|
||||
List<String> sort;
|
||||
|
||||
public QueryWrapper<OpMessageConfig> toQueryWrapper() {
|
||||
QueryWrapper<OpMessageConfig> wrapper = QueryWrapperHelper.fromBean(this, OpMessageConfig.class);
|
||||
wrapper.eq("is_delete", 0);
|
||||
|
||||
if (!CollectionUtils.isEmpty(this.getReceivePlatforms())) {
|
||||
String sql = this.getReceivePlatforms().stream()
|
||||
.map(e -> "json_contains(receive_data->'$.platforms', '\"" + e + "\"')")
|
||||
.collect(Collectors.joining(" or "));
|
||||
wrapper.and(e -> e.apply(sql));
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
@SuperBuilder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class OpMessageConfigDTO extends OpMessageConfig {
|
||||
|
||||
private SendUserInfo sendUserInfo;
|
||||
|
||||
private PersonProfileDto createPersonProfile;
|
||||
|
||||
private PersonProfileDto submitPersonProfile;
|
||||
|
||||
public static OpMessageConfigDTO from(OpMessageConfig opMessageConfig,
|
||||
Map<String, SendUserInfo> sendUserInfos,
|
||||
Map<Long, PersonProfileDto> createPersonProfiles,
|
||||
Map<Long, PersonProfileDto> submitPersonProfiles) {
|
||||
OpMessageConfigDTO opMessageConfigDTO = OpMessageConfigDTO.builder().build();
|
||||
BeanUtils.copyProperties(opMessageConfig, opMessageConfigDTO);
|
||||
|
||||
opMessageConfigDTO.setSendUserInfo(sendUserInfos.get(opMessageConfigDTO.getSendImAccount()));
|
||||
|
||||
opMessageConfigDTO.setCreatePersonProfile(createPersonProfiles.get(opMessageConfigDTO.getCreatePersonId()));
|
||||
opMessageConfigDTO.setSubmitPersonProfile(submitPersonProfiles.get(opMessageConfigDTO.getSubmitPersonId()));
|
||||
return opMessageConfigDTO;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,169 @@
|
||||
package cn.axzo.nanopart.server.service.impl;
|
||||
|
||||
import cn.axzo.basics.profiles.api.UserProfileServiceApi;
|
||||
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||
import cn.axzo.im.center.api.feign.RobotInfoApi;
|
||||
import cn.axzo.nanopart.server.domain.OpMessageConfig;
|
||||
import cn.axzo.nanopart.server.mapper.OpMessageConfigMapper;
|
||||
import cn.axzo.nanopart.server.service.OpMessageConfigService;
|
||||
import cn.axzo.pokonyan.dao.converter.PageConverter;
|
||||
import cn.axzo.pokonyan.exception.Aassert;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.nanopart.server.config.BizResultCode.DELETE_OP_MESSAGE_CONFIG_STATUS_ERROR;
|
||||
import static cn.axzo.nanopart.server.config.BizResultCode.OP_MESSAGE_CONFIG_NOT_FOUND;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class OpMessageConfigServiceImpl extends ServiceImpl<OpMessageConfigMapper, OpMessageConfig>
|
||||
implements OpMessageConfigService {
|
||||
|
||||
private static final Long DEFAULT_ZERO_PERSON_ID = 0L;
|
||||
|
||||
@Autowired
|
||||
private RobotInfoApi robotInfoApi;
|
||||
@Autowired
|
||||
private UserProfileServiceApi userProfileServiceApi;
|
||||
|
||||
@Override
|
||||
public Page<OpMessageConfigDTO> page(PageOpMessageConfigParam param) {
|
||||
QueryWrapper<OpMessageConfig> wrapper = param.toQueryWrapper();
|
||||
|
||||
Page<OpMessageConfig> page = this.page(PageConverter.convertToMybatis(param, OpMessageConfig.class), wrapper);
|
||||
|
||||
Map<String, SendUserInfo> sendUserInfos = listSendUserInfo(param, page.getRecords());
|
||||
|
||||
Map<Long, PersonProfileDto> createPersonProfiles = listCreatePersonProfile(param, page.getRecords());
|
||||
Map<Long, PersonProfileDto> submitPersonProfiles = listSubmitPersonProfile(param, page.getRecords());
|
||||
|
||||
return PageConverter.convert(page, (record) -> OpMessageConfigDTO.from(record,
|
||||
sendUserInfos,
|
||||
createPersonProfiles,
|
||||
submitPersonProfiles));
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpMessageConfig create(CreateOpMessageConfigParam param) {
|
||||
OpMessageConfig opMessageConfig = param.to();
|
||||
this.save(opMessageConfig);
|
||||
return this.getById(opMessageConfig.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public OpMessageConfig update(UpdateOpMessageConfigParam param) {
|
||||
OpMessageConfig oldOpMessageConfig = getAndLock(param.getId());
|
||||
|
||||
OpMessageConfig opMessageConfig = param.to();
|
||||
if (param.getAction() != null) {
|
||||
opMessageConfig.setStatus(param.getAction().getNextStatus(oldOpMessageConfig.getStatus()));
|
||||
}
|
||||
|
||||
this.updateById(opMessageConfig);
|
||||
return this.getById(param.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(DeleteOpMessageConfigParam param) {
|
||||
OpMessageConfig oldOpMessageConfig = getAndLock(param.getId());
|
||||
Aassert.check(oldOpMessageConfig.canDelete(), DELETE_OP_MESSAGE_CONFIG_STATUS_ERROR);
|
||||
|
||||
// 因为updateById处理的时候,有拦截器过滤掉了isDelete的更新
|
||||
this.lambdaUpdate()
|
||||
.set(OpMessageConfig::getIsDelete, 1)
|
||||
.set(OpMessageConfig::getDeletePersonId, param.getDeletePersonId())
|
||||
.eq(OpMessageConfig::getId, param.getId())
|
||||
.update();
|
||||
}
|
||||
|
||||
private OpMessageConfig getAndLock(Long id) {
|
||||
OpMessageConfig oldOpMessageConfig = this.lambdaQuery()
|
||||
.eq(OpMessageConfig::getId, id)
|
||||
.last("for update")
|
||||
.one();
|
||||
Aassert.notNull(oldOpMessageConfig, OP_MESSAGE_CONFIG_NOT_FOUND);
|
||||
return oldOpMessageConfig;
|
||||
}
|
||||
|
||||
private Map<String, SendUserInfo> listSendUserInfo(PageOpMessageConfigParam param,
|
||||
List<OpMessageConfig> opMessageConfigs) {
|
||||
if (CollectionUtils.isEmpty(opMessageConfigs) || BooleanUtils.isNotTrue(param.isNeedSendUserInfo())) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
List<String> sendImAccounts = opMessageConfigs.stream()
|
||||
.map(OpMessageConfig::getSendImAccount)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(sendImAccounts)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 现在发送者只有机器人,所以发送者的头像信息从robotInfoApi中获取
|
||||
return robotInfoApi.page(RobotInfoApi.PageRobotInfoParam.builder()
|
||||
.imAccounts(sendImAccounts)
|
||||
.build())
|
||||
.getData()
|
||||
.getList()
|
||||
.stream()
|
||||
.map(SendUserInfo::from)
|
||||
.collect(Collectors.toMap(SendUserInfo::getImAccount, Function.identity()));
|
||||
}
|
||||
|
||||
private Map<Long, PersonProfileDto> listCreatePersonProfile(PageOpMessageConfigParam param,
|
||||
List<OpMessageConfig> opMessageConfigs) {
|
||||
if (CollectionUtils.isEmpty(opMessageConfigs) || BooleanUtils.isNotTrue(param.isNeedCreatePersonInfo())) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
List<Long> createPersonIds = opMessageConfigs.stream()
|
||||
.map(OpMessageConfig::getCreatePersonId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(createPersonIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return userProfileServiceApi.postPersonProfiles(createPersonIds).getData()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(PersonProfileDto::getId, Function.identity()));
|
||||
}
|
||||
|
||||
private Map<Long, PersonProfileDto> listSubmitPersonProfile(PageOpMessageConfigParam param,
|
||||
List<OpMessageConfig> opMessageConfigs) {
|
||||
if (CollectionUtils.isEmpty(opMessageConfigs) || BooleanUtils.isNotTrue(param.isNeedSubmitPersonInfo())) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
List<Long> submitPersonIds = opMessageConfigs.stream()
|
||||
.map(OpMessageConfig::getSubmitPersonId)
|
||||
.filter(id -> !Objects.equals(DEFAULT_ZERO_PERSON_ID, id))
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(submitPersonIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return userProfileServiceApi.postPersonProfiles(submitPersonIds).getData()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(PersonProfileDto::getId, Function.identity()));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,234 @@
|
||||
package cn.axzo.nanopart.server.xxljob;
|
||||
|
||||
import cn.axzo.framework.domain.web.result.ApiListResult;
|
||||
import cn.axzo.im.center.api.feign.MessageApi;
|
||||
import cn.axzo.im.center.api.vo.req.AsyncSendMessageParam;
|
||||
import cn.axzo.im.center.api.vo.resp.MessageTaskResp;
|
||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||
import cn.axzo.maokai.api.client.CooperateShipQueryApi;
|
||||
import cn.axzo.maokai.api.vo.request.CooperateShipQueryReq;
|
||||
import cn.axzo.maokai.api.vo.response.CooperateShipResp;
|
||||
import cn.axzo.nanopart.server.domain.OpMessageConfig;
|
||||
import cn.axzo.nanopart.server.service.OpMessageConfigService;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SendMessageJob extends IJobHandler {
|
||||
|
||||
public static final String BIZ_ID_PREFIX = "op-message";
|
||||
@Autowired
|
||||
private OpMessageConfigService opMessageConfigService;
|
||||
@Autowired
|
||||
private MessageApi messageApi;
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
@Autowired
|
||||
private CooperateShipQueryApi cooperateShipQueryApi;
|
||||
|
||||
private static final Integer DEFAULT_PAGE_SIZE = 10;
|
||||
|
||||
@Override
|
||||
@XxlJob("sendMessageJob")
|
||||
public ReturnT<String> execute(String s) throws Exception {
|
||||
log.info("start sendMessageJob,s:{}", s);
|
||||
SendMessageParam sendMessageParam = Optional.ofNullable(s)
|
||||
.map(e -> JSONObject.parseObject(e, SendMessageParam.class))
|
||||
.orElseGet(() -> SendMessageParam.builder().build());
|
||||
Integer pageNumber = 1;
|
||||
Date now = new Date();
|
||||
|
||||
SendMessageJob proxySendMessageJob = applicationContext.getBean(this.getClass());
|
||||
|
||||
while (true) {
|
||||
OpMessageConfigService.PageOpMessageConfigParam req = OpMessageConfigService.PageOpMessageConfigParam.builder()
|
||||
.ids(sendMessageParam.getIds())
|
||||
.planStartTimeLE(now)
|
||||
.statuses(Lists.newArrayList(OpMessageConfig.Status.PENDING.name()))
|
||||
.page(pageNumber)
|
||||
.pageSize(DEFAULT_PAGE_SIZE)
|
||||
.build();
|
||||
|
||||
Page<OpMessageConfigService.OpMessageConfigDTO> page = opMessageConfigService.page(req);
|
||||
if (CollectionUtils.isNotEmpty(page.getRecords())) {
|
||||
// 一个一个更新,数据量不大,一个失败不影响其他的运营消息
|
||||
page.getRecords().forEach(e -> {
|
||||
try {
|
||||
proxySendMessageJob.sendMessage(e);
|
||||
} catch (Exception ex) {
|
||||
log.error("job 执行失败, job{}, ex", e.getId(), ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!page.hasNext()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
log.info("end sendMessageJob");
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void sendMessage(OpMessageConfigService.OpMessageConfigDTO opMessageConfig) {
|
||||
opMessageConfigService.update(OpMessageConfigService.UpdateOpMessageConfigParam.builder()
|
||||
.id(opMessageConfig.getId())
|
||||
.action(OpMessageConfig.ActionEnum.RUN)
|
||||
.startedTime(new Date())
|
||||
.build());
|
||||
|
||||
OpMessageConfig.ReceiveData receiveData = opMessageConfig.resolveReceiveData();
|
||||
OpMessageConfig.ReceiveType receiveType = OpMessageConfig.ReceiveType.of(receiveData.getType());
|
||||
boolean isAllPerson = Objects.equals(OpMessageConfig.ReceiveType.ALL, receiveType);
|
||||
|
||||
List<AppTypeEnum> appTypes = BooleanUtils.isTrue(isAllPerson) ? receiveData.getPlatforms().stream().map(AppTypeEnum::valueOf).collect(Collectors.toList()) : null;
|
||||
|
||||
List<AsyncSendMessageParam.ReceivePerson> receivePersons = resolveReceivePerson(receiveData);
|
||||
// 接收方式是import,且解析后没有接收人,则直接完成任务
|
||||
// 存在只配置了管理端,但是import的人员没导入ouId,导致接收人为空
|
||||
if (CollectionUtils.isEmpty(receivePersons) && Objects.equals(OpMessageConfig.ReceiveType.IMPORT, receiveType)) {
|
||||
opMessageConfigService.update(OpMessageConfigService.UpdateOpMessageConfigParam.builder()
|
||||
.id(opMessageConfig.getId())
|
||||
// 消息是异步执行的,准确的完成时间,需要监听messageTask的完成时间才准确,现在mq配置较低,消息服务没有发送mq
|
||||
.finishedTime(new Date())
|
||||
.action(OpMessageConfig.ActionEnum.COMPLETE)
|
||||
.build());
|
||||
} else {
|
||||
MessageTaskResp messageTask = messageApi.sendMessageAsync(AsyncSendMessageParam.builder()
|
||||
.bizId(String.format("%s:%s", BIZ_ID_PREFIX, opMessageConfig.getId()))
|
||||
.sendImAccount(opMessageConfig.getSendImAccount())
|
||||
.receivePersons(receivePersons)
|
||||
.allPerson(isAllPerson)
|
||||
.appTypes(appTypes)
|
||||
.msgHeader(opMessageConfig.getTitle())
|
||||
.msgContent(opMessageConfig.getContent())
|
||||
.jumpData(resolveJumpData(opMessageConfig))
|
||||
.cardBannerUrl(opMessageConfig.getCoverImg())
|
||||
.build()).getData();
|
||||
opMessageConfigService.update(OpMessageConfigService.UpdateOpMessageConfigParam.builder()
|
||||
.id(opMessageConfig.getId())
|
||||
.imMessageTaskId(messageTask.getId())
|
||||
// 消息是异步执行的,准确的完成时间,需要监听messageTask的完成时间才准确,现在mq配置较低,消息服务没有发送mq
|
||||
.finishedTime(new Date())
|
||||
.action(OpMessageConfig.ActionEnum.COMPLETE)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<AsyncSendMessageParam.ReceivePerson> resolveReceivePerson(OpMessageConfig.ReceiveData receiveData) {
|
||||
OpMessageConfig.ReceiveType receiveType = OpMessageConfig.ReceiveType.of(receiveData.getType());
|
||||
boolean isAllPerson = Objects.equals(OpMessageConfig.ReceiveType.ALL, receiveType);
|
||||
|
||||
if (BooleanUtils.isTrue(isAllPerson)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<AsyncSendMessageParam.ReceivePerson> cmReceivePersons = listCmReceivePersons(receiveData);
|
||||
List<AsyncSendMessageParam.ReceivePerson> cmpReceivePersons = listCmPReceivePersons(receiveData);
|
||||
cmReceivePersons.addAll(cmpReceivePersons);
|
||||
return cmReceivePersons;
|
||||
}
|
||||
|
||||
private List<AsyncSendMessageParam.ReceivePerson> listCmReceivePersons(OpMessageConfig.ReceiveData receiveData) {
|
||||
boolean isCm = receiveData.getPlatforms().stream()
|
||||
.anyMatch(platform -> AppTypeEnum.valueOf(platform) == AppTypeEnum.CM);
|
||||
|
||||
if (BooleanUtils.isNotTrue(isCm)) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
return receiveData.getPersons().stream()
|
||||
.map(OpMessageConfig.Person::getPersonId)
|
||||
.distinct()
|
||||
.map(personId -> AsyncSendMessageParam.ReceivePerson.builder()
|
||||
.personId(personId.toString())
|
||||
.appType(AppTypeEnum.CM)
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<AsyncSendMessageParam.ReceivePerson> listCmPReceivePersons(OpMessageConfig.ReceiveData receiveData) {
|
||||
boolean isCmp = receiveData.getPlatforms().stream()
|
||||
.anyMatch(platform -> AppTypeEnum.valueOf(platform) == AppTypeEnum.CMP);
|
||||
|
||||
if (BooleanUtils.isNotTrue(isCmp)) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
Map<Long, Long> workspaceIds = listWorkspaceIds(receiveData);
|
||||
|
||||
return receiveData.getPersons().stream()
|
||||
.filter(person -> person.getOuId() != null)
|
||||
.map(person -> AsyncSendMessageParam.ReceivePerson.builder()
|
||||
.personId(person.getPersonId().toString())
|
||||
.ouId(person.getOuId())
|
||||
.appType(AppTypeEnum.CMP)
|
||||
.workspaceId(workspaceIds.get(person.getOuId()))
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Map<Long, Long> listWorkspaceIds(OpMessageConfig.ReceiveData receiveData) {
|
||||
List<Long> ouIds = receiveData.getPersons().stream()
|
||||
.map(OpMessageConfig.Person::getOuId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(ouIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
log.info("list workspaceId,{}", ouIds);
|
||||
ApiListResult<CooperateShipResp> cooperateShipRespApiListResult = cooperateShipQueryApi.genericQuery(CooperateShipQueryReq.builder()
|
||||
.ouIdList(ouIds)
|
||||
.workspaceType(1)
|
||||
.build());
|
||||
log.info("list workspaceId result,{}", cooperateShipRespApiListResult);
|
||||
return cooperateShipRespApiListResult.getData()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(CooperateShipResp::getOrganizationalUnitId, CooperateShipResp::getWorkspaceId, (f, s) -> f));
|
||||
}
|
||||
|
||||
private List<cn.axzo.im.center.api.vo.req.SendMessageParam.JumpData> resolveJumpData(OpMessageConfigService.OpMessageConfigDTO opMessageConfig) {
|
||||
return opMessageConfig.resolveJumpData().getPlatforms().stream()
|
||||
.map(platform -> cn.axzo.im.center.api.vo.req.SendMessageParam.JumpData.builder()
|
||||
.platform(cn.axzo.im.center.api.vo.req.SendMessageParam.JumpPlatform.valueOf(platform.getPlatform().name()))
|
||||
.url(platform.getUrl())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class SendMessageParam {
|
||||
private List<Long> ids;
|
||||
}
|
||||
}
|
||||
30
op/op-server/src/test/resources/mysql/schema.sql
Normal file
30
op/op-server/src/test/resources/mysql/schema.sql
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
CREATE TABLE IF NOT EXISTS op_message_config
|
||||
(
|
||||
id bigint auto_increment comment '主键',
|
||||
im_message_task_id bigint not null default 0 comment 'im-center服务im_message_task的id',
|
||||
`name` varchar(50) not null default '' comment '消息名字',
|
||||
send_im_account varchar(100) not null default '' comment '发送者的三方平台账号id',
|
||||
receive_data json null comment '消息接收配置',
|
||||
status varchar(32) not null default 'DRAFT' comment '消息状态:DRAFT、PENDING、RUNNING、COMPLETED',
|
||||
title varchar(128) not null default '' comment '消息标题',
|
||||
content varchar(512) not null default '' comment '消息内容',
|
||||
content_type varchar(32) not null default '' comment '消息形式:IMAGE_TEXT_SAMPLE',
|
||||
cover_img varchar(512) not null default '' comment '消息封面大图',
|
||||
jump_data json comment '跳转配置',
|
||||
push_data json comment 'push配置',
|
||||
ext varchar(1024) not null default '{}' COMMENT '其它额外信息',
|
||||
plan_start_time DATETIME(3) null comment '任务计划开始时间,时间大于改时间会对未完成的任务进行执行操作',
|
||||
started_time DATETIME(3) null comment '实际开始时间',
|
||||
finished_time DATETIME(3) null comment '实际完成时间',
|
||||
submit_time DATETIME(3) null comment '提交审核时间',
|
||||
is_delete tinyint default 0 not null comment '未删除0,删除1',
|
||||
create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间',
|
||||
create_person_id bigint not null comment '创建人id',
|
||||
submit_person_id bigint not null default 0 comment '提交审核人id,可能跟crate_person_id不一样,比如先保存草稿',
|
||||
delete_person_id bigint not null default 0 comment '删除人id',
|
||||
update_person_id bigint not null default 0 comment '更新人id',
|
||||
update_at datetime default CURRENT_TIMESTAMP not null comment '更新时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8 comment '运营消息配置';
|
||||
102
op/pom.xml
Normal file
102
op/pom.xml
Normal file
@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.axzo.nanopart</groupId>
|
||||
<artifactId>nanopart</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>cn.axzo.nanopart</groupId>
|
||||
<artifactId>op</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>op</name>
|
||||
|
||||
<properties>
|
||||
<axzo-bom.version>2.0.0-SNAPSHOT</axzo-bom.version>
|
||||
<axzo-dependencies.version>2.0.0-SNAPSHOT</axzo-dependencies.version>
|
||||
<lombok.version>1.18.22</lombok.version>
|
||||
<mapstruct.version>1.4.2.Final</mapstruct.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- 导入axzo通用api依赖 -->
|
||||
<dependency>
|
||||
<groupId>cn.axzo.infra</groupId>
|
||||
<artifactId>axzo-bom</artifactId>
|
||||
<version>${axzo-bom.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.infra</groupId>
|
||||
<artifactId>axzo-dependencies</artifactId>
|
||||
<version>${axzo-dependencies.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- for test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- maven-compiler-plugin 插件,解决 Lombok + MapStruct 组合 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-processor</artifactId>
|
||||
<version>${mapstruct.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>axzo</id>
|
||||
<name>axzo repository</name>
|
||||
<url>https://nexus.axzo.cn/repository/axzo/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<modules>
|
||||
<module>op-server</module>
|
||||
<module>op-api</module>
|
||||
</modules>
|
||||
</project>
|
||||
Loading…
Reference in New Issue
Block a user