feat(qms): 支持检测项导入时物料类别编号和排序号校验及排序逻辑
- 统一检测项导入文件中的物料类别编号格式,并校验物料类别存在性 - 实现导入时图片单元格嵌入解析并上传替换图例字段 - 新增检测项明细排序号字段,支持不传则默认插最前面,已有排序号整体+1 - 排序号超出范围自动修正,重复排序号会抛出业务异常 - 导入时校验同一物料类别内排序号不允许重复,并标记错误信息 - 新增保存检测项明细排序号处理的服务方法,替换原先简单保存调用 - 导入时检测类型和判定类型支持文字(定向/定量,目视/量具)转数字映射 - 导入后根据物料类别编号自动生成检测项编号和名称,按物料类别分组合并导入 - 查询检测项明细时按排序号升序返回 - 导入模板示例数据更新为物料类别编号和示例文字,导入接口支持错误提示文件返回 - 优化检测项导入导出Excel响应设置,提高导入导出用户体验
This commit is contained in:
parent
04109205c8
commit
eabaf79d53
|
|
@ -12,11 +12,12 @@ import com.nflg.wms.common.pojo.dto.QmsInspectionItemImportDTO;
|
||||||
import com.nflg.wms.common.pojo.qo.QmsInspectionItemAddQO;
|
import com.nflg.wms.common.pojo.qo.QmsInspectionItemAddQO;
|
||||||
import com.nflg.wms.common.pojo.qo.QmsInspectionItemSearchQO;
|
import com.nflg.wms.common.pojo.qo.QmsInspectionItemSearchQO;
|
||||||
import com.nflg.wms.common.pojo.qo.QmsInspectionItemUpdateQO;
|
import com.nflg.wms.common.pojo.qo.QmsInspectionItemUpdateQO;
|
||||||
import com.nflg.wms.common.pojo.vo.QmsInspectionItemDetailsVO;
|
|
||||||
import com.nflg.wms.common.pojo.vo.QmsInspectionItemVO;
|
import com.nflg.wms.common.pojo.vo.QmsInspectionItemVO;
|
||||||
import com.nflg.wms.common.util.DateTimeUtil;
|
import com.nflg.wms.common.util.DateTimeUtil;
|
||||||
import com.nflg.wms.common.util.EecExcelUtil;
|
import com.nflg.wms.common.util.EecExcelUtil;
|
||||||
|
import com.nflg.wms.repository.entity.QmsQcMaterialCategory;
|
||||||
import com.nflg.wms.repository.service.IQmsInspectionItemService;
|
import com.nflg.wms.repository.service.IQmsInspectionItemService;
|
||||||
|
import com.nflg.wms.repository.service.IQmsQcMaterialCategoryService;
|
||||||
import com.nflg.wms.starter.BaseController;
|
import com.nflg.wms.starter.BaseController;
|
||||||
import com.nflg.wms.starter.service.FileUploadService;
|
import com.nflg.wms.starter.service.FileUploadService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
|
@ -37,6 +38,10 @@ import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测项管理
|
* 检测项管理
|
||||||
|
|
@ -48,6 +53,9 @@ public class QmsInspectionItemController extends BaseController {
|
||||||
@Resource
|
@Resource
|
||||||
private IQmsInspectionItemService inspectionItemService;
|
private IQmsInspectionItemService inspectionItemService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IQmsQcMaterialCategoryService materialCategoryService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private FileUploadService fileUploadService;
|
private FileUploadService fileUploadService;
|
||||||
|
|
||||||
|
|
@ -131,14 +139,13 @@ public class QmsInspectionItemController extends BaseController {
|
||||||
@GetMapping("template")
|
@GetMapping("template")
|
||||||
public void template(HttpServletResponse response) throws IOException {
|
public void template(HttpServletResponse response) throws IOException {
|
||||||
// 构造一行示例数据
|
// 构造一行示例数据
|
||||||
QmsInspectionItemExportDTO example = new QmsInspectionItemExportDTO();
|
QmsInspectionItemImportDTO example = new QmsInspectionItemImportDTO();
|
||||||
example.setMaterialTypeId(1001L);
|
example.setCategoryCode("物料类别编号");
|
||||||
example.setDetectionType(0);
|
example.setSerialNo("数字1、2、3、4");
|
||||||
example.setInspectionItemName("示例检测项名称");
|
example.setTestStandard("检测标准内容");
|
||||||
example.setInspectionNo("示例检测项编号");
|
example.setLegend("在此单元格嵌入图片");
|
||||||
example.setTestStandard("示例检测标准内容");
|
example.setDetectionType("定向/定量");
|
||||||
example.setLegend("示例图例URL(可不填)");
|
example.setDeterminationType("目视/量具");
|
||||||
example.setDeterminationType(0);
|
|
||||||
|
|
||||||
EecExcelUtil.export("检测项导入模板", "检测项导入模板", List.of(example), response);
|
EecExcelUtil.export("检测项导入模板", "检测项导入模板", List.of(example), response);
|
||||||
}
|
}
|
||||||
|
|
@ -148,59 +155,100 @@ public class QmsInspectionItemController extends BaseController {
|
||||||
/**
|
/**
|
||||||
* 导入检测项
|
* 导入检测项
|
||||||
* 校验失败时返回带错误信息的文件URL
|
* 校验失败时返回带错误信息的文件URL
|
||||||
* 图例字段支持:图片URL
|
* 图例字段支持:单元格嵌入图片
|
||||||
*
|
*
|
||||||
* @param file 导入文件
|
* @param file 导入文件
|
||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
@PostMapping("import")
|
@PostMapping("import")
|
||||||
public ApiResult<String> importFromExcel(@RequestParam("file") MultipartFile file) throws Exception {
|
public ApiResult<String> importFromExcel(@RequestParam("file") MultipartFile file) throws Exception {
|
||||||
List<QmsInspectionItemImportDTO> data = EecExcelUtil.getExcelContext(file.getInputStream(), QmsInspectionItemImportDTO.class);
|
byte[] fileBytes = file.getBytes();
|
||||||
|
|
||||||
|
List<QmsInspectionItemImportDTO> data = EecExcelUtil.getExcelContext(
|
||||||
|
new ByteArrayInputStream(fileBytes), QmsInspectionItemImportDTO.class);
|
||||||
if (CollectionUtil.isEmpty(data)) {
|
if (CollectionUtil.isEmpty(data)) {
|
||||||
throw new NflgException(STATE.BusinessError, "导入文件内容为空");
|
throw new NflgException(STATE.BusinessError, "导入文件内容为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 读取 Excel 里的所有图片
|
||||||
|
List<Drawings.Picture> pictures = new ExcelReader(new ByteArrayInputStream(fileBytes)).listPictures();
|
||||||
|
|
||||||
// 2. 读取 Excel 里的所有图片(EEC 标准方式)
|
// 遍历 DTO,遇到 DISPIMG 就上传图片并替换地址
|
||||||
List<Drawings.Picture> pictures = new ExcelReader(file.getInputStream()).listPictures();
|
|
||||||
|
|
||||||
// 3. 遍历 DTO,遇到 DISPIMG 就上传图片并替换地址
|
|
||||||
for (int i = 0; i < data.size(); i++) {
|
for (int i = 0; i < data.size(); i++) {
|
||||||
QmsInspectionItemImportDTO dto = data.get(i);
|
QmsInspectionItemImportDTO dto = data.get(i);
|
||||||
String legend = dto.getLegend();
|
String legend = dto.getLegend();
|
||||||
|
|
||||||
// 如果是图片公式,就取图片上传,把地址填回去
|
|
||||||
if (StrUtil.isNotBlank(legend) && legend.startsWith("=DISPIMG(")) {
|
if (StrUtil.isNotBlank(legend) && legend.startsWith("=DISPIMG(")) {
|
||||||
if (i < pictures.size()) {
|
if (i < pictures.size()) {
|
||||||
Drawings.Picture pic = pictures.get(i);
|
Drawings.Picture pic = pictures.get(i);
|
||||||
FileInputStream fis = new FileInputStream(pic.getLocalPath().toFile());
|
try (FileInputStream fis = new FileInputStream(pic.getLocalPath().toFile())) {
|
||||||
// 上传图片 → 获取地址
|
String imageUrl = fileUploadService.upload(
|
||||||
String imageUrl = fileUploadService.upload(
|
"image/" + IdUtil.fastUUID() + ".png",
|
||||||
"image/" + IdUtil.fastUUID() + ".png",
|
fis,
|
||||||
fis,
|
"image/png"
|
||||||
"image/png"
|
);
|
||||||
);
|
dto.setLegend(imageUrl);
|
||||||
dto.setLegend(imageUrl); // 把地址塞回去
|
}
|
||||||
} else {
|
} else {
|
||||||
dto.setLegend(null);
|
dto.setLegend(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验必填字段
|
// 校验必填字段 & 文字转数字
|
||||||
boolean hasError = false;
|
boolean hasError = false;
|
||||||
for (QmsInspectionItemImportDTO dto : data) {
|
for (QmsInspectionItemImportDTO dto : data) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
if (dto.getMaterialTypeId() == null) sb.append("物料类别ID不能为空;");
|
if (StrUtil.isBlank(dto.getCategoryCode())) {
|
||||||
if (dto.getDetectionType() == null) sb.append("检测类型不能为空;");
|
sb.append("物料类别编号不能为空;");
|
||||||
if (dto.getInspectionItemName() == null || dto.getInspectionItemName().isBlank())
|
} else {
|
||||||
sb.append("检测项名称不能为空;");
|
// 校验物料类别编号是否存在
|
||||||
if (dto.getInspectionNo() == null || dto.getInspectionNo().isBlank())
|
QmsQcMaterialCategory category = materialCategoryService.lambdaQuery()
|
||||||
sb.append("检测项编号不能为空;");
|
.eq(QmsQcMaterialCategory::getCategoryCode, dto.getCategoryCode())
|
||||||
if (dto.getTestStandard() == null || dto.getTestStandard().isBlank()) sb.append("检测标准不能为空;");
|
.one();
|
||||||
if (dto.getDeterminationType() == null) sb.append("判定类型不能为空;");
|
if (category == null) {
|
||||||
|
sb.append("物料类别编号[" + dto.getCategoryCode() + "]不存在;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(dto.getTestStandard())) sb.append("检测标准不能为空;");
|
||||||
|
if (StrUtil.isBlank(dto.getDetectionType())) {
|
||||||
|
sb.append("检测类型不能为空;");
|
||||||
|
} else if (!"定向".equals(dto.getDetectionType()) && !"定量".equals(dto.getDetectionType())
|
||||||
|
&& !"0".equals(dto.getDetectionType()) && !"1".equals(dto.getDetectionType())) {
|
||||||
|
sb.append("检测类型须为'定向'或'定量';");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(dto.getDeterminationType())) {
|
||||||
|
sb.append("判定类型不能为空;");
|
||||||
|
} else if (!"目视".equals(dto.getDeterminationType()) && !"量具".equals(dto.getDeterminationType())
|
||||||
|
&& !"0".equals(dto.getDeterminationType()) && !"1".equals(dto.getDeterminationType())) {
|
||||||
|
sb.append("判定类型须为'目视'或'量具';");
|
||||||
|
}
|
||||||
dto.setError(sb.toString());
|
dto.setError(sb.toString());
|
||||||
if (sb.length() > 0) hasError = true;
|
if (!sb.isEmpty()) hasError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验同一物料类别编号内排序号不重复
|
||||||
|
Map<String, List<QmsInspectionItemImportDTO>> grouped = data.stream()
|
||||||
|
.filter(dto -> StrUtil.isNotBlank(dto.getCategoryCode()))
|
||||||
|
.collect(Collectors.groupingBy(QmsInspectionItemImportDTO::getCategoryCode));
|
||||||
|
for (List<QmsInspectionItemImportDTO> group : grouped.values()) {
|
||||||
|
List<String> sortNos = group.stream()
|
||||||
|
.map(QmsInspectionItemImportDTO::getSerialNo)
|
||||||
|
.filter(StrUtil::isNotBlank)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
Set<String> unique = new HashSet<>(sortNos);
|
||||||
|
if (unique.size() < sortNos.size()) {
|
||||||
|
// 标记重复的行
|
||||||
|
Set<String> seen = new HashSet<>();
|
||||||
|
for (QmsInspectionItemImportDTO dto : group) {
|
||||||
|
if (StrUtil.isNotBlank(dto.getSerialNo())) {
|
||||||
|
if (!seen.add(dto.getSerialNo().trim())) {
|
||||||
|
String err = dto.getError() == null ? "" : dto.getError();
|
||||||
|
dto.setError(err + "同一物料类别内排序号重复;");
|
||||||
|
hasError = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasError) {
|
if (!hasError) {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.ttzero.excel.entity.ListSheet;
|
||||||
|
import org.ttzero.excel.entity.Workbook;
|
||||||
import org.ttzero.excel.reader.Drawings;
|
import org.ttzero.excel.reader.Drawings;
|
||||||
import org.ttzero.excel.reader.ExcelReader;
|
import org.ttzero.excel.reader.ExcelReader;
|
||||||
|
|
||||||
|
|
@ -168,7 +170,10 @@ public class QmsPdiStatusItemControllerService {
|
||||||
}
|
}
|
||||||
statusName.append("检测项");
|
statusName.append("检测项");
|
||||||
|
|
||||||
EecExcelUtil.export(statusName.toString(), statusName.toString(), data, response);
|
EecExcelUtil.setResponseExcelHeader(response, statusName.toString());
|
||||||
|
new Workbook()
|
||||||
|
.addSheet(new ListSheet<>(statusName.toString(), data).setRowHeight(60))
|
||||||
|
.writeTo(response.getOutputStream());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================= 下载导入模板 =========================
|
// ========================= 下载导入模板 =========================
|
||||||
|
|
|
||||||
|
|
@ -10,28 +10,16 @@ import org.ttzero.excel.annotation.ExcelColumn;
|
||||||
public class QmsInspectionItemImportDTO {
|
public class QmsInspectionItemImportDTO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 物料类别ID
|
* 物料类别编号(用户填写 category_code)
|
||||||
*/
|
*/
|
||||||
@ExcelColumn("物料类别ID*")
|
@ExcelColumn("物料类别编号*")
|
||||||
private Long materialTypeId;
|
private String categoryCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测类型:0=定向,1=定量
|
* 检测项序号(数字1、2、3、4...)
|
||||||
*/
|
*/
|
||||||
@ExcelColumn("检测类型(0定向/1定量)*")
|
@ExcelColumn("检测项序号*")
|
||||||
private Integer detectionType;
|
private String serialNo;
|
||||||
|
|
||||||
/**
|
|
||||||
* 检测项名称
|
|
||||||
*/
|
|
||||||
@ExcelColumn("检测项名称*")
|
|
||||||
private String inspectionItemName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检测项编号
|
|
||||||
*/
|
|
||||||
@ExcelColumn("检测项编号*")
|
|
||||||
private String inspectionNo;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测标准
|
* 检测标准
|
||||||
|
|
@ -46,10 +34,16 @@ public class QmsInspectionItemImportDTO {
|
||||||
private String legend;
|
private String legend;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判定类型:0=目视,1=量具
|
* 检测类型:用户输入"定向"/"定量",后端匹配为0/1
|
||||||
|
*/
|
||||||
|
@ExcelColumn("检测类型(0定向/1定量)*")
|
||||||
|
private String detectionType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判定类型:用户输入"目视"/"量具",后端匹配为0/1
|
||||||
*/
|
*/
|
||||||
@ExcelColumn("判定类型(0目视/1量具)*")
|
@ExcelColumn("判定类型(0目视/1量具)*")
|
||||||
private Integer determinationType;
|
private String determinationType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 错误信息(导入校验结果)
|
* 错误信息(导入校验结果)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.nflg.wms.common.pojo.dto;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
import org.ttzero.excel.annotation.ExcelColumn;
|
import org.ttzero.excel.annotation.ExcelColumn;
|
||||||
|
import org.ttzero.excel.annotation.MediaColumn;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
|
@ -20,6 +21,7 @@ public class QmsPdiStatusItemExportDTO {
|
||||||
private String inspectionContent;
|
private String inspectionContent;
|
||||||
|
|
||||||
@ExcelColumn("检测示例图")
|
@ExcelColumn("检测示例图")
|
||||||
|
@MediaColumn
|
||||||
private String inspectionImage;
|
private String inspectionImage;
|
||||||
|
|
||||||
@ExcelColumn("状态")
|
@ExcelColumn("状态")
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,11 @@ public class QmsInspectionItemAddQO {
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public static class DetailQO {
|
public static class DetailQO {
|
||||||
|
/**
|
||||||
|
* 排序号(可选,不传则默认插到最前面,已有记录+1)
|
||||||
|
*/
|
||||||
|
private Integer sortNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测标准(必传)
|
* 检测标准(必传)
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,11 @@ public class QmsInspectionItemDetailAddQO {
|
||||||
@NotNull(message = "检测项ID不能为空")
|
@NotNull(message = "检测项ID不能为空")
|
||||||
private Long inspectionItemId;
|
private Long inspectionItemId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序号(可选,不传则默认插到最前面,已有记录+1)
|
||||||
|
*/
|
||||||
|
private Integer sortNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测标准(必传)
|
* 检测标准(必传)
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,11 @@ public class QmsInspectionItemUpdateQO {
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public static class DetailQO {
|
public static class DetailQO {
|
||||||
|
/**
|
||||||
|
* 排序号(可选)
|
||||||
|
*/
|
||||||
|
private Integer sortNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测标准(必传)
|
* 检测标准(必传)
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,11 @@ public class QmsInspectionItemDetailsVO {
|
||||||
*/
|
*/
|
||||||
private Long inspectionItemId;
|
private Long inspectionItemId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序号
|
||||||
|
*/
|
||||||
|
private Integer sortNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测标准
|
* 检测标准
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,11 @@ public class QmsInspectionItemDetails implements Serializable {
|
||||||
*/
|
*/
|
||||||
private Long inspectionItemId;
|
private Long inspectionItemId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测项序号
|
||||||
|
*/
|
||||||
|
private Integer sortNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测标准
|
* 检测标准
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -19,4 +19,12 @@ public interface IQmsInspectionItemDetailsService extends IService<QmsInspection
|
||||||
* 批量删除(按明细表ID,可多个)
|
* 批量删除(按明细表ID,可多个)
|
||||||
*/
|
*/
|
||||||
void deleteByIds(List<Long> ids);
|
void deleteByIds(List<Long> ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存明细并处理排序号逻辑:
|
||||||
|
* - sortNo为null → 默认1,已有记录全部+1
|
||||||
|
* - sortNo已存在 → 报错
|
||||||
|
* - sortNo超出max+1 → 自动修正为max+1
|
||||||
|
*/
|
||||||
|
void saveDetailWithSortNo(QmsInspectionItemDetails detail);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.nflg.wms.repository.service.impl;
|
package com.nflg.wms.repository.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.nflg.wms.common.constant.STATE;
|
||||||
|
import com.nflg.wms.common.exception.NflgException;
|
||||||
import com.nflg.wms.repository.entity.QmsInspectionItemDetails;
|
import com.nflg.wms.repository.entity.QmsInspectionItemDetails;
|
||||||
import com.nflg.wms.repository.mapper.QmsInspectionItemDetailsMapper;
|
import com.nflg.wms.repository.mapper.QmsInspectionItemDetailsMapper;
|
||||||
import com.nflg.wms.repository.service.IQmsInspectionItemDetailsService;
|
import com.nflg.wms.repository.service.IQmsInspectionItemDetailsService;
|
||||||
|
|
@ -21,6 +23,7 @@ public class QmsInspectionItemDetailsServiceImpl
|
||||||
public List<QmsInspectionItemDetails> listByItemId(Long inspectionItemId) {
|
public List<QmsInspectionItemDetails> listByItemId(Long inspectionItemId) {
|
||||||
return lambdaQuery()
|
return lambdaQuery()
|
||||||
.eq(QmsInspectionItemDetails::getInspectionItemId, inspectionItemId)
|
.eq(QmsInspectionItemDetails::getInspectionItemId, inspectionItemId)
|
||||||
|
.orderByAsc(QmsInspectionItemDetails::getSortNo)
|
||||||
.list();
|
.list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,4 +34,42 @@ public class QmsInspectionItemDetailsServiceImpl
|
||||||
removeByIds(ids);
|
removeByIds(ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public void saveDetailWithSortNo(QmsInspectionItemDetails detail) {
|
||||||
|
Long itemId = detail.getInspectionItemId();
|
||||||
|
Integer sortNo = detail.getSortNo();
|
||||||
|
|
||||||
|
// 获取当前最大排序号
|
||||||
|
QmsInspectionItemDetails maxRecord = lambdaQuery()
|
||||||
|
.eq(QmsInspectionItemDetails::getInspectionItemId, itemId)
|
||||||
|
.orderByDesc(QmsInspectionItemDetails::getSortNo)
|
||||||
|
.last("LIMIT 1")
|
||||||
|
.one();
|
||||||
|
int maxSortNo = (maxRecord != null && maxRecord.getSortNo() != null) ? maxRecord.getSortNo() : 0;
|
||||||
|
|
||||||
|
if (sortNo == null) {
|
||||||
|
// 未传排序号 → 插到最前面(1),已有记录全部+1
|
||||||
|
lambdaUpdate()
|
||||||
|
.eq(QmsInspectionItemDetails::getInspectionItemId, itemId)
|
||||||
|
.setSql("sort_no = sort_no + 1")
|
||||||
|
.update();
|
||||||
|
detail.setSortNo(1);
|
||||||
|
} else {
|
||||||
|
// 检查重复
|
||||||
|
boolean exists = lambdaQuery()
|
||||||
|
.eq(QmsInspectionItemDetails::getInspectionItemId, itemId)
|
||||||
|
.eq(QmsInspectionItemDetails::getSortNo, sortNo)
|
||||||
|
.exists();
|
||||||
|
if (exists) {
|
||||||
|
throw new NflgException(STATE.BusinessError, "排序号[" + sortNo + "]已存在");
|
||||||
|
}
|
||||||
|
// 超出范围则修正为 max+1
|
||||||
|
if (sortNo > maxSortNo + 1) {
|
||||||
|
detail.setSortNo(maxSortNo + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
save(detail);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,10 +82,11 @@ public class QmsInspectionItemServiceImpl extends ServiceImpl<QmsInspectionItemM
|
||||||
for (QmsInspectionItemAddQO.DetailQO detailQO : qo.getDetails()) {
|
for (QmsInspectionItemAddQO.DetailQO detailQO : qo.getDetails()) {
|
||||||
QmsInspectionItemDetails detail = new QmsInspectionItemDetails()
|
QmsInspectionItemDetails detail = new QmsInspectionItemDetails()
|
||||||
.setInspectionItemId(item.getId())
|
.setInspectionItemId(item.getId())
|
||||||
|
.setSortNo(detailQO.getSortNo())
|
||||||
.setTestStandard(detailQO.getTestStandard())
|
.setTestStandard(detailQO.getTestStandard())
|
||||||
.setLegend(detailQO.getLegend())
|
.setLegend(detailQO.getLegend())
|
||||||
.setDeterminationType(detailQO.getDeterminationType());
|
.setDeterminationType(detailQO.getDeterminationType());
|
||||||
detailsService.save(detail);
|
detailsService.saveDetailWithSortNo(detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,10 +153,11 @@ public class QmsInspectionItemServiceImpl extends ServiceImpl<QmsInspectionItemM
|
||||||
for (QmsInspectionItemUpdateQO.DetailQO detailQO : qo.getDetails()) {
|
for (QmsInspectionItemUpdateQO.DetailQO detailQO : qo.getDetails()) {
|
||||||
QmsInspectionItemDetails detail = new QmsInspectionItemDetails()
|
QmsInspectionItemDetails detail = new QmsInspectionItemDetails()
|
||||||
.setInspectionItemId(qo.getId())
|
.setInspectionItemId(qo.getId())
|
||||||
|
.setSortNo(detailQO.getSortNo())
|
||||||
.setTestStandard(detailQO.getTestStandard())
|
.setTestStandard(detailQO.getTestStandard())
|
||||||
.setLegend(detailQO.getLegend())
|
.setLegend(detailQO.getLegend())
|
||||||
.setDeterminationType(detailQO.getDeterminationType());
|
.setDeterminationType(detailQO.getDeterminationType());
|
||||||
detailsService.save(detail);
|
detailsService.saveDetailWithSortNo(detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -215,6 +217,7 @@ public class QmsInspectionItemServiceImpl extends ServiceImpl<QmsInspectionItemM
|
||||||
// 查询明细列表
|
// 查询明细列表
|
||||||
List<QmsInspectionItemDetailsVO> detailsList = detailsService.lambdaQuery()
|
List<QmsInspectionItemDetailsVO> detailsList = detailsService.lambdaQuery()
|
||||||
.eq(QmsInspectionItemDetails::getInspectionItemId, id)
|
.eq(QmsInspectionItemDetails::getInspectionItemId, id)
|
||||||
|
.orderByAsc(QmsInspectionItemDetails::getSortNo)
|
||||||
.list()
|
.list()
|
||||||
.stream()
|
.stream()
|
||||||
.map(this::toDetailsVO)
|
.map(this::toDetailsVO)
|
||||||
|
|
@ -269,29 +272,40 @@ public class QmsInspectionItemServiceImpl extends ServiceImpl<QmsInspectionItemM
|
||||||
String operator = UserUtil.getUserName();
|
String operator = UserUtil.getUserName();
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
|
||||||
// 按检测项编号+名称分组,合并为一条主表记录,多行合并到明细表
|
// 按物料类别编号分组,同一类别合并为一条主表记录,多行合并到明细表
|
||||||
Map<String, List<QmsInspectionItemImportDTO>> grouped = dtos.stream()
|
Map<String, List<QmsInspectionItemImportDTO>> grouped = dtos.stream()
|
||||||
.filter(dto -> Objects.nonNull(dto.getMaterialTypeId())
|
.filter(dto -> StrUtil.isNotBlank(dto.getCategoryCode())
|
||||||
&& Objects.nonNull(dto.getDetectionType())
|
|
||||||
&& StrUtil.isNotBlank(dto.getInspectionItemName())
|
|
||||||
&& StrUtil.isNotBlank(dto.getInspectionNo())
|
|
||||||
&& StrUtil.isNotBlank(dto.getTestStandard())
|
&& StrUtil.isNotBlank(dto.getTestStandard())
|
||||||
&& Objects.nonNull(dto.getDeterminationType()))
|
&& StrUtil.isNotBlank(dto.getDetectionType())
|
||||||
.collect(Collectors.groupingBy(dto -> dto.getInspectionNo() + "|" + dto.getInspectionItemName()));
|
&& StrUtil.isNotBlank(dto.getDeterminationType()))
|
||||||
|
.collect(Collectors.groupingBy(QmsInspectionItemImportDTO::getCategoryCode));
|
||||||
|
|
||||||
for (Map.Entry<String, List<QmsInspectionItemImportDTO>> entry : grouped.entrySet()) {
|
for (Map.Entry<String, List<QmsInspectionItemImportDTO>> entry : grouped.entrySet()) {
|
||||||
List<QmsInspectionItemImportDTO> list = entry.getValue();
|
List<QmsInspectionItemImportDTO> list = entry.getValue();
|
||||||
if (list.isEmpty()) continue;
|
if (list.isEmpty()) continue;
|
||||||
|
|
||||||
// 取第一行作为主表数据
|
String categoryCode = entry.getKey();
|
||||||
QmsInspectionItemImportDTO first = list.get(0);
|
QmsInspectionItemImportDTO first = list.get(0);
|
||||||
|
|
||||||
|
// 查找物料类别
|
||||||
|
QmsQcMaterialCategory category = materialCategoryService.lambdaQuery()
|
||||||
|
.eq(QmsQcMaterialCategory::getCategoryCode, categoryCode)
|
||||||
|
.one();
|
||||||
|
if (category == null) continue;
|
||||||
|
|
||||||
|
// 自动生成编号和名称
|
||||||
|
String inspectionNo = "CATD_" + categoryCode;
|
||||||
|
String inspectionItemName = buildCategoryFullPath(category.getId());
|
||||||
|
|
||||||
|
// 检测类型文字转数字
|
||||||
|
Integer detectionType = parseDetectionType(first.getDetectionType());
|
||||||
|
|
||||||
// 创建主表记录
|
// 创建主表记录
|
||||||
QmsInspectionItem item = new QmsInspectionItem()
|
QmsInspectionItem item = new QmsInspectionItem()
|
||||||
.setMaterialTypeId(first.getMaterialTypeId())
|
.setMaterialTypeId(category.getId())
|
||||||
.setDetectionType(first.getDetectionType())
|
.setDetectionType(detectionType)
|
||||||
.setInspectionItemName(first.getInspectionItemName())
|
.setInspectionItemName(inspectionItemName)
|
||||||
.setInspectionNo(first.getInspectionNo())
|
.setInspectionNo(inspectionNo)
|
||||||
.setCreateBy(operator)
|
.setCreateBy(operator)
|
||||||
.setCreateTime(now)
|
.setCreateTime(now)
|
||||||
.setUpdateBy(operator)
|
.setUpdateBy(operator)
|
||||||
|
|
@ -300,16 +314,37 @@ public class QmsInspectionItemServiceImpl extends ServiceImpl<QmsInspectionItemM
|
||||||
|
|
||||||
// 所有行作为明细插入
|
// 所有行作为明细插入
|
||||||
for (QmsInspectionItemImportDTO dto : list) {
|
for (QmsInspectionItemImportDTO dto : list) {
|
||||||
|
Integer determinationType = parseDeterminationType(dto.getDeterminationType());
|
||||||
|
Integer serialNo = StrUtil.isNotBlank(dto.getSerialNo()) ? Integer.valueOf(dto.getSerialNo().trim()) : null;
|
||||||
QmsInspectionItemDetails detail = new QmsInspectionItemDetails()
|
QmsInspectionItemDetails detail = new QmsInspectionItemDetails()
|
||||||
.setInspectionItemId(item.getId())
|
.setInspectionItemId(item.getId())
|
||||||
|
.setSortNo(serialNo)
|
||||||
.setTestStandard(dto.getTestStandard())
|
.setTestStandard(dto.getTestStandard())
|
||||||
.setLegend(dto.getLegend())
|
.setLegend(dto.getLegend())
|
||||||
.setDeterminationType(dto.getDeterminationType());
|
.setDeterminationType(determinationType);
|
||||||
detailsService.save(detail);
|
detailsService.saveDetailWithSortNo(detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测类型文字转数字:定向→0,定量→1
|
||||||
|
*/
|
||||||
|
private Integer parseDetectionType(String text) {
|
||||||
|
if ("定向".equals(text) || "0".equals(text)) return 0;
|
||||||
|
if ("定量".equals(text) || "1".equals(text)) return 1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判定类型文字转数字:目视→0,量具→1
|
||||||
|
*/
|
||||||
|
private Integer parseDeterminationType(String text) {
|
||||||
|
if ("目视".equals(text) || "0".equals(text)) return 0;
|
||||||
|
if ("量具".equals(text) || "1".equals(text)) return 1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 私有工具 ====================
|
// ==================== 私有工具 ====================
|
||||||
|
|
||||||
private QmsInspectionItemVO toVO(QmsInspectionItem item) {
|
private QmsInspectionItemVO toVO(QmsInspectionItem item) {
|
||||||
|
|
@ -339,6 +374,7 @@ public class QmsInspectionItemServiceImpl extends ServiceImpl<QmsInspectionItemM
|
||||||
QmsInspectionItemDetailsVO vo = new QmsInspectionItemDetailsVO();
|
QmsInspectionItemDetailsVO vo = new QmsInspectionItemDetailsVO();
|
||||||
vo.setId(d.getId());
|
vo.setId(d.getId());
|
||||||
vo.setInspectionItemId(d.getInspectionItemId());
|
vo.setInspectionItemId(d.getInspectionItemId());
|
||||||
|
vo.setSortNo(d.getSortNo());
|
||||||
vo.setTestStandard(d.getTestStandard());
|
vo.setTestStandard(d.getTestStandard());
|
||||||
vo.setLegend(d.getLegend());
|
vo.setLegend(d.getLegend());
|
||||||
vo.setDeterminationType(d.getDeterminationType());
|
vo.setDeterminationType(d.getDeterminationType());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue