吴树波 1 тиждень тому
батько
коміт
bcbb9e2c0d
60 змінених файлів з 1274 додано та 262 видалено
  1. 2 0
      fs-common/src/main/java/com/fs/common/enums/DataSourceType.java
  2. 8 1
      fs-company/src/main/java/com/fs/framework/config/DataSourceConfig.java
  3. 8 5
      fs-service/src/main/java/com/fs/company/service/impl/CompanyWxServiceImpl.java
  4. 72 0
      fs-service/src/main/java/com/fs/wxcid/domain/WxMsgLog.java
  5. 17 0
      fs-service/src/main/java/com/fs/wxcid/domain/wx/AddMsgDb.java
  6. 48 0
      fs-service/src/main/java/com/fs/wxcid/domain/wx/Command.java
  7. 33 0
      fs-service/src/main/java/com/fs/wxcid/domain/wx/DeviceInfoEntity.java
  8. 25 0
      fs-service/src/main/java/com/fs/wxcid/domain/wx/LicenseKey.java
  9. 25 0
      fs-service/src/main/java/com/fs/wxcid/domain/wx/MessageCallbackConfig.java
  10. 17 0
      fs-service/src/main/java/com/fs/wxcid/domain/wx/ModContactDb.java
  11. 15 0
      fs-service/src/main/java/com/fs/wxcid/domain/wx/ProxyMapping.java
  12. 15 0
      fs-service/src/main/java/com/fs/wxcid/domain/wx/UserBusinessLog.java
  13. 40 0
      fs-service/src/main/java/com/fs/wxcid/domain/wx/UserInfoEntity.java
  14. 20 0
      fs-service/src/main/java/com/fs/wxcid/domain/wx/UserLoginLog.java
  15. 13 0
      fs-service/src/main/java/com/fs/wxcid/domain/wx/UserMessageLog.java
  16. 40 0
      fs-service/src/main/java/com/fs/wxcid/dto/callback/WxCallbackVo.java
  17. 8 0
      fs-service/src/main/java/com/fs/wxcid/dto/common/IntegerWrapper.java
  18. 61 0
      fs-service/src/main/java/com/fs/wxcid/mapper/WxMsgLogMapper.java
  19. 9 0
      fs-service/src/main/java/com/fs/wxcid/mapper/wx/AddMsgDbMapper.java
  20. 8 0
      fs-service/src/main/java/com/fs/wxcid/mapper/wx/CommandMapper.java
  21. 9 0
      fs-service/src/main/java/com/fs/wxcid/mapper/wx/DeviceInfoEntityMapper.java
  22. 11 0
      fs-service/src/main/java/com/fs/wxcid/mapper/wx/LicenseKeyMapper.java
  23. 12 0
      fs-service/src/main/java/com/fs/wxcid/mapper/wx/MessageCallbackConfigMapper.java
  24. 11 0
      fs-service/src/main/java/com/fs/wxcid/mapper/wx/ModContactDbMapper.java
  25. 10 0
      fs-service/src/main/java/com/fs/wxcid/mapper/wx/ProxyMappingMapper.java
  26. 10 0
      fs-service/src/main/java/com/fs/wxcid/mapper/wx/UserBusinessLogMapper.java
  27. 10 0
      fs-service/src/main/java/com/fs/wxcid/mapper/wx/UserInfoEntityMapper.java
  28. 11 0
      fs-service/src/main/java/com/fs/wxcid/mapper/wx/UserLoginLogMapper.java
  29. 10 0
      fs-service/src/main/java/com/fs/wxcid/mapper/wx/UserMessageLogMapper.java
  30. 6 27
      fs-service/src/main/java/com/fs/wxcid/service/FriendService.java
  31. 65 0
      fs-service/src/main/java/com/fs/wxcid/service/IWxMsgLogService.java
  32. 0 4
      fs-service/src/main/java/com/fs/wxcid/service/LoginService.java
  33. 1 1
      fs-service/src/main/java/com/fs/wxcid/service/MessageCallbackService.java
  34. 1 1
      fs-service/src/main/java/com/fs/wxcid/service/MessageService.java
  35. 27 110
      fs-service/src/main/java/com/fs/wxcid/service/impl/FriendServiceImpl.java
  36. 6 44
      fs-service/src/main/java/com/fs/wxcid/service/impl/LoginServiceImpl.java
  37. 24 16
      fs-service/src/main/java/com/fs/wxcid/service/impl/MessageCallbackServiceImpl.java
  38. 11 51
      fs-service/src/main/java/com/fs/wxcid/service/impl/MessageServiceImpl.java
  39. 3 1
      fs-service/src/main/java/com/fs/wxcid/service/impl/UserServiceImpl.java
  40. 115 0
      fs-service/src/main/java/com/fs/wxcid/service/impl/WxMsgLogServiceImpl.java
  41. 14 0
      fs-service/src/main/java/com/fs/wxcid/vo/VerifyUserVo.java
  42. 1 0
      fs-service/src/main/resources/application-config-dev.yml
  43. 5 0
      fs-service/src/main/resources/application-dev.yml
  44. 131 0
      fs-service/src/main/resources/mapper/WxMsgLog/WxMsgLogMapper.xml
  45. 7 0
      fs-service/src/main/resources/mapper/wxcid/AddMsgDbMapper.xml
  46. 7 0
      fs-service/src/main/resources/mapper/wxcid/CommandMapper.xml
  47. 7 0
      fs-service/src/main/resources/mapper/wxcid/DeviceInfoEntityMapper.xml
  48. 7 0
      fs-service/src/main/resources/mapper/wxcid/LicenseKeyMapper.xml
  49. 7 0
      fs-service/src/main/resources/mapper/wxcid/MessageCallbackConfigMapper.xml
  50. 7 0
      fs-service/src/main/resources/mapper/wxcid/ModContactDbMapper.xml
  51. 7 0
      fs-service/src/main/resources/mapper/wxcid/ProxyMappingMapper.xml
  52. 7 0
      fs-service/src/main/resources/mapper/wxcid/UserBusinessLogMapper.xml
  53. 7 0
      fs-service/src/main/resources/mapper/wxcid/UserInfoEntityMapper.xml
  54. 7 0
      fs-service/src/main/resources/mapper/wxcid/UserLoginLogMapper.xml
  55. 7 0
      fs-service/src/main/resources/mapper/wxcid/UserMessageLogMapper.xml
  56. 9 0
      fs-wx-api/pom.xml
  57. 8 0
      fs-wx-api/src/main/java/com/fs/FsWxApiApplication.java
  58. 46 0
      fs-wx-api/src/main/java/com/fs/app/controller/CallBackController.java
  59. 144 0
      fs-wx-api/src/main/java/com/fs/app/controller/WebscoketServer.java
  60. 2 1
      fs-wx-api/src/main/resources/application.yml

+ 2 - 0
fs-common/src/main/java/com/fs/common/enums/DataSourceType.java

@@ -15,6 +15,8 @@ public enum DataSourceType
     CLICKHOUSE,
 
     SOP,
+    WX,
+    WX_READ,
     /**
      * 从库
      */

+ 8 - 1
fs-company/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -34,14 +34,21 @@ public class DataSourceConfig {
         return new DruidDataSource();
     }
 
+    @Bean
+    @ConfigurationProperties(prefix = "spring.datasource.mysql.druid.wx")
+    public DataSource wxDataSource() {
+        return new DruidDataSource();
+    }
+
 
 
     @Bean
     @Primary
-    public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
+    public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource, @Qualifier("wxDataSource") DataSource wxDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
         targetDataSources.put(DataSourceType.MASTER, masterDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
+        targetDataSources.put(DataSourceType.WX, wxDataSource);
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }
 

+ 8 - 5
fs-service/src/main/java/com/fs/company/service/impl/CompanyWxServiceImpl.java

@@ -20,14 +20,13 @@ import com.fs.wxcid.dto.login.LoginStatusResponseData;
 import com.fs.wxcid.dto.user.UserInfo;
 import com.fs.wxcid.dto.user.UserInfoExt;
 import com.fs.wxcid.dto.user.UserProfileData;
-import com.fs.wxcid.service.AdminLicenseService;
-import com.fs.wxcid.service.FriendService;
-import com.fs.wxcid.service.ICidIpadServerService;
-import com.fs.wxcid.service.ICidIpadServerUserService;
+import com.fs.wxcid.mapper.wx.ModContactDbMapper;
+import com.fs.wxcid.service.*;
 import com.fs.wxcid.service.impl.LoginServiceImpl;
 import com.fs.wxcid.service.impl.UserServiceImpl;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
