Commit 1d8a42888d36e5616c5ad6df60191e91607327b1

Authored by 房远帅
1 parent 5e265dfc

试样订单:产品试样确单-导出

1 1 package com.lframework.xingyun.sc.controller.sample;
2 2
  3 +import cn.hutool.core.io.resource.ClassPathResource;
3 4 import com.lframework.starter.bpm.dto.FlowTaskDto;
4 5 import com.lframework.starter.bpm.mappers.FlowTaskWrapperMapper;
5 6 import com.lframework.starter.bpm.vo.flow.task.QueryTodoTaskListVo;
... ... @@ -10,7 +11,10 @@ import com.lframework.starter.web.core.utils.PageResultUtil;
10 11 import com.lframework.starter.web.core.components.resp.PageResult;
11 12 import com.lframework.starter.web.core.components.resp.InvokeResult;
12 13 import javax.annotation.Resource;
  14 +import javax.servlet.http.HttpServletResponse;
13 15 import javax.validation.constraints.NotBlank;
  16 +import com.lframework.starter.web.inner.dto.system.UserInfoDto;
  17 +import com.lframework.starter.web.inner.service.system.SysUserService;
14 18 import com.lframework.xingyun.sc.bo.sample.confirm.GetProductSampleConfirmationSlipBo;
15 19 import com.lframework.xingyun.sc.bo.sample.confirm.QueryProductSampleConfirmationSlipBo;
16 20 import com.lframework.xingyun.sc.bo.sample.confirm.QueryProductSampleConfirmationSlipDetailBo;
... ... @@ -18,6 +22,8 @@ import com.lframework.xingyun.sc.entity.ProductSampleConfirmationSlip;
18 22 import com.lframework.xingyun.sc.entity.ProductSampleConfirmationSlipDetail;
19 23 import com.lframework.xingyun.sc.service.sample.ProductSampleConfirmationSlipDetailService;
20 24 import com.lframework.xingyun.sc.service.sample.ProductSampleConfirmationSlipService;
  25 +import com.lframework.xingyun.sc.utils.ExcelUtil;
  26 +import com.lframework.xingyun.sc.utils.LatexFormulaExcelExporterUtil;
21 27 import com.lframework.xingyun.sc.vo.sample.confirm.CreateProductSampleConfirmationSlipVo;
22 28 import com.lframework.xingyun.sc.vo.sample.confirm.QueryProductSampleConfirmationSlipDetailVo;
23 29 import com.lframework.xingyun.sc.vo.sample.confirm.QueryProductSampleConfirmationSlipVo;
... ... @@ -28,12 +34,25 @@ import com.lframework.starter.common.exceptions.impl.DefaultClientException;
28 34 import io.swagger.annotations.ApiOperation;
29 35 import com.lframework.starter.common.utils.CollectionUtil;
30 36 import io.swagger.annotations.Api;
  37 +import lombok.extern.slf4j.Slf4j;
31 38 import org.apache.commons.collections.CollectionUtils;
  39 +import org.apache.commons.lang3.StringUtils;
  40 +import org.apache.poi.ss.usermodel.Cell;
  41 +import org.apache.poi.ss.usermodel.Row;
  42 +import org.apache.poi.ss.usermodel.Sheet;
  43 +import org.apache.poi.ss.usermodel.Workbook;
  44 +import org.apache.poi.ss.util.CellRangeAddress;
  45 +import org.apache.poi.util.IOUtils;
  46 +import org.apache.poi.xssf.usermodel.XSSFWorkbook;
32 47 import org.springframework.web.bind.annotation.DeleteMapping;
33 48 import org.springframework.validation.annotation.Validated;
34 49 import org.springframework.web.bind.annotation.*;
35 50 import javax.validation.Valid;
36   -import java.util.List;
  51 +import java.io.FileNotFoundException;
  52 +import java.io.IOException;
  53 +import java.io.InputStream;
  54 +import java.net.URLEncoder;
  55 +import java.util.*;
37 56 import java.util.stream.Collectors;
38 57
39 58 /**
... ... @@ -41,6 +60,7 @@ import java.util.stream.Collectors;
41 60 *
42 61 */
43 62 @Api(tags = "产品试样确认单")
  63 +@Slf4j
