Image使用字符串格式

- 清理任务记录Service中示例图ID到URL的转换逻辑,改为直接使用refactor(pdi-statusURL
- 修改Controller中异常抛出类型,统一抛Exception
--item 引入文件上传服务和): 修改inspectionImage字段类型为字符串并更新相关处理逻辑

-相关工具类处理图片上传与路径生成 将QmsPdiDetectionRulesStatusItem及相关DTO中inspectionImage字段由Long改为String类型
- 修改导出及导入逻辑以适应inspectionImage为URL字符串的变化
- 优化导入流程,支持识别Excel中图片公式并上传图片获取URL
- 清理旧有根据ID查询文件记录并转换为URL的逻辑,直接使用inspectionImage字段的URL
- 调整接口和服务层异常及参数类型,提升导入文件安全性和灵活性
- 更新Excel导出模板示例中的inspectionImage示例数据为字符串格式
This commit is contained in:
funny 2026-05-06 15:19:10 +08:00
parent 179322612b
commit 5b24459bcb
10 changed files with 94 additions and 47 deletions

View File

@ -88,7 +88,7 @@ public class QmsPdiStatusItemController extends BaseController {
@PostMapping("/import")
public ApiResult<?> importData(@RequestParam("file") MultipartFile file,
@NotNull(message = "PDI检测规则ID不能为空") @RequestParam Long detectionRulesId,
@NotNull(message = "状态不能为空") @RequestParam Integer status) throws IOException {
@NotNull(message = "状态不能为空") @RequestParam Integer status) throws Exception {
statusItemControllerService.importFromExcel(file, detectionRulesId, status);
return ApiResult.success();
}

View File

@ -1,6 +1,7 @@
package com.nflg.qms.admin.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.wms.common.exception.NflgException;
@ -13,20 +14,28 @@ import com.nflg.wms.common.pojo.qo.QmsPdiStatusItemAddQO;
import com.nflg.wms.common.pojo.qo.QmsPdiStatusItemSearchQO;
import com.nflg.wms.common.pojo.qo.QmsPdiStatusItemUpdateQO;
import com.nflg.wms.common.pojo.vo.QmsPdiStatusItemGroupVO;
import com.nflg.wms.common.util.DateTimeUtil;
import com.nflg.wms.common.util.EecExcelUtil;
import com.nflg.wms.common.util.UserUtil;
import com.nflg.wms.repository.entity.FileUploadRecord;
import com.nflg.wms.repository.entity.QmsPdiDetectionRulesStatusItem;
import com.nflg.wms.repository.entity.QmsPdiDetectionRules;
import com.nflg.wms.repository.mapper.QmsPdiDetectionRulesStatusItemMapper;
import com.nflg.wms.repository.service.IFileUploadRecordService;
import com.nflg.wms.repository.service.IQmsPdiDetectionRulesStatusItemService;
import com.nflg.wms.repository.service.IQmsPdiDetectionRulesService;
import com.nflg.wms.starter.service.FileUploadService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.ttzero.excel.reader.Drawings;
import org.ttzero.excel.reader.ExcelReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
@ -42,6 +51,8 @@ public class QmsPdiStatusItemControllerService {
private final IQmsPdiDetectionRulesStatusItemService statusItemService;
private final QmsPdiDetectionRulesStatusItemMapper statusItemMapper;
private final IQmsPdiDetectionRulesService pdiDetectionRulesService;
private final FileUploadService fileUploadService;
private final IFileUploadRecordService fileUploadRecordService;
// ========================= 新增 =========================
@ -169,7 +180,7 @@ public class QmsPdiStatusItemControllerService {
QmsPdiStatusItemImportDTO example = new QmsPdiStatusItemImportDTO()
.setComponentsDes("示例部件描述")
.setInspectionContent("示例检查核实内容")
.setInspectionImage(123456L);
.setInspectionImage("123456");
EecExcelUtil.export("PDI检测项导入模板", "PDI检测项导入模板", List.of(example), response);
}
@ -179,11 +190,42 @@ public class QmsPdiStatusItemControllerService {
* 导入PDI检测项
*/
@Transactional
public void importFromExcel(MultipartFile file, Long detectionRulesId, Integer status) throws IOException {
List<QmsPdiStatusItemImportDTO> data = EecExcelUtil.readTo(file.getInputStream(), QmsPdiStatusItemImportDTO.class);
public void importFromExcel(MultipartFile file, Long detectionRulesId, Integer status) throws Exception {
// 先将文件内容缓存为字节数组避免流只能读一次
byte[] fileBytes = file.getBytes();
List<QmsPdiStatusItemImportDTO> data = EecExcelUtil.readTo(new java.io.ByteArrayInputStream(fileBytes), QmsPdiStatusItemImportDTO.class);
if (CollectionUtil.isEmpty(data)) {
throw new NflgException(STATE.BusinessError, "导入文件内容为空");
}
// 读取 Excel 里的所有图片
List<Drawings.Picture> pictures = new ExcelReader(new java.io.ByteArrayInputStream(fileBytes)).listPictures();
// 遍历 DTO遇到 DISPIMG 就上传图片并替换地址
for (int i = 0; i < data.size(); i++) {
QmsPdiStatusItemImportDTO dto = data.get(i);
String inspectionImage = dto.getInspectionImage();
// 如果是图片公式就取图片上传把地址填回去
if (StrUtil.isNotBlank(inspectionImage) && inspectionImage.startsWith("=DISPIMG(")) {
if (i < pictures.size()) {
Drawings.Picture pic = pictures.get(i);
try (FileInputStream fis = new FileInputStream(pic.getLocalPath().toFile())) {
// 上传图片 获取地址
String imageUrl = fileUploadService.upload(
"image/" + DateTimeUtil.format(LocalDate.now(), "yyyyMMdd") + "/" + IdUtil.fastUUID() + ".png",
fis,
"image/png"
);
dto.setInspectionImage(imageUrl);
}
} else {
dto.setInspectionImage(null);
}
}
}
String operator = UserUtil.getUserName();
LocalDateTime now = LocalDateTime.now();
List<QmsPdiDetectionRulesStatusItem> entities = data.stream()

View File

@ -154,21 +154,8 @@ public class QmsPdiTaskRecordControllerService {
.collect(Collectors.toMap(QmsPdiDetectionRulesStatusItem::getId, si -> si, (a, b) -> a));
}
// 收集所有示例图ID批量查询file_upload_record
Set<Long> exampleImageIds = statusItemMap.values().stream()
.map(QmsPdiDetectionRulesStatusItem::getInspectionImage)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
Map<Long, String> exampleImageUrlMap = Map.of();
if (!exampleImageIds.isEmpty()) {
List<FileUploadRecord> files = fileUploadRecordService.listByIds(exampleImageIds);
exampleImageUrlMap = files.stream()
.collect(Collectors.toMap(FileUploadRecord::getId, FileUploadRecord::getUrl, (a, b) -> a));
}
// 映射
Map<Long, QmsPdiDetectionRulesStatusItem> finalStatusMap = statusItemMap;
Map<Long, String> finalExampleImageUrlMap = exampleImageUrlMap;
List<QmsPdiTaskRecordDetailVO.StatusItemVO> voList = records.stream().map(r -> {
QmsPdiTaskRecordDetailVO.StatusItemVO vo = new QmsPdiTaskRecordDetailVO.StatusItemVO();
vo.setId(r.getId());
@ -176,10 +163,8 @@ public class QmsPdiTaskRecordControllerService {
if (si != null) {
vo.setComponentsDes(si.getComponentsDes());
vo.setInspectionContent(si.getInspectionContent());
// 示例图ID转URL
if (si.getInspectionImage() != null) {
vo.setInspectionImage(finalExampleImageUrlMap.get(si.getInspectionImage()));
}
// inspectionImage 已经是URL直接使用
vo.setInspectionImage(si.getInspectionImage());
}
// 现场图已经是List<FileDetailVO>无需转换在下一步处理
vo.setInspectionItemImage(convertImageIdsToVO(r.getInspectionItemImage()));
@ -223,21 +208,8 @@ public class QmsPdiTaskRecordControllerService {
.collect(Collectors.toMap(QmsPdiDetectionRulesStatusItem::getId, si -> si, (a, b) -> a));
}
// 收集所有示例图ID批量查询file_upload_record
Set<Long> exampleImageIds = statusItemMap.values().stream()
.map(QmsPdiDetectionRulesStatusItem::getInspectionImage)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
Map<Long, String> exampleImageUrlMap = Map.of();
if (!exampleImageIds.isEmpty()) {
List<FileUploadRecord> files = fileUploadRecordService.listByIds(exampleImageIds);
exampleImageUrlMap = files.stream()
.collect(Collectors.toMap(FileUploadRecord::getId, FileUploadRecord::getUrl, (a, b) -> a));
}
// 映射
Map<Long, QmsPdiDetectionRulesStatusItem> finalStatusMap = statusItemMap;
Map<Long, String> finalExampleImageUrlMap = exampleImageUrlMap;
return records.stream().map(r -> {
QmsPdiTaskRecordDetailVO.StatusItemVO vo = new QmsPdiTaskRecordDetailVO.StatusItemVO();
vo.setId(r.getId());
@ -245,9 +217,8 @@ public class QmsPdiTaskRecordControllerService {
if (si != null) {
vo.setComponentsDes(si.getComponentsDes());
vo.setInspectionContent(si.getInspectionContent());
if (si.getInspectionImage() != null) {
vo.setInspectionImage(finalExampleImageUrlMap.get(si.getInspectionImage()));
}
// inspectionImage 已经是URL直接使用
vo.setInspectionImage(si.getInspectionImage());
}
vo.setInspectionItemImage(convertImageIdsToVO(r.getInspectionItemImage()));
vo.setInspectionBy(r.getInspectionBy());

View File

@ -19,8 +19,8 @@ public class QmsPdiStatusItemExportDTO {
@ExcelColumn("检查核实内容")
private String inspectionContent;
@ExcelColumn("检测示例图文件ID")
private Long inspectionImage;
@ExcelColumn("检测示例图")
private String inspectionImage;
@ExcelColumn("状态")
private String statusName;

View File

@ -24,10 +24,10 @@ public class QmsPdiStatusItemImportDTO {
private String inspectionContent;
/**
* 检测示例图文件记录ID
* 检测示例图URL
*/
@ExcelColumn("检测示例图文件ID")
private Long inspectionImage;
@ExcelColumn("检测示例图")
private String inspectionImage;
/**
* 排序

View File

@ -31,7 +31,7 @@ public class QmsPdiStatusItemAddQO {
* 检测示例图文件记录ID必传
*/
@NotNull(message = "检测示例图不能为空")
private Long inspectionImage;
private String inspectionImage;
/**
* 状态0为静态1为动态2为特殊必传

View File

@ -50,7 +50,7 @@ public class QmsPdiStatusItemGroupVO {
/**
* 检测示例图文件记录ID
*/
private Long inspectionImage;
private String inspectionImage;
/**
* 状态0为静态1为动态2为特殊

View File

@ -44,7 +44,7 @@ public class QmsPdiDetectionRulesStatusItem implements Serializable {
/**
* 检测示例图文件记录ID
*/
private Long inspectionImage;
private String inspectionImage;
/**
* 状态0为静态1为动态2为特殊

View File

@ -24,4 +24,11 @@ public interface QmsPdiDetectionRulesStatusItemMapper extends BaseMapper<QmsPdiD
List<QmsPdiStatusItemExportDTO> listForExport(@Param("ids") List<Long> ids,
@Param("detectionRulesId") Long detectionRulesId,
@Param("status") List<Integer> status);
/**
* 导出检测项返回实体对象
*/
List<QmsPdiDetectionRulesStatusItem> listForExportRaw(@Param("ids") List<Long> ids,
@Param("detectionRulesId") Long detectionRulesId,
@Param("status") List<Integer> status);
}

View File

@ -26,4 +26,31 @@
ORDER BY s.id ASC
</select>
<!-- 导出检测项(返回实体对象) -->
<select id="listForExportRaw" resultType="com.nflg.wms.repository.entity.QmsPdiDetectionRulesStatusItem">
SELECT
s.id,
s.detection_rules_id,
s.components_des,
s.inspection_content,
s.inspection_image,
s.status,
s.sort,
s.create_by,
s.create_time
FROM qms_pdi_detection_rules_status_item s
WHERE s.detection_rules_id = #{detectionRulesId}
AND s.status IN
<foreach collection="status" item="st" open="(" separator="," close=")">
#{st}
</foreach>
<if test="ids != null and ids.size() > 0">
AND s.id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</if>
ORDER BY s.id ASC
</select>
</mapper>