Browse Source

Merge remote-tracking branch 'refs/remotes/origin/develop_zqc' into develop_rayson

# Conflicts:
#	citu-gateway/src/main/resources/banner.txt
rayson 10 months ago
parent
commit
f0da32d141
41 changed files with 1688 additions and 85 deletions
  1. 27 27
      citu-gateway/src/main/java/com/citu/gateway/util/BannerApplicationRunner.java
  2. 1 14
      citu-gateway/src/main/resources/banner.txt
  3. 12 0
      menduner/menduner-im-biz/pom.xml
  4. 51 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/ImStatisticsController.java
  5. 17 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/WuKongSessionController.java
  6. 24 4
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/WuKongWebhookController.java
  7. 107 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/statistics/ImRecentConversationsStatisticsReqVo.java
  8. 61 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/statistics/imRecentConversationsStatisticsRespVo.java
  9. 12 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/user/ImUserInfoVo.java
  10. 27 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ChannelDeleteReqVo.java
  11. 11 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ConversationSyncRespVo.java
  12. 58 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ConversationsUnreadReqVo.java
  13. 51 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ImHeaderReqVo.java
  14. 104 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ImMessageSendReqVo.java
  15. 33 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ImUserDeviceQuitReqVo.java
  16. 37 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/MessageSendbatchRespVo.java
  17. 47 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserMsgPageReqVO.java
  18. 62 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserMsgRespVO.java
  19. 48 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserMsgSaveReqVO.java
  20. 29 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserOnlinePageReqVO.java
  21. 38 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserOnlineRespVO.java
  22. 30 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserOnlineSaveReqVO.java
  23. 87 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/dal/dataobject/UserMsgDO.java
  24. 49 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/dal/dataobject/UserOnlineDO.java
  25. 36 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/dal/mysql/UserMsgMapper.java
  26. 30 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/dal/mysql/UserOnlineMapper.java
  27. 18 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/dal/mysql/statistics/ImRecentConversationsStatisticsMapper.java
  28. 2 1
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/framework/rpc/config/RpcConfiguration.java
  29. 1 1
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/framework/security/config/SecurityConfiguration.java
  30. 0 23
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/interceptor/WuKongWuKongApiInterceptor.java
  31. 144 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/mybatis/plugin/SqlInterceptor.java
  32. 44 5
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/UserServiceImpl.java
  33. 8 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/statistics/ImRecentConversationsStatisticsService.java
  34. 124 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/statistics/ImRecentConversationsStatisticsServiceImpl.java
  35. 61 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/wukong/WuKongApiService.java
  36. 3 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/wukong/WuKongSessionService.java
  37. 20 6
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/wukong/WuKongSessionServiceImpl.java
  38. 10 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/wukong/WukongWebhookService.java
  39. 94 0
      menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/wukong/WukongWebhookServiceImpl.java
  40. 7 4
      menduner/menduner-im-biz/src/main/resources/bootstrap.yaml
  41. 63 0
      menduner/menduner-im-biz/src/main/resources/mapper/statistics/ImRecentConversationsStatisticsMapper.xml

+ 27 - 27
citu-gateway/src/main/java/com/citu/gateway/util/BannerApplicationRunner.java

@@ -19,33 +19,33 @@ public class BannerApplicationRunner implements ApplicationRunner {
 
     @Override
     public void run(ApplicationArguments args) {
-        ThreadUtil.execute(() -> {
-            ThreadUtil.sleep(1, TimeUnit.SECONDS); // 延迟 1 秒,保证输出到结尾
-            log.info("\n----------------------------------------------------------\n\t" +
-                            "项目启动成功!\n\t" +
-                            "接口文档: \t{} \n\t" +
-                            "开发文档: \t{} \n\t" +
-                            "视频教程: \t{} \n" +
-                            "----------------------------------------------------------",
-                    "https://cloud.iocoder.cn/api-doc/",
-                    "https://cloud.iocoder.cn",
-                    "https://t.zsxq.com/02Yf6M7Qn");
-
-            // 数据报表
-            System.out.println("[报表模块 citu-module-report 教程][参考 https://cloud.iocoder.cn/report/ 开启]");
-            // 工作流
-            System.out.println("[工作流模块 citu-module-bpm 教程][参考 https://cloud.iocoder.cn/bpm/ 开启]");
-            // 商城系统
-            System.out.println("[商城系统 citu-module-mall 教程][参考 https://cloud.iocoder.cn/mall/build/ 开启]");
-            // ERP 系统
-            System.out.println("[ERP 系统 citu-module-erp - 教程][参考 https://cloud.iocoder.cn/erp/build/ 开启]");
-            // CRM 系统
-            System.out.println("[CRM 系统 citu-module-crm - 教程][参考 https://cloud.iocoder.cn/crm/build/ 开启]");
-            // 微信公众号
-            System.out.println("[微信公众号 citu-module-mp 教程][参考 https://cloud.iocoder.cn/mp/build/ 开启]");
-            // 支付平台
-            System.out.println("[支付系统 citu-module-pay - 教程][参考 https://doc.iocoder.cn/pay/build/ 开启]");
-        });
+//        ThreadUtil.execute(() -> {
+//            ThreadUtil.sleep(1, TimeUnit.SECONDS); // 延迟 1 秒,保证输出到结尾
+//            log.info("\n----------------------------------------------------------\n\t" +
+//                            "项目启动成功!\n\t" +
+//                            "接口文档: \t{} \n\t" +
+//                            "开发文档: \t{} \n\t" +
+//                            "视频教程: \t{} \n" +
+//                            "----------------------------------------------------------",
+//                    "https://cloud.iocoder.cn/api-doc/",
+//                    "https://cloud.iocoder.cn",
+//                    "https://t.zsxq.com/02Yf6M7Qn");
+//
+//            // 数据报表
+//            System.out.println("[报表模块 citu-module-report 教程][参考 https://cloud.iocoder.cn/report/ 开启]");
+//            // 工作流
+//            System.out.println("[工作流模块 citu-module-bpm 教程][参考 https://cloud.iocoder.cn/bpm/ 开启]");
+//            // 商城系统
+//            System.out.println("[商城系统 citu-module-mall 教程][参考 https://cloud.iocoder.cn/mall/build/ 开启]");
+//            // ERP 系统
+//            System.out.println("[ERP 系统 citu-module-erp - 教程][参考 https://cloud.iocoder.cn/erp/build/ 开启]");
+//            // CRM 系统
+//            System.out.println("[CRM 系统 citu-module-crm - 教程][参考 https://cloud.iocoder.cn/crm/build/ 开启]");
+//            // 微信公众号
+//            System.out.println("[微信公众号 citu-module-mp 教程][参考 https://cloud.iocoder.cn/mp/build/ 开启]");
+//            // 支付平台
+//            System.out.println("[支付系统 citu-module-pay - 教程][参考 https://doc.iocoder.cn/pay/build/ 开启]");
+//        });
     }
 
 }

+ 1 - 14
citu-gateway/src/main/resources/banner.txt

@@ -1,17 +1,4 @@
-Rayson http://www.iocoder.cn
+
 Application Version: ${citu.info.version}
 Spring Boot Version: ${spring-boot.version}
 
-.__   __.   ______      .______    __    __    _______
-|  \ |  |  /  __  \     |   _  \  |  |  |  |  /  _____|
-|   \|  | |  |  |  |    |  |_)  | |  |  |  | |  |  __
-|  . `  | |  |  |  |    |   _  <  |  |  |  | |  | |_ |
-|  |\   | |  `--'  |    |  |_)  | |  `--'  | |  |__| |
-|__| \__|  \______/     |______/   \______/   \______|
-
-███╗   ██╗ ██████╗     ██████╗ ██╗   ██╗ ██████╗
-████╗  ██║██╔═══██╗    ██╔══██╗██║   ██║██╔════╝
-██╔██╗ ██║██║   ██║    ██████╔╝██║   ██║██║  ███╗
-██║╚██╗██║██║   ██║    ██╔══██╗██║   ██║██║   ██║
-██║ ╚████║╚██████╔╝    ██████╔╝╚██████╔╝╚██████╔╝
-╚═╝  ╚═══╝ ╚═════╝     ╚═════╝  ╚═════╝  ╚═════╝

+ 12 - 0
menduner/menduner-im-biz/pom.xml

@@ -31,6 +31,12 @@
             <version>${revision}</version>
         </dependency>
 
+        <dependency>
+            <groupId>com.citu</groupId>
+            <artifactId>menduner-system-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
+
 
         <!-- Registry 注册中心相关 -->
         <dependency>
@@ -50,6 +56,12 @@
             <artifactId>citu-spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.citu</groupId>
+            <artifactId>menduner-system-api</artifactId>
+            <version>2.1.0-snapshot</version>
+            <scope>compile</scope>
+        </dependency>
 
     </dependencies>
 

+ 51 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/ImStatisticsController.java

@@ -0,0 +1,51 @@
+package com.citu.module.menduner.im.controller.app;
+
+
+import com.citu.framework.common.pojo.CommonResult;
+import com.citu.module.menduner.im.controller.app.base.statistics.ImRecentConversationsStatisticsReqVo;
+import com.citu.module.menduner.im.controller.app.base.statistics.imRecentConversationsStatisticsRespVo;
+import com.citu.module.menduner.im.service.statistics.ImRecentConversationsStatisticsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @eo.api-type http
+ * @eo.groupName 新门墩.聊天.统计分析
+ * @eo.path /app-api
+ */
+
+@RestController
+public class ImStatisticsController {
+
+
+    ImRecentConversationsStatisticsService service;
+
+    /**
+     * @eo.name 联系我的和我联系的统计
+     * @eo.url /im/recent/conversations/statistics
+     * @eo.method post
+     * @eo.request-type json
+     * @param reqVo
+     * @return CommonResult
+     */
+    @PostMapping("/im/recent/conversations/statistics")
+    public CommonResult<imRecentConversationsStatisticsRespVo>
+                    imRecentConversationsStatistics(@RequestBody ImRecentConversationsStatisticsReqVo reqVo){
+        return service.imRecentConversationsStatistics(reqVo);
+    }
+
+    /**
+     * @eo.name setService
+     * @eo.url
+     * @eo.method get
+     * @eo.request-type formdata
+     * @param service
+     * @return void
+     */
+    @Autowired
+    public void setService(ImRecentConversationsStatisticsService service) {
+        this.service = service;
+    }
+}

+ 17 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/WuKongSessionController.java

@@ -4,6 +4,7 @@ import com.citu.framework.common.pojo.CommonResult;
 import com.citu.framework.security.core.annotations.PreAuthenticated;
 import com.citu.module.menduner.im.controller.app.base.wukong.ConversationSyncReqVo;
 import com.citu.module.menduner.im.controller.app.base.wukong.ConversationsDeleteReqVo;
+import com.citu.module.menduner.im.controller.app.base.wukong.ConversationsUnreadReqVo;
 import com.citu.module.menduner.im.service.wukong.WuKongSessionService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -52,6 +53,22 @@ public class WuKongSessionController {
     }
 
 
+    /**
+     * @eo.name 设置最近会话未读数量
+     * @eo.urlconversations/setUnread
+     * @eo.method post
+     * @eo.request-type json
+     * @param reqVo
+     * @return CommonResult
+     */
+    @PreAuthenticated
+    @PostMapping("/conversations/setUnread")
+    public CommonResult conversatioSetUnread(@RequestBody ConversationsUnreadReqVo reqVo){
+        return service.conversatioSetUnread(reqVo);
+    }
+
+
+
 
     /**
      * @eo.name setService

+ 24 - 4
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/WuKongWebhookController.java

@@ -1,19 +1,39 @@
 package com.citu.module.menduner.im.controller.app;
 
+import com.alibaba.fastjson.JSON;
 import com.citu.framework.common.pojo.CommonResult;
+import com.citu.module.menduner.im.service.wukong.WukongWebhookService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.security.PermitAll;
+import java.util.List;
 import java.util.Map;
 
 @RestController
 public class WuKongWebhookController {
 
 
-//    @PostMapping("/wukong/webhook")
-//    public CommonResult wukongWebhook(@RequestParam("event")String event, @RequestParam Map reqVo){
-//
-//    }
+    WukongWebhookService service;
 
+    /**
+     * 悟空 web hook 回调
+     * @param event
+     * @param reqVo
+     * @return
+     */
+    @PermitAll
+    @PostMapping("/im/wukong/webhook")
+    public CommonResult wukongWebhook(@RequestParam("event")String event, @RequestBody String reqVo){
+            return service.wukongWebhook(event, reqVo);
+    }
+
+
+    @Autowired
+    public void setService(WukongWebhookService service) {
+        this.service = service;
+    }
 }

+ 107 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/statistics/ImRecentConversationsStatisticsReqVo.java

@@ -0,0 +1,107 @@
+package com.citu.module.menduner.im.controller.app.base.statistics;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static com.citu.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+public class ImRecentConversationsStatisticsReqVo {
+
+    /**
+     * 企业id选传
+     */
+
+    private Long enterpriseId;
+
+
+    /**
+     * 企业id选传
+     */
+
+    private Long userId;
+
+    public static final String TYPE_RECENT_7_DAYS = "0";
+    public static final String TYPE_LAST_MONTH = "1";
+    public static final String TYPE_LAST_QUARTER = "2";
+    public static final String TYPE_CUSTOM = "99";
+
+    @Schema(description = "统计类型 0最近7天|1上个月|2上季度|99自定义",required = true)
+    private String type="0";
+
+    @Schema(description = "自定义时间范围")
+//    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private List<String> time;
+
+    /**
+     * 沟通类型
+     * 0.我发起的
+     * 1.沟通我的
+     */
+    private Integer communicateType=0;
+
+    private Long startTime;
+
+    private Long endTime;
+
+
+    public Long getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Long startTime) {
+        this.startTime = startTime;
+    }
+
+    public Long getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Long endTime) {
+        this.endTime = endTime;
+    }
+
+    public Long getEnterpriseId() {
+        return enterpriseId;
+    }
+
+    public void setEnterpriseId(Long enterpriseId) {
+        this.enterpriseId = enterpriseId;
+    }
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+
+
+    public Integer getCommunicateType() {
+        return communicateType;
+    }
+
+    public void setCommunicateType(Integer communicateType) {
+        this.communicateType = communicateType;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public List<String> getTime() {
+        return time;
+    }
+
+    public void setTime(List<String> time) {
+        this.time = time;
+    }
+}

+ 61 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/statistics/imRecentConversationsStatisticsRespVo.java

@@ -0,0 +1,61 @@
+package com.citu.module.menduner.im.controller.app.base.statistics;
+
+public class imRecentConversationsStatisticsRespVo {
+
+    /**
+     * 主动联系我的数量
+     */
+    private Long activeContactCount;
+
+
+    /**
+     * 主动联系我的 环比
+     */
+    private Double qqactiveContactCount;
+
+
+
+    /**
+     *我 主动联系的数量
+     */
+    private Long usContactCount;
+
+
+    /**
+     * 我的主动联系 环比
+     */
+    private Double qqUsContactCount;
+
+
+    public Long getActiveContactCount() {
+        return activeContactCount;
+    }
+
+    public void setActiveContactCount(Long activeContactCount) {
+        this.activeContactCount = activeContactCount;
+    }
+
+    public Double getQqactiveContactCount() {
+        return qqactiveContactCount;
+    }
+
+    public void setQqactiveContactCount(Double qqactiveContactCount) {
+        this.qqactiveContactCount = qqactiveContactCount;
+    }
+
+    public Long getUsContactCount() {
+        return usContactCount;
+    }
+
+    public void setUsContactCount(Long usContactCount) {
+        this.usContactCount = usContactCount;
+    }
+
+    public Double getQqUsContactCount() {
+        return qqUsContactCount;
+    }
+
+    public void setQqUsContactCount(Double qqUsContactCount) {
+        this.qqUsContactCount = qqUsContactCount;
+    }
+}

+ 12 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/user/ImUserInfoVo.java

@@ -1,11 +1,15 @@
 package com.citu.module.menduner.im.controller.app.base.user;
 