44 64 @Validated
45 65 @RestController
46 66 @RequestMapping("/confirmationSlip")
... ... @@ -52,6 +72,9 @@ public class ProductSampleConfirmationSlipController extends DefaultBaseControll
52 72 private ProductSampleConfirmationSlipDetailService productSampleConfirmationSlipDetailService;
53 73 @Resource
54 74 private FlowTaskWrapperMapper flowTaskWrapperMapper;
  75 + @Resource
  76 + private SysUserService sysUserService;
  77 +
55 78
56 79 /**
57 80 * 查询列表
... ... @@ -147,4 +170,349 @@ public class ProductSampleConfirmationSlipController extends DefaultBaseControll
147 170
148 171 return InvokeResultBuilder.success();
149 172 }
  173 +
  174 + @ApiOperation("产品试样确认单")
  175 + @GetMapping("/printConfirmationSlip")
  176 + public void printConfirmationSlip(@NotBlank(message = "id不能为空") String id, HttpServletResponse response) throws IOException {
  177 + ProductSampleConfirmationSlip data = productSampleConfirmationSlipService.findById(id);
  178 +
  179 + // 设置响应头
  180 + setupResponse(response, data.getOrderingUnitName() + "-产品试样确认单打印.xlsx");
  181 +
  182 + GetProductSampleConfirmationSlipBo result = new GetProductSampleConfirmationSlipBo(data);
  183 + QueryProductSampleConfirmationSlipDetailVo vo = new QueryProductSampleConfirmationSlipDetailVo();
  184 + vo.setConfirmationSlipId(id);
  185 + List<ProductSampleConfirmationSlipDetail> detailList = productSampleConfirmationSlipDetailService.query(vo);
  186 + List<QueryProductSampleConfirmationSlipDetailBo> detailBoList = new ArrayList<>();
  187 + if (CollectionUtil.isNotEmpty(detailList)) {
  188 + detailBoList = detailList.stream().map(QueryProductSampleConfirmationSlipDetailBo::new).collect(Collectors.toList());
  189 + }
  190 +
  191 +
  192 + try {
  193 + // 加载模板文件
  194 + ClassPathResource templateResource = new ClassPathResource("templates/confirmationSlipTemplate.xlsx");
  195 + try (InputStream inputStream = templateResource.getStream();
  196 + Workbook workbook = new XSSFWorkbook(inputStream)) {
  197 + try {
  198 + Sheet sheet = workbook.getSheetAt(0);
  199 + int startRow = 5; // 产品开始行
  200 + if (CollectionUtils.isNotEmpty(detailBoList)) {
  201 +
  202 + for (int i = 1; i < detailBoList.size(); i++) {
  203 + int targetBrandRow = startRow + (i * 2); // 第2条:5+2=7(Excel第8行)
  204 + int targetSpecRow = startRow + (i * 2) + 1; // 第2条:5+3=8(Excel第9行)
  205 + // 复制模板的两行
  206 + copyRow(workbook, sheet, startRow, targetBrandRow); // 牌号行模板 → 目标
  207 + //合并B-D
  208 + CellRangeAddress mergeRegion1 = new CellRangeAddress(targetBrandRow, targetBrandRow, 1, 3);
  209 + sheet.addMergedRegion(mergeRegion1);
  210 + copyRow(workbook, sheet, startRow + 1, targetSpecRow); // 规格行模板 → 目
  211 + //合并B-C
  212 + CellRangeAddress mergeRegion2 = new CellRangeAddress(targetSpecRow, targetSpecRow, 1, 2);
  213 + sheet.addMergedRegion(mergeRegion2);
  214 + //合并E targetBrandRow-E targetSpecRow
  215 + CellRangeAddress mergeRegion3 = new CellRangeAddress(targetBrandRow, targetSpecRow, 4, 4);
  216 + sheet.addMergedRegion(mergeRegion3);
  217 + //合并F targetBrandRow-F targetSpecRow
  218 + CellRangeAddress mergeRegion4 = new CellRangeAddress(targetBrandRow, targetSpecRow, 5, 5);
  219 + sheet.addMergedRegion(mergeRegion4);
  220 + //合并G targetBrandRow-G targetSpecRow
  221 + CellRangeAddress mergeRegion5 = new CellRangeAddress(targetBrandRow, targetSpecRow, 6, 6);
  222 + sheet.addMergedRegion(mergeRegion5);
  223 + }
  224 + // 创建合并区域:A5:A10
  225 + int size = detailBoList.size();
  226 + if (size > 0) {
  227 + int endRow = startRow + size * 2;
  228 + CellRangeAddress region = new CellRangeAddress(startRow - 1, endRow, 0, 0);
  229 + sheet.addMergedRegion(region);
  230 + }
  231 + //合并B6-D6
  232 + CellRangeAddress mergeRegion6 = new CellRangeAddress(5, 5, 1, 3);
  233 + sheet.addMergedRegion(mergeRegion6);
  234 + //合并B7-C7
  235 + CellRangeAddress mergeRegion7 = new CellRangeAddress(6, 6, 1, 2);
  236 + sheet.addMergedRegion(mergeRegion7);
  237 + //合并E6-E7
  238 + CellRangeAddress mergeRegion8 = new CellRangeAddress(5, 6, 4, 4);
  239 + sheet.addMergedRegion(mergeRegion8);
  240 + //合并F6-F7
  241 + CellRangeAddress mergeRegion9 = new CellRangeAddress(5, 6, 5, 5);
  242 + sheet.addMergedRegion(mergeRegion9);
  243 + //合并G6-G7
  244 + CellRangeAddress mergeRegion10 = new CellRangeAddress(5, 6, 6, 6);
  245 + sheet.addMergedRegion(mergeRegion10);
  246 + for (int i = 0; i < detailBoList.size(); i++) {
  247 + QueryProductSampleConfirmationSlipDetailBo bo = detailBoList.get(i);
  248 + List<LatexFormulaExcelExporterUtil.FormulaComponent> formulaComponentList = new ArrayList<>(3);
  249 + if (bo.getThickness() != null) {
  250 + LatexFormulaExcelExporterUtil.FormulaComponent formulaComponent = new LatexFormulaExcelExporterUtil.FormulaComponent();
  251 + formulaComponent.setBase(bo.getThickness());
  252 + formulaComponent.setSup(bo.getThicknessTolPos());
  253 + formulaComponent.setSub(bo.getThicknessTolNeg());
  254 + formulaComponentList.add(formulaComponent);
  255 + }
  256 +
  257 + if (bo.getWidth() != null) {
  258 + LatexFormulaExcelExporterUtil.FormulaComponent formulaComponent = new LatexFormulaExcelExporterUtil.FormulaComponent();
  259 + formulaComponent.setBase(bo.getWidth());
  260 + formulaComponent.setSup(bo.getWidthTolPos());
  261 + formulaComponent.setSub(bo.getWidthTolNeg());
  262 + formulaComponentList.add(formulaComponent);
  263 + }
  264 +
  265 + if (bo.getLength() != null) {
  266 + LatexFormulaExcelExporterUtil.FormulaComponent formulaComponent = new LatexFormulaExcelExporterUtil.FormulaComponent();
  267 + formulaComponent.setBase(bo.getLength());
  268 + formulaComponent.setSup(bo.getLengthTolPos());
  269 + formulaComponent.setSub(bo.getLengthTolNeg());
  270 + formulaComponentList.add(formulaComponent);
  271 + }
  272 + int brandRow = startRow + (i * 2); // 5, 7, 9, ...
  273 + int specRow = startRow + (i * 2) + 1; // 6, 8, 10, ...
  274 + ExcelUtil.setCellValue(sheet, brandRow, 1, bo.getBrand());
  275 + ExcelUtil.setCellValue(sheet, specRow, 3, bo.getStatus());
  276 + String latex = LatexFormulaExcelExporterUtil.convertToLatex(formulaComponentList);
  277 + if (StringUtils.isNotBlank(latex)) {
  278 + LatexFormulaExcelExporterUtil.insertLatexImageToCell(workbook, sheet, latex, specRow, 1, 1, 2);
  279 + }
  280 +
  281 + ExcelUtil.setCellValue(sheet, brandRow, 4, bo.getQuantity());
  282 + ExcelUtil.setCellValue(sheet, brandRow, 5, bo.getProvideSamplesName());
  283 + ExcelUtil.setCellValue(sheet, brandRow, 6, bo.getClearParametersName());
  284 + }
  285 + }
  286 +
  287 + Map<String, Object> dataMap = new HashMap<>();
  288 + dataMap.put("orderingUnitName", result.getOrderingUnitName() == null ? "" : result.getOrderingUnitName());
  289 + dataMap.put("sampleTypeName", result.getSampleTypeName() == null ? "" : result.getSampleTypeName());
  290 + dataMap.put("customerTypeName", result.getCustomerTypeName() == null ? "" : result.getCustomerTypeName());
  291 + dataMap.put("workshopName", result.getWorkshopName() == null ? "" : result.getWorkshopName());
  292 + dataMap.put("belongingBreed", result.getBelongingBreed() == null ? "" : result.getBelongingBreed());
  293 + dataMap.put("originalSupplierPeer", result.getOriginalSupplierPeer() == null ? "" : result.getOriginalSupplierPeer());
  294 + dataMap.put("totalQuantity", result.getTotalQuantity() == null ? "" : result.getTotalQuantity().stripTrailingZeros());
  295 + dataMap.put("sampleQuantityRegulation", result.isSampleQuantityRegulation() ? "是" : "否");
  296 + dataMap.put("specificationQuantityRegulation", result.isSpecificationQuantityRegulation() ? "是" : "否");
  297 + dataMap.put("sampleFrequency", result.getSampleFrequency() == null ? "" : result.getSampleFrequency());
  298 + dataMap.put("earlyNonconformityDescription", result.getEarlyNonconformityDescription() == null ? "" : result.getEarlyNonconformityDescription());
  299 + dataMap.put("preparedByName", result.getPreparedByName() == null ? "" : result.getPreparedByName());
  300 + if (StringUtils.isNotEmpty(result.getOfficeClerk())) {
  301 + UserInfoDto info = sysUserService.getInfo(result.getOfficeClerk());
  302 + dataMap.put("officeClerkName", info == null ? "" : info.getName() == null ? "" : info.getName());
  303 + } else {
  304 + dataMap.put("officeClerkName", "");
  305 + }
  306 + dataMap.put("officeSupervisorOpinion", "");
  307 + if (StringUtils.isNotEmpty(result.getOfficeSupervisorReview())) {
  308 + if ("PASS".equals(result.getOfficeSupervisorReview())) {
  309 + dataMap.put("officeSupervisorPass", "☑同意生产");
  310 + dataMap.put("officeSupervisorRefuse", "□不同意生产及原因");
  311 + } else {
  312 + dataMap.put("officeSupervisorPass", "□同意生产");
  313 + dataMap.put("officeSupervisorRefuse", "☑不同意生产及原因");
  314 + dataMap.put("officeSupervisorOpinion", result.getOfficeSupervisorOpinion() == null ? "" : result.getOfficeSupervisorOpinion());
  315 + }
  316 + } else {
  317 + dataMap.put("officeSupervisorPass", "□同意生产");
  318 + dataMap.put("officeSupervisorRefuse", "□不同意生产及原因");
  319 + }
  320 + dataMap.put("marketingDeputyDirectorOpinion", "");
  321 + if (StringUtils.isNotEmpty(result.getMarketingDeputyDirectorReview())) {
  322 + if ("PASS".equals(result.getMarketingDeputyDirectorReview())) {
  323 + dataMap.put("marketingDeputyDirectorPass", "☑同意生产");
  324 + dataMap.put("marketingDeputyDirectorRefuse", "□不同意生产及原因");
  325 + } else {
  326 + dataMap.put("marketingDeputyDirectorPass", "□同意生产");
  327 + dataMap.put("marketingDeputyDirectorRefuse", "☑不同意生产及原因");
  328 + dataMap.put("marketingDeputyDirectorOpinion", result.getMarketingDeputyDirectorOpinion() == null ? "" : result.getMarketingDeputyDirectorOpinion());
  329 + }
  330 + } else {
  331 + dataMap.put("marketingDeputyDirectorPass", "□同意生产");
  332 + dataMap.put("marketingDeputyDirectorRefuse", "□不同意生产及原因");
  333 + }
  334 + dataMap.put("officeManagementSupervisorOpinion", "");
  335 + if (StringUtils.isNotEmpty(result.getOfficeManagementSupervisorReview())) {
  336 + if ("PASS".equals(result.getOfficeManagementSupervisorReview())) {
  337 + dataMap.put("officeManagementSupervisorPass", "☑同意生产");
  338 + dataMap.put("officeManagementSupervisorRefuse", "□不同意生产及原因");
  339 + } else {
  340 + dataMap.put("officeManagementSupervisorPass", "□同意生产");
  341 + dataMap.put("officeManagementSupervisorRefuse", "☑不同意生产及原因");
  342 + dataMap.put("officeManagementSupervisorOpinion", result.getOfficeManagementSupervisorOpinion() == null ? "" : result.getOfficeManagementSupervisorOpinion());
  343 + }
  344 + } else {
  345 + dataMap.put("officeManagementSupervisorPass", "□同意生产");
  346 + dataMap.put("officeManagementSupervisorRefuse", "□不同意生产及原因");
  347 + }
  348 + dataMap.put("qualityManagerOpinion", "");
  349 + if (StringUtils.isNotEmpty(result.getQualityManagerReview())) {
  350 + if ("PASS".equals(result.getQualityManagerReview())) {
  351 + dataMap.put("qualityManagerPass", "☑同意生产");
  352 + dataMap.put("qualityManagerRefuse", "□不同意生产及原因");
  353 + } else {
  354 + dataMap.put("qualityManagerPass", "□同意生产");
  355 + dataMap.put("qualityManagerRefuse", "☑不同意生产及原因");
  356 + dataMap.put("qualityManagerOpinion", result.getQualityManagerOpinion() == null ? "" : result.getQualityManagerOpinion());
  357 + }
  358 + } else {
  359 + dataMap.put("qualityManagerPass", "□同意生产");
  360 + dataMap.put("qualityManagerRefuse", "□不同意生产及原因");
  361 + }
  362 + dataMap.put("branchFactorySupervisorOpinion", "");
  363 + if (StringUtils.isNotEmpty(result.getBranchFactorySupervisorReview())) {
  364 + if ("PASS".equals(result.getBranchFactorySupervisorReview())) {
  365 + dataMap.put("branchFactorySupervisorPass", "☑同意生产");
  366 + dataMap.put("branchFactorySupervisorRefuse", "□不同意生产及原因");
  367 + } else {
  368 + dataMap.put("branchFactorySupervisorPass", "□同意生产");
  369 + dataMap.put("branchFactorySupervisorRefuse", "☑不同意生产及原因");
  370 + dataMap.put("branchFactorySupervisorOpinion", result.getBranchFactorySupervisorOpinion() == null ? "" : result.getBranchFactorySupervisorOpinion());
  371 + }
  372 + } else {
  373 + dataMap.put("branchFactorySupervisorPass", "□同意生产");
  374 + dataMap.put("branchFactorySupervisorRefuse", "□不同意生产及原因");
  375 + }
  376 + dataMap.put("marketingDepartmentManagerOpinion", "");
  377 + if (StringUtils.isNotEmpty(result.getMarketingDepartmentManagerReview())) {
  378 + if ("PASS".equals(result.getMarketingDepartmentManagerReview())) {
  379 + dataMap.put("marketingDepartmentManagerPass", "☑同意生产");
  380 + dataMap.put("marketingDepartmentManagerRefuse", "□不同意生产及原因");
  381 + } else {
  382 + dataMap.put("marketingDepartmentManagerPass", "□同意生产");
  383 + dataMap.put("marketingDepartmentManagerRefuse", "☑不同意生产及原因");
  384 + dataMap.put("marketingDepartmentManagerOpinion", result.getMarketingDepartmentManagerOpinion() == null ? "" : result.getMarketingDepartmentManagerOpinion());
  385 + }
  386 + } else {
  387 + dataMap.put("marketingDepartmentManagerPass", "□同意生产");
  388 + dataMap.put("marketingDepartmentManagerRefuse", "□不同意生产及原因");
  389 + }
  390 + dataMap.put("marketingCenterSupervisorOpinion", "");
  391 + if (StringUtils.isNotEmpty(result.getMarketingCenterSupervisorReview())) {
  392 + if ("PASS".equals(result.getMarketingCenterSupervisorReview())) {
  393 + dataMap.put("marketingCenterSupervisorPass", "☑同意生产");
  394 + dataMap.put("marketingCenterSupervisorRefuse", "□不同意生产及原因");
  395 + } else {
  396 + dataMap.put("marketingCenterSupervisorPass", "□同意生产");
  397 + dataMap.put("marketingCenterSupervisorRefuse", "☑不同意生产及原因");
  398 + dataMap.put("marketingCenterSupervisorOpinion", result.getMarketingCenterSupervisorOpinion() == null ? "" : result.getMarketingCenterSupervisorOpinion());
  399 + }
  400 + } else {
  401 + dataMap.put("marketingCenterSupervisorPass", "□同意生产");
  402 + dataMap.put("marketingCenterSupervisorRefuse", "□不同意生产及原因");
  403 + }
  404 + dataMap.put("generalManagerOpinion", "");
  405 + if (StringUtils.isNotEmpty(result.getGeneralManagerReview())) {
  406 + if ("PASS".equals(result.getGeneralManagerReview())) {
  407 + dataMap.put("generalManagerPass", "☑同意生产");
  408 + dataMap.put("generalManagerRefuse", "□不同意生产及原因");
  409 + } else {
  410 + dataMap.put("generalManagerPass", "□同意生产");
  411 + dataMap.put("generalManagerRefuse", "☑不同意生产及原因");
  412 + dataMap.put("generalManagerOpinion", result.getGeneralManagerOpinion() == null ? "" : result.getGeneralManagerOpinion());
  413 + }
  414 + } else {
  415 + dataMap.put("generalManagerPass", "□同意生产");
  416 + dataMap.put("generalManagerRefuse", "□不同意生产及原因");
  417 + }
  418 + ExcelUtil.processTemplate(workbook, dataMap);
  419 +
  420 + // 写入响应流
  421 + workbook.write(response.getOutputStream());
  422 + response.getOutputStream().flush();
  423 + } finally {
  424 + IOUtils.closeQuietly(workbook);
  425 + }
  426 +
  427 + } catch (FileNotFoundException e) {
  428 + throw new RuntimeException("模板文件不存在: templates/confirmationSlipTemplate.xlsx", e);
  429 + } catch (IOException e) {
  430 + throw new RuntimeException("无法读取模板文件: templates/confirmationSlipTemplate.xlsx", e);
  431 + }
  432 + } catch (Exception e) {
  433 + log.error("产品试样确认单打印: {}", e.getMessage(), e);
  434 + throw e;
  435 + }
  436 + }
  437 +
  438 +
  439 + /**
  440 + * 设置HTTP响应头
  441 + */
  442 + private void setupResponse(HttpServletResponse response, String fileName) throws IOException {
  443 + String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
  444 +
  445 + response.setContentType("application/vnd.ms-excel");
  446 + response.setCharacterEncoding("UTF-8");
  447 + response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName);
  448 + response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
  449 + }
  450 +
  451 + public static void copyRow(Workbook workbook, Sheet sheet,
  452 + int sourceRowIndex, int targetRowIndex) {
  453 +
  454 + // 移动目标行及之后的行
  455 + if (targetRowIndex <= sheet.getLastRowNum()) {
  456 + sheet.shiftRows(targetRowIndex, sheet.getLastRowNum(), 1, true, false);
  457 + }
  458 +
  459 + // 复制行内容
  460 + Row sourceRow = sheet.getRow(sourceRowIndex);
  461 + Row newRow = sheet.createRow(targetRowIndex);
  462 + newRow.setHeight(sourceRow.getHeight());
  463 +
  464 + // 复制单元格
  465 + for (int i = 0; i < sourceRow.getLastCellNum(); i++) {
  466 + Cell oldCell = sourceRow.getCell(i);
  467 + Cell newCell = newRow.createCell(i);
  468 +
  469 + if (oldCell != null) {
  470 + copyCell(workbook, oldCell, newCell);
  471 + }
  472 + }
  473 + // === 关键:清除源行上的所有合并区域(防止被“复制”)===
  474 + List<Integer> regionsToRemove = new ArrayList<>();
  475 + for (int j = 0; j < sheet.getNumMergedRegions(); j++) {
  476 + CellRangeAddress region = sheet.getMergedRegion(j);
  477 + if (region.getFirstRow() == sourceRowIndex || region.getLastRow() == sourceRowIndex) {
  478 + regionsToRemove.add(j);
  479 + }
  480 + }
  481 +
  482 + // 从后往前删除,避免索引偏移
  483 + Collections.reverse(regionsToRemove);
  484 + for (int idx : regionsToRemove) {
  485 + sheet.removeMergedRegion(idx);
  486 + }
  487 +
  488 + }
  489 +
  490 +
  491 + /**
  492 + * 复制单元格内容和样式
  493 + */
  494 + private static void copyCell(Workbook workbook, Cell oldCell, Cell newCell) {
  495 + if (oldCell.getCellStyle() != null) {
  496 + newCell.setCellStyle(oldCell.getCellStyle());
  497 + }
  498 +
  499 + switch (oldCell.getCellTypeEnum()) {
  500 + case STRING:
  501 + newCell.setCellValue(oldCell.getStringCellValue());
  502 + break;
  503 + case NUMERIC:
  504 + newCell.setCellValue(oldCell.getNumericCellValue());
  505 + break;
  506 + case BOOLEAN:
  507 + newCell.setCellValue(oldCell.getBooleanCellValue());
  508 + break;
  509 + case FORMULA:
  510 + newCell.setCellFormula(oldCell.getCellFormula());
  511 + break;
  512 + default:
  513 + newCell.setCellValue(oldCell.getStringCellValue());
  514 + break;
  515 + }
  516 + }
  517 +
