package com.ruoyi.demo.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.ruoyi.demo.constant.RedisContant; import com.ruoyi.demo.entity.*; import com.ruoyi.demo.entity.bo.Histogram; import com.ruoyi.demo.entity.bo.StoreWdCategoryCount; import com.ruoyi.demo.entity.bo.StoreWdCategoryCountBody; import com.ruoyi.demo.entity.vo.ChannelAnalyseAceeptVo; import com.ruoyi.demo.entity.vo.ChannelMapAceeptVo; import com.ruoyi.demo.entity.vo.TagAnalyse; import com.ruoyi.demo.mapper.*; import com.ruoyi.demo.service.ChannelAnalyseService; import com.ruoyi.demo.utils.InitMapUtil; import com.ruoyi.demo.utils.WdRedisStoreage; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.geo.Circle; import org.springframework.data.geo.Distance; import org.springframework.data.geo.GeoResults; import org.springframework.data.geo.Point; import org.springframework.data.redis.connection.RedisGeoCommands; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.stream.Collectors; @Slf4j @Service @Transactional public class ChannelAnalyseServiceImpl implements ChannelAnalyseService { @Autowired private AddrCategoryDao addrCategoryDao; @Autowired WdInfoDao wdInfoDao; @Autowired InitMapUtil initMapUtil; @Autowired BrandMapper brandMapper; @Autowired WdTopologicalInfoDao wdTopologicalInfoDao; @Autowired private WdRedisStoreage wdRedisStoreage; @Autowired private StoreWdDao storeWdDao; @Autowired @Qualifier("executor") ExecutorService executor; /** * 网点城市等级分布统计 * @param channelMapAceeptVo 渠道地图过滤请求接收体 * @return */ @Override public HashMap cityTier(ChannelMapAceeptVo channelMapAceeptVo) { //1.初始化统计结果 HashMap result = new HashMap<>(); result.put("一线", 0L); result.put("新一线", 0L); result.put("二线", 0L); result.put("三线", 0L); result.put("四线", 0L); result.put("五线", 0L); result.put("其他", 0L); //2.获取所有符合条件的网点信息 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("addr_code","count(*) as audit"); assembleQueryWrapper(queryWrapper,channelMapAceeptVo); //封装过滤条件 queryWrapper.groupBy("addr_code"); List wdInfos = wdInfoDao.selectList(queryWrapper); //3.统计各个城市等级的网点数量 for (WdInfo wdInfo : wdInfos) { //通过 网点区码 得到 该网点属于几线城市 例如:4509010000 -> 二线 String initCityTierMap = initMapUtil.getInitCityTierMap(wdInfo.getAddrCode()); if (initCityTierMap != null) { result.put(initCityTierMap, result.get(initCityTierMap) + wdInfo.getAudit()); } else result.put("其他", result.get("其他") + wdInfo.getAudit()); } return result; } /** * 品牌列表 * @param channelAnalyseAceeptVo 渠道地图过滤请求接收体 * @return */ @Override public Page brandList(ChannelAnalyseAceeptVo channelAnalyseAceeptVo) { QueryWrapper queryWrapper = new QueryWrapper<>(); if (channelAnalyseAceeptVo.getSearchText() != null && !channelAnalyseAceeptVo.getSearchText().equals("")) queryWrapper.like("brand_name",channelAnalyseAceeptVo.getSearchText()); Page page = new Page<>(); page.setSize(channelAnalyseAceeptVo.getPageSize()); page.setCurrent(channelAnalyseAceeptVo.getPageNum()); Page brandPage = brandMapper.selectPage(page, queryWrapper); return brandPage; } //TODO 待优化 @Override public HashMap tagAnalyse(ChannelMapAceeptVo channelMapAceeptVo) { //1.根据条件的到位网点信息 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("wd_id"); assembleQueryWrapper(queryWrapper,channelMapAceeptVo); List queryWd = wdInfoDao.selectList(queryWrapper); //2.得到网点Id List collect = queryWd.stream().map(item -> { return RedisContant.WD_TAG + "_" + item.getWdId(); }).collect(Collectors.toList()); queryWd = null; //3.切割网点分批次获取网点标签 ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<>(); concurrentHashMap.put("total",0); int split = 4000; //每次获取的网点次数 int splitCount = collect.size()%split == 0 ? (collect.size()/split) : (collect.size()/split + 1); //共计次数 int p1 = 0,p2 = split; ArrayList> splitList = new ArrayList<>(); for (int i=1;i<=splitCount;i++){ if (p2 > collect.size()) p2 = collect.size(); List list2 = collect.subList(p1, p2); //创建线程任务 CompletableFuture future = CompletableFuture.runAsync(()->{ tagAnalyseItem(concurrentHashMap,list2); //统计 },executor); splitList.add(future); p1 = p2; p2+=split; } //3.统计 CompletableFuture.allOf(splitList.toArray(new CompletableFuture[splitList.size()])).join(); splitList = null; //4.封装统计值 HashMap result = new HashMap<>(); List list = new ArrayList<>(); Integer total = concurrentHashMap.get("total"); for (String s : concurrentHashMap.keySet()) { if (s.equals("total")) continue; TagAnalyse tagAnalyse = new TagAnalyse(); tagAnalyse.setName(s); tagAnalyse.setCount(concurrentHashMap.get(s)); BigDecimal bigDecimal = new BigDecimal((double) tagAnalyse.getCount() / total); double v = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); tagAnalyse.setRadio(v); list.add(tagAnalyse); } //5.对结果集进行排序 Collections.sort(list, new Comparator() { @Override public int compare(TagAnalyse o1, TagAnalyse o2) { return o2.getCount() - o1.getCount(); } }); //5.分页返回结果集 int i = 1; int start = 0,end = channelMapAceeptVo.getPageSize(); while(start=list.size()) end = list.size(); result.put(""+i++,new ArrayList(list.subList(start,end))); start=end; end += channelMapAceeptVo.getPageSize(); } result.put("pages",i-1); result.put("total",list.size()); return result; } //TODO 待优化 public void tagAnalyseItem(ConcurrentHashMap concurrentHashMap, List keys){ //2.获取网点周边标签,并进行统计 int total = 0; List> wdTagList = wdRedisStoreage.getWdTagList(keys); for (List list : wdTagList) { if (list == null || list.size() == 0) continue; for (String s : list) { s += "边"; Integer integer = concurrentHashMap.get(s); if (integer == null) concurrentHashMap.put(s,1); else concurrentHashMap.put(s,integer+1); } total++; } wdTagList = null; concurrentHashMap.put("total",concurrentHashMap.get("total")+total); } /** * 网点分类统计 * @param channelMapAceeptVo 渠道地图过滤请求接收体 * @return */ @Override public List category(ChannelMapAceeptVo channelMapAceeptVo) { //1.查询所有符合的门店网点 channelMapAceeptVo.setChannel(new String[]{"1"}); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("wd_id"); assembleQueryWrapper(queryWrapper,channelMapAceeptVo); //封装过滤条件 List storeWds = storeWdDao.category(queryWrapper); //2.统计各个分类的网点数量 HashMap<分类code,门店网点分类数量对象> HashMap hashMap = new HashMap<>(); for (StoreWd storeWd : storeWds) { //分类为null、空跳过 if(storeWd.getManageTypeCode() == null || storeWd.getManageTypeCode().equals("")) continue; //2.1 通过 分类Code 得到 具体的分类实体 ManageType manageType = initMapUtil.getInitManageType(storeWd.getManageTypeCode()); //2.2 通过 分类Code 得到 门店网点分类数量对象 String s = storeWd.getManageTypeCode().substring(0, 4) + "00"; StoreWdCategoryCount storeWdCategoryCount = hashMap.get(s); if (storeWdCategoryCount == null){ //创建 门店网点分类数量体 StoreWdCategoryCountBody storeWdCategoryCountBody = createStoreWdCategoryCountBody(manageType); storeWdCategoryCountBody.setManageTypeCode(storeWd.getManageTypeCode()); //分类code storeWdCategoryCountBody.setCount(storeWd.getCommentCount()); //数量 //初始化 门店网点分类数量对象 StoreWdCategoryCount storeWdCategoryCount1 = new StoreWdCategoryCount(); storeWdCategoryCount1.setManageTypeCode(s); storeWdCategoryCount1.setName(initMapUtil.getInitManageType(s).getMidCategory()); storeWdCategoryCount1.setCount(storeWd.getCommentCount()); //将 门店网点分类数量体 封装进 门店网点数量对象 ArrayList list = new ArrayList<>(); list.add(storeWdCategoryCountBody); storeWdCategoryCount1.setStoreWdCategoryCountBodyList(list); hashMap.put(s,storeWdCategoryCount1); }else { //创建 门店网点分类数量体 StoreWdCategoryCountBody storeWdCategoryCountBody = createStoreWdCategoryCountBody(manageType); storeWdCategoryCountBody.setManageTypeCode(storeWd.getManageTypeCode()); storeWdCategoryCountBody.setCount(storeWd.getCommentCount()); //将 门店网点分类数量体 封装进 门店网点数量对象 storeWdCategoryCount.getStoreWdCategoryCountBodyList().add(storeWdCategoryCountBody); storeWdCategoryCount.setCount(storeWdCategoryCountBody.getCount()+storeWdCategoryCount.getCount()); //hashMap.put(s,storeWdCategoryCount); } } //3.组装结果集 List storeWdCategoryCounts = new ArrayList<>(); for (String s : hashMap.keySet()) { storeWdCategoryCounts.add(hashMap.get(s)); } return storeWdCategoryCounts; } /** * 创建门店网点分类体 * @param manageType 具体的分类实体 * @return */ public StoreWdCategoryCountBody createStoreWdCategoryCountBody(ManageType manageType){ StoreWdCategoryCountBody storeWdCategoryCountBody = new StoreWdCategoryCountBody(); if(manageType.getSubCategory() != null && !manageType.getSubCategory().equals("")){ storeWdCategoryCountBody.setName(manageType.getSubCategory()); }else if(manageType.getMidCategory() != null && !manageType.getMidCategory().equals("")){ storeWdCategoryCountBody.setName(manageType.getMidCategory()); }else if (manageType.getBigCategory() != null && !manageType.getBigCategory().equals("")){ storeWdCategoryCountBody.setName(manageType.getBigCategory()); } return storeWdCategoryCountBody; } /** * 网点营业状态统计 * @param channelMapAceeptVo 渠道地图过滤请求接收体 * @return */ @Override public HashMap businessStatusAnalyse(ChannelMapAceeptVo channelMapAceeptVo) { //1.查询所有符合的门店网点 channelMapAceeptVo.setChannel(new String[]{"1"}); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("wd_id"); assembleQueryWrapper(queryWrapper,channelMapAceeptVo); //封装过滤条件 List storeWds = storeWdDao.businessStatusAnalyse(queryWrapper); //2.统计 HashMap<营业状态,直方图统计体> ArrayList list = new ArrayList<>(); int total = 0; for (StoreWd storeWd : storeWds) { total+=storeWd.getCommentCount(); Histogram histogram = new Histogram(); histogram.setName(storeWd.getBusinessStatus()); histogram.setCount(storeWd.getCommentCount()); list.add(histogram); } //3.返回结果集 HashMap result = new HashMap<>(); result.put("total",total); result.put("data",list); return result; } /** * 楼宇类别统计 * @param channelMapAceeptVo * @return */ @Override public ArrayList aroundBuildAnalyse(ChannelMapAceeptVo channelMapAceeptVo) { //1.查询所有符合的网点 channelMapAceeptVo.setChannel(new String[]{"3"}); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("type_code_by","count(*) as audit"); assembleQueryWrapper(queryWrapper,channelMapAceeptVo); //封装过滤条件 queryWrapper.and(queryWrapper1 -> { queryWrapper1.isNotNull("type_code_by"); }); queryWrapper.groupBy("type_code_by"); List wdInfos = wdInfoDao.selectList(queryWrapper); //2.统计楼宇类别数量 int total = 0; HashMap hashMap = new HashMap<>(); for (WdInfo wdInfo : wdInfos) { String typeCodeBy = wdInfo.getTypeCodeBy().substring(0,2); Integer integer = hashMap.get(typeCodeBy); if (integer == null){ hashMap.put(typeCodeBy,wdInfo.getAudit()); }else { hashMap.put(typeCodeBy,hashMap.get(typeCodeBy)+wdInfo.getAudit()); } total+=wdInfo.getAudit(); } //3.分装统计结果 ArrayList list = new ArrayList<>(); for (String s : hashMap.keySet()) { Integer integer = hashMap.get(s); String initTypeByMap = initMapUtil.getInitTypeByMap(s + "0000").replace(":",""); //根据需求取大类 Histogram histogram = new Histogram(); histogram.setName(initTypeByMap); histogram.setCount(integer); list.add(histogram); } return list; } /** * 获取人均消费直方图 * @param channelMapAceeptVo * @return */ @Override public ArrayList perCapitaConsumpAnalyse(ChannelMapAceeptVo channelMapAceeptVo) { //1.查询所有符合的网点 channelMapAceeptVo.setChannel(new String[]{"1"}); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("wd_id"); assembleQueryWrapper(queryWrapper,channelMapAceeptVo); List storeWds = storeWdDao.perCapitaConsumpAnalyse(queryWrapper); //初始化 //初始化 String[] arr = new String[]{"0~20","20~50","50~100","100~200","200以上"}; ArrayList list = new ArrayList<>(); for (String s:arr){ list.add(new Histogram(s,0)); } //2.统计各个人均消费的数量 for (StoreWd storeWd : storeWds) { if (storeWd.getPerCapitaConsumption() != null){ if (storeWd.getPerCapitaConsumption() >= 0 && storeWd.getPerCapitaConsumption()<20){ Histogram histogram = list.get(0); histogram.setCount(histogram.getCount()+1); }else if(storeWd.getPerCapitaConsumption() >= 20 && storeWd.getPerCapitaConsumption()<50){ Histogram histogram = list.get(1); histogram.setCount(histogram.getCount()+1); }else if(storeWd.getPerCapitaConsumption() >= 50 && storeWd.getPerCapitaConsumption()< 100){ Histogram histogram = list.get(2); histogram.setCount(histogram.getCount()+1); }else if(storeWd.getPerCapitaConsumption() >= 100 && storeWd.getPerCapitaConsumption()< 200){ Histogram histogram = list.get(3); histogram.setCount(histogram.getCount()+1); }else { Histogram histogram = list.get(4); histogram.setCount(histogram.getCount()+1); } } } //3.分装统计结果 return list; } /** * 获取聚道分析-店龄 / 经营时长统计 * @param channelMapAceeptVo * @return */ @Override public ArrayList operateTimeAnalyse(ChannelMapAceeptVo channelMapAceeptVo) { //1.查询所有符合的网点 channelMapAceeptVo.setChannel(new String[]{"1"}); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select("wd_id"); assembleQueryWrapper(queryWrapper,channelMapAceeptVo); List storeWds = storeWdDao.operateTimeAnalyse(queryWrapper); //2.统计经营时长 //初始化 String[] arr = new String[]{"0~5","6~10","11~15","16~24"}; ArrayList list = new ArrayList<>(); for (String s:arr){ list.add(new Histogram(s,0)); } for (StoreWd storeWd : storeWds) { Integer opentime = Integer.valueOf(storeWd.getOpentime().substring(0,2)); Integer closetime = Integer.valueOf(storeWd.getClosetime().substring(0,2)); int i = closetime - opentime; if (i >=0 && i <=5){ Histogram histogram = list.get(0); histogram.setCount(histogram.getCount()+1); }else if (i >= 6 && i <= 10){ Histogram histogram = list.get(1); histogram.setCount(histogram.getCount()+1); }else if(i >= 11 && i <= 15){ Histogram histogram = list.get(2); histogram.setCount(histogram.getCount()+1); }else if(i >= 16){ Histogram histogram = list.get(3); histogram.setCount(histogram.getCount()+1); } } //3.返回结果 return list; } /** * 封装网点过滤条件(v1.0) * @param queryWrapper * @param channelMapAceeptVo */ // public void assembleQueryWrapper(QueryWrapper queryWrapper,ChannelMapAceeptVo channelMapAceeptVo){ // //1.根据不同级别得到需要查询的 地区码 // List addrCodeList = new ArrayList<>(); // if ("province".equals(channelMapAceeptVo.getRankType())) { // //省码 // for (String s : channelMapAceeptVo.getAddrCode()) { // String substring = s.substring(0, 2); // addrCodeList.add(substring); // } // } else if ("city".equals(channelMapAceeptVo.getRankType())) { // //省的所有市 // for (String s : channelMapAceeptVo.getAddrCode()) { // String substring = s.substring(0, 2); // addrCodeList.add(substring); // } // } else if ("zone".equals(channelMapAceeptVo.getRankType())) { // //市的所有区 // for (String s : channelMapAceeptVo.getAddrCode()) { // String substring = s.substring(0, 4); // addrCodeList.add(substring); // } // } else if ("district".equals(channelMapAceeptVo.getRankType())){ // //区的所有街道 // for (String s : channelMapAceeptVo.getAddrCode()) { // String substring = s.substring(0, 6); // addrCodeList.add(substring); // } // }else { // //省码 // for (String s : channelMapAceeptVo.getAddrCode()) { // String substring = s.substring(0, 2); // addrCodeList.add(substring); // } // } // // queryWrapper.in("wd_type_code", channelMapAceeptVo.getChannel()).and(originWdInfoQueryWrapper -> { // for (String s : addrCodeList) { // originWdInfoQueryWrapper.likeRight("addr_code", s).or(); // } // }); // // //搜索字段 // if (channelMapAceeptVo.getSearchText() != null && !channelMapAceeptVo.getSearchText() .trim().equals("")) { // queryWrapper.and(originWdInfoQueryWrapper -> { // originWdInfoQueryWrapper.like("wd_name", channelMapAceeptVo.getSearchText() ); // }); // } // // //城市等级分类 // if(channelMapAceeptVo.getCityTier() != null && channelMapAceeptVo.getCityTier().length > 0){ // List tierCode = new ArrayList<>(); // for (String s : channelMapAceeptVo.getCityTier()) { // List list = initMapUtil.getInitCityTierListMap(s); // if (list != null){ // tierCode.addAll(list); // } // } // queryWrapper.and(wdInfoQueryWrapper -> { // for (String s : tierCode) { // wdInfoQueryWrapper.likeRight("addr_code", s).or(); // } // }); // } // // //排序字段查询 // if (channelMapAceeptVo.getOrderby() != null && !channelMapAceeptVo.getOrderby().trim().equals("")) { // PageHelper.orderBy(channelMapAceeptVo.getOrderby()); // } // // } /** * 封装网点过滤条件(v2.0) * @param queryWrapper * @param channelMapAceeptVo */ public void assembleQueryWrapper(QueryWrapper queryWrapper,ChannelMapAceeptVo channelMapAceeptVo){ //1.根据不同级别得到需要查询的 地区码 List wdAddrCode = findWdAddrCode(channelMapAceeptVo.getRankType(), channelMapAceeptVo.getAddrCode()); //是否有联系方式 if(channelMapAceeptVo.getIsTelephone() != null && !channelMapAceeptVo.getIsTelephone().equals("")){ queryWrapper.and(wdInfoQueryWrapper -> { wdInfoQueryWrapper.eq("is_telephone",channelMapAceeptVo.getIsTelephone().equals("true") ? 1:0); }); } //是否关联品牌 if(channelMapAceeptVo.getIsBrand() != null && !channelMapAceeptVo.getIsBrand().equals("")){ queryWrapper.and(wdInfoQueryWrapper -> { wdInfoQueryWrapper.eq("is_brand",channelMapAceeptVo.getIsTelephone().equals("true") ? 1:0); }); } //店龄 if(channelMapAceeptVo.getStoreAge() != null && !channelMapAceeptVo.getStoreAge().equals("")){ queryWrapper.and(wdInfoQueryWrapper -> { wdInfoQueryWrapper.eq("store_age",channelMapAceeptVo.getStoreAge()); }); } //组织结构 if(channelMapAceeptVo.getOrganization() != null && !channelMapAceeptVo.getOrganization().equals("")){ queryWrapper.and(wdInfoQueryWrapper -> { wdInfoQueryWrapper.eq("organization",channelMapAceeptVo.getOrganization()); }); } //地区过滤 queryWrapper.and(wdInfoQueryWrapper -> { wdInfoQueryWrapper.in("addr_code", wdAddrCode); }); //渠道过滤 if(channelMapAceeptVo.getChannel() != null && channelMapAceeptVo.getChannel().length != 6){ queryWrapper.and(wdInfoQueryWrapper -> { wdInfoQueryWrapper.in("wd_type_code", channelMapAceeptVo.getChannel()); }); } //城市等级分类 if(channelMapAceeptVo.getCityTier() != null && channelMapAceeptVo.getCityTier().length > 0){ List tierCode = new ArrayList<>(); for (String s : channelMapAceeptVo.getCityTier()) { List list = initMapUtil.getInitCityTierListMap(s); if (list != null){ tierCode.addAll(list); } } if(!tierCode.isEmpty()){ queryWrapper.and(wdInfoQueryWrapper -> { wdInfoQueryWrapper.in("addr_code",tierCode); }); } } //搜索字段 if (channelMapAceeptVo.getSearchText() != null && !channelMapAceeptVo.getSearchText() .trim().equals("")) { queryWrapper.and(originWdInfoQueryWrapper -> { originWdInfoQueryWrapper.like("wd_name", channelMapAceeptVo.getSearchText() ); }); } //排序字段查询 if (channelMapAceeptVo.getOrderby() != null && !channelMapAceeptVo.getOrderby().trim().equals("")) { PageHelper.orderBy(channelMapAceeptVo.getOrderby()); } } /** * 找到所有满足条件的网点addrCode * @param rankType * @param addrCode * @return */ private List findWdAddrCode(String rankType,String[] addrCode){ //1.根据不同级别得到 找到所有 完整的 区码 List addrCodeList = new ArrayList<>(); if ("province".equals(rankType)) { //addrCode:省码 for (String string:addrCode) addrCodeList.add(string.substring(0, 2)); } else if ("city".equals(rankType)) { //addrCode:省码(只允许有一个) String substring = addrCode[0].substring(0, 2); //根据该省码找到旗下的所有的区 addrCodeList.add(substring); } else if ("zone".equals(rankType)) { //addrCode:市码(只允许有一个) String substring = addrCode[0].substring(0, 4); //根据该市码找到旗下的所有的区 addrCodeList.add(substring); } else { for (String string:addrCode) addrCodeList.add(string.substring(0, 2)); } //2.找到所有完整的区码 QueryWrapper queryWrapper1 = new QueryWrapper<>(); queryWrapper1.select("addr_code"); queryWrapper1.eq("type", "zone"); queryWrapper1.and(addrCategoryQueryWrapper -> { for (String s : addrCodeList) { addrCategoryQueryWrapper.likeRight("addr_code", s).or(); } }); List addrCategories1 = addrCategoryDao.selectList(queryWrapper1); List collect = addrCategories1.stream().map(item -> { return item.getAddrCode(); }).collect(Collectors.toList()); return collect; } }