Преглед на файлове

Merge branch 'dev-xym-callback' of Server/we-com-manage into master

xueyiming преди 8 месеца
родител
ревизия
41da14fe17
променени са 51 файла, в които са добавени 3060 реда и са изтрити 1177 реда
  1. 33 1
      pom.xml
  2. 3 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/common/constant/MessageConstant.java
  3. 4 2
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/common/constant/RedisConstant.java
  4. 36 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/common/constant/WeComConstant.java
  5. 10 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/common/constant/WeComServerConstant.java
  6. 6 8
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/controller/MessageController.java
  7. 121 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/controller/WeComController.java
  8. 2 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/AlertMessageMapper.java
  9. 1 3
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/HistoryMessageMapper.java
  10. 2 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/SendMessageMapper.java
  11. 2 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/StaffMapper.java
  12. 0 1
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/StaffWithUserMapper.java
  13. 2 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/UserMapper.java
  14. 251 166
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/job/WeComHistoryDataJob.java
  15. 141 104
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/job/WeComMessageDataJob.java
  16. 71 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/job/WeComStaffDataJob.java
  17. 125 223
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/job/WeComUserDataJob.java
  18. 13 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/bo/ExternalUser.java
  19. 13 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/bo/SendDetail.java
  20. 14 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/bo/VideoParam.java
  21. 2 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/bo/XxlJobParam.java
  22. 33 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/po/HistoryMessage.java
  23. 180 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/po/HistoryMessageExample.java
  24. 22 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/po/StaffWithUser.java
  25. 120 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/po/StaffWithUserExample.java
  26. 14 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/vo/GuaranteedParam.java
  27. 1 1
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/vo/MessageTextParam.java
  28. 3 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/AccessTokenService.java
  29. 23 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/Impl/AccessTokenServiceImpl.java
  30. 77 12
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/Impl/MessageAttachmentServiceImpl.java
  31. 26 9
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/Impl/MessageServiceImpl.java
  32. 218 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/Impl/UserServiceImpl.java
  33. 6 2
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/MessageAttachmentService.java
  34. 4 2
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/MessageService.java
  35. 16 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/UserService.java
  36. 7 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/DateUtil.java
  37. 10 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/HttpPoolClient.java
  38. 5 6
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/LarkRobotUtil.java
  39. 59 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/AesException.java
  40. 26 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/ByteGroup.java
  41. 67 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/PKCS7Encoder.java
  42. 61 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/SHA1.java
  43. 289 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/WXBizMsgCrypt.java
  44. 95 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/WxUtil.java
  45. 104 0
      we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/XMLParse.java
  46. 79 28
      we-com-server/src/main/resources/mapper/HistoryMessageMapper.xml
  47. 12 0
      we-com-server/src/main/resources/mapper/SendMessageMapper.xml
  48. 2 2
      we-com-server/src/main/resources/mapper/StaffMapper.xml
  49. 257 228
      we-com-server/src/main/resources/mapper/StaffWithUserMapper.xml
  50. 390 377
      we-com-server/src/main/resources/mapper/UserMapper.xml
  51. 2 2
      we-com-server/src/main/resources/mybatis-generator-config.xml

+ 33 - 1
pom.xml

@@ -106,9 +106,25 @@
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
-            <version>4.5.13</version> <!-- 使用最新版本 -->
+            <version>4.5.14</version> <!-- 使用最新版本 -->
         </dependency>
 
+        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpmime</artifactId>
+            <version>4.5.14</version>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpcore</artifactId>
+            <version>4.4.16</version>
+        </dependency>
+
+
+
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
@@ -131,6 +147,22 @@
             <artifactId>xxl-job-core</artifactId>
         </dependency>
 
+        <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.17.1</version>
+        </dependency>
+
+        <!--XML 解析包-->
+        <dependency>
+            <groupId>org.jdom</groupId>
+            <artifactId>jdom2</artifactId>
+            <version>2.0.6</version>
+        </dependency>
+
+
+
     </dependencies>
 
 </project>

+ 3 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/common/constant/MessageConstant.java

@@ -13,5 +13,8 @@ public interface MessageConstant {
 
     String defaultName = "日常push-%s-%s";
 
+    //发送视频数量
+    int MAX_VIDEO_NUM = 3;
+
 
 }

+ 4 - 2
we-com-server/src/main/java/com/tzld/piaoquan/wecom/common/constant/RedisConstant.java

@@ -5,6 +5,8 @@ public interface RedisConstant {
     String PUSH_MESSAGE_TEXT = "push_message_text";
     String ACCESS_TOKEN = "ACCESS_TOKEN";
 
-    //小程序保底视频列表key
-    String GUARANTEED_MINIPROGRAM_KEY = "guaranteed_miniprogram_list";
+    String WE_COM_ACCESS_TOKEN = "WE_COM_ACCESS_TOKEN";
+
+    //小程序保底视频key
+    String GUARANTEED_MINI_PROGRAM_KEY = "guaranteed_mini_program_%s";
 }

+ 36 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/common/constant/WeComConstant.java

@@ -14,4 +14,40 @@ public interface WeComConstant {
     String POST_MESSAGE_PUSH_URL = "https://open.weibanzhushou.com/open-api/group_msg/add";
     //获取删除用户接口
     String GET_DELETE_USER_URL = "https://open.weibanzhushou.com/open-api/external_user/list/outflow";
+
+    String GET_WE_COM_ACCESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
+
+    String WE_COM_SECRET = "X13JWOI5ud_IsT2RBXGDZmknysLKqZfGdAO8eszA090";
+
+    String WE_COM_CROP_ID = "wwa4015dc7d652a21f";
+
+    //获取群发记录列表
+    String POST_WE_COM_GROUP_MSG_LIST_URL = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_list_v2";
+
+    //获取群发成员发送任务列表
+    String POST_WE_COM_GROUP_MSG_TASK = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_task";
+
+    //获取企业群发成员执行结果
+    String POST_WE_COM_GROUP_MSG_SEND_RESULT = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_groupmsg_send_result";
+
+    //创建企业群发
+    String POST_WE_COM_ADD_MSG_TEMPLATE = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/add_msg_template";
+
+    //批量获取客户详情
+    String POST_WE_COM_GET_BY_USER = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/batch/get_by_user";
+
+    //上传临时素材
+    String POST_WE_COM_MEDIA_UPLOAD = "https://qyapi.weixin.qq.com/cgi-bin/media/upload";
+
+    //获取客户列表
+    String GET_WE_COM_EXTERNAL_CONTACT_LIST = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/list";
+
+    //获取客户详情
+    String GET_WE_COM_EXTERNAL_CONTACT_GET = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get";
+
+    //external_userid转换
+    String POST_WE_COM_EXTERNAL_USER_ID = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/from_service_external_userid";
+
+    //获取配置了客户联系功能的成员列表
+    String GET_WE_COM_FOLLOW_USER_LIST = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_follow_user_list";
 }

+ 10 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/common/constant/WeComServerConstant.java

@@ -0,0 +1,10 @@
+package com.tzld.piaoquan.wecom.common.constant;
+
+public interface WeComServerConstant {
+
+    String TOKEN = "Sk4rwob1vD9bjZDINuYVBU";
+
+    String ENCODING_AES_KEY = "i2DhQ6AjBGpacrSA8NNXIW1MWRzCAwowbrEd30GWEeR";
+
+    String CORP_ID = "wwa4015dc7d652a21f";
+}

+ 6 - 8
we-com-server/src/main/java/com/tzld/piaoquan/wecom/controller/MessageController.java

@@ -2,14 +2,13 @@ package com.tzld.piaoquan.wecom.controller;
 
 
 import com.tzld.piaoquan.wecom.common.base.CommonResponse;
-import com.tzld.piaoquan.wecom.model.vo.MessageTextVo;
+import com.tzld.piaoquan.wecom.model.vo.GuaranteedParam;
+import com.tzld.piaoquan.wecom.model.vo.MessageTextParam;
 import com.tzld.piaoquan.wecom.service.MessageAttachmentService;
 import com.tzld.piaoquan.wecom.service.MessageService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.List;
