From 7b1c8d26722a0a2c89d5f489224d96031f7f9614 Mon Sep 17 00:00:00 2001 From: aike <17730485278@139.com> Date: Wed, 11 Feb 2026 09:35:09 +0800 Subject: [PATCH 1/7] =?UTF-8?q?demand:=20=20=20TMS-=E8=B4=A2=E5=8A=A1?= =?UTF-8?q?=E4=B8=AD=E5=BF=83=E9=94=80=E8=B4=A6=E5=AE=A1=E6=A0=B8=EF=BC=9A?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=95=B0=E6=8D=AE=E5=B1=95=E7=A4=BA=E5=A2=9E?= =?UTF-8?q?=E6=B7=BB=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xdadan/erp/web/emis/EmisTransPlanRuleController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisTransPlanRuleController.java b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisTransPlanRuleController.java index bcbd60b5a..9ea4a553f 100644 --- a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisTransPlanRuleController.java +++ b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisTransPlanRuleController.java @@ -24,7 +24,7 @@ import org.springframework.dao.DuplicateKeyException; /** * 供应商线路规划Controller - * + * * @author heyu * @date 2024-04-21 */ @@ -163,7 +163,7 @@ public class EmisTransPlanRuleController extends EmisBaseController { /** * 查询供应商线路规划树结构 */ - // @PreAuthorize("@ss.hasPermi('emis:emisTransPlanRule:tree')") + @PreAuthorize("@ss.hasPermi('emis:emisTransPlanRule:tree')") @GetMapping("/tree") public TableDataInfo tree(EmisTransPlanRule emisTransPlanRule) { return getDataTable(emisTransPlanRuleService.selectEmisTransPlanRuleTree(emisTransPlanRule)); @@ -182,4 +182,4 @@ public class EmisTransPlanRuleController extends EmisBaseController { } return getDataTable(cycles); } -} \ No newline at end of file +} From 6dd335a11bc47f4f73daa7df869a5f2b33226ef3 Mon Sep 17 00:00:00 2001 From: aike <17730485278@139.com> Date: Wed, 11 Feb 2026 10:02:09 +0800 Subject: [PATCH 2/7] =?UTF-8?q?demand:=20=20=20TMS-=E8=B4=A2=E5=8A=A1?= =?UTF-8?q?=E4=B8=AD=E5=BF=83=E9=94=80=E8=B4=A6=E5=AE=A1=E6=A0=B8=EF=BC=9A?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=95=B0=E6=8D=AE=E5=B1=95=E7=A4=BA=E5=A2=9E?= =?UTF-8?q?=E6=B7=BB=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/xdadan/erp/web/emis/EmisTransPlanRuleController.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisTransPlanRuleController.java b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisTransPlanRuleController.java index 9ea4a553f..658bf9609 100644 --- a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisTransPlanRuleController.java +++ b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisTransPlanRuleController.java @@ -1,5 +1,6 @@ package com.xdadan.erp.web.emis; +import java.util.ArrayList; import java.util.List; import com.alibaba.excel.support.ExcelTypeEnum; @@ -166,7 +167,9 @@ public class EmisTransPlanRuleController extends EmisBaseController { @PreAuthorize("@ss.hasPermi('emis:emisTransPlanRule:tree')") @GetMapping("/tree") public TableDataInfo tree(EmisTransPlanRule emisTransPlanRule) { - return getDataTable(emisTransPlanRuleService.selectEmisTransPlanRuleTree(emisTransPlanRule)); + return getDataTable(new ArrayList<>()); + +// return getDataTable(emisTransPlanRuleService.selectEmisTransPlanRuleTree(emisTransPlanRule)); } /** From 1335ae889021e192f3012cef671d68b4157688a5 Mon Sep 17 00:00:00 2001 From: aike <17730485278@139.com> Date: Thu, 12 Feb 2026 10:02:15 +0800 Subject: [PATCH 3/7] =?UTF-8?q?demand:=20=20=20=E6=9C=88=E7=BB=93=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E8=BE=BE=E6=A0=87=E7=BB=9F=E8=AE=A1=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/emis/EmisCustomerUserController.java | 14 +- .../vo/MonthlyCustomerShipmentStatVO.java | 9 + .../emis/mapper/EmisCustomerUserMapper.java | 10 + .../MonthlyShipmentStatExcelUtil.java | 126 ++++++-- .../impl/EmisCustomerUserServiceImpl.java | 293 +++++++++++++++++- .../mapper/EmisCustomerUserMapper.xml | 156 ++++++++++ .../resources/mapper/EmisWaybillMapper.xml | 6 + 7 files changed, 593 insertions(+), 21 deletions(-) diff --git a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisCustomerUserController.java b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisCustomerUserController.java index a6eaae39f..7e22b242b 100644 --- a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisCustomerUserController.java +++ b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisCustomerUserController.java @@ -495,7 +495,19 @@ public class EmisCustomerUserController extends EmisBaseController setPrivParams(emisWaybill); List list = emisCustomerUserService .selectMonthlyCustomerShipmentStat(emisWaybill); - return getDataTable(list); + TableDataInfo dataTable = getDataTable(list); + + // 如果使用了应用层过滤(complianceStatType=3/4/5/6),需要手动设置总数 + if (emisWaybill.getParams() != null && emisWaybill.getParams().containsKey("_filteredTotal")) { + Object filteredTotal = emisWaybill.getParams().get("_filteredTotal"); + if (filteredTotal instanceof Long) { + dataTable.setTotal((Long) filteredTotal); + } else if (filteredTotal instanceof Number) { + dataTable.setTotal(((Number) filteredTotal).longValue()); + } + } + + return dataTable; } /** diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/vo/MonthlyCustomerShipmentStatVO.java b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/vo/MonthlyCustomerShipmentStatVO.java index c50600b31..a2b14e8de 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/vo/MonthlyCustomerShipmentStatVO.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/vo/MonthlyCustomerShipmentStatVO.java @@ -203,5 +203,14 @@ public class MonthlyCustomerShipmentStatVO implements Serializable { /* 创建日期(现金客户导出使用,对应 create_time) */ private String createTime; + + /* 是否达标;1:已达标,2:未达标 */ + private String blCompliance; + + /* 寄件月份 */ + private String sendMonth; + + /* 总运费 */ + private Integer totalBillFee; } diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisCustomerUserMapper.java b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisCustomerUserMapper.java index 654e48412..f9a8da5fd 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisCustomerUserMapper.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisCustomerUserMapper.java @@ -13,6 +13,8 @@ package com.xdadan.erp.emis.mapper; import java.util.List; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.xdadan.erp.emis.domain.EmisCustomerUser; +import com.xdadan.erp.emis.domain.EmisWaybill; +import com.xdadan.erp.emis.domain.vo.MonthlyCustomerShipmentStatVO; import org.apache.ibatis.annotations.Param; /** * @ClassName EmisCustomerUserMapper @@ -134,4 +136,12 @@ public interface EmisCustomerUserMapper extends BaseMapper */ public int clearMoneyUserIdByMoneyUserIds(@Param("moneyUserIds") Long[] moneyUserIds); + /** + * 月结客户达标统计 + * + * @param emisWaybill 查询条件 + * @return + */ + List selectMonthlyCustomerShipmentStatIsCompliance(EmisWaybill emisWaybill); + } diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/MonthlyShipmentStatExcelUtil.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/MonthlyShipmentStatExcelUtil.java index eadb94b83..9209a80a1 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/MonthlyShipmentStatExcelUtil.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/MonthlyShipmentStatExcelUtil.java @@ -70,9 +70,31 @@ public class MonthlyShipmentStatExcelUtil { MonthlyCustomerShipmentStatVO::getOtherWeightCompareFlag) ); - private static final String[] BASE_HEADERS = {"客户名称", "首次签约日期", "总票数", "总重量", "销售联系人"}; + /** + * 默认(月结/现金)出货统计基础列(原有导出保持不变) + * 客户名称、首次签约日期(或创建日期)、总票数、总重量、销售联系人 + */ + private static final String[] BASE_HEADERS = { + "客户名称", "首次签约日期", "总票数", "总重量", "销售联系人" + }; private static final int[] BASE_WIDTHS = {28, 18, 12, 16, 24}; + /** + * 月结客户达标统计基础列(仅 statType=5 使用) + * + * 列顺序要求: + * 1)寄件月份 字段放在“首次签约日期”后边; + * 2)总运费 字段放在“总重量”后边; + * 3)是否达标 字段放在“寄件月份”后边; + * + * 最终基础表头顺序: + * 客户名称、首次签约日期、寄件月份、是否达标、总票数、总重量、总运费、销售联系人 + */ + private static final String[] COMPLIANCE_HEADERS = { + "客户名称", "首次签约日期", "寄件月份", "是否达标", "总票数", "总重量", "总运费", "销售联系人" + }; + private static final int[] COMPLIANCE_BASE_WIDTHS = {28, 18, 16, 12, 12, 16, 16, 24}; + private MonthlyShipmentStatExcelUtil() { } @@ -94,21 +116,36 @@ public class MonthlyShipmentStatExcelUtil { private static void exportInternal(HttpServletResponse response, List dataList, int statType, boolean moneyCustomer) { - boolean transportLayout = statType == 1 || statType == 3; + boolean transportLayout = statType == 1 || statType == 3 || statType == 5; boolean compareMode = statType == 3 || statType == 4; + // 是否为月结达标统计(仅 statType=5) + boolean complianceLayout = !moneyCustomer && statType == 5; List safeList = dataList == null ? new ArrayList<>() : dataList; // 为保证 Excel 导出稳定排序:先按总重量降序,再按总票数降序,最后按客户名称升序 - sortForExport(safeList); + if(!complianceLayout){ + sortForExport(safeList); + } List exportList = new ArrayList<>(safeList); exportList.add(buildTotalRow(safeList)); String sheetName = moneyCustomer ? "现金客户出货统计" : "月结客户出货统计"; - String[] headers = moneyCustomer - ? new String[]{"客户名称", "创建日期", "总票数", "总重量", "销售联系人"} - : BASE_HEADERS; + + + String[] headers; + int[] baseWidths; + if (moneyCustomer) { + headers = new String[]{"客户名称", "创建日期", "总票数", "总重量", "销售联系人"}; + baseWidths = BASE_WIDTHS; + } else if (complianceLayout) { + headers = COMPLIANCE_HEADERS; + baseWidths = COMPLIANCE_BASE_WIDTHS; + } else { + headers = BASE_HEADERS; + baseWidths = BASE_WIDTHS; + } try { SXSSFWorkbook workbook = new SXSSFWorkbook(200); @@ -131,7 +168,7 @@ public class MonthlyShipmentStatExcelUtil { // 样式缓存:避免在对比模式下创建过多样式导致超过Excel样式限制 Map styleCache = new HashMap<>(); - createHeader(sheet, headers, transportLayout ? TRANSPORT_GROUPS : COUNTRY_GROUPS, headerStyle); + createHeader(sheet, headers, baseWidths, transportLayout ? TRANSPORT_GROUPS : COUNTRY_GROUPS, headerStyle); int dataStartRow = 2; for (int i = 0; i < exportList.size(); i++) { @@ -143,17 +180,64 @@ public class MonthlyShipmentStatExcelUtil { int col = 0; // 客户名称:月结用 customerName;现金用 company String customerName = moneyCustomer ? vo.getCompany() : vo.getCustomerName(); - String dateValue = moneyCustomer ? vo.getCreateTime() : vo.getFirstSigningDay(); - col = writeTextCell(row, col, customerName, totalRow ? totalTextStyle : textStyle); - col = writeTextCell(row, col, dateValue, totalRow ? totalTextStyle : textStyle); - col = writeIntegerCell(row, col, vo.getTotalTickets(), vo.getTotalTicketsCompareFlag(), - totalRow ? totalNumberStyle : numberStyle, compareMode && !totalRow, workbook, - redArrowFont, greenArrowFont, blueArrowFont, styleCache); - col = writeDecimalCell(row, col, vo.getTotalWeight(), vo.getTotalWeightCompareFlag(), - totalRow ? totalDecimalStyle : decimalStyle, compareMode && !totalRow, workbook, - redArrowFont, greenArrowFont, blueArrowFont, styleCache); - col = writeTextCell(row, col, vo.getSalesmen(), totalRow ? totalTextStyle : textStyle); + + if (moneyCustomer) { + // 现金客户出货统计:保持原有列顺序不变 + String dateValue = vo.getCreateTime(); + col = writeTextCell(row, col, dateValue, totalRow ? totalTextStyle : textStyle); + col = writeIntegerCell(row, col, vo.getTotalTickets(), vo.getTotalTicketsCompareFlag(), + totalRow ? totalNumberStyle : numberStyle, compareMode && !totalRow, workbook, + redArrowFont, greenArrowFont, blueArrowFont, styleCache); + col = writeDecimalCell(row, col, vo.getTotalWeight(), vo.getTotalWeightCompareFlag(), + totalRow ? totalDecimalStyle : decimalStyle, compareMode && !totalRow, workbook, + redArrowFont, greenArrowFont, blueArrowFont, styleCache); + col = writeTextCell(row, col, vo.getSalesmen(), totalRow ? totalTextStyle : textStyle); + } else if (complianceLayout) { + // 月结客户达标统计:使用新增三列 + String dateValue = vo.getFirstSigningDay(); + // 首次签约日期 + col = writeTextCell(row, col, dateValue, totalRow ? totalTextStyle : textStyle); + // 寄件月份 + col = writeTextCell(row, col, vo.getSendMonth(), totalRow ? totalTextStyle : textStyle); + // 是否达标(1=已达标,2=未达标) + String complianceText; + if (vo.getBlCompliance() == null || vo.getBlCompliance().isEmpty()) { + complianceText = ""; + } else if ("1".equals(vo.getBlCompliance())) { + complianceText = "已达标"; + } else if ("2".equals(vo.getBlCompliance())) { + complianceText = "未达标"; + } else { + complianceText = vo.getBlCompliance(); + } + col = writeTextCell(row, col, complianceText, totalRow ? totalTextStyle : textStyle); + + // 总票数、总重量 + col = writeIntegerCell(row, col, vo.getTotalTickets(), vo.getTotalTicketsCompareFlag(), + totalRow ? totalNumberStyle : numberStyle, compareMode && !totalRow, workbook, + redArrowFont, greenArrowFont, blueArrowFont, styleCache); + col = writeDecimalCell(row, col, vo.getTotalWeight(), vo.getTotalWeightCompareFlag(), + totalRow ? totalDecimalStyle : decimalStyle, compareMode && !totalRow, workbook, + redArrowFont, greenArrowFont, blueArrowFont, styleCache); + // 总运费(达标统计专用) + col = writeIntegerCell(row, col, vo.getTotalBillFee(), null, + totalRow ? totalNumberStyle : numberStyle, false, workbook, + redArrowFont, greenArrowFont, blueArrowFont, styleCache); + // 销售联系人 + col = writeTextCell(row, col, vo.getSalesmen(), totalRow ? totalTextStyle : textStyle); + } else { + // 普通月结出货统计:保持原有 5 列 + String dateValue = vo.getFirstSigningDay(); + col = writeTextCell(row, col, dateValue, totalRow ? totalTextStyle : textStyle); + col = writeIntegerCell(row, col, vo.getTotalTickets(), vo.getTotalTicketsCompareFlag(), + totalRow ? totalNumberStyle : numberStyle, compareMode && !totalRow, workbook, + redArrowFont, greenArrowFont, blueArrowFont, styleCache); + col = writeDecimalCell(row, col, vo.getTotalWeight(), vo.getTotalWeightCompareFlag(), + totalRow ? totalDecimalStyle : decimalStyle, compareMode && !totalRow, workbook, + redArrowFont, greenArrowFont, blueArrowFont, styleCache); + col = writeTextCell(row, col, vo.getSalesmen(), totalRow ? totalTextStyle : textStyle); + } List groups = transportLayout ? TRANSPORT_GROUPS : COUNTRY_GROUPS; for (MetricGroup group : groups) { @@ -174,7 +258,8 @@ public class MonthlyShipmentStatExcelUtil { } } - private static void createHeader(Sheet sheet, String[] baseHeaders, List groups, CellStyle headerStyle) { + private static void createHeader(Sheet sheet, String[] baseHeaders, int[] baseWidths, + List groups, CellStyle headerStyle) { Row topRow = sheet.createRow(0); Row subRow = sheet.createRow(1); topRow.setHeightInPoints(22); @@ -186,7 +271,7 @@ public class MonthlyShipmentStatExcelUtil { cell.setCellValue(baseHeaders[i]); cell.setCellStyle(headerStyle); sheet.addMergedRegion(new CellRangeAddress(0, 1, col, col)); - sheet.setColumnWidth(col, BASE_WIDTHS[i] * 256); + sheet.setColumnWidth(col, baseWidths[i] * 256); col++; } @@ -400,9 +485,12 @@ public class MonthlyShipmentStatExcelUtil { total.setCustomerName("合计"); total.setFirstSigningDay(""); total.setSalesmen(""); + total.setSendMonth(""); + total.setBlCompliance(""); total.setTotalTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getTotalTickets)); total.setTotalWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getTotalWeight)); + total.setTotalBillFee(sumInt(source, MonthlyCustomerShipmentStatVO::getTotalBillFee)); total.setExpressTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getExpressTickets)); total.setExpressWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getExpressWeight)); diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java index a593ff905..eca969e16 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java @@ -11,7 +11,15 @@ package com.xdadan.erp.emis.service.impl; import java.util.*; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.stream.Collectors; +import com.github.pagehelper.PageHelper; +import com.xdadan.erp.common.core.page.PageDomain; +import com.xdadan.erp.common.core.page.TableSupport; +import com.xdadan.erp.common.utils.DateUtils; import com.xdadan.erp.common.utils.SecurityUtils; import com.xdadan.erp.emis.domain.exception.EmisBizError; import com.xdadan.erp.emis.domain.enumtype.EmisBizErrorType; @@ -175,14 +183,119 @@ public class EmisCustomerUserServiceImpl extends EmisBaseService implements IEmi } else if ("4".equals(emisWaybill.getParams().get("statType"))) { // 按目的国家统计,增加与上一个时间段的票数、重量对比标记(根据客户类型自动选择 key) result = buildShipmentStatWithCompare(emisWaybill, false); + } else if ("5".equals(emisWaybill.getParams().get("statType"))) { + // 月结客户达标统计 + // 校验:当complianceStatType=3/4/5/6时,寄件时间段需大于等于3个月 + checkDateForComplianceStat(emisWaybill); + if(Objects.isNull(emisWaybill.getParams().get("beginSendDate"))){ + emisWaybill.getParams().put("beginSendDate","2024-01-01 00:00:00"); + } + if(Objects.isNull(emisWaybill.getParams().get("endSendDate"))){ + emisWaybill.getParams().put("endSendDate", DateUtils.getDate("yyyy-MM-dd HH:mm:ss")); + } + + Object complianceStatTypeObj = emisWaybill.getParams().get("complianceStatType"); + String complianceStatType = complianceStatTypeObj != null ? String.valueOf(complianceStatTypeObj) : null; + + // 统一使用应用层过滤:先清除 PageHelper 分页,查询所有数据 + PageHelper.clearPage(); + List allResults = emisCustomerUserMapper.selectMonthlyCustomerShipmentStatIsCompliance(emisWaybill); + + // 先根据 totalTickets / totalBillFee 在代码中计算 blCompliance(1=达标,2=未达标) + if (allResults != null) { + for (MonthlyCustomerShipmentStatVO vo : allResults) { + if (vo == null) { + continue; + } + Integer tickets = vo.getTotalTickets(); + Integer fee = vo.getTotalBillFee(); + int safeTickets = tickets == null ? 0 : tickets; + int safeFee = fee == null ? 0 : fee; + // 规则:票数>=5 或 总运费>=3000 视为达标 + vo.setBlCompliance((safeTickets >= 5 || safeFee >= 3000) ? "1" : "2"); + } + } + + // 按 complianceStatType 在应用层过滤(1~6 全走代码逻辑) + if (complianceStatType != null && !complianceStatType.trim().isEmpty()) { + result = filterComplianceStat(allResults, complianceStatType.trim()); + } else { + result = allResults; + } + + // 保存过滤后的总数到 params 中,供 Controller 使用 + if (emisWaybill.getParams() == null) { + emisWaybill.setParams(new HashMap<>()); + } + emisWaybill.getParams().put("_filteredTotal", result == null ? 0L : (long) result.size()); + + // 手动分页 + if (result == null) { + result = Collections.emptyList(); + } + PageDomain pageDomain = TableSupport.buildPageRequest(); + Integer pageNum = pageDomain.getPageNum(); + Integer pageSize = pageDomain.getPageSize(); + if (pageNum != null && pageSize != null && pageNum > 0 && pageSize > 0) { + int start = (pageNum - 1) * pageSize; + int end = Math.min(start + pageSize, result.size()); + if (start < result.size()) { + result = result.subList(start, end); + } else { + result = Collections.emptyList(); + } + } } else { result = Collections.emptyList(); } - sortShipmentStat(result); + if(!"5".equals(emisWaybill.getParams().get("statType"))){ + sortShipmentStat(result); + } return result; } + private void checkDateForComplianceStat(EmisWaybill emisWaybill) throws EmisBizError { + Object complianceStatTypeObj = emisWaybill.getParams().get("complianceStatType"); + if (complianceStatTypeObj != null) { + String complianceStatType = String.valueOf(complianceStatTypeObj); + if ("3".equals(complianceStatType) || "4".equals(complianceStatType) + || "5".equals(complianceStatType) || "6".equals(complianceStatType)) { + // 验证时间段必须大于等于3个月 + Object beginSendObj = emisWaybill.getParams().get("beginSendDate"); + Object endSendObj = emisWaybill.getParams().get("endSendDate"); + + if (beginSendObj == null || endSendObj == null) { + throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "请选择寄件日期"); + } + + try { + String beginSendDate = String.valueOf(beginSendObj).trim(); + String endSendDate = String.valueOf(endSendObj).trim(); + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDate beginDate = LocalDate.parse(beginSendDate, formatter); + LocalDate endDate = LocalDate.parse(endSendDate, formatter); + + long monthsBetween = ChronoUnit.MONTHS.between( + beginDate.withDayOfMonth(1), + endDate.withDayOfMonth(1) + ); + + if (monthsBetween < 3) { + throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, + "当达标统计类型为" + getComplianceStatTypeName(complianceStatType) + "时,寄件时间段需大于等于3个月"); + } + } catch (Exception e) { + if (e instanceof EmisBizError) { + throw e; + } + throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "日期格式错误,请使用yyyy-MM-dd HH:mm:ss格式"); + } + } + } + } + /** * 查询现金客户出货统计 * @@ -429,6 +542,184 @@ public class EmisCustomerUserServiceImpl extends EmisBaseService implements IEmi return v == null ? 0 : v; } + /** + * 获取达标统计类型名称 + */ + private String getComplianceStatTypeName(String complianceStatType) { + switch (complianceStatType) { + case "3": return "连续3个月未出货"; + case "4": return "累计3个月未出货"; + case "5": return "连续3个月出货未达标"; + case "6": return "累计3个月出货未达标"; + default: return complianceStatType; + } + } + + /** + * 应用层过滤:根据 complianceStatType 过滤统计结果 + * 优化:将复杂的 SQL EXISTS 子查询移到应用层处理,提升查询性能 + * + * @param allResults 所有查询结果(已按客户+月份分组) + * @param complianceStatType 达标统计类型:3-连续3个月未出货,4-累计3个月未出货,5-连续3个月未达标,6-累计3个月未达标 + * @return 过滤后的结果列表 + */ + private List filterComplianceStat( + List allResults, String complianceStatType) { + if (allResults == null || allResults.isEmpty()) { + return Collections.emptyList(); + } + + // 1/2:简单按 blCompliance 过滤(1=已达标,2=未达标) + if ("1".equals(complianceStatType)) { + return allResults.stream() + .filter(m -> "1".equals(m.getBlCompliance())) + .collect(Collectors.toList()); + } + if ("2".equals(complianceStatType)) { + return allResults.stream() + .filter(m -> "2".equals(m.getBlCompliance())) + .collect(Collectors.toList()); + } + + // 按客户分组,便于后续判断连续/累计 + Map> customerMap = allResults.stream() + .collect(Collectors.groupingBy( + item -> item.getCustNo() != null ? item.getCustNo() : "", + LinkedHashMap::new, + Collectors.toList() + )); + + List filteredResults = new ArrayList<>(); + + for (Map.Entry> entry : customerMap.entrySet()) { + List customerMonths = entry.getValue(); + // 按月份排序(升序) + customerMonths.sort(Comparator.comparing(MonthlyCustomerShipmentStatVO::getSendMonth)); + + switch (complianceStatType) { + case "3": + // 连续3个月以上出货为0 + filteredResults.addAll(filterConsecutiveZeroTickets(customerMonths)); + break; + case "4": + // 累计超过3个月出货为0 + filteredResults.addAll(filterAccumulatedZeroTickets(customerMonths, 3)); + break; + case "5": + // 连续3个月以上出货未达标 + filteredResults.addAll(filterConsecutiveNonCompliance(customerMonths)); + break; + case "6": + // 累计3个月以上出货未达标 + filteredResults.addAll(filterAccumulatedNonCompliance(customerMonths, 3)); + break; + default: + filteredResults.addAll(customerMonths); + break; + } + } + + return filteredResults; + } + + /** + * 过滤连续3个月以上出货为0的月份 + */ + private List filterConsecutiveZeroTickets( + List customerMonths) { + List result = new ArrayList<>(); + for (int i = 0; i < customerMonths.size(); i++) { + MonthlyCustomerShipmentStatVO current = customerMonths.get(i); + if (current.getTotalTickets() == null || current.getTotalTickets() == 0) { + // 检查前两个月是否也为0 + boolean prev1Zero = (i >= 1 && (customerMonths.get(i - 1).getTotalTickets() == null + || customerMonths.get(i - 1).getTotalTickets() == 0)); + boolean prev2Zero = (i >= 2 && (customerMonths.get(i - 2).getTotalTickets() == null + || customerMonths.get(i - 2).getTotalTickets() == 0)); + // 检查后两个月是否也为0 + boolean next1Zero = (i < customerMonths.size() - 1 + && (customerMonths.get(i + 1).getTotalTickets() == null + || customerMonths.get(i + 1).getTotalTickets() == 0)); + boolean next2Zero = (i < customerMonths.size() - 2 + && (customerMonths.get(i + 2).getTotalTickets() == null + || customerMonths.get(i + 2).getTotalTickets() == 0)); + + // 连续口径:某月在连续>=3的窗口内即可返回(包含窗口的前两个月或后两个月) + if ((prev1Zero && prev2Zero) || (prev1Zero && next1Zero) || (next1Zero && next2Zero)) { + result.add(current); + } + } + } + return result; + } + + /** + * 过滤累计超过指定月数出货为0的月份 + */ + private List filterAccumulatedZeroTickets( + List customerMonths, int minMonths) { + // 统计该客户出货为0的月份总数 + long zeroTicketMonths = customerMonths.stream() + .filter(m -> m.getTotalTickets() == null || m.getTotalTickets() == 0) + .count(); + + if (zeroTicketMonths >= minMonths) { + // 返回所有出货为0的月份 + return customerMonths.stream() + .filter(m -> m.getTotalTickets() == null || m.getTotalTickets() == 0) + .collect(Collectors.toList()); + } + return Collections.emptyList(); + } + + /** + * 过滤连续3个月以上出货未达标的月份 + */ + private List filterConsecutiveNonCompliance( + List customerMonths) { + List result = new ArrayList<>(); + for (int i = 0; i < customerMonths.size(); i++) { + MonthlyCustomerShipmentStatVO current = customerMonths.get(i); + if ("2".equals(current.getBlCompliance())) { + // 检查前两个月是否也未达标 + boolean prev1NonCompliance = (i >= 1 && "2".equals(customerMonths.get(i - 1).getBlCompliance())); + boolean prev2NonCompliance = (i >= 2 && "2".equals(customerMonths.get(i - 2).getBlCompliance())); + // 检查后两个月是否也未达标 + boolean next1NonCompliance = (i < customerMonths.size() - 1 + && "2".equals(customerMonths.get(i + 1).getBlCompliance())); + boolean next2NonCompliance = (i < customerMonths.size() - 2 + && "2".equals(customerMonths.get(i + 2).getBlCompliance())); + + // 连续口径:某月在连续>=3的窗口内即可返回 + if ((prev1NonCompliance && prev2NonCompliance) + || (prev1NonCompliance && next1NonCompliance) + || (next1NonCompliance && next2NonCompliance)) { + result.add(current); + } + } + } + return result; + } + + /** + * 过滤累计超过指定月数出货未达标的月份 + */ + private List filterAccumulatedNonCompliance( + List customerMonths, int minMonths) { + // 统计该客户未达标的月份总数 + long nonComplianceMonths = customerMonths.stream() + .filter(m -> "2".equals(m.getBlCompliance())) + .count(); + + if (nonComplianceMonths >= minMonths) { + // 返回所有未达标的月份 + return customerMonths.stream() + .filter(m -> "2".equals(m.getBlCompliance())) + .collect(Collectors.toList()); + } + return Collections.emptyList(); + } + /** * 查询月结客户出货明细 * diff --git a/emis-biz/src/main/resources/mapper/EmisCustomerUserMapper.xml b/emis-biz/src/main/resources/mapper/EmisCustomerUserMapper.xml index 75e145e5f..318b3fe1d 100644 --- a/emis-biz/src/main/resources/mapper/EmisCustomerUserMapper.xml +++ b/emis-biz/src/main/resources/mapper/EmisCustomerUserMapper.xml @@ -674,4 +674,160 @@ AND del_flag = '0' + + + + diff --git a/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml b/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml index d154230cb..29b2ba73f 100644 --- a/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml +++ b/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml @@ -3183,6 +3183,9 @@ or a.take_piece_employee_code=#{params.privEmpCode} ) + + and DATE_FORMAT(a.send_date,'%Y%m')= #{params.billMonth} + @@ -5083,6 +5086,9 @@ ) + + and DATE_FORMAT(a.send_date,'%Y-%m')= #{params.sendMonth} + AND EXISTS ( From c3dc8ae7f27632c102fa88bf123f3b9aeddd8d4c Mon Sep 17 00:00:00 2001 From: aike <17730485278@139.com> Date: Thu, 12 Feb 2026 10:37:42 +0800 Subject: [PATCH 4/7] =?UTF-8?q?demand:=20=20=20=E6=9C=88=E7=BB=93=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E8=BE=BE=E6=A0=87=E7=BB=9F=E8=AE=A1=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../erp/emis/service/impl/EmisCustomerUserServiceImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java index eca969e16..11e5b71ba 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java @@ -278,9 +278,9 @@ public class EmisCustomerUserServiceImpl extends EmisBaseService implements IEmi LocalDate endDate = LocalDate.parse(endSendDate, formatter); long monthsBetween = ChronoUnit.MONTHS.between( - beginDate.withDayOfMonth(1), - endDate.withDayOfMonth(1) - ); + beginDate.withDayOfMonth(1), + endDate.withDayOfMonth(1) + ) + 1L; if (monthsBetween < 3) { throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, From d8853d8d178a1cbb0dc6dbcda75fbcae71c09e41 Mon Sep 17 00:00:00 2001 From: aike <17730485278@139.com> Date: Thu, 12 Feb 2026 11:12:38 +0800 Subject: [PATCH 5/7] =?UTF-8?q?demand:=20=20=20=E6=9C=88=E7=BB=93=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E8=BE=BE=E6=A0=87=E7=BB=9F=E8=AE=A1=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E6=AE=B5=E6=A0=BC=E5=BC=8F=E6=94=B9=E4=B8=BAyyyy-MM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/EmisCustomerUserServiceImpl.java | 24 ++++++++++--------- .../mapper/EmisCustomerUserMapper.xml | 8 +++---- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java index 11e5b71ba..c2d6bfc72 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java @@ -11,7 +11,7 @@ package com.xdadan.erp.emis.service.impl; import java.util.*; -import java.time.LocalDate; +import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.stream.Collectors; @@ -188,10 +188,10 @@ public class EmisCustomerUserServiceImpl extends EmisBaseService implements IEmi // 校验:当complianceStatType=3/4/5/6时,寄件时间段需大于等于3个月 checkDateForComplianceStat(emisWaybill); if(Objects.isNull(emisWaybill.getParams().get("beginSendDate"))){ - emisWaybill.getParams().put("beginSendDate","2024-01-01 00:00:00"); + emisWaybill.getParams().put("beginSendDate","2024-01"); } if(Objects.isNull(emisWaybill.getParams().get("endSendDate"))){ - emisWaybill.getParams().put("endSendDate", DateUtils.getDate("yyyy-MM-dd HH:mm:ss")); + emisWaybill.getParams().put("endSendDate", DateUtils.getDate("yyyy-MM")); } Object complianceStatTypeObj = emisWaybill.getParams().get("complianceStatType"); @@ -273,14 +273,16 @@ public class EmisCustomerUserServiceImpl extends EmisBaseService implements IEmi String beginSendDate = String.valueOf(beginSendObj).trim(); String endSendDate = String.valueOf(endSendObj).trim(); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - LocalDate beginDate = LocalDate.parse(beginSendDate, formatter); - LocalDate endDate = LocalDate.parse(endSendDate, formatter); + DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM"); + // 验证格式是否为 yyyy-MM + monthFormatter.parse(beginSendDate); + monthFormatter.parse(endSendDate); + // 解析为 YearMonth 来计算月份差 + YearMonth beginMonth = YearMonth.parse(beginSendDate, monthFormatter); + YearMonth endMonth = YearMonth.parse(endSendDate, monthFormatter); - long monthsBetween = ChronoUnit.MONTHS.between( - beginDate.withDayOfMonth(1), - endDate.withDayOfMonth(1) - ) + 1L; + // 计算月份差,应大于等于3个月 + long monthsBetween = ChronoUnit.MONTHS.between(beginMonth, endMonth) + 1L; if (monthsBetween < 3) { throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, @@ -290,7 +292,7 @@ public class EmisCustomerUserServiceImpl extends EmisBaseService implements IEmi if (e instanceof EmisBizError) { throw e; } - throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "日期格式错误,请使用yyyy-MM-dd HH:mm:ss格式"); + throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "日期格式错误,请使用yyyy-MM格式"); } } } diff --git a/emis-biz/src/main/resources/mapper/EmisCustomerUserMapper.xml b/emis-biz/src/main/resources/mapper/EmisCustomerUserMapper.xml index 318b3fe1d..8b2622b7d 100644 --- a/emis-biz/src/main/resources/mapper/EmisCustomerUserMapper.xml +++ b/emis-biz/src/main/resources/mapper/EmisCustomerUserMapper.xml @@ -732,8 +732,8 @@ FROM emis_customer_user cu JOIN ( SELECT - DATE_FORMAT(DATE_ADD(STR_TO_DATE(#{params.beginSendDate}, '%Y-%m-%d %H:%i:%s'), INTERVAL n.n MONTH), '%Y-%m') AS sendMonth, - DATE_FORMAT(DATE_ADD(STR_TO_DATE(#{params.beginSendDate}, '%Y-%m-%d %H:%i:%s'), INTERVAL n.n MONTH), '%Y-%m-01') AS monthStart + DATE_FORMAT(DATE_ADD(STR_TO_DATE(CONCAT(#{params.beginSendDate}, '-01'), '%Y-%m-%d'), INTERVAL n.n MONTH), '%Y-%m') AS sendMonth, + DATE_FORMAT(DATE_ADD(STR_TO_DATE(CONCAT(#{params.beginSendDate}, '-01'), '%Y-%m-%d'), INTERVAL n.n MONTH), '%Y-%m-01') AS monthStart FROM ( SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL @@ -743,8 +743,8 @@ SELECT 30 UNION ALL SELECT 31 UNION ALL SELECT 32 UNION ALL SELECT 33 UNION ALL SELECT 34 UNION ALL SELECT 35 UNION ALL SELECT 36 ) n - WHERE DATE_ADD(STR_TO_DATE(#{params.beginSendDate}, '%Y-%m-%d %H:%i:%s'), INTERVAL n.n MONTH) - STR_TO_DATE(#{params.endSendDate}, '%Y-%m-%d %H:%i:%s') + WHERE DATE_ADD(STR_TO_DATE(CONCAT(#{params.beginSendDate}, '-01'), '%Y-%m-%d'), INTERVAL n.n MONTH) + STR_TO_DATE(CONCAT(#{params.endSendDate}, '-01'), '%Y-%m-%d') ) m LEFT JOIN emis_waybill a ON cu.monthly_pay_code = a.cust_no From a1ffe2d9b54cb9f55ef0091b71da068292c6f44c Mon Sep 17 00:00:00 2001 From: aike <17730485278@139.com> Date: Thu, 12 Feb 2026 16:24:34 +0800 Subject: [PATCH 6/7] =?UTF-8?q?demand:=20=20=20=E6=9C=88=E7=BB=93=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E8=BE=BE=E6=A0=87=E7=BB=9F=E8=AE=A1=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E6=AE=B5=E6=A0=BC=E5=BC=8F=E6=94=B9=E4=B8=BAyyyy-MM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../erp/emis/service/impl/EmisCustomerUserServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java index c2d6bfc72..5923381bd 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java @@ -188,7 +188,7 @@ public class EmisCustomerUserServiceImpl extends EmisBaseService implements IEmi // 校验:当complianceStatType=3/4/5/6时,寄件时间段需大于等于3个月 checkDateForComplianceStat(emisWaybill); if(Objects.isNull(emisWaybill.getParams().get("beginSendDate"))){ - emisWaybill.getParams().put("beginSendDate","2024-01"); + emisWaybill.getParams().put("beginSendDate","2024-07"); } if(Objects.isNull(emisWaybill.getParams().get("endSendDate"))){ emisWaybill.getParams().put("endSendDate", DateUtils.getDate("yyyy-MM")); From 5582cb534d658d5383d2fbcbad6b60c0a6576627 Mon Sep 17 00:00:00 2001 From: aike <17730485278@139.com> Date: Thu, 12 Feb 2026 16:52:41 +0800 Subject: [PATCH 7/7] =?UTF-8?q?demand:=20=20=20=E6=9C=88=E7=BB=93=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E8=BE=BE=E6=A0=87=E7=BB=9F=E8=AE=A1=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E6=AE=B5=E6=A0=BC=E5=BC=8F=E6=94=B9=E4=B8=BAyyyy-MM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../erp/emis/service/impl/EmisCustomerUserServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java index 5923381bd..9528d1fa5 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisCustomerUserServiceImpl.java @@ -595,8 +595,8 @@ public class EmisCustomerUserServiceImpl extends EmisBaseService implements IEmi for (Map.Entry> entry : customerMap.entrySet()) { List customerMonths = entry.getValue(); - // 按月份排序(升序) - customerMonths.sort(Comparator.comparing(MonthlyCustomerShipmentStatVO::getSendMonth)); + // 按月份排序(降序) + customerMonths.sort(Comparator.comparing(MonthlyCustomerShipmentStatVO::getSendMonth).reversed()); switch (complianceStatType) { case "3":