Commit de2b6ca9582918c023328797feab1b0e9fcff2e7

Authored by 房远帅
1 parent 1d7e73d9

楚江ERP:规格变更-打印模板修改

... ... @@ -29,6 +29,8 @@ import com.lframework.starter.common.utils.CollectionUtil;
29 29 import io.swagger.annotations.Api;
30 30 import lombok.extern.slf4j.Slf4j;
31 31 import org.apache.commons.lang3.StringUtils;
  32 +import org.apache.poi.ss.usermodel.Cell;
  33 +import org.apache.poi.ss.usermodel.Row;
32 34 import org.apache.poi.ss.usermodel.Sheet;
33 35 import org.apache.poi.ss.usermodel.Workbook;
34 36 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
... ... @@ -41,8 +43,7 @@ import java.io.FileNotFoundException;
41 43 import java.io.IOException;
42 44 import java.io.InputStream;
43 45 import java.time.format.DateTimeFormatter;
44   -import java.util.List;
45   -import java.util.Map;
  46 +import java.util.*;
46 47 import java.util.stream.Collectors;
47 48
48 49 /**
... ... @@ -160,76 +161,244 @@ public class OrderChangeRecordController extends DefaultBaseController {
160 161 public void printOrderSpecChangeRecord(@NotBlank(message = "id不能为空") String id, HttpServletResponse response) {
161 162 OrderInfoChangeRecord data = orderChangeRecordService.findById(id);
162 163 if (data == null) {
163   - throw new DefaultClientException("规格变更记录不存在!");
  164 + throw new DefaultClientException("规格变更记录不存在!");
164 165 }
165   - // 加载模板文件
  166 +
166 167 ClassPathResource templateResource = new ClassPathResource("templates/orderSpecChangeTemplate.xlsx");
167 168 try (InputStream inputStream = templateResource.getStream();
168   - Workbook workbook = new XSSFWorkbook(inputStream)) {
169   - // 设置响应头
170   - ResponseUtil.setExcelResponseHead(response, data.getOrderNo() + "-订货单变更记录.xlsx");
  169 + Workbook workbook = new XSSFWorkbook(inputStream)) {
171 170
  171 + ResponseUtil.setExcelResponseHead(response, data.getOrderNo() + "-订货单变更记录.xlsx");
172 172 Sheet sheet = workbook.getSheetAt(0);
173   - // 规格变更开始行
174   - int startRow = 5;
  173 +
175 174 DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  175 +
  176 + // 获取变更前后数据
176 177 List<PurchaseOrderLine> beforeChangeSpecList = data.getBeforeChangeSpecList();
177 178 List<PurchaseOrderLine> afterChangeSpecList = data.getAfterChangeSpecList();
178   - // 取最大数据行
179   - int dataLine = Math.max(beforeChangeSpecList.size(), afterChangeSpecList.size());
180   - for (int i = startRow + 1; i < startRow + dataLine; i++) {
181   - ExcelUtil.copyRow(workbook, sheet, startRow, i);
  179 +
  180 + updateWithChangeInfo(beforeChangeSpecList, afterChangeSpecList);
  181 +
  182 + // 过滤需要显示的变更前记录(DELETE 或 UPDATE 且有变化)
  183 + List<PurchaseOrderLine> beforeLines = beforeChangeSpecList.stream()
  184 + .filter(line -> "DELETE".equals(line.getType()) ||
  185 + ("UPDATE".equals(line.getType()) &&
  186 + (line.getBrandChange() || line.getLengthChange() || line.getWidthChange() ||
  187 + line.getThicknessChange() || line.getStatusChange() ||
  188 + line.getQuantityChange() || line.getSalesPriceChange())))
  189 + .collect(Collectors.toList());
  190 +
  191 + // 过滤需要显示的变更后记录(ADD 或 UPDATE 且有变化)
  192 + List<PurchaseOrderLine> afterLines = afterChangeSpecList.stream()
  193 + .filter(line -> "ADD".equals(line.getType()) ||
  194 + ("UPDATE".equals(line.getType()) &&
  195 + (line.getBrandChange() || line.getLengthChange() || line.getWidthChange() ||
  196 + line.getThicknessChange() || line.getStatusChange() ||
  197 + line.getQuantityChange() || line.getSalesPriceChange())))
  198 + .collect(Collectors.toList());
  199 +
  200 + // ========== 填充变更前区域(起始行:6)==========
  201 + // ========== 填充变更前区域 ==========
  202 + int beforeStartRow = 5;
  203 + int beforeRowCount = Math.max(beforeLines.size(), 1);
  204 + for (int i = beforeStartRow + 1; i < beforeStartRow + beforeRowCount; i++) {
  205 + ExcelUtil.copyRow(workbook, sheet, beforeStartRow, i);
182 206 }
183   - for (int i = 0; i < dataLine; i++) {
184   - PurchaseOrderLine beforeOrderLine = (i + 1) <= beforeChangeSpecList.size() ? beforeChangeSpecList.get(i) : null;
185   - PurchaseOrderLine afterOrderLine = (i + 1) <= afterChangeSpecList.size() ? afterChangeSpecList.get(i) : null;
186   - // 变更前数据填充
187   - if (beforeOrderLine != null ) {
188   - ExcelUtil.setCellValue(sheet, startRow, 0, beforeOrderLine.getBrand());
189   - ExcelUtil.setCellValue(sheet, startRow, 1, beforeOrderLine.getThickness());
190   - ExcelUtil.setCellValue(sheet, startRow, 2, beforeOrderLine.getWidth());
191   - ExcelUtil.setCellValue(sheet, startRow, 3, beforeOrderLine.getLength());
192   - ExcelUtil.setCellValue(sheet, startRow, 4, beforeOrderLine.getStatus());
193   - ExcelUtil.setCellValue(sheet, startRow, 5, beforeOrderLine.getQuantity());
194   - ExcelUtil.setCellValue(sheet, startRow, 6, beforeOrderLine.getSalesPrice());
  207 + for (int i = 0; i < beforeRowCount; i++) {
  208 + PurchaseOrderLine line = i < beforeLines.size() ? beforeLines.get(i) : null;
  209 + int rowIdx = beforeStartRow + i;
  210 + if (line != null) {
  211 + ExcelUtil.setCellValue(sheet, rowIdx, 0, line.getBrand());
  212 + ExcelUtil.setCellValue(sheet, rowIdx, 1, line.getThickness());
  213 + ExcelUtil.setCellValue(sheet, rowIdx, 2, line.getWidth());
  214 + ExcelUtil.setCellValue(sheet, rowIdx, 3, line.getLength());
  215 + ExcelUtil.setCellValue(sheet, rowIdx, 4, line.getStatus());
  216 + ExcelUtil.setCellValue(sheet, rowIdx, 5, line.getQuantity());
  217 + ExcelUtil.setCellValue(sheet, rowIdx, 6, line.getSalesPrice());
  218 + ExcelUtil.setCellValue(sheet, rowIdx, 7,
  219 + line.getDeliveryDate() == null ? "" : line.getDeliveryDate().format(dateFormatter));
  220 + } else {
  221 + for (int col = 0; col <= 7; col++) {
  222 + ExcelUtil.setCellValue(sheet, rowIdx, col, "");
  223 + }
195 224 }
196   - // 变更后数据填充
197   - if (afterOrderLine != null) {
198   - ExcelUtil.setCellValue(sheet, startRow, 7, afterOrderLine.getBrand());
199   - ExcelUtil.setCellValue(sheet, startRow, 8, afterOrderLine.getThickness());
200   - ExcelUtil.setCellValue(sheet, startRow, 9, afterOrderLine.getWidth());
201   - ExcelUtil.setCellValue(sheet, startRow, 10, afterOrderLine.getLength());
202   - ExcelUtil.setCellValue(sheet, startRow, 11, afterOrderLine.getStatus());
203   - ExcelUtil.setCellValue(sheet, startRow, 12, afterOrderLine.getQuantity());
204   - ExcelUtil.setCellValue(sheet, startRow, 13, afterOrderLine.getSalesPrice());
  225 + }
  226 +
  227 + // ========== 填充变更后区域 ==========
  228 + int afterStartRow = 9 + (beforeRowCount - 1); //(默认第10行起始行,需要加上复制的行)
  229 + int afterRowCount = Math.max(afterLines.size(), 1);
  230 + for (int i = afterStartRow + 1; i < afterStartRow + afterRowCount; i++) {
  231 + ExcelUtil.copyRow(workbook, sheet, afterStartRow, i);
  232 + }
  233 + for (int i = 0; i < afterRowCount; i++) {
  234 + PurchaseOrderLine line = i < afterLines.size() ? afterLines.get(i) : null;
  235 + int rowIdx = afterStartRow + i;
  236 + if (line != null) {
  237 + ExcelUtil.setCellValue(sheet, rowIdx, 0, line.getBrand());
  238 + ExcelUtil.setCellValue(sheet, rowIdx, 1, line.getThickness());
  239 + ExcelUtil.setCellValue(sheet, rowIdx, 2, line.getWidth());
  240 + ExcelUtil.setCellValue(sheet, rowIdx, 3, line.getLength());
  241 + ExcelUtil.setCellValue(sheet, rowIdx, 4, line.getStatus());
  242 + ExcelUtil.setCellValue(sheet, rowIdx, 5, line.getQuantity());
  243 + ExcelUtil.setCellValue(sheet, rowIdx, 6, line.getSalesPrice());
  244 + ExcelUtil.setCellValue(sheet, rowIdx, 7,
  245 + line.getDeliveryDate() == null ? "" : line.getDeliveryDate().format(dateFormatter));
  246 + } else {
  247 + for (int col = 0; col <= 7; col++) {
  248 + ExcelUtil.setCellValue(sheet, rowIdx, col, "");
  249 + }
205 250 }
206   - startRow++;
207 251 }
208   - Map<String, Object> dataMap = JsonUtil.parseMap(JsonUtil.toJsonString(data), String.class, Object.class);
  252 +
  253 + // ========== 填充顶部固定字段 ==========
  254 + Map<String, Object> dataMap = new HashMap<>();
  255 + dataMap.put("orderingUnitName", StringUtils.defaultString(data.getOrderingUnitName()));
  256 + dataMap.put("orderNo", StringUtils.defaultString(data.getOrderNo()));
209 257 dataMap.put("orderDate", data.getOrderDate() == null ? "" : data.getOrderDate().format(dateFormatter));
210   - dataMap.put("createTime", data.getCreateTime().format(dateFormatter));
211   - // 供货单位
  258 + dataMap.put("createTime", data.getCreateTime() == null ? "" : data.getCreateTime().format(dateFormatter));
  259 + dataMap.put("createBy", StringUtils.defaultString(data.getCreateBy()));
  260 + dataMap.put("changeDescription", StringUtils.defaultString(data.getChangeDescription()));
  261 +
212 262 String supplyUnit = data.getSupplyUnit();
213   - if (StringUtils.isNotBlank(supplyUnit)) {
214   - if ("GJ".equals(supplyUnit)) {
215   - dataMap.put("supplyUnit", "安徽楚江高精铜带有限公司");
216   - } else if ("XC".equals(supplyUnit)) {
217   - dataMap.put("supplyUnit", "安徽楚江科技新材料股份有限公司");
218   - }
  263 + if ("GJ".equals(supplyUnit)) {
  264 + dataMap.put("supplyUnit", "安徽楚江高精铜带有限公司");
  265 + } else if ("XC".equals(supplyUnit)) {
  266 + dataMap.put("supplyUnit", "安徽楚江科技新材料股份有限公司");
  267 + } else {
  268 + dataMap.put("supplyUnit", StringUtils.defaultString(supplyUnit));
219 269 }
  270 +
220 271 ExcelUtil.processTemplate(workbook, dataMap);
221   - // 写入响应流
  272 +
  273 + // 输出
222 274 workbook.write(response.getOutputStream());
223 275 response.getOutputStream().flush();
224   - } catch (FileNotFoundException e) {
225   - log.error("订货单变更模版打印失败: ", e);
226   - throw new DefaultClientException("模板文件不存在: templates/orderSpecChangeTemplate.xlsx");
227   - } catch (IOException e) {
228   - log.error("订货单变更模版打印失败: ", e);
229   - throw new DefaultClientException("无法读取模板文件: templates/orderSpecChangeTemplate.xlsx");
  276 +
230 277 } catch (Exception e) {
231   - log.error("订货单变更模版打印失败: ", e);
232   - throw new DefaultClientException(e.getMessage());
  278 + log.error("规格变更打印失败", e);
  279 + throw new DefaultClientException("打印失败:" + e.getMessage());
  280 + }
  281 + }
  282 +
  283 + /**
  284 + * 完善两个核心人员列表中的 type 和 xxxChange 字段
  285 + * 不增删对象,仅完善字段
  286 + *
  287 + * @param beforeChangeSpecList 变更前列表(会被完善字段)
  288 + * @param afterChangeSpecList 变更后列表(会被完善字段)
  289 + */
  290 + public void updateWithChangeInfo(
  291 + List<PurchaseOrderLine> beforeChangeSpecList,
  292 + List<PurchaseOrderLine> afterChangeSpecList) {
  293 +
  294 + // 允许 null 输入
  295 + if (beforeChangeSpecList == null) beforeChangeSpecList = new ArrayList<>();
  296 + if (afterChangeSpecList == null) afterChangeSpecList = new ArrayList<>();
  297 +
  298 + // 构建 Map<id, obj> 便于快速查找
  299 + Map<String, PurchaseOrderLine> beforeMap = toMapBefore(beforeChangeSpecList);
  300 + Map<String, PurchaseOrderLine> afterMap = toMapAfter(afterChangeSpecList);
  301 +
  302 + // === 1. 处理变更前列表:判断是 DELETE 还是 UPDATE ===
  303 + for (PurchaseOrderLine beforeItem : beforeChangeSpecList) {
  304 + String id = beforeItem.getId();
  305 + PurchaseOrderLine afterItem = afterMap.get(id);
  306 +
  307 + if (afterItem == null) {
  308 + // 只在 before 中存在 → 删除
  309 + beforeItem.setType("DELETE");
  310 + setAllChangeFields(beforeItem, false); // 删除时字段无变化
  311 + } else {
  312 + // 在前后都存在 → 修改
  313 + beforeItem.setType("UPDATE");
  314 + // 比较字段,设置 change 标志
  315 + compareAndSetChanges(beforeItem, beforeItem, afterItem);
  316 + }
  317 + }
  318 +
  319 + // === 2. 处理变更后列表:判断是 ADD 还是 UPDATE ===
  320 + for (PurchaseOrderLine afterItem : afterChangeSpecList) {
  321 + String id = afterItem.getAfterId();
  322 + PurchaseOrderLine beforeItem = beforeMap.get(id);
  323 +
  324 + if (beforeItem == null) {
  325 + // 只在 after 中存在 → 新增
  326 + afterItem.setType("ADD");
  327 + setAllChangeFields(afterItem, false); // 新增时字段视为“未变”(或可设 true)
  328 + } else {
  329 + // 在前后都存在 → 修改
  330 + afterItem.setType("UPDATE");
  331 + // 比较字段,设置 change 标志
  332 + compareAndSetChanges(afterItem, beforeItem, afterItem);
  333 + }
233 334 }
234 335 }
  336 +
  337 + // 辅助方法:转为 Map<id, entity>
  338 + private Map<String, PurchaseOrderLine> toMapBefore(List<PurchaseOrderLine> list) {
  339 + Map<String, PurchaseOrderLine> map = new HashMap<>();
  340 + for (PurchaseOrderLine obj : list) {
  341 + if (obj != null && obj.getId() != null) {
  342 + map.put(obj.getId(), obj);
  343 + }
  344 + }
  345 + return map;
  346 + }
  347 +
  348 + // 辅助方法:转为 Map<id, entity>
  349 + private Map<String, PurchaseOrderLine> toMapAfter(List<PurchaseOrderLine> list) {
  350 + Map<String, PurchaseOrderLine> map = new HashMap<>();
  351 + for (PurchaseOrderLine obj : list) {
  352 + if (obj != null) {
  353 + if (obj.getAfterId() != null) {
  354 + map.put(obj.getAfterId(), obj);
  355 + } else {
  356 + map.put(obj.getId(), obj);
  357 + }
  358 + }
  359 + }
  360 + return map;
  361 + }
  362 +
  363 + // 辅助方法:设置所有 change 字段
  364 + private void setAllChangeFields(PurchaseOrderLine item, boolean value) {
  365 + if (item == null) return;
  366 + item.setBrandChange(value);
  367 + item.setThicknessChange(value);
  368 + item.setWidthChange(value);
  369 + item.setLengthChange(value);
  370 + item.setStatusChange(value);
  371 + item.setQuantityChange(value);
  372 + item.setSalesPriceChange(value);
  373 + }
  374 +
  375 + /**
  376 + * 比较 before 和 after,将变化的字段在 target 上设为 true
  377 + */
  378 + private void compareAndSetChanges(
  379 + PurchaseOrderLine target,
  380 + PurchaseOrderLine before,
  381 + PurchaseOrderLine after) {
  382 +
  383 + if (target == null || before == null || after == null) return;
  384 +
  385 + target.setBrandChange(!Objects.equals(before.getBrand(), after.getBrand()));
  386 + target.setThicknessChange(before.getThickness() != null && after.getThickness() != null
  387 + ? before.getThickness().compareTo(after.getThickness()) != 0
  388 + : !Objects.equals(before.getThickness(), after.getThickness()));
  389 + target.setWidthChange(before.getWidth() != null && after.getWidth() != null
  390 + ? before.getWidth().compareTo(after.getWidth()) != 0
  391 + : !Objects.equals(before.getWidth(), after.getWidth()));
  392 + target.setLengthChange(before.getLength() != null && after.getLength() != null
  393 + ? before.getLength().compareTo(after.getLength()) != 0
  394 + : !Objects.equals(before.getLength(), after.getLength()));
  395 + target.setStatusChange(!Objects.equals(before.getStatus(), after.getStatus()));
  396 + target.setQuantityChange(before.getQuantity() != null && after.getQuantity() != null
  397 + ? before.getQuantity().compareTo(after.getQuantity()) != 0
  398 + : !Objects.equals(before.getQuantity(), after.getQuantity()));
  399 + target.setSalesPriceChange(before.getSalesPrice() != null && after.getSalesPrice() != null
  400 + ? before.getSalesPrice().compareTo(after.getSalesPrice()) != 0
  401 + : !Objects.equals(before.getSalesPrice(), after.getSalesPrice()));
  402 + }
  403 +
235 404 }
... ...