|
@@ -0,0 +1,944 @@
|
|
|
+package org.jeecg.modules.ProdPlan.service.impl;
|
|
|
+
|
|
|
+import org.apache.commons.lang.StringUtils;
|
|
|
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|
|
+import org.apache.poi.ss.usermodel.*;
|
|
|
+import org.apache.poi.ss.util.CellRangeAddress;
|
|
|
+import org.apache.poi.util.Units;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFPicture;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
+import org.jeecg.modules.Contact.entity.Contact;
|
|
|
+import org.jeecg.modules.Contact.service.IContactService;
|
|
|
+import org.jeecg.modules.DefectiveProduct.entity.DefectiveProduct;
|
|
|
+import org.jeecg.modules.DefectiveProduct.service.IDefectiveProductService;
|
|
|
+import org.jeecg.modules.DestRule.entity.DestRule;
|
|
|
+import org.jeecg.modules.DestRule.service.IDestRuleService;
|
|
|
+import org.jeecg.modules.ProdPlan.entity.DelayProduct;
|
|
|
+import org.jeecg.modules.ProdPlan.entity.DeliveredQuantity;
|
|
|
+import org.jeecg.modules.ProdPlan.entity.ProdPlan;
|
|
|
+import org.jeecg.modules.ProdPlan.mapper.ProdPlanMapper;
|
|
|
+import org.jeecg.modules.ProdPlan.service.IDelayProductService;
|
|
|
+import org.jeecg.modules.ProdPlan.service.IDeliveredQuantityService;
|
|
|
+import org.jeecg.modules.ProdPlan.service.IProdPlanService;
|
|
|
+import org.jeecg.modules.ProdPlan.util.EmailUtil;
|
|
|
+import org.jeecg.modules.ProdPlan.vo.ReportDetailVo;
|
|
|
+import org.jeecg.modules.ReasonRule.entity.ReasonRule;
|
|
|
+import org.jeecg.modules.ReasonRule.service.IReasonRuleService;
|
|
|
+import org.jeecg.modules.RegionRule.entity.RegionRule;
|
|
|
+import org.jeecg.modules.RegionRule.service.IRegionRuleService;
|
|
|
+import org.jetbrains.annotations.NotNull;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+
|
|
|
+import java.io.ByteArrayOutputStream;
|
|
|
+import java.io.FileInputStream;
|
|
|
+import java.io.IOException;
|
|
|
+import java.time.*;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.temporal.IsoFields;
|
|
|
+import java.time.temporal.WeekFields;
|
|
|
+import java.util.*;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Description: 生产计划
|
|
|
+ * @Author: jeecg-boot
|
|
|
+ * @Date: 2025-06-04
|
|
|
+ * @Version: V1.0
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class ProdPlanServiceImpl extends ServiceImpl<ProdPlanMapper, ProdPlan> implements IProdPlanService {
|
|
|
+ @Autowired
|
|
|
+ private IDelayProductService delayProductService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IRegionRuleService regionRuleService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IDestRuleService destRuleService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IReasonRuleService reasonRuleService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IDefectiveProductService defectiveProductService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IDeliveredQuantityService deliveredQuantityService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IContactService contactService;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<DelayProduct> parseExcel(String filePath) {
|
|
|
+ List<DelayProduct> delayProducts = new ArrayList<>();
|
|
|
+ try (FileInputStream fis = new FileInputStream(filePath)) {
|
|
|
+ Workbook workbook;
|
|
|
+ // 根据文件扩展名选择合适的工作簿类型
|
|
|
+ if (filePath.endsWith(".xlsx")) {
|
|
|
+ workbook = new XSSFWorkbook(fis);
|
|
|
+ } else if (filePath.endsWith(".xls")) {
|
|
|
+ workbook = new HSSFWorkbook(fis);
|
|
|
+ } else {
|
|
|
+ throw new IllegalArgumentException("不支持的文件格式,请使用.xlsx或.xls文件");
|
|
|
+ }
|
|
|
+ //第一张表
|
|
|
+ Sheet sheet = workbook.getSheetAt(0);
|
|
|
+ //第二行为表头
|
|
|
+ Row headerRow = sheet.getRow(1);
|
|
|
+ if (headerRow == null) {
|
|
|
+ throw new RuntimeException("未找到表头行");
|
|
|
+ }
|
|
|
+ //获取表头对应的列索引
|
|
|
+ Map<String, Integer> columnIndices = parseHeadRow(headerRow);
|
|
|
+ //获取表头中的日期列
|
|
|
+ Map<String, Integer> dateColumnIndices = parseDateColumn(columnIndices);
|
|
|
+ //从第三行开始读取数据
|
|
|
+ for (int i = 2; i <= sheet.getLastRowNum(); i++) {
|
|
|
+ Row row = sheet.getRow(i);
|
|
|
+ if(row==null) break;
|
|
|
+ if (row.getCell(columnIndices.get("Line"))==null) break;
|
|
|
+
|
|
|
+ parseDataRow(row, columnIndices, dateColumnIndices, delayProducts);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<RegionRule> regionRuleList = regionRuleService.list();
|
|
|
+ Map<String, RegionRule> regionRules = regionRuleList.stream().collect(Collectors.toMap(RegionRule::getSuffix, i -> i));
|
|
|
+ List<DestRule> destRuleList = destRuleService.list();
|
|
|
+ Map<String, String> destRules = destRuleList.stream().collect(Collectors.toMap(DestRule::getDestination, DestRule::getSchedule));
|
|
|
+ List<ReasonRule> reasonRuleList = reasonRuleService.list();
|
|
|
+ Map<String, String> reasonRules = reasonRuleList.stream().collect(Collectors.toMap(ReasonRule::getComment2, ReasonRule::getRemark));
|
|
|
+
|
|
|
+ // 清洗数据,按规则匹配规定交付时间,计算超出时间,并转换延期原因
|
|
|
+ for (int i = 0; i < delayProducts.size(); i++) {
|
|
|
+ DelayProduct delayProduct = delayProducts.get(i);
|
|
|
+
|
|
|
+ //通过后缀匹配国别规则
|
|
|
+ String model = delayProduct.getModel().trim();
|
|
|
+ String suffix = model.substring(model.length() - 3);
|
|
|
+ RegionRule regionRule = regionRules.get(suffix);
|
|
|
+ if(regionRule==null) continue;
|
|
|
+ delayProduct.setRegion(regionRule.getRegion());
|
|
|
+
|
|
|
+ // 按国别规则匹配到期规则
|
|
|
+ String schecule = regionRule.getSchedule();
|
|
|
+ if("EU".equals(regionRule.getRegion())){
|
|
|
+ //EU地区需要根据目的地匹配到期规则
|
|
|
+ schecule = destRules.get(delayProduct.getFinalDest());
|
|
|
+ }
|
|
|
+ if(StringUtils.isBlank(schecule)) continue;
|
|
|
+ // 根据要求周别和到期规则,计算要求完成日期
|
|
|
+ LocalDate dueDate = getDueDate(delayProduct.getBucket(), schecule);
|
|
|
+ if(dueDate==null) continue;
|
|
|
+ delayProduct.setDueDate(dueDate);
|
|
|
+
|
|
|
+ // 计算计划生产日期超出要求完成日期天数
|
|
|
+ if (delayProduct.getPst() != null && delayProduct.getDueDate() != null) {
|
|
|
+ int days = delayProduct.getDueDate().until(delayProduct.getPst()).getDays();
|
|
|
+// Long days = ChronoUnit.DAYS.between(delayProduct.getDueDate(), delayProduct.getPst());
|
|
|
+ delayProduct.setOverdueDays(days);
|
|
|
+ }
|
|
|
+ // 计算要求完成周别
|
|
|
+ String week = "W" + delayProduct.getDueDate().get(WeekFields.ISO.weekOfYear());
|
|
|
+ delayProduct.setWeek(week);
|
|
|
+
|
|
|
+ reasonRules.forEach((reason,remark)->{
|
|
|
+ Pattern pattern = Pattern.compile("^"+reason+"$");
|
|
|
+ Matcher matcher = pattern.matcher(delayProduct.getComment2());
|
|
|
+ if (matcher.matches()) {
|
|
|
+ String newRemark = matcher.replaceAll(remark);
|
|
|
+ delayProduct.setRemark(newRemark);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ List<DelayProduct> overDueList = delayProducts.stream().filter(i -> i.getRemark()!=null && i.getOverdueDays()!=null && i.getOverdueDays() > 0).collect(Collectors.toList());
|
|
|
+
|
|
|
+ return overDueList;
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取表头对应的列索引
|
|
|
+ * @param headerRow
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @NotNull
|
|
|
+ private Map<String, Integer> parseHeadRow(Row headerRow) {
|
|
|
+ Map<String, Integer> columnIndices = new LinkedHashMap<>();
|
|
|
+ for (Cell cell : headerRow) {
|
|
|
+ String headerValue = getCellValueAsString(cell);
|
|
|
+ columnIndices.put(headerValue, cell.getColumnIndex());
|
|
|
+ }
|
|
|
+ return columnIndices;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取表头中的日期列
|
|
|
+ * @param columnIndices
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @NotNull
|
|
|
+ private Map<String, Integer> parseDateColumn(Map<String, Integer> columnIndices) {
|
|
|
+ Map<String, Integer> dateColumnIndices = new LinkedHashMap<>();
|
|
|
+ columnIndices.forEach((key, value) -> {
|
|
|
+ if (key.matches("\\d{2}/\\d{2}") || key.matches("\\d{1,2}/\\d{1,2}")) {
|
|
|
+ dateColumnIndices.put(key, value);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return dateColumnIndices;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 读取明细行数据
|
|
|
+ * @param row
|
|
|
+ * @param columnIndices
|
|
|
+ * @param dateColumnIndices
|
|
|
+ * @param delayProducts
|
|
|
+ */
|
|
|
+ private void parseDataRow(Row row, Map<String, Integer> columnIndices, Map<String, Integer> dateColumnIndices, List<DelayProduct> delayProducts) {
|
|
|
+ String Line = getCellValueAsString(row.getCell(columnIndices.get("Line")));
|
|
|
+ String demandId = getCellValueAsString(row.getCell(columnIndices.get("Demand ID")));
|
|
|
+ String tool = getCellValueAsString(row.getCell(columnIndices.get("Tool")));
|
|
|
+ String model = getCellValueAsString(row.getCell(columnIndices.get("Model.Suffix")));
|
|
|
+ String bucket = getCellValueAsString(row.getCell(columnIndices.get("Bucket")));
|
|
|
+ String finalDest = getCellValueAsString(row.getCell(columnIndices.get("Final Dest.")));
|
|
|
+ String comment1 = getCellValueAsString(row.getCell(columnIndices.get("Comment1")));
|
|
|
+ String comment2 = getCellValueAsString(row.getCell(columnIndices.get("Comment2")));
|
|
|
+
|
|
|
+ dateColumnIndices.forEach((date, columnIndex) -> {
|
|
|
+ Cell cell = row.getCell(columnIndex);
|
|
|
+ if (cell != null) {
|
|
|
+ String quantityStr = getCellValueAsString(cell);
|
|
|
+ if (quantityStr != null && !quantityStr.isEmpty()) {
|
|
|
+ try {
|
|
|
+ Integer quantity = Integer.parseInt(quantityStr);
|
|
|
+ if (quantity > 0) {
|
|
|
+ DelayProduct delayProduct = new DelayProduct()
|
|
|
+ .setLine(Line)
|
|
|
+ .setDemandId(demandId)
|
|
|
+ .setTool(tool)
|
|
|
+ .setModel(model)
|
|
|
+ .setBucket(bucket)
|
|
|
+ .setFinalDest(finalDest)
|
|
|
+ .setComment1(comment1)
|
|
|
+ .setComment2(comment2)
|
|
|
+ .setPst(getDateFromMonthDayStr(date))
|
|
|
+ .setPo(quantity);
|
|
|
+ delayProducts.add(delayProduct);
|
|
|
+ }
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ log.error("无法解析数量: " + quantityStr, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取单元格的值,作为字符串返回
|
|
|
+ * @param cell
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static String getCellValueAsString(Cell cell) {
|
|
|
+ if (cell == null) return null;
|
|
|
+
|
|
|
+ switch (cell.getCellType()) {
|
|
|
+ case STRING:
|
|
|
+ return cell.getStringCellValue().trim();
|
|
|
+ case NUMERIC:
|
|
|
+ if (DateUtil.isCellDateFormatted(cell)) {
|
|
|
+ return cell.getDateCellValue().toString();
|
|
|
+ } else {
|
|
|
+ // Remove decimal if it's .0
|
|
|
+ double num = cell.getNumericCellValue();
|
|
|
+ if (num == (long) num) {
|
|
|
+ return String.valueOf((long) num);
|
|
|
+ } else {
|
|
|
+ return String.valueOf(num);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case BOOLEAN:
|
|
|
+ return String.valueOf(cell.getBooleanCellValue());
|
|
|
+ case FORMULA:
|
|
|
+ switch (cell.getCachedFormulaResultType()) {
|
|
|
+ case STRING:
|
|
|
+ return cell.getStringCellValue().trim();
|
|
|
+ case NUMERIC:
|
|
|
+ return String.valueOf(cell.getNumericCellValue());
|
|
|
+ case BOOLEAN:
|
|
|
+ return String.valueOf(cell.getBooleanCellValue());
|
|
|
+ default:
|
|
|
+ return cell.getCellFormula();
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将日期列名字符串转换为日期
|
|
|
+ * @param monthDayStr
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static LocalDate getDateFromMonthDayStr(String monthDayStr) {
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd");
|
|
|
+ MonthDay monthDay = MonthDay.parse(monthDayStr, formatter);
|
|
|
+ LocalDate date = monthDay.atYear(LocalDate.now().getYear());
|
|
|
+ return date;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通过周别和到期规则获取要求完成日期
|
|
|
+ * @param yearWeekStr
|
|
|
+ * @param schedule
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static LocalDate getDueDate(String yearWeekStr,String schedule) {
|
|
|
+ if (StringUtils.isBlank(yearWeekStr)||yearWeekStr.length() != 6) {
|
|
|
+ throw new IllegalArgumentException("周别格式必须为YYYYWW,如:202523");
|
|
|
+ }
|
|
|
+ int year = Integer.parseInt(yearWeekStr.substring(0, 4));
|
|
|
+ int week = Integer.parseInt(yearWeekStr.substring(4, 6));
|
|
|
+
|
|
|
+ Map<String, DayOfWeek> DAYS = new HashMap<>();
|
|
|
+ DAYS.put("MON", DayOfWeek.MONDAY);
|
|
|
+ DAYS.put("TUE", DayOfWeek.TUESDAY);
|
|
|
+ DAYS.put("WED", DayOfWeek.WEDNESDAY);
|
|
|
+ DAYS.put("THU", DayOfWeek.THURSDAY);
|
|
|
+ DAYS.put("FRI", DayOfWeek.FRIDAY);
|
|
|
+ DAYS.put("SAT", DayOfWeek.SATURDAY);
|
|
|
+ DAYS.put("SUN", DayOfWeek.SUNDAY);
|
|
|
+
|
|
|
+ boolean isLast = schedule.startsWith("Last ");
|
|
|
+ String dayStr = isLast ? schedule.substring(5).trim() : schedule;
|
|
|
+ if (isLast) {
|
|
|
+ week = week - 1;
|
|
|
+ if (week < 1) {
|
|
|
+ year = year - 1;
|
|
|
+ week = LocalDate.of(year, 12, 31).get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ DayOfWeek dayOfWeek = DAYS.get(dayStr);
|
|
|
+
|
|
|
+ return LocalDate.now()
|
|
|
+ .with(WeekFields.ISO.weekBasedYear(), year)
|
|
|
+ .with(WeekFields.ISO.weekOfWeekBasedYear(), week)
|
|
|
+ .with(WeekFields.ISO.dayOfWeek(), dayOfWeek.getValue());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public XSSFWorkbook report(String id, byte[] pie) {
|
|
|
+ ProdPlan prodPlan = this.getById(id);
|
|
|
+ int currentWeek = prodPlan.getPlanDate().get(WeekFields.ISO.weekOfYear());
|
|
|
+ List<ReportDetailVo> detailVos = new ArrayList<>();
|
|
|
+ // TODO 根据计划日期增加当前周期查询条件
|
|
|
+ List<DelayProduct> delayProductList = this.delayProductService.list();
|
|
|
+ delayProductList.forEach(delayProduct -> {
|
|
|
+ ReportDetailVo detailVo = new ReportDetailVo();
|
|
|
+ BeanUtils.copyProperties(delayProduct, detailVo);
|
|
|
+ detailVo.setPst(delayProduct.getPst().format(DateTimeFormatter.ofPattern("MM/dd")));
|
|
|
+ detailVo.setDueDate(delayProduct.getDueDate().format(DateTimeFormatter.ofPattern("MM/dd")));
|
|
|
+ LocalDate endDate = delayProduct.getPst();
|
|
|
+ LocalDate startDate = delayProduct.getDueDate();
|
|
|
+ while(endDate.isAfter(startDate)){
|
|
|
+ int startWeek = startDate.get(WeekFields.ISO.weekOfYear());
|
|
|
+ if(startWeek==currentWeek-3){
|
|
|
+ detailVo.setWeek1(detailVo.getPo());
|
|
|
+ } else if (startWeek==currentWeek-2) {
|
|
|
+ detailVo.setWeek2(detailVo.getPo());
|
|
|
+ } else if (startWeek==currentWeek-1) {
|
|
|
+ detailVo.setWeek3(detailVo.getPo());
|
|
|
+ } else if (startWeek==currentWeek) {
|
|
|
+ detailVo.setWeek4(detailVo.getPo());
|
|
|
+ } else if (startWeek==currentWeek+1) {
|
|
|
+ detailVo.setWeek5(detailVo.getPo());
|
|
|
+ } else if (startWeek==currentWeek+2) {
|
|
|
+ detailVo.setWeek6(detailVo.getPo());
|
|
|
+ }
|
|
|
+ startDate = startDate.plusWeeks(1l);
|
|
|
+ }
|
|
|
+ detailVos.add(detailVo);
|
|
|
+ });
|
|
|
+
|
|
|
+ List<DefectiveProduct> defectiveProductList = this.defectiveProductService.list();
|
|
|
+ defectiveProductList.forEach(defectiveProduct -> {
|
|
|
+ ReportDetailVo detailVo = new ReportDetailVo();
|
|
|
+ BeanUtils.copyProperties(defectiveProduct, detailVo);
|
|
|
+ detailVo.setPo(defectiveProduct.getPo());
|
|
|
+ detailVo.setDueDate(defectiveProduct.getDueDate().format(DateTimeFormatter.ofPattern("MM/dd")));
|
|
|
+ int week = Integer.valueOf(defectiveProduct.getWeek().substring(1));
|
|
|
+ if(week==currentWeek-3){
|
|
|
+ detailVo.setWeek1(detailVo.getPo());
|
|
|
+ } else if (week==currentWeek-2) {
|
|
|
+ detailVo.setWeek2(detailVo.getPo());
|
|
|
+ } else if (week==currentWeek-1) {
|
|
|
+ detailVo.setWeek3(detailVo.getPo());
|
|
|
+ } else if (week==currentWeek) {
|
|
|
+ detailVo.setWeek4(detailVo.getPo());
|
|
|
+ } else if (week==currentWeek+1) {
|
|
|
+ detailVo.setWeek5(detailVo.getPo());
|
|
|
+ } else if (week==currentWeek+2) {
|
|
|
+ detailVo.setWeek6(detailVo.getPo());
|
|
|
+ }
|
|
|
+ detailVos.add(detailVo);
|
|
|
+ });
|
|
|
+ List<DeliveredQuantity> deliveredQuantityList = this.deliveredQuantityService.list();
|
|
|
+ // TODO 按照计划日期,过滤影响到当前周的数据
|
|
|
+
|
|
|
+
|
|
|
+ XSSFWorkbook workbook=new XSSFWorkbook();
|
|
|
+ Sheet sheet = workbook.createSheet("生产数据统计");
|
|
|
+ // 隐藏网格线
|
|
|
+ sheet.setDisplayGridlines(false);
|
|
|
+ sheet.setPrintGridlines(false);
|
|
|
+ sheet.setDefaultRowHeightInPoints(20f);
|
|
|
+ try {
|
|
|
+ insertImageToSheetAtPosition(workbook,sheet,pie,"pie",0,0);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建各种样式
|
|
|
+ CellStyle darkHeaderStyle = createDarkHeaderStyle(workbook);
|
|
|
+ CellStyle subtotalStyle = createSubtotalStyle(workbook);
|
|
|
+ CellStyle dataStyle = createDataStyle(workbook);
|
|
|
+ CellStyle darkDataStyle = createDarkDataStyle(workbook);
|
|
|
+ CellStyle percentStyle = createPercentStyle(workbook);
|
|
|
+ CellStyle redPercentStyle = createRedPercentStyle(workbook);
|
|
|
+ CellStyle totalStyle = createTotalStyle(workbook);
|
|
|
+ CellStyle groupStyle = createGroupStyle(workbook);
|
|
|
+
|
|
|
+ int currentRow = 30;
|
|
|
+ int startColumn = 1;
|
|
|
+
|
|
|
+ // 第一部分:原因部门数据
|
|
|
+ currentRow = createFirstSection(currentWeek,sheet, currentRow,startColumn, darkHeaderStyle, subtotalStyle,
|
|
|
+ dataStyle, percentStyle, totalStyle, groupStyle);
|
|
|
+ List<ReportDetailVo> sumDetailVos = new ArrayList<>();
|
|
|
+ ReportDetailVo totalVo = getSummaryDetailVo(detailVos);
|
|
|
+ totalVo.setComment1("合计");
|
|
|
+
|
|
|
+ Map<String, List<ReportDetailVo>> deptMap = detailVos.stream().collect(Collectors.groupingBy(ReportDetailVo::getComment1, Collectors.toList()));
|
|
|
+ deptMap.forEach((dept,deptList)->{
|
|
|
+ ReportDetailVo subTotalVo = getSummaryDetailVo(deptList);
|
|
|
+ subTotalVo.setComment1(dept);
|
|
|
+ subTotalVo.setLine("小计");
|
|
|
+ subTotalVo.setPercent((double)subTotalVo.getPo()/totalVo.getPo());
|
|
|
+
|
|
|
+ Map<String, Map<String, List<ReportDetailVo>>> lineMap = deptList.stream().collect(Collectors.groupingBy(ReportDetailVo::getLine, Collectors.groupingBy(ReportDetailVo::getTool, Collectors.toList())));
|
|
|
+ lineMap.forEach((line,toolMap)->{
|
|
|
+ toolMap.forEach((tool,toolList)->{
|
|
|
+ ReportDetailVo toolVo = getSummaryDetailVo(toolList);
|
|
|
+ toolVo.setComment1(dept);
|
|
|
+ toolVo.setLine(line);
|
|
|
+ toolVo.setTool(tool);
|
|
|
+ toolVo.setPercent((double)toolVo.getPo()/subTotalVo.getPo());
|
|
|
+ toolVo.setRemark(toolList.get(0).getRemark()+" "+toolList.get(0).getModel());
|
|
|
+ sumDetailVos.add(toolVo);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ sumDetailVos.add(subTotalVo);
|
|
|
+ } );
|
|
|
+ sumDetailVos.add(totalVo);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ String currentDept = "";
|
|
|
+ String currentLine = "";
|
|
|
+ int deptStartRow = currentRow;
|
|
|
+ int lineStartRow = currentRow;
|
|
|
+ CellStyle cellStyle = dataStyle;
|
|
|
+ for(ReportDetailVo detailVo:sumDetailVos){
|
|
|
+ if("合计".equals(detailVo.getComment1())) {
|
|
|
+ cellStyle = totalStyle;
|
|
|
+ }else if("小计".equals(detailVo.getLine())) {
|
|
|
+ cellStyle = subtotalStyle;
|
|
|
+ }else {
|
|
|
+ cellStyle = dataStyle;
|
|
|
+ }
|
|
|
+ Row dataRow = sheet.createRow(currentRow++);
|
|
|
+ int currentColumn = startColumn;
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getComment1(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,"",cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,"",cellStyle);
|
|
|
+ if (!currentDept.equals(detailVo.getComment1())) {
|
|
|
+ if (!currentDept.isEmpty()) {
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(deptStartRow, currentRow-2, startColumn, startColumn+2));
|
|
|
+ }
|
|
|
+ currentDept = detailVo.getComment1();
|
|
|
+ deptStartRow = currentRow-1;
|
|
|
+ }
|
|
|
+ if("合计".equals(detailVo.getComment1())){
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow-1, currentRow-1, startColumn, startColumn+2));
|
|
|
+ }
|
|
|
+
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getLine(),cellStyle);
|
|
|
+ if (!currentLine.equals(detailVo.getLine())) {
|
|
|
+ if (!currentLine.isEmpty() &¤tRow-2>lineStartRow) {
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(lineStartRow, currentRow-2, currentColumn-1, currentColumn-1));
|
|
|
+ }
|
|
|
+ currentLine = detailVo.getLine();
|
|
|
+ lineStartRow = currentRow-1;
|
|
|
+ }
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getTool(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getPo(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getWeek3()==null?0:detailVo.getWeek3(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getWeek4()==null?0:detailVo.getWeek4(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getWeek5()==null?0:detailVo.getWeek5(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getWeek6()==null?0:detailVo.getWeek6(),cellStyle);
|
|
|
+
|
|
|
+ if("合计".equals(detailVo.getComment1())) {
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getPercent()==null?0:detailVo.getPercent(),cellStyle);
|
|
|
+ }else if("小计".equals(detailVo.getLine())) {
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getPercent()==null?0:detailVo.getPercent(),redPercentStyle);
|
|
|
+ }else {
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getPercent()==null?0:detailVo.getPercent(),percentStyle);
|
|
|
+ }
|
|
|
+
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getRemark(),cellStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow-1, currentRow-1, currentColumn-1, currentColumn+2));
|
|
|
+ createCell(dataRow,currentColumn++,"",cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,"",cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,"",cellStyle);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ Map<String, Integer> deliveredQuantityMap = deliveredQuantityList.stream().collect(Collectors.toMap(DeliveredQuantity::getWeek, DeliveredQuantity::getQuantity));
|
|
|
+ Row quantityRow = sheet.createRow(currentRow++);
|
|
|
+ createCell(quantityRow,startColumn,"计划交付量",dataStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow-1, currentRow-1, startColumn, startColumn+2));
|
|
|
+ createCell(quantityRow,startColumn+1,"",dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+2,"",dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+3,"",dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+4,"",dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+5,"",dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+6,deliveredQuantityMap.get("W"+(currentWeek-1))==null?0:deliveredQuantityMap.get("W"+(currentWeek-1)),dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+7,deliveredQuantityMap.get("W"+(currentWeek))==null?0:deliveredQuantityMap.get("W"+(currentWeek)),dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+8,deliveredQuantityMap.get("W"+(currentWeek+1))==null?0:deliveredQuantityMap.get("W"+(currentWeek+1)),dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+9,deliveredQuantityMap.get("W"+(currentWeek+2))==null?0:deliveredQuantityMap.get("W"+(currentWeek+2)),dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+10,"",dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+11,"",dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+12,"",dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+13,"",dataStyle);
|
|
|
+ createCell(quantityRow,startColumn+14,"",dataStyle);
|
|
|
+
|
|
|
+ Row lossrow = sheet.createRow(currentRow++);
|
|
|
+ createCell(lossrow,startColumn,"OTD0 Loss率",dataStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow-1, currentRow-1, startColumn, startColumn+2));
|
|
|
+ createCell(lossrow,startColumn+3,"",dataStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow-1, currentRow-1, startColumn+3, startColumn+5));
|
|
|
+ createCell(lossrow,startColumn+10,"",dataStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow-1, currentRow-1, startColumn+10, startColumn+14));
|
|
|
+ Row otdrow = sheet.createRow(currentRow++);
|
|
|
+ createCell(otdrow,startColumn,"OTD0",dataStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow-1, currentRow-1, startColumn, startColumn+2));
|
|
|
+ createCell(otdrow,startColumn+10,"",dataStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow-1, currentRow-1, startColumn+10, startColumn+14));
|
|
|
+ createCell(otdrow,startColumn+3,"",dataStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(currentRow-1, currentRow-1, startColumn+3, startColumn+5));
|
|
|
+ createCell(lossrow,startColumn+1,"",dataStyle);
|
|
|
+ createCell(lossrow,startColumn+2,"",dataStyle);
|
|
|
+ createCell(lossrow,startColumn+3,"",dataStyle);
|
|
|
+ createCell(lossrow,startColumn+4,"",dataStyle);
|
|
|
+ createCell(lossrow,startColumn+5,"",dataStyle);
|
|
|
+ createCell(lossrow,startColumn+10,"",dataStyle);
|
|
|
+ createCell(lossrow,startColumn+11,"",dataStyle);
|
|
|
+ createCell(lossrow,startColumn+12,"",dataStyle);
|
|
|
+ createCell(lossrow,startColumn+13,"",dataStyle);
|
|
|
+ createCell(lossrow,startColumn+14,"",dataStyle);
|
|
|
+ if(totalVo.getWeek3()!=null && deliveredQuantityMap.get("W" + (currentWeek - 1))!=null) {
|
|
|
+ createCell(lossrow, startColumn+6, (double)totalVo.getWeek3()/ deliveredQuantityMap.get("W" + (currentWeek - 1)), percentStyle);
|
|
|
+ createCell(otdrow, startColumn+6, 1-(double)totalVo.getWeek3()/ deliveredQuantityMap.get("W" + (currentWeek - 1)), percentStyle);
|
|
|
+ }else{
|
|
|
+
|
|
|
+ createCell(lossrow, startColumn+6, "", percentStyle);
|
|
|
+ createCell(otdrow, startColumn+6, "", percentStyle);
|
|
|
+ }
|
|
|
+ if(totalVo.getWeek4()!=null && deliveredQuantityMap.get("W" + (currentWeek))!=null) {
|
|
|
+ createCell(lossrow, startColumn+7, (double)totalVo.getWeek4()/ deliveredQuantityMap.get("W" + (currentWeek)), percentStyle);
|
|
|
+ createCell(otdrow, startColumn+7, 1-(double)totalVo.getWeek4()/ deliveredQuantityMap.get("W" + (currentWeek)), percentStyle);
|
|
|
+ }
|
|
|
+ if(totalVo.getWeek5()!=null && deliveredQuantityMap.get("W" + (currentWeek+1))!=null) {
|
|
|
+ createCell(lossrow, startColumn+8, (double)totalVo.getWeek5()/ deliveredQuantityMap.get("W" + (currentWeek+1)), percentStyle);
|
|
|
+ createCell(otdrow, startColumn+8, 1-(double)totalVo.getWeek5()/ deliveredQuantityMap.get("W" + (currentWeek+1)), percentStyle);
|
|
|
+ }
|
|
|
+ if(totalVo.getWeek6()!=null && deliveredQuantityMap.get("W" + (currentWeek+2))!=null) {
|
|
|
+ createCell(lossrow, startColumn+9, (double)totalVo.getWeek6()/ deliveredQuantityMap.get("W" + (currentWeek+2)), percentStyle);
|
|
|
+ createCell(otdrow, startColumn+9, 1-(double)totalVo.getWeek6()/ deliveredQuantityMap.get("W" + (currentWeek+2)), percentStyle);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第二部分:产品需求数据
|
|
|
+ currentRow = createSecondSection(currentWeek,sheet, currentRow,startColumn, darkHeaderStyle, subtotalStyle, dataStyle, groupStyle);
|
|
|
+ cellStyle = darkDataStyle;
|
|
|
+ for(ReportDetailVo detailVo:detailVos){
|
|
|
+ Row dataRow = sheet.createRow(currentRow++);
|
|
|
+ int currentColumn = startColumn;
|
|
|
+ cellStyle = cellStyle.equals(dataStyle) ? darkDataStyle : dataStyle;
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getRegion(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getModel(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getWeek(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getLine(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getTool(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getPo(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getWeek3()==null?0:detailVo.getWeek3(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getWeek4()==null?0:detailVo.getWeek4(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getWeek5()==null?0:detailVo.getWeek5(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getWeek6()==null?0:detailVo.getWeek6(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getPst(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getDueDate(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getOverdueDays()==null?0:detailVo.getOverdueDays(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getComment1(),cellStyle);
|
|
|
+ createCell(dataRow,currentColumn++,detailVo.getRemark(),cellStyle);
|
|
|
+ }
|
|
|
+
|
|
|
+// // 自动调整列宽
|
|
|
+ autoSizeColumns(sheet, startColumn+15);
|
|
|
+ return workbook;
|
|
|
+ }
|
|
|
+
|
|
|
+ @NotNull
|
|
|
+ private ReportDetailVo getSummaryDetailVo(List<ReportDetailVo> detailVos) {
|
|
|
+ Integer poQty = detailVos.stream().map(ReportDetailVo::getPo).filter(Objects::nonNull).reduce(0, Integer::sum);
|
|
|
+ Integer week1 = detailVos.stream().map(ReportDetailVo::getWeek1).filter(Objects::nonNull).reduce(0, Integer::sum);
|
|
|
+ Integer week2 = detailVos.stream().map(ReportDetailVo::getWeek2).filter(Objects::nonNull).reduce(0, Integer::sum);
|
|
|
+ Integer week3 = detailVos.stream().map(ReportDetailVo::getWeek3).filter(Objects::nonNull).reduce(0, Integer::sum);
|
|
|
+ Integer week4 = detailVos.stream().map(ReportDetailVo::getWeek4).filter(Objects::nonNull).reduce(0, Integer::sum);
|
|
|
+ Integer week5 = detailVos.stream().map(ReportDetailVo::getWeek5).filter(Objects::nonNull).reduce(0, Integer::sum);
|
|
|
+ Integer week6 = detailVos.stream().map(ReportDetailVo::getWeek6).filter(Objects::nonNull).reduce(0, Integer::sum);
|
|
|
+ ReportDetailVo totalVo = new ReportDetailVo();
|
|
|
+ totalVo.setPo(poQty);
|
|
|
+ totalVo.setWeek1(week1);
|
|
|
+ totalVo.setWeek2(week2);
|
|
|
+ totalVo.setWeek3(week3);
|
|
|
+ totalVo.setWeek4(week4);
|
|
|
+ totalVo.setWeek5(week5);
|
|
|
+ totalVo.setWeek6(week6);
|
|
|
+ return totalVo;
|
|
|
+ }
|
|
|
+ private void insertImageToSheetAtPosition(Workbook workbook, Sheet sheet, byte[] imageBytes,
|
|
|
+ String fileName, int startRow, int startCol) throws Exception {
|
|
|
+ int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG);
|
|
|
+ Drawing drawing = sheet.createDrawingPatriarch();
|
|
|
+ ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
|
|
|
+
|
|
|
+ // 设置图片位置
|
|
|
+ anchor.setCol1(startCol);
|
|
|
+ anchor.setRow1(startRow);
|
|
|
+ anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
|
|
|
+
|
|
|
+ XSSFPicture picture = (XSSFPicture)drawing.createPicture(anchor, pictureIdx);
|
|
|
+ picture.resize();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建第一部分数据表格
|
|
|
+ */
|
|
|
+ private static int createFirstSection(int currentWeek,Sheet sheet, int startRow, int startColumn, CellStyle darkHeaderStyle,
|
|
|
+ CellStyle subtotalStyle, CellStyle dataStyle,
|
|
|
+ CellStyle percentStyle, CellStyle totalStyle,
|
|
|
+ CellStyle groupStyle) {
|
|
|
+ int currentRow = startRow;
|
|
|
+
|
|
|
+ // 创建表头
|
|
|
+ Row headerRow1 = sheet.createRow(currentRow++);
|
|
|
+ String[] headers1 = {"原因部门", "", "", "Line", "Tool", "PO Qty", "周别累计影响数量", "", "", "", "%", "Remark"};
|
|
|
+ for (int i = 0; i < headers1.length; i++) {
|
|
|
+ Cell cell = headerRow1.createCell(startColumn+i);
|
|
|
+ cell.setCellValue(headers1[i]);
|
|
|
+ cell.setCellStyle(darkHeaderStyle);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第二行表头
|
|
|
+ Row headerRow2 = sheet.createRow(currentRow++);
|
|
|
+ String[] headers2 = {"", "", "", "", "", "", "W"+(currentWeek-1), "W"+currentWeek, "W"+(currentWeek+1), "W"+(currentWeek+2), "", ""};
|
|
|
+ for (int i = 0; i < headers2.length; i++) {
|
|
|
+ Cell cell = headerRow2.createCell(startColumn+i);
|
|
|
+ cell.setCellValue(headers2[i]);
|
|
|
+ cell.setCellStyle(darkHeaderStyle);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 合并单元格
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn, startColumn+2)); // 原因部门
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+3, startColumn+3)); // Line
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+4, startColumn+4)); // Tool
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+5, startColumn+5)); // PO Qty
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, startColumn+6, startColumn+9)); // 周别累计影响数量
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+10, startColumn+10)); // %
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+11, startColumn+14)); // Remark
|
|
|
+
|
|
|
+ return currentRow;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建第二部分数据表格
|
|
|
+ */
|
|
|
+ private static int createSecondSection(int currentWeek,Sheet sheet, int startRow, int startColumn,CellStyle darkHeaderStyle,
|
|
|
+ CellStyle subtotalStyle, CellStyle dataStyle,
|
|
|
+ CellStyle groupStyle) {
|
|
|
+ int currentRow = startRow;
|
|
|
+
|
|
|
+ // 创建第二个表格的表头
|
|
|
+ Row headerRow = sheet.createRow(currentRow++);
|
|
|
+ String[] headers = {"产品需求", "","", "Line", "Tool", "PO", "周别累计影响数量", "", "","",
|
|
|
+ "当前日期", "要求完成日期", "超出天数", "原因部门", "Remark"};
|
|
|
+ for (int i = 0; i < headers.length; i++) {
|
|
|
+ Cell cell = headerRow.createCell(startColumn+i);
|
|
|
+ cell.setCellValue(headers[i]);
|
|
|
+ cell.setCellStyle(darkHeaderStyle);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第二行表头
|
|
|
+ Row headerRow2 = sheet.createRow(currentRow++);
|
|
|
+ String[] headers2 = { "Region","LG Model","Week", "", "", "", "W"+(currentWeek-1), "W"+currentWeek, "W"+(currentWeek+1), "W"+(currentWeek+2), "", "", "", "", ""};
|
|
|
+ for (int i = 0; i < headers2.length; i++) {
|
|
|
+ Cell cell = headerRow2.createCell(startColumn+i);
|
|
|
+ cell.setCellValue(headers2[i]);
|
|
|
+ cell.setCellStyle(darkHeaderStyle);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 合并单元格
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow , startColumn, startColumn+2)); // 产品需求
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+3, startColumn+3)); // Line
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+4, startColumn+4)); // Tool
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+5, startColumn+5)); // PO Qty
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow, startColumn+6, startColumn+9)); // 周别累计影响数量
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+10, startColumn+10)); // 当前日期
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+11, startColumn+11)); // 要求完成日期
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+12, startColumn+12)); // 超出天数
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+13, startColumn+13)); // 原因部门
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 1, startColumn+14, startColumn+14)); // Remark
|
|
|
+
|
|
|
+ return currentRow;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建深色表头样式
|
|
|
+ */
|
|
|
+ private static CellStyle createDarkHeaderStyle(Workbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+
|
|
|
+ // 设置深灰色背景
|
|
|
+ style.setFillForegroundColor(IndexedColors.GREY_80_PERCENT.getIndex());
|
|
|
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
+
|
|
|
+ // 设置白色字体
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setColor(IndexedColors.WHITE.getIndex());
|
|
|
+ font.setBold(true);
|
|
|
+ font.setFontHeightInPoints((short) 12);
|
|
|
+ style.setFont(font);
|
|
|
+
|
|
|
+ // 设置边框
|
|
|
+ style.setBorderTop(BorderStyle.NONE);
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ style.setBorderLeft(BorderStyle.NONE);
|
|
|
+ style.setBorderRight(BorderStyle.NONE);
|
|
|
+
|
|
|
+ // 设置对齐
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建小计样式
|
|
|
+ */
|
|
|
+ private static CellStyle createSubtotalStyle(Workbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+
|
|
|
+ style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
|
|
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
+
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setBold(true);
|
|
|
+ font.setFontHeightInPoints((short) 12);
|
|
|
+ style.setFont(font);
|
|
|
+
|
|
|
+ style.setBorderTop(BorderStyle.NONE);
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ style.setBorderLeft(BorderStyle.NONE);
|
|
|
+ style.setBorderRight(BorderStyle.NONE);
|
|
|
+
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建合计样式
|
|
|
+ */
|
|
|
+ private static CellStyle createTotalStyle(Workbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+
|
|
|
+ style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
|
|
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
+
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setBold(true);
|
|
|
+ font.setFontHeightInPoints((short) 12);
|
|
|
+ style.setFont(font);
|
|
|
+
|
|
|
+ style.setBorderTop(BorderStyle.NONE);
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ style.setBorderLeft(BorderStyle.NONE);
|
|
|
+ style.setBorderRight(BorderStyle.NONE);
|
|
|
+
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建数据样式
|
|
|
+ */
|
|
|
+ private static CellStyle createDataStyle(Workbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+
|
|
|
+ style.setBorderTop(BorderStyle.NONE);
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ style.setBorderLeft(BorderStyle.NONE);
|
|
|
+ style.setBorderRight(BorderStyle.NONE);
|
|
|
+
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setFontHeightInPoints((short) 11);
|
|
|
+ style.setFont(font);
|
|
|
+
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+ private static CellStyle createDarkDataStyle(Workbook workbook) {
|
|
|
+ CellStyle style = createDataStyle(workbook);
|
|
|
+
|
|
|
+ style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
|
|
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建百分比样式
|
|
|
+ */
|
|
|
+ private static CellStyle createPercentStyle(Workbook workbook) {
|
|
|
+ CellStyle style = createDataStyle(workbook);
|
|
|
+ DataFormat format = workbook.createDataFormat();
|
|
|
+ style.setDataFormat(format.getFormat("0.0%"));
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setBold(true);
|
|
|
+ font.setFontHeightInPoints((short) 12);
|
|
|
+ style.setFont(font);
|
|
|
+
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+ private static CellStyle createRedPercentStyle(Workbook workbook) {
|
|
|
+ CellStyle style = createSubtotalStyle(workbook);
|
|
|
+ DataFormat format = workbook.createDataFormat();
|
|
|
+ style.setDataFormat(format.getFormat("0.0%"));
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setColor(IndexedColors.RED.getIndex());
|
|
|
+ font.setBold(true);
|
|
|
+ font.setFontHeightInPoints((short) 12);
|
|
|
+ style.setFont(font);
|
|
|
+
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建分组样式
|
|
|
+ */
|
|
|
+ private static CellStyle createGroupStyle(Workbook workbook) {
|
|
|
+ CellStyle style = workbook.createCellStyle();
|
|
|
+
|
|
|
+ style.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
|
|
|
+ style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
|
+
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setBold(true);
|
|
|
+ font.setFontHeightInPoints((short) 12);
|
|
|
+ style.setFont(font);
|
|
|
+
|
|
|
+
|
|
|
+ style.setBorderTop(BorderStyle.NONE);
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
+ style.setBorderLeft(BorderStyle.NONE);
|
|
|
+ style.setBorderRight(BorderStyle.NONE);
|
|
|
+
|
|
|
+ style.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+ style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+
|
|
|
+ return style;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void createCell(Row row, int column, String value, CellStyle style) {
|
|
|
+ Cell cell = row.createCell(column);
|
|
|
+ cell.setCellValue(value);
|
|
|
+ cell.setCellStyle(style);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void createCell(Row row, int column, int value, CellStyle style) {
|
|
|
+ Cell cell = row.createCell(column);
|
|
|
+ if(value>0) cell.setCellValue(value);
|
|
|
+ cell.setCellStyle(style);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void createCell(Row row, int column, double value, CellStyle style) {
|
|
|
+ Cell cell = row.createCell(column);
|
|
|
+ if(value>0) cell.setCellValue(value);
|
|
|
+ cell.setCellStyle(style);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 自动调整列宽
|
|
|
+ */
|
|
|
+ private static void autoSizeColumns(Sheet sheet, int maxColumns) {
|
|
|
+ for (int i = 0; i < maxColumns; i++) {
|
|
|
+ sheet.autoSizeColumn(i);
|
|
|
+ // 设置最小和最大宽度
|
|
|
+ int currentWidth = sheet.getColumnWidth(i);
|
|
|
+ if (currentWidth < 2000) {
|
|
|
+ sheet.setColumnWidth(i, 2000); // 最小宽度
|
|
|
+ } else if (currentWidth > 8000) {
|
|
|
+ sheet.setColumnWidth(i, 8000); // 最大宽度
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean sendEmail(String id, byte[] pie) {
|
|
|
+ ProdPlan prodPlan = this.getById(id);
|
|
|
+ String date = prodPlan.getPlanDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
|
|
+
|
|
|
+ List<Contact> list = contactService.list();
|
|
|
+ List<String> contactsTO = list.stream().filter(i -> "Y".equals(i.getIsActive()) && "TO".equals(i.getRecType())).map(Contact::getEmail).collect(Collectors.toList());
|
|
|
+ List<String> contactsCC = list.stream().filter(i -> "Y".equals(i.getIsActive()) && "CC".equals(i.getRecType())).map(Contact::getEmail).collect(Collectors.toList());
|
|
|
+
|
|
|
+ Workbook workbook = this.report(id, pie);
|
|
|
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
|
|
+ byte[] excelBytes = null;
|
|
|
+ try {
|
|
|
+ workbook.write(outputStream);
|
|
|
+ excelBytes = outputStream.toByteArray();
|
|
|
+ workbook.close();
|
|
|
+ Boolean success = EmailUtil.sendEmailWithExcelAttachment(contactsTO, contactsCC, "生产异常追踪表_" + date, "生产异常追踪表_" + date, excelBytes);
|
|
|
+ return success;
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|