+import com.citu.module.menduner.system.api.user.UserInfoRespDTO;
+
 public class ImUserInfoVo {
 
     private Long userId;
 
     private String uid;
 
+    private UserInfoRespDTO userInfoResp;
+
 
     public Long getUserId() {
         return userId;
@@ -22,4 +26,12 @@ public class ImUserInfoVo {
     public void setUid(String uid) {
         this.uid = uid;
     }
+
+    public UserInfoRespDTO getUserInfoResp() {
+        return userInfoResp;
+    }
+
+    public void setUserInfoResp(UserInfoRespDTO userInfoResp) {
+        this.userInfoResp = userInfoResp;
+    }
 }

+ 27 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ChannelDeleteReqVo.java

@@ -0,0 +1,27 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ChannelDeleteReqVo {
+    @JsonProperty("channel_id")
+    private String channelId;
+
+    @JsonProperty("channel_type")
+    private Integer channelType;
+
+    public String getChannelId() {
+        return channelId;
+    }
+
+    public void setChannelId(String channelId) {
+        this.channelId = channelId;
+    }
+
+    public Integer getChannelType() {
+        return channelType;
+    }
+
+    public void setChannelType(Integer channelType) {
+        this.channelType = channelType;
+    }
+}

+ 11 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ConversationSyncRespVo.java

@@ -1,5 +1,6 @@
 package com.citu.module.menduner.im.controller.app.base.wukong;
 
+import com.citu.module.menduner.im.controller.app.base.user.ImUserInfoVo;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
 import java.util.List;
@@ -13,6 +14,8 @@ public class ConversationSyncRespVo {
     @JsonProperty("channel_id")
     private String channelId;
 
+    private ImUserInfoVo userInfoVo;
+
     /**
      *  频道类型 1.单聊 2.群聊 3.客服
      */
@@ -120,4 +123,12 @@ public class ConversationSyncRespVo {
     public void setRecents(List<Map> recents) {
         this.recents = recents;
     }
+
+    public ImUserInfoVo getUserInfoVo() {
+        return userInfoVo;
+    }
+
+    public void setUserInfoVo(ImUserInfoVo userInfoVo) {
+        this.userInfoVo = userInfoVo;
+    }
 }

+ 58 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ConversationsUnreadReqVo.java

@@ -0,0 +1,58 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ConversationsUnreadReqVo {
+
+    private Long enterpriseId;
+    private String uid;
+
+    @JsonProperty("channel_id")
+    private String channelId;
+
+    @JsonProperty("channel_type")
+    private Integer channelType;
+
+    private Integer unread=0;
+
+
+    public String getUid() {
+        return uid;
+    }
+
+    public void setUid(String uid) {
+        this.uid = uid;
+    }
+
+    public String getChannelId() {
+        return channelId;
+    }
+
+    public void setChannelId(String channelId) {
+        this.channelId = channelId;
+    }
+
+    public Integer getChannelType() {
+        return channelType;
+    }
+
+    public void setChannelType(Integer channelType) {
+        this.channelType = channelType;
+    }
+
+    public Integer getUnread() {
+        return unread;
+    }
+
+    public void setUnread(Integer unread) {
+        this.unread = unread;
+    }
+
+    public Long getEnterpriseId() {
+        return enterpriseId;
+    }
+
+    public void setEnterpriseId(Long enterpriseId) {
+        this.enterpriseId = enterpriseId;
+    }
+}

+ 51 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ImHeaderReqVo.java

@@ -0,0 +1,51 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ImHeaderReqVo {
+
+
+    /**
+     * 是否不存储消息 0.存储 1.不存储
+     */
+    @JsonProperty("no_persist")
+    private Integer noPersist;
+
+    /**
+     * 是否显示红点计数,0.不显示 1.显示
+     */
+    @JsonProperty("red_dot")
+    private Integer redDot;
+
+
+    /**
+     *  是否是写扩散,这里一般是0,只有cmd消息才是1
+     */
+    @JsonProperty("sync_once")
+    private Integer syncOnce;
+
+
+    public Integer getNoPersist() {
+        return noPersist;
+    }
+
+    public void setNoPersist(Integer noPersist) {
+        this.noPersist = noPersist;
+    }
+
+    public Integer getRedDot() {
+        return redDot;
+    }
+
+    public void setRedDot(Integer redDot) {
+        this.redDot = redDot;
+    }
+
+    public Integer getSyncOnce() {
+        return syncOnce;
+    }
+
+    public void setSyncOnce(Integer syncOnce) {
+        this.syncOnce = syncOnce;
+    }
+}

+ 104 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ImMessageSendReqVo.java

@@ -0,0 +1,104 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+public class ImMessageSendReqVo {
+    private ImHeaderReqVo header;
+
+
+    /**
+     * 发送者uid
+     */
+    @JsonProperty("from_uid")
+    private String fromUid;
+
+
+    /**
+     * 消息内容,base64编码
+     */
+    private String payload;
+
+
+    /**
+     * 接收者的uid,分批指定,每次建议 1000-10000之间,视系统情况而定
+     */
+    private List<String> subscribers;
+
+
+    /**
+     * 流式消息编号,如果是流式消息,需要指定,否则为空
+     */
+    @JsonProperty("stream_no")
+    private String streamNo;
+
+    /**
+     * 接收频道ID 如果channel_type=1 channel_id为个人uid 如果channel_type=2 channel_id为群id
+     */
+    @JsonProperty("channel_id")
+    private  String channelId;
+
+    /**
+     * 接收频道类型  1.个人频道 2.群聊频道
+     */
+    @JsonProperty("channel_type")
+    private Integer channelType;
+
+
+    public ImHeaderReqVo getHeader() {
+        return header;
+    }
+
+    public void setHeader(ImHeaderReqVo header) {
+        this.header = header;
+    }
+
+    public String getFromUid() {
+        return fromUid;
+    }
+
+    public void setFromUid(String fromUid) {
+        this.fromUid = fromUid;
+    }
+
+    public String getPayload() {
+        return payload;
+    }
+
+    public void setPayload(String payload) {
+        this.payload = payload;
+    }
+
+    public List<String> getSubscribers() {
+        return subscribers;
+    }
+
+    public void setSubscribers(List<String> subscribers) {
+        this.subscribers = subscribers;
+    }
+
+    public String getStreamNo() {
+        return streamNo;
+    }
+
+    public void setStreamNo(String streamNo) {
+        this.streamNo = streamNo;
+    }
+
+    public String getChannelId() {
+        return channelId;
+    }
+
+    public void setChannelId(String channelId) {
+        this.channelId = channelId;
+    }
+
+    public Integer getChannelType() {
+        return channelType;
+    }
+
+    public void setChannelType(Integer channelType) {
+        this.channelType = channelType;
+    }
+}

+ 33 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/ImUserDeviceQuitReqVo.java

@@ -0,0 +1,33 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ImUserDeviceQuitReqVo {
+
+    /**
+     * 需要踢出的用户uid
+     */
+    private String uid;
+
+    /**
+     * 需要踢出的设备标记 -1: 当前用户下所有设备 0: 当前用户下的app 1: 当前用户下的web 2: 当前用户下的pc
+     */
+    @JsonProperty("device_flag")
+    private Integer deviceFag;
+
+    public String getUid() {
+        return uid;
+    }
+
+    public void setUid(String uid) {
+        this.uid = uid;
+    }
+
+    public Integer getDeviceFag() {
+        return deviceFag;
+    }
+
+    public void setDeviceFag(Integer deviceFag) {
+        this.deviceFag = deviceFag;
+    }
+}

+ 37 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/MessageSendbatchRespVo.java

@@ -0,0 +1,37 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+public class MessageSendbatchRespVo {
+
+    /**
+     * 回发送失败的用户列表
+     */
+    @JsonProperty("fail_uids")
+    private List<String> failUids;
+
+
+    /**
+     * 发送失败用户列表对应的失败原因列表,与fail_uids一一对应
+     */
+    private List<String> reason;
+
+
+    public List<String> getFailUids() {
+        return failUids;
+    }
+
+    public void setFailUids(List<String> failUids) {
+        this.failUids = failUids;
+    }
+
+    public List<String> getReason() {
+        return reason;
+    }
+
+    public void setReason(List<String> reason) {
+        this.reason = reason;
+    }
+}

+ 47 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserMsgPageReqVO.java

@@ -0,0 +1,47 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import com.citu.framework.common.pojo.PageParam;
+
+@Schema(description = "管理后台 - im聊天记录分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class UserMsgPageReqVO extends PageParam {
+
+    @Schema(description = "服务端的消息ID(全局唯一)", example = "25023")
+    private Integer messageId;
+
+    @Schema(description = "字符串类型服务端的消息ID(全局唯一)")
+    private String messageIdStr;
+
+    @Schema(description = "客户端消息唯一编号")
+    private Integer clientMsgNo;
+
+    @Schema(description = "消息序列号 (用户唯一,有序递增)")
+    private String messageSeq;
+
+    @Schema(description = "发送者UID", example = "17682")
+    private Integer fromUid;
+
+    @Schema(description = "频道ID", example = "12640")
+    private Integer channelId;
+
+    @Schema(description = "频道类型", example = "2")
+    private String channelType;
+
+    @Schema(description = "服务器消息时间戳(10位,到秒)")
+    private Long timestamp;
+
+    @Schema(description = "base64消息内容")
+    private String payload;
+
+    @Schema(description = "消息头")
+    private String header;
+
+    @Schema(description = "设置")
+    private String setting;
+
+}

+ 62 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserMsgRespVO.java

@@ -0,0 +1,62 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import java.util.*;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - im聊天记录 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class UserMsgRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "9844")
+    @ExcelProperty("主键")
+    private Long imUserMsgId;
+
+    @Schema(description = "服务端的消息ID(全局唯一)", example = "25023")
+    @ExcelProperty("服务端的消息ID(全局唯一)")
+    private Integer messageId;
+
+    @Schema(description = "字符串类型服务端的消息ID(全局唯一)")
+    @ExcelProperty("字符串类型服务端的消息ID(全局唯一)")
+    private String messageIdStr;
+
+    @Schema(description = "客户端消息唯一编号")
+    @ExcelProperty("客户端消息唯一编号")
+    private Integer clientMsgNo;
+
+    @Schema(description = "消息序列号 (用户唯一,有序递增)")
+    @ExcelProperty("消息序列号 (用户唯一,有序递增)")
+    private String messageSeq;
+
+    @Schema(description = "发送者UID", example = "17682")
+    @ExcelProperty("发送者UID")
+    private Integer fromUid;
+
+    @Schema(description = "频道ID", example = "12640")
+    @ExcelProperty("频道ID")
+    private Integer channelId;
+
+    @Schema(description = "频道类型", example = "2")
+    @ExcelProperty("频道类型")
+    private String channelType;
+
+    @Schema(description = "服务器消息时间戳(10位,到秒)")
+    @ExcelProperty("服务器消息时间戳(10位,到秒)")
+    private Long timestamp;
+
+    @Schema(description = "base64消息内容")
+    @ExcelProperty("base64消息内容")
+    private String payload;
+
+    @Schema(description = "消息头")
+    @ExcelProperty("消息头")
+    private String header;
+
+    @Schema(description = "设置")
+    @ExcelProperty("设置")
+    private String setting;
+
+}

+ 48 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserMsgSaveReqVO.java

@@ -0,0 +1,48 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+
+@Schema(description = "管理后台 - im聊天记录新增/修改 Request VO")
+@Data
+public class UserMsgSaveReqVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "9844")
+    private Long imUserMsgId;
+
+    @Schema(description = "服务端的消息ID(全局唯一)", example = "25023")
+    private Integer messageId;
+
+    @Schema(description = "字符串类型服务端的消息ID(全局唯一)")
+    private String messageIdStr;
+
+    @Schema(description = "客户端消息唯一编号")
+    private Integer clientMsgNo;
+
+    @Schema(description = "消息序列号 (用户唯一,有序递增)")
+    private String messageSeq;
+
+    @Schema(description = "发送者UID", example = "17682")
+    private Integer fromUid;
+
+    @Schema(description = "频道ID", example = "12640")
+    private Integer channelId;
+
+    @Schema(description = "频道类型", example = "2")
+    private String channelType;
+
+    @Schema(description = "服务器消息时间戳(10位,到秒)")
+    private Long timestamp;
+
+    @Schema(description = "base64消息内容")
+    private String payload;
+
+    @Schema(description = "消息头")
+    private String header;
+
+    @Schema(description = "设置")
+    private String setting;
+
+}

