feat(我的绩效): 支持多份excel合并为一个大excel的不同sheet页。
fix(我的绩效): 修复非直属上级也能对下属的绩效表,进行编辑/删除/发送等动作的问题。
This commit is contained in:
@@ -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.common.pojo.PageResult;
|
||||||
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
|
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
|
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.controller.admin.performance.vo.PerformanceSheetPageReqVO;
|
||||||
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetDO;
|
import com.njcn.rdms.module.project.dal.dataobject.performance.PerformanceSheetDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
@@ -22,6 +23,9 @@ public interface PerformanceSheetMapper extends BaseMapperX<PerformanceSheetDO>
|
|||||||
default PageResult<PerformanceSheetDO> selectEmployeePage(Long employeeId, PerformanceSheetPageReqVO reqVO) {
|
default PageResult<PerformanceSheetDO> selectEmployeePage(Long employeeId, PerformanceSheetPageReqVO reqVO) {
|
||||||
LambdaQueryWrapperX<PerformanceSheetDO> wrapper = buildPageQuery(reqVO)
|
LambdaQueryWrapperX<PerformanceSheetDO> wrapper = buildPageQuery(reqVO)
|
||||||
.eq(PerformanceSheetDO::getEmployeeId, employeeId)
|
.eq(PerformanceSheetDO::getEmployeeId, employeeId)
|
||||||
|
.in(PerformanceSheetDO::getStatusCode, List.of(
|
||||||
|
PerformanceConstants.STATUS_SENT,
|
||||||
|
PerformanceConstants.STATUS_CONFIRMED))
|
||||||
.orderByDesc(PerformanceSheetDO::getPeriodMonth)
|
.orderByDesc(PerformanceSheetDO::getPeriodMonth)
|
||||||
.orderByDesc(PerformanceSheetDO::getId);
|
.orderByDesc(PerformanceSheetDO::getId);
|
||||||
return selectPage(reqVO, wrapper);
|
return selectPage(reqVO, wrapper);
|
||||||
|
|||||||
@@ -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.api.user.dto.AdminUserRespDTO;
|
||||||
import com.njcn.rdms.module.system.enums.notify.NotifyMessageLevelConstants;
|
import com.njcn.rdms.module.system.enums.notify.NotifyMessageLevelConstants;
|
||||||
import jakarta.annotation.Resource;
|
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.context.ApplicationEventPublisher;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
@@ -55,11 +79,15 @@ import java.time.format.DateTimeParseException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
@@ -102,11 +130,11 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
@Override
|
@Override
|
||||||
public PageResult<PerformanceSheetRespVO> getSheetPage(PerformanceSheetPageReqVO reqVO) {
|
public PageResult<PerformanceSheetRespVO> getSheetPage(PerformanceSheetPageReqVO reqVO) {
|
||||||
PageResult<PerformanceSheetDO> pageResult;
|
PageResult<PerformanceSheetDO> pageResult;
|
||||||
if (reqVO.getEmployeeIds() != null) {
|
if (reqVO.getEmployeeIds() != null) { //团队视角下进入
|
||||||
List<Long> employeeIds = teamDashboardAccessService.resolveRequestedSubordinateUserIds(
|
List<Long> employeeIds = teamDashboardAccessService.resolveRequestedSubordinateUserIds(
|
||||||
reqVO.getEmployeeIds(), PerformanceConstants.PERMISSION_TEAM_DASHBOARD);
|
reqVO.getEmployeeIds(), PerformanceConstants.PERMISSION_TEAM_DASHBOARD);
|
||||||
pageResult = performanceSheetMapper.selectEmployeePage(employeeIds, reqVO);
|
pageResult = performanceSheetMapper.selectEmployeePage(employeeIds, reqVO);
|
||||||
} else {
|
} else { //个人视角下进入
|
||||||
pageResult = performanceSheetMapper.selectEmployeePage(SecurityFrameworkUtils.getLoginUserId(), reqVO);
|
pageResult = performanceSheetMapper.selectEmployeePage(SecurityFrameworkUtils.getLoginUserId(), reqVO);
|
||||||
}
|
}
|
||||||
return new PageResult<>(pageResult.getList().stream().map(this::toRespVO).toList(), pageResult.getTotal());
|
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) {
|
for (Long id : ids) {
|
||||||
sheets.add(validateReadableSheet(id));
|
sheets.add(validateReadableSheet(id));
|
||||||
}
|
}
|
||||||
return zipSheets("绩效表_" + LocalDate.now() + ".zip", sheets);
|
return zipSheetsWithMergedWorkbook("绩效表_" + LocalDate.now() + ".zip", sheets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -238,10 +266,10 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
employeeIds = teamDashboardAccessService.resolveRequestedSubordinateUserIds(
|
employeeIds = teamDashboardAccessService.resolveRequestedSubordinateUserIds(
|
||||||
reqVO.getEmployeeIds(), PerformanceConstants.PERMISSION_TEAM_DASHBOARD);
|
reqVO.getEmployeeIds(), PerformanceConstants.PERMISSION_TEAM_DASHBOARD);
|
||||||
} else {
|
} else {
|
||||||
employeeIds = List.of(SecurityFrameworkUtils.getLoginUserId());
|
employeeIds = List.of(Objects.requireNonNull(SecurityFrameworkUtils.getLoginUserId()));
|
||||||
}
|
}
|
||||||
List<PerformanceSheetDO> sheets = performanceSheetMapper.selectExportList(reqVO, employeeIds);
|
List<PerformanceSheetDO> sheets = performanceSheetMapper.selectExportList(reqVO, employeeIds);
|
||||||
return zipSheets("绩效表_" + LocalDate.now() + ".zip", sheets);
|
return zipSheetsWithMergedWorkbook("绩效表_" + LocalDate.now() + ".zip", sheets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -461,16 +489,19 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
return respVO;
|
return respVO;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PerformanceDownloadFile zipSheets(String filename, List<PerformanceSheetDO> sheets) {
|
private PerformanceDownloadFile zipSheetsWithMergedWorkbook(String filename, List<PerformanceSheetDO> sheets) {
|
||||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
|
ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
|
||||||
Map<String, Integer> filenameCounts = new HashMap<>();
|
Map<String, Integer> filenameCounts = new HashMap<>();
|
||||||
|
Map<PerformanceSheetDO, byte[]> fileContents = loadFileContents(sheets);
|
||||||
|
if (sheets != null && !sheets.isEmpty()) {
|
||||||
|
byte[] mergedWorkbookContent = buildMergedWorkbook(sheets, fileContents);
|
||||||
|
putStoredZipEntry(zipOutputStream, buildMergedWorkbookEntryName(sheets), mergedWorkbookContent);
|
||||||
|
}
|
||||||
for (PerformanceSheetDO sheet : sheets) {
|
for (PerformanceSheetDO sheet : sheets) {
|
||||||
byte[] content = readFileContent(sheet);
|
byte[] content = fileContents.get(sheet);
|
||||||
String entryName = uniqueFilename(defaultDownloadName(sheet), filenameCounts);
|
String entryName = uniqueFilename(defaultDownloadName(sheet), filenameCounts);
|
||||||
zipOutputStream.putNextEntry(new ZipEntry(entryName));
|
putStoredZipEntry(zipOutputStream, entryName, content);
|
||||||
zipOutputStream.write(content);
|
|
||||||
zipOutputStream.closeEntry();
|
|
||||||
}
|
}
|
||||||
zipOutputStream.finish();
|
zipOutputStream.finish();
|
||||||
return new PerformanceDownloadFile(filename, ZIP_CONTENT_TYPE, outputStream.toByteArray());
|
return new PerformanceDownloadFile(filename, ZIP_CONTENT_TYPE, outputStream.toByteArray());
|
||||||
@@ -479,6 +510,379 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<PerformanceSheetDO, byte[]> loadFileContents(List<PerformanceSheetDO> sheets) {
|
||||||
|
Map<PerformanceSheetDO, byte[]> 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<PerformanceSheetDO> sheets, Map<PerformanceSheetDO, byte[]> fileContents) {
|
||||||
|
try (XSSFWorkbook targetWorkbook = new XSSFWorkbook();
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||||
|
Set<String> 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<PerformanceSheetDO> sheets) {
|
||||||
|
Set<String> 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<String> 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<Row> 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<CellAddress, ? extends Comment> comments = sourceSheet.getCellComments();
|
||||||
|
if (comments == null || comments.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Map.Entry<CellAddress, ? extends Comment> 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) {
|
private byte[] readFileContent(PerformanceSheetDO sheet) {
|
||||||
if (sheet.getFileId() == null) {
|
if (sheet.getFileId() == null) {
|
||||||
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_FILE_REQUIRED);
|
throw exception(ErrorCodeConstants.PERFORMANCE_SHEET_FILE_REQUIRED);
|
||||||
@@ -631,4 +1035,11 @@ public class PerformanceSheetServiceImpl implements PerformanceSheetService {
|
|||||||
private String defaultText(String value) {
|
private String defaultText(String value) {
|
||||||
return StringUtils.hasText(value) ? value.trim() : "";
|
return StringUtils.hasText(value) ? value.trim() : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class SheetCopyContext {
|
||||||
|
|
||||||
|
private final Map<CellStyle, CellStyle> styleCache = new IdentityHashMap<>();
|
||||||
|
private final Map<Font, Font> fontCache = new IdentityHashMap<>();
|
||||||
|
private final Map<String, Short> dataFormatCache = new HashMap<>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user