diff --git a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/report/ProjectOutputReportServiceImpl.java b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/report/ProjectOutputReportServiceImpl.java index cb66f0e..85ead63 100644 --- a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/report/ProjectOutputReportServiceImpl.java +++ b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/report/ProjectOutputReportServiceImpl.java @@ -73,6 +73,7 @@ public class ProjectOutputReportServiceImpl implements ProjectOutputReportServic private static final BigDecimal ZERO_AMOUNT = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); private static final BigDecimal ZERO_RATIO = BigDecimal.ZERO.setScale(4, RoundingMode.HALF_UP); private static final BigDecimal DEFAULT_K_VALUE = new BigDecimal("0.4000"); + private static final BigDecimal FULL_RATIO = new BigDecimal("1.0000"); private static final String SORT_OUTPUT_DESC = "output_desc"; private static final String SORT_OUTPUT_ASC = "output_asc"; @@ -155,43 +156,21 @@ public class ProjectOutputReportServiceImpl implements ProjectOutputReportServic throws IOException { ProjectPlanningDO anchorPlanning = validateMajorPlanning(reqVO.getPlanningId()); ProjectDO project = validateProjectExists(anchorPlanning.getProjectId()); - Integer reportYear = resolveReportYear(anchorPlanning); - List planningList = sortPlanningList(getProjectPlanningScope(anchorPlanning, true)); + Integer reportYear = LocalDate.now().getYear(); + List planningList = sortPlanningList(projectPlanningMapper.selectListByProjectId(project.getId())); Map> quarterMap = getQuarterMap(planningList); - Map outputSplitMap = getOutputSplitMap(planningList); + Map outputSplitMap = getExistingOutputSplitMap(planningList); ProjectQuarterOutputExcelBuilder.ExportData data = new ProjectQuarterOutputExcelBuilder.ExportData(); + data.setProjectCode(""); data.setProjectName(project.getProjectName()); data.setYear(reportYear); - - List rows = new ArrayList<>(); - for (ProjectPlanningDO planning : planningList) { - QuarterSummary quarterSummary = buildQuarterSummary(planning, quarterMap.get(planning.getId()), reportYear); - ProjectOutputSplitDO outputSplit = outputSplitMap.get(planning.getId()); - if (outputSplit == null) { - continue; - } - ProjectQuarterOutputExcelBuilder.QuarterRow row = new ProjectQuarterOutputExcelBuilder.QuarterRow(); - row.setOwnershipType(planning.getOwnershipType()); - row.setPlanningContent(planning.getPlanningContent()); - row.setHistoricalIssuedRatio(quarterSummary.getHistoricalIssuedRatio()); - row.setCurrentYearRatio(quarterSummary.getCurrentYearRatio()); - row.setPendingRatio(quarterSummary.getPendingRatio()); - row.setQuarterOneAmount(quarterSummary.getQuarterOneAmount()); - row.setQuarterTwoAmount(quarterSummary.getQuarterTwoAmount()); - row.setQuarterThreeAmount(quarterSummary.getQuarterThreeAmount()); - row.setQuarterFourAmount(quarterSummary.getQuarterFourAmount()); - row.setYearTotalAmount(quarterSummary.getYearTotalAmount()); - row.setProjectLeadAmount(multiplyAmount(quarterSummary.getYearTotalAmount(), outputSplit.getProjectLeadRatio())); - row.setOfficeAmount(multiplyAmount(quarterSummary.getYearTotalAmount(), outputSplit.getOfficeRatio())); - row.setSpecialtySummaryText(buildSpecialtySummary(outputSplit, quarterSummary.getYearTotalAmount())); - row.setAssessmentOutputValue(amount(planning.getAssessmentOutputValue())); - rows.add(row); - } - data.setRows(rows); + data.setCenterSignerLabel("设计中心相关负责人(签名):"); + data.setProjectSignerLabel("项目经理/工程负责人(签名):"); + data.setRows(buildProjectQuarterOutputRows(planningList, quarterMap, outputSplitMap, reportYear)); projectQuarterOutputExcelBuilder.writeWorkbook(response, - buildFileName(project.getProjectName(), "项目级年度季度计取表"), + buildFileName(project.getProjectName(), "专业间项目考核产值年度季度计取表"), projectQuarterOutputExcelBuilder.build(data)); } @@ -548,6 +527,179 @@ public class ProjectOutputReportServiceImpl implements ProjectOutputReportServic .collect(Collectors.toList()); } + private List buildProjectQuarterOutputRows( + List planningList, Map> quarterMap, + Map outputSplitMap, Integer reportYear) { + if (planningList == null || planningList.isEmpty()) { + return Collections.emptyList(); + } + + List rows = new ArrayList<>(); + BigDecimal totalAssessmentOutputValue = ZERO_AMOUNT; + BigDecimal totalQuarterOneAmount = ZERO_AMOUNT; + BigDecimal totalQuarterTwoAmount = ZERO_AMOUNT; + BigDecimal totalQuarterThreeAmount = ZERO_AMOUNT; + BigDecimal totalQuarterFourAmount = ZERO_AMOUNT; + BigDecimal totalYearAmount = ZERO_AMOUNT; + BigDecimal totalProjectLeadAssessment = ZERO_AMOUNT; + BigDecimal totalProjectLeadQuarterOneAmount = ZERO_AMOUNT; + BigDecimal totalProjectLeadQuarterTwoAmount = ZERO_AMOUNT; + BigDecimal totalProjectLeadQuarterThreeAmount = ZERO_AMOUNT; + BigDecimal totalProjectLeadQuarterFourAmount = ZERO_AMOUNT; + BigDecimal totalProjectLeadYearAmount = ZERO_AMOUNT; + BigDecimal totalOfficeAssessment = ZERO_AMOUNT; + BigDecimal totalOfficeQuarterOneAmount = ZERO_AMOUNT; + BigDecimal totalOfficeQuarterTwoAmount = ZERO_AMOUNT; + BigDecimal totalOfficeQuarterThreeAmount = ZERO_AMOUNT; + BigDecimal totalOfficeQuarterFourAmount = ZERO_AMOUNT; + BigDecimal totalOfficeYearAmount = ZERO_AMOUNT; + BigDecimal totalArchAssessment = ZERO_AMOUNT; + BigDecimal totalDecorAssessment = ZERO_AMOUNT; + BigDecimal totalStructAssessment = ZERO_AMOUNT; + BigDecimal totalWaterAssessment = ZERO_AMOUNT; + BigDecimal totalHvacAssessment = ZERO_AMOUNT; + BigDecimal totalElecAssessment = ZERO_AMOUNT; + int serialNo = 1; + + for (ProjectPlanningDO planning : planningList) { + QuarterSummary quarterSummary = buildQuarterSummary(planning, quarterMap.get(planning.getId()), reportYear); + ProjectOutputSplitDO outputSplit = resolveQuarterOutputSplit(planning, outputSplitMap); + BigDecimal assessmentOutputValue = amount(planning.getAssessmentOutputValue()); + BigDecimal quarterOneAmount = amount(quarterSummary.getQuarterOneAmount()); + BigDecimal quarterTwoAmount = amount(quarterSummary.getQuarterTwoAmount()); + BigDecimal quarterThreeAmount = amount(quarterSummary.getQuarterThreeAmount()); + BigDecimal quarterFourAmount = amount(quarterSummary.getQuarterFourAmount()); + BigDecimal yearTotalAmount = amount(quarterSummary.getYearTotalAmount()); + + BigDecimal projectLeadRatio = ratio(outputSplit.getProjectLeadRatio()); + BigDecimal officeRatio = ratio(outputSplit.getOfficeRatio()); + BigDecimal projectLeadAssessment = multiplyAmount(assessmentOutputValue, projectLeadRatio); + BigDecimal projectLeadQuarterOneAmount = multiplyAmount(quarterOneAmount, projectLeadRatio); + BigDecimal projectLeadQuarterTwoAmount = multiplyAmount(quarterTwoAmount, projectLeadRatio); + BigDecimal projectLeadQuarterThreeAmount = multiplyAmount(quarterThreeAmount, projectLeadRatio); + BigDecimal projectLeadQuarterFourAmount = multiplyAmount(quarterFourAmount, projectLeadRatio); + BigDecimal projectLeadYearAmount = multiplyAmount(yearTotalAmount, projectLeadRatio); + + BigDecimal officeAssessment = multiplyAmount(assessmentOutputValue, officeRatio); + BigDecimal officeQuarterOneAmount = multiplyAmount(quarterOneAmount, officeRatio); + BigDecimal officeQuarterTwoAmount = multiplyAmount(quarterTwoAmount, officeRatio); + BigDecimal officeQuarterThreeAmount = multiplyAmount(quarterThreeAmount, officeRatio); + BigDecimal officeQuarterFourAmount = multiplyAmount(quarterFourAmount, officeRatio); + BigDecimal officeYearAmount = multiplyAmount(yearTotalAmount, officeRatio); + + BigDecimal archRatio = ratio(outputSplit.getArchRatio()); + BigDecimal decorRatio = ratio(outputSplit.getDecorRatio()); + BigDecimal structRatio = ratio(outputSplit.getStructRatio()); + BigDecimal waterRatio = ratio(outputSplit.getWaterRatio()); + BigDecimal hvacRatio = ratio(outputSplit.getHvacRatio()); + BigDecimal elecRatio = ratio(outputSplit.getElecRatio()); + BigDecimal archAssessment = multiplyAmount(officeAssessment, archRatio); + BigDecimal decorAssessment = multiplyAmount(officeAssessment, decorRatio); + BigDecimal structAssessment = multiplyAmount(officeAssessment, structRatio); + BigDecimal waterAssessment = multiplyAmount(officeAssessment, waterRatio); + BigDecimal hvacAssessment = multiplyAmount(officeAssessment, hvacRatio); + BigDecimal elecAssessment = multiplyAmount(officeAssessment, elecRatio); + + ProjectQuarterOutputExcelBuilder.QuarterRow row = new ProjectQuarterOutputExcelBuilder.QuarterRow(); + row.setSerialNo(serialNo++); + row.setOutputType(resolveBudgetCategoryLabel(planning.getOwnershipType())); + row.setDesignContent(defaultString(planning.getPlanningContent())); + row.setQuarterOneAmountWan(amountToWan(quarterOneAmount)); + row.setQuarterTwoAmountWan(amountToWan(quarterTwoAmount)); + row.setQuarterThreeAmountWan(amountToWan(quarterThreeAmount)); + row.setQuarterFourAmountWan(amountToWan(quarterFourAmount)); + row.setYearTotalAmountWan(amountToWan(yearTotalAmount)); + row.setProjectLeadRatio(projectLeadRatio); + row.setProjectLeadAssessmentOutputWan(amountToWan(projectLeadAssessment)); + row.setProjectLeadQuarterOneAmountWan(amountToWan(projectLeadQuarterOneAmount)); + row.setProjectLeadQuarterTwoAmountWan(amountToWan(projectLeadQuarterTwoAmount)); + row.setProjectLeadQuarterThreeAmountWan(amountToWan(projectLeadQuarterThreeAmount)); + row.setProjectLeadQuarterFourAmountWan(amountToWan(projectLeadQuarterFourAmount)); + row.setProjectLeadYearTotalAmountWan(amountToWan(projectLeadYearAmount)); + row.setOfficeRatio(officeRatio); + row.setOfficeAssessmentOutputWan(amountToWan(officeAssessment)); + row.setOfficeQuarterOneAmountWan(amountToWan(officeQuarterOneAmount)); + row.setOfficeQuarterTwoAmountWan(amountToWan(officeQuarterTwoAmount)); + row.setOfficeQuarterThreeAmountWan(amountToWan(officeQuarterThreeAmount)); + row.setOfficeQuarterFourAmountWan(amountToWan(officeQuarterFourAmount)); + row.setOfficeYearTotalAmountWan(amountToWan(officeYearAmount)); + row.setArchRatio(archRatio); + row.setDecorRatio(decorRatio); + row.setStructRatio(structRatio); + row.setWaterRatio(waterRatio); + row.setHvacRatio(hvacRatio); + row.setElecRatio(elecRatio); + row.setArchAssessmentOutputWan(amountToWan(archAssessment)); + row.setDecorAssessmentOutputWan(amountToWan(decorAssessment)); + row.setStructAssessmentOutputWan(amountToWan(structAssessment)); + row.setWaterAssessmentOutputWan(amountToWan(waterAssessment)); + row.setHvacAssessmentOutputWan(amountToWan(hvacAssessment)); + row.setElecAssessmentOutputWan(amountToWan(elecAssessment)); + rows.add(row); + + totalAssessmentOutputValue = totalAssessmentOutputValue.add(assessmentOutputValue).setScale(2, RoundingMode.HALF_UP); + totalQuarterOneAmount = totalQuarterOneAmount.add(quarterOneAmount).setScale(2, RoundingMode.HALF_UP); + totalQuarterTwoAmount = totalQuarterTwoAmount.add(quarterTwoAmount).setScale(2, RoundingMode.HALF_UP); + totalQuarterThreeAmount = totalQuarterThreeAmount.add(quarterThreeAmount).setScale(2, RoundingMode.HALF_UP); + totalQuarterFourAmount = totalQuarterFourAmount.add(quarterFourAmount).setScale(2, RoundingMode.HALF_UP); + totalYearAmount = totalYearAmount.add(yearTotalAmount).setScale(2, RoundingMode.HALF_UP); + totalProjectLeadAssessment = totalProjectLeadAssessment.add(projectLeadAssessment).setScale(2, RoundingMode.HALF_UP); + totalProjectLeadQuarterOneAmount = totalProjectLeadQuarterOneAmount.add(projectLeadQuarterOneAmount) + .setScale(2, RoundingMode.HALF_UP); + totalProjectLeadQuarterTwoAmount = totalProjectLeadQuarterTwoAmount.add(projectLeadQuarterTwoAmount) + .setScale(2, RoundingMode.HALF_UP); + totalProjectLeadQuarterThreeAmount = totalProjectLeadQuarterThreeAmount.add(projectLeadQuarterThreeAmount) + .setScale(2, RoundingMode.HALF_UP); + totalProjectLeadQuarterFourAmount = totalProjectLeadQuarterFourAmount.add(projectLeadQuarterFourAmount) + .setScale(2, RoundingMode.HALF_UP); + totalProjectLeadYearAmount = totalProjectLeadYearAmount.add(projectLeadYearAmount).setScale(2, RoundingMode.HALF_UP); + totalOfficeAssessment = totalOfficeAssessment.add(officeAssessment).setScale(2, RoundingMode.HALF_UP); + totalOfficeQuarterOneAmount = totalOfficeQuarterOneAmount.add(officeQuarterOneAmount).setScale(2, RoundingMode.HALF_UP); + totalOfficeQuarterTwoAmount = totalOfficeQuarterTwoAmount.add(officeQuarterTwoAmount).setScale(2, RoundingMode.HALF_UP); + totalOfficeQuarterThreeAmount = totalOfficeQuarterThreeAmount.add(officeQuarterThreeAmount) + .setScale(2, RoundingMode.HALF_UP); + totalOfficeQuarterFourAmount = totalOfficeQuarterFourAmount.add(officeQuarterFourAmount) + .setScale(2, RoundingMode.HALF_UP); + totalOfficeYearAmount = totalOfficeYearAmount.add(officeYearAmount).setScale(2, RoundingMode.HALF_UP); + totalArchAssessment = totalArchAssessment.add(archAssessment).setScale(2, RoundingMode.HALF_UP); + totalDecorAssessment = totalDecorAssessment.add(decorAssessment).setScale(2, RoundingMode.HALF_UP); + totalStructAssessment = totalStructAssessment.add(structAssessment).setScale(2, RoundingMode.HALF_UP); + totalWaterAssessment = totalWaterAssessment.add(waterAssessment).setScale(2, RoundingMode.HALF_UP); + totalHvacAssessment = totalHvacAssessment.add(hvacAssessment).setScale(2, RoundingMode.HALF_UP); + totalElecAssessment = totalElecAssessment.add(elecAssessment).setScale(2, RoundingMode.HALF_UP); + } + + ProjectQuarterOutputExcelBuilder.QuarterRow totalRow = new ProjectQuarterOutputExcelBuilder.QuarterRow(); + totalRow.setTotalRow(true); + totalRow.setQuarterOneAmountWan(amountToWan(totalQuarterOneAmount)); + totalRow.setQuarterTwoAmountWan(amountToWan(totalQuarterTwoAmount)); + totalRow.setQuarterThreeAmountWan(amountToWan(totalQuarterThreeAmount)); + totalRow.setQuarterFourAmountWan(amountToWan(totalQuarterFourAmount)); + totalRow.setYearTotalAmountWan(amountToWan(totalYearAmount)); + totalRow.setProjectLeadRatio(divideAmountRatio(totalProjectLeadAssessment, totalAssessmentOutputValue)); + totalRow.setProjectLeadAssessmentOutputWan(amountToWan(totalProjectLeadAssessment)); + totalRow.setProjectLeadQuarterOneAmountWan(amountToWan(totalProjectLeadQuarterOneAmount)); + totalRow.setProjectLeadQuarterTwoAmountWan(amountToWan(totalProjectLeadQuarterTwoAmount)); + totalRow.setProjectLeadQuarterThreeAmountWan(amountToWan(totalProjectLeadQuarterThreeAmount)); + totalRow.setProjectLeadQuarterFourAmountWan(amountToWan(totalProjectLeadQuarterFourAmount)); + totalRow.setProjectLeadYearTotalAmountWan(amountToWan(totalProjectLeadYearAmount)); + totalRow.setOfficeRatio(divideAmountRatio(totalOfficeAssessment, totalAssessmentOutputValue)); + totalRow.setOfficeAssessmentOutputWan(amountToWan(totalOfficeAssessment)); + totalRow.setOfficeQuarterOneAmountWan(amountToWan(totalOfficeQuarterOneAmount)); + totalRow.setOfficeQuarterTwoAmountWan(amountToWan(totalOfficeQuarterTwoAmount)); + totalRow.setOfficeQuarterThreeAmountWan(amountToWan(totalOfficeQuarterThreeAmount)); + totalRow.setOfficeQuarterFourAmountWan(amountToWan(totalOfficeQuarterFourAmount)); + totalRow.setOfficeYearTotalAmountWan(amountToWan(totalOfficeYearAmount)); + totalRow.setArchAssessmentOutputWan(amountToWan(totalArchAssessment)); + totalRow.setDecorAssessmentOutputWan(amountToWan(totalDecorAssessment)); + totalRow.setStructAssessmentOutputWan(amountToWan(totalStructAssessment)); + totalRow.setWaterAssessmentOutputWan(amountToWan(totalWaterAssessment)); + totalRow.setHvacAssessmentOutputWan(amountToWan(totalHvacAssessment)); + totalRow.setElecAssessmentOutputWan(amountToWan(totalElecAssessment)); + rows.add(totalRow); + return rows; + } + private List buildProjectBudgetRows(List planningList) { if (planningList == null || planningList.isEmpty()) { return Collections.emptyList(); @@ -795,6 +947,38 @@ public class ProjectOutputReportServiceImpl implements ProjectOutputReportServic .collect(Collectors.toList()); } + private ProjectOutputSplitDO resolveQuarterOutputSplit(ProjectPlanningDO planning, + Map outputSplitMap) { + if (planning == null) { + return buildQuarterOutputDefaultSplit(null); + } + ProjectOutputSplitDO outputSplit = outputSplitMap == null ? null : outputSplitMap.get(planning.getId()); + if (outputSplit != null) { + return outputSplit; + } + return buildQuarterOutputDefaultSplit(planning); + } + + private ProjectOutputSplitDO buildQuarterOutputDefaultSplit(ProjectPlanningDO planning) { + ProjectOutputSplitDO outputSplit = new ProjectOutputSplitDO(); + if (planning != null) { + outputSplit.setProjectId(planning.getProjectId()); + outputSplit.setPlanningId(planning.getId()); + outputSplit.setYear(resolveReportYear(planning)); + } + outputSplit.setProjectLeadRatio(ZERO_RATIO); + boolean majorPlanning = planning != null && ProjectPlanningBizTypeConstants.isMajor(planning.getOwnershipType()); + outputSplit.setOfficeRatio(majorPlanning ? FULL_RATIO : ZERO_RATIO); + outputSplit.setArchRatio(majorPlanning ? FULL_RATIO : ZERO_RATIO); + outputSplit.setDecorRatio(ZERO_RATIO); + outputSplit.setStructRatio(ZERO_RATIO); + outputSplit.setWaterRatio(ZERO_RATIO); + outputSplit.setElecRatio(ZERO_RATIO); + outputSplit.setHvacRatio(ZERO_RATIO); + outputSplit.setDigitalRatio(ZERO_RATIO); + return outputSplit; + } + private int designPartOrder(String designPart) { if (Objects.equals(designPart, ProjectPlanningBizTypeConstants.DESIGN_PART_REAL_ESTATE)) { return 1; @@ -847,6 +1031,14 @@ public class ProjectOutputReportServiceImpl implements ProjectOutputReportServic return map; } + private Map getExistingOutputSplitMap(Collection planningList) { + if (planningList == null || planningList.isEmpty()) { + return Collections.emptyMap(); + } + List planningIds = planningList.stream().map(ProjectPlanningDO::getId).collect(Collectors.toList()); + return projectOutputSplitService.getProjectOutputSplitMap(planningIds); + } + private Map> getRoleSplitMap(Collection planningList) { if (planningList == null || planningList.isEmpty()) { return Collections.emptyMap(); @@ -1199,6 +1391,14 @@ public class ProjectOutputReportServiceImpl implements ProjectOutputReportServic return ratio(left).add(ratio(right)).setScale(4, RoundingMode.HALF_UP); } + private BigDecimal divideAmountRatio(BigDecimal numerator, BigDecimal denominator) { + BigDecimal denominatorAmount = amount(denominator); + if (denominatorAmount.compareTo(BigDecimal.ZERO) == 0) { + return ZERO_RATIO; + } + return amount(numerator).divide(denominatorAmount, 4, RoundingMode.HALF_UP); + } + private String percentText(BigDecimal value) { return ratio(value).multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP) + "%"; } diff --git a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/report/builder/ProjectQuarterOutputExcelBuilder.java b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/report/builder/ProjectQuarterOutputExcelBuilder.java index 5922c36..3608506 100644 --- a/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/report/builder/ProjectQuarterOutputExcelBuilder.java +++ b/lyzsys-module-tjt/src/main/java/cn/iocoder/lyzsys/module/tjt/service/report/builder/ProjectQuarterOutputExcelBuilder.java @@ -2,86 +2,282 @@ package cn.iocoder.lyzsys.module.tjt.service.report.builder; import lombok.Data; import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.stereotype.Component; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.List; @Component public class ProjectQuarterOutputExcelBuilder extends AbstractProjectOutputExcelBuilder { + private static final String SHEET_NAME = "专业间项目考核产值年度季度计取表"; + private static final String SHEET_FALLBACK_NAME = "项目级年度季度计取"; + private static final String SHEET_TITLE = "专业间项目考核产值年度/季度计取表"; + private static final String TOTAL_LABEL = "合计"; + private static final String SUMMARY_PLACEHOLDER = "/"; + public Workbook build(ExportData data) { Workbook workbook = createWorkbook(); - Sheet sheet = createSheet(workbook, "年度季度计取", "年度季度计取"); - setColumnWidths(sheet, 8, 24, 12, 22, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12); + Sheet sheet = createSheet(workbook, SHEET_NAME, SHEET_FALLBACK_NAME); + setColumnWidths(sheet, + 10, 24, 16, 20, 12, 12, 12, 12, 14, + 10, 14, 12, 12, 12, 12, 14, + 10, 14, 12, 12, 12, 12, 14, + 10, 10, 10, 10, 10, 10, + 12, 12, 12, 12, 12, 12); CellStyle titleStyle = createTitleStyle(workbook); - CellStyle infoStyle = createInfoStyle(workbook); - CellStyle headerStyle = createHeaderStyle(workbook); - CellStyle cellStyle = createCellStyle(workbook); + CellStyle baseHeaderStyle = createHeaderStyle(workbook); + CellStyle headerStyle = createDerivedStyle(workbook, baseHeaderStyle, + IndexedColors.LEMON_CHIFFON, HorizontalAlignment.CENTER, true, (short) 10); + CellStyle cellStyle = createDerivedStyle(workbook, createCellStyle(workbook), + null, HorizontalAlignment.CENTER, false, (short) 10); + CellStyle leftCellStyle = createDerivedStyle(workbook, cellStyle, + null, HorizontalAlignment.LEFT, false, (short) 10); + CellStyle totalStyle = createDerivedStyle(workbook, baseHeaderStyle, + IndexedColors.GOLD, HorizontalAlignment.CENTER, true, (short) 10); + CellStyle totalLeftStyle = createDerivedStyle(workbook, totalStyle, + IndexedColors.GOLD, HorizontalAlignment.LEFT, true, (short) 10); + CellStyle signatureStyle = createDerivedStyle(workbook, createInfoStyle(workbook), + null, HorizontalAlignment.LEFT, false, (short) 10); int rowIndex = 0; - rowIndex = writeMergedTitleRow(sheet, rowIndex, "项目考核产值年度/季度计取表", titleStyle, 15); + rowIndex = writeMergedTitleRow(sheet, rowIndex, SHEET_TITLE, titleStyle, 34); + rowIndex = buildHeader(sheet, rowIndex, data, headerStyle, cellStyle); - Row infoRow = sheet.createRow(rowIndex++); - writeLabelValue(infoRow, 0, 1, "项目名称", data.getProjectName(), infoStyle); - writeLabelValue(infoRow, 4, 5, "年度", data.getYear(), infoStyle); - - rowIndex = writeRow(sheet, rowIndex, headerStyle, (Object[]) new String[]{ - "序号", "项目名称", "归属类型", "规划内容", "往年已发放比例", "本年度发放比例", - "未发放比例", "一季度", "二季度", "三季度", "四季度", "本年度小计", - "项目经理/项目负责人", "专业所合计", "专业分配说明", "考核产值" - }); - - int serialNo = 1; - for (QuarterRow rowData : data.getRows()) { - Row row = sheet.createRow(rowIndex++); - setText(row, 0, serialNo++, cellStyle); - setText(row, 1, data.getProjectName(), cellStyle); - setText(row, 2, rowData.getOwnershipType(), cellStyle); - setText(row, 3, rowData.getPlanningContent(), cellStyle); - setText(row, 4, percentText(rowData.getHistoricalIssuedRatio()), cellStyle); - setText(row, 5, percentText(rowData.getCurrentYearRatio()), cellStyle); - setText(row, 6, percentText(rowData.getPendingRatio()), cellStyle); - setText(row, 7, text(rowData.getQuarterOneAmount()), cellStyle); - setText(row, 8, text(rowData.getQuarterTwoAmount()), cellStyle); - setText(row, 9, text(rowData.getQuarterThreeAmount()), cellStyle); - setText(row, 10, text(rowData.getQuarterFourAmount()), cellStyle); - setText(row, 11, text(rowData.getYearTotalAmount()), cellStyle); - setText(row, 12, text(rowData.getProjectLeadAmount()), cellStyle); - setText(row, 13, text(rowData.getOfficeAmount()), cellStyle); - setText(row, 14, rowData.getSpecialtySummaryText(), cellStyle); - setText(row, 15, text(rowData.getAssessmentOutputValue()), cellStyle); + if (data.getRows() != null) { + for (QuarterRow rowData : data.getRows()) { + if (rowData == null) { + continue; + } + if (rowData.isTotalRow()) { + writeTotalRow(sheet, rowIndex++, data, rowData, totalStyle, totalLeftStyle); + continue; + } + writeDetailRow(sheet, rowIndex++, data, rowData, cellStyle, leftCellStyle); + } } + + writeSignatureRow(sheet, rowIndex, data, signatureStyle); return workbook; } + private int buildHeader(Sheet sheet, int rowIndex, ExportData data, + CellStyle headerStyle, CellStyle valueStyle) { + int firstRow = rowIndex; + sheet.createRow(firstRow); + sheet.createRow(firstRow + 1); + sheet.createRow(firstRow + 2); + + setMergedRegionText(sheet, firstRow, firstRow + 1, 0, 0, "工程编号", headerStyle); + setMergedRegionText(sheet, firstRow, firstRow + 1, 1, 1, safeText(data.getProjectCode()), valueStyle); + setText(sheet.getRow(firstRow + 2), 0, "序号", headerStyle); + setText(sheet.getRow(firstRow + 2), 1, "项目名称", headerStyle); + + setMergedRegionText(sheet, firstRow, firstRow + 1, 2, 3, "类别", headerStyle); + setText(sheet.getRow(firstRow + 2), 2, "产值类型", headerStyle); + setText(sheet.getRow(firstRow + 2), 3, "设计内容", headerStyle); + + setMergedRegionText(sheet, firstRow, firstRow + 1, 4, 8, "本年度项目考核产值(万元)", headerStyle); + setText(sheet.getRow(firstRow + 2), 4, "一季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 5, "二季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 6, "三季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 7, "四季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 8, "本年度小计", headerStyle); + + setMergedRegionText(sheet, firstRow, firstRow, 9, 15, "项目经理 / 工程负责人年度 / 季度项目考核产值", headerStyle); + setMergedRegionText(sheet, firstRow + 1, firstRow + 1, 9, 10, "项总 / 工程负责人", headerStyle); + setMergedRegionText(sheet, firstRow + 1, firstRow + 1, 11, 15, "考核产值(万元)", headerStyle); + setText(sheet.getRow(firstRow + 2), 9, "占比", headerStyle); + setText(sheet.getRow(firstRow + 2), 10, "总考核产值", headerStyle); + setText(sheet.getRow(firstRow + 2), 11, "一季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 12, "二季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 13, "三季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 14, "四季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 15, "本年度总计", headerStyle); + + setMergedRegionText(sheet, firstRow, firstRow, 16, 22, "六大专业年度 / 季度项目考核产值合计", headerStyle); + setMergedRegionText(sheet, firstRow + 1, firstRow + 1, 16, 17, "六大专业", headerStyle); + setMergedRegionText(sheet, firstRow + 1, firstRow + 1, 18, 22, "考核产值(万元)", headerStyle); + setText(sheet.getRow(firstRow + 2), 16, "占比", headerStyle); + setText(sheet.getRow(firstRow + 2), 17, "总考核产值", headerStyle); + setText(sheet.getRow(firstRow + 2), 18, "一季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 19, "二季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 20, "三季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 21, "四季度", headerStyle); + setText(sheet.getRow(firstRow + 2), 22, "本年度总计", headerStyle); + + setMergedRegionText(sheet, firstRow, firstRow, 23, 34, "各专业年度 / 季度项目考核产值", headerStyle); + setMergedRegionText(sheet, firstRow + 1, firstRow + 1, 23, 28, "各专业考核产值占比", headerStyle); + setMergedRegionText(sheet, firstRow + 1, firstRow + 1, 29, 34, "各专业考核产值", headerStyle); + setText(sheet.getRow(firstRow + 2), 23, "建筑", headerStyle); + setText(sheet.getRow(firstRow + 2), 24, "精装", headerStyle); + setText(sheet.getRow(firstRow + 2), 25, "结构", headerStyle); + setText(sheet.getRow(firstRow + 2), 26, "给排水", headerStyle); + setText(sheet.getRow(firstRow + 2), 27, "暖通", headerStyle); + setText(sheet.getRow(firstRow + 2), 28, "电气", headerStyle); + setText(sheet.getRow(firstRow + 2), 29, "建筑", headerStyle); + setText(sheet.getRow(firstRow + 2), 30, "精装", headerStyle); + setText(sheet.getRow(firstRow + 2), 31, "结构", headerStyle); + setText(sheet.getRow(firstRow + 2), 32, "给排水", headerStyle); + setText(sheet.getRow(firstRow + 2), 33, "暖通", headerStyle); + setText(sheet.getRow(firstRow + 2), 34, "电气", headerStyle); + return rowIndex + 3; + } + + private void writeDetailRow(Sheet sheet, int rowIndex, ExportData data, QuarterRow rowData, + CellStyle cellStyle, CellStyle leftCellStyle) { + Row row = sheet.createRow(rowIndex); + setText(row, 0, rowData.getSerialNo(), cellStyle); + setText(row, 1, safeText(data.getProjectName()), cellStyle); + setText(row, 2, safeText(rowData.getOutputType()), cellStyle); + setText(row, 3, safeText(rowData.getDesignContent()), leftCellStyle); + setText(row, 4, textOrBlank(rowData.getQuarterOneAmountWan()), cellStyle); + setText(row, 5, textOrBlank(rowData.getQuarterTwoAmountWan()), cellStyle); + setText(row, 6, textOrBlank(rowData.getQuarterThreeAmountWan()), cellStyle); + setText(row, 7, textOrBlank(rowData.getQuarterFourAmountWan()), cellStyle); + setText(row, 8, textOrBlank(rowData.getYearTotalAmountWan()), cellStyle); + setText(row, 9, percentTextOrBlank(rowData.getProjectLeadRatio()), cellStyle); + setText(row, 10, textOrBlank(rowData.getProjectLeadAssessmentOutputWan()), cellStyle); + setText(row, 11, textOrBlank(rowData.getProjectLeadQuarterOneAmountWan()), cellStyle); + setText(row, 12, textOrBlank(rowData.getProjectLeadQuarterTwoAmountWan()), cellStyle); + setText(row, 13, textOrBlank(rowData.getProjectLeadQuarterThreeAmountWan()), cellStyle); + setText(row, 14, textOrBlank(rowData.getProjectLeadQuarterFourAmountWan()), cellStyle); + setText(row, 15, textOrBlank(rowData.getProjectLeadYearTotalAmountWan()), cellStyle); + setText(row, 16, percentTextOrBlank(rowData.getOfficeRatio()), cellStyle); + setText(row, 17, textOrBlank(rowData.getOfficeAssessmentOutputWan()), cellStyle); + setText(row, 18, textOrBlank(rowData.getOfficeQuarterOneAmountWan()), cellStyle); + setText(row, 19, textOrBlank(rowData.getOfficeQuarterTwoAmountWan()), cellStyle); + setText(row, 20, textOrBlank(rowData.getOfficeQuarterThreeAmountWan()), cellStyle); + setText(row, 21, textOrBlank(rowData.getOfficeQuarterFourAmountWan()), cellStyle); + setText(row, 22, textOrBlank(rowData.getOfficeYearTotalAmountWan()), cellStyle); + setText(row, 23, percentTextOrBlank(rowData.getArchRatio()), cellStyle); + setText(row, 24, percentTextOrBlank(rowData.getDecorRatio()), cellStyle); + setText(row, 25, percentTextOrBlank(rowData.getStructRatio()), cellStyle); + setText(row, 26, percentTextOrBlank(rowData.getWaterRatio()), cellStyle); + setText(row, 27, percentTextOrBlank(rowData.getHvacRatio()), cellStyle); + setText(row, 28, percentTextOrBlank(rowData.getElecRatio()), cellStyle); + setText(row, 29, textOrBlank(rowData.getArchAssessmentOutputWan()), cellStyle); + setText(row, 30, textOrBlank(rowData.getDecorAssessmentOutputWan()), cellStyle); + setText(row, 31, textOrBlank(rowData.getStructAssessmentOutputWan()), cellStyle); + setText(row, 32, textOrBlank(rowData.getWaterAssessmentOutputWan()), cellStyle); + setText(row, 33, textOrBlank(rowData.getHvacAssessmentOutputWan()), cellStyle); + setText(row, 34, textOrBlank(rowData.getElecAssessmentOutputWan()), cellStyle); + } + + private void writeTotalRow(Sheet sheet, int rowIndex, ExportData data, QuarterRow rowData, + CellStyle totalStyle, CellStyle totalLeftStyle) { + Row row = sheet.createRow(rowIndex); + setText(row, 0, "", totalStyle); + setText(row, 1, safeText(data.getProjectName()), totalStyle); + setMergedRegionText(sheet, rowIndex, rowIndex, 2, 3, TOTAL_LABEL, totalStyle); + setText(row, 4, textOrBlank(rowData.getQuarterOneAmountWan()), totalStyle); + setText(row, 5, textOrBlank(rowData.getQuarterTwoAmountWan()), totalStyle); + setText(row, 6, textOrBlank(rowData.getQuarterThreeAmountWan()), totalStyle); + setText(row, 7, textOrBlank(rowData.getQuarterFourAmountWan()), totalStyle); + setText(row, 8, textOrBlank(rowData.getYearTotalAmountWan()), totalStyle); + setText(row, 9, percentTextOrBlank(rowData.getProjectLeadRatio()), totalStyle); + setText(row, 10, textOrBlank(rowData.getProjectLeadAssessmentOutputWan()), totalStyle); + setText(row, 11, textOrBlank(rowData.getProjectLeadQuarterOneAmountWan()), totalStyle); + setText(row, 12, textOrBlank(rowData.getProjectLeadQuarterTwoAmountWan()), totalStyle); + setText(row, 13, textOrBlank(rowData.getProjectLeadQuarterThreeAmountWan()), totalStyle); + setText(row, 14, textOrBlank(rowData.getProjectLeadQuarterFourAmountWan()), totalStyle); + setText(row, 15, textOrBlank(rowData.getProjectLeadYearTotalAmountWan()), totalStyle); + setText(row, 16, percentTextOrBlank(rowData.getOfficeRatio()), totalStyle); + setText(row, 17, textOrBlank(rowData.getOfficeAssessmentOutputWan()), totalStyle); + setText(row, 18, textOrBlank(rowData.getOfficeQuarterOneAmountWan()), totalStyle); + setText(row, 19, textOrBlank(rowData.getOfficeQuarterTwoAmountWan()), totalStyle); + setText(row, 20, textOrBlank(rowData.getOfficeQuarterThreeAmountWan()), totalStyle); + setText(row, 21, textOrBlank(rowData.getOfficeQuarterFourAmountWan()), totalStyle); + setText(row, 22, textOrBlank(rowData.getOfficeYearTotalAmountWan()), totalStyle); + setMergedRegionText(sheet, rowIndex, rowIndex, 23, 28, SUMMARY_PLACEHOLDER, totalLeftStyle); + setText(row, 29, textOrBlank(rowData.getArchAssessmentOutputWan()), totalStyle); + setText(row, 30, textOrBlank(rowData.getDecorAssessmentOutputWan()), totalStyle); + setText(row, 31, textOrBlank(rowData.getStructAssessmentOutputWan()), totalStyle); + setText(row, 32, textOrBlank(rowData.getWaterAssessmentOutputWan()), totalStyle); + setText(row, 33, textOrBlank(rowData.getHvacAssessmentOutputWan()), totalStyle); + setText(row, 34, textOrBlank(rowData.getElecAssessmentOutputWan()), totalStyle); + } + + private void writeSignatureRow(Sheet sheet, int rowIndex, ExportData data, CellStyle signatureStyle) { + Row row = sheet.createRow(rowIndex); + setMergedRegionText(sheet, rowIndex, rowIndex, 0, 16, + safeText(defaultSignatureLabel(data.getCenterSignerLabel(), "设计中心相关负责人(签名):")), + signatureStyle); + setMergedRegionText(sheet, rowIndex, rowIndex, 17, 34, + safeText(defaultSignatureLabel(data.getProjectSignerLabel(), "项目经理/工程负责人(签名):")), + signatureStyle); + } + + private String defaultSignatureLabel(String value, String fallback) { + String text = safeText(value); + return text.isEmpty() ? fallback : text; + } + + private String textOrBlank(BigDecimal value) { + if (value == null) { + return ""; + } + return value.setScale(2, RoundingMode.HALF_UP).toPlainString(); + } + + private String percentTextOrBlank(BigDecimal value) { + return value == null ? "" : percentText(value); + } + @Data public static class ExportData { + private String projectCode; private String projectName; private Integer year; + private String centerSignerLabel; + private String projectSignerLabel; private List rows; } @Data public static class QuarterRow { - private String ownershipType; - private String planningContent; - private BigDecimal historicalIssuedRatio; - private BigDecimal currentYearRatio; - private BigDecimal pendingRatio; - private BigDecimal quarterOneAmount; - private BigDecimal quarterTwoAmount; - private BigDecimal quarterThreeAmount; - private BigDecimal quarterFourAmount; - private BigDecimal yearTotalAmount; - private BigDecimal projectLeadAmount; - private BigDecimal officeAmount; - private String specialtySummaryText; - private BigDecimal assessmentOutputValue; + private Integer serialNo; + private boolean totalRow; + private String outputType; + private String designContent; + private BigDecimal quarterOneAmountWan; + private BigDecimal quarterTwoAmountWan; + private BigDecimal quarterThreeAmountWan; + private BigDecimal quarterFourAmountWan; + private BigDecimal yearTotalAmountWan; + private BigDecimal projectLeadRatio; + private BigDecimal projectLeadAssessmentOutputWan; + private BigDecimal projectLeadQuarterOneAmountWan; + private BigDecimal projectLeadQuarterTwoAmountWan; + private BigDecimal projectLeadQuarterThreeAmountWan; + private BigDecimal projectLeadQuarterFourAmountWan; + private BigDecimal projectLeadYearTotalAmountWan; + private BigDecimal officeRatio; + private BigDecimal officeAssessmentOutputWan; + private BigDecimal officeQuarterOneAmountWan; + private BigDecimal officeQuarterTwoAmountWan; + private BigDecimal officeQuarterThreeAmountWan; + private BigDecimal officeQuarterFourAmountWan; + private BigDecimal officeYearTotalAmountWan; + private BigDecimal archRatio; + private BigDecimal decorRatio; + private BigDecimal structRatio; + private BigDecimal waterRatio; + private BigDecimal hvacRatio; + private BigDecimal elecRatio; + private BigDecimal archAssessmentOutputWan; + private BigDecimal decorAssessmentOutputWan; + private BigDecimal structAssessmentOutputWan; + private BigDecimal waterAssessmentOutputWan; + private BigDecimal hvacAssessmentOutputWan; + private BigDecimal elecAssessmentOutputWan; } }