+ 29 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserOnlinePageReqVO.java

@@ -0,0 +1,29 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import com.citu.framework.common.pojo.PageParam;
+
+@Schema(description = "管理后台 - im在线状态分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class UserOnlinePageReqVO extends PageParam {
+
+    @Schema(description = "设备标识 0.app 1.web")
+    private Integer deviceCategory;
+
+    @Schema(description = "在线状态 0.离线 1.在线", example = "1")
+    private Integer onlineStatus;
+
+    @Schema(description = "客户端id", example = "10024")
+    private String clientId;
+
+    @Schema(description = "当前设备在线数量")
+    private Integer onlineNum;
+
+    @Schema(description = "所有设备累计在线数量")
+    private String totalOnlineNum;
+
+}

+ 38 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserOnlineRespVO.java

@@ -0,0 +1,38 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import java.util.*;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - im在线状态 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class UserOnlineRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1071")
+    @ExcelProperty("主键")
+    private Long imUserOnlineId;
+
+    @Schema(description = "设备标识 0.app 1.web")
+    @ExcelProperty("设备标识 0.app 1.web")
+    private Integer deviceCategory;
+
+    @Schema(description = "在线状态 0.离线 1.在线", example = "1")
+    @ExcelProperty("在线状态 0.离线 1.在线")
+    private Integer onlineStatus;
+
+    @Schema(description = "客户端id", example = "10024")
+    @ExcelProperty("客户端id")
+    private String clientId;
+
+    @Schema(description = "当前设备在线数量")
+    @ExcelProperty("当前设备在线数量")
+    private Integer onlineNum;
+
+    @Schema(description = "所有设备累计在线数量")
+    @ExcelProperty("所有设备累计在线数量")
+    private String totalOnlineNum;
+
+}

+ 30 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/controller/app/base/wukong/UserOnlineSaveReqVO.java

@@ -0,0 +1,30 @@
+package com.citu.module.menduner.im.controller.app.base.wukong;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+
+@Schema(description = "管理后台 - im在线状态新增/修改 Request VO")
+@Data
+public class UserOnlineSaveReqVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1071")
+    private Long imUserOnlineId;
+
+    @Schema(description = "设备标识 0.app 1.web")
+    private Integer deviceCategory;
+
+    @Schema(description = "在线状态 0.离线 1.在线", example = "1")
+    private Integer onlineStatus;
+
+    @Schema(description = "客户端id", example = "10024")
+    private String clientId;
+
+    @Schema(description = "当前设备在线数量")
+    private Integer onlineNum;
+
+    @Schema(description = "所有设备累计在线数量")
+    private String totalOnlineNum;
+
+}

+ 87 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/dal/dataobject/UserMsgDO.java

@@ -0,0 +1,87 @@
+package com.citu.module.menduner.im.dal.dataobject;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.*;
+import java.util.*;
+import com.baomidou.mybatisplus.annotation.*;
+import com.citu.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * im聊天记录 DO
+ *
+ * @author 辞图科技
+ */
+@TableName(value = "im_user_msg",autoResultMap = true)
+@KeySequence("im_user_msg_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserMsgDO extends BaseDO {
+
+    /**
+     * 主键
+     */
+    @TableId
+    private Long imUserMsgId;
+    /**
+     * 服务端的消息ID(全局唯一)
+     */
+    private Integer messageId;
+    /**
+     * 字符串类型服务端的消息ID(全局唯一)
+     */
+    @JsonProperty("client_msg_no")
+    @JSONField(name="client_msg_no")
+    private String messageIdStr;
+    /**
+     * 客户端消息唯一编号
+     */
+    @JsonProperty("message_idstr")
+    @JSONField(name="message_idstr")
+    private Integer clientMsgNo;
+    /**
+     * 消息序列号 (用户唯一,有序递增)
+     */
+    private String messageSeq;
+    /**
+     * 发送者UID
+     */
+    @JsonProperty("form_uid")
+    @JSONField(name="form_uid")
+    private String fromUid;
+    /**
+     * 频道ID
+     */
+    @JsonProperty("channel_id")
+    @JSONField(name="channel_id")
+    private String channelId;
+    /**
+     * 频道类型
+     */
+    private String channelType;
+    /**
+     * 服务器消息时间戳(10位,到秒)
+     */
+    private Long timestamp;
+    /**
+     * base64消息内容
+     */
+    private String payload;
+    /**
+     * 消息头
+     */
+    @TableField(typeHandler = JacksonTypeHandler.class)
+    private Map header;
+    /**
+     * 设置
+     */
+    private String setting;
+
+    private Integer type;
+
+}

+ 49 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/dal/dataobject/UserOnlineDO.java

