瀏覽代碼

add(backend) [定时任务暂定模块 1.0]

wangxiao 4 年之前
父節點
當前提交
59f4aec4c9
共有 15 個文件被更改,包括 652 次插入78 次删除
  1. 9 0
      operation-backend/src/main/java/com/idiot/operationbackend/controller/group/CustomerMsgController.java
  2. 14 0
      operation-backend/src/main/java/com/idiot/operationbackend/controller/group/GroupMsgController.java
  3. 14 0
      operation-backend/src/main/java/com/idiot/operationbackend/controller/group/TemplateMsgController.java
  4. 14 0
      operation-backend/src/main/java/com/idiot/operationbackend/entity/CustomerMsg.java
  5. 15 15
      operation-backend/src/main/java/com/idiot/operationbackend/entity/GroupMsg.java
  6. 25 0
      operation-backend/src/main/java/com/idiot/operationbackend/entity/JobTask.java
  7. 68 0
      operation-backend/src/main/java/com/idiot/operationbackend/entity/TemplateMsg.java
  8. 25 6
      operation-backend/src/main/java/com/idiot/operationbackend/handler/JobScheduleHandler.java
  9. 20 1
      operation-backend/src/main/java/com/idiot/operationbackend/service/facade/WeChatService.java
  10. 402 44
      operation-backend/src/main/java/com/idiot/operationbackend/service/impl/WeChatServiceImpl.java
  11. 9 10
      operation-backend/src/main/java/com/idiot/operationbackend/support/Constants.java
  12. 29 0
      operation-backend/src/main/java/com/idiot/operationbackend/support/job/CustomerJobTask.java
  13. 1 1
      operation-backend/src/main/java/com/idiot/operationbackend/support/job/GroupJobTask.java
  14. 1 1
      operation-backend/src/main/java/com/idiot/operationbackend/support/job/TemplateJobTask.java
  15. 6 0
      sql/dataBase.sql

+ 9 - 0
operation-backend/src/main/java/com/idiot/operationbackend/controller/group/CustomerMsgController.java

@@ -3,6 +3,8 @@ package com.idiot.operationbackend.controller.group;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.idiot.operationbackend.entity.AccountCustomerMsg;
 import com.idiot.operationbackend.entity.CustomerMsg;
+import com.idiot.operationbackend.entity.JobTask;
+import com.idiot.operationbackend.handler.JobScheduleHandler;
 import com.idiot.operationbackend.service.facade.AccountCustomerMsgService;
 import com.idiot.operationbackend.service.facade.AuthUserService;
 import com.idiot.operationbackend.service.facade.CustomerMsgService;
@@ -45,6 +47,9 @@ public class CustomerMsgController {
     @Autowired
     private AccountCustomerMsgService accountCustomerMsgService;
 
+    @Autowired
+    private JobScheduleHandler jobScheduleHandler;
+
 
     @GetMapping
     @ApiOperation(value = "查询客服消息")
@@ -85,6 +90,7 @@ public class CustomerMsgController {
         customerMsg.setAuthId(authId);
         customerMsg.setCreateTime(LocalDateTime.now().format(Constants.DATE_TIME_FORMATTER));
         customerMsg.setStatus(Constants.WAITING);
+        String sendTime = customerMsg.getSendTime();
         boolean addResult =  customerMsgService.save(customerMsg);
         if (addResult) {
             String msgId = customerMsg.getId();
@@ -101,6 +107,9 @@ public class CustomerMsgController {
             }
             accountCustomerMsgService.saveBatch(accountCustomerMsgs);
         }
+        JobTask customerJob = new JobTask("客服消息定时推送任务",sendTime,customerMsg.getId(),Constants.CUSTOMER);
+        jobScheduleHandler.save(customerJob);
+        jobScheduleHandler.addAndRegisterJob(customerJob);
         return ResponseEntity.ok(JsonResult.success(addResult));
     }
 

+ 14 - 0
operation-backend/src/main/java/com/idiot/operationbackend/controller/group/GroupMsgController.java

@@ -3,8 +3,11 @@ package com.idiot.operationbackend.controller.group;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.idiot.operationbackend.entity.Account;
 import com.idiot.operationbackend.entity.GroupMsg;
+import com.idiot.operationbackend.entity.JobTask;
+import com.idiot.operationbackend.handler.JobScheduleHandler;
 import com.idiot.operationbackend.service.facade.AccountService;
 import com.idiot.operationbackend.service.facade.GroupMsgService;
+import com.idiot.operationbackend.support.Constants;
 import com.idiot.operationbackend.support.CustomException;
 import com.idiot.operationbackend.support.JsonResult;
 import com.idiot.operationbackend.util.JwtTokenUtil;
@@ -40,6 +43,9 @@ public class GroupMsgController {
     @Autowired
     private GroupMsgService groupMsgService;
 
+    @Autowired
+    private JobScheduleHandler jobScheduleHandler;
+
     @GetMapping
     @ApiOperation(value = "查询高级群发")
     public ResponseEntity<JsonResult<Page<GroupMsg>>> pageGroupMsg (@RequestHeader String token,
@@ -82,10 +88,18 @@ public class GroupMsgController {
         if (Objects.isNull(account)) {
             throw new CustomException(500,"选择的公众号不存在");
         }
+        String sendTime = groupMsg.getSendTime();
         groupMsg.setNikeName(account.getNickName());
         groupMsg.setHeadImage(account.getHeadImage());
+        groupMsg.setStatus(Constants.WAITING);
         logger.info("用户:{}高级群发groupMsg:{}",userId,groupMsg.toString());
         boolean delResult = groupMsgService.save(groupMsg);
+        JobTask job = new JobTask("高级群发消息定时推送任务",sendTime,groupMsg.getId(),Constants.GROUP);
+        job.setAccountId(accountId);
+        job.setNikeName(account.getNickName());
+        job.setHeadImage(account.getHeadImage());
+        jobScheduleHandler.save(job);
+        jobScheduleHandler.addAndRegisterJob(job);
         return ResponseEntity.ok(JsonResult.success(delResult));
     }
 

+ 14 - 0
operation-backend/src/main/java/com/idiot/operationbackend/controller/group/TemplateMsgController.java

@@ -4,10 +4,13 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.idiot.operationbackend.entity.Account;
+import com.idiot.operationbackend.entity.JobTask;
 import com.idiot.operationbackend.entity.TemplateMsg;
+import com.idiot.operationbackend.handler.JobScheduleHandler;
 import com.idiot.operationbackend.service.facade.AccountService;
 import com.idiot.operationbackend.service.facade.TemplateMsgService;
 import com.idiot.operationbackend.service.facade.WeChatService;
+import com.idiot.operationbackend.support.Constants;
 import com.idiot.operationbackend.support.CustomException;
 import com.idiot.operationbackend.support.JsonResult;
 import com.idiot.operationbackend.util.JwtTokenUtil;
@@ -47,6 +50,9 @@ public class TemplateMsgController {
     @Autowired
     private WeChatService weChatService;
 
+    @Autowired
+    private JobScheduleHandler jobScheduleHandler;
+
 
     @GetMapping
     @ApiOperation(value = "查询模板消息")
@@ -76,8 +82,16 @@ public class TemplateMsgController {
         if (Objects.isNull(account)) {
             throw new CustomException(500,"选择的公众号不存在");
         }
+        String sendTime = templateMsg.getSendTime();
         templateMsg.setHeadImage(account.getHeadImage());
         templateMsg.setNikeName(account.getNickName());
+        templateMsg.setStatus(Constants.WAITING);
+        JobTask job = new JobTask("模板消息定时推送任务",sendTime,templateMsg.getId(),Constants.TEMPLATE);
+        job.setAccountId(accountId);
+        job.setNikeName(account.getNickName());
+        job.setHeadImage(account.getHeadImage());
+        jobScheduleHandler.save(job);
+        jobScheduleHandler.addAndRegisterJob(job);
         logger.info("用户:{}查询公众号:{}模板消息,templateMsg:{}",userId,accountId,templateMsg.toString());
         return ResponseEntity.ok(JsonResult.success(false));
     }

+ 14 - 0
operation-backend/src/main/java/com/idiot/operationbackend/entity/CustomerMsg.java

@@ -29,6 +29,9 @@ public class CustomerMsg {
     @NotEmpty(message = "请填写客服消息发送时间")
     private String sendTime;
 
+    @NotEmpty(message = "请选择客服消息发送类型")
+    private Integer sendType;
+
     /**
      * 0 条件筛选 1 全部
      */
@@ -184,6 +187,14 @@ public class CustomerMsg {
         this.authId = authId;
     }
 
+    public Integer getSendType() {
+        return sendType;
+    }
+
+    public void setSendType(Integer sendType) {
+        this.sendType = sendType;
+    }
+
     @Override
     public String toString() {
         return "CustomerMsg{" +
@@ -192,6 +203,7 @@ public class CustomerMsg {
                 ", label='" + label + '\'' +
                 ", contents='" + contents + '\'' +
                 ", sendTime='" + sendTime + '\'' +
+                ", sendType=" + sendType +
                 ", type=" + type +
                 ", selectSex=" + selectSex +
                 ", selectSubscribeTime='" + selectSubscribeTime + '\'' +
@@ -200,7 +212,9 @@ public class CustomerMsg {
                 ", selectTag='" + selectTag + '\'' +
                 ", successNum=" + successNum +
                 ", preSuccessNum=" + preSuccessNum +
+                ", status=" + status +
                 ", createTime='" + createTime + '\'' +
+                ", authId='" + authId + '\'' +
                 '}';
     }
 }

+ 15 - 15
operation-backend/src/main/java/com/idiot/operationbackend/entity/GroupMsg.java

@@ -37,7 +37,7 @@ public class GroupMsg {
      * 0 条件筛选 1 全部
      */
     @NotNull(message = "请选择群发类型")
-    private Integer type;
+    private Boolean type;
 
     private Integer selectSex;
 
@@ -55,12 +55,12 @@ public class GroupMsg {
      * 微信后台设置
      */
 
-    private Integer power;
+    private Boolean power;
 
     /**
      * 转载是否继续发送
      */
-    private Boolean repeatSend;
+    private Integer repeatSend;
 
     private Integer status;
 
@@ -118,22 +118,14 @@ public class GroupMsg {
         this.msgType = msgType;
     }
 
-    public Integer getType() {
+    public Boolean getType() {
         return type;
     }
 
-    public void setType(Integer type) {
+    public void setType(Boolean type) {
         this.type = type;
     }
 
-    public Integer getPower() {
-        return power;
-    }
-
-    public void setPower(Integer power) {
-        this.power = power;
-    }
-
     public Integer getSelectSex() {
         return selectSex;
     }
@@ -190,11 +182,19 @@ public class GroupMsg {
         this.status = status;
     }
 
-    public Boolean getRepeatSend() {
+    public Boolean getPower() {
+        return power;
+    }
+
+    public void setPower(Boolean power) {
+        this.power = power;
+    }
+
+    public Integer getRepeatSend() {
         return repeatSend;
     }
 
-    public void setRepeatSend(Boolean repeatSend) {
+    public void setRepeatSend(Integer repeatSend) {
         this.repeatSend = repeatSend;
     }
 

+ 25 - 0
operation-backend/src/main/java/com/idiot/operationbackend/entity/JobTask.java

@@ -2,6 +2,9 @@ package com.idiot.operationbackend.entity;
 
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.idiot.operationbackend.support.Constants;
+
+import java.time.LocalDateTime;
 
 /**
  * 定时任务
@@ -123,6 +126,28 @@ public class JobTask {
     }
 
 
+    public JobTask() {
+    }
+
+    public JobTask(String accountId, String nikeName, String headImage, String taskLabel, Long taskTimer, String taskKey) {
+        this.accountId = accountId;
+        this.nikeName = nikeName;
+        this.headImage = headImage;
+        this.taskLabel = taskLabel;
+        this.taskTimer = taskTimer;
+        this.taskKey = taskKey;
+        this.createTime = LocalDateTime.now().format(Constants.DATE_TIME_FORMATTER);
+    }
+
+
+    public JobTask(String taskLabel, String sendTime, String taskKey,Integer type) {
+        this.taskLabel = taskLabel;
+        this.taskTimer = Constants.toEpochMilli(sendTime);
+        this.taskKey = taskKey;
+        this.type = type;
+        this.status =Constants.WAITING;
+    }
+
     @Override
     public String toString() {
         return "JobTask{" +

+ 68 - 0
operation-backend/src/main/java/com/idiot/operationbackend/entity/TemplateMsg.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 
 import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
 
 /**
  * 模板消息
@@ -48,6 +49,19 @@ public class TemplateMsg {
 
     private String headImage;
 
+    @NotNull(message = "请选择发送类型")
+    private Boolean type;
+
+    private Integer selectSex;
+
+    private String  selectSubscribeTime;
+
+    private String selectProvince;
+
+    private String selectCity;
+
+    private String selectTag;
+
 
     public String getId() {
         return id;
@@ -162,6 +176,54 @@ public class TemplateMsg {
     }
 
 
+    public Boolean getType() {
+        return type;
+    }
+
+    public void setType(Boolean type) {
+        this.type = type;
+    }
+
+    public Integer getSelectSex() {
+        return selectSex;
+    }
+
+    public void setSelectSex(Integer selectSex) {
+        this.selectSex = selectSex;
+    }
+
+    public String getSelectSubscribeTime() {
+        return selectSubscribeTime;
+    }
+
+    public void setSelectSubscribeTime(String selectSubscribeTime) {
+        this.selectSubscribeTime = selectSubscribeTime;
+    }
+
+    public String getSelectProvince() {
+        return selectProvince;
+    }
+
+    public void setSelectProvince(String selectProvince) {
+        this.selectProvince = selectProvince;
+    }
+
+    public String getSelectCity() {
+        return selectCity;
+    }
+
+    public void setSelectCity(String selectCity) {
+        this.selectCity = selectCity;
+    }
+
+    public String getSelectTag() {
+        return selectTag;
+    }
+
+    public void setSelectTag(String selectTag) {
+        this.selectTag = selectTag;
+    }
+
     @Override
     public String toString() {
         return "TemplateMsg{" +
@@ -179,6 +241,12 @@ public class TemplateMsg {
                 ", createTime='" + createTime + '\'' +
                 ", nikeName='" + nikeName + '\'' +
                 ", headImage='" + headImage + '\'' +
+                ", type=" + type +
+                ", selectSex=" + selectSex +
+                ", selectSubscribeTime='" + selectSubscribeTime + '\'' +
+                ", selectProvince='" + selectProvince + '\'' +
+                ", selectCity='" + selectCity + '\'' +
+                ", selectTag='" + selectTag + '\'' +
                 '}';
     }
 }

+ 25 - 6
operation-backend/src/main/java/com/idiot/operationbackend/handler/JobScheduleHandler.java

@@ -1,15 +1,17 @@
 package com.idiot.operationbackend.handler;
 
+import com.idiot.operationbackend.entity.CustomerMsg;
 import com.idiot.operationbackend.entity.GroupMsg;
 import com.idiot.operationbackend.entity.JobTask;
-import com.idiot.operationbackend.service.facade.GroupMsgService;
-import com.idiot.operationbackend.service.facade.JobTaskService;
-import com.idiot.operationbackend.service.facade.WeChatService;
+import com.idiot.operationbackend.entity.TemplateMsg;
+import com.idiot.operationbackend.service.facade.*;
 import com.idiot.operationbackend.support.Constants;
 
 
 import com.idiot.operationbackend.support.job.BaseJobTask;
+import com.idiot.operationbackend.support.job.CustomerJobTask;
 import com.idiot.operationbackend.support.job.GroupJobTask;
+import com.idiot.operationbackend.support.job.TemplateJobTask;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.InitializingBean;
@@ -63,6 +65,14 @@ public class JobScheduleHandler implements InitializingBean {
     private GroupMsgService groupMsgService;
 
 
+    @Autowired
+    private TemplateMsgService templateMsgService;
+
+
+    @Autowired
+    private CustomerMsgService customerMsgService;
+
+
     /**
      *  添加任务
      * @author wangxiao
@@ -126,7 +136,6 @@ public class JobScheduleHandler implements InitializingBean {
         registerTask(taskKey);
     }
 
-
    /**
     * 取消任务
     * @author wangxiao
@@ -191,10 +200,10 @@ public class JobScheduleHandler implements InitializingBean {
     }
 
     /**
-     *
+     * 获取任务
      * @author wangxiao
      * @date 16:29 2020/9/23
-     * @param taskKey
+     * @param taskKey 任务key
      * @return com.idiot.operationbackend.support.job.BaseScheduledTask
      */
     private BaseJobTask getTaskByKey (String taskKey) {
@@ -205,10 +214,20 @@ public class JobScheduleHandler implements InitializingBean {
         if (Constants.GROUP == jobTask.getType()) {
             GroupMsg groupMsg = groupMsgService.getById(taskKey);
             return new GroupJobTask(groupMsg,weChatService);
+        }else if (Constants.TEMPLATE == jobTask.getType()) {
+            TemplateMsg templateMsg = templateMsgService.getById(taskKey);
+            return new TemplateJobTask(templateMsg,weChatService);
+        }else if (Constants.CUSTOMER == jobTask.getType()) {
+            CustomerMsg customerMsg = customerMsgService.getById(taskKey);
+            return new CustomerJobTask(customerMsg,weChatService);
         }
         return null;
     }
 
+    public void save (JobTask jobTask) {
+        jobTaskService.saveOrUpdate(jobTask);
+    }
+
 
     @Override
     public void afterPropertiesSet() throws Exception {

+ 20 - 1
operation-backend/src/main/java/com/idiot/operationbackend/service/facade/WeChatService.java

@@ -359,7 +359,26 @@ public interface WeChatService {
     * @date 17:35 2020/9/23
     * @param groupMsg  groupMsg
     */
-   void groupMsgTask(GroupMsg groupMsg);
+   void doGroupMsgTask(GroupMsg groupMsg);
+
+
+   /**
+    *  模板消息 任务
+    * @author wangxiao
+    * @date 13:45 2020/9/24
+    * @param templateMsg templateMsg
+    */
+   void doTemplateMsgTask (TemplateMsg templateMsg);
+
+
+   /**
+    *  客服消息
+    * @author wangxiao
+    * @date 14:36 2020/9/24
+    * @param customerMsg customerMsg
+    */
+   void doCustomerMsgTask (CustomerMsg customerMsg);
+
 
   /**
    * 不支持的消息

+ 402 - 44
operation-backend/src/main/java/com/idiot/operationbackend/service/impl/WeChatServiceImpl.java

@@ -8,10 +8,7 @@ import com.google.common.cache.*;
 import com.idiot.operationbackend.config.PlatformProperties;
 import com.idiot.operationbackend.entity.*;
 import com.idiot.operationbackend.handler.FansInfoHandler;
-import com.idiot.operationbackend.service.facade.AccountFansService;
-import com.idiot.operationbackend.service.facade.AccountService;
-import com.idiot.operationbackend.service.facade.AccountTagService;
-import com.idiot.operationbackend.service.facade.WeChatService;
+import com.idiot.operationbackend.service.facade.*;
 import com.idiot.operationbackend.support.Constants;
 import com.idiot.operationbackend.support.CustomException;
 import com.idiot.operationbackend.support.WxInputStreamResource;
@@ -33,6 +30,7 @@ import javax.annotation.Resource;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 
 /**
@@ -70,6 +68,13 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
 
     private FansInfoHandler fansInfoHandler;
 
+    private GroupMsgService groupMsgService;
+
+    private TemplateMsgService templateMsgService;
+
+    private CustomerMsgService customerMsgService;
+
+    private AccountCustomerMsgService accountCustomerMsgService;
 
     @Override
     public String notice(Map<String, String> param) {
@@ -271,7 +276,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
             throw new CustomException(500,"当前公众号正在后台同步粉丝数据,请您稍等一会!");
         }
         cache.put(lockKey,lockKey);
-        logger.info("公众号:{}同步粉丝数据---- start,时间:{}",accountId, LocalDateTime.now().toString());
+        logger.info("公众号:{}同步粉丝数据---- start,时间:{}",accountId, LocalDateTime.now());
         String requestUrl = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s&next_openid=%s";
         String nextOpenId = "";
         String accessToken = getAuthorizerAccessToken(accountId);
@@ -298,7 +303,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
             fansInfoHandler.doSyncUserTask(accountId,openIds);
         }while (count < total);
         cache.invalidate(lockKey);
-        logger.info("公众号:{}同步粉丝数据----end,时间:{}",accountId, LocalDateTime.now().toString());
+        logger.info("公众号:{}同步粉丝数据----end,时间:{}",accountId, LocalDateTime.now());
         return count;
     }
 
@@ -311,7 +316,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
             return;
         }
         int size = openIds.size();
-        logger.info("公众号:{}同步粉丝请求粉丝信息,openId 大小:{}---- start,时间:{}",accountId,size,LocalDateTime.now().toString());
+        logger.info("公众号:{}同步粉丝请求粉丝信息,openId 大小:{}---- start,时间:{}",accountId,size,LocalDateTime.now());
         List<AccountFans> accountFans =  new ArrayList<>(size);
 
         for (String openId : openIds) {
@@ -337,7 +342,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
             fans.setTags(fans.initTags());
             accountFans.add(fans);
         }
-        logger.info("公众号:{}同步粉丝请求粉丝信息,openId 大小:{}---- end,时间:{}",accountId,size,LocalDateTime.now().toString());
+        logger.info("公众号:{}同步粉丝请求粉丝信息,openId 大小:{}---- end,时间:{}",accountId,size,LocalDateTime.now());
         //  保存用户
         fansService.saveOrUpdateBatch(accountFans,1000);
     }
@@ -353,7 +358,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
             throw new CustomException(500,"");
         }
         cache.put(lockKey,lockKey);
-        logger.info("公众号:{}同步标签 ---- start,时间:{}",accountId,LocalDateTime.now().toString());
+        logger.info("公众号:{}同步标签 ---- start,时间:{}",accountId,LocalDateTime.now());
         String requestUrl = "https://api.weixin.qq.com/cgi-bin/tags/get?access_token=%s";
         String accessToken =  getAuthorizerAccessToken(accountId);
         HttpHeaders headers = new HttpHeaders();
@@ -377,7 +382,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
             tempTag.setCreateTime(createTime);
             accountTags.add(tempTag);
         }
-        logger.info("公众号:{}同步标签 ---- end,时间:{}",accountId,LocalDateTime.now().toString());
+        logger.info("公众号:{}同步标签 ---- end,时间:{}",accountId,LocalDateTime.now());
         // 新增 多余的 删掉缺少的 俗称覆盖
         boolean ifOverlay = tagService.overlayAccountTag(accountId,accountTags);
         cache.invalidate(lockKey);
@@ -386,7 +391,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
 
     @Override
     public String getFansInfo(String accountId, String openId) {
-        logger.info("查询粉丝信息,openId:{}----start,时间:{}",accountId, LocalDateTime.now().toString());
+        logger.info("查询粉丝信息,openId:{}----start,时间:{}",accountId, LocalDateTime.now());
         String requestUrl = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=OPENID&lang=zh_CN";
         String accessToken =  getAuthorizerAccessToken(accountId);
         requestUrl = String.format(requestUrl,accessToken);
@@ -395,7 +400,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         HttpEntity<MultiValueMap<String, String>>  entity = new HttpEntity<> (headers);
         ResponseEntity<String> respStr = restTemplate.exchange(requestUrl,HttpMethod.GET,entity,String.class);
         String jsonStr = respStr.getBody();
-        logger.info("查询粉丝信息,openId:{}----end,时间:{},微信返回:{}",accountId, LocalDateTime.now().toString(),jsonStr);
+        logger.info("查询粉丝信息,openId:{}----end,时间:{},微信返回:{}",accountId, LocalDateTime.now(),jsonStr);
         return jsonStr;
     }
 
@@ -410,7 +415,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         String requestUrl = "https://api.weixin.qq.com/datacube/getusersummary?access_token=%s";
         String accessToken = getAuthorizerAccessToken(accountId);
         requestUrl = String.format(requestUrl,accessToken);
-        logger.info("获取微信用户增减数据,accountId:{}----start,时间:{}",accountId, LocalDateTime.now().toString());
+        logger.info("获取微信用户增减数据,accountId:{}----start,时间:{}",accountId, LocalDateTime.now());
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_JSON);
         MultiValueMap<String,String> params = new LinkedMultiValueMap<>(2);
@@ -420,7 +425,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         ResponseEntity<String> respStr = restTemplate.exchange(requestUrl,HttpMethod.POST,entity,String.class);
         String jsonStr = respStr.getBody();
         logger.info("获取微信用户增减数据,accountId:{}----end,时间:{},微信返回{}",accountId,
-                LocalDateTime.now().toString(),jsonStr);
+                LocalDateTime.now(),jsonStr);
         return jsonStr;
     }
 
@@ -430,7 +435,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         String requestUrl = "https://api.weixin.qq.com/datacube/getusercumulate?access_token=%s";
         String accessToken = getAuthorizerAccessToken(accountId);
         requestUrl = String.format(requestUrl,accessToken);
-        logger.info("获取微信用户汇总数据,accountId:{}----start,时间:{}",accountId, LocalDateTime.now().toString());
+        logger.info("获取微信用户汇总数据,accountId:{}----start,时间:{}",accountId, LocalDateTime.now());
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_JSON);
         MultiValueMap<String,String> params = new LinkedMultiValueMap<>(2);
@@ -440,7 +445,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         ResponseEntity<String> respStr = restTemplate.exchange(requestUrl,HttpMethod.POST,entity,String.class);
         String jsonStr = respStr.getBody();
         logger.info("获取微信用户汇总数据,accountId:{}----end,时间:{},微信返回{}",accountId,
-                LocalDateTime.now().toString(),jsonStr);
+                LocalDateTime.now(),jsonStr);
         return null;
     }
 
@@ -451,7 +456,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         requestUrl = String.format(requestUrl,accessToken);
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_JSON);
-        logger.info("获取微信图文阅读数据,accountId:{}----start,时间:{}",accountId, LocalDateTime.now().toString());
+        logger.info("获取微信图文阅读数据,accountId:{}----start,时间:{}",accountId, LocalDateTime.now());
         MultiValueMap<String,String> params = new LinkedMultiValueMap<>(2);
         params.add("begin_date",startDate);
         params.add("end_date",endDate);
@@ -459,7 +464,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         ResponseEntity<String> respStr = restTemplate.exchange(requestUrl,HttpMethod.POST,entity,String.class);
         String jsonStr = respStr.getBody();
         logger.info("获取微信图文阅读数据,accountId:{}----end,时间:{},微信返回{}",accountId,
-                LocalDateTime.now().toString(),jsonStr);
+                LocalDateTime.now(),jsonStr);
         return jsonStr;
     }
 
@@ -470,14 +475,14 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         requestUrl = String.format(requestUrl,accessToken);
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_JSON);
-        logger.info("微信设置备注,accountId:{}----start,时间:{}",accountId, LocalDateTime.now().toString());
+        logger.info("微信设置备注,accountId:{}----start,时间:{}",accountId, LocalDateTime.now());
         MultiValueMap<String,String> params = new LinkedMultiValueMap<>(2);
         params.add("openid",openId);
         params.add("remark",remark);
         HttpEntity<MultiValueMap<String, String>>  entity = new HttpEntity<> (params,headers);
         ResponseEntity<String> respStr = restTemplate.exchange(requestUrl,HttpMethod.POST,entity,String.class);
         String jsonStr = respStr.getBody();
-        logger.info("微信设置备注,accountId:{}----end,时间:{},微信返回{}",accountId,LocalDateTime.now().toString(),jsonStr);
+        logger.info("微信设置备注,accountId:{}----end,时间:{},微信返回{}",accountId,LocalDateTime.now(),jsonStr);
         if (0 ==JSONObject.parseObject(jsonStr).getIntValue(ERROR_CODE)) {
             return fansService.updateFansRemark(accountId,openId,remark);
         }
@@ -497,10 +502,11 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         map.put("name",tagLabel);
         params.add("tag",map);
         HttpEntity<MultiValueMap<String, Object>>  entity = new HttpEntity<> (params,headers);
-        logger.info("微信创建标签,accountId:{}----start,时间:{}",accountId, LocalDateTime.now().toString());
+        logger.info("微信创建标签,accountId:{}----start,时间:{}",accountId, LocalDateTime.now());
         ResponseEntity<String> respStr = restTemplate.exchange(requestUrl,HttpMethod.POST,entity,String.class);
         String jsonStr = respStr.getBody();
-        logger.info("微信创建标签,accountId:{}----end,时间:{},微信返回{}",accountId,LocalDateTime.now().toString(),jsonStr);
+        logger.info("微信创建标签,accountId:{}----end,时间:{},微信返回{}",accountId,
+                LocalDateTime.now(),jsonStr);
         JSONObject temp = JSONObject.parseObject(jsonStr).getJSONObject("tag");
         if (null != temp) {
             Integer wxId = temp.getInteger("id");
@@ -523,10 +529,11 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         params.add("tagid",wxId);
         int size = openIds.size();
         HttpEntity<MultiValueMap<String, Object>>  entity = new HttpEntity<> (params,headers);
-        logger.info("微信用户打标签,accountId:{},opedId size:{}----start,时间:{}",accountId,size, LocalDateTime.now().toString());
+        logger.info("微信用户打标签,accountId:{},opedId size:{}----start,时间:{}",accountId,size, LocalDateTime.now());
         ResponseEntity<String> respStr = restTemplate.exchange(requestUrl,HttpMethod.POST,entity,String.class);
         String jsonStr = respStr.getBody();
-        logger.info("微信用户打标签,accountId:{},opedId size:{}----end,时间:{},微信返回:{}",accountId,size, LocalDateTime.now().toString(),jsonStr);
+        logger.info("微信用户打标签,accountId:{},opedId size:{}----end,时间:{},微信返回:{}",accountId,size,
+                LocalDateTime.now(),jsonStr);
         if (0 ==JSONObject.parseObject(jsonStr).getIntValue(ERROR_CODE)) {
             return tagService.addTagSize(accountId,wxId,size);
         }
@@ -546,10 +553,11 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         params.add("tagid",wxId);
         int size = openIds.size();
         HttpEntity<MultiValueMap<String, Object>>  entity = new HttpEntity<> (params,headers);
-        logger.info("微信用户去除标签,accountId:{},opedId size:{}----start,时间:{}",accountId,size, LocalDateTime.now().toString());
+        logger.info("微信用户去除标签,accountId:{},opedId size:{}----start,时间:{}",accountId,size, LocalDateTime.now());
         ResponseEntity<String> respStr = restTemplate.exchange(requestUrl,HttpMethod.POST,entity,String.class);
         String jsonStr = respStr.getBody();
-        logger.info("微信用去除标签,accountId:{},opedId size:{}----end,时间:{},微信返回:{}",accountId,size, LocalDateTime.now().toString(),jsonStr);
+        logger.info("微信用去除标签,accountId:{},opedId size:{}----end,时间:{},微信返回:{}",accountId,size,
+                LocalDateTime.now(),jsonStr);
         if (0 ==JSONObject.parseObject(jsonStr).getIntValue(ERROR_CODE)) {
             return tagService.subTagSize(accountId,wxId,size);
         }
@@ -571,10 +579,10 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         map.put("id",wxId);
         params.add("tag",map);
         HttpEntity<MultiValueMap<String, Object>>  entity = new HttpEntity<> (params,headers);
-        logger.info("微信创建标签,accountId:{}----start,时间:{}",accountId, LocalDateTime.now().toString());
+        logger.info("微信创建标签,accountId:{}----start,时间:{}",accountId, LocalDateTime.now());
         ResponseEntity<String> respStr = restTemplate.exchange(requestUrl,HttpMethod.POST,entity,String.class);
         String jsonStr = respStr.getBody();
-        logger.info("微信创建标签,accountId:{}----end,时间:{},微信返回{}",accountId,LocalDateTime.now().toString(),jsonStr);
+        logger.info("微信创建标签,accountId:{}----end,时间:{},微信返回{}",accountId,LocalDateTime.now(),jsonStr);
         int errorCode = JSONObject.parseObject(jsonStr).getIntValue(ERROR_CODE);
         return 0 == errorCode;
     }
@@ -596,10 +604,10 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
             data.add("description", p.toString());
         }
         HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(data,httpHeaders);
-        logger.info("微信上传素材,accountId:{},type:{}----start,时间:{}",accountId,type, LocalDateTime.now().toString());
+        logger.info("微信上传素材,accountId:{},type:{}----start,时间:{}",accountId,type, LocalDateTime.now());
         String resultJson = restTemplate.postForObject(requestUrl, requestEntity, String.class);
         logger.info("微信上传素材,accountId:{},type:{}----end,时间:{},微信返回结果:{}",accountId,type,
-                LocalDateTime.now().toString(),resultJson);
+                LocalDateTime.now(),resultJson);
         return resultJson;
     }
 
@@ -623,10 +631,10 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         httpHeaders.setContentType(MediaType.APPLICATION_JSON);
         HttpEntity<MultiValueMap<String,Object>> httpEntity = new HttpEntity<>(valueMap,httpHeaders);
         logger.info("微信上传图文素材,accountId:{},articles:{}----start,时间:{}",accountId,articles.toString(),
-                LocalDateTime.now().toString());
+                LocalDateTime.now());
         String respJson = restTemplate.postForObject(requestUrl,httpEntity,String.class);
         logger.info("微信上传图文素材,accountId:{},articles:{}----end,时间:{},微信返回:{}",accountId,articles.toString(),
-                LocalDateTime.now().toString(),respJson);
+                LocalDateTime.now(),respJson);
         return respJson;
     }
 
@@ -648,11 +656,11 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         headers.setContentType(MediaType.APPLICATION_JSON);
         HttpEntity<String> request = new HttpEntity<String>(parentNode.toJSONString(), headers);
         logger.info("微信上生成二维码,accountId:{},QrCode:{}----start,时间:{}",accountId,qrCode.toString(),
-                LocalDateTime.now().toString());
+                LocalDateTime.now());
         ResponseEntity<String> responseEntity = restTemplate.postForEntity(requestUrl,request,String.class);
         String jsonStr = responseEntity.getBody();
         logger.info("微信上生成二维码,accountId:{},QrCode:{}----end,时间:{},微信返回:{}",accountId,qrCode.toString(),
-                LocalDateTime.now().toString(),jsonStr);
+                LocalDateTime.now(),jsonStr);
         return jsonStr;
     }
 
@@ -669,11 +677,10 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         HttpHeaders  headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_JSON);
         HttpEntity<String> request = new HttpEntity<String>(param, headers);
-        logger.info("微信创建公众号菜单,accountId:{},accountMenus:{}----start,时间:{}",accountId,param,
-                LocalDateTime.now().toString());
+        logger.info("微信创建公众号菜单,accountId:{},accountMenus:{}----start,时间:{}",accountId,param, LocalDateTime.now());
         String jsonStr = restTemplate.postForObject(requestUrl,request,String.class);
         logger.info("微信创建公众号菜单,accountId:{},accountMenus:{}----end,时间:{},微信返回:{}",accountId,param,
-                LocalDateTime.now().toString(),jsonStr);
+                LocalDateTime.now(),jsonStr);
         int errcode = JSONObject.parseObject(jsonStr).getIntValue(ERROR_CODE);
         return 0 == errcode;
     }
@@ -684,9 +691,9 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         String url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=%s";
         String accessToken = getAuthorizerAccessToken(accountId);
         url = String.format(url,accessToken);
-        logger.info("微信删除公众号菜单,accountId:{}----start,时间:{}",accountId,LocalDateTime.now().toString());
+        logger.info("微信删除公众号菜单,accountId:{}----start,时间:{}",accountId,LocalDateTime.now());
         String jsonStr = restTemplate.getForObject(url,String.class);
-        logger.info("微信创建公众号菜单,accountId:{}----end,时间:{},微信返回:{}",accountId,LocalDateTime.now().toString(),jsonStr);
+        logger.info("微信创建公众号菜单,accountId:{}----end,时间:{},微信返回:{}",accountId,LocalDateTime.now(),jsonStr);
         int errcode = JSONObject.parseObject(jsonStr).getIntValue(ERROR_CODE);
         return 0 == errcode;
     }
@@ -697,35 +704,238 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         String requestUrl = " https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=%s";
         String accessToken = getAuthorizerAccessToken(accountId);
         requestUrl = String.format(requestUrl,accessToken);
-        logger.info("微信请求公众号模板消息列表,accountId:{}----start,时间:{}",accountId,LocalDateTime.now().toString());
+        logger.info("微信请求公众号模板消息列表,accountId:{}----start,时间:{}",accountId,LocalDateTime.now());
         String jsonStr = restTemplate.getForObject(requestUrl,String.class);
-        logger.info("微信请求公众号模板消息列表,accountId:{}----end,时间:{},微信返回:{}",accountId,LocalDateTime.now().toString(),jsonStr);
+        logger.info("微信请求公众号模板消息列表,accountId:{}----end,时间:{},微信返回:{}",accountId,LocalDateTime.now(),jsonStr);
         return jsonStr;
     }
 
 
     @Override
-    public void groupMsgTask(GroupMsg groupMsg) {
+    public void doGroupMsgTask(GroupMsg groupMsg) {
+
         if (Objects.isNull(groupMsg)) {
             return ;
         }
+        logger.info("微信公众号群发消息任务,groupMsg:{}----start,时间:{}",groupMsg.toString(),LocalDateTime.now());
+        List<String> openIds = null;
         String accountId = groupMsg.getAccountId();
         Integer sex = null;
         String province = null;
         String city = null;
         String tag = null;
         String subscribeTime = null;
-        if (Constants.SELECT == groupMsg.getType()) {
+        if (!groupMsg.getType()) {
             sex = groupMsg.getSelectSex();
             province = groupMsg.getSelectProvince();
             city = groupMsg.getSelectCity();
             tag = groupMsg.getSelectTag();
             subscribeTime = groupMsg.getSelectSubscribeTime();
+            List<AccountFans> fans = fansService.queryAccountFans(accountId,sex,province,city,tag,subscribeTime);
+            openIds = fans.stream().map(AccountFans::getOpenId).collect(Collectors.toList());
+        }
+        long count = sendGroupMessage(accountId,groupMsg.getContents(),groupMsg.getType(),groupMsg.getRepeatSend(),openIds);
+        groupMsg.setStatus(count>0?Constants.SUCCESSED:Constants.FAILED);
+        groupMsg.setSendNum(count);
+        groupMsgService.updateById(groupMsg);
+        logger.info("微信公众号群发消息任务,groupMsg:{}----end,时间:{}",groupMsg.toString(),LocalDateTime.now());
+    }
+
+
+    @Override
+    public void doTemplateMsgTask(TemplateMsg templateMsg) {
+        if (Objects.isNull(templateMsg)) {
+            return;
         }
+        logger.info("微信公众号模板消息任务,templateMsg:{}----start,时间:{}",templateMsg.toString(),LocalDateTime.now());
+        String accountId = templateMsg.getAccountId();
+        Integer sex = templateMsg.getSelectSex();
+        String province = templateMsg.getSelectProvince();
+        String city = templateMsg.getSelectCity();
+        String tag = templateMsg.getSelectTag();
+        String subscribeTime = templateMsg.getSelectSubscribeTime();
         List<AccountFans> fans = fansService.queryAccountFans(accountId,sex,province,city,tag,subscribeTime);
+        long count = sendTemplateMessage(accountId,fans,templateMsg);
+        templateMsg.setStatus(count>0?Constants.SUCCESSED:Constants.FAILED);
+        templateMsg.setSendNum(count);
+        templateMsgService.updateById(templateMsg);
+        logger.info("微信公众号模板消息任务,templateMsg:{}----end,时间:{}",templateMsg.toString(),LocalDateTime.now());
+    }
+
+
+    @Override
+    public void doCustomerMsgTask(CustomerMsg customerMsg) {
+        if (Objects.isNull(customerMsg)) {
+            return;
+        }
+        logger.info("微信公众号客服消息任务,customerMsg:{}----start,时间:{}",customerMsg.toString(),LocalDateTime.now());
+        String contents = customerMsg.getContents();
+        Integer sex = customerMsg.getSelectSex();
+        String province = customerMsg.getSelectProvince();
+        String city = customerMsg.getSelectCity();
+        String tag = customerMsg.getSelectTag();
+        String subscribeTime = customerMsg.getSelectSubscribeTime();
+        String msgId = customerMsg.getId();
+        List<AccountCustomerMsg> accountCustomerMsgs = accountCustomerMsgService.queryByMsgId(msgId);
+        if (CollectionUtils.isEmpty(accountCustomerMsgs)){
+            return;
+        }
+        String accountId = null;
+        long count = 0;
+        String requestUrl = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s";
+        for (AccountCustomerMsg accountCustomerMsg : accountCustomerMsgs) {
+            accountId = accountCustomerMsg.getAccountId();
+            List<AccountFans> fans = fansService.queryAccountFans(accountId,sex,province,city,tag,subscribeTime);
+            long temp = sendCustomerMessage(accountId,fans,contents,requestUrl);
+            accountCustomerMsg.setSuccessNum(temp);
+            accountCustomerMsg.setStatus(temp>0?Constants.SUCCESSED:Constants.FAILED);
+            count += temp;
+        }
+        customerMsg.setStatus(count>0?Constants.SUCCESSED:Constants.FAILED);
+        customerMsg.setSuccessNum(count);
+        accountCustomerMsgService.updateBatchById(accountCustomerMsgs);
+        customerMsgService.updateById(customerMsg);
+        logger.info("微信公众号客服消息任务,customerMsg:{}----end,时间:{}",customerMsg.toString(),LocalDateTime.now());
+    }
+
+
+
+    /**
+     *  群发消息
+     * @author wangxiao
+     * @date 13:58 2020/9/24
+     * @param accountId 公众号id
+     * @param contents 群发内容json
+     * @param toAll 是否全部
+     * @param repeatSend 转载继续
+     * @param openIds 发送用户群体
+     * @return java.lang.Boolean
+     */
+    private long  sendGroupMessage(String accountId, String contents, boolean toAll, int repeatSend, List<String> openIds) {
+        logger.info("公众号:{}群发消息:{},toAll:{},repeatSend:{},openIds:{}",accountId,contents,toAll,repeatSend,openIds);
+        String requestUrl =  "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=%s";
+        String accessToken = getAuthorizerAccessToken(accountId);
+        requestUrl = String.format(requestUrl,accessToken);
+        JSONArray jsonArray = JSONArray.parseArray(contents);
+        int size = jsonArray.size();
+        if (size == 0) {
+            return 0;
+        }
+        int  groupCount =0;
+        JSONObject temp = null;
+        for (int i = 0; i < size; i++) {
+            temp = jsonArray.getJSONObject(i);
+            logger.info("微信群发消息,accountId:{},openIds:{}----start,时间:{}",accountId,openIds,LocalDateTime.now());
+            String param = parseToJson(temp,openIds,repeatSend,toAll);
+            HttpHeaders  headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            HttpEntity<String> request = new HttpEntity<>(param, headers);
+            String jsonStr = restTemplate.postForObject(requestUrl,request,String.class);
+            logger.info("微信群发消息,accountId:{},openIds:{}----end,时间:{},微信返回:{}",accountId,openIds,LocalDateTime.now(),jsonStr);
+            int errcode = JSONObject.parseObject(jsonStr).getIntValue(ERROR_CODE);
+             if (0 == errcode) {
+                 groupCount+=1;
+             };
+            logger.info("公众号:{}群发消息第{}条,发送结果:{}",accountId,i,0 == errcode);
+        }
+        return groupCount;
+    }
+
+
+    /**
+     *  发送模板消息
+     * @author wangxiao
+     * @date 14:05 2020/9/24
+     * @param fansList 用户集群
+     * @param templateMsg 模板消息内容
+     * @return boolean 是否成功
+     */
+    private long sendTemplateMessage (String accountId,List<AccountFans> fansList,TemplateMsg templateMsg) {
+        logger.info("公众号:{}发送模板消息:,AccountFans size :{},templateMsg:{}",accountId, fansList.size(),templateMsg.toString());
+        String requestUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s";
+        String accessToken = getAuthorizerAccessToken(accountId);
+        requestUrl = String.format(requestUrl,accessToken);
+        String templateData = templateMsg.getTemplateData();
+        int templateCount = 0;
+        for (AccountFans fans : fansList) {
+            templateData = templateData.replace("<粉丝昵称>",fans.getNickName());
+            String json = parseJson(fans.getOpenId(),templateData,templateMsg.getTemplateId(),
+                    templateMsg.getLinkUrl(),templateMsg.getLinkAppId());
+            logger.info("微信模板消息消息,accountId:{},openId:{}----start,时间:{}",accountId,
+                    fans.getOpenId(),LocalDateTime.now());
+            HttpHeaders  headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            HttpEntity<String> request = new HttpEntity<>(json, headers);
+            String jsonStr = restTemplate.postForObject(requestUrl,request,String.class);
+            logger.info("微信模板消息消息,accountId:{},openId:{}----end,时间:{},微信返回:{}",accountId,
+                    fans.getOpenId(),LocalDateTime.now(),jsonStr);
+            int errcode = JSONObject.parseObject(jsonStr).getIntValue(ERROR_CODE);
+            if (0 == errcode) {
+                templateCount+=1;
+            };
+        }
+        return templateCount;
+    }
+
+
+    public long sendCustomerMessage (String accountId,List<AccountFans> fansList,String contents,String url) {
+        int result = 0;
+        if (CollectionUtils.isEmpty(fansList)) {
+            return 0;
+        }
+        int count = 0;
+        String nikeName = null;
+        String openId = null;
+        for (AccountFans fans : fansList) {
+            openId = fans.getOpenId();
+            nikeName =fans.getNickName();
+            logger.info("微信客服消息,粉丝逐条发送,accountId:{},openId:{},nikeName:{}",accountId,openId,nikeName);
+            sendCustomerMessage(openId,contents,nikeName,accountId,url);
+            count +=1;
+        }
+        return count;
 
     }
 
+    /**
+     *  单人 发送客服消息消息
+     * @author wangxiao
+     * @date 15:20 2020/9/24
+     * @param openId
+     * @param nikeName
+     * @param contents
+     * @param url
+     * @return void
+     */
+    private void sendCustomerMessage(String openId,String contents,String nikeName,String accountId,String url) {
+        contents = contents.replace("<粉丝昵称>",nikeName);
+        JSONArray jsonArray = JSONArray.parseArray(contents);
+        int size = jsonArray.size();
+        if (size == 0) {
+            return;
+        }
+        String accessToken = getAuthorizerAccessToken(accountId);
+        url = String.format(url,accessToken);
+        JSONObject temp  = null;
+        for (int i = 0; i < size; i++) {
+            temp = jsonArray.getJSONObject(i);
+            String param = parseJson(openId,temp);
+            logger.info("微信客服消息,单人第{}条发送,accountId:{},openId:{}----start,时间:{}",i,accountId,openId,LocalDateTime.now());
+            HttpHeaders  headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            HttpEntity<String> request = new HttpEntity<>(param, headers);
+            String jsonStr = restTemplate.postForObject(url,request,String.class);
+            logger.info("微信客服消息,单人第{}条发送,accountId:{},openId:{}----end,时间:{},微信返回:{}",i,accountId,openId,LocalDateTime.now(),jsonStr);
+        }
+    }
+
+    /**
+     *  菜单转换 微信json格式
+     * @author wangxiao
+     * @date 10:59 2020/9/24
+     * @param accountMenus accountMenus
+     * @return java.lang.String
+     */
     private String parseToJson (List<AccountMenu> accountMenus) {
         int size  = accountMenus.size();
         JSONObject jsonObject = new JSONObject(1);
@@ -755,7 +965,135 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
             button.add(temp);
         }
         jsonObject.put("button",button);
-        return jsonObject.toJSONString();
+        String result = jsonObject.toJSONString();
+        logger.info("自定义菜单 转换json 格式结果:{}",result);
+        return result;
+    }
+
+    /**
+     *  转换群发消息得json
+     * @author wangxiao
+     * @date 11:53 2020/9/24
+     * @param jsonObject jsonObject
+     * @param openIds openIds
+     * @param repeatSend 转载是否继续
+     * @param toAll 全部
+     * @return java.lang.String
+     */
+    public String parseToJson(JSONObject jsonObject,List<String> openIds,int repeatSend,boolean toAll ) {
+        int type = jsonObject.getIntValue("type");
+        JSONObject parent = new JSONObject();
+        JSONObject filter = new JSONObject();
+        JSONObject target = new JSONObject();
+        filter.put("is_to_all",toAll);
+        if (toAll) {
+            parent.put("filter",filter);
+        }else {
+            parent.put("touser",openIds);
+        }
+        if (Constants.VID == type) {
+            target.put("media_id",jsonObject.getString("media_id"));
+            target.put("title",jsonObject.getString("title"));
+            target.put("description",jsonObject.getString("description"));
+            parent.put("mpvideo",target);
+            parent.put("msgtype","mpvideo");
+        }else if (Constants.VOI == type) {
+            target.put("media_id",jsonObject.getString("media_id"));
+            parent.put("voice",target);
+            parent.put("msgtype","voice");
+        }else if (Constants.TEXT == type) {
+            target.put("content",jsonObject.getString("content"));
+            parent.put("voice",target);
+            parent.put("msgtype","text");
+        }else if (Constants.IMG == type) {
+            target.put("media_ids",Arrays.asList(jsonObject.getString("media_id")));
+            target.put("recommend","分享图片");
+            target.put("need_open_comment",1);
+            target.put("only_fans_can_comment",0);
+            parent.put("images",target);
+            parent.put("msgtype","image");
+        }else if (Constants.NEWS == type) {
+            target.put("media_ids",jsonObject.getString("media_id"));
+            parent.put("mpnews",target);
+            parent.put("msgtype","mpnews");
+            parent.put("send_ignore_reprint",repeatSend);
+        }
+        String result = parent.toJSONString();
+        logger.info("群发消息 转换json 格式结果:{}",result);
+        return result;
+    }
+
+    /**
+     *  模板数据转换json
+     * @author wangxiao
+     * @date 14:16 2020/9/24
+     * @param openId openiD
+     * @param templateData 模板数据
+     * @param templateId 模板id
+     * @param linkUrl 链接地址
+     * @param linkAppId 链接小程序appid
+     * @return java.lang.String
+     */
+    private String parseJson (String openId,String templateData,String templateId,String linkUrl,String linkAppId) {
+        JSONObject parent = new JSONObject();
+        parent.put("touser",openId);
+        parent.put("template_id",templateId);
+        parent.put("data",JSONArray.parseArray(templateData));
+        if (!StringUtils.isEmpty(linkAppId)) {
+            JSONObject  miniprogram = new JSONObject();
+            miniprogram.put("appid",linkAppId);
+            miniprogram.put("pagepath",linkUrl);
+            parent.put("miniprogram",miniprogram);
+        }else if (!StringUtils.isEmpty(linkUrl)) {
+            parent.put("url",linkUrl);
+        }
+        String result = parent.toJSONString();
+        logger.info("模板消息 转换json 格式结果:{}",result);
+        return result;
+    }
+
+    /**
+     *  客服消息转换 json
+     * @author wangxiao
+     * @date 15:40 2020/9/24
+     * @param openId  openId
+     * @param jsonObject jsonObject
+     * @return java.lang.String
+     */
+    private String parseJson(String openId, JSONObject jsonObject) {
+        int type = jsonObject.getIntValue("type");
+        JSONObject parent = new JSONObject();
+        parent.put("touser",openId);
+        JSONObject target = new JSONObject();
+        if (Constants.VID == type) {
+            target.put("media_id",jsonObject.getString("media_id"));
+            target.put("thumb_media_id",jsonObject.getString("thumb_media_id"));
+            target.put("description",jsonObject.getString("description"));
+            parent.put("mpvideo",target);
+        }else if (Constants.VOI == type) {
+            target.put("media_id",jsonObject.getString("media_id"));
+            parent.put("voice",target);
+            parent.put("msgtype","voice");
+        }else if (Constants.TEXT == type) {
+            target.put("content",jsonObject.getString("content"));
+            parent.put("voice",target);
+            parent.put("msgtype","text");
+        }else if (Constants.IMG == type) {
+            target.put("media_ids",jsonObject.getString("media_id"));
+            parent.put("images",target);
+            parent.put("msgtype","image");
+        }else if (Constants.NEWS == type) {
+            target.put("articles",jsonObject.getJSONArray("articles"));
+            parent.put("news",target);
+            parent.put("msgtype","news");
+        }else if (Constants.MNEWS == type){
+            target.put("media_id",jsonObject.getJSONArray("media_id"));
+            parent.put("mpnews",target);
+            parent.put("msgtype","mpnews");
+        }
+        String result = parent.toJSONString();
+        logger.info("客服消息 转换json 格式结果:{}",result);
+        return result;
     }
 
     @Resource(name = "rpcRestTemplate")
@@ -787,4 +1125,24 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
     public void setFansInfoHandler(FansInfoHandler fansInfoHandler) {
         this.fansInfoHandler = fansInfoHandler;
     }
+
+    @Autowired
+    public void setGroupMsgService(GroupMsgService groupMsgService) {
+        this.groupMsgService = groupMsgService;
+    }
+
+    @Autowired
+    public void setTemplateMsgService(TemplateMsgService templateMsgService) {
+        this.templateMsgService = templateMsgService;
+    }
+
+    @Autowired
+    public void setCustomerMsgService(CustomerMsgService customerMsgService) {
+        this.customerMsgService = customerMsgService;
+    }
+
+    @Autowired
+    public void setAccountCustomerMsgService(AccountCustomerMsgService accountCustomerMsgService) {
+        this.accountCustomerMsgService = accountCustomerMsgService;
+    }
 }

+ 9 - 10
operation-backend/src/main/java/com/idiot/operationbackend/support/Constants.java

@@ -114,6 +114,8 @@ public class Constants {
 
     public static final int VID = 5;
 
+    public static final int MNEWS= 6;
+
     /**
      *  消息任务类型 群发,模板 ,客服
      * @author wangxiao
@@ -122,13 +124,6 @@ public class Constants {
     public static final int TEMPLATE = 2;
     public static final int CUSTOMER = 3;
 
-    /**
-     *  全部 ,筛选
-     * @author wangxiao
-     */
-    public static final int ALL =1;
-    public static final int SELECT = 0;
-
 
     /**
      *  计算 比率
@@ -157,7 +152,11 @@ public class Constants {
      * @return java.time.LocalDateTime
      */
     public static LocalDateTime toLocalDateTime (String dateStr) {
-        return LocalDate.parse(dateStr,Constants.DATE_FORMATTER).atTime(0,0,0);
+        return LocalDate.parse(dateStr,DATE_FORMATTER).atTime(0,0,0);
+    }
+
+    public static long  toEpochMilli (String dateStr) {
+        return LocalDateTime.parse(dateStr,DATE_TIME_FORMATTER).toInstant(DEFAULT_ZONE).toEpochMilli();
     }
 
     public static LocalDateTime toLocalDateTime1 (String dateStr) {
@@ -172,7 +171,7 @@ public class Constants {
      * @return java.time.LocalDateTime
      */
     public static LocalDateTime toLocalDateTime (long epochSecond ) {
-        return LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond),Constants.DEFAULT_ZONE);
+        return LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond),DEFAULT_ZONE);
 
     }
 
@@ -184,7 +183,7 @@ public class Constants {
      * @return java.time.LocalDateTime
      */
     public static long toEpochSecond (LocalDateTime dateTime) {
-        return dateTime.toEpochSecond(Constants.DEFAULT_ZONE);
+        return dateTime.toEpochSecond(DEFAULT_ZONE);
     }
     // 以上三个方法 感觉是多余 但是懒得删除 --- end
 

+ 29 - 0
operation-backend/src/main/java/com/idiot/operationbackend/support/job/CustomerJobTask.java

@@ -0,0 +1,29 @@
+package com.idiot.operationbackend.support.job;
+
+import com.idiot.operationbackend.entity.CustomerMsg;
+import com.idiot.operationbackend.service.facade.WeChatService;
+
+/**
+ * 客服消息
+ * @author wang xiao
+ * @date Created in 14:33 2020/9/24
+ */
+public class CustomerJobTask implements BaseJobTask{
+
+    private CustomerMsg customerMsg;
+
+    private WeChatService weChatService;
+
+    public CustomerJobTask() {
+    }
+
+    public CustomerJobTask(CustomerMsg customerMsg, WeChatService weChatService) {
+        this.customerMsg = customerMsg;
+        this.weChatService = weChatService;
+    }
+
+    @Override
+    public void run() {
+        weChatService.doCustomerMsgTask(customerMsg);
+    }
+}

+ 1 - 1
operation-backend/src/main/java/com/idiot/operationbackend/support/job/GroupJobTask.java

@@ -24,7 +24,7 @@ public class GroupJobTask implements BaseJobTask {
 
     @Override
     public void run() {
-        weChatService.groupMsgTask(groupMsg);
+        weChatService.doGroupMsgTask(groupMsg);
     }
 
 

+ 1 - 1
operation-backend/src/main/java/com/idiot/operationbackend/support/job/TemplateJobTask.java

@@ -24,6 +24,6 @@ public class TemplateJobTask implements BaseJobTask {
 
     @Override
     public void run() {
-
+        weChatService.doTemplateMsgTask(templateMsg);
     }
 }

+ 6 - 0
sql/dataBase.sql

@@ -422,6 +422,12 @@ CREATE TABLE `t_template_msg`  (
   `nike_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
   `head_image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
   `create_time` datetime(0) NULL DEFAULT NULL,
+  `type` tinyint(1) NULL DEFAULT NULL COMMENT '发送类型 1 全部',
+  `select_sex` tinyint(1) NULL DEFAULT NULL COMMENT '选择性别',
+  `select_tag` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '标签',
+  `select_province` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
+  `select_city` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
+  `select_subscribe_time` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
   PRIMARY KEY (`id`) USING BTREE
 ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '模板消息' ROW_FORMAT = Dynamic;