From fea34d1d10535e6d470cf88faecf25226e035ac0 Mon Sep 17 00:00:00 2001 From: caojia <1301869380@qq.com> Date: Thu, 8 Oct 2026 16:51:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=B4=A6=E5=8D=95=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ar/service/impl/ArBillServiceImpl.java | 111 +++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java index 889ce3bd..dabbb42d 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java @@ -102,6 +102,15 @@ public class ArBillServiceImpl implements IArBillService { private static final int TEMPLATE_DATA_START_ROW = 5; private static final int TEMPLATE_FOOTER_START_ROW = 5; private static final int TEMPLATE_COLUMN_COUNT = 20; + /** 客户订单号、运单号位于 Excel 的 C、D 列,按给定样例长度并额外保留两字符边距。 */ + private static final int CUSTOMER_ORDER_NO_COLUMN_INDEX = 3; + private static final int TRACKING_NO_COLUMN_INDEX = 4; + private static final int FORMULA_COLUMN_INDEX = 16; + private static final int FEE_TYPE_COLUMN_INDEX = 17; + private static final double MIN_CUSTOMER_ORDER_NO_COLUMN_WIDTH = 20.0; + private static final double MIN_TRACKING_NO_COLUMN_WIDTH = 35.0; + private static final double MIN_FORMULA_COLUMN_WIDTH = 25.0; + private static final double MIN_FEE_TYPE_COLUMN_WIDTH = 25.0; /** * 单次查询订单数;费用仅查询当前订单批次,避免大账单占满堆内存。 */ @@ -122,6 +131,10 @@ public class ArBillServiceImpl implements IArBillService { */ private static final int TEMPLATE_DETAIL_STYLE_INDEX = 31; private static final String TEMPLATE_SHEET_XML = "xl/worksheets/sheet1.xml"; + private static final Pattern TEMPLATE_COLUMN_PATTERN = Pattern.compile("]*)/\\s*>", Pattern.DOTALL); + private static final Pattern TEMPLATE_COLUMN_MIN_PATTERN = Pattern.compile("\\bmin\\s*=\\s*[\"'](\\d+)[\"']"); + private static final Pattern TEMPLATE_COLUMN_MAX_PATTERN = Pattern.compile("\\bmax\\s*=\\s*[\"'](\\d+)[\"']"); + private static final Pattern TEMPLATE_COLUMN_WIDTH_PATTERN = Pattern.compile("\\bwidth\\s*=\\s*[\"']([\\d.]+)[\"']"); private static final Pattern TEMPLATE_ROW_PATTERN = Pattern.compile( "]*\\br=\"(\\d+)\"[^>]*>.*?", Pattern.DOTALL); private static final Pattern CELL_PATTERN = Pattern.compile( @@ -1286,7 +1299,8 @@ public class ArBillServiceImpl implements IArBillService { } Map templateRows = extractTemplateRows(templateXml.substring(sheetDataOpenEnd + 1, sheetDataEnd)); - String prefix = removeSheetDimension(templateXml.substring(0, sheetDataOpenEnd + 1)); + String prefix = adjustExportColumnWidths( + removeSheetDimension(templateXml.substring(0, sheetDataOpenEnd + 1))); writeUtf8(output, prefix); String headerRow = replaceCellXml(templateRows.get(1), "A1", @@ -1319,6 +1333,101 @@ public class ArBillServiceImpl implements IArBillService { writeUtf8(output, suffix); } + /** + * 仅加宽客户订单号、运单号、计算公式和费用类型列;不缩小模板原有列宽。 + */ + private String adjustExportColumnWidths(String sheetPrefix) throws IOException { + Matcher columnMatcher = TEMPLATE_COLUMN_PATTERN.matcher(sheetPrefix); + StringBuffer result = new StringBuffer(); + int[] targetColumns = { + CUSTOMER_ORDER_NO_COLUMN_INDEX, + TRACKING_NO_COLUMN_INDEX, + FORMULA_COLUMN_INDEX, + FEE_TYPE_COLUMN_INDEX + }; + double[] minimumWidths = { + MIN_CUSTOMER_ORDER_NO_COLUMN_WIDTH, + MIN_TRACKING_NO_COLUMN_WIDTH, + MIN_FORMULA_COLUMN_WIDTH, + MIN_FEE_TYPE_COLUMN_WIDTH + }; + boolean[] targetColumnsFound = new boolean[targetColumns.length]; + + while (columnMatcher.find()) { + String attributes = columnMatcher.group(1); + Matcher minMatcher = TEMPLATE_COLUMN_MIN_PATTERN.matcher(attributes); + Matcher maxMatcher = TEMPLATE_COLUMN_MAX_PATTERN.matcher(attributes); + Matcher widthMatcher = TEMPLATE_COLUMN_WIDTH_PATTERN.matcher(attributes); + if (!minMatcher.find() || !maxMatcher.find() || !widthMatcher.find()) { + columnMatcher.appendReplacement(result, Matcher.quoteReplacement(columnMatcher.group())); + continue; + } + + int min = Integer.parseInt(minMatcher.group(1)); + int max = Integer.parseInt(maxMatcher.group(1)); + double currentWidth = Double.parseDouble(widthMatcher.group(1)); + boolean needsExpansion = false; + for (int index = 0; index < targetColumns.length; index++) { + if (min <= targetColumns[index] && max >= targetColumns[index]) { + targetColumnsFound[index] = true; + needsExpansion |= currentWidth < minimumWidths[index]; + } + } + if (!needsExpansion) { + columnMatcher.appendReplacement(result, Matcher.quoteReplacement(columnMatcher.group())); + continue; + } + + StringBuilder replacement = new StringBuilder(); + int segmentStart = min; + for (int index = 0; index < targetColumns.length; index++) { + int column = targetColumns[index]; + if (column < min || column > max || currentWidth >= minimumWidths[index]) { + continue; + } + if (segmentStart < column) { + appendColumnSegment(replacement, attributes, segmentStart, column - 1, currentWidth, false); + } + appendColumnSegment(replacement, attributes, column, column, minimumWidths[index], true); + segmentStart = column + 1; + } + if (segmentStart <= max) { + appendColumnSegment(replacement, attributes, segmentStart, max, currentWidth, false); + } + columnMatcher.appendReplacement(result, Matcher.quoteReplacement(replacement.toString())); + } + columnMatcher.appendTail(result); + + for (boolean found : targetColumnsFound) { + if (!found) { + throw new IOException("应收账单导出模板缺少客户订单号、运单号、计算公式或费用类型列宽定义"); + } + } + return result.toString(); + } + + private void appendColumnSegment(StringBuilder xml, String attributes, int min, int max, double width, + boolean customWidth) { + String segmentAttributes = replaceColumnAttribute(attributes, "min", String.valueOf(min)); + segmentAttributes = replaceColumnAttribute(segmentAttributes, "max", String.valueOf(max)); + segmentAttributes = replaceColumnAttribute(segmentAttributes, "width", String.valueOf(width)); + if (customWidth) { + segmentAttributes = replaceColumnAttribute(segmentAttributes, "customWidth", "1"); + } + xml.append(""); + } + + private String replaceColumnAttribute(String attributes, String name, String value) { + Pattern attributePattern = Pattern.compile("(\\b" + name + "\\s*=\\s*[\"'])([^\"']*)([\"'])", + Pattern.CASE_INSENSITIVE); + Matcher matcher = attributePattern.matcher(attributes); + if (matcher.find()) { + String replacement = matcher.group(1) + value + matcher.group(3); + return matcher.replaceFirst(Matcher.quoteReplacement(replacement)); + } + return attributes + " " + name + "=\"" + value + "\""; + } + private Map extractTemplateRows(String sheetData) { Map rows = new HashMap<>(); Matcher matcher = TEMPLATE_ROW_PATTERN.matcher(sheetData);