@@ -0,0 +1,49 @@
+package com.citu.module.menduner.im.dal.dataobject;
+
+import lombok.*;
+import java.util.*;
+import com.baomidou.mybatisplus.annotation.*;
+import com.citu.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * im在线状态 DO
+ *
+ * @author 辞图科技
+ */
+@TableName("im_user_online")
+@KeySequence("im_user_online_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserOnlineDO extends BaseDO {
+
+    /**
+     * 主键
+     */
+    @TableId
+    private Long imUserOnlineId;
+    /**
+     * 设备标识 0.app 1.web
+     */
+    private Integer deviceCategory;
+    /**
+     * 在线状态 0.离线 1.在线
+     */
+    private Integer onlineStatus;
+    /**
+     * 客户端id
+     */
+    private String clientId;
+    /**
+     * 当前设备在线数量
+     */
+    private Integer onlineNum;
+    /**
+     * 所有设备累计在线数量
+     */
+    private String totalOnlineNum;
+
+}

+ 36 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/dal/mysql/UserMsgMapper.java

@@ -0,0 +1,36 @@
+package com.citu.module.menduner.im.dal.mysql;
+
+import java.util.*;
+
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.mybatis.core.query.LambdaQueryWrapperX;
+import com.citu.framework.mybatis.core.mapper.BaseMapperX;
+import com.citu.module.menduner.im.controller.app.base.wukong.UserMsgPageReqVO;
+import com.citu.module.menduner.im.dal.dataobject.UserMsgDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * im聊天记录 Mapper
+ *
+ * @author 辞图科技
+ */
+@Mapper
+public interface UserMsgMapper extends BaseMapperX<UserMsgDO> {
+
+    default PageResult<UserMsgDO> selectPage(UserMsgPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<UserMsgDO>()
+                .eqIfPresent(UserMsgDO::getMessageId, reqVO.getMessageId())
+                .eqIfPresent(UserMsgDO::getMessageIdStr, reqVO.getMessageIdStr())
+                .eqIfPresent(UserMsgDO::getClientMsgNo, reqVO.getClientMsgNo())
+                .eqIfPresent(UserMsgDO::getMessageSeq, reqVO.getMessageSeq())
+                .eqIfPresent(UserMsgDO::getFromUid, reqVO.getFromUid())
+                .eqIfPresent(UserMsgDO::getChannelId, reqVO.getChannelId())
+                .eqIfPresent(UserMsgDO::getChannelType, reqVO.getChannelType())
+                .eqIfPresent(UserMsgDO::getTimestamp, reqVO.getTimestamp())
+                .eqIfPresent(UserMsgDO::getPayload, reqVO.getPayload())
+                .eqIfPresent(UserMsgDO::getHeader, reqVO.getHeader())
+                .eqIfPresent(UserMsgDO::getSetting, reqVO.getSetting())
+                .orderByDesc(UserMsgDO::getImUserMsgId));
+    }
+
+}

+ 30 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/dal/mysql/UserOnlineMapper.java

@@ -0,0 +1,30 @@
+package com.citu.module.menduner.im.dal.mysql;
+
+import java.util.*;
+
+import com.citu.framework.common.pojo.PageResult;
+import com.citu.framework.mybatis.core.query.LambdaQueryWrapperX;
+import com.citu.framework.mybatis.core.mapper.BaseMapperX;
+import com.citu.module.menduner.im.controller.app.base.wukong.UserOnlinePageReqVO;
+import com.citu.module.menduner.im.dal.dataobject.UserOnlineDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * im在线状态 Mapper
+ *
+ * @author 辞图科技
+ */
+@Mapper
+public interface UserOnlineMapper extends BaseMapperX<UserOnlineDO> {
+
+    default PageResult<UserOnlineDO> selectPage(UserOnlinePageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<UserOnlineDO>()
+                .eqIfPresent(UserOnlineDO::getDeviceCategory, reqVO.getDeviceCategory())
+                .eqIfPresent(UserOnlineDO::getOnlineStatus, reqVO.getOnlineStatus())
+                .eqIfPresent(UserOnlineDO::getClientId, reqVO.getClientId())
+                .eqIfPresent(UserOnlineDO::getOnlineNum, reqVO.getOnlineNum())
+                .eqIfPresent(UserOnlineDO::getTotalOnlineNum, reqVO.getTotalOnlineNum())
+                .orderByDesc(UserOnlineDO::getImUserOnlineId));
+    }
+
+}

+ 18 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/dal/mysql/statistics/ImRecentConversationsStatisticsMapper.java

@@ -0,0 +1,18 @@
+package com.citu.module.menduner.im.dal.mysql.statistics;
+
+import com.citu.module.menduner.im.controller.app.base.statistics.ImRecentConversationsStatisticsReqVo;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface ImRecentConversationsStatisticsMapper {
+
+    /**
+     * 获取最近会话统计
+     * @param reqVo
+     * @return
+     */
+    List<Map<String,Long>> imRecentConversationsStatistics(ImRecentConversationsStatisticsReqVo reqVo);
+}

+ 2 - 1
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/framework/rpc/config/RpcConfiguration.java

@@ -1,6 +1,7 @@
 package com.citu.module.menduner.im.framework.rpc.config;
 
 import com.citu.module.menduner.im.service.wukong.WuKongApiService;
+import com.citu.module.menduner.system.api.user.UserApi;
 import com.citu.module.system.api.logger.LoginLogApi;
 import com.citu.module.system.api.sms.SmsCodeApi;
 import com.citu.module.system.api.social.SocialClientApi;
@@ -9,6 +10,6 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.Configuration;
 
 @Configuration(proxyBeanMethods = false)
-@EnableFeignClients(clients = {WuKongApiService.class})
+@EnableFeignClients(clients = {WuKongApiService.class, UserApi.class})
 public class RpcConfiguration {
 }

+ 1 - 1
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/framework/security/config/SecurityConfiguration.java

@@ -1,7 +1,7 @@
 package com.citu.module.menduner.im.framework.security.config;
 
 import com.citu.framework.security.config.AuthorizeRequestsCustomizer;
-import com.citu.module.system.enums.ApiConstants;
+import com.citu.module.menduner.im.enums.ApiConstants;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;

+ 0 - 23
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/interceptor/WuKongWuKongApiInterceptor.java

@@ -1,23 +0,0 @@
-//package com.citu.module.menduner.im.interceptor;
-//
-//import com.alibaba.excel.util.StringUtils;
-//import com.citu.module.menduner.im.MendunerIMApplication;
-//import feign.RequestInterceptor;
-//import feign.RequestTemplate;
-//
-//public class WuKongWuKongApiInterceptor implements RequestInterceptor {
-//
-//    private String uri;
-//
-//
-//    @Override
-//    public void apply(RequestTemplate requestTemplate) {
-//        if(StringUtils.isBlank(uri)){
-//            uri =  MendunerIMApplication.applicationContext.getEnvironment().getProperty("im.wulong.url");
-//        }
-//        requestTemplate.uri(uri);
-//
-//
-//        System.out.println(requestTemplate);
-//    }
-//}

+ 144 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/mybatis/plugin/SqlInterceptor.java

