wks 1 год назад
Родитель
Сommit
be3c3f56de
25 измененных файлов с 1120 добавлено и 125 удалено
  1. 10 9
      src/main/java/com/ydtech/aop/GlobalExceptionHandler.java
  2. 24 20
      src/main/java/com/ydtech/config/WechatWorkConfig.java
  3. 2 0
      src/main/java/com/ydtech/config/properties/ChengTaiApiConfigurationProperties.java
  4. 0 1
      src/main/java/com/ydtech/modules/admin/constants/WechatCustomerEnum.java
  5. 4 20
      src/main/java/com/ydtech/modules/admin/controller/WechatController.java
  6. 98 0
      src/main/java/com/ydtech/modules/admin/controller/wechat/SysWechatCustomerConfigController.java
  7. 18 0
      src/main/java/com/ydtech/modules/admin/dao/SysWechatCustomerDutyMapper.java
  8. 29 0
      src/main/java/com/ydtech/modules/admin/dao/SysWechatCustomerMapper.java
  9. 87 0
      src/main/java/com/ydtech/modules/admin/model/po/SysWechatCustomer.java
  10. 55 0
      src/main/java/com/ydtech/modules/admin/model/po/SysWechatCustomerDuty.java
  11. 20 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWeComUserVo.java
  12. 48 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerAddVo.java
  13. 35 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerDeptVo.java
  14. 39 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerDutyRulesVo.java
  15. 19 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerQueryVo.java
  16. 38 0
      src/main/java/com/ydtech/modules/admin/model/vo/wechat/SysWechatCustomerVo.java
  17. 64 0
      src/main/java/com/ydtech/modules/admin/service/SysWechatCustomerBusinessService.java
  18. 35 0
      src/main/java/com/ydtech/modules/admin/service/SysWechatCustomerDutyService.java
  19. 45 0
      src/main/java/com/ydtech/modules/admin/service/SysWechatCustomerService.java
  20. 208 0
      src/main/java/com/ydtech/modules/admin/service/impl/SysWechatCustomerBusinessServiceImpl.java
  21. 39 0
      src/main/java/com/ydtech/modules/admin/service/impl/SysWechatCustomerDutyServiceImpl.java
  22. 90 0
      src/main/java/com/ydtech/modules/admin/service/impl/SysWechatCustomerServiceImpl.java
  23. 55 75
      src/main/java/com/ydtech/utils/DateTimeUtil.java
  24. 18 0
      src/main/resources/mapper/modules/admin/SysWechatCustomerDutyMapper.xml
  25. 40 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, "未获得权限,无法访问。");
     }
 
-
-
-
 }
 

+ 24 - 20
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,35 @@ public class WechatWorkConfig {
         }));
     }
 
-
     @Bean
-    public WxCpKfService wxCpKfService(){
+    public WxCpService wxCpService() {
         WxCpDefaultConfigImpl config = new WxCpDefaultConfigImpl();
         config.setCorpId(corpId);
-        config.setCorpSecret(wechatCustomerProperties.getSecret());
-        config.setToken(wechatCustomerProperties.getToken());
-        config.setAesKey(wechatCustomerProperties.getEncodingAesKey());
+        config.setCorpSecret(secret);
+        config.setAgentId(agentId);
         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;
 }
+
+

+ 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"),

+ 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

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

@@ -0,0 +1,98 @@
+package com.ydtech.modules.admin.controller.wechat;
+
+
+import com.ydtech.core.page.HttpResult;
+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.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);
+    }
+
+    @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("/{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();
+    }
+
+}

+ 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);
+
+}
+
+
+
+

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

@@ -0,0 +1,87 @@
+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.Data;
+
+import java.io.Serializable;
+
+/**
+ * 微信客服
+ *
+ * @TableName sys_wechat_customer
+ */
+@TableName(value = "sys_wechat_customer")
+@Data
+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 = "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.receptionist = sysWechatCustomerAddVo.getReceptionist();
+        this.receptionistId = sysWechatCustomerAddVo.getReceptionistId();
+    }
+
+}

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

@@ -0,0 +1,55 @@
+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.Data;
+
+/**
+ * 微信客服值班时间
+ * @TableName sys_wechat_customer_duty
+ */
+@TableName(value ="sys_wechat_customer_duty")
+@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;
+    }
+}

+ 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;
+
+
+}

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

@@ -0,0 +1,48 @@
+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("接待人企业微信客服")
+    @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());
+    }
+
+}

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

@@ -0,0 +1,39 @@
+package com.ydtech.modules.admin.model.vo.wechat;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+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;
+
+        @ApiModelProperty("值班时间")
+        private String startTime;
+
+        @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;
+
+}

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