@@ -46,7 +45,7 @@ import java.util.stream.Collectors;
 @Service
 public class CompanyWxServiceImpl extends ServiceImpl<CompanyWxAccountMapper, CompanyWxAccount> implements ICompanyWxAccountService {
     private final static String FRIEND_KEY = "cid:wx:friend-list:";
-    private final static List<String> REMOVE_FRIEND_STR_ARRAY = Arrays.asList("weixin", "fmessage", "medianote", "gh_3dfda90e39d6");
+    private final static List<String> REMOVE_FRIEND_STR_ARRAY = Arrays.asList("weixin", "fmessage", "medianote", "gh_3dfda90e39d6", "qqmail");
     private final static String IS_ROOM_KEY = "@chatroom";
     @Autowired
     private CompanyWxAccountMapper companyWxAccountMapper;
@@ -67,7 +66,11 @@ public class CompanyWxServiceImpl extends ServiceImpl<CompanyWxAccountMapper, Co
     @Autowired
     private FriendService friendService;
     @Autowired
+    private MessageCallbackService messageCallbackService;
+    @Autowired
     private RedisCacheT<List<String>> friendListRedis;
+    @Autowired
+    private ModContactDbMapper modContactDbMapper;
 
     /**
      * 查询企微账号

+ 72 - 0
fs-service/src/main/java/com/fs/wxcid/domain/WxMsgLog.java

@@ -0,0 +1,72 @@
+package com.fs.wxcid.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntityTow;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 个微消息记录对象 wx_msg_log
+ *
+ * @author fs
+ * @date 2025-12-16
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class WxMsgLog extends BaseEntityTow {
+
+    /** 账号ID */
+    @Excel(name = "账号ID")
+    private Long accountId;
+
+    /** 设备标识 */
+    @Excel(name = "设备标识")
+    private String authKey;
+
+    /** 发送类型 */
+    @Excel(name = "发送类型")
+    private String type;
+
+    /** 消息ID */
+    @Excel(name = "消息ID")
+    private Long msgId;
+
+    /** 发送微信号 */
+    @Excel(name = "发送微信号")
+    private String fromUserName;
+
+    /** 接收微信号 */
+    @Excel(name = "接收微信号")
+    private String toUserName;
+
+    /** 消息类型 */
+    @Excel(name = "消息类型")
+    private Integer msgType;
+
+    /** 内容 */
+    @Excel(name = "内容")
+    private String content;
+
+    /** $column.columnComment */
+    @Excel(name = "内容")
+    private Integer imgStatus;
+
+    /** $column.columnComment */
+    @Excel(name = "内容")
+    private Long imgBuf;
+
+    /** $column.columnComment */
+    @Excel(name = "内容")
+    private String pushContent;
+
+    /** 消息ID */
+    @Excel(name = "消息ID")
+    private Long newMsgId;
+    /** 接收状态0收1发 */
+    @Excel(name = "接收状态0收1发")
+    private Integer receiveType;
+
+
+}

+ 17 - 0
fs-service/src/main/java/com/fs/wxcid/domain/wx/AddMsgDb.java

@@ -0,0 +1,17 @@
+package com.fs.wxcid.domain.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class AddMsgDb {
+    private String uuid;
+    private String newMsgId;
+    @TableId
+    private String msgUuidCombined;
+    private String data;
+    private LocalDateTime createTime;
+
+}

+ 48 - 0
fs-service/src/main/java/com/fs/wxcid/domain/wx/Command.java

@@ -0,0 +1,48 @@
+package com.fs.wxcid.domain.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class Command {
+    @TableId
+    private String uuid;
+    private Integer a101;
+    private Integer a111;
+    private Integer a102;
+    private Integer a103;
+    private Integer a104;
+    private String a104Str;
+    private Integer a105;
+    private Integer a106;
+    private Integer a107;
+    private Integer a109;
+    private Integer a116;
+    private String a116Str;
+    private Integer a118;
+    private String a118Str;
+    private Integer a301;
+    private String a301Str;
+    private Integer a401;
+    private Integer a402;
+    private Integer a403;
+    private Integer a601;
+    private Integer a801;
+    private Integer a811;
+    private Integer b001;
+    private String b001Str;
+    private Integer b002;
+    private String b002Str;
+    private Integer b003;
+    private String b003Str;
+    private Integer b004;
+    private String b004Str;
+    private Integer b005;
+    private String b005Str;
+    private Integer b006;
+    private String b006Str;
+
+
+}

+ 33 - 0
fs-service/src/main/java/com/fs/wxcid/domain/wx/DeviceInfoEntity.java

@@ -0,0 +1,33 @@
+package com.fs.wxcid.domain.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class DeviceInfoEntity {
+    @TableId
+    private String wxid;
+    private String uuidone;
+    private String uuidtwo;
+    private String imei;
+    private String deviceid;
+    private String devicename;
+    private String timezone;
+    private String language;
+    private String devicebrand;
+    private String realcountry;
+    private String iphonever;
+    private String boudleid;
+    private String ostype;
+    private String adsource;
+    private String ostypenumber;
+    private Integer corecount;
+    private String carriername;
+    private String softtypexml;
+    private String clientcheckdataxml;
+    private String guid2;
+
+
+}

+ 25 - 0
fs-service/src/main/java/com/fs/wxcid/domain/wx/LicenseKey.java

@@ -0,0 +1,25 @@
+package com.fs.wxcid.domain.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class LicenseKey {
+    @TableId
+    private Integer id;
+    private String deviceToken;
+    private Integer status;
+    private String license;
+    private String expiryDate;
+    private String startDate;
+    private String wxId;
+    private String nickName;
+    private String bindmobile;
+    private String alias;
+    private Integer type;
+    private Integer isBanned;
+
+
+}

+ 25 - 0
fs-service/src/main/java/com/fs/wxcid/domain/wx/MessageCallbackConfig.java

@@ -0,0 +1,25 @@
+package com.fs.wxcid.domain.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class MessageCallbackConfig {
+    @TableId
+    private String id;
+    private String uuid;
+    private String key;
+    private String callbackUrl;
+    private Integer enabled;
+    private LocalDateTime createdAt;
+    private LocalDateTime updatedAt;
+
+
+
+
+
+
+
+}

+ 17 - 0
fs-service/src/main/java/com/fs/wxcid/domain/wx/ModContactDb.java

@@ -0,0 +1,17 @@
+package com.fs.wxcid.domain.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class ModContactDb {
+    private String uuid;
+    private String userName;
+    @TableId
+    private String userUuidCombined;
+    private String data;
+
+
+}

+ 15 - 0
fs-service/src/main/java/com/fs/wxcid/domain/wx/ProxyMapping.java

@@ -0,0 +1,15 @@
+package com.fs.wxcid.domain.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+@Data
+public class ProxyMapping {
+    @TableId
+    private Integer id;
+    private String proxyNumber;
+    private String proxyValue;
+    private String createTime;
+    private String updateTime;
+
+}

+ 15 - 0
fs-service/src/main/java/com/fs/wxcid/domain/wx/UserBusinessLog.java

@@ -0,0 +1,15 @@
+package com.fs.wxcid.domain.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+@Data
+public class UserBusinessLog {
+    @TableId
+    private Integer id;
+    private String uuid;
+    private String userName;
+    private String businessType;
+    private String exResult;
+
+}

+ 40 - 0
fs-service/src/main/java/com/fs/wxcid/domain/wx/UserInfoEntity.java

@@ -0,0 +1,40 @@
+package com.fs.wxcid.domain.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+@Data
+public class UserInfoEntity {
+    @TableId
+    private Integer wxId;
+    private String targetIp;
+    private String uuid;
+    private String uin;
+    private String nickname;
+    private String bindmobile;
+    private String alias;
+    private String userName;
+    private String password;
+    private String headurl;
+    private String cookie;
+    private String sessionKey;
+    private String proxy;
+    private Integer clientVersion;
+    private String shorthost;
+    private String longhost;
+    private String ecpukey;
+    private String ecprkey;
+    private String checksumkey;
+    private String autoauthkey;
+    private Integer state;
+    private Integer initcontact;
+    private String synckey;
+    private String favsynckey;
+    private Integer loginRsaVer;
+    private String errMsg;
+    private String deviceCreateTime;
+    private String lastLoginTime;
+    private String lastAuthTime;
+    private Integer shortLinkEnabled;
+
+}

+ 20 - 0
fs-service/src/main/java/com/fs/wxcid/domain/wx/UserLoginLog.java

@@ -0,0 +1,20 @@
+package com.fs.wxcid.domain.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+@Data
+public class UserLoginLog {
+    @TableId
+    private Integer id;
+    private String targetIp;
+    private String uUid;
+    private String userName;
+    private String nickName;
+    private String loginType;
+    private String updatedAt;
+    private Integer retCode;
+    private String errMsg;
+
+
+}

+ 13 - 0
fs-service/src/main/java/com/fs/wxcid/domain/wx/UserMessageLog.java

@@ -0,0 +1,13 @@
+package com.fs.wxcid.domain.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+@Data
+public class UserMessageLog {
+    @TableId
+    private String userName;
+    private String msgIds;
+
+
+}

+ 40 - 0
fs-service/src/main/java/com/fs/wxcid/dto/callback/WxCallbackVo.java

@@ -0,0 +1,40 @@
+package com.fs.wxcid.dto.callback;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fs.wxcid.dto.common.IntegerWrapper;
+import com.fs.wxcid.dto.common.StringWrapper;
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class WxCallbackVo {
+    private String key;
+    private Message message;
+    private String type;
+    @Data
+    public static class Message{
+        @JsonProperty("msg_id")
+        private Long msgId;
+        @JsonProperty("from_user_name")
+        private StringWrapper fromUserName;
+        @JsonProperty("to_user_name")
+        private StringWrapper toUserName;
+        @JsonProperty("msg_type")
+        private Integer msgType;
+        private StringWrapper content;
+        private Integer status;
+        @JsonProperty("img_status")
+        private Integer imgStatus;
+        @JsonProperty("img_buf")
+        private IntegerWrapper imgBuf;
+        @JsonProperty("create_time")
+        private Integer createTime;
+        @JsonProperty("msg_source")
+        private String msgSource;
+        @JsonProperty("push_content")
+        private String pushContent;
+        @JsonProperty("new_msg_id")
+        private Long newMsgId;
+    }
+}

+ 8 - 0
fs-service/src/main/java/com/fs/wxcid/dto/common/IntegerWrapper.java

@@ -0,0 +1,8 @@
+package com.fs.wxcid.dto.common;
+
+import lombok.Data;
+
+@Data
+public class IntegerWrapper {
+    private Long len;
+}

+ 61 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/WxMsgLogMapper.java

@@ -0,0 +1,61 @@
+package com.fs.wxcid.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.WxMsgLog;
+
+/**
+ * 个微消息记录Mapper接口
+ * 
+ * @author fs
+ * @date 2025-12-16
+ */
+public interface WxMsgLogMapper extends BaseMapper<WxMsgLog>{
+    /**
+     * 查询个微消息记录
+     * 
+     * @param id 个微消息记录主键
+     * @return 个微消息记录
+     */
+    WxMsgLog selectWxMsgLogById(Long id);
+
+    /**
+     * 查询个微消息记录列表
+     * 
+     * @param wxMsgLog 个微消息记录
+     * @return 个微消息记录集合
+     */
+    List<WxMsgLog> selectWxMsgLogList(WxMsgLog wxMsgLog);
+
+    /**
+     * 新增个微消息记录
+     * 
+     * @param wxMsgLog 个微消息记录
+     * @return 结果
+     */
+    int insertWxMsgLog(WxMsgLog wxMsgLog);
+
+    /**
+     * 修改个微消息记录
+     * 
+     * @param wxMsgLog 个微消息记录
+     * @return 结果
+     */
+    int updateWxMsgLog(WxMsgLog wxMsgLog);
+
+    /**
+     * 删除个微消息记录
+     * 
+     * @param id 个微消息记录主键
+     * @return 结果
+     */
+    int deleteWxMsgLogById(Long id);
+
+    /**
+     * 批量删除个微消息记录
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteWxMsgLogByIds(Long[] ids);
+}

+ 9 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/wx/AddMsgDbMapper.java

@@ -0,0 +1,9 @@
+package com.fs.wxcid.mapper.wx;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.wx.AddMsgDb;
+import lombok.Data;
+
+public interface AddMsgDbMapper extends BaseMapper<AddMsgDb> {
+
+}

+ 8 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/wx/CommandMapper.java

@@ -0,0 +1,8 @@
+package com.fs.wxcid.mapper.wx;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.wx.Command;
+
+public interface CommandMapper extends BaseMapper<Command> {
+
+}

+ 9 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/wx/DeviceInfoEntityMapper.java

@@ -0,0 +1,9 @@
+package com.fs.wxcid.mapper.wx;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.wx.DeviceInfoEntity;
+
+public interface DeviceInfoEntityMapper extends BaseMapper<DeviceInfoEntity> {
+
+
+}

+ 11 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/wx/LicenseKeyMapper.java

@@ -0,0 +1,11 @@
+package com.fs.wxcid.mapper.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.wx.LicenseKey;
+import lombok.Data;
+
+public interface LicenseKeyMapper extends BaseMapper<LicenseKey> {
+
+
+}

+ 12 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/wx/MessageCallbackConfigMapper.java

@@ -0,0 +1,12 @@
+package com.fs.wxcid.mapper.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.wx.MessageCallbackConfig;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+public interface MessageCallbackConfigMapper extends BaseMapper<MessageCallbackConfig> {
+
+}

+ 11 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/wx/ModContactDbMapper.java

@@ -0,0 +1,11 @@
+package com.fs.wxcid.mapper.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.wx.ModContactDb;
+import lombok.Data;
+
+public interface ModContactDbMapper extends BaseMapper<ModContactDb> {
+
+
+}

+ 10 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/wx/ProxyMappingMapper.java

@@ -0,0 +1,10 @@
+package com.fs.wxcid.mapper.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.wx.ProxyMapping;
+import lombok.Data;
+
+public interface ProxyMappingMapper extends BaseMapper<ProxyMapping> {
+
+}

+ 10 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/wx/UserBusinessLogMapper.java

@@ -0,0 +1,10 @@
+package com.fs.wxcid.mapper.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.wx.UserBusinessLog;
+import lombok.Data;
+
+public interface UserBusinessLogMapper extends BaseMapper<UserBusinessLog> {
+
+}

+ 10 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/wx/UserInfoEntityMapper.java

@@ -0,0 +1,10 @@
+package com.fs.wxcid.mapper.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.wx.UserInfoEntity;
+import lombok.Data;
+
+public interface UserInfoEntityMapper extends BaseMapper<UserInfoEntity> {
+
+}

+ 11 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/wx/UserLoginLogMapper.java

@@ -0,0 +1,11 @@
+package com.fs.wxcid.mapper.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.wx.UserLoginLog;
+import lombok.Data;
+
+public interface UserLoginLogMapper extends BaseMapper<UserLoginLog> {
+
+
+}

+ 10 - 0
fs-service/src/main/java/com/fs/wxcid/mapper/wx/UserMessageLogMapper.java

@@ -0,0 +1,10 @@
+package com.fs.wxcid.mapper.wx;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.wxcid.domain.wx.UserMessageLog;
+import lombok.Data;
+
+public interface UserMessageLogMapper extends BaseMapper<UserMessageLog> {
+
+}

+ 6 - 27
fs-service/src/main/java/com/fs/wxcid/service/FriendService.java

@@ -2,9 +2,11 @@
 
 package com.fs.wxcid.service;
 
-import com.fs.wxcid.dto.common.ApiResponseCommon;
 import com.fs.wxcid.dto.common.BaseResponse;
 import com.fs.wxcid.dto.friend.*;
+import com.fs.wxcid.vo.VerifyUserVo;
+
+import java.util.List;
 
 /**
  * 好友管理服务接口
@@ -22,28 +24,9 @@ public interface FriendService {
      * 对应接口:POST /friend/GetContactDetailsList
      * 可同时查询多个用户或群聊的详细资料。
      * </p>
-     *
-     * @param authKey    账号唯一标识
-     * @param request 查询参数(支持 UserNames 和 RoomWxIDList)
      * @return 统一响应结果
      */
-    ApiResponseCommon<GetContactDetailsResponseData> getContactDetailsList(String authKey, GetContactDetailsListRequest request);
-    /**
-     * 分页获取全部联系人(包括好友和群聊)
-     * <p>
-     * 对应接口:POST /friend/GetContactList
-     * 通过序列号实现分页加载,避免一次性拉取过多数据。
-     * </p>
-     *
-     * @param authKey    账号唯一标识
-     * @param request 分页参数(CurrentWxcontactSeq / CurrentChatRoomContactSeq)
-     * @return 统一响应结果
-     */
-    // 反序列化为泛型响应对象
-    ApiResponseCommon<ContactListResponse> getContactList(String authKey, GetContactListRequest request);
-
-
-
+    GetContactDetailsResponseData getContactDetailsList(Long accountId, List<String> wxIdList);
     /**
      * 搜索联系人
      * <p>
@@ -51,11 +34,9 @@ public interface FriendService {
      * 支持按昵称、微信号、手机号等模糊搜索。
      * </p>
      *
-     * @param authKey    账号唯一标识
-     * @param request 搜索参数(UserName + 场景配置)
      * @return 统一响应结果
      */
-    ApiResponseCommon<SearchContactResponse> searchContact(String authKey, SearchContactRequest request);
+    SearchContactResponse searchContact(Long accountId, String phone);
 
     /**
      * 发起好友验证或添加请求
@@ -65,10 +46,8 @@ public interface FriendService {
      * 若无 V3/V4,部分场景可能无法添加。
      * </p>
      *
-     * @param authKey    账号唯一标识
-     * @param request 添加请求参数(含 V3、V4、Scene、验证语等)
      * @return 统一响应结果
      */
-    ApiResponseCommon<BaseResponse> verifyUser(String authKey, AgreeAddRequest request);
+    BaseResponse verifyUser(Long accountId, VerifyUserVo vo);
     ContactListResponse getContactListNotKey(Long accountId);
 }

+ 65 - 0
fs-service/src/main/java/com/fs/wxcid/service/IWxMsgLogService.java

@@ -0,0 +1,65 @@
+package com.fs.wxcid.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.company.domain.CompanyWxAccount;
+import com.fs.wxcid.domain.WxMsgLog;
+import com.fs.wxcid.dto.callback.WxCallbackVo;
+
+/**
+ * 个微消息记录Service接口
+ * 
+ * @author fs
+ * @date 2025-12-16
+ */
+public interface IWxMsgLogService extends IService<WxMsgLog>{
+    /**
+     * 查询个微消息记录
+     * 
+     * @param id 个微消息记录主键
+     * @return 个微消息记录
+     */
+    WxMsgLog selectWxMsgLogById(Long id);
+
+    /**
+     * 查询个微消息记录列表
+     * 
+     * @param wxMsgLog 个微消息记录
+     * @return 个微消息记录集合
+     */
+    List<WxMsgLog> selectWxMsgLogList(WxMsgLog wxMsgLog);
+
+    /**
+     * 新增个微消息记录
+     * 
+     * @param wxMsgLog 个微消息记录
+     * @return 结果
+     */
+    int insertWxMsgLog(WxMsgLog wxMsgLog);
+
+    /**
+     * 修改个微消息记录
+     * 
+     * @param wxMsgLog 个微消息记录
+     * @return 结果
+     */
+    int updateWxMsgLog(WxMsgLog wxMsgLog);
+
+    /**
+     * 批量删除个微消息记录
+     * 
+     * @param ids 需要删除的个微消息记录主键集合
+     * @return 结果
+     */
+    int deleteWxMsgLogByIds(Long[] ids);
+
+    /**
+     * 删除个微消息记录信息
+     * 
+     * @param id 个微消息记录主键
+     * @return 结果
+     */
+    int deleteWxMsgLogById(Long id);
+
+    void insertLog(WxCallbackVo callbackVo, CompanyWxAccount account, int type);
+}

+ 0 - 4
fs-service/src/main/java/com/fs/wxcid/service/LoginService.java

@@ -12,13 +12,9 @@ public interface LoginService {
     // 检测扫码是否完成
     LoginStatusResponseData checkLoginStatus(Long accountId);
 
-    // 获取当前在线状态
-    ApiResponseCommon<LoginStatusData> getLoginStatus(String authKey);
-
     // 退出登录
     ApiResponseCommon<Void> logOut(Long accountId);
 
     /// 唤醒登录
-    ApiResponseCommon<Void> wakeUpLogin(String authKey, QrCodeRequest request);
     ApiResponseCommon<Void> wakeUpLogin(Long authKey);
 }

+ 1 - 1
fs-service/src/main/java/com/fs/wxcid/service/MessageCallbackService.java

@@ -25,7 +25,7 @@ public interface MessageCallbackService {
      * @param config 回调配置(URL + 启用状态)
      * @return 统一响应结果
      */
-    ApiResponseCommon<Void> setCallback(String authKey, CallbackConfigRequest config);
+    ApiResponseCommon<Void> setCallback(Long accountId);
 
     /**
      * 获取当前账号的消息回调配置

+ 1 - 1
fs-service/src/main/java/com/fs/wxcid/service/MessageService.java

@@ -7,6 +7,6 @@ import com.fs.wxcid.dto.message.*;
 import java.util.List;
 
 public interface MessageService {
-    ApiResponseCommon<List<SendMessageResult>> sendTextMessage(String authKey, SendTextMessageRequest request);
+    ApiResponseCommon<List<SendMessageResult>> sendTextMessage(Long accountId);
 
 }

+ 27 - 110
fs-service/src/main/java/com/fs/wxcid/service/impl/FriendServiceImpl.java

@@ -1,21 +1,18 @@
 package com.fs.wxcid.service.impl;
 
-import com.fs.common.exception.CustomException;
 import com.fs.wxcid.ServiceUtils;
-import com.fs.wxcid.dto.common.ApiResponse;
 import com.fs.wxcid.dto.common.ApiResponseCommon;
 import com.fs.wxcid.dto.common.BaseResponse;
 import com.fs.wxcid.dto.friend.*;
 import com.fs.wxcid.dto.login.RequestBaseVo;
 import com.fs.wxcid.service.FriendService;
-import com.fs.wxwork.utils.WxWorkHttpUtil;
+import com.fs.wxcid.vo.VerifyUserVo;
 import com.alibaba.fastjson.TypeReference;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.util.List;
 
 /**
  * 好友管理服务实现类
@@ -28,95 +25,45 @@ public class FriendServiceImpl implements FriendService {
     private ServiceUtils serviceUtils;
 
     /** 微信接口基础 URL */
-    private static final String BASE_URL = "http://114.117.215.244:7006";
+    private static final String BASE_URL = "/friend/";
 
     @Override
-    public ApiResponseCommon<GetContactDetailsResponseData> getContactDetailsList(
-            String authKey, GetContactDetailsListRequest request) {
-
-        String url = BASE_URL + "/friend/GetContactDetailsList?key=" + authKey;
-        ApiResponseCommon<GetContactDetailsResponseData> response = WxWorkHttpUtil.postWithType(
-                url,
-                request,
-                new TypeReference<ApiResponseCommon<GetContactDetailsResponseData>>() {}
-        );
-
-        //异常处理
-        if (response.getCode() != 200 || response.getData() == null) {
-            String errorMsg = response.getText() != null ? response.getText() : "获取联系人详情失败";
-            throw new CustomException("获取联系人列表失败: " + errorMsg);
-        }
-
-        return response;
-    }
-    @Override
-    public ApiResponseCommon<ContactListResponse> getContactList(String authKey, GetContactListRequest request) {
-        log.info("开始获取联系人列表");
-
-        String url = BASE_URL + "/friend/GetContactList?key=" + authKey;
-        ApiResponseCommon<ContactListResponse> response = WxWorkHttpUtil.postWithType(
-                url,
-                request,
-                new TypeReference<ApiResponseCommon<ContactListResponse>>() {}
-        );
-        if (response.getCode() != 200 || response.getData() == null) {
-            throw new CustomException("获取联系人失败: " + response.getText());
-        }
-
-        // 安全打印日志(避免 NPE)
-        ContactListResponse data = response.getData();
-        if (data.getContactList() != null) {
-            log.info("联系人id合集: {}", data.getContactList().getContactUsernameList());
-        }
-        return response;
-
+    public GetContactDetailsResponseData getContactDetailsList(Long accountId, List<String> wxIdList) {
+        GetContactDetailsListRequest request = new GetContactDetailsListRequest();
+        request.setUserNames(wxIdList);
+        ApiResponseCommon<GetContactDetailsResponseData> response = serviceUtils.sendPost(BASE_URL + "GetContactDetailsList", RequestBaseVo.builder().accountId(accountId).data(request).build(), new TypeReference<ApiResponseCommon<GetContactDetailsResponseData>>() {});
+        return response.getData();
     }
-
     @Override
-    public ApiResponseCommon<SearchContactResponse> searchContact(String authKey, SearchContactRequest request) {
-        log.info("开始搜索联系人,authKey: {}, request: {}", authKey, request);
-
-        String url = BASE_URL + "/friend/SearchContact?key=" + authKey;
-
-        ApiResponseCommon<SearchContactResponse> response = WxWorkHttpUtil.postWithType(
-                url,
-                request,
-                new TypeReference<ApiResponseCommon<SearchContactResponse>>() {}
-        );
-
-        // 校验响应
-        if (response.getCode() != 200 || response.getData() == null) {
-            throw new CustomException("搜索联系人失败: " + response.getText());
-        }
-
+    public SearchContactResponse searchContact(Long accountId, String phone) {
+        SearchContactRequest request = new SearchContactRequest();
+        request.setFromScene(0);
+        request.setOpCode(2);
+        request.setSearchScene(1);
+        request.setUserName(phone);
+        ApiResponseCommon<SearchContactResponse> response = serviceUtils.sendPost(BASE_URL + "SearchContact", RequestBaseVo.builder().accountId(accountId).data(request).build(), new TypeReference<ApiResponseCommon<SearchContactResponse>>() {});
         SearchContactResponse data = response.getData();
         String userNameStr = data.getUserNameStr();
         String antispamTicket = data.getAntispamTicket();
-
         log.info("搜索成功 - V3: {}, V4: {}",
                 userNameStr != null ? userNameStr : "null",
                 antispamTicket != null ? antispamTicket : "null"
         );
-
-        return response;
+        return data;
     }
 
     @Override
-    public ApiResponseCommon<BaseResponse> verifyUser(String authKey, AgreeAddRequest request) {
-        String url = BASE_URL + "/friend/VerifyUser?key=" + authKey;
-
-        ApiResponseCommon<BaseResponse> response = WxWorkHttpUtil.postWithType(
-                url,
-                request,
-                new TypeReference<ApiResponseCommon<BaseResponse>>() {}
-        );
-
-        // 校验通用响应
-        if (response.getCode() != 200 || response.getData() == null) {
-            throw new CustomException("发起好友验证失败: " + response.getText());
-        }
+    public BaseResponse verifyUser(Long accountId, VerifyUserVo vo) {
+        AgreeAddRequest request = new AgreeAddRequest();
+        request.setChatRoomUserName(vo.getChatRoomUserName());
+        request.setOpCode(vo.getOpCode());
+        request.setScene(vo.getScene());
+        request.setV3(vo.getV3());
+        request.setV4(vo.getV4());
+        request.setVerifyContent(vo.getContent());
+        ApiResponseCommon<BaseResponse> response = serviceUtils.sendPost(BASE_URL + "VerifyUser", RequestBaseVo.builder().accountId(accountId).data(request).build(), new TypeReference<ApiResponseCommon<BaseResponse>>() {});
         log.info("好友验证请求已成功发送");
-        return response;
+        return response.getData();
     }
 
     @Override
@@ -124,37 +71,7 @@ public class FriendServiceImpl implements FriendService {
         GetContactListRequest request = new GetContactListRequest();
         request.setCurrentChatRoomContactSeq(0);
         request.setCurrentWxcontactSeq(0);
-        ApiResponseCommon<ContactListResponse> response = serviceUtils.sendPost("/friend/GetContactList", RequestBaseVo.builder().accountId(accountId).data(request).build(), new TypeReference<ApiResponseCommon<ContactListResponse>>() {});
+        ApiResponseCommon<ContactListResponse> response = serviceUtils.sendPost(BASE_URL + "GetContactList", RequestBaseVo.builder().accountId(accountId).data(request).build(), new TypeReference<ApiResponseCommon<ContactListResponse>>() {});
         return response.getData();
     }
-
-
-    // ------------------ 工具方法 ------------------
-    /**
-     * 通用 POST 请求方法
-     *
-     * @param path   接口路径,如 "/friend/AgreeAdd"
-     * @param authKey    账号唯一标识(query 参数)
-     * @param request 请求体对象
-     * @return 统一响应结果
-     */
-    private ApiResponse post(String path, String authKey, Object request) {
-        String url = BASE_URL + path + "?key=" + authKey;
-        return WxWorkHttpUtil.postWithType(url, request, new TypeReference<ApiResponse>() {});
-    }
-
-    /**
-     * 通用 GET 请求方法(无请求体)
-     *
-     * @param path 接口路径
-     * @param authKey  账号唯一标识
-     * @return 统一响应结果
-     */
-    private ApiResponse get(String path, String authKey) {
-        String url = BASE_URL + path;
-        Map<String, Object> params = new HashMap<>();
-        params.put("authKey", authKey);
-        String resp = WxWorkHttpUtil.get(url, params);
-        return com.alibaba.fastjson.JSON.parseObject(resp, ApiResponse.class);
-    }
 }

+ 6 - 44
fs-service/src/main/java/com/fs/wxcid/service/impl/LoginServiceImpl.java

@@ -18,28 +18,27 @@ import org.springframework.stereotype.Service;
 @Service
 public class LoginServiceImpl implements LoginService {
 
-    private static final String BASE_URL = "http://114.117.215.244:7006";
-
     @Autowired
     private RedisCache redisCache;
     @Autowired
     private AdminLicenseService adminLicenseService;
     @Autowired
     private ServiceUtils serviceUtils;
+    private static final String BASE_URL = "/login/";
 
     public String getLoginQrCodeNewDirect(Long accountId, String ipadOrMac) {
         QrCodeRequest request = new QrCodeRequest();
         request.setCheck(false);
         request.setIpadOrmac(ipadOrMac);
         request.setProxy(serviceUtils.getProxy(accountId));
-        ApiResponseCommon<LoginQrCodeResponseData> response = serviceUtils.sendPost("/login/GetLoginQrCodeNewDirect", RequestBaseVo.builder().accountId(accountId).data(request).build(), new TypeReference<ApiResponseCommon<LoginQrCodeResponseData>>() {});
+        ApiResponseCommon<LoginQrCodeResponseData> response = serviceUtils.sendPost(BASE_URL + "GetLoginQrCodeNewDirect", RequestBaseVo.builder().accountId(accountId).data(request).build(), new TypeReference<ApiResponseCommon<LoginQrCodeResponseData>>() {});
         //安全访问 data
         log.info("二维码照片url: {}", response.getData().getQrCodeUrl());
         return response.getData().getQrCodeUrl();
     }
     @Override
     public LoginStatusResponseData checkLoginStatus(Long accountId) {
-        ApiResponseCommon<LoginStatusResponseData> response = serviceUtils.sendGet("/login/CheckLoginStatus", RequestBaseVo.builder().accountId(accountId).build(), new TypeReference<ApiResponseCommon<LoginStatusResponseData>>() {});
+        ApiResponseCommon<LoginStatusResponseData> response = serviceUtils.sendGet(BASE_URL + "CheckLoginStatus", RequestBaseVo.builder().accountId(accountId).build(), new TypeReference<ApiResponseCommon<LoginStatusResponseData>>() {});
         // 只认 text == "账号已登录"
         if ("账号已登录".equals(response.getText()) || "登录成功".equals(response.getText())) {
             if (response.getData() == null) {
@@ -54,33 +53,15 @@ public class LoginServiceImpl implements LoginService {
 
     public LoginStatusData getLoginStatus(Long accountId) {
         try {
-            ApiResponseCommon<LoginStatusData> response = serviceUtils.sendGet("/login/GetLoginStatus", RequestBaseVo.builder().accountId(accountId).data(null).build(), new TypeReference<ApiResponseCommon<LoginStatusData>>() {});
+            ApiResponseCommon<LoginStatusData> response = serviceUtils.sendGet(BASE_URL + "GetLoginStatus", RequestBaseVo.builder().accountId(accountId).data(null).build(), new TypeReference<ApiResponseCommon<LoginStatusData>>() {});
             return response.getData();
         }catch (Exception e){
             return new LoginStatusData();
         }
     }
-    public ApiResponseCommon<LoginStatusData> getLoginStatus(String authKey) {
-        String url = BASE_URL + "/login/GetLoginStatus?key=" + authKey;
-        ApiResponseCommon<LoginStatusData> response = WxWorkHttpUtil.getWithType(
-                url,
-                new TypeReference<ApiResponseCommon<LoginStatusData>>() {}
-        );
-
-        //核心判断:只有 code=200 且 data 不为 null 才算成功
-        if (response.getCode() != 200 || response.getData() == null) {
-            String errorMsg = response.getText() != null
-                    ? response.getText()
-                    : "获取登录状态失败,未知错误";
-            throw new CustomException("账号未登录或状态异常: " + errorMsg);
-        }
-
-        return response;
-    }
-
 
     public ApiResponseCommon<Void> logOut(Long accountId) {
-        ApiResponseCommon<Void> response = serviceUtils.sendGet("/login/LogOut", RequestBaseVo.builder().accountId(accountId).build(), new TypeReference<ApiResponseCommon<Void>>() {});
+        ApiResponseCommon<Void> response = serviceUtils.sendGet(BASE_URL + "LogOut", RequestBaseVo.builder().accountId(accountId).build(), new TypeReference<ApiResponseCommon<Void>>() {});
         String text = response.getText();
         int code = response.getCode();
         //真正的成功退出
@@ -98,32 +79,13 @@ public class LoginServiceImpl implements LoginService {
         }
     }
 
-    @Override
-    public ApiResponseCommon<Void> wakeUpLogin(String authKey, QrCodeRequest request) {
-        String url = BASE_URL + "/login/WakeUpLogin?key=" + authKey;
-        ApiResponseCommon<Void> response = WxWorkHttpUtil.postWithType(
-                url,
-                request,
-                new TypeReference<ApiResponseCommon<Void>>() {}
-        );
-        String text = response.getText();
-        int code = response.getCode();
-        if (code == 200) {
-            return response;
-        }
-        else {
-            String errorMsg = text != null ? text : "唤醒登录失败,未知错误";
-            throw new CustomException("唤醒登录失败: " + errorMsg);
-        }
-    }
-
     @Override
     public ApiResponseCommon<Void> wakeUpLogin(Long accountId) {
         QrCodeRequest request = new QrCodeRequest();
         request.setCheck(false);
         request.setIpadOrmac("ipad");
         request.setProxy(serviceUtils.getProxy(accountId));
-        ApiResponseCommon<Void> response = serviceUtils.sendPost("/login/WakeUpLogin", RequestBaseVo.builder().accountId(accountId).data(request).build(), new TypeReference<ApiResponseCommon<Void>>() {});
+        ApiResponseCommon<Void> response = serviceUtils.sendPost(BASE_URL + "WakeUpLogin", RequestBaseVo.builder().accountId(accountId).data(request).build(), new TypeReference<ApiResponseCommon<Void>>() {});
         String text = response.getText();
         int code = response.getCode();
         if (code == 200) {

+ 24 - 16
fs-service/src/main/java/com/fs/wxcid/service/impl/MessageCallbackServiceImpl.java

@@ -2,15 +2,20 @@ package com.fs.wxcid.service.impl;
 
 
 import com.fs.common.exception.CustomException;
+import com.fs.wxcid.ServiceUtils;
 import com.fs.wxcid.dto.callback.CallbackConfigResponse;
 import com.fs.wxcid.dto.callback.ReturnMessage;
 import com.fs.wxcid.dto.common.ApiResponse;
 import com.fs.wxcid.dto.callback.CallbackConfigRequest;
 import com.fs.wxcid.dto.common.ApiResponseCommon;
+import com.fs.wxcid.dto.login.LoginQrCodeResponseData;
+import com.fs.wxcid.dto.login.RequestBaseVo;
 import com.fs.wxcid.service.MessageCallbackService;
 import com.fs.wxwork.utils.WxWorkHttpUtil;
 import com.alibaba.fastjson.TypeReference;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.HashMap;
@@ -19,7 +24,12 @@ import java.util.Map;
 @Service
 public class MessageCallbackServiceImpl implements MessageCallbackService {
 
-    private static final String BASE_URL = "http://114.117.215.244:7006";
+    private static final String BASE_URL = "/message/";
+    @Value("${ipad.wxIpadUrl}")
+    private String wxIpadUrl;
+    @Autowired
+    private ServiceUtils serviceUtils;
+
 
     @Override
     public ReturnMessage returnMessage(Map<String, Object> callback) {
@@ -85,22 +95,20 @@ public class MessageCallbackServiceImpl implements MessageCallbackService {
         return returnMessage;
     }
 
-    /**
-     * 设置消息回调
-     */
-    public ApiResponseCommon<Void> setCallback(String key, CallbackConfigRequest config) {
-        String url = BASE_URL + "/message/SetCallback?key=" + key;
-        ApiResponseCommon<Void> response = WxWorkHttpUtil.postWithType(
-                url,
-                config,
-                new TypeReference<ApiResponseCommon<Void>>() {}
-        );
-
-        if (response.getCode() != 200) {
-            throw new CustomException("设置回调失败: " + (response.getText() != null ? response.getText() : "未知错误"));
+    @Override
+    public ApiResponseCommon<Void> setCallback(Long accountId) {
+        CallbackConfigRequest request = new CallbackConfigRequest();
+        request.setCallbackURL(wxIpadUrl);
+        request.setEnabled(true);
+        ApiResponseCommon<Void> response = serviceUtils.sendPost(BASE_URL + "SetCallback", RequestBaseVo.builder().accountId(accountId).data(request).build(), new TypeReference<ApiResponseCommon<Void>>() {});
+        String text = response.getText();
+        int code = response.getCode();
+        if (code == 200) {
+            return response;
+        }else{
+            String errorMsg = text != null ? text : "设置回调地址,未知错误";
+            throw new CustomException("设置回调地址: " + errorMsg);
         }
-
-        return response;
     }
 
     /**

+ 11 - 51
fs-service/src/main/java/com/fs/wxcid/service/impl/MessageServiceImpl.java

@@ -1,40 +1,29 @@
 package com.fs.wxcid.service.impl;
 
+import com.alibaba.fastjson.TypeReference;
 import com.fs.common.exception.CustomException;
-import com.fs.wxcid.dto.common.ApiResponse;
+import com.fs.wxcid.ServiceUtils;
 import com.fs.wxcid.dto.common.ApiResponseCommon;
-import com.fs.wxcid.dto.message.*;
+import com.fs.wxcid.dto.login.RequestBaseVo;
+import com.fs.wxcid.dto.message.SendMessageResult;
+import com.fs.wxcid.dto.message.SendTextMessageRequest;
 import com.fs.wxcid.service.MessageService;
-import com.fs.wxwork.utils.WxWorkHttpUtil;
-import com.alibaba.fastjson.TypeReference;
 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;
 @Slf4j
 @Service
 public class MessageServiceImpl implements MessageService {
-
-    private static final String BASE_URL = "http://114.117.215.244:7006";
+    @Autowired
+    private ServiceUtils serviceUtils;
 
     @Override
-    public ApiResponseCommon<List<SendMessageResult>> sendTextMessage(String authKey, SendTextMessageRequest request) {
-        String url = BASE_URL + "/message/SendTextMessage?key=" + authKey;
-        ApiResponseCommon<List<SendMessageResult>> response = WxWorkHttpUtil.postWithType(
-                url,
-                request,
-                new TypeReference<ApiResponseCommon<List<SendMessageResult>>>() {}
-        );
-
-        // 第一层:检查 HTTP/协议级错误
-        if (response.getCode() != 200 || response.getData() == null) {
-            String errorMsg = response.getText() != null ? response.getText() : "发送消息失败,未知错误";
-            throw new CustomException("发送文本消息失败: " + errorMsg);
-        }
-
+    public ApiResponseCommon<List<SendMessageResult>> sendTextMessage(Long accountId) {
+        SendTextMessageRequest request = new SendTextMessageRequest();
+        ApiResponseCommon<List<SendMessageResult>> response = serviceUtils.sendPost("/message/SendTextMessage", RequestBaseVo.builder().accountId(accountId).data(request).build(), new TypeReference<ApiResponseCommon<List<SendMessageResult>>>() {});
         // 第二层:检查每条消息是否真正发送成功
         List<SendMessageResult> results = response.getData();
         List<String> failedRecipients = new ArrayList<>();
@@ -51,33 +40,4 @@ public class MessageServiceImpl implements MessageService {
 
         return response;
     }
-
-    // ------------------ 工具方法 ------------------
-    /**
-     * 通用 POST 请求方法
-     *
-     * @param path   接口路径,如 "/friend/AgreeAdd"
-     * @param authKey    账号唯一标识(query 参数)
-     * @param request 请求体对象
-     * @return 统一响应结果
-     */
-    private ApiResponse post(String path, String authKey, Object request) {
-        String url = BASE_URL + path + "?key=" + authKey;
-        return WxWorkHttpUtil.postWithType(url, request, new TypeReference<ApiResponse>() {});
-    }
-
-    /**
-     * 通用 GET 请求方法(无请求体)
-     *
-     * @param path 接口路径
-     * @param authKey  账号唯一标识
-     * @return 统一响应结果
-     */
-    private ApiResponse get(String path, String authKey) {
-        String url = BASE_URL + path;
-        Map<String, Object> params = new HashMap<>();
-        params.put("authKey", authKey);
-        String resp = WxWorkHttpUtil.get(url, params);
-        return com.alibaba.fastjson.JSON.parseObject(resp, ApiResponse.class);
-    }
 }

+ 3 - 1
fs-service/src/main/java/com/fs/wxcid/service/impl/UserServiceImpl.java

@@ -18,12 +18,14 @@ import org.springframework.stereotype.Service;
 @Slf4j
 @Service
 public class UserServiceImpl implements UserService {
+
+    private static final String BASE_URL = "/user/";
     @Autowired
     private ServiceUtils serviceUtils;
     @Override
     public UserProfileData getProfile(Long accountId) {
         try {
-            ApiResponseCommon<UserProfileData> response = serviceUtils.sendGet("/user/GetProfile", RequestBaseVo.builder().accountId(accountId).data(null).build(), new TypeReference<ApiResponseCommon<UserProfileData>>() {});
+            ApiResponseCommon<UserProfileData> response = serviceUtils.sendGet(BASE_URL + "GetProfile", RequestBaseVo.builder().accountId(accountId).data(null).build(), new TypeReference<ApiResponseCommon<UserProfileData>>() {});
             return response.getData();
         }catch (Exception e){
             return new UserProfileData();

+ 115 - 0
fs-service/src/main/java/com/fs/wxcid/service/impl/WxMsgLogServiceImpl.java

@@ -0,0 +1,115 @@
+package com.fs.wxcid.service.impl;
+
+import java.util.List;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.company.domain.CompanyWxAccount;
+import com.fs.wxcid.dto.callback.WxCallbackVo;
+import org.springframework.stereotype.Service;
+import com.fs.wxcid.mapper.WxMsgLogMapper;
+import com.fs.wxcid.domain.WxMsgLog;
+import com.fs.wxcid.service.IWxMsgLogService;
+
+/**
+ * 个微消息记录Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-12-16
+ */
+@Service
+public class WxMsgLogServiceImpl extends ServiceImpl<WxMsgLogMapper, WxMsgLog> implements IWxMsgLogService {
+
+    /**
+     * 查询个微消息记录
+     * 
+     * @param id 个微消息记录主键
+     * @return 个微消息记录
+     */
+    @Override
+    public WxMsgLog selectWxMsgLogById(Long id)
+    {
+        return baseMapper.selectWxMsgLogById(id);
+    }
+
+    /**
+     * 查询个微消息记录列表
+     * 
+     * @param wxMsgLog 个微消息记录
+     * @return 个微消息记录
+     */
+    @Override
+    public List<WxMsgLog> selectWxMsgLogList(WxMsgLog wxMsgLog)
+    {
+        return baseMapper.selectWxMsgLogList(wxMsgLog);
+    }
+
+    /**
+     * 新增个微消息记录
+     * 
+     * @param wxMsgLog 个微消息记录
+     * @return 结果
+     */
+    @Override
+    public int insertWxMsgLog(WxMsgLog wxMsgLog)
+    {
+        wxMsgLog.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertWxMsgLog(wxMsgLog);
+    }
+
+    /**
+     * 修改个微消息记录
+     * 
+     * @param wxMsgLog 个微消息记录
+     * @return 结果
+     */
+    @Override
+    public int updateWxMsgLog(WxMsgLog wxMsgLog)
+    {
+        wxMsgLog.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateWxMsgLog(wxMsgLog);
+    }
+
+    /**
+     * 批量删除个微消息记录
+     * 
+     * @param ids 需要删除的个微消息记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteWxMsgLogByIds(Long[] ids)
+    {
+        return baseMapper.deleteWxMsgLogByIds(ids);
+    }
+
+    /**
+     * 删除个微消息记录信息
+     * 
+     * @param id 个微消息记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteWxMsgLogById(Long id)
+    {
+        return baseMapper.deleteWxMsgLogById(id);
+    }
+
+    @Override
+    public void insertLog(WxCallbackVo callbackVo, CompanyWxAccount account, int type) {
+        String formUser = callbackVo.getMessage().getFromUserName().getStr();
+        WxMsgLog logs = new WxMsgLog();
+        logs.setAccountId(account.getId());
+        logs.setAuthKey(account.getAuthKey());
+        logs.setType(callbackVo.getType());
+        logs.setMsgId(callbackVo.getMessage().getMsgId());
+        logs.setFromUserName(formUser);
+        logs.setToUserName(callbackVo.getMessage().getToUserName().getStr());
+        logs.setMsgType(callbackVo.getMessage().getMsgType());
+        logs.setContent(callbackVo.getMessage().getContent().getStr());
+        logs.setImgStatus(callbackVo.getMessage().getImgStatus());
+        logs.setImgBuf(callbackVo.getMessage().getImgBuf().getLen());
+        logs.setPushContent(callbackVo.getMessage().getPushContent());
+        logs.setNewMsgId(callbackVo.getMessage().getNewMsgId());
+        logs.setReceiveType(type);
+        save(logs);
+    }
+}

+ 14 - 0
fs-service/src/main/java/com/fs/wxcid/vo/VerifyUserVo.java

@@ -0,0 +1,14 @@
+package com.fs.wxcid.vo;
+
+import lombok.Data;
+
+@Data
+public class VerifyUserVo {
+    private String v3;
+    private String v4;
+    // 15 手机号添加
+    private Integer scene;
+    private Integer opCode;
+    private String chatRoomUserName;
+    private String content;
+}

+ 1 - 0
fs-service/src/main/resources/application-config-dev.yml

@@ -111,6 +111,7 @@ headerImg:
 ipad:
   url:
   ipadUrl: http://ipad.cdwjyyh.com
+  wxIpadUrl: http://ipad.cdwjyyh.com
   aiApi: http://152.136.202.157:3000/api
   voiceApi:
   commonApi:

+ 5 - 0
fs-service/src/main/resources/application-dev.yml

@@ -46,6 +46,11 @@ spring:
                     url: jdbc:mysql://139.186.77.83:3306/ylrz_his_scrm?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
                     username: Rtroot
                     password: Rtroot
+                # 主库数据源
+                wx:
+                    url: jdbc:mysql://139.186.77.83:3306/wechat_mmtls?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
+                    username: Rtroot
+                    password: Rtroot
                 # 初始连接数
                 initialSize: 5
                 # 最小连接池数量

+ 131 - 0
fs-service/src/main/resources/mapper/WxMsgLog/WxMsgLogMapper.xml

@@ -0,0 +1,131 @@
+<?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.fs.wxcid.mapper.WxMsgLogMapper">
+    
+    <resultMap type="WxMsgLog" id="WxMsgLogResult">
+        <result property="id"    column="id"    />
+        <result property="accountId"    column="account_id"    />
+        <result property="key"    column="key"    />
+        <result property="type"    column="type"    />
+        <result property="msgId"    column="msg_id"    />
+        <result property="fromUserName"    column="from_user_name"    />
+        <result property="toUserName"    column="to_user_name"    />
+        <result property="msgType"    column="msg_type"    />
+        <result property="content"    column="content"    />
+        <result property="imgStatus"    column="img_status"    />
+        <result property="imgBuf"    column="img_buf"    />
+        <result property="pushContent"    column="push_content"    />
+        <result property="newMsgId"    column="new_msg_id"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="remark"    column="remark"    />
+    </resultMap>
+
+    <sql id="selectWxMsgLogVo">
+        select id, account_id, key, type, msg_id, from_user_name, to_user_name, msg_type, content, img_status, img_buf, push_content, new_msg_id, create_time, create_by, update_time, update_by, remark from wx_msg_log
+    </sql>
+
+    <select id="selectWxMsgLogList" parameterType="WxMsgLog" resultMap="WxMsgLogResult">
+        <include refid="selectWxMsgLogVo"/>
+        <where>  
+            <if test="accountId != null "> and account_id = #{accountId}</if>
+            <if test="key != null  and key != ''"> and key = #{key}</if>
+            <if test="type != null "> and type = #{type}</if>
+            <if test="msgId != null "> and msg_id = #{msgId}</if>
+            <if test="fromUserName != null  and fromUserName != ''"> and from_user_name like concat('%', #{fromUserName}, '%')</if>
+            <if test="toUserName != null  and toUserName != ''"> and to_user_name like concat('%', #{toUserName}, '%')</if>
+            <if test="msgType != null "> and msg_type = #{msgType}</if>
+            <if test="content != null  and content != ''"> and content = #{content}</if>
+            <if test="imgStatus != null  and imgStatus != ''"> and img_status = #{imgStatus}</if>
+            <if test="imgBuf != null  and imgBuf != ''"> and img_buf = #{imgBuf}</if>
+            <if test="pushContent != null  and pushContent != ''"> and push_content = #{pushContent}</if>
+            <if test="newMsgId != null "> and new_msg_id = #{newMsgId}</if>
+        </where>
+    </select>
+    
+    <select id="selectWxMsgLogById" parameterType="Long" resultMap="WxMsgLogResult">
+        <include refid="selectWxMsgLogVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertWxMsgLog" parameterType="WxMsgLog" useGeneratedKeys="true" keyProperty="id">
+        insert into wx_msg_log
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="accountId != null">account_id,</if>
+            <if test="key != null">key,</if>
+            <if test="type != null">type,</if>
+            <if test="msgId != null">msg_id,</if>
+            <if test="fromUserName != null">from_user_name,</if>
+            <if test="toUserName != null">to_user_name,</if>
+            <if test="msgType != null">msg_type,</if>
+            <if test="content != null">content,</if>
+            <if test="imgStatus != null">img_status,</if>
+            <if test="imgBuf != null">img_buf,</if>
+            <if test="pushContent != null">push_content,</if>
+            <if test="newMsgId != null">new_msg_id,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="remark != null">remark,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="accountId != null">#{accountId},</if>
+            <if test="key != null">#{key},</if>
+            <if test="type != null">#{type},</if>
+            <if test="msgId != null">#{msgId},</if>
+            <if test="fromUserName != null">#{fromUserName},</if>
+            <if test="toUserName != null">#{toUserName},</if>
+            <if test="msgType != null">#{msgType},</if>
+            <if test="content != null">#{content},</if>
+            <if test="imgStatus != null">#{imgStatus},</if>
+            <if test="imgBuf != null">#{imgBuf},</if>
+            <if test="pushContent != null">#{pushContent},</if>
+            <if test="newMsgId != null">#{newMsgId},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="remark != null">#{remark},</if>
+         </trim>
+    </insert>
+
+    <update id="updateWxMsgLog" parameterType="WxMsgLog">
+        update wx_msg_log
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="accountId != null">account_id = #{accountId},</if>
+            <if test="key != null">key = #{key},</if>
+            <if test="type != null">type = #{type},</if>
+            <if test="msgId != null">msg_id = #{msgId},</if>
+            <if test="fromUserName != null">from_user_name = #{fromUserName},</if>
+            <if test="toUserName != null">to_user_name = #{toUserName},</if>
+            <if test="msgType != null">msg_type = #{msgType},</if>
+            <if test="content != null">content = #{content},</if>
+            <if test="imgStatus != null">img_status = #{imgStatus},</if>
+            <if test="imgBuf != null">img_buf = #{imgBuf},</if>
+            <if test="pushContent != null">push_content = #{pushContent},</if>
+            <if test="newMsgId != null">new_msg_id = #{newMsgId},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="remark != null">remark = #{remark},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteWxMsgLogById" parameterType="Long">
+        delete from wx_msg_log where id = #{id}
+    </delete>
+
+    <delete id="deleteWxMsgLogByIds" parameterType="String">
+        delete from wx_msg_log where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 7 - 0
fs-service/src/main/resources/mapper/wxcid/AddMsgDbMapper.xml

@@ -0,0 +1,7 @@
+<?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.fs.wxcid.mapper.wx.AddMsgDbMapper">
+
+</mapper>

+ 7 - 0
fs-service/src/main/resources/mapper/wxcid/CommandMapper.xml

@@ -0,0 +1,7 @@
+<?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.fs.wxcid.mapper.wx.CommandMapper">
+
+</mapper>

+ 7 - 0
fs-service/src/main/resources/mapper/wxcid/DeviceInfoEntityMapper.xml

@@ -0,0 +1,7 @@
+<?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.fs.wxcid.mapper.wx.DeviceInfoEntityMapper">
+
+</mapper>

+ 7 - 0
fs-service/src/main/resources/mapper/wxcid/LicenseKeyMapper.xml

@@ -0,0 +1,7 @@
+<?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.fs.wxcid.mapper.wx.LicenseKeyMapper">
+
+</mapper>

+ 7 - 0
fs-service/src/main/resources/mapper/wxcid/MessageCallbackConfigMapper.xml

@@ -0,0 +1,7 @@
+<?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.fs.wxcid.mapper.wx.MessageCallbackConfigMapper">
+
+</mapper>

+ 7 - 0
fs-service/src/main/resources/mapper/wxcid/ModContactDbMapper.xml

@@ -0,0 +1,7 @@
+<?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.fs.wxcid.mapper.wx.ModContactDbMapper">
+
+</mapper>

+ 7 - 0
fs-service/src/main/resources/mapper/wxcid/ProxyMappingMapper.xml

@@ -0,0 +1,7 @@
+<?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.fs.wxcid.mapper.wx.ProxyMappingMapper">
+
+</mapper>

+ 7 - 0
fs-service/src/main/resources/mapper/wxcid/UserBusinessLogMapper.xml

@@ -0,0 +1,7 @@
+<?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.fs.wxcid.mapper.wx.UserBusinessLogMapper">
+
+</mapper>

+ 7 - 0
fs-service/src/main/resources/mapper/wxcid/UserInfoEntityMapper.xml

@@ -0,0 +1,7 @@
+<?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.fs.wxcid.mapper.wx.UserInfoEntityMapper">
+
+</mapper>

+ 7 - 0
fs-service/src/main/resources/mapper/wxcid/UserLoginLogMapper.xml

@@ -0,0 +1,7 @@
+<?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.fs.wxcid.mapper.wx.UserLoginLogMapper">
+
+</mapper>

+ 7 - 0
fs-service/src/main/resources/mapper/wxcid/UserMessageLogMapper.xml

@@ -0,0 +1,7 @@
+<?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.fs.wxcid.mapper.wx.UserMessageLogMapper">
+
+</mapper>

+ 9 - 0
fs-wx-api/pom.xml

@@ -106,6 +106,15 @@
             <artifactId>lombok</artifactId>
         </dependency>
 
+        <!-- SpringBoot 基础(若已有可省略) -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-messaging</artifactId>
+        </dependency>
     </dependencies>
 
     <build>

+ 8 - 0
fs-wx-api/src/main/java/com/fs/FsWxApiApplication.java

@@ -1,8 +1,11 @@
 package com.fs;
 
+import com.fs.app.controller.WebscoketServer;
+import org.springframework.boot.CommandLineRunner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.context.annotation.Bean;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
@@ -22,4 +25,9 @@ public class FsWxApiApplication
         SpringApplication.run(FsWxApiApplication.class, args);
         System.out.println("WXAPI启动成功");
     }
+    // ========== 可选 1:启动原生 WebSocket 客户端 ==========
+    @Bean
+    public CommandLineRunner startNativeWsClient(WebscoketServer webscoketServer) {
+        return args -> webscoketServer.start();
+    }
 }

+ 46 - 0
fs-wx-api/src/main/java/com/fs/app/controller/CallBackController.java

@@ -0,0 +1,46 @@
+package com.fs.app.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fs.common.core.domain.R;
+import com.fs.company.domain.CompanyWxAccount;
+import com.fs.company.service.ICompanyWxAccountService;
+import com.fs.wxcid.domain.WxMsgLog;
+import com.fs.wxcid.dto.callback.WxCallbackVo;
+import com.fs.wxcid.service.IWxMsgLogService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.IOException;
+
+/**
+ * 客户Controller
+ *
+ * @author fs
+ * @date 2022-12-21
+ */
+@Slf4j
+@AllArgsConstructor
+@RestController
+@RequestMapping("/wx/back")
+public class CallBackController {
+    @Autowired
+    private ICompanyWxAccountService companyWxAccountService;
+    @Autowired
+    private IWxMsgLogService wxMsgLogService;
+    @PostMapping
+    public R addWxResult(@RequestBody WxCallbackVo callbackVo) throws IOException {
+//        log.info("===进入回调===");
+//        CompanyWxAccount account = companyWxAccountService.getOne(new QueryWrapper<CompanyWxAccount>().eq("auth_key", callbackVo.getKey()));
+//        String formUser = callbackVo.getMessage().getFromUserName().getStr();
+//        if(formUser.equals(account.getWxNo())){
+//            wxMsgLogService.insertLog(callbackVo, account, 1);
+//        }
+        return R.ok();
+    }
+
+}

+ 144 - 0
fs-wx-api/src/main/java/com/fs/app/controller/WebscoketServer.java

@@ -0,0 +1,144 @@
+package com.fs.app.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fs.common.utils.PubFun;
+import com.fs.company.domain.CompanyWxAccount;
+import com.fs.company.service.ICompanyWxAccountService;
+import com.fs.wxcid.domain.CidIpadServer;
+import com.fs.wxcid.domain.WxMsgLog;
+import com.fs.wxcid.dto.callback.WxCallbackVo;
+import com.fs.wxcid.service.ICidIpadServerService;
+import com.fs.wxcid.service.IWxMsgLogService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.websocket.*;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+
+@Slf4j
+@Component
+public class WebscoketServer {
+    @Autowired
+    private ICidIpadServerService cidIpadServerService;
+    @Autowired
+    private ICompanyWxAccountService companyWxAccountService;
+    @Autowired
+    private IWxMsgLogService wxMsgLogService;
+    @Value("${group-no}")
+    private String groupNo;
+
+    // 重连间隔(秒)
+    private static final int RECONNECT_INTERVAL = 5;
+    // 客户端会话
+    private Map<Long, Session> sessionMap = new ConcurrentHashMap<>();
+    // ipad 数据
+    private Map<Long, CidIpadServer> ipadMap = new HashMap<>();
+    // 重连调度器
+    private final ScheduledExecutorService reconnectScheduler = Executors.newSingleThreadScheduledExecutor();
+
+    /**
+     * 启动客户端(连接第三方 + 监听消息)
+     */
+    public void start() {
+        List<CidIpadServer> ipadList = cidIpadServerService.list(new QueryWrapper<CidIpadServer>().eq("group_no", groupNo));
+        if(ipadList.isEmpty()){
+            log.info("没有需要连接的账号");
+            return;
+        }
+        ipadMap = PubFun.listToMapByGroupObject(ipadList, CidIpadServer::getId);
+        List<CompanyWxAccount> list = companyWxAccountService.list(new QueryWrapper<CompanyWxAccount>().eq("server_status", 1).eq("login_status", 1).in("server_id", PubFun.listToNewList(ipadList, CidIpadServer::getId)));
+        list.forEach(this::connect);
+//        connect();
+    }
+
+    /**
+     * 连接第三方 WebSocket 服务
+     */
+    private void connect(CompanyWxAccount account) {
+        try {
+            CidIpadServer ipad = ipadMap.get(account.getServerId());
+            String url = "ws://" + ipad.getIp() + ":" + ipad.getPort() + "/ws/GetSyncMsg?key=" + account.getAuthKey();
+            // 1. 创建 WebSocket 客户端容器(SpringBoot 2 内置)
+            WebSocketContainer container = ContainerProvider.getWebSocketContainer();
+            // 2. 连接第三方服务,绑定消息处理器
+            container.connectToServer(new WebSocketMessageHandler(account, ipad), URI.create(url));
+            log.info("✅ 原生 WebSocket 连接第三方服务成功:{}", url);
+        } catch (Exception e) {
+            log.error("❌ 原生 WebSocket 连接失败:{}", e.getMessage(), e);
+            scheduleReconnect(account);
+        }
+    }
+
+    /**
+     * 消息处理器(核心:接收/处理第三方消息)
+     */
+    @ClientEndpoint
+    public class WebSocketMessageHandler {
+        private CompanyWxAccount account;
+        private CidIpadServer ipad;
+        public WebSocketMessageHandler(CompanyWxAccount account, CidIpadServer ipad) {
+            this.account = account;
+            this.ipad = ipad;
+        }
+
+        // 连接成功回调(保存会话)
+        @OnOpen
+        public void onOpen(Session session) {
+            sessionMap.put(account.getId(), session);
+            log.info("✅ WebSocket 会话建立,SessionID:{}", session.getId());
+            // 取消重连(若有)
+            reconnectScheduler.shutdownNow();
+        }
+
+        // 接收第三方消息(核心业务逻辑)
+        @OnMessage
+        public void onMessage(String message) {
+            WxCallbackVo callbackVo = JSON.parseObject(message, WxCallbackVo.class);
+            log.info("📩 收到第三方 WebSocket 消息:{}", callbackVo);
+            String formUser = callbackVo.getMessage().getFromUserName().getStr();
+            wxMsgLogService.insertLog(callbackVo, account, !formUser.equals(account.getWxNo()) ? 0 : 1);
+        }
+
+        // 处理二进制消息(若第三方推送二进制数据,如文件/字节流)
+        @OnMessage
+        public void onMessage(byte[] binaryData) {
+            log.info("📩 收到第三方二进制消息,长度:{} 字节", binaryData.length);
+        }
+
+        // 连接关闭回调(触发重连)
+        @OnClose
+        public void onClose(Session session, CloseReason reason) {
+            log.error("❌ WebSocket 会话关闭:{},{}秒后重连", reason.getReasonPhrase(), RECONNECT_INTERVAL);
+            sessionMap.remove(account.getId());
+            scheduleReconnect(account);
+        }
+
+        // 连接异常回调(触发重连)
+        @OnError
+        public void onError(Session session, Throwable error) {
+            log.error("连接报错!!!", error);
+        }
+    }
+
+    /**
+     * 调度重连
+     */
+    private void scheduleReconnect(CompanyWxAccount account) {
+        if (!reconnectScheduler.isShutdown()) {
+            reconnectScheduler.schedule(() -> connect(account), RECONNECT_INTERVAL, TimeUnit.SECONDS);
+            log.info("⏳ 已调度 {} 秒后重连第三方 WebSocket 服务", RECONNECT_INTERVAL);
+        }
+    }
+}
+

+ 2 - 1
fs-wx-api/src/main/resources/application.yml

@@ -6,4 +6,5 @@ server:
 # Spring配置
 spring:
   profiles:
-    active: dev
+    active: dev
+group-no: 1