Browse Source

CRM系统升级优化

kaick 1 year ago
parent
commit
83f25e63ba

+ 5 - 1
pom.xml

@@ -154,7 +154,11 @@
             <version>3.0.0</version>
         </dependency>
 
-
+        <dependency>
+            <groupId>com.github.tobato</groupId>
+            <artifactId>fastdfs-client</artifactId>
+            <version>1.27.2</version>
+        </dependency>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-test</artifactId>

+ 60 - 4
src/main/java/com/caimei365/user/components/WeChatService.java

@@ -5,7 +5,9 @@ import cn.hutool.http.HttpUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.caimei365.user.model.ResponseJson;
+import com.caimei365.user.utils.FastDfsUtil;
 import com.caimei365.user.utils.RequestUtil;
+import com.sun.org.apache.regexp.internal.RE;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.lang.StringUtils;
@@ -14,18 +16,19 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.HttpHeaders;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.Resource;
 import javax.crypto.Cipher;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.net.URLDecoder;
 import java.security.AlgorithmParameters;
 import java.security.Security;
 import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.*;
 
 /**
  * 微信 服务工具类
@@ -59,6 +62,11 @@ public class WeChatService {
     private String mcareAppId;
     @Value("${wx.mcare-app-secret}")
     private String mcareAppSecret;
+    @Value("${spring.cloud.config.profile}")
+    private String active;
+    @Resource
+    private FastDfsUtil fastDfsUtil;
+
 
     public void setRedirectUri(String redirectUri) {
         redirectUri = redirectUri;
@@ -638,5 +646,53 @@ public class WeChatService {
         return ResponseJson.success(result);
     }
 
+    /**
+     * 根据accessToken生成小程序二维码
+     */
+    public ResponseJson<String> generateWxacode(String access_token,String params) throws Exception {
+        String requestUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + access_token;
+        ByteArrayInputStream inputStream = RequestUtil.sendPost(requestUrl, params);
+        try {
+            String fileUrl = null;
+            String url = saveFile(inputStream);
+            fileUrl = "https://img-b.caimei365.com" + "/" + url;
+            log.info("【图片上传】>>>>>>>>>>>>>>>>上传成功:" + fileUrl);
+            return ResponseJson.success(fileUrl);
+        } catch (IOException e) {
+            log.error("【图片上传】>>>>>>>>>>>>>>>>上传失败:" + e);
+            return ResponseJson.error("图片上传失败", null);
+        }
+    }
 
+
+    /**
+     * 保存文件到FastDFS
+     */
+    private String saveFile(ByteArrayInputStream inputStream) throws IOException {
+        String randomStr = UUID.randomUUID().toString();
+        String name = ".jpeg";
+        // 图片暂存本地服务器路径
+        String filePath = "/mnt/newdatadrive/data/runtime/jar-instance/mall2c/tempImage/";
+        if ("dev".equals(active)){
+            filePath = "D:\\";
+        }
+        filePath += randomStr + name;
+        FileOutputStream outputStream = new FileOutputStream(filePath);
+        int i = 0;
+        byte[] buffer = new byte[200];
+        while ((i = inputStream.read(buffer)) != -1) {
+            outputStream.write(buffer, 0, i);
+        }
+        outputStream.flush();
+        outputStream.close();
+        inputStream.close();
+        // 临时图片
+        File tempFile = new File(filePath);
+        log.info("【图片上传】>>>>>>>>>>>>>>>>图片临时路径:" + filePath);
+        String fileUrl = fastDfsUtil.uploadFile(filePath);
+        // 删除临时图片
+        boolean delete = tempFile.delete();
+        log.info("【图片上传】>>>>>>>>>>>>>>>>删除临时图片:" + delete);
+        return fileUrl;
+    }
 }

+ 7 - 0
src/main/java/com/caimei365/user/controller/BaseApi.java

