feat:极光推送
This commit is contained in:
1 parent
122160ba8d
commit
df1eeef0d0
45 files changed
+2157
-90
No files matched your search
+117
-19
@@ -175,27 +175,125 @@ CREATE TABLE `third_pay_order`
|
||||
DROP TABLE IF EXISTS `third_fz_order`;
|
||||
CREATE TABLE `third_fz_order`
|
||||
(
|
||||
`id` bigint NOT NULL COMMENT '主键',
|
||||
`pay_no` varchar(128) DEFAULT NULL COMMENT '支付订单号',
|
||||
`fz_no` varchar(128) DEFAULT NULL COMMENT '分账订单号',
|
||||
`create_req` text DEFAULT NULL COMMENT '发起分账req',
|
||||
`create_res` text DEFAULT NULL COMMENT '发起分账res',
|
||||
`create_error` text DEFAULT NULL COMMENT '发起分账error',
|
||||
`status` varchar(128) DEFAULT NULL COMMENT '支付状态',
|
||||
`fz_time` datetime DEFAULT NULL COMMENT '分账时间',
|
||||
`fz_refund_no` varchar(128) DEFAULT NULL COMMENT '分账退款订单号',
|
||||
`fz_refund_time` datetime DEFAULT NULL COMMENT '分账退款时间',
|
||||
`fz_refund_req` text DEFAULT NULL COMMENT '分账退款req',
|
||||
`fz_refund_res` text DEFAULT NULL COMMENT '分账退款res',
|
||||
`fz_refund_error` text DEFAULT NULL COMMENT '分账退款error',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`create_by` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
|
||||
`update_by` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
|
||||
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '删除时间',
|
||||
`tenant_id` bigint(20) DEFAULT NULL,
|
||||
`id` bigint NOT NULL COMMENT '主键',
|
||||
`pay_no` varchar(128) DEFAULT NULL COMMENT '支付订单号',
|
||||
`fz_no` varchar(128) DEFAULT NULL COMMENT '分账订单号',
|
||||
`create_req` text DEFAULT NULL COMMENT '发起分账req',
|
||||
`create_res` text DEFAULT NULL COMMENT '发起分账res',
|
||||
`create_error` text DEFAULT NULL COMMENT '发起分账error',
|
||||
`status` varchar(128) DEFAULT NULL COMMENT '支付状态',
|
||||
`fz_time` datetime DEFAULT NULL COMMENT '分账时间',
|
||||
`fz_refund_no` varchar(128) DEFAULT NULL COMMENT '分账退款订单号',
|
||||
`fz_refund_time` datetime DEFAULT NULL COMMENT '分账退款时间',
|
||||
`fz_refund_req` text DEFAULT NULL COMMENT '分账退款req',
|
||||
`fz_refund_res` text DEFAULT NULL COMMENT '分账退款res',
|
||||
`fz_refund_error` text DEFAULT NULL COMMENT '分账退款error',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`create_by` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
|
||||
`update_by` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
|
||||
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '删除时间',
|
||||
`tenant_id` bigint(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_general_ci
|
||||
ROW_FORMAT = DYNAMIC COMMENT ='第三方支付分账';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for third_push_conf
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS third_push_conf;
|
||||
CREATE TABLE third_push_conf
|
||||
(
|
||||
id bigint NOT NULL COMMENT '主键',
|
||||
biz_type varchar(32) NOT NULL COMMENT '业务类型',
|
||||
biz_id varchar(256) NOT NULL COMMENT '业务id',
|
||||
title varchar(64) NOT NULL COMMENT '通知标题',
|
||||
content varchar(256) NOT NULL COMMENT '通知内容',
|
||||
enable varchar(32) NOT NULL COMMENT '是否开启',
|
||||
inform_type int NOT NULL COMMENT '每天、每月',
|
||||
inform_time time NOT NULL COMMENT '通知时间',
|
||||
create_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
|
||||
create_time datetime DEFAULT NULL COMMENT '创建时间',
|
||||
update_by varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '修改人',
|
||||
update_time datetime DEFAULT NULL COMMENT '修改时间',
|
||||
del_flag char(1) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标记',
|
||||
tenant_id bigint DEFAULT NULL COMMENT '租户ID',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_third_push_conf_biz (tenant_id, biz_type, biz_id, del_flag),
|
||||
KEY idx_third_push_conf_inform (tenant_id, enable, inform_type, inform_time, del_flag)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_general_ci COMMENT ='推送配置';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for third_push_record
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `third_push_record`;
|
||||
CREATE TABLE `third_push_record`
|
||||
(
|
||||
`id` bigint NOT NULL COMMENT '主键',
|
||||
`conf_id` bigint NOT NULL COMMENT '推送配置id',
|
||||
`batch_no` varchar(64) NOT NULL COMMENT '推送批次号',
|
||||
`biz_type` varchar(32) NOT NULL COMMENT '业务类型',
|
||||
`biz_id` varchar(256) NOT NULL COMMENT '业务id',
|
||||
`title` varchar(64) NOT NULL COMMENT '通知标题',
|
||||
`content` varchar(256) NOT NULL COMMENT '通知内容',
|
||||
`inform_type` int NOT NULL COMMENT '每天、每月',
|
||||
`inform_time` time NOT NULL COMMENT '通知时间',
|
||||
`receiver_count` int DEFAULT 0 COMMENT '接收总人数',
|
||||
`success_count` int DEFAULT 0 COMMENT '成功人数',
|
||||
`fail_count` int DEFAULT 0 COMMENT '失败人数',
|
||||
`send_time` datetime DEFAULT NULL COMMENT '发送时间',
|
||||
`status` varchar(32) NOT NULL COMMENT '批次状态',
|
||||
`push_result` text DEFAULT NULL COMMENT '推送结果摘要',
|
||||
`error_msg` varchar(512) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '失败原因',
|
||||
`create_by` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '修改人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
|
||||
`del_flag` char(1) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标记',
|
||||
`tenant_id` bigint DEFAULT NULL COMMENT '租户ID',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY idx_third_push_record_conf_id (`conf_id`),
|
||||
KEY idx_third_push_record_batch_no (`batch_no`),
|
||||
KEY idx_third_push_record_biz (`tenant_id`, `biz_type`, `biz_id`, `del_flag`),
|
||||
KEY idx_third_push_record_send_time (`tenant_id`, `send_time`),
|
||||
KEY idx_third_push_record_status_time (`tenant_id`, `status`, `send_time`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_general_ci COMMENT ='推送通知批次记录';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for third_push_record_user
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `third_push_record_user`;
|
||||
CREATE TABLE `third_push_record_user`
|
||||
(
|
||||
`id` bigint NOT NULL COMMENT '主键',
|
||||
`record_id` bigint NOT NULL COMMENT '推送批次记录id',
|
||||
`conf_id` bigint NOT NULL COMMENT '推送配置id',
|
||||
`batch_no` varchar(64) NOT NULL COMMENT '推送批次号',
|
||||
`user_id` bigint NOT NULL COMMENT '接收用户id',
|
||||
`biz_type` varchar(32) NOT NULL COMMENT '业务类型',
|
||||
`biz_id` varchar(256) NOT NULL COMMENT '业务id',
|
||||
`send_time` datetime DEFAULT NULL COMMENT '发送时间',
|
||||
`status` varchar(32) NOT NULL COMMENT '发送状态',
|
||||
`error_msg` varchar(512) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '失败原因',
|
||||
`read_time` datetime DEFAULT NULL COMMENT '已读时间',
|
||||
`create_by` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '修改人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
|
||||
`del_flag` char(1) COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标记',
|
||||
`tenant_id` bigint DEFAULT NULL COMMENT '租户ID',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY idx_third_push_record_user_record_id (`record_id`),
|
||||
KEY idx_third_push_record_user_batch_no (`batch_no`),
|
||||
KEY idx_third_push_record_user_user_time (`tenant_id`, `user_id`, `send_time`),
|
||||
KEY idx_third_push_record_user_status_time (`tenant_id`, `status`, `send_time`),
|
||||
KEY idx_third_push_record_user_biz (`tenant_id`, `biz_type`, `biz_id`, `del_flag`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_general_ci COMMENT ='推送通知用户明细记录';
|
||||
+5
@@ -96,4 +96,9 @@ public interface ServiceNameConstants {
|
||||
* 综合服务
|
||||
*/
|
||||
String INTEGRATED_SERVICE = "pjcloud-integrated-biz";
|
||||
|
||||
/**
|
||||
* Quartz 定时任务服务
|
||||
*/
|
||||
String DAEMON_QUARTZ_SERVICE = "pjcloud-daemon-quartz";
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.bsd.pjcloud.thirdparty.constant.push;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 推送通知类型
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum ThirdPushBizTypeEnum {
|
||||
MCH_PUSH("1", "商户用餐提醒推送"),
|
||||
;
|
||||
|
||||
@EnumValue
|
||||
private final String type;
|
||||
|
||||
private final String description;
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.bsd.pjcloud.thirdparty.constant.push;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 推送通知类型
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum ThirdPushInformTypeEnum {
|
||||
|
||||
DAY(1, "每天"),
|
||||
MONTH(2, "每月");
|
||||
|
||||
@EnumValue
|
||||
private final Integer type;
|
||||
|
||||
private final String description;
|
||||
}
|
||||
|
||||
+2
@@ -13,4 +13,6 @@ public class JgPusDto {
|
||||
|
||||
private List<Long> userIds;
|
||||
|
||||
private List<String> tagList;
|
||||
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package com.bsd.pjcloud.thirdparty.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.bsd.pjcloud.common.core.util.TenantTable;
|
||||
import com.bsd.pjcloud.thirdparty.constant.push.ThirdPushInformTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* 推送配置
|
||||
*/
|
||||
@Data
|
||||
@TenantTable
|
||||
@TableName("third_push_conf")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "推送配置")
|
||||
public class ThirdPushConfEntity extends Model<ThirdPushConfEntity> {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "业务类型")
|
||||
private String bizType;
|
||||
|
||||
@Schema(description = "业务id")
|
||||
private String bizId;
|
||||
|
||||
@Schema(description = "通知标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "通知内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "是否开启")
|
||||
private String enable;
|
||||
|
||||
@Schema(description = "通知类型:每天、每月")
|
||||
private Integer informType;
|
||||
|
||||
@Schema(description = "通知时间")
|
||||
private LocalTime informTime;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@Schema(description = "创建人")
|
||||
private String createBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@Schema(description = "修改人")
|
||||
private String updateBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@Schema(description = "修改时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@TableLogic
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@Schema(description = "删除标记")
|
||||
private String delFlag;
|
||||
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 生成对应的 cron 表达式(Quartz)
|
||||
* <p>
|
||||
* informType=DAY:每天指定时间触发
|
||||
* informType=MONTH:每月 1 号指定时间触发
|
||||
*/
|
||||
public String buildCron() {
|
||||
if (informType == null || informTime == null) {
|
||||
return null;
|
||||
}
|
||||
int second = informTime.getSecond();
|
||||
int minute = informTime.getMinute();
|
||||
int hour = informTime.getHour();
|
||||
|
||||
if (ThirdPushInformTypeEnum.DAY.getType().equals(informType)) {
|
||||
return String.format("%d %d %d * * ?", second, minute, hour);
|
||||
}
|
||||
if (ThirdPushInformTypeEnum.MONTH.getType().equals(informType)) {
|
||||
return String.format("%d %d %d 1 * ?", second, minute, hour);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package com.bsd.pjcloud.thirdparty.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.bsd.pjcloud.common.core.util.TenantTable;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* 推送通知批次记录
|
||||
*/
|
||||
@Data
|
||||
@TenantTable
|
||||
@TableName("third_push_record")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "推送通知批次记录")
|
||||
public class ThirdPushRecordEntity extends Model<ThirdPushRecordEntity> {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "推送配置id")
|
||||
private Long confId;
|
||||
|
||||
@Schema(description = "推送批次号")
|
||||
private String batchNo;
|
||||
|
||||
@Schema(description = "业务类型")
|
||||
private String bizType;
|
||||
|
||||
@Schema(description = "业务id")
|
||||
private String bizId;
|
||||
|
||||
@Schema(description = "通知标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "通知内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "通知类型:每天、每月")
|
||||
private Integer informType;
|
||||
|
||||
@Schema(description = "通知时间")
|
||||
private LocalTime informTime;
|
||||
|
||||
@Schema(description = "接收总人数")
|
||||
private Integer receiverCount;
|
||||
|
||||
@Schema(description = "成功人数")
|
||||
private Integer successCount;
|
||||
|
||||
@Schema(description = "失败人数")
|
||||
private Integer failCount;
|
||||
|
||||
@Schema(description = "发送时间")
|
||||
private LocalDateTime sendTime;
|
||||
|
||||
@Schema(description = "批次状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "推送结果摘要")
|
||||
private String pushResult;
|
||||
|
||||
@Schema(description = "失败原因")
|
||||
private String errorMsg;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@Schema(description = "创建人")
|
||||
private String createBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@Schema(description = "修改人")
|
||||
private String updateBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@Schema(description = "修改时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@TableLogic
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@Schema(description = "删除标记")
|
||||
private String delFlag;
|
||||
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.bsd.pjcloud.thirdparty.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.bsd.pjcloud.common.core.util.TenantTable;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 推送通知用户明细记录
|
||||
*/
|
||||
@Data
|
||||
@TenantTable
|
||||
@TableName("third_push_record_user")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "推送通知用户明细记录")
|
||||
public class ThirdPushRecordUserEntity extends Model<ThirdPushRecordUserEntity> {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "推送批次记录id")
|
||||
private Long recordId;
|
||||
|
||||
@Schema(description = "推送配置id")
|
||||
private Long confId;
|
||||
|
||||
@Schema(description = "推送批次号")
|
||||
private String batchNo;
|
||||
|
||||
@Schema(description = "接收用户id")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "业务类型")
|
||||
private String bizType;
|
||||
|
||||
@Schema(description = "业务id")
|
||||
private String bizId;
|
||||
|
||||
@Schema(description = "发送时间")
|
||||
private LocalDateTime sendTime;
|
||||
|
||||
@Schema(description = "发送状态")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "失败原因")
|
||||
private String errorMsg;
|
||||
|
||||
@Schema(description = "已读时间")
|
||||
private LocalDateTime readTime;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@Schema(description = "创建人")
|
||||
private String createBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@Schema(description = "修改人")
|
||||
private String updateBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
@Schema(description = "修改时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@TableLogic
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@Schema(description = "删除标记")
|
||||
private String delFlag;
|
||||
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,9 +3,9 @@ com.bsd.pjcloud.thirdparty.api.feign.RemoterThirdKsService
|
||||
com.bsd.pjcloud.thirdparty.api.feign.RemoterThirdDoorApiService
|
||||
com.bsd.pjcloud.thirdparty.api.feign.RemoterThirdLbApiService
|
||||
com.bsd.pjcloud.thirdparty.api.feign.RemoterThirdPartyAuthService
|
||||
com.bsd.pjcloud.thirdparty.api.feign.RemoterThirdPushConfService
|
||||
com.bsd.pjcloud.thirdparty.api.feign.RemoterThirdZyService
|
||||
com.bsd.pjcloud.thirdparty.api.feign.RemoterVisitorService
|
||||
com.bsd.pjcloud.thirdparty.api.feign.RemoterThirdPartySmsService
|
||||
|
||||
|
||||
|
||||
@@ -196,6 +196,11 @@
|
||||
<version>5.7.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.bsd</groupId>
|
||||
<artifactId>pjcloud-daemon-quartz-api</artifactId>
|
||||
<version>5.7.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<profiles>
|
||||
<profile>
|
||||
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
package com.bsd.pjcloud.thirdparty.controller.push;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.security.annotation.Inner;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushConfEntity;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushConfService;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushExecuteService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 推送配置
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/push-conf")
|
||||
@Tag(description = "push-conf", name = "推送配置")
|
||||
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
|
||||
public class ThirdPushConfController {
|
||||
|
||||
private final ThirdPushConfService thirdPushConfService;
|
||||
private final ThirdPushExecuteService thirdPushExecuteService;
|
||||
|
||||
/**
|
||||
* 新增推送配置
|
||||
*/
|
||||
@Operation(summary = "新增推送配置")
|
||||
@PostMapping("/create")
|
||||
public R<Boolean> create(@RequestBody ThirdPushConfEntity dto) {
|
||||
if (ObjectUtil.isEmpty(dto)) {
|
||||
return R.ok(false);
|
||||
}
|
||||
return R.ok(thirdPushConfService.create(dto));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改推送配置
|
||||
*/
|
||||
@Operation(summary = "修改推送配置")
|
||||
@PostMapping("/edit")
|
||||
public R<Boolean> edit(@RequestBody ThirdPushConfEntity dto) {
|
||||
if (ObjectUtil.isEmpty(dto) || ObjectUtil.isEmpty(dto.getId())) {
|
||||
return R.ok(false);
|
||||
}
|
||||
return R.ok(thirdPushConfService.edit(dto));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除推送配置
|
||||
*/
|
||||
@Operation(summary = "删除推送配置")
|
||||
@PostMapping("/remove/{id}")
|
||||
public R<Boolean> remove(@PathVariable Long id) {
|
||||
if (ObjectUtil.isEmpty(id)) {
|
||||
return R.ok(false);
|
||||
}
|
||||
return R.ok(thirdPushConfService.removeById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询详情
|
||||
*/
|
||||
@Operation(summary = "查询详情")
|
||||
@GetMapping("/detail/{id}")
|
||||
public R<ThirdPushConfEntity> detail(@PathVariable Long id) {
|
||||
return R.ok(thirdPushConfService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询推送配置列表
|
||||
*/
|
||||
@Operation(summary = "查询推送配置列表")
|
||||
@PostMapping("/list")
|
||||
public R<List<ThirdPushConfEntity>> list(@RequestBody(required = false) ThirdPushConfEntity dto) {
|
||||
ThirdPushConfEntity query = ObjectUtil.defaultIfNull(dto, new ThirdPushConfEntity());
|
||||
|
||||
LambdaQueryWrapper<ThirdPushConfEntity> wrapper = Wrappers.<ThirdPushConfEntity>lambdaQuery()
|
||||
.eq(ObjectUtil.isNotEmpty(query.getBizType()), ThirdPushConfEntity::getBizType, query.getBizType())
|
||||
.eq(ObjectUtil.isNotEmpty(query.getBizId()), ThirdPushConfEntity::getBizId, query.getBizId())
|
||||
.like(ObjectUtil.isNotEmpty(query.getTitle()), ThirdPushConfEntity::getTitle, query.getTitle())
|
||||
.eq(ObjectUtil.isNotEmpty(query.getEnable()), ThirdPushConfEntity::getEnable, query.getEnable())
|
||||
.eq(ObjectUtil.isNotEmpty(query.getInformType()), ThirdPushConfEntity::getInformType, query.getInformType())
|
||||
.eq(ObjectUtil.isNotEmpty(query.getInformTime()), ThirdPushConfEntity::getInformTime, query.getInformTime())
|
||||
.orderByDesc(ThirdPushConfEntity::getCreateTime)
|
||||
.orderByDesc(ThirdPushConfEntity::getId);
|
||||
|
||||
return R.ok(thirdPushConfService.list(wrapper));
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供给 Quartz 服务的内部执行入口
|
||||
*/
|
||||
@Inner(value = false)
|
||||
@GetMapping("/inner/execute/{id}")
|
||||
public R<String> execute(@PathVariable("id") Long id) {
|
||||
if (ObjectUtil.isEmpty(id)) {
|
||||
return R.failed("推送配置ID不能为空");
|
||||
}
|
||||
return R.ok(thirdPushExecuteService.executeByConfId(String.valueOf(id)));
|
||||
}
|
||||
}
|
||||
+6
-15
@@ -3,6 +3,7 @@ package com.bsd.pjcloud.thirdparty.job;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.thirdparty.dto.jg.JgPusDto;
|
||||
import com.bsd.pjcloud.thirdparty.service.ThirdJgPushService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@@ -21,22 +22,12 @@ public class ThirdAppJgPushJob {
|
||||
|
||||
private final List<Long> testUserIdList = List.of(2029755089492066305L, 2034824566572941314L);
|
||||
|
||||
// 早饭提醒(每天早上6点7点)
|
||||
@Scheduled(cron = "0 0 6,7 * * ?")
|
||||
public void breakfastReminder() {
|
||||
|
||||
@PostConstruct
|
||||
public void test() {
|
||||
pushToAllUsers("早餐提醒", "早餐时间就要到了,请尽快预约哦!!");
|
||||
}
|
||||
|
||||
// 午饭提醒(每天中午10点11点)
|
||||
@Scheduled(cron = "0 0 10,11 * * ?")
|
||||
public void lunchReminder() {
|
||||
pushToAllUsers("午餐提醒", "午餐间就要到了,请尽快预约哦!!");
|
||||
}
|
||||
|
||||
// 晚餐提醒(每天下午5点6点)
|
||||
@Scheduled(cron = "0 0 17,18 * * ?")
|
||||
public void dinnerReminder() {
|
||||
pushToAllUsers("晚餐提醒", "晚餐时间就要到了,请尽快预约哦!!");
|
||||
// pushToAllUsers("午餐提醒", "午餐间就要到了,请尽快预约哦!!");
|
||||
// pushToAllUsers("晚餐提醒", "晚餐时间就要到了,请尽快预约哦!!");
|
||||
}
|
||||
|
||||
private void pushToAllUsers(String title, String subtitle) {
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.bsd.pjcloud.thirdparty.mapper.push;
|
||||
|
||||
import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushConfEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface ThirdPushConfMapper extends PjcloudBaseMapper<ThirdPushConfEntity> {
|
||||
}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.bsd.pjcloud.thirdparty.mapper.push;
|
||||
|
||||
import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushRecordEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface ThirdPushRecordMapper extends PjcloudBaseMapper<ThirdPushRecordEntity> {
|
||||
}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.bsd.pjcloud.thirdparty.mapper.push;
|
||||
|
||||
import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushRecordUserEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface ThirdPushRecordUserMapper extends PjcloudBaseMapper<ThirdPushRecordUserEntity> {
|
||||
}
|
||||
|
||||
+17
-1
@@ -1,10 +1,12 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.impl.jg;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.jiguang.sdk.api.PushApi;
|
||||
import cn.jiguang.sdk.bean.push.PushSendParam;
|
||||
import cn.jiguang.sdk.bean.push.PushSendResult;
|
||||
import cn.jiguang.sdk.bean.push.audience.Audience;
|
||||
import cn.jiguang.sdk.bean.push.message.notification.NotificationMessage;
|
||||
import cn.jiguang.sdk.bean.push.options.Options;
|
||||
import cn.jiguang.sdk.constants.ApiConstants;
|
||||
import com.bsd.pjcloud.thirdparty.config.JgConfig;
|
||||
import com.bsd.pjcloud.thirdparty.dto.jg.JgPusDto;
|
||||
@@ -60,8 +62,22 @@ public class ThirdThirdJgPushServiceImpl implements ThirdJgPushService {
|
||||
notificationMessage.setAndroid(android);
|
||||
notificationMessage.setIos(iOS);
|
||||
|
||||
// start 通知人 ios start
|
||||
Audience audience = new Audience();
|
||||
audience.setAliasList(jgPusDto.getUserIds().stream().map(String::valueOf).toList());
|
||||
if (ObjectUtil.isNotEmpty(jgPusDto.getUserIds())) {
|
||||
audience.setAliasList(jgPusDto.getUserIds().stream().map(String::valueOf).toList());
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(jgPusDto.getTagList())) {
|
||||
audience.setTagAndList(jgPusDto.getTagList());
|
||||
}
|
||||
// end 通知人 ios end
|
||||
|
||||
// start 通知options ios start
|
||||
Options options = new Options();
|
||||
// true:表示推送生产环境,false:表示推送开发环境
|
||||
options.setApnsProduction(false);
|
||||
param.setOptions(options);
|
||||
// end 通知options ios end
|
||||
|
||||
param.setNotification(notificationMessage);
|
||||
param.setAudience(audience);
|
||||
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.impl.push;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bsd.pjcloud.common.core.constant.ServiceNameConstants;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.daemon.quartz.api.dto.SysJobDTO;
|
||||
import com.bsd.pjcloud.daemon.quartz.api.feign.RemoteSysJobService;
|
||||
import com.bsd.pjcloud.thirdparty.constant.push.ThirdPushBizTypeEnum;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushConfEntity;
|
||||
import com.bsd.pjcloud.thirdparty.mapper.push.ThirdPushConfMapper;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushConfService;
|
||||
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
|
||||
import com.bsd.pjcloud.wallet.api.vo.MchManageVo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 推送配置
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ThirdPushConfServiceImpl extends ServiceImpl<ThirdPushConfMapper, ThirdPushConfEntity> implements ThirdPushConfService {
|
||||
|
||||
private static final String JOB_GROUP = "third_push";
|
||||
private static final String JOB_TYPE_REST = "3";
|
||||
private static final String JOB_TENANT_TYPE = "1";
|
||||
private static final String JOB_ORDER = "5";
|
||||
private static final String MISFIRE_POLICY_DEFAULT = "0";
|
||||
private static final String JOB_STATUS_SUCCESS = "0";
|
||||
private static final String JOB_STATUS_RUNNING = "2";
|
||||
private static final String JOB_STATUS_NOT_RUNNING = "3";
|
||||
private static final String EXECUTE_URL_TEMPLATE = "http://127.0.0.1:9999/third/push-conf/inner/execute/%s";
|
||||
|
||||
private final RemoteSysJobService remoteSysJobService;
|
||||
private final RemoteMchService remoteMchService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean create(ThirdPushConfEntity entity) {
|
||||
if (entity == null) {
|
||||
return false;
|
||||
}
|
||||
if (existTitle(entity)) {
|
||||
throw new RuntimeException("推送标题不能重复");
|
||||
}
|
||||
validateCron(entity);
|
||||
boolean saved = save(entity);
|
||||
if (!saved || entity.getId() == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
saveRemoteQuartzJob(entity);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
removeRemoteQuartzJobQuietly(entity);
|
||||
throw new RuntimeException("创建推送配置并同步定时任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean edit(ThirdPushConfEntity entity) {
|
||||
if (entity == null || entity.getId() == null) {
|
||||
return false;
|
||||
}
|
||||
if (existTitle(entity)) {
|
||||
throw new RuntimeException("推送标题不能重复");
|
||||
}
|
||||
ThirdPushConfEntity oldEntity = getById(entity.getId());
|
||||
if (oldEntity == null) {
|
||||
return false;
|
||||
}
|
||||
mergeEditFields(entity, oldEntity);
|
||||
validateCron(entity);
|
||||
boolean updated = updateById(entity);
|
||||
if (!updated) {
|
||||
return false;
|
||||
}
|
||||
ThirdPushConfEntity latest = getById(entity.getId());
|
||||
try {
|
||||
upsertRemoteQuartzJob(latest);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
// 尽最大努力恢复旧任务,避免编辑失败后任务丢失
|
||||
try {
|
||||
upsertRemoteQuartzJob(oldEntity);
|
||||
} catch (Exception restoreException) {
|
||||
log.error("恢复旧 Quartz 任务失败 pushConfId={}", oldEntity.getId(), restoreException);
|
||||
}
|
||||
throw new RuntimeException("修改推送配置并同步定时任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean removeById(Serializable id) {
|
||||
if (!(id instanceof Long pushConfId)) {
|
||||
return false;
|
||||
}
|
||||
ThirdPushConfEntity entity = getById(pushConfId);
|
||||
if (entity == null) {
|
||||
return false;
|
||||
}
|
||||
removeRemoteQuartzJob(entity);
|
||||
return super.removeById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题不能重复(同 bizType + bizId 下)
|
||||
*/
|
||||
private boolean existTitle(ThirdPushConfEntity dto) {
|
||||
Long count = baseMapper.selectCount(new LambdaQueryWrapper<ThirdPushConfEntity>()
|
||||
.eq(ObjectUtil.isNotEmpty(dto.getTitle()), ThirdPushConfEntity::getTitle, dto.getTitle())
|
||||
.eq(ObjectUtil.isNotEmpty(dto.getBizType()), ThirdPushConfEntity::getBizType, dto.getBizType())
|
||||
.eq(ObjectUtil.isNotEmpty(dto.getBizId()), ThirdPushConfEntity::getBizId, dto.getBizId())
|
||||
.ne(ObjectUtil.isNotEmpty(dto.getId()), ThirdPushConfEntity::getId, dto.getId())
|
||||
);
|
||||
if (ObjectUtil.isNotEmpty(dto.getId())) {
|
||||
return count >= 1;
|
||||
}
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 cron 表达式是否合法
|
||||
*/
|
||||
private void validateCron(ThirdPushConfEntity entity) {
|
||||
String cron = entity.buildCron();
|
||||
if (ObjectUtil.isEmpty(cron)) {
|
||||
throw new RuntimeException("推送配置生成的定时表达式不合法");
|
||||
}
|
||||
R<Boolean> result = remoteSysJobService.validateCron(cron);
|
||||
if (result == null || !result.isOk() || Boolean.FALSE.equals(result.getData())) {
|
||||
throw new RuntimeException(result == null || ObjectUtil.isEmpty(result.getMsg())
|
||||
? "推送配置生成的定时表达式不合法"
|
||||
: result.getMsg());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增远程 Quartz 任务
|
||||
*/
|
||||
private void saveRemoteQuartzJob(ThirdPushConfEntity entity) {
|
||||
SysJobDTO sysJob = buildSysJob(entity);
|
||||
R<Boolean> result = remoteSysJobService.saveInner(sysJob);
|
||||
assertRemoteSuccess(result, "新增 Quartz 任务失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程新增或更新 Quartz 任务
|
||||
*/
|
||||
private void upsertRemoteQuartzJob(ThirdPushConfEntity entity) {
|
||||
SysJobDTO sysJob = buildSysJob(entity);
|
||||
SysJobDTO exists = getRemoteQuartzJob(entity);
|
||||
if (exists == null) {
|
||||
saveRemoteQuartzJob(entity);
|
||||
return;
|
||||
}
|
||||
sysJob.setJobId(exists.getJobId());
|
||||
R<Boolean> result = remoteSysJobService.updateInner(sysJob);
|
||||
assertRemoteSuccess(result, "修改 Quartz 任务失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除远程 Quartz 任务
|
||||
*/
|
||||
private void removeRemoteQuartzJob(ThirdPushConfEntity pushConfEntity) {
|
||||
SysJobDTO exists = getRemoteQuartzJob(pushConfEntity);
|
||||
if (exists == null || exists.getJobId() == null) {
|
||||
return;
|
||||
}
|
||||
R<Boolean> result = remoteSysJobService.removeInnerById(exists.getJobId());
|
||||
assertRemoteSuccess(result, "删除 Quartz 任务失败");
|
||||
}
|
||||
|
||||
private void removeRemoteQuartzJobQuietly(ThirdPushConfEntity pushConfEntity) {
|
||||
try {
|
||||
SysJobDTO exists = getRemoteQuartzJob(pushConfEntity);
|
||||
if (exists != null && exists.getJobId() != null) {
|
||||
remoteSysJobService.removeInnerById(exists.getJobId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("移除 Quartz 任务失败 pushConfId={}", pushConfEntity.getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private SysJobDTO getRemoteQuartzJob(ThirdPushConfEntity pushConfEntity) {
|
||||
R<SysJobDTO> result = remoteSysJobService.getByJobName(buildJobName(pushConfEntity), JOB_GROUP);
|
||||
if (result == null || !result.isOk()) {
|
||||
throw new RuntimeException(result == null ? "查询 Quartz 任务失败" : result.getMsg());
|
||||
}
|
||||
return result.getData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 sys_job 元数据,便于统一在任务中心查看
|
||||
*/
|
||||
private SysJobDTO buildSysJob(ThirdPushConfEntity entity) {
|
||||
String jobName = buildJobName(entity);
|
||||
SysJobDTO sysJob = new SysJobDTO();
|
||||
sysJob.setJobName(jobName);
|
||||
sysJob.setJobGroup(JOB_GROUP);
|
||||
sysJob.setJobOrder(JOB_ORDER);
|
||||
sysJob.setJobType(JOB_TYPE_REST);
|
||||
sysJob.setExecutePath(buildExecutePath(entity.getId()));
|
||||
sysJob.setCronExpression(entity.buildCron());
|
||||
sysJob.setMisfirePolicy(MISFIRE_POLICY_DEFAULT);
|
||||
sysJob.setJobTenantType(JOB_TENANT_TYPE);
|
||||
sysJob.setJobStatus(isEnable(entity) ? JOB_STATUS_RUNNING : JOB_STATUS_NOT_RUNNING);
|
||||
sysJob.setJobExecuteStatus(JOB_STATUS_SUCCESS);
|
||||
sysJob.setTenantId(entity.getTenantId());
|
||||
sysJob.setRemark(String.format("pushConfId=%s,bizType=%s,bizId=%s,title=%s", entity.getId(), entity.getBizType(), entity.getBizId(), entity.getTitle()));
|
||||
return sysJob;
|
||||
}
|
||||
|
||||
private boolean isEnable(ThirdPushConfEntity entity) {
|
||||
return ObjectUtil.equals(entity.getEnable(), YesNoEnum.YES.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑时补全未传的关键字段,避免校验与任务同步拿到空值
|
||||
*/
|
||||
private void mergeEditFields(ThirdPushConfEntity entity, ThirdPushConfEntity oldEntity) {
|
||||
if (ObjectUtil.isEmpty(entity.getBizType())) {
|
||||
entity.setBizType(oldEntity.getBizType());
|
||||
}
|
||||
if (ObjectUtil.isEmpty(entity.getBizId())) {
|
||||
entity.setBizId(oldEntity.getBizId());
|
||||
}
|
||||
if (ObjectUtil.isEmpty(entity.getTitle())) {
|
||||
entity.setTitle(oldEntity.getTitle());
|
||||
}
|
||||
if (ObjectUtil.isEmpty(entity.getContent())) {
|
||||
entity.setContent(oldEntity.getContent());
|
||||
}
|
||||
if (ObjectUtil.isEmpty(entity.getEnable())) {
|
||||
entity.setEnable(oldEntity.getEnable());
|
||||
}
|
||||
if (entity.getInformType() == null) {
|
||||
entity.setInformType(oldEntity.getInformType());
|
||||
}
|
||||
if (entity.getInformTime() == null) {
|
||||
entity.setInformTime(oldEntity.getInformTime());
|
||||
}
|
||||
if (entity.getTenantId() == null) {
|
||||
entity.setTenantId(oldEntity.getTenantId());
|
||||
}
|
||||
}
|
||||
|
||||
private String buildJobName(ThirdPushConfEntity pushConfEntity) {
|
||||
String jobName = "第三方推送(自动创建,请勿删除或停止)";
|
||||
if (ObjectUtil.equals(pushConfEntity.getBizType(), ThirdPushBizTypeEnum.MCH_PUSH.getType())) {
|
||||
R<MchManageVo> mchRes = remoteMchService.getById(Long.valueOf(pushConfEntity.getBizId()));
|
||||
if (!mchRes.isOk() || ObjectUtil.isEmpty(mchRes)) {
|
||||
throw new RuntimeException("添加定时任务错误,无效的店铺id");
|
||||
}
|
||||
jobName += ",店铺" + mchRes.getData().getName() + "定时推送";
|
||||
}
|
||||
jobName += ",推送配置id:" + pushConfEntity.getId();
|
||||
return jobName;
|
||||
}
|
||||
|
||||
private String buildExecutePath(Long pushConfId) {
|
||||
return String.format(EXECUTE_URL_TEMPLATE, pushConfId);
|
||||
}
|
||||
|
||||
private void assertRemoteSuccess(R<Boolean> result, String defaultMessage) {
|
||||
if (result == null || !result.isOk() || Boolean.FALSE.equals(result.getData())) {
|
||||
throw new RuntimeException(result == null || ObjectUtil.isEmpty(result.getMsg()) ? defaultMessage : result.getMsg());
|
||||
}
|
||||
}
|
||||
}
|
||||
+224
@@ -0,0 +1,224 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.impl.push;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysUser;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.thirdparty.constant.push.ThirdPushBizTypeEnum;
|
||||
import com.bsd.pjcloud.thirdparty.dto.jg.JgPusDto;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushConfEntity;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushRecordEntity;
|
||||
import com.bsd.pjcloud.thirdparty.service.ThirdJgPushService;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushConfService;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushExecuteService;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushRecordService;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushRecordUserService;
|
||||
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 推送任务统一执行入口
|
||||
* <p>
|
||||
* Quartz 触发时统一走这里,避免调度层直接依赖极光推送细节。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service("thirdPushExecuteService")
|
||||
@RequiredArgsConstructor
|
||||
public class ThirdPushExecuteServiceImpl implements ThirdPushExecuteService {
|
||||
|
||||
private static final String JOB_LOG_STATUS_SUCCESS = "0";
|
||||
private static final String JOB_LOG_STATUS_FAIL = "1";
|
||||
private static final int PUSH_BATCH_SIZE = 500;
|
||||
private static final int PUSH_MAX_RETRY_TIMES = 3;
|
||||
private static final long PUSH_RETRY_INTERVAL_MILLIS = 1000L;
|
||||
|
||||
private final ThirdPushConfService thirdPushConfService;
|
||||
private final ThirdPushRecordService thirdPushRecordService;
|
||||
private final ThirdPushRecordUserService thirdPushRecordUserService;
|
||||
private final ThirdJgPushService thirdJgPushService;
|
||||
private final RemoteUserService remoteUserService;
|
||||
private final RemoteMchService remoteMchService;
|
||||
;
|
||||
|
||||
@Override
|
||||
public String executeByConfId(String confId) {
|
||||
Long pushConfId = parseConfId(confId);
|
||||
if (pushConfId == null) {
|
||||
return JOB_LOG_STATUS_FAIL;
|
||||
}
|
||||
ThirdPushConfEntity conf = thirdPushConfService.getById(pushConfId);
|
||||
if (conf == null) {
|
||||
log.warn("推送配置不存在 confId={}", pushConfId);
|
||||
return JOB_LOG_STATUS_FAIL;
|
||||
}
|
||||
if (ObjectUtil.notEqual(conf.getEnable(), YesNoEnum.YES.getCode())) {
|
||||
log.info("推送配置未启用,跳过执行 confId={}", pushConfId);
|
||||
return JOB_LOG_STATUS_SUCCESS;
|
||||
}
|
||||
List<Long> targetDeptIds = listTargetDeptIds(conf);
|
||||
if (CollUtil.isEmpty(targetDeptIds)) {
|
||||
log.info("推送目标为空,跳过执行 confId={}", pushConfId);
|
||||
return JOB_LOG_STATUS_SUCCESS;
|
||||
}
|
||||
List<Long> targetUserIds = listTargetUserIds(targetDeptIds);
|
||||
if (CollUtil.isEmpty(targetUserIds)) {
|
||||
log.info("推送目标部门下无合法用户,跳过执行 confId={} deptIds={}", pushConfId, targetDeptIds);
|
||||
return JOB_LOG_STATUS_SUCCESS;
|
||||
}
|
||||
String batchNo = IdUtil.fastUUID();
|
||||
ThirdPushRecordEntity record = thirdPushRecordService.createBatchRecord(conf, batchNo, targetUserIds.size());
|
||||
if (record == null || record.getId() == null) {
|
||||
log.error("创建推送批次记录失败 confId={}", pushConfId);
|
||||
return JOB_LOG_STATUS_FAIL;
|
||||
}
|
||||
boolean savedUsers = thirdPushRecordUserService.saveUsersByUserIds(record.getId(), conf.getId(), batchNo, targetUserIds, conf.getBizType(), conf.getBizId(), "INIT");
|
||||
if (!savedUsers) {
|
||||
log.error("写入推送用户明细失败 confId={} batchNo={} userIds={}", pushConfId, batchNo, targetUserIds);
|
||||
thirdPushRecordService.markBatchFail(record.getId(), "写入推送用户明细失败", "推送失败");
|
||||
return JOB_LOG_STATUS_FAIL;
|
||||
}
|
||||
try {
|
||||
pushByUserIdsInBatches(pushConfId, batchNo, conf, targetUserIds);
|
||||
thirdPushRecordService.markBatchSuccess(record.getId(), targetUserIds.size(), 0, "推送成功");
|
||||
thirdPushRecordUserService.updateStatusByRecordId(record.getId(), "SUCCESS", null);
|
||||
return JOB_LOG_STATUS_SUCCESS;
|
||||
} catch (Exception e) {
|
||||
log.error("执行推送任务失败 confId={} batchNo={}", pushConfId, batchNo, e);
|
||||
thirdPushRecordService.markBatchFail(record.getId(), e.getMessage(), "推送失败");
|
||||
thirdPushRecordUserService.updateStatusByRecordId(record.getId(), "FAIL", e.getMessage());
|
||||
return JOB_LOG_STATUS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询需要推送的部门标签
|
||||
*/
|
||||
private List<Long> listTargetDeptIds(ThirdPushConfEntity conf) {
|
||||
if (ObjectUtil.equals(conf.getBizType(), ThirdPushBizTypeEnum.MCH_PUSH.getType())) {
|
||||
Long mchId = Long.valueOf(conf.getBizId());
|
||||
R<List<Long>> apiRes = remoteMchService.getSelfCanteenUserDeptIdList(mchId);
|
||||
if (apiRes == null || !apiRes.isOk() || CollUtil.isEmpty(apiRes.getData())) {
|
||||
return List.of();
|
||||
}
|
||||
return apiRes.getData().stream()
|
||||
.filter(ObjectUtil::isNotEmpty)
|
||||
.distinct()
|
||||
.toList();
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门解析实际推送用户
|
||||
*/
|
||||
private List<Long> listTargetUserIds(List<Long> deptIds) {
|
||||
if (CollUtil.isEmpty(deptIds)) {
|
||||
return List.of();
|
||||
}
|
||||
R<List<SysUser>> result = remoteUserService.getUserIdListByDeptIdList(deptIds);
|
||||
if (result == null || !result.isOk() || CollUtil.isEmpty(result.getData())) {
|
||||
return List.of();
|
||||
}
|
||||
return result.getData().stream()
|
||||
.map(SysUser::getUserId)
|
||||
.filter(ObjectUtil::isNotEmpty)
|
||||
.distinct()
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按用户ID分组分批推送
|
||||
*/
|
||||
private void pushByUserIdsInBatches(Long pushConfId, String batchNo, ThirdPushConfEntity conf, List<Long> targetUserIds) {
|
||||
List<List<Long>> userIdGroups = splitList(targetUserIds, PUSH_BATCH_SIZE);
|
||||
int totalDeviceCount = targetUserIds.size();
|
||||
int totalGroupCount = userIdGroups.size();
|
||||
int successDeviceCount = 0;
|
||||
|
||||
log.info("开始分组推送 confId={} batchNo={} totalDeviceCount={} totalGroupCount={} batchSize={}",
|
||||
pushConfId, batchNo, totalDeviceCount, totalGroupCount, PUSH_BATCH_SIZE);
|
||||
|
||||
for (int index = 0; index < totalGroupCount; index++) {
|
||||
List<Long> userIdGroup = userIdGroups.get(index);
|
||||
int groupNo = index + 1;
|
||||
pushSingleGroupWithRetry(pushConfId, batchNo, conf, userIdGroup, groupNo, totalGroupCount);
|
||||
successDeviceCount += userIdGroup.size();
|
||||
}
|
||||
|
||||
log.info("分组推送完成 confId={} batchNo={} totalDeviceCount={} totalGroupCount={} successDeviceCount={} failDeviceCount={}",
|
||||
pushConfId, batchNo, totalDeviceCount, totalGroupCount, successDeviceCount, totalDeviceCount - successDeviceCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送单个分组,失败后自动重试
|
||||
*/
|
||||
private void pushSingleGroupWithRetry(Long pushConfId, String batchNo, ThirdPushConfEntity conf, List<Long> userIdGroup,
|
||||
int groupNo, int totalGroupCount) {
|
||||
for (int attempt = 1; attempt <= PUSH_MAX_RETRY_TIMES; attempt++) {
|
||||
try {
|
||||
JgPusDto dto = new JgPusDto();
|
||||
dto.setTitle(conf.getTitle());
|
||||
dto.setSubtitle(conf.getContent());
|
||||
dto.setUserIds(userIdGroup);
|
||||
|
||||
log.info("开始推送分组 confId={} batchNo={} groupNo={}/{} groupDeviceCount={} attempt={}",
|
||||
pushConfId, batchNo, groupNo, totalGroupCount, userIdGroup.size(), attempt);
|
||||
thirdJgPushService.push(dto);
|
||||
log.info("推送分组成功 confId={} batchNo={} groupNo={}/{} groupDeviceCount={} attempt={}",
|
||||
pushConfId, batchNo, groupNo, totalGroupCount, userIdGroup.size(), attempt);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
log.error("推送分组失败 confId={} batchNo={} groupNo={}/{} groupDeviceCount={} attempt={} maxRetry={}",
|
||||
pushConfId, batchNo, groupNo, totalGroupCount, userIdGroup.size(), attempt, PUSH_MAX_RETRY_TIMES, e);
|
||||
if (attempt >= PUSH_MAX_RETRY_TIMES) {
|
||||
throw new RuntimeException(String.format("分组推送失败 groupNo=%s totalGroupCount=%s", groupNo, totalGroupCount), e);
|
||||
}
|
||||
sleepBeforeRetry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表按固定大小分片
|
||||
*/
|
||||
private List<List<Long>> splitList(List<Long> sourceList, int batchSize) {
|
||||
if (CollUtil.isEmpty(sourceList) || batchSize <= 0) {
|
||||
return List.of();
|
||||
}
|
||||
java.util.ArrayList<List<Long>> result = new java.util.ArrayList<>();
|
||||
for (int start = 0; start < sourceList.size(); start += batchSize) {
|
||||
int end = Math.min(start + batchSize, sourceList.size());
|
||||
result.add(sourceList.subList(start, end));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分组失败后的重试间隔
|
||||
*/
|
||||
protected void sleepBeforeRetry() {
|
||||
try {
|
||||
Thread.sleep(PUSH_RETRY_INTERVAL_MILLIS);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("分组推送重试等待被中断", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Long parseConfId(String confId) {
|
||||
try {
|
||||
return Long.valueOf(confId);
|
||||
} catch (Exception e) {
|
||||
log.error("解析推送配置ID失败 confId={}", confId, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.impl.push;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushConfEntity;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushRecordEntity;
|
||||
import com.bsd.pjcloud.thirdparty.mapper.push.ThirdPushRecordMapper;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushRecordService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 推送通知批次记录
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ThirdPushRecordServiceImpl extends ServiceImpl<ThirdPushRecordMapper, ThirdPushRecordEntity> implements ThirdPushRecordService {
|
||||
|
||||
@Override
|
||||
public ThirdPushRecordEntity createBatchRecord(ThirdPushConfEntity conf, String batchNo, Integer receiverCount) {
|
||||
if (conf == null || conf.getId() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ThirdPushRecordEntity record = new ThirdPushRecordEntity();
|
||||
record.setConfId(conf.getId());
|
||||
record.setBatchNo(ObjectUtil.defaultIfEmpty(batchNo, IdUtil.fastUUID()));
|
||||
record.setBizType(conf.getBizType());
|
||||
record.setBizId(conf.getBizId());
|
||||
record.setTitle(conf.getTitle());
|
||||
record.setContent(conf.getContent());
|
||||
record.setInformType(conf.getInformType());
|
||||
record.setInformTime(conf.getInformTime());
|
||||
record.setReceiverCount(ObjectUtil.defaultIfNull(receiverCount, 0));
|
||||
record.setSuccessCount(0);
|
||||
record.setFailCount(0);
|
||||
record.setStatus("INIT");
|
||||
record.setSendTime(LocalDateTime.now());
|
||||
|
||||
boolean saved = save(record);
|
||||
return saved ? record : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean markBatchSuccess(Long recordId, Integer successCount, Integer failCount, String pushResult) {
|
||||
if (recordId == null) {
|
||||
return false;
|
||||
}
|
||||
ThirdPushRecordEntity update = new ThirdPushRecordEntity();
|
||||
update.setId(recordId);
|
||||
update.setSuccessCount(ObjectUtil.defaultIfNull(successCount, 0));
|
||||
update.setFailCount(ObjectUtil.defaultIfNull(failCount, 0));
|
||||
update.setStatus("SUCCESS");
|
||||
update.setPushResult(pushResult);
|
||||
return updateById(update);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean markBatchFail(Long recordId, String errorMsg, String pushResult) {
|
||||
if (recordId == null) {
|
||||
return false;
|
||||
}
|
||||
ThirdPushRecordEntity update = new ThirdPushRecordEntity();
|
||||
update.setId(recordId);
|
||||
update.setStatus("FAIL");
|
||||
update.setErrorMsg(errorMsg);
|
||||
update.setPushResult(pushResult);
|
||||
return updateById(update);
|
||||
}
|
||||
}
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.impl.push;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysUser;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushRecordUserEntity;
|
||||
import com.bsd.pjcloud.thirdparty.mapper.push.ThirdPushRecordUserMapper;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushRecordUserService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 推送通知用户明细记录
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ThirdPushRecordUserServiceImpl extends ServiceImpl<ThirdPushRecordUserMapper, ThirdPushRecordUserEntity> implements ThirdPushRecordUserService {
|
||||
|
||||
private final RemoteUserService remoteUserService;
|
||||
|
||||
@Override
|
||||
public Boolean saveUsers(Long recordId, Long confId, String batchNo, List<Long> deptIds, String bizType, String bizId, String status) {
|
||||
if (recordId == null || confId == null || ObjectUtil.isEmpty(batchNo) || CollUtil.isEmpty(deptIds)) {
|
||||
return false;
|
||||
}
|
||||
List<Long> userIds = listUserIdsByDeptIds(deptIds);
|
||||
if (CollUtil.isEmpty(userIds)) {
|
||||
log.warn("根据部门查询推送用户为空 recordId={} confId={} deptIds={}", recordId, confId, deptIds);
|
||||
return false;
|
||||
}
|
||||
return saveUsersByUserIds(recordId, confId, batchNo, userIds, bizType, bizId, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean saveUsersByUserIds(Long recordId, Long confId, String batchNo, List<Long> userIds, String bizType, String bizId, String status) {
|
||||
if (recordId == null || confId == null || ObjectUtil.isEmpty(batchNo) || CollUtil.isEmpty(userIds)) {
|
||||
return false;
|
||||
}
|
||||
List<ThirdPushRecordUserEntity> list = buildRecordUsers(recordId, confId, batchNo, userIds, bizType, bizId, status);
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return false;
|
||||
}
|
||||
return saveBatch(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateStatusByRecordId(Long recordId, String status, String errorMsg) {
|
||||
if (recordId == null || ObjectUtil.isEmpty(status)) {
|
||||
return false;
|
||||
}
|
||||
return update(new LambdaUpdateWrapper<ThirdPushRecordUserEntity>()
|
||||
.eq(ThirdPushRecordUserEntity::getRecordId, recordId)
|
||||
.set(ThirdPushRecordUserEntity::getStatus, status)
|
||||
.set(ObjectUtil.isNotEmpty(errorMsg), ThirdPushRecordUserEntity::getErrorMsg, errorMsg)
|
||||
.set(ObjectUtil.isEmpty(errorMsg), ThirdPushRecordUserEntity::getErrorMsg, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门列表解析目标用户
|
||||
*/
|
||||
private List<Long> listUserIdsByDeptIds(List<Long> deptIds) {
|
||||
List<Long> validDeptIds = deptIds.stream()
|
||||
.filter(ObjectUtil::isNotEmpty)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (CollUtil.isEmpty(validDeptIds)) {
|
||||
return List.of();
|
||||
}
|
||||
R<List<SysUser>> result = remoteUserService.getUserIdListByDeptIdList(validDeptIds);
|
||||
if (result == null || !result.isOk() || CollUtil.isEmpty(result.getData())) {
|
||||
return List.of();
|
||||
}
|
||||
return result.getData().stream()
|
||||
.map(SysUser::getUserId)
|
||||
.filter(ObjectUtil::isNotEmpty)
|
||||
.distinct()
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建推送用户明细
|
||||
*/
|
||||
private List<ThirdPushRecordUserEntity> buildRecordUsers(Long recordId, Long confId, String batchNo, List<Long> userIds,
|
||||
String bizType, String bizId, String status) {
|
||||
String finalStatus = ObjectUtil.defaultIfEmpty(status, "INIT");
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return userIds.stream()
|
||||
.filter(ObjectUtil::isNotEmpty)
|
||||
.distinct()
|
||||
.map(userId -> {
|
||||
ThirdPushRecordUserEntity entity = new ThirdPushRecordUserEntity();
|
||||
entity.setRecordId(recordId);
|
||||
entity.setConfId(confId);
|
||||
entity.setBatchNo(batchNo);
|
||||
entity.setUserId(userId);
|
||||
entity.setBizType(bizType);
|
||||
entity.setBizId(bizId);
|
||||
entity.setStatus(finalStatus);
|
||||
entity.setSendTime(now);
|
||||
return entity;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.push;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushConfEntity;
|
||||
|
||||
/**
|
||||
* 推送配置
|
||||
*/
|
||||
public interface ThirdPushConfService extends IService<ThirdPushConfEntity> {
|
||||
|
||||
/**
|
||||
* 创建推送配置
|
||||
*/
|
||||
Boolean create(ThirdPushConfEntity entity);
|
||||
|
||||
/**
|
||||
* 修改推送配置
|
||||
*/
|
||||
Boolean edit(ThirdPushConfEntity entity);
|
||||
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.push;
|
||||
|
||||
/**
|
||||
* 推送任务执行服务
|
||||
*/
|
||||
public interface ThirdPushExecuteService {
|
||||
|
||||
/**
|
||||
* 根据推送配置 ID 执行一次推送
|
||||
*
|
||||
* @param confId 推送配置 ID
|
||||
* @return Quartz 约定返回值,0 表示成功,1 表示失败
|
||||
*/
|
||||
String executeByConfId(String confId);
|
||||
}
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.push;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushConfEntity;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushRecordEntity;
|
||||
|
||||
/**
|
||||
* 推送通知批次记录
|
||||
*/
|
||||
public interface ThirdPushRecordService extends IService<ThirdPushRecordEntity> {
|
||||
|
||||
/**
|
||||
* 创建推送批次记录
|
||||
*
|
||||
* @param conf 推送配置
|
||||
* @param batchNo 批次号(外部传入或内部生成)
|
||||
* @param receiverCount 接收人数
|
||||
*/
|
||||
ThirdPushRecordEntity createBatchRecord(ThirdPushConfEntity conf, String batchNo, Integer receiverCount);
|
||||
|
||||
/**
|
||||
* 批次发送成功后回写统计信息
|
||||
*/
|
||||
Boolean markBatchSuccess(Long recordId, Integer successCount, Integer failCount, String pushResult);
|
||||
|
||||
/**
|
||||
* 批次发送失败
|
||||
*/
|
||||
Boolean markBatchFail(Long recordId, String errorMsg, String pushResult);
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.push;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushRecordUserEntity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 推送通知用户明细记录
|
||||
*/
|
||||
public interface ThirdPushRecordUserService extends IService<ThirdPushRecordUserEntity> {
|
||||
|
||||
/**
|
||||
* 根据部门批量写入用户明细
|
||||
*
|
||||
* @param recordId 推送批次记录id
|
||||
* @param confId 推送配置id
|
||||
* @param batchNo 批次号
|
||||
* @param deptIds 部门id列表
|
||||
* @param bizType 业务类型
|
||||
* @param bizId 业务id
|
||||
* @param status 初始状态
|
||||
*/
|
||||
Boolean saveUsers(Long recordId, Long confId, String batchNo, List<Long> deptIds, String bizType, String bizId, String status);
|
||||
|
||||
/**
|
||||
* 根据用户ID批量写入用户明细
|
||||
*
|
||||
* @param recordId 推送批次记录id
|
||||
* @param confId 推送配置id
|
||||
* @param batchNo 批次号
|
||||
* @param userIds 用户id列表
|
||||
* @param bizType 业务类型
|
||||
* @param bizId 业务id
|
||||
* @param status 初始状态
|
||||
*/
|
||||
Boolean saveUsersByUserIds(Long recordId, Long confId, String batchNo, List<Long> userIds, String bizType, String bizId, String status);
|
||||
|
||||
/**
|
||||
* 按批次记录更新用户明细状态
|
||||
*/
|
||||
Boolean updateStatusByRecordId(Long recordId, String status, String errorMsg);
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.impl.push;
|
||||
|
||||
import com.bsd.pjcloud.admin.api.entity.SysUser;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.thirdparty.constant.push.ThirdPushBizTypeEnum;
|
||||
import com.bsd.pjcloud.thirdparty.dto.jg.JgPusDto;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushConfEntity;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushRecordEntity;
|
||||
import com.bsd.pjcloud.thirdparty.service.ThirdJgPushService;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushConfService;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushRecordService;
|
||||
import com.bsd.pjcloud.thirdparty.service.push.ThirdPushRecordUserService;
|
||||
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ThirdPushExecuteServiceImplTest {
|
||||
|
||||
@Mock
|
||||
private ThirdPushConfService thirdPushConfService;
|
||||
|
||||
@Mock
|
||||
private ThirdPushRecordService thirdPushRecordService;
|
||||
|
||||
@Mock
|
||||
private ThirdPushRecordUserService thirdPushRecordUserService;
|
||||
|
||||
@Mock
|
||||
private ThirdJgPushService thirdJgPushService;
|
||||
|
||||
@Mock
|
||||
private RemoteUserService remoteUserService;
|
||||
|
||||
@Mock
|
||||
private RemoteMchService remoteMchService;
|
||||
|
||||
@Test
|
||||
void executeByConfIdShouldPushByUserIdsAndKeepDeptLogicAsFallbackSource() {
|
||||
ThirdPushExecuteServiceImpl thirdPushExecuteService = newTestService();
|
||||
List<JgPusDto> pushDtos = executeAndCapturePushDtos(thirdPushExecuteService, 2, 0);
|
||||
|
||||
Assertions.assertEquals(1, pushDtos.size());
|
||||
Assertions.assertEquals(List.of(1L, 2L), pushDtos.get(0).getUserIds());
|
||||
Assertions.assertTrue(pushDtos.get(0).getTagList() == null || pushDtos.get(0).getTagList().isEmpty());
|
||||
verify(thirdPushRecordUserService).saveUsersByUserIds(anyLong(), anyLong(), anyString(), anyList(), anyString(), anyString(), anyString());
|
||||
verify(thirdPushRecordUserService, never()).saveUsers(anyLong(), anyLong(), anyString(), anyList(), anyString(), anyString(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void executeByConfIdShouldSplitHundredUsersIntoOneGroup() {
|
||||
ThirdPushExecuteServiceImpl thirdPushExecuteService = newTestService();
|
||||
List<JgPusDto> pushDtos = executeAndCapturePushDtos(thirdPushExecuteService, 100, 0);
|
||||
|
||||
Assertions.assertEquals(1, pushDtos.size());
|
||||
Assertions.assertEquals(100, pushDtos.get(0).getUserIds().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void executeByConfIdShouldSplitThousandUsersIntoTwoGroups() {
|
||||
ThirdPushExecuteServiceImpl thirdPushExecuteService = newTestService();
|
||||
List<JgPusDto> pushDtos = executeAndCapturePushDtos(thirdPushExecuteService, 1000, 0);
|
||||
|
||||
Assertions.assertEquals(2, pushDtos.size());
|
||||
Assertions.assertTrue(pushDtos.stream().allMatch(item -> item.getUserIds().size() <= 500));
|
||||
Assertions.assertEquals(1000, pushDtos.stream().mapToInt(item -> item.getUserIds().size()).sum());
|
||||
}
|
||||
|
||||
@Test
|
||||
void executeByConfIdShouldSplitTenThousandUsersIntoTwentyGroups() {
|
||||
ThirdPushExecuteServiceImpl thirdPushExecuteService = newTestService();
|
||||
List<JgPusDto> pushDtos = executeAndCapturePushDtos(thirdPushExecuteService, 10000, 0);
|
||||
|
||||
Assertions.assertEquals(20, pushDtos.size());
|
||||
Assertions.assertTrue(pushDtos.stream().allMatch(item -> item.getUserIds().size() <= 500));
|
||||
Assertions.assertEquals(10000, pushDtos.stream().mapToInt(item -> item.getUserIds().size()).sum());
|
||||
}
|
||||
|
||||
@Test
|
||||
void executeByConfIdShouldRetryFailedGroupAndThenSucceed() {
|
||||
ThirdPushExecuteServiceImpl thirdPushExecuteService = newTestService();
|
||||
List<JgPusDto> pushDtos = executeAndCapturePushDtos(thirdPushExecuteService, 1000, 2);
|
||||
|
||||
Assertions.assertEquals(2, pushDtos.size());
|
||||
}
|
||||
|
||||
private ThirdPushExecuteServiceImpl newTestService() {
|
||||
return new ThirdPushExecuteServiceImpl(
|
||||
thirdPushConfService,
|
||||
thirdPushRecordService,
|
||||
thirdPushRecordUserService,
|
||||
thirdJgPushService,
|
||||
remoteUserService,
|
||||
remoteMchService
|
||||
) {
|
||||
@Override
|
||||
protected void sleepBeforeRetry() {
|
||||
// 测试场景跳过真实等待,避免单元测试耗时过长
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private List<JgPusDto> executeAndCapturePushDtos(ThirdPushExecuteServiceImpl thirdPushExecuteService, int userCount, int failTimes) {
|
||||
ThirdPushConfEntity conf = new ThirdPushConfEntity();
|
||||
conf.setId(10L);
|
||||
conf.setTitle("测试标题");
|
||||
conf.setContent("测试内容");
|
||||
conf.setBizType(ThirdPushBizTypeEnum.MCH_PUSH.getType());
|
||||
conf.setBizId("66");
|
||||
conf.setEnable(YesNoEnum.YES.getCode());
|
||||
|
||||
ThirdPushRecordEntity record = new ThirdPushRecordEntity();
|
||||
record.setId(99L);
|
||||
|
||||
when(thirdPushConfService.getById(10L)).thenReturn(conf);
|
||||
when(remoteMchService.getSelfCanteenUserDeptIdList(66L)).thenReturn(R.ok(List.of(10001L, 10002L)));
|
||||
when(remoteUserService.getUserIdListByDeptIdList(List.of(10001L, 10002L))).thenReturn(R.ok(buildUsers(userCount)));
|
||||
when(thirdPushRecordService.createBatchRecord(any(), anyString(), anyInt())).thenReturn(record);
|
||||
when(thirdPushRecordUserService.saveUsersByUserIds(anyLong(), anyLong(), anyString(), anyList(), anyString(), anyString(), anyString()))
|
||||
.thenReturn(true);
|
||||
when(thirdPushRecordService.markBatchSuccess(99L, userCount, 0, "推送成功")).thenReturn(true);
|
||||
when(thirdPushRecordUserService.updateStatusByRecordId(99L, "SUCCESS", null)).thenReturn(true);
|
||||
|
||||
List<JgPusDto> pushDtos = new ArrayList<>();
|
||||
AtomicInteger counter = new AtomicInteger();
|
||||
doAnswer(invocation -> {
|
||||
JgPusDto dto = invocation.getArgument(0);
|
||||
int current = counter.getAndIncrement();
|
||||
if (current < failTimes) {
|
||||
throw new RuntimeException("模拟推送失败");
|
||||
}
|
||||
pushDtos.add(dto);
|
||||
return null;
|
||||
}).when(thirdJgPushService).push(any(JgPusDto.class));
|
||||
|
||||
String result = thirdPushExecuteService.executeByConfId("10");
|
||||
|
||||
Assertions.assertEquals("0", result);
|
||||
return pushDtos;
|
||||
}
|
||||
|
||||
private List<SysUser> buildUsers(int count) {
|
||||
List<SysUser> users = new ArrayList<>();
|
||||
for (int i = 1; i <= count; i++) {
|
||||
SysUser user = new SysUser();
|
||||
user.setUserId((long) i);
|
||||
users.add(user);
|
||||
}
|
||||
return users;
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.impl.push;
|
||||
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.thirdparty.entity.ThirdPushRecordUserEntity;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
class ThirdPushRecordUserServiceImplTest {
|
||||
|
||||
@Test
|
||||
void saveUsersByUserIdsShouldSaveDistinctUsers() {
|
||||
TestableThirdPushRecordUserServiceImpl service = new TestableThirdPushRecordUserServiceImpl();
|
||||
|
||||
boolean result = service.saveUsersByUserIds(1L, 2L, "batch-1",
|
||||
Arrays.asList(1001L, 1002L, 1001L, null), "MCH_PUSH", "88", "INIT");
|
||||
|
||||
Assertions.assertTrue(result);
|
||||
Assertions.assertEquals(2, service.savedEntities.size());
|
||||
Assertions.assertEquals(List.of(1001L, 1002L), service.savedEntities.stream().map(ThirdPushRecordUserEntity::getUserId).toList());
|
||||
Assertions.assertTrue(service.savedEntities.stream().allMatch(item -> "INIT".equals(item.getStatus())));
|
||||
}
|
||||
|
||||
private static class TestableThirdPushRecordUserServiceImpl extends ThirdPushRecordUserServiceImpl {
|
||||
|
||||
private final List<ThirdPushRecordUserEntity> savedEntities = new ArrayList<>();
|
||||
|
||||
private TestableThirdPushRecordUserServiceImpl() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveBatch(Collection<ThirdPushRecordUserEntity> entityList) {
|
||||
this.savedEntities.clear();
|
||||
this.savedEntities.addAll(entityList);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0"?>
|
||||
<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>
|
||||
<groupId>com.bsd</groupId>
|
||||
<artifactId>pjcloud-visual</artifactId>
|
||||
<version>5.7.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pjcloud-daemon-quartz-api</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.bsd</groupId>
|
||||
<artifactId>pjcloud-common-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.bsd</groupId>
|
||||
<artifactId>pjcloud-common-feign</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package com.bsd.pjcloud.daemon.quartz.api.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 定时任务远程传输对象
|
||||
*/
|
||||
@Data
|
||||
public class SysJobDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 任务主键ID
|
||||
*/
|
||||
private Long jobId;
|
||||
|
||||
/**
|
||||
* 任务名称
|
||||
*/
|
||||
private String jobName;
|
||||
|
||||
/**
|
||||
* 任务分组
|
||||
*/
|
||||
private String jobGroup;
|
||||
|
||||
/**
|
||||
* 任务排序值
|
||||
*/
|
||||
private String jobOrder;
|
||||
|
||||
/**
|
||||
* 任务类型
|
||||
*/
|
||||
private String jobType;
|
||||
|
||||
/**
|
||||
* REST任务执行地址
|
||||
*/
|
||||
private String executePath;
|
||||
|
||||
/**
|
||||
* Java类任务的类名
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* Java类任务的执行方法名
|
||||
*/
|
||||
private String methodName;
|
||||
|
||||
/**
|
||||
* Java类任务的方法参数值
|
||||
*/
|
||||
private String methodParamsValue;
|
||||
|
||||
/**
|
||||
* Cron表达式
|
||||
*/
|
||||
private String cronExpression;
|
||||
|
||||
/**
|
||||
* 误触发策略
|
||||
*/
|
||||
private String misfirePolicy;
|
||||
|
||||
/**
|
||||
* 租户任务类型
|
||||
*/
|
||||
private String jobTenantType;
|
||||
|
||||
/**
|
||||
* 任务状态
|
||||
*/
|
||||
private String jobStatus;
|
||||
|
||||
/**
|
||||
* 最近一次执行状态
|
||||
*/
|
||||
private String jobExecuteStatus;
|
||||
|
||||
/**
|
||||
* 所属租户ID
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 任务备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.bsd.pjcloud.daemon.quartz.api.feign;
|
||||
|
||||
import com.bsd.pjcloud.common.core.constant.ServiceNameConstants;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.feign.annotation.NoToken;
|
||||
import com.bsd.pjcloud.daemon.quartz.api.dto.SysJobDTO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* Quartz 任务远程服务
|
||||
*/
|
||||
@FeignClient(contextId = "remoteSysJobService", value = ServiceNameConstants.DAEMON_QUARTZ_SERVICE)
|
||||
public interface RemoteSysJobService {
|
||||
|
||||
/**
|
||||
* 根据任务名称和任务组查询任务
|
||||
*/
|
||||
@NoToken
|
||||
@GetMapping("/sys-job/inner/by-name")
|
||||
R<SysJobDTO> getByJobName(@RequestParam("jobName") String jobName, @RequestParam("jobGroup") String jobGroup);
|
||||
|
||||
/**
|
||||
* 校验 cron 表达式
|
||||
*/
|
||||
@NoToken
|
||||
@GetMapping("/sys-job/inner/validate-cron")
|
||||
R<Boolean> validateCron(@RequestParam("cron") String cron);
|
||||
|
||||
/**
|
||||
* 新增定时任务
|
||||
*/
|
||||
@NoToken
|
||||
@PostMapping("/sys-job/inner")
|
||||
R<Boolean> saveInner(@RequestBody SysJobDTO sysJob);
|
||||
|
||||
/**
|
||||
* 修改定时任务
|
||||
*/
|
||||
@NoToken
|
||||
@PutMapping("/sys-job/inner")
|
||||
R<Boolean> updateInner(@RequestBody SysJobDTO sysJob);
|
||||
|
||||
/**
|
||||
* 删除定时任务
|
||||
*/
|
||||
@NoToken
|
||||
@DeleteMapping("/sys-job/inner/{id}")
|
||||
R<Boolean> removeInnerById(@PathVariable("id") Long id);
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
com.bsd.pjcloud.daemon.quartz.api.feign.RemoteSysJobService
|
||||
@@ -15,6 +15,11 @@
|
||||
<description>基于quartz后台跑批定时任务模块</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.bsd</groupId>
|
||||
<artifactId>pjcloud-daemon-quartz-api</artifactId>
|
||||
<version>5.7.0</version>
|
||||
</dependency>
|
||||
<!--注册中心客户端-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
|
||||
+18
-11
@@ -46,17 +46,24 @@ public class PjcloudInitQuartzJob implements InitializingBean {
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
sysJobService.list().forEach(sysjob -> {
|
||||
if (PjcloudQuartzEnum.JOB_STATUS_RELEASE.getType().equals(sysjob.getJobStatus())) {
|
||||
taskUtil.removeJob(sysjob, scheduler);
|
||||
}
|
||||
else if (PjcloudQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysjob.getJobStatus())) {
|
||||
taskUtil.resumeJob(sysjob, scheduler);
|
||||
}
|
||||
else if (PjcloudQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(sysjob.getJobStatus())) {
|
||||
taskUtil.pauseJob(sysjob, scheduler);
|
||||
}
|
||||
else {
|
||||
taskUtil.removeJob(sysjob, scheduler);
|
||||
try {
|
||||
if (PjcloudQuartzEnum.JOB_STATUS_RELEASE.getType().equals(sysjob.getJobStatus())) {
|
||||
taskUtil.removeJob(sysjob, scheduler);
|
||||
}
|
||||
else if (PjcloudQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysjob.getJobStatus())) {
|
||||
taskUtil.addOrUpateJob(sysjob, scheduler);
|
||||
}
|
||||
else if (PjcloudQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(sysjob.getJobStatus())) {
|
||||
taskUtil.addOrUpateJob(sysjob, scheduler);
|
||||
}
|
||||
else {
|
||||
taskUtil.removeJob(sysjob, scheduler);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("初始化定时任务失败 jobId={}, jobName={}, jobGroup={}, jobStatus={}, cron={}, jobType={}, className={}, methodName={}, methodParams={}",
|
||||
sysjob.getJobId(), sysjob.getJobName(), sysjob.getJobGroup(), sysjob.getJobStatus(),
|
||||
sysjob.getCronExpression(), sysjob.getJobType(), sysjob.getClassName(), sysjob.getMethodName(),
|
||||
sysjob.getMethodParamsValue(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+47
-21
@@ -76,7 +76,7 @@ public class SysJobController {
|
||||
LambdaQueryWrapper<SysJob> wrapper = Wrappers.<SysJob>lambdaQuery()
|
||||
.like(StrUtil.isNotBlank(sysJob.getJobName()), SysJob::getJobName, sysJob.getJobName())
|
||||
.like(StrUtil.isNotBlank(sysJob.getJobGroup()), SysJob::getJobGroup, sysJob.getJobGroup())
|
||||
.eq(StrUtil.isNotBlank(sysJob.getJobStatus()), SysJob::getJobStatus, sysJob.getJobGroup())
|
||||
.eq(StrUtil.isNotBlank(sysJob.getJobStatus()), SysJob::getJobStatus, sysJob.getJobStatus())
|
||||
.eq(StrUtil.isNotBlank(sysJob.getJobExecuteStatus()), SysJob::getJobExecuteStatus,
|
||||
sysJob.getJobExecuteStatus());
|
||||
return R.ok(sysJobService.page(page, wrapper));
|
||||
@@ -103,10 +103,19 @@ public class SysJobController {
|
||||
@HasPermission("job_sys_job_add")
|
||||
@Operation(description = "新增定时任务")
|
||||
public R save(@RequestBody SysJob sysJob) {
|
||||
if (!taskUtil.isValidCron(sysJob.getCronExpression())) {
|
||||
return R.failed("cron表达式不合法");
|
||||
}
|
||||
if (sysJobService.count(Wrappers.query(SysJob.builder()
|
||||
.jobName(sysJob.getJobName())
|
||||
.jobGroup(sysJob.getJobGroup())
|
||||
.build())) > 0) {
|
||||
return R.failed("任务重复,请检查此组内是否已包含同名任务");
|
||||
}
|
||||
sysJob.setJobStatus(PjcloudQuartzEnum.JOB_STATUS_RUNNING.getType());
|
||||
sysJob.setCreateBy(SecurityUtils.getUser().getUsername());
|
||||
// 初始化任务
|
||||
taskUtil.addOrUpateJob(sysJob, scheduler);
|
||||
sysJob.setJobStatus(PjcloudQuartzEnum.JOB_STATUS_RELEASE.getType());
|
||||
sysJob.setCreateBy(SecurityUtils.getUser().getUsername());
|
||||
return R.ok(sysJobService.save(sysJob));
|
||||
}
|
||||
|
||||
@@ -120,15 +129,31 @@ public class SysJobController {
|
||||
@HasPermission("job_sys_job_edit")
|
||||
@Operation(description = "修改定时任务")
|
||||
public R updateById(@RequestBody SysJob sysJob) {
|
||||
sysJob.setUpdateBy(SecurityUtils.getUser().getUsername());
|
||||
SysJob querySysJob = this.sysJobService.getById(sysJob.getJobId());
|
||||
if (PjcloudQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(querySysJob.getJobStatus())) {
|
||||
if (querySysJob == null) {
|
||||
return R.failed("任务不存在");
|
||||
}
|
||||
if (!taskUtil.isValidCron(sysJob.getCronExpression())) {
|
||||
return R.failed("cron表达式不合法");
|
||||
}
|
||||
|
||||
sysJob.setUpdateBy(SecurityUtils.getUser().getUsername());
|
||||
sysJob.setJobStatus(querySysJob.getJobStatus());
|
||||
sysJob.setJobExecuteStatus(querySysJob.getJobExecuteStatus());
|
||||
|
||||
boolean jobKeyChanged = !StrUtil.equals(querySysJob.getJobName(), sysJob.getJobName())
|
||||
|| !StrUtil.equals(querySysJob.getJobGroup(), sysJob.getJobGroup());
|
||||
if (jobKeyChanged) {
|
||||
this.taskUtil.removeJob(querySysJob, scheduler);
|
||||
}
|
||||
|
||||
if (PjcloudQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysJob.getJobStatus())
|
||||
|| PjcloudQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(sysJob.getJobStatus())) {
|
||||
this.taskUtil.addOrUpateJob(sysJob, scheduler);
|
||||
sysJobService.updateById(sysJob);
|
||||
}
|
||||
else if (PjcloudQuartzEnum.JOB_STATUS_RELEASE.getType().equals(querySysJob.getJobStatus())) {
|
||||
sysJobService.updateById(sysJob);
|
||||
} else {
|
||||
this.taskUtil.removeJob(sysJob, scheduler);
|
||||
}
|
||||
sysJobService.updateById(sysJob);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@@ -143,13 +168,11 @@ public class SysJobController {
|
||||
@Operation(description = "唯一标识查询定时任务,暂停任务才能删除")
|
||||
public R removeById(@PathVariable Long id) {
|
||||
SysJob querySysJob = this.sysJobService.getById(id);
|
||||
if (PjcloudQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(querySysJob.getJobStatus())) {
|
||||
this.taskUtil.removeJob(querySysJob, scheduler);
|
||||
this.sysJobService.removeById(id);
|
||||
}
|
||||
else if (PjcloudQuartzEnum.JOB_STATUS_RELEASE.getType().equals(querySysJob.getJobStatus())) {
|
||||
this.sysJobService.removeById(id);
|
||||
if (querySysJob == null) {
|
||||
return R.failed("任务不存在");
|
||||
}
|
||||
this.taskUtil.removeJob(querySysJob, scheduler);
|
||||
this.sysJobService.removeById(id);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@@ -231,12 +254,11 @@ public class SysJobController {
|
||||
@Operation(description = "启动定时任务")
|
||||
public R startJob(@PathVariable("id") Long jobId) {
|
||||
SysJob querySysJob = this.sysJobService.getById(jobId);
|
||||
if (querySysJob != null && PjcloudQuartzEnum.JOB_LOG_STATUS_FAIL.getType().equals(querySysJob.getJobStatus())) {
|
||||
taskUtil.addOrUpateJob(querySysJob, scheduler);
|
||||
}
|
||||
else {
|
||||
taskUtil.resumeJob(querySysJob, scheduler);
|
||||
if (querySysJob == null) {
|
||||
return R.failed("任务不存在");
|
||||
}
|
||||
querySysJob.setJobStatus(PjcloudQuartzEnum.JOB_STATUS_RUNNING.getType());
|
||||
taskUtil.addOrUpateJob(querySysJob, scheduler);
|
||||
// 更新定时任务状态条件,暂停状态3更新为运行状态2
|
||||
this.sysJobService
|
||||
.updateById(SysJob.builder().jobId(jobId).jobStatus(PjcloudQuartzEnum.JOB_STATUS_RUNNING.getType()).build());
|
||||
@@ -267,12 +289,16 @@ public class SysJobController {
|
||||
@Operation(description = "暂停定时任务")
|
||||
public R shutdownJob(@PathVariable("id") Long id) {
|
||||
SysJob querySysJob = this.sysJobService.getById(id);
|
||||
if (querySysJob == null) {
|
||||
return R.failed("任务不存在");
|
||||
}
|
||||
// 更新定时任务状态条件,运行状态2更新为暂停状态3
|
||||
this.sysJobService.updateById(SysJob.builder()
|
||||
.jobId(querySysJob.getJobId())
|
||||
.jobStatus(PjcloudQuartzEnum.JOB_STATUS_NOT_RUNNING.getType())
|
||||
.build());
|
||||
taskUtil.pauseJob(querySysJob, scheduler);
|
||||
querySysJob.setJobStatus(PjcloudQuartzEnum.JOB_STATUS_NOT_RUNNING.getType());
|
||||
taskUtil.addOrUpateJob(querySysJob, scheduler);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
package com.bsd.pjcloud.daemon.quartz.controller;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.security.annotation.Inner;
|
||||
import com.bsd.pjcloud.daemon.quartz.api.dto.SysJobDTO;
|
||||
import com.bsd.pjcloud.daemon.quartz.constants.PjcloudQuartzEnum;
|
||||
import com.bsd.pjcloud.daemon.quartz.entity.SysJob;
|
||||
import com.bsd.pjcloud.daemon.quartz.service.SysJobService;
|
||||
import com.bsd.pjcloud.daemon.quartz.util.TaskUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.quartz.Scheduler;
|
||||
|
||||
/**
|
||||
* Quartz 内部远程接口
|
||||
*/
|
||||
@Inner
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/sys-job/inner")
|
||||
public class SysJobInnerController {
|
||||
|
||||
private final SysJobService sysJobService;
|
||||
|
||||
private final TaskUtil taskUtil;
|
||||
|
||||
private final Scheduler scheduler;
|
||||
|
||||
/**
|
||||
* 根据任务名称和分组查询任务
|
||||
*/
|
||||
@GetMapping("/by-name")
|
||||
public R<SysJobDTO> getByJobName(@RequestParam("jobName") String jobName, @RequestParam("jobGroup") String jobGroup) {
|
||||
SysJob sysJob = sysJobService.getOne(Wrappers.<SysJob>lambdaQuery()
|
||||
.eq(SysJob::getJobName, jobName)
|
||||
.eq(SysJob::getJobGroup, jobGroup), false);
|
||||
if (sysJob == null) {
|
||||
return R.ok();
|
||||
}
|
||||
return R.ok(toDto(sysJob));
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 cron 表达式
|
||||
*/
|
||||
@GetMapping("/validate-cron")
|
||||
public R<Boolean> validateCron(@RequestParam("cron") String cron) {
|
||||
return taskUtil.isValidCron(cron) ? R.ok(Boolean.TRUE) : R.failed(Boolean.FALSE, "cron表达式不合法");
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增定时任务
|
||||
*/
|
||||
@PostMapping
|
||||
public R<Boolean> save(@RequestBody SysJobDTO sysJobDto) {
|
||||
SysJob sysJob = toEntity(sysJobDto);
|
||||
if (!taskUtil.isValidCron(sysJob.getCronExpression())) {
|
||||
return R.failed("cron表达式不合法");
|
||||
}
|
||||
if (sysJobService.count(Wrappers.query(SysJob.builder()
|
||||
.jobName(sysJob.getJobName())
|
||||
.jobGroup(sysJob.getJobGroup())
|
||||
.build())) > 0) {
|
||||
return R.failed("任务重复,请检查此组内是否已包含同名任务");
|
||||
}
|
||||
if (StrUtil.isBlank(sysJob.getJobStatus())) {
|
||||
sysJob.setJobStatus(PjcloudQuartzEnum.JOB_STATUS_RUNNING.getType());
|
||||
}
|
||||
taskUtil.addOrUpateJob(sysJob, scheduler);
|
||||
return R.ok(sysJobService.save(sysJob));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改定时任务
|
||||
*/
|
||||
@PutMapping
|
||||
public R<Boolean> update(@RequestBody SysJobDTO sysJobDto) {
|
||||
if (sysJobDto.getJobId() == null) {
|
||||
return R.failed("任务ID不能为空");
|
||||
}
|
||||
SysJob querySysJob = sysJobService.getById(sysJobDto.getJobId());
|
||||
if (querySysJob == null) {
|
||||
return R.failed("任务不存在");
|
||||
}
|
||||
SysJob sysJob = toEntity(sysJobDto);
|
||||
if (!taskUtil.isValidCron(sysJob.getCronExpression())) {
|
||||
return R.failed("cron表达式不合法");
|
||||
}
|
||||
|
||||
sysJob.setJobStatus(querySysJob.getJobStatus());
|
||||
sysJob.setJobExecuteStatus(querySysJob.getJobExecuteStatus());
|
||||
|
||||
boolean jobKeyChanged = !StrUtil.equals(querySysJob.getJobName(), sysJob.getJobName())
|
||||
|| !StrUtil.equals(querySysJob.getJobGroup(), sysJob.getJobGroup());
|
||||
if (jobKeyChanged) {
|
||||
taskUtil.removeJob(querySysJob, scheduler);
|
||||
}
|
||||
|
||||
if (PjcloudQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysJob.getJobStatus())
|
||||
|| PjcloudQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(sysJob.getJobStatus())) {
|
||||
taskUtil.addOrUpateJob(sysJob, scheduler);
|
||||
} else {
|
||||
taskUtil.removeJob(sysJob, scheduler);
|
||||
}
|
||||
return R.ok(sysJobService.updateById(sysJob));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除定时任务
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public R<Boolean> removeById(@PathVariable("id") Long id) {
|
||||
SysJob querySysJob = sysJobService.getById(id);
|
||||
if (querySysJob == null) {
|
||||
return R.ok(Boolean.TRUE);
|
||||
}
|
||||
taskUtil.removeJob(querySysJob, scheduler);
|
||||
return R.ok(sysJobService.removeById(id));
|
||||
}
|
||||
|
||||
private SysJobDTO toDto(SysJob sysJob) {
|
||||
SysJobDTO dto = new SysJobDTO();
|
||||
BeanUtils.copyProperties(sysJob, dto);
|
||||
return dto;
|
||||
}
|
||||
|
||||
private SysJob toEntity(SysJobDTO dto) {
|
||||
SysJob sysJob = new SysJob();
|
||||
BeanUtils.copyProperties(dto, sysJob);
|
||||
return sysJob;
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -55,8 +55,9 @@ public class JavaClassTaskInvok implements ITaskInvok {
|
||||
method = clazz.getDeclaredMethod(sysJob.getMethodName());
|
||||
returnValue = method.invoke(obj);
|
||||
}
|
||||
if (StrUtil.isEmpty(returnValue.toString())
|
||||
|| PjcloudQuartzEnum.JOB_LOG_STATUS_FAIL.getType().equals(returnValue.toString())) {
|
||||
if (returnValue != null
|
||||
&& (StrUtil.isEmpty(returnValue.toString())
|
||||
|| PjcloudQuartzEnum.JOB_LOG_STATUS_FAIL.getType().equals(returnValue.toString()))) {
|
||||
log.error("定时任务javaClassTaskInvok异常,执行任务:{}", sysJob.getClassName());
|
||||
throw new TaskException("定时任务javaClassTaskInvok业务执行失败,任务:" + sysJob.getClassName());
|
||||
}
|
||||
|
||||
+3
-2
@@ -56,8 +56,9 @@ public class SpringBeanTaskInvok implements ITaskInvok {
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
returnValue = method.invoke(target);
|
||||
}
|
||||
if (StrUtil.isEmpty(returnValue.toString())
|
||||
|| PjcloudQuartzEnum.JOB_LOG_STATUS_FAIL.getType().equals(returnValue.toString())) {
|
||||
if (returnValue != null
|
||||
&& (StrUtil.isEmpty(returnValue.toString())
|
||||
|| PjcloudQuartzEnum.JOB_LOG_STATUS_FAIL.getType().equals(returnValue.toString()))) {
|
||||
log.error("定时任务springBeanTaskInvok异常,执行任务:{}", sysJob.getClassName());
|
||||
throw new TaskException("定时任务springBeanTaskInvok业务执行失败,任务:" + sysJob.getClassName());
|
||||
}
|
||||
|
||||
+11
-6
@@ -99,12 +99,17 @@ public class TaskInvokUtil {
|
||||
finally {
|
||||
// 记录执行时间 立刻执行使用的是simpleTeigger
|
||||
if (trigger instanceof CronTrigger) {
|
||||
updateSysjob
|
||||
.setStartTime(trigger.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
|
||||
updateSysjob.setPreviousTime(
|
||||
trigger.getPreviousFireTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
|
||||
updateSysjob.setNextTime(
|
||||
trigger.getNextFireTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
|
||||
if (trigger.getStartTime() != null) {
|
||||
updateSysjob.setStartTime(trigger.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
|
||||
}
|
||||
if (trigger.getPreviousFireTime() != null) {
|
||||
updateSysjob.setPreviousTime(
|
||||
trigger.getPreviousFireTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
|
||||
}
|
||||
if (trigger.getNextFireTime() != null) {
|
||||
updateSysjob.setNextTime(
|
||||
trigger.getNextFireTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
|
||||
}
|
||||
}
|
||||
// 记录执行时长
|
||||
endTime = System.currentTimeMillis();
|
||||
|
||||
+24
-1
@@ -59,10 +59,27 @@ public class TaskUtil {
|
||||
public void addOrUpateJob(SysJob sysjob, Scheduler scheduler) {
|
||||
CronTrigger trigger = null;
|
||||
try {
|
||||
if (!isValidCron(sysjob.getCronExpression())) {
|
||||
throw new IllegalArgumentException("cron表达式不合法");
|
||||
}
|
||||
JobKey jobKey = getJobKey(sysjob);
|
||||
// 获得触发器
|
||||
TriggerKey triggerKey = getTriggerKey(sysjob);
|
||||
boolean jobExists = scheduler.checkExists(jobKey);
|
||||
trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
// JDBC 持久化场景下,可能出现只残留 Job 或 Trigger 的脏数据,这里先做自愈。
|
||||
if (jobExists && trigger == null) {
|
||||
log.warn("检测到 Quartz 残留 Job,准备重建任务 jobId={}, jobName={}, jobGroup={}",
|
||||
sysjob.getJobId(), sysjob.getJobName(), sysjob.getJobGroup());
|
||||
scheduler.deleteJob(jobKey);
|
||||
jobExists = false;
|
||||
}
|
||||
if (!jobExists && trigger != null) {
|
||||
log.warn("检测到 Quartz 残留 Trigger,准备重建任务 jobId={}, jobName={}, jobGroup={}",
|
||||
sysjob.getJobId(), sysjob.getJobName(), sysjob.getJobGroup());
|
||||
scheduler.unscheduleJob(triggerKey);
|
||||
trigger = null;
|
||||
}
|
||||
// 判断触发器是否存在(如果存在说明之前运行过但是在当前被禁用了,如果不存在说明一次都没运行过)
|
||||
if (trigger == null) {
|
||||
// 新建一个工作任务 指定任务类型为串接进行的
|
||||
@@ -99,7 +116,10 @@ public class TaskUtil {
|
||||
}
|
||||
}
|
||||
catch (SchedulerException e) {
|
||||
log.error("添加或更新定时任务,失败信息:{}", e.getMessage());
|
||||
log.error("添加或更新定时任务失败 jobId={}, jobName={}, jobGroup={}, cron={}, jobType={}, className={}, methodName={}, methodParams={}",
|
||||
sysjob.getJobId(), sysjob.getJobName(), sysjob.getJobGroup(), sysjob.getCronExpression(),
|
||||
sysjob.getJobType(), sysjob.getClassName(), sysjob.getMethodName(), sysjob.getMethodParamsValue(), e);
|
||||
throw new IllegalStateException("添加或更新定时任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +155,7 @@ public class TaskUtil {
|
||||
}
|
||||
catch (SchedulerException e) {
|
||||
log.error("暂停任务失败,失败信息:{}", e.getMessage());
|
||||
throw new IllegalStateException("暂停任务失败", e);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -152,6 +173,7 @@ public class TaskUtil {
|
||||
}
|
||||
catch (SchedulerException e) {
|
||||
log.error("恢复任务失败,失败信息:{}", e.getMessage());
|
||||
throw new IllegalStateException("恢复任务失败", e);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -174,6 +196,7 @@ public class TaskUtil {
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("移除定时任务失败,失败信息:{}", e.getMessage());
|
||||
throw new IllegalStateException("移除定时任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
<module>pjcloud-report-platform</module>
|
||||
<module>pjcloud-codegen</module>
|
||||
<module>pjcloud-daemon-elastic-job</module>
|
||||
<module>pjcloud-daemon-quartz-api</module>
|
||||
<module>pjcloud-daemon-quartz</module>
|
||||
<module>pjcloud-jimu-platform</module>
|
||||
<module>pjcloud-pay-platform</module>
|
||||
|
||||
+4
@@ -63,4 +63,8 @@ public interface RemoteMchService {
|
||||
@NoToken
|
||||
@GetMapping("/mch-manage/get-views-mch-by-dept-id")
|
||||
R<MchManageVo> getViewsMchByDeptId(@RequestParam Long deptId, @RequestParam List<MerchantTypeEnum> mchTypeList);
|
||||
|
||||
@NoToken
|
||||
@GetMapping("/mch-manage/get-self-canteen-user-dept-id-list")
|
||||
R<List<Long>> getSelfCanteenUserDeptIdList(@RequestParam Long mchId);
|
||||
}
|
||||
+17
-10
@@ -163,12 +163,22 @@ public class MchManageController {
|
||||
if (ObjectUtil.isEmpty(mchManage)) return R.failed("商户不存在");
|
||||
return R.ok(mchManage);
|
||||
}
|
||||
|
||||
@Inner
|
||||
@GetMapping("/get-self-canteen-user-dept-id-list")
|
||||
public R<List<Long>> getSelfCanteenUserDeptIdList(@RequestParam Long mchId) {
|
||||
List<Long> userDeptIdList = mchManageService.getSelfCanteenUserDeptIdList(mchId);
|
||||
if (ObjectUtil.isEmpty(userDeptIdList)) return R.failed("商户不存在");
|
||||
return R.ok(userDeptIdList);
|
||||
}
|
||||
|
||||
/* ************************************* end 远程调用 end ************************************* */
|
||||
|
||||
/* ************************************* start app start ************************************* */
|
||||
@Operation(summary = "查询用户的直属商户", description = "查询用户的直属商户")
|
||||
@ApiCryptoAes
|
||||
@GetMapping("/app/getZsMch")
|
||||
|
||||
public R<MchManageVo> appZsMch() {
|
||||
PjcloudUser user = SecurityUtils.getUser();
|
||||
UserInfo userInfo = remoteUserService.getByUserId(user.getId()).getData();
|
||||
@@ -256,16 +266,13 @@ public class MchManageController {
|
||||
@GetMapping("/select")
|
||||
public R getSelect(@ParameterObject Page page, @ParameterObject MchManageDto dto) {
|
||||
DataScope dataScope = null;
|
||||
if (ObjectUtil.isNotEmpty(dto.getParentDeptId())) {
|
||||
List<SysDept> deptIdList = remoteDeptService.getDescendantList(dto.getParentDeptId()).getData();
|
||||
if (ObjectUtil.isNotEmpty(deptIdList)) {
|
||||
List<Long> deptIds = dto.getDeptIds();
|
||||
if (ObjectUtil.isEmpty(deptIds)) {
|
||||
deptIds = new ArrayList<>();
|
||||
}
|
||||
deptIds.addAll(deptIdList.stream().map(SysDept::getDeptId).toList());
|
||||
dto.setDeptIds(deptIds);
|
||||
}
|
||||
PjcloudUser user = SecurityUtils.getUser();
|
||||
List<Long> selfMchIdList = mchManageService.getSelfCanteenMchIdList(user.getId(), List.of(MerchantTypeEnum.CANTEEN));
|
||||
if (ObjectUtil.isNotEmpty(selfMchIdList)) {
|
||||
List<Long> ids = dto.getIds();
|
||||
if (ObjectUtil.isEmpty(ids)) ids = new ArrayList<>();
|
||||
ids.addAll(selfMchIdList);
|
||||
dto.setIds(ids);
|
||||
}
|
||||
return R.ok(mchManageService.scopePageList(page, dto, dataScope));
|
||||
}
|
||||
|
||||
+2
@@ -17,4 +17,6 @@ public interface MchDeptViewMapper {
|
||||
WalletMchDeptViewVo selectByDeptId(@Param("deptId") Long deptId, @Param("mchTypeList") List<String> mchTypeList);
|
||||
|
||||
List<Long> selectMchIdList(@Param("dto") WalletMchDeptViewDto dto);
|
||||
|
||||
List<Long> selectDeptIdList(@Param("dto") WalletMchDeptViewDto dto);
|
||||
}
|
||||
+6
-1
@@ -65,7 +65,12 @@ public interface MchManageService extends IService<MchManageEntity> {
|
||||
/**
|
||||
* 获取用户的食堂商户列表
|
||||
*/
|
||||
List<Long> getSelfCanteenMchIdList(Long userId,List<MerchantTypeEnum> mchTypeList);
|
||||
List<Long> getSelfCanteenMchIdList(Long userId, List<MerchantTypeEnum> mchTypeList);
|
||||
|
||||
/**
|
||||
* 获当前食堂商户列表对应的用户部门列表
|
||||
*/
|
||||
List<Long> getSelfCanteenUserDeptIdList(Long mchId);
|
||||
|
||||
/**
|
||||
* 判断用户是否能查看到所有食堂
|
||||
|
||||
+28
@@ -496,6 +496,34 @@ public class MchManageServiceImpl extends ServiceImpl<MchManageMapper, MchManage
|
||||
return selfMchIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户食堂商户列表对应的用户部门列表
|
||||
*/
|
||||
@Override
|
||||
public List<Long> getSelfCanteenUserDeptIdList(Long mchId) {
|
||||
List<Long> mchIds = new ArrayList<>();
|
||||
List<Long> deptIdList = new ArrayList<>();
|
||||
MchManageEntity mchDetail = baseMapper.selectById(mchId);
|
||||
if (ObjectUtil.isEmpty(mchDetail)) {
|
||||
return mchIds;
|
||||
}
|
||||
deptIdList.add(mchDetail.getDeptId());
|
||||
// 查询下级部门
|
||||
List<SysDept> descendantList = remoteDeptService.getInnerDescendantList(mchDetail.getDeptId()).getData();
|
||||
if (ObjectUtil.isNotEmpty(descendantList)) {
|
||||
List<Long> descendantIds = descendantList.stream().map(SysDept::getDeptId).toList();
|
||||
if (ObjectUtil.isNotEmpty(descendantIds)) deptIdList.addAll(descendantIds);
|
||||
}
|
||||
WalletMchDeptViewDto dto = new WalletMchDeptViewDto();
|
||||
dto.setDeptIdList(deptIdList);
|
||||
dto.setMchTypeList(List.of(mchDetail.getTypes()));
|
||||
List<Long> selfMchIdList = mchDeptViewMapper.selectDeptIdList(dto);
|
||||
if (ObjectUtil.isEmpty(selfMchIdList)) {
|
||||
return mchIds;
|
||||
}
|
||||
return selfMchIdList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否能查看到所有食堂
|
||||
*/
|
||||
|
||||
+10
@@ -91,4 +91,14 @@
|
||||
group by a.mchId
|
||||
order by a.mchId
|
||||
</select>
|
||||
|
||||
<select id="selectDeptIdList" resultType="java.lang.Long">
|
||||
select a.deptId
|
||||
from v_all_mch_dept_tree a
|
||||
<where>
|
||||
<include refid="whereA"/>
|
||||
</where>
|
||||
group by a.deptId
|
||||
order by a.deptId
|
||||
</select>
|
||||
</mapper>
|
||||
Reference in new issue
Block a user