浏览代码

Merge branch 'dev_v1.0.0' into release_v1.0.0
merge

wangliang 1 年之前
父节点
当前提交
2e39886d90
共有 20 个文件被更改,包括 1021 次插入6 次删除
  1. 169 0
      sop-api/src/main/java/com/qmth/sop/server/api/CrmAnalyseController.java
  2. 66 0
      sop-api/src/main/java/com/qmth/sop/server/api/FxxkAsyncController.java
  3. 1 0
      sop-api/src/main/java/com/qmth/sop/server/api/TBCrmController.java
  4. 51 0
      sop-business/src/main/java/com/qmth/sop/business/bean/result/CrmAnalyseResult.java
  5. 22 0
      sop-business/src/main/java/com/qmth/sop/business/bean/result/TBCrmResult.java
  6. 55 0
      sop-business/src/main/java/com/qmth/sop/business/mapper/CrmAnalyseMapper.java
  7. 39 0
      sop-business/src/main/java/com/qmth/sop/business/service/CrmAnalyseService.java
  8. 1 0
      sop-business/src/main/java/com/qmth/sop/business/service/TBCrmService.java
  9. 9 0
      sop-business/src/main/java/com/qmth/sop/business/service/TBUserArchivesAllocationService.java
  10. 83 0
      sop-business/src/main/java/com/qmth/sop/business/service/impl/CrmAnalyseServiceImpl.java
  11. 24 2
      sop-business/src/main/java/com/qmth/sop/business/service/impl/TBCrmServiceImpl.java
  12. 42 2
      sop-business/src/main/java/com/qmth/sop/business/service/impl/TBUserArchivesAllocationServiceImpl.java
  13. 2 2
      sop-business/src/main/java/com/qmth/sop/business/sync/FaceApiUtils.java
  14. 186 0
      sop-business/src/main/java/com/qmth/sop/business/sync/FxxkApiUtils.java
  15. 44 0
      sop-business/src/main/java/com/qmth/sop/business/sync/been/FxxkAppAuthInfo.java
  16. 32 0
      sop-business/src/main/java/com/qmth/sop/business/sync/been/FxxkAppAuthResult.java
  17. 12 0
      sop-business/src/main/java/com/qmth/sop/business/sync/been/FxxkCustomQuery.java
  18. 11 0
      sop-business/src/main/resources/db/log/caozixuan_update_log.sql
  19. 162 0
      sop-business/src/main/resources/mapper/CrmAnalyseMapper.xml
  20. 10 0
      sop-common/src/main/java/com/qmth/sop/common/contant/SystemConstant.java

+ 169 - 0
sop-api/src/main/java/com/qmth/sop/server/api/CrmAnalyseController.java

@@ -0,0 +1,169 @@
+package com.qmth.sop.server.api;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qmth.boot.api.annotation.Aac;
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.sop.business.bean.result.CrmAnalyseResult;
+import com.qmth.sop.business.bean.result.TBCrmResult;
+import com.qmth.sop.business.service.CrmAnalyseService;
+import com.qmth.sop.common.contant.SystemConstant;
+import com.qmth.sop.common.enums.ProductTypeEnum;
+import com.qmth.sop.common.util.Result;
+import com.qmth.sop.common.util.ResultUtil;
+import io.swagger.annotations.*;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 派单分析 控制器
+ *
+ * @author: shudonghui
+ * @date: 2023-08-14 15:55:18
+ * @version: 1.0
+ * @email: shudonghui@qmth.com.cn
+ * @Company: www.qmth.com.cn
+ */
+@Api(tags = "派单分析 Controller")
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + SystemConstant.PREFIX_URL_CRM + "/analyse")
+public class CrmAnalyseController {
+
+
+    @Resource
+    CrmAnalyseService crmAnalyseService;
+
+   
+    @ApiOperation(value = "客户类型分布接口")
+    @RequestMapping(value = "/custom/type", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "客户类型分布", response = Map.class)})
+    public Result customType(@ApiParam(value = "年度", required = true) @RequestParam String year) {
+        Map<String, Object> map = crmAnalyseService.countCustomType(year);
+
+        return ResultUtil.ok(map);
+    }
+
+   
+    @ApiOperation(value = "客户类型分布下钻接口")
+    @RequestMapping(value = "/custom/type/detail", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "客户类型分布下钻", response = TBCrmResult.class)})
+    public Result customTypeDetail(@ApiParam(value = "年度", required = true) @RequestParam String year,
+                                   @ApiParam(value = "客户类型", required = true) @RequestParam ProductTypeEnum type,
+                                   @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                                   @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        IPage<TBCrmResult> resultIPage = crmAnalyseService.customTypeDetail(new Page<>(pageNumber, pageSize), year, type);
+
+        return ResultUtil.ok(resultIPage);
+    }
+
+
+   
+    @ApiOperation(value = "月度派单分布及对比接口")
+    @RequestMapping(value = "/monthly", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "月度派单分布及对比接口", response = Map.class)})
+    public Result monthly(@ApiParam(value = "年度", required = true) @RequestParam String year,
+                          @ApiParam(value = "客户类型", required = true) @RequestParam ProductTypeEnum type) {
+        Map<String, List<Map<String,String>>> map = crmAnalyseService.monthly(year, type);
+        return ResultUtil.ok(map);
+    }
+
+
+   
+    @ApiOperation(value = "月度派单分布下钻接口")
+    @RequestMapping(value = "/monthly/detail", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "月度派单分布下钻", response = TBCrmResult.class)})
+    public Result monthlyDetail(@ApiParam(value = "年度", required = true) @RequestParam String year,
+                                @ApiParam(value = "月份", required = true) @RequestParam String month,
+                                @ApiParam(value = "客户类型", required = true) @RequestParam ProductTypeEnum type,
+                                @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                                @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        IPage<TBCrmResult> resultIPage = crmAnalyseService.monthlyDetail(new Page<>(pageNumber, pageSize), year,month, type);
+
+        return ResultUtil.ok(resultIPage);
+    }
+
+    //供应商派单分布
+   
+    @ApiOperation(value = "供应商派单分布接口")
+    @RequestMapping(value = "/supplier", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "供应商派单分布", response = CrmAnalyseResult.class)})
+    public Result supplier(@ApiParam(value = "年度", required = true) @RequestParam String year) {
+        List<CrmAnalyseResult> list = crmAnalyseService.supplier(year);
+        return ResultUtil.ok(list);
+    }
+
+   
+    @ApiOperation(value = "供应商派单分布下钻接口")
+    @RequestMapping(value = "/supplier/detail", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "供应商派单分布下钻", response = TBCrmResult.class)})
+    public Result supplierDetail(@ApiParam(value = "年度", required = true) @RequestParam String year,
+                                @ApiParam(value = "供应商", required = true) @RequestParam Long supplierId,
+                                @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                                @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        IPage<TBCrmResult> resultIPage = crmAnalyseService.supplierDetail(new Page<>(pageNumber, pageSize), year,supplierId);
+
+        return ResultUtil.ok(resultIPage);
+    }
+    //大区在执行派单排名
+   
+    @ApiOperation(value = "大区在执行派单排名接口")
+    @RequestMapping(value = "/region", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "大区在执行派单排名", response = CrmAnalyseResult.class)})
+    public Result region(@ApiParam(value = "年度", required = true) @RequestParam String year,
+                         @ApiParam(value = "客户类型", required = true) @RequestParam ProductTypeEnum type) {
+        Map<String, List<CrmAnalyseResult>> map = crmAnalyseService.region(year,type);
+        return ResultUtil.ok(map);
+    }
+
+
+    //大区在执行派单排名
+   
+    @ApiOperation(value = "大区在执行派单排名下钻接口")
+    @RequestMapping(value = "/region/detail", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "大区在执行派单排名下钻", response = CrmAnalyseResult.class)})
+    public Result regionDetail(@ApiParam(value = "年度", required = true) @RequestParam String year,
+                         @ApiParam(value = "大区", required = true) @RequestParam Long regionId,
+                         @ApiParam(value = "客户类型", required = true) @RequestParam ProductTypeEnum type,
+                         @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                         @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        IPage<TBCrmResult> resultIPage = crmAnalyseService.regionDetail(new Page<>(pageNumber, pageSize), year,regionId,type);
+
+        return ResultUtil.ok(resultIPage);
+    }
+
+
+    //项目派单完成率
+   
+    @ApiOperation(value = "项目派单完成率接口")
+    @RequestMapping(value = "/project", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "项目派单完成率", response = CrmAnalyseResult.class)})
+    public Result project(@ApiParam(value = "年度", required = true) @RequestParam String year) {
+        List<CrmAnalyseResult> list = crmAnalyseService.project(year);
+        return ResultUtil.ok(list);
+    }
+
+    //项目派单完成率详细
+   
+    @ApiOperation(value = "项目派单完成率详细接口")
+    @RequestMapping(value = "/project/detail", method = RequestMethod.POST)
+    @ApiResponses({@ApiResponse(code = 200, message = "项目派单完成率详细", response = CrmAnalyseResult.class)})
+    public Result projectDetail(@ApiParam(value = "年度", required = true) @RequestParam String year,
+                          @ApiParam(value = "服务单元", required = true) @RequestParam Long serviceId,
+                          @ApiParam(value = "分页页码", required = true) @RequestParam @Min(SystemConstant.PAGE_NUMBER_MIN) Integer pageNumber,
+                          @ApiParam(value = "分页数", required = true) @RequestParam @Min(SystemConstant.PAGE_SIZE_MIN) @Max(SystemConstant.PAGE_SIZE_MAX) Integer pageSize) {
+        IPage<TBCrmResult> resultIPage = crmAnalyseService.projectDetail(new Page<>(pageNumber, pageSize), year,serviceId);
+
+        return ResultUtil.ok(resultIPage);
+    }
+
+
+
+}

+ 66 - 0
sop-api/src/main/java/com/qmth/sop/server/api/FxxkAsyncController.java

@@ -0,0 +1,66 @@
+package com.qmth.sop.server.api;
+
+import com.qmth.boot.api.annotation.Aac;
+import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.sop.business.sync.FxxkApiUtils;
+import com.qmth.sop.business.sync.been.FxxkAppAuthInfo;
+import com.qmth.sop.common.contant.SystemConstant;
+import com.qmth.sop.common.util.Result;
+import com.qmth.sop.common.util.ResultUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * @Description: 分享逍客同步控制器
+ * @Author: CaoZixuan
+ * @Date: 2023-10-28
+ */
+@Api(tags = "纷享销客数据同步 Controller")
+@RestController
+@RequestMapping(ApiConstant.DEFAULT_URI_PREFIX + SystemConstant.PREFIX_URL_FXXK)
+public class FxxkAsyncController {
+    @Resource
+    FxxkApiUtils fxxkApiUtils;
+
+    @ApiOperation(value = "纷享销客数据推送接口(接收)")
+    @ApiResponses({@ApiResponse(code = 200, message = "数据推送接口", response = Object.class)})
+    @RequestMapping(value = "/data/push", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
+    @Aac(auth = false)
+    public Result crmCallBack(@RequestBody String arg) {
+        System.out.println(arg);
+        return ResultUtil.ok();
+    }
+
+    @ApiOperation(value = "纷享销客-获取应用级授权信息")
+    @ApiResponses({@ApiResponse(code = 200, message = "成功", response = FxxkAppAuthInfo.class)})
+    @RequestMapping(value = "/app/auth/info", method = RequestMethod.POST)
+    @Aac(auth = false)
+    public Result findFxxkAppAuthInfo() {
+        return ResultUtil.ok(fxxkApiUtils.findFxxkAppAuthInfo());
+    }
+
+    @ApiOperation(value = "纷享销客-根据手机号获取openUserId")
+    @ApiResponses({@ApiResponse(code = 200, message = "成功", response = String.class)})
+    @RequestMapping(value = "/find/open_user_id", method = RequestMethod.POST)
+    @Aac(auth = false)
+    public Result findCurrentOpenUserId() {
+        return ResultUtil.ok(fxxkApiUtils.findCurrentOpenUserId());
+    }
+
+    @ApiOperation(value = "纷享销客-查询自定义对象列表")
+    @ApiResponses({@ApiResponse(code = 200, message = "成功", response = Result.class)})
+    @RequestMapping(value = "/find/custom_list", method = RequestMethod.POST)
+    @Aac(auth = false)
+    public Result findCustomList() {
+        fxxkApiUtils.findCustomList();
+        return ResultUtil.ok();
+    }
+}

+ 1 - 0
sop-api/src/main/java/com/qmth/sop/server/api/TBCrmController.java

@@ -89,6 +89,7 @@ public class TBCrmController {
 
     //批量划定服务单元
 
+    @Deprecated
     @ApiOperation(value = "批量划定服务单元接口")
     @RequestMapping(value = "/batchZone", method = RequestMethod.POST)
     @ApiResponses({@ApiResponse(code = 200, message = "返回信息", response = Object.class)})

+ 51 - 0
sop-business/src/main/java/com/qmth/sop/business/bean/result/CrmAnalyseResult.java

@@ -0,0 +1,51 @@
+package com.qmth.sop.business.bean.result;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * @Description:
+ * @Param:
+ * @return:
+ * @Author: dhshu
+ */
+public class CrmAnalyseResult implements Serializable {
+
+    @ApiModelProperty(value = "id")
+    @JsonSerialize(using = ToStringSerializer.class)
+    Long id;
+
+    @ApiModelProperty(value = "name")
+    String name;
+
+    @ApiModelProperty(value = "count")
+    String count;
+
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getCount() {
+        return count;
+    }
+
+    public void setCount(String count) {
+        this.count = count;
+    }
+}

+ 22 - 0
sop-business/src/main/java/com/qmth/sop/business/bean/result/TBCrmResult.java

@@ -33,6 +33,12 @@ public class TBCrmResult extends TBCrm implements Serializable {
     @ApiModelProperty(value = "服务单元状态")
     private ServiceStatusEnum serviceUnitStatus;
 
+    @ApiModelProperty(value = "区域协调人")
+    private String regionCoordinator;
+
+    @ApiModelProperty(value = "供应商")
+    private String supplier;
+
     public String getService() {
         return service;
     }
@@ -96,4 +102,20 @@ public class TBCrmResult extends TBCrm implements Serializable {
     public void setServiceUnitStatus(ServiceStatusEnum serviceUnitStatus) {
         this.serviceUnitStatus = serviceUnitStatus;
     }
+
+    public String getRegionCoordinator() {
+        return regionCoordinator;
+    }
+
+    public void setRegionCoordinator(String regionCoordinator) {
+        this.regionCoordinator = regionCoordinator;
+    }
+
+    public String getSupplier() {
+        return supplier;
+    }
+
+    public void setSupplier(String supplier) {
+        this.supplier = supplier;
+    }
 }

+ 55 - 0
sop-business/src/main/java/com/qmth/sop/business/mapper/CrmAnalyseMapper.java

@@ -0,0 +1,55 @@
+package com.qmth.sop.business.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qmth.sop.business.bean.result.CrmAnalyseResult;
+import com.qmth.sop.business.bean.result.TBCrmResult;
+import com.qmth.sop.business.entity.TBCrm;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * </p>
+ *
+ * @author dhshu
+ *
+ */
+public interface CrmAnalyseMapper extends BaseMapper<TBCrm> {
+
+
+    Map<String,Object> countCustomType(@Param("year") String year);
+
+    IPage<TBCrmResult> crmDetail(Page<Object> iPage, @Param("year") String year, @Param("month") String month, @Param("crmYear") String crmYear, @Param("type") String type,@Param("supplierId") Long supplierId,@Param("regionId") Long regionId,@Param("serviceId") Long serviceId);
+
+    default IPage<TBCrmResult> crmDetail(Page<Object> iPage,String year, String type) {
+        return crmDetail(iPage,year,null,null,type,null,null,null);
+    }
+
+    List<Map<String,String>> monthly(@Param("year") String year,@Param("type") String type);
+
+    default IPage<TBCrmResult> crmDetail(Page<Object> iPage, String year, String month, String type) {
+        return crmDetail(iPage,year,month,null,type,null,null,null);
+    }
+
+    List<CrmAnalyseResult> supplier(@Param("year") String year);
+
+    default IPage<TBCrmResult> crmDetail(Page<Object> iPage, String year,  Long supplierId) {
+        return crmDetail(iPage,null,null,year,null,supplierId,null,null);
+    }
+
+    List<CrmAnalyseResult> region(@Param("year") String year, @Param("type") String type);
+
+    default IPage<TBCrmResult> crmDetail(Page<Object> iPage,  String year, Long regionId, String type) {
+        return crmDetail(iPage,year,null,null,type,null,regionId,null);
+    }
+
+    default IPage<TBCrmResult> crmDetail(Page<Object> iPage, Long serviceId, String year) {
+        return crmDetail(iPage,year,null,null,null,null,null,serviceId);
+    }
+
+    List<CrmAnalyseResult> project(@Param("year") String year);
+}

+ 39 - 0
sop-business/src/main/java/com/qmth/sop/business/service/CrmAnalyseService.java

@@ -0,0 +1,39 @@
+package com.qmth.sop.business.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qmth.sop.business.bean.result.TBCrmResult;
+import com.qmth.sop.business.bean.result.CrmAnalyseResult;
+import com.qmth.sop.business.entity.TBCrm;
+import com.qmth.sop.common.enums.ProductTypeEnum;
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * @author dhshu
+ * @date:
+ */
+public interface CrmAnalyseService extends IService<TBCrm> {
+    Map<String,Object> countCustomType(String year);
+
+    IPage<TBCrmResult> customTypeDetail(Page<Object> objectPage, String year, ProductTypeEnum type);
+
+    Map<String, List<Map<String,String>>> monthly(String year, ProductTypeEnum type);
+
+    IPage<TBCrmResult> monthlyDetail(Page<Object> objectPage, String year, String month, ProductTypeEnum type);
+
+    List<CrmAnalyseResult> supplier(String year);
+
+    IPage<TBCrmResult> supplierDetail(Page<Object> objectPage, String year, Long supplierId);
+
+    Map<String, List<CrmAnalyseResult>> region(String year, ProductTypeEnum type);
+
+    IPage<TBCrmResult> regionDetail(Page<Object> objectPage, String year, Long regionId, ProductTypeEnum type);
+
+    List<CrmAnalyseResult> project(String year);
+
+    IPage<TBCrmResult> projectDetail(Page<Object> objectPage, String year, Long serviceId);
+}

+ 1 - 0
sop-business/src/main/java/com/qmth/sop/business/service/TBCrmService.java

@@ -121,6 +121,7 @@ public interface TBCrmService extends IService<TBCrm> {
      */
     Boolean delete(Long id);
 
+    @Deprecated
     boolean batchZone(long serviceId, long[] crmIds);
 
     boolean batchDisable(long[] crmIds);

+ 9 - 0
sop-business/src/main/java/com/qmth/sop/business/service/TBUserArchivesAllocationService.java

@@ -85,4 +85,13 @@ public interface TBUserArchivesAllocationService extends IService<TBUserArchives
      * @param crmNo crmNo
      */
     void unPublishSop(String crmNo);
+
+    /**
+     * 派单重新划定服务单元
+     *
+     * @param crmNo            派单号
+     * @param oldServiceUnitId 划定前派单的服务单元id
+     * @param newServiceUnitId 划定后派单的服务单元id
+     */
+    void crmReBindServiceUnit(String crmNo, Long oldServiceUnitId, Long newServiceUnitId);
 }

+ 83 - 0
sop-business/src/main/java/com/qmth/sop/business/service/impl/CrmAnalyseServiceImpl.java

@@ -0,0 +1,83 @@
+package com.qmth.sop.business.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.sop.business.bean.result.CrmAnalyseResult;
+import com.qmth.sop.business.bean.result.TBCrmResult;
+import com.qmth.sop.business.entity.TBCrm;
+import com.qmth.sop.business.mapper.CrmAnalyseMapper;
+import com.qmth.sop.business.service.CrmAnalyseService;
+import com.qmth.sop.common.enums.ProductTypeEnum;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+
+/**
+ * @author dhshu
+ * @date:
+ */
+@Service
+public class CrmAnalyseServiceImpl extends ServiceImpl<CrmAnalyseMapper, TBCrm> implements CrmAnalyseService {
+
+    @Override
+    public Map<String,Object> countCustomType(String year) {
+        return this.baseMapper.countCustomType(year);
+    }
+
+    @Override
+    public IPage<TBCrmResult> customTypeDetail(Page<Object> iPage, String year, ProductTypeEnum type) {
+        return this.baseMapper.crmDetail(iPage,year, Objects.nonNull(type) ? type.name() : null);
+    }
+
+    @Override
+    public  Map<String, List<Map<String,String>>> monthly(String year, ProductTypeEnum type) {
+        Map<String, List<Map<String,String>>> map=new HashMap<>();
+        map.put("year",this.baseMapper.monthly(year, Objects.nonNull(type) ? type.name() : null));
+        map.put("lastYear",this.baseMapper.monthly(String.valueOf(Integer.parseInt(year)-1), Objects.nonNull(type) ? type.name() : null));
+        return map;
+    }
+
+    @Override
+    public IPage<TBCrmResult> monthlyDetail(Page<Object> iPage, String year, String month, ProductTypeEnum type) {
+        return this.baseMapper.crmDetail(iPage,year,month, Objects.nonNull(type) ? type.name() : null);
+    }
+
+    @Override
+    public List<CrmAnalyseResult> supplier(String year) {
+        return this.baseMapper.supplier(year);
+    }
+
+    @Override
+    public IPage<TBCrmResult> supplierDetail(Page<Object> iPage, String year, Long supplierId) {
+        return this.baseMapper.crmDetail(iPage,year, supplierId);
+    }
+
+    @Override
+    public Map<String,  List<CrmAnalyseResult>> region(String year, ProductTypeEnum type) {
+        Map<String,  List<CrmAnalyseResult>> map=new HashMap<>();
+        map.put("day",this.baseMapper.region(year,Objects.nonNull(type) ? type.name() : null));
+        map.put("lastDay",this.baseMapper.region(String.valueOf(Integer.parseInt(year)-1),Objects.nonNull(type) ? type.name() : null));
+        return map;
+    }
+
+    @Override
+    public IPage<TBCrmResult> regionDetail(Page<Object> iPage, String year, Long regionId, ProductTypeEnum type) {
+        return this.baseMapper.crmDetail(iPage,year,regionId,Objects.nonNull(type) ? type.name() : null);
+    }
+
+    @Override
+    public List<CrmAnalyseResult> project(String year) {
+        return this.baseMapper.project(year);
+    }
+
+    @Override
+    public IPage<TBCrmResult> projectDetail(Page<Object> iPage, String year, Long serviceId) {
+        return this.baseMapper.crmDetail(iPage,serviceId,year);
+    }
+}

+ 24 - 2
sop-business/src/main/java/com/qmth/sop/business/service/impl/TBCrmServiceImpl.java

@@ -99,9 +99,16 @@ public class TBCrmServiceImpl extends ServiceImpl<TBCrmMapper, TBCrm> implements
             }
         }
         List<TBCrm> tbCrmList = this.listByIds(crmIdList);
+        // 派单调配资源变换
+        for (TBCrm dbCrm : tbCrmList) {
+            tbUserArchivesAllocationService.crmReBindServiceUnit(dbCrm.getCrmNo(), dbCrm.getServiceId(), serviceUnitId);
+        }
+
+        // 绑定服务单元
         tbCrmList = tbCrmList.stream().peek(e -> e.setServiceId(serviceUnitId)).collect(Collectors.toList());
         this.updateBatchById(tbCrmList);
 
+        // 自动匹配派单对应的大区经理
         tbCrmList = tbCrmList.stream().peek(e -> {
             Long regionLeaderId = tbServiceRegionService.findRegionLeader(serviceUnitId, e.getCrmNo());
             if (Objects.nonNull(regionLeaderId)) {
@@ -132,6 +139,7 @@ public class TBCrmServiceImpl extends ServiceImpl<TBCrmMapper, TBCrm> implements
                 .set(TBCrm::getLeadId, null)
                 .eq(TBCrm::getId, tbCrm.getId());
         this.update(updateWrapper);
+        tbUserArchivesAllocationService.crmReBindServiceUnit(tbCrm.getCrmNo(), serviceUnitId, null);
     }
 
     @Override
@@ -180,6 +188,7 @@ public class TBCrmServiceImpl extends ServiceImpl<TBCrmMapper, TBCrm> implements
     @Transactional
     public Boolean saveTBCrm(TBCrm tBCrm) {
         try {
+            Long oldServiceUnitId = null;
             tBCrm.setSync(false);
             tBCrm.setEnable(true);
             SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
@@ -187,6 +196,11 @@ public class TBCrmServiceImpl extends ServiceImpl<TBCrmMapper, TBCrm> implements
                 tBCrm.setStatus(CrmStatusEnum.UN_PUBLISH);
                 tBCrm.insertInfo(sysUser.getId());
             } else { // 修改
+                TBCrm dbTBCrm = this.getById(tBCrm.getId());
+                if (Objects.isNull(dbTBCrm)) {
+                    throw ExceptionResultEnum.ERROR.exception("未找到派单信息");
+                }
+                oldServiceUnitId = dbTBCrm.getServiceId();
                 tBCrm.updateInfo(sysUser.getId());
             }
             boolean result = saveOrUpdate(tBCrm);
@@ -194,9 +208,10 @@ public class TBCrmServiceImpl extends ServiceImpl<TBCrmMapper, TBCrm> implements
             if (result && serviceId != null && serviceId > 0) {
                 Long regionLeaderId = tbServiceRegionService.findRegionLeader(serviceId, tBCrm.getCrmNo());
                 UpdateWrapper<TBCrm> updateWrapper = new UpdateWrapper<>();
-                updateWrapper.lambda().eq(TBCrm::getId,tBCrm.getId()).set(TBCrm::getLeadId,regionLeaderId);
+                updateWrapper.lambda().eq(TBCrm::getId, tBCrm.getId()).set(TBCrm::getLeadId, regionLeaderId);
                 this.update(updateWrapper);
             }
+            tbUserArchivesAllocationService.crmReBindServiceUnit(tBCrm.getCrmNo(), oldServiceUnitId, serviceId);
             return result;
         } catch (Exception e) {
             if (e instanceof DuplicateKeyException) {
@@ -247,7 +262,14 @@ public class TBCrmServiceImpl extends ServiceImpl<TBCrmMapper, TBCrm> implements
         //批量修改
         List<Long> crmIdList = Arrays.stream(crmIds).boxed().collect(Collectors.toList());
         List<TBCrm> tbCrmList = this.listByIds(crmIdList);
-        tbCrmList.forEach(e -> e.setEnable(false));
+        for (TBCrm tbCrm : tbCrmList) {
+            Long serviceId = tbCrm.getServiceId();
+            if (serviceId != null && serviceId > 0){
+                throw ExceptionResultEnum.ERROR.exception(String.format("已经划分的派单[%s]不能作废",tbCrm.getCrmNo()));
+            }
+            tbCrm.setEnable(false);
+        }
+
         return this.updateBatchById(tbCrmList);
     }
 

+ 42 - 2
sop-business/src/main/java/com/qmth/sop/business/service/impl/TBUserArchivesAllocationServiceImpl.java

@@ -186,8 +186,8 @@ public class TBUserArchivesAllocationServiceImpl extends ServiceImpl<TBUserArchi
         // 更新区域负责人
         UpdateWrapper<TBCrm> coordinatorUpdateWrapper = new UpdateWrapper<>();
         coordinatorUpdateWrapper.lambda()
-                .set(TBCrm::getRegionCoordinatorId,regionUserId)
-                .eq(TBCrm::getId,tbCrm.getId());
+                .set(TBCrm::getRegionCoordinatorId, regionUserId)
+                .eq(TBCrm::getId, tbCrm.getId());
         tbCrmService.update(coordinatorUpdateWrapper);
 
         // 新增前删除派单关系
@@ -500,6 +500,46 @@ public class TBUserArchivesAllocationServiceImpl extends ServiceImpl<TBUserArchi
         activitiService.flowEnd(crmNo);
     }
 
+    @Transactional
+    @Override
+    public void crmReBindServiceUnit(String crmNo, Long oldServiceUnitId, Long newServiceUnitId) {
+        TBCrm tbCrm = tbCrmService.findByCrmNo(crmNo);
+        if (CrmStatusEnum.PUBLISH.equals(tbCrm.getStatus())) {
+            throw ExceptionResultEnum.ERROR.exception(String.format("已发布的派单[%s]不能重新划分,请先撤销发布", tbCrm.getCrmNo()));
+        }
+
+        if (oldServiceUnitId != null && oldServiceUnitId > 0) {
+            if (newServiceUnitId != null && newServiceUnitId > 0) {
+                // 更新派单分配详情
+                UpdateWrapper<TBUserArchivesAllocation> allocationUpdateWrapper = new UpdateWrapper<>();
+                allocationUpdateWrapper.lambda()
+                        .eq(TBUserArchivesAllocation::getCrmNo, crmNo)
+                        .eq(TBUserArchivesAllocation::getServiceId, oldServiceUnitId)
+                        .set(TBUserArchivesAllocation::getServiceId, newServiceUnitId);
+                this.update(allocationUpdateWrapper);
+            } else {
+                List<TBUserArchivesAllocation> dbAllocationList = this.list(new QueryWrapper<TBUserArchivesAllocation>().lambda()
+                        .eq(TBUserArchivesAllocation::getCrmNo, crmNo)
+                        .eq(TBUserArchivesAllocation::getServiceId, oldServiceUnitId));
+
+                if (CollectionUtils.isNotEmpty(dbAllocationList)) {
+                    // 释放工程师资源
+                    List<Long> archivesIdList = dbAllocationList.stream().map(TBUserArchivesAllocation::getArchivesId).distinct().collect(Collectors.toList());
+                    if (CollectionUtils.isNotEmpty(archivesIdList)) {
+                        UpdateWrapper<TBUserArchives> archivesUpdateWrapper = new UpdateWrapper<>();
+                        archivesUpdateWrapper.lambda()
+                                .in(TBUserArchives::getId, archivesIdList)
+                                .set(TBUserArchives::getStatus, UserArchivesStatusEnum.FREE);
+                        tbUserArchivesService.update(archivesUpdateWrapper);
+                    }
+                    // 删除之前的派单分配详情
+                    this.removeByIds(dbAllocationList.stream().map(TBUserArchivesAllocation::getId).distinct().collect(Collectors.toList()));
+                }
+
+            }
+        }
+    }
+
     /**
      * 处理临时新增的分配名单
      *

+ 2 - 2
sop-business/src/main/java/com/qmth/sop/business/sync/FaceApiUtils.java

@@ -8,7 +8,7 @@ import com.qmth.sop.common.contant.SystemConstant;
 import com.qmth.sop.common.enums.ExceptionResultEnum;
 import com.qmth.sop.common.util.FileUtil;
 import com.qmth.sop.common.util.HttpUtil;
-import org.springframework.stereotype.Service;
+import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
 import java.io.File;
@@ -23,7 +23,7 @@ import java.util.List;
  * @Author: CaoZixuan
  * @Date: 2023-09-14
  */
-@Service
+@Component
 public class FaceApiUtils {
     @Resource
     private SysConfigService sysConfigService;

+ 186 - 0
sop-business/src/main/java/com/qmth/sop/business/sync/FxxkApiUtils.java

@@ -0,0 +1,186 @@
+package com.qmth.sop.business.sync;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.qmth.sop.business.service.SysConfigService;
+import com.qmth.sop.business.sync.been.FxxkAppAuthInfo;
+import com.qmth.sop.business.sync.been.FxxkAppAuthResult;
+import com.qmth.sop.common.contant.SystemConstant;
+import com.qmth.sop.common.enums.ExceptionResultEnum;
+import com.qmth.sop.common.util.HttpUtil;
+import com.qmth.sop.common.util.JacksonUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+/**
+ * @Description: 纷享销客开放接口工具类
+ * @Author: CaoZixuan
+ * @Date: 2023-10-10
+ */
+@Component
+public class FxxkApiUtils {
+    @Resource
+    private SysConfigService sysConfigService;
+
+    private static final Logger log = LoggerFactory.getLogger(FxxkApiUtils.class);
+
+    /**
+     * 查询纷享销客应用级授权
+     *
+     * @return 应用级授权信息
+     */
+    public FxxkAppAuthInfo findFxxkAppAuthInfo() {
+        String appId = sysConfigService.findByConfigKey(SystemConstant.FXXK_APP_ID).getConfigValue();
+        String appSecret = sysConfigService.findByConfigKey(SystemConstant.FXXK_APP_SECRET).getConfigValue();
+        String permanentCode = sysConfigService.findByConfigKey(SystemConstant.FXXK_PERMANENT_CODE).getConfigValue();
+        String postUrl = sysConfigService.findByConfigKey(SystemConstant.FXXK_APP_AUTH_URL).getConfigValue();
+        try {
+            Map<String, Object> map = new HashMap<>();
+            map.put("appId", validParam(appId, null, true, "纷享销客AppID"));
+            map.put("appSecret", validParam(appSecret, null, true, "纷享销客APPSecret"));
+            map.put("permanentCode", validParam(permanentCode, null, true, "纷享销客永久授权码"));
+            String requestJson = JacksonUtil.parseJson(map);
+
+            String result = HttpUtil.postJson(postUrl, requestJson, null, null, false);
+            FxxkAppAuthResult fxxkAppAuthResult = JSONObject.parseObject(result, FxxkAppAuthResult.class);
+            if (Objects.isNull(fxxkAppAuthResult) || fxxkAppAuthResult.getErrorCode() != 0) {
+                throw ExceptionResultEnum.ERROR.exception("获取纷享销客应用级授权信息失败 : " + fxxkAppAuthResult.getErrorMessage());
+            }
+            FxxkAppAuthInfo fxxkAppAuthInfo = new FxxkAppAuthInfo();
+            fxxkAppAuthInfo.setCorpId(fxxkAppAuthResult.getCorpId());
+            fxxkAppAuthInfo.setCorpAccessToken(fxxkAppAuthResult.getCorpAccessToken());
+            fxxkAppAuthInfo.setExpiresIn(fxxkAppAuthResult.getExpiresIn());
+            return fxxkAppAuthInfo;
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+        }
+    }
+
+    /**
+     * 获取当前登录人openUserId
+     *
+     * @return currentOpenUserId
+     */
+    public String findCurrentOpenUserId() {
+        final String mobile = "18903719928";
+        String postUrl = sysConfigService.findByConfigKey(SystemConstant.FXXK_USER_BY_MOBILE_URL).getConfigValue();
+
+        try {
+            FxxkAppAuthInfo fxxkAppAuthInfo = this.findFxxkAppAuthInfo();
+            String corpAccessToken = fxxkAppAuthInfo.getCorpAccessToken();
+            String corpId = fxxkAppAuthInfo.getCorpId();
+
+            Map<String, Object> map = new HashMap<>();
+            map.put("corpAccessToken", validParam(corpAccessToken, null, true, "企业应用访问公司合法性凭证"));
+            map.put("corpId", validParam(corpId, null, true, "开放平台公司帐号"));
+            map.put("mobile", validParam(mobile, null, true, "员工手机号"));
+            String requestJson = JacksonUtil.parseJson(map);
+
+            String result = HttpUtil.postJson(postUrl, requestJson, null, null, false);
+            JSONObject jsonObject = JSONObject.parseObject(result);
+            Long errorCode = jsonObject.getLong("errorCode");
+            String errorMessage = jsonObject.getString("errorMessage");
+            if (errorCode != 0) {
+                throw ExceptionResultEnum.ERROR.exception("获取员工信息失败 : " + errorMessage);
+            }
+            JSONArray empList = jsonObject.getJSONArray("empList");
+            JSONObject emp = empList.getJSONObject(0);
+            return emp.getString("openUserId");
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+        }
+    }
+
+    /**
+     * 查询自定义对象列表
+     */
+    public void findCustomList() {
+        String currentOpenUserId = sysConfigService.findByConfigKey(SystemConstant.FXXK_CURRENT_OPEN_USER_ID).getConfigValue();
+        String postUrl = sysConfigService.findByConfigKey(SystemConstant.FXXK_CUSTOM_QUERY_URL).getConfigValue();
+        try {
+            FxxkAppAuthInfo fxxkAppAuthInfo = this.findFxxkAppAuthInfo();
+            String corpAccessToken = fxxkAppAuthInfo.getCorpAccessToken();
+            String corpId = fxxkAppAuthInfo.getCorpId();
+
+            Map<String, Object> map = new HashMap<>();
+            map.put("corpAccessToken", validParam(corpAccessToken, null, true, "企业应用访问公司合法性凭证"));
+            map.put("corpId", validParam(corpId, null, true, "开放平台公司帐号"));
+            map.put("currentOpenUserId", validParam(currentOpenUserId, null, true, "当前操作人OpenUserID"));
+
+            Map<String, Object> dataMap = new HashMap<>();
+            dataMap.put("dataObjectApiName", sysConfigService.findByConfigKey(SystemConstant.FXXK_API_NAME_CRM).getConfigValue());
+
+            Map<String, Object> queryMap = new HashMap<>();
+            queryMap.put("offset", 0.0);
+            queryMap.put("limit", 2.0);
+            queryMap.put("filters", new ArrayList<>());
+
+            dataMap.put("search_query_info", queryMap);
+            map.put("data", dataMap);
+
+            String requestJson = JacksonUtil.parseJson(map);
+
+            String result = HttpUtil.postJson(postUrl, requestJson, null, null, false);
+            JSONObject jsonObject = JSONObject.parseObject(result);
+            Long errorCode = jsonObject.getLong("errorCode");
+            String errorMessage = jsonObject.getString("errorMessage");
+            if (errorCode != 0) {
+                throw ExceptionResultEnum.ERROR.exception("获取自定义对象列表失败 : " + errorMessage);
+            }
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+        }
+    }
+
+
+    /**
+     * 校验参数值并返回(字符型)
+     *
+     * @param value        参数值
+     * @param defaultValue 默认值
+     * @param require      是否必填(true:是,false:否)
+     * @param name         参数名称
+     */
+    private String validParam(String value, String defaultValue, boolean require, String name) {
+        if (require && StringUtils.isAllBlank(value, defaultValue)) {
+            throw ExceptionResultEnum.ERROR.exception((StringUtils.isBlank(name) ? "" : name) + "值必填");
+        }
+        return StringUtils.isBlank(value) ? defaultValue : value;
+
+    }
+
+    /**
+     * 校验参数值并返回(Long型)
+     *
+     * @param value        参数值
+     * @param defaultValue 默认值
+     * @param require      是否必填(true:是,false:否)
+     * @param name         参数名称
+     */
+    private Long validParam(Long value, Long defaultValue, boolean require, String name) {
+        if (require && Objects.isNull(value) && Objects.isNull(defaultValue)) {
+            throw ExceptionResultEnum.ERROR.exception((StringUtils.isBlank(name) ? "" : name) + "值必填");
+        }
+        return Objects.isNull(value) ? defaultValue : value;
+    }
+
+    /**
+     * 校验参数值并返回 (布尔型)
+     *
+     * @param value        参数值
+     * @param defaultValue 默认值
+     * @param require      是否必填
+     * @param name         描述
+     */
+    private Boolean validParam(Boolean value, Boolean defaultValue, Boolean require, String name) {
+        if (require && value == null && defaultValue == null) {
+            throw ExceptionResultEnum.ERROR.exception((StringUtils.isBlank(name) ? "" : name) + "值必填");
+        }
+        return value == null ? defaultValue : value;
+    }
+}

+ 44 - 0
sop-business/src/main/java/com/qmth/sop/business/sync/been/FxxkAppAuthInfo.java

@@ -0,0 +1,44 @@
+package com.qmth.sop.business.sync.been;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description: 纷享销客应用级授权信息
+ * @Author: CaoZixuan
+ * @Date: 2023-10-10
+ */
+public class FxxkAppAuthInfo {
+    @ApiModelProperty("企业应用访问公司合法性凭证")
+    private String corpAccessToken;
+
+    @ApiModelProperty("开放平台派发的公司帐号")
+    private String corpId;
+
+    // 企业应用访问公司合法性凭证的过期时间,单位为秒,取值在0~7200之间,在过期时间在0-6600之间请求该接口会返回相同的corpAccessToken,在6600-7200之间请求该接口会返回新的token,如果要续期token,则需要在该时刻进行请求。
+    @ApiModelProperty("过期时间")
+    private Long expiresIn;
+
+    public String getCorpAccessToken() {
+        return corpAccessToken;
+    }
+
+    public void setCorpAccessToken(String corpAccessToken) {
+        this.corpAccessToken = corpAccessToken;
+    }
+
+    public String getCorpId() {
+        return corpId;
+    }
+
+    public void setCorpId(String corpId) {
+        this.corpId = corpId;
+    }
+
+    public Long getExpiresIn() {
+        return expiresIn;
+    }
+
+    public void setExpiresIn(Long expiresIn) {
+        this.expiresIn = expiresIn;
+    }
+}

+ 32 - 0
sop-business/src/main/java/com/qmth/sop/business/sync/been/FxxkAppAuthResult.java

@@ -0,0 +1,32 @@
+package com.qmth.sop.business.sync.been;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description: 纷享销客应用级授权信息查询结果
+ * @Author: CaoZixuan
+ * @Date: 2023-10-10
+ */
+public class FxxkAppAuthResult extends FxxkAppAuthInfo{
+    @ApiModelProperty("返回码")
+    private Long errorCode;
+
+    @ApiModelProperty("对返回码的文本描述内容")
+    private String errorMessage;
+
+    public Long getErrorCode() {
+        return errorCode;
+    }
+
+    public void setErrorCode(Long errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+}

+ 12 - 0
sop-business/src/main/java/com/qmth/sop/business/sync/been/FxxkCustomQuery.java

@@ -0,0 +1,12 @@
+package com.qmth.sop.business.sync.been;
+
+/**
+ * @Description: 纷享销客自定义对象查询条件构造器
+ * @Author: CaoZixuan
+ * @Date: 2023-10-10
+ */
+public class FxxkCustomQuery {
+    private Integer limit;
+    private Integer offer;
+
+}

+ 11 - 0
sop-business/src/main/resources/db/log/caozixuan_update_log.sql

@@ -330,3 +330,14 @@ ALTER TABLE t_b_user_archives
 
 INSERT INTO sys_privilege (id, name, url, type, parent_id, sequence, property, enable, default_auth, front_display) VALUES ('2051', '人员档案管理-作废', '/api/admin/user/archives/cancel', 'URL', '33', '7', 'AUTH', '1', '1', '0');
 UPDATE sys_privilege SET related = '2051' WHERE (id = '159');
+
+-- 2023-10-10
+INSERT INTO sys_config (id, config_key, config_name, config_value, enable, sort, create_id) VALUES ('39', 'fxxk.app.id', '纷享销客AppID', 'FSAID_131c93b', '1', '1', '1');
+INSERT INTO sys_config (id, config_key, config_name, config_value, enable, sort, create_id) VALUES ('40', 'fxxk.app.secrete', '纷享销客APPSecret', '5d590b10cca24ce5a51fc716564aac9f', '1', '1', '1');
+INSERT INTO sys_config (id, config_key, config_name, config_value, enable, sort, create_id) VALUES ('41', 'fxxk.permanent.code', '纷享销客永久授权码', '4EFBD3FCF655B4D934C163EA5ECE638D', '1', '1', '1');
+INSERT INTO sys_config (id, config_key, config_name, config_value, enable, sort, create_id) VALUES ('42', 'fxxk.curren.open.user.id', '纷享销客当前操作人OpenUserID', 'FSUID_AE9192D544DCF7924E88E9EA800641C7', '1', '1', '1');
+INSERT INTO sys_config (id, config_key, config_name, config_value, enable, sort, create_id) VALUES ('43', 'fxxk.api.name.crm', '纷享销客项目派单apiName', 'object_zS8me__c', '1', '1', '1');
+INSERT INTO sys_config (id, config_key, config_name, config_value, enable, sort, create_id) VALUES ('44', 'fxxk.api.name.crm.detail', '纷享销客项目派单明细apiName', 'object_bs553__c', '1', '1', '1');
+INSERT INTO sys_config (id, config_key, config_name, config_value, enable, sort, create_id) VALUES ('45', 'fxxk.app.auth.url', '纷享销客应用级授权接口', 'https://open.fxiaoke.com/cgi/corpAccessToken/get/V2', '1', '1', '1');
+INSERT INTO sys_config (id, config_key, config_name, config_value, enable, sort, create_id) VALUES ('46', 'fxxk.user.by.mobile.url', '纷享销客根据手机号查询员工接口', 'https://open.fxiaoke.com/cgi/user/getByMobile', '1', '1', '1');
+INSERT INTO sys_config (id, config_key, config_name, config_value, enable, sort, create_id) VALUES ('47', 'fxxk.custom.query.url', '纷享销客查询自定义对象接口', 'https://openfxiaokecom/cgi/crm/custom/v2/data/query', '1', '1', '1');

+ 162 - 0
sop-business/src/main/resources/mapper/CrmAnalyseMapper.xml

@@ -0,0 +1,162 @@
+<?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.qmth.sop.business.mapper.CrmAnalyseMapper">
+    <select id="region" resultType="com.qmth.sop.business.bean.result.CrmAnalyseResult">
+        SELECT
+        r.id,
+        d.province name,
+        count( c.id ) count
+        FROM
+        t_b_crm c
+        LEFT JOIN sys_custom cu ON cu.id = c.custom_id
+        LEFT JOIN t_b_service s ON c.service_id = s.id
+        left join t_b_service_region r on r.service_id=s.id
+        left join t_b_service_region_detail d on d.service_region_id=r.id
+        <where>
+            and s.`status`='PUBLISH' and c.service_id is not null and r.id is not null
+            <if test="type != null and type != ''">
+                and cu.type = #{type}
+            </if>
+            <if test="year != null and year != ''">
+                and YEAR ( FROM_UNIXTIME( s.start_time / 1000 ))=  #{year}
+            </if>
+        </where>
+        GROUP BY
+        r.id,
+        d.province
+        order by count( c.id )
+    </select>
+    <select id="project" resultType="com.qmth.sop.business.bean.result.CrmAnalyseResult">
+        SELECT
+        s.id,
+        s.`name`,
+        sum(case when c.`status`='FINISH' then 1 else 0 end)/count( c.id )  count
+        FROM
+        t_b_crm c
+        LEFT JOIN sys_custom cu ON cu.id = c.custom_id
+        LEFT JOIN t_b_service s ON c.service_id = s.id
+        <where>
+            s.`status` IN ( 'PUBLISH', 'FINISH' )
+            <if test="year != null and year != ''">
+                and YEAR ( FROM_UNIXTIME( s.start_time / 1000 ))=  #{year}
+            </if>
+        </where>
+        GROUP BY
+        s.id,
+        s.`name`
+    </select>
+
+    <select id="supplier" resultType="com.qmth.sop.business.bean.result.CrmAnalyseResult">
+        SELECT
+        su.id,
+        su.`name`,
+        count( c.id ) count
+        FROM
+        t_b_crm c
+        LEFT JOIN t_b_service s ON c.service_id = s.id
+        LEFT JOIN sys_user u ON u.id = c.region_coordinator_id
+        LEFT JOIN t_b_user_archives ua ON u.mobile_number = ua.mobile_number
+        LEFT JOIN t_b_user_archives_supplier us ON us.user_archives_id = ua.id
+        LEFT JOIN sys_supplier su ON su.id = us.supplier_id
+        <where>
+            and c.region_coordinator_id IS NOT NULL
+            <if test="year != null and year != ''">
+                and YEAR ( FROM_UNIXTIME( s.start_time / 1000 ))=  #{year}
+            </if>
+        </where>
+        GROUP BY
+        su.id,
+        su.`name`
+
+    </select>
+
+    <select id="monthly" resultType="java.util.Map">
+        SELECT MONTH ( FROM_UNIXTIME( s.start_time / 1000 )) month,
+        count( c.id ) count
+        FROM
+        t_b_crm c
+        LEFT JOIN t_b_service s ON c.service_id = s.id
+        LEFT JOIN sys_custom cu ON cu.id = c.custom_id
+        <where>
+            <if test="type != null and type != ''">
+                and cu.type = #{type}
+            </if>
+
+            <if test="year != null and year != ''">
+                and YEAR ( FROM_UNIXTIME( s.start_time / 1000 ))=  #{year}
+            </if>
+
+        </where>
+        GROUP BY MONTH ( FROM_UNIXTIME( s.start_time / 1000 ))
+        order BY MONTH ( FROM_UNIXTIME( s.start_time / 1000 ))
+    </select>
+
+
+    <select id="countCustomType" resultType="java.util.Map">
+        SELECT
+        sum(case when cu.type='OFFICE' then 1 else 0 end) as OFFICE,
+        sum(case when cu.type='CLOUD_MARK' then 1 else 0 end) as CLOUD_MARK
+        FROM
+        t_b_crm c
+        LEFT JOIN t_b_service s ON c.service_id = s.id
+        LEFT join sys_custom cu on cu.id=c.custom_id
+        WHERE
+        YEAR ( FROM_UNIXTIME( s.start_time / 1000 ))=  #{year}
+    </select>
+
+
+    <select id="crmDetail" resultType="com.qmth.sop.business.bean.result.TBCrmResult">
+        SELECT
+        a.*,
+        tbs.name service,
+        cru.real_name crm_user_name,
+        sc.NAME custom,
+        sc.type custom_type,
+        p.name product,
+        lu.real_name leadName,
+        cu.real_name createName,
+        tbs.status serviceUnitStatus,
+        u.real_name regionCoordinator,
+        su.name supplier
+        FROM
+        t_b_crm a
+        LEFT JOIN sys_user cru ON cru.id = a.crm_user_id
+        LEFT JOIN sys_user lu ON lu.id = a.lead_id
+        LEFT JOIN sys_user cu ON cu.id = a.create_id
+        LEFT JOIN t_b_product p ON p.id = a.product_id
+        LEFT JOIN t_b_service tbs ON a.service_id = tbs.id
+        left join t_b_service_region r on r.service_id=tbs.id
+        LEFT JOIN sys_custom sc ON sc.id = a.custom_id
+
+        LEFT JOIN sys_user u ON u.id = a.region_coordinator_id
+        LEFT JOIN t_b_user_archives ua ON u.mobile_number = ua.mobile_number
+        LEFT JOIN t_b_user_archives_supplier us ON us.user_archives_id = ua.id
+        LEFT JOIN sys_supplier su ON su.id = us.supplier_id
+        <where>
+            <if test="serviceId != null and serviceId != ''">
+                and a.service_id = #{serviceId}
+            </if>
+            <if test="regionId != null and regionId != ''">
+                and r.id = #{regionId}
+            </if>
+            <if test="type != null and type != ''">
+                and sc.type = #{type}
+            </if>
+            <if test="supplierId != null and supplierId != ''">
+                and su.id = #{supplierId}
+            </if>
+            <if test="year != null and year != ''">
+                and YEAR ( FROM_UNIXTIME( tbs.start_time / 1000 ))=  #{year}
+            </if>
+            <if test="crmYear != null and crmYear != ''">
+                and YEAR ( FROM_UNIXTIME( a.begin_time / 1000 ))=  #{crmYear}
+            </if>
+            <if test="month != null and month != ''">
+                and MONTH ( FROM_UNIXTIME( tbs.start_time / 1000 ))=  #{month}
+            </if>
+        </where>
+
+        ORDER BY
+        a.create_time DESC
+    </select>
+</mapper>

+ 10 - 0
sop-common/src/main/java/com/qmth/sop/common/contant/SystemConstant.java

@@ -205,6 +205,16 @@ public class SystemConstant {
     public static final String FACE_VERIFY_BAIDU_LOCAL_URL_PREFIX = "face.verify.baiduLocalUrlPrefix";
     public static final String BAIDU_FACE_COMPARE_URL = "baidu.face.compare.url";
     public static final String BAIDU_FACE_COMPARE_SCORE = "baidu.face.compare.score";
+    public static final String FXXK_APP_ID = "fxxk.app.id";
+    public static final String FXXK_APP_SECRET = "fxxk.app.secret";
+    public static final String FXXK_PERMANENT_CODE = "fxxk.permanent.code";
+    public static final String FXXK_CURRENT_OPEN_USER_ID = "fxxk.curren.open.user.id";
+    public static final String FXXK_API_NAME_CRM = "fxxk.api.name.crm";
+    public static final String FXXK_API_NAME_CRM_DETAIL = "fxxk.api.name.crm.detail";
+    public static final String FXXK_APP_AUTH_URL = "fxxk.app.auth.url";
+    public static final String FXXK_USER_BY_MOBILE_URL = "fxxk.user.by.mobile.url";
+    public static final String FXXK_CUSTOM_QUERY_URL = "fxxk.custom.query.url";
+
 
     /**
      * api前缀