Showing
2 changed files
with
222 additions
and
53 deletions
xingyun-sc/src/main/java/com/lframework/xingyun/sc/controller/order/OrderChangeRecordController.java
| ... | ... | @@ -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 | } | ... | ... |
No preview for this file type