@@ -0,0 +1,38 @@
+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;
+
+    @ApiModelProperty("客服昵称")
+    private String nickname;
+
+    @ApiModelProperty("姓名")
+    private String username;
+
+    @ApiModelProperty("工号")
+    private String userId;
+
+    @ApiModelProperty("企微用户")
+    private String receptionist;
+
+    @ApiModelProperty("值班客服")
+    private String dutyCustomer;
+
+    @ApiModelProperty("值班时间")
+    private List<String> dutyDatetime;
+
+}

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

@@ -0,0 +1,64 @@
+package com.ydtech.modules.admin.service;
+
+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;
+
+}

+ 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);
+    }
+
+}

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

@@ -0,0 +1,45 @@
+package com.ydtech.modules.admin.service;
+
+import com.github.pagehelper.PageInfo;
+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;
+
+/**
+ * @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);
+}

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

@@ -0,0 +1,208 @@
+package com.ydtech.modules.admin.service.impl;
+
+import com.github.pagehelper.PageInfo;
+import com.ydtech.exception.SystemException;
+import com.ydtech.modules.admin.model.po.SysWechatCustomer;
+import com.ydtech.modules.admin.model.po.SysWechatCustomerDuty;
+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 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.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.io.File;
+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;
+
+    @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::getId, customer)
+                    .list()
+                    .stream()
+                    .collect(Collectors.groupingBy(SysWechatCustomerDuty::getCustomerId));
+
+            // 设置值班时间
+            sysWechatCustomerVoPageInfo.getList().forEach(sysWechatCustomerVo -> {
+                List<SysWechatCustomerDuty> sysWechatCustomerDuties = dutyMap.get(Long.valueOf(sysWechatCustomerVo.getId()));
+                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 {
+
+        WxCpKfAccountAdd wxCpKfAccountAdd = new WxCpKfAccountAdd();
+        wxCpKfAccountAdd.setName(sysWechatCustomerAddVo.getNickname());
+
+        // 头像
+        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, "客服不存在");
+        WxCpKfAccountDel wxCpKfAccountDel = new WxCpKfAccountDel();
+        wxCpKfAccountDel.setOpenKfid(sysWechatCustomer.getOpenKfId());
+        WxCpBaseResp wxCpBaseResp;
+        wxCpBaseResp = wxCpKfService.delAccount(wxCpKfAccountDel);
+        if (wxCpBaseResp.getErrcode() == 0) {
+            sysWechatCustomerService.deleteAllInfo(customerId);
+        }
+    }
+
+    @Override
+    public void updateWechatCustomer(String customerId, SysWechatCustomerAddVo sysWechatCustomerAddVo) throws WxErrorException {
+        SysWechatCustomer sysWechatCustomer = sysWechatCustomerService.getByIdExist(customerId, "客服不存在");
+        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());
+        }
+
+        // 昵称和头像是否跟换
+        if (isNicknameSame || isAvatarSame) {
+            wxCpKfService.updAccount(wxCpKfAccountUpd);
+        }
+
+        sysWechatCustomer.setNickname(sysWechatCustomerAddVo.getNickname());
+        sysWechatCustomer.setAvatar(sysWechatCustomerAddVo.getAvatar());
+        sysWechatCustomerService.updateById(sysWechatCustomer);
+    }
+}

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

@@ -0,0 +1,39 @@
+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 {
+
+}
+
+
+
+

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

@@ -0,0 +1,90 @@
+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.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.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+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;
+
+    @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()));
+        sysWechatCustomerDutyRulesVo.setDutyCustomerId(String.valueOf(customer.getDutyCustomerId()));
+        List<SysWechatCustomerDutyRulesVo.DutyDateTime> collect = sysWechatCustomerDuties.stream()
+                .map(sysWechatCustomerDuty -> {
+                    SysWechatCustomerDutyRulesVo.DutyDateTime dutyDateTime = new SysWechatCustomerDutyRulesVo.DutyDateTime();
+                    dutyDateTime.setEndTime(DateTimeUtil.getStartTimeOfDayStr(sysWechatCustomerDuty.getEndTime()));
+                    dutyDateTime.setStartTime(DateTimeUtil.getStartTimeOfDayStr(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(), "值班客服不存在");
+        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);
+    }
+
+
+}
+
+
+
+

+ 55 - 75
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();
     }
@@ -261,7 +259,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 +321,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 +449,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 +480,49 @@ 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;
     }
 
-
-
-    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);
-
-
-
+    /**
+     * 格式化时间格式
+     * 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 = localDateTime2.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;
     }
+
 }

+ 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>

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

@@ -0,0 +1,40 @@
+<?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.url as avatar,
+        c.nickname as nickname,
+        u.name as username,
+        u.id as userId,
+        c.receptionist as receptionist,
+        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>
+    </select>
+
+</mapper>