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);