|
|
|
@ -1,6 +1,12 @@ |
|
|
|
package com.xujie.sys.modules.sampletracking.service.impl; |
|
|
|
|
|
|
|
import com.alibaba.excel.EasyExcel; |
|
|
|
import com.alibaba.excel.metadata.Head; |
|
|
|
import com.alibaba.excel.metadata.data.WriteCellData; |
|
|
|
import com.alibaba.excel.write.builder.ExcelWriterBuilder; |
|
|
|
import com.alibaba.excel.write.handler.CellWriteHandler; |
|
|
|
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; |
|
|
|
import com.alibaba.excel.write.metadata.holder.WriteTableHolder; |
|
|
|
import com.alibaba.excel.write.metadata.style.WriteCellStyle; |
|
|
|
import com.alibaba.excel.write.metadata.style.WriteFont; |
|
|
|
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; |
|
|
|
@ -30,6 +36,8 @@ import com.xujie.sys.modules.sampletracking.service.SampleProofTrackingService; |
|
|
|
import jakarta.servlet.http.HttpServletResponse; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.apache.poi.ss.usermodel.BorderStyle; |
|
|
|
import org.apache.poi.ss.usermodel.Cell; |
|
|
|
import org.apache.poi.ss.usermodel.CellStyle; |
|
|
|
import org.springframework.beans.BeanWrapper; |
|
|
|
import org.springframework.beans.BeanUtils; |
|
|
|
import org.springframework.beans.BeanWrapperImpl; |
|
|
|
@ -52,6 +60,8 @@ import java.util.Objects; |
|
|
|
import java.util.Set; |
|
|
|
|
|
|
|
import org.apache.poi.ss.usermodel.FillPatternType; |
|
|
|
import org.apache.poi.ss.usermodel.IndexedColors; |
|
|
|
import org.apache.poi.ss.usermodel.Workbook; |
|
|
|
|
|
|
|
/** |
|
|
|
* 产品打样记录跟踪 Service 实现 |
|
|
|
@ -138,6 +148,15 @@ public class SampleProofTrackingServiceImpl implements SampleProofTrackingServic |
|
|
|
normalizedBuNo, |
|
|
|
buProcessConfigMap |
|
|
|
); |
|
|
|
int exportHeaderRowCount = resolveExportHeaderRowCount(headerRows); |
|
|
|
Set<Long> completedProcessCellKeySet = collectCompletedProcessCellKeySet( |
|
|
|
exportRows, |
|
|
|
trackingColumns, |
|
|
|
processColumns, |
|
|
|
normalizedBuNo, |
|
|
|
buProcessConfigMap, |
|
|
|
exportHeaderRowCount |
|
|
|
); |
|
|
|
try { |
|
|
|
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); |
|
|
|
String fileName = URLEncoder.encode("项目打样跟踪_" + timestamp, StandardCharsets.UTF_8.name()) |
|
|
|
@ -170,10 +189,15 @@ public class SampleProofTrackingServiceImpl implements SampleProofTrackingServic |
|
|
|
|
|
|
|
HorizontalCellStyleStrategy noHeaderBackgroundStyle = |
|
|
|
new HorizontalCellStyleStrategy(headCellStyle, contentCellStyle); |
|
|
|
EasyExcel.write(response.getOutputStream()) |
|
|
|
ExcelWriterBuilder writerBuilder = EasyExcel.write(response.getOutputStream()) |
|
|
|
.autoCloseStream(false) |
|
|
|
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) |
|
|
|
.registerWriteHandler(noHeaderBackgroundStyle) |
|
|
|
.registerWriteHandler(noHeaderBackgroundStyle); |
|
|
|
if (!completedProcessCellKeySet.isEmpty()) { |
|
|
|
// 已完成工序单元格灰底高亮,导出视觉与前端表格“完成态”保持一致。 |
|
|
|
writerBuilder.registerWriteHandler(new CompletedProcessCellStyleHandler(completedProcessCellKeySet)); |
|
|
|
} |
|
|
|
writerBuilder |
|
|
|
.head(headerRows) |
|
|
|
.sheet("项目打样跟踪") |
|
|
|
.doWrite(bodyRows); |
|
|
|
@ -302,6 +326,22 @@ public class SampleProofTrackingServiceImpl implements SampleProofTrackingServic |
|
|
|
return row; |
|
|
|
} |
|
|
|
|
|
|
|
private int resolveExportHeaderRowCount(List<List<String>> headerRows) { |
|
|
|
int rowCount = 0; |
|
|
|
if (headerRows == null || headerRows.isEmpty()) { |
|
|
|
return rowCount; |
|
|
|
} |
|
|
|
for (List<String> oneHeaderRow : headerRows) { |
|
|
|
if (oneHeaderRow == null || oneHeaderRow.isEmpty()) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (oneHeaderRow.size() > rowCount) { |
|
|
|
rowCount = oneHeaderRow.size(); |
|
|
|
} |
|
|
|
} |
|
|
|
return rowCount; |
|
|
|
} |
|
|
|
|
|
|
|
private List<List<String>> buildExportBodyRows(List<ProofTrackingData> exportRows, |
|
|
|
List<ProofTrackingExportColumnData> trackingColumns, |
|
|
|
List<ProofTrackingProcessColumnData> processColumns, |
|
|
|
@ -328,6 +368,40 @@ public class SampleProofTrackingServiceImpl implements SampleProofTrackingServic |
|
|
|
return rows; |
|
|
|
} |
|
|
|
|
|
|
|
private Set<Long> collectCompletedProcessCellKeySet(List<ProofTrackingData> exportRows, |
|
|
|
List<ProofTrackingExportColumnData> trackingColumns, |
|
|
|
List<ProofTrackingProcessColumnData> processColumns, |
|
|
|
String selectedBuNo, |
|
|
|
Map<String, ProofTrackingBuProcessConfigData> buProcessConfigMap, |
|
|
|
int headerRowCount) { |
|
|
|
Set<Long> rows = new LinkedHashSet<>(); |
|
|
|
if (exportRows == null || exportRows.isEmpty() || processColumns == null || processColumns.isEmpty()) { |
|
|
|
return rows; |
|
|
|
} |
|
|
|
int trackingColumnSize = trackingColumns == null ? 0 : trackingColumns.size(); |
|
|
|
for (int rowIndex = 0; rowIndex < exportRows.size(); rowIndex++) { |
|
|
|
ProofTrackingData rowData = exportRows.get(rowIndex); |
|
|
|
for (int processIndex = 0; processIndex < processColumns.size(); processIndex++) { |
|
|
|
ProofTrackingProcessColumnData processColumn = processColumns.get(processIndex); |
|
|
|
if (processColumn == null || isBlank(processColumn.getCode())) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (!isProcessColumnVisibleForRow(rowData, processColumn, processColumns.size(), selectedBuNo, buProcessConfigMap)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (!isProcessCompleteForExport(rowData, processColumn)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
rows.add(buildExportCellCoordinateKey(headerRowCount + rowIndex, trackingColumnSize + processIndex)); |
|
|
|
} |
|
|
|
} |
|
|
|
return rows; |
|
|
|
} |
|
|
|
|
|
|
|
private static long buildExportCellCoordinateKey(int rowIndex, int columnIndex) { |
|
|
|
return (((long) rowIndex) << 32) | (columnIndex & 0xffffffffL); |
|
|
|
} |
|
|
|
|
|
|
|
private String resolveTrackingColumnExportValue(ProofTrackingData rowData, |
|
|
|
ProofTrackingExportColumnData trackingColumn, |
|
|
|
List<ProofTrackingProcessColumnData> processColumns, |
|
|
|
@ -338,7 +412,7 @@ public class SampleProofTrackingServiceImpl implements SampleProofTrackingServic |
|
|
|
} |
|
|
|
String columnProp = trackingColumn.getColumnProp().trim(); |
|
|
|
if (rowData == null) { |
|
|
|
return "-"; |
|
|
|
return ""; |
|
|
|
} |
|
|
|
switch (columnProp) { |
|
|
|
case "proofingStatus": |
|
|
|
@ -376,9 +450,16 @@ public class SampleProofTrackingServiceImpl implements SampleProofTrackingServic |
|
|
|
List<ProofTrackingProcessColumnData> processColumns, |
|
|
|
String selectedBuNo, |
|
|
|
Map<String, ProofTrackingBuProcessConfigData> buProcessConfigMap) { |
|
|
|
if (rowData == null) { |
|
|
|
return ""; |
|
|
|
} |
|
|
|
// 业务口径:打样状态为“打样完成”时,Tracking Status 固定展示 Complete,不再展示 Delay/On schedule。 |
|
|
|
if (isTrackingProofingCompleted(rowData.getProofingStatus())) { |
|
|
|
return "Complete"; |
|
|
|
} |
|
|
|
String requiredDeliveryDate = toDateString(rowData.getRequiredDeliveryDate()); |
|
|
|
if (isBlank(requiredDeliveryDate)) { |
|
|
|
return "-"; |
|
|
|
return ""; |
|
|
|
} |
|
|
|
String today = toDateString(new Date()); |
|
|
|
String statusPrefix = today.compareTo(requiredDeliveryDate) <= 0 ? "On schedule" : "Delay"; |
|
|
|
@ -574,7 +655,7 @@ public class SampleProofTrackingServiceImpl implements SampleProofTrackingServic |
|
|
|
return roleNameValue.toString().trim(); |
|
|
|
} |
|
|
|
if (isBlank(roleValue)) { |
|
|
|
return "-"; |
|
|
|
return ""; |
|
|
|
} |
|
|
|
String normalizedRoleValue = roleValue.trim(); |
|
|
|
int splitIndex = normalizedRoleValue.indexOf('-'); |
|
|
|
@ -586,15 +667,15 @@ public class SampleProofTrackingServiceImpl implements SampleProofTrackingServic |
|
|
|
|
|
|
|
private String getExportDisplayValue(Object value) { |
|
|
|
if (value == null) { |
|
|
|
return "-"; |
|
|
|
return ""; |
|
|
|
} |
|
|
|
if (value instanceof Date) { |
|
|
|
// 导出场景下 Date 默认 toString() 会变成 Thu Aug...,统一转 yyyy-MM-dd 便于 Excel 阅读与筛选。 |
|
|
|
String dateText = toDateString(value); |
|
|
|
return isBlank(dateText) ? "-" : dateText; |
|
|
|
return isBlank(dateText) ? "" : dateText; |
|
|
|
} |
|
|
|
String text = String.valueOf(value); |
|
|
|
return isBlank(text) ? "-" : text; |
|
|
|
return isBlank(text) ? "" : text; |
|
|
|
} |
|
|
|
|
|
|
|
private String toDateString(Object value) { |
|
|
|
@ -2843,6 +2924,53 @@ public class SampleProofTrackingServiceImpl implements SampleProofTrackingServic |
|
|
|
data.setProofingStatusList(normalizedStatusList.isEmpty() ? null : normalizedStatusList); |
|
|
|
} |
|
|
|
|
|
|
|
private static class CompletedProcessCellStyleHandler implements CellWriteHandler { |
|
|
|
|
|
|
|
private final Set<Long> completedCellKeySet; |
|
|
|
private final Map<Integer, CellStyle> completedStyleCache = new HashMap<>(); |
|
|
|
|
|
|
|
private CompletedProcessCellStyleHandler(Set<Long> completedCellKeySet) { |
|
|
|
this.completedCellKeySet = completedCellKeySet == null ? new LinkedHashSet<>() : completedCellKeySet; |
|
|
|
} |
|
|
|
|
|
|
|
public int order() { |
|
|
|
// 晚于默认样式策略执行,避免灰底被后续样式覆盖。 |
|
|
|
return Integer.MAX_VALUE; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void afterCellDispose(WriteSheetHolder writeSheetHolder, |
|
|
|
WriteTableHolder writeTableHolder, |
|
|
|
List<WriteCellData<?>> cellDataList, |
|
|
|
Cell cell, |
|
|
|
Head head, |
|
|
|
Integer relativeRowIndex, |
|
|
|
Boolean isHead) { |
|
|
|
if (cell == null || Boolean.TRUE.equals(isHead) || completedCellKeySet.isEmpty()) { |
|
|
|
return; |
|
|
|
} |
|
|
|
long cellKey = buildExportCellCoordinateKey(cell.getRowIndex(), cell.getColumnIndex()); |
|
|
|
if (!completedCellKeySet.contains(cellKey)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
CellStyle sourceStyle = cell.getCellStyle(); |
|
|
|
Workbook workbook = cell.getSheet().getWorkbook(); |
|
|
|
int sourceStyleKey = sourceStyle == null ? -1 : sourceStyle.getIndex(); |
|
|
|
CellStyle completedStyle = completedStyleCache.get(sourceStyleKey); |
|
|
|
if (completedStyle == null) { |
|
|
|
completedStyle = workbook.createCellStyle(); |
|
|
|
if (sourceStyle != null) { |
|
|
|
completedStyle.cloneStyleFrom(sourceStyle); |
|
|
|
} |
|
|
|
completedStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); |
|
|
|
completedStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); |
|
|
|
completedStyle.setFillBackgroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); |
|
|
|
completedStyleCache.put(sourceStyleKey, completedStyle); |
|
|
|
} |
|
|
|
cell.setCellStyle(completedStyle); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private boolean isBlank(String value) { |
|
|
|
return value == null || value.trim().isEmpty(); |
|
|
|
} |
|
|
|
|