From a3eeb24f4ff893cef72b49a3462476966f2b1aa6 Mon Sep 17 00:00:00 2001 From: b2894lxlx <517289602@qq.com> Date: Tue, 8 Sep 2026 10:58:21 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=BB=93=E7=AE=97=E6=A8=A1?= =?UTF-8?q?=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transport/pojo/entity/VoucherFile.java | 40 ++++ .../transport/pojo/vo/VoucherFileVO.java | 32 ++++ .../transport/pojo/vo/VoucherManageVO.java | 2 + .../transport/mapper/VoucherFileMapper.java | 15 ++ .../impl/VoucherManageServiceImpl.java | 171 ++++++++++++++---- .../transport/blade_voucher_file_20260908.sql | 28 +++ script/docker/app/deploy.sh | 2 +- 7 files changed, 249 insertions(+), 41 deletions(-) create mode 100644 blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/VoucherFile.java create mode 100644 blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/VoucherFileVO.java create mode 100644 blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/VoucherFileMapper.java create mode 100644 doc/sql/transport/blade_voucher_file_20260908.sql diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/VoucherFile.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/VoucherFile.java new file mode 100644 index 0000000..919dc09 --- /dev/null +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/VoucherFile.java @@ -0,0 +1,40 @@ +/** + * BladeX Commercial License Agreement + * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved. + */ +package org.springblade.transport.pojo.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.core.tenant.mp.TenantEntity; + +import java.io.Serial; + +/** + * 凭证压缩包解压文件明细。 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("blade_voucher_file") +@Schema(description = "凭证文件明细") +public class VoucherFile extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + private Long voucherId; + private String voucherBatchNo; + private Long waybillId; + private String waybillNo; + private String plateNo; + private String folderName; + private String entryName; + private String fileName; + private String objectKey; + private Long fileSize; + private String contentType; + private String fileType; + private Integer matched; +} diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/VoucherFileVO.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/VoucherFileVO.java new file mode 100644 index 0000000..7ea0a3a --- /dev/null +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/VoucherFileVO.java @@ -0,0 +1,32 @@ +package org.springblade.transport.pojo.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 凭证解压文件详情。 + */ +@Data +public class VoucherFileVO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + private Long voucherId; + private String voucherBatchNo; + private Long waybillId; + private String waybillNo; + private String plateNo; + private String folderName; + private String entryName; + private String fileName; + private String objectKey; + private Long fileSize; + private String contentType; + private String fileType; + private Integer matched; + private String url; +} diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/VoucherManageVO.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/VoucherManageVO.java index bea50c6..aedf165 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/VoucherManageVO.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/vo/VoucherManageVO.java @@ -7,6 +7,7 @@ import org.springblade.transport.pojo.entity.VoucherManage; import java.io.Serial; import java.time.LocalDateTime; +import java.util.List; @Data @EqualsAndHashCode(callSuper = true) @@ -16,4 +17,5 @@ public class VoucherManageVO extends VoucherManage { @TableField(exist = false) private String updateUserName; @TableField(exist = false) private LocalDateTime createTimeStart; @TableField(exist = false) private LocalDateTime createTimeEnd; + @TableField(exist = false) private List voucherFiles; } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/VoucherFileMapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/VoucherFileMapper.java new file mode 100644 index 0000000..886c3b8 --- /dev/null +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mapper/VoucherFileMapper.java @@ -0,0 +1,15 @@ +package org.springblade.transport.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.springblade.transport.pojo.entity.VoucherFile; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Param; + +/** + * 凭证解压文件明细 Mapper。 + */ +public interface VoucherFileMapper extends BaseMapper { + + @Delete("DELETE FROM blade_voucher_file WHERE voucher_id = #{voucherId}") + void deleteByVoucherId(@Param("voucherId") Long voucherId); +} diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/VoucherManageServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/VoucherManageServiceImpl.java index 5120c70..0a8e28e 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/VoucherManageServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/VoucherManageServiceImpl.java @@ -10,6 +10,7 @@ import org.springblade.core.tool.jackson.JsonUtil; import org.springblade.core.tool.utils.Func; import org.springblade.transport.mapper.VoucherManageMapper; import org.springblade.transport.mapper.VoucherImageMapper; +import org.springblade.transport.mapper.VoucherFileMapper; import org.springblade.transport.mapper.VoucherWaybillBatchMapper; import org.springblade.transport.event.VoucherUploadCompletedEvent; import org.springblade.transport.pojo.dto.VoucherManageSubmitRequest; @@ -18,9 +19,11 @@ import org.springblade.transport.pojo.dto.VoucherFileCompleteRequest; import org.springblade.transport.pojo.entity.VoucherManage; import org.springblade.transport.pojo.entity.VoucherWaybillBatch; import org.springblade.transport.pojo.entity.VoucherImage; +import org.springblade.transport.pojo.entity.VoucherFile; import org.springblade.transport.pojo.entity.Waybill; import org.springblade.transport.pojo.entity.ProjectApply; import org.springblade.transport.pojo.vo.VoucherManageVO; +import org.springblade.transport.pojo.vo.VoucherFileVO; import org.springblade.transport.service.IVoucherManageService; import org.springblade.transport.service.IProjectApplyService; import org.springblade.transport.service.IWaybillService; @@ -30,13 +33,17 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.transaction.annotation.Transactional; import io.minio.MinioClient; +import io.minio.GetPresignedObjectUrlArgs; import io.minio.PutObjectArgs; +import io.minio.http.Method; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -58,6 +65,7 @@ public class VoucherManageServiceImpl extends BaseServiceImpl files = voucherFileMapper.selectList(Wrappers.lambdaQuery() + .eq(VoucherFile::getTenantId, record.getTenantId()) + .eq(VoucherFile::getVoucherId, record.getId()) + .eq(VoucherFile::getIsDeleted, 0) + .orderByAsc(VoucherFile::getEntryName)); + result.setVoucherFiles(files.stream().map(this::toVoucherFileVO).toList()); + return result; } @Override @@ -225,6 +242,8 @@ public class VoucherManageServiceImpl extends BaseServiceImpl relatedWaybillIds = new HashSet<>(); @@ -239,51 +258,72 @@ public class VoucherManageServiceImpl extends BaseServiceImpl pathParts = Arrays.stream(entryName.split("/")) + .filter(Func::isNotEmpty).toList(); + if (pathParts.isEmpty()) { continue; } - String plateNo = normalizePlateNo(pathParts[0]); - String imageName = safeFileName(pathParts[pathParts.length - 1]); - if (Func.isEmpty(plateNo) || Func.isEmpty(imageName)) { + String folderName = pathParts.size() > 1 ? safeArchiveSegment(pathParts.get(0)) : null; + String plateNo = normalizePlateNo(folderName); + String rawFileName = pathParts.get(pathParts.size() - 1); + boolean imageFile = isImageFile(rawFileName); + String fileName = safeFileName(rawFileName); + if (Func.isEmpty(fileName)) { continue; } Waybill waybill = waybillByPlate.get(plateNo); - if (waybill == null) { - log.warn("[凭证处理] 图片未匹配运单 voucherId={}, plateNo={}, indexedPlates={}", - voucherId, plateNo, waybillByPlate.keySet()); - } else { - log.info("[凭证处理] 图片匹配运单 voucherId={}, plateNo={}, waybillId={}, waybillNo={}", - voucherId, plateNo, waybill.getId(), waybill.getWaybillNo()); - } + if (imageFile && waybill == null) log.warn("[凭证处理] 图片未匹配运单 voucherId={}, plateNo={}, indexedPlates={}", + voucherId, plateNo, waybillByPlate.keySet()); String waybillNo = waybill == null ? "unmatched" : safePathPart(waybill.getWaybillNo()); - String objectKey = buildObjectKey(voucher.getId(), waybillNo, plateNo, imageName); + String objectKey = buildObjectKey(voucher.getId(), waybillNo, + Func.isEmpty(plateNo) ? "root" : plateNo, entryName); + String contentType = contentType(fileName); minioClient.putObject(PutObjectArgs.builder().bucket(minioBucketName).object(objectKey) - .stream(zipInputStream, entry.getSize(), 10 * 1024 * 1024).build()); - VoucherImage image = new VoucherImage(); - image.setVoucherId(voucher.getId()); - image.setVoucherBatchNo(voucher.getVoucherBatchNo()); - image.setWaybillId(waybill == null ? null : waybill.getId()); - image.setWaybillNo(waybill == null ? null : waybill.getWaybillNo()); - image.setPlateNo(plateNo); - image.setImageName(imageName); - image.setObjectKey(objectKey); - image.setMatched(waybill == null ? 0 : 1); - image.setTenantId(voucher.getTenantId()); - voucherImageMapper.insert(image); - imageCount++; - if (waybill != null) { + .stream(zipInputStream, entry.getSize(), 10 * 1024 * 1024) + .contentType(contentType).build()); + VoucherFile file = new VoucherFile(); + file.setVoucherId(voucher.getId()); + file.setVoucherBatchNo(voucher.getVoucherBatchNo()); + file.setWaybillId(waybill == null ? null : waybill.getId()); + file.setWaybillNo(waybill == null ? null : waybill.getWaybillNo()); + file.setPlateNo(Func.isEmpty(plateNo) ? null : plateNo); + file.setFolderName(folderName); + file.setEntryName(entryName); + file.setFileName(fileName); + file.setObjectKey(objectKey); + file.setFileSize(entry.getSize() < 0 ? null : entry.getSize()); + file.setContentType(contentType); + file.setFileType(imageFile ? "image" : "file"); + file.setMatched(waybill == null ? 0 : 1); + file.setTenantId(voucher.getTenantId()); + voucherFileMapper.insert(file); + fileCount++; + if (imageFile) { + VoucherImage image = new VoucherImage(); + image.setVoucherId(voucher.getId()); + image.setVoucherBatchNo(voucher.getVoucherBatchNo()); + image.setWaybillId(waybill == null ? null : waybill.getId()); + image.setWaybillNo(waybill == null ? null : waybill.getWaybillNo()); + image.setPlateNo(Func.isEmpty(plateNo) ? "" : plateNo); + image.setImageName(fileName); + image.setObjectKey(objectKey); + image.setMatched(waybill == null ? 0 : 1); + image.setTenantId(voucher.getTenantId()); + voucherImageMapper.insert(image); + imageCount++; + } + if (waybill != null && imageFile) { matchedImageCount++; relatedWaybillIds.add(waybill.getId()); } - if (imageCount % 10 == 0) { - log.info("[凭证处理] 图片处理中 voucherId={}, processedImages={}, matchedImages={}, relatedWaybills={}", - voucherId, imageCount, matchedImageCount, relatedWaybillIds.size()); + if (fileCount % 10 == 0) { + log.info("[凭证处理] 文件处理中 voucherId={}, processedFiles={}, imageCount={}, matchedImages={}, relatedWaybills={}", + voucherId, fileCount, imageCount, matchedImageCount, relatedWaybillIds.size()); } } } - log.info("[凭证处理] 进度 90%:图片解压上传完成 voucherId={}, imageCount={}, matchedImageCount={}", - voucherId, imageCount, matchedImageCount); + log.info("[凭证处理] 进度 90%:文件解压上传完成 voucherId={}, fileCount={}, imageCount={}, matchedImageCount={}", + voucherId, fileCount, imageCount, matchedImageCount); VoucherManage update = new VoucherManage(); update.setId(voucher.getId()); update.setVoucherCount(imageCount); @@ -291,8 +331,8 @@ public class VoucherManageServiceImpl extends BaseServiceImpllambdaQuery().eq(VoucherWaybillBatch::getVoucherId, id)); + voucherFileMapper.deleteByVoucherId(id); + voucherImageMapper.deleteByVoucherId(id); } @Override @@ -347,26 +389,75 @@ public class VoucherManageServiceImpl extends BaseServiceImpl