From 6d7e011b4938debe18548d8c06bf71facb2e97ec Mon Sep 17 00:00:00 2001 From: dk <1260500659@qq.com> Date: Wed, 24 Jun 2026 17:50:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=88=91=E7=9A=84=E7=BB=A9=E6=95=88):=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A4=9A=E4=BB=BDexcel=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E4=B8=BA=E4=B8=80=E4=B8=AA=E5=A4=A7excel=E7=9A=84=E4=B8=8D?= =?UTF-8?q?=E5=90=8Csheet=E9=A1=B5=E3=80=82=20fix(=E6=88=91=E7=9A=84?= =?UTF-8?q?=E7=BB=A9=E6=95=88):=20=E4=BF=AE=E5=A4=8D=E9=9D=9E=E7=9B=B4?= =?UTF-8?q?=E5=B1=9E=E4=B8=8A=E7=BA=A7=E4=B9=9F=E8=83=BD=E5=AF=B9=E4=B8=8B?= =?UTF-8?q?=E5=B1=9E=E7=9A=84=E7=BB=A9=E6=95=88=E8=A1=A8=EF=BC=8C=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E7=BC=96=E8=BE=91/=E5=88=A0=E9=99=A4/=E5=8F=91?= =?UTF-8?q?=E9=80=81=E7=AD=89=E5=8A=A8=E4=BD=9C=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../performance/PerformanceSheetMapper.java | 4 + .../PerformanceSheetServiceImpl.java | 431 +++++++++++++++++- 2 files changed, 425 insertions(+), 10 deletions(-) diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/mysql/performance/PerformanceSheetMapper.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/mysql/performance/PerformanceSheetMapper.java index ae9a2ba..fc647ac 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/mysql/performance/PerformanceSheetMapper.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/mysql/performance/PerformanceSheetMapper.java @@ -3,6 +3,7 @@ package com.njcn.rdms.module.project.dal.mysql.performance; import com.njcn.rdms.framework.common.pojo.PageResult; import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX; import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX; +import com.njcn.rdms.module.project.constant.PerformanceConstants; import com.njcn.rdms.module.project.controller.admin.performance.vo.PerformanceSheetPageReqVO; import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetDO; import org.apache.ibatis.annotations.Mapper; @@ -22,6 +23,9 @@ public interface PerformanceSheetMapper extends BaseMapperX default PageResult selectEmployeePage(Long employeeId, PerformanceSheetPageReqVO reqVO) { LambdaQueryWrapperX wrapper = buildPageQuery(reqVO) .eq(PerformanceSheetDO::getEmployeeId, employeeId) + .in(PerformanceSheetDO::getStatusCode, List.of( + PerformanceConstants.STATUS_SENT, + PerformanceConstants.STATUS_CONFIRMED)) .orderByDesc(PerformanceSheetDO::getPeriodMonth) .orderByDesc(PerformanceSheetDO::getId); return selectPage(reqVO, wrapper); diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/performance/PerformanceSheetServiceImpl.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/performance/PerformanceSheetServiceImpl.java index a42e4ff..4f4af87 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/performance/PerformanceSheetServiceImpl.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/service/performance/PerformanceSheetServiceImpl.java @@ -40,11 +40,35 @@ import com.njcn.rdms.module.system.api.user.UserManagementRelationApi; import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO; import com.njcn.rdms.module.system.enums.notify.NotifyMessageLevelConstants; import jakarta.annotation.Resource; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellCopyContext; +import org.apache.poi.ss.usermodel.CellCopyPolicy; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.ClientAnchor; +import org.apache.poi.ss.usermodel.Comment; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.ss.usermodel.DataFormat; +import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.PageMargin; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.apache.poi.ss.util.CellAddress; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.PaneInformation; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFColor; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.math.BigDecimal; import java.math.RoundingMode; @@ -55,11 +79,15 @@ import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; +import java.util.zip.CRC32; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -102,11 +130,11 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService { @Override public PageResult getSheetPage(PerformanceSheetPageReqVO reqVO) { PageResult pageResult; - if (reqVO.getEmployeeIds() != null) { + if (reqVO.getEmployeeIds() != null) { //团队视角下进入 List employeeIds = teamDashboardAccessService.resolveRequestedSubordinateUserIds( reqVO.getEmployeeIds(), PerformanceConstants.PERMISSION_TEAM_DASHBOARD); pageResult = performanceSheetMapper.selectEmployeePage(employeeIds, reqVO); - } else { + } else { //个人视角下进入 pageResult = performanceSheetMapper.selectEmployeePage(SecurityFrameworkUtils.getLoginUserId(), reqVO); } return new PageResult<>(pageResult.getList().stream().map(this::toRespVO).toList(), pageResult.getTotal()); @@ -228,7 +256,7 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService { for (Long id : ids) { sheets.add(validateReadableSheet(id)); } - return zipSheets("绩效表_" + LocalDate.now() + ".zip", sheets); + return zipSheetsWithMergedWorkbook("绩效表_" + LocalDate.now() + ".zip", sheets); } @Override @@ -238,10 +266,10 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService { employeeIds = teamDashboardAccessService.resolveRequestedSubordinateUserIds( reqVO.getEmployeeIds(), PerformanceConstants.PERMISSION_TEAM_DASHBOARD); } else { - employeeIds = List.of(SecurityFrameworkUtils.getLoginUserId()); + employeeIds = List.of(Objects.requireNonNull(SecurityFrameworkUtils.getLoginUserId())); } List sheets = performanceSheetMapper.selectExportList(reqVO, employeeIds); - return zipSheets("绩效表_" + LocalDate.now() + ".zip", sheets); + return zipSheetsWithMergedWorkbook("绩效表_" + LocalDate.now() + ".zip", sheets); } @Override @@ -461,16 +489,19 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService { return respVO; } - private PerformanceDownloadFile zipSheets(String filename, List sheets) { + private PerformanceDownloadFile zipSheetsWithMergedWorkbook(String filename, List sheets) { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) { Map filenameCounts = new HashMap<>(); + Map fileContents = loadFileContents(sheets); + if (sheets != null && !sheets.isEmpty()) { + byte[] mergedWorkbookContent = buildMergedWorkbook(sheets, fileContents); + putStoredZipEntry(zipOutputStream, buildMergedWorkbookEntryName(sheets), mergedWorkbookContent); + } for (PerformanceSheetDO sheet : sheets) { - byte[] content = readFileContent(sheet); + byte[] content = fileContents.get(sheet); String entryName = uniqueFilename(defaultDownloadName(sheet), filenameCounts); - zipOutputStream.putNextEntry(new ZipEntry(entryName)); - zipOutputStream.write(content); - zipOutputStream.closeEntry(); + putStoredZipEntry(zipOutputStream, entryName, content); } zipOutputStream.finish(); return new PerformanceDownloadFile(filename, ZIP_CONTENT_TYPE, outputStream.toByteArray()); @@ -479,6 +510,379 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService { } } + private Map loadFileContents(List sheets) { + Map fileContents = new IdentityHashMap<>(); + if (sheets == null || sheets.isEmpty()) { + return fileContents; + } + for (PerformanceSheetDO sheet : sheets) { + fileContents.put(sheet, readFileContent(sheet)); + } + return fileContents; + } + + private void putStoredZipEntry(ZipOutputStream zipOutputStream, String entryName, byte[] content) throws Exception { + CRC32 crc32 = new CRC32(); + crc32.update(content); + ZipEntry zipEntry = new ZipEntry(entryName); + zipEntry.setMethod(ZipEntry.STORED); + zipEntry.setSize(content.length); + zipEntry.setCompressedSize(content.length); + zipEntry.setCrc(crc32.getValue()); + zipOutputStream.putNextEntry(zipEntry); + zipOutputStream.write(content); + zipOutputStream.closeEntry(); + } + + private byte[] buildMergedWorkbook(List sheets, Map fileContents) { + try (XSSFWorkbook targetWorkbook = new XSSFWorkbook(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + Set usedSheetNames = new HashSet<>(); + for (PerformanceSheetDO performanceSheet : sheets) { + byte[] sourceBytes = fileContents.get(performanceSheet); + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(sourceBytes); + Workbook sourceWorkbook = WorkbookFactory.create(inputStream)) { + if (!(sourceWorkbook instanceof XSSFWorkbook)) { + throw new IllegalStateException("绩效汇总导出仅支持 .xlsx 文件"); + } + if (sourceWorkbook.getNumberOfSheets() <= 0) { + continue; + } + Sheet sourceSheet = sourceWorkbook.getSheetAt(0); + String targetSheetName = sanitizeSheetName(buildMergedSheetName(performanceSheet), usedSheetNames); + Sheet targetSheet = targetWorkbook.createSheet(targetSheetName); + copySheet(sourceWorkbook, sourceSheet, targetWorkbook, targetSheet); + } + } + targetWorkbook.setForceFormulaRecalculation(true); + targetWorkbook.write(outputStream); + return outputStream.toByteArray(); + } catch (Exception ex) { + throw new IllegalStateException("生成绩效汇总 Excel 失败", ex); + } + } + + private String buildMergedWorkbookEntryName(List sheets) { + Set periodMonths = new LinkedHashSet<>(); + for (PerformanceSheetDO sheet : sheets) { + if (sheet != null && StringUtils.hasText(sheet.getPeriodMonth())) { + periodMonths.add(sheet.getPeriodMonth().trim()); + } + } + if (periodMonths.size() == 1) { + return "0_绩效表汇总_" + periodMonths.iterator().next() + "月.xlsx"; + } + return "0_绩效表汇总.xlsx"; + } + + private String buildMergedSheetName(PerformanceSheetDO sheet) { + return defaultText(sheet.getPeriodMonth()) + "_" + defaultText(sheet.getEmployeeName()); + } + + private String sanitizeSheetName(String rawName, Set usedNames) { + String name = StringUtils.hasText(rawName) ? rawName.trim() : "Sheet"; + name = name.replace("\\", "_") + .replace("/", "_") + .replace("?", "_") + .replace("*", "_") + .replace("[", "_") + .replace("]", "_") + .replace(":", "_"); + if (name.length() > 31) { + name = name.substring(0, 31); + } + if (!StringUtils.hasText(name)) { + name = "Sheet"; + } + if (usedNames.add(name)) { + return name; + } + int index = 2; + while (true) { + String suffix = "_" + index; + int maxLength = 31 - suffix.length(); + String base = name.length() > maxLength ? name.substring(0, maxLength) : name; + String candidate = base + suffix; + if (usedNames.add(candidate)) { + return candidate; + } + index++; + } + } + + private void copySheet(Workbook sourceWorkbook, Sheet sourceSheet, Workbook targetWorkbook, Sheet targetSheet) { + if (!(sourceSheet instanceof XSSFSheet sourceXssfSheet) || !(targetSheet instanceof XSSFSheet targetXssfSheet)) { + throw new IllegalStateException("绩效汇总导出仅支持 .xlsx 文件"); + } + copySheetSettings(sourceSheet, targetSheet); + CellCopyPolicy copyPolicy = new CellCopyPolicy(); + copyPolicy.setCopyCellValue(true); + copyPolicy.setCopyCellStyle(true); + copyPolicy.setCopyCellFormula(true); + copyPolicy.setCopyHyperlink(true); + copyPolicy.setCopyRowHeight(true); + copyPolicy.setCopyMergedRegions(false); + CellCopyContext cellCopyContext = new CellCopyContext(); + int firstRowNum = sourceXssfSheet.getFirstRowNum(); + int lastRowNum = sourceXssfSheet.getLastRowNum(); + int rangeStart = -1; + List rangeRows = new ArrayList<>(); + for (int rowIndex = firstRowNum; rowIndex <= lastRowNum; rowIndex++) { + Row sourceRow = sourceXssfSheet.getRow(rowIndex); + if (sourceRow == null) { + if (rangeStart >= 0 && !rangeRows.isEmpty()) { + targetXssfSheet.copyRows(rangeRows, rangeStart, copyPolicy, cellCopyContext); + rangeStart = -1; + rangeRows = new ArrayList<>(); + } + continue; + } + if (rangeStart < 0) { + rangeStart = rowIndex; + } + rangeRows.add(sourceRow); + } + if (rangeStart >= 0 && !rangeRows.isEmpty()) { + targetXssfSheet.copyRows(rangeRows, rangeStart, copyPolicy, cellCopyContext); + } + syncRowStyles(sourceWorkbook, targetWorkbook, sourceSheet, targetSheet, new SheetCopyContext()); + copyMergedRegions(sourceSheet, targetSheet); + copyColumnWidths(sourceSheet, targetSheet); + copySheetComments(sourceSheet, targetSheet); + targetSheet.setForceFormulaRecalculation(true); + } + + private void copySheetComments(Sheet sourceSheet, Sheet targetSheet) { + Map comments = sourceSheet.getCellComments(); + if (comments == null || comments.isEmpty()) { + return; + } + for (Map.Entry entry : comments.entrySet()) { + CellAddress cellAddress = entry.getKey(); + Row targetRow = targetSheet.getRow(cellAddress.getRow()); + if (targetRow == null) { + continue; + } + Cell targetCell = targetRow.getCell(cellAddress.getColumn()); + if (targetCell == null) { + continue; + } + copyCellComment(entry.getValue(), cellAddress.getRow(), cellAddress.getColumn(), targetCell); + } + } + + private void syncRowStyles(Workbook sourceWorkbook, Workbook targetWorkbook, Sheet sourceSheet, Sheet targetSheet, + SheetCopyContext copyContext) { + int firstRowNum = sourceSheet.getFirstRowNum(); + int lastRowNum = sourceSheet.getLastRowNum(); + for (int rowIndex = firstRowNum; rowIndex <= lastRowNum; rowIndex++) { + Row sourceRow = sourceSheet.getRow(rowIndex); + Row targetRow = targetSheet.getRow(rowIndex); + if (sourceRow == null || targetRow == null) { + continue; + } + CellStyle sourceRowStyle = sourceRow.getRowStyle(); + if (sourceRowStyle != null) { + targetRow.setRowStyle(cloneStyle(sourceWorkbook, targetWorkbook, sourceRowStyle, copyContext)); + } + } + } + + private CellStyle cloneStyle(Workbook sourceWorkbook, Workbook targetWorkbook, CellStyle sourceStyle, + SheetCopyContext copyContext) { + CellStyle cachedStyle = copyContext.styleCache.get(sourceStyle); + if (cachedStyle != null) { + return cachedStyle; + } + CellStyle newStyle = targetWorkbook.createCellStyle(); + copyCellStyleProperties(sourceWorkbook, targetWorkbook, sourceStyle, newStyle, copyContext); + copyContext.styleCache.put(sourceStyle, newStyle); + return newStyle; + } + + private void copyCellStyleProperties(Workbook sourceWorkbook, Workbook targetWorkbook, CellStyle sourceStyle, + CellStyle targetStyle, SheetCopyContext copyContext) { + boolean xssfCloned = false; + if (sourceStyle instanceof XSSFCellStyle sourceXssfStyle && targetStyle instanceof XSSFCellStyle targetXssfStyle) { + try { + targetXssfStyle.cloneStyleFrom(sourceXssfStyle); + xssfCloned = true; + } catch (RuntimeException ignored) { + // fallback to generic property copy + } + } + if (!xssfCloned) { + targetStyle.setAlignment(sourceStyle.getAlignment()); + targetStyle.setVerticalAlignment(sourceStyle.getVerticalAlignment()); + targetStyle.setBorderBottom(sourceStyle.getBorderBottom()); + targetStyle.setBorderLeft(sourceStyle.getBorderLeft()); + targetStyle.setBorderRight(sourceStyle.getBorderRight()); + targetStyle.setBorderTop(sourceStyle.getBorderTop()); + targetStyle.setBottomBorderColor(sourceStyle.getBottomBorderColor()); + targetStyle.setLeftBorderColor(sourceStyle.getLeftBorderColor()); + targetStyle.setRightBorderColor(sourceStyle.getRightBorderColor()); + targetStyle.setTopBorderColor(sourceStyle.getTopBorderColor()); + targetStyle.setFillPattern(sourceStyle.getFillPattern()); + targetStyle.setFillForegroundColor(sourceStyle.getFillForegroundColor()); + targetStyle.setFillBackgroundColor(sourceStyle.getFillBackgroundColor()); + targetStyle.setHidden(sourceStyle.getHidden()); + targetStyle.setIndention(sourceStyle.getIndention()); + targetStyle.setLocked(sourceStyle.getLocked()); + targetStyle.setRotation(sourceStyle.getRotation()); + targetStyle.setShrinkToFit(sourceStyle.getShrinkToFit()); + targetStyle.setWrapText(sourceStyle.getWrapText()); + targetStyle.setQuotePrefixed(sourceStyle.getQuotePrefixed()); + } + + String dataFormatString = sourceStyle.getDataFormatString(); + if (StringUtils.hasText(dataFormatString)) { + Short targetDataFormat = copyContext.dataFormatCache.get(dataFormatString); + if (targetDataFormat == null) { + DataFormat dataFormat = targetWorkbook.createDataFormat(); + targetDataFormat = dataFormat.getFormat(dataFormatString); + copyContext.dataFormatCache.put(dataFormatString, targetDataFormat); + } + targetStyle.setDataFormat(targetDataFormat); + } + + if (sourceStyle instanceof XSSFCellStyle sourceXssfStyle && targetStyle instanceof XSSFCellStyle targetXssfStyle) { + applyXssfStyleColors(sourceXssfStyle, targetXssfStyle); + } + + Font sourceFont = sourceWorkbook.getFontAt(sourceStyle.getFontIndex()); + if (sourceFont != null) { + Font targetFont = copyContext.fontCache.get(sourceFont); + if (targetFont == null) { + targetFont = cloneFont(targetWorkbook, sourceFont); + copyContext.fontCache.put(sourceFont, targetFont); + } + targetStyle.setFont(targetFont); + } + } + + private Font cloneFont(Workbook targetWorkbook, Font sourceFont) { + Font targetFont = targetWorkbook.createFont(); + targetFont.setBold(sourceFont.getBold()); + targetFont.setCharSet(sourceFont.getCharSet()); + targetFont.setColor(sourceFont.getColor()); + targetFont.setFontHeight(sourceFont.getFontHeight()); + targetFont.setFontHeightInPoints(sourceFont.getFontHeightInPoints()); + targetFont.setFontName(sourceFont.getFontName()); + targetFont.setItalic(sourceFont.getItalic()); + targetFont.setStrikeout(sourceFont.getStrikeout()); + targetFont.setTypeOffset(sourceFont.getTypeOffset()); + targetFont.setUnderline(sourceFont.getUnderline()); + if (sourceFont instanceof XSSFFont sourceXssfFont && targetFont instanceof XSSFFont targetXssfFont) { + targetXssfFont.setFamily(sourceXssfFont.getFamily()); + if (sourceXssfFont.getScheme() != null) { + targetXssfFont.setScheme(sourceXssfFont.getScheme()); + } + targetXssfFont.setThemeColor(sourceXssfFont.getThemeColor()); + XSSFColor xssfColor = sourceXssfFont.getXSSFColor(); + if (xssfColor != null) { + targetXssfFont.setColor(xssfColor); + } + } + return targetFont; + } + + private void applyXssfStyleColors(XSSFCellStyle sourceStyle, XSSFCellStyle targetStyle) { + XSSFColor fillForegroundColor = sourceStyle.getFillForegroundColorColor(); + if (fillForegroundColor != null) { + targetStyle.setFillForegroundColor(fillForegroundColor); + } + XSSFColor fillBackgroundColor = sourceStyle.getFillBackgroundColorColor(); + if (fillBackgroundColor != null) { + targetStyle.setFillBackgroundColor(fillBackgroundColor); + } + XSSFColor topBorderColor = sourceStyle.getTopBorderXSSFColor(); + if (topBorderColor != null) { + targetStyle.setTopBorderColor(topBorderColor); + } + XSSFColor bottomBorderColor = sourceStyle.getBottomBorderXSSFColor(); + if (bottomBorderColor != null) { + targetStyle.setBottomBorderColor(bottomBorderColor); + } + XSSFColor leftBorderColor = sourceStyle.getLeftBorderXSSFColor(); + if (leftBorderColor != null) { + targetStyle.setLeftBorderColor(leftBorderColor); + } + XSSFColor rightBorderColor = sourceStyle.getRightBorderXSSFColor(); + if (rightBorderColor != null) { + targetStyle.setRightBorderColor(rightBorderColor); + } + } + + private void copyCellComment(Comment sourceComment, int rowIndex, int columnIndex, Cell targetCell) { + if (sourceComment == null) { + return; + } + Sheet targetSheet = targetCell.getSheet(); + Drawing drawing = targetSheet.getDrawingPatriarch(); + if (drawing == null) { + drawing = targetSheet.createDrawingPatriarch(); + } + CreationHelper creationHelper = targetSheet.getWorkbook().getCreationHelper(); + ClientAnchor anchor = creationHelper.createClientAnchor(); + anchor.setCol1(columnIndex); + anchor.setCol2(columnIndex + 3); + anchor.setRow1(rowIndex); + anchor.setRow2(rowIndex + 4); + + Comment targetComment = drawing.createCellComment(anchor); + targetComment.setAuthor(sourceComment.getAuthor()); + targetComment.setVisible(sourceComment.isVisible()); + targetComment.setString(creationHelper.createRichTextString(sourceComment.getString().getString())); + targetCell.setCellComment(targetComment); + } + + private void copySheetSettings(Sheet sourceSheet, Sheet targetSheet) { + targetSheet.setDisplayGridlines(sourceSheet.isDisplayGridlines()); + targetSheet.setPrintGridlines(sourceSheet.isPrintGridlines()); + targetSheet.setDefaultRowHeight(sourceSheet.getDefaultRowHeight()); + targetSheet.setDefaultColumnWidth(sourceSheet.getDefaultColumnWidth()); + targetSheet.setHorizontallyCenter(sourceSheet.getHorizontallyCenter()); + targetSheet.setVerticallyCenter(sourceSheet.getVerticallyCenter()); + targetSheet.setMargin(PageMargin.LEFT, sourceSheet.getMargin(PageMargin.LEFT)); + targetSheet.setMargin(PageMargin.RIGHT, sourceSheet.getMargin(PageMargin.RIGHT)); + targetSheet.setMargin(PageMargin.TOP, sourceSheet.getMargin(PageMargin.TOP)); + targetSheet.setMargin(PageMargin.BOTTOM, sourceSheet.getMargin(PageMargin.BOTTOM)); + targetSheet.setZoom(40); + PaneInformation paneInformation = sourceSheet.getPaneInformation(); + if (paneInformation != null && paneInformation.isFreezePane()) { + targetSheet.createFreezePane( + paneInformation.getVerticalSplitPosition(), + paneInformation.getHorizontalSplitPosition(), + paneInformation.getVerticalSplitLeftColumn(), + paneInformation.getHorizontalSplitTopRow()); + } + } + + private void copyColumnWidths(Sheet sourceSheet, Sheet targetSheet) { + int maxColumnNum = 0; + int firstRowNum = sourceSheet.getFirstRowNum(); + int lastRowNum = sourceSheet.getLastRowNum(); + for (int rowIndex = firstRowNum; rowIndex <= lastRowNum; rowIndex++) { + Row row = sourceSheet.getRow(rowIndex); + if (row != null && row.getLastCellNum() > maxColumnNum) { + maxColumnNum = row.getLastCellNum(); + } + } + for (int columnIndex = 0; columnIndex < maxColumnNum; columnIndex++) { + targetSheet.setColumnWidth(columnIndex, sourceSheet.getColumnWidth(columnIndex)); + targetSheet.setColumnHidden(columnIndex, sourceSheet.isColumnHidden(columnIndex)); + } + } + + private void copyMergedRegions(Sheet sourceSheet, Sheet targetSheet) { + int mergedRegionCount = sourceSheet.getNumMergedRegions(); + for (int i = 0; i < mergedRegionCount; i++) { + CellRangeAddress region = sourceSheet.getMergedRegion(i); + targetSheet.addMergedRegion(new CellRangeAddress( + region.getFirstRow(), region.getLastRow(), region.getFirstColumn(), region.getLastColumn())); + } + } + private byte[] readFileContent(PerformanceSheetDO sheet) { if (sheet.getFileId() == null) { throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_FILE_REQUIRED); @@ -631,4 +1035,11 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService { private String defaultText(String value) { return StringUtils.hasText(value) ? value.trim() : ""; } + + private static final class SheetCopyContext { + + private final Map styleCache = new IdentityHashMap<>(); + private final Map fontCache = new IdentityHashMap<>(); + private final Map dataFormatCache = new HashMap<>(); + } }