-
 @RestController
 @RequestMapping("/wecom/message")
 public class MessageController {
@@ -22,15 +21,14 @@ public class MessageController {
 
     //创建保底小程序
     @PostMapping("/miniprogram/guaranteed/create")
-    public CommonResponse<Void> createGuaranteedMiniprogram(@RequestBody List<Long> videoIds){
-        messageAttachmentService.createGuaranteedMiniprogram(videoIds);
-        return CommonResponse.success();
+    public CommonResponse<Void> createGuaranteedMiniProgram(@RequestBody GuaranteedParam guaranteedParam){
+        return messageAttachmentService.createGuaranteedMiniProgram(guaranteedParam);
     }
 
     //创建新text 有时限和无时限  新创建覆盖原text 未创建取默认保底
     @PostMapping("/text/create")
-    public CommonResponse<Void> createMessageText(@RequestBody MessageTextVo messageTextVo){
-        messageService.createMessageText(messageTextVo);
+    public CommonResponse<Void> createMessageText(@RequestBody MessageTextParam messageTextParam){
+        messageService.createMessageText(messageTextParam);
         return CommonResponse.success();
     }
 

+ 121 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/controller/WeComController.java

@@ -0,0 +1,121 @@
+package com.tzld.piaoquan.wecom.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.tzld.piaoquan.wecom.common.constant.WeComServerConstant;
+import com.tzld.piaoquan.wecom.service.UserService;
+import com.tzld.piaoquan.wecom.utils.wecom.WXBizMsgCrypt;
+import com.tzld.piaoquan.wecom.utils.wecom.WxUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.Map;
+
+@Slf4j
+@RestController
+@RequestMapping("/wecom/server")
+public class WeComController {
+
+
+    @Autowired
+    private UserService userService;
+
+    @GetMapping("/verify")
+    public void verifyGet(HttpServletRequest request, HttpServletResponse response) {
+        try {
+            // 微信加密签名
+            String msgSignature = request.getParameter("msg_signature");
+            // 时间戳
+            String timestamp = request.getParameter("timestamp");
+            // 随机数
+            String nonce = request.getParameter("nonce");
+            // 随机字符串
+            // 如果是刷新,需返回原echostr
+            String echoStr = request.getParameter("echostr");
+            // 微信加密签名
+            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeComServerConstant.TOKEN,
+                    WeComServerConstant.ENCODING_AES_KEY,
+                    WeComServerConstant.CORP_ID);
+
+            String sEchoStr = ""; //需要返回的明文
+            PrintWriter out;
+
+            sEchoStr = wxcpt.VerifyURL(msgSignature, timestamp,
+                    nonce, echoStr);
+            log.info("verifyurl echostr: " + sEchoStr);
+
+            // 验证URL成功,将sEchoStr返回
+            out = response.getWriter();
+            out.print(sEchoStr);
+        } catch (Exception e) {
+            //验证URL失败,错误原因请查看异常
+            log.error("verifyGet error", e);
+        }
+
+    }
+
+    /**
+     * 刷新 ticket
+     */
+    @PostMapping(value = "/verify")
+    public String verifyPost(HttpServletRequest request) {
+
+        try {
+            // 微信加密签名
+            String msg_signature = request.getParameter("msg_signature");
+            // 时间戳
+            String timestamp = request.getParameter("timestamp");
+            // 随机数
+            String nonce = request.getParameter("nonce");
+
+            String id = WeComServerConstant.CORP_ID;
+
+            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeComServerConstant.TOKEN, WeComServerConstant.ENCODING_AES_KEY, id);
+
+            String postData = "";   // 密文,对应POST请求的数据
+            //1.获取加密的请求消息:使用输入流获得加密请求消息postData
+            ServletInputStream in = request.getInputStream();
+            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+
+            String tempStr = "";   //作为输出字符串的临时串,用于判断是否读取完毕
+            while (null != (tempStr = reader.readLine())) {
+                postData += tempStr;
+            }
+
+            String suiteXml = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, postData);
+            log.info("suiteXml: " + suiteXml);
+
+            Map suiteMap = WxUtil.transferXmlToMap(suiteXml);
+            log.info("suiteMap = {}", JSONObject.toJSONString(suiteMap));
+            if (suiteMap != null) {
+                String changeType = (String) suiteMap.get("ChangeType");
+                if (StringUtils.isNotEmpty(changeType) && changeType.equals("add_external_contact")) {
+                    String userId = (String) suiteMap.get("UserID");
+                    String externalUserId = (String) suiteMap.get("ExternalUserID");
+                    log.info("addStaffWithUser userId={} externalUserId={}", userId, externalUserId);
+                    userService.addStaffWithUser(externalUserId, userId);
+                }
+
+                if (StringUtils.isNotEmpty(changeType) && changeType.equals("del_follow_user")) {
+                    String userId = (String) suiteMap.get("UserID");
+                    String externalUserId = (String) suiteMap.get("ExternalUserID");
+                    log.info("delStaffWithUser userId={} externalUserId={}", userId, externalUserId);
+                    userService.delStaffWithUser(externalUserId, userId);
+                }
+            }
+
+
+        } catch (Exception e) {
+            log.error("verifyPost error", e);
+        }
+        String success = "success";
+        return success;
+    }
+}

+ 2 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/AlertMessageMapper.java

@@ -4,7 +4,9 @@ import com.tzld.piaoquan.wecom.model.po.AlertMessage;
 import com.tzld.piaoquan.wecom.model.po.AlertMessageExample;
 import java.util.List;
 import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
 
+@Repository
 public interface AlertMessageMapper {
     long countByExample(AlertMessageExample example);
 

+ 1 - 3
we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/HistoryMessageMapper.java

@@ -2,12 +2,10 @@ package com.tzld.piaoquan.wecom.dao.mapper;
 
 import com.tzld.piaoquan.wecom.model.po.HistoryMessage;
 import com.tzld.piaoquan.wecom.model.po.HistoryMessageExample;
+import java.util.List;
 import org.apache.ibatis.annotations.Param;
 import org.springframework.stereotype.Repository;
 
-import java.util.List;
-
-
 @Repository
 public interface HistoryMessageMapper {
     long countByExample(HistoryMessageExample example);

+ 2 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/SendMessageMapper.java

@@ -39,4 +39,6 @@ public interface SendMessageMapper {
 
     List<String> selectExternalUserId3rdParty(@Param("record") SendMessage record);
 
+    List<String> selectExternalUserId(@Param("record") SendMessage record);
+
 }

+ 2 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/StaffMapper.java

@@ -4,7 +4,9 @@ import com.tzld.piaoquan.wecom.model.po.Staff;
 import com.tzld.piaoquan.wecom.model.po.StaffExample;
 import java.util.List;
 import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
 
+@Repository
 public interface StaffMapper {
     long countByExample(StaffExample example);
 

+ 0 - 1
we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/StaffWithUserMapper.java

@@ -3,7 +3,6 @@ package com.tzld.piaoquan.wecom.dao.mapper;
 import com.tzld.piaoquan.wecom.model.po.StaffWithUser;
 import com.tzld.piaoquan.wecom.model.po.StaffWithUserExample;
 import java.util.List;
-
 import org.apache.ibatis.annotations.Param;
 import org.springframework.stereotype.Repository;
 

+ 2 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/dao/mapper/UserMapper.java

@@ -34,5 +34,7 @@ public interface UserMapper {
 
     Long selectIdByExternalUserId3rdParty(String externalUserId3rdParty);
 
+    Long selectIdByExternalUserId(String externalUserId);
+
     void insertList(@Param("list") List<User> list);
 }

+ 251 - 166
we-com-server/src/main/java/com/tzld/piaoquan/wecom/job/WeComHistoryDataJob.java

@@ -2,34 +2,41 @@ package com.tzld.piaoquan.wecom.job;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
 import com.tzld.piaoquan.wecom.common.constant.TimeConstant;
 import com.tzld.piaoquan.wecom.common.enums.MessageAttachmentTypeEnum;
-import com.tzld.piaoquan.wecom.dao.mapper.AlertMessageMapper;
 import com.tzld.piaoquan.wecom.dao.mapper.HistoryMessageMapper;
 import com.tzld.piaoquan.wecom.dao.mapper.StaffMapper;
 import com.tzld.piaoquan.wecom.dao.mapper.UserMapper;
+import com.tzld.piaoquan.wecom.model.bo.ExternalUser;
 import com.tzld.piaoquan.wecom.model.bo.MiniprogramRecord;
+import com.tzld.piaoquan.wecom.model.bo.SendDetail;
 import com.tzld.piaoquan.wecom.model.bo.XxlJobParam;
 import com.tzld.piaoquan.wecom.model.po.*;
 import com.tzld.piaoquan.wecom.service.AccessTokenService;
 import com.tzld.piaoquan.wecom.service.HistoryMessageService;
 import com.tzld.piaoquan.wecom.service.MessageAttachmentService;
-import com.tzld.piaoquan.wecom.utils.*;
+import com.tzld.piaoquan.wecom.service.UserService;
+import com.tzld.piaoquan.wecom.utils.HttpClientUtil;
+import com.tzld.piaoquan.wecom.utils.HttpPoolClient;
+import com.tzld.piaoquan.wecom.utils.LarkRobotUtil;
+import com.tzld.piaoquan.wecom.utils.MessageUtil;
 import com.tzld.piaoquan.wecom.utils.page.Page;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
 
-import static com.tzld.piaoquan.wecom.common.constant.WeComConstant.GET_HISTORY_DATA_URL;
+import static com.tzld.piaoquan.wecom.common.constant.WeComConstant.*;
 
 @Slf4j
 @Component
@@ -37,7 +44,6 @@ public class WeComHistoryDataJob {
 
     private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(30000, 30000, 2000, 5000, 5, 30000);
 
-    final int size = 20;
 
     @Autowired
     private AccessTokenService accessTokenService;
@@ -55,10 +61,10 @@ public class WeComHistoryDataJob {
     private MessageAttachmentService messageAttachmentService;
 
     @Autowired
-    private AlertMessageMapper alertMessageMapper;
+    private StaffMapper staffMapper;
 
     @Autowired
-    private StaffMapper staffMapper;
+    private UserService userService;
 
 
     @XxlJob("saveHistoryMessageJob")
@@ -72,7 +78,12 @@ public class WeComHistoryDataJob {
             example.setOrderByClause("create_time desc");
             example.setPage(new Page<>(1, 1));
             List<HistoryMessage> historyMessages = historyMessageMapper.selectByExample(example);
-            xxlJobParam.setStartTime(historyMessages.get(0).getCreateTime().getTime() / 1000);
+            if (CollectionUtils.isEmpty(historyMessages)) {
+                xxlJobParam.setStartTime(1721404800L);
+            } else {
+                xxlJobParam.setStartTime(historyMessages.get(0).getCreateTime().getTime() / 1000);
+            }
+
         }
         if (xxlJobParam.getEndTime() == null) {
             xxlJobParam.setEndTime(System.currentTimeMillis() / 1000);
@@ -81,217 +92,291 @@ public class WeComHistoryDataJob {
         Long endTime = xxlJobParam.getEndTime();
 
         for (; startTime < endTime; startTime += TimeConstant.DAY) {
-            selectHistoryMessage(startTime, Math.min(startTime + TimeConstant.DAY, endTime));
+            selectGroupMsgList(startTime, Math.min(startTime + TimeConstant.DAY, endTime));
         }
+        selectAlertHistoryMessage(xxlJobParam.getStartTime(), xxlJobParam.getEndTime());
         return ReturnT.SUCCESS;
     }
 
-    public void selectHistoryMessage(Long startTime, Long endTime) {
-        try {
-            Integer total = getHistoryDataTotal(startTime, endTime);
-            if (total == null || total == 0) {
-                return;
+    private void selectAlertHistoryMessage(Long startTime, Long endTime) {
+
+        StaffExample staffExample = new StaffExample();
+        List<Staff> staffList = staffMapper.selectByExample(staffExample);
+        ArrayList<Integer> statusList = Lists.newArrayList(0, 1, 2, 3);
+        List<SendDetail> sendDetailList = new ArrayList<>();
+        for (Staff staff : staffList) {
+            SendDetail sendDetail = new SendDetail();
+            sendDetail.setRemark(staff.getRemark());
+            List<Long> countList = new ArrayList<>();
+            for (Integer status : statusList) {
+                HistoryMessageExample example = new HistoryMessageExample();
+                example.createCriteria().andSendTimeBetween(new Date(startTime * 1000), new Date(endTime * 1000))
+                        .andStaffIdEqualTo(staff.getId())
+                        .andStatusEqualTo(status)
+                        .andIsDeleteEqualTo(0);
+                long l = historyMessageMapper.countByExample(example);
+                countList.add(l);
             }
-            int page = total / size + 1;
-            for (int n = 0; n < page; n++) {
-                String res = getHistoryData(size, n * size, startTime, endTime);
-                log.info("selectHistoryMessage size={}, n={}, startTime={}, endTime={}, res={}", size, n, startTime, endTime, res);
-                if (ObjectUtils.isEmpty(res)) {
+            sendDetail.setSendCountList(countList);
+            sendDetailList.add(sendDetail);
+        }
+        StringBuilder stringBuilder = new StringBuilder();
+        for (SendDetail sendDetail : sendDetailList) {
+            List<Long> sendCountList = sendDetail.getSendCountList();
+            if (CollectionUtils.isEmpty(sendCountList)) {
+                continue;
+            }
+            stringBuilder.append(sendDetail.getRemark());
+            long count = sendCountList.get(0) + sendCountList.get(1) + sendCountList.get(2) + sendCountList.get(3);
+            stringBuilder.append("总发送数量:").append(count).append("   ");
+            stringBuilder.append("未发送数量:").append(sendCountList.get(0)).append("   ");
+            stringBuilder.append("已发送数量:").append(sendCountList.get(1)).append("   ");
+            stringBuilder.append("不是好友发送失败数量:").append(sendCountList.get(2)).append("   ");
+            stringBuilder.append("已经收到其他群发消息失败发送数量:").append(sendCountList.get(3)).append("   ");
+            stringBuilder.append("\n");
+        }
+        LarkRobotUtil.sendMessage(stringBuilder.toString());
+    }
+
+    public void selectGroupMsgList(Long startTime, Long endTime) {
+        delHistoryMessageList(startTime, endTime);
+        try {
+            String cursor = "";
+            do {
+                String res = getGroupMsgList(startTime, endTime, cursor);
+                JSONObject jsonObject = JSONObject.parseObject(res);
+                Integer errCode = jsonObject.getInteger("errcode");
+                if (errCode != 0) {
+                    LarkRobotUtil.sendMessage("selectGroupMsgList error startTime = " + startTime + "endTime = " + endTime);
+                    log.error("selectGroupMsgList error startTime={}, endTime={}", startTime, endTime);
                     return;
                 }
-                JSONObject jsonObject = JSONObject.parseObject(res);
-                JSONArray jsonArray = jsonObject.getJSONArray("missions");
-                for (int i = 0; i < jsonArray.size(); i++) {
-                    List<String> allExternalUserList = new ArrayList<>();
+                JSONArray groupMsgList = jsonObject.getJSONArray("group_msg_list");
+                if (CollectionUtils.isEmpty(groupMsgList)) {
+                    continue;
+                }
+                for (int i = 0; i < groupMsgList.size(); i++) {
+                    JSONObject groupMsg = groupMsgList.getJSONObject(i);
+                    JSONArray attachments = groupMsg.getJSONArray("attachments");
+                    String msgId = groupMsg.getString("msgid");
+                    Long createTime = null;
+                    if (groupMsg.getLong("create_time") != null) {
+                        createTime = groupMsg.getLong("create_time") * 1000;
+                    }
+                    if (CollectionUtils.isEmpty(attachments)) {
+                        continue;
+                    }
                     List<MiniprogramRecord> miniprogramRecordList = new ArrayList<>();
                     List<MessageAttachment> messageAttachmentList = new ArrayList<>();
-                    Date sendAt = jsonArray.getJSONObject(i).getDate("send_at");
-                    JSONArray attachments = jsonArray.getJSONObject(i).getJSONObject("msg_data").getJSONArray("attachments");
                     for (int j = 0; j < attachments.size(); j++) {
+                        JSONObject miniprogram = attachments.getJSONObject(j).getJSONObject("miniprogram");
+                        if (miniprogram == null) {
+                            continue;
+                        }
                         MiniprogramRecord miniprogramRecord = new MiniprogramRecord();
                         MessageAttachment messageAttachment = new MessageAttachment();
-                        String indexPage = attachments.getJSONObject(j).getJSONObject("miniprogram").getString("page");
-                        Long videoId = MessageUtil.getVideoId(indexPage);
+                        String title = miniprogram.getString("title");
+                        String appid = miniprogram.getString("appid");
+                        String page = miniprogram.getString("page");
+                        Long videoId = MessageUtil.getVideoId(page);
+
                         miniprogramRecord.setVideoId(videoId);
                         miniprogramRecord.setAttachmentIdx(j + 1);
                         miniprogramRecordList.add(miniprogramRecord);
-                        String cover = attachments.getJSONObject(j).getJSONObject("miniprogram").getString("cover");
-                        String appid = attachments.getJSONObject(j).getJSONObject("miniprogram").getString("appid");
-                        String title = attachments.getJSONObject(j).getJSONObject("miniprogram").getString("title");
+
                         messageAttachment.setAppid(appid);
-                        messageAttachment.setCover(cover);
-                        messageAttachment.setPage(indexPage);
+                        messageAttachment.setPage(page);
                         messageAttachment.setTitle(title);
                         messageAttachment.setMiniprogramVideoId(videoId);
-                        messageAttachment.setSendTime(sendAt);
                         messageAttachment.setType(MessageAttachmentTypeEnum.MINIPROGRAM.getType());
                         messageAttachmentList.add(messageAttachment);
                     }
-                    JSONArray subMissionList = jsonArray.getJSONObject(i).getJSONArray("sub_mission_list");
-                    for (int k = 0; k < subMissionList.size(); k++) {
-                        if (!"sended".equals(subMissionList.getJSONObject(k).getString("status"))) {
+                    List<String> userIdList = selectGroupMsgTask(msgId);
+                    if (CollectionUtils.isEmpty(userIdList)) {
+                        continue;
+                    }
+                    for (String userId : userIdList) {
+                        StaffExample example = new StaffExample();
+                        example.createCriteria().andCarrierIdEqualTo(userId);
+                        List<Staff> staffList = staffMapper.selectByExample(example);
+                        if (CollectionUtils.isEmpty(staffList)) {
+                            LarkRobotUtil.sendMessage("企微推送报警:userId不存在请检查 " + userId);
                             continue;
                         }
-                        List<String> externalUserList = subMissionList.getJSONObject(k).getJSONArray("external_user_list").toJavaList(String.class);
-                        if (CollectionUtils.isEmpty(externalUserList)) {
+                        List<ExternalUser> externalUsers = selectGroupMsgSendResult(msgId, userId);
+                        if (CollectionUtils.isEmpty(externalUsers)) {
                             continue;
                         }
-                        allExternalUserList.addAll(externalUserList);
+                        insertHistoryMessageList(staffList.get(0), externalUsers, miniprogramRecordList, createTime);
+                        messageAttachmentService.addMiniProgram(messageAttachmentList);
                     }
-                    insertHistoryMessageList(allExternalUserList, miniprogramRecordList, sendAt);
-                    messageAttachmentService.addMiniprogram(messageAttachmentList);
                 }
-            }
+                String nextCursor = jsonObject.getString("next_cursor");
+                if (cursor.equals(nextCursor)) {
+                    break;
+                }
+                cursor = nextCursor;
+            } while (StringUtils.isNotEmpty(cursor));
         } catch (IOException e) {
-            log.error("selectHistoryMessage error", e);
+            LarkRobotUtil.sendMessage("selectGroupMsgList error" + e);
+            log.error("selectGroupMsgList error", e);
         }
     }
 
 
-    private void insertHistoryMessageList(List<String> allExternalUserList, List<MiniprogramRecord> miniprogramRecordList, Date sendTime) {
-        List<HistoryMessage> historyMessageList = new ArrayList<>();
-        for (String externalUserId3rdParty : allExternalUserList) {
-            Long userId = userMapper.selectIdByExternalUserId3rdParty(externalUserId3rdParty);
-            if (userId == null) {
-                continue;
+    private List<ExternalUser> selectGroupMsgSendResult(String msgId, String userId) throws IOException {
+        List<ExternalUser> resList = new ArrayList<>();
+        String cursor = "";
+        do {
+            String res = getGroupMsgSendResult(msgId, userId, cursor);
+            JSONObject jsonObject = JSONObject.parseObject(res);
+            Integer errCode = jsonObject.getInteger("errcode");
+            if (errCode != 0) {
+                String errmsg = jsonObject.getString("errmsg");
+                log.error("selectGroupMsgSendResult error msgId={} userId={} errCode={} errmsg={}", msgId, userId, errCode, errmsg);
+                return resList;
             }
-            for (MiniprogramRecord miniprogramRecord : miniprogramRecordList) {
-                HistoryMessage historyMessage = new HistoryMessage();
-                historyMessage.setSendTime(sendTime);
-                historyMessage.setAttachmentIdx(miniprogramRecord.getAttachmentIdx());
-                historyMessage.setVideoId(miniprogramRecord.getVideoId());
-                historyMessage.setUserId(userId);
-                historyMessageList.add(historyMessage);
+            JSONArray sendList = jsonObject.getJSONArray("send_list");
+            for (int i = 0; i < sendList.size(); i++) {
+                JSONObject send = sendList.getJSONObject(i);
+                ExternalUser externalUser = new ExternalUser();
+                externalUser.setExternalUserId(send.getString("external_userid"));
+                externalUser.setStatus(send.getInteger("status"));
+                if (send.getLong("send_time") != null) {
+                    externalUser.setSendTime(send.getLong("send_time") * 1000);
+                }
+                resList.add(externalUser);
             }
-        }
-        historyMessageService.batchInsertHistoryMessage(historyMessageList);
-    }
-
-    public Integer getHistoryDataTotal(Long startTime, Long endTime) throws IOException {
-        String res = getHistoryData(1, 0, startTime, endTime);
-        JSONObject jsonObject = JSONObject.parseObject(res);
-        return jsonObject.getInteger("total_count");
+            String nextCursor = jsonObject.getString("next_cursor");
+            if (cursor.equals(nextCursor)) {
+                break;
+            }
+            cursor = nextCursor;
+        } while (StringUtils.isNotEmpty(cursor));
+        return resList;
     }
 
-    public String getHistoryData(Integer limit, Integer offset, Long startTime, Long endTime) throws IOException {
-        String accessToken = accessTokenService.getAccessToken();
-        String url = GET_HISTORY_DATA_URL
-                + "?access_token=" + accessToken
-                + "&limit=" + limit + "&offset=" + offset + "&start_time=" + startTime + "&end_time=" + endTime;
-        return httpPoolClientDefault.get(url);
+    private String getGroupMsgSendResult(String msgId, String userId, String cursor) throws IOException {
+        String accessToken = accessTokenService.getWeComAccessToken();
+        String url = POST_WE_COM_GROUP_MSG_SEND_RESULT
+                + "?access_token=" + accessToken;
+        JSONObject param = new JSONObject();
+        param.put("msgid", msgId);
+        param.put("userid", userId);
+        param.put("limit", 1000);
+        if (StringUtils.isNotEmpty(cursor)) {
+            param.put("cursor", cursor);
+        }
+        return httpPoolClientDefault.post(url, param.toJSONString());
     }
 
 
-    @XxlJob("deleteHistoryMessageJob")
-    public ReturnT<String> deleteHistoryMessage(String param) {
-        UserExample userExample = new UserExample();
-        userExample.createCriteria().andIsDeleteEqualTo(1);
-        List<User> userList = userMapper.selectByExample(userExample);
-        for (User user : userList) {
-            HistoryMessageExample example = new HistoryMessageExample();
-            example.createCriteria().andUserIdEqualTo(user.getId());
-            List<HistoryMessage> historyMessages = historyMessageMapper.selectByExample(example);
-            for (HistoryMessage historyMessage : historyMessages) {
-                if (historyMessage.getSendTime().getTime() > user.getDeletedAt() * 1000) {
-                    historyMessageMapper.deleteByPrimaryKey(historyMessage.getId());
-                }
+    private List<String> selectGroupMsgTask(String msgId) throws IOException {
+        List<String> resList = new ArrayList<>();
+        String cursor = "";
+        do {
+            String res = getGroupMsgTask(msgId, cursor);
+            JSONObject jsonObject = JSONObject.parseObject(res);
+            Integer errCode = jsonObject.getInteger("errcode");
+            if (errCode != 0) {
+                String errmsg = jsonObject.getString("errmsg");
+                log.error("selectGroupMsgTask error msgId={} errCode={} errmsg={}", msgId, errCode, errmsg);
+                return resList;
             }
-        }
-        return ReturnT.SUCCESS;
+            JSONArray taskList = jsonObject.getJSONArray("task_list");
+            for (int i = 0; i < taskList.size(); i++) {
+                JSONObject task = taskList.getJSONObject(i);
+                String userId = task.getString("userid");
+                resList.add(userId);
+            }
+            String nextCursor = jsonObject.getString("next_cursor");
+            if (cursor.equals(nextCursor)) {
+                break;
+            }
+            cursor = nextCursor;
+        } while (StringUtils.isNotEmpty(cursor));
+        return resList;
     }
 
-    @XxlJob("sendMessageAlertJob")
-    public ReturnT<String> sendMessageAlert(String param) {
-        XxlJobParam xxlJobParam = new XxlJobParam();
-        if (StringUtils.isNotEmpty(param)) {
-            xxlJobParam = JSONObject.parseObject(param, XxlJobParam.class);
-        }
-        if (xxlJobParam.getStartTime() == null) {
-            xxlJobParam.setStartTime(TimeUtil.getTodayTimestamp() / 1000);
-        }
-        if (xxlJobParam.getEndTime() == null) {
-            xxlJobParam.setEndTime(System.currentTimeMillis() / 1000);
+    private String getGroupMsgTask(String msgId, String cursor) throws IOException {
+        String accessToken = accessTokenService.getWeComAccessToken();
+        String url = POST_WE_COM_GROUP_MSG_TASK
+                + "?access_token=" + accessToken;
+        JSONObject param = new JSONObject();
+        param.put("msgid", msgId);
+        param.put("limit", 1000);
+        if (StringUtils.isNotEmpty(cursor)) {
+            param.put("cursor", cursor);
         }
-        Long startTime = xxlJobParam.getStartTime();
-        Long endTime = xxlJobParam.getEndTime();
-        selectAlertHistoryMessage(startTime, endTime);
-        return ReturnT.SUCCESS;
+        return httpPoolClientDefault.post(url, param.toJSONString());
     }
 
-    public void selectAlertHistoryMessage(Long startTime, Long endTime) {
-        try {
-            Integer total = getHistoryDataTotal(startTime, endTime);
-            if (total == null || total == 0) {
-                return;
+    private void delHistoryMessageList(Long startTime, Long endTime) {
+        HistoryMessage historyMessage = new HistoryMessage();
+        historyMessage.setIsDelete(1);
+        HistoryMessageExample example = new HistoryMessageExample();
+        example.createCriteria().andSendTimeBetween(new Date(startTime * 1000), new Date(endTime * 1000));
+        historyMessageMapper.updateByExample(historyMessage, example);
+
+    }
+
+
+    private void insertHistoryMessageList(Staff staff, List<ExternalUser> externalUsers, List<MiniprogramRecord> miniprogramRecordList, Long createTime) {
+        if (CollectionUtils.isEmpty(externalUsers) || CollectionUtils.isEmpty(miniprogramRecordList)) {
+            return;
+        }
+        Long sendTime = externalUsers.stream().map(ExternalUser::getSendTime).filter(Objects::nonNull).findFirst().orElse(null);
+        List<HistoryMessage> historyMessageList = new ArrayList<>();
+        for (ExternalUser externalUser : externalUsers) {
+            Long userId = userMapper.selectIdByExternalUserId(externalUser.getExternalUserId());
+            if (userId == null) {
+                continue;
             }
-            Set<String> filterStatus = new HashSet<String>() {{
-                add("sended");
-                add("waiting_confirm");
-            }};
-            List<AlertMessage> alertMessageList = new ArrayList<>();
-            int page = total / size + 1;
-            for (int n = 0; n < page; n++) {
-                String res = getHistoryData(size, n * size, startTime, endTime);
-                log.info("selectAlertHistoryMessage size={}, n={}, startTime={}, endTime={}, res={}", size, n, startTime, endTime, res);
-                if (ObjectUtils.isEmpty(res)) {
-                    return;
-                }
-                JSONObject jsonObject = JSONObject.parseObject(res);
-                JSONArray jsonArray = jsonObject.getJSONArray("missions");
-                for (int i = 0; i < jsonArray.size(); i++) {
-                    JSONArray attachments = jsonArray.getJSONObject(i).getJSONObject("msg_data").getJSONArray("attachments");
-                    List<Long> videoIds = new ArrayList<>();
-                    for (int j = 0; j < attachments.size(); j++) {
-                        String indexPage = attachments.getJSONObject(j).getJSONObject("miniprogram").getString("page");
-                        Long videoId = MessageUtil.getVideoId(indexPage);
-                        videoIds.add(videoId);
-                    }
-                    JSONArray subMissionList = jsonArray.getJSONObject(i).getJSONArray("sub_mission_list");
-                    for (int k = 0; k < subMissionList.size(); k++) {
-                        if (!filterStatus.contains(subMissionList.getJSONObject(k).getString("status"))) {
-                            Long messageId = jsonArray.getJSONObject(i).getLong("id");
-                            AlertMessageExample example = new AlertMessageExample();
-                            example.createCriteria().andMessageIdEqualTo(messageId);
-                            List<AlertMessage> alertMessages = alertMessageMapper.selectByExample(example);
-                            if (!CollectionUtils.isEmpty(alertMessages)) {
-                                continue;
-                            }
-                            Long sendAt = jsonArray.getJSONObject(i).getLong("send_at");
-                            AlertMessage alertMessage = new AlertMessage();
-                            alertMessage.setMessageId(messageId);
-                            alertMessage.setVideoIds(videoIds.toString());
-                            alertMessage.setSendTime(DateUtil.getDateString(sendAt));
-                            alertMessage.setStatus(subMissionList.getJSONObject(k).getString("status"));
-                            JSONArray staffIdList = jsonArray.getJSONObject(i).getJSONArray("staff_id_list");
-                            for (int s = 0; s < staffIdList.size(); s++) {
-                                AlertMessage newAlertMessage = new AlertMessage();
-                                BeanUtils.copyProperties(alertMessage, newAlertMessage);
-                                StaffExample staffExample = new StaffExample();
-                                staffExample.createCriteria().andStaffExtIdEqualTo(staffIdList.getString(s));
-                                List<Staff> staffList = staffMapper.selectByExample(staffExample);
-                                if (CollectionUtils.isEmpty(staffList)) {
-                                    continue;
-                                }
-                                newAlertMessage.setStaffName(staffList.get(0).getRemark());
-                                alertMessageList.add(newAlertMessage);
-                                alertMessageMapper.insert(newAlertMessage);
-                            }
-                        }
+            for (MiniprogramRecord miniprogramRecord : miniprogramRecordList) {
+                Integer status = externalUser.getStatus();
+                HistoryMessage historyMessage = new HistoryMessage();
+                if (externalUser.getSendTime() != null) {
+                    historyMessage.setSendTime(new Date(externalUser.getSendTime()));
+                } else {
+                    if (sendTime != null) {
+                        historyMessage.setSendTime(new Date(sendTime));
+                    } else if (createTime != null) {
+                        historyMessage.setSendTime(new Date(createTime));
                     }
                 }
+                historyMessage.setAttachmentIdx(miniprogramRecord.getAttachmentIdx());
+                historyMessage.setVideoId(miniprogramRecord.getVideoId());
+                historyMessage.setUserId(userId);
+                historyMessage.setStaffId(staff.getId());
+                historyMessage.setStatus(status);
+                historyMessageList.add(historyMessage);
+                if (status == 2) {
+                    userService.delStaffWithUser(userId, staff.getId(), sendTime);
+                }
             }
-            if (!CollectionUtils.isEmpty(alertMessageList)) {
-                LarkRobotUtil.sendMessage(JSONArray.toJSONString(alertMessageList));
-            }
-        } catch (IOException e) {
-            log.error("selectAlertHistoryMessage error", e);
         }
+        historyMessageService.batchInsertHistoryMessage(historyMessageList);
     }
 
-}
 
+    private String getGroupMsgList(Long startTime, Long endTime, String cursor) throws IOException {
+        String accessToken = accessTokenService.getWeComAccessToken();
+        String url = POST_WE_COM_GROUP_MSG_LIST_URL
+                + "?access_token=" + accessToken;
+        JSONObject param = new JSONObject();
+        param.put("chat_type", "single");
+        param.put("start_time", startTime);
+        param.put("end_time", endTime);
+        param.put("limit", 100);
+        if (StringUtils.isNotEmpty(cursor)) {
+            param.put("cursor", cursor);
+        }
+        return httpPoolClientDefault.post(url, param.toJSONString());
+    }
 
 
+}
+
 
 
 

+ 141 - 104
we-com-server/src/main/java/com/tzld/piaoquan/wecom/job/WeComMessageDataJob.java

@@ -1,16 +1,20 @@
 package com.tzld.piaoquan.wecom.job;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.aliyun.odps.data.Record;
 import com.google.common.collect.Lists;
 import com.tzld.piaoquan.wecom.dao.mapper.*;
 import com.tzld.piaoquan.wecom.model.bo.PushMessage;
+import com.tzld.piaoquan.wecom.model.bo.VideoParam;
+import com.tzld.piaoquan.wecom.model.bo.XxlJobParam;
 import com.tzld.piaoquan.wecom.model.po.*;
+import com.tzld.piaoquan.wecom.model.vo.GuaranteedParam;
 import com.tzld.piaoquan.wecom.service.MessageAttachmentService;
 import com.tzld.piaoquan.wecom.service.MessageService;
 import com.tzld.piaoquan.wecom.utils.DateUtil;
-import com.tzld.piaoquan.wecom.utils.MessageUtil;
+import com.tzld.piaoquan.wecom.utils.LarkRobotUtil;
 import com.tzld.piaoquan.wecom.utils.OdpsUtil;
 import com.tzld.piaoquan.wecom.utils.ToolUtils;
 import com.tzld.piaoquan.wecom.utils.page.Page;
@@ -18,7 +22,6 @@ import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
@@ -28,7 +31,8 @@ import java.nio.charset.StandardCharsets;
 import java.util.*;
 import java.util.stream.Collectors;
 
-import static com.tzld.piaoquan.wecom.common.constant.RedisConstant.GUARANTEED_MINIPROGRAM_KEY;
+import static com.tzld.piaoquan.wecom.common.constant.MessageConstant.MAX_VIDEO_NUM;
+import static com.tzld.piaoquan.wecom.common.constant.RedisConstant.GUARANTEED_MINI_PROGRAM_KEY;
 import static com.tzld.piaoquan.wecom.common.constant.TimeConstant.MILLISECOND_DAY;
 
 @Log4j2
@@ -59,7 +63,6 @@ public class WeComMessageDataJob {
     @Autowired
     SendMessageMapper sendMessageMapper;
 
-    private static final int MAX_VIDEO_NUM = 3;
 
     //发送小程序标题限制字节数
     private static final int MAX_BYTES = 64;
@@ -68,17 +71,14 @@ public class WeComMessageDataJob {
     List<PushMessage> goodHistoryPushList = new ArrayList<>();
 
     //保底视频列表
-    List<Long> guaranteedVideoIdList = new ArrayList<>();
-
-    //从缓存中获取的保底视频数量
-    int getGuaranteedVideoIdNum = 0;
-
+    Map<Long, List<Long>> guaranteedVideoMap = new HashMap<>();
     Map<String, String> pageMap = new HashMap<>();
 
     //初始化操作
     void init() {
         //历史优质视频获取
-        String sql = String.format("SELECT * FROM loghubods.history_good_video_can_push_user_list where dt = %s;", DateUtil.getBeforeDayDateString());
+        String sql = String.format("SELECT * FROM loghubods.history_good_video_can_push_user_list where dt = %s;",
+                DateUtil.getBeforeDayDateString());
         List<Record> recordList = OdpsUtil.getOdpsData(sql);
         if (CollectionUtils.isEmpty(recordList)) {
             return;
@@ -94,48 +94,65 @@ public class WeComMessageDataJob {
         }
         goodHistoryPushList = list;
 
-        getGuaranteedVideoIdNum = 0;
         //保底视频获取
-        List<Long> videoIdList = Objects.requireNonNull(redisTemplate.opsForList().range(GUARANTEED_MINIPROGRAM_KEY, 0, -1))
-                .stream().map(o -> (Integer) o).map(String::valueOf).map(Long::parseLong).collect(Collectors.toList());
-        if (CollectionUtils.isEmpty(videoIdList)) {
-            log.error("推送消息初始化失败,保底数据为空");
-            throw new RuntimeException("保底数据为空");
+
+        String key = String.format(GUARANTEED_MINI_PROGRAM_KEY, DateUtil.getThatDayDateString());
+        GuaranteedParam guaranteedParam = (GuaranteedParam) redisTemplate.opsForValue().get(key);
+        if (guaranteedParam == null
+                || CollectionUtils.isEmpty(guaranteedParam.getVideoParamList())) {
+            LarkRobotUtil.sendMessage("保底视频获取异常,请检查" + DateUtil.getThatDayDateString());
+            throw new RuntimeException();
         }
-        List<Long> saveVideoIds = new ArrayList<>();
-        for (Long videoId : videoIdList) {
-            getGuaranteedVideoIdNum++;
-            MessageAttachmentExample example = new MessageAttachmentExample();
-            example.createCriteria().andMiniprogramVideoIdEqualTo(videoId);
-            List<MessageAttachment> messageAttachmentList = messageAttachmentMapper.selectByExample(example);
-            if (CollectionUtils.isEmpty(messageAttachmentList)) {
-                continue;
+        Map<Long, List<Long>> videoMap = new HashMap<>();
+        for (VideoParam videoParam : guaranteedParam.getVideoParamList()) {
+            if (videoParam.getStaffId() == null) {
+                LarkRobotUtil.sendMessage("保底视频获取异常,StaffId为空" + DateUtil.getThatDayDateString());
+                throw new RuntimeException();
             }
-            MessageAttachment messageAttachment = messageAttachmentList.get(0);
-            if (messageAttachment.getSendTime() != null
-                    && DateUtil.dateDifference(new Date(), messageAttachment.getSendTime()) < 180 * MILLISECOND_DAY) {
-                continue;
+            if (CollectionUtils.isEmpty(videoParam.getVideoIds()) || videoParam.getVideoIds().size() < MAX_VIDEO_NUM) {
+                LarkRobotUtil.sendMessage("保底视频数量异常,请查看" + guaranteedParam.getDate() + videoParam.getStaffId());
+                throw new RuntimeException();
             }
-            saveVideoIds.add(videoId);
-            if (saveVideoIds.size() >= MAX_VIDEO_NUM) {
-                break;
+            for (Long videoId : videoParam.getVideoIds()) {
+                MessageAttachmentExample example = new MessageAttachmentExample();
+                example.createCriteria().andMiniprogramVideoIdEqualTo(videoId);
+                List<MessageAttachment> messageAttachmentList = messageAttachmentMapper.selectByExample(example);
+                if (CollectionUtils.isEmpty(messageAttachmentList)) {
+                    LarkRobotUtil.sendMessage("保底视频不存在,请查看videoId=" + videoId);
+                    throw new RuntimeException();
+                }
+                MessageAttachment messageAttachment = messageAttachmentList.get(0);
+                if (messageAttachment.getSendTime() != null
+                        && DateUtil.dateDifference(new Date(), messageAttachment.getSendTime()) < 180 * MILLISECOND_DAY) {
+                    LarkRobotUtil.sendMessage("保底视频半年内已发送,请查看videoId=" + videoId);
+                    throw new RuntimeException();
+                }
             }
+            videoMap.put(videoParam.getStaffId(), videoParam.getVideoIds());
         }
-        if (saveVideoIds.size() < MAX_VIDEO_NUM) {
-            log.error("推送消息初始化失败,保底数据不足");
-            throw new RuntimeException("保底数据不足");
+        if (!videoMap.containsKey(0L)) {
+            LarkRobotUtil.sendMessage("保底视频没有默认组,请查看" + guaranteedParam.getDate());
+            throw new RuntimeException();
         }
-        guaranteedVideoIdList = saveVideoIds;
+        this.guaranteedVideoMap = videoMap;
     }
 
     @XxlJob("assembleSendMessageJob")
     public ReturnT<String> assembleSendMessage(String param) {
+        XxlJobParam xxlJobParam = new XxlJobParam();
+        if (StringUtils.isNotEmpty(param)) {
+            xxlJobParam = JSONObject.parseObject(param, XxlJobParam.class);
+        }
         init();
         Long staffId = null;
-        if (StringUtils.isNotEmpty(param)) {
-            staffId = Long.parseLong(param);
+        if (xxlJobParam != null && xxlJobParam.getStaffId() != null) {
+            staffId = xxlJobParam.getStaffId();
         }
         UserExample example = new UserExample();
+        example.createCriteria().andExternalUserIdIsNotNull();
+        if (xxlJobParam != null && xxlJobParam.getUserId() != null) {
+            example.createCriteria().andIdEqualTo(xxlJobParam.getUserId());
+        }
         long count = userMapper.countByExample(example);
         int page = 1;
         int pageSize = 1000;
@@ -159,11 +176,24 @@ public class WeComMessageDataJob {
             }
         }
         //组装好当天要发送的消息后  记录时间  删除保底数据
-        saveGuaranteedVideoIdList(guaranteedVideoIdList);
+        saveGuaranteedVideoIdList();
         return ReturnT.SUCCESS;
     }
 
-    public void saveGuaranteedVideoIdList(List<Long> videoIdList) {
+    public void saveGuaranteedVideoIdList() {
+        String key = String.format(GUARANTEED_MINI_PROGRAM_KEY, DateUtil.getThatDayDateString());
+        GuaranteedParam guaranteedParam = (GuaranteedParam) redisTemplate.opsForValue().get(key);
+        if (guaranteedParam == null || CollectionUtils.isEmpty(guaranteedParam.getVideoParamList())) {
+            return;
+        }
+        List<Long> videoIdList = new ArrayList<>();
+        for (VideoParam videoParam : guaranteedParam.getVideoParamList()) {
+            if (CollectionUtils.isEmpty(videoParam.getVideoIds())) {
+                continue;
+            }
+            videoIdList.addAll(videoParam.getVideoIds());
+        }
+
         MessageAttachmentExample example = new MessageAttachmentExample();
         example.createCriteria().andMiniprogramVideoIdIn(videoIdList);
         List<MessageAttachment> messageAttachmentList = messageAttachmentMapper.selectByExample(example);
@@ -173,72 +203,75 @@ public class WeComMessageDataJob {
             updateMessageAttachment.setSendTime(new Date());
             messageAttachmentMapper.updateByPrimaryKeySelective(updateMessageAttachment);
         }
-        log.info("getGuaranteedVideoIdNum={}", getGuaranteedVideoIdNum);
-        //移除从redis中获取的保底数据
-        for (int i = 0; i < getGuaranteedVideoIdNum; i++) {
-            redisTemplate.opsForList().leftPop(GUARANTEED_MINIPROGRAM_KEY);
-        }
+        redisTemplate.delete(key);
     }
 
     public List<SendMessage> getSendMessage(User user, Long staffId) {
         StaffWithUserExample example = new StaffWithUserExample();
         StaffWithUserExample.Criteria criteria = example.createCriteria();
         criteria.andUserIdEqualTo(user.getId());
+        criteria.andIsDeleteEqualTo(0);
         if (staffId != null) {
-            criteria.andUserIdEqualTo(staffId);
+            criteria.andStaffIdEqualTo(staffId);
         }
         List<StaffWithUser> staffWithUserList = staffWithUserMapper.selectByExample(example);
         if (CollectionUtils.isEmpty(staffWithUserList)) {
             return null;
         }
-        int n = 0;
         List<SendMessage> sendMessageList = new ArrayList<>();
-        SendMessage sendMessage = new SendMessage();
-        for (PushMessage pushMessage : goodHistoryPushList) {
-            if (pushMessage.getUserIds().contains(user.getId())) {
-                if (n == 0) {
-                    sendMessage.setVideoId1(pushMessage.getVideoId());
-                }
-                if (n == 1) {
-                    sendMessage.setVideoId2(pushMessage.getVideoId());
-                }
-                if (n == 2) {
-                    sendMessage.setVideoId3(pushMessage.getVideoId());
-                }
-                n++;
-                if (n >= MAX_VIDEO_NUM) {
-                    break;
+        for (StaffWithUser staffWithUser : staffWithUserList) {
+            int n = 0;
+            SendMessage sendMessage = new SendMessage();
+            for (PushMessage pushMessage : goodHistoryPushList) {
+                if (pushMessage.getUserIds().contains(user.getId())) {
+                    if (n == 0) {
+                        sendMessage.setVideoId1(pushMessage.getVideoId());
+                    }
+                    if (n == 1) {
+                        sendMessage.setVideoId2(pushMessage.getVideoId());
+                    }
+                    if (n == 2) {
+                        sendMessage.setVideoId3(pushMessage.getVideoId());
+                    }
+                    n++;
+                    if (n >= MAX_VIDEO_NUM) {
+                        break;
+                    }
                 }
             }
-        }
-        //保底数据
-        if (n < MAX_VIDEO_NUM) {
-            for (Long videoId : guaranteedVideoIdList) {
-                if (n == 0) {
-                    sendMessage.setVideoId1(videoId);
-                }
-                if (n == 1) {
-                    sendMessage.setVideoId2(videoId);
-                }
-                if (n == 2) {
-                    sendMessage.setVideoId3(videoId);
-                }
-                n++;
-                if (n >= MAX_VIDEO_NUM) {
-                    break;
+            //保底数据
+            List<Long> guaranteedVideoIdList = guaranteedVideoMap.get(staffWithUser.getStaffId());
+            if (CollectionUtils.isEmpty(guaranteedVideoIdList)) {
+                guaranteedVideoIdList = guaranteedVideoMap.get(0L);
+            }
+            if (CollectionUtils.isEmpty(guaranteedVideoIdList)) {
+                LarkRobotUtil.sendMessage("组装数据时,保底数据获取异常");
+                throw new RuntimeException();
+            }
+            if (n < MAX_VIDEO_NUM) {
+                for (Long videoId : guaranteedVideoIdList) {
+                    if (n == 0) {
+                        sendMessage.setVideoId1(videoId);
+                    }
+                    if (n == 1) {
+                        sendMessage.setVideoId2(videoId);
+                    }
+                    if (n == 2) {
+                        sendMessage.setVideoId3(videoId);
+                    }
+                    n++;
+                    if (n >= MAX_VIDEO_NUM) {
+                        break;
+                    }
                 }
             }
-        }
-        if (n < MAX_VIDEO_NUM) {
-            log.error("组装数据失败 user={}", user);
-            return null;
-        }
-        for (StaffWithUser staffWithUser : staffWithUserList) {
-            SendMessage newSendMessage = new SendMessage();
-            BeanUtils.copyProperties(sendMessage, newSendMessage);
-            newSendMessage.setStaffId(staffWithUser.getStaffId());
-            newSendMessage.setUserId(staffWithUser.getUserId());
-            sendMessageList.add(newSendMessage);
+            if (n < MAX_VIDEO_NUM) {
+                LarkRobotUtil.sendMessage("组装数据失败 user=" + user);
+                throw new RuntimeException();
+            }
+            sendMessage.setStaffId(staffWithUser.getStaffId());
+            sendMessage.setUserId(staffWithUser.getUserId());
+            sendMessageList.add(sendMessage);
         }
         return sendMessageList;
     }
@@ -256,7 +289,7 @@ public class WeComMessageDataJob {
         for (SendMessage sendMessage : groupList) {
             sendMessage.setIsSend(0);
             sendMessage.setCreateTime(DateUtil.getThatDayDate());
-            List<String> sendUserList = sendMessageMapper.selectExternalUserId3rdParty(sendMessage);
+            List<String> sendUserList = sendMessageMapper.selectExternalUserId(sendMessage);
             boolean flag = pushMessage(sendUserList, sendMessage);
             if (flag) {
                 SendMessage updateSendMessage = new SendMessage();
@@ -275,18 +308,20 @@ public class WeComMessageDataJob {
         return ReturnT.SUCCESS;
     }
 
+
     public boolean pushMessage(List<String> sendUserList, SendMessage sendMessage) {
         List<JSONObject> pushList = new ArrayList<>();
         StaffExample staffExample = new StaffExample();
         staffExample.createCriteria().andIdEqualTo(sendMessage.getStaffId());
         List<Staff> staffList = staffMapper.selectByExample(staffExample);
         Staff staff = staffList.get(0);
-        String text = messageService.getMessageText();
-        String name = MessageUtil.getName(staff.getRemark());
-
         JSONObject jsonObject = new JSONObject();
-        jsonObject.put("name", name);
+        jsonObject.put("chat_type", "single");
+        JSONObject text = new JSONObject();
+        String content = messageService.getMessageText();
+        text.put("content", content);
         jsonObject.put("text", text);
+        jsonObject.put("sender", staff.getCarrierId());
         JSONArray attachments = new JSONArray();
         List<Long> videoIdList = new ArrayList<>();
         videoIdList.add(sendMessage.getVideoId1());
@@ -309,9 +344,14 @@ public class WeComMessageDataJob {
                 title = ToolUtils.truncateString(title, MAX_BYTES - 3) + "...";
             }
             miniprogram.put("title", title);
-            miniprogram.put("cover", messageAttachment.getCover());
+            String picMediaId = messageAttachmentService.getPicMediaId(messageAttachment.getCover());
+            if (StringUtils.isEmpty(picMediaId)) {
+                log.error("pushMessage getPicMediaId error cover={}", messageAttachment.getCover());
+                return false;
+            }
+            miniprogram.put("pic_media_id", picMediaId);
             String page = "";
-            String key = staff.getStaffExtId() + "_" + videoId;
+            String key = staff.getCarrierId() + "_" + videoId;
             if (pageMap.containsKey(key)) {
                 page = pageMap.get(key);
             } else {
@@ -319,24 +359,20 @@ public class WeComMessageDataJob {
                 pageMap.put(key, page);
             }
             if (StringUtils.isEmpty(page)) {
-                throw new RuntimeException("获取page失败");
+                log.error("pushMessage get page error videoId={} staff={}", videoId, staff);
+                return false;
             }
             miniprogram.put("page", page);
-
             attachment.put("miniprogram", miniprogram);
             attachments.add(0, attachment);
         }
         jsonObject.put("attachments", attachments);
         List<List<String>> lists = Lists.partition(sendUserList, 10000);
         for (List<String> list : lists) {
-            List<JSONObject> staffEuList = new ArrayList<>();
+            JSONArray externalUserIds = JSONArray.parseArray(JSON.toJSONString(list));
             JSONObject newJSONObject = new JSONObject();
             newJSONObject.putAll(jsonObject);
-            JSONObject staff_eu = new JSONObject();
-            staff_eu.put("staff_ext_id", staff.getStaffExtId());
-            staff_eu.put("eu_ext_ids", list);
-            staffEuList.add(staff_eu);
-            newJSONObject.put("staff_eu_list", staffEuList);
+            newJSONObject.put("external_userid", externalUserIds);
             pushList.add(newJSONObject);
         }
         if (CollectionUtils.isEmpty(pushList)) {
@@ -344,7 +380,7 @@ public class WeComMessageDataJob {
         }
         for (JSONObject pushJsonObject : pushList) {
             log.info("pushMessage pushJsonObject={}", pushJsonObject);
-            boolean flag = messageService.pushMessage(pushJsonObject);
+            boolean flag = messageService.pushWeComMessage(pushJsonObject);
             if (!flag) {
                 return flag;
             }
@@ -352,4 +388,5 @@ public class WeComMessageDataJob {
         return true;
     }
 
+
 }

+ 71 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/job/WeComStaffDataJob.java

@@ -0,0 +1,71 @@
+package com.tzld.piaoquan.wecom.job;
+
+import com.alibaba.fastjson.JSONObject;
+import com.tzld.piaoquan.wecom.dao.mapper.StaffMapper;
+import com.tzld.piaoquan.wecom.model.po.Staff;
+import com.tzld.piaoquan.wecom.model.po.StaffExample;
+import com.tzld.piaoquan.wecom.service.AccessTokenService;
+import com.tzld.piaoquan.wecom.utils.HttpClientUtil;
+import com.tzld.piaoquan.wecom.utils.HttpPoolClient;
+import com.tzld.piaoquan.wecom.utils.LarkRobotUtil;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.tzld.piaoquan.wecom.common.constant.WeComConstant.GET_WE_COM_FOLLOW_USER_LIST;
+
+@Slf4j
+@Component
+public class WeComStaffDataJob {
+
+    private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(30000, 30000, 2000, 5000, 5, 30000);
+
+
+    @Autowired
+    private AccessTokenService accessTokenService;
+
+    @Autowired
+    private StaffMapper staffMapper;
+
+    @XxlJob("insertStaffJob")
+    public ReturnT<String> insertStaff(String param) {
+        try {
+            List<String> carrierIdList = getCarrierIdList();
+            for (String carrierId : carrierIdList) {
+                StaffExample example = new StaffExample();
+                example.createCriteria().andCarrierIdEqualTo(carrierId);
+                List<Staff> staffList = staffMapper.selectByExample(example);
+                if (CollectionUtils.isEmpty(staffList)) {
+                    Staff staff = new Staff();
+                    staff.setCarrierId(carrierId);
+                    staff.setRemark("");
+                    staffMapper.insert(staff);
+                }
+            }
+        } catch (Exception e) {
+            LarkRobotUtil.sendMessage("更新员工失败");
+            log.error("insertStaff error", e);
+        }
+        return ReturnT.SUCCESS;
+    }
+
+    public List<String> getCarrierIdList() throws IOException {
+        String weComAccessToken = accessTokenService.getWeComAccessToken();
+        String url = String.format(GET_WE_COM_FOLLOW_USER_LIST + "?access_token=%s", weComAccessToken);
+        String res = httpPoolClientDefault.get(url);
+        JSONObject jsonObject = JSONObject.parseObject(res);
+        Integer errcode = jsonObject.getInteger("errcode");
+        if (errcode == 0) {
+            return jsonObject.getJSONArray("follow_user").stream().map(String::valueOf).collect(Collectors.toList());
+        }
+        return null;
+    }
+
+}

+ 125 - 223
we-com-server/src/main/java/com/tzld/piaoquan/wecom/job/WeComUserDataJob.java

@@ -2,28 +2,28 @@ package com.tzld.piaoquan.wecom.job;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
-import com.tzld.piaoquan.wecom.common.constant.TimeConstant;
 import com.tzld.piaoquan.wecom.dao.mapper.StaffMapper;
 import com.tzld.piaoquan.wecom.dao.mapper.StaffWithUserMapper;
 import com.tzld.piaoquan.wecom.dao.mapper.UserMapper;
 import com.tzld.piaoquan.wecom.model.bo.XxlJobParam;
 import com.tzld.piaoquan.wecom.model.po.*;
 import com.tzld.piaoquan.wecom.service.AccessTokenService;
+import com.tzld.piaoquan.wecom.service.UserService;
 import com.tzld.piaoquan.wecom.utils.HttpClientUtil;
 import com.tzld.piaoquan.wecom.utils.HttpPoolClient;
+import com.tzld.piaoquan.wecom.utils.LarkRobotUtil;
 import com.tzld.piaoquan.wecom.utils.page.Page;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import static com.tzld.piaoquan.wecom.common.constant.WeComConstant.*;
 
@@ -33,118 +33,16 @@ public class WeComUserDataJob {
 
     private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(30000, 30000, 2000, 5000, 5, 30000);
 
-    final int size = 100;
-
+    @Autowired
+    private StaffMapper staffMapper;
     @Autowired
     private UserMapper userMapper;
-
     @Autowired
     private AccessTokenService accessTokenService;
-
-    @Autowired
-    private StaffMapper staffMapper;
-
     @Autowired
     private StaffWithUserMapper staffWithUserMapper;
-
-    @XxlJob("insertStaffWithUserJob")
-    public ReturnT<String> insertStaffWithUser(String param) {
-        XxlJobParam xxlJobParam = new XxlJobParam();
-        if (StringUtils.isNotEmpty(param)) {
-            xxlJobParam = JSONObject.parseObject(param, XxlJobParam.class);
-        }
-        if (xxlJobParam.getStartTime() == null) {
-            xxlJobParam.setStartTime(1720540800L);
-        }
-        if (xxlJobParam.getEndTime() == null) {
-            xxlJobParam.setEndTime(System.currentTimeMillis() / 1000);
-        }
-        StaffExample example = new StaffExample();
-        StaffExample.Criteria criteria = example.createCriteria();
-        if (xxlJobParam.getStaffId() != null) {
-            criteria.andIdEqualTo(xxlJobParam.getStaffId());
-        }
-        List<Staff> staffList = staffMapper.selectByExample(example);
-        for (Staff staff : staffList) {
-            insertAllUser(xxlJobParam.getStartTime(), xxlJobParam.getEndTime(), staff);
-        }
-        return ReturnT.SUCCESS;
-    }
-
-    //初始化用户使用此任务
-    private void insertAllUser(long startTime, long endTime, Staff staff) {
-        try {
-            Integer total = getUserTotal(startTime, endTime, staff.getStaffExtId());
-            if (total == null || total == 0) {
-                return;
-            }
-            int page = total / size + 1;
-            int sum = 0;
-            for (int i = 0; i < page; i++) {
-                String res = getUser(size, i * size, startTime, endTime, staff.getStaffExtId());
-                log.info("insertAllUser size={}, i={}, staffExtId = {}, startTime={}, endTime={}, res={}", size, i, staff.getStaffExtId(), startTime, endTime, res);
-                if (ObjectUtils.isEmpty(res)) {
-                    continue;
-                }
-                JSONObject jsonObject = JSONObject.parseObject(res);
-                JSONArray jsonArray = jsonObject.getJSONArray("external_user_list");
-                List<StaffWithUser> insertStaffWithUserList = new ArrayList<>();
-                for (int j = 0; j < jsonArray.size(); j++) {
-                    String externalUserId3rdParty = (String) jsonArray.getJSONObject(j).get("id");
-                    Long userId = userMapper.selectIdByExternalUserId3rdParty(externalUserId3rdParty);
-                    if (userId == null) {
-                        jsonArray.getJSONObject(j).put("id", null);
-                        User user = jsonArray.getJSONObject(j).toJavaObject(User.class);
-                        user.setExternalUserId3rdParty(externalUserId3rdParty);
-                        userMapper.insert(user);
-                        userId = user.getId();
-                    }
-                    if (userId == null) {
-                        System.out.println("插入数据异常:" + jsonArray.getJSONObject(j));
-                        continue;
-                    }
-                    StaffWithUserExample staffWithUserExample = new StaffWithUserExample();
-                    staffWithUserExample.createCriteria().andStaffIdEqualTo(staff.getId()).andUserIdEqualTo(userId);
-                    List<StaffWithUser> staffWithUserList = staffWithUserMapper.selectByExample(staffWithUserExample);
-                    if (CollectionUtils.isEmpty(staffWithUserList)) {
-                        StaffWithUser staffWithUser = new StaffWithUser();
-                        staffWithUser.setUserId(userId);
-                        staffWithUser.setStaffId(staff.getId());
-                        insertStaffWithUserList.add(staffWithUser);
-                    }
-                    sum++;
-                }
-                if (!CollectionUtils.isEmpty(insertStaffWithUserList)) {
-                    staffWithUserMapper.insertList(insertStaffWithUserList);
-                }
-                if (jsonArray.size() < size) {
-                    break;
-                }
-            }
-            if (total > sum) {
-                log.error("insertAllUser插入数量不足 total = {}, sum={}", total, sum);
-            }
-        } catch (Exception e) {
-            log.error("insertAllUser error", e);
-        }
-    }
-
-    private Integer getUserTotal(Long startTime, Long endTime, String staffId) throws IOException {
-        String res = getUser(1, 0, startTime, endTime, staffId);
-        JSONObject jsonObject = JSONObject.parseObject(res);
-        return jsonObject.getInteger("total");
-    }
-
-    private String getUser(Integer limit, Integer offset, Long startTime, Long endTime, String staffExtId) throws IOException {
-        String accessToken = accessTokenService.getAccessToken();
-        String url = GET_USER_URL
-                + "?access_token=" + accessToken
-                + "&limit=" + limit + "&offset=" + offset + "&start_time=" + startTime + "&end_time=" + endTime;
-        if (StringUtils.isNotEmpty(staffExtId)) {
-            url = url + "&staff_id=" + staffExtId;
-        }
-        return httpPoolClientDefault.get(url);
-    }
+    @Autowired
+    private UserService userService;
 
     @XxlJob("updateStaffWithUserJob")
     public ReturnT<String> updateStaffWithUser(String param) {
@@ -152,16 +50,6 @@ public class WeComUserDataJob {
         if (StringUtils.isNotEmpty(param)) {
             xxlJobParam = JSONObject.parseObject(param, XxlJobParam.class);
         }
-        if (xxlJobParam.getStartTime() == null) {
-            UserExample userExample = new UserExample();
-            userExample.setOrderByClause("create_time desc");
-            userExample.setPage(new Page<>(1, 1));
-            List<User> userList = userMapper.selectByExample(userExample);
-            xxlJobParam.setStartTime(userList.get(0).getCreateTime().getTime() / 1000 - 2L * TimeConstant.HOUR);
-        }
-        if (xxlJobParam.getEndTime() == null) {
-            xxlJobParam.setEndTime(System.currentTimeMillis() / 1000);
-        }
         StaffExample example = new StaffExample();
         StaffExample.Criteria criteria = example.createCriteria();
         if (xxlJobParam.getStaffId() != null) {
@@ -169,43 +57,52 @@ public class WeComUserDataJob {
         }
         List<Staff> staffList = staffMapper.selectByExample(example);
         for (Staff staff : staffList) {
-            updateUser(xxlJobParam.getStartTime(), xxlJobParam.getEndTime(), staff);
+            updateUserList(staff);
         }
         return ReturnT.SUCCESS;
     }
 
 
-    private void updateUser(long startTime, long endTime, Staff staff) {
+    private void updateUserList(Staff staff) {
         try {
-            Integer total = getUpdateUserTotal(startTime, endTime, staff.getStaffExtId());
-            if (total == null || total == 0) {
-                return;
-            }
-            int page = total / size + 1;
-            int sum = 0;
-            for (int i = 0; i < page; i++) {
-                String res = getUpdateUser(size, i * size, startTime, endTime, staff.getStaffExtId());
-                log.info("updateUser size={}, i={}, staffExtId = {}, startTime={}, endTime={}, res={}", size, i, staff.getStaffExtId(), startTime, endTime, res);
-                if (ObjectUtils.isEmpty(res)) {
-                    continue;
-                }
+            String cursor = "";
+            do {
+                String res = getUserDetailList(staff.getCarrierId(), cursor);
+                log.info("updateUserList res={} cursor={}", res, cursor);
                 JSONObject jsonObject = JSONObject.parseObject(res);
-                JSONArray jsonArray = jsonObject.getJSONArray("external_user_list");
-                for (int j = 0; j < jsonArray.size(); j++) {
-                    String id = (String) jsonArray.getJSONObject(j).get("id");
-                    jsonArray.getJSONObject(j).put("id", null);
-                    User user = jsonArray.getJSONObject(j).toJavaObject(User.class);
-                    user.setExternalUserId3rdParty(id);
+                Integer errCode = jsonObject.getInteger("errcode");
+                if (errCode != 0) {
+                    log.error("updateUserList error carrierId={} cursor={}", staff.getCarrierId(), cursor);
+                    return;
+                }
+                JSONArray externalContactList = jsonObject.getJSONArray("external_contact_list");
+                for (int i = 0; i < externalContactList.size(); i++) {
+                    JSONObject externalContact = externalContactList.getJSONObject(i).getJSONObject("external_contact");
+                    JSONObject followInfo = externalContactList.getJSONObject(i).getJSONObject("follow_info");
+                    Long createAt = followInfo.getLong("createtime");
+                    String externalUserId = externalContact.getString("external_userid");
+                    String name = externalContact.getString("name");
+                    String unionId = externalContact.getString("unionid");
+                    String avatar = externalContact.getString("avatar");
+                    Integer type = externalContact.getInteger("type");
+                    Integer gender = externalContact.getInteger("gender");
                     UserExample example = new UserExample();
-                    example.createCriteria().andExternalUserId3rdPartyEqualTo(user.getExternalUserId3rdParty());
-                    List<User> list = userMapper.selectByExample(example);
+                    example.createCriteria().andExternalUserIdEqualTo(externalUserId);
+                    List<User> userList = userMapper.selectByExample(example);
+                    User user = new User();
+                    user.setExternalUserId(externalUserId);
+                    user.setName(name);
+                    user.setType(type);
+                    user.setUnionId(unionId);
+                    user.setGender(gender);
+                    user.setAvatar(avatar);
+                    user.setCreatedAt(createAt);
                     Long userId;
-                    if (CollectionUtils.isEmpty(list)) {
-                        //没有用户,走插入逻辑
+                    if (CollectionUtils.isEmpty(userList)) {
                         userMapper.insert(user);
                         userId = user.getId();
                     } else {
-                        User oldUser = list.get(0);
+                        User oldUser = userList.get(0);
                         user.setId(oldUser.getId());
                         userMapper.updateByPrimaryKeySelective(user);
                         userId = oldUser.getId();
@@ -222,115 +119,120 @@ public class WeComUserDataJob {
                         staffWithUser.setUserId(userId);
                         staffWithUserMapper.insert(staffWithUser);
                     }
-                    sum++;
                 }
-                if (jsonArray.size() < size) {
+                String nextCursor = jsonObject.getString("next_cursor");
+                if (cursor.equals(nextCursor)) {
                     break;
                 }
-            }
-
-            if (total > sum) {
-                log.error("updateUser插入数量不足 total = {}, sum={}", total, sum);
-            }
+                cursor = nextCursor;
+            } while (StringUtils.isNotEmpty(cursor));
         } catch (IOException e) {
+            LarkRobotUtil.sendMessage("updateUser error" + e);
             log.error("updateUser error", e);
         }
     }
 
-    private Integer getUpdateUserTotal(Long startTime, Long endTime, String staffExtId) throws IOException {
-        String res = getUpdateUser(1, 0, startTime, endTime, staffExtId);
-        JSONObject jsonObject = JSONObject.parseObject(res);
-        return jsonObject.getInteger("total");
+    private String getUserDetailList(String userId, String cursor) throws IOException {
+        String accessToken = accessTokenService.getWeComAccessToken();
+        String url = POST_WE_COM_GET_BY_USER
+                + "?access_token=" + accessToken;
+        JSONObject param = new JSONObject();
+        JSONArray userIdList = new JSONArray();
+        userIdList.add(userId);
+        param.put("userid_list", userIdList);
+        param.put("limit", 100);
+        if (StringUtils.isNotEmpty(cursor)) {
+            param.put("cursor", cursor);
+        }
+        return httpPoolClientDefault.post(url, param.toJSONString());
     }
 
-    private String getUpdateUser(Integer limit, Integer offset, Long startTime, Long endTime, String staffExtId) throws IOException {
-        String accessToken = accessTokenService.getAccessToken();
-        String url = UPDATE_USER_URL
-                + "?access_token=" + accessToken
-                + "&limit=" + limit + "&offset=" + offset + "&start_update_time=" + startTime + "&end_update_time=" + endTime
-                + "&source=external_user";
-        if (StringUtils.isNotEmpty(staffExtId)) {
-            url = url + "&staff_id=" + staffExtId;
+    @XxlJob("insertStaffWithUserJob")
+    public ReturnT<String> insertStaffWithUserJob(String param) {
+        try {
+            StaffExample example = new StaffExample();
+            List<Staff> staffList = staffMapper.selectByExample(example);
+            for (Staff staff : staffList) {
+                List<String> externalUserIds = getUserList(staff.getCarrierId());
+                if (CollectionUtils.isEmpty(externalUserIds)) {
+                    continue;
+                }
+                for (String externalUserId : externalUserIds) {
+                    userService.insertStaffWithUser(externalUserId, staff);
+                }
+            }
+        } catch (Exception e) {
+            LarkRobotUtil.sendMessage("insertStaffWithUserJob error" + e);
+            log.error("insertStaffWithUserJob error", e);
         }
-        return httpPoolClientDefault.get(url);
-    }
 
+        return ReturnT.SUCCESS;
 
-    @XxlJob("deleteUserJob")
-    public ReturnT<String> deleteUserJob(String param) {
-        XxlJobParam xxlJobParam = new XxlJobParam();
-        if (StringUtils.isNotEmpty(param)) {
-            xxlJobParam = JSONObject.parseObject(param, XxlJobParam.class);
-        }
-        if (xxlJobParam.getStartTime() == null) {
-            UserExample userExample = new UserExample();
-            userExample.createCriteria().andIsDeleteEqualTo(1);
-            userExample.setOrderByClause("deleted_at desc");
-            userExample.setPage(new Page<>(1, 1));
-            List<User> userList = userMapper.selectByExample(userExample);
-            if (CollectionUtils.isEmpty(userList)) {
-                xxlJobParam.setStartTime(1720540800L);
-            } else {
-                xxlJobParam.setStartTime(userList.get(0).getDeletedAt());
-            }
-        }
-        if (xxlJobParam.getEndTime() == null) {
-            xxlJobParam.setEndTime(System.currentTimeMillis() / 1000);
+    }
+
+    public List<String> getUserList(String userId) throws IOException {
+        String weComAccessToken = accessTokenService.getWeComAccessToken();
+        String url = String.format(GET_WE_COM_EXTERNAL_CONTACT_LIST + "?access_token=%s&userid=%s", weComAccessToken, userId);
+        String res = httpPoolClientDefault.get(url);
+        JSONObject jsonObject = JSONObject.parseObject(res);
+        Integer errcode = jsonObject.getInteger("errcode");
+        if (errcode == 0) {
+            return jsonObject.getJSONArray("external_userid").stream().map(String::valueOf).collect(Collectors.toList());
         }
-        deleteUser(xxlJobParam.getStartTime(), xxlJobParam.getEndTime());
-        return ReturnT.SUCCESS;
+        return null;
     }
 
-    //查询删除用户并更新
-    private void deleteUser(long startTime, long endTime) {
+
+    @XxlJob("setExternalUserIdJob")
+    public ReturnT<String> setExternalUserId(String param) {
         try {
-            Integer total = getDeleteUserTotal(startTime, endTime);
-            if (total == null || total == 0) {
-                return;
+            UserExample example = new UserExample();
+            if (StringUtils.isNotEmpty(param)) {
+                example.createCriteria().andIdGreaterThanOrEqualTo(Long.parseLong(param));
             }
-            int page = total / size + 1;
-            int sum = 0;
-            for (int i = 0; i < page; i++) {
-                String res = getDeleteUser(size, i * size, startTime, endTime);
-                log.info("deleteUser size={}, i={}, startTime={}, endTime={}, res={}", size, i, startTime, endTime, res);
-                if (ObjectUtils.isEmpty(res)) {
+            long count = userMapper.countByExample(example);
+            int page = 1;
+            int pageSize = 1000;
+            long totalPageSize = count / pageSize + 1;
+            for (; page <= totalPageSize; page++) {
+                example.setPage(new Page<>(page, pageSize));
+                List<User> userList = userMapper.selectByExample(example);
+                if (CollectionUtils.isEmpty(userList)) {
                     continue;
                 }
-                JSONObject jsonObject = JSONObject.parseObject(res);
-                JSONArray jsonArray = jsonObject.getJSONArray("external_user_list");
-                for (int j = 0; j < jsonArray.size(); j++) {
-                    JSONObject staffRelation = jsonArray.getJSONObject(j).getJSONObject("staff_relation");
-                    Long deletedAt = staffRelation.getLong("deleted_at");
-                    String externalUserId3rdParty = staffRelation.getString("external_user_ext_id");
-                    Long userId = userMapper.selectIdByExternalUserId3rdParty(externalUserId3rdParty);
+                for (User user : userList) {
+                    String externalUserId3rdParty = user.getExternalUserId3rdParty();
+                    String externalUserId = getExternalUserId(externalUserId3rdParty);
+                    if (StringUtils.isEmpty(externalUserId)) {
+                        continue;
+                    }
                     User updateUser = new User();
-                    updateUser.setId(userId);
-                    updateUser.setIsDelete(1);
-                    updateUser.setDeletedAt(deletedAt);
+                    updateUser.setId(user.getId());
+                    updateUser.setExternalUserId(externalUserId);
                     userMapper.updateByPrimaryKeySelective(updateUser);
-                    sum++;
                 }
             }
-            if (total > sum) {
-                log.error("deleteUser数量不足 total = {}, sum={}", total, sum);
-            }
         } catch (Exception e) {
-            log.error("deleteUser error", e);
+            log.error("setExternalUserId error", e);
         }
+
+        return ReturnT.SUCCESS;
     }
 
-    private Integer getDeleteUserTotal(Long startTime, Long endTime) throws IOException {
-        String res = getDeleteUser(1, 0, startTime, endTime);
+    public String getExternalUserId(String externalUserId3rdParty) throws IOException {
+        String weComAccessToken = accessTokenService.getWeComAccessToken();
+        String url = String.format(POST_WE_COM_EXTERNAL_USER_ID + "?access_token=%s", weComAccessToken);
+        JSONObject param = new JSONObject();
+        param.put("external_userid", externalUserId3rdParty);
+        param.put("source_agentid", 1000009);
+        String res = httpPoolClientDefault.post(url, param.toJSONString());
         JSONObject jsonObject = JSONObject.parseObject(res);
-        return jsonObject.getInteger("total_count");
+        Integer errcode = jsonObject.getInteger("errcode");
+        if (errcode == 0) {
+            return jsonObject.getString("external_userid");
+        }
+        return null;
     }
 
-    private String getDeleteUser(Integer limit, Integer offset, Long startTime, Long endTime) throws IOException {
-        String accessToken = accessTokenService.getAccessToken();
-        String url = GET_DELETE_USER_URL
-                + "?access_token=" + accessToken
-                + "&limit=" + limit + "&offset=" + offset + "&start_time=" + startTime + "&end_time=" + endTime;
-        return httpPoolClientDefault.get(url);
-    }
 
 }

+ 13 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/bo/ExternalUser.java

@@ -0,0 +1,13 @@
+package com.tzld.piaoquan.wecom.model.bo;
+
+import lombok.Data;
+
+@Data
+public class ExternalUser {
+
+    private String externalUserId;
+
+    private Integer status;
+
+    private Long sendTime;
+}

+ 13 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/bo/SendDetail.java

@@ -0,0 +1,13 @@
+package com.tzld.piaoquan.wecom.model.bo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class SendDetail {
+
+    private String remark;
+
+    private List<Long> sendCountList;
+}

+ 14 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/bo/VideoParam.java

@@ -0,0 +1,14 @@
+package com.tzld.piaoquan.wecom.model.bo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class VideoParam {
+
+    private Long staffId;
+
+    private List<Long> videoIds;
+
+}

+ 2 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/bo/XxlJobParam.java

@@ -10,4 +10,6 @@ public class XxlJobParam {
     private Long endTime;
 
     private Long staffId;
+
+    private Long userId;
 }

+ 33 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/po/HistoryMessage.java

@@ -7,14 +7,20 @@ public class HistoryMessage {
 
     private Long userId;
 
+    private Long staffId;
+
     private Long videoId;
 
     private Integer attachmentIdx;
 
     private Long messageId;
 
+    private Integer status;
+
     private Date sendTime;
 
+    private Integer isDelete;
+
     private Date createTime;
 
     public Long getId() {
@@ -33,6 +39,14 @@ public class HistoryMessage {
         this.userId = userId;
     }
 
+    public Long getStaffId() {
+        return staffId;
+    }
+
+    public void setStaffId(Long staffId) {
+        this.staffId = staffId;
+    }
+
     public Long getVideoId() {
         return videoId;
     }
@@ -57,6 +71,14 @@ public class HistoryMessage {
         this.messageId = messageId;
     }
 
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
     public Date getSendTime() {
         return sendTime;
     }
@@ -65,6 +87,14 @@ public class HistoryMessage {
         this.sendTime = sendTime;
     }
 
+    public Integer getIsDelete() {
+        return isDelete;
+    }
+
+    public void setIsDelete(Integer isDelete) {
+        this.isDelete = isDelete;
+    }
+
     public Date getCreateTime() {
         return createTime;
     }
@@ -81,10 +111,13 @@ public class HistoryMessage {
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", userId=").append(userId);
+        sb.append(", staffId=").append(staffId);
         sb.append(", videoId=").append(videoId);
         sb.append(", attachmentIdx=").append(attachmentIdx);
         sb.append(", messageId=").append(messageId);
+        sb.append(", status=").append(status);
         sb.append(", sendTime=").append(sendTime);
+        sb.append(", isDelete=").append(isDelete);
         sb.append(", createTime=").append(createTime);
         sb.append("]");
         return sb.toString();

+ 180 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/po/HistoryMessageExample.java

@@ -236,6 +236,66 @@ public class HistoryMessageExample {
             return (Criteria) this;
         }
 
+        public Criteria andStaffIdIsNull() {
+            addCriterion("staff_id is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andStaffIdIsNotNull() {
+            addCriterion("staff_id is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andStaffIdEqualTo(Long value) {
+            addCriterion("staff_id =", value, "staffId");
+            return (Criteria) this;
+        }
+
+        public Criteria andStaffIdNotEqualTo(Long value) {
+            addCriterion("staff_id <>", value, "staffId");
+            return (Criteria) this;
+        }
+
+        public Criteria andStaffIdGreaterThan(Long value) {
+            addCriterion("staff_id >", value, "staffId");
+            return (Criteria) this;
+        }
+
+        public Criteria andStaffIdGreaterThanOrEqualTo(Long value) {
+            addCriterion("staff_id >=", value, "staffId");
+            return (Criteria) this;
+        }
+
+        public Criteria andStaffIdLessThan(Long value) {
+            addCriterion("staff_id <", value, "staffId");
+            return (Criteria) this;
+        }
+
+        public Criteria andStaffIdLessThanOrEqualTo(Long value) {
+            addCriterion("staff_id <=", value, "staffId");
+            return (Criteria) this;
+        }
+
+        public Criteria andStaffIdIn(List<Long> values) {
+            addCriterion("staff_id in", values, "staffId");
+            return (Criteria) this;
+        }
+
+        public Criteria andStaffIdNotIn(List<Long> values) {
+            addCriterion("staff_id not in", values, "staffId");
+            return (Criteria) this;
+        }
+
+        public Criteria andStaffIdBetween(Long value1, Long value2) {
+            addCriterion("staff_id between", value1, value2, "staffId");
+            return (Criteria) this;
+        }
+
+        public Criteria andStaffIdNotBetween(Long value1, Long value2) {
+            addCriterion("staff_id not between", value1, value2, "staffId");
+            return (Criteria) this;
+        }
+
         public Criteria andVideoIdIsNull() {
             addCriterion("video_id is null");
             return (Criteria) this;
@@ -416,6 +476,66 @@ public class HistoryMessageExample {
             return (Criteria) this;
         }
 
+        public Criteria andStatusIsNull() {
+            addCriterion("`status` is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andStatusIsNotNull() {
+            addCriterion("`status` is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andStatusEqualTo(Integer value) {
+            addCriterion("`status` =", value, "status");
+            return (Criteria) this;
+        }
+
+        public Criteria andStatusNotEqualTo(Integer value) {
+            addCriterion("`status` <>", value, "status");
+            return (Criteria) this;
+        }
+
+        public Criteria andStatusGreaterThan(Integer value) {
+            addCriterion("`status` >", value, "status");
+            return (Criteria) this;
+        }
+
+        public Criteria andStatusGreaterThanOrEqualTo(Integer value) {
+            addCriterion("`status` >=", value, "status");
+            return (Criteria) this;
+        }
+
+        public Criteria andStatusLessThan(Integer value) {
+            addCriterion("`status` <", value, "status");
+            return (Criteria) this;
+        }
+
+        public Criteria andStatusLessThanOrEqualTo(Integer value) {
+            addCriterion("`status` <=", value, "status");
+            return (Criteria) this;
+        }
+
+        public Criteria andStatusIn(List<Integer> values) {
+            addCriterion("`status` in", values, "status");
+            return (Criteria) this;
+        }
+
+        public Criteria andStatusNotIn(List<Integer> values) {
+            addCriterion("`status` not in", values, "status");
+            return (Criteria) this;
+        }
+
+        public Criteria andStatusBetween(Integer value1, Integer value2) {
+            addCriterion("`status` between", value1, value2, "status");
+            return (Criteria) this;
+        }
+
+        public Criteria andStatusNotBetween(Integer value1, Integer value2) {
+            addCriterion("`status` not between", value1, value2, "status");
+            return (Criteria) this;
+        }
+
         public Criteria andSendTimeIsNull() {
             addCriterion("send_time is null");
             return (Criteria) this;
@@ -476,6 +596,66 @@ public class HistoryMessageExample {
             return (Criteria) this;
         }
 
+        public Criteria andIsDeleteIsNull() {
+            addCriterion("is_delete is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteIsNotNull() {
+            addCriterion("is_delete is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteEqualTo(Integer value) {
+            addCriterion("is_delete =", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteNotEqualTo(Integer value) {
+            addCriterion("is_delete <>", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteGreaterThan(Integer value) {
+            addCriterion("is_delete >", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteGreaterThanOrEqualTo(Integer value) {
+            addCriterion("is_delete >=", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteLessThan(Integer value) {
+            addCriterion("is_delete <", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteLessThanOrEqualTo(Integer value) {
+            addCriterion("is_delete <=", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteIn(List<Integer> values) {
+            addCriterion("is_delete in", values, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteNotIn(List<Integer> values) {
+            addCriterion("is_delete not in", values, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteBetween(Integer value1, Integer value2) {
+            addCriterion("is_delete between", value1, value2, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteNotBetween(Integer value1, Integer value2) {
+            addCriterion("is_delete not between", value1, value2, "isDelete");
+            return (Criteria) this;
+        }
+
         public Criteria andCreateTimeIsNull() {
             addCriterion("create_time is null");
             return (Criteria) this;

+ 22 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/po/StaffWithUser.java

@@ -9,6 +9,10 @@ public class StaffWithUser {
 
     private Long userId;
 
+    private Integer isDelete;
+
+    private Date deleteTime;
+
     private Date createTime;
 
     private Date updateTime;
@@ -37,6 +41,22 @@ public class StaffWithUser {
         this.userId = userId;
     }
 
+    public Integer getIsDelete() {
+        return isDelete;
+    }
+
+    public void setIsDelete(Integer isDelete) {
+        this.isDelete = isDelete;
+    }
+
+    public Date getDeleteTime() {
+        return deleteTime;
+    }
+
+    public void setDeleteTime(Date deleteTime) {
+        this.deleteTime = deleteTime;
+    }
+
     public Date getCreateTime() {
         return createTime;
     }
@@ -62,6 +82,8 @@ public class StaffWithUser {
         sb.append(", id=").append(id);
         sb.append(", staffId=").append(staffId);
         sb.append(", userId=").append(userId);
+        sb.append(", isDelete=").append(isDelete);
+        sb.append(", deleteTime=").append(deleteTime);
         sb.append(", createTime=").append(createTime);
         sb.append(", updateTime=").append(updateTime);
         sb.append("]");

+ 120 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/po/StaffWithUserExample.java

@@ -296,6 +296,126 @@ public class StaffWithUserExample {
             return (Criteria) this;
         }
 
+        public Criteria andIsDeleteIsNull() {
+            addCriterion("is_delete is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteIsNotNull() {
+            addCriterion("is_delete is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteEqualTo(Integer value) {
+            addCriterion("is_delete =", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteNotEqualTo(Integer value) {
+            addCriterion("is_delete <>", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteGreaterThan(Integer value) {
+            addCriterion("is_delete >", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteGreaterThanOrEqualTo(Integer value) {
+            addCriterion("is_delete >=", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteLessThan(Integer value) {
+            addCriterion("is_delete <", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteLessThanOrEqualTo(Integer value) {
+            addCriterion("is_delete <=", value, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteIn(List<Integer> values) {
+            addCriterion("is_delete in", values, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteNotIn(List<Integer> values) {
+            addCriterion("is_delete not in", values, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteBetween(Integer value1, Integer value2) {
+            addCriterion("is_delete between", value1, value2, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andIsDeleteNotBetween(Integer value1, Integer value2) {
+            addCriterion("is_delete not between", value1, value2, "isDelete");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeIsNull() {
+            addCriterion("delete_time is null");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeIsNotNull() {
+            addCriterion("delete_time is not null");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeEqualTo(Date value) {
+            addCriterion("delete_time =", value, "deleteTime");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeNotEqualTo(Date value) {
+            addCriterion("delete_time <>", value, "deleteTime");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeGreaterThan(Date value) {
+            addCriterion("delete_time >", value, "deleteTime");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeGreaterThanOrEqualTo(Date value) {
+            addCriterion("delete_time >=", value, "deleteTime");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeLessThan(Date value) {
+            addCriterion("delete_time <", value, "deleteTime");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeLessThanOrEqualTo(Date value) {
+            addCriterion("delete_time <=", value, "deleteTime");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeIn(List<Date> values) {
+            addCriterion("delete_time in", values, "deleteTime");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeNotIn(List<Date> values) {
+            addCriterion("delete_time not in", values, "deleteTime");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeBetween(Date value1, Date value2) {
+            addCriterion("delete_time between", value1, value2, "deleteTime");
+            return (Criteria) this;
+        }
+
+        public Criteria andDeleteTimeNotBetween(Date value1, Date value2) {
+            addCriterion("delete_time not between", value1, value2, "deleteTime");
+            return (Criteria) this;
+        }
+
         public Criteria andCreateTimeIsNull() {
             addCriterion("create_time is null");
             return (Criteria) this;

+ 14 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/vo/GuaranteedParam.java

@@ -0,0 +1,14 @@
+package com.tzld.piaoquan.wecom.model.vo;
+
+import com.tzld.piaoquan.wecom.model.bo.VideoParam;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class GuaranteedParam {
+
+    private String date;
+
+    private List<VideoParam> videoParamList;
+}

+ 1 - 1
we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/vo/MessageTextVo.java → we-com-server/src/main/java/com/tzld/piaoquan/wecom/model/vo/MessageTextParam.java

@@ -3,7 +3,7 @@ package com.tzld.piaoquan.wecom.model.vo;
 import lombok.Data;
 
 @Data
-public class MessageTextVo {
+public class MessageTextParam {
 
     private String text;
 

+ 3 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/AccessTokenService.java

@@ -3,4 +3,7 @@ package com.tzld.piaoquan.wecom.service;
 public interface AccessTokenService {
 
     String getAccessToken();
+
+    String getWeComAccessToken();
+
 }

+ 23 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/Impl/AccessTokenServiceImpl.java

@@ -14,6 +14,7 @@ import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 
 import static com.tzld.piaoquan.wecom.common.constant.RedisConstant.ACCESS_TOKEN;
+import static com.tzld.piaoquan.wecom.common.constant.RedisConstant.WE_COM_ACCESS_TOKEN;
 import static com.tzld.piaoquan.wecom.common.constant.WeComConstant.*;
 
 @Slf4j
@@ -46,4 +47,26 @@ public class AccessTokenServiceImpl implements AccessTokenService {
         }
         return "";
     }
+
+    @Override
+    public String getWeComAccessToken() {
+        String accessToken = (String) redisTemplate.opsForValue().get(WE_COM_ACCESS_TOKEN);
+        if (StringUtils.isNotEmpty(accessToken)) {
+            return accessToken;
+        }
+        JSONObject param = new JSONObject();
+        param.put("corp_id", CROP_ID);
+        param.put("secret", SECRET);
+        try {
+            String res = httpPoolClientDefault.get(String.format(GET_WE_COM_ACCESS_TOKEN_URL + "?corpid=%s&corpsecret=%s", WE_COM_CROP_ID, WE_COM_SECRET));
+            JSONObject jsonObject = JSONObject.parseObject(res);
+            Long expiresIn = jsonObject.getLong("expires_in");
+            String newAccessToken = jsonObject.getString("access_token");
+            redisTemplate.opsForValue().set(WE_COM_ACCESS_TOKEN, newAccessToken, expiresIn, TimeUnit.SECONDS);
+            return newAccessToken;
+        } catch (IOException e) {
+            log.error("getWeComAccessToken error", e);
+        }
+        return "";
+    }
 }

+ 77 - 12
we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/Impl/MessageAttachmentServiceImpl.java

@@ -2,34 +2,46 @@ package com.tzld.piaoquan.wecom.service.Impl;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.tzld.piaoquan.wecom.common.base.CommonResponse;
 import com.tzld.piaoquan.wecom.common.enums.MessageAttachmentTypeEnum;
-import com.tzld.piaoquan.wecom.common.exception.CustomizeException;
 import com.tzld.piaoquan.wecom.dao.mapper.MessageAttachmentMapper;
 import com.tzld.piaoquan.wecom.model.bo.AdPutFlowParam;
 import com.tzld.piaoquan.wecom.model.bo.VideoDetail;
+import com.tzld.piaoquan.wecom.model.bo.VideoParam;
 import com.tzld.piaoquan.wecom.model.po.MessageAttachment;
 import com.tzld.piaoquan.wecom.model.po.MessageAttachmentExample;
 import com.tzld.piaoquan.wecom.model.po.Staff;
+import com.tzld.piaoquan.wecom.model.vo.GuaranteedParam;
+import com.tzld.piaoquan.wecom.service.AccessTokenService;
 import com.tzld.piaoquan.wecom.service.MessageAttachmentService;
 import com.tzld.piaoquan.wecom.utils.DateUtil;
 import com.tzld.piaoquan.wecom.utils.HttpClientUtil;
 import com.tzld.piaoquan.wecom.utils.HttpPoolClient;
+import com.tzld.piaoquan.wecom.utils.LarkRobotUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 
+import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 
+import static com.tzld.piaoquan.wecom.common.constant.MessageConstant.MAX_VIDEO_NUM;
 import static com.tzld.piaoquan.wecom.common.constant.MessageConstant.appid;
 import static com.tzld.piaoquan.wecom.common.constant.OtherServerURL.POST_ADD_TENCENT;
 import static com.tzld.piaoquan.wecom.common.constant.OtherServerURL.POST_VIDEO_DETAIL_URL;
-import static com.tzld.piaoquan.wecom.common.constant.RedisConstant.GUARANTEED_MINIPROGRAM_KEY;
-import static com.tzld.piaoquan.wecom.common.enums.ExceptionCodeEnum.PARAMS_ERROR;
+import static com.tzld.piaoquan.wecom.common.constant.RedisConstant.GUARANTEED_MINI_PROGRAM_KEY;
+import static com.tzld.piaoquan.wecom.common.constant.WeComConstant.POST_WE_COM_MEDIA_UPLOAD;
 
 
 @Slf4j
@@ -38,6 +50,9 @@ public class MessageAttachmentServiceImpl implements MessageAttachmentService {
 
     private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(30000, 30000, 2000, 5000, 5, 30000);
 
+    @Autowired
+    private AccessTokenService accessTokenService;
+
     @Autowired
     private MessageAttachmentMapper messageAttachmentMapper;
 
@@ -45,7 +60,7 @@ public class MessageAttachmentServiceImpl implements MessageAttachmentService {
     private RedisTemplate<String, Object> redisTemplate;
 
     @Override
-    public void addMiniprogram(List<MessageAttachment> messageAttachmentList) {
+    public void addMiniProgram(List<MessageAttachment> messageAttachmentList) {
         for (MessageAttachment messageAttachment : messageAttachmentList) {
             MessageAttachmentExample example = new MessageAttachmentExample();
             example.createCriteria()
@@ -63,9 +78,18 @@ public class MessageAttachmentServiceImpl implements MessageAttachmentService {
     }
 
     @Override
-    public void createGuaranteedMiniprogram(List<Long> videoIds) {
-        if (CollectionUtils.isEmpty(videoIds)) {
-            throw new CustomizeException(PARAMS_ERROR);
+    public CommonResponse<Void> createGuaranteedMiniProgram(GuaranteedParam guaranteedParam) {
+        if (guaranteedParam == null
+                || StringUtils.isEmpty(guaranteedParam.getDate())
+                || CollectionUtils.isEmpty(guaranteedParam.getVideoParamList())) {
+            return CommonResponse.create(500, "参数错误");
+        }
+        List<Long> videoIds = new ArrayList<>();
+        for (VideoParam videoParam : guaranteedParam.getVideoParamList()) {
+            if (CollectionUtils.isEmpty(videoParam.getVideoIds()) || videoParam.getVideoIds().size() < MAX_VIDEO_NUM) {
+                LarkRobotUtil.sendMessage("保底视频数量异常,请查看" + guaranteedParam.getDate());
+            }
+            videoIds.addAll(videoParam.getVideoIds());
         }
         Map<Long, VideoDetail> coverMap = getVideoDetail(videoIds);
         List<MessageAttachment> messageAttachmentList = new ArrayList<>();
@@ -73,6 +97,7 @@ public class MessageAttachmentServiceImpl implements MessageAttachmentService {
             MessageAttachment messageAttachment = new MessageAttachment();
             VideoDetail videoDetail = coverMap.get(videoId);
             if (videoDetail == null || StringUtils.isEmpty(videoDetail.getCover()) || StringUtils.isEmpty(videoDetail.getTitle())) {
+                LarkRobotUtil.sendMessage("获取视频详情异常,请查看" + videoId);
                 throw new RuntimeException("获取视频详情异常");
             }
             messageAttachment.setMiniprogramVideoId(videoId);
@@ -82,10 +107,11 @@ public class MessageAttachmentServiceImpl implements MessageAttachmentService {
             messageAttachment.setAppid(appid);
             messageAttachmentList.add(messageAttachment);
         }
-        addMiniprogram(messageAttachmentList);
-        for (Long video : videoIds) {
-            redisTemplate.opsForList().rightPush(GUARANTEED_MINIPROGRAM_KEY, video);
-        }
+        addMiniProgram(messageAttachmentList);
+        String date = guaranteedParam.getDate();
+        String key = String.format(GUARANTEED_MINI_PROGRAM_KEY, date);
+        redisTemplate.opsForValue().set(key, guaranteedParam);
+        return CommonResponse.success();
     }
 
     public Map<Long, VideoDetail> getVideoDetail(List<Long> videoIdList) {
@@ -113,6 +139,45 @@ public class MessageAttachmentServiceImpl implements MessageAttachmentService {
         return new HashMap<>();
     }
 
+    @Override
+    public String getPicMediaId(String cover) {
+        String mediaId = (String) redisTemplate.opsForValue().get(cover);
+        if (StringUtils.isNotEmpty(mediaId)) {
+            return mediaId;
+        }
+        String filePath = UUID.randomUUID() + ".jpg"; // 临时文件路径
+        try {
+            HttpURLConnection httpUrl = (HttpURLConnection) new URL(cover).openConnection();
+            httpUrl.connect();
+            InputStream inputStream = httpUrl.getInputStream();
+
+            // 将文件内容写入临时文件
+            try (OutputStream outputStream = Files.newOutputStream(Paths.get(filePath))) {
+                byte[] buffer = new byte[4096];
+                int bytesRead;
+                while ((bytesRead = inputStream.read(buffer)) != -1) {
+                    outputStream.write(buffer, 0, bytesRead);
+                }
+            }
+            inputStream.close();
+            httpUrl.disconnect();
+            File file = new java.io.File(filePath);
+            String weComAccessToken = accessTokenService.getWeComAccessToken();
+            String url = String.format(POST_WE_COM_MEDIA_UPLOAD + "?access_token=%s&type=%s", weComAccessToken, "image");
+            String res = httpPoolClientDefault.post(url, file);
+            JSONObject jsonObject = JSONObject.parseObject(res);
+            if (jsonObject != null && jsonObject.getInteger("errcode") == 0) {
+                mediaId = jsonObject.getString("media_id");
+                redisTemplate.opsForValue().set(cover, mediaId, 2, TimeUnit.DAYS);
+            }
+            Files.delete(Paths.get(filePath));
+        } catch (Exception e) {
+            log.error("getPicMediaId error", e);
+        }
+        return mediaId;
+    }
+
+
     @Override
     public String getPage(Staff staff, Long videoId) {
         try {

+ 26 - 9
we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/Impl/MessageServiceImpl.java

@@ -3,7 +3,7 @@ package com.tzld.piaoquan.wecom.service.Impl;
 import com.alibaba.fastjson.JSONObject;
 import com.tzld.piaoquan.wecom.common.constant.MessageConstant;
 import com.tzld.piaoquan.wecom.common.exception.CustomizeException;
-import com.tzld.piaoquan.wecom.model.vo.MessageTextVo;
+import com.tzld.piaoquan.wecom.model.vo.MessageTextParam;
 import com.tzld.piaoquan.wecom.service.AccessTokenService;
 import com.tzld.piaoquan.wecom.service.MessageService;
 import com.tzld.piaoquan.wecom.utils.HttpClientUtil;
@@ -18,6 +18,7 @@ import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 
 import static com.tzld.piaoquan.wecom.common.constant.RedisConstant.PUSH_MESSAGE_TEXT;
+import static com.tzld.piaoquan.wecom.common.constant.WeComConstant.POST_WE_COM_ADD_MSG_TEMPLATE;
 import static com.tzld.piaoquan.wecom.common.enums.ExceptionCodeEnum.PARAMS_ERROR;
 import static com.tzld.piaoquan.wecom.common.constant.WeComConstant.POST_MESSAGE_PUSH_URL;
 
@@ -40,26 +41,42 @@ public class MessageServiceImpl implements MessageService {
             String url = POST_MESSAGE_PUSH_URL
                     + "?access_token=" + accessToken;
             String s = httpPoolClientDefault.post(url, jsonObject.toJSONString());
-            System.out.println(s);
             JSONObject res = JSONObject.parseObject(s);
-            log.info("MessageServiceImpl pushMessage res={}", res);
+            log.info("pushMessage res={}", res);
             Integer code = res.getInteger("errcode");
             return code == 0;
         } catch (IOException e) {
-            log.error("MessageServiceImpl pushMessage error", e);
+            log.error("pushMessage error", e);
         }
         return false;
     }
 
     @Override
-    public void createMessageText(MessageTextVo messageTextVo) {
-        if (messageTextVo == null || messageTextVo.getHour() == null) {
+    public boolean pushWeComMessage(JSONObject jsonObject) {
+        try {
+            String accessToken = accessTokenService.getWeComAccessToken();
+            String url = POST_WE_COM_ADD_MSG_TEMPLATE
+                    + "?access_token=" + accessToken;
+            String s = httpPoolClientDefault.post(url, jsonObject.toJSONString());
+            JSONObject res = JSONObject.parseObject(s);
+            log.info("pushWeComMessage res={}", res);
+            Integer code = res.getInteger("errcode");
+            return code == 0;
+        } catch (IOException e) {
+            log.error("pushWeComMessage error", e);
+        }
+        return false;
+    }
+
+    @Override
+    public void createMessageText(MessageTextParam messageTextParam) {
+        if (messageTextParam == null || messageTextParam.getHour() == null) {
             throw new CustomizeException(PARAMS_ERROR);
         }
-        if (messageTextVo.getHour() == -1) {
-            redisTemplate.opsForValue().set(PUSH_MESSAGE_TEXT, messageTextVo.getText());
+        if (messageTextParam.getHour() == -1) {
+            redisTemplate.opsForValue().set(PUSH_MESSAGE_TEXT, messageTextParam.getText());
         } else {
-            redisTemplate.opsForValue().set(PUSH_MESSAGE_TEXT, messageTextVo.getText(), messageTextVo.getHour(), TimeUnit.HOURS);
+            redisTemplate.opsForValue().set(PUSH_MESSAGE_TEXT, messageTextParam.getText(), messageTextParam.getHour(), TimeUnit.HOURS);
         }
     }
 

+ 218 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/Impl/UserServiceImpl.java

@@ -0,0 +1,218 @@
+package com.tzld.piaoquan.wecom.service.Impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.tzld.piaoquan.wecom.dao.mapper.StaffMapper;
+import com.tzld.piaoquan.wecom.dao.mapper.StaffWithUserMapper;
+import com.tzld.piaoquan.wecom.dao.mapper.UserMapper;
+import com.tzld.piaoquan.wecom.model.po.*;
+import com.tzld.piaoquan.wecom.service.AccessTokenService;
+import com.tzld.piaoquan.wecom.service.UserService;
+import com.tzld.piaoquan.wecom.utils.HttpClientUtil;
+import com.tzld.piaoquan.wecom.utils.HttpPoolClient;
+import com.tzld.piaoquan.wecom.utils.LarkRobotUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import static com.tzld.piaoquan.wecom.common.constant.WeComConstant.GET_WE_COM_EXTERNAL_CONTACT_GET;
+
+@Slf4j
+@Service
+public class UserServiceImpl implements UserService {
+    private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(30000, 30000, 2000, 5000, 5, 30000);
+
+    @Autowired
+    private AccessTokenService accessTokenService;
+
+    @Autowired
+    private UserMapper userMapper;
+
+    @Autowired
+    private StaffWithUserMapper staffWithUserMapper;
+
+    @Autowired
+    private StaffMapper staffMapper;
+
+    public void addStaffWithUser(String externalUserId, String carrierId) {
+        if (StringUtils.isEmpty(externalUserId) || StringUtils.isEmpty(carrierId)) {
+            return;
+        }
+        Staff staff = getStaff(carrierId);
+        insertStaffWithUser(externalUserId, staff);
+    }
+
+
+    public void insertStaffWithUser(String externalUserId, Staff staff) {
+        try {
+            UserExample userExample = new UserExample();
+            userExample.createCriteria().andExternalUserIdEqualTo(externalUserId);
+            List<User> userList = userMapper.selectByExample(userExample);
+            if (CollectionUtils.isEmpty(userList)) {
+                JSONObject userDetail = getUserDetail(externalUserId);
+                if (userDetail == null) {
+                    return;
+                }
+                JSONObject externalContact = userDetail.getJSONObject("external_contact");
+                JSONArray followUserList = userDetail.getJSONArray("follow_user");
+                Long createAt = null;
+                List<String> staffUserIdList = new ArrayList<>();
+                for (int i = 0; i < followUserList.size(); i++) {
+                    JSONObject followUser = followUserList.getJSONObject(i);
+                    if (createAt == null) {
+                        createAt = followUser.getLong("createtime");
+                    } else {
+                        createAt = Math.min(createAt, followUser.getLong("createtime"));
+                    }
+                    String userId = followUser.getString("userid");
+                    if (StringUtils.isNotEmpty(userId)) {
+                        staffUserIdList.add(userId);
+                    }
+                }
+                String name = externalContact.getString("name");
+                String unionId = externalContact.getString("unionid");
+                String avatar = externalContact.getString("avatar");
+                Integer type = externalContact.getInteger("type");
+                Integer gender = externalContact.getInteger("gender");
+                User user = new User();
+                user.setExternalUserId(externalUserId);
+                user.setCreatedAt(createAt);
+                user.setName(name);
+                user.setUnionId(unionId);
+                user.setAvatar(avatar);
+                user.setType(type);
+                user.setGender(gender);
+                userMapper.insert(user);
+                Long userId = user.getId();
+                if (userId == null) {
+                    log.error("insertStaffWithUserJob insert user error user={}", user);
+                    return;
+                }
+                if (CollectionUtils.isEmpty(staffUserIdList)) {
+                    return;
+                }
+                for (String staffUserId : staffUserIdList) {
+                    StaffExample staffExample = new StaffExample();
+                    staffExample.createCriteria().andCarrierIdEqualTo(staffUserId);
+                    List<Staff> staffList1 = staffMapper.selectByExample(staffExample);
+                    if (CollectionUtils.isEmpty(staffList1)) {
+                        continue;
+                    }
+                    Staff staff1 = staffList1.get(0);
+                    Long staffId = staff1.getId();
+                    StaffWithUser staffWithUser = new StaffWithUser();
+                    staffWithUser.setStaffId(staffId);
+                    staffWithUser.setUserId(userId);
+                    staffWithUserMapper.insert(staffWithUser);
+                }
+            } else {
+                User user = userList.get(0);
+                StaffWithUserExample staffWithUserExample = new StaffWithUserExample();
+                staffWithUserExample.createCriteria().andUserIdEqualTo(user.getId()).andStaffIdEqualTo(staff.getId());
+                List<StaffWithUser> staffWithUserList = staffWithUserMapper.selectByExample(staffWithUserExample);
+                if (CollectionUtils.isEmpty(staffWithUserList)) {
+                    StaffWithUser staffWithUser = new StaffWithUser();
+                    staffWithUser.setStaffId(staff.getId());
+                    staffWithUser.setUserId(user.getId());
+                    staffWithUserMapper.insert(staffWithUser);
+                } else {
+                    StaffWithUser staffWithUser = staffWithUserList.get(0);
+                    if (staffWithUser.getIsDelete() == 1) {
+                        staffWithUser.setIsDelete(0);
+                        staffWithUserMapper.updateByPrimaryKeySelective(staffWithUser);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            LarkRobotUtil.sendMessage("insertUser error externalUserId=" + externalUserId + e);
+            log.error("insertUser error", e);
+        }
+    }
+
+    @Override
+    public void delStaffWithUser(String externalUserId, String carrierId) {
+        if (StringUtils.isEmpty(externalUserId) || StringUtils.isEmpty(carrierId)) {
+            return;
+        }
+        Staff staff = getStaff(carrierId);
+        if (staff == null) {
+            return;
+        }
+        User user = getUser(externalUserId);
+        if (user == null) {
+            return;
+        }
+        StaffWithUserExample example = new StaffWithUserExample();
+        example.createCriteria().andStaffIdEqualTo(staff.getId()).andUserIdEqualTo(user.getId());
+        List<StaffWithUser> staffWithUserList = staffWithUserMapper.selectByExample(example);
+        if (CollectionUtils.isEmpty(staffWithUserList) || staffWithUserList.get(0).getIsDelete() == 1) {
+            return;
+        }
+        StaffWithUser staffWithUser = staffWithUserList.get(0);
+        staffWithUser.setDeleteTime(new Date());
+        staffWithUser.setIsDelete(1);
+        staffWithUserMapper.updateByPrimaryKeySelective(staffWithUser);
+    }
+
+    @Override
+    public void delStaffWithUser(Long userId, Long staffId, Long deleteTime) {
+        if (userId == null || staffId == null) {
+            return;
+        }
+        StaffWithUserExample example = new StaffWithUserExample();
+        example.createCriteria().andStaffIdEqualTo(staffId).andUserIdEqualTo(userId);
+        List<StaffWithUser> staffWithUserList = staffWithUserMapper.selectByExample(example);
+        if (CollectionUtils.isEmpty(staffWithUserList) || staffWithUserList.get(0).getIsDelete() == 1) {
+            return;
+        }
+        StaffWithUser staffWithUser = staffWithUserList.get(0);
+        if(deleteTime != null){
+            staffWithUser.setDeleteTime(new Date(deleteTime));
+        }
+        staffWithUser.setIsDelete(1);
+        staffWithUserMapper.updateByPrimaryKeySelective(staffWithUser);
+    }
+
+
+    private Staff getStaff(String carrierId) {
+        StaffExample example = new StaffExample();
+        example.createCriteria().andCarrierIdEqualTo(carrierId);
+        List<Staff> staffList = staffMapper.selectByExample(example);
+        if (CollectionUtils.isEmpty(staffList)) {
+            log.error("getStaff staff empty carrierId={}", carrierId);
+            return null;
+        }
+        return staffList.get(0);
+    }
+
+    private User getUser(String externalUserId) {
+        UserExample userExample = new UserExample();
+        userExample.createCriteria().andExternalUserIdEqualTo(externalUserId);
+        List<User> userList = userMapper.selectByExample(userExample);
+        if (CollectionUtils.isEmpty(userList)) {
+            log.error("getUser user empty externalUserId={}", externalUserId);
+            return null;
+        }
+        return userList.get(0);
+    }
+
+
+    public JSONObject getUserDetail(String externalUserId) throws IOException {
+        String weComAccessToken = accessTokenService.getWeComAccessToken();
+        String url = String.format(GET_WE_COM_EXTERNAL_CONTACT_GET + "?access_token=%s&external_userid=%s", weComAccessToken, externalUserId);
+        String res = httpPoolClientDefault.get(url);
+        JSONObject jsonObject = JSONObject.parseObject(res);
+        Integer errcode = jsonObject.getInteger("errcode");
+        if (errcode == 0) {
+            return jsonObject;
+        }
+        return null;
+    }
+}

+ 6 - 2
we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/MessageAttachmentService.java

@@ -1,15 +1,19 @@
 package com.tzld.piaoquan.wecom.service;
 
+import com.tzld.piaoquan.wecom.common.base.CommonResponse;
 import com.tzld.piaoquan.wecom.model.po.MessageAttachment;
 import com.tzld.piaoquan.wecom.model.po.Staff;
+import com.tzld.piaoquan.wecom.model.vo.GuaranteedParam;
 
 import java.util.List;
 
 public interface MessageAttachmentService {
 
-    void addMiniprogram(List<MessageAttachment> messageAttachmentList);
+    void addMiniProgram(List<MessageAttachment> messageAttachmentList);
 
-    void createGuaranteedMiniprogram(List<Long> videos);
+    CommonResponse<Void> createGuaranteedMiniProgram(GuaranteedParam guaranteedParam);
+
+    String getPicMediaId(String cover);
 
     String getPage(Staff staff, Long videoId);
 }

+ 4 - 2
we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/MessageService.java

@@ -1,13 +1,15 @@
 package com.tzld.piaoquan.wecom.service;
 
 import com.alibaba.fastjson.JSONObject;
-import com.tzld.piaoquan.wecom.model.vo.MessageTextVo;
+import com.tzld.piaoquan.wecom.model.vo.MessageTextParam;
 
 public interface MessageService {
 
     boolean pushMessage(JSONObject jsonObject);
 
-    void createMessageText(MessageTextVo messageTextVo);
+    boolean pushWeComMessage(JSONObject jsonObject);
+
+    void createMessageText(MessageTextParam messageTextParam);
 
     String getMessageText();
 }

+ 16 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/service/UserService.java

@@ -0,0 +1,16 @@
+package com.tzld.piaoquan.wecom.service;
+
+import com.tzld.piaoquan.wecom.model.po.Staff;
+
+
+public interface UserService {
+
+
+    void addStaffWithUser(String externalUserId, String staffUserId);
+
+    void insertStaffWithUser(String externalUserId, Staff staff);
+
+    void delStaffWithUser(String externalUserId, String staffUserId);
+
+    void delStaffWithUser(Long userId, Long staffId, Long deleteTime);
+}

+ 7 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/DateUtil.java

@@ -28,6 +28,13 @@ public class DateUtil {
         return dateFormat.format(yesterday);
     }
 
+    public static String getThatDayDateString() {
+        DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        LocalDate today = LocalDate.now();
+        return dateFormat.format(today);
+    }
+
+
     public static String getDayDateString(String pattern) {
         DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern(pattern);
         LocalDate today = LocalDate.now();

+ 10 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/HttpPoolClient.java

@@ -16,6 +16,7 @@ import org.apache.http.conn.socket.PlainConnectionSocketFactory;
 import org.apache.http.conn.ssl.NoopHostnameVerifier;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.entity.StringEntity;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
 import org.apache.http.impl.client.HttpClientBuilder;
@@ -27,6 +28,7 @@ import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
 
 import javax.net.ssl.SSLContext;
+import java.io.File;
 import java.io.IOException;
 import java.net.SocketTimeoutException;
 import java.nio.charset.StandardCharsets;
@@ -104,6 +106,14 @@ public class HttpPoolClient {
         return request(httpPost);
     }
 
+    public String post(String url, File file) throws IOException {
+        HttpPost uploadFile = new HttpPost(url);
+        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+        builder.addBinaryBody("media", file);
+        uploadFile.setEntity(builder.build());
+        return request(uploadFile);
+    }
+
     public String request(HttpRequestBase request) throws IOException {
 
         if (LOGGER.isDebugEnabled()) {

+ 5 - 6
we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/LarkRobotUtil.java

@@ -15,22 +15,22 @@ public class LarkRobotUtil {
 
     private static final String SECRET = "iYGMzvTCIIX35WyPlxB3Lh";
 
-    private static final String URL = "https://open.feishu.cn/open-apis/bot/v2/hook/5cab8414-03c2-4300-83f4-709cec256d12";
+    private static final String URL = "https://open.feishu.cn/open-apis/bot/v2/hook/93787b70-33d3-42c1-beae-c09310c9b38b";
 
     private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(30000, 30000, 2000, 5000, 5, 30000);
 
 
     public static void sendMessage(String msg) {
-        sendMessage("text", msg);
+        sendMessage("text", "企微推送报警:" + msg);
     }
 
     public static void sendMessage(String type, String msg) {
         try {
             long timestamp = System.currentTimeMillis() / 1000;
-            String sign = getSign(timestamp);
+//            String sign = getSign(timestamp);
             JSONObject param = new JSONObject();
-            param.put("timestamp", String.valueOf(timestamp));
-            param.put("sign", sign);
+//            param.put("timestamp", String.valueOf(timestamp));
+//            param.put("sign", sign);
             param.put("msg_type", type);
             JSONObject content = new JSONObject();
             content.put("text", msg);
@@ -41,7 +41,6 @@ public class LarkRobotUtil {
         }
     }
 
-
     private static String getSign(long timestamp) throws NoSuchAlgorithmException, InvalidKeyException {
         //把timestamp+"\n"+密钥当做签名字符串
         String stringToSign = timestamp + "\n" + SECRET;

+ 59 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/AesException.java

@@ -0,0 +1,59 @@
+package com.tzld.piaoquan.wecom.utils.wecom;
+
+@SuppressWarnings("serial")
+public class AesException extends Exception {
+
+    public final static int OK = 0;
+    public final static int ValidateSignatureError = -40001;
+    public final static int ParseXmlError = -40002;
+    public final static int ComputeSignatureError = -40003;
+    public final static int IllegalAesKey = -40004;
+    public final static int ValidateCorpidError = -40005;
+    public final static int EncryptAESError = -40006;
+    public final static int DecryptAESError = -40007;
+    public final static int IllegalBuffer = -40008;
+    //public final static int EncodeBase64Error = -40009;
+    //public final static int DecodeBase64Error = -40010;
+    //public final static int GenReturnXmlError = -40011;
+
+    private int code;
+
+    private static String getMessage(int code) {
+        switch (code) {
+            case ValidateSignatureError:
+                return "签名验证错误";
+            case ParseXmlError:
+                return "xml解析失败";
+            case ComputeSignatureError:
+                return "sha加密生成签名失败";
+            case IllegalAesKey:
+                return "SymmetricKey非法";
+            case ValidateCorpidError:
+                return "corpid校验失败";
+            case EncryptAESError:
+                return "aes加密失败";
+            case DecryptAESError:
+                return "aes解密失败";
+            case IllegalBuffer:
+                return "解密后得到的buffer非法";
+//		case EncodeBase64Error:
+//			return "base64加密错误";
+//		case DecodeBase64Error:
+//			return "base64解密错误";
+//		case GenReturnXmlError:
+//			return "xml生成失败";
+            default:
+                return null; // cannot be
+        }
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    AesException(int code) {
+        super(getMessage(code));
+        this.code = code;
+    }
+
+}

+ 26 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/ByteGroup.java

@@ -0,0 +1,26 @@
+package com.tzld.piaoquan.wecom.utils.wecom;
+
+import java.util.ArrayList;
+
+class ByteGroup {
+	ArrayList<Byte> byteContainer = new ArrayList<Byte>();
+
+	public byte[] toBytes() {
+		byte[] bytes = new byte[byteContainer.size()];
+		for (int i = 0; i < byteContainer.size(); i++) {
+			bytes[i] = byteContainer.get(i);
+		}
+		return bytes;
+	}
+
+	public ByteGroup addBytes(byte[] bytes) {
+		for (byte b : bytes) {
+			byteContainer.add(b);
+		}
+		return this;
+	}
+
+	public int size() {
+		return byteContainer.size();
+	}
+}

+ 67 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/PKCS7Encoder.java

@@ -0,0 +1,67 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.tzld.piaoquan.wecom.utils.wecom;
+
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+/**
+ * 提供基于PKCS7算法的加解密接口.
+ */
+class PKCS7Encoder {
+	static Charset CHARSET = Charset.forName("utf-8");
+	static int BLOCK_SIZE = 32;
+
+	/**
+	 * 获得对明文进行补位填充的字节.
+	 * 
+	 * @param count 需要进行填充补位操作的明文字节个数
+	 * @return 补齐用的字节数组
+	 */
+	static byte[] encode(int count) {
+		// 计算需要填充的位数
+		int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
+		if (amountToPad == 0) {
+			amountToPad = BLOCK_SIZE;
+		}
+		// 获得补位所用的字符
+		char padChr = chr(amountToPad);
+		String tmp = new String();
+		for (int index = 0; index < amountToPad; index++) {
+			tmp += padChr;
+		}
+		return tmp.getBytes(CHARSET);
+	}
+
+	/**
+	 * 删除解密后明文的补位字符
+	 * 
+	 * @param decrypted 解密后的明文
+	 * @return 删除补位字符后的明文
+	 */
+	static byte[] decode(byte[] decrypted) {
+		int pad = (int) decrypted[decrypted.length - 1];
+		if (pad < 1 || pad > 32) {
+			pad = 0;
+		}
+		return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
+	}
+
+	/**
+	 * 将数字转化成ASCII码对应的字符,用于对明文进行补码
+	 * 
+	 * @param a 需要转化的数字
+	 * @return 转化得到的字符
+	 */
+	static char chr(int a) {
+		byte target = (byte) (a & 0xFF);
+		return (char) target;
+	}
+
+}

+ 61 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/SHA1.java

@@ -0,0 +1,61 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.tzld.piaoquan.wecom.utils.wecom;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+/**
+ * SHA1 class
+ *
+ * 计算消息签名接口.
+ */
+class SHA1 {
+
+	/**
+	 * 用SHA1算法生成安全签名
+	 * @param token 票据
+	 * @param timestamp 时间戳
+	 * @param nonce 随机字符串
+	 * @param encrypt 密文
+	 * @return 安全签名
+	 * @throws AesException 
+	 */
+	public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException
+			  {
+		try {
+			String[] array = new String[] { token, timestamp, nonce, encrypt };
+			StringBuffer sb = new StringBuffer();
+			// 字符串排序
+			Arrays.sort(array);
+			for (int i = 0; i < 4; i++) {
+				sb.append(array[i]);
+			}
+			String str = sb.toString();
+			// SHA1签名生成
+			MessageDigest md = MessageDigest.getInstance("SHA-1");
+			md.update(str.getBytes());
+			byte[] digest = md.digest();
+
+			StringBuffer hexstr = new StringBuffer();
+			String shaHex = "";
+			for (int i = 0; i < digest.length; i++) {
+				shaHex = Integer.toHexString(digest[i] & 0xFF);
+				if (shaHex.length() < 2) {
+					hexstr.append(0);
+				}
+				hexstr.append(shaHex);
+			}
+			return hexstr.toString();
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.ComputeSignatureError);
+		}
+	}
+}

+ 289 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/WXBizMsgCrypt.java

@@ -0,0 +1,289 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * 针对org.apache.commons.codec.binary.Base64,
+ * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
+ * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
+ */
+package com.tzld.piaoquan.wecom.utils.wecom;
+
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Random;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.codec.binary.Base64;
+
+/**
+ * 提供接收和推送给企业微信消息的加解密接口(UTF8编码的字符串).
+ * <ol>
+ * 	<li>第三方回复加密消息给企业微信</li>
+ * 	<li>第三方收到企业微信发送的消息,验证消息的安全性,并对消息进行解密。</li>
+ * </ol>
+ * 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案
+ * <ol>
+ * 	<li>在官方网站下载JCE无限制权限策略文件(JDK7的下载地址:
+ *      http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html</li>
+ * 	<li>下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt</li>
+ * 	<li>如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件</li>
+ * 	<li>如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件</li>
+ * </ol>
+ */
+public class WXBizMsgCrypt {
+	static Charset CHARSET = Charset.forName("utf-8");
+	Base64 base64 = new Base64();
+	byte[] aesKey;
+	String token;
+	String receiveid;
+
+	/**
+	 * 构造函数
+	 * @param token 企业微信后台,开发者设置的token
+	 * @param encodingAesKey 企业微信后台,开发者设置的EncodingAESKey
+	 * @param receiveid, 不同场景含义不同,详见文档
+	 * 
+	 * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+	 */
+	public WXBizMsgCrypt(String token, String encodingAesKey, String receiveid) throws AesException {
+		if (encodingAesKey.length() != 43) {
+			throw new AesException(AesException.IllegalAesKey);
+		}
+
+		this.token = token;
+		this.receiveid = receiveid;
+		aesKey = Base64.decodeBase64(encodingAesKey + "=");
+	}
+
+	// 生成4个字节的网络字节序
+	byte[] getNetworkBytesOrder(int sourceNumber) {
+		byte[] orderBytes = new byte[4];
+		orderBytes[3] = (byte) (sourceNumber & 0xFF);
+		orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
+		orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
+		orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
+		return orderBytes;
+	}
+
+	// 还原4个字节的网络字节序
+	int recoverNetworkBytesOrder(byte[] orderBytes) {
+		int sourceNumber = 0;
+		for (int i = 0; i < 4; i++) {
+			sourceNumber <<= 8;
+			sourceNumber |= orderBytes[i] & 0xff;
+		}
+		return sourceNumber;
+	}
+
+	// 随机生成16位字符串
+	String getRandomStr() {
+		String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+		Random random = new Random();
+		StringBuffer sb = new StringBuffer();
+		for (int i = 0; i < 16; i++) {
+			int number = random.nextInt(base.length());
+			sb.append(base.charAt(number));
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * 对明文进行加密.
+	 * 
+	 * @param text 需要加密的明文
+	 * @return 加密后base64编码的字符串
+	 * @throws AesException aes加密失败
+	 */
+	String encrypt(String randomStr, String text) throws AesException {
+		ByteGroup byteCollector = new ByteGroup();
+		byte[] randomStrBytes = randomStr.getBytes(CHARSET);
+		byte[] textBytes = text.getBytes(CHARSET);
+		byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
+		byte[] receiveidBytes = receiveid.getBytes(CHARSET);
+
+		// randomStr + networkBytesOrder + text + receiveid
+		byteCollector.addBytes(randomStrBytes);
+		byteCollector.addBytes(networkBytesOrder);
+		byteCollector.addBytes(textBytes);
+		byteCollector.addBytes(receiveidBytes);
+
+		// ... + pad: 使用自定义的填充方式对明文进行补位填充
+		byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
+		byteCollector.addBytes(padBytes);
+
+		// 获得最终的字节流, 未加密
+		byte[] unencrypted = byteCollector.toBytes();
+
+		try {
+			// 设置加密模式为AES的CBC模式
+			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+			SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
+			IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
+			cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
+
+			// 加密
+			byte[] encrypted = cipher.doFinal(unencrypted);
+
+			// 使用BASE64对加密后的字符串进行编码
+			String base64Encrypted = base64.encodeToString(encrypted);
+
+			return base64Encrypted;
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.EncryptAESError);
+		}
+	}
+
+	/**
+	 * 对密文进行解密.
+	 * 
+	 * @param text 需要解密的密文
+	 * @return 解密得到的明文
+	 * @throws AesException aes解密失败
+	 */
+	String decrypt(String text) throws AesException {
+		byte[] original;
+		try {
+			// 设置解密模式为AES的CBC模式
+			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+			SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
+			IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
+			cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
+
+			// 使用BASE64对密文进行解码
+			byte[] encrypted = Base64.decodeBase64(text);
+
+			// 解密
+			original = cipher.doFinal(encrypted);
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.DecryptAESError);
+		}
+
+		String xmlContent, from_receiveid;
+		try {
+			// 去除补位字符
+			byte[] bytes = PKCS7Encoder.decode(original);
+
+			// 分离16位随机字符串,网络字节序和receiveid
+			byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
+
+			int xmlLength = recoverNetworkBytesOrder(networkOrder);
+
+			xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
+			from_receiveid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
+					CHARSET);
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.IllegalBuffer);
+		}
+
+		// receiveid不相同的情况
+		if (!from_receiveid.equals(receiveid)) {
+			throw new AesException(AesException.ValidateCorpidError);
+		}
+		return xmlContent;
+
+	}
+
+	/**
+	 * 将企业微信回复用户的消息加密打包.
+	 * <ol>
+	 * 	<li>对要发送的消息进行AES-CBC加密</li>
+	 * 	<li>生成安全签名</li>
+	 * 	<li>将消息密文和安全签名打包成xml格式</li>
+	 * </ol>
+	 * 
+	 * @param replyMsg 企业微信待回复用户的消息,xml格式的字符串
+	 * @param timeStamp 时间戳,可以自己生成,也可以用URL参数的timestamp
+	 * @param nonce 随机串,可以自己生成,也可以用URL参数的nonce
+	 * 
+	 * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串
+	 * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+	 */
+	public String EncryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {
+		// 加密
+		String encrypt = encrypt(getRandomStr(), replyMsg);
+
+		// 生成安全签名
+		if (timeStamp == "") {
+			timeStamp = Long.toString(System.currentTimeMillis());
+		}
+
+		String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);
+
+		// System.out.println("发送给平台的签名是: " + signature[1].toString());
+		// 生成发送的xml
+		String result = XMLParse.generate(encrypt, signature, timeStamp, nonce);
+		return result;
+	}
+
+	/**
+	 * 检验消息的真实性,并且获取解密后的明文.
+	 * <ol>
+	 * 	<li>利用收到的密文生成安全签名,进行签名验证</li>
+	 * 	<li>若验证通过,则提取xml中的加密消息</li>
+	 * 	<li>对消息进行解密</li>
+	 * </ol>
+	 * 
+	 * @param msgSignature 签名串,对应URL参数的msg_signature
+	 * @param timeStamp 时间戳,对应URL参数的timestamp
+	 * @param nonce 随机串,对应URL参数的nonce
+	 * @param postData 密文,对应POST请求的数据
+	 * 
+	 * @return 解密后的原文
+	 * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+	 */
+	public String DecryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
+			throws AesException {
+
+		// 密钥,公众账号的app secret
+		// 提取密文
+		Object[] encrypt = XMLParse.extract(postData);
+
+		// 验证安全签名
+		String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString());
+
+		// 和URL中的签名比较是否相等
+		// System.out.println("第三方收到URL中的签名:" + msg_sign);
+		// System.out.println("第三方校验签名:" + signature);
+		if (!signature.equals(msgSignature)) {
+			throw new AesException(AesException.ValidateSignatureError);
+		}
+
+		// 解密
+		String result = decrypt(encrypt[1].toString());
+		return result;
+	}
+
+	/**
+	 * 验证URL
+	 * @param msgSignature 签名串,对应URL参数的msg_signature
+	 * @param timeStamp 时间戳,对应URL参数的timestamp
+	 * @param nonce 随机串,对应URL参数的nonce
+	 * @param echoStr 随机串,对应URL参数的echostr
+	 * 
+	 * @return 解密之后的echostr
+	 * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+	 */
+	public String VerifyURL(String msgSignature, String timeStamp, String nonce, String echoStr)
+			throws AesException {
+		String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);
+
+		if (!signature.equals(msgSignature)) {
+			throw new AesException(AesException.ValidateSignatureError);
+		}
+
+		String result = decrypt(echoStr);
+		return result;
+	}
+
+}

+ 95 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/WxUtil.java

@@ -0,0 +1,95 @@
+package com.tzld.piaoquan.wecom.utils.wecom;
+
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.JDOMException;
+import org.jdom2.input.SAXBuilder;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+public class WxUtil {
+
+    /**
+     * 将 Map 转化为 XML
+     *
+     * @param map
+     * @return
+     */
+    public static String transferMapToXml(SortedMap<String, Object> map) {
+        StringBuffer sb = new StringBuffer();
+        sb.append("<xml>");
+        for (String key : map.keySet()) {
+            sb.append("<").append(key).append(">")
+                    .append(map.get(key))
+                    .append("</").append(key).append(">");
+        }
+        return sb.append("</xml>").toString();
+    }
+
+    /**
+     * 将 XML 转化为 map
+     *
+     * @param strxml
+     * @return
+     * @throws IOException
+     */
+    public static Map transferXmlToMap(String strxml) throws IOException {
+        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
+        if (null == strxml || "".equals(strxml)) {
+            return null;
+        }
+        Map m = new HashMap();
+        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
+        SAXBuilder builder = new SAXBuilder();
+        Document doc = null;
+        try {
+            doc = builder.build(in);
+        } catch (JDOMException e) {
+            throw new IOException(e.getMessage()); // 统一转化为 IO 异常输出
+        }
+        // 解析 DOM
+        Element root = doc.getRootElement();
+        List list = root.getChildren();
+        Iterator it = list.iterator();
+        while (it.hasNext()) {
+            Element e = (Element) it.next();
+            String k = e.getName();
+            String v = "";
+            List children = e.getChildren();
+            if (children.isEmpty()) {
+                v = e.getTextNormalize();
+            } else {
+                v = getChildrenText(children);
+            }
+            m.put(k, v);
+        }
+        //关闭流
+        in.close();
+        return m;
+    }
+
+    // 辅助 transferXmlToMap 方法递归提取子节点数据
+    private static String getChildrenText(List<Element> children) {
+        StringBuffer sb = new StringBuffer();
+        if (!children.isEmpty()) {
+            Iterator<Element> it = children.iterator();
+            while (it.hasNext()) {
+                Element e = (Element) it.next();
+                String name = e.getName();
+                String value = e.getTextNormalize();
+                List<Element> list = e.getChildren();
+                sb.append("<" + name + ">");
+                if (!list.isEmpty()) {
+                    sb.append(getChildrenText(list));
+                }
+                sb.append(value);
+                sb.append("</" + name + ">");
+            }
+        }
+        return sb.toString();
+    }
+
+}

+ 104 - 0
we-com-server/src/main/java/com/tzld/piaoquan/wecom/utils/wecom/XMLParse.java

@@ -0,0 +1,104 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ * 
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.tzld.piaoquan.wecom.utils.wecom;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+/**
+ * XMLParse class
+ *
+ * 提供提取消息格式中的密文及生成回复消息格式的接口.
+ */
+class XMLParse {
+
+	/**
+	 * 提取出xml数据包中的加密消息
+	 * @param xmltext 待提取的xml字符串
+	 * @return 提取出的加密消息字符串
+	 * @throws AesException 
+	 */
+	public static Object[] extract(String xmltext) throws AesException     {
+		Object[] result = new Object[3];
+		try {
+			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+			
+			String FEATURE = null;
+			// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
+			// Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
+			FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
+			dbf.setFeature(FEATURE, true);
+			
+			// If you can't completely disable DTDs, then at least do the following:
+			// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
+			// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
+			// JDK7+ - http://xml.org/sax/features/external-general-entities 
+			FEATURE = "http://xml.org/sax/features/external-general-entities";
+			dbf.setFeature(FEATURE, false);
+			
+			// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
+			// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
+			// JDK7+ - http://xml.org/sax/features/external-parameter-entities 
+			FEATURE = "http://xml.org/sax/features/external-parameter-entities";
+			dbf.setFeature(FEATURE, false);
+			
+			// Disable external DTDs as well
+			FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
+			dbf.setFeature(FEATURE, false);
+			
+			// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
+			dbf.setXIncludeAware(false);
+			dbf.setExpandEntityReferences(false);
+			
+			// And, per Timothy Morgan: "If for some reason support for inline DOCTYPEs are a requirement, then 
+			// ensure the entity settings are disabled (as shown above) and beware that SSRF attacks
+			// (http://cwe.mitre.org/data/definitions/918.html) and denial 
+			// of service attacks (such as billion laughs or decompression bombs via "jar:") are a risk."
+			
+			// remaining parser logic
+			DocumentBuilder db = dbf.newDocumentBuilder();
+			StringReader sr = new StringReader(xmltext);
+			InputSource is = new InputSource(sr);
+			Document document = db.parse(is);
+
+			Element root = document.getDocumentElement();
+			NodeList nodelist1 = root.getElementsByTagName("Encrypt");
+			result[0] = 0;
+			result[1] = nodelist1.item(0).getTextContent();
+			return result;
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw new AesException(AesException.ParseXmlError);
+		}
+	}
+
+	/**
+	 * 生成xml消息
+	 * @param encrypt 加密后的消息密文
+	 * @param signature 安全签名
+	 * @param timestamp 时间戳
+	 * @param nonce 随机字符串
+	 * @return 生成的xml字符串
+	 */
+	public static String generate(String encrypt, String signature, String timestamp, String nonce) {
+
+		String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n"
+				+ "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n"
+				+ "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n" + "</xml>";
+		return String.format(format, encrypt, signature, timestamp, nonce);
+
+	}
+}

+ 79 - 28
we-com-server/src/main/resources/mapper/HistoryMessageMapper.xml

@@ -4,10 +4,13 @@
   <resultMap id="BaseResultMap" type="com.tzld.piaoquan.wecom.model.po.HistoryMessage">
     <id column="id" jdbcType="BIGINT" property="id" />
     <result column="user_id" jdbcType="BIGINT" property="userId" />
+    <result column="staff_id" jdbcType="BIGINT" property="staffId" />
     <result column="video_id" jdbcType="BIGINT" property="videoId" />
     <result column="attachment_idx" jdbcType="INTEGER" property="attachmentIdx" />
     <result column="message_id" jdbcType="BIGINT" property="messageId" />
+    <result column="status" jdbcType="INTEGER" property="status" />
     <result column="send_time" jdbcType="TIMESTAMP" property="sendTime" />
+    <result column="is_delete" jdbcType="INTEGER" property="isDelete" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
   <sql id="Example_Where_Clause">
@@ -69,7 +72,8 @@
     </where>
   </sql>
   <sql id="Base_Column_List">
-    id, user_id, video_id, attachment_idx, message_id, send_time, create_time
+    id, user_id, staff_id, video_id, attachment_idx, message_id, `status`, send_time, 
+    is_delete, create_time
   </sql>
   <select id="selectByExample" parameterType="com.tzld.piaoquan.wecom.model.po.HistoryMessageExample" resultMap="BaseResultMap">
     select
@@ -105,11 +109,13 @@
     </if>
   </delete>
   <insert id="insert" parameterType="com.tzld.piaoquan.wecom.model.po.HistoryMessage">
-    insert into we_com_history_message (id, user_id, video_id, 
-      attachment_idx, message_id, send_time, 
+    insert into we_com_history_message (id, user_id, staff_id, 
+      video_id, attachment_idx, message_id, 
+      `status`, send_time,
       create_time)
-    values (#{id,jdbcType=BIGINT}, #{userId,jdbcType=BIGINT}, #{videoId,jdbcType=BIGINT}, 
-      #{attachmentIdx,jdbcType=INTEGER}, #{messageId,jdbcType=BIGINT}, #{sendTime,jdbcType=TIMESTAMP}, 
+    values (#{id,jdbcType=BIGINT}, #{userId,jdbcType=BIGINT}, #{staffId,jdbcType=BIGINT}, 
+      #{videoId,jdbcType=BIGINT}, #{attachmentIdx,jdbcType=INTEGER}, #{messageId,jdbcType=BIGINT}, 
+      #{status,jdbcType=INTEGER}, #{sendTime,jdbcType=TIMESTAMP},
       #{createTime,jdbcType=TIMESTAMP})
   </insert>
   <insert id="insertSelective" parameterType="com.tzld.piaoquan.wecom.model.po.HistoryMessage">
@@ -121,6 +127,9 @@
       <if test="userId != null">
         user_id,
       </if>
+      <if test="staffId != null">
+        staff_id,
+      </if>
       <if test="videoId != null">
         video_id,
       </if>
@@ -130,9 +139,15 @@
       <if test="messageId != null">
         message_id,
       </if>
+      <if test="status != null">
+        `status`,
+      </if>
       <if test="sendTime != null">
         send_time,
       </if>
+      <if test="isDelete != null">
+        is_delete,
+      </if>
       <if test="createTime != null">
         create_time,
       </if>
@@ -144,6 +159,9 @@
       <if test="userId != null">
         #{userId,jdbcType=BIGINT},
       </if>
+      <if test="staffId != null">
+        #{staffId,jdbcType=BIGINT},
+      </if>
       <if test="videoId != null">
         #{videoId,jdbcType=BIGINT},
       </if>
@@ -153,9 +171,15 @@
       <if test="messageId != null">
         #{messageId,jdbcType=BIGINT},
       </if>
+      <if test="status != null">
+        #{status,jdbcType=INTEGER},
+      </if>
       <if test="sendTime != null">
         #{sendTime,jdbcType=TIMESTAMP},
       </if>
+      <if test="isDelete != null">
+        #{isDelete,jdbcType=INTEGER},
+      </if>
       <if test="createTime != null">
         #{createTime,jdbcType=TIMESTAMP},
       </if>
@@ -176,6 +200,9 @@
       <if test="record.userId != null">
         user_id = #{record.userId,jdbcType=BIGINT},
       </if>
+      <if test="record.staffId != null">
+        staff_id = #{record.staffId,jdbcType=BIGINT},
+      </if>
       <if test="record.videoId != null">
         video_id = #{record.videoId,jdbcType=BIGINT},
       </if>
@@ -185,9 +212,15 @@
       <if test="record.messageId != null">
         message_id = #{record.messageId,jdbcType=BIGINT},
       </if>
+      <if test="record.status != null">
+        `status` = #{record.status,jdbcType=INTEGER},
+      </if>
       <if test="record.sendTime != null">
         send_time = #{record.sendTime,jdbcType=TIMESTAMP},
       </if>
+      <if test="record.isDelete != null">
+        is_delete = #{record.isDelete,jdbcType=INTEGER},
+      </if>
       <if test="record.createTime != null">
         create_time = #{record.createTime,jdbcType=TIMESTAMP},
       </if>
@@ -200,10 +233,13 @@
     update we_com_history_message
     set id = #{record.id,jdbcType=BIGINT},
       user_id = #{record.userId,jdbcType=BIGINT},
+      staff_id = #{record.staffId,jdbcType=BIGINT},
       video_id = #{record.videoId,jdbcType=BIGINT},
       attachment_idx = #{record.attachmentIdx,jdbcType=INTEGER},
       message_id = #{record.messageId,jdbcType=BIGINT},
+      `status` = #{record.status,jdbcType=INTEGER},
       send_time = #{record.sendTime,jdbcType=TIMESTAMP},
+      is_delete = #{record.isDelete,jdbcType=INTEGER},
       create_time = #{record.createTime,jdbcType=TIMESTAMP}
     <if test="_parameter != null">
       <include refid="Update_By_Example_Where_Clause" />
@@ -215,6 +251,9 @@
       <if test="userId != null">
         user_id = #{userId,jdbcType=BIGINT},
       </if>
+      <if test="staffId != null">
+        staff_id = #{staffId,jdbcType=BIGINT},
+      </if>
       <if test="videoId != null">
         video_id = #{videoId,jdbcType=BIGINT},
       </if>
@@ -224,9 +263,15 @@
       <if test="messageId != null">
         message_id = #{messageId,jdbcType=BIGINT},
       </if>
+      <if test="status != null">
+        `status` = #{status,jdbcType=INTEGER},
+      </if>
       <if test="sendTime != null">
         send_time = #{sendTime,jdbcType=TIMESTAMP},
       </if>
+      <if test="isDelete != null">
+        is_delete = #{isDelete,jdbcType=INTEGER},
+      </if>
       <if test="createTime != null">
         create_time = #{createTime,jdbcType=TIMESTAMP},
       </if>
@@ -236,35 +281,41 @@
   <update id="updateByPrimaryKey" parameterType="com.tzld.piaoquan.wecom.model.po.HistoryMessage">
     update we_com_history_message
     set user_id = #{userId,jdbcType=BIGINT},
+      staff_id = #{staffId,jdbcType=BIGINT},
       video_id = #{videoId,jdbcType=BIGINT},
       attachment_idx = #{attachmentIdx,jdbcType=INTEGER},
       message_id = #{messageId,jdbcType=BIGINT},
+      `status` = #{status,jdbcType=INTEGER},
       send_time = #{sendTime,jdbcType=TIMESTAMP},
+      is_delete = #{isDelete,jdbcType=INTEGER},
       create_time = #{createTime,jdbcType=TIMESTAMP}
     where id = #{id,jdbcType=BIGINT}
   </update>
 
-  <insert id="insertList" parameterType="java.util.List">
-    insert into we_com_history_message
-    (
-     user_id,
-     video_id,
-     attachment_idx,
-     message_id,
-     send_time,
-     create_time
-    )
-    values
-    <foreach collection="list" item="item" separator=",">
-      (
-       #{item.userId,jdbcType=BIGINT},
-       #{item.videoId,jdbcType=BIGINT},
-       #{item.attachmentIdx,jdbcType=INTEGER},
-       #{item.messageId,jdbcType=BIGINT},
-       #{item.sendTime,jdbcType=TIMESTAMP},
-       #{item.createTime,jdbcType=TIMESTAMP}
-      )
-    </foreach>
-  </insert>
-
+    <insert id="insertList" parameterType="java.util.List">
+        insert into we_com_history_message
+        (
+        user_id,
+        staff_id,
+        video_id,
+        attachment_idx,
+        message_id,
+        `status`,
+        send_time,
+        create_time
+        )
+        values
+        <foreach collection="list" item="item" separator=",">
+            (
+            #{item.userId,jdbcType=BIGINT},
+            #{item.staffId,jdbcType=BIGINT},
+            #{item.videoId,jdbcType=BIGINT},
+            #{item.attachmentIdx,jdbcType=INTEGER},
+            #{item.messageId,jdbcType=BIGINT},
+            #{item.status,jdbcType=INTEGER},
+            #{item.sendTime,jdbcType=TIMESTAMP},
+            #{item.createTime,jdbcType=TIMESTAMP}
+            )
+        </foreach>
+    </insert>
 </mapper>

+ 12 - 0
we-com-server/src/main/resources/mapper/SendMessageMapper.xml

@@ -320,4 +320,16 @@
           and t1.create_time > #{record.createTime}
           and t1.is_send = #{record.isSend}
     </select>
+
+    <select id="selectExternalUserId" parameterType="com.tzld.piaoquan.wecom.model.po.SendMessage" resultType="java.lang.String">
+        select
+            t2.external_user_id
+        from we_com_send_message t1 left join we_com_user t2 on t1.user_id = t2.id
+        where t1.staff_id = #{record.staffId}
+          and t1.video_id_1 = #{record.videoId1}
+          and t1.video_id_2 = #{record.videoId2}
+          and t1.video_id_3 = #{record.videoId3}
+          and t1.create_time > #{record.createTime}
+          and t1.is_send = #{record.isSend}
+    </select>
 </mapper>

+ 2 - 2
we-com-server/src/main/resources/mapper/StaffMapper.xml

@@ -106,10 +106,10 @@
   </delete>
   <insert id="insert" parameterType="com.tzld.piaoquan.wecom.model.po.Staff">
     insert into we_com_staff (id, staff_ext_id, carrier_id, 
-      remark, is_delete, create_time, 
+      remark, create_time,
       update_time)
     values (#{id,jdbcType=BIGINT}, #{staffExtId,jdbcType=VARCHAR}, #{carrierId,jdbcType=VARCHAR}, 
-      #{remark,jdbcType=VARCHAR}, #{isDelete,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP}, 
+      #{remark,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP},
       #{updateTime,jdbcType=TIMESTAMP})
   </insert>
   <insert id="insertSelective" parameterType="com.tzld.piaoquan.wecom.model.po.Staff">

+ 257 - 228
we-com-server/src/main/resources/mapper/StaffWithUserMapper.xml

@@ -1,239 +1,268 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.tzld.piaoquan.wecom.dao.mapper.StaffWithUserMapper">
-    <resultMap id="BaseResultMap" type="com.tzld.piaoquan.wecom.model.po.StaffWithUser">
-        <id column="id" jdbcType="BIGINT" property="id"/>
-        <result column="staff_id" jdbcType="BIGINT" property="staffId"/>
-        <result column="user_id" jdbcType="BIGINT" property="userId"/>
-        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
-        <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
-    </resultMap>
-    <sql id="Example_Where_Clause">
-        <where>
-            <foreach collection="oredCriteria" item="criteria" separator="or">
-                <if test="criteria.valid">
-                    <trim prefix="(" prefixOverrides="and" suffix=")">
-                        <foreach collection="criteria.criteria" item="criterion">
-                            <choose>
-                                <when test="criterion.noValue">
-                                    and ${criterion.condition}
-                                </when>
-                                <when test="criterion.singleValue">
-                                    and ${criterion.condition} #{criterion.value}
-                                </when>
-                                <when test="criterion.betweenValue">
-                                    and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
-                                </when>
-                                <when test="criterion.listValue">
-                                    and ${criterion.condition}
-                                    <foreach close=")" collection="criterion.value" item="listItem" open="("
-                                             separator=",">
-                                        #{listItem}
-                                    </foreach>
-                                </when>
-                            </choose>
-                        </foreach>
-                    </trim>
-                </if>
+  <resultMap id="BaseResultMap" type="com.tzld.piaoquan.wecom.model.po.StaffWithUser">
+    <id column="id" jdbcType="BIGINT" property="id" />
+    <result column="staff_id" jdbcType="BIGINT" property="staffId" />
+    <result column="user_id" jdbcType="BIGINT" property="userId" />
+    <result column="is_delete" jdbcType="INTEGER" property="isDelete" />
+    <result column="delete_time" jdbcType="TIMESTAMP" property="deleteTime" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
+  </resultMap>
+  <sql id="Example_Where_Clause">
+    <where>
+      <foreach collection="oredCriteria" item="criteria" separator="or">
+        <if test="criteria.valid">
+          <trim prefix="(" prefixOverrides="and" suffix=")">
+            <foreach collection="criteria.criteria" item="criterion">
+              <choose>
+                <when test="criterion.noValue">
+                  and ${criterion.condition}
+                </when>
+                <when test="criterion.singleValue">
+                  and ${criterion.condition} #{criterion.value}
+                </when>
+                <when test="criterion.betweenValue">
+                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+                </when>
+                <when test="criterion.listValue">
+                  and ${criterion.condition}
+                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
+                    #{listItem}
+                  </foreach>
+                </when>
+              </choose>
             </foreach>
-        </where>
-    </sql>
-    <sql id="Update_By_Example_Where_Clause">
-        <where>
-            <foreach collection="example.oredCriteria" item="criteria" separator="or">
-                <if test="criteria.valid">
-                    <trim prefix="(" prefixOverrides="and" suffix=")">
-                        <foreach collection="criteria.criteria" item="criterion">
-                            <choose>
-                                <when test="criterion.noValue">
-                                    and ${criterion.condition}
-                                </when>
-                                <when test="criterion.singleValue">
-                                    and ${criterion.condition} #{criterion.value}
-                                </when>
-                                <when test="criterion.betweenValue">
-                                    and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
-                                </when>
-                                <when test="criterion.listValue">
-                                    and ${criterion.condition}
-                                    <foreach close=")" collection="criterion.value" item="listItem" open="("
-                                             separator=",">
-                                        #{listItem}
-                                    </foreach>
-                                </when>
-                            </choose>
-                        </foreach>
-                    </trim>
-                </if>
-            </foreach>
-        </where>
-    </sql>
-    <sql id="Base_Column_List">
-        id
-        , staff_id, user_id, create_time, update_time
-    </sql>
-    <select id="selectByExample" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUserExample"
-            resultMap="BaseResultMap">
-        select
-        <if test="distinct">
-            distinct
-        </if>
-        <include refid="Base_Column_List"/>
-        from we_com_staff_with_user
-        <if test="_parameter != null">
-            <include refid="Example_Where_Clause"/>
-        </if>
-        <if test="orderByClause != null">
-            order by ${orderByClause}
-        </if>
-        <if test="page != null">
-            limit #{page.offset} , #{page.pageSize}
+          </trim>
         </if>
-    </select>
-    <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
-        select
-        <include refid="Base_Column_List"/>
-        from we_com_staff_with_user
-        where id = #{id,jdbcType=BIGINT}
-    </select>
-    <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
-        delete
-        from we_com_staff_with_user
-        where id = #{id,jdbcType=BIGINT}
-    </delete>
-    <delete id="deleteByExample" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUserExample">
-        delete from we_com_staff_with_user
-        <if test="_parameter != null">
-            <include refid="Example_Where_Clause"/>
-        </if>
-    </delete>
-    <insert id="insert" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUser">
-        insert into we_com_staff_with_user (id, staff_id, user_id,
-                                            create_time, update_time)
-        values (#{id,jdbcType=BIGINT}, #{staffId,jdbcType=BIGINT}, #{userId,jdbcType=BIGINT},
-                #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP})
-    </insert>
-    <insert id="insertSelective" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUser">
-        insert into we_com_staff_with_user
-        <trim prefix="(" suffix=")" suffixOverrides=",">
-            <if test="id != null">
-                id,
-            </if>
-            <if test="staffId != null">
-                staff_id,
-            </if>
-            <if test="userId != null">
-                user_id,
-            </if>
-            <if test="createTime != null">
-                create_time,
-            </if>
-            <if test="updateTime != null">
-                update_time,
-            </if>
-        </trim>
-        <trim prefix="values (" suffix=")" suffixOverrides=",">
-            <if test="id != null">
-                #{id,jdbcType=BIGINT},
-            </if>
-            <if test="staffId != null">
-                #{staffId,jdbcType=BIGINT},
-            </if>
-            <if test="userId != null">
-                #{userId,jdbcType=BIGINT},
-            </if>
-            <if test="createTime != null">
-                #{createTime,jdbcType=TIMESTAMP},
-            </if>
-            <if test="updateTime != null">
-                #{updateTime,jdbcType=TIMESTAMP},
-            </if>
-        </trim>
-    </insert>
-    <select id="countByExample" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUserExample"
-            resultType="java.lang.Long">
-        select count(*) from we_com_staff_with_user
-        <if test="_parameter != null">
-            <include refid="Example_Where_Clause"/>
-        </if>
-    </select>
-    <update id="updateByExampleSelective" parameterType="map">
-        update we_com_staff_with_user
-        <set>
-            <if test="record.id != null">
-                id = #{record.id,jdbcType=BIGINT},
-            </if>
-            <if test="record.staffId != null">
-                staff_id = #{record.staffId,jdbcType=BIGINT},
-            </if>
-            <if test="record.userId != null">
-                user_id = #{record.userId,jdbcType=BIGINT},
-            </if>
-            <if test="record.createTime != null">
-                create_time = #{record.createTime,jdbcType=TIMESTAMP},
-            </if>
-            <if test="record.updateTime != null">
-                update_time = #{record.updateTime,jdbcType=TIMESTAMP},
-            </if>
-        </set>
-        <if test="_parameter != null">
-            <include refid="Update_By_Example_Where_Clause"/>
+      </foreach>
+    </where>
+  </sql>
+  <sql id="Update_By_Example_Where_Clause">
+    <where>
+      <foreach collection="example.oredCriteria" item="criteria" separator="or">
+        <if test="criteria.valid">
+          <trim prefix="(" prefixOverrides="and" suffix=")">
+            <foreach collection="criteria.criteria" item="criterion">
+              <choose>
+                <when test="criterion.noValue">
+                  and ${criterion.condition}
+                </when>
+                <when test="criterion.singleValue">
+                  and ${criterion.condition} #{criterion.value}
+                </when>
+                <when test="criterion.betweenValue">
+                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+                </when>
+                <when test="criterion.listValue">
+                  and ${criterion.condition}
+                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
+                    #{listItem}
+                  </foreach>
+                </when>
+              </choose>
+            </foreach>
+          </trim>
         </if>
-    </update>
-    <update id="updateByExample" parameterType="map">
-        update we_com_staff_with_user
-        set id = #{record.id,jdbcType=BIGINT},
+      </foreach>
+    </where>
+  </sql>
+  <sql id="Base_Column_List">
+    id, staff_id, user_id, is_delete, delete_time, create_time, update_time
+  </sql>
+  <select id="selectByExample" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUserExample" resultMap="BaseResultMap">
+    select
+    <if test="distinct">
+      distinct
+    </if>
+    <include refid="Base_Column_List" />
+    from we_com_staff_with_user
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+    <if test="orderByClause != null">
+      order by ${orderByClause}
+    </if>
+    <if test="page != null">
+      limit #{page.offset} , #{page.pageSize}
+    </if>
+  </select>
+  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+    select
+    <include refid="Base_Column_List" />
+    from we_com_staff_with_user
+    where id = #{id,jdbcType=BIGINT}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+    delete from we_com_staff_with_user
+    where id = #{id,jdbcType=BIGINT}
+  </delete>
+  <delete id="deleteByExample" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUserExample">
+    delete from we_com_staff_with_user
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+  </delete>
+  <insert id="insert" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUser">
+    insert into we_com_staff_with_user (id, staff_id, user_id, delete_time, create_time,
+      update_time)
+    values (#{id,jdbcType=BIGINT}, #{staffId,jdbcType=BIGINT}, #{userId,jdbcType=BIGINT},
+      #{deleteTime,jdbcType=TIMESTAMP}, #{createTime,jdbcType=TIMESTAMP},
+      #{updateTime,jdbcType=TIMESTAMP})
+  </insert>
+  <insert id="insertSelective" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUser">
+    insert into we_com_staff_with_user
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="id != null">
+        id,
+      </if>
+      <if test="staffId != null">
+        staff_id,
+      </if>
+      <if test="userId != null">
+        user_id,
+      </if>
+      <if test="isDelete != null">
+        is_delete,
+      </if>
+      <if test="deleteTime != null">
+        delete_time,
+      </if>
+      <if test="createTime != null">
+        create_time,
+      </if>
+      <if test="updateTime != null">
+        update_time,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="id != null">
+        #{id,jdbcType=BIGINT},
+      </if>
+      <if test="staffId != null">
+        #{staffId,jdbcType=BIGINT},
+      </if>
+      <if test="userId != null">
+        #{userId,jdbcType=BIGINT},
+      </if>
+      <if test="isDelete != null">
+        #{isDelete,jdbcType=INTEGER},
+      </if>
+      <if test="deleteTime != null">
+        #{deleteTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="createTime != null">
+        #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="updateTime != null">
+        #{updateTime,jdbcType=TIMESTAMP},
+      </if>
+    </trim>
+  </insert>
+  <select id="countByExample" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUserExample" resultType="java.lang.Long">
+    select count(*) from we_com_staff_with_user
+    <if test="_parameter != null">
+      <include refid="Example_Where_Clause" />
+    </if>
+  </select>
+  <update id="updateByExampleSelective" parameterType="map">
+    update we_com_staff_with_user
+    <set>
+      <if test="record.id != null">
+        id = #{record.id,jdbcType=BIGINT},
+      </if>
+      <if test="record.staffId != null">
         staff_id = #{record.staffId,jdbcType=BIGINT},
+      </if>
+      <if test="record.userId != null">
         user_id = #{record.userId,jdbcType=BIGINT},
+      </if>
+      <if test="record.isDelete != null">
+        is_delete = #{record.isDelete,jdbcType=INTEGER},
+      </if>
+      <if test="record.deleteTime != null">
+        delete_time = #{record.deleteTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="record.createTime != null">
         create_time = #{record.createTime,jdbcType=TIMESTAMP},
-        update_time = #{record.updateTime,jdbcType=TIMESTAMP}
-        <if test="_parameter != null">
-            <include refid="Update_By_Example_Where_Clause"/>
-        </if>
-    </update>
-    <update id="updateByPrimaryKeySelective" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUser">
-        update we_com_staff_with_user
-        <set>
-            <if test="staffId != null">
-                staff_id = #{staffId,jdbcType=BIGINT},
-            </if>
-            <if test="userId != null">
-                user_id = #{userId,jdbcType=BIGINT},
-            </if>
-            <if test="createTime != null">
-                create_time = #{createTime,jdbcType=TIMESTAMP},
-            </if>
-            <if test="updateTime != null">
-                update_time = #{updateTime,jdbcType=TIMESTAMP},
-            </if>
-        </set>
-        where id = #{id,jdbcType=BIGINT}
-    </update>
-    <update id="updateByPrimaryKey" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUser">
-        update we_com_staff_with_user
-        set staff_id    = #{staffId,jdbcType=BIGINT},
-            user_id     = #{userId,jdbcType=BIGINT},
-            create_time = #{createTime,jdbcType=TIMESTAMP},
-            update_time = #{updateTime,jdbcType=TIMESTAMP}
-        where id = #{id,jdbcType=BIGINT}
-    </update>
+      </if>
+      <if test="record.updateTime != null">
+        update_time = #{record.updateTime,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    <if test="_parameter != null">
+      <include refid="Update_By_Example_Where_Clause" />
+    </if>
+  </update>
+  <update id="updateByExample" parameterType="map">
+    update we_com_staff_with_user
+    set id = #{record.id,jdbcType=BIGINT},
+      staff_id = #{record.staffId,jdbcType=BIGINT},
+      user_id = #{record.userId,jdbcType=BIGINT},
+      is_delete = #{record.isDelete,jdbcType=INTEGER},
+      delete_time = #{record.deleteTime,jdbcType=TIMESTAMP},
+      create_time = #{record.createTime,jdbcType=TIMESTAMP},
+      update_time = #{record.updateTime,jdbcType=TIMESTAMP}
+    <if test="_parameter != null">
+      <include refid="Update_By_Example_Where_Clause" />
+    </if>
+  </update>
+  <update id="updateByPrimaryKeySelective" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUser">
+    update we_com_staff_with_user
+    <set>
+      <if test="staffId != null">
+        staff_id = #{staffId,jdbcType=BIGINT},
+      </if>
+      <if test="userId != null">
+        user_id = #{userId,jdbcType=BIGINT},
+      </if>
+      <if test="isDelete != null">
+        is_delete = #{isDelete,jdbcType=INTEGER},
+      </if>
+      <if test="deleteTime != null">
+        delete_time = #{deleteTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="createTime != null">
+        create_time = #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="updateTime != null">
+        update_time = #{updateTime,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="com.tzld.piaoquan.wecom.model.po.StaffWithUser">
+    update we_com_staff_with_user
+    set staff_id = #{staffId,jdbcType=BIGINT},
+      user_id = #{userId,jdbcType=BIGINT},
+      is_delete = #{isDelete,jdbcType=INTEGER},
+      delete_time = #{deleteTime,jdbcType=TIMESTAMP},
+      create_time = #{createTime,jdbcType=TIMESTAMP},
+      update_time = #{updateTime,jdbcType=TIMESTAMP}
+    where id = #{id,jdbcType=BIGINT}
+  </update>
 
-    <insert id="insertList" parameterType="java.util.List">
-        insert into we_com_staff_with_user
-        (
-        staff_id,
-        user_id,
-        create_time,
-        update_time
-        )
-        values
-        <foreach collection="list" item="item" separator=",">
-            (
-            #{item.staffId,jdbcType=BIGINT},
-            #{item.userId,jdbcType=BIGINT},
-            #{item.createTime,jdbcType=TIMESTAMP},
-            #{item.updateTime,jdbcType=TIMESTAMP}
-            )
-        </foreach>
-    </insert>
+  <insert id="insertList" parameterType="java.util.List">
+    insert into we_com_staff_with_user
+    (
+    staff_id,
+    user_id,
+    is_delete,
+    delete_time,
+    create_time,
+    update_time
+    )
+    values
+    <foreach collection="list" item="item" separator=",">
+      (
+      #{item.staffId,jdbcType=BIGINT},
+      #{item.userId,jdbcType=BIGINT},
+      #{item.isDelete,jdbcType=INTEGER},
+      #{item.deleteTime,jdbcType=TIMESTAMP},
+      #{item.createTime,jdbcType=TIMESTAMP},
+      #{item.updateTime,jdbcType=TIMESTAMP}
+      )
+    </foreach>
+  </insert>
 </mapper>

+ 390 - 377
we-com-server/src/main/resources/mapper/UserMapper.xml

@@ -1,399 +1,412 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.tzld.piaoquan.wecom.dao.mapper.UserMapper">
-  <resultMap id="BaseResultMap" type="com.tzld.piaoquan.wecom.model.po.User">
-    <id column="id" jdbcType="BIGINT" property="id" />
-    <result column="external_user_id" jdbcType="VARCHAR" property="externalUserId" />
-    <result column="union_id" jdbcType="VARCHAR" property="unionId" />
-    <result column="external_user_id_3rd_party" jdbcType="VARCHAR" property="externalUserId3rdParty" />
-    <result column="type" jdbcType="INTEGER" property="type" />
-    <result column="name" jdbcType="VARCHAR" property="name" />
-    <result column="avatar" jdbcType="VARCHAR" property="avatar" />
-    <result column="gender" jdbcType="INTEGER" property="gender" />
-    <result column="is_delete" jdbcType="INTEGER" property="isDelete" />
-    <result column="created_at" jdbcType="BIGINT" property="createdAt" />
-    <result column="updated_at" jdbcType="BIGINT" property="updatedAt" />
-    <result column="deleted_at" jdbcType="BIGINT" property="deletedAt" />
-    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
-    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
-  </resultMap>
-  <sql id="Example_Where_Clause">
-    <where>
-      <foreach collection="oredCriteria" item="criteria" separator="or">
-        <if test="criteria.valid">
-          <trim prefix="(" prefixOverrides="and" suffix=")">
-            <foreach collection="criteria.criteria" item="criterion">
-              <choose>
-                <when test="criterion.noValue">
-                  and ${criterion.condition}
-                </when>
-                <when test="criterion.singleValue">
-                  and ${criterion.condition} #{criterion.value}
-                </when>
-                <when test="criterion.betweenValue">
-                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
-                </when>
-                <when test="criterion.listValue">
-                  and ${criterion.condition}
-                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
-                    #{listItem}
-                  </foreach>
-                </when>
-              </choose>
+    <resultMap id="BaseResultMap" type="com.tzld.piaoquan.wecom.model.po.User">
+        <id column="id" jdbcType="BIGINT" property="id"/>
+        <result column="external_user_id" jdbcType="VARCHAR" property="externalUserId"/>
+        <result column="union_id" jdbcType="VARCHAR" property="unionId"/>
+        <result column="external_user_id_3rd_party" jdbcType="VARCHAR" property="externalUserId3rdParty"/>
+        <result column="type" jdbcType="INTEGER" property="type"/>
+        <result column="name" jdbcType="VARCHAR" property="name"/>
+        <result column="avatar" jdbcType="VARCHAR" property="avatar"/>
+        <result column="gender" jdbcType="INTEGER" property="gender"/>
+        <result column="is_delete" jdbcType="INTEGER" property="isDelete"/>
+        <result column="created_at" jdbcType="BIGINT" property="createdAt"/>
+        <result column="updated_at" jdbcType="BIGINT" property="updatedAt"/>
+        <result column="deleted_at" jdbcType="BIGINT" property="deletedAt"/>
+        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
+        <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
+    </resultMap>
+    <sql id="Example_Where_Clause">
+        <where>
+            <foreach collection="oredCriteria" item="criteria" separator="or">
+                <if test="criteria.valid">
+                    <trim prefix="(" prefixOverrides="and" suffix=")">
+                        <foreach collection="criteria.criteria" item="criterion">
+                            <choose>
+                                <when test="criterion.noValue">
+                                    and ${criterion.condition}
+                                </when>
+                                <when test="criterion.singleValue">
+                                    and ${criterion.condition} #{criterion.value}
+                                </when>
+                                <when test="criterion.betweenValue">
+                                    and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+                                </when>
+                                <when test="criterion.listValue">
+                                    and ${criterion.condition}
+                                    <foreach close=")" collection="criterion.value" item="listItem" open="("
+                                             separator=",">
+                                        #{listItem}
+                                    </foreach>
+                                </when>
+                            </choose>
+                        </foreach>
+                    </trim>
+                </if>
             </foreach>
-          </trim>
-        </if>
-      </foreach>
-    </where>
-  </sql>
-  <sql id="Update_By_Example_Where_Clause">
-    <where>
-      <foreach collection="example.oredCriteria" item="criteria" separator="or">
-        <if test="criteria.valid">
-          <trim prefix="(" prefixOverrides="and" suffix=")">
-            <foreach collection="criteria.criteria" item="criterion">
-              <choose>
-                <when test="criterion.noValue">
-                  and ${criterion.condition}
-                </when>
-                <when test="criterion.singleValue">
-                  and ${criterion.condition} #{criterion.value}
-                </when>
-                <when test="criterion.betweenValue">
-                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
-                </when>
-                <when test="criterion.listValue">
-                  and ${criterion.condition}
-                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
-                    #{listItem}
-                  </foreach>
-                </when>
-              </choose>
+        </where>
+    </sql>
+    <sql id="Update_By_Example_Where_Clause">
+        <where>
+            <foreach collection="example.oredCriteria" item="criteria" separator="or">
+                <if test="criteria.valid">
+                    <trim prefix="(" prefixOverrides="and" suffix=")">
+                        <foreach collection="criteria.criteria" item="criterion">
+                            <choose>
+                                <when test="criterion.noValue">
+                                    and ${criterion.condition}
+                                </when>
+                                <when test="criterion.singleValue">
+                                    and ${criterion.condition} #{criterion.value}
+                                </when>
+                                <when test="criterion.betweenValue">
+                                    and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+                                </when>
+                                <when test="criterion.listValue">
+                                    and ${criterion.condition}
+                                    <foreach close=")" collection="criterion.value" item="listItem" open="("
+                                             separator=",">
+                                        #{listItem}
+                                    </foreach>
+                                </when>
+                            </choose>
+                        </foreach>
+                    </trim>
+                </if>
             </foreach>
-          </trim>
-        </if>
-      </foreach>
-    </where>
-  </sql>
-  <sql id="Base_Column_List">
-    id, external_user_id, union_id, external_user_id_3rd_party, `type`, `name`, avatar, 
+        </where>
+    </sql>
+    <sql id="Base_Column_List">
+        id
+        , external_user_id, union_id, external_user_id_3rd_party, `type`, `name`, avatar,
     gender, is_delete, created_at, updated_at, deleted_at, create_time, update_time
-  </sql>
-  <select id="selectByExample" parameterType="com.tzld.piaoquan.wecom.model.po.UserExample" resultMap="BaseResultMap">
-    select
-    <if test="distinct">
-      distinct
-    </if>
-    <include refid="Base_Column_List" />
-    from we_com_user
-    <if test="_parameter != null">
-      <include refid="Example_Where_Clause" />
-    </if>
-    <if test="orderByClause != null">
-      order by ${orderByClause}
-    </if>
-    <if test="page != null">
-      limit #{page.offset} , #{page.pageSize}
-    </if>
-  </select>
-  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
-    select 
-    <include refid="Base_Column_List" />
-    from we_com_user
-    where id = #{id,jdbcType=BIGINT}
-  </select>
-  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
-    delete from we_com_user
-    where id = #{id,jdbcType=BIGINT}
-  </delete>
-  <delete id="deleteByExample" parameterType="com.tzld.piaoquan.wecom.model.po.UserExample">
-    delete from we_com_user
-    <if test="_parameter != null">
-      <include refid="Example_Where_Clause" />
-    </if>
-  </delete>
-  <insert id="insert" parameterType="com.tzld.piaoquan.wecom.model.po.User">
-    insert into we_com_user (id, external_user_id, union_id, 
-      external_user_id_3rd_party, `type`, `name`, 
-      avatar, gender,
-      created_at, updated_at, deleted_at, 
-      create_time, update_time)
-    values (#{id,jdbcType=BIGINT}, #{externalUserId,jdbcType=VARCHAR}, #{unionId,jdbcType=VARCHAR}, 
-      #{externalUserId3rdParty,jdbcType=VARCHAR}, #{type,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, 
-      #{avatar,jdbcType=VARCHAR}, #{gender,jdbcType=INTEGER},
-      #{createdAt,jdbcType=BIGINT}, #{updatedAt,jdbcType=BIGINT}, #{deletedAt,jdbcType=BIGINT}, 
-      #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP})
-  </insert>
-  <insert id="insertSelective" parameterType="com.tzld.piaoquan.wecom.model.po.User">
-    insert into we_com_user
-    <trim prefix="(" suffix=")" suffixOverrides=",">
-      <if test="id != null">
-        id,
-      </if>
-      <if test="externalUserId != null">
-        external_user_id,
-      </if>
-      <if test="unionId != null">
-        union_id,
-      </if>
-      <if test="externalUserId3rdParty != null">
-        external_user_id_3rd_party,
-      </if>
-      <if test="type != null">
-        `type`,
-      </if>
-      <if test="name != null">
-        `name`,
-      </if>
-      <if test="avatar != null">
-        avatar,
-      </if>
-      <if test="gender != null">
-        gender,
-      </if>
-      <if test="isDelete != null">
-        is_delete,
-      </if>
-      <if test="createdAt != null">
-        created_at,
-      </if>
-      <if test="updatedAt != null">
-        updated_at,
-      </if>
-      <if test="deletedAt != null">
-        deleted_at,
-      </if>
-      <if test="createTime != null">
-        create_time,
-      </if>
-      <if test="updateTime != null">
-        update_time,
-      </if>
-    </trim>
-    <trim prefix="values (" suffix=")" suffixOverrides=",">
-      <if test="id != null">
-        #{id,jdbcType=BIGINT},
-      </if>
-      <if test="externalUserId != null">
-        #{externalUserId,jdbcType=VARCHAR},
-      </if>
-      <if test="unionId != null">
-        #{unionId,jdbcType=VARCHAR},
-      </if>
-      <if test="externalUserId3rdParty != null">
-        #{externalUserId3rdParty,jdbcType=VARCHAR},
-      </if>
-      <if test="type != null">
-        #{type,jdbcType=INTEGER},
-      </if>
-      <if test="name != null">
-        #{name,jdbcType=VARCHAR},
-      </if>
-      <if test="avatar != null">
-        #{avatar,jdbcType=VARCHAR},
-      </if>
-      <if test="gender != null">
-        #{gender,jdbcType=INTEGER},
-      </if>
-      <if test="isDelete != null">
-        #{isDelete,jdbcType=INTEGER},
-      </if>
-      <if test="createdAt != null">
-        #{createdAt,jdbcType=BIGINT},
-      </if>
-      <if test="updatedAt != null">
-        #{updatedAt,jdbcType=BIGINT},
-      </if>
-      <if test="deletedAt != null">
-        #{deletedAt,jdbcType=BIGINT},
-      </if>
-      <if test="createTime != null">
-        #{createTime,jdbcType=TIMESTAMP},
-      </if>
-      <if test="updateTime != null">
-        #{updateTime,jdbcType=TIMESTAMP},
-      </if>
-    </trim>
-  </insert>
-  <select id="countByExample" parameterType="com.tzld.piaoquan.wecom.model.po.UserExample" resultType="java.lang.Long">
-    select count(*) from we_com_user
-    <if test="_parameter != null">
-      <include refid="Example_Where_Clause" />
-    </if>
-  </select>
-  <update id="updateByExampleSelective" parameterType="map">
-    update we_com_user
-    <set>
-      <if test="record.id != null">
-        id = #{record.id,jdbcType=BIGINT},
-      </if>
-      <if test="record.externalUserId != null">
+    </sql>
+    <select id="selectByExample" parameterType="com.tzld.piaoquan.wecom.model.po.UserExample" resultMap="BaseResultMap">
+        select
+        <if test="distinct">
+            distinct
+        </if>
+        <include refid="Base_Column_List"/>
+        from we_com_user
+        <if test="_parameter != null">
+            <include refid="Example_Where_Clause"/>
+        </if>
+        <if test="orderByClause != null">
+            order by ${orderByClause}
+        </if>
+        <if test="page != null">
+            limit #{page.offset} , #{page.pageSize}
+        </if>
+    </select>
+    <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from we_com_user
+        where id = #{id,jdbcType=BIGINT}
+    </select>
+    <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+        delete
+        from we_com_user
+        where id = #{id,jdbcType=BIGINT}
+    </delete>
+    <delete id="deleteByExample" parameterType="com.tzld.piaoquan.wecom.model.po.UserExample">
+        delete from we_com_user
+        <if test="_parameter != null">
+            <include refid="Example_Where_Clause"/>
+        </if>
+    </delete>
+    <insert id="insert" parameterType="com.tzld.piaoquan.wecom.model.po.User" useGeneratedKeys="true" keyProperty="id">
+        insert into we_com_user (id, external_user_id, union_id,
+        external_user_id_3rd_party, `type`, `name`,
+        avatar, gender,
+        created_at, updated_at, deleted_at,
+        create_time, update_time)
+        values (#{id,jdbcType=BIGINT}, #{externalUserId,jdbcType=VARCHAR}, #{unionId,jdbcType=VARCHAR},
+        #{externalUserId3rdParty,jdbcType=VARCHAR}, #{type,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR},
+        #{avatar,jdbcType=VARCHAR}, #{gender,jdbcType=INTEGER},
+        #{createdAt,jdbcType=BIGINT}, #{updatedAt,jdbcType=BIGINT}, #{deletedAt,jdbcType=BIGINT},
+        #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP})
+        <selectKey resultType="java.lang.Long" order="AFTER" keyProperty="id">
+            select LAST_INSERT_ID()
+        </selectKey>
+    </insert>
+    <insert id="insertSelective" parameterType="com.tzld.piaoquan.wecom.model.po.User">
+        insert into we_com_user
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">
+                id,
+            </if>
+            <if test="externalUserId != null">
+                external_user_id,
+            </if>
+            <if test="unionId != null">
+                union_id,
+            </if>
+            <if test="externalUserId3rdParty != null">
+                external_user_id_3rd_party,
+            </if>
+            <if test="type != null">
+                `type`,
+            </if>
+            <if test="name != null">
+                `name`,
+            </if>
+            <if test="avatar != null">
+                avatar,
+            </if>
+            <if test="gender != null">
+                gender,
+            </if>
+            <if test="isDelete != null">
+                is_delete,
+            </if>
+            <if test="createdAt != null">
+                created_at,
+            </if>
+            <if test="updatedAt != null">
+                updated_at,
+            </if>
+            <if test="deletedAt != null">
+                deleted_at,
+            </if>
+            <if test="createTime != null">
+                create_time,
+            </if>
+            <if test="updateTime != null">
+                update_time,
+            </if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">
+                #{id,jdbcType=BIGINT},
+            </if>
+            <if test="externalUserId != null">
+                #{externalUserId,jdbcType=VARCHAR},
+            </if>
+            <if test="unionId != null">
+                #{unionId,jdbcType=VARCHAR},
+            </if>
+            <if test="externalUserId3rdParty != null">
+                #{externalUserId3rdParty,jdbcType=VARCHAR},
+            </if>
+            <if test="type != null">
+                #{type,jdbcType=INTEGER},
+            </if>
+            <if test="name != null">
+                #{name,jdbcType=VARCHAR},
+            </if>
+            <if test="avatar != null">
+                #{avatar,jdbcType=VARCHAR},
+            </if>
+            <if test="gender != null">
+                #{gender,jdbcType=INTEGER},
+            </if>
+            <if test="isDelete != null">
+                #{isDelete,jdbcType=INTEGER},
+            </if>
+            <if test="createdAt != null">
+                #{createdAt,jdbcType=BIGINT},
+            </if>
+            <if test="updatedAt != null">
+                #{updatedAt,jdbcType=BIGINT},
+            </if>
+            <if test="deletedAt != null">
+                #{deletedAt,jdbcType=BIGINT},
+            </if>
+            <if test="createTime != null">
+                #{createTime,jdbcType=TIMESTAMP},
+            </if>
+            <if test="updateTime != null">
+                #{updateTime,jdbcType=TIMESTAMP},
+            </if>
+        </trim>
+    </insert>
+    <select id="countByExample" parameterType="com.tzld.piaoquan.wecom.model.po.UserExample"
+            resultType="java.lang.Long">
+        select count(*) from we_com_user
+        <if test="_parameter != null">
+            <include refid="Example_Where_Clause"/>
+        </if>
+    </select>
+    <update id="updateByExampleSelective" parameterType="map">
+        update we_com_user
+        <set>
+            <if test="record.id != null">
+                id = #{record.id,jdbcType=BIGINT},
+            </if>
+            <if test="record.externalUserId != null">
+                external_user_id = #{record.externalUserId,jdbcType=VARCHAR},
+            </if>
+            <if test="record.unionId != null">
+                union_id = #{record.unionId,jdbcType=VARCHAR},
+            </if>
+            <if test="record.externalUserId3rdParty != null">
+                external_user_id_3rd_party = #{record.externalUserId3rdParty,jdbcType=VARCHAR},
+            </if>
+            <if test="record.type != null">
+                `type` = #{record.type,jdbcType=INTEGER},
+            </if>
+            <if test="record.name != null">
+                `name` = #{record.name,jdbcType=VARCHAR},
+            </if>
+            <if test="record.avatar != null">
+                avatar = #{record.avatar,jdbcType=VARCHAR},
+            </if>
+            <if test="record.gender != null">
+                gender = #{record.gender,jdbcType=INTEGER},
+            </if>
+            <if test="record.isDelete != null">
+                is_delete = #{record.isDelete,jdbcType=INTEGER},
+            </if>
+            <if test="record.createdAt != null">
+                created_at = #{record.createdAt,jdbcType=BIGINT},
+            </if>
+            <if test="record.updatedAt != null">
+                updated_at = #{record.updatedAt,jdbcType=BIGINT},
+            </if>
+            <if test="record.deletedAt != null">
+                deleted_at = #{record.deletedAt,jdbcType=BIGINT},
+            </if>
+            <if test="record.createTime != null">
+                create_time = #{record.createTime,jdbcType=TIMESTAMP},
+            </if>
+            <if test="record.updateTime != null">
+                update_time = #{record.updateTime,jdbcType=TIMESTAMP},
+            </if>
+        </set>
+        <if test="_parameter != null">
+            <include refid="Update_By_Example_Where_Clause"/>
+        </if>
+    </update>
+    <update id="updateByExample" parameterType="map">
+        update we_com_user
+        set id = #{record.id,jdbcType=BIGINT},
         external_user_id = #{record.externalUserId,jdbcType=VARCHAR},
-      </if>
-      <if test="record.unionId != null">
         union_id = #{record.unionId,jdbcType=VARCHAR},
-      </if>
-      <if test="record.externalUserId3rdParty != null">
         external_user_id_3rd_party = #{record.externalUserId3rdParty,jdbcType=VARCHAR},
-      </if>
-      <if test="record.type != null">
         `type` = #{record.type,jdbcType=INTEGER},
-      </if>
-      <if test="record.name != null">
         `name` = #{record.name,jdbcType=VARCHAR},
-      </if>
-      <if test="record.avatar != null">
         avatar = #{record.avatar,jdbcType=VARCHAR},
-      </if>
-      <if test="record.gender != null">
         gender = #{record.gender,jdbcType=INTEGER},
-      </if>
-      <if test="record.isDelete != null">
         is_delete = #{record.isDelete,jdbcType=INTEGER},
-      </if>
-      <if test="record.createdAt != null">
         created_at = #{record.createdAt,jdbcType=BIGINT},
-      </if>
-      <if test="record.updatedAt != null">
         updated_at = #{record.updatedAt,jdbcType=BIGINT},
-      </if>
-      <if test="record.deletedAt != null">
         deleted_at = #{record.deletedAt,jdbcType=BIGINT},
-      </if>
-      <if test="record.createTime != null">
         create_time = #{record.createTime,jdbcType=TIMESTAMP},
-      </if>
-      <if test="record.updateTime != null">
-        update_time = #{record.updateTime,jdbcType=TIMESTAMP},
-      </if>
-    </set>
-    <if test="_parameter != null">
-      <include refid="Update_By_Example_Where_Clause" />
-    </if>
-  </update>
-  <update id="updateByExample" parameterType="map">
-    update we_com_user
-    set id = #{record.id,jdbcType=BIGINT},
-      external_user_id = #{record.externalUserId,jdbcType=VARCHAR},
-      union_id = #{record.unionId,jdbcType=VARCHAR},
-      external_user_id_3rd_party = #{record.externalUserId3rdParty,jdbcType=VARCHAR},
-      `type` = #{record.type,jdbcType=INTEGER},
-      `name` = #{record.name,jdbcType=VARCHAR},
-      avatar = #{record.avatar,jdbcType=VARCHAR},
-      gender = #{record.gender,jdbcType=INTEGER},
-      is_delete = #{record.isDelete,jdbcType=INTEGER},
-      created_at = #{record.createdAt,jdbcType=BIGINT},
-      updated_at = #{record.updatedAt,jdbcType=BIGINT},
-      deleted_at = #{record.deletedAt,jdbcType=BIGINT},
-      create_time = #{record.createTime,jdbcType=TIMESTAMP},
-      update_time = #{record.updateTime,jdbcType=TIMESTAMP}
-    <if test="_parameter != null">
-      <include refid="Update_By_Example_Where_Clause" />
-    </if>
-  </update>
-  <update id="updateByPrimaryKeySelective" parameterType="com.tzld.piaoquan.wecom.model.po.User">
-    update we_com_user
-    <set>
-      <if test="externalUserId != null">
-        external_user_id = #{externalUserId,jdbcType=VARCHAR},
-      </if>
-      <if test="unionId != null">
-        union_id = #{unionId,jdbcType=VARCHAR},
-      </if>
-      <if test="externalUserId3rdParty != null">
-        external_user_id_3rd_party = #{externalUserId3rdParty,jdbcType=VARCHAR},
-      </if>
-      <if test="type != null">
-        `type` = #{type,jdbcType=INTEGER},
-      </if>
-      <if test="name != null">
-        `name` = #{name,jdbcType=VARCHAR},
-      </if>
-      <if test="avatar != null">
-        avatar = #{avatar,jdbcType=VARCHAR},
-      </if>
-      <if test="gender != null">
-        gender = #{gender,jdbcType=INTEGER},
-      </if>
-      <if test="isDelete != null">
-        is_delete = #{isDelete,jdbcType=INTEGER},
-      </if>
-      <if test="createdAt != null">
-        created_at = #{createdAt,jdbcType=BIGINT},
-      </if>
-      <if test="updatedAt != null">
-        updated_at = #{updatedAt,jdbcType=BIGINT},
-      </if>
-      <if test="deletedAt != null">
-        deleted_at = #{deletedAt,jdbcType=BIGINT},
-      </if>
-      <if test="createTime != null">
-        create_time = #{createTime,jdbcType=TIMESTAMP},
-      </if>
-      <if test="updateTime != null">
-        update_time = #{updateTime,jdbcType=TIMESTAMP},
-      </if>
-    </set>
-    where id = #{id,jdbcType=BIGINT}
-  </update>
-  <update id="updateByPrimaryKey" parameterType="com.tzld.piaoquan.wecom.model.po.User">
-    update we_com_user
-    set external_user_id = #{externalUserId,jdbcType=VARCHAR},
-      union_id = #{unionId,jdbcType=VARCHAR},
-      external_user_id_3rd_party = #{externalUserId3rdParty,jdbcType=VARCHAR},
-      `type` = #{type,jdbcType=INTEGER},
-      `name` = #{name,jdbcType=VARCHAR},
-      avatar = #{avatar,jdbcType=VARCHAR},
-      gender = #{gender,jdbcType=INTEGER},
-      is_delete = #{isDelete,jdbcType=INTEGER},
-      created_at = #{createdAt,jdbcType=BIGINT},
-      updated_at = #{updatedAt,jdbcType=BIGINT},
-      deleted_at = #{deletedAt,jdbcType=BIGINT},
-      create_time = #{createTime,jdbcType=TIMESTAMP},
-      update_time = #{updateTime,jdbcType=TIMESTAMP}
-    where id = #{id,jdbcType=BIGINT}
-  </update>
+        update_time = #{record.updateTime,jdbcType=TIMESTAMP}
+        <if test="_parameter != null">
+            <include refid="Update_By_Example_Where_Clause"/>
+        </if>
+    </update>
+    <update id="updateByPrimaryKeySelective" parameterType="com.tzld.piaoquan.wecom.model.po.User">
+        update we_com_user
+        <set>
+            <if test="externalUserId != null">
+                external_user_id = #{externalUserId,jdbcType=VARCHAR},
+            </if>
+            <if test="unionId != null">
+                union_id = #{unionId,jdbcType=VARCHAR},
+            </if>
+            <if test="externalUserId3rdParty != null">
+                external_user_id_3rd_party = #{externalUserId3rdParty,jdbcType=VARCHAR},
+            </if>
+            <if test="type != null">
+                `type` = #{type,jdbcType=INTEGER},
+            </if>
+            <if test="name != null">
+                `name` = #{name,jdbcType=VARCHAR},
+            </if>
+            <if test="avatar != null">
+                avatar = #{avatar,jdbcType=VARCHAR},
+            </if>
+            <if test="gender != null">
+                gender = #{gender,jdbcType=INTEGER},
+            </if>
+            <if test="isDelete != null">
+                is_delete = #{isDelete,jdbcType=INTEGER},
+            </if>
+            <if test="createdAt != null">
+                created_at = #{createdAt,jdbcType=BIGINT},
+            </if>
+            <if test="updatedAt != null">
+                updated_at = #{updatedAt,jdbcType=BIGINT},
+            </if>
+            <if test="deletedAt != null">
+                deleted_at = #{deletedAt,jdbcType=BIGINT},
+            </if>
+            <if test="createTime != null">
+                create_time = #{createTime,jdbcType=TIMESTAMP},
+            </if>
+            <if test="updateTime != null">
+                update_time = #{updateTime,jdbcType=TIMESTAMP},
+            </if>
+        </set>
+        where id = #{id,jdbcType=BIGINT}
+    </update>
+    <update id="updateByPrimaryKey" parameterType="com.tzld.piaoquan.wecom.model.po.User">
+        update we_com_user
+        set external_user_id           = #{externalUserId,jdbcType=VARCHAR},
+            union_id                   = #{unionId,jdbcType=VARCHAR},
+            external_user_id_3rd_party = #{externalUserId3rdParty,jdbcType=VARCHAR},
+            `type`                     = #{type,jdbcType=INTEGER},
+            `name`                     = #{name,jdbcType=VARCHAR},
+            avatar                     = #{avatar,jdbcType=VARCHAR},
+            gender                     = #{gender,jdbcType=INTEGER},
+            is_delete                  = #{isDelete,jdbcType=INTEGER},
+            created_at                 = #{createdAt,jdbcType=BIGINT},
+            updated_at                 = #{updatedAt,jdbcType=BIGINT},
+            deleted_at                 = #{deletedAt,jdbcType=BIGINT},
+            create_time                = #{createTime,jdbcType=TIMESTAMP},
+            update_time                = #{updateTime,jdbcType=TIMESTAMP}
+        where id = #{id,jdbcType=BIGINT}
+    </update>
 
 
-  <select id="selectIdByExternalUserId3rdParty" parameterType="String" resultType="Long">
-    select
-        id
-    from we_com_user
-    where external_user_id_3rd_party = #{externalUserId3rdParty}
-  </select>
+    <select id="selectIdByExternalUserId3rdParty" parameterType="String" resultType="Long">
+        select id
+        from we_com_user
+        where external_user_id_3rd_party = #{externalUserId3rdParty}
+    </select>
 
-  <insert id="insertList" parameterType="java.util.List">
-    insert into we_com_user
-    (
-    external_user_id,
-    union_id,
-    external_user_id_3rd_party,
-    `type`,
-    `name`,
-    avatar,
-    gender,
-    created_at,
-    updated_at,
-    deleted_at,
-    create_time,
-    update_time
-    )
-    values
-    <foreach collection="list" item="item" separator=",">
-      (
-      #{item.externalUserId,jdbcType=VARCHAR},
-      #{item.unionId,jdbcType=VARCHAR},
-      #{item.externalUserId3rdParty,jdbcType=VARCHAR},
-      #{item.type,jdbcType=INTEGER},
-      #{item.name,jdbcType=VARCHAR},
-      #{item.avatar,jdbcType=VARCHAR},
-      #{item.gender,jdbcType=INTEGER},
-      #{item.createdAt,jdbcType=BIGINT},
-      #{item.updatedAt,jdbcType=BIGINT},
-      #{item.deletedAt,jdbcType=BIGINT},
-      #{item.createTime,jdbcType=TIMESTAMP},
-      #{item.updateTime,jdbcType=TIMESTAMP}
-      )
-    </foreach>
-  </insert>
+    <select id="selectIdByExternalUserId" parameterType="String" resultType="Long">
+        select id
+        from we_com_user
+        where external_user_id = #{externalUserId}
+    </select>
+
+    <insert id="insertList" parameterType="java.util.List">
+        insert into we_com_user
+        (
+        external_user_id,
+        union_id,
+        external_user_id_3rd_party,
+        `type`,
+        `name`,
+        avatar,
+        gender,
+        created_at,
+        updated_at,
+        deleted_at,
+        create_time,
+        update_time
+        )
+        values
+        <foreach collection="list" item="item" separator=",">
+            (
+            #{item.externalUserId,jdbcType=VARCHAR},
+            #{item.unionId,jdbcType=VARCHAR},
+            #{item.externalUserId3rdParty,jdbcType=VARCHAR},
+            #{item.type,jdbcType=INTEGER},
+            #{item.name,jdbcType=VARCHAR},
+            #{item.avatar,jdbcType=VARCHAR},
+            #{item.gender,jdbcType=INTEGER},
+            #{item.createdAt,jdbcType=BIGINT},
+            #{item.updatedAt,jdbcType=BIGINT},
+            #{item.deletedAt,jdbcType=BIGINT},
+            #{item.createTime,jdbcType=TIMESTAMP},
+            #{item.updateTime,jdbcType=TIMESTAMP}
+            )
+        </foreach>
+    </insert>
 </mapper>

+ 2 - 2
we-com-server/src/main/resources/mybatis-generator-config.xml

@@ -50,8 +50,8 @@
             <property name="enableSubPackages" value="true"/>
         </javaClientGenerator>
 
-        <table tableName="we_com_alert_message" domainObjectName="AlertMessage" alias=""/>
-<!--        <table tableName="we_com_history_message" domainObjectName="HistoryMessage" alias=""/>-->
+<!--        <table tableName="we_com_alert_message" domainObjectName="AlertMessage" alias=""/>-->
+        <table tableName="we_com_history_message" domainObjectName="HistoryMessage" alias=""/>
 <!--        <table tableName="we_com_message_attachment" domainObjectName="MessageAttachment" alias=""/>-->
 <!--        <table tableName="we_com_staff" domainObjectName="Staff" alias=""/>-->
 <!--        <table tableName="we_com_staff_with_user" domainObjectName="StaffWithUser" alias=""/>-->