Browse Source

alpha

master
han\hanst 2 months ago
parent
commit
3853951705
  1. 750
      src/main/java/com/xujie/sys/common/utils/ExcelTemplateALPHA.java
  2. 28
      src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelTXServiceImpl.java
  3. BIN
      src/main/resources/templates/ALPHA/declaration-all-template-pdf.xlsx
  4. BIN
      src/main/resources/templates/ALPHA/declaration-all-template.xlsx
  5. BIN
      src/main/resources/templates/ALPHA/declaration-contract-template.xlsx
  6. BIN
      src/main/resources/templates/ALPHA/declaration-elements-template.xlsx
  7. BIN
      src/main/resources/templates/ALPHA/declaration-invoice2-template.xlsx
  8. BIN
      src/main/resources/templates/ALPHA/declaration-packingList-template.xlsx
  9. BIN
      src/main/resources/templates/ALPHA/declaration-template.xlsx
  10. BIN
      src/main/resources/templates/ALPHA/export-goods-template.xlsx

750
src/main/java/com/xujie/sys/common/utils/ExcelTemplateALPHA.java

@ -0,0 +1,750 @@
package com.xujie.sys.common.utils;
import lombok.Setter;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ExcelTemplateALPHA {
final private static Pattern PATTERN_HDR_FIELD = Pattern.compile("\\$\\{(.*?)}", Pattern.MULTILINE);
final private static Pattern PATTERN_DTL_FIELD = Pattern.compile("#\\{(.*?)}", Pattern.MULTILINE);
private XSSFWorkbook workbook;
private Map<String, Object> variables = new HashMap<>();
private List<Map<String, Object>> listVariables = new ArrayList<>();
// 存储需要合并的单元格区域信息[列表起始索引, 列表结束索引, 列索引]
private List<int[]> mergeRegions = new ArrayList<>();
// 存储需要设置行高的行信息[起始行索引, 结束行索引, 行高]
private List<int[]> rowHeights = new ArrayList<>();
// 是否下移形状格式
@Setter
private boolean moveShape = false;
// 是否下移印章印章是图片
@Setter
private boolean moveSeal = false;
// 是否设置单元格样式
@Setter
private boolean cellStyle = false;
// 是否设置单元格样式 针对RFID不需要序号定制
@Setter
private boolean cellStyle2 = false;
// 是否设置合并单元格样式
@Setter
private boolean rangeStyle = false;
// 价格靠右 发票
@Setter
private boolean priceRight = false;
// 价格靠右 发票
@Setter
private boolean invoiceLie = false;
// 数字靠右 箱单
@Setter
private boolean intRight = false;
// 报关单
@Setter
private boolean delRight = false;
// 箱单
@Setter
private boolean boxFlag = false;
private ExcelTemplateALPHA(){}
public static ExcelTemplateALPHA load(InputStream template) throws IOException {
ExcelTemplateALPHA excelTemplate = new ExcelTemplateALPHA();
excelTemplate.workbook = new XSSFWorkbook(template);
return excelTemplate;
}
public void addVar(String key, Object value){
variables.put(key, value);
}
public void addVarAll(Map values){
variables.putAll(values);
}
public void addListVar(Map<String, Object> row){
listVariables.add(row);
}
public void addListVarAll(Collection rows){
listVariables.addAll(rows);
}
/**
* 添加需要合并的单元格区域基于列表索引
* @param startListIndex 列表起始索引相对于listVariables
* @param endListIndex 列表结束索引相对于listVariables
* @param colIndex 列索引
*/
public void addMergeRegion(int startListIndex, int endListIndex, int colIndex) {
if (startListIndex <= endListIndex) {
mergeRegions.add(new int[]{startListIndex, endListIndex, colIndex, colIndex, 0}); // 格式[startRow, endRow, startCol, endCol, alignType]
}
}
/**
* 添加合并区域并指定对齐方式
* @param startListIndex 起始行索引
* @param endListIndex 结束行索引
* @param colIndex 列索引
* @param alignType 对齐方式0=右对齐1=左对齐2=居中
*/
public void addMergeRegion(int startListIndex, int endListIndex, int colIndex, int alignType) {
if (startListIndex <= endListIndex) {
mergeRegions.add(new int[]{startListIndex, endListIndex, colIndex, colIndex, alignType});
}
}
/**
* 添加跨列的合并区域支持横向和纵向同时合并
* @param startListIndex 起始行索引
* @param endListIndex 结束行索引
* @param startColIndex 起始列索引
* @param endColIndex 结束列索引
* @param alignType 对齐方式0=右对齐1=左对齐2=居中
*/
public void addMergeRegion(int startListIndex, int endListIndex, int startColIndex, int endColIndex, int alignType) {
if (startListIndex <= endListIndex && startColIndex <= endColIndex) {
mergeRegions.add(new int[]{startListIndex, endListIndex, startColIndex, endColIndex, alignType});
}
}
/**
* 设置行高
* @param startListIndex 起始行索引相对于listVariables
* @param endListIndex 结束行索引相对于listVariables
* @param height 行高单位
*/
public void setRowHeight(int startListIndex, int endListIndex, int height) {
if (startListIndex <= endListIndex) {
rowHeights.add(new int[]{startListIndex, endListIndex, height});
}
}
public void clearAll(){
variables.clear();
listVariables.clear();
mergeRegions.clear();
rowHeights.clear();
moveShape = false;
moveSeal = false;
cellStyle = false;
cellStyle2 = false;
rangeStyle = false;
priceRight = false;
intRight = false;
delRight = false;
}
private boolean findAndRemoveMergedRegion(XSSFSheet sheet, int rowIndex) {
for (int mi = 0; mi < sheet.getMergedRegions().size(); mi++) {
if (sheet.getMergedRegions().get(mi).getFirstRow() == rowIndex) {
sheet.removeMergedRegion(mi);
return true;
}
}
return false;
}
public XSSFWorkbook render(int index) throws IOException {
XSSFSheet sheet = workbook.getSheetAt(index);
CellCopyPolicy copyPolicy = new CellCopyPolicy();
int dtlRowIndex = -1;
// find detail rows
for (int i = 0; i < sheet.getLastRowNum(); i++) {
XSSFRow row = sheet.getRow(i);
if (row == null) {
continue;
}
for (int j = 0; j < row.getLastCellNum(); j++) {
XSSFCell c = sheet.getRow(i).getCell(j);
if (c == null) {
continue;
}
String cellValue = c.toString();
Matcher matcherDtl = PATTERN_DTL_FIELD.matcher(cellValue);
if (matcherDtl.find()) {
dtlRowIndex = i;
break;
}
}
if (dtlRowIndex >= 0) {
break;
}
}
if (dtlRowIndex < sheet.getLastRowNum() && listVariables.size() > 1) {
//循环列表以下区域整体下移
int _rows = sheet.getLastRowNum();
for(int i = _rows; i > dtlRowIndex; i--){
sheet.copyRows(i, i, i + listVariables.size() -1 , copyPolicy);
}
for(int i = 0; i < listVariables.size() - 1; i++) {
int destRowIndex = dtlRowIndex + 1 + i;
sheet.createRow(destRowIndex); //clear destination row
while(findAndRemoveMergedRegion(sheet, destRowIndex)){
continue;
}
sheet.copyRows(dtlRowIndex, dtlRowIndex, destRowIndex, copyPolicy);
}
}
// 遍历所有形状 将列表下方的形状坐标也下移
if (moveShape) {
int listStartRow = 24; // Excel 第25行0-based
int moveOffset = listVariables.size() - 1;
for (POIXMLDocumentPart part : sheet.getRelations()) {
if (!(part instanceof XSSFDrawing)) {
continue;
}
XSSFDrawing drawing = (XSSFDrawing) part;
for (XSSFShape shape : drawing.getShapes()) {
if (!(shape instanceof XSSFSimpleShape)) {
continue;
}
XSSFSimpleShape simpleShape = (XSSFSimpleShape) shape;
ClientAnchor anchor = (ClientAnchor) simpleShape.getAnchor();
if (anchor != null && anchor.getRow1() >= listStartRow) {
anchor.setRow1(anchor.getRow1() + moveOffset);
if (anchor instanceof XSSFClientAnchor) {
XSSFClientAnchor xAnchor = (XSSFClientAnchor) anchor;
try {
xAnchor.setRow2(xAnchor.getRow2() + moveOffset);
} catch (Exception ignore) {
// row2 不存在忽略
}
}
}
}
}
}
// 遍历所有图片 将列表下方的形状坐标也下移
if (moveSeal) {
List<POIXMLDocumentPart> relations = sheet.getRelations();
for (POIXMLDocumentPart part : relations) {
if (part instanceof XSSFDrawing) {
XSSFDrawing drawing = (XSSFDrawing) part;
List<XSSFShape> shapes = drawing.getShapes();
for (XSSFShape shape : shapes) {
// 只处理图片类型的形状
if (shape instanceof XSSFPicture) {
XSSFPicture picture = (XSSFPicture) shape;
// 调整行坐标实现下移
ClientAnchor anchor = (ClientAnchor) picture.getAnchor();
if (anchor.getRow1() > 10) { // 只下移位于10行之后的图片
anchor.setRow1(anchor.getRow1() + listVariables.size() - 1);
anchor.setRow2(anchor.getRow2() + listVariables.size() - 1);
}
}
}
}
}
}
Set<Integer> dtlRows = new LinkedHashSet<>();
List<Integer> boxRows = new ArrayList<>();
Set<Integer> poNoCols = new HashSet<>();
//整体填值
for (int i = 0; i <= sheet.getLastRowNum(); i++) {
XSSFRow row = sheet.getRow(i);
if (row == null) {
continue;
}
for (int j = 0; j < row.getLastCellNum(); j++) {
XSSFCell c = sheet.getRow(i).getCell(j);
if (c == null) {
continue;
}
String cellValue = c.toString();
if ("#{pn}".equals(cellValue) || "#{levy}".equals(cellValue) || "#{artNo}".equals(cellValue)) {
dtlRows.add(i);
}
if ("#{cmcInvoice}".equals(cellValue)) {
boxRows.add(i);
}
// 仅记录明细模板行上的po_no列避免同名占位符误伤其它数字列
if (i == dtlRowIndex && "#{po_no}".equalsIgnoreCase(cellValue)) {
poNoCols.add(j);
}
Matcher matcherHdr = PATTERN_HDR_FIELD.matcher(cellValue);
String result = c.getStringCellValue();
while (matcherHdr.find()) {
for (int ri = 1; ri <= matcherHdr.groupCount(); ri++) {
String field = matcherHdr.group(ri);
Object value = variables.getOrDefault(field, "");
result = result.replace(matcherHdr.group(0), String.valueOf(value));
}
if ("${phone1}".equals(cellValue) || "${phone2}".equals(cellValue) || "${hs_code}".equals(cellValue)) {
c.setCellValue(result); // 字符串
} else {
try {
// 更严格的数字检查
String cleanResult = result.replace(",", "").trim();
if (!cleanResult.isEmpty() && !cleanResult.equals("-") && !cleanResult.equals(".")) {
double num = Double.parseDouble(cleanResult);
if (Double.isFinite(num)) {
c.setCellValue(num); // 数值
// goods_total_qty 根据实际小数位动态设置格式
if ("${goods_total_qty}".equals(cellValue)) {
XSSFCellStyle fmtStyle = workbook.createCellStyle();
fmtStyle.cloneStyleFrom(c.getCellStyle());
DataFormat dataFormat = workbook.createDataFormat();
fmtStyle.setDataFormat(dataFormat.getFormat(buildDecimalFormat(num)));
c.setCellStyle(fmtStyle);
}
} else {
c.setCellValue(result); // 字符串
}
} else {
c.setCellValue(result); // 字符串
}
} catch (NumberFormatException e) {
c.setCellValue(result); // 字符串
}
}
}
Matcher matcherDtl = PATTERN_DTL_FIELD.matcher(cellValue);
while (matcherDtl.find()) {
for (int ri = 1; ri <= matcherDtl.groupCount(); ri++) {
String field = matcherDtl.group(ri);
// 检查数组边界避免越界异常
int listIndex = i - dtlRowIndex;
if (listIndex >= 0 && listIndex < listVariables.size()) {
c.setCellValue(cellValue.replace(matcherDtl.group(0), String.valueOf(listVariables.get(listIndex).getOrDefault(field, ""))));
}
}
}
// 设置样式
if (cellStyle && dtlRowIndex >= 0 && i >= dtlRowIndex && i < dtlRowIndex + listVariables.size()) {
XSSFCellStyle style = c.getCellStyle();
style.setBorderBottom(BorderStyle.NONE);
style.setBorderTop(BorderStyle.NONE);
style.setWrapText(true);
style.setAlignment(HorizontalAlignment.LEFT);
c.setCellStyle(style);
if (rangeStyle && j < 4) {
for (int mi = 0; mi < 3; mi++) {
XSSFCell nextc = sheet.getRow(i).getCell(c.getColumnIndex()+mi+1);
if (nextc == null) {
continue;
}
nextc.setCellStyle(style);
}
}
}
}
}
// 设置明细样式因为明细是动态添加的会有样式和模版偏差此处主要是第23列的样式需要设置
if (cellStyle) {
for (Integer dtlRow : dtlRows) {
XSSFCell c1 = sheet.getRow(dtlRow).getCell(cellStyle2?0:1);
if (c1 == null) {
continue;
}
XSSFCellStyle style = workbook.createCellStyle();
style.setBorderRight(BorderStyle.NONE);
style.setBorderLeft(BorderStyle.MEDIUM); // 实线
style.setBorderBottom(BorderStyle.NONE);
style.setBorderTop(BorderStyle.NONE);
Font font = workbook.createFont();
font.setFontName("Arial"); // 设置字体
font.setFontHeightInPoints((short) 10); // 设置字号
style.setFont(font);
style.setVerticalAlignment(VerticalAlignment.TOP);
style.setWrapText(true);
c1.setCellStyle(style);
XSSFCell c2 = sheet.getRow(dtlRow).getCell(cellStyle2?1:2);
if (c2 == null) {
continue;
}
XSSFCellStyle style2 = workbook.createCellStyle();
style2.setBorderRight(BorderStyle.MEDIUM);
style2.setBorderLeft(BorderStyle.NONE);
style2.setBorderBottom(BorderStyle.NONE);
style2.setBorderTop(BorderStyle.NONE);
Font font2 = workbook.createFont();
font2.setFontName("Arial"); // 设置字体
font2.setFontHeightInPoints((short) 10); // 设置字号
style2.setFont(font2);
style2.setVerticalAlignment(VerticalAlignment.TOP);
style2.setAlignment(HorizontalAlignment.LEFT);
style2.setWrapText(true);
c2.setCellStyle(style2);
if (priceRight) { //仅供发票excel使用第678是价格列居右
for (int i = 6; i < (invoiceLie?11:9); i++) {
XSSFRow row = sheet.getRow(dtlRow);
if (row == null) {
continue;
}
XSSFCell c7 = row.getCell(i);
if (c7 == null) {
continue;
}
// 尝试把字符串转成数值
if (c7.getCellType() == CellType.STRING) {
String strVal = c7.getStringCellValue();
if (strVal != null && !strVal.trim().isEmpty()) {
try {
double num = Double.parseDouble(strVal.replace(",", ""));
c7.setCellValue(num); // 转换为数值写回
} catch (NumberFormatException e) {
// 如果不是数字就保留原字符串
System.out.println("非数字,保持原值: " + strVal);
}
}
}
// 创建样式
XSSFCellStyle style7 = workbook.createCellStyle();
style7.setBorderRight(BorderStyle.MEDIUM);
style7.setBorderLeft(BorderStyle.NONE);
style7.setBorderBottom(BorderStyle.NONE);
style7.setBorderTop(BorderStyle.NONE);
Font font7 = workbook.createFont();
font7.setFontName("Arial");
font7.setFontHeightInPoints((short) 10);
style7.setFont(font7);
style7.setVerticalAlignment(VerticalAlignment.TOP);
style7.setAlignment(HorizontalAlignment.RIGHT);
// 设置千分位格式根据单元格实际小数位动态决定格式
DataFormat dataFormat = workbook.createDataFormat();
String numFmt;
if (c7.getCellType() == CellType.NUMERIC) {
numFmt = buildDecimalFormat(c7.getNumericCellValue());
} else {
numFmt = "#,##0.00";
}
style7.setDataFormat(dataFormat.getFormat(numFmt));
c7.setCellStyle(style7);
}
}
if (intRight) { //仅供箱单excel使用
// 覆盖到第10列索引9保证910列按数字处理
for (int i = 4; i < 11; i++) {
XSSFRow row = sheet.getRow(dtlRow);
if (row == null) {
continue;
}
XSSFCell c7 = row.getCell(i);
if (c7 == null) {
continue;
}
boolean isPoNoColumn = poNoCols.contains(i);
BigDecimal numericValue = null;
// 尝试把字符串转成数值
if (!isPoNoColumn && c7.getCellType() == CellType.STRING) {
String strVal = c7.getStringCellValue();
BigDecimal parsed = parseNumericString(strVal);
if (parsed != null) {
numericValue = parsed;
c7.setCellValue(parsed.doubleValue()); // 转换为数值写回
}
} else if (!isPoNoColumn && c7.getCellType() == CellType.NUMERIC) {
numericValue = BigDecimal.valueOf(c7.getNumericCellValue());
}
// 创建样式
XSSFCellStyle style7 = workbook.createCellStyle();
style7.setBorderRight(BorderStyle.MEDIUM);
style7.setBorderLeft(i==4?BorderStyle.MEDIUM:BorderStyle.NONE);
style7.setBorderBottom(BorderStyle.NONE);
style7.setBorderTop(BorderStyle.NONE);
// 判断单元格的值是否小于等于0如果小于等于0则加粗
boolean isBold = false;
if (numericValue != null && numericValue.compareTo(BigDecimal.ZERO) <= 0) {
isBold = true;
}
Font font7 = workbook.createFont();
font7.setFontName("Arial");
font7.setFontHeightInPoints((short) 10);
if (isBold) {
font7.setBold(true);
}
style7.setFont(font7);
style7.setVerticalAlignment(VerticalAlignment.TOP);
style7.setAlignment(HorizontalAlignment.CENTER);
DataFormat dataFormat = workbook.createDataFormat();
if (isPoNoColumn) {
// po_no 是编号列必须按文本处理不能套用千分位
style7.setDataFormat(dataFormat.getFormat("@"));
} else {
// 设置千分位格式根据单元格实际小数位动态决定格式
String numFmt2;
if (numericValue != null) {
// 去掉末尾0后按实际小数位显示20.000000 -> 200.150000 -> 0.15
numFmt2 = buildDecimalFormatByDecimal(numericValue);
} else if (c7.getCellType() == CellType.NUMERIC) {
numFmt2 = buildDecimalFormat(c7.getNumericCellValue());
} else {
numFmt2 = "#,##0";
}
style7.setDataFormat(dataFormat.getFormat(numFmt2));
}
c7.setCellStyle(style7);
}
// net_weight列J列索引9保持顶部右对齐
/*XSSFRow row = sheet.getRow(dtlRow);
if (row != null) {
XSSFCell netWeightCell = row.getCell(9);
if (netWeightCell != null) {
XSSFCellStyle netWeightStyle = workbook.createCellStyle();
netWeightStyle.cloneStyleFrom(netWeightCell.getCellStyle());
netWeightStyle.setVerticalAlignment(VerticalAlignment.TOP);
netWeightStyle.setAlignment(HorizontalAlignment.RIGHT);
netWeightCell.setCellStyle(netWeightStyle);
}
}*/
}
}
}
if (delRight) {
for (Integer dtlRow : dtlRows) {
for (int i = 0; i < 17; i++) {
XSSFRow row = sheet.getRow(dtlRow);
if (row == null) {
continue;
}
XSSFCell c7 = row.getCell(i);
if (c7 == null) {
continue;
}
// 创建样式
XSSFCellStyle style = workbook.createCellStyle();
style.setBorderRight(i==16?BorderStyle.THIN:BorderStyle.NONE);
style.setBorderLeft(i==0?BorderStyle.THIN:BorderStyle.NONE);
style.setBorderBottom(BorderStyle.THIN);
style.setBorderTop(BorderStyle.NONE);
Font font = workbook.createFont();
font.setFontName("Arial");
font.setFontHeightInPoints((short) 10);
style.setFont(font);
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setAlignment(HorizontalAlignment.LEFT);
c7.setCellStyle(style);
if (i==6 || i==11) {
// 尝试把字符串转成数值
if (c7.getCellType() == CellType.STRING) {
String strVal = c7.getStringCellValue();
if (strVal != null && !strVal.trim().isEmpty()) {
try {
double num = Double.parseDouble(strVal.replace(",", ""));
c7.setCellValue(num); // 转换为数值写回
} catch (NumberFormatException e) {
// 如果不是数字就保留原字符串
System.out.println("非数字,保持原值: " + strVal);
}
}
}
// 创建样式
XSSFCellStyle style7 = workbook.createCellStyle();
style7.setBorderRight(BorderStyle.NONE);
style7.setBorderLeft(BorderStyle.NONE);
style7.setBorderBottom(BorderStyle.THIN);
style7.setBorderTop(BorderStyle.NONE);
Font font7 = workbook.createFont();
font7.setFontName("Arial");
font7.setFontHeightInPoints((short) 10);
style7.setFont(font7);
style7.setVerticalAlignment(VerticalAlignment.CENTER);
style7.setAlignment(HorizontalAlignment.RIGHT);
// 设置千分位格式根据单元格实际小数位动态决定格式
DataFormat dataFormat = workbook.createDataFormat();
String numFmt3 = (c7.getCellType() == CellType.NUMERIC)
? buildDecimalFormat(c7.getNumericCellValue())
: "#,##0.00";
style7.setDataFormat(dataFormat.getFormat(numFmt3));
c7.setCellStyle(style7);
}
}
}
}
if (boxFlag) {
for (Integer dtlRow : boxRows) {
for (int i = 1; i < 6; i++) {
if (i==1 || i==4 || i==5) {
XSSFRow row = sheet.getRow(dtlRow);
if (row == null) {
continue;
}
XSSFCell c7 = row.getCell(i);
if (c7 == null) {
continue;
}
// 尝试把字符串转成数值
if (c7.getCellType() == CellType.STRING) {
String strVal = c7.getStringCellValue();
if (strVal != null && !strVal.trim().isEmpty()) {
try {
double num = Double.parseDouble(strVal.replace(",", ""));
c7.setCellValue(num); // 转换为数值写回
} catch (NumberFormatException e) {
// 如果不是数字就保留原字符串
System.out.println("非数字,保持原值: " + strVal);
}
}
}
// 创建样式
XSSFCellStyle style7 = workbook.createCellStyle();
style7.setBorderRight(BorderStyle.THIN);
style7.setBorderLeft(BorderStyle.THIN);
style7.setBorderBottom(BorderStyle.THIN);
style7.setBorderTop(BorderStyle.THIN);
Font font7 = workbook.createFont();
font7.setFontName("DengXian"); // 等线
font7.setFontHeightInPoints((short) 11); // 11号
style7.setFont(font7);
style7.setVerticalAlignment(VerticalAlignment.CENTER);
style7.setAlignment(HorizontalAlignment.RIGHT);
// 设置千分位格式根据单元格实际小数位动态决定格式
DataFormat dataFormat = workbook.createDataFormat();
String numFmt4 = (c7.getCellType() == CellType.NUMERIC)
? buildDecimalFormat(c7.getNumericCellValue())
: "#,##0";
style7.setDataFormat(dataFormat.getFormat(numFmt4));
c7.setCellStyle(style7);
}
}
}
}
// 处理合并单元格 - 将列表索引转换为实际行号并合并
if (dtlRowIndex >= 0 && !mergeRegions.isEmpty()) {
for (int[] region : mergeRegions) {
int startRow = dtlRowIndex + region[0];
int endRow = dtlRowIndex + region[1];
int startCol = region[2];
int endCol = region.length >= 4 ? region[3] : region[2]; // 支持跨列如果没有指定endCol则等于startCol
boolean needMerge = startRow < endRow || startCol < endCol;
if (needMerge) {
// 创建新的合并区域支持横向和纵向合并
CellRangeAddress mergeRange = new CellRangeAddress(startRow, endRow, startCol, endCol);
// 检查并删除与新合并区域冲突的已存在合并区域
List<Integer> toRemove = new ArrayList<>();
for (int i = 0; i < sheet.getNumMergedRegions(); i++) {
CellRangeAddress existingRegion = sheet.getMergedRegion(i);
if (existingRegion != null && mergeRange.intersects(existingRegion)) {
toRemove.add(i);
}
}
// 从后往前删除避免索引变化
for (int i = toRemove.size() - 1; i >= 0; i--) {
sheet.removeMergedRegion(toRemove.get(i));
}
// 添加新的合并区域
sheet.addMergedRegion(mergeRange);
}
// 根据是否实际合并设置对齐方式
// 1) 已合并垂直居中 + 水平居中
// 2) 未合并单格垂直顶对齐 + 水平居中
XSSFRow row = sheet.getRow(startRow);
if (row != null) {
XSSFCell cell = row.getCell(startCol);
if (cell != null) {
XSSFCellStyle mergeStyle = workbook.createCellStyle();
mergeStyle.cloneStyleFrom(cell.getCellStyle());
mergeStyle.setVerticalAlignment(needMerge ? VerticalAlignment.CENTER : VerticalAlignment.TOP);
mergeStyle.setAlignment(HorizontalAlignment.CENTER);
cell.setCellStyle(mergeStyle);
}
}
}
}
// 处理行高设置
if (dtlRowIndex >= 0 && !rowHeights.isEmpty()) {
for (int[] heightInfo : rowHeights) {
int startRow = dtlRowIndex + heightInfo[0];
int endRow = dtlRowIndex + heightInfo[1];
int height = heightInfo[2];
for (int rowIdx = startRow; rowIdx <= endRow; rowIdx++) {
XSSFRow row = sheet.getRow(rowIdx);
if (row != null) {
// 设置行高Excel行高单位是1/20点所以需要乘以20
row.setHeight((short) (height * 20));
}
}
}
}
return workbook;
}
private BigDecimal parseNumericString(String value) {
if (value == null) {
return null;
}
String clean = value.replace(",", "").trim();
if (clean.isEmpty() || "-".equals(clean) || ".".equals(clean)) {
return null;
}
try {
return new BigDecimal(clean);
} catch (NumberFormatException e) {
return null;
}
}
private String buildDecimalFormatByDecimal(BigDecimal value) {
if (value == null) {
return "#,##0";
}
int scale = Math.max(0, value.stripTrailingZeros().scale());
if (scale <= 0) {
return "#,##0";
}
return "#,##0." + "0".repeat(scale);
}
/**
* 根据数值的实际小数位数动态生成 Excel 数字格式串带千分位
* 1.0 "#,##0"12.34 "#,##0.00"0.00123 "#,##0.00000"
* 使用 Double.toString() BigDecimal 再去尾零避免浮点误差导致位数虚高
*/
private String buildDecimalFormat(double value) {
if (value == 0) {
return "#,##0";
}
BigDecimal bd = new BigDecimal(Double.toString(Math.abs(value))).stripTrailingZeros();
int scale = Math.max(0, bd.scale());
if (scale == 0) {
return "#,##0";
}
return "#,##0." + "0".repeat(scale);
}
}