150 518 }
... ...
... ... @@ -111,6 +111,12 @@ public class ProductSampleConfirmationSlip extends BaseEntity implements BaseDto
111 111 private String preparedBy;
112 112
113 113 /**
  114 + * 制单人姓名
  115 + */
  116 + @TableField(exist = false)
  117 + private String preparedByName;
  118 +
  119 + /**
114 120 * 审核状态
115 121 */
116 122 private String status;
... ...
... ... @@ -20,6 +20,7 @@
20 20 <result column="sample_frequency" property="sampleFrequency"/>
21 21 <result column="early_nonconformity_description" property="earlyNonconformityDescription"/>
22 22 <result column="prepared_by" property="preparedBy"/>
  23 + <result column="prepared_by_name" property="preparedByName"/>
23 24 <result column="status" property="status"/>
24 25 <result column="office_clerk" property="officeClerk"/>
25 26 <result column="office_clerk_review" property="officeClerkReview"/>
... ... @@ -74,6 +75,7 @@
74 75 tb.sample_frequency,
75 76 tb.early_nonconformity_description,
76 77 tb.prepared_by,
  78 + su.name AS prepared_by_name,
77 79 tb.status,
78 80 tb.office_clerk,
79 81 tb.office_clerk_review,
... ... @@ -110,6 +112,7 @@
110 112 FROM product_sample_confirmation_slip AS tb
111 113 left join base_data_customer as cu on cu.id = tb.ordering_unit
112 114 left join base_data_workshop as ws on ws.id = tb.workshop_id
  115 + left join sys_user as su on su.id = tb.prepared_by
113 116 </sql>
114 117
115 118 <select id="query" resultMap="ProductSampleConfirmationSlip">
... ...