@@ -251,6 +251,13 @@ public class BaseApi {
     public ResponseJson getWechatLink(String path, String query, String env) {
         return weChatService.getOpenLink(path, query, env);
     }
+    @ApiOperation("获取小程序二维码图片")
+    @PostMapping("/wxacode")
+    public ResponseJson<String> generateWxacode(@RequestBody String params) throws Exception {
+        String accessToken = weChatService.getAccessToken();
+        ResponseJson<String> result = weChatService.generateWxacode(accessToken, params);
+        return result;
+    }
     @ApiOperation("获取Dict")
     @GetMapping("/getDict")
     public ResponseJson getDict(String type) {

+ 32 - 0
src/main/java/com/caimei365/user/controller/SellerApi.java

@@ -8,6 +8,7 @@ import com.caimei365.user.model.vo.ClubTemporaryVo;
 import com.caimei365.user.model.vo.ClubVo;
 import com.caimei365.user.model.vo.ServiceProviderVo;
 import com.caimei365.user.service.SellerService;
+import com.caimei365.user.utils.MathUtil;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
@@ -17,6 +18,9 @@ import lombok.RequiredArgsConstructor;
 import org.apache.commons.lang.StringUtils;
 import org.springframework.web.bind.annotation.*;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -106,6 +110,34 @@ public class SellerApi {
         return sellerService.getClubList(spId, status, type, name, userIdentity, groupServiceId, pageNum, pageSize);
     }
 
+    /**
+     * 机构活跃分析
+     * 原spi的 /seller/club/list
+     *
+     * @param spId           协销Id
+     * @param status         机构状态
+     * @param type           1.我的机构2.组员机构3.待分配机构
+     * @param name           机构名字关键字(搜索用)
+     */
+    @ApiOperation("机构活跃分析列表")
+    @GetMapping("/club/livelyClubList")
+    public ResponseJson<Map<String, Object>> getLivelyClubList(Integer spId,
+                                                                         Integer status,
+                                                                         Integer type,
+                                                                         String name,
+                                                                         Integer userIdentity,
+                                                                         @RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
+                                                                         @RequestParam(value = "pageSize", defaultValue = "10") int pageSize) {
+        if (null == spId || null == status || null == type) {
+            return ResponseJson.error("spId 或 status 或 type 参数不全!", null);
+        }
+        if (4 != type || 5 != type ) {
+            return ResponseJson.error("type 参数错误!", null);
+        }
+
+        return sellerService.getLivelyClubList(spId, status, type, name, userIdentity, pageNum, pageSize);
+    }
+
     @ApiOperation("组员筛选侧边栏")
     @GetMapping("/service/team")
     public ResponseJson<List<ServiceProviderVo>> getClubList(Integer spId) {

+ 2 - 0
src/main/java/com/caimei365/user/mapper/ClubMapper.java

@@ -380,4 +380,6 @@ public interface ClubMapper {
     void inProvider(@Param("spId") Integer spId, @Param("clubId") Integer clubId, @Param("operator") String operator, @Param("isOneself") Integer isOneself );
 
     Integer getSpIdRAND();
+
+    Integer getSpUserId(@Param("spId") Integer spId);
 }

+ 11 - 1
src/main/java/com/caimei365/user/mapper/SellerMapper.java

@@ -10,6 +10,7 @@ import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * Description
@@ -59,7 +60,16 @@ public interface SellerMapper {
      */
     void deleteTemporaryClub(Integer id);
 
-    List<ClubVo> findClubs(@Param("serviceProviderId") Integer serviceProviderId, @Param("status") Integer status, @Param("name") String name, @Param("userIdentity") Integer userIdentity,@Param("type") Integer type,@Param("serviceIds") List<Integer> serviceIds);
+    List<ClubVo> findClubs(@Param("serviceProviderId") Integer serviceProviderId, @Param("status") Integer status, @Param("name") String name, @Param("userIdentity") Integer userIdentity, @Param("type") Integer type, @Param("serviceIds") List<Integer> serviceIds);
+
+    /***
+     * 功能描述: 机构活跃分析用户登录数量
+     * @auther: Kaick
+     * @date: 2023/8/30 15:25
+     * @param spID
+     * @return [spID]
+     */
+    Map<String, Object> findSpUserLoginSum(@Param("spID") String spID);
 
     Integer findOrderNum(ClubVo club);
 

+ 5 - 0
src/main/java/com/caimei365/user/model/vo/ClubVo.java

@@ -200,4 +200,9 @@ public class ClubVo implements Serializable {
      */
     private String ipAddress;
 
+    /***
+     * 分配时间:
+     */
+    private Date providerTime;
+
 }

+ 15 - 0
src/main/java/com/caimei365/user/service/SellerService.java

@@ -11,6 +11,7 @@ import com.caimei365.user.model.vo.UserLoginVo;
 import com.github.pagehelper.PageInfo;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * Description
@@ -29,7 +30,21 @@ public interface SellerService {
      * @return
      */
     ResponseJson<PageInfo<ClubVo>> getClubList(Integer serviceProviderId, Integer status, Integer type, String name, Integer userIdentity, Integer groupServiceId, Integer pageNum, Integer pageSize);
+/**
+ * 功能描述: 机构活跃分析
+ * @auther: Kaick
+ * @date: 2023/8/30 16:54
+ * @param serviceProviderId
+ * @param status
+ * @param type
+ * @param name
+ * @param userIdentity
+ * @param pageNum
+ * @param pageSize
+ * @return [serviceProviderId, status, type, name, userIdentity, pageNum, pageSize]
+ */
 
+    ResponseJson<Map<String, Object>> getLivelyClubList(Integer serviceProviderId, Integer status, Integer type, String name, Integer userIdentity, Integer pageNum, Integer pageSize);
     /**
      * 协销登录(手机号,密码)
      *

+ 10 - 0
src/main/java/com/caimei365/user/service/impl/RegisterServiceImpl.java

@@ -278,6 +278,16 @@ public class RegisterServiceImpl implements RegisterService {
         // 添加机构协销记录
         if (StringUtils.isNotBlank(club.getLinkMan())) {
             clubMapper.inProvider(spId, club.getClubId(), spId!=1342?"系统自动分配":club.getLinkMan(), 0);
+            if(spId!=1342){
+                //短信
+                String spMessage = "【采美365】系统已为你分配机构客户,请及时跟进。机构名称【"+user.getUserName()+"】,联系人【"+user.getUserName()+"】,手机号【"+user.getBindMobile()+"】。微信小程序https://....com,退订回T。";
+                String mobile = vipMapper.findMobile(clubMapper.getSpUserId(spId));
+                String clubMessage = "【采美365】采美平台已为您提供专属客户经理,为您提供专业服务。客户经理【"+clubMapper.selSpName(spId)+"】,手机号【"+mobile+"】。微信小程序https://....com,退订回T。";
+                if (mobile != null && mobile != "") {
+                    remoteCallService.remoteSendSms(25, 1, mobile, spMessage);
+                    remoteCallService.remoteSendSms(25, 1, user.getBindMobile(), clubMessage);
+                }
+            }
         }
         //推送信息中心-账户通知
         MessageCenter messageCenter = new MessageCenter();

+ 34 - 1
src/main/java/com/caimei365/user/service/impl/SellerServiceImpl.java

@@ -13,6 +13,7 @@ import com.caimei365.user.model.po.SuperVipPo;
 import com.caimei365.user.model.vo.*;
 import com.caimei365.user.service.SellerService;
 import com.caimei365.user.utils.JwtUtil;
+import com.caimei365.user.utils.MathUtil;
 import com.caimei365.user.utils.Md5Util;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
@@ -22,6 +23,8 @@ import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.*;
 
 /**
@@ -63,7 +66,7 @@ public class SellerServiceImpl implements SellerService {
         // 获取协销用户下的机构列表
         List<ClubVo> clubList = new ArrayList<ClubVo>();
         List<Integer> serviceIds = new ArrayList<Integer>();
-        if (1 == type || 3 == type) {
+        if (1 == type || 3 == type|| 6 == type) {
             if(null != groupServiceId && groupServiceId > 0){
                 return ResponseJson.success();
             }else{
@@ -112,6 +115,36 @@ public class SellerServiceImpl implements SellerService {
         return ResponseJson.success(pageData);
     }
 
+    /**
+     * 机构活跃分析
+     *
+     * @param serviceProviderId 协销Id
+     * @param status            机构状态:
+     *                          1:待审查资料, 2:电话预约, 3:已预约
+     *                          20:待确认, 21:待拜访, 30:待员工推荐
+     *                          90:已上线, 91:已冻结, 92:审查资料未通过,待补充资料, 40:已完成第一次采购
+     *                          66:协销下所有上线的机构----虚拟状态
+     * @param name              机构名字关键字(搜索用)
+     * @param type              1.我的机构2.组员机构(组长展示全组,总管理员展示所有人)3.待分配机构
+     * @return
+     */
+    @Override
+    public ResponseJson<Map<String, Object>> getLivelyClubList(Integer serviceProviderId, Integer status, Integer type, String name, Integer userIdentity, Integer pageNum, Integer pageSize) {
+        PageHelper.startPage(pageNum, pageSize);
+        Map<String, Object> map = new HashMap<>();
+        Map<String, Object> spUserLoginSum = sellerMapper.findSpUserLoginSum(serviceProviderId.toString());
+        Integer loginSum = Integer.valueOf(spUserLoginSum.get("loginSum").toString());
+        Integer not_loginSum = Integer.valueOf(spUserLoginSum.get("not_loginSum").toString());
+//        机构活跃与不活跃占比计算方法,例如:机构活跃数/机构活跃数+机构不活跃数(60/(60+30)=0.666...),保留小数点后2位,四舍五入,0.67;
+        BigDecimal livelyClubProportion = new BigDecimal((loginSum + not_loginSum) != 0 ? loginSum / (loginSum + not_loginSum) * 100 : 0).setScale(2, RoundingMode.UP);
+        map.put("livelyClub", loginSum);
+        map.put("noLivelyClub", not_loginSum);
+        map.put("livelyClubProportion", livelyClubProportion);
+        map.put("noLivelyClubProportion", MathUtil.sub(100, livelyClubProportion).setScale(2));
+        map.put("clubList", new PageInfo<>(sellerMapper.findClubs(serviceProviderId, status, name, userIdentity, type, null)));
+        return ResponseJson.success(map);
+    }
+
     /**
      * 协销登录(手机号,密码)
      *

+ 60 - 0
src/main/java/com/caimei365/user/utils/FastDfsUtil.java

@@ -0,0 +1,60 @@
+package com.caimei365.user.utils;
+
+import com.github.tobato.fastdfs.domain.fdfs.StorePath;
+import com.github.tobato.fastdfs.domain.proto.storage.DownloadByteArray;
+import com.github.tobato.fastdfs.service.FastFileStorageClient;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.io.*;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2021/10/25
+ */
+@Component
+public class FastDfsUtil {
+    @Resource
+    private FastFileStorageClient storageClient;
+
+
+    // 文件上传
+    public String uploadFile(String path) throws FileNotFoundException {
+        File file = new File(path);
+        InputStream input = new FileInputStream(file);
+        long size = FileUtils.sizeOf(file);
+        String name = file.getName();
+        String fileName = name.substring(name.lastIndexOf("/") + 1);
+        StorePath storePath = storageClient.uploadFile(input, size, FilenameUtils.getExtension(fileName), null);
+        return storePath.getFullPath();
+    }
+
+    // 文件上传
+    public String uploadStream(String path) throws FileNotFoundException {
+        File file = new File(path);
+        InputStream input = new FileInputStream(file);
+        long size = FileUtils.sizeOf(file);
+        String name = file.getName();
+        String fileName = name.substring(name.lastIndexOf("/") + 1);
+        StorePath storePath = storageClient.uploadFile(input, size, FilenameUtils.getExtension(fileName), null);
+        return storePath.getFullPath();
+    }
+
+    // 文件下载
+    public boolean downloadFile(String path, String downloadFilePath) throws IOException {
+        File file = new File(downloadFilePath);
+        FileOutputStream outputStream = null;
+        // fastdfs 文件读取
+        String filepath = path.substring(path.lastIndexOf("group1/") + 7);
+        DownloadByteArray callback = new DownloadByteArray();
+        byte[] content = storageClient.downloadFile("group1", filepath, callback);
+        // 数据写入指定文件夹中
+        outputStream = new FileOutputStream(file);
+        outputStream.write(content);
+        return true;
+    }
+}

+ 33 - 0
src/main/java/com/caimei365/user/utils/RequestUtil.java

@@ -1,5 +1,12 @@
 package com.caimei365.user.utils;
 
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.protocol.HttpContext;
 import org.springframework.util.StringUtils;
 
 import javax.net.ssl.HttpsURLConnection;
@@ -7,6 +14,8 @@ import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
 import java.io.*;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.nio.charset.StandardCharsets;
@@ -117,7 +126,31 @@ public class RequestUtil {
         }
         return result.toString();
     }
+    public static ByteArrayInputStream sendPost(String url, String params) throws URISyntaxException, IOException {
+        CloseableHttpClient client = HttpClients.createDefault();
+        HttpPost httpPost = new HttpPost();
+        httpPost.addHeader("Content-type","application/json;charset=UTF-8");
+        httpPost.setHeader("Accept","application/json");
+        URI uri = new URI(url);
+        httpPost.setURI(uri);
+        StringEntity entity = new StringEntity(params, "UTF-8");
+        httpPost.setEntity(entity);
+        CloseableHttpResponse response = client.execute(httpPost, (HttpContext) null);
+        HttpEntity responseEntity = response.getEntity();
+        InputStream inputStream = responseEntity.getContent();
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        byte[] buffer = new byte[1024];
+        int len = 0;
+        while ((len = inputStream.read(buffer)) != -1) {
+            outputStream.write(buffer, 0, len);
+        }
+        inputStream.close();
+        ByteArrayInputStream byteInputStream = new ByteArrayInputStream(outputStream.toByteArray());
+        outputStream.flush();
+        outputStream.close();
+        return byteInputStream;
 
+    }
     /**
      * 向指定 URL 发送请求
      * @param requestUrl 发送请求的 URL

+ 7 - 0
src/main/resources/mapper/ClubMapper.xml

@@ -1143,6 +1143,13 @@
         ORDER BY RAND()
         LIMIT 0,1;
     </select>
+    <select id="getSpUserId" resultType="java.lang.Integer">
+        SELECT sp.userId FROM serviceprovider sp
+        WHERE sp.organizeID = 0
+          and sp.status=90
+          and sp.serviceProviderID=#{spId}
+        LIMIT 0,1;
+    </select>
     <insert id="inProvider">
         insert into cm_provider_record (spId, clubId, operator, isOneself, createTime)
         values (#{spId}, #{clubId}, #{operator}, #{isOneself}, now())

+ 33 - 3
src/main/resources/mapper/SellerMapper.xml

@@ -106,7 +106,7 @@
     </select>
 
     <select id="findClubs" resultType="com.caimei365.user.model.vo.ClubVo">
-        select DISTINCT c.clubID as clubId, c.userID as userId, c.name, c.sname as shortName, c.contractMobile,
+        select  c.clubID as clubId, c.userID as userId, c.name, c.sname as shortName, c.contractMobile,
         c.contractEmail as contractEmail,
         c.contractPhone, c.linkMan, c.provinceID as proviceId, c.cityID as cityId, c.townID as townId,
         c.address, c.headpic as shopPhoto, c.businessLicenseImage as businessLicense, c.socialCreditCode,
@@ -116,12 +116,14 @@
         u.userIdentity,c.newDeal as newDeal,IF(r.id IS NOT NULL,1,0) AS recordCount,
         sp.name AS serviceName,
         covs.activeState AS activeState,
-        covs.customerValue AS customerValue
+        covs.customerValue AS customerValue,
+        cpr.createTime AS providerTime
         from club c
         left join user u on c.userID = u.userID
         LEFT JOIN record_link r ON r.`clubId`=c.`clubID`
         LEFT JOIN cm_organ_value_system covs ON covs.userID = u.userID
         LEFT JOIN serviceprovider sp ON c.spID = sp.serviceProviderID
+        LEFT JOIN cm_provider_record cpr ON cpr.spID = sp.serviceProviderID and cpr.clubId = c.clubId
         where
         <if test="1 == type">
             c.spID = #{serviceProviderId}
@@ -136,6 +138,20 @@
             r.clubId IS NOT NULL
             AND c.spId=1342
         </if>
+        <if test="4 == type">
+            c.spID = #{serviceProviderId}
+            AND sp.status = 90
+                AND (u.loginTime >= DATE_SUB(CURRENT_DATE, INTERVAL 6 MONTH)
+        </if>
+        <if test="5 == type">
+            c.spID = #{serviceProviderId}
+            AND sp.status = 90
+                AND (u.loginTime<![CDATA[ < ]]> DATE_SUB(CURRENT_DATE, INTERVAL 6 MONTH)
+        </if>
+        <if test="6 == type">
+            c.spID = #{serviceProviderId}
+            AND c.newDeal =1
+        </if>
         <if test="status != null and status != 66">
             AND c.status = #{status}
         </if>
@@ -149,7 +165,21 @@
             AND u.userIdentity = #{userIdentity}
         </if>
         AND covs.stage = 0 AND covs.delType = 1
-        order by c.clubID desc
+        group by c.clubID
+        order by cpr.createTime desc
+    </select>
+
+    <select id="findSpUserLoginSum" resultType="java.util.HashMap" parameterType="string">
+        select
+        ifnull(COUNT(CASE WHEN u.loginTime >= DATE_SUB(CURRENT_DATE, INTERVAL 6 MONTH) THEN 1 END),0) AS loginSum,
+        ifnull(COUNT(CASE WHEN u.loginTime <![CDATA[ < ]]> DATE_SUB(CURRENT_DATE, INTERVAL 6 MONTH) THEN 1 END),0) AS not_loginSum
+        FROM club c
+        LEFT JOIN user u ON u.userID = c.userID
+        LEFT JOIN serviceprovider sp ON sp.serviceProviderID = c.spID
+        where sp.status=90
+        <if test="spID != null">
+            and  c.spID=#{spID}
+        </if>
     </select>
     <select id="getAllClubList" resultType="com.caimei365.user.model.vo.ClubVo">
         SELECT DISTINCT c.clubID as clubId, c.userID as userId, c.name, c.sname as shortName, c.contractMobile,