@@ -0,0 +1,144 @@
+package com.citu.module.menduner.im.mybatis.plugin;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.cache.CacheKey;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.ParameterMapping;
+import org.apache.ibatis.mapping.SqlCommandType;
+import org.apache.ibatis.plugin.*;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.apache.ibatis.type.TypeHandlerRegistry;
+
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * 1.可以用来分析SQL执行效率
+ * 2.可以用来获取实际执行的SQL
+ */
+
+@Intercepts({
+        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
+        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
+        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}
+)
+@Slf4j
+public class SqlInterceptor implements Interceptor {
+//    private static final Log log = LogFactory.getLog(SqlInterceptor.class);    
+    /**
+     * 最小打印时间 sql时间超过这个值才打印日志 毫秒
+     **/
+    private int MIN_SIZE = 0;
+
+    @Override
+    public Object intercept(Invocation invocation) throws Throwable {
+        // 判断是否需要执行插件,避免浪费性能
+        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
+        Object parameter = null;
+        if (invocation.getArgs().length > 1) {
+            parameter = invocation.getArgs()[1];
+        }
+        String sqlId = mappedStatement.getId();
+        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
+        Configuration configuration = mappedStatement.getConfiguration();
+
+        long startTime = System.currentTimeMillis();
+        Object result = null;
+        try {
+            result = invocation.proceed();
+        } finally {
+            try {
+                long sqlCostTime = System.currentTimeMillis() - startTime;
+                String sql = getSql(configuration, boundSql);
+                formatSqlLog(mappedStatement.getSqlCommandType(), sqlId, sql, sqlCostTime, result);
+            } catch (Exception ignored) {
+                log.error("SQL插件执行失败 Mapper:{} 参数对象:{}", sqlId, JSON.toJSONString(boundSql.getParameterObject()), ignored);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public Object plugin(Object target) {
+        return Plugin.wrap(target, this);
+    }
+
+    @Override
+    public void setProperties(Properties properties) {
+        if (properties == null) {
+            return;
+        }
+        if (properties.containsKey("minLogSize")) {
+            MIN_SIZE = Integer.valueOf(properties.getProperty("minLogSize"));
+        }
+    }
+
+    private String getSql(Configuration configuration, BoundSql boundSql) {
+        // 输入sql字符串空判断
+        String sql = boundSql.getSql();
+        if (StrUtil.isBlank(sql)) {
+            return "";
+        }
+
+        //去掉换行符
+        sql = sql.replaceAll("[\\s\n ]+", " ");
+
+        //填充占位符, 目前基本不用mybatis存储过程调用,故此处不做考虑
+        Object parameterObject = boundSql.getParameterObject();
+        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
+        if (!parameterMappings.isEmpty() && parameterObject != null) {
+            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
+            if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
+                sql = this.replacePlaceholder(sql, parameterObject);
+            } else {
+                MetaObject metaObject = configuration.newMetaObject(parameterObject);
+                for (ParameterMapping parameterMapping : parameterMappings) {
+                    String propertyName = parameterMapping.getProperty();
+                    if (metaObject.hasGetter(propertyName)) {
+                        Object obj = metaObject.getValue(propertyName);
+                        sql = replacePlaceholder(sql, obj);
+                    } else if (boundSql.hasAdditionalParameter(propertyName)) {
+                        Object obj = boundSql.getAdditionalParameter(propertyName);
+                        sql = replacePlaceholder(sql, obj);
+                    }
+                }
+            }
+        }
+        return sql;
+    }
+
+    private String replacePlaceholder(String sql, Object parameterObject) {
+        String result;
+        if (parameterObject == null) {
+            result = "NULL";
+        } else if (parameterObject instanceof String) {
+            result = String.format("'%s'", parameterObject.toString());
+        } else if (parameterObject instanceof Date) {
+            result = String.format("'%s'", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(parameterObject));
+        } else {
+            result = parameterObject.toString();
+        }
+        return sql.replaceFirst("\\?", result);
+    }
+
+    private void formatSqlLog(SqlCommandType sqlCommandType, String sqlId, String sql, long costTime, Object obj) {
+        if (costTime > MIN_SIZE) {
+            if (sqlCommandType == SqlCommandType.UPDATE || sqlCommandType == SqlCommandType.INSERT || sqlCommandType == SqlCommandType.DELETE) {
+                log.info("[执行时长{}ms] [{}] {}; 影响行数:{}", costTime, sqlId, sql, obj);
+            }
+            if (sqlCommandType == SqlCommandType.SELECT) {
+                log.info("[执行时长{}ms] [{}] {}; 结果行数:{}", costTime, sqlId, sql, null==obj?"无":((Collection<?>) obj).size());
+            }
+        }
+    }
+}

+ 44 - 5
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/UserServiceImpl.java

@@ -1,6 +1,7 @@
 package com.citu.module.menduner.im.service;
 
 import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.citu.framework.common.exception.enums.GlobalErrorCodeConstants;
 import com.citu.framework.common.pojo.CommonResult;
@@ -13,15 +14,16 @@ import com.citu.module.menduner.im.convert.UserConvert;
 import com.citu.module.menduner.im.dal.dataobject.UserDO;
 import com.citu.module.menduner.im.dal.mysql.UserMapper;
 import com.citu.module.menduner.im.service.wukong.WuKongUserService;
+import com.citu.module.menduner.system.api.user.UserApi;
+import com.citu.module.menduner.system.api.user.UserInfoReqDTO;
+import com.citu.module.menduner.system.api.user.UserInfoRespDTO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
+import java.util.stream.Collectors;
 
 @Service
 public class UserServiceImpl implements UserService{
@@ -31,6 +33,8 @@ public class UserServiceImpl implements UserService{
     WuKongUserService wuKongUserService;
 
 
+    UserApi userApi;
+
     private static final Long DEFAULT_ENTERPRISE_ID = -999L;
 
 
@@ -109,7 +113,38 @@ public class UserServiceImpl implements UserService{
             return CommonResult.success(new ArrayList<ImUserInfoVo>());
         }
         List<UserDO> userDOS = mapper.selectList(new LambdaQueryWrapper<UserDO>().in(UserDO::getUid, uids));
-        return null;
+        List<UserInfoReqDTO> list = new ArrayList<>(userDOS.size()+1);
+        for (UserDO userDO : userDOS) {
+            UserInfoReqDTO  item =new UserInfoReqDTO();
+            item.setUserId(userDO.getUserId());
+
+            item.setUserType(DEFAULT_ENTERPRISE_ID.equals(userDO.getEnterpriseId())
+                    ?UserInfoReqDTO.USER_TYPE_USER:UserInfoReqDTO.USER_TYPE_ENTERPRISE);
+
+            item.setEnterpriseId(DEFAULT_ENTERPRISE_ID.equals(userDO.getEnterpriseId())?null:userDO.getEnterpriseId());
+            list.add(item);
+        }
+
+        List<UserInfoRespDTO> result = userApi.getUserInfo(list).getCheckedData();
+        List<ImUserInfoVo> resultVo =  new ArrayList<>(result.size()+1);
+        Map<String, UserInfoRespDTO> collect = result.stream().collect(Collectors.toMap(item -> item.getUserId().toString() +"-"+ (null == item.getEnterpriseId() ? DEFAULT_ENTERPRISE_ID.intValue() : item.getEnterpriseId()), item -> item));
+//        System.out.println(JSON.toJSONString(collect));
+        for (UserDO userDO : userDOS) {
+            Long userId = userDO.getUserId();
+            Long enterpriseId = userDO.getEnterpriseId();
+            String key = userId+"-"+enterpriseId;
+//            System.out.println(key);
+            ImUserInfoVo item =new ImUserInfoVo();
+            item.setUserInfoResp(collect.get(key));
+            item.setUserId(userId);
+            item.setUid(userDO.getUid());
+
+            resultVo.add(item);
+        }
+
+
+
+        return CommonResult.success(resultVo);
     }
 
 
@@ -122,4 +157,8 @@ public class UserServiceImpl implements UserService{
     public void setMapper(UserMapper mapper) {
         this.mapper = mapper;
     }
+    @Autowired
+    public void setUserApi(UserApi userApi) {
+        this.userApi = userApi;
+    }
 }

+ 8 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/statistics/ImRecentConversationsStatisticsService.java

@@ -0,0 +1,8 @@
+package com.citu.module.menduner.im.service.statistics;
+
+import com.citu.framework.common.pojo.CommonResult;
+import com.citu.module.menduner.im.controller.app.base.statistics.ImRecentConversationsStatisticsReqVo;
+
+public interface ImRecentConversationsStatisticsService {
+    CommonResult imRecentConversationsStatistics(ImRecentConversationsStatisticsReqVo reqVo);
+}

+ 124 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/statistics/ImRecentConversationsStatisticsServiceImpl.java

@@ -0,0 +1,124 @@
+package com.citu.module.menduner.im.service.statistics;
+
+import cn.hutool.core.date.DateUtil;
+import com.citu.framework.common.pojo.CommonResult;
+import com.citu.module.menduner.im.controller.app.base.statistics.ImRecentConversationsStatisticsReqVo;
+import com.citu.module.menduner.im.controller.app.base.statistics.imRecentConversationsStatisticsRespVo;
+import com.citu.module.menduner.im.dal.mysql.statistics.ImRecentConversationsStatisticsMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalField;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class ImRecentConversationsStatisticsServiceImpl implements ImRecentConversationsStatisticsService{
+
+    ImRecentConversationsStatisticsMapper mapper;
+
+
+
+    @Override
+    public CommonResult<imRecentConversationsStatisticsRespVo> imRecentConversationsStatistics(ImRecentConversationsStatisticsReqVo reqVo) {
+        LocalDateTime[] localDateTimes = generateDateTimeRange(reqVo);
+        reqVo.setStartTime(  DateUtil.date(localDateTimes[0]).getTime()/1000L);
+        reqVo.setEndTime( DateUtil.date(localDateTimes[1]).getTime()/1000L);
+
+        imRecentConversationsStatisticsRespVo resp =new imRecentConversationsStatisticsRespVo();
+        BigDecimal bigDecimal =new BigDecimal("100");
+        reqVo.setCommunicateType(0);  // 我发起的
+        List<Map<String, Long>> maps = mapper.imRecentConversationsStatistics(reqVo);
+        Long currentCount = 0L;  // 本期数量
+        Long parentCount = 0L;  // 上期数量
+        for (int i = 0; i < maps.size(); i++) {
+             Long count =    maps.get(i).get("count");
+             if(i==0){
+                 currentCount=count;
+             }
+            if(i==1){
+                parentCount=count;
+            }
+        }
+
+        resp.setUsContactCount(currentCount);
+        if(currentCount-parentCount==0 ){
+            resp.setQqUsContactCount(0.0);
+        } else if (parentCount==0 ) {
+            resp.setQqUsContactCount(Double.valueOf(currentCount*100));
+        }else if(currentCount == 0){
+            resp.setQqUsContactCount(-Double.valueOf(currentCount*100));
+        }else {
+            resp.setQqUsContactCount(new BigDecimal(currentCount - parentCount).divide(new BigDecimal(parentCount), 2, BigDecimal.ROUND_HALF_UP).multiply(bigDecimal).doubleValue());
+        }
+        reqVo.setCommunicateType(1);  // 我发起的
+        List<Map<String, Long>> maps2 = mapper.imRecentConversationsStatistics(reqVo);
+         currentCount = 0L;
+         parentCount = 0L;
+        for (int i = 0; i < maps.size(); i++) {
+            Long count =    maps.get(i).get("count");
+            if(i==0){
+                currentCount=count;
+            }
+            if(i==1){
+                parentCount=count;
+            }
+        }
+        resp.setActiveContactCount(currentCount);
+        if(currentCount-parentCount==0  || parentCount == 0 || currentCount ==0){
+            resp.setQqactiveContactCount(0.0);
+        }else if (parentCount==0 ) {
+            resp.setQqactiveContactCount(Double.valueOf(currentCount*100));
+        }else if(currentCount == 0){
+            resp.setQqactiveContactCount(-Double.valueOf(currentCount*100));
+        }else {
+            resp.setQqactiveContactCount(new BigDecimal(currentCount - parentCount).divide(new BigDecimal(parentCount), 2, BigDecimal.ROUND_HALF_UP).multiply(bigDecimal).doubleValue());
+        }
+        return CommonResult.success(resp);
+    }
+
+    private LocalDateTime parseDateTime(String dateTimeStr) {
+        // 实现你的解析逻辑
+        return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+    }
+    public LocalDateTime[] generateDateTimeRange(ImRecentConversationsStatisticsReqVo reqVO) {
+        if (ImRecentConversationsStatisticsReqVo.TYPE_CUSTOM.equals(reqVO.getType())) {
+            return reqVO.getTime().stream().map(this::parseDateTime).toArray(LocalDateTime[]::new);
+        }
+        LocalDateTime[] dateTimeRange = new LocalDateTime[2];
+        LocalDateTime now = LocalDateTime.now();
+        switch (reqVO.getType()) {
+            case ImRecentConversationsStatisticsReqVo.TYPE_RECENT_7_DAYS:
+                // 最新7天内
+                dateTimeRange[0] = now.minusDays(7);
+                dateTimeRange[1] = now;
+                break;
+            case ImRecentConversationsStatisticsReqVo.TYPE_LAST_MONTH:
+                // 上个月
+                dateTimeRange[0] = now.minusMonths(1).withDayOfMonth(1);
+                dateTimeRange[1] = now.withDayOfMonth(1).minusNanos(1);
+                break;
+            case ImRecentConversationsStatisticsReqVo.TYPE_LAST_QUARTER:
+                // 上季度
+                int currentMonth = now.getMonthValue();
+                // 计算上一季度的起始月份
+                int quarterStartMonth = ((currentMonth - 1) / 3) * 3 + 1;
+                int lastQuarterStartMonth = quarterStartMonth - 3;
+                dateTimeRange[0] = now.withMonth(lastQuarterStartMonth).withDayOfMonth(1);
+                dateTimeRange[1] = now.withMonth(quarterStartMonth).withDayOfMonth(1).minusNanos(1);
+                break;
+        }
+        return dateTimeRange;
+    }
+
+
+
+    @Autowired
+    public void setMapper(ImRecentConversationsStatisticsMapper mapper) {
+        this.mapper = mapper;
+    }
+}

+ 61 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/wukong/WuKongApiService.java

@@ -30,5 +30,66 @@ public interface WuKongApiService {
     @PostMapping("/channel/messagesync")
     public ChannelMessageSyncResp channelMessageSync(@RequestBody ChannelMessageSyncReqVo reqVo);
 
+    /**
+     * 删除频道
+     * @param reqVo
+     * @return
+     */
+
+    @PostMapping("/channel/delete")
+    public ChannelMessageSyncResp channelDelete(@RequestBody ChannelDeleteReqVo reqVo);
+
+    @PostMapping("/conversations/setUnread")
+    public WukongApiResp   conversationsSetUnread(@RequestBody ConversationsUnreadReqVo reqVo);
+
+
+    /**
+     * 添加系统账号
+     */
+    @PostMapping("/user/systemuids_add")
+    public WukongApiResp   userSystemUidsAdd(@RequestBody List<String> uids);
+
+
+    /**
+     * 移除系统账号
+     */
+    @PostMapping("/user/systemuids_remove")
+    public WukongApiResp   userSystemUidsRemove(@RequestBody List<String> uids);
+
+
+    /**
+     *  踢出用户的设备登录
+     *      将用户的设备踢出登录,(可以实现类似微信的 app 可以踢出 pc 登录)
+     * @param reqVo
+     * @return
+     */
+    @PostMapping("/user/device_quit")
+    public WukongApiResp   userDeviceQuid(@RequestBody ImUserDeviceQuitReqVo reqVo);
+
+
+
+
+    /**
+     *  发送消息
+     *   服务端调用发送消息接口可以主要用来发送系统类的消息,比如群成员进群通知,消息撤回通知等等
+     * @param reqVo
+     * @return
+     */
+    @PostMapping("/message/send")
+    public WukongApiResp   userSend(@RequestBody ImMessageSendReqVo reqVo);
+
+
+    /**
+     *   批量发送消息
+     *   服务端调用发送消息接口可以主要用来发送系统类的消息,比如群成员进群通知,消息撤回通知等等
+     * @param reqVo
+     * @return
+     */
+    @PostMapping("/message/sendbatch")
+    public MessageSendbatchRespVo   userSendbatch(@RequestBody ImMessageSendReqVo reqVo);
+
+
+
+
 
 }

+ 3 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/wukong/WuKongSessionService.java

@@ -3,9 +3,12 @@ package com.citu.module.menduner.im.service.wukong;
 import com.citu.framework.common.pojo.CommonResult;
 import com.citu.module.menduner.im.controller.app.base.wukong.ConversationSyncReqVo;
 import com.citu.module.menduner.im.controller.app.base.wukong.ConversationsDeleteReqVo;
+import com.citu.module.menduner.im.controller.app.base.wukong.ConversationsUnreadReqVo;
 
 public interface WuKongSessionService {
     CommonResult conversatioSync(ConversationSyncReqVo reqVo);
 
     CommonResult conversatioSyncDelete(ConversationsDeleteReqVo reqVo);
+
+    CommonResult conversatioSetUnread(ConversationsUnreadReqVo reqVo);
 }

+ 20 - 6
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/wukong/WuKongSessionServiceImpl.java

@@ -1,18 +1,19 @@
 package com.citu.module.menduner.im.service.wukong;
 
+import com.alibaba.fastjson.JSON;
 import com.citu.framework.common.pojo.CommonResult;
 import com.citu.module.menduner.im.controller.app.base.user.ImUserInfoVo;
 import com.citu.module.menduner.im.controller.app.base.user.ImUserResoVO;
 import com.citu.module.menduner.im.controller.app.base.wukong.ConversationSyncReqVo;
 import com.citu.module.menduner.im.controller.app.base.wukong.ConversationSyncRespVo;
 import com.citu.module.menduner.im.controller.app.base.wukong.ConversationsDeleteReqVo;
+import com.citu.module.menduner.im.controller.app.base.wukong.ConversationsUnreadReqVo;
 import com.citu.module.menduner.im.service.UserService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
+import java.util.stream.Collectors;
 
 @Service
 public class WuKongSessionServiceImpl implements WuKongSessionService{
@@ -31,11 +32,17 @@ public class WuKongSessionServiceImpl implements WuKongSessionService{
         Set<String> uids =new HashSet<>();
         for (ConversationSyncRespVo conversationSyncRespVo : conversationSyncRespVos) {
             conversationSyncRespVo.getRecents().forEach(item->uids.add(item.get("from_uid").toString()));
+            uids.add(conversationSyncRespVo.getChannelId());
+        }
+        Map<String, ImUserInfoVo> imUserInfoVoMap = userService.getUserByUids(uids).getData().stream().collect(Collectors.toMap(ImUserInfoVo::getUid, item -> item));
+//        System.out.println(JSON.toJSONString(imUserInfoVoMap));
+        for (ConversationSyncRespVo conversationSyncRespVo : conversationSyncRespVos) {
+            String fromUid = conversationSyncRespVo.getChannelId();
+            //
+            conversationSyncRespVo.setUserInfoVo(imUserInfoVoMap.get(fromUid));
         }
 
-        CommonResult<List<ImUserInfoVo>> result =   userService.getUserByUids(uids);
-
-        return CommonResult.success(wuKongApiService.conversationSync(reqVo));
+        return CommonResult.success(conversationSyncRespVos);
     }
 
     @Override
@@ -45,6 +52,13 @@ public class WuKongSessionServiceImpl implements WuKongSessionService{
         return CommonResult.success(wuKongApiService.conversationsDelete(reqVo));
     }
 
+    @Override
+    public CommonResult conversatioSetUnread(ConversationsUnreadReqVo reqVo) {
+        String uid  =  userService.getCurrentLoginUid(reqVo.getEnterpriseId());
+        reqVo.setUid(uid);
+        return CommonResult.success(wuKongApiService.conversationsSetUnread(reqVo));
+    }
+
     @Autowired
     public void setUserService(UserService userService) {
         this.userService = userService;

+ 10 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/wukong/WukongWebhookService.java

@@ -0,0 +1,10 @@
+package com.citu.module.menduner.im.service.wukong;
+
+import com.citu.framework.common.pojo.CommonResult;
+
+import java.util.List;
+import java.util.Map;
+
+public interface WukongWebhookService {
+    CommonResult wukongWebhook(String event,String reqVo);
+}

+ 94 - 0
menduner/menduner-im-biz/src/main/java/com/citu/module/menduner/im/service/wukong/WukongWebhookServiceImpl.java

@@ -0,0 +1,94 @@
+package com.citu.module.menduner.im.service.wukong;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.codec.Base64;
+import com.alibaba.fastjson.JSON;
+import com.citu.framework.common.pojo.CommonResult;
+import com.citu.module.menduner.im.dal.dataobject.UserMsgDO;
+import com.citu.module.menduner.im.dal.mysql.UserMsgMapper;
+import com.citu.module.menduner.im.dal.mysql.UserOnlineMapper;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@Slf4j
+public class WukongWebhookServiceImpl implements WukongWebhookService{
+
+    UserMsgMapper userMsgMapper;
+
+    UserOnlineMapper userOnlineMapper;
+
+
+    private final Map<String,EventHandle> eventHandleMap = new HashMap<>(ImmutableMap.of("msg.notify", new UserMsgEventHandle(),"user.onlinestatus",new UserOnlineEventHandle()));
+
+    @Override
+    public CommonResult wukongWebhook(String event, String reqVo) {
+        EventHandle eventHandle = eventHandleMap.get(event);
+        if(null != eventHandle){
+            log.debug("处理webhook事件");
+            eventHandle.handle(reqVo);
+        }
+        return CommonResult.success("");
+    }
+
+
+
+
+
+    interface EventHandle{
+
+
+        void handle(String  reqVo);
+    }
+
+
+
+    class UserMsgEventHandle implements EventHandle{
+
+        @Override
+        public void handle(String reqVo) {
+            List<Map> msg =new ArrayList<>();
+
+            if(reqVo.startsWith("[")){
+                msg = JSON.parseArray(reqVo, Map.class);
+            }else {
+                msg.add(JSON.parseObject(reqVo, Map.class));
+            }
+
+            List<UserMsgDO> userMsgDOs =new ArrayList<>(msg.size()+1);
+            for (Map map : msg) {
+                String payload = Base64.decodeStr(map.get("payload").toString());
+                map.put("payload",payload) ;
+                map.put("type",JSON.parseObject(payload).getInteger("type"));
+                userMsgDOs.add( BeanUtil.mapToBean(map, UserMsgDO.class, true));
+            }
+            userMsgMapper.insertBatch(userMsgDOs);
+        }
+    }
+
+
+    class UserOnlineEventHandle implements EventHandle{
+
+        @Override
+        public void handle(String reqVo) {
+            log.info("收到用户上下线通知,{}", reqVo);
+        }
+    }
+
+    @Autowired
+    public void setUserMsgMapper(UserMsgMapper userMsgMapper) {
+        this.userMsgMapper = userMsgMapper;
+    }
+    @Autowired
+    public void setUserOnlineMapper(UserOnlineMapper userOnlineMapper) {
+        this.userOnlineMapper = userOnlineMapper;
+    }
+}

+ 7 - 4
menduner/menduner-im-biz/src/main/resources/bootstrap.yaml

@@ -8,18 +8,18 @@ spring:
     allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
     allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Feign 等会存在重复定义的服务
   profiles:
-    active: local
+    active: prod
   cloud:
     nacos:
       server-addr: ${nacosHost:127.0.0.1:8848}
       discovery:
-        namespace: dev # 命名空间。这里使用 dev 开发环境
+        namespace: menduner-dev # 命名空间。这里使用 dev 开发环境
         metadata:
           version: 1.0.0 # 服务实例的版本号,可用于灰度发布
       # Nacos Config 配置项,对应 NacosConfigProperties 配置属性类
       config:
         server-addr: ${nacosHost:127.0.0.1:8848} # Nacos 服务器地址
-        namespace: dev # 命名空间 dev 的ID,不能直接使用 dev 名称。创建命名空间的时候需要指定ID为 dev,这里使用 dev 开发环境
+        namespace: menduner-dev # 命名空间 dev 的ID,不能直接使用 dev 名称。创建命名空间的时候需要指定ID为 dev,这里使用 dev 开发环境
         group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
         name: ${spring.application.name} # 使用的 Nacos 配置集的 dataId,默认为 spring.application.name
         file-extension: yaml # 使用的 Nacos 配置集的 dataId 的文件拓展名,同时也是 Nacos 配置集的配置格式,默认为 properties
@@ -31,5 +31,8 @@ server:
 logging:
   file:
     name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径
-
+citu:
+  info:
+    version: 1.0.0
+    base-package: com.citu.module.menduner.im
 

+ 63 - 0
menduner/menduner-im-biz/src/main/resources/mapper/statistics/ImRecentConversationsStatisticsMapper.xml

@@ -0,0 +1,63 @@
+<?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.citu.module.menduner.im.dal.mysql.statistics.ImRecentConversationsStatisticsMapper">
+
+
+    <select id="imRecentConversationsStatistics" resultType="java.util.Map">
+        SELECT
+            count(1) as count
+        FROM
+            `im_user` u inner join im_user_msg  msg
+            <if test="0==communicateType">
+                on u.uid = msg.from_uid
+            </if>
+            <if test="1==communicateType">
+                on u.uid = msg.channel_id
+            </if>
+        <where>
+            msg.message_seq='1'
+            <if test="userId != null">
+              and   u.user_id = #{userId}
+            </if>
+            <if test="enterpriseId != null">
+                and   u.enterprise_id = #{enterpriseId}
+            </if>
+            <if test="startTime != null">
+                and   msg.timestamp >= #{startTime}
+            </if>
+            <if test="endTime != null">
+                and   msg.timestamp &lt;= #{endTime}
+            </if>
+        </where>
+        union all
+        SELECT
+        count(1) as count
+        FROM
+        `im_user` u inner join im_user_msg  msg
+        <if test="0==communicateType">
+            on u.uid = msg.from_uid
+        </if>
+        <if test="1==communicateType">
+            on u.uid = msg.channel_id
+        </if>
+        <where>
+            msg.message_seq='1'
+            <if test="userId != null">
+                and   u.user_id = #{userId}
+            </if>
+            <if test="enterpriseId != null">
+                and   u.enterprise_id = #{enterpriseId}
+            </if>
+            <if test="startTime != null">
+                and   msg.timestamp >= (#{startTime}-(#{endTime}-#{startTime}))
+            </if>
+            <if test="endTime != null">
+                and   msg.timestamp &lt;= #{startTime}
+            </if>
+        </where>
+
+
+
+
+     </select>
+</mapper>