From ba3f96b2d3219e446deb3813a6fae94af729725d Mon Sep 17 00:00:00 2001 From: MerCry Date: Fri, 13 Mar 2026 22:35:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=88=90=E5=8D=95=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=92=8C=E8=BF=9B=E7=B2=89=E6=95=B0=E6=8D=AE=E4=B8=8D?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/wecom/helper/HandleAllData.java | 328 ++++++++++++------ .../excel/wecom/helper/HandleAllDataV2.java | 100 ++++-- .../mapper/CustomerExportDataMapper.java | 36 ++ .../mapper/wecom/CustomerExportDataMapper.xml | 48 +++ 4 files changed, 383 insertions(+), 129 deletions(-) diff --git a/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllData.java b/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllData.java index cf26933..3d22327 100644 --- a/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllData.java +++ b/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllData.java @@ -492,7 +492,7 @@ import java.util.concurrent.atomic.AtomicInteger; stats.setStudentDailyOrderCount(stats.getStudentDailyOrderCount() + 1); } } - } else { + } else if(data.getAddDate().compareTo(targetDate) == 0){ stats.setManagerAcceptCount(stats.getManagerAcceptCount() + 1); } } @@ -542,6 +542,9 @@ import java.util.concurrent.atomic.AtomicInteger; GROUP_ATTR_MAP.put("AD组", "tag_group17"); GROUP_ATTR_MAP.put("AE组", "tag_group18"); } + + private static final String UNGROUPED_NAME = "未分组"; + /** * 字段反射缓存 */ @@ -563,9 +566,11 @@ import java.util.concurrent.atomic.AtomicInteger; } private boolean matchesSource(CustomerExportData data) { + if(data.getSource() == null) { + return true; + } // 条件: 排除"由管理员XXX分配" - if (data.getSource() != null && - data.getSource().contains("管理员") && + if (data.getSource().contains("管理员") && data.getSource().contains("分配")) { return false; } @@ -657,13 +662,16 @@ import java.util.concurrent.atomic.AtomicInteger; } } - private boolean matchOrderCompleted(CustomerExportData data,Date curDate) { + /** + * 检查是否是成单状态 + */ + private boolean isOrderCompleted(CustomerExportData data) { String orderStatus = data.getTagGroup7(); // T列:成交状态 - // 校验成交状态 - if (!orderStatus.equals("已成交及时单9元+") && !orderStatus.equals("已成交非及时单9元+")) { + if (orderStatus == null || orderStatus.trim().isEmpty()) { return false; } - return true; + // 校验成交状态 + return orderStatus.contains("已成交及时单9元+") || orderStatus.contains("已成交非及时单9元+"); } private boolean isTimelyOrder(CustomerExportData data) { @@ -684,6 +692,8 @@ import java.util.concurrent.atomic.AtomicInteger; * 处理单条数据记录,累加到所有相关组的统计中 */ private void processDataRecord(CustomerExportData data, Date date, StatisticsAccumulator accumulator) { + boolean hasGroup = false; + // 遍历所有组 for (Map.Entry entry : GROUP_FIELD_MAP.entrySet()) { String groupName = entry.getKey(); @@ -696,6 +706,8 @@ import java.util.concurrent.atomic.AtomicInteger; if (tagValue == null || tagValue.trim().isEmpty()) { continue; } + + hasGroup = true; // 获取该组的统计器 StatisticsAccumulator.GroupStatistics stats = accumulator.getGroupStats(groupName); @@ -703,6 +715,12 @@ import java.util.concurrent.atomic.AtomicInteger; // 累加各项统计指标 accumulateGroupStatistics(data, date, stats); } + + // 如果不属于任何组,统计到"未分组" + if (!hasGroup) { + StatisticsAccumulator.GroupStatistics ungroupedStats = accumulator.getGroupStats(UNGROUPED_NAME); + accumulateGroupStatistics(data, date, ungroupedStats); + } } /** @@ -856,6 +874,7 @@ import java.util.concurrent.atomic.AtomicInteger; /** * 从累加器生成最终统计结果 + * 修复:遍历所有预定义的组,确保"有成单但无进粉"的组也被统计 */ private List generateStatisticsResults(String corpId,Date curDate,StatisticsAccumulator accumulator) { // 使用 Map 来存储每个指标对应的 CustomerStatisticsData @@ -863,127 +882,230 @@ import java.util.concurrent.atomic.AtomicInteger; Map indicatorMap = new LinkedHashMap<>(); //设置一个默认排序 int sortNo = 0; - // 为每个组生成23个统计指标 - for (Map.Entry entry : accumulator.getGroupStatsMap().entrySet()) { + // 为每个组生成统计指标 - 遍历所有预定义的组,确保有成单但无进粉的组也被统计 + for (Map.Entry groupEntry : GROUP_ATTR_MAP.entrySet()) { + String groupName = groupEntry.getKey(); + String attr = groupEntry.getValue(); + + // 获取或创建该组的统计器 + StatisticsAccumulator.GroupStatistics stats = accumulator.getGroupStats(groupName); + + // 成单数需要从历史数据中获取成交日期 = date的数据 + Long finishCount = customerExportDataMapper.selectByFinishDate(corpId, curDate, attr, finishFlag); + + // 只有当有成单数或进粉数时才生成记录 + if (finishCount > 0 || stats.getCustomerCount() > 0) { + // 21-23. 成本相关(需要手工填写) + setIndicatorValue(corpId,indicatorMap,curDate, "总成本(当日)", groupName, "需手工填写",(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "单条成本(当日)", groupName, "需手工填写",(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "成单成本(当日)", groupName, "需手工填写",(10*sortNo++)); - String groupName = entry.getKey(); - StatisticsAccumulator.GroupStatistics stats = entry.getValue(); + // 1. 成单数 + setIndicatorValue(corpId,indicatorMap,curDate, "成单数(当日)", groupName, String.valueOf(finishCount),(10*sortNo++)); + // 2. 进粉数 + setIndicatorValue(corpId,indicatorMap,curDate, "进粉数(当日)", groupName, String.valueOf(stats.getCustomerCount()),(10*sortNo++)); + + // 3. 转化率 = 成单数 / 进粉数 + String conversionRate = calculateRate(finishCount.intValue(), stats.getCustomerCount()); + setIndicatorValue(corpId,indicatorMap,curDate, "转化率(当日)", groupName, conversionRate,(10*sortNo++)); + + // 4. 及时单占比 = 及时单数 / 成单数(当日) + Long timelyCount = customerExportDataMapper.selectTimelyOrderCount(corpId, curDate, attr, timelyFinishFlag); + String timelyRate = calculateRate(timelyCount.intValue(), finishCount.intValue()); + setIndicatorValue(corpId,indicatorMap,curDate, "及时单占比(当日)", groupName, timelyRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "及时单数量(当日)", groupName, String.valueOf(timelyCount),(10*sortNo++),true); + + // 5. 非及时单占比 = 非及时单数 / 成单数(当日) + Long nonTimelyCount = customerExportDataMapper.selectNonTimelyOrderCount(corpId, curDate, attr, noTimelyfinishFlag); + String nonTimelyRate = calculateRate(nonTimelyCount.intValue(), finishCount.intValue()); + setIndicatorValue(corpId,indicatorMap,curDate, "非及时单占比(当日)", groupName, nonTimelyRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "非及时单数量(当日)", groupName, String.valueOf(nonTimelyCount),(10*sortNo++),true); + + // 6. 客户属性数量 + setIndicatorValue(corpId,indicatorMap,curDate, "客户属性数量(当日)", groupName, String.valueOf(stats.getTotalCustomerAttr()),(10*sortNo++)); + + // 7. 家长占比 + String parentRate = calculateRate(stats.getParentCount(), stats.getTotalCustomerAttr()); + setIndicatorValue(corpId,indicatorMap,curDate, "家长占比(当日)", groupName, parentRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "家长数量(当日)", groupName, String.valueOf(stats.getParentCount()),(10*sortNo++),true); + + // 8. 学生占比 + String studentRate = calculateRate(stats.getStudentCount(), stats.getTotalCustomerAttr()); + setIndicatorValue(corpId,indicatorMap,curDate, "学生占比(当日)", groupName, studentRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "学生数量(当日)", groupName, String.valueOf(stats.getStudentCount()),(10*sortNo++),true); + + // 8. 老师占比 + String teacherRate = calculateRate(stats.getTeacherCount(), stats.getTotalCustomerAttr()); + setIndicatorValue(corpId,indicatorMap,curDate, "老师占比(当日)", groupName, teacherRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "老师数量(当日)", groupName, String.valueOf(stats.getTeacherCount()),(10*sortNo++),true); + + // 9. 未知占比 + String unknownRate = calculateRate(stats.getUnknownAttrCount(), stats.getTotalCustomerAttr()); + setIndicatorValue(corpId,indicatorMap,curDate, "未知占比(当日)", groupName, unknownRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "未知数量(当日)", groupName, String.valueOf(stats.getUnknownAttrCount()),(10*sortNo++),true); + + // 10. 意向度数量 + setIndicatorValue(corpId,indicatorMap,curDate, "意向度数量(当日)", groupName, String.valueOf(stats.getTotalIntention()),(10*sortNo++)); + + // 11. 主动报价占比 + String activeQuoteRate = calculateRate(stats.getActiveQuoteCount(), stats.getTotalIntention()); + setIndicatorValue(corpId,indicatorMap,curDate, "主动报价占比(当日)", groupName, activeQuoteRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "主动报价数量(当日)", groupName, String.valueOf(stats.getActiveQuoteCount()),(10*sortNo++),true); + + // 12. 被动报价占比 + String passiveQuoteRate = calculateRate(stats.getPassiveQuoteCount(), stats.getTotalIntention()); + setIndicatorValue(corpId,indicatorMap,curDate, "被动报价占比(当日)", groupName, passiveQuoteRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "被动报价数量(当日)", groupName, String.valueOf(stats.getPassiveQuoteCount()),(10*sortNo++),true); + + // 13. 未开口报价占比 + String noQuoteRate = calculateRate(stats.getNoQuoteCount(), stats.getTotalIntention()); + setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价占比(当日)", groupName, noQuoteRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价数量(当日)", groupName, String.valueOf(stats.getNoQuoteCount()),(10*sortNo++),true); + + // 14. 已删除报价占比 + String deletedQuoteRate = calculateRate(stats.getDeletedQuoteCount(), stats.getTotalIntention()); + setIndicatorValue(corpId,indicatorMap,curDate, "已删除报价占比(当日)", groupName, deletedQuoteRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "已删除数量(当日)", groupName, String.valueOf(stats.getDeletedQuoteCount()),(10*sortNo++),true); + + // 15. 年级数量 + setIndicatorValue(corpId,indicatorMap,curDate, "年级数量(当日)", groupName, String.valueOf(stats.getTotalGrade()),(10*sortNo++)); + + // 16. 小学占比 + String primaryRate = calculateRate(stats.getPrimaryCount(), stats.getTotalGrade()); + setIndicatorValue(corpId,indicatorMap,curDate, "小学占比(当日)", groupName, primaryRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "小学数量(当日)", groupName, String.valueOf(stats.getPrimaryCount()),(10*sortNo++),true); + + // 17. 初中占比 + String middleRate = calculateRate(stats.getMiddleCount(), stats.getTotalGrade()); + setIndicatorValue(corpId,indicatorMap,curDate, "初中占比(当日)", groupName, middleRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "初中数量(当日)", groupName, String.valueOf(stats.getMiddleCount()),(10*sortNo++),true); + + // 18. 高中占比 + String highRate = calculateRate(stats.getHighCount(), stats.getTotalGrade()); + setIndicatorValue(corpId,indicatorMap,curDate, "高中占比(当日)", groupName, highRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "高中数量(当日)", groupName, String.valueOf(stats.getHighCount()),(10*sortNo++),true); + + // 19. 家长出单占比 + String parentOrderRate = calculateRate(stats.getParentOrderCount(), stats.getParentCount()); + setIndicatorValue(corpId,indicatorMap,curDate, "家长出单占比(当日)", groupName, parentOrderRate,(10*sortNo++),true); + setIndicatorValue(corpId,indicatorMap,curDate, "家长出单数量(当日)", groupName, String.valueOf(stats.getParentOrderCount()),(10*sortNo++),true); + + // 20. 学生出单占比 + String studentOrderRate = calculateRate(stats.getStudentOrderCount(), stats.getStudentCount()); + setIndicatorValue(corpId,indicatorMap,curDate, "学生出单占比(当日)", groupName, studentOrderRate,(10*sortNo++),true); + setIndicatorValue(corpId,indicatorMap,curDate, "学生出单数量(当日)", groupName, String.valueOf(stats.getStudentOrderCount()),(10*sortNo++),true); + + // 21. 家长出单率(当日) + String parentDailyOrderRate = calculateRate(stats.getParentDailyOrderCount(), stats.getParentDailyCount()); + setIndicatorValue(corpId,indicatorMap,curDate, "家长出单率(当日)", groupName, parentDailyOrderRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "家长即时单数量(当日)", groupName, String.valueOf(stats.getParentDailyOrderCount()),(10*sortNo++),true); + + // 22. 学生出单率(当日) + String studentDailyOrderRate = calculateRate(stats.getStudentDailyOrderCount(), stats.getStudentDailyCount()); + setIndicatorValue(corpId,indicatorMap,curDate, "学生出单率(当日)", groupName, studentDailyOrderRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "学生即时单数量(当日)", groupName, String.valueOf(stats.getStudentDailyOrderCount()),(10*sortNo++),true); + } + } + + // 处理"未分组"数据 + StatisticsAccumulator.GroupStatistics ungroupedStats = accumulator.getGroupStats(UNGROUPED_NAME); + Long ungroupedFinishCount = customerExportDataMapper.selectUngroupedFinishCount(corpId, curDate, finishFlag); + + if (ungroupedFinishCount > 0 || ungroupedStats.getCustomerCount() > 0) { // 21-23. 成本相关(需要手工填写) - setIndicatorValue(corpId,indicatorMap,curDate, "总成本(当日)", groupName, "需手工填写",(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "单条成本(当日)", groupName, "需手工填写",(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "成单成本(当日)", groupName, "需手工填写",(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "总成本(当日)", UNGROUPED_NAME, "需手工填写",(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "单条成本(当日)", UNGROUPED_NAME, "需手工填写",(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "成单成本(当日)", UNGROUPED_NAME, "需手工填写",(10*sortNo++)); // 1. 成单数 - //成单数 需要从历史的所有数据中获取 成交日期 = date的数据 - Long finishCount = customerExportDataMapper.selectByFinishDate(corpId,curDate,GROUP_ATTR_MAP.get(groupName),finishFlag); - setIndicatorValue(corpId,indicatorMap,curDate, "成单数(当日)", groupName, String.valueOf(finishCount),(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "成单数(当日)", UNGROUPED_NAME, String.valueOf(ungroupedFinishCount),(10*sortNo++)); // 2. 进粉数 - setIndicatorValue(corpId,indicatorMap,curDate, "进粉数(当日)", groupName, String.valueOf(stats.getCustomerCount()),(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "进粉数(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getCustomerCount()),(10*sortNo++)); - // 3. 转化率 = 成单数 / 进粉数(使用finishCount而不是stats.getOrderCount()) - String conversionRate = calculateRate(finishCount.intValue(), stats.getCustomerCount()); - setIndicatorValue(corpId,indicatorMap,curDate, "转化率(当日)", groupName, conversionRate,(10*sortNo++)); + // 3. 转化率 + String conversionRate = calculateRate(ungroupedFinishCount.intValue(), ungroupedStats.getCustomerCount()); + setIndicatorValue(corpId,indicatorMap,curDate, "转化率(当日)", UNGROUPED_NAME, conversionRate,(10*sortNo++)); - // 4. 及时单占比 = 及时单数 / 成单数(当日) - // 及时单数量需要从历史数据中获取(根据成交日期和订单状态) - Long timelyCount = customerExportDataMapper.selectTimelyOrderCount(corpId, curDate, GROUP_ATTR_MAP.get(groupName),timelyFinishFlag); - String timelyRate = calculateRate(timelyCount.intValue(), finishCount.intValue()); - setIndicatorValue(corpId,indicatorMap,curDate, "及时单占比(当日)", groupName, timelyRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "及时单数量(当日)", groupName, String.valueOf(timelyCount),(10*sortNo++),true); + // 4. 及时单占比 + Long ungroupedTimelyCount = customerExportDataMapper.selectUngroupedTimelyOrderCount(corpId, curDate, timelyFinishFlag); + String timelyRate = calculateRate(ungroupedTimelyCount.intValue(), ungroupedFinishCount.intValue()); + setIndicatorValue(corpId,indicatorMap,curDate, "及时单占比(当日)", UNGROUPED_NAME, timelyRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "及时单数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedTimelyCount),(10*sortNo++),true); - // 5. 非及时单占比 = 非及时单数 / 成单数(当日) - // 非及时单数量需要从历史数据中获取(根据成交日期和订单状态) - Long nonTimelyCount = customerExportDataMapper.selectNonTimelyOrderCount(corpId, curDate, GROUP_ATTR_MAP.get(groupName),noTimelyfinishFlag); - String nonTimelyRate = calculateRate(nonTimelyCount.intValue(), finishCount.intValue()); - setIndicatorValue(corpId,indicatorMap,curDate, "非及时单占比(当日)", groupName, nonTimelyRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "非及时单数量(当日)", groupName, String.valueOf(nonTimelyCount),(10*sortNo++),true); + // 5. 非及时单占比 + Long ungroupedNonTimelyCount = customerExportDataMapper.selectUngroupedNonTimelyOrderCount(corpId, curDate, noTimelyfinishFlag); + String nonTimelyRate = calculateRate(ungroupedNonTimelyCount.intValue(), ungroupedFinishCount.intValue()); + setIndicatorValue(corpId,indicatorMap,curDate, "非及时单占比(当日)", UNGROUPED_NAME, nonTimelyRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "非及时单数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedNonTimelyCount),(10*sortNo++),true); - // 6. 客户属性数量 - setIndicatorValue(corpId,indicatorMap,curDate, "客户属性数量(当日)", groupName, String.valueOf(stats.getTotalCustomerAttr()),(10*sortNo++)); + // 6-22 其他指标(未分组记录的属性统计) + setIndicatorValue(corpId,indicatorMap,curDate, "客户属性数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getTotalCustomerAttr()),(10*sortNo++)); + + String parentRate = calculateRate(ungroupedStats.getParentCount(), ungroupedStats.getTotalCustomerAttr()); + setIndicatorValue(corpId,indicatorMap,curDate, "家长占比(当日)", UNGROUPED_NAME, parentRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "家长数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getParentCount()),(10*sortNo++),true); - // 7. 家长占比 - String parentRate = calculateRate(stats.getParentCount(), stats.getTotalCustomerAttr()); - setIndicatorValue(corpId,indicatorMap,curDate, "家长占比(当日)", groupName, parentRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "家长数量(当日)", groupName, String.valueOf(stats.getParentCount()),(10*sortNo++),true); + String studentRate = calculateRate(ungroupedStats.getStudentCount(), ungroupedStats.getTotalCustomerAttr()); + setIndicatorValue(corpId,indicatorMap,curDate, "学生占比(当日)", UNGROUPED_NAME, studentRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "学生数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getStudentCount()),(10*sortNo++),true); - // 8. 学生占比 - String studentRate = calculateRate(stats.getStudentCount(), stats.getTotalCustomerAttr()); - setIndicatorValue(corpId,indicatorMap,curDate, "学生占比(当日)", groupName, studentRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "学生数量(当日)", groupName, String.valueOf(stats.getStudentCount()),(10*sortNo++),true); + String teacherRate = calculateRate(ungroupedStats.getTeacherCount(), ungroupedStats.getTotalCustomerAttr()); + setIndicatorValue(corpId,indicatorMap,curDate, "老师占比(当日)", UNGROUPED_NAME, teacherRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "老师数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getTeacherCount()),(10*sortNo++),true); - // 8. 老师占比 - String teacherRate = calculateRate(stats.getTeacherCount(), stats.getTotalCustomerAttr()); - setIndicatorValue(corpId,indicatorMap,curDate, "老师占比(当日)", groupName, teacherRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "老师数量(当日)", groupName, String.valueOf(stats.getTeacherCount()),(10*sortNo++),true); + String unknownRate = calculateRate(ungroupedStats.getUnknownAttrCount(), ungroupedStats.getTotalCustomerAttr()); + setIndicatorValue(corpId,indicatorMap,curDate, "未知占比(当日)", UNGROUPED_NAME, unknownRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "未知数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getUnknownAttrCount()),(10*sortNo++),true); - // 9. 未知占比 - String unknownRate = calculateRate(stats.getUnknownAttrCount(), stats.getTotalCustomerAttr()); - setIndicatorValue(corpId,indicatorMap,curDate, "未知占比(当日)", groupName, unknownRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "未知数量(当日)", groupName, String.valueOf(stats.getUnknownAttrCount()),(10*sortNo++),true); + setIndicatorValue(corpId,indicatorMap,curDate, "意向度数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getTotalIntention()),(10*sortNo++)); - // 10. 意向度数量 - setIndicatorValue(corpId,indicatorMap,curDate, "意向度数量(当日)", groupName, String.valueOf(stats.getTotalIntention()),(10*sortNo++)); + String activeQuoteRate = calculateRate(ungroupedStats.getActiveQuoteCount(), ungroupedStats.getTotalIntention()); + setIndicatorValue(corpId,indicatorMap,curDate, "主动报价占比(当日)", UNGROUPED_NAME, activeQuoteRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "主动报价数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getActiveQuoteCount()),(10*sortNo++),true); - // 11. 主动报价占比 - String activeQuoteRate = calculateRate(stats.getActiveQuoteCount(), stats.getTotalIntention()); - setIndicatorValue(corpId,indicatorMap,curDate, "主动报价占比(当日)", groupName, activeQuoteRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "主动报价数量(当日)", groupName, String.valueOf(stats.getActiveQuoteCount()),(10*sortNo++),true); + String passiveQuoteRate = calculateRate(ungroupedStats.getPassiveQuoteCount(), ungroupedStats.getTotalIntention()); + setIndicatorValue(corpId,indicatorMap,curDate, "被动报价占比(当日)", UNGROUPED_NAME, passiveQuoteRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "被动报价数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getPassiveQuoteCount()),(10*sortNo++),true); - // 12. 被动报价占比 - String passiveQuoteRate = calculateRate(stats.getPassiveQuoteCount(), stats.getTotalIntention()); - setIndicatorValue(corpId,indicatorMap,curDate, "被动报价占比(当日)", groupName, passiveQuoteRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "被动报价数量(当日)", groupName, String.valueOf(stats.getPassiveQuoteCount()),(10*sortNo++),true); + String noQuoteRate = calculateRate(ungroupedStats.getNoQuoteCount(), ungroupedStats.getTotalIntention()); + setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价占比(当日)", UNGROUPED_NAME, noQuoteRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getNoQuoteCount()),(10*sortNo++),true); - // 13. 未开口报价占比 - String noQuoteRate = calculateRate(stats.getNoQuoteCount(), stats.getTotalIntention()); - setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价占比(当日)", groupName, noQuoteRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价数量(当日)", groupName, String.valueOf(stats.getNoQuoteCount()),(10*sortNo++),true); + String deletedQuoteRate = calculateRate(ungroupedStats.getDeletedQuoteCount(), ungroupedStats.getTotalIntention()); + setIndicatorValue(corpId,indicatorMap,curDate, "已删除报价占比(当日)", UNGROUPED_NAME, deletedQuoteRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "已删除数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getDeletedQuoteCount()),(10*sortNo++),true); - // 14. 已删除报价占比 - String deletedQuoteRate = calculateRate(stats.getDeletedQuoteCount(), stats.getTotalIntention()); - setIndicatorValue(corpId,indicatorMap,curDate, "已删除报价占比(当日)", groupName, deletedQuoteRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "已删除数量(当日)", groupName, String.valueOf(stats.getDeletedQuoteCount()),(10*sortNo++),true); + setIndicatorValue(corpId,indicatorMap,curDate, "年级数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getTotalGrade()),(10*sortNo++)); - // 15. 年级数量 - setIndicatorValue(corpId,indicatorMap,curDate, "年级数量(当日)", groupName, String.valueOf(stats.getTotalGrade()),(10*sortNo++)); + String primaryRate = calculateRate(ungroupedStats.getPrimaryCount(), ungroupedStats.getTotalGrade()); + setIndicatorValue(corpId,indicatorMap,curDate, "小学占比(当日)", UNGROUPED_NAME, primaryRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "小学数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getPrimaryCount()),(10*sortNo++),true); - // 16. 小学占比 - String primaryRate = calculateRate(stats.getPrimaryCount(), stats.getTotalGrade()); - setIndicatorValue(corpId,indicatorMap,curDate, "小学占比(当日)", groupName, primaryRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "小学数量(当日)", groupName, String.valueOf(stats.getPrimaryCount()),(10*sortNo++),true); + String middleRate = calculateRate(ungroupedStats.getMiddleCount(), ungroupedStats.getTotalGrade()); + setIndicatorValue(corpId,indicatorMap,curDate, "初中占比(当日)", UNGROUPED_NAME, middleRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "初中数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getMiddleCount()),(10*sortNo++),true); - // 17. 初中占比 - String middleRate = calculateRate(stats.getMiddleCount(), stats.getTotalGrade()); - setIndicatorValue(corpId,indicatorMap,curDate, "初中占比(当日)", groupName, middleRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "初中数量(当日)", groupName, String.valueOf(stats.getMiddleCount()),(10*sortNo++),true); + String highRate = calculateRate(ungroupedStats.getHighCount(), ungroupedStats.getTotalGrade()); + setIndicatorValue(corpId,indicatorMap,curDate, "高中占比(当日)", UNGROUPED_NAME, highRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "高中数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getHighCount()),(10*sortNo++),true); - // 18. 高中占比 - String highRate = calculateRate(stats.getHighCount(), stats.getTotalGrade()); - setIndicatorValue(corpId,indicatorMap,curDate, "高中占比(当日)", groupName, highRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "高中数量(当日)", groupName, String.valueOf(stats.getHighCount()),(10*sortNo++),true); + String parentOrderRate = calculateRate(ungroupedStats.getParentOrderCount(), ungroupedStats.getParentCount()); + setIndicatorValue(corpId,indicatorMap,curDate, "家长出单占比(当日)", UNGROUPED_NAME, parentOrderRate,(10*sortNo++),true); + setIndicatorValue(corpId,indicatorMap,curDate, "家长出单数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getParentOrderCount()),(10*sortNo++),true); - // 19. 家长出单占比 - String parentOrderRate = calculateRate(stats.getParentOrderCount(), stats.getParentCount()); - setIndicatorValue(corpId,indicatorMap,curDate, "家长出单占比(当日)", groupName, parentOrderRate,(10*sortNo++),true); - setIndicatorValue(corpId,indicatorMap,curDate, "家长出单数量(当日)", groupName, String.valueOf(stats.getParentOrderCount()),(10*sortNo++),true); + String studentOrderRate = calculateRate(ungroupedStats.getStudentOrderCount(), ungroupedStats.getStudentCount()); + setIndicatorValue(corpId,indicatorMap,curDate, "学生出单占比(当日)", UNGROUPED_NAME, studentOrderRate,(10*sortNo++),true); + setIndicatorValue(corpId,indicatorMap,curDate, "学生出单数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getStudentOrderCount()),(10*sortNo++),true); - // 20. 学生出单占比 - String studentOrderRate = calculateRate(stats.getStudentOrderCount(), stats.getStudentCount()); - setIndicatorValue(corpId,indicatorMap,curDate, "学生出单占比(当日)", groupName, studentOrderRate,(10*sortNo++),true); - setIndicatorValue(corpId,indicatorMap,curDate, "学生出单数量(当日)", groupName, String.valueOf(stats.getStudentOrderCount()),(10*sortNo++),true); - - // 21. 家长出单率(当日) - String parentDailyOrderRate = calculateRate(stats.getParentDailyOrderCount(), stats.getParentDailyCount()); - setIndicatorValue(corpId,indicatorMap,curDate, "家长出单率(当日)", groupName, parentDailyOrderRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "家长即时单数量(当日)", groupName, String.valueOf(stats.getParentDailyOrderCount()),(10*sortNo++),true); - - // 22. 学生出单率(当日) - String studentDailyOrderRate = calculateRate(stats.getStudentDailyOrderCount(), stats.getStudentDailyCount()); - setIndicatorValue(corpId,indicatorMap,curDate, "学生出单率(当日)", groupName, studentDailyOrderRate,(10*sortNo++)); - setIndicatorValue(corpId,indicatorMap,curDate, "学生即时单数量(当日)", groupName, String.valueOf(stats.getStudentDailyOrderCount()),(10*sortNo++),true); + String parentDailyOrderRate = calculateRate(ungroupedStats.getParentDailyOrderCount(), ungroupedStats.getParentDailyCount()); + setIndicatorValue(corpId,indicatorMap,curDate, "家长出单率(当日)", UNGROUPED_NAME, parentDailyOrderRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "家长即时单数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getParentDailyOrderCount()),(10*sortNo++),true); + String studentDailyOrderRate = calculateRate(ungroupedStats.getStudentDailyOrderCount(), ungroupedStats.getStudentDailyCount()); + setIndicatorValue(corpId,indicatorMap,curDate, "学生出单率(当日)", UNGROUPED_NAME, studentDailyOrderRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "学生即时单数量(当日)", UNGROUPED_NAME, String.valueOf(ungroupedStats.getStudentDailyOrderCount()),(10*sortNo++),true); } // 将 Map 转换为 List 返回 @@ -1097,10 +1219,12 @@ import java.util.concurrent.atomic.AtomicInteger; /** * 处理单条数据记录,累加到部门统计中 + * 修复:添加对tag_group7成单状态的验证 */ private void processDepartmentRecord(CustomerExportData data, Date targetDate, DepartmentStatisticsAccumulator.DepartmentStats stats) { - if(matchesQValue(data,targetDate)) { + // 成单统计:需要同时满足成交日期匹配 AND 成单状态匹配 + if(matchesQValue(data,targetDate) && isOrderCompleted(data)) { stats.setTotalOrderCount(stats.getTotalOrderCount() + 1); // 及时单和非及时单统计 diff --git a/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllDataV2.java b/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllDataV2.java index 4ae29c3..ce528c0 100644 --- a/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllDataV2.java +++ b/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllDataV2.java @@ -45,6 +45,8 @@ public class HandleAllDataV2 { private List finishFlag = Arrays.asList("已成交及时单9元+", "已成交非及时单9元+"); private List timelyFinishFlag = Arrays.asList("已成交及时单9元+"); private List noTimelyfinishFlag = Arrays.asList("已成交非及时单9元+"); + private static final String UNGROUPED_NAME = "未分组"; + /** * 组名到字段名的映射(使用括号内的名称) */ @@ -201,6 +203,8 @@ public class HandleAllDataV2 { * 处理单条数据记录,累加到组级和标签级统计 */ private void processDataRecordV2(CustomerExportData data, Date date, GroupTagAccumulator accumulator) { + boolean hasGroup = false; + // 遍历所有组 for (Map.Entry entry : GROUP_FIELD_MAP.entrySet()) { String groupName = entry.getKey(); @@ -213,6 +217,8 @@ public class HandleAllDataV2 { if (tagValue == null || tagValue.trim().isEmpty()) { continue; } + + hasGroup = true; // 获取该组的统计器 GroupStatistics groupStats = accumulator.getGroupStats(groupName); @@ -231,6 +237,12 @@ public class HandleAllDataV2 { accumulateGroupStatistics(data, date, tagStats); } } + + // 如果不属于任何组,统计到"未分组" + if (!hasGroup) { + GroupStatistics ungroupedStats = accumulator.getGroupStats(UNGROUPED_NAME); + accumulateGroupStatistics(data, date, ungroupedStats); + } } /** @@ -256,11 +268,9 @@ public class HandleAllDataV2 { stats.setOrderCount(stats.getOrderCount() + 1); String orderStatus = data.getTagGroup7(); if (orderStatus != null) { - String[] split = orderStatus.split(","); - String statusInfo = split[split.length - 1]; - if (statusInfo.contains("已成交及时单9元+")) { + if (orderStatus.equals("已成交及时单9元+")) { stats.setTimelyOrderCount(stats.getTimelyOrderCount() + 1); - } else if (statusInfo.contains("已成交非及时单9元+")) { + } else if (orderStatus.equals("已成交非及时单9元+")) { stats.setNonTimelyOrderCount(stats.getNonTimelyOrderCount() + 1); } } @@ -342,46 +352,79 @@ public class HandleAllDataV2 { /** * 从累加器生成最终统计结果V2 + * 修复:遍历所有预定义的组,确保"有成单但无进粉"的组也被统计 */ private List generateStatisticsResultsV2( String corpId, Date date, GroupTagAccumulator accumulator) { List result = new ArrayList<>(); int sortNo = 0; - long tempId = 1; // 临时ID生成器 + long tempId = 1; - // 1. 生成组级数据 + // 1. 生成组级数据 - 遍历所有预定义的组,确保有成单但无进粉的组也被统计 Map groupIdMap = new HashMap<>(); - for (Map.Entry entry : accumulator.getGroupStatsMap().entrySet()) { - String groupName = entry.getKey(); - GroupStatistics stats = entry.getValue(); - + for (Map.Entry groupEntry : GROUP_FIELD_MAP.entrySet()) { + String groupName = groupEntry.getKey(); + String attr = GROUP_ATTR_MAP.get(groupName); + + // 获取或创建该组的统计器 + GroupStatistics stats = accumulator.getGroupStats(groupName); + // 使用SQL查询获取成单数(与V1保持一致) Long finishCount = customerExportDataMapper.selectByFinishDate( - corpId, date, GROUP_ATTR_MAP.get(groupName),finishFlag); + corpId, date, attr, finishFlag); stats.setOrderCount(finishCount.intValue()); // 使用SQL查询获取及时单数量(根据成交日期和订单状态) Long timelyCount = customerExportDataMapper.selectTimelyOrderCount( - corpId, date, GROUP_ATTR_MAP.get(groupName),timelyFinishFlag); + corpId, date, attr, timelyFinishFlag); stats.setTimelyOrderCount(timelyCount.intValue()); // 使用SQL查询获取非及时单数量(根据成交日期和订单状态) Long nonTimelyCount = customerExportDataMapper.selectNonTimelyOrderCount( - corpId, date, GROUP_ATTR_MAP.get(groupName),noTimelyfinishFlag); + corpId, date, attr, noTimelyfinishFlag); stats.setNonTimelyOrderCount(nonTimelyCount.intValue()); + + // 只有当有成单数或进粉数时才生成记录 + if (stats.getOrderCount() > 0 || stats.getCustomerCount() > 0) { + CustomerStatisticsDataV2 groupData = createStatisticsDataV2( + corpId, date, groupName, null, stats, sortNo++); + groupData.setDataLevel(1); + groupData.setId(tempId); + result.add(groupData); - CustomerStatisticsDataV2 groupData = createStatisticsDataV2( - corpId, date, groupName, null, stats, sortNo++); - groupData.setDataLevel(1); - groupData.setId(tempId); // 设置临时ID - result.add(groupData); + groupIdMap.put(groupName, tempId); + tempId++; + } + } - // 临时存储组ID(用于标签级数据的parentId) - groupIdMap.put(groupName, tempId); + // 2. 处理"未分组"数据 + GroupStatistics ungroupedStats = accumulator.getGroupStats(UNGROUPED_NAME); + // 查询未分组记录的成单数 + Long ungroupedFinishCount = customerExportDataMapper.selectUngroupedFinishCount( + corpId, date, finishFlag); + ungroupedStats.setOrderCount(ungroupedFinishCount.intValue()); + + // 查询未分组记录的及时单数量 + Long ungroupedTimelyCount = customerExportDataMapper.selectUngroupedTimelyOrderCount( + corpId, date, timelyFinishFlag); + ungroupedStats.setTimelyOrderCount(ungroupedTimelyCount.intValue()); + + // 查询未分组记录的非及时单数量 + Long ungroupedNonTimelyCount = customerExportDataMapper.selectUngroupedNonTimelyOrderCount( + corpId, date, noTimelyfinishFlag); + ungroupedStats.setNonTimelyOrderCount(ungroupedNonTimelyCount.intValue()); + + // 只有当有成单数或进粉数时才生成记录 + if (ungroupedStats.getOrderCount() > 0 || ungroupedStats.getCustomerCount() > 0) { + CustomerStatisticsDataV2 ungroupedData = createStatisticsDataV2( + corpId, date, UNGROUPED_NAME, null, ungroupedStats, sortNo++); + ungroupedData.setDataLevel(1); + ungroupedData.setId(tempId); + result.add(ungroupedData); tempId++; } - // 2. 生成标签级数据 + // 3. 生成标签级数据 for (Map.Entry> groupEntry : accumulator.getTagStatsMap().entrySet()) { String groupName = groupEntry.getKey(); @@ -393,23 +436,23 @@ public class HandleAllDataV2 { // 使用SQL查询获取该标签的成单数(根据标签值筛选) Long finishCount = customerExportDataMapper.selectByFinishDateAndTag( - corpId, date, GROUP_ATTR_MAP.get(groupName), tagName,finishFlag); + corpId, date, GROUP_ATTR_MAP.get(groupName), tagName, finishFlag); stats.setOrderCount(finishCount.intValue()); // 使用SQL查询获取该标签的及时单数量 Long timelyCount = customerExportDataMapper.selectTimelyOrderCountByTag( - corpId, date, GROUP_ATTR_MAP.get(groupName), tagName,timelyFinishFlag); + corpId, date, GROUP_ATTR_MAP.get(groupName), tagName, timelyFinishFlag); stats.setTimelyOrderCount(timelyCount.intValue()); // 使用SQL查询获取该标签的非及时单数量 Long nonTimelyCount = customerExportDataMapper.selectNonTimelyOrderCountByTag( - corpId, date, GROUP_ATTR_MAP.get(groupName), tagName,noTimelyfinishFlag); + corpId, date, GROUP_ATTR_MAP.get(groupName), tagName, noTimelyfinishFlag); stats.setNonTimelyOrderCount(nonTimelyCount.intValue()); CustomerStatisticsDataV2 tagData = createStatisticsDataV2( corpId, date, groupName, tagName, stats, sortNo++); tagData.setDataLevel(2); - tagData.setId(tempId); // 设置临时ID + tagData.setId(tempId); tagData.setParentId(parentId); result.add(tagData); tempId++; @@ -523,10 +566,13 @@ public class HandleAllDataV2 { /** * 检查数据来源是否匹配 + * 排除"由管理员XXX分配"的记录 */ private boolean matchesSource(CustomerExportData data) { - if (data.getSource() != null && - data.getSource().contains("管理员") && + if(data == null || data.getSource() == null) { + return true; + } + if (data.getSource().contains("管理员") && data.getSource().contains("分配")) { return false; } diff --git a/excel-handle/src/main/java/com/ruoyi/excel/wecom/mapper/CustomerExportDataMapper.java b/excel-handle/src/main/java/com/ruoyi/excel/wecom/mapper/CustomerExportDataMapper.java index 9023258..0396049 100644 --- a/excel-handle/src/main/java/com/ruoyi/excel/wecom/mapper/CustomerExportDataMapper.java +++ b/excel-handle/src/main/java/com/ruoyi/excel/wecom/mapper/CustomerExportDataMapper.java @@ -240,5 +240,41 @@ public interface CustomerExportDataMapper extends BaseMapper @Param("corpId") String corpId, @Param("startDate") Date startDate, @Param("endDate") Date endDate,@Param("successFlags") List successFlags); + + /** + * 查询未分组记录的成单数(所有组字段都为空) + * @param corpId 企业ID + * @param date 成交日期 + * @param successFlags 成单状态标志 + * @return 成单数 + */ + Long selectUngroupedFinishCount( + @Param("corpId") String corpId, + @Param("date") Date date, + @Param("successFlags") List successFlags); + + /** + * 查询未分组记录的及时单数量 + * @param corpId 企业ID + * @param date 成交日期 + * @param successFlags 及时单状态标志 + * @return 及时单数量 + */ + Long selectUngroupedTimelyOrderCount( + @Param("corpId") String corpId, + @Param("date") Date date, + @Param("successFlags") List successFlags); + + /** + * 查询未分组记录的非及时单数量 + * @param corpId 企业ID + * @param date 成交日期 + * @param successFlags 非及时单状态标志 + * @return 非及时单数量 + */ + Long selectUngroupedNonTimelyOrderCount( + @Param("corpId") String corpId, + @Param("date") Date date, + @Param("successFlags") List successFlags); } diff --git a/excel-handle/src/main/resources/mapper/wecom/CustomerExportDataMapper.xml b/excel-handle/src/main/resources/mapper/wecom/CustomerExportDataMapper.xml index 55ef4af..c522f23 100644 --- a/excel-handle/src/main/resources/mapper/wecom/CustomerExportDataMapper.xml +++ b/excel-handle/src/main/resources/mapper/wecom/CustomerExportDataMapper.xml @@ -702,4 +702,52 @@ + + + + + + + + +