商城报表统计
1 package net.baiqu.shop.data.core.service.impl; 2 3 import com.baiqu.api.model.ApiResultResponse; 4 import lombok.extern.slf4j.Slf4j; 5 import net.baiqu.shop.data.api.AppResponseUtils; 6 import net.baiqu.shop.data.api.enums.report.ReportTypeEnum; 7 import net.baiqu.shop.data.api.models.request.report.ReportQueryRequest; 8 import net.baiqu.shop.data.api.models.response.report.ReportQueryResponse; 9 import net.baiqu.shop.data.core.service.AmountStatisticService; 10 import net.baiqu.shop.data.core.service.ReportQueryService; 11 import net.baiqu.shop.data.core.service.RepurchaseService; 12 import net.baiqu.shop.data.core.service.VipStatisticService; 13 import net.baiqu.shop.data.dal.entity.document.*; 14 import org.springframework.beans.factory.annotation.Autowired; 15 import org.springframework.stereotype.Service; 16 17 import java.util.Arrays; 18 import java.util.List; 19 import java.util.concurrent.*; 20 import java.util.stream.Collectors; 21 22 @Service 23 @Slf4j 24 public class ReportQueryServiceImpl implements ReportQueryService { 25 26 @Autowired 27 private AmountStatisticService amountStatisticService; 28 29 @Autowired 30 private VipStatisticService vipStatisticService; 31 32 @Autowired 33 private RepurchaseService repurchaseService; 34 35 @Override 36 public ApiResultResponse<List<ReportQueryResponse>> getStatistic(ReportQueryRequest request) { 37 ExecutorService executor = new ThreadPoolExecutor( 38 10, 39 10, 40 60, 41 TimeUnit.SECONDS, 42 new LinkedBlockingQueue<>(), 43 new ThreadPoolExecutor.AbortPolicy()); 44 List<Integer> indexs = Arrays.asList(0, 1, 2, 3, 4, 5); 45 46 List<CompletableFuture<ReportQueryResponse>> listTasks = indexs.stream() 47 .map(index -> CompletableFuture.supplyAsync(() -> syncFunc(index, request), executor)) 48 .collect(Collectors.toList()); 49 50 List<ReportQueryResponse> list = listTasks.stream().map(CompletableFuture::join).collect(Collectors.toList()); 51 executor.shutdown(); 52 53 return AppResponseUtils.buildSuccessResponse(list); 54 } 55 56 /** 57 * 异步调用统计查询 58 */ 59 private ReportQueryResponse syncFunc(Integer index, ReportQueryRequest request) { 60 ReportQueryResponse result = null; 61 switch (index) { 62 case 0: result = queryBalance(request);break; 63 case 1: result = queryVipConsume(request);break; 64 case 2: result = queryCustomerSave(request);break; 65 case 3: result = queryFormalVip(request);break; 66 case 4: result = queryExpVip(request);break; 67 case 5: result = queryRepurchaseVip(request);break; 68 default: 69 } 70 return result; 71 } 72 73 /** 74 * 余额增长 75 */ 76 private ReportQueryResponse queryBalance(ReportQueryRequest request) { 77 log.info("开始查询余额增长"); 78 ReportQueryResponse balanceResp = new ReportQueryResponse(); 79 balanceResp.setStatisticType(ReportTypeEnum.BALANCE); 80 balanceResp.setStatisticResult(amountStatisticService.getAmountStatistic(request, MBalance.class)); 81 //log.info("getStatistic->balanceResp",JSON.toJSONString(balanceResp)); 82 log.info("完成余额增长查询"); 83 return balanceResp; 84 } 85 86 /** 87 * 会员消费 88 */ 89 private ReportQueryResponse queryVipConsume(ReportQueryRequest request) { 90 log.info("开始查询会员消费"); 91 ReportQueryResponse vipConsumeResp = new ReportQueryResponse(); 92 vipConsumeResp.setStatisticType(ReportTypeEnum.VIP_CONSUME); 93 vipConsumeResp.setStatisticResult(amountStatisticService.getAmountStatistic(request, MVipConsume.class)); 94 //log.info("getStatistic->vipConsumeResp",JSON.toJSONString(vipConsumeResp)); 95 log.info("完成查询会员消费"); 96 return vipConsumeResp; 97 } 98 99 /** 100 * 客户节约 101 */ 102 private ReportQueryResponse queryCustomerSave(ReportQueryRequest request) { 103 log.info("开始查询客户节约"); 104 ReportQueryResponse customerResp = new ReportQueryResponse(); 105 customerResp.setStatisticType(ReportTypeEnum.CUSTOMER_SAVE); 106 customerResp.setStatisticResult(amountStatisticService.getAmountStatistic(request, MCustomerSave.class)); 107 //log.info("getStatistic->customerResp",JSON.toJSONString(customerResp)); 108 log.info("完成查询客户节约"); 109 return customerResp; 110 } 111 112 /** 113 * 食堂会员增长 114 */ 115 private ReportQueryResponse queryFormalVip(ReportQueryRequest request) { 116 log.info("开始查询会员增长"); 117 ReportQueryResponse formalVipResp = new ReportQueryResponse(); 118 formalVipResp.setStatisticType(ReportTypeEnum.VIP); 119 formalVipResp.setStatisticResult(vipStatisticService.getVipStatistic(request, MFormalVip.class)); 120 //log.info("getStatistic->formalVipResp",JSON.toJSONString(formalVipResp)); 121 log.info("完成查询会员增长"); 122 return formalVipResp; 123 } 124 125 /** 126 * 体验会员增长 127 */ 128 private ReportQueryResponse queryExpVip(ReportQueryRequest request) { 129 log.info("开始查询体验会员增长"); 130 ReportQueryResponse expVipResp = new ReportQueryResponse(); 131 expVipResp.setStatisticType(ReportTypeEnum.EXP_VIP); 132 expVipResp.setStatisticResult(vipStatisticService.getVipStatistic(request, MExpVip.class)); 133 //log.info("getStatistic->expVipResp",JSON.toJSONString(expVipResp)); 134 log.info("完成查询体验会员增长"); 135 return expVipResp; 136 } 137 138 /** 139 * 复购会员 140 */ 141 private ReportQueryResponse queryRepurchaseVip(ReportQueryRequest request) { 142 log.info("开始查询复购会员增长"); 143 ReportQueryResponse repurchaseVipResp = new ReportQueryResponse(); 144 repurchaseVipResp.setStatisticType(ReportTypeEnum.REPURCHASE_VIP); 145 repurchaseVipResp.setStatisticResult(repurchaseService.getRepurchaseStatistic(request, MCustomerSave.class)); 146 //log.info("getStatistic->repurchaseVipResp",JSON.toJSONString(repurchaseVipResp)); 147 log.info("完成查询复购会员增长"); 148 return repurchaseVipResp; 149 } 150 151 }
1 package net.baiqu.shop.data.core.service.impl; 2 3 import com.alibaba.fastjson.JSONObject; 4 import com.mongodb.BasicDBObject; 5 import com.mongodb.DBObject; 6 import lombok.extern.slf4j.Slf4j; 7 import net.baiqu.shop.data.api.enums.ApiResponseCodeEnum; 8 import net.baiqu.shop.data.api.enums.report.AreaTypeEnum; 9 import net.baiqu.shop.data.api.models.request.report.ReportQueryRequest; 10 import net.baiqu.shop.data.api.models.response.vip.VipChartResponse; 11 import net.baiqu.shop.data.api.models.response.vip.VipStatisticResponse; 12 import net.baiqu.shop.data.core.exception.AppException; 13 import net.baiqu.shop.data.core.service.VipStatisticService; 14 import net.baiqu.shop.data.core.util.DateUtils; 15 import org.springframework.beans.factory.annotation.Autowired; 16 import org.springframework.data.domain.Sort; 17 import org.springframework.data.mongodb.core.MongoTemplate; 18 import org.springframework.data.mongodb.core.aggregation.Aggregation; 19 import org.springframework.data.mongodb.core.aggregation.AggregationResults; 20 import org.springframework.data.mongodb.core.query.Criteria; 21 import org.springframework.stereotype.Service; 22 import org.springframework.util.CollectionUtils; 23 24 import java.util.*; 25 import java.util.concurrent.*; 26 import java.util.stream.Collectors; 27 28 import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; 29 30 @Service 31 @Slf4j 32 public class VipStatisticServiceImpl implements VipStatisticService { 33 34 private ExecutorService executor; 35 36 public VipStatisticServiceImpl() { 37 executor = new ThreadPoolExecutor( 38 5, 39 10, 40 60, 41 TimeUnit.SECONDS, new LinkedBlockingQueue<>(), 42 new ThreadPoolExecutor.AbortPolicy()); 43 } 44 45 @Autowired 46 private MongoTemplate mongoTemplate; 47 48 private Class<?> clazz; 49 50 /** 51 * 查询食堂会员增长 | 查询体验会员增长 52 * 53 * @param request 查询条件 省、市、县、支行封装对象 54 * @param clazz 查询类 例: MVip.class, MExpVip.class 55 * @return 查询结果 56 */ 57 @Override 58 public VipStatisticResponse getVipStatistic(ReportQueryRequest request, Class<?> clazz) { 59 log.info("getVipStatistic->request:{}", JSONObject.toJSONString(request)); 60 this.clazz = clazz; 61 String province = request.getProvince(); 62 String city = request.getCity(); 63 String area = request.getArea(); 64 String bank = request.getBank(); 65 66 VipStatisticResponse vipStatistic; 67 List<VipStatisticResponse> child = new ArrayList<>(); 68 if (city == null) { 69 // 查询全省统计数据 70 vipStatistic = this.findVipStatistic("province", province, clazz); 71 log.info("getVipStatistic->vipStatistic 省统计数据:{}", JSONObject.toJSONString(vipStatistic)); 72 vipStatistic.setChild(child); 73 Map<String, Integer> childMap = this.getChildAndChildCount("province", "city", province, clazz); 74 // 异步查询省下所有城市统计数据 75 List<CompletableFuture<Integer>> listTasks = childMap.keySet().stream() 76 .map(c -> CompletableFuture.supplyAsync(() -> 77 this.findProvinceVipStatisticChild(child, c, childMap.get(c)), executor)) 78 .collect(Collectors.toList()); 79 listTasks.stream().map(CompletableFuture::join).collect(Collectors.toList()); 80 } else if (area == null) { 81 // 查询某市统计数据 82 vipStatistic = this.findVipStatistic("city", city, clazz); 83 log.info("getVipStatistic->vipStatistic 地市统计数据:{}", JSONObject.toJSONString(vipStatistic)); 84 vipStatistic.setChild(child); 85 Map<String, Integer> childMap = this.getChildAndChildCount("city", "area", city, clazz); 86 // 查询child 87 List<CompletableFuture<Integer>> listTasks = childMap.keySet().stream() 88 .map(a -> CompletableFuture.supplyAsync(() -> 89 this.findCityVipStatisticChild(child, a, childMap.get(a)), executor)) 90 .collect(Collectors.toList()); 91 listTasks.stream().map(CompletableFuture::join).collect(Collectors.toList()); 92 } else if (bank == null) { 93 // 查询某县统计数据 94 vipStatistic = this.findVipStatistic("area", area, clazz); 95 log.info("getVipStatistic->vipStatistic 县市统计数据:{}", JSONObject.toJSONString(vipStatistic)); 96 vipStatistic.setChild(child); 97 Map<String, Integer> childMap = this.getChildAndChildCount("area", "bank", area, clazz); 98 // 查询child 99 List<CompletableFuture<Integer>> listTasks = childMap.keySet().stream() 100 .map(b -> CompletableFuture.supplyAsync(() -> 101 this.findAreaVipStatisticChild(child, b, childMap.get(b)), executor)) 102 .collect(Collectors.toList()); 103 listTasks.stream().map(CompletableFuture::join).collect(Collectors.toList()); 104 } else { 105 // 查询某支行统计数据 106 vipStatistic = this.findVipStatistic("bank", bank, clazz); 107 log.info("getVipStatistic->vipStatistic 支行统计数据:{}", JSONObject.toJSONString(vipStatistic)); 108 } 109 110 //log.info("getVipStatistic->vipStatistic:{}", JSONObject.toJSONString(vipStatistic)); 111 return vipStatistic; 112 } 113 114 /** 115 * 获取parent区划的下线和下线各自的会员总数的map 116 * @param parentRefer 查询父标识 117 * @param childRefer 查询子标识 118 * @param query 查询条件 119 * @param clazz 类型 120 * @return map -> child, childCount 121 */ 122 private Map<String, Integer> getChildAndChildCount(String parentRefer, String childRefer, String query, Class<?> clazz) { 123 Map<String, Integer> map = new HashMap<>(); 124 Aggregation aggregation = Aggregation.newAggregation( 125 match( 126 Criteria.where(parentRefer).is(query)), 127 group(childRefer).count().as("total")); 128 AggregationResults<BasicDBObject> result = mongoTemplate.aggregate(aggregation, clazz, BasicDBObject.class); 129 if (CollectionUtils.isEmpty(result.getMappedResults())) { 130 throw new AppException(ApiResponseCodeEnum.USER_NOT_EXIST); 131 } 132 for (Iterator<BasicDBObject> iterator = result.iterator(); iterator.hasNext(); ) { 133 DBObject obj = iterator.next(); 134 map.put(obj.get("_id").toString(), Integer.valueOf(obj.get("total").toString())); 135 } 136 return map; 137 } 138 139 /** 140 * 查询县市下线会员统计数据 141 * @param child 下线 142 * @param bank 支行 143 * @param count 支行会员数 144 * @return 145 */ 146 private int findAreaVipStatisticChild(List<VipStatisticResponse> child, String bank, Integer count) { 147 VipStatisticResponse bankVipStatistic = this.findVipStatistic("bank", bank, count, clazz); 148 child.add(bankVipStatistic); 149 return 1; 150 } 151 152 /** 153 * 查询地市下线会员统计数据 154 * @param child 下线 155 * @param area 县市 156 * @param count 县市会员数 157 * @return 158 */ 159 private int findCityVipStatisticChild(List<VipStatisticResponse> child, String area, Integer count) { 160 VipStatisticResponse areaVipStatistic = this.findVipStatistic("area", area, count, clazz); 161 child.add(areaVipStatistic); 162 List<VipStatisticResponse> areaChild = new ArrayList<>(); 163 areaVipStatistic.setChild(areaChild); 164 Map<String, Integer> bankMap = this.getChildAndChildCount("area", "bank", area, clazz); 165 for (String b : bankMap.keySet()) { 166 this.findAreaVipStatisticChild(areaChild, b, bankMap.get(b)); 167 } 168 return 1; 169 } 170 171 /** 172 * 查询省下线会员统计数据 173 * @param child 下线 174 * @param city 地市 175 * @param count 地市会员数 176 * @return 177 */ 178 private int findProvinceVipStatisticChild(List<VipStatisticResponse> child, String city, Integer count) { 179 VipStatisticResponse cityVipStatistic = this.findVipStatistic("city", city, count, clazz); 180 child.add(cityVipStatistic); 181 List<VipStatisticResponse> cityChild = new ArrayList<>(); 182 cityVipStatistic.setChild(cityChild); 183 Map<String, Integer> areaMap = this.getChildAndChildCount("city", "area", city, clazz); 184 // 查询地市下所有县市统计数据 185 for (String a : areaMap.keySet()) { 186 this.findCityVipStatisticChild(cityChild, a, areaMap.get(a)); 187 } 188 return 1; 189 } 190 191 /** 192 * 通用封装统计数据 193 * @param refer 查询标识 194 * @param query 查询条件 195 * @param count 会员数量 196 * @param clazz 类型 197 * @return vipStatistic 198 */ 199 private VipStatisticResponse generateVipStatistic(String refer, String query, Integer count, Class<?> clazz) { 200 VipStatisticResponse vipStatistic = new VipStatisticResponse(); 201 // 查询近7日 202 List<String> past7Date = DateUtils.getSevenDays(); 203 Aggregation aggregation = Aggregation.newAggregation( 204 match( 205 Criteria.where(refer).is(query).and("day").in(past7Date)), 206 group("day") 207 .count().as("total") 208 .first("day").as("day"), 209 project("total", "day"), 210 sort(Sort.Direction.DESC, "day")); 211 AggregationResults<BasicDBObject> result = 212 mongoTemplate.aggregate(aggregation, clazz, BasicDBObject.class); 213 214 if (CollectionUtils.isEmpty(result.getMappedResults())) { 215 throw new AppException(ApiResponseCodeEnum.USER_NOT_EXIST); 216 } 217 218 List<VipChartResponse> sevenDays = new ArrayList<>(); 219 Map<String, Integer> map = new HashMap<>(); 220 for (Iterator<BasicDBObject> iterator = result.iterator(); iterator.hasNext(); ) { 221 DBObject obj = iterator.next(); 222 map.put(obj.get("day").toString(), Integer.valueOf(obj.get("total").toString())); 223 } 224 for (String day : past7Date) { 225 if (map.containsKey(day)) { 226 sevenDays.add(new VipChartResponse(day, map.get(day))); 227 } else { 228 sevenDays.add(new VipChartResponse(day, 0)); 229 } 230 } 231 // 当日 232 int todayCount = sevenDays.get(0).getVip(); 233 234 // 查询近6月 235 List<String> past6Months = DateUtils.getSixMonths(); 236 aggregation = Aggregation.newAggregation( 237 match( 238 Criteria.where(refer).is(query).and("month").in(past6Months)), 239 group("month") 240 .count().as("total") 241 .first("month").as("month"), 242 project("total", "month"), 243 sort(Sort.Direction.DESC, "month")); 244 result = mongoTemplate.aggregate(aggregation, clazz, BasicDBObject.class); 245 if (CollectionUtils.isEmpty(result.getMappedResults())) { 246 throw new AppException(ApiResponseCodeEnum.USER_NOT_EXIST); 247 } 248 List<VipChartResponse> sixMonths = new ArrayList<>(); 249 map = new HashMap<>(); 250 for (Iterator<BasicDBObject> iterator = result.iterator(); iterator.hasNext(); ) { 251 DBObject obj = iterator.next(); 252 map.put(obj.get("month").toString(), Integer.valueOf(obj.get("total").toString())); 253 } 254 255 for (String month : past6Months) { 256 if (map.containsKey(month)) { 257 sixMonths.add(new VipChartResponse(month, map.get(month))); 258 } else { 259 sixMonths.add(new VipChartResponse(month, 0)); 260 } 261 } 262 // 当月 263 int monthCount = sixMonths.get(0).getVip(); 264 265 // 查询累计 266 int total; 267 if (count == null) { 268 aggregation = Aggregation.newAggregation( 269 match( 270 Criteria.where(refer).is(query)), 271 group(refer).count().as("total")); 272 result = mongoTemplate.aggregate(aggregation, clazz, BasicDBObject.class); 273 if (CollectionUtils.isEmpty(result.getMappedResults())) { 274 throw new AppException(ApiResponseCodeEnum.USER_NOT_EXIST); 275 } 276 total = Integer.valueOf(result.getMappedResults().get(0).get("total").toString()); 277 } else { 278 total = count; 279 } 280 vipStatistic.setName(query); 281 vipStatistic.setType(AreaTypeEnum.getByCode(refer.toUpperCase())); 282 vipStatistic.setToday(todayCount); 283 vipStatistic.setThisMonth(monthCount); 284 vipStatistic.setTotal(total); 285 vipStatistic.setSevenDays(sevenDays); 286 vipStatistic.setSixMonths(sixMonths); 287 288 return vipStatistic; 289 } 290 291 /** 292 * 通用会员查询统计方法:可用于邮储食堂正式会员, 体验会员和复购会员 293 * 仅用于父级查询 294 * @param refer 查询标识 295 * @param query 查询条件 296 * @param clazz 类型 297 * @return vipStatistic 298 */ 299 private VipStatisticResponse findVipStatistic(String refer, String query, Class<?> clazz) { 300 return this.generateVipStatistic(refer, query, null, clazz); 301 } 302 303 /** 304 * 通用会员查询统计方法:可用于邮储食堂正式会员, 体验会员和复购会员 305 * 仅用于子级查询 306 * @param refer 查询标识 307 * @param query 查询条件 308 * @param clazz 类型 309 * @return vipStatistic 310 */ 311 private VipStatisticResponse findVipStatistic(String refer, String query, Integer count, Class<?> clazz) { 312 return this.generateVipStatistic(refer, query, count, clazz); 313 } 314 315 }
1 package net.baiqu.shop.data.core.service.impl; 2 3 import com.alibaba.fastjson.JSONObject; 4 import com.mongodb.BasicDBObject; 5 import lombok.extern.slf4j.Slf4j; 6 import net.baiqu.shop.data.api.enums.ApiResponseCodeEnum; 7 import net.baiqu.shop.data.api.enums.report.AreaTypeEnum; 8 import net.baiqu.shop.data.api.models.request.report.ReportQueryRequest; 9 import net.baiqu.shop.data.api.models.response.amount.AmountChartResponse; 10 import net.baiqu.shop.data.api.models.response.amount.AmountStatisticResponse; 11 import net.baiqu.shop.data.core.exception.AppException; 12 import net.baiqu.shop.data.core.service.AmountStatisticService; 13 import net.baiqu.shop.data.core.util.DateUtils; 14 import org.springframework.beans.factory.annotation.Autowired; 15 import org.springframework.data.domain.Sort; 16 import org.springframework.data.mongodb.core.MongoTemplate; 17 import org.springframework.data.mongodb.core.aggregation.Aggregation; 18 import org.springframework.data.mongodb.core.aggregation.AggregationResults; 19 import org.springframework.data.mongodb.core.query.Criteria; 20 import org.springframework.stereotype.Service; 21 import org.springframework.util.CollectionUtils; 22 23 import java.math.BigDecimal; 24 import java.util.ArrayList; 25 import java.util.HashMap; 26 import java.util.List; 27 import java.util.Map; 28 import java.util.concurrent.*; 29 import java.util.stream.Collectors; 30 31 import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; 32 33 @Service 34 @Slf4j 35 public class AmountStatisticServiceImpl implements AmountStatisticService { 36 37 private ExecutorService executor; 38 39 @Autowired 40 private MongoTemplate mongoTemplate; 41 42 private Class<?> clazz; 43 44 public AmountStatisticServiceImpl() { 45 executor = new ThreadPoolExecutor( 46 5, 47 10, 48 60, 49 TimeUnit.SECONDS, new LinkedBlockingQueue<>(), 50 new ThreadPoolExecutor.AbortPolicy()); 51 } 52 53 /** 54 * 查询消费统计 55 * 56 * @return 57 */ 58 @Override 59 public AmountStatisticResponse getAmountStatistic(ReportQueryRequest request, Class<?> clazz) { 60 this.clazz = clazz; 61 String province = request.getProvince(); 62 String city = request.getCity(); 63 String area = request.getArea(); 64 String bank = request.getBank(); 65 //下线集合 66 List<AmountStatisticResponse> child = new ArrayList<>(); 67 AmountStatisticResponse reportStatistic; 68 if (city == null) { 69 reportStatistic = getAmountChart("province", province); 70 reportStatistic.setTotal(getTotal("province", province)); 71 log.info("getAmountStatistic->reportStatistic 省统计数据:{}", JSONObject.toJSONString(reportStatistic)); 72 //查询省份下线城市 73 Map<String, BigDecimal> proChild = getChildMap("province", province, "city"); 74 List<CompletableFuture<Integer>> tasks = proChild.keySet().stream() 75 .map(c -> CompletableFuture.supplyAsync(() -> { 76 return getProChild(proChild, child, c); 77 }, executor)).collect(Collectors.toList()); 78 tasks.stream().map(CompletableFuture::join).collect(Collectors.toList()); 79 reportStatistic.setChild(child); 80 } else if (area == null) { 81 reportStatistic = getAmountChart("city", city); 82 reportStatistic.setTotal(getTotal("city", city)); 83 log.info("getAmountStatistic->reportStatistic 地市统计数据:{}", JSONObject.toJSONString(reportStatistic)); 84 //查询城市下线地区 85 Map<String, BigDecimal> cityChild = getChildMap("city", city, "area"); 86 List<CompletableFuture<Integer>> tasks = cityChild.keySet().stream() 87 .map(c -> CompletableFuture.supplyAsync(() -> { 88 return getCityChild(cityChild, child, c); 89 }, executor)).collect(Collectors.toList()); 90 tasks.stream().map(CompletableFuture::join).collect(Collectors.toList()); 91 reportStatistic.setChild(child); 92 } else if (bank == null) { 93 reportStatistic = getAmountChart("area", area); 94 reportStatistic.setTotal(getTotal("area", area)); 95 log.info("getAmountStatistic->reportStatistic 县市统计数据:{}", JSONObject.toJSONString(reportStatistic)); 96 //查询地区下线支行 97 Map<String, BigDecimal> areaChild = getChildMap("area", area, "bank"); 98 List<CompletableFuture<Integer>> tasks = areaChild.keySet().stream() 99 .map(c -> CompletableFuture.supplyAsync(() -> { 100 return getAreaChild(areaChild, child, c); 101 }, executor)).collect(Collectors.toList()); 102 tasks.stream().map(CompletableFuture::join).collect(Collectors.toList()); 103 reportStatistic.setChild(child); 104 } else { 105 reportStatistic = getAmountChart("bank", bank); 106 reportStatistic.setTotal(getTotal("bank", bank)); 107 log.info("getAmountStatistic->reportStatistic 支行统计数据:{}", JSONObject.toJSONString(reportStatistic)); 108 } 109 //log.info("getReportStastic-->response:{}", JSONObject.toJSONString(reportStatistic)); 110 return reportStatistic; 111 } 112 113 /** 114 * 查询顶级组织的总金额 115 * 116 * @param areaType 区域类型 117 * @param area 区域 118 * @return 119 */ 120 private BigDecimal getTotal(String areaType, String area) { 121 Aggregation agg = Aggregation.newAggregation( 122 match(Criteria.where(areaType).is(area)), 123 group(areaType).sum("amount").as("total")); 124 AggregationResults<BasicDBObject> results = mongoTemplate.aggregate(agg, clazz, BasicDBObject.class); 125 if (results.getMappedResults() == null || results.getMappedResults().size() < 1) { 126 return new BigDecimal(0); 127 } 128 return new BigDecimal(results.getMappedResults().get(0).get("total").toString()); 129 } 130 131 /** 132 * 获取折现图和当日、当月金额 133 * 134 * @param areaType 区域类型 135 * @param area 区域 136 * @return 137 */ 138 private AmountStatisticResponse getAmountChart(String areaType, String area) { 139 AmountStatisticResponse reportStatistic = new AmountStatisticResponse(); 140 reportStatistic.setName(area); 141 reportStatistic.setType(AreaTypeEnum.getByCode(areaType.toUpperCase())); 142 //7日数据 143 List<AmountChartResponse> sevenDays = getAmountChartResults(areaType, area, "day", DateUtils.getSevenDays()); 144 reportStatistic.setToday(sevenDays.get(0).getAmount()); 145 reportStatistic.setSevenDays(sevenDays); 146 //6个月数据 147 List<AmountChartResponse> sixMonths = getAmountChartResults(areaType, area, "month", DateUtils.getSixMonths()); 148 reportStatistic.setThisMonth(sixMonths.get(0).getAmount()); 149 reportStatistic.setSixMonths(sixMonths); 150 return reportStatistic; 151 } 152 153 /** 154 * 获取折线图数据 155 * 156 * @param areaType 区域类型 157 * @param area 区域 158 * @param dateType 时间类型 159 * @param dates 时间集合 160 * @return 161 */ 162 private List<AmountChartResponse> getAmountChartResults(String areaType, String area, String dateType, List<String> dates) { 163 Aggregation agg = Aggregation.newAggregation( 164 match(Criteria.where(areaType).is(area).and(dateType).in(dates)), 165 group(dateType).sum("amount").as("amount"), 166 project("amount").and("_id").as("date"), 167 sort(Sort.Direction.DESC, "date")); 168 AggregationResults<BasicDBObject> results = mongoTemplate.aggregate(agg, clazz, BasicDBObject.class); 169 if (CollectionUtils.isEmpty(results.getMappedResults())) { 170 throw new AppException(ApiResponseCodeEnum.ORDER_NOT_EXIST); 171 } 172 Map<String, BigDecimal> map = new HashMap<>(); 173 for (BasicDBObject result : results) { 174 String date = result.getString("date"); 175 BigDecimal amount = new BigDecimal(result.get("amount").toString()); 176 map.put(date, amount); 177 } 178 List<AmountChartResponse> list = new ArrayList<>(); 179 for (int i = 0; i < dates.size(); i++) { 180 AmountChartResponse amountChart = new AmountChartResponse(); 181 if (map.containsKey(dates.get(i))) { 182 amountChart.setAmount(map.get(dates.get(i))); 183 } else { 184 amountChart.setAmount(new BigDecimal(0)); 185 } 186 amountChart.setDate(dates.get(i)); 187 list.add(amountChart); 188 } 189 // log.info("AmountStatisticServiceImpl->getAmountChartResults: {}", JSONObject.toJSONString(list)); 190 return list; 191 } 192 193 194 /** 195 * 查询下线以及下线的总金额 196 * 197 * @param parentType 上级类型 198 * @param area 要查询的地区 199 * @param childType 下级类型 200 * @return 201 */ 202 private Map<String, BigDecimal> getChildMap(String parentType, String area, String childType) { 203 Map<String, BigDecimal> map = new HashMap<>(); 204 Aggregation agg = Aggregation.newAggregation( 205 match(Criteria.where(parentType).is(area)), 206 group(childType).sum("amount").as("amount")); 207 AggregationResults<BasicDBObject> results = mongoTemplate.aggregate(agg, clazz, BasicDBObject.class); 208 if (CollectionUtils.isEmpty(results.getMappedResults())) { 209 throw new AppException(ApiResponseCodeEnum.ORDER_NOT_EXIST); 210 } 211 for (BasicDBObject result : results) { 212 String newArea = result.getString("_id"); 213 BigDecimal amount = new BigDecimal(result.get("amount").toString()); 214 map.put(newArea, amount); 215 } 216 // log.info("AmountStatisticServiceImpl->getChildMap: {}", JSONObject.toJSONString(map)); 217 return map; 218 } 219 220 221 /** 222 * 获取省份子集 223 * 224 * @param childMap 子集map 225 * @param child 下线子集 226 * @param city 城市 227 * @return 228 */ 229 private int getProChild(Map<String, BigDecimal> childMap, List<AmountStatisticResponse> child, String city) { 230 AmountStatisticResponse cityStatistic = getAmountChart("city", city); 231 cityStatistic.setTotal(childMap.get(city)); 232 Map<String, BigDecimal> cityChild = getChildMap("city", city, "area"); 233 //查询下线区域孩子 234 List<AmountStatisticResponse> cityChildStatistic = new ArrayList<>(); 235 for (String area : cityChild.keySet()) { 236 getCityChild(cityChild, cityChildStatistic, area); 237 } 238 // log.info("AmountStatisticServiceImpl->getProChild: {}", JSONObject.toJSONString(cityChildStatistic)); 239 cityStatistic.setChild(cityChildStatistic); 240 child.add(cityStatistic); 241 return 1; 242 } 243 244 245 /** 246 * 获取城市子集 247 * 248 * @param childMap 子集map 249 * @param child 下线子集 250 * @param area 区域 251 * @return 252 */ 253 private int getCityChild(Map<String, BigDecimal> childMap, List<AmountStatisticResponse> child, String area) { 254 AmountStatisticResponse areaStatistic = getAmountChart("area", area); 255 areaStatistic.setTotal(childMap.get(area)); 256 Map<String, BigDecimal> areaChild = getChildMap("area", area, "bank"); 257 //查询下线区域孩子 258 List<AmountStatisticResponse> areaChildStatistic = new ArrayList<>(); 259 for (String bank : areaChild.keySet()) { 260 getAreaChild(areaChild, areaChildStatistic, bank); 261 } 262 // log.info("AmountStatisticServiceImpl->getCityChild: {}", JSONObject.toJSONString(areaChildStatistic)); 263 areaStatistic.setChild(areaChildStatistic); 264 child.add(areaStatistic); 265 return 1; 266 } 267 268 269 /** 270 * 获取区域子集 271 * 272 * @param childMap 子集map 273 * @param child 下线子集 274 * @param bank 支行 275 * @return 276 */ 277 private int getAreaChild(Map<String, BigDecimal> childMap, List<AmountStatisticResponse> child, String bank) { 278 AmountStatisticResponse bankStatistic = getbankStatistic(childMap, bank); 279 // log.info("AmountStatisticServiceImpl->getAreaChild: {}", JSONObject.toJSONString(bankStatistic)); 280 child.add(bankStatistic); 281 return 1; 282 } 283 284 /** 285 * 获取支行统计 286 * 287 * @param childMap 子集map 288 * @param bank 支行 289 * @return 290 */ 291 private AmountStatisticResponse getbankStatistic(Map<String, BigDecimal> childMap, String bank) { 292 AmountStatisticResponse bankStatistic = getAmountChart("bank", bank); 293 // log.info("AmountStatisticServiceImpl->getbankStatistic: {}", JSONObject.toJSONString(bankStatistic)); 294 bankStatistic.setTotal(childMap.get(bank)); 295 return bankStatistic; 296 } 297 298 }