优化
This commit is contained in:
@@ -5,7 +5,10 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.util.*;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.validation.ValidationUtil;
|
||||
import cn.hutool.http.ContentType;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
@@ -17,15 +20,12 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dreamlu.mica.core.result.R;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
@@ -61,8 +61,6 @@ import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -70,7 +68,6 @@ import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import static top.wms.admin.system.enums.ImportPolicyEnum.*;
|
||||
import static top.wms.admin.system.enums.ImportPolicyEnum.SKIP;
|
||||
|
||||
/**
|
||||
* 物料信息业务实现
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package top.wms.admin.materialProcess.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import top.continew.starter.data.mp.base.BaseMapper;
|
||||
import top.wms.admin.materialProcess.model.entity.MaterialProcessDO;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 海康物料流程 Mapper
|
||||
*
|
||||
@@ -13,4 +16,7 @@ import org.springframework.stereotype.Repository;
|
||||
@Repository
|
||||
public interface MaterialProcessMapper extends BaseMapper<MaterialProcessDO> {
|
||||
|
||||
void updateByName(@Param("list") List<MaterialProcessDO> updateByNameList);
|
||||
|
||||
void updateByCode(@Param("list") List<MaterialProcessDO> updateByCodeList);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package top.wms.admin.materialProcess.model.req;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import top.wms.admin.system.enums.ImportPolicyEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 物料流程导入请求
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/20
|
||||
*/
|
||||
@Data
|
||||
public class MaterialProcessImportReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 导入key
|
||||
*/
|
||||
private String importKey;
|
||||
|
||||
/**
|
||||
* 重复流程名称处理策略: 0-跳过 1-更新 2-退出
|
||||
*/
|
||||
private ImportPolicyEnum duplicateName;
|
||||
|
||||
/**
|
||||
* 重复流程编码处理策略: 0-跳过 1-更新 2-退出
|
||||
*/
|
||||
private ImportPolicyEnum duplicateCode;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package top.wms.admin.materialProcess.model.req;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* 物料流程导入行数据
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/20
|
||||
*/
|
||||
@Data
|
||||
public class MaterialProcessImportRowReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@NotBlank(message = "流程名称不能为空")
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 流程编码
|
||||
*/
|
||||
@NotBlank(message = "流程编码不能为空")
|
||||
private String processCode;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package top.wms.admin.materialProcess.model.resp;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "用户导入解析结果")
|
||||
public class MaterialProcessImportParseResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 导入会话 Key
|
||||
*/
|
||||
@Schema(description = "导入会话Key", example = "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed")
|
||||
private String importKey;
|
||||
|
||||
/**
|
||||
* 总计行数
|
||||
*/
|
||||
@Schema(description = "总计行数", example = "100")
|
||||
private Integer totalRows;
|
||||
|
||||
/**
|
||||
* 有效行数
|
||||
*/
|
||||
@Schema(description = "有效行数", example = "100")
|
||||
private Integer validRows;
|
||||
|
||||
/**
|
||||
* 重复名称行数
|
||||
*/
|
||||
@Schema(description = "重复名称行数", example = "100")
|
||||
private Integer duplicateNameRows;
|
||||
|
||||
/**
|
||||
* 重复编码行数
|
||||
*/
|
||||
@Schema(description = "重复编码行数", example = "100")
|
||||
private Integer duplicateCodeRows;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package top.wms.admin.materialProcess.model.resp;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 物料流程导入响应
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/20
|
||||
*/
|
||||
@Data
|
||||
public class MaterialProcessImportResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 总处理数
|
||||
*/
|
||||
private Integer totalHandleCount;
|
||||
|
||||
/**
|
||||
* 新增数
|
||||
*/
|
||||
private Integer insertCount;
|
||||
|
||||
/**
|
||||
* 更新数
|
||||
*/
|
||||
private Integer updateCount;
|
||||
|
||||
public MaterialProcessImportResp(Integer totalHandleCount, Integer insertCount, Integer updateCount) {
|
||||
this.totalHandleCount = totalHandleCount;
|
||||
this.insertCount = insertCount;
|
||||
this.updateCount = updateCount;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package top.wms.admin.materialProcess.model.resp;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@@ -26,11 +27,13 @@ public class MaterialProcessResp extends BaseDetailResp {
|
||||
* 流程名称
|
||||
*/
|
||||
@Schema(description = "流程名称")
|
||||
@ExcelProperty(value = "流程名称", order = 1)
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 流程编码
|
||||
*/
|
||||
@Schema(description = "流程编码")
|
||||
@ExcelProperty(value = "流程编码", order = 2)
|
||||
private String processCode;
|
||||
}
|
||||
@@ -4,11 +4,11 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.continew.starter.extension.crud.model.resp.LabelValueResp;
|
||||
import top.continew.starter.extension.crud.service.BaseService;
|
||||
import top.wms.admin.material.model.req.MaterialInfoImportReq;
|
||||
import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
||||
import top.wms.admin.materialProcess.model.query.MaterialProcessQuery;
|
||||
import top.wms.admin.materialProcess.model.req.MaterialProcessImportReq;
|
||||
import top.wms.admin.materialProcess.model.req.MaterialProcessReq;
|
||||
import top.wms.admin.materialProcess.model.resp.MaterialProcessImportParseResp;
|
||||
import top.wms.admin.materialProcess.model.resp.MaterialProcessImportResp;
|
||||
import top.wms.admin.materialProcess.model.resp.MaterialProcessResp;
|
||||
|
||||
import java.util.List;
|
||||
@@ -36,14 +36,14 @@ public interface MaterialProcessService extends BaseService<MaterialProcessResp,
|
||||
/**
|
||||
* 解析导入文件
|
||||
* @param file 导入文件
|
||||
* @param file 导入文件
|
||||
* @return 解析响应
|
||||
*/
|
||||
MaterialImportParseResp parseImport(MultipartFile file);
|
||||
MaterialProcessImportParseResp parseImport(MultipartFile file);
|
||||
|
||||
/**
|
||||
* 导入物料信息
|
||||
* 导入物料流程
|
||||
* @param req 导入请求
|
||||
* @return 导入响应
|
||||
*/
|
||||
MaterialInfoImportResp importMaterial(MaterialInfoImportReq req);
|
||||
MaterialProcessImportResp importMaterialProcess(MaterialProcessImportReq req);
|
||||
}
|
||||
@@ -2,29 +2,47 @@ package top.wms.admin.materialProcess.service.impl;
|
||||
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.validation.ValidationUtil;
|
||||
import cn.hutool.http.ContentType;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.dreamlu.mica.core.result.R;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
import top.continew.starter.core.exception.BusinessException;
|
||||
import top.continew.starter.core.validation.CheckUtils;
|
||||
import top.continew.starter.extension.crud.model.query.SortQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.LabelValueResp;
|
||||
import top.continew.starter.extension.crud.service.BaseServiceImpl;
|
||||
import top.continew.starter.file.excel.util.ExcelUtils;
|
||||
import top.continew.starter.web.util.FileUploadUtils;
|
||||
import top.wms.admin.material.model.req.MaterialInfoImportReq;
|
||||
import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
||||
import top.wms.admin.common.constant.CacheConstants;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoResp;
|
||||
import top.wms.admin.materialProcess.mapper.MaterialProcessMapper;
|
||||
import top.wms.admin.materialProcess.mapstruct.MaterialProcessConvert;
|
||||
import top.wms.admin.materialProcess.model.entity.MaterialProcessDO;
|
||||
import top.wms.admin.materialProcess.model.query.MaterialProcessQuery;
|
||||
import top.wms.admin.materialProcess.model.req.MaterialProcessImportReq;
|
||||
import top.wms.admin.materialProcess.model.req.MaterialProcessImportRowReq;
|
||||
import top.wms.admin.materialProcess.model.req.MaterialProcessReq;
|
||||
import top.wms.admin.materialProcess.model.resp.MaterialProcessImportParseResp;
|
||||
import top.wms.admin.materialProcess.model.resp.MaterialProcessImportResp;
|
||||
import top.wms.admin.materialProcess.model.resp.MaterialProcessResp;
|
||||
import top.wms.admin.materialProcess.service.MaterialProcessService;
|
||||
|
||||
import java.util.List;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static top.wms.admin.system.enums.ImportPolicyEnum.*;
|
||||
|
||||
/**
|
||||
* 海康物料流程业务实现
|
||||
@@ -38,6 +56,39 @@ public class MaterialProcessServiceImpl extends BaseServiceImpl<MaterialProcessM
|
||||
|
||||
private final MaterialProcessConvert materialProcessConvert;
|
||||
|
||||
|
||||
@Override
|
||||
public void beforeAdd(MaterialProcessReq req) {
|
||||
// 校验流程名称是否重复
|
||||
MaterialProcessDO processDO = baseMapper.selectOne(Wrappers.lambdaQuery(MaterialProcessDO.class)
|
||||
.eq(MaterialProcessDO::getProcessName, req.getProcessName()));
|
||||
CheckUtils.throwIf(ObjectUtil.isNotEmpty(processDO), "流程名称已存在");
|
||||
// 校验流程编码是否重复
|
||||
processDO = baseMapper.selectOne(Wrappers.lambdaQuery(MaterialProcessDO.class)
|
||||
.eq(MaterialProcessDO::getProcessCode, req.getProcessCode()));
|
||||
CheckUtils.throwIf(ObjectUtil.isNotEmpty(processDO), "流程编码已存在");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeUpdate(MaterialProcessReq req, Long id) {
|
||||
// 校验流程名称是否重复
|
||||
MaterialProcessDO processDO = baseMapper.selectOne(Wrappers.lambdaQuery(MaterialProcessDO.class)
|
||||
.eq(MaterialProcessDO::getProcessName, req.getProcessName()).ne(MaterialProcessDO::getId, id));
|
||||
CheckUtils.throwIf(ObjectUtil.isNotEmpty(processDO), "流程名称已存在");
|
||||
// 校验流程编码是否重复
|
||||
processDO = baseMapper.selectOne(Wrappers.lambdaQuery(MaterialProcessDO.class)
|
||||
.eq(MaterialProcessDO::getProcessCode, req.getProcessCode()).ne(MaterialProcessDO::getId, id));
|
||||
CheckUtils.throwIf(ObjectUtil.isNotEmpty(processDO), "流程编码已存在");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void export(MaterialProcessQuery query, SortQuery sortQuery, HttpServletResponse response) {
|
||||
List<MaterialProcessResp> list = super.list(query, sortQuery, this.getDetailClass());
|
||||
list.forEach(super::fill);
|
||||
ExcelUtils.export(list, "物料流程导出", MaterialProcessResp.class, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LabelValueResp> getSelectList() {
|
||||
List<MaterialProcessDO> materialProcessDOS = baseMapper.selectList(new QueryWrapper<>());
|
||||
@@ -58,12 +109,210 @@ public class MaterialProcessServiceImpl extends BaseServiceImpl<MaterialProcessM
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialImportParseResp parseImport(MultipartFile file) {
|
||||
return null;
|
||||
public MaterialProcessImportParseResp parseImport(MultipartFile file) {
|
||||
MaterialProcessImportParseResp importResp = new MaterialProcessImportParseResp();
|
||||
List<MaterialProcessImportRowReq> importRowList;
|
||||
// 读取表格数据
|
||||
try {
|
||||
importRowList = com.alibaba.excel.EasyExcel.read(file.getInputStream())
|
||||
.head(MaterialProcessImportRowReq.class)
|
||||
.sheet()
|
||||
.headRowNumber(1)
|
||||
.doReadSync();
|
||||
} catch (Exception e) {
|
||||
log.error("物料流程导入数据文件解析异常:", e);
|
||||
throw new BusinessException("数据文件解析异常");
|
||||
}
|
||||
// 总计行数
|
||||
importResp.setTotalRows(importRowList.size());
|
||||
CheckUtils.throwIfEmpty(importRowList, "数据文件格式错误");
|
||||
// 有效行数:过滤无效数据
|
||||
List<MaterialProcessImportRowReq> validRowList = this.filterImportData(importRowList);
|
||||
importResp.setValidRows(validRowList.size());
|
||||
CheckUtils.throwIfEmpty(validRowList, "数据文件格式错误");
|
||||
|
||||
// 检测表格内数据是否合法
|
||||
Set<String> seenCode = new HashSet<>();
|
||||
boolean hasDuplicateCode = validRowList.stream()
|
||||
.map(MaterialProcessImportRowReq::getProcessCode)
|
||||
.anyMatch(code -> code != null && !seenCode.add(code));
|
||||
CheckUtils.throwIf(hasDuplicateCode, "存在重复流程编码,请检测数据");
|
||||
|
||||
// 查询重复流程名称
|
||||
importResp
|
||||
.setDuplicateNameRows(countExistByField(validRowList, MaterialProcessImportRowReq::getProcessName, MaterialProcessDO::getProcessName));
|
||||
// 查询重复流程编码
|
||||
importResp
|
||||
.setDuplicateCodeRows(countExistByField(validRowList, MaterialProcessImportRowReq::getProcessCode, MaterialProcessDO::getProcessCode));
|
||||
// 设置导入会话并缓存数据,有效期10分钟
|
||||
String importKey = java.util.UUID.randomUUID().toString().replace("-", "");
|
||||
RedisUtils.set(CacheConstants.DATA_IMPORT_KEY + importKey, JSONUtil.toJsonStr(validRowList), Duration
|
||||
.ofMinutes(10));
|
||||
importResp.setImportKey(importKey);
|
||||
return importResp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialInfoImportResp importMaterial(MaterialInfoImportReq req) {
|
||||
return null;
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public MaterialProcessImportResp importMaterialProcess(MaterialProcessImportReq req) {
|
||||
// 校验导入会话是否过期
|
||||
List<MaterialProcessImportRowReq> importMaterialList;
|
||||
try {
|
||||
String data = RedisUtils.get(CacheConstants.DATA_IMPORT_KEY + req.getImportKey());
|
||||
importMaterialList = JSONUtil.toList(data, MaterialProcessImportRowReq.class);
|
||||
CheckUtils.throwIf(ObjectUtil.isEmpty(importMaterialList), "导入已过期,请重新上传");
|
||||
} catch (Exception e) {
|
||||
log.error("导入异常:", e);
|
||||
throw new BusinessException("导入已过期,请重新上传");
|
||||
}
|
||||
// 已存在数据查询
|
||||
List<String> existName = listExistByField(importMaterialList, MaterialProcessImportRowReq::getProcessName, MaterialProcessDO::getProcessName);
|
||||
List<String> existCode = listExistByField(importMaterialList, MaterialProcessImportRowReq::getProcessCode, MaterialProcessDO::getProcessCode);
|
||||
CheckUtils.throwIf(isExitImportMaterial(req, importMaterialList, existName, existCode), "数据不符合导入策略,已退出导入");
|
||||
|
||||
// 批量操作数据库集合
|
||||
List<MaterialProcessDO> insertList = new ArrayList<>();
|
||||
List<MaterialProcessDO> updateByNameList = new ArrayList<>();
|
||||
List<MaterialProcessDO> updateByCodeList = new ArrayList<>();
|
||||
// 处理导入数据
|
||||
for (MaterialProcessImportRowReq row : importMaterialList) {
|
||||
if (isSkipMaterialImport(req, row, existName, existCode)) {
|
||||
continue;
|
||||
}
|
||||
MaterialProcessDO materialProcessDO = new MaterialProcessDO();
|
||||
materialProcessDO.setProcessName(row.getProcessName());
|
||||
materialProcessDO.setProcessCode(row.getProcessCode());
|
||||
// 修改 or 新增
|
||||
if (UPDATE.validate(req.getDuplicateName(), row.getProcessName(), existName)) {
|
||||
materialProcessDO.setProcessCode(row.getProcessCode());
|
||||
materialProcessDO.setUpdateUser(UserContextHolder.getUserId());
|
||||
updateByNameList.add(materialProcessDO);
|
||||
} else if (UPDATE.validate(req.getDuplicateCode(), row.getProcessCode(), existCode)) {
|
||||
materialProcessDO.setProcessCode(row.getProcessCode());
|
||||
materialProcessDO.setUpdateUser(UserContextHolder.getUserId());
|
||||
updateByCodeList.add(materialProcessDO);
|
||||
} else {
|
||||
insertList.add(materialProcessDO);
|
||||
}
|
||||
}
|
||||
doImportMaterial(insertList, updateByNameList, updateByCodeList);
|
||||
RedisUtils.delete(CacheConstants.DATA_IMPORT_KEY + req.getImportKey());
|
||||
int insertCount = insertList.size();
|
||||
int updateByNameCount = updateByNameList.size();
|
||||
int updateByCodeCount = updateByCodeList.size();
|
||||
int totalUpdateCount = updateByNameCount + updateByCodeCount;
|
||||
int totalHandleCount = insertCount + totalUpdateCount;
|
||||
return new MaterialProcessImportResp(totalHandleCount, // 总处理数
|
||||
insertCount, // 新增数
|
||||
totalUpdateCount // 更新总数
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按指定数据集获取数据库已存在的数量
|
||||
*
|
||||
* @param materialRowList 导入的数据源
|
||||
* @param rowField 导入数据的字段
|
||||
* @param dbField 对比数据库的字段
|
||||
* @return 存在的数量
|
||||
*/
|
||||
private int countExistByField(List<MaterialProcessImportRowReq> materialRowList,
|
||||
Function<MaterialProcessImportRowReq, String> rowField,
|
||||
SFunction<MaterialProcessDO, ?> dbField) {
|
||||
List<String> fieldValues = materialRowList.stream().map(rowField).filter(Objects::nonNull).toList();
|
||||
if (fieldValues.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return (int)this.count(Wrappers.<MaterialProcessDO>lambdaQuery()
|
||||
.in(dbField, fieldValues));
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤无效的导入数据
|
||||
*
|
||||
* @param importRowList 导入数据
|
||||
*/
|
||||
private List<MaterialProcessImportRowReq> filterImportData(List<MaterialProcessImportRowReq> importRowList) {
|
||||
// 校验过滤
|
||||
return importRowList.stream()
|
||||
.filter(row -> ValidationUtil.validate(row).isEmpty())
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按指定数据集获取数据库已存在内容
|
||||
*
|
||||
* @param materialRowList 导入的数据源
|
||||
* @param rowField 导入数据的字段
|
||||
* @param dbField 对比数据库的字段
|
||||
* @return 存在的内容
|
||||
*/
|
||||
private List<String> listExistByField(List<MaterialProcessImportRowReq> materialRowList,
|
||||
Function<MaterialProcessImportRowReq, String> rowField,
|
||||
SFunction<MaterialProcessDO, String> dbField) {
|
||||
List<String> fieldValues = materialRowList.stream().map(rowField).filter(Objects::nonNull).toList();
|
||||
if (fieldValues.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<MaterialProcessDO> materialProcessDOList = baseMapper.selectList(Wrappers.<MaterialProcessDO>lambdaQuery()
|
||||
.in(dbField, fieldValues)
|
||||
.select(dbField));
|
||||
return materialProcessDOList.stream().map(dbField).filter(Objects::nonNull).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否退出导入
|
||||
*
|
||||
* @param req 导入参数
|
||||
* @param list 导入数据
|
||||
* @param existName 导入数据中已存在的流程名称
|
||||
* @param existCode 导入数据中已存在的流程编码
|
||||
* @return 是否退出
|
||||
*/
|
||||
private boolean isExitImportMaterial(MaterialProcessImportReq req,
|
||||
List<MaterialProcessImportRowReq> list,
|
||||
List<String> existName,
|
||||
List<String> existCode) {
|
||||
return list.stream()
|
||||
.anyMatch(row -> EXIT.validate(req.getDuplicateName(), row.getProcessName(), existName) || EXIT
|
||||
.validate(req.getDuplicateCode(), row.getProcessCode(), existCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否跳过导入
|
||||
*
|
||||
* @param req 导入参数
|
||||
* @param row 导入数据
|
||||
* @param existName 导入数据中已存在的流程名称
|
||||
* @param existCode 导入数据中已存在的流程编码
|
||||
* @return 是否跳过
|
||||
*/
|
||||
private boolean isSkipMaterialImport(MaterialProcessImportReq req,
|
||||
MaterialProcessImportRowReq row,
|
||||
List<String> existName,
|
||||
List<String> existCode) {
|
||||
return SKIP.validate(req.getDuplicateName(), row.getProcessName(), existName) || SKIP.validate(req
|
||||
.getDuplicateCode(), row.getProcessCode(), existCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入物料流程
|
||||
*
|
||||
* @param insertList 新增流程
|
||||
* @param updateByNameList 根据名称修改流程
|
||||
* @param updateByCodeList 根据编码修改流程
|
||||
*/
|
||||
private void doImportMaterial(List<MaterialProcessDO> insertList,
|
||||
List<MaterialProcessDO> updateByNameList,
|
||||
List<MaterialProcessDO> updateByCodeList) {
|
||||
if (insertList != null && !insertList.isEmpty()) {
|
||||
baseMapper.insertBatch(insertList);
|
||||
}
|
||||
if (updateByNameList != null && !updateByNameList.isEmpty()) {
|
||||
baseMapper.updateByName(updateByNameList);
|
||||
}
|
||||
if (updateByCodeList != null && !updateByCodeList.isEmpty()) {
|
||||
baseMapper.updateByCode(updateByCodeList);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="top.wms.admin.materialProcess.mapper.MaterialProcessMapper">
|
||||
<!-- 按流程名称批量更新 -->
|
||||
<update id="updateByName">
|
||||
UPDATE sys_material_process
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="list != null and list.size() > 0">
|
||||
process_code = CASE
|
||||
<foreach collection="list" item="item" separator="">
|
||||
<if test="item.processCode != null and item.processCode != ''">
|
||||
WHEN process_name = #{item.processName} THEN #{item.processCode}
|
||||
</if>
|
||||
</foreach>
|
||||
ELSE process_code
|
||||
END,
|
||||
update_user = CASE
|
||||
<foreach collection="list" item="item" separator="">
|
||||
<if test="item.updateUser != null">
|
||||
WHEN process_name = #{item.processName} THEN #{item.updateUser}
|
||||
</if>
|
||||
</foreach>
|
||||
ELSE update_user
|
||||
END,
|
||||
update_time = NOW()
|
||||
</if>
|
||||
</trim>
|
||||
WHERE process_name IN
|
||||
<foreach collection="list" item="item" open="(" close=")" separator=",">
|
||||
#{item.processName}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<update id="updateByCode">
|
||||
UPDATE sys_material_process
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="list != null and list.size() > 0">
|
||||
process_name = CASE
|
||||
<foreach collection="list" item="item" separator="">
|
||||
<if test="item.processName != null and item.processName != ''">
|
||||
WHEN process_code = #{item.processCode} THEN #{item.processName}
|
||||
</if>
|
||||
</foreach>
|
||||
ELSE process_name
|
||||
END,
|
||||
update_user = CASE
|
||||
<foreach collection="list" item="item" separator="">
|
||||
<if test="item.updateUser != null">
|
||||
WHEN process_code = #{item.processCode} THEN #{item.updateUser}
|
||||
</if>
|
||||
</foreach>
|
||||
ELSE update_user
|
||||
END,
|
||||
update_time = NOW()
|
||||
</if>
|
||||
</trim>
|
||||
WHERE process_code IN
|
||||
<foreach collection="list" item="item" open="(" close=")" separator=",">
|
||||
#{item.processCode}
|
||||
</foreach>
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -4,46 +4,76 @@
|
||||
|
||||
<!-- 按物料名称批量更新 -->
|
||||
<update id="updateByName">
|
||||
<foreach collection="list" item="item" separator=";">
|
||||
UPDATE sys_material_info
|
||||
<set>
|
||||
<if test="item.encoding != null and item.encoding != ''" >
|
||||
encoding = #{item.encoding},
|
||||
</if>
|
||||
<if test="item.unitWeight != null">
|
||||
unit_weight = #{item.unitWeight},
|
||||
</if>
|
||||
<if test="item.materialSpec != null and item.materialSpec != ''">
|
||||
material_spec = #{item.materialSpec},
|
||||
</if>
|
||||
<if test="item.updateUser != null">
|
||||
update_user = #{item.updateUser},
|
||||
</if>
|
||||
UPDATE sys_material_info
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="list != null and list.size() > 0">
|
||||
encoding = CASE
|
||||
<foreach collection="list" item="item" separator="">
|
||||
<if test="item.encoding != null and item.encoding != ''">
|
||||
WHEN material_name = #{item.materialName} THEN #{item.encoding}
|
||||
</if>
|
||||
</foreach>
|
||||
ELSE encoding
|
||||
END,
|
||||
unit_weight = CASE
|
||||
<foreach collection="list" item="item" separator="">
|
||||
<if test="item.unitWeight != null">
|
||||
WHEN material_name = #{item.materialName} THEN #{item.unitWeight}
|
||||
</if>
|
||||
</foreach>
|
||||
ELSE unit_weight
|
||||
END,
|
||||
update_user = CASE
|
||||
<foreach collection="list" item="item" separator="">
|
||||
<if test="item.updateUser != null">
|
||||
WHEN material_name = #{item.materialName} THEN #{item.updateUser}
|
||||
</if>
|
||||
</foreach>
|
||||
ELSE update_user
|
||||
END,
|
||||
update_time = NOW()
|
||||
</set>
|
||||
WHERE material_name = #{item.materialName}
|
||||
</if>
|
||||
</trim>
|
||||
WHERE material_name IN
|
||||
<foreach collection="list" item="item" open="(" close=")" separator=",">
|
||||
#{item.materialName}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<update id="updateByCode">
|
||||
<foreach collection="list" item="item" separator=";">
|
||||
UPDATE sys_material_info
|
||||
<set>
|
||||
<if test="item.materialName != null and item.materialName != ''">
|
||||
material_name = #{item.materialName},
|
||||
</if>
|
||||
<if test="item.unitWeight != null">
|
||||
unit_weight = #{item.unitWeight},
|
||||
</if>
|
||||
<if test="item.materialSpec != null and item.materialSpec != ''">
|
||||
material_spec = #{item.materialSpec},
|
||||
</if>
|
||||
<if test="item.updateUser != null ">
|
||||
update_user = #{item.updateUser},
|
||||
</if>
|
||||
UPDATE sys_material_info
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="list != null and list.size() > 0">
|
||||
material_name = CASE
|
||||
<foreach collection="list" item="item" separator="">
|
||||
<if test="item.materialName != null and item.materialName != ''">
|
||||
WHEN encoding = #{item.encoding} THEN #{item.materialName}
|
||||
</if>
|
||||
</foreach>
|
||||
ELSE material_name
|
||||
END,
|
||||
unit_weight = CASE
|
||||
<foreach collection="list" item="item" separator="">
|
||||
<if test="item.unitWeight != null">
|
||||
WHEN encoding = #{item.encoding} THEN #{item.unitWeight}
|
||||
</if>
|
||||
</foreach>
|
||||
ELSE unit_weight
|
||||
END,
|
||||
update_user = CASE
|
||||
<foreach collection="list" item="item" separator="">
|
||||
<if test="item.updateUser != null">
|
||||
WHEN encoding = #{item.encoding} THEN #{item.updateUser}
|
||||
</if>
|
||||
</foreach>
|
||||
ELSE update_user
|
||||
END,
|
||||
update_time = NOW()
|
||||
</set>
|
||||
WHERE encoding = #{item.encoding}
|
||||
</if>
|
||||
</trim>
|
||||
WHERE encoding IN
|
||||
<foreach collection="list" item="item" open="(" close=")" separator=",">
|
||||
#{item.encoding}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
@@ -70,4 +100,4 @@
|
||||
${ew.customSqlSegment}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
</mapper>
|
||||
@@ -2,32 +2,31 @@ package top.wms.admin.controller.materialProcess;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.continew.starter.core.validation.ValidationUtils;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
import top.continew.starter.extension.crud.model.resp.LabelValueResp;
|
||||
import top.continew.starter.log.annotation.Log;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.material.model.req.MaterialInfoImportReq;
|
||||
import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
||||
import top.wms.admin.materialProcess.model.query.MaterialProcessQuery;
|
||||
import top.wms.admin.materialProcess.model.req.MaterialProcessImportReq;
|
||||
import top.wms.admin.materialProcess.model.req.MaterialProcessReq;
|
||||
import top.wms.admin.materialProcess.model.resp.MaterialProcessImportParseResp;
|
||||
import top.wms.admin.materialProcess.model.resp.MaterialProcessImportResp;
|
||||
import top.wms.admin.materialProcess.model.resp.MaterialProcessResp;
|
||||
import top.wms.admin.materialProcess.service.MaterialProcessService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -61,7 +60,7 @@ public class MaterialProcessController extends BaseController<MaterialProcessSer
|
||||
@Operation(summary = "解析导入数据", description = "解析导入数据")
|
||||
@SaCheckPermission("materialProcess:materialProcess:import")
|
||||
@PostMapping("/import/parse")
|
||||
public MaterialImportParseResp parseImport(@NotNull(message = "文件不能为空") MultipartFile file) {
|
||||
public MaterialProcessImportParseResp parseImport(@NotNull(message = "文件不能为空") MultipartFile file) {
|
||||
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
|
||||
return baseService.parseImport(file);
|
||||
}
|
||||
@@ -69,8 +68,8 @@ public class MaterialProcessController extends BaseController<MaterialProcessSer
|
||||
@Operation(summary = "导入数据", description = "导入数据")
|
||||
@SaCheckPermission("materialProcess:materialProcess:import")
|
||||
@PostMapping(value = "/import")
|
||||
public MaterialInfoImportResp importUser(@Validated @RequestBody MaterialInfoImportReq req) {
|
||||
return baseService.importMaterial(req);
|
||||
public MaterialProcessImportResp importUser(@Validated @RequestBody MaterialProcessImportReq req) {
|
||||
return baseService.importMaterialProcess(req);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,7 +18,7 @@ spring:
|
||||
spring.datasource:
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
# 请务必提前创建好名为 wms_admin 的数据库,如果使用其他数据库名请注意同步修改 DB_NAME 配置
|
||||
url: jdbc:p6spy:mysql://127.0.0.1:3306/wms?serverTimezone=Asia/Shanghai&useSSL=false&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&allowMultiQueries=true
|
||||
url: jdbc:p6spy:mysql://127.0.0.1:3306/wms?serverTimezone=Asia/Shanghai&useSSL=false&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||
username: root
|
||||
password: root
|
||||
# PostgreSQL 配置
|
||||
|
||||
@@ -14,7 +14,7 @@ server:
|
||||
spring.datasource:
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
# 请务必提前创建好名为 wms_admin 的数据库,如果使用其他数据库名请注意同步修改 DB_NAME 配置
|
||||
url: jdbc:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:wms_admin}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&allowMultiQueries=true
|
||||
url: jdbc:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:wms_admin}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||
username: ${DB_USER:root}
|
||||
password: ${DB_PWD:123456}
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
Reference in New Issue
Block a user