Sfoglia il codice sorgente

Merge branch 'test-wks' into test

wks 1 anno fa
parent
commit
35ec6f2c08
37 ha cambiato i file con 1522 aggiunte e 139 eliminazioni
  1. 10 9
      src/main/java/com/ydtech/aop/GlobalExceptionHandler.java
  2. 23 18
      src/main/java/com/ydtech/config/WechatWorkConfig.java
  3. 2 0
      src/main/java/com/ydtech/config/properties/ChengTaiApiConfigurationProperties.java
  4. 2 0
      src/main/java/com/ydtech/modules/admin/constants/SwitchConfig.java
  5. 0 1
      src/main/java/com/ydtech/modules/admin/constants/WechatCustomerEnum.java
  6. 14 8
      src/main/java/com/ydtech/modules/admin/controller/SysQyWeChatController.java
  7. 4 20
      src/main/java/com/ydtech/modules/admin/controller/WechatController.java
  8. 115 0
      src/main/java/com/ydtech/modules/admin/controller/wechat/SysWechatCustomerConfigController.java
  9. 2 1
      src/main/java/com/ydtech/modules/admin/controller/wechat/WechatCustomerController.java
  10. 18 0
      src/main/java/com/ydtech/modules/admin/dao/SysWechatCustomerDutyMapper.java
  11. 29 0
      src/main/java/com/ydtech/modules/admin/dao/SysWechatCustomerMapper.java
  12. 18 0
      src/main/java/com/ydtech/modules/admin/dao/SysWechatCustomerRecordingMapper.java
  13. 96 0
      src/main/java/com/ydtech/modules/admin/model/po/SysWechatCustomer.java
  14. 59 0
      src/main/java/com/ydtech/modules/admin/model/po/SysWechatCustomerDuty.java
  15. 43 0
      src/main/java/com/ydtech/modules/admin/model/po/SysWechatCustomerRecording.java
  16. 20 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWeComUserVo.java
  17. 51 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerAddVo.java
  18. 35 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerDeptVo.java
  19. 42 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerDutyRulesVo.java
  20. 19 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerQueryVo.java
  21. 47 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerVo.java
  22. 3 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/WechatCustomerCallbackVo.java
  23. 72 0
      src/main/java/com/ydtech/modules/admin/service/SysWechatCustomerBusinessService.java
  24. 35 0
      src/main/java/com/ydtech/modules/admin/service/SysWechatCustomerDutyService.java
  25. 13 0
      src/main/java/com/ydtech/modules/admin/service/SysWechatCustomerRecordingService.java
  26. 79 0
      src/main/java/com/ydtech/modules/admin/service/SysWechatCustomerService.java
  27. 2 1
      src/main/java/com/ydtech/modules/admin/service/WechatCustomerService.java
  28. 275 0
      src/main/java/com/ydtech/modules/admin/service/impl/SysWechatCustomerBusinessServiceImpl.java
  29. 41 0
      src/main/java/com/ydtech/modules/admin/service/impl/SysWechatCustomerDutyServiceImpl.java
  30. 22 0
      src/main/java/com/ydtech/modules/admin/service/impl/SysWechatCustomerRecordingServiceImpl.java
  31. 129 0
      src/main/java/com/ydtech/modules/admin/service/impl/SysWechatCustomerServiceImpl.java
  32. 47 7
      src/main/java/com/ydtech/modules/admin/service/impl/WechatCustomerServiceImpl.java
  33. 76 73
      src/main/java/com/ydtech/utils/DateTimeUtil.java
  34. 1 1
      src/main/resources/application-pre.yml
  35. 16 0
      src/main/resources/mapper/SysWechatCustomerRecordingMapper.xml
  36. 18 0
      src/main/resources/mapper/modules/admin/SysWechatCustomerDutyMapper.xml
  37. 44 0
      src/main/resources/mapper/modules/admin/SysWechatCustomerMapper.xml

+ 10 - 9
src/main/java/com/ydtech/aop/GlobalExceptionHandler.java

@@ -3,7 +3,6 @@ package com.ydtech.aop;
 import cn.dev33.satoken.exception.NotLoginException;
 import cn.dev33.satoken.exception.NotPermissionException;
 import com.ydtech.aop.exception.DescribeException;
-import com.ydtech.aop.exception.ErrorInfo;
 import com.ydtech.core.page.HttpResult;
 import com.ydtech.core.page.HttpStatus;
 import com.ydtech.exception.SystemException;
@@ -16,8 +15,8 @@ import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.annotation.ControllerAdvice;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestControllerAdvice;
 
+import javax.validation.ConstraintViolationException;
 import java.sql.SQLIntegrityConstraintViolationException;
 import java.util.List;
 
@@ -72,28 +71,30 @@ public class GlobalExceptionHandler {
         return HttpResult.error(400, message);
     }
 
-
     @ExceptionHandler(value = DuplicateKeyException.class)
     @ResponseBody
     public HttpResult sqlExceptionHandle(SQLIntegrityConstraintViolationException sqlException) {
-        return HttpResult.error("违反唯一约束:" + sqlException.getMessage().substring(0, sqlException.getMessage().indexOf("for key")));
+        return HttpResult.error("违反唯一约束:" + sqlException.getMessage()
+                .substring(0, sqlException.getMessage().indexOf("for key")));
     }
 
+    @ExceptionHandler(value = ConstraintViolationException.class)
+    @ResponseBody
+    public HttpResult constraintViolation(ConstraintViolationException constraintViolationException) {
+        return HttpResult.error(constraintViolationException.getMessage());
+    }
 
     @ExceptionHandler(value = NotLoginException.class)
     @ResponseBody
     public HttpResult notLoginException(NotLoginException e) {
-        return HttpResult.error(HttpStatus.SC_UNAUTHORIZED,"未登录状态,无法访问。");
+        return HttpResult.error(HttpStatus.SC_UNAUTHORIZED, "未登录状态,无法访问。");
     }
 
     @ExceptionHandler(value = NotPermissionException.class)
     @ResponseBody
     public HttpResult notPermissionException(NotPermissionException e) {
-        return HttpResult.error(HttpStatus.SC_FORBIDDEN,"未获得权限,无法访问。");
+        return HttpResult.error(HttpStatus.SC_FORBIDDEN, "未获得权限,无法访问。");
     }
 
-
-
-
 }
 

+ 23 - 18
src/main/java/com/ydtech/config/WechatWorkConfig.java

@@ -2,10 +2,8 @@ package com.ydtech.config;
 
 import com.ydtech.config.properties.WechatCustomerProperties;
 import com.ydtech.config.properties.WechatOpenProperties;
-import me.chanjar.weixin.cp.api.WxCpKfService;
-import me.chanjar.weixin.cp.api.WxCpService;
-import me.chanjar.weixin.cp.api.impl.WxCpKfServiceImpl;
-import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
+import me.chanjar.weixin.cp.api.*;
+import me.chanjar.weixin.cp.api.impl.*;
 import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
@@ -41,17 +39,6 @@ public class WechatWorkConfig {
     @Resource
     private WechatCustomerProperties wechatCustomerProperties;
 
-    @Bean
-    public WxCpService wxCpService() {
-        WxCpDefaultConfigImpl config = new WxCpDefaultConfigImpl();
-        config.setCorpId(corpId);
-        config.setCorpSecret(secret);
-        config.setAgentId(agentId);
-        WxCpServiceImpl wxCpService = new WxCpServiceImpl();
-        wxCpService.setWxCpConfigStorage(config);
-        return new WxCpServiceImpl();
-    }
-
     @Bean
     public Map<String, WxMpService> wxMpService() {
         Map<String, WxMpDefaultConfigImpl> collect = wechatOpenProperties.getProperties().keySet()
@@ -72,18 +59,36 @@ public class WechatWorkConfig {
         }));
     }
 
-
     @Bean
-    public WxCpKfService wxCpKfService(){
+    public WxCpService wxCpService() {
         WxCpDefaultConfigImpl config = new WxCpDefaultConfigImpl();
-        config.setCorpId(corpId);
+        config.setCorpId(wechatCustomerProperties.getCorpId());
         config.setCorpSecret(wechatCustomerProperties.getSecret());
         config.setToken(wechatCustomerProperties.getToken());
         config.setAesKey(wechatCustomerProperties.getEncodingAesKey());
         WxCpServiceImpl wxCpService = new WxCpServiceImpl();
         wxCpService.setWxCpConfigStorage(config);
+        return wxCpService;
+    }
+
+    @Bean
+    public WxCpKfService wxCpKfService(){
         return new WxCpKfServiceImpl(wxCpService());
     }
 
+    @Bean
+    public WxCpMediaService wxCpMediaService(){
+        return new WxCpMediaServiceImpl(wxCpService());
+    }
+
+    @Bean
+    public WxCpDepartmentService wxCpDepartmentService(){
+        return new WxCpDepartmentServiceImpl(wxCpService());
+    }
+
+    @Bean
+    public WxCpUserService wxCpUserService(){
+        return new WxCpUserServiceImpl(wxCpService());
+    }
 
 }

+ 2 - 0
src/main/java/com/ydtech/config/properties/ChengTaiApiConfigurationProperties.java

@@ -20,3 +20,5 @@ public class ChengTaiApiConfigurationProperties {
     //我司RSA私钥
     private String privateKey;
 }
+
+

+ 2 - 0
src/main/java/com/ydtech/modules/admin/constants/SwitchConfig.java

