From 8819caa79166d0d4e8d874850285c5095c5350d0 Mon Sep 17 00:00:00 2001 From: xuyuncong <3422692813@qq.com> Date: Tue, 4 Nov 2025 18:40:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=91=98=E5=B7=A5=E7=BB=9F=E8=AE=A1=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=80=BB=E6=A3=80=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../base/mapper/RepairStatisticsMapper.java | 9 + .../impl/RepairStatisticsServiceImpl.java | 360 ++++++++++++++---- .../mapper/base/RepairStatisticsMapper.xml | 30 +- 3 files changed, 318 insertions(+), 81 deletions(-) diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/mapper/RepairStatisticsMapper.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/mapper/RepairStatisticsMapper.java index 5fff2528..f1de2ec4 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/mapper/RepairStatisticsMapper.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/mapper/RepairStatisticsMapper.java @@ -286,4 +286,13 @@ public interface RepairStatisticsMapper { List> selectWorkerStatisticsByUserIds(@Param("userIds") List userIds, @Param("startDate") String startDate, @Param("endDate") String endDate); + + /** + * 查询指定服务顾问的统计数据(产值和毛利) + * @param advisorId 服务顾问ID + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 包含产值和毛利的统计数据 + */ + Map selectAdvisorStatistics(@Param("advisorId") Long advisorId, @Param("startDate") String startDate, @Param("endDate") String endDate); } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStatisticsServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStatisticsServiceImpl.java index 9400e567..fb129604 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStatisticsServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStatisticsServiceImpl.java @@ -14,11 +14,13 @@ import cn.iocoder.yudao.module.business.entity.DlBusinessChannel; import cn.iocoder.yudao.module.business.service.BusinessChannelService; import cn.iocoder.yudao.module.system.api.dict.DictDataApi; import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; +import cn.iocoder.yudao.module.system.api.user.dto.UserDTO; import cn.iocoder.yudao.module.tickets.entity.DlRepairTickets; import cn.iocoder.yudao.module.tickets.service.DlRepairTicketsService; import cn.iocoder.yudao.module.tickets.vo.DlRepairTicketsRespVO; import cn.iocoder.yudao.util.StringUtils; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -33,6 +35,7 @@ import cn.hutool.core.util.ObjectUtil; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; import static cn.iocoder.yudao.common.RepairCons.DICT_REPAIR_WORK_TYPE; @@ -69,6 +72,9 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService { @Resource private RepairWorkerService workerService; + @Resource + private cn.iocoder.yudao.module.system.api.permission.RoleApi roleApi; + /** * 将统计结果列表转换为Map格式 * @param list 统计结果列表,每个元素包含key和value字段 @@ -250,7 +256,7 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService { /** * @Author 许 - * @Description 统计最近业务(车辆或客户) + * @Description 统计最近业务(车辆或客户) * @Date 15:03 2025/8/25 * @Param [reqVO, page] * @return com.baomidou.mybatisplus.core.metadata.IPage @@ -259,9 +265,9 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService { public IPage listBusinessByCustomerOrCar(QueryBusinessReqVO reqVO, Page page) { IPage queryBusinessResps = null; if ("customer".equals(reqVO.getType())) { - queryBusinessResps = statisticsMapper.listBusinessByCustomer(reqVO,page); - }else if ("car".equals(reqVO.getType())) { - queryBusinessResps = statisticsMapper.listBusinessByCar(reqVO,page); + queryBusinessResps = statisticsMapper.listBusinessByCustomer(reqVO, page); + } else if ("car".equals(reqVO.getType())) { + queryBusinessResps = statisticsMapper.listBusinessByCar(reqVO, page); } return queryBusinessResps; } @@ -275,7 +281,7 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService { */ @Override public IPage pageByCustomerOrCar(QueryBusinessReqVO reqVO, Page page) { - IPage queryTableResps = statisticsMapper.pageByCustomerOrCar(reqVO,page); + IPage queryTableResps = statisticsMapper.pageByCustomerOrCar(reqVO, page); return queryTableResps; } @@ -304,7 +310,7 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService { // 查询所有渠道 List channels = businessChannelService.list(Wrappers.lambdaQuery() .eq(DlBusinessChannel::getSystemCode, "repair") - .eq(StringUtils.isEmpty(reqVO.getSearch()),DlBusinessChannel::getType, 0) + .eq(StringUtils.isEmpty(reqVO.getSearch()), DlBusinessChannel::getType, 0) .eq(StringUtils.isNotEmpty(reqVO.getSearch()), DlBusinessChannel::getPid, reqVO.getSearch())); List> resp = new ArrayList<>(); @@ -324,7 +330,7 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService { try { // 查询渠道排名 Map bossNumStatistics = ticketsService.getBossNumStatistics( - startDate, endDate, StringUtils.isNotEmpty(reqVO.getSearch()) ? null :channel.getName(), StringUtils.isNotEmpty(reqVO.getSearch()) ? channel.getName() :null, false); + startDate, endDate, StringUtils.isNotEmpty(reqVO.getSearch()) ? null : channel.getName(), StringUtils.isNotEmpty(reqVO.getSearch()) ? channel.getName() : null, false); respMap.put("name", channel.getName()); respMap.put("id", channel.getId()); @@ -402,8 +408,8 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService { List tickets = ticketsService.list(Wrappers.lambdaQuery() .between("insurance".equals(reqVO.getType()) && CollUtil.isNotEmpty(reqVO.getDateRange()), DlRepairTickets::getInsuranceExpiryDate, reqVO.getDateRange().get(0), reqVO.getDateRange().get(1)) .between("inspection".equals(reqVO.getType()) && CollUtil.isNotEmpty(reqVO.getDateRange()), DlRepairTickets::getNextInspectionDate, reqVO.getDateRange().get(0), reqVO.getDateRange().get(1)) - .orderByDesc("insurance".equals(reqVO.getType()),DlRepairTickets::getInsuranceExpiryDate) - .orderByDesc("inspection".equals(reqVO.getType()),DlRepairTickets::getNextInspectionDate)); + .orderByDesc("insurance".equals(reqVO.getType()), DlRepairTickets::getInsuranceExpiryDate) + .orderByDesc("inspection".equals(reqVO.getType()), DlRepairTickets::getNextInspectionDate)); return tickets; } @@ -557,14 +563,14 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService { //查询记录表 zj的数量 long zjCount = repairRecordsService.count(Wrappers.lambdaQuery() - .eq(RepairRecords::getType, RecordTypeEnum.ZJ.getCode()) - .between(StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate), RepairRecords::getCreateTime, startDate, endDate)); + .eq(RepairRecords::getType, RecordTypeEnum.ZJ.getCode()) + .between(StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate), RepairRecords::getCreateTime, startDate, endDate)); resp.add(new HashMap() {{ put("name", "总检"); put("id", "zj"); - put("count", nfpgCount); - put("count2", zjCount); + put("nfpgCount", nfpgCount); + put("zjCount", zjCount); }}); return resp; @@ -692,74 +698,276 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService { List> resp = new ArrayList<>(); - // 根据workType查询该工种下的所有员工 - List workers = workerService.listByWorkType(workType); - - // 如果没有员工,直接返回空列表 - if (workers == null || workers.isEmpty()) { - return resp; - } - - // 对每个员工进行统计 - for (RepairWorkerRespVO worker : workers) { - Long userId = worker.getUserId(); - if (userId == null) { - continue; - } - - List userIds = Collections.singletonList(userId); + // 特殊处理:当workType等于fwgw时,查询角色为fwgw的员工 + if ("fwgw".equals(workType)) { try { - // 查询员工的统计数据 - List> workerStats = statisticsMapper.selectWorkerStatisticsByUserIds(userIds, startDate, endDate); - if (workerStats != null && !workerStats.isEmpty()) { - Map workerStat = workerStats.get(0); + // 获取当前租户ID + Long tenantId = cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder.getRequiredTenantId(); + // 查询角色为fwgw的员工列表(服务顾问) + List advisors = roleApi.selectUserListByRoleCode(tenantId, "service_advisor"); - Map respMap = new HashMap<>(); - respMap.put("name", worker.getUserName()); - respMap.put("id", userId); + // 如果没有员工,直接返回空列表 + if (advisors == null || advisors.isEmpty()) { + return resp; + } - // 构造与workTypeStatistics相同格式的数据 - Map dataMap = new HashMap<>(); - List> statsList = new ArrayList<>(); + // 对每个服务顾问进行统计 + for (cn.iocoder.yudao.module.system.api.user.dto.UserDTO advisor : advisors) { + Long userId = advisor.getId(); + if (userId == null) { + continue; + } - // 添加进厂数统计 - Map newOrderNode = new HashMap<>(); - newOrderNode.put("code", "newOrderNum"); - newOrderNode.put("name", "订单(进厂数)"); - newOrderNode.put("selectType", "jinchang"); - newOrderNode.put("total", workerStat.get("ticketCount")); - statsList.add(newOrderNode); - respMap.put("count", workerStat.get("ticketCount")); + try { + Map respMap = new HashMap<>(); + respMap.put("name", advisor.getNickname()); + respMap.put("id", userId); - // 添加维修中统计 - Map workingNode = new HashMap<>(); - workingNode.put("code", "workingNum"); - workingNode.put("name", "维修中"); - workingNode.put("selectType", "weixiuzhong"); - workingNode.put("total", workerStat.get("workingCount")); - statsList.add(workingNode); + // 构造与workTypeStatistics相同格式的数据 + Map dataMap = new HashMap<>(); + List> statsList = new ArrayList<>(); - // 添加已竣工统计 - Map completedNode = new HashMap<>(); - completedNode.put("code", "overNum"); - completedNode.put("name", "已竣工"); - completedNode.put("selectType", "yijungong"); - completedNode.put("total", workerStat.get("completedCount")); - statsList.add(completedNode); + // 初始化统计数据 +// Integer ticketCount = 0; +// Integer workingCount = 0; +// Integer completedCount = 0; + BigDecimal totalAmount = BigDecimal.ZERO; + BigDecimal grossProfit = BigDecimal.ZERO; - dataMap.put("stats", statsList); - respMap.put("data", dataMap); + // 1. 查询该服务顾问的工单统计数据(接单量、维修中、已竣工) +// List userIds = Collections.singletonList(userId); +// List> workerStats = statisticsMapper.selectWorkerStatisticsByUserIds(userIds, startDate, endDate); +// +// if (workerStats != null && !workerStats.isEmpty()) { +// Map workerStat = workerStats.get(0); +// ticketCount = workerStat.get("ticketCount") instanceof Number ? ((Number) workerStat.get("ticketCount")).intValue() : 0; +// workingCount = workerStat.get("workingCount") instanceof Number ? ((Number) workerStat.get("workingCount")).intValue() : 0; +// completedCount = workerStat.get("completedCount") instanceof Number ? ((Number) workerStat.get("completedCount")).intValue() : 0; +// } - resp.add(respMap); + // 2. 使用selectAdvisorStatistics方法统计产值和毛利润 + Map statistics = statisticsMapper.selectAdvisorStatistics(userId, startDate, endDate); + + if (statistics != null) { + // 获取产值(总金额) + totalAmount = statistics.get("totalOutput") instanceof Number ? + new BigDecimal(statistics.get("totalOutput").toString()) : BigDecimal.ZERO; + // 获取毛利(配件毛利) + grossProfit = statistics.get("totalProfit") instanceof Number ? + new BigDecimal(statistics.get("totalProfit").toString()) : BigDecimal.ZERO; + } + + // 添加产值统计 + Map amountNode = new HashMap<>(); + amountNode.put("code", "totalAmount"); + amountNode.put("name", "产值"); + amountNode.put("selectType", "chanzhi"); + amountNode.put("total", totalAmount); + statsList.add(amountNode); + respMap.put("amount", totalAmount); + respMap.put("count", totalAmount); + + // 添加毛利润统计 + Map profitNode = new HashMap<>(); + profitNode.put("code", "grossProfit"); + profitNode.put("name", "毛利润"); + profitNode.put("selectType", "maolirun"); + profitNode.put("total", grossProfit); + statsList.add(profitNode); + respMap.put("profit", grossProfit); + + dataMap.put("stats", statsList); + respMap.put("data", dataMap); + + resp.add(respMap); + } catch (Exception e) { + // 记录异常但不中断整个流程 + log.warn("获取服务顾问统计信息时发生异常,员工ID: {}", userId, e); + // 添加一个默认的统计对象,避免前端出现空值 + Map defaultStats = new HashMap<>(); + defaultStats.put("name", advisor.getNickname()); + defaultStats.put("id", userId); + resp.add(defaultStats); + } } } catch (Exception e) { - // 记录异常但不中断整个流程 - log.warn("获取员工统计信息时发生异常,员工ID: {}", userId, e); - // 添加一个默认的统计对象,避免前端出现空值 - Map defaultStats = new HashMap<>(); - defaultStats.put("name", worker.getUserName()); - defaultStats.put("id", userId); - resp.add(defaultStats); + log.error("查询服务顾问列表时发生异常", e); + return resp; + } + } else if ("zj".equals(workType)) { + try { + // 获取当前租户ID + Long tenantId = cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder.getRequiredTenantId(); + // 查询角色为 general_inspection(总检)的员工列表 + List advisors = + roleApi.selectUserListByRoleCode(tenantId, "general_inspection"); + if (advisors == null || advisors.isEmpty()) { + return resp; + } + + // 查询记录表(根据时间筛选) + List rescueRefuelRecords = repairRecordsService.list( + new LambdaQueryWrapper() + .in(RepairRecords::getType, RecordTypeEnum.NFPG.getCode(), RecordTypeEnum.ZJ.getCode()) + .between(StringUtils.isNotEmpty(startDate), RepairRecords::getCreateTime, startDate, endDate) + ); + + // 按员工ID分组(注意 null-safe) + Map> recordsByUserId = (rescueRefuelRecords == null) + ? Collections.emptyMap() + : rescueRefuelRecords.stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(RepairRecords::getDealUserId)); + + // 遍历每个总检员工并组装返回值 + for (UserDTO advisor : advisors) { + Long userId = advisor.getId(); + if (userId == null) { + // 跳过没有 id 的记录 + continue; + } + + try { + Map respMap = new HashMap<>(); + respMap.put("name", advisor.getNickname()); + respMap.put("id", userId); + + Map dataMap = new HashMap<>(); + List> statsList = new ArrayList<>(); + + // 取出该员工对应的记录列表(可能为 null) + List repairRecords = recordsByUserId.get(userId); + if (repairRecords == null) { + repairRecords = Collections.emptyList(); + } + + // 统计总检类型记录数(ZJ) + long zjCount = repairRecords.stream() + .filter(Objects::nonNull) + .filter(record -> RecordTypeEnum.ZJ.getCode().equals(record.getType())) + .count(); + + // 统计内排返工类型记录数(NFPG) + long nfpgCount = repairRecords.stream() + .filter(Objects::nonNull) + .filter(record -> RecordTypeEnum.NFPG.getCode().equals(record.getType())) + .count(); + + // 如果还需要统计金额等,可以在这里聚合,例如: + // BigDecimal totalAmount = repairRecords.stream() + // .map(RepairRecords::getAmount) + // .filter(Objects::nonNull) + // .reduce(BigDecimal.ZERO, BigDecimal::add); + + // 封装 ZJ 统计节点 + Map zjNode = new HashMap<>(); + zjNode.put("code", "zjCount"); + zjNode.put("name", "总检次数"); + zjNode.put("selectType", "zj"); + zjNode.put("total", zjCount); + statsList.add(zjNode); + + // 封装 NFPG 统计节点 + Map nfpgNode = new HashMap<>(); + nfpgNode.put("code", "nfpgCount"); + nfpgNode.put("name", "内排返工次数"); + nfpgNode.put("selectType", "nfpg"); + nfpgNode.put("total", nfpgCount); + statsList.add(nfpgNode); + + // 可选:把合计次数放在 resp 顶层,前端如果需要也能直接取 + respMap.put("count", zjCount); + + // 可选:如果有金额、产值等,也可以放到 respMap(示例注释) + // respMap.put("amount", totalAmount); + + dataMap.put("stats", statsList); + respMap.put("data", dataMap); + + resp.add(respMap); + } catch (Exception e) { + // 记录异常但不中断整个流程 + log.warn("获取总检统计信息时发生异常,员工ID: {}", userId, e); + Map defaultStats = new HashMap<>(); + defaultStats.put("name", advisor.getNickname()); + defaultStats.put("id", userId); + resp.add(defaultStats); + } + } + } catch (Exception e) { + log.error("查询总检列表或记录时发生异常", e); + return resp; + } + } + else { + // 原有逻辑:根据workType查询该工种下的所有员工 + List workers = workerService.listByWorkType(workType); + + // 如果没有员工,直接返回空列表 + if (workers == null || workers.isEmpty()) { + return resp; + } + + // 对每个员工进行统计 + for (RepairWorkerRespVO worker : workers) { + Long userId = worker.getUserId(); + if (userId == null) { + continue; + } + + List userIds = Collections.singletonList(userId); + try { + // 查询员工的统计数据 + List> workerStats = statisticsMapper.selectWorkerStatisticsByUserIds(userIds, startDate, endDate); + if (workerStats != null && !workerStats.isEmpty()) { + Map workerStat = workerStats.get(0); + + Map respMap = new HashMap<>(); + respMap.put("name", worker.getUserName()); + respMap.put("id", userId); + + // 构造与workTypeStatistics相同格式的数据 + Map dataMap = new HashMap<>(); + List> statsList = new ArrayList<>(); + + // 添加进厂数统计 + Map newOrderNode = new HashMap<>(); + newOrderNode.put("code", "newOrderNum"); + newOrderNode.put("name", "订单(进厂数)"); + newOrderNode.put("selectType", "jinchang"); + newOrderNode.put("total", workerStat.get("ticketCount")); + statsList.add(newOrderNode); + respMap.put("count", workerStat.get("ticketCount")); + + // 添加维修中统计 + Map workingNode = new HashMap<>(); + workingNode.put("code", "workingNum"); + workingNode.put("name", "维修中"); + workingNode.put("selectType", "weixiuzhong"); + workingNode.put("total", workerStat.get("workingCount")); + statsList.add(workingNode); + + // 添加已竣工统计 + Map completedNode = new HashMap<>(); + completedNode.put("code", "overNum"); + completedNode.put("name", "已竣工"); + completedNode.put("selectType", "yijungong"); + completedNode.put("total", workerStat.get("completedCount")); + statsList.add(completedNode); + + dataMap.put("stats", statsList); + respMap.put("data", dataMap); + + resp.add(respMap); + } + } catch (Exception e) { + // 记录异常但不中断整个流程 + log.warn("获取员工统计信息时发生异常,员工ID: {}", userId, e); + // 添加一个默认的统计对象,避免前端出现空值 + Map defaultStats = new HashMap<>(); + defaultStats.put("name", worker.getUserName()); + defaultStats.put("id", userId); + resp.add(defaultStats); + } } } @@ -771,9 +979,13 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService { if (countA == null) return 1; if (countB == null) return -1; - int valA = Integer.parseInt(countA.toString()); - int valB = Integer.parseInt(countB.toString()); - return Integer.compare(valB, valA); // 降序 + // 处理BigDecimal和其他类型 + BigDecimal valA = (countA instanceof BigDecimal) ? (BigDecimal) countA : + (countA instanceof Number) ? new BigDecimal(countA.toString()) : BigDecimal.ZERO; + BigDecimal valB = (countB instanceof BigDecimal) ? (BigDecimal) countB : + (countB instanceof Number) ? new BigDecimal(countB.toString()) : BigDecimal.ZERO; + + return valB.compareTo(valA); // 降序 }); return resp; } diff --git a/dl-module-repair/src/main/resources/mapper/base/RepairStatisticsMapper.xml b/dl-module-repair/src/main/resources/mapper/base/RepairStatisticsMapper.xml index 64546262..37bed359 100644 --- a/dl-module-repair/src/main/resources/mapper/base/RepairStatisticsMapper.xml +++ b/dl-module-repair/src/main/resources/mapper/base/RepairStatisticsMapper.xml @@ -624,7 +624,7 @@ GROUP BY drw.work_type - + - + - + + + +