|
@@ -1204,7 +1204,7 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
|
|
|
LambdaUpdateWrapper<OrderMain> updateWrapper = new LambdaUpdateWrapper<>();
|
|
LambdaUpdateWrapper<OrderMain> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
|
|
|
|
|
// 设置更新后的值
|
|
// 设置更新后的值
|
|
|
- updateWrapper.set(OrderMain::getOrderStatus, OrderStatus.COMPLETED.getCode());
|
|
|
|
|
|
|
+ updateWrapper.set(OrderMain::getOrderStatus, OrderStatus.COMPLETED.getCode()).set(OrderMain::getReceivingTime, new Date());
|
|
|
|
|
|
|
|
// 构建 WHERE 条件逻辑:
|
|
// 构建 WHERE 条件逻辑:
|
|
|
// (id IN (...) OR parentOrderId IN (...)) AND orderStatus = SHIPPED
|
|
// (id IN (...) OR parentOrderId IN (...)) AND orderStatus = SHIPPED
|
|
@@ -2288,4 +2288,214 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
|
|
|
|
|
|
|
|
return R.ok(vo);
|
|
return R.ok(vo);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public TableDataInfo<DeptPurchaseVo> deptPurchase(Long customerId, Long contactId, PageQuery pageQuery) {
|
|
|
|
|
+ // 1. 查询当前客户的所有非子单订单
|
|
|
|
|
+ LambdaQueryWrapper<OrderMain> wrapper = new LambdaQueryWrapper<OrderMain>()
|
|
|
|
|
+ .eq(OrderMain::getCustomerId, customerId)
|
|
|
|
|
+ .eq(OrderMain::getCurrentLevel, 1)
|
|
|
|
|
+ .eq(OrderMain::getDelFlag, "0");
|
|
|
|
|
+ // 可选:按下单人筛选
|
|
|
|
|
+ if (contactId != null) {
|
|
|
|
|
+ wrapper.eq(OrderMain::getContactId, contactId);
|
|
|
|
|
+ }
|
|
|
|
|
+ List<OrderMain> orders = baseMapper.selectList(wrapper
|
|
|
|
|
+ .select(OrderMain::getTotalAmount, OrderMain::getOrderStatus, OrderMain::getContactId));
|
|
|
|
|
+
|
|
|
|
|
+ if (CollUtil.isEmpty(orders)) {
|
|
|
|
|
+ return new TableDataInfo<>(Collections.emptyList(), 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 按 contactId 分组,计算金额
|
|
|
|
|
+ Map<Long, BigDecimal[]> amountMap = new LinkedHashMap<>(); // [totalAmount, completedAmount, pendingAmount]
|
|
|
|
|
+ for (OrderMain order : orders) {
|
|
|
|
|
+ Long orderContactId = order.getContactId();
|
|
|
|
|
+ if (orderContactId == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ BigDecimal orderAmount = order.getTotalAmount() != null ? order.getTotalAmount() : BigDecimal.ZERO;
|
|
|
|
|
+ BigDecimal[] amounts = amountMap.computeIfAbsent(orderContactId, k -> new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO});
|
|
|
|
|
+ amounts[0] = amounts[0].add(orderAmount); // 总金额
|
|
|
|
|
+ // orderStatus >= 5 为已完成
|
|
|
|
|
+ if (Integer.parseInt(order.getOrderStatus()) >= 5) {
|
|
|
|
|
+ amounts[1] = amounts[1].add(orderAmount); // 已完成
|
|
|
|
|
+ } else {
|
|
|
|
|
+ amounts[2] = amounts[2].add(orderAmount); // 待完成
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (amountMap.isEmpty()) {
|
|
|
|
|
+ return new TableDataInfo<>(Collections.emptyList(), 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 远程批量查询联系人信息(含部门名称、联系人姓名)
|
|
|
|
|
+ Map<Long, RemoteCustomerContactVo> contactMap = remoteCustomerContactService.selectCustomerContactByIds(amountMap.keySet());
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 组装结果列表
|
|
|
|
|
+ List<DeptPurchaseVo> allList = new ArrayList<>();
|
|
|
|
|
+ for (Map.Entry<Long, BigDecimal[]> entry : amountMap.entrySet()) {
|
|
|
|
|
+ Long ctId = entry.getKey();
|
|
|
|
|
+ BigDecimal[] amounts = entry.getValue();
|
|
|
|
|
+
|
|
|
|
|
+ DeptPurchaseVo vo = new DeptPurchaseVo();
|
|
|
|
|
+ RemoteCustomerContactVo contact = contactMap.get(ctId);
|
|
|
|
|
+ if (contact != null) {
|
|
|
|
|
+ vo.setDeptName(contact.getDeptName());
|
|
|
|
|
+ vo.setOrderPerson(contact.getContactName());
|
|
|
|
|
+ }
|
|
|
|
|
+ vo.setOrderAmount(amounts[0]);
|
|
|
|
|
+ vo.setCompletedAmount(amounts[1]);
|
|
|
|
|
+ vo.setPendingAmount(amounts[2]);
|
|
|
|
|
+ allList.add(vo);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 内存分页
|
|
|
|
|
+ int total = allList.size();
|
|
|
|
|
+ int pageNum = pageQuery != null ? pageQuery.getPageNum() : 1;
|
|
|
|
|
+ int pageSize = pageQuery != null ? pageQuery.getPageSize() : 10;
|
|
|
|
|
+ int fromIndex = (pageNum - 1) * pageSize;
|
|
|
|
|
+ if (fromIndex >= total) {
|
|
|
|
|
+ return new TableDataInfo<>(Collections.emptyList(), total);
|
|
|
|
|
+ }
|
|
|
|
|
+ int toIndex = Math.min(fromIndex + pageSize, total);
|
|
|
|
|
+ List<DeptPurchaseVo> pageList = allList.subList(fromIndex, toIndex);
|
|
|
|
|
+
|
|
|
|
|
+ return new TableDataInfo<>(pageList, total);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public R<PurchaseDetailVo> purchaseDetail(Long customerId) {
|
|
|
|
|
+ PurchaseDetailVo vo = new PurchaseDetailVo();
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 1. 查询当前客户的非子单订单 ==========
|
|
|
|
|
+ List<OrderMain> orders = baseMapper.selectList(new LambdaQueryWrapper<OrderMain>()
|
|
|
|
|
+ .eq(OrderMain::getCustomerId, customerId)
|
|
|
|
|
+ .eq(OrderMain::getCurrentLevel, 1)
|
|
|
|
|
+ .eq(OrderMain::getDelFlag, "0"));
|
|
|
|
|
+
|
|
|
|
|
+ long orderCount = orders.size(); // 购买数量(件)
|
|
|
|
|
+
|
|
|
|
|
+ if (CollUtil.isEmpty(orders)) {
|
|
|
|
|
+ vo.setStatData(buildStatData("0", "0", "0", "0"));
|
|
|
|
|
+ vo.setAfterSaleData(buildAfterSaleData("0", "0", "0%",
|
|
|
|
|
+ Collections.emptyList(), Collections.emptyList(), Collections.emptyList()));
|
|
|
|
|
+ return R.ok(vo);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ List<Long> orderIds = orders.stream().map(OrderMain::getId).collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 2. 查询订单商品(去重产品数、品牌数、品类数) ==========
|
|
|
|
|
+ List<OrderProduct> orderProducts = orderProductMapper.selectList(new LambdaQueryWrapper<OrderProduct>()
|
|
|
|
|
+ .in(OrderProduct::getOrderId, orderIds)
|
|
|
|
|
+ .eq(OrderProduct::getDelFlag, "0"));
|
|
|
|
|
+
|
|
|
|
|
+ Set<Long> productIds = orderProducts.stream()
|
|
|
|
|
+ .map(OrderProduct::getProductId)
|
|
|
|
|
+ .filter(Objects::nonNull)
|
|
|
|
|
+ .collect(Collectors.toSet());
|
|
|
|
|
+ long productCount = productIds.size(); // 商品数量(件)
|
|
|
|
|
+
|
|
|
|
|
+ // 远程查询商品品牌和品类
|
|
|
|
|
+ long brandCount = 0;
|
|
|
|
|
+ long categoryCount = 0;
|
|
|
|
|
+ if (CollUtil.isNotEmpty(productIds)) {
|
|
|
|
|
+ List<ProductVo> productVos = remoteProductService.getProductDetails(new ArrayList<>(productIds));
|
|
|
|
|
+ if (CollUtil.isNotEmpty(productVos)) {
|
|
|
|
|
+ brandCount = productVos.stream()
|
|
|
|
|
+ .map(ProductVo::getBrandId)
|
|
|
|
|
+ .filter(Objects::nonNull)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .count();
|
|
|
|
|
+ // 三类品类 = 去重的底级分类
|
|
|
|
|
+ categoryCount = productVos.stream()
|
|
|
|
|
+ .map(ProductVo::getBottomCategoryId)
|
|
|
|
|
+ .filter(Objects::nonNull)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .count();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 3. 售后统计 ==========
|
|
|
|
|
+ // 售后商品数量 = sum(returnProductNum)
|
|
|
|
|
+ List<OrderReturn> orderReturns = orderReturnMapper.selectList(new LambdaQueryWrapper<OrderReturn>()
|
|
|
|
|
+ .eq(OrderReturn::getCustomerId, customerId)
|
|
|
|
|
+ .eq(OrderReturn::getDelFlag, "0"));
|
|
|
|
|
+ long afterSaleProductCount = orderReturns.stream()
|
|
|
|
|
+ .map(OrderReturn::getReturnProductNum)
|
|
|
|
|
+ .filter(Objects::nonNull)
|
|
|
|
|
+ .mapToLong(Long::longValue)
|
|
|
|
|
+ .sum();
|
|
|
|
|
+
|
|
|
|
|
+ // 售后商品占比 = 售后商品数 / 商品总数 * 100%
|
|
|
|
|
+ String afterSaleRatio;
|
|
|
|
|
+ if (productCount > 0) {
|
|
|
|
|
+ BigDecimal ratio = BigDecimal.valueOf(afterSaleProductCount)
|
|
|
|
|
+ .multiply(BigDecimal.valueOf(100))
|
|
|
|
|
+ .divide(BigDecimal.valueOf(productCount), 1, java.math.RoundingMode.HALF_UP);
|
|
|
|
|
+ afterSaleRatio = ratio.stripTrailingZeros().toPlainString() + "%";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ afterSaleRatio = "0%";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 平均完成时效 = average(receivingTime - createTime) for 已完成订单(orderStatus >= 5)
|
|
|
|
|
+ long avgDays = 0;
|
|
|
|
|
+ List<OrderMain> completedOrders = orders.stream()
|
|
|
|
|
+ .filter(o -> o.getReceivingTime() != null && o.getCreateTime() != null
|
|
|
|
|
+ && Integer.parseInt(o.getOrderStatus()) >= 5)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ if (!completedOrders.isEmpty()) {
|
|
|
|
|
+ long totalDays = completedOrders.stream()
|
|
|
|
|
+ .mapToLong(o -> {
|
|
|
|
|
+ long diffMillis = o.getReceivingTime().getTime() - o.getCreateTime().getTime();
|
|
|
|
|
+ return Math.max(0, diffMillis / (1000 * 60 * 60 * 24));
|
|
|
|
|
+ })
|
|
|
|
|
+ .sum();
|
|
|
|
|
+ avgDays = totalDays / completedOrders.size();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 4. 组装返回数据 ==========
|
|
|
|
|
+ vo.setStatData(buildStatData(
|
|
|
|
|
+ String.valueOf(orderCount),
|
|
|
|
|
+ String.valueOf(productCount),
|
|
|
|
|
+ String.valueOf(brandCount),
|
|
|
|
|
+ String.valueOf(categoryCount)
|
|
|
|
|
+ ));
|
|
|
|
|
+ vo.setAfterSaleData(buildAfterSaleData(
|
|
|
|
|
+ String.valueOf(afterSaleProductCount),
|
|
|
|
|
+ String.valueOf(avgDays),
|
|
|
|
|
+ afterSaleRatio,
|
|
|
|
|
+ Collections.emptyList(),
|
|
|
|
|
+ Collections.emptyList(),
|
|
|
|
|
+ Collections.emptyList()
|
|
|
|
|
+ ));
|
|
|
|
|
+
|
|
|
|
|
+ return R.ok(vo);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private List<PurchaseDetailVo.StatItem> buildStatData(String orderCount, String productCount,
|
|
|
|
|
+ String brandCount, String categoryCount) {
|
|
|
|
|
+ List<PurchaseDetailVo.StatItem> list = new ArrayList<>();
|
|
|
|
|
+ list.add(new PurchaseDetailVo.StatItem().setValue(orderCount).setLabel("购买数量(件)"));
|
|
|
|
|
+ list.add(new PurchaseDetailVo.StatItem().setValue(productCount).setLabel("商品数量(件)"));
|
|
|
|
|
+ list.add(new PurchaseDetailVo.StatItem().setValue(brandCount).setLabel("品牌数量(件)"));
|
|
|
|
|
+ list.add(new PurchaseDetailVo.StatItem().setValue(categoryCount).setLabel("三类品类数量(件)"));
|
|
|
|
|
+ return list;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private List<PurchaseDetailVo.AfterSaleItem> buildAfterSaleData(String afterSaleCount, String avgDays,
|
|
|
|
|
+ String ratio, List<Integer> data1,
|
|
|
|
|
+ List<Integer> data2, List<Integer> data3) {
|
|
|
|
|
+ List<PurchaseDetailVo.AfterSaleItem> list = new ArrayList<>();
|
|
|
|
|
+ list.add(new PurchaseDetailVo.AfterSaleItem()
|
|
|
|
|
+ .setLabel("售后商品数量(件)").setValue(afterSaleCount)
|
|
|
|
|
+ .setData(data1).setColor("#e60012").setType("line"));
|
|
|
|
|
+ list.add(new PurchaseDetailVo.AfterSaleItem()
|
|
|
|
|
+ .setLabel("平均完成时效(天)").setValue(avgDays)
|
|
|
|
|
+ .setData(data2).setColor("#3498db").setType("bar"));
|
|
|
|
|
+ list.add(new PurchaseDetailVo.AfterSaleItem()
|
|
|
|
|
+ .setLabel("售后商品占比").setValue(ratio)
|
|
|
|
|
+ .setData(data3).setColor("#f4c542").setType("line"));
|
|
|
|
|
+ return list;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|