1.2.01后端:

feat(budget):根据研发预算新模板修改导出功能
dev
xs 2 months ago
parent 1045837bd7
commit bb59628452

@ -10,9 +10,9 @@ import lombok.Getter;
@Getter @Getter
public enum TechTypeEnum { public enum TechTypeEnum {
/** /**
* *
*/ */
TECH_CONSULT("1", "技术咨询开发"), TECH_CONSULT("1", "新产品设计费"),
/** /**
* - * -

@ -0,0 +1,51 @@
package org.dromara.oa.erp.enums;
import lombok.Getter;
/**
* @author xins
* @description erp_rd_budget_travel_cost
* @date 2025/12/11 13:58
*/
@Getter
public enum TripTypeEnum {
/**
*
*/
TRAVEL("1", "差旅费"),
/**
*
*/
TRANSPORTATION("2", "交通费");
/**
*
*/
private final String code;
/**
*
*/
private final String name;
TripTypeEnum(String code, String name) {
this.code = code;
this.name = name;
}
/**
*
*/
public static TripTypeEnum getByCode(String code) {
for (TripTypeEnum config : values()) {
if (config.getCode().equals(code)) {
return config;
}
}
return null;
}
}

@ -10,6 +10,8 @@ import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -24,6 +26,10 @@ public abstract class BaseExcelExporter {
protected Workbook workbook; protected Workbook workbook;
//字体定义
protected Font yaheiNormal10Font;
protected Font yaheiBold10Font;
// 样式定义 // 样式定义
protected CellStyle titleStyle; protected CellStyle titleStyle;
protected CellStyle formLeftStyle; protected CellStyle formLeftStyle;
@ -40,9 +46,54 @@ public abstract class BaseExcelExporter {
protected CellStyle remarkStyle; protected CellStyle remarkStyle;
protected CellStyle leftMergeStyle; protected CellStyle leftMergeStyle;
protected CellStyle rdCoverTitleStyle;
protected CellStyle rdCoverSubtitleStyle;
protected CellStyle rdCoverFormKeyStyle;
protected CellStyle rdCoverFormValueStyle;
protected CellStyle rdTitleStyle;
protected CellStyle rdHeaderStyle;
protected CellStyle rdNoTopBorderHeaderStyle;
protected CellStyle rdNoBottomBorderHeaderStyle;
protected CellStyle rdLeftHeaderStyle;
protected CellStyle rdRightHeaderStyle;
protected CellStyle rdFooterStyle;
protected CellStyle rdLeftFooterStyle;
protected CellStyle rdRightFooterStyle;
protected CellStyle rdDataStyle;
protected CellStyle rdLeftDataStyle;
protected CellStyle rdRightDataStyle;
protected CellStyle rdLeftBottomDataStyle;
protected CellStyle rdRightBottomDataStyle;
protected CellStyle rdDataBoldStyle;
protected CellStyle rdLeftDataBoldStyle;
protected CellStyle rdRightDataBoldStyle;
protected CellStyle rdDataRedBoldStyle;
protected CellStyle rdLeftDataRedBoldStyle;
protected CellStyle rdRightDataRedBoldStyle;
protected CellStyle rdBottomDataRedBoldStyle;
protected CellStyle rdFormulaStyle;
protected CellStyle rdRightFormulaStyle;
protected CellStyle rdFooterFormulaStyle;
protected CellStyle rdFormulaPercentageStyle;
protected CellStyle rdFooterFormulaPercentageStyle;
protected CellStyle rdFooterRightFormulaStyle;
protected CellStyle rdInstructionStyle;
protected CellStyle rdFormDataStyle;
protected CellStyle rdFormStyle;
protected CellStyle rdFormFormulaStyle;
// 存储各sheet的总计行位置 // 存储各sheet的总计行位置
protected final Map<String, Integer> sheetTotalRowMap = new ConcurrentHashMap<>(); protected final Map<String, Integer> sheetTotalRowMap = new ConcurrentHashMap<>();
// 富文本样式缓存
protected final Map<String, Font> fontCache = new ConcurrentHashMap<>();
/** /**
* Excel * Excel
*/ */
@ -64,6 +115,9 @@ public abstract class BaseExcelExporter {
* *
*/ */
protected void createStyles() { protected void createStyles() {
//创建字体样式
createFont();
// 创建标题样式 // 创建标题样式
createTitleStyle(); createTitleStyle();
@ -78,8 +132,69 @@ public abstract class BaseExcelExporter {
// 创建其他样式 // 创建其他样式
createOtherStyles(); createOtherStyles();
// 创建研发预算封面样式
createRdCoverStyle();
} }
/**
*
*/
protected void createFont() {
yaheiNormal10Font = workbook.createFont();
yaheiNormal10Font.setFontName("微软雅黑");
yaheiNormal10Font.setFontHeightInPoints((short) 10);
yaheiBold10Font = workbook.createFont();
yaheiBold10Font.setBold(true);
yaheiBold10Font.setFontName("微软雅黑");
yaheiBold10Font.setFontHeightInPoints((short) 10);
initFontCache();
}
/**
*
*/
protected void initFontCache() {
fontCache.clear();
fontCache.put("normal-10", yaheiNormal10Font);
fontCache.put("bold-10", yaheiBold10Font);
}
/**
*
*/
protected Font getOrCreateFont(String fontKey, FontStyleConfig config) {
if (fontCache.containsKey(fontKey)) {
return fontCache.get(fontKey);
}
Font font = workbook.createFont();
font.setFontName(config.getFontName() != null ? config.getFontName() : "微软雅黑");
font.setFontHeightInPoints(config.getFontSize());
if (config.isBold()) {
font.setBold(true);
}
if (config.getColor() != null) {
font.setColor(config.getColor());
}
if (config.isItalic()) {
font.setItalic(true);
}
if (config.isUnderline()) {
font.setUnderline(Font.U_SINGLE);
}
fontCache.put(fontKey, font);
return font;
}
/** /**
* *
*/ */
@ -95,6 +210,275 @@ public abstract class BaseExcelExporter {
setBorder(titleStyle, BorderStyle.MEDIUM); setBorder(titleStyle, BorderStyle.MEDIUM);
} }
/**
*
*/
protected void createRdCoverStyle() {
rdCoverTitleStyle = workbook.createCellStyle();
Font titleFont = workbook.createFont();
titleFont.setBold(true);
titleFont.setFontName("宋体");
titleFont.setFontHeightInPoints((short) 26);
rdCoverTitleStyle.setFont(titleFont);
rdCoverTitleStyle.setAlignment(HorizontalAlignment.CENTER);
rdCoverTitleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdCoverSubtitleStyle = workbook.createCellStyle();
Font rdSubtitleFont = workbook.createFont();
rdSubtitleFont.setBold(true);
rdSubtitleFont.setFontName("宋体");
rdSubtitleFont.setFontHeightInPoints((short) 48);
rdCoverSubtitleStyle.setFont(rdSubtitleFont);
rdCoverSubtitleStyle.setAlignment(HorizontalAlignment.CENTER);
rdCoverSubtitleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
Font formFont = workbook.createFont();
formFont.setFontName("宋体");
formFont.setFontHeightInPoints((short) 18);
rdCoverFormKeyStyle = workbook.createCellStyle();
rdCoverFormKeyStyle.setFont(formFont);
rdCoverFormKeyStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdCoverFormKeyStyle.setAlignment(HorizontalAlignment.LEFT);
rdCoverFormValueStyle = workbook.createCellStyle();
rdCoverFormValueStyle.setFont(formFont);
rdCoverFormValueStyle.setBorderBottom(BorderStyle.THIN);
rdCoverFormValueStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
rdCoverFormValueStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdCoverFormValueStyle.setAlignment(HorizontalAlignment.CENTER);
// 研发预算表头样式
rdTitleStyle = workbook.createCellStyle();
Font rdTitleFont = workbook.createFont();
rdTitleFont.setBold(true);
rdTitleFont.setFontName("微软雅黑");
rdTitleFont.setFontHeightInPoints((short) 18);
rdTitleStyle.setFont(rdTitleFont);
rdTitleStyle.setAlignment(HorizontalAlignment.CENTER);
rdTitleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdHeaderStyle = workbook.createCellStyle();
rdHeaderStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
rdHeaderStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
Font dataBoldFont = workbook.createFont();
dataBoldFont.setFontName("微软雅黑");
dataBoldFont.setFontHeightInPoints((short) 11);
dataBoldFont.setBold(true);
rdHeaderStyle.setFont(dataBoldFont);
setBorder(rdHeaderStyle, BorderStyle.DOUBLE, BorderStyle.THIN, BorderStyle.THIN, BorderStyle.THIN);
rdHeaderStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdHeaderStyle.setAlignment(HorizontalAlignment.CENTER);
rdLeftHeaderStyle = workbook.createCellStyle();
rdLeftHeaderStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
rdLeftHeaderStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rdLeftHeaderStyle.setFont(dataBoldFont);
setBorder(rdLeftHeaderStyle, BorderStyle.DOUBLE, BorderStyle.THIN, BorderStyle.DOUBLE, BorderStyle.THIN);
rdLeftHeaderStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdLeftHeaderStyle.setAlignment(HorizontalAlignment.CENTER);
rdRightHeaderStyle = workbook.createCellStyle();
rdRightHeaderStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
rdRightHeaderStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rdRightHeaderStyle.setFont(dataBoldFont);
setBorder(rdRightHeaderStyle, BorderStyle.DOUBLE, BorderStyle.THIN, BorderStyle.THIN, BorderStyle.DOUBLE);
rdRightHeaderStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdRightHeaderStyle.setAlignment(HorizontalAlignment.CENTER);
rdNoTopBorderHeaderStyle = workbook.createCellStyle();
rdNoTopBorderHeaderStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
rdNoTopBorderHeaderStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rdNoTopBorderHeaderStyle.setFont(dataBoldFont);
setBorder(rdNoTopBorderHeaderStyle, null, BorderStyle.THIN, BorderStyle.THIN, BorderStyle.THIN);
rdNoTopBorderHeaderStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdNoTopBorderHeaderStyle.setAlignment(HorizontalAlignment.CENTER);
rdNoBottomBorderHeaderStyle = workbook.createCellStyle();
rdNoBottomBorderHeaderStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
rdNoBottomBorderHeaderStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rdNoBottomBorderHeaderStyle.setFont(dataBoldFont);
setBorder(rdNoBottomBorderHeaderStyle, BorderStyle.DOUBLE, null, BorderStyle.THIN, BorderStyle.THIN);
rdNoBottomBorderHeaderStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdNoBottomBorderHeaderStyle.setAlignment(HorizontalAlignment.CENTER);
Font dataFont = workbook.createFont();
dataFont.setFontName("微软雅黑");
dataFont.setFontHeightInPoints((short) 11);
rdDataStyle = workbook.createCellStyle();
rdDataStyle.setFont(dataFont);
setBorder(rdDataStyle, BorderStyle.THIN);
rdDataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdDataStyle.setAlignment(HorizontalAlignment.CENTER);
rdDataStyle.setWrapText(true);
rdLeftDataStyle = workbook.createCellStyle();
rdLeftDataStyle.setFont(dataFont);
setBorder(rdLeftDataStyle, BorderStyle.THIN, BorderStyle.THIN, BorderStyle.DOUBLE, BorderStyle.THIN);
rdLeftDataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdLeftDataStyle.setAlignment(HorizontalAlignment.CENTER);
rdRightDataStyle = workbook.createCellStyle();
rdRightDataStyle.setFont(dataFont);
setBorder(rdRightDataStyle, BorderStyle.THIN, BorderStyle.THIN, BorderStyle.THIN, BorderStyle.DOUBLE);
rdRightDataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdRightDataStyle.setAlignment(HorizontalAlignment.CENTER);
rdRightDataStyle.setWrapText(true);
rdLeftBottomDataStyle = workbook.createCellStyle();
rdLeftBottomDataStyle.setFont(dataFont);
setBorder(rdLeftBottomDataStyle, BorderStyle.THIN, BorderStyle.DOUBLE, BorderStyle.DOUBLE, BorderStyle.THIN);
rdLeftBottomDataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdLeftBottomDataStyle.setAlignment(HorizontalAlignment.CENTER);
rdRightBottomDataStyle = workbook.createCellStyle();
rdRightBottomDataStyle.setFont(dataFont);
setBorder(rdRightBottomDataStyle, BorderStyle.THIN, BorderStyle.DOUBLE, BorderStyle.THIN, BorderStyle.DOUBLE);
rdRightBottomDataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdRightBottomDataStyle.setAlignment(HorizontalAlignment.CENTER);
rdRightBottomDataStyle.setWrapText(true);
rdDataBoldStyle = workbook.createCellStyle();
rdDataBoldStyle.setFont(dataBoldFont);
setBorder(rdDataBoldStyle, BorderStyle.THIN);
rdDataBoldStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdDataBoldStyle.setAlignment(HorizontalAlignment.CENTER);
rdDataBoldStyle.setWrapText(true);
rdLeftDataBoldStyle = workbook.createCellStyle();
rdLeftDataBoldStyle.setFont(dataBoldFont);
setBorder(rdLeftDataBoldStyle, BorderStyle.DOUBLE, BorderStyle.THIN, BorderStyle.THIN, BorderStyle.DOUBLE);
rdLeftDataBoldStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdLeftDataBoldStyle.setAlignment(HorizontalAlignment.CENTER);
rdRightDataBoldStyle = workbook.createCellStyle();
rdRightDataBoldStyle.setFont(dataBoldFont);
setBorder(rdRightDataBoldStyle, BorderStyle.DOUBLE, BorderStyle.THIN, BorderStyle.DOUBLE, BorderStyle.THIN);
rdRightDataBoldStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdRightDataBoldStyle.setAlignment(HorizontalAlignment.CENTER);
rdRightDataBoldStyle.setWrapText(true);
Font dataRedBoldFont = workbook.createFont();
dataRedBoldFont.setFontName("微软雅黑");
dataRedBoldFont.setFontHeightInPoints((short) 11);
dataRedBoldFont.setBold(true);
dataRedBoldFont.setColor(IndexedColors.RED.getIndex());
rdDataRedBoldStyle = workbook.createCellStyle();
rdDataRedBoldStyle.setFont(dataRedBoldFont);
setBorder(rdDataRedBoldStyle, BorderStyle.THIN, BorderStyle.THIN, BorderStyle.THIN, BorderStyle.THIN);
rdDataRedBoldStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdDataRedBoldStyle.setAlignment(HorizontalAlignment.CENTER);
rdLeftDataRedBoldStyle = workbook.createCellStyle();
rdLeftDataRedBoldStyle.setFont(dataRedBoldFont);
setBorder(rdLeftDataRedBoldStyle, BorderStyle.DOUBLE, BorderStyle.THIN, BorderStyle.DOUBLE, BorderStyle.THIN);
rdLeftDataRedBoldStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdLeftDataRedBoldStyle.setAlignment(HorizontalAlignment.CENTER);
rdRightDataRedBoldStyle = workbook.createCellStyle();
rdRightDataRedBoldStyle.setFont(dataRedBoldFont);
setBorder(rdRightDataRedBoldStyle, BorderStyle.DOUBLE, BorderStyle.THIN, BorderStyle.THIN, BorderStyle.DOUBLE);
rdRightDataRedBoldStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdRightDataRedBoldStyle.setAlignment(HorizontalAlignment.CENTER);
rdBottomDataRedBoldStyle = workbook.createCellStyle();
rdBottomDataRedBoldStyle.setFont(dataRedBoldFont);
setBorder(rdBottomDataRedBoldStyle, BorderStyle.THIN, BorderStyle.DOUBLE, BorderStyle.THIN, BorderStyle.THIN);
rdBottomDataRedBoldStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdBottomDataRedBoldStyle.setAlignment(HorizontalAlignment.CENTER);
rdFooterStyle = workbook.createCellStyle();
rdFooterStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
rdFooterStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rdFooterStyle.setFont(dataBoldFont);
setBorder(rdFooterStyle, BorderStyle.THIN, BorderStyle.DOUBLE, BorderStyle.THIN, BorderStyle.THIN);
rdFooterStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdFooterStyle.setAlignment(HorizontalAlignment.CENTER);
rdLeftFooterStyle = workbook.createCellStyle();
rdLeftFooterStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
rdLeftFooterStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rdLeftFooterStyle.setFont(dataBoldFont);
setBorder(rdLeftFooterStyle, BorderStyle.THIN, BorderStyle.DOUBLE, BorderStyle.DOUBLE, BorderStyle.THIN);
rdLeftFooterStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdLeftFooterStyle.setAlignment(HorizontalAlignment.CENTER);
rdRightFooterStyle = workbook.createCellStyle();
rdRightFooterStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
rdRightFooterStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rdRightFooterStyle.setFont(dataBoldFont);
setBorder(rdRightFooterStyle, BorderStyle.THIN, BorderStyle.DOUBLE, BorderStyle.THIN, BorderStyle.DOUBLE);
rdRightFooterStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdRightFooterStyle.setAlignment(HorizontalAlignment.CENTER);
// footer表单公式样式
rdFooterFormulaStyle = workbook.createCellStyle();
rdFooterFormulaStyle.cloneStyleFrom(rdFooterStyle);
rdFooterFormulaStyle.setDataFormat(workbook.createDataFormat().getFormat("0.00"));
// 百分比样式
rdFormulaPercentageStyle = workbook.createCellStyle();
rdFormulaPercentageStyle.cloneStyleFrom(rdDataStyle);
rdFormulaPercentageStyle.setFillForegroundColor(IndexedColors.LIGHT_ORANGE.getIndex());
rdFormulaPercentageStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rdFormulaPercentageStyle.setDataFormat(workbook.createDataFormat().getFormat("0.00%"));
rdFooterFormulaPercentageStyle = workbook.createCellStyle();
rdFooterFormulaPercentageStyle.cloneStyleFrom(rdFooterStyle);
rdFooterFormulaPercentageStyle.setDataFormat(workbook.createDataFormat().getFormat("0.00%"));
rdFooterRightFormulaStyle = workbook.createCellStyle();
rdFooterRightFormulaStyle.cloneStyleFrom(rdRightFooterStyle);
rdFooterRightFormulaStyle.setDataFormat(workbook.createDataFormat().getFormat("0.00"));
rdInstructionStyle = workbook.createCellStyle();
rdInstructionStyle.setFont(yaheiNormal10Font);
rdInstructionStyle.setWrapText(true);
rdFormulaStyle = workbook.createCellStyle();
rdFormulaStyle.cloneStyleFrom(rdDataStyle);
rdFormulaStyle.setFillForegroundColor(IndexedColors.LIGHT_ORANGE.getIndex());
rdFormulaStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rdFormulaStyle.setDataFormat(workbook.createDataFormat().getFormat("0.00"));
rdRightFormulaStyle = workbook.createCellStyle();
rdRightFormulaStyle.cloneStyleFrom(rdRightDataStyle);
rdRightFormulaStyle.setFillForegroundColor(IndexedColors.LIGHT_ORANGE.getIndex());
rdRightFormulaStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
rdRightFormulaStyle.setDataFormat(workbook.createDataFormat().getFormat("0.00"));
rdFormDataStyle = workbook.createCellStyle();
Font rdFormDataFont = workbook.createFont();
rdFormDataFont.setFontName("微软雅黑");
rdFormDataFont.setFontHeightInPoints((short) 9);
rdFormDataStyle.setFont(rdFormDataFont);
rdFormDataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdFormDataStyle.setAlignment(HorizontalAlignment.LEFT);
rdFormStyle = workbook.createCellStyle();
rdFormStyle.setFont(rdFormDataFont);
rdFormStyle.setVerticalAlignment(VerticalAlignment.CENTER);
rdFormStyle.setAlignment(HorizontalAlignment.LEFT);
// 公式样式
rdFormFormulaStyle = workbook.createCellStyle();
rdFormFormulaStyle.cloneStyleFrom(rdFormDataStyle);
rdFormFormulaStyle.setDataFormat(workbook.createDataFormat().getFormat("0.00"));
}
/** /**
* *
*/ */
@ -223,6 +607,7 @@ public abstract class BaseExcelExporter {
setBorder(leftMergeStyle, BorderStyle.MEDIUM); setBorder(leftMergeStyle, BorderStyle.MEDIUM);
} }
/** /**
* *
*/ */
@ -238,6 +623,29 @@ public abstract class BaseExcelExporter {
style.setRightBorderColor(IndexedColors.BLACK.getIndex()); style.setRightBorderColor(IndexedColors.BLACK.getIndex());
} }
/**
*
*/
protected void setBorder(CellStyle style, BorderStyle topBorderStyle, BorderStyle bottomBorderStyle,
BorderStyle leftBorderStyle, BorderStyle rightBorderStyle) {
if (topBorderStyle != null) {
style.setBorderTop(topBorderStyle);
style.setTopBorderColor(IndexedColors.BLACK.getIndex());
}
if (bottomBorderStyle != null) {
style.setBorderBottom(bottomBorderStyle);
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
}
style.setBorderLeft(leftBorderStyle);
style.setBorderRight(rightBorderStyle);
style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setRightBorderColor(IndexedColors.BLACK.getIndex());
}
/** /**
* *
*/ */
@ -457,9 +865,9 @@ public abstract class BaseExcelExporter {
// 1. 先横向合并前两列A列和B列 // 1. 先横向合并前两列A列和B列
// 在数据区域的第一行创建"人工费"单元格 // 在数据区域的第一行创建"人工费"单元格
Row firstDataRow = getOrCreateRow(sheet, dataStartRow); Row firstDataRow = getOrCreateRow(sheet, dataStartRow);
Cell leftMergeCell = firstDataRow.createCell(0); Cell leftMergeCell = firstDataRow.createCell(firstCol);
leftMergeCell.setCellValue(cellValue); leftMergeCell.setCellValue(cellValue);
leftMergeStyle.setWrapText(true);
// 创建左侧合并单元格的样式 // 创建左侧合并单元格的样式
leftMergeCell.setCellStyle(leftMergeStyle); leftMergeCell.setCellStyle(leftMergeStyle);
@ -544,7 +952,7 @@ public abstract class BaseExcelExporter {
/** /**
* *
*/ */
protected int fillEmptyRow(Sheet sheet, int rowNum, int startCol, int endCol, int fillRowNum,String formula, CellStyle style) { protected int fillEmptyRow(Sheet sheet, int rowNum, int startCol, int endCol, int fillRowNum, String formula, CellStyle style) {
while (rowNum < fillRowNum) { while (rowNum < fillRowNum) {
Row dataRow = sheet.getRow(rowNum); Row dataRow = sheet.getRow(rowNum);
if (dataRow == null) { if (dataRow == null) {
@ -676,4 +1084,225 @@ public abstract class BaseExcelExporter {
style.setLeftBorderColor(borderColor); style.setLeftBorderColor(borderColor);
style.setRightBorderColor(borderColor); style.setRightBorderColor(borderColor);
} }
/**
*
* @param sheet
* @param startRow
* @param endRow
* @param startCol
* @param endCol
* @param fullText
* @param boldSegments [start, end]
* @param baseStyle
* @param rowHeight
*/
protected void createMergedCellWithPartialBold(
Sheet sheet,
int startRow, int endRow,
int startCol, int endCol,
String fullText,
List<TextSegment> boldSegments,
CellStyle baseStyle,
float rowHeight) {
// 1. 创建合并区域
CellRangeAddress mergedRegion = new CellRangeAddress(
startRow, endRow, startCol, endCol);
sheet.addMergedRegion(mergedRegion);
// 2. 创建主单元格
Row mainRow = getOrCreateRow(sheet, startRow);
mainRow.setHeightInPoints(rowHeight);
Cell mainCell = mainRow.createCell(startCol);
// 3. 创建富文本
RichTextString richText = workbook.getCreationHelper()
.createRichTextString(fullText);
// 4. 默认使用基础字体的正常版本
Font normalFont = getNormalFont(baseStyle);
richText.applyFont(0, fullText.length(), normalFont);
// 5. 应用加粗段落
for (TextSegment segment : boldSegments) {
if (segment.isValid() && segment.isWithinBounds(fullText.length())) {
Font boldFont = getBoldFont(baseStyle, segment.getColor());
richText.applyFont(segment.getStart(), segment.getEnd(), boldFont);
}
}
mainCell.setCellValue(richText);
// 6. 设置样式(保留原有的边框、对齐等)
if (baseStyle != null) {
mainCell.setCellStyle(baseStyle);
}
// 7. 修复合并单元格的边框
fixMergedCellBorders(sheet, mergedRegion, baseStyle);
}
/**
*
*/
protected void createMergedCellWithBoldKeywords(
Sheet sheet,
int startRow, int endRow,
int startCol, int endCol,
String text,
List<String> keywords,
CellStyle baseStyle,
float rowHeight) {
List<TextSegment> boldSegments = new ArrayList<>();
for (String keyword : keywords) {
int index = 0;
while (index < text.length()) {
int foundIndex = text.indexOf(keyword, index);
if (foundIndex >= 0) {
boldSegments.add(new TextSegment(foundIndex, foundIndex + keyword.length()));
index = foundIndex + keyword.length();
} else {
break;
}
}
}
// 创建合并单元格
createMergedCellWithPartialBold(sheet, startRow, endRow,
startCol, endCol, text, boldSegments, baseStyle,rowHeight);
}
/**
*
*/
private Font getNormalFont(CellStyle style) {
if (style == null) {
return yaheiNormal10Font;
}
Font existingFont = workbook.getFontAt(style.getFontIndex());
Font normalFont = workbook.createFont();
// 复制所有属性,但取消加粗
normalFont.setFontName(existingFont.getFontName());
normalFont.setFontHeightInPoints(existingFont.getFontHeightInPoints());
normalFont.setColor(existingFont.getColor());
normalFont.setItalic(existingFont.getItalic());
normalFont.setUnderline(existingFont.getUnderline());
return normalFont;
}
/**
*
*/
private Font getBoldFont(CellStyle style, Short color) {
if (style == null) {
Font boldFont = workbook.createFont();
boldFont.setBold(true);
boldFont.setFontName("微软雅黑");
boldFont.setFontHeightInPoints((short) 10);
if (color != null) {
boldFont.setColor(color);
}
return boldFont;
}
Font existingFont = workbook.getFontAt(style.getFontIndex());
Font boldFont = workbook.createFont();
// 复制所有属性,并设置为加粗
boldFont.setFontName(existingFont.getFontName());
boldFont.setFontHeightInPoints(existingFont.getFontHeightInPoints());
boldFont.setBold(true);
if (color != null) {
boldFont.setColor(color);
} else {
boldFont.setColor(existingFont.getColor());
}
boldFont.setItalic(existingFont.getItalic());
boldFont.setUnderline(existingFont.getUnderline());
return boldFont;
}
/**
*
*/
protected static class TextSegment {
private int start; // 起始位置(包含)
private int end; // 结束位置(不包含)
private Short color; // 字体颜色
public TextSegment(int start, int end) {
this.start = start;
this.end = end;
}
public TextSegment(int start, int end, Short color) {
this.start = start;
this.end = end;
this.color = color;
}
public boolean isValid() {
return start >= 0 && end > start;
}
public boolean isWithinBounds(int textLength) {
return start < textLength && end <= textLength;
}
// Getters and Setters
public int getStart() { return start; }
public void setStart(int start) { this.start = start; }
public int getEnd() { return end; }
public void setEnd(int end) { this.end = end; }
public Short getColor() { return color; }
public void setColor(Short color) { this.color = color; }
}
/**
*
*/
protected static class FontStyleConfig {
private short fontSize = 10;
private boolean bold = false;
private Short color = null;
private String fontName = "微软雅黑";
private boolean italic = false;
private boolean underline = false;
// Getters and Setters
public short getFontSize() { return fontSize; }
public void setFontSize(short fontSize) { this.fontSize = fontSize; }
public boolean isBold() { return bold; }
public void setBold(boolean bold) { this.bold = bold; }
public Short getColor() { return color; }
public void setColor(Short color) { this.color = color; }
public String getFontName() { return fontName; }
public void setFontName(String fontName) { this.fontName = fontName; }
public boolean isItalic() { return italic; }
public void setItalic(boolean italic) { this.italic = italic; }
public boolean isUnderline() { return underline; }
public void setUnderline(boolean underline) { this.underline = underline; }
}
} }

@ -0,0 +1,309 @@
package org.dromara.oa.excel;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
/**
* @Author xins
* @Date 2025/12/29 15:25
* @Description:Excel
* *
*/
public class ExcelStyleBuilder {
private final Workbook workbook;
private final Map<String, CellStyle> styleCache = new HashMap<>();
// 常用字体名称
private static final String FONT_SONG = "宋体";
private static final String FONT_YA_HEI = "微软雅黑";
public ExcelStyleBuilder(Workbook workbook) {
this.workbook = workbook;
}
/**
*
*/
public StyleBuilder base() {
return new StyleBuilder();
}
/**
*
*/
public CellStyle getStyle(String key) {
return styleCache.get(key);
}
/**
*
*/
public CellStyle getOrCreate(String key, Consumer<StyleBuilder> styleConfig) {
if (styleCache.containsKey(key)) {
return styleCache.get(key);
}
StyleBuilder builder = new StyleBuilder();
styleConfig.accept(builder);
CellStyle style = builder.build();
styleCache.put(key, style);
return style;
}
/**
*
*/
public Font createFont(Consumer<Font> fontConfig) {
Font font = workbook.createFont();
fontConfig.accept(font);
return font;
}
/**
*
*/
public class StyleBuilder {
private CellStyle style;
private Font font;
public StyleBuilder() {
this.style = workbook.createCellStyle();
}
/**
*
*/
public StyleBuilder font(String fontName, short fontSize, boolean bold) {
this.font = createFont(f -> {
f.setFontName(fontName);
f.setFontHeightInPoints(fontSize);
f.setBold(bold);
});
style.setFont(font);
return this;
}
/**
*
*/
public StyleBuilder song(short fontSize, boolean bold) {
return font(FONT_SONG, fontSize, bold);
}
/**
*
*/
public StyleBuilder yaHei(short fontSize, boolean bold) {
return font(FONT_YA_HEI, fontSize, bold);
}
/**
*
*/
public StyleBuilder fontColor(IndexedColors color) {
if (font == null) {
yaHei((short) 10, false);
}
font.setColor(color.getIndex());
return this;
}
/**
*
*/
public StyleBuilder bgColor(IndexedColors color) {
style.setFillForegroundColor(color.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
return this;
}
/**
*
*/
public StyleBuilder align(HorizontalAlignment horizontal, VerticalAlignment vertical) {
style.setAlignment(horizontal);
style.setVerticalAlignment(vertical);
return this;
}
/**
*
*/
public StyleBuilder center() {
return align(HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
}
/**
*
*/
public StyleBuilder left() {
return align(HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
}
/**
*
*/
public StyleBuilder right() {
return align(HorizontalAlignment.RIGHT, VerticalAlignment.CENTER);
}
/**
*
*/
public StyleBuilder border(BorderStyle borderStyle) {
style.setBorderTop(borderStyle);
style.setBorderBottom(borderStyle);
style.setBorderLeft(borderStyle);
style.setBorderRight(borderStyle);
short color = IndexedColors.BLACK.getIndex();
style.setTopBorderColor(color);
style.setBottomBorderColor(color);
style.setLeftBorderColor(color);
style.setRightBorderColor(color);
return this;
}
/**
*
*/
public StyleBuilder border(BorderStyle top, BorderStyle bottom,
BorderStyle left, BorderStyle right) {
style.setBorderTop(top);
style.setBorderBottom(bottom);
style.setBorderLeft(left);
style.setBorderRight(right);
short color = IndexedColors.BLACK.getIndex();
style.setTopBorderColor(color);
style.setBottomBorderColor(color);
style.setLeftBorderColor(color);
style.setRightBorderColor(color);
return this;
}
/**
*
*/
public StyleBuilder bottomBorder(BorderStyle borderStyle) {
style.setBorderBottom(borderStyle);
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
return this;
}
/**
*
*/
public StyleBuilder dataFormat(String format) {
DataFormat dataFormat = workbook.createDataFormat();
style.setDataFormat(dataFormat.getFormat(format));
return this;
}
/**
*
*/
public StyleBuilder numberFormat() {
return dataFormat("0.00");
}
/**
*
*/
public StyleBuilder percentFormat() {
return dataFormat("0.00%");
}
/**
*
*/
public StyleBuilder moneyFormat() {
return dataFormat("#,##0.00");
}
/**
*
*/
public StyleBuilder wrapText(boolean wrap) {
style.setWrapText(wrap);
return this;
}
/**
*
*/
public StyleBuilder clone(CellStyle source, Consumer<StyleBuilder> customizer) {
this.style.cloneStyleFrom(source);
customizer.accept(this);
return this;
}
/**
*
*/
public CellStyle build() {
return style;
}
/**
*
*/
public CellStyle buildAndCache(String key) {
CellStyle builtStyle = build();
styleCache.put(key, builtStyle);
return builtStyle;
}
}
/**
*
*/
public static class Keys {
// 标题样式
public static final String TITLE = "title";
public static final String SUBTITLE = "subtitle";
// 表单样式
public static final String FORM_LEFT = "form_left";
public static final String FORM_RIGHT = "form_right";
public static final String FORM_FORMULA = "form_formula";
public static final String FORM_PERCENT = "form_percent";
// 表头样式
public static final String HEADER = "header";
public static final String MERGED_HEADER = "merged_header";
// 数据样式
public static final String DATA = "data";
public static final String DATA_LEFT = "data_left";
public static final String DATA_RIGHT = "data_right";
public static final String DATA_BOTTOM = "data_bottom";
public static final String DATA_CENTER = "data_center";
// 特殊格式
public static final String PERCENT = "percent";
public static final String FORMULA = "formula";
public static final String MONEY = "money";
public static final String FOOTER_FORMULA = "footer_formula";
// 备注样式
public static final String REMARK = "remark";
// 合并单元格样式
public static final String LEFT_MERGE = "left_merge";
// 研发预算相关
public static final String RD_COVER_TITLE = "rd_cover_title";
public static final String RD_COVER_SUBTITLE = "rd_cover_subtitle";
public static final String RD_HEADER = "rd_header";
public static final String RD_DATA = "rd_data";
public static final String RD_DATA_BOLD = "rd_data_bold";
public static final String RD_DATA_RED = "rd_data_red";
}
}

@ -676,7 +676,7 @@ public class MarketProjectBudgetExcelExporter extends BaseExcelExporter {
Double reducePeopleNumber = detail.getReducePeopleNumber() != null ? detail.getReducePeopleNumber().doubleValue() : null; Double reducePeopleNumber = detail.getReducePeopleNumber() != null ? detail.getReducePeopleNumber().doubleValue() : null;
Double reduceCumulativeTime = detail.getReduceCumulativeTime() != null ? detail.getReduceCumulativeTime().doubleValue() : null; Double reduceCumulativeTime = detail.getReduceCumulativeTime() != null ? detail.getReduceCumulativeTime().doubleValue() : null;
Double reduceArtificialStandard = detail.getReduceArtificialStandard() != null ? detail.getReduceArtificialStandard().doubleValue() : null; Double reduceArtificialStandard = detail.getReduceArtificialStandard() != null ? detail.getReduceArtificialStandard().doubleValue() : null;
createCell(dataRow, 8, detail.getPersonnelCategory(), dataStyle); createCell(dataRow, 8, detail.getReducePersonnelCategory(), dataStyle);
createNumericCell(dataRow, 9, reducePeopleNumber, dataStyle); createNumericCell(dataRow, 9, reducePeopleNumber, dataStyle);
createNumericCell(dataRow, 10, reduceCumulativeTime, dataStyle); createNumericCell(dataRow, 10, reduceCumulativeTime, dataStyle);
createNumericCell(dataRow, 11, detail.getReduceMonthRate() == null ? BigDecimal.ZERO : createNumericCell(dataRow, 11, detail.getReduceMonthRate() == null ? BigDecimal.ZERO :
@ -860,7 +860,7 @@ public class MarketProjectBudgetExcelExporter extends BaseExcelExporter {
Double reducePeopleNumber = detail.getReducePeopleNumber() != null ? detail.getReducePeopleNumber().doubleValue() : null; Double reducePeopleNumber = detail.getReducePeopleNumber() != null ? detail.getReducePeopleNumber().doubleValue() : null;
Double reduceCumulativeTime = detail.getReduceCumulativeTime() != null ? detail.getReduceCumulativeTime().doubleValue() : null; Double reduceCumulativeTime = detail.getReduceCumulativeTime() != null ? detail.getReduceCumulativeTime().doubleValue() : null;
Double reduceArtificialStandard = detail.getReduceArtificialStandard() != null ? detail.getReduceArtificialStandard().doubleValue() : null; Double reduceArtificialStandard = detail.getReduceArtificialStandard() != null ? detail.getReduceArtificialStandard().doubleValue() : null;
createCell(dataRow, 8, detail.getPersonnelCategory(), dataStyle); createCell(dataRow, 8, detail.getReducePersonnelCategory(), dataStyle);
createNumericCell(dataRow, 9, reducePeopleNumber, dataStyle); createNumericCell(dataRow, 9, reducePeopleNumber, dataStyle);
createNumericCell(dataRow, 10, reduceCumulativeTime, dataStyle); createNumericCell(dataRow, 10, reduceCumulativeTime, dataStyle);
createNumericCell(dataRow, 11, detail.getReduceMonthRate() == null ? BigDecimal.ZERO : createNumericCell(dataRow, 11, detail.getReduceMonthRate() == null ? BigDecimal.ZERO :

@ -0,0 +1,55 @@
package org.dromara.oa.excel;
/**
* @Author xins
* @Date 2025/12/30 17:21
* @Description:
*/
public enum RdBudgetItemEnums {
MATERIAL("材料费", "表2-材料费", "表2-材料费", "H"),
LABOR("人工费", "表3-人工费", "表3-人工费", "H"),
TRAVEL("差旅费", "表4-差旅费", "表4-差旅费", "M"),
TESTING("测试化验加工费", "表5-测试化验加工费","表5-测试化验加工费", "H"),
CONSULTATION("专家咨询费用", "表6-咨询费、设计费","专家费", "I"),
DESIGN("新产品设计费", "表6-咨询费、设计费", "新产品设计费", "H"),
OTHER("其他费用", "表7-其他费用", "表7-其他费用","D");
private final String name;
private final String sheetName;
private final String childSheetName;
private final String sheetPosition;
RdBudgetItemEnums(String name, String sheetName, String childSheetName, String sheetPosition) {
this.name = name;
this.sheetName = sheetName;
this.childSheetName = childSheetName;
this.sheetPosition = sheetPosition;
}
// 获取所有项目名称
public static String[] getAllItemNames() {
RdBudgetItemEnums[] items = values();
String[] names = new String[items.length];
for (int i = 0; i < items.length; i++) {
names[i] = items[i].getName();
}
return names;
}
// getter 方法
public String getName() {
return name;
}
public String getSheetName() {
return sheetName;
}
public String getChildSheetName() {
return childSheetName;
}
public String getSheetPosition() {
return sheetPosition;
}
}
Loading…
Cancel
Save