28
src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelTXServiceImpl.java

@ -6,7 +6,7 @@ import com.aspose.cells.PaperSizeType;
import com.aspose.cells.SaveFormat; import com.aspose.cells.SaveFormat;
import com.xujie.sys.common.utils.DateUtils; import com.xujie.sys.common.utils.DateUtils;
import com.xujie.sys.common.utils.ExcelTemplateTX; import com.xujie.sys.common.utils.ExcelTemplateTX;
import com.xujie.sys.common.utils.ExcelTemplateYB;
import com.xujie.sys.common.utils.ExcelTemplateALPHA;
import com.xujie.sys.modules.ecss.data.*; import com.xujie.sys.modules.ecss.data.*;
import com.xujie.sys.modules.ecss.dto.SheetErrorInfo; import com.xujie.sys.modules.ecss.dto.SheetErrorInfo;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
@ -233,7 +233,9 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
}); });
if (cmcInvoice != null) {
successList.add(cmcInvoice); successList.add(cmcInvoice);
}
} catch (Exception e) { } catch (Exception e) {
Throwable cause = e; Throwable cause = e;
while (cause.getCause() != null) { while (cause.getCause() != null) {
@ -977,9 +979,9 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService {
} }
private static class YbExcelTemplateAdapter implements ExcelTemplateAdapter { private static class YbExcelTemplateAdapter implements ExcelTemplateAdapter {
private final ExcelTemplateYB delegate;
private final ExcelTemplateALPHA delegate;
private YbExcelTemplateAdapter(ExcelTemplateYB delegate) {
private YbExcelTemplateAdapter(ExcelTemplateALPHA delegate) {
this.delegate = delegate; this.delegate = delegate;
} }
@ -1077,9 +1079,9 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService {
workbook.write(response.getOutputStream()); workbook.write(response.getOutputStream());
} }
} else { } else {
String xlsx = "templates/YB/declaration-packingList-template.xlsx";
ExcelTemplateYB template = ExcelTemplateYB.load(new ClassPathResource(xlsx).getInputStream());
exportPackingListYB(data, template, notifyHeader, 0);
String xlsx = "templates/ALPHA/declaration-packingList-template.xlsx";
ExcelTemplateALPHA template = ExcelTemplateALPHA.load(new ClassPathResource(xlsx).getInputStream());
exportPackingListAlpha(data, template, notifyHeader, 0);
try (XSSFWorkbook workbook = template.render(0)) { try (XSSFWorkbook workbook = template.render(0)) {
workbook.write(response.getOutputStream()); workbook.write(response.getOutputStream());
} }
@ -1238,7 +1240,7 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService {
extractedContract(data, templateAdapter); extractedContract(data, templateAdapter);
template.render(5); template.render(5);
} else { } else {
ExcelTemplateYB template = ExcelTemplateYB.load(new ClassPathResource("templates/YB/declaration-all-template.xlsx").getInputStream());
ExcelTemplateALPHA template = ExcelTemplateALPHA.load(new ClassPathResource("templates/ALPHA/declaration-all-template.xlsx").getInputStream());
ExcelTemplateAdapter templateAdapter = new YbExcelTemplateAdapter(template); ExcelTemplateAdapter templateAdapter = new YbExcelTemplateAdapter(template);
// 第一个sheet - 出口货物委托书 // 第一个sheet - 出口货物委托书
@ -1252,7 +1254,7 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService {
// 第三个sheet - 箱单 // 第三个sheet - 箱单
templateAdapter.clearAll(); templateAdapter.clearAll();
exportPackingListYB(data, template, notifyHeader, 0);
exportPackingListAlpha(data, template, notifyHeader, 0);
template.render(2); template.render(2);
// 第四个sheet - 报关单 // 第四个sheet - 报关单
@ -1328,8 +1330,8 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService {
extractedContract(data, templateAdapter); extractedContract(data, templateAdapter);
template.render(4); template.render(4);
} else { } else {
String xlsx = "templates/YB/declaration-all-template-pdf.xlsx";
ExcelTemplateYB template = ExcelTemplateYB.load(new ClassPathResource(xlsx).getInputStream());
String xlsx = "templates/ALPHA/declaration-all-template-pdf.xlsx";
ExcelTemplateALPHA template = ExcelTemplateALPHA.load(new ClassPathResource(xlsx).getInputStream());
ExcelTemplateAdapter templateAdapter = new YbExcelTemplateAdapter(template); ExcelTemplateAdapter templateAdapter = new YbExcelTemplateAdapter(template);
// 第一个sheet - 发票PDF导出时跳过出口货物委托书 // 第一个sheet - 发票PDF导出时跳过出口货物委托书
@ -1338,7 +1340,7 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService {
// 第二个sheet - 箱单 // 第二个sheet - 箱单
templateAdapter.clearAll(); templateAdapter.clearAll();
exportPackingListYB(data, template, notifyHeader, 0);
exportPackingListAlpha(data, template, notifyHeader, 0);
template.render(1); template.render(1);
// 第三个sheet - 报关单 // 第三个sheet - 报关单
@ -1994,14 +1996,14 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService {
} }
/** /**
* YB装箱单导出逻辑与TX基本一致区别在于YB的装箱单模板与TX不同部分字段需要特殊处理
* Alpha装箱单导出
* 第一列展示托号pallet_no * 第一列展示托号pallet_no
* @param data * @param data
* @param template * @param template
* @param notifyHeader * @param notifyHeader
* @param type * @param type
*/ */
private void exportPackingListYB(EcssDeclarationHeaderData data, ExcelTemplateYB template,
private void exportPackingListAlpha(EcssDeclarationHeaderData data, ExcelTemplateALPHA template,
EcssCoDelNotifyHeaderData notifyHeader,int type) { EcssCoDelNotifyHeaderData notifyHeader,int type) {
List<EcssCoDelNotifyDetailData> notifyDetailList; List<EcssCoDelNotifyDetailData> notifyDetailList;
if (type==0) { if (type==0) {

BIN
src/main/resources/templates/ALPHA/declaration-all-template-pdf.xlsx

BIN
src/main/resources/templates/ALPHA/declaration-all-template.xlsx

BIN
src/main/resources/templates/ALPHA/declaration-contract-template.xlsx

BIN
src/main/resources/templates/ALPHA/declaration-elements-template.xlsx

BIN
src/main/resources/templates/ALPHA/declaration-invoice2-template.xlsx

BIN
src/main/resources/templates/ALPHA/declaration-packingList-template.xlsx

BIN
src/main/resources/templates/ALPHA/declaration-template.xlsx

BIN
src/main/resources/templates/ALPHA/export-goods-template.xlsx

Loading…
Cancel
Save