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 95821223b..805e9e7b9 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 @@ -34,7 +34,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.xdadan.erp.common.annotation.Log; -import com.xdadan.erp.common.core.controller.BaseController; import com.xdadan.erp.common.core.domain.AjaxResult; import com.xdadan.erp.common.core.page.TableDataInfo; import com.xdadan.erp.common.enums.BusinessType; @@ -44,6 +43,7 @@ import com.xdadan.erp.common.utils.poi.ExcelUtil; import com.xdadan.erp.emis.service.IEmisCustomerUserService; import com.xdadan.erp.emis.domain.EmisWaybill; import com.xdadan.erp.emis.domain.vo.MonthlyCustomerShipmentStatVO; +import com.xdadan.erp.emis.service.excelCellStrategy.MonthlyShipmentStatExcelUtil; /** * 快递客户用户Controller @@ -518,8 +518,22 @@ public class EmisCustomerUserController extends EmisBaseController setPrivParams(emisWaybill); List list = emisCustomerUserService .selectMonthlyCustomerShipmentStat(emisWaybill); - ExcelUtil util = new ExcelUtil( - MonthlyCustomerShipmentStatVO.class); - util.exportExcel(response, list, "月结客户出货统计"); + int statType = resolveStatType(emisWaybill); + MonthlyShipmentStatExcelUtil.export(response, list, statType); + } + + private int resolveStatType(EmisWaybill emisWaybill) { + if (emisWaybill == null || emisWaybill.getParams() == null) { + return 1; + } + Object statTypeObj = emisWaybill.getParams().get("statType"); + if (statTypeObj == null) { + return 1; + } + try { + return Integer.parseInt(statTypeObj.toString()); + } catch (NumberFormatException e) { + return 1; + } } } 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 new file mode 100644 index 000000000..97d793088 --- /dev/null +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/MonthlyShipmentStatExcelUtil.java @@ -0,0 +1,489 @@ +package com.xdadan.erp.emis.service.excelCellStrategy; + +import com.xdadan.erp.emis.domain.vo.MonthlyCustomerShipmentStatVO; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URLEncoder; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.Collator; +import java.util.*; +import java.util.function.Function; + +/** + * 自定义月结客户出货统计导出工具 + * + *

支持两套布局(运输方式/国家维度)和两种模式(普通/同比对比箭头)。

+ */ +public class MonthlyShipmentStatExcelUtil { + + private static final List TRANSPORT_GROUPS = Arrays.asList( + new MetricGroup("快递", MonthlyCustomerShipmentStatVO::getExpressTickets, + MonthlyCustomerShipmentStatVO::getExpressWeight, MonthlyCustomerShipmentStatVO::getExpressTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getExpressWeightCompareFlag), + new MetricGroup("空运", MonthlyCustomerShipmentStatVO::getAirTickets, + MonthlyCustomerShipmentStatVO::getAirWeight, MonthlyCustomerShipmentStatVO::getAirTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getAirWeightCompareFlag), + new MetricGroup("陆运", MonthlyCustomerShipmentStatVO::getLandTickets, + MonthlyCustomerShipmentStatVO::getLandWeight, MonthlyCustomerShipmentStatVO::getLandTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getLandWeightCompareFlag), + new MetricGroup("进口", MonthlyCustomerShipmentStatVO::getImportTickets, + MonthlyCustomerShipmentStatVO::getImportWeight, MonthlyCustomerShipmentStatVO::getImportTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getImportWeightCompareFlag), + new MetricGroup("海运", MonthlyCustomerShipmentStatVO::getSeaTickets, + MonthlyCustomerShipmentStatVO::getSeaWeight, MonthlyCustomerShipmentStatVO::getSeaTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getSeaWeightCompareFlag), + new MetricGroup("其他", MonthlyCustomerShipmentStatVO::getOtherTickets, + MonthlyCustomerShipmentStatVO::getOtherWeight, MonthlyCustomerShipmentStatVO::getOtherTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getOtherWeightCompareFlag) + ); + + private static final List COUNTRY_GROUPS = Arrays.asList( + new MetricGroup("中国", MonthlyCustomerShipmentStatVO::getChinaTickets, + MonthlyCustomerShipmentStatVO::getChinaWeight, MonthlyCustomerShipmentStatVO::getChinaTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getChinaWeightCompareFlag), + new MetricGroup("越南", MonthlyCustomerShipmentStatVO::getVietnamTickets, + MonthlyCustomerShipmentStatVO::getVietnamWeight, MonthlyCustomerShipmentStatVO::getVietnamTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getVietnamWeightCompareFlag), + new MetricGroup("柬埔寨", MonthlyCustomerShipmentStatVO::getCambodiaTickets, + MonthlyCustomerShipmentStatVO::getCambodiaWeight, MonthlyCustomerShipmentStatVO::getCambodiaTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getCambodiaWeightCompareFlag), + new MetricGroup("缅甸", MonthlyCustomerShipmentStatVO::getMyanmarTickets, + MonthlyCustomerShipmentStatVO::getMyanmarWeight, MonthlyCustomerShipmentStatVO::getMyanmarTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getMyanmarWeightCompareFlag), + new MetricGroup("孟加拉", MonthlyCustomerShipmentStatVO::getBangladeshTickets, + MonthlyCustomerShipmentStatVO::getBangladeshWeight, MonthlyCustomerShipmentStatVO::getBangladeshTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getBangladeshWeightCompareFlag), + new MetricGroup("老挝", MonthlyCustomerShipmentStatVO::getLaosTickets, + MonthlyCustomerShipmentStatVO::getLaosWeight, MonthlyCustomerShipmentStatVO::getLaosTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getLaosWeightCompareFlag), + new MetricGroup("泰国", MonthlyCustomerShipmentStatVO::getThailandTickets, + MonthlyCustomerShipmentStatVO::getThailandWeight, MonthlyCustomerShipmentStatVO::getThailandTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getThailandWeightCompareFlag), + new MetricGroup("其他", MonthlyCustomerShipmentStatVO::getOtherTickets, + MonthlyCustomerShipmentStatVO::getOtherWeight, MonthlyCustomerShipmentStatVO::getOtherTicketsCompareFlag, + MonthlyCustomerShipmentStatVO::getOtherWeightCompareFlag) + ); + + private static final String[] BASE_HEADERS = {"客户名称", "首次签约日期", "总票数", "总重量", "销售联系人"}; + private static final int[] BASE_WIDTHS = {28, 18, 12, 16, 24}; + + private MonthlyShipmentStatExcelUtil() { + } + + public static void export(HttpServletResponse response, List dataList, int statType) { + boolean transportLayout = statType == 1 || statType == 3; + boolean compareMode = statType == 3 || statType == 4; + + List safeList = dataList == null ? new ArrayList<>() : dataList; + + // 为保证 Excel 导出稳定排序:先按总重量降序,再按总票数降序,最后按客户名称升序 + sortForExport(safeList); + + List exportList = new ArrayList<>(safeList); + exportList.add(buildTotalRow(safeList)); + + try { + SXSSFWorkbook workbook = new SXSSFWorkbook(200); + Sheet sheet = workbook.createSheet("月结客户出货统计"); + sheet.createFreezePane(0, 2); + + // styles + CellStyle headerStyle = createHeaderStyle(workbook); + CellStyle textStyle = createTextStyle(workbook); + CellStyle numberStyle = createNumberStyle(workbook, false); + CellStyle decimalStyle = createNumberStyle(workbook, true); + CellStyle totalTextStyle = cloneWithBold(workbook, textStyle); + CellStyle totalNumberStyle = cloneWithBold(workbook, numberStyle); + CellStyle totalDecimalStyle = cloneWithBold(workbook, decimalStyle); + + Font redArrowFont = createArrowFont(workbook, IndexedColors.RED.getIndex()); + Font greenArrowFont = createArrowFont(workbook, IndexedColors.GREEN.getIndex()); + Font blueArrowFont = createArrowFont(workbook, IndexedColors.BLUE.getIndex()); + + createHeader(sheet, transportLayout ? TRANSPORT_GROUPS : COUNTRY_GROUPS, headerStyle); + + int dataStartRow = 2; + for (int i = 0; i < exportList.size(); i++) { + MonthlyCustomerShipmentStatVO vo = exportList.get(i); + boolean totalRow = i == exportList.size() - 1; + Row row = sheet.createRow(dataStartRow + i); + row.setHeightInPoints(20); + + int col = 0; + col = writeTextCell(row, col, vo.getCustomerName(), totalRow ? totalTextStyle : textStyle); + col = writeTextCell(row, col, vo.getFirstSigningDay(), totalRow ? totalTextStyle : textStyle); + col = writeIntegerCell(row, col, vo.getTotalTickets(), vo.getTotalTicketsCompareFlag(), + totalRow ? totalNumberStyle : numberStyle, compareMode && !totalRow, workbook, + redArrowFont, greenArrowFont, blueArrowFont); + col = writeDecimalCell(row, col, vo.getTotalWeight(), vo.getTotalWeightCompareFlag(), + totalRow ? totalDecimalStyle : decimalStyle, compareMode && !totalRow, workbook, + redArrowFont, greenArrowFont, blueArrowFont); + col = writeTextCell(row, col, vo.getSalesmen(), totalRow ? totalTextStyle : textStyle); + + List groups = transportLayout ? TRANSPORT_GROUPS : COUNTRY_GROUPS; + for (MetricGroup group : groups) { + col = writeIntegerCell(row, col, group.ticketGetter.apply(vo), group.ticketFlagGetter.apply(vo), + totalRow ? totalNumberStyle : numberStyle, compareMode && !totalRow, workbook, + redArrowFont, greenArrowFont, blueArrowFont); + col = writeDecimalCell(row, col, group.weightGetter.apply(vo), group.weightFlagGetter.apply(vo), + totalRow ? totalDecimalStyle : decimalStyle, compareMode && !totalRow, workbook, + redArrowFont, greenArrowFont, blueArrowFont); + } + } + + autoSize(sheet); + writeToResponse(response, workbook, "月结客户出货统计"); + } catch (IOException e) { + throw new RuntimeException("导出月结客户出货统计失败:" + e.getMessage(), e); + } + } + + private static void createHeader(Sheet sheet, List groups, CellStyle headerStyle) { + Row topRow = sheet.createRow(0); + Row subRow = sheet.createRow(1); + topRow.setHeightInPoints(22); + subRow.setHeightInPoints(22); + + int col = 0; + for (int i = 0; i < BASE_HEADERS.length; i++) { + Cell cell = topRow.createCell(col); + cell.setCellValue(BASE_HEADERS[i]); + cell.setCellStyle(headerStyle); + sheet.addMergedRegion(new CellRangeAddress(0, 1, col, col)); + sheet.setColumnWidth(col, BASE_WIDTHS[i] * 256); + col++; + } + + for (MetricGroup group : groups) { + Cell groupCell = topRow.createCell(col); + groupCell.setCellValue(group.label); + groupCell.setCellStyle(headerStyle); + sheet.addMergedRegion(new CellRangeAddress(0, 0, col, col + 1)); + + Cell ticketsCell = subRow.createCell(col); + ticketsCell.setCellValue("票数"); + ticketsCell.setCellStyle(headerStyle); + sheet.setColumnWidth(col, 12 * 256); + col++; + + Cell weightCell = subRow.createCell(col); + weightCell.setCellValue("实际重量"); + weightCell.setCellStyle(headerStyle); + sheet.setColumnWidth(col, 16 * 256); + col++; + } + } + + private static int writeTextCell(Row row, int colIndex, String value, CellStyle style) { + Cell cell = row.createCell(colIndex); + cell.setCellStyle(style); + cell.setCellValue(value == null ? "" : value); + return colIndex + 1; + } + + private static int writeIntegerCell(Row row, int colIndex, Integer value, Integer compareFlag, CellStyle style, + boolean compareMode, Workbook workbook, Font redArrowFont, + Font greenArrowFont, Font blueArrowFont) { + String text = value == null ? "" : value.toString(); + applyRichText(row.createCell(colIndex), text, compareFlag, style, compareMode, workbook, + redArrowFont, greenArrowFont, blueArrowFont); + return colIndex + 1; + } + + private static int writeDecimalCell(Row row, int colIndex, BigDecimal value, Integer compareFlag, CellStyle style, + boolean compareMode, Workbook workbook, Font redArrowFont, + Font greenArrowFont, Font blueArrowFont) { + String text = formatDecimal(value); + applyRichText(row.createCell(colIndex), text, compareFlag, style, compareMode, workbook, + redArrowFont, greenArrowFont, blueArrowFont); + return colIndex + 1; + } + + private static void applyRichText(Cell cell, String valueText, Integer compareFlag, CellStyle style, + boolean compareMode, Workbook workbook, Font redArrowFont, + Font greenArrowFont, Font blueArrowFont) { + if (!compareMode) { + cell.setCellStyle(style); + cell.setCellValue(valueText); + return; + } + CompareArrow arrow = CompareArrow.of(compareFlag); + if (arrow == null) { + cell.setCellStyle(style); + cell.setCellValue(valueText); + return; + } + + // 为兼容 SXSSFWorkbook,这里不再使用富文本局部着色,而是整格字体着色 + Font arrowFont = arrow.pickFont(redArrowFont, greenArrowFont, blueArrowFont); + CellStyle coloredStyle = workbook.createCellStyle(); + coloredStyle.cloneStyleFrom(style); + coloredStyle.setFont(arrowFont); + + String display = (valueText == null || valueText.isEmpty()) + ? arrow.symbol + : valueText + " " + arrow.symbol; + + cell.setCellStyle(coloredStyle); + cell.setCellValue(display); + } + + private static String formatDecimal(BigDecimal value) { + if (value == null) { + return ""; + } + BigDecimal stripped = value.stripTrailingZeros(); + if (stripped.scale() < 0) { + stripped = stripped.setScale(0); + } + return stripped.toPlainString(); + } + + private static void autoSize(Sheet sheet) { + // SXSSF不支持autoSize,手动设置的宽度已满足,此处预留接口 + } + + private static CellStyle createHeaderStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + setBorder(style); + + Font font = workbook.createFont(); + font.setBold(true); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 12); + style.setFont(font); + return style; + } + + private static CellStyle createTextStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + style.setAlignment(HorizontalAlignment.LEFT); + style.setVerticalAlignment(VerticalAlignment.CENTER); + setBorder(style); + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 11); + style.setFont(font); + return style; + } + + private static CellStyle createNumberStyle(Workbook workbook, boolean decimal) { + CellStyle style = workbook.createCellStyle(); + style.setAlignment(HorizontalAlignment.RIGHT); + style.setVerticalAlignment(VerticalAlignment.CENTER); + setBorder(style); + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 11); + style.setFont(font); + if (decimal) { + style.setDataFormat(workbook.createDataFormat().getFormat("@")); + } + return style; + } + + private static CellStyle cloneWithBold(Workbook workbook, CellStyle source) { + CellStyle style = workbook.createCellStyle(); + style.cloneStyleFrom(source); + Font font = workbook.createFont(); + font.setBold(true); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 11); + style.setFont(font); + return style; + } + + private static void setBorder(CellStyle style) { + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + } + + private static Font createArrowFont(Workbook workbook, short colorIndex) { + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 11); + font.setBold(true); + font.setColor(colorIndex); + return font; + } + + /** + * 导出排序:总重量 desc、总票数 desc、客户名称 asc(中文按本地 Collator) + */ + private static void sortForExport(List list) { + if (list == null || list.isEmpty()) { + return; + } + final Collator collator = Collator.getInstance(Locale.CHINA); + + list.sort(Comparator + .comparing((MonthlyCustomerShipmentStatVO vo) -> nvl(vo.getTotalWeight()), Comparator.reverseOrder()) + .thenComparing(vo -> nvl(vo.getTotalTickets()), Comparator.reverseOrder()) + .thenComparing( + vo -> Optional.ofNullable(vo.getCustomerName()).orElse(""), + collator + )); + } + + private static BigDecimal nvl(BigDecimal v) { + return v == null ? BigDecimal.ZERO : v; + } + + private static Integer nvl(Integer v) { + return v == null ? 0 : v; + } + + private static void writeToResponse(HttpServletResponse response, SXSSFWorkbook workbook, String sheetName) + throws IOException { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String fileName = URLEncoder.encode(sheetName + ".xlsx", "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName); + try (OutputStream outputStream = response.getOutputStream()) { + workbook.write(outputStream); + workbook.close(); + workbook.dispose(); + } + } + + private static MonthlyCustomerShipmentStatVO buildTotalRow(List source) { + MonthlyCustomerShipmentStatVO total = new MonthlyCustomerShipmentStatVO(); + total.setCustomerName("合计"); + total.setFirstSigningDay(""); + total.setSalesmen(""); + + total.setTotalTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getTotalTickets)); + total.setTotalWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getTotalWeight)); + + total.setExpressTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getExpressTickets)); + total.setExpressWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getExpressWeight)); + total.setAirTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getAirTickets)); + total.setAirWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getAirWeight)); + total.setLandTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getLandTickets)); + total.setLandWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getLandWeight)); + total.setImportTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getImportTickets)); + total.setImportWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getImportWeight)); + total.setSeaTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getSeaTickets)); + total.setSeaWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getSeaWeight)); + total.setOtherTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getOtherTickets)); + total.setOtherWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getOtherWeight)); + + total.setChinaTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getChinaTickets)); + total.setChinaWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getChinaWeight)); + total.setVietnamTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getVietnamTickets)); + total.setVietnamWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getVietnamWeight)); + total.setCambodiaTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getCambodiaTickets)); + total.setCambodiaWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getCambodiaWeight)); + total.setMyanmarTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getMyanmarTickets)); + total.setMyanmarWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getMyanmarWeight)); + total.setBangladeshTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getBangladeshTickets)); + total.setBangladeshWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getBangladeshWeight)); + total.setLaosTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getLaosTickets)); + total.setLaosWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getLaosWeight)); + total.setThailandTickets(sumInt(source, MonthlyCustomerShipmentStatVO::getThailandTickets)); + total.setThailandWeight(sumDecimal(source, MonthlyCustomerShipmentStatVO::getThailandWeight)); + return total; + } + + private static Integer sumInt(List source, + Function getter) { + long sum = 0; + for (MonthlyCustomerShipmentStatVO item : source) { + Integer value = getter.apply(item); + if (value != null) { + sum += value; + } + } + if (sum > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + return (int) sum; + } + + private static BigDecimal sumDecimal(List source, + Function getter) { + BigDecimal sum = BigDecimal.ZERO; + for (MonthlyCustomerShipmentStatVO item : source) { + BigDecimal value = getter.apply(item); + if (value != null) { + sum = sum.add(value); + } + } + if (sum.compareTo(BigDecimal.ZERO) == 0) { + return BigDecimal.ZERO; + } + return sum.setScale(2, RoundingMode.HALF_UP); + } + + private static class MetricGroup { + private final String label; + private final Function ticketGetter; + private final Function weightGetter; + private final Function ticketFlagGetter; + private final Function weightFlagGetter; + + private MetricGroup(String label, + Function ticketGetter, + Function weightGetter, + Function ticketFlagGetter, + Function weightFlagGetter) { + this.label = label; + this.ticketGetter = ticketGetter; + this.weightGetter = weightGetter; + this.ticketFlagGetter = ticketFlagGetter; + this.weightFlagGetter = weightFlagGetter; + } + } + + private enum CompareArrow { + UP(1, "\u2191"), + DOWN(2, "\u2193"), + FLAT(0, "\u2192"); + + private final int flag; + private final String symbol; + + CompareArrow(int flag, String symbol) { + this.flag = flag; + this.symbol = symbol; + } + + private static CompareArrow of(Integer flag) { + if (flag == null) { + return null; + } + for (CompareArrow arrow : values()) { + if (arrow.flag == flag) { + return arrow; + } + } + return null; + } + + private Font pickFont(Font red, Font green, Font blue) { + switch (this) { + case UP: + return red; + case DOWN: + return green; + case FLAT: + return blue; + default: + return red; + } + } + } +} + 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 eada1c6f5..9408141b1 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 @@ -162,24 +162,25 @@ public class EmisCustomerUserServiceImpl extends EmisBaseService implements IEmi */ @Override public List selectMonthlyCustomerShipmentStat(EmisWaybill emisWaybill) throws EmisBizError { - if("1".equals(emisWaybill.getParams().get("statType"))){ + List result; + if ("1".equals(emisWaybill.getParams().get("statType"))) { // 按运输方式统计 - return emisWaybillMapper.selectMonthlyCustomerShipmentStat(emisWaybill); - } - if("2".equals(emisWaybill.getParams().get("statType"))){ + result = emisWaybillMapper.selectMonthlyCustomerShipmentStat(emisWaybill); + } else if ("2".equals(emisWaybill.getParams().get("statType"))) { // 按目的国家统计 - return emisWaybillMapper.selectMonthlyCustomerShipmentStatByCountry(emisWaybill); - } - if("3".equals(emisWaybill.getParams().get("statType"))){ + result = emisWaybillMapper.selectMonthlyCustomerShipmentStatByCountry(emisWaybill); + } else if ("3".equals(emisWaybill.getParams().get("statType"))) { // 按运输方式统计,增加与上一个时间段的票数、重量对比标记 - return buildShipmentStatWithCompare(emisWaybill, true); - } - if("4".equals(emisWaybill.getParams().get("statType"))){ + result = buildShipmentStatWithCompare(emisWaybill, true); + } else if ("4".equals(emisWaybill.getParams().get("statType"))) { // 按目的国家统计,增加与上一个时间段的票数、重量对比标记 - return buildShipmentStatWithCompare(emisWaybill, false); + result = buildShipmentStatWithCompare(emisWaybill, false); + } else { + result = Collections.emptyList(); } - return Collections.emptyList(); + sortShipmentStat(result); + return result; } /** @@ -341,6 +342,33 @@ public class EmisCustomerUserServiceImpl extends EmisBaseService implements IEmi return 0; } + /** + * 统一排序规则:总重量 desc、总票数 desc、客户名称 asc + * + */ + private void sortShipmentStat(List list) { + if (list == null || list.isEmpty()) { + return; + } + final java.text.Collator collator = java.text.Collator.getInstance(Locale.CHINA); + + list.sort(Comparator + .comparing((MonthlyCustomerShipmentStatVO vo) -> nvl(vo.getTotalWeight()), Comparator.reverseOrder()) + .thenComparing(vo -> nvl(vo.getTotalTickets()), Comparator.reverseOrder()) + .thenComparing( + vo -> Optional.ofNullable(vo.getCustomerName()).orElse(""), + collator + )); + } + + private java.math.BigDecimal nvl(java.math.BigDecimal v) { + return v == null ? java.math.BigDecimal.ZERO : v; + } + + private Integer nvl(Integer v) { + return v == null ? 0 : v; + } + /** * 查询月结客户出货明细 * diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSalesCommissionRatioServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSalesCommissionRatioServiceImpl.java index ce73dc52c..4ab9771df 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSalesCommissionRatioServiceImpl.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSalesCommissionRatioServiceImpl.java @@ -23,7 +23,7 @@ public class EmisSalesCommissionRatioServiceImpl implements IEmisSalesCommission /** * 根据主键ID查询销售计提比例配置 - * + * * @param id 主键ID * @return 配置实体 */ @@ -34,7 +34,7 @@ public class EmisSalesCommissionRatioServiceImpl implements IEmisSalesCommission /** * 查询销售计提比例配置列表 - * + * * @param query 查询条件 * @return 配置列表 */ @@ -45,7 +45,7 @@ public class EmisSalesCommissionRatioServiceImpl implements IEmisSalesCommission /** * 新增销售计提比例配置 - * + * * @param entity 配置实体 * @return 影响行数 * @throws IllegalArgumentException 占比校验不通过时抛出 @@ -67,7 +67,7 @@ public class EmisSalesCommissionRatioServiceImpl implements IEmisSalesCommission /** * 修改销售计提比例配置 - * + * * @param entity 配置实体 * @return 影响行数 * @throws IllegalArgumentException 占比校验不通过时抛出 @@ -89,7 +89,7 @@ public class EmisSalesCommissionRatioServiceImpl implements IEmisSalesCommission /** * 批量删除销售计提比例配置 - * + * * @param ids 主键ID数组 * @return 影响行数 */ @@ -100,7 +100,7 @@ public class EmisSalesCommissionRatioServiceImpl implements IEmisSalesCommission /** * 删除单个销售计提比例配置 - * + * * @param id 主键ID * @return 影响行数 */ @@ -111,7 +111,7 @@ public class EmisSalesCommissionRatioServiceImpl implements IEmisSalesCommission /** * 校验销售计提比例总和是否有效(<=100%) - * + * * @param entity 配置实体 * @return true-有效,false-无效 */ @@ -133,7 +133,7 @@ public class EmisSalesCommissionRatioServiceImpl implements IEmisSalesCommission /** * 验证一个销售联系人只能对应一个销售主管 - * + * * @param entity 配置实体 * @throws EmisBizError 如果销售联系人已经对应了其他销售主管 */ @@ -142,7 +142,7 @@ public class EmisSalesCommissionRatioServiceImpl implements IEmisSalesCommission && entity.getSalesExecutive() != null && !entity.getSalesExecutive().trim().isEmpty()) { int count = emisSalesCommissionRatioMapper.countBySalesmenAndDifferentExecutive(entity); if (count > 0) { - throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, + throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "销售联系人[" + entity.getSalesmen() + "]已经对应了其他销售主管,一个销售联系人只能对应一个销售主管"); } } @@ -150,24 +150,24 @@ public class EmisSalesCommissionRatioServiceImpl implements IEmisSalesCommission /** * 验证一个销售支持只能对应一个销售联系人、只能对应一个销售主管 - * + * * @param entity 配置实体 * @throws EmisBizError 如果销售支持已经对应了其他销售联系人或销售主管 */ private void validateSalesSupport(EmisSalesCommissionRatio entity) throws EmisBizError { if (entity.getSalesSupport() != null && !entity.getSalesSupport().trim().isEmpty()) { - // 检查销售支持是否已经对应了其他销售联系人 - int countSalesmen = emisSalesCommissionRatioMapper.countBySalesSupportAndDifferentSalesmen(entity); - if (countSalesmen > 0) { - throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, - "销售支持[" + entity.getSalesSupport() + "]已经对应了其他销售联系人,一个销售支持只能对应一个销售联系人"); - } +// // 检查销售支持是否已经对应了其他销售联系人 +// int countSalesmen = emisSalesCommissionRatioMapper.countBySalesSupportAndDifferentSalesmen(entity); +// if (countSalesmen > 0) { +// throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, +// "销售支持[" + entity.getSalesSupport() + "]已经对应了其他销售联系人,一个销售支持只能对应一个销售联系人"); +// } // 检查销售支持是否已经对应了其他销售主管 int countExecutive = emisSalesCommissionRatioMapper.countBySalesSupportAndDifferentExecutive(entity); if (countExecutive > 0) { - throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, + throw new EmisBizError(EmisBizErrorType.PARAM_ERROR, "销售支持[" + entity.getSalesSupport() + "]已经对应了其他销售主管,一个销售支持只能对应一个销售主管"); } } } -} \ No newline at end of file +} diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisTmsSiteBatchMissServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisTmsSiteBatchMissServiceImpl.java index 59e4fe731..398ba4602 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisTmsSiteBatchMissServiceImpl.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisTmsSiteBatchMissServiceImpl.java @@ -902,12 +902,10 @@ public class EmisTmsSiteBatchMissServiceImpl extends EmisBaseService implements // 创建漏组记录 EmisTmsSiteBatchMiss miss = createMissRecord(waybill); - miss.setMissReason(waybill.getStartSiteName() +" 尚未完成组批次,请尽快完成,避免影响下一程同事组批次进度" ); + miss.setMissReason("当前运单没有组批次"); + miss.setMissType("2"); miss.setLineCode(waybill.getTransLineType()); miss.setProductType(waybill.getProductType()); - miss.setStartSiteCode(waybill.getStartSiteCode()); - miss.setNextSiteCode(""); - miss.setMissType("0"); missRecords.add(miss); successCount++; diff --git a/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml b/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml index c5eb0eee8..46a2d875e 100644 --- a/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml +++ b/emis-biz/src/main/resources/mapper/EmisWaybillMapper.xml @@ -4114,8 +4114,8 @@ ) - GROUP BY cu.monthly_pay_code - ORDER BY totalWeight desc,totalTickets desc + GROUP BY cu.monthly_pay_code, cu.customer_name + ORDER BY totalWeight DESC, totalTickets DESC, customerName ASC