You've already forked FrameTour-BE
refactor(printer): 优化照片处理管线与自动发券逻辑
- 调整自动发券判断条件,仅当存在type=3的source记录时触发 - 修改普通照片与拼图处理流程中的图像增强控制逻辑 - 移除冗余的图像缩放阶段,优化处理效率 - 增加processPhotoWithPipeline重载方法支持图像增强选项 - 重构水印配置方法,新增scale参数控制缩放比例 - 异步处理打印任务创建与推送,提升响应速度 - 复用processPhotoWithPipeline方法简化重打印处理逻辑
This commit is contained in:
@@ -351,6 +351,8 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
|
||||
log.info("照片裁剪成功: memberId={}, scenicId={}, 原图={}, 裁剪后={}, 尺寸={}x{}",
|
||||
memberId, scenicId, url, cropUrl, printWidth, printHeight);
|
||||
String crop = JacksonUtil.toJSONString(new Crop(270));
|
||||
entity.setCrop(crop);
|
||||
} finally {
|
||||
// 清理临时文件
|
||||
if (croppedFile != null && croppedFile.exists()) {
|
||||
@@ -471,6 +473,34 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
|
||||
request.setProducts(productItems);
|
||||
|
||||
// 检查是否存在type=3的source记录,存在才自动发券
|
||||
boolean hasType3Source = userPhotoList.stream()
|
||||
.filter(item -> item.getSourceId() != null && item.getSourceId() > 0)
|
||||
.anyMatch(item -> {
|
||||
try {
|
||||
SourceEntity source = sourceMapper.getEntity(item.getSourceId());
|
||||
return source != null && Integer.valueOf(3).equals(source.getType());
|
||||
} catch (Exception e) {
|
||||
log.warn("查询source失败: sourceId={}, error={}", item.getSourceId(), e.getMessage());
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasType3Source) {
|
||||
if (normalCount > 0) {
|
||||
try {
|
||||
autoCouponService.autoGrantCoupon(
|
||||
memberId,
|
||||
faceId,
|
||||
scenicId,
|
||||
ProductType.PHOTO_PRINT
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.warn("自动发券失败,不影响下单流程: memberId={}, faceId={}, scenicId={}, error={}",
|
||||
memberId, faceId, scenicId, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mobileCount > 0) {
|
||||
try {
|
||||
autoCouponService.autoGrantCoupon(
|
||||
@@ -484,19 +514,6 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
memberId, faceId, scenicId, e.getMessage());
|
||||
}
|
||||
}
|
||||
if (normalCount > 0) {
|
||||
try {
|
||||
autoCouponService.autoGrantCoupon(
|
||||
memberId,
|
||||
faceId,
|
||||
scenicId,
|
||||
ProductType.PHOTO_PRINT
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.warn("自动发券失败,不影响下单流程: memberId={}, faceId={}, scenicId={}, error={}",
|
||||
memberId, faceId, scenicId, e.getMessage());
|
||||
}
|
||||
}
|
||||
request.setAutoUseCoupon(true);
|
||||
request.setPreviewOnly(true); // 仅查询价格,不实际使用优惠
|
||||
|
||||
@@ -795,7 +812,6 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
.addStage(new ImageOrientationStage())
|
||||
.addStage(new ConditionalRotateStage())
|
||||
.addStage(new ImageEnhanceStage(config)) // 通过setStageState方法设置是否启用
|
||||
.addStage(new ImageResizeStage(2.0 / 3.0)) // 缩小2/3倍(回到原分辨率)
|
||||
.addStage(new WatermarkStage(watermarkConfig))
|
||||
.addStage(new RestoreOrientationStage())
|
||||
.addStage(new UploadStage())
|
||||
@@ -823,6 +839,18 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
* @return 处理后的URL,失败返回原URL
|
||||
*/
|
||||
private String processPhotoWithPipeline(MemberPrintResp item, Long scenicId, File qrCodeFile) {
|
||||
return processPhotoWithPipeline(item, scenicId, qrCodeFile, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用管线处理照片(支持增强选项)
|
||||
* @param item 打印项
|
||||
* @param scenicId 景区ID
|
||||
* @param qrCodeFile 二维码文件
|
||||
* @param needEnhance 是否需要图像增强(null 或 false 表示不增强)
|
||||
* @return 处理后的URL,失败返回原URL
|
||||
*/
|
||||
private String processPhotoWithPipeline(MemberPrintResp item, Long scenicId, File qrCodeFile, Boolean needEnhance) {
|
||||
PrinterOrderItem orderItem = PrinterOrderItem.fromMemberPrintResp(item);
|
||||
|
||||
PhotoProcessContext context = PhotoProcessContext.fromPrinterOrderItem(orderItem, scenicId);
|
||||
@@ -835,6 +863,11 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
// 设置管线场景为图片打印
|
||||
context.setScene(PipelineScene.IMAGE_PRINT);
|
||||
|
||||
// 处理图像增强选项
|
||||
if (needEnhance != null && needEnhance) {
|
||||
context.setStageState("image_enhance", true);
|
||||
}
|
||||
|
||||
// 根据sourceId判断图片来源和source类型
|
||||
SourceEntity source = null;
|
||||
if (item.getSourceId() != null && item.getSourceId() > 0) {
|
||||
@@ -861,13 +894,13 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
bceConfig.setSecretKey("dYatXReVriPeiktTjUblhfubpcmYfuMk");
|
||||
|
||||
// 准备水印配置
|
||||
WatermarkConfig watermarkConfig = prepareWatermarkConfig(context, qrCodeFile);
|
||||
WatermarkConfig watermarkConfig = prepareWatermarkConfig(context, qrCodeFile, 3.0);
|
||||
// 准备存储适配器
|
||||
prepareStorageAdapter(context);
|
||||
context.enableStage("image_sr");
|
||||
context.enableStage("image_enhance");
|
||||
|
||||
// 构建特殊管线: 放大1.5倍 -> 超分(2倍) -> 增强 -> 更新MemberPrint -> 缩小3倍 -> 水印 -> 上传
|
||||
// 构建特殊管线: 超分(2倍) -> 增强 -> 更新MemberPrint -> 缩小2倍 -> 水印 -> 上传
|
||||
pipeline = new PipelineBuilder<PhotoProcessContext>("Type3Pipeline")
|
||||
.addStage(new DownloadStage()) // 1. 下载图片
|
||||
.addStage(new ImageOrientationStage()) // 2. 检测方向
|
||||
@@ -877,7 +910,6 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
.addStage(new UploadStage()) // 6. 上传(用于更新MemberPrint)
|
||||
.addStage(new UpdateMemberPrintStage(printerMapper, // 7. 更新MemberPrint的cropUrl
|
||||
item.getId(), item.getMemberId(), scenicId))
|
||||
.addStage(new ImageResizeStage(4.0 / 3.0)) // 8. 缩小3倍(回到原分辨率)
|
||||
.addStage(new WatermarkStage(watermarkConfig)) // 9. 添加水印
|
||||
.addStage(new RestoreOrientationStage()) // 10. 恢复方向
|
||||
.addStage(new UploadStage()) // 11. 最终上传
|
||||
@@ -886,7 +918,7 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
|
||||
} else if (context.getImageType() == ImageType.NORMAL_PHOTO) {
|
||||
// 普通照片处理流程
|
||||
WatermarkConfig watermarkConfig = prepareWatermarkConfig(context, qrCodeFile);
|
||||
WatermarkConfig watermarkConfig = prepareWatermarkConfig(context, qrCodeFile, 1.5);
|
||||
prepareStorageAdapter(context);
|
||||
pipeline = createNormalPhotoPipeline(watermarkConfig);
|
||||
} else {
|
||||
@@ -924,7 +956,7 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
* @param qrCodeFile 二维码文件
|
||||
* @return WatermarkConfig
|
||||
*/
|
||||
private WatermarkConfig prepareWatermarkConfig(PhotoProcessContext context, File qrCodeFile) {
|
||||
private WatermarkConfig prepareWatermarkConfig(PhotoProcessContext context, File qrCodeFile, Double scale) {
|
||||
ScenicConfigManager scenicConfig = context.getScenicConfigManager();
|
||||
if (scenicConfig == null) {
|
||||
log.warn("scenicConfigManager未设置,返回空水印配置");
|
||||
@@ -945,6 +977,7 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
.scenicText(scenicText)
|
||||
.dateFormat(dateFormat)
|
||||
.qrcodeFile(qrCodeFile)
|
||||
.scale(scale)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -994,53 +1027,55 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
userPhotoListByOrderId.forEach(item -> {
|
||||
PrinterEntity printer = printerMapper.getById(item.getPrinterId());
|
||||
Thread.ofVirtual().start(() -> {
|
||||
userPhotoListByOrderId.forEach(item -> {
|
||||
PrinterEntity printer = printerMapper.getById(item.getPrinterId());
|
||||
|
||||
// 使用管线处理照片
|
||||
String printUrl = processPhotoWithPipeline(item, item.getScenicId(), qrCodeFile);
|
||||
// 使用管线处理照片
|
||||
String printUrl = processPhotoWithPipeline(item, item.getScenicId(), qrCodeFile);
|
||||
|
||||
// 根据数量创建多个打印任务
|
||||
Integer quantity = item.getQuantity();
|
||||
if (quantity == null || quantity <= 0) {
|
||||
quantity = 1; // 默认至少打印1张
|
||||
}
|
||||
// 根据数量创建多个打印任务
|
||||
Integer quantity = item.getQuantity();
|
||||
if (quantity == null || quantity <= 0) {
|
||||
quantity = 1; // 默认至少打印1张
|
||||
}
|
||||
|
||||
for (int i = 0; i < quantity; i++) {
|
||||
// 获取打印机名称(支持轮询)
|
||||
String selectedPrinter = getNextPrinter(printer);
|
||||
for (int i = 0; i < quantity; i++) {
|
||||
// 获取打印机名称(支持轮询)
|
||||
String selectedPrinter = getNextPrinter(printer);
|
||||
|
||||
// 根据景区配置决定任务初始状态
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(order.getScenicId());
|
||||
Boolean purchaseNeedReview = scenicConfig.getBoolean("printer_manual_approve");
|
||||
int initialStatus = (purchaseNeedReview != null && purchaseNeedReview)
|
||||
? TASK_STATUS_PENDING_REVIEW
|
||||
: TASK_STATUS_PENDING;
|
||||
// 根据景区配置决定任务初始状态
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(order.getScenicId());
|
||||
Boolean purchaseNeedReview = scenicConfig.getBoolean("printer_manual_approve");
|
||||
int initialStatus = (purchaseNeedReview != null && purchaseNeedReview)
|
||||
? TASK_STATUS_PENDING_REVIEW
|
||||
: TASK_STATUS_PENDING;
|
||||
|
||||
PrintTaskEntity task = new PrintTaskEntity();
|
||||
task.setPrinterId(printer.getId());
|
||||
task.setPrinterName(selectedPrinter);
|
||||
task.setMpId(item.getId());
|
||||
task.setPaper(printer.getPreferPaper());
|
||||
task.setStatus(initialStatus);
|
||||
task.setUrl(printUrl);
|
||||
task.setHeight(printer.getPreferH());
|
||||
task.setWidth(printer.getPreferW());
|
||||
task.setCreateTime(new Date());
|
||||
task.setUpdateTime(new Date());
|
||||
printTaskMapper.insertTask(task);
|
||||
PrintTaskEntity task = new PrintTaskEntity();
|
||||
task.setPrinterId(printer.getId());
|
||||
task.setPrinterName(selectedPrinter);
|
||||
task.setMpId(item.getId());
|
||||
task.setPaper(printer.getPreferPaper());
|
||||
task.setStatus(initialStatus);
|
||||
task.setUrl(printUrl);
|
||||
task.setHeight(printer.getPreferH());
|
||||
task.setWidth(printer.getPreferW());
|
||||
task.setCreateTime(new Date());
|
||||
task.setUpdateTime(new Date());
|
||||
printTaskMapper.insertTask(task);
|
||||
|
||||
// ========== WebSocket 推送任务 ==========
|
||||
// 只推送立即可处理的任务(status=0),待审核任务(status=4)等审核通过后再推送
|
||||
if (initialStatus == TASK_STATUS_PENDING) {
|
||||
try {
|
||||
taskPushService.pushTaskToPrinter(printer.getId(), task.getId());
|
||||
} catch (Exception e) {
|
||||
log.error("推送任务失败: printerId={}, taskId={}", printer.getId(), task.getId(), e);
|
||||
// 推送失败不影响任务创建,任务会通过 HTTP 轮询获取
|
||||
// ========== WebSocket 推送任务 ==========
|
||||
// 只推送立即可处理的任务(status=0),待审核任务(status=4)等审核通过后再推送
|
||||
if (initialStatus == TASK_STATUS_PENDING) {
|
||||
try {
|
||||
taskPushService.pushTaskToPrinter(printer.getId(), task.getId());
|
||||
} catch (Exception e) {
|
||||
log.error("推送任务失败: printerId={}, taskId={}", printer.getId(), task.getId(), e);
|
||||
// 推送失败不影响任务创建,任务会通过 HTTP 轮询获取
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1475,58 +1510,15 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
needEnhance = false; // 默认不增强
|
||||
}
|
||||
|
||||
// 3.1 创建图片处理上下文
|
||||
PrinterOrderItem orderItem = PrinterOrderItem.fromMemberPrintResp(memberPrint);
|
||||
PhotoProcessContext context = PhotoProcessContext.fromPrinterOrderItem(orderItem, memberPrint.getScenicId());
|
||||
context.setStageState("image_enhance", needEnhance); // 通过setStageState方法设置是否启用
|
||||
|
||||
// 3.2 设置景区配置和场景
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(memberPrint.getScenicId());
|
||||
context.setScenicConfigManager(scenicConfig);
|
||||
context.setScene(PipelineScene.IMAGE_PRINT);
|
||||
|
||||
// 3.3 判断图片来源
|
||||
if (memberPrint.getSourceId() != null && memberPrint.getSourceId() > 0) {
|
||||
context.setSource(ImageSource.IPC);
|
||||
} else if (memberPrint.getSourceId() == null) {
|
||||
context.setSource(ImageSource.PHONE);
|
||||
} else {
|
||||
context.setSource(ImageSource.UNKNOWN);
|
||||
}
|
||||
|
||||
// 3.4 构建管线(关键:条件性添加 ImageEnhanceStage)
|
||||
Pipeline<PhotoProcessContext> pipeline;
|
||||
String newPrintUrl = null;
|
||||
|
||||
// 3.1 使用管线处理照片(复用 processPhotoWithPipeline)
|
||||
String newPrintUrl;
|
||||
try {
|
||||
if (context.getImageType() == ImageType.NORMAL_PHOTO) {
|
||||
// 准备水印配置(重打印需要二维码)
|
||||
WatermarkConfig watermarkConfig = prepareWatermarkConfig(context, qrCodeFile);
|
||||
prepareStorageAdapter(context);
|
||||
|
||||
// 创建管线,条件性添加增强 Stage
|
||||
pipeline = createNormalPhotoPipeline(watermarkConfig);
|
||||
} else {
|
||||
// 拼图
|
||||
prepareStorageAdapter(context);
|
||||
pipeline = createPuzzlePipeline();
|
||||
}
|
||||
|
||||
// 3.5 执行管线
|
||||
boolean success = pipeline.execute(context);
|
||||
if (success && context.getResultUrl() != null) {
|
||||
newPrintUrl = context.getResultUrl();
|
||||
log.info("handleReprint: 照片重新处理成功, taskId={}, mpId={}, enhance={}, newUrl={}",
|
||||
id, mpId, needEnhance, newPrintUrl);
|
||||
} else {
|
||||
log.warn("handleReprint: 照片重新处理失败, taskId={}, 使用原图", id);
|
||||
newPrintUrl = memberPrint.getCropUrl(); // 使用原裁剪图
|
||||
}
|
||||
newPrintUrl = processPhotoWithPipeline(memberPrint, memberPrint.getScenicId(), qrCodeFile, needEnhance);
|
||||
log.info("handleReprint: 照片重新处理成功, taskId={}, mpId={}, enhance={}, newUrl={}",
|
||||
id, mpId, needEnhance, newPrintUrl);
|
||||
} catch (Exception e) {
|
||||
log.error("handleReprint: 照片重新处理异常, taskId={}, 使用原图", id, e);
|
||||
newPrintUrl = memberPrint.getCropUrl();
|
||||
} finally {
|
||||
context.cleanup();
|
||||
}
|
||||
|
||||
// 4. 更新打印任务
|
||||
|
||||
Reference in New Issue
Block a user