@@ -39,6 +39,8 @@ public enum SwitchConfig {
     APP_UNDEVELOPED("appUndeveloped", "app未开发完功能隐藏"),
 
     CT_DISCOUNT_01("ctDiscountFlag", "诚泰自动调整折扣"),
+
+    CUSTOMER("customer", "客服功能")
     ;
 
 

+ 0 - 1
src/main/java/com/ydtech/modules/admin/constants/WechatCustomerEnum.java

@@ -12,7 +12,6 @@ import lombok.Getter;
 @AllArgsConstructor
 public enum WechatCustomerEnum {
 
-
     GET_ACCESS_TOKEN("获取调用凭证access_token", "/cgi-bin/gettoken"),
     LIST("获取客服账号列表", "/cgi-bin/kf/account/list"),
     ADD_CONTACT_WAY("获取客服账号链接", "/cgi-bin/kf/add_contact_way"),

+ 14 - 8
src/main/java/com/ydtech/modules/admin/controller/SysQyWeChatController.java

@@ -3,18 +3,17 @@ package com.ydtech.modules.admin.controller;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ydtech.core.page.HttpResult;
+import com.ydtech.modules.admin.constants.SwitchConfig;
 import com.ydtech.modules.admin.model.SysUser;
 import com.ydtech.modules.admin.model.po.SysQyWeChat;
-import com.ydtech.modules.admin.service.SysQyWeChatService;
-import com.ydtech.modules.admin.service.SysSwitchConfigService;
-import com.ydtech.modules.admin.service.SysUserService;
-import com.ydtech.modules.admin.service.WechatCustomerService;
+import com.ydtech.modules.admin.service.*;
 import com.ydtech.modules.base.controller.BaseController;
 import com.ydtech.modules.protocol.utils.AssertionUtils;
 import com.ydtech.utils.StringUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
+import me.chanjar.weixin.common.error.WxErrorException;
 import org.springframework.web.bind.annotation.*;
 
 import java.time.LocalDateTime;
@@ -33,8 +32,12 @@ public class SysQyWeChatController {
 
     private final SysSwitchConfigService sysSwitchConfigService;
 
+    private final SysWechatCustomerBusinessService sysWechatCustomerBusinessService;
+
     private final WechatCustomerService wechatCustomerService;
 
+    private final SysSwitchConfigService switchConfigService;
+
     @ApiOperation(value = "配置宣传图/客服")
     @PostMapping(value = "/save/picture")
     public HttpResult<SysQyWeChat> save(@RequestBody SysQyWeChat sysQyWeChat) {
@@ -45,7 +48,7 @@ public class SysQyWeChatController {
         if (serviceOne != null) {
             sysQyWeChat.setId(serviceOne.getId());
             save = sysQyWeChatService.updateById(sysQyWeChat);
-        }else{
+        } else {
             save = sysQyWeChatService.save(sysQyWeChat);
         }
         AssertionUtils.isSucceed(save, "添加失败");
@@ -79,20 +82,23 @@ public class SysQyWeChatController {
 
     @ApiOperation(value = "查询微信客服链接")
     @PostMapping(value = "/find/wechatCustomer")
-    public HttpResult<String> findWechatPictureByUserId() {
+    public HttpResult<String> findWechatCustomerLink() throws WxErrorException {
         String userId = BaseController.getUser().getId();
         SysUser user = sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getId, userId));
+        if (switchConfigService.isEnabled(SwitchConfig.CUSTOMER.getCode())) {
+            String link = sysWechatCustomerBusinessService.getWeChatCustomer(user);
+            return HttpResult.ok(link);
+        }
         SysQyWeChat sysQyWeChat = sysQyWeChatService.getOne(new LambdaQueryWrapper<SysQyWeChat>().eq(SysQyWeChat::getUserId, user.getLeaderId()));
         if (sysQyWeChat == null) {
             List<SysQyWeChat> list = sysQyWeChatService.list();
             sysQyWeChat = list.get(new Random().nextInt(list.size()));
         }
         String s = wechatCustomerService.addContactWay(sysQyWeChat.getOpenKfId());
-        if(StringUtils.isNotEmpty(s)){
+        if (StringUtils.isNotEmpty(s)) {
             String url = s + "&scene_param=" + userId;
             return HttpResult.ok(url);
         }
         return HttpResult.ok(sysQyWeChat.getSupportStaffUrl());
     }
-
 }

+ 4 - 20
src/main/java/com/ydtech/modules/admin/controller/WechatController.java

@@ -1,37 +1,21 @@
 package com.ydtech.modules.admin.controller;
 
-import cn.hutool.core.util.XmlUtil;
-import com.alibaba.fastjson.JSON;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.dataformat.xml.XmlMapper;
 import com.ydtech.core.page.HttpResult;
 import com.ydtech.exception.SystemException;
 import com.ydtech.modules.admin.model.vo.WechatBindVo;
 import com.ydtech.modules.admin.model.vo.WechatLoginVo;
 import com.ydtech.modules.admin.model.vo.WechatVo;
-import com.ydtech.modules.admin.model.vo.wechat.WechatCustomerCallbackVo;
-import com.ydtech.modules.admin.model.vo.wechat.WechatEncryptVo;
 import com.ydtech.modules.admin.service.WechatService;
 import com.ydtech.modules.base.controller.BaseController;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import io.swagger.models.Xml;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.crypto.WxCryptUtil;
-import me.chanjar.weixin.cp.api.WxCpKfService;
-import me.chanjar.weixin.cp.bean.kf.WxCpKfMsgListResp;
-import me.chanjar.weixin.cp.bean.kf.WxCpKfMsgSendRequest;
-import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
+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;
 
 @Api(tags = "微信业务")
 @Slf4j

+ 115 - 0
src/main/java/com/ydtech/modules/admin/controller/wechat/SysWechatCustomerConfigController.java

@@ -0,0 +1,115 @@
+package com.ydtech.modules.admin.controller.wechat;
+
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.ydtech.core.page.HttpResult;
+import com.ydtech.modules.admin.model.po.SysWechatCustomer;
+import com.ydtech.modules.admin.model.vo.wechat.*;
+import com.ydtech.modules.admin.service.SysWechatCustomerBusinessService;
+import com.ydtech.modules.admin.service.SysWechatCustomerDutyService;
+import com.ydtech.modules.admin.service.SysWechatCustomerService;
+import com.ydtech.modules.order.entity.BasePageResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.NotBlank;
+import java.util.List;
+
+@Api(tags = "微信客服管理")
+@Slf4j
+@RestController
+@RequestMapping("/wechat/customer/manage")
+@Validated
+@RequiredArgsConstructor
+public class SysWechatCustomerConfigController {
+
+    private final SysWechatCustomerBusinessService sysWechatCustomerBusinessService;
+
+    private final SysWechatCustomerDutyService sysWechatCustomerDutyService;
+
+    private final SysWechatCustomerService sysWechatCustomerService;
+
+    @GetMapping("/getDeptTree")
+    @ApiOperation(value = "获取企业微信通讯录部门树")
+    public HttpResult<List<SysWechatCustomerDeptVo>> getDeptTree() throws WxErrorException {
+        List<SysWechatCustomerDeptVo> deptByDeptId = sysWechatCustomerBusinessService.getDeptByDeptId();
+        return HttpResult.ok(deptByDeptId);
+    }
+
+    @GetMapping("/getDeptUser")
+    @ApiOperation(value = "通过部门id获取用户列表")
+    public HttpResult<List<SysWeComUserVo>> getDeptUser(@NotBlank(message = "部门id不能为空") String deptId) throws WxErrorException {
+        List<SysWeComUserVo> user = sysWechatCustomerBusinessService.getUser(deptId);
+        return HttpResult.ok(user);
+    }
+
+    @GetMapping("/getDutyConfig/{customerId}")
+    @ApiOperation(value = "获取值班配置")
+    public HttpResult<SysWechatCustomerDutyRulesVo> getDutyConfig(@PathVariable String customerId) {
+        SysWechatCustomerDutyRulesVo customerDutyRules = sysWechatCustomerService.getCustomerDutyRules(customerId);
+        return HttpResult.ok(customerDutyRules);
+    }
+
+    @PutMapping("/dutyConfig")
+    @ApiOperation(value = "值班配置")
+    public HttpResult<Object> getDutyConfig(@RequestBody SysWechatCustomerDutyRulesVo sysWechatCustomerDutyRules) {
+        sysWechatCustomerService.saveOrUpdateCustomerDutyRules(sysWechatCustomerDutyRules);
+        return HttpResult.ok();
+    }
+
+    @DeleteMapping("/clearDutyConfig/{customerId}")
+    @ApiOperation(value = "清除值班配置")
+    public HttpResult<Object> clearDutyConfig(@PathVariable String customerId) {
+        sysWechatCustomerDutyService.clearCustomerDuty(customerId);
+        return HttpResult.ok();
+    }
+
+    @PostMapping("/pageQuery")
+    @ApiOperation("分页查询客服数据")
+    public HttpResult<BasePageResult<SysWechatCustomerVo>> pageQuery(@RequestBody SysWechatCustomerQueryVo sysWechatCustomerQuery) {
+        BasePageResult<SysWechatCustomerVo> sysWechatCustomerVoBasePageResult = sysWechatCustomerBusinessService.pageQuery(sysWechatCustomerQuery);
+        return HttpResult.ok(sysWechatCustomerVoBasePageResult);
+    }
+
+    @GetMapping("/getAll")
+    @ApiOperation("获取所有客服")
+    public HttpResult<List<SysWechatCustomer>> all() {
+        List<SysWechatCustomer> list = sysWechatCustomerService.list();
+        return HttpResult.ok(list);
+    }
+
+    @GetMapping("/{customerId}")
+    @ApiOperation(value = "编辑客服")
+    public HttpResult<SysWechatCustomerAddVo> get(@PathVariable String customerId) throws WxErrorException {
+        SysWechatCustomerAddVo wechatCustomerAddVo = sysWechatCustomerBusinessService.getWechatCustomer(customerId);
+        return HttpResult.ok(wechatCustomerAddVo);
+    }
+
+    @PostMapping
+    @ApiOperation(value = "添加客服")
+    public HttpResult<Object> add(@RequestBody SysWechatCustomerAddVo sysWechatCustomerAddVo) throws WxErrorException {
+        sysWechatCustomerBusinessService.addWechatCustomer(sysWechatCustomerAddVo);
+        return HttpResult.ok();
+    }
+
+    @DeleteMapping("/{customerId}")
+    @ApiOperation(value = "删除客服")
+    public HttpResult<Object> delete(@PathVariable String customerId) throws WxErrorException {
+        sysWechatCustomerBusinessService.deleteWechatCustomer(customerId);
+        return HttpResult.ok();
+    }
+
+    @PutMapping("/{customerId}")
+    @ApiOperation(value = "修改客服")
+    public HttpResult<Object> revise(@PathVariable String customerId, @RequestBody SysWechatCustomerAddVo sysWechatCustomerAddVo) throws WxErrorException {
+        sysWechatCustomerBusinessService.updateWechatCustomer(customerId, sysWechatCustomerAddVo);
+        return HttpResult.ok();
+    }
+
+}

+ 2 - 1
src/main/java/com/ydtech/modules/admin/controller/wechat/WechatCustomerController.java

@@ -9,6 +9,7 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxErrorException;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.*;
 
@@ -35,7 +36,7 @@ public class WechatCustomerController {
 
     @PostMapping(path = "/callback", consumes = MediaType.TEXT_XML_VALUE, produces = MediaType.TEXT_XML_VALUE)
     @ApiOperation(value = "客服回调(处理事件发送欢迎语)")
-    public HttpResult<String> customerCallback(@RequestBody String wechatEncrypt) throws JsonProcessingException {
+    public HttpResult<String> customerCallback(@RequestBody String wechatEncrypt) throws JsonProcessingException, WxErrorException {
         customerService.callbackSendMsgOnEvent(wechatEncrypt);
         return HttpResult.ok();
     }

+ 18 - 0
src/main/java/com/ydtech/modules/admin/dao/SysWechatCustomerDutyMapper.java

@@ -0,0 +1,18 @@
+package com.ydtech.modules.admin.dao;
+
+import com.ydtech.modules.admin.model.po.SysWechatCustomerDuty;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+* @author Administrator
+* @description 针对表【sys_wechat_customer_duty(微信客服值班时间)】的数据库操作Mapper
+* @createDate 2025-04-17 10:14:27
+* @Entity com.ydtech.modules.admin.model.po.SysWechatCustomerDuty
+*/
+public interface SysWechatCustomerDutyMapper extends BaseMapper<SysWechatCustomerDuty> {
+
+}
+
+
+
+

+ 29 - 0
src/main/java/com/ydtech/modules/admin/dao/SysWechatCustomerMapper.java

@@ -0,0 +1,29 @@
+package com.ydtech.modules.admin.dao;
+
+import com.ydtech.modules.admin.model.po.SysWechatCustomer;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ydtech.modules.admin.model.vo.wechat.SysWechatCustomerVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+* @author Administrator
+* @description 针对表【sys_wechat_customer(微信客服)】的数据库操作Mapper
+* @createDate 2025-04-17 10:14:27
+* @Entity com.ydtech.modules.admin.model.po.SysWechatCustomer
+*/
+public interface SysWechatCustomerMapper extends BaseMapper<SysWechatCustomer> {
+
+    /**
+     * 通过昵称查询
+     * @param nickname 昵称
+     * @return 微信客服列表
+     */
+    List<SysWechatCustomerVo> getByNickname(@Param("nickname") String nickname);
+
+}
+
+
+
+

+ 18 - 0
src/main/java/com/ydtech/modules/admin/dao/SysWechatCustomerRecordingMapper.java

@@ -0,0 +1,18 @@
+package com.ydtech.modules.admin.dao;
+
+import com.ydtech.modules.admin.model.po.SysWechatCustomerRecording;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+* @author Administrator
+* @description 针对表【sys_wechat_customer_recording(微信客服记录表)】的数据库操作Mapper
+* @createDate 2025-04-22 17:18:47
+* @Entity com.ydtech.modules.admin.model.po.SysWechatCustomerRecording
+*/
+public interface SysWechatCustomerRecordingMapper extends BaseMapper<SysWechatCustomerRecording> {
+
+}
+
+
+
+

+ 96 - 0
src/main/java/com/ydtech/modules/admin/model/po/SysWechatCustomer.java

@@ -0,0 +1,96 @@
+package com.ydtech.modules.admin.model.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ydtech.modules.admin.model.vo.wechat.SysWechatCustomerAddVo;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 微信客服
+ *
+ * @TableName sys_wechat_customer
+ */
+@TableName(value = "sys_wechat_customer")
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class SysWechatCustomer implements Serializable {
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private long id;
+
+    /**
+     * 客服昵称
+     */
+    @TableField(value = "nickname")
+    private String nickname;
+
+    /**
+     * 客服头像
+     */
+    @TableField(value = "avatar")
+    private String avatar;
+
+    /**
+     * 后线人员id
+     */
+    @TableField(value = "user_id")
+    private String userId;
+    /**
+     * 接待人的部门
+     */
+    @TableField(value = "department_id")
+    private String departmentId;
+    /**
+     * 接待人企业微信客服
+     */
+    @TableField(value = "receptionist")
+    private String receptionist;
+    /**
+     * 接待人企业微信用户id
+     */
+    @TableField(value = "receptionist_id")
+    private String receptionistId;
+    /**
+     * 客服账号ID
+     */
+    @TableField("open_kf_id")
+    private String openKfId;
+    /**
+     * 值班客服
+     */
+    @TableField(value = "duty_customer_id")
+    private long dutyCustomerId;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+
+    public SysWechatCustomer(long id, String nickname, String avatar, String userId, String receptionist, String receptionistId, String openKfId, long dutyCustomerId) {
+        this.id = id;
+        this.nickname = nickname;
+        this.avatar = avatar;
+        this.userId = userId;
+        this.receptionist = receptionist;
+        this.receptionistId = receptionistId;
+        this.openKfId = openKfId;
+        this.dutyCustomerId = dutyCustomerId;
+    }
+
+    public SysWechatCustomer(SysWechatCustomerAddVo sysWechatCustomerAddVo) {
+        this.nickname = sysWechatCustomerAddVo.getNickname();
+        this.avatar = sysWechatCustomerAddVo.getAvatar();
+        this.userId = sysWechatCustomerAddVo.getUserId();
+        this.departmentId = sysWechatCustomerAddVo.getDepartmentId();
+        this.receptionist = sysWechatCustomerAddVo.getReceptionist();
+        this.receptionistId = sysWechatCustomerAddVo.getReceptionistId();
+    }
+
+}

+ 59 - 0
src/main/java/com/ydtech/modules/admin/model/po/SysWechatCustomerDuty.java

@@ -0,0 +1,59 @@
+package com.ydtech.modules.admin.model.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.Date;
+
+import com.ydtech.modules.admin.model.vo.wechat.SysWechatCustomerDutyRulesVo;
+import com.ydtech.utils.DateTimeUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 微信客服值班时间
+ * @TableName sys_wechat_customer_duty
+ */
+@TableName(value ="sys_wechat_customer_duty")
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+public class SysWechatCustomerDuty implements Serializable {
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private long id;
+
+    /**
+     * 值班开始时间
+     */
+    @TableField(value = "start_time")
+    private LocalDateTime startTime;
+
+    /**
+     * 值班结束时间
+     */
+    @TableField(value = "end_time")
+    private LocalDateTime endTime;
+
+    /**
+     * 客服id
+     */
+    @TableField(value = "customer_id")
+    private long customerId;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+
+
+    public SysWechatCustomerDuty(long customerId, SysWechatCustomerDutyRulesVo.DutyDateTime dutyDateTime) {
+        this.startTime = DateTimeUtil.parseLocalDateTime(dutyDateTime.getStartTime(), DateTimeUtil.DATETIME_PATTERN);
+        this.endTime = DateTimeUtil.parseLocalDateTime(dutyDateTime.getEndTime(), DateTimeUtil.DATETIME_PATTERN);
+        this.customerId = customerId;
+    }
+}

+ 43 - 0
src/main/java/com/ydtech/modules/admin/model/po/SysWechatCustomerRecording.java

@@ -0,0 +1,43 @@
+package com.ydtech.modules.admin.model.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 微信客服记录表
+ * @TableName sys_wechat_customer_recording
+ */
+@TableName(value ="sys_wechat_customer_recording")
+@Data
+public class SysWechatCustomerRecording implements Serializable {
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+    /**
+     * 客服id
+     */
+    @TableField(value = "customer_id")
+    private Long customerId;
+    /**
+     * 用户id
+     */
+    @TableField(value = "user_id")
+    private String userId;
+    /**
+     * 创建时间
+     */
+    @TableField(value = "create_time")
+    private Date createTime;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+
+
+}

+ 20 - 0
src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWeComUserVo.java

@@ -0,0 +1,20 @@
+package com.ydtech.modules.admin.model.vo.wechat;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@ApiModel("企业微信用户")
+@AllArgsConstructor
+public class SysWeComUserVo {
+
+    @ApiModelProperty("成员UserID")
+    private String userId;
+
+    @ApiModelProperty("name")
+    private String name;
+
+
+}

+ 51 - 0
src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerAddVo.java

@@ -0,0 +1,51 @@
+package com.ydtech.modules.admin.model.vo.wechat;
+
+import com.ydtech.modules.admin.model.po.SysWechatCustomer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@ApiModel("添加客服列表")
+public class SysWechatCustomerAddVo implements Serializable {
+
+    private static final long serialVersionUID = -6784892832795974243L;
+
+    @ApiModelProperty("昵称")
+    @NotBlank(message = "请输入客服昵称")
+    private String nickname;
+
+    @ApiModelProperty("客服头像")
+    private String avatar;
+
+    @ApiModelProperty("后线人员")
+    @NotBlank(message = "请输入后线人员")
+    private String userId;
+
+    @ApiModelProperty("企微选择的")
+    private String departmentId;
+
+    @ApiModelProperty("接待人企业微信客服")
+    @NotBlank(message = "请输入企业微信用户")
+    private String receptionist;
+
+    @ApiModelProperty("接待人企业微信用户id")
+    @NotBlank(message = "请输入企业微信用户")
+    private String receptionistId;
+
+    public SysWechatCustomerAddVo(SysWechatCustomer sysWechatCustomer) {
+        this.nickname = sysWechatCustomer.getNickname();
+        this.avatar = sysWechatCustomer.getAvatar();
+        this.userId = sysWechatCustomer.getUserId();
+        this.receptionist = sysWechatCustomer.getReceptionist();
+        this.receptionistId = sysWechatCustomer.getReceptionistId();
+    }
+
+}

+ 35 - 0
src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerDeptVo.java

@@ -0,0 +1,35 @@
+package com.ydtech.modules.admin.model.vo.wechat;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import me.chanjar.weixin.cp.bean.WxCpDepart;
+
+import java.io.Serializable;
+import java.util.List;
+
+@ApiModel("企微部门")
+@Data
+public class SysWechatCustomerDeptVo implements Serializable {
+
+    private static final long serialVersionUID = 5154076136571383722L;
+
+    @ApiModelProperty("部门编号")
+    private String deptId;
+
+    @ApiModelProperty("部门名称")
+    private String deptName;
+
+    @ApiModelProperty("上级部门编号")
+    private String parentId;
+
+    @ApiModelProperty("下级部门列表")
+    private List<SysWechatCustomerDeptVo> childDept;
+
+    public SysWechatCustomerDeptVo(WxCpDepart wxCpDepart) {
+        this.deptId = String.valueOf(wxCpDepart.getId());
+        this.deptName = wxCpDepart.getName();
+        this.parentId = String.valueOf(wxCpDepart.getParentId());
+    }
+
+}

+ 42 - 0
src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerDutyRulesVo.java

@@ -0,0 +1,42 @@
+package com.ydtech.modules.admin.model.vo.wechat;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+@ApiModel("值班规则配置")
+public class SysWechatCustomerDutyRulesVo implements Serializable {
+
+    private static final long serialVersionUID = 5313784741514176124L;
+
+    @ApiModelProperty("客服")
+    private String customerId;
+
+    @ApiModelProperty("值班客服")
+    private String dutyCustomerId;
+
+    @ApiModelProperty("值班规则列表")
+    private List<DutyDateTime> dutyDateTimeList;
+
+    @Data
+    @ApiModel("值班时间")
+    public static class DutyDateTime implements Serializable {
+
+        private static final long serialVersionUID = -633472086045531848L;
+
+        @NotBlank(message = "值班开始时间不能为空")
+        @ApiModelProperty("值班时间")
+        private String startTime;
+
+        @NotBlank(message = "值班结束时间不能为空")
+        @ApiModelProperty("结束时间")
+        private String endTime;
+
+    }
+
+}

+ 19 - 0
src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerQueryVo.java

@@ -0,0 +1,19 @@
+package com.ydtech.modules.admin.model.vo.wechat;
+
+import com.ydtech.core.page.BasePageVO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@ApiModel("客服列表查询")
+public class SysWechatCustomerQueryVo extends BasePageVO {
+
+    private static final long serialVersionUID = -5145905629582875982L;
+
+    @ApiModelProperty("客服昵称")
+    private String nickname;
+
+}

+ 47 - 0
src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerVo.java

@@ -0,0 +1,47 @@
+package com.ydtech.modules.admin.model.vo.wechat;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@ApiModel("客服账号")
+public class SysWechatCustomerVo {
+
+    @ApiModelProperty("序号")
+    private String id;
+
+    @TableField(value = "客服头像")
+    private String avatar;
+
+    @TableField("客服链接")
+    private String avatarUrl;
+
+    @ApiModelProperty("客服昵称")
+    private String nickname;
+
+    @ApiModelProperty("姓名")
+    private String username;
+
+    @ApiModelProperty("工号")
+    private String userId;
+
+    @ApiModelProperty("企业微信客服")
+    private String departmentId;
+
+    @ApiModelProperty("企微用户")
+    private String receptionist;
+
+    @ApiModelProperty("企微用户Id")
+    private String receptionistId;
+
+    @ApiModelProperty("值班客服")
+    private String dutyCustomer;
+
+    @ApiModelProperty("值班时间")
+    private List<String> dutyDatetime;
+
+}

+ 3 - 0
src/main/java/com/ydtech/modules/admin/model/vo/wechat/WechatCustomerCallbackVo.java

@@ -21,6 +21,9 @@ public class WechatCustomerCallbackVo {
     @JacksonXmlProperty(localName = "ToUserName")
     private String toUserName;
 
+    @JacksonXmlProperty(localName = "FromUserName")
+    private String fromUserName;
+
     @JacksonXmlProperty(localName = "CreateTime")
     private String createTime;
 

+ 72 - 0
src/main/java/com/ydtech/modules/admin/service/SysWechatCustomerBusinessService.java

@@ -0,0 +1,72 @@
+package com.ydtech.modules.admin.service;
+
+import com.ydtech.modules.admin.model.SysUser;
+import com.ydtech.modules.admin.model.vo.wechat.*;
+import com.ydtech.modules.order.entity.BasePageResult;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+import java.util.List;
+
+public interface SysWechatCustomerBusinessService {
+
+    /**
+     * 获取企业微信部门列表
+     *
+     * @return 企业微信部门列表
+     */
+    List<SysWechatCustomerDeptVo> getDeptByDeptId() throws WxErrorException;
+
+    /**
+     * 通过部门获取用户列表
+     *
+     * @param deptId 部门id
+     * @return 用户列表
+     */
+    List<SysWeComUserVo> getUser(String deptId) throws WxErrorException;
+
+    /**
+     * 分页查询客服列表
+     *
+     * @param sysWechatCustomerQuery 查询信息
+     * @return 客服列表
+     */
+    BasePageResult<SysWechatCustomerVo> pageQuery(SysWechatCustomerQueryVo sysWechatCustomerQuery);
+
+    /**
+     * 编辑客服
+     *
+     * @param customerId 客服id
+     * @return 客服信息
+     */
+    SysWechatCustomerAddVo getWechatCustomer(String customerId);
+
+    /**
+     * 添加客服
+     *
+     * @param sysWechatCustomerAddVo 客服信息
+     */
+    void addWechatCustomer(SysWechatCustomerAddVo sysWechatCustomerAddVo) throws WxErrorException;
+
+    /**
+     * 删除客服
+     *
+     * @param customerId 客服id
+     */
+    void deleteWechatCustomer(String customerId) throws WxErrorException;
+
+    /**
+     * 修改客服
+     *
+     * @param customerId             客服id
+     * @param sysWechatCustomerAddVo 客服信息
+     */
+    void updateWechatCustomer(String customerId, SysWechatCustomerAddVo sysWechatCustomerAddVo) throws WxErrorException;
+
+    /**
+     * 通过领导人的userId获取跳转链接
+     * @param user 用户
+     * @return 跳转链接
+     */
+    String getWeChatCustomer(SysUser user) throws WxErrorException;
+
+}

+ 35 - 0
src/main/java/com/ydtech/modules/admin/service/SysWechatCustomerDutyService.java

@@ -0,0 +1,35 @@
+package com.ydtech.modules.admin.service;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ydtech.modules.admin.model.po.SysWechatCustomer;
+import com.ydtech.modules.admin.model.po.SysWechatCustomerDuty;
+import com.ydtech.modules.admin.model.vo.wechat.SysWechatCustomerDutyRulesVo;
+
+import java.util.List;
+
+/**
+ * @author Administrator
+ * @description 针对表【sys_wechat_customer_duty(微信客服值班时间)】的数据库操作Service
+ * @createDate 2025-04-17 10:14:27
+ */
+public interface SysWechatCustomerDutyService extends IService<SysWechatCustomerDuty> {
+
+    /**
+     * 清除值班配置
+     *
+     * @param customerId 客服id
+     */
+    default void clearCustomerDuty(String customerId) {
+        LambdaUpdateWrapper<SysWechatCustomerDuty> wr = new LambdaUpdateWrapper<SysWechatCustomerDuty>()
+                .eq(SysWechatCustomerDuty::getCustomerId, customerId);
+        remove(wr);
+    }
+
+    default List<SysWechatCustomerDuty> getByCustomerId(String customerId){
+        LambdaUpdateWrapper<SysWechatCustomerDuty> wr = new LambdaUpdateWrapper<SysWechatCustomerDuty>()
+                .eq(SysWechatCustomerDuty::getCustomerId, customerId);
+        return list(wr);
+    }
+
+}

+ 13 - 0
src/main/java/com/ydtech/modules/admin/service/SysWechatCustomerRecordingService.java

@@ -0,0 +1,13 @@
+package com.ydtech.modules.admin.service;
+
+import com.ydtech.modules.admin.model.po.SysWechatCustomerRecording;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+* @author Administrator
+* @description 针对表【sys_wechat_customer_recording(微信客服记录表)】的数据库操作Service
+* @createDate 2025-04-22 17:18:47
+*/
+public interface SysWechatCustomerRecordingService extends IService<SysWechatCustomerRecording> {
+
+}

+ 79 - 0
src/main/java/com/ydtech/modules/admin/service/SysWechatCustomerService.java

@@ -0,0 +1,79 @@
+package com.ydtech.modules.admin.service;
+
+import com.github.pagehelper.PageInfo;
+import com.ydtech.exception.SystemException;
+import com.ydtech.extension.BaseIService;
+import com.ydtech.modules.admin.model.po.SysWechatCustomer;
+import com.ydtech.modules.admin.model.vo.wechat.SysWechatCustomerDutyRulesVo;
+import com.ydtech.modules.admin.model.vo.wechat.SysWechatCustomerQueryVo;
+import com.ydtech.modules.admin.model.vo.wechat.SysWechatCustomerVo;
+
+import java.util.List;
+
+/**
+ * @author Administrator
+ * @description 针对表【sys_wechat_customer(微信客服)】的数据库操作Service
+ * @createDate 2025-04-17 10:14:27
+ */
+public interface SysWechatCustomerService extends BaseIService<SysWechatCustomer> {
+
+    /**
+     * 删除微信客服数据和值班数据
+     *
+     * @param customerId 客服id
+     */
+    void deleteAllInfo(String customerId);
+
+    /**
+     * 分页查询 通过昵称查询
+     *
+     * @param sysWechatCustomerQuery 查询实体
+     * @return 客服分页数据
+     */
+    PageInfo<SysWechatCustomerVo> getByNickname(SysWechatCustomerQueryVo sysWechatCustomerQuery);
+
+    /**
+     * 通过客户id 获取规则
+     *
+     * @return 规则列表
+     */
+    SysWechatCustomerDutyRulesVo getCustomerDutyRules(String customerId);
+
+    /**
+     * 值班规则配置
+     *
+     * @param sysWechatCustomerDutyRules 值班规则
+     */
+    void saveOrUpdateCustomerDutyRules(SysWechatCustomerDutyRulesVo sysWechatCustomerDutyRules);
+
+    /**
+     * 通过用户id 获取微信客服
+     *
+     * @param userId 用户id
+     * @return 微信客服
+     */
+    default SysWechatCustomer getByUserId(String userId) {
+        return lambdaQuery().eq(SysWechatCustomer::getUserId, userId).one();
+    }
+
+    /**
+     * 昵称是否存在
+     * @param nickname
+     */
+    default void isNicknameRepeat(String nickname) {
+        List<SysWechatCustomer> list = lambdaQuery().eq(SysWechatCustomer::getNickname, nickname).list();
+        if (!list.isEmpty()) {
+            throw new SystemException("客服昵称已存在");
+        }
+    }
+
+    default void isDutyCustomerId(Long customerId) {
+        List<SysWechatCustomer> list = lambdaQuery().eq(SysWechatCustomer::getDutyCustomerId, customerId).list();
+        if (!list.isEmpty()) {
+            throw new SystemException("此客服还在值班客服中配置,请删除后重试");
+        }
+    }
+
+    void getCacheCustomerId(SysWechatCustomer sysWechatCustomer);
+
+}

+ 2 - 1
src/main/java/com/ydtech/modules/admin/service/WechatCustomerService.java

@@ -3,6 +3,7 @@ package com.ydtech.modules.admin.service;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.ydtech.core.page.BasePageVO;
 import com.ydtech.modules.admin.components.wechat.customer.response.CustomerListResponse;
+import me.chanjar.weixin.common.error.WxErrorException;
 
 import java.util.List;
 
@@ -24,7 +25,7 @@ public interface WechatCustomerService {
      *
      * @param wechatEncrypt
      */
-    void callbackSendMsgOnEvent(String wechatEncrypt) throws JsonProcessingException;
+    void callbackSendMsgOnEvent(String wechatEncrypt) throws JsonProcessingException, WxErrorException;
 
 
     /**

+ 275 - 0
src/main/java/com/ydtech/modules/admin/service/impl/SysWechatCustomerBusinessServiceImpl.java

@@ -0,0 +1,275 @@
+package com.ydtech.modules.admin.service.impl;
+
+import com.github.pagehelper.PageInfo;
+import com.ydtech.exception.SystemException;
+import com.ydtech.modules.admin.model.SysUser;
+import com.ydtech.modules.admin.model.po.SysWechatCustomer;
+import com.ydtech.modules.admin.model.po.SysWechatCustomerDuty;
+import com.ydtech.modules.admin.model.po.SysWechatCustomerRecording;
+import com.ydtech.modules.admin.model.vo.wechat.*;
+import com.ydtech.modules.admin.service.SysWechatCustomerBusinessService;
+import com.ydtech.modules.admin.service.SysWechatCustomerDutyService;
+import com.ydtech.modules.admin.service.SysWechatCustomerRecordingService;
+import com.ydtech.modules.admin.service.SysWechatCustomerService;
+import com.ydtech.modules.order.entity.BasePageResult;
+import com.ydtech.modules.order.entity.po.InsUploadFiles;
+import com.ydtech.modules.order.service.InsUploadFilesService;
+import com.ydtech.utils.DateTimeUtil;
+import lombok.RequiredArgsConstructor;
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.cp.api.WxCpDepartmentService;
+import me.chanjar.weixin.cp.api.WxCpKfService;
+import me.chanjar.weixin.cp.api.WxCpMediaService;
+import me.chanjar.weixin.cp.api.WxCpUserService;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.bean.WxCpDepart;
+import me.chanjar.weixin.cp.bean.WxCpUser;
+import me.chanjar.weixin.cp.bean.kf.*;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+
+import java.io.File;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+@RequiredArgsConstructor
+public class SysWechatCustomerBusinessServiceImpl implements SysWechatCustomerBusinessService {
+
+    private final WxCpKfService wxCpKfService;
+
+    private final WxCpMediaService wxCpMediaService;
+
+    private final WxCpUserService wxCpUserService;
+
+    private final WxCpDepartmentService wxCpDepartmentService;
+
+    private final InsUploadFilesService insUploadFilesService;
+
+    private final SysWechatCustomerService sysWechatCustomerService;
+
+    private final SysWechatCustomerDutyService sysWechatCustomerDutyService;
+
+    private final SysWechatCustomerRecordingService sysWechatCustomerRecordingService;
+
+    @Override
+    public List<SysWechatCustomerDeptVo> getDeptByDeptId() throws WxErrorException {
+        List<WxCpDepart> list = wxCpDepartmentService.list(null);
+        List<SysWechatCustomerDeptVo> deptVos = list.stream()
+                .map(SysWechatCustomerDeptVo::new)
+                .collect(Collectors.toList());
+        Map<String, List<SysWechatCustomerDeptVo>> parentGroup = deptVos.stream()
+                .collect(Collectors.groupingBy(SysWechatCustomerDeptVo::getParentId));
+        Set<String> strings = parentGroup.keySet();
+
+        deptVos.forEach(node -> node.setChildDept(parentGroup.getOrDefault(node.getDeptId(), Collections.emptyList())));
+        return deptVos.stream()
+                .filter(node -> node.getParentId() != null && strings.contains(node.getDeptId()))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public List<SysWeComUserVo> getUser(String deptId) throws WxErrorException {
+        List<WxCpUser> wxCpUsers = wxCpUserService.listSimpleByDepartment(Long.valueOf(deptId), true, 0);
+        return wxCpUsers.stream().map(x -> new SysWeComUserVo(x.getUserId(), x.getName())).collect(Collectors.toList());
+    }
+
+    @Override
+    public BasePageResult<SysWechatCustomerVo> pageQuery(SysWechatCustomerQueryVo sysWechatCustomerQuery) {
+        PageInfo<SysWechatCustomerVo> sysWechatCustomerVoPageInfo = sysWechatCustomerService.getByNickname(sysWechatCustomerQuery);
+
+        // 查询本页的值班人员
+        List<String> customer = sysWechatCustomerVoPageInfo.getList()
+                .stream()
+                .map(SysWechatCustomerVo::getId)
+                .collect(Collectors.toList());
+
+        if (!customer.isEmpty()) {
+            // 获取值班时间列表
+            Map<Long, List<SysWechatCustomerDuty>> dutyMap = sysWechatCustomerDutyService.lambdaQuery()
+                    .in(SysWechatCustomerDuty::getCustomerId, customer)
+                    .list()
+                    .stream()
+                    .collect(Collectors.groupingBy(SysWechatCustomerDuty::getCustomerId));
+
+            // 设置值班时间
+            sysWechatCustomerVoPageInfo.getList().forEach(sysWechatCustomerVo -> {
+                List<SysWechatCustomerDuty> sysWechatCustomerDuties = dutyMap.get(Long.valueOf(sysWechatCustomerVo.getId()));
+                if (!CollectionUtils.isEmpty(sysWechatCustomerDuties)) {
+                    List<String> collect = sysWechatCustomerDuties.stream()
+                            .map(x -> DateTimeUtil.startAndEndTimeFormatting(x.getStartTime(), x.getEndTime()))
+                            .collect(Collectors.toList());
+                    sysWechatCustomerVo.setDutyDatetime(collect);
+                }
+            });
+        }
+
+        return new BasePageResult<>(sysWechatCustomerQuery.getPageNum(), sysWechatCustomerQuery.getPageSize(), sysWechatCustomerVoPageInfo.getTotal(), sysWechatCustomerVoPageInfo.getPages(), sysWechatCustomerVoPageInfo.getList());
+    }
+
+
+    @Override
+    public SysWechatCustomerAddVo getWechatCustomer(String customerId) {
+        SysWechatCustomer sysWechatCustomer = sysWechatCustomerService.getById(customerId);
+        return Optional.ofNullable(sysWechatCustomer)
+                .map(SysWechatCustomerAddVo::new)
+                .orElse(new SysWechatCustomerAddVo());
+    }
+
+    @Override
+    public void addWechatCustomer(SysWechatCustomerAddVo sysWechatCustomerAddVo) throws WxErrorException {
+        sysWechatCustomerService.isNicknameRepeat(sysWechatCustomerAddVo.getNickname());
+        WxCpKfAccountAdd wxCpKfAccountAdd = new WxCpKfAccountAdd();
+        wxCpKfAccountAdd.setName(sysWechatCustomerAddVo.getNickname());
+        // 头像
+        if (StringUtils.hasLength(sysWechatCustomerAddVo.getAvatar())) {
+            InsUploadFiles insUploadFiles = insUploadFilesService.getById(sysWechatCustomerAddVo.getAvatar());
+            Optional.ofNullable(insUploadFiles).map(InsUploadFiles::getFilePath).ifPresent(filePath -> {
+                File file = new File(filePath);
+                // 上传素材
+                WxMediaUploadResult image;
+                try {
+                    image = wxCpMediaService.upload("image", file);
+                } catch (WxErrorException e) {
+                    throw new SystemException("图片上传失败");
+                }
+                String mediaId = image.getMediaId();
+                wxCpKfAccountAdd.setMediaId(mediaId);
+            });
+        }
+        // 添加
+        WxCpKfAccountAddResp wxCpKfAccountAddResp = wxCpKfService.addAccount(wxCpKfAccountAdd);
+        SysWechatCustomer sysWechatCustomer = new SysWechatCustomer(sysWechatCustomerAddVo);
+        sysWechatCustomer.setOpenKfId(wxCpKfAccountAddResp.getOpenKfid());
+        List<String> list = new ArrayList<>();
+        list.add(sysWechatCustomerAddVo.getReceptionistId());
+        WxCpKfServicerOpResp wxCpKfServicerOpResp = wxCpKfService.addServicer(wxCpKfAccountAddResp.getOpenKfid(), list);
+
+        if (wxCpKfServicerOpResp.getErrcode() == 0) {
+            sysWechatCustomerService.save(sysWechatCustomer);
+        }
+    }
+
+    @Override
+    public void deleteWechatCustomer(String customerId) throws WxErrorException {
+        SysWechatCustomer sysWechatCustomer = sysWechatCustomerService.getByIdExist(customerId, "客服不存在");
+        sysWechatCustomerService.isDutyCustomerId(sysWechatCustomer.getId());
+        WxCpKfAccountDel wxCpKfAccountDel = new WxCpKfAccountDel();
+        wxCpKfAccountDel.setOpenKfid(sysWechatCustomer.getOpenKfId());
+        WxCpBaseResp wxCpBaseResp;
+        wxCpBaseResp = wxCpKfService.delAccount(wxCpKfAccountDel);
+        if (wxCpBaseResp.getErrcode() == 0) {
+            sysWechatCustomerService.deleteAllInfo(customerId);
+            sysWechatCustomerDutyService.clearCustomerDuty(customerId);
+        }
+    }
+
+    @Override
+    public void updateWechatCustomer(String customerId, SysWechatCustomerAddVo sysWechatCustomerAddVo) throws WxErrorException {
+        SysWechatCustomer sysWechatCustomer = sysWechatCustomerService.getByIdExist(customerId, "客服不存在");
+        if(!sysWechatCustomer.getNickname().equals(sysWechatCustomerAddVo.getNickname())){
+            sysWechatCustomerService.isNicknameRepeat(sysWechatCustomerAddVo.getNickname());
+        }
+        WxCpKfAccountUpd wxCpKfAccountUpd = new WxCpKfAccountUpd();
+        wxCpKfAccountUpd.setOpenKfid(sysWechatCustomer.getOpenKfId());
+        boolean isAvatarSame = StringUtils.hasLength(sysWechatCustomer.getAvatar()) && !sysWechatCustomer.getAvatar()
+                .equals(sysWechatCustomerAddVo.getAvatar());
+
+        // 头像是否更换
+        if (isAvatarSame) {
+            InsUploadFiles insUploadFiles = insUploadFilesService.getById(sysWechatCustomerAddVo.getAvatar());
+            File file = new File(insUploadFiles.getFilePath());
+            WxMediaUploadResult image = wxCpMediaService.upload("image", file);
+            String mediaId = image.getMediaId();
+            wxCpKfAccountUpd.setMediaId(mediaId);
+            sysWechatCustomer.setAvatar(sysWechatCustomerAddVo.getAvatar());
+        }
+
+        // 昵称是否相同
+        boolean isNicknameSame = !sysWechatCustomer.getNickname().equals(sysWechatCustomerAddVo.getNickname());
+        if (isNicknameSame) {
+            wxCpKfAccountUpd.setName(sysWechatCustomerAddVo.getNickname());
+        }
+
+        // 客服人员是否替换
+        if (!sysWechatCustomer.getReceptionistId().equals(sysWechatCustomerAddVo.getReceptionistId())) {
+            List<String> list = new ArrayList<>();
+            list.add(sysWechatCustomer.getReceptionistId());
+            wxCpKfService.delServicer(sysWechatCustomer.getOpenKfId(), list);
+            list = new ArrayList<>();
+            list.add(sysWechatCustomerAddVo.getReceptionistId());
+            wxCpKfService.addServicer(sysWechatCustomer.getOpenKfId(), list);
+            sysWechatCustomer.setReceptionistId(sysWechatCustomerAddVo.getReceptionistId());
+            sysWechatCustomer.setReceptionist(sysWechatCustomerAddVo.getReceptionist());
+        }
+
+        // 昵称和头像是否跟换
+        if (isNicknameSame || isAvatarSame) {
+            wxCpKfService.updAccount(wxCpKfAccountUpd);
+        }
+
+        sysWechatCustomer.setNickname(sysWechatCustomerAddVo.getNickname());
+        sysWechatCustomer.setAvatar(sysWechatCustomerAddVo.getAvatar());
+        sysWechatCustomer.setUserId(sysWechatCustomerAddVo.getUserId());
+        sysWechatCustomerService.updateById(sysWechatCustomer);
+    }
+
+    @Override
+    public String getWeChatCustomer(SysUser user) throws WxErrorException {
+        SysWechatCustomer sysWechatCustomer = sysWechatCustomerService.getByUserId(user.getLeaderId());
+        List<SysWechatCustomer> sysWechatCustomerList = sysWechatCustomerService.list();
+        List<Long> sysWechatCustomerIdList = sysWechatCustomerList.stream()
+                .map(SysWechatCustomer::getId)
+                .collect(Collectors.toList());
+        if (ObjectUtils.isEmpty(sysWechatCustomer)) {
+            // 获取最近一次的客服记录
+            SysWechatCustomerRecording sysWechatCustomerRecording = sysWechatCustomerRecordingService.lambdaQuery()
+                    .in(!sysWechatCustomerIdList.isEmpty(), SysWechatCustomerRecording::getCustomerId, sysWechatCustomerIdList)
+                    .eq(SysWechatCustomerRecording::getUserId, user.getId())
+                    .orderByDesc(SysWechatCustomerRecording::getCreateTime)
+                    .last("limit 1")
+                    .one();
+            if (ObjectUtils.isEmpty(sysWechatCustomerRecording)) {
+                sysWechatCustomerService.getCacheCustomerId(sysWechatCustomer);
+            } else {
+                // 使用上一次的客服
+                sysWechatCustomer = sysWechatCustomerService.lambdaQuery()
+                        .eq(SysWechatCustomer::getId, sysWechatCustomerRecording.getCustomerId())
+                        .one();
+                if (ObjectUtils.isEmpty(sysWechatCustomer)) {
+                    sysWechatCustomerService.getCacheCustomerId(sysWechatCustomer);
+                }
+            }
+            SysWechatCustomerRecording customerRecording = new SysWechatCustomerRecording();
+            customerRecording.setCustomerId(sysWechatCustomer.getId());
+            customerRecording.setUserId(user.getId());
+            sysWechatCustomerRecordingService.save(customerRecording);
+        }
+
+        List<SysWechatCustomerDuty> list = sysWechatCustomerDutyService.lambdaQuery()
+                .eq(SysWechatCustomerDuty::getCustomerId, sysWechatCustomer.getId())
+                .le(SysWechatCustomerDuty::getStartTime, LocalDateTime.now())
+                .ge(SysWechatCustomerDuty::getEndTime, LocalDateTime.now())
+                .list();
+        if (sysWechatCustomer.getDutyCustomerId() > 0 && list != null && !list.isEmpty()) {
+            sysWechatCustomer = sysWechatCustomerService.getById(sysWechatCustomer.getDutyCustomerId());
+        }
+
+        if (ObjectUtils.isEmpty(sysWechatCustomer)) {
+            throw new SystemException("请联系管理员,配置客服");
+        }
+
+        String openKfId = sysWechatCustomer.getOpenKfId();
+        WxCpKfAccountLink wxCpKfAccountLink = new WxCpKfAccountLink();
+        wxCpKfAccountLink.setOpenKfid(openKfId);
+        wxCpKfAccountLink.setScene(user.getId());
+        WxCpKfAccountLinkResp accountLink = wxCpKfService.getAccountLink(wxCpKfAccountLink);
+        return accountLink.getUrl();
+    }
+
+}

+ 41 - 0
src/main/java/com/ydtech/modules/admin/service/impl/SysWechatCustomerDutyServiceImpl.java

@@ -0,0 +1,41 @@
+package com.ydtech.modules.admin.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ydtech.exception.SystemException;
+import com.ydtech.modules.admin.dao.SysWechatCustomerDutyMapper;
+import com.ydtech.modules.admin.model.po.SysWechatCustomerDuty;
+import com.ydtech.modules.admin.model.vo.wechat.*;
+import com.ydtech.modules.admin.service.SysWechatCustomerDutyService;
+import com.ydtech.modules.order.entity.BasePageResult;
+import lombok.RequiredArgsConstructor;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.cp.api.WxCpDepartmentService;
+import me.chanjar.weixin.cp.api.WxCpKfService;
+import me.chanjar.weixin.cp.api.WxCpMediaService;
+import me.chanjar.weixin.cp.api.WxCpUserService;
+import me.chanjar.weixin.cp.bean.WxCpDepart;
+import me.chanjar.weixin.cp.bean.WxCpUser;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author Administrator
+ * @description 针对表【sys_wechat_customer_duty(微信客服值班时间)】的数据库操作Service实现
+ * @createDate 2025-04-17 10:14:27
+ */
+@Service
+public class SysWechatCustomerDutyServiceImpl extends ServiceImpl<SysWechatCustomerDutyMapper, SysWechatCustomerDuty>
+        implements SysWechatCustomerDutyService {
+
+
+
+}
+
+
+
+

+ 22 - 0
src/main/java/com/ydtech/modules/admin/service/impl/SysWechatCustomerRecordingServiceImpl.java

@@ -0,0 +1,22 @@
+package com.ydtech.modules.admin.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ydtech.modules.admin.model.po.SysWechatCustomerRecording;
+import com.ydtech.modules.admin.service.SysWechatCustomerRecordingService;
+import com.ydtech.modules.admin.dao.SysWechatCustomerRecordingMapper;
+import org.springframework.stereotype.Service;
+
+/**
+* @author Administrator
+* @description 针对表【sys_wechat_customer_recording(微信客服记录表)】的数据库操作Service实现
+* @createDate 2025-04-22 17:18:47
+*/
+@Service
+public class SysWechatCustomerRecordingServiceImpl extends ServiceImpl<SysWechatCustomerRecordingMapper, SysWechatCustomerRecording>
+    implements SysWechatCustomerRecordingService{
+
+}
+
+
+
+

+ 129 - 0
src/main/java/com/ydtech/modules/admin/service/impl/SysWechatCustomerServiceImpl.java

@@ -0,0 +1,129 @@
+package com.ydtech.modules.admin.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.ydtech.exception.SystemException;
+import com.ydtech.modules.admin.dao.SysWechatCustomerMapper;
+import com.ydtech.modules.admin.model.po.SysWechatCustomer;
+import com.ydtech.modules.admin.model.po.SysWechatCustomerDuty;
+import com.ydtech.modules.admin.model.vo.wechat.SysWechatCustomerDutyRulesVo;
+import com.ydtech.modules.admin.model.vo.wechat.SysWechatCustomerQueryVo;
+import com.ydtech.modules.admin.model.vo.wechat.SysWechatCustomerVo;
+import com.ydtech.modules.admin.service.SysWechatCustomerDutyService;
+import com.ydtech.modules.admin.service.SysWechatCustomerService;
+import com.ydtech.utils.DateTimeUtil;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author Administrator
+ * @description 针对表【sys_wechat_customer(微信客服)】的数据库操作Service实现
+ * @createDate 2025-04-17 10:14:27
+ */
+@Service
+@RequiredArgsConstructor
+public class SysWechatCustomerServiceImpl extends ServiceImpl<SysWechatCustomerMapper, SysWechatCustomer>
+        implements SysWechatCustomerService {
+
+    private final SysWechatCustomerDutyService sysWechatCustomerDutyService;
+
+    private final StringRedisTemplate redisTemplate;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteAllInfo(String customerId) {
+        removeById(customerId);
+        sysWechatCustomerDutyService.clearCustomerDuty(customerId);
+    }
+
+    @Override
+    public PageInfo<SysWechatCustomerVo> getByNickname(SysWechatCustomerQueryVo sysWechatCustomerQuery) {
+        Page<SysWechatCustomerVo> ignored = PageHelper.startPage(sysWechatCustomerQuery.getPageNum(), sysWechatCustomerQuery.getPageSize());
+        List<SysWechatCustomerVo> sysWechatCustomerVoList = baseMapper.getByNickname(sysWechatCustomerQuery.getNickname());
+        return new PageInfo<>(sysWechatCustomerVoList);
+    }
+
+    @Override
+    public SysWechatCustomerDutyRulesVo getCustomerDutyRules(String customerId) {
+        SysWechatCustomer customer = getByIdExist(customerId, "客服不存在");
+        List<SysWechatCustomerDuty> sysWechatCustomerDuties = sysWechatCustomerDutyService.getByCustomerId(customerId);
+        SysWechatCustomerDutyRulesVo sysWechatCustomerDutyRulesVo = new SysWechatCustomerDutyRulesVo();
+        sysWechatCustomerDutyRulesVo.setCustomerId(String.valueOf(customer.getId()));
+        if (customer.getDutyCustomerId() > 0) {
+            sysWechatCustomerDutyRulesVo.setDutyCustomerId(String.valueOf(customer.getDutyCustomerId()));
+        }else {
+            sysWechatCustomerDutyRulesVo.setDutyCustomerId(null);
+        }
+        List<SysWechatCustomerDutyRulesVo.DutyDateTime> collect = sysWechatCustomerDuties.stream()
+                .map(sysWechatCustomerDuty -> {
+                    SysWechatCustomerDutyRulesVo.DutyDateTime dutyDateTime = new SysWechatCustomerDutyRulesVo.DutyDateTime();
+                    dutyDateTime.setEndTime(DateTimeUtil.localDateTimetoString(sysWechatCustomerDuty.getEndTime()));
+                    dutyDateTime.setStartTime(DateTimeUtil.localDateTimetoString(sysWechatCustomerDuty.getStartTime()));
+                    return dutyDateTime;
+                })
+                .collect(Collectors.toList());
+        sysWechatCustomerDutyRulesVo.setDutyDateTimeList(collect);
+        return sysWechatCustomerDutyRulesVo;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void saveOrUpdateCustomerDutyRules(SysWechatCustomerDutyRulesVo sysWechatCustomerDutyRules) {
+        SysWechatCustomer customer = getByIdExist(sysWechatCustomerDutyRules.getCustomerId(), "客服不存在");
+        SysWechatCustomer dutyCustomer = getByIdExist(sysWechatCustomerDutyRules.getDutyCustomerId(), "值班客服不存在");
+
+        Optional.ofNullable(sysWechatCustomerDutyRules.getDutyDateTimeList())
+                        .ifPresent(sysWechatCustomerDutyRulesList -> {
+                            sysWechatCustomerDutyRulesList.forEach(sysWechatCustomerDutyRule -> {
+                                if (DateTimeUtil.timeComparison(sysWechatCustomerDutyRule.getStartTime(), sysWechatCustomerDutyRule.getEndTime())) {
+                                    throw new SystemException("结束时间必须晚于开始时间");
+                                }
+                            });
+                        });
+
+        customer.setDutyCustomerId(dutyCustomer.getId());
+        updateById(customer);
+        // 清楚再删除
+        sysWechatCustomerDutyService.clearCustomerDuty(String.valueOf(customer.getId()));
+
+        List<SysWechatCustomerDuty> collect = sysWechatCustomerDutyRules.getDutyDateTimeList()
+                .stream()
+                .map(x -> new SysWechatCustomerDuty(customer.getId(), x))
+                .collect(Collectors.toList());
+        sysWechatCustomerDutyService.saveBatch(collect);
+    }
+
+    @Override
+    public void getCacheCustomerId(SysWechatCustomer sysWechatCustomer) {
+        String customerCache = redisTemplate.opsForValue().get("sys:wechat:customer");
+        String s1 = Optional.ofNullable(customerCache)
+                .orElse("0");
+        sysWechatCustomer = lambdaQuery()
+                .gt(StringUtils.hasLength(s1), SysWechatCustomer::getId, s1)
+                .orderByAsc(SysWechatCustomer::getId)
+                .last("limit 1")
+                .one();
+
+        if (ObjectUtils.isEmpty(sysWechatCustomer)) {
+            sysWechatCustomer = lambdaQuery()
+                    .orderByAsc(SysWechatCustomer::getId)
+                    .last("limit 1")
+                    .one();
+        }
+        redisTemplate.opsForValue().set("sys:wechat:customer", String.valueOf(sysWechatCustomer.getId()));
+    }
+}
+
+
+
+

+ 47 - 7
src/main/java/com/ydtech/modules/admin/service/impl/WechatCustomerServiceImpl.java

@@ -11,18 +11,24 @@ import com.ydtech.modules.admin.components.wechat.customer.response.CustomerAddC
 import com.ydtech.modules.admin.components.wechat.customer.response.CustomerListResponse;
 import com.ydtech.modules.admin.components.wechat.customer.response.CustomerSyncMsgResponse;
 import com.ydtech.modules.admin.model.SysUser;
+import com.ydtech.modules.admin.model.po.SysWechatCustomer;
 import com.ydtech.modules.admin.model.vo.wechat.WechatCustomerCallbackVo;
 import com.ydtech.modules.admin.model.vo.wechat.WechatEncryptVo;
 import com.ydtech.modules.admin.service.SysUserService;
+import com.ydtech.modules.admin.service.SysWechatCustomerService;
 import com.ydtech.modules.admin.service.WechatCustomerService;
 import com.ydtech.utils.StringUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.crypto.WxCryptUtil;
+import me.chanjar.weixin.cp.api.WxCpKfService;
+import me.chanjar.weixin.cp.bean.kf.WxCpKfServiceStateResp;
 import org.springframework.stereotype.Service;
 import org.springframework.util.ObjectUtils;
 
 import java.util.List;
+import java.util.stream.Collectors;
 
 @Slf4j
 @Service
@@ -35,6 +41,11 @@ public class WechatCustomerServiceImpl implements WechatCustomerService {
 
     private final XmlMapper xmlMapper = new XmlMapper();
 
+    private final WxCpKfService wxCpKfService;
+
+    private final SysWechatCustomerService sysWechatCustomerService;
+
+
     @Override
     public String customerCallback(String msgSignature, String timestamp, String nonce, String echoStr) {
         WxCryptUtil wxCryptUtil = wechatCustomerComponents.getWxCryptUtil();
@@ -42,7 +53,7 @@ public class WechatCustomerServiceImpl implements WechatCustomerService {
     }
 
     @Override
-    public void callbackSendMsgOnEvent(String wechatEncrypt) throws JsonProcessingException {
+    public void callbackSendMsgOnEvent(String wechatEncrypt) throws JsonProcessingException, WxErrorException {
         log.info("回调参数为{}", wechatEncrypt);
         WechatEncryptVo wechatEncryptVo = xmlMapper.readValue(wechatEncrypt, WechatEncryptVo.class);
         WxCryptUtil wxCryptUtil = wechatCustomerComponents.getWxCryptUtil();
@@ -56,21 +67,50 @@ public class WechatCustomerServiceImpl implements WechatCustomerService {
         customerSyncMsgRequest.setToken(wechatCustomerCallbackVo.getToken());
         customerSyncMsgRequest.setOpenKfid(wechatCustomerCallbackVo.getOpenKfId());
         CustomerSyncMsgResponse customerSyncMsgResponse = wechatCustomerComponents.syncMsg(customerSyncMsgRequest);
+        while (customerSyncMsgResponse.getHasMore() == 1) {
+            String nextCursor = customerSyncMsgResponse.getNextCursor();
+            customerSyncMsgRequest.setCursor(nextCursor);
+            customerSyncMsgResponse = wechatCustomerComponents.syncMsg(customerSyncMsgRequest);
+        }
         List<CustomerSyncMsgResponse.MsgListDTO> msgList = customerSyncMsgResponse.getMsgList();
         CustomerSyncMsgResponse.MsgListDTO msgListDTO = customerSyncMsgResponse.getMsgList().get(msgList.size() - 1);
 
+        if (msgListDTO.getOrigin() == 3) {
+            List<CustomerSyncMsgResponse.MsgListDTO> msgListDTOList = msgList.stream()
+                    .filter(x -> "event".equals(x.getMsgtype()))
+                    .collect(Collectors.toList());
+            msgListDTOList.forEach(x -> {
+                try {
+                    CustomerSyncMsgResponse.MsgListDTO.EventDTO xEvent = x.getEvent();
+                    WxCpKfServiceStateResp serviceState = wxCpKfService.getServiceState(xEvent.getOpenKfid(), xEvent.getExternalUserid());
+                    if (serviceState.getServiceState() == 0) {
+                        List<SysWechatCustomer> list = sysWechatCustomerService.lambdaQuery()
+                                .eq(SysWechatCustomer::getOpenKfId, xEvent.getOpenKfid())
+                                .list();
+                        wxCpKfService.transServiceState(xEvent.getOpenKfid(), xEvent.getExternalUserid(), 3, list.get(0)
+                                .getReceptionistId());
+                    }
+                } catch (WxErrorException e) {
+                    throw new RuntimeException(e);
+                }
+            });
+        }
+
         CustomerSyncMsgResponse.MsgListDTO.EventDTO event = msgListDTO.getEvent();
-        if(ObjectUtils.isEmpty(event)) {
+        if (ObjectUtils.isEmpty(event)) {
             return;
         }
-        String sceneParam = event.getSceneParam();
-        if (StringUtils.isEmpty(sceneParam)) {
+
+        String scene = event.getScene();
+        if (StringUtils.isEmpty(scene)) {
             return;
         }
+        if (msgListDTO.getOrigin() == 4) {
+            SysUser sysUser = sysUserService.getById(scene);
+            CustomerSendMsgOnEventRequest customerSendMsgOnEventRequest = CustomerSendMsgOnEventRequest.sendMsgOnEvent(sysUser, msgListDTO.getMsgid(), event.getWelcomeCode());
+            wechatCustomerComponents.sendMsgOnEvent(customerSendMsgOnEventRequest);
+        }
 
-        SysUser sysUser = sysUserService.getById(sceneParam);
-        CustomerSendMsgOnEventRequest customerSendMsgOnEventRequest = CustomerSendMsgOnEventRequest.sendMsgOnEvent(sysUser, msgListDTO.getMsgid(), event.getWelcomeCode());
-        wechatCustomerComponents.sendMsgOnEvent(customerSendMsgOnEventRequest);
     }
 
     @Override

+ 76 - 73
src/main/java/com/ydtech/utils/DateTimeUtil.java

@@ -1,16 +1,14 @@
 package com.ydtech.utils;
 
-import cn.hutool.core.collection.CollUtil;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.time.*;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoField;
 import java.time.temporal.ChronoUnit;
 import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalAdjusters;
-import java.util.*;
+import java.util.Locale;
 
 /**
  * 日期时间工具类   后期替换DateUtil工具类
@@ -150,7 +148,7 @@ public class DateTimeUtil {
      */
     public static String parseLocalDateToStringFrontOne(String localDateStr, String pattern) {
         DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
-        LocalDate date = LocalDate.parse(localDateStr,dateTimeFormatter);
+        LocalDate date = LocalDate.parse(localDateStr, dateTimeFormatter);
         LocalDate yesterday = date.plusDays(-1);
         return yesterday.toString();
     }
@@ -232,6 +230,16 @@ public class DateTimeUtil {
         return getFirstDayOfYearStr(localDateTime, DATETIME_PATTERN);
     }
 
+    /**
+     * 获取指定日期
+     *
+     * @param localDateTime 指定日期时间
+     * @return String 格式:yyyy-MM-dd HH:mm:ss
+     */
+    public static String localDateTimetoString(LocalDateTime localDateTime){
+        return localDateTime.format(DateTimeFormatter.ofPattern(DATETIME_PATTERN));
+    }
+
     /**
      * 获取指定日期当年最后一天的日期字符串
      *
@@ -261,7 +269,10 @@ public class DateTimeUtil {
      * @return String 格式:yyyy-MM-dd 23:59:59
      */
     public static String getLastDayOfYearStr(LocalDateTime localDateTime, String pattern) {
-        return format(localDateTime.with(TemporalAdjusters.lastDayOfYear()).withHour(23).withMinute(59).withSecond(59), pattern);
+        return format(localDateTime.with(TemporalAdjusters.lastDayOfYear())
+                .withHour(23)
+                .withMinute(59)
+                .withSecond(59), pattern);
     }
 
     /**
@@ -320,7 +331,10 @@ public class DateTimeUtil {
      * @return String 格式:yyyy-MM-dd 23:59:59
      */
     public static String getLastDayOfMonthStr(LocalDateTime localDateTime, String pattern) {
-        return format(localDateTime.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59), pattern);
+        return format(localDateTime.with(TemporalAdjusters.lastDayOfMonth())
+                .withHour(23)
+                .withMinute(59)
+                .withSecond(59), pattern);
     }
 
     /**
@@ -445,21 +459,27 @@ public class DateTimeUtil {
 
 
     /**
-     *  date1 是否大于 date2
-     * @param date1  格式yyyy-MM-dd HH:mm:ss
-     * @param date2  格式 yyyyMM 或 yyyy
+     * date1 是否大于 date2
      *
+     * @param date1 格式yyyy-MM-dd HH:mm:ss
+     * @param date2 格式 yyyyMM 或 yyyy
      * @author: lig
      * @date: 2023年09月06日 0006
      */
-    public static boolean dateIsAfter(String date1,String date2) {
+    public static boolean dateIsAfter(String date1, String date2) {
 
-        if(StringUtils.isEmpty(date2)) return false;
+        if (StringUtils.isEmpty(date2)) {
+            return false;
+        }
 
 //        String dateStr = "2018-06-20 00:00:00";
 //        String dateStr2 = "201806";
-        if(date2.length() < 5)date2 = date2 + "0101";
-        if(date2.length() < 7)date2 = date2 +"01";
+        if (date2.length() < 5) {
+            date2 = date2 + "0101";
+        }
+        if (date2.length() < 7) {
+            date2 = date2 + "01";
+        }
 
 
         LocalDate lRegisterDate = DateTimeUtil.parseLocalDate(date1, DateTimeUtil.DATE_PATTERN);
@@ -470,79 +490,62 @@ public class DateTimeUtil {
         return lVehicleYearDate.isBefore(lRegisterDate);
 
 
-
-
     }
 
     /**
-     *  一天内  true 时间大于00:00:00   小于23:59:59
-     * @param dateTime
+     * 一天内  true 时间大于00:00:00   小于23:59:59
      *
+     * @param dateTime
      * @author: lig
      * @date: 2023年09月11日 0011
      */
-    public static boolean inOneDay(LocalDateTime dateTime){
+    public static boolean inOneDay(LocalDateTime dateTime) {
 //        LocalDateTime sDateTime = parseLocalDateTime(dateTime,DATETIME_PATTERN);
         LocalDateTime minTime = LocalDateTime.of(dateTime.toLocalDate(), LocalTime.MIN);
         LocalDateTime maxTime = LocalDateTime.of(dateTime.toLocalDate(), LocalTime.MAX);
-        if(dateTime.isAfter(minTime) && dateTime.isBefore(maxTime)){
+        if (dateTime.isAfter(minTime) && dateTime.isBefore(maxTime)) {
 //            System.err.println("时间大于0点 小于23.59:"+sDateTime.isAfter(minTime));
             return true;
         }
         return false;
     }
 
+    /**
+     * 格式化时间格式
+     * 2025年3月21日 星期五 08:00  – 18:00
+     *
+     * @param localDateTime1 开始时间
+     * @param localDateTime2 结束时间
+     * @return 格式化时间
+     */
+    public static String startAndEndTimeFormatting(LocalDateTime localDateTime1, LocalDateTime localDateTime2) {
+        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy年M月d日 E", Locale.CHINA);
+        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
+        String datePart;
+        String timeRange;
+        if (localDateTime1.toLocalDate().isEqual(localDateTime2.toLocalDate())) {
+            datePart = localDateTime1.format(dateFormatter);
+            timeRange = localDateTime1.format(timeFormatter) + " – " + localDateTime2.format(timeFormatter);
+            return datePart + " " + timeRange;
+        } else {
+            DateTimeFormatter dateFormatter2 = DateTimeFormatter.ofPattern("yyyy年M月d日 E HH:mm", Locale.CHINA);
+            datePart = localDateTime1.format(dateFormatter2);
+            timeRange = localDateTime2.format(dateFormatter2);
+        }
+        return datePart + " – " + timeRange;
+    }
 
-
-    public static void main(String[] args) throws ParseException {
-
-        List list = null;
-        System.out.println(CollUtil.isEmpty(list));
-        System.out.println("222:"+list.isEmpty());
-
-        String dateStr = "2023-10-02 23:59:59";
-        LocalDateTime sDateTime = parseLocalDateTime(dateStr,DATETIME_PATTERN);
-        System.out.println("前一年:"+ DateTimeUtil.parseLocalDateToString(sDateTime.minusYears(1).toString(), DateTimeUtil.DATETIME_PATTERN));
-//        LocalDateTime one = ;
-
-
-
-
-//        String dateStr = "2018-06-20 23:59:59";
-//
-//        LocalDateTime sDateTime = parseLocalDateTime(dateStr,DATETIME_PATTERN);
-//
-//        LocalDateTime minTime = LocalDateTime.of(sDateTime.toLocalDate(), LocalTime.MIN);
-//
-//        LocalDateTime maxTime = LocalDateTime.of(sDateTime.toLocalDate(), LocalTime.MAX);
-//
-//        System.err.println("000:"+maxTime.toString());
-//
-//        System.err.println("2222:"+sDateTime.isBefore(maxTime));
-//
-//
-//        if(sDateTime.isAfter(minTime) && sDateTime.isBefore(maxTime)){
-//            System.err.println("时间大于0点 小于23.59:"+sDateTime.isAfter(minTime));
-//
-//        }
-
-//        String dateStr2 = "201806";
-//        if(dateStr2.length() < 7)dateStr2 = dateStr2 +"01";
-////        String aaa = DateTimeUtil.parseLocalDateToString(dateStr, DateTimeUtil.DATETIME_PATTERN);
-////        System.out.println("aaaa: " + aaa);
-//
-//
-//        LocalDate lRegisterDate = DateTimeUtil.parseLocalDate(dateStr, DateTimeUtil.DATETIME_PATTERN);
-//        LocalDate lVehicleYearDate = DateTimeUtil.parseLocalDate(dateStr2, DateTimeUtil.UNSIGNED_DATE_PATTERN);
-//
-//        if(lVehicleYearDate.isAfter(lRegisterDate)){
-//
-//        }
-//
-//        System.err.println("注册日期:"+lRegisterDate);
-//        System.err.println("上市日期:"+lVehicleYearDate);
-
+    /**
+     * 时间比较
+     * @param date1 yyyy-MM-dd HH:mm:ss
+     * @param date2 yyyy-MM-dd HH:mm:ss
+     * @return
+     */
+    public static boolean timeComparison(String date1, String date2) {
+        LocalDateTime dateTime1 = DateTimeUtil.parseLocalDateTime(date1, DateTimeUtil.DATETIME_PATTERN);
+        LocalDateTime dateTime2 = DateTimeUtil.parseLocalDateTime(date2, DateTimeUtil.DATETIME_PATTERN);
+        return dateTime1.isAfter(dateTime2);
+    }
 
 
-    }
 }

+ 1 - 1
src/main/resources/application-pre.yml

@@ -244,7 +244,7 @@ wechat:
   # 微信客服
   customer:
     corp-id: wwfe67d19509d43ec5
-    secret: lbn1DU7VhqK3dG0XDciPDXf_AdSryne84nvRhtSEGLc
+    secret: 5M_5mGONe-t4xCPlwPU-EJt53GiWaUjtbJjY5CR-dgc
     token: btgwGK2r
     encoding-aes-key: eevs11QeInJYRysGYnC8gK68F4CGsedM1Dn1X79cPCs
   open:

+ 16 - 0
src/main/resources/mapper/SysWechatCustomerRecordingMapper.xml

@@ -0,0 +1,16 @@
+<?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.ydtech.modules.admin.dao.SysWechatCustomerRecordingMapper">
+
+    <resultMap id="BaseResultMap" type="com.ydtech.modules.admin.model.po.SysWechatCustomerRecording">
+            <id property="id" column="id" jdbcType="INTEGER"/>
+            <result property="customerId" column="customer_id" jdbcType="INTEGER"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,customer_id,create_time
+    </sql>
+</mapper>

+ 18 - 0
src/main/resources/mapper/modules/admin/SysWechatCustomerDutyMapper.xml

@@ -0,0 +1,18 @@
+<?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.ydtech.modules.admin.dao.SysWechatCustomerDutyMapper">
+
+    <resultMap id="BaseResultMap" type="com.ydtech.modules.admin.model.po.SysWechatCustomerDuty">
+            <id property="id" column="id" jdbcType="INTEGER"/>
+            <result property="startTime" column="start_time" jdbcType="TIMESTAMP"/>
+            <result property="endTime" column="end_time" jdbcType="TIMESTAMP"/>
+            <result property="customerId" column="customer_id" jdbcType="INTEGER"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,start_time,end_time,
+        customer_id
+    </sql>
+</mapper>

+ 44 - 0
src/main/resources/mapper/modules/admin/SysWechatCustomerMapper.xml

@@ -0,0 +1,44 @@
+<?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.ydtech.modules.admin.dao.SysWechatCustomerMapper">
+
+    <resultMap id="BaseResultMap" type="com.ydtech.modules.admin.model.po.SysWechatCustomer">
+            <id property="id" column="id" jdbcType="INTEGER"/>
+            <result property="nickname" column="nickname" jdbcType="VARCHAR"/>
+            <result property="avatar" column="avatar" jdbcType="VARCHAR"/>
+            <result property="userId" column="user_id" jdbcType="VARCHAR"/>
+            <result property="receptionist" column="receptionist" jdbcType="VARCHAR"/>
+            <result property="receptionistId" column="receptionist_id" jdbcType="VARCHAR"/>
+            <result property="openKfId" column="open_kf_id" jdbcType="VARCHAR"/>
+            <result property="dutyCustomerId" column="duty_customer_id" jdbcType="INTEGER"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,nickname,avatar,
+        user_id,receptionist,duty_customer_id
+    </sql>
+
+    <select id="getByNickname" resultType="com.ydtech.modules.admin.model.vo.wechat.SysWechatCustomerVo">
+        select c.id as id,
+        f.id as avatar,
+        f.url as avatarUrl,
+        c.nickname as nickname,
+        u.name as username,
+        u.id as userId,
+        c.department_id as departmentId,
+        c.receptionist as receptionist,
+        c.receptionist_id as receptionistId,
+        swc.nickname as dutyCustomer
+        from sys_wechat_customer c
+        left join sys_user u on u.id = c.user_id
+        left join ins_upload_files f on f.id = c.avatar
+        left join sys_wechat_customer swc on swc.id = c.duty_customer_id
+        <if test="nickname != null and nickname != ''">
+            where c.nickname = #{nickname}
+        </if>
+        order by c.id
+    </select>
+
+</mapper>