优化
This commit is contained in:
@@ -28,4 +28,8 @@ public interface MaterialInfoMapper extends BaseMapper<MaterialInfoDO> {
|
||||
@Param(Constants.WRAPPER) QueryWrapper<MaterialInfoDO> queryWrapper);
|
||||
|
||||
List<MaterialInfoResp> selectMaterialInfoExport(@Param(Constants.WRAPPER) QueryWrapper<MaterialInfoDO> queryWrapper);
|
||||
|
||||
void updateBatchNull();
|
||||
|
||||
int updateBatchByCode(List<MaterialInfoDO> materialInfoDOS);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class MaterialInfoDO extends BaseDO {
|
||||
private String photoUrl;
|
||||
|
||||
/**
|
||||
* 物料类型ID
|
||||
* 物料品类ID
|
||||
*/
|
||||
private Long materialTypeId;
|
||||
|
||||
@@ -66,4 +66,10 @@ public class MaterialInfoDO extends BaseDO {
|
||||
* 颜色
|
||||
*/
|
||||
private String color;
|
||||
|
||||
/**
|
||||
* 批次
|
||||
*/
|
||||
private String batch;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package top.wms.admin.material.model.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Schema(description = "批次导入参数")
|
||||
public class BatchImportReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 导入会话KEY
|
||||
*/
|
||||
@Schema(description = "导入会话KEY", example = "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed")
|
||||
@NotBlank(message = "导入已过期,请重新上传")
|
||||
private String importKey;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package top.wms.admin.material.model.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Schema(description = "物料信息导入行数据")
|
||||
public class BatchImportRowReq implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 物料名称
|
||||
*/
|
||||
@Schema(description = "物料编码")
|
||||
@NotBlank(message = "物料编码不能为空")
|
||||
@Length(max = 255, message = "物料编码长度不能超过 {max} 个字符")
|
||||
private String encoding;
|
||||
|
||||
/**
|
||||
* 批次
|
||||
*/
|
||||
@Schema(description = "批次")
|
||||
@NotBlank(message = "批次不能为空")
|
||||
@Length(max = 255, message = "批次长度不能超过 {max} 个字符")
|
||||
private String batch;
|
||||
|
||||
}
|
||||
@@ -52,9 +52,9 @@ public class MaterialImportRowReq implements Serializable {
|
||||
private Double materialSpec;
|
||||
|
||||
/**
|
||||
* 物料类型名称
|
||||
* 物料品类名称
|
||||
*/
|
||||
@Schema(description = "物料类型名称")
|
||||
@Schema(description = "物料品类名称")
|
||||
private String typeName;
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,8 +48,8 @@ public class MaterialInfoReq implements Serializable {
|
||||
private Double unitWeight;
|
||||
|
||||
/*
|
||||
* 物料直径
|
||||
* */
|
||||
* 物料直径
|
||||
* */
|
||||
@Schema(description = "物料直径")
|
||||
private Double materialSpec;
|
||||
|
||||
@@ -61,10 +61,10 @@ public class MaterialInfoReq implements Serializable {
|
||||
private String photoUrl;
|
||||
|
||||
/**
|
||||
* 物料类型ID
|
||||
* 物料品类ID
|
||||
*/
|
||||
@Schema(description = "物料类型ID")
|
||||
@NotNull(message = "物料类型ID不能为空")
|
||||
@Schema(description = "物料品类ID")
|
||||
@NotNull(message = "物料品类ID不能为空")
|
||||
private Long materialTypeId;
|
||||
|
||||
/**
|
||||
@@ -85,4 +85,11 @@ public class MaterialInfoReq implements Serializable {
|
||||
*/
|
||||
@Schema(description = "颜色")
|
||||
private String color;
|
||||
|
||||
/**
|
||||
* 批次
|
||||
*/
|
||||
@Schema(description = "批次")
|
||||
private String batch;
|
||||
|
||||
}
|
||||
|
||||
@@ -58,10 +58,10 @@ public class MaterialInfoResp extends BaseDetailResp {
|
||||
private String photoUrl;
|
||||
|
||||
/**
|
||||
* 物料类型名称
|
||||
* 物料品类名称
|
||||
*/
|
||||
@Schema(description = "物料类型名称")
|
||||
@ExcelProperty(value = "物料类型")
|
||||
@Schema(description = "物料品类名称")
|
||||
@ExcelProperty(value = "物料品类")
|
||||
private String typeName;
|
||||
|
||||
/**
|
||||
@@ -72,9 +72,9 @@ public class MaterialInfoResp extends BaseDetailResp {
|
||||
private String materialProcess;
|
||||
|
||||
/**
|
||||
* 物料类型ID
|
||||
* 物料品类ID
|
||||
*/
|
||||
@Schema(description = "物料类型ID")
|
||||
@Schema(description = "物料品类ID")
|
||||
@ExcelIgnore
|
||||
private Long materialTypeId;
|
||||
|
||||
@@ -106,4 +106,11 @@ public class MaterialInfoResp extends BaseDetailResp {
|
||||
@ExcelProperty(value = "颜色", order = 6)
|
||||
private String color;
|
||||
|
||||
/**
|
||||
* 批次
|
||||
*/
|
||||
@Schema(description = "批次")
|
||||
@ExcelProperty(value = "批次", order = 7)
|
||||
private String batch;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.continew.starter.extension.crud.service.BaseService;
|
||||
import top.wms.admin.material.model.query.MaterialInfoQuery;
|
||||
import top.wms.admin.material.model.req.BatchImportReq;
|
||||
import top.wms.admin.material.model.req.MaterialInfoImportReq;
|
||||
import top.wms.admin.material.model.req.MaterialInfoReq;
|
||||
import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
||||
@@ -69,4 +70,28 @@ public interface MaterialInfoService extends BaseService<MaterialInfoResp, Mater
|
||||
* 称重时照片抓取
|
||||
* */
|
||||
String catchPhoto(MultipartFile file);
|
||||
|
||||
/**
|
||||
* 下载批量导入模板
|
||||
*
|
||||
* @param response 响应对象
|
||||
* @throws IOException /
|
||||
*/
|
||||
void downloadBatchImportTemplate(HttpServletResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* 解析批量导入数据
|
||||
*
|
||||
* @param file 导入文件
|
||||
* @return 解析结果
|
||||
*/
|
||||
MaterialImportParseResp parseBatchImport(MultipartFile file);
|
||||
|
||||
/**
|
||||
* 导入批量数据
|
||||
*
|
||||
* @param req 导入信息
|
||||
* @return 导入结果
|
||||
*/
|
||||
MaterialInfoImportResp importBatchMaterial(BatchImportReq req);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ import com.alibaba.excel.EasyExcel;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
|
||||
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@@ -43,9 +45,7 @@ import top.wms.admin.common.util.SecureUtils;
|
||||
import top.wms.admin.material.mapper.MaterialInfoMapper;
|
||||
import top.wms.admin.material.model.entity.MaterialInfoDO;
|
||||
import top.wms.admin.material.model.query.MaterialInfoQuery;
|
||||
import top.wms.admin.material.model.req.MaterialImportRowReq;
|
||||
import top.wms.admin.material.model.req.MaterialInfoImportReq;
|
||||
import top.wms.admin.material.model.req.MaterialInfoReq;
|
||||
import top.wms.admin.material.model.req.*;
|
||||
import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoResp;
|
||||
@@ -135,10 +135,10 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
||||
FileUploadUtils.download(response, ResourceUtil
|
||||
.getStream("templates/import/materialInfo.xlsx"), "物料信息导入模板.xlsx");
|
||||
} catch (Exception e) {
|
||||
log.error("下载用户导入模板失败:", e);
|
||||
log.error("下载物料信息导入模板失败:", e);
|
||||
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
||||
response.setContentType(ContentType.JSON.toString());
|
||||
response.getWriter().write(JSONUtil.toJsonStr(R.fail("下载用户导入模板失败")));
|
||||
response.getWriter().write(JSONUtil.toJsonStr(R.fail("下载物料信息导入模板失败")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
||||
List<String> existCode = listExistByField(importMaterialList, MaterialImportRowReq::getEncoding, MaterialInfoDO::getEncoding);
|
||||
CheckUtils.throwIf(isExitImportMaterial(req, importMaterialList, existName, existCode), "数据不符合导入策略,已退出导入");
|
||||
|
||||
//查询物料类型
|
||||
//查询物料品类
|
||||
List<String> collect = importMaterialList.stream().map(MaterialImportRowReq::getTypeName).distinct().toList();
|
||||
Map<String, Long> materialTypeMap = new HashMap<>();
|
||||
if (CollUtil.isNotEmpty(collect)) {
|
||||
@@ -290,6 +290,16 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
||||
return importRowList.stream().filter(row -> ValidationUtil.validate(row).isEmpty()).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤无效的导入用户数据(批量导入不严格校验数据)
|
||||
*
|
||||
* @param importRowList 导入数据
|
||||
*/
|
||||
private List<BatchImportRowReq> filterImportData2(List<BatchImportRowReq> importRowList) {
|
||||
// 校验过滤
|
||||
return importRowList.stream().filter(row -> ValidationUtil.validate(row).isEmpty()).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按指定数据集获取数据库已存在内容
|
||||
*
|
||||
@@ -472,4 +482,84 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
||||
return fileInfo.getUrl();
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void downloadBatchImportTemplate(HttpServletResponse response) throws IOException {
|
||||
try {
|
||||
FileUploadUtils.download(response, ResourceUtil
|
||||
.getStream("templates/import/batch.xlsx"), "批次导入模板.xlsx");
|
||||
} catch (Exception e) {
|
||||
log.error("下载批次导入模板失败:", e);
|
||||
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
||||
response.setContentType(ContentType.JSON.toString());
|
||||
response.getWriter().write(JSONUtil.toJsonStr(R.fail("下载批次导入模板失败")));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialImportParseResp parseBatchImport(MultipartFile file) {
|
||||
MaterialImportParseResp materialImportResp = new MaterialImportParseResp();
|
||||
List<BatchImportRowReq> importRowList;
|
||||
// 读取表格数据
|
||||
try {
|
||||
importRowList = EasyExcel.read(file.getInputStream())
|
||||
.head(BatchImportRowReq.class)
|
||||
.sheet()
|
||||
.headRowNumber(1)
|
||||
.doReadSync();
|
||||
} catch (Exception e) {
|
||||
log.error("物料信息导入数据文件解析异常:", e);
|
||||
throw new BusinessException("数据文件解析异常");
|
||||
}
|
||||
// 总计行数
|
||||
materialImportResp.setTotalRows(importRowList.size());
|
||||
CheckUtils.throwIfEmpty(importRowList, "数据文件格式错误");
|
||||
// 有效行数:过滤无效(同名物料)数据
|
||||
List<BatchImportRowReq> validRowList = this.filterImportData2(importRowList);
|
||||
materialImportResp.setValidRows(validRowList.size());
|
||||
CheckUtils.throwIfEmpty(validRowList, "数据文件格式错误");
|
||||
|
||||
// 设置导入会话并缓存数据,有效期10分钟
|
||||
String importKey = UUID.fastUUID().toString(true);
|
||||
RedisUtils.set(CacheConstants.DATA_IMPORT_KEY + importKey, JSONUtil.toJsonStr(validRowList), Duration
|
||||
.ofMinutes(10));
|
||||
materialImportResp.setImportKey(importKey);
|
||||
return materialImportResp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialInfoImportResp importBatchMaterial(BatchImportReq req) {
|
||||
// 校验导入会话是否过期
|
||||
List<BatchImportRowReq> batchImportRowReqs;
|
||||
try {
|
||||
String data = RedisUtils.get(CacheConstants.DATA_IMPORT_KEY + req.getImportKey());
|
||||
batchImportRowReqs = JSONUtil.toList(data, BatchImportRowReq.class);
|
||||
CheckUtils.throwIf(CollUtil.isEmpty(batchImportRowReqs), "导入已过期,请重新上传");
|
||||
} catch (Exception e) {
|
||||
log.error("导入异常:", e);
|
||||
throw new BusinessException("导入已过期,请重新上传");
|
||||
}
|
||||
|
||||
// 转换为MaterialInfoDO列表
|
||||
List<MaterialInfoDO> materialInfoDOS = batchImportRowReqs.stream()
|
||||
.map(row -> {
|
||||
MaterialInfoDO materialInfoDO = new MaterialInfoDO();
|
||||
materialInfoDO.setEncoding(row.getEncoding());
|
||||
materialInfoDO.setBatch(row.getBatch());
|
||||
materialInfoDO.setUpdateUser(UserContextHolder.getUserId());
|
||||
return materialInfoDO;
|
||||
})
|
||||
.toList();
|
||||
|
||||
// 批量操作数据库集合
|
||||
try {
|
||||
InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().blockAttack(true).build());
|
||||
baseMapper.updateBatchNull();
|
||||
} finally {
|
||||
InterceptorIgnoreHelper.clearIgnoreStrategy();
|
||||
}
|
||||
int totalUpdateCount = baseMapper.updateBatchByCode(materialInfoDOS);
|
||||
RedisUtils.delete(CacheConstants.DATA_IMPORT_KEY + req.getImportKey());
|
||||
return new MaterialInfoImportResp(materialInfoDOS.size(), 0, totalUpdateCount);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package top.wms.admin.materialType.model.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import top.wms.admin.system.enums.ImportPolicyEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Schema(description = "物料品类导入参数")
|
||||
public class MaterialTypeImportReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 导入会话KEY
|
||||
*/
|
||||
@Schema(description = "导入会话KEY", example = "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed")
|
||||
@NotBlank(message = "导入已过期,请重新上传")
|
||||
private String importKey;
|
||||
|
||||
/**
|
||||
* 品类名称重复策略
|
||||
*/
|
||||
@Schema(description = "品类名称重复策略", example = "1")
|
||||
@NotNull(message = "品类名称重复策略不能为空")
|
||||
private ImportPolicyEnum duplicateTypeName;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package top.wms.admin.materialType.model.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@Schema(description = "物料品类导入行数据")
|
||||
public class MaterialTypeImportRowReq implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 品类名称
|
||||
*/
|
||||
@Schema(description = "品类名称")
|
||||
@NotBlank(message = "品类名称不能为空")
|
||||
@Length(max = 255, message = "品类名称长度不能超过 {max} 个字符")
|
||||
private String typeName;
|
||||
|
||||
/**
|
||||
* 品类下行浮动范围(%)
|
||||
*/
|
||||
@Schema(description = "品类下行浮动范围(%)")
|
||||
@NotNull(message = "品类下行浮动范围不能为空")
|
||||
private BigDecimal downFloatRatio;
|
||||
|
||||
/**
|
||||
* 品类上行浮动范围(%)
|
||||
*/
|
||||
@Schema(description = "品类上行浮动范围(%)")
|
||||
@NotNull(message = "品类上行浮动范围不能为空")
|
||||
private BigDecimal upFloatRatio;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package top.wms.admin.materialType.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 MaterialTypeImportParseResp 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;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package top.wms.admin.materialType.model.resp;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Schema(description = "物料品类导入结果")
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class MaterialTypeImportResp implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 总计行数
|
||||
*/
|
||||
@Schema(description = "总计行数", example = "100")
|
||||
private Integer totalRows;
|
||||
|
||||
/**
|
||||
* 新增行数
|
||||
*/
|
||||
@Schema(description = "新增行数", example = "100")
|
||||
private Integer insertRows;
|
||||
|
||||
/**
|
||||
* 修改行数
|
||||
*/
|
||||
@Schema(description = "修改行数", example = "100")
|
||||
private Integer updateRows;
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
package top.wms.admin.materialType.service;
|
||||
|
||||
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.materialType.model.query.MaterialTypeQuery;
|
||||
import top.wms.admin.materialType.model.req.MaterialTypeImportReq;
|
||||
import top.wms.admin.materialType.model.req.MaterialTypeReq;
|
||||
import top.wms.admin.materialType.model.resp.MaterialTypeImportParseResp;
|
||||
import top.wms.admin.materialType.model.resp.MaterialTypeImportResp;
|
||||
import top.wms.admin.materialType.model.resp.MaterialTypeResp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -17,4 +23,10 @@ import java.util.List;
|
||||
public interface MaterialTypeService extends BaseService<MaterialTypeResp, MaterialTypeResp, MaterialTypeQuery, MaterialTypeReq> {
|
||||
|
||||
List<LabelValueResp> getSelectList();
|
||||
|
||||
void downloadImportTemplate(HttpServletResponse response) throws IOException;
|
||||
|
||||
MaterialTypeImportParseResp parseImport(MultipartFile file);
|
||||
|
||||
MaterialTypeImportResp importMaterial(MaterialTypeImportReq req);
|
||||
}
|
||||
@@ -1,21 +1,49 @@
|
||||
package top.wms.admin.materialType.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.extra.validation.ValidationUtil;
|
||||
import cn.hutool.http.ContentType;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.resp.LabelValueResp;
|
||||
import top.continew.starter.extension.crud.service.BaseServiceImpl;
|
||||
import top.continew.starter.web.util.FileUploadUtils;
|
||||
import top.wms.admin.common.constant.CacheConstants;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
import top.wms.admin.materialType.mapper.MaterialTypeMapper;
|
||||
import top.wms.admin.materialType.mapstruct.MaterialTypeConvert;
|
||||
import top.wms.admin.materialType.model.entity.MaterialTypeDO;
|
||||
import top.wms.admin.materialType.model.query.MaterialTypeQuery;
|
||||
import top.wms.admin.materialType.model.req.MaterialTypeImportReq;
|
||||
import top.wms.admin.materialType.model.req.MaterialTypeImportRowReq;
|
||||
import top.wms.admin.materialType.model.req.MaterialTypeReq;
|
||||
import top.wms.admin.materialType.model.resp.MaterialTypeImportParseResp;
|
||||
import top.wms.admin.materialType.model.resp.MaterialTypeImportResp;
|
||||
import top.wms.admin.materialType.model.resp.MaterialTypeResp;
|
||||
import top.wms.admin.materialType.service.MaterialTypeService;
|
||||
|
||||
import java.util.List;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static top.wms.admin.system.enums.ImportPolicyEnum.*;
|
||||
|
||||
/**
|
||||
* 物料品类业务实现
|
||||
@@ -25,6 +53,7 @@ import java.util.List;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MaterialTypeServiceImpl extends BaseServiceImpl<MaterialTypeMapper, MaterialTypeDO, MaterialTypeResp, MaterialTypeResp, MaterialTypeQuery, MaterialTypeReq> implements MaterialTypeService {
|
||||
|
||||
private final MaterialTypeConvert materialTypeConvert;
|
||||
@@ -34,4 +63,150 @@ public class MaterialTypeServiceImpl extends BaseServiceImpl<MaterialTypeMapper,
|
||||
List<MaterialTypeDO> materialTypeDOS = baseMapper.selectList(new QueryWrapper<>());
|
||||
return materialTypeConvert.labelValueList(materialTypeDOS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
|
||||
try {
|
||||
FileUploadUtils.download(response, ResourceUtil
|
||||
.getStream("templates/import/materialType.xlsx"), "物料品类导入模板.xlsx");
|
||||
} catch (Exception e) {
|
||||
log.error("下载物料品类导入模板失败:", e);
|
||||
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
||||
response.setContentType(ContentType.JSON.toString());
|
||||
response.getWriter().write(JSONUtil.toJsonStr(R.fail("下载批次导入模板失败")));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialTypeImportParseResp parseImport(MultipartFile file) {
|
||||
MaterialTypeImportParseResp materialTypeImportResp = new MaterialTypeImportParseResp();
|
||||
List<MaterialTypeImportRowReq> importRowList;
|
||||
try {
|
||||
importRowList = EasyExcel.read(file.getInputStream())
|
||||
.head(MaterialTypeImportRowReq.class)
|
||||
.sheet()
|
||||
.headRowNumber(1)
|
||||
.doReadSync();
|
||||
} catch (Exception e) {
|
||||
log.error("物料品类导入数据文件解析异常:", e);
|
||||
throw new BusinessException("数据文件解析异常");
|
||||
}
|
||||
materialTypeImportResp.setTotalRows(importRowList.size());
|
||||
CheckUtils.throwIfEmpty(importRowList, "数据文件格式错误");
|
||||
List<MaterialTypeImportRowReq> validRowList = this.filterImportData(importRowList);
|
||||
materialTypeImportResp.setValidRows(validRowList.size());
|
||||
CheckUtils.throwIfEmpty(validRowList, "数据文件格式错误");
|
||||
|
||||
Set<String> seenTypeName = new HashSet<>();
|
||||
boolean hasDuplicateTypeName = validRowList.stream()
|
||||
.map(MaterialTypeImportRowReq::getTypeName)
|
||||
.anyMatch(typeName -> typeName != null && !seenTypeName.add(typeName));
|
||||
CheckUtils.throwIf(hasDuplicateTypeName, "存在重复品类名称,请检测数据");
|
||||
|
||||
materialTypeImportResp.setDuplicateNameRows(countExistByField(validRowList, MaterialTypeImportRowReq::getTypeName, MaterialTypeDO::getTypeName, false));
|
||||
|
||||
String importKey = UUID.fastUUID().toString(true);
|
||||
RedisUtils.set(CacheConstants.DATA_IMPORT_KEY + importKey, JSONUtil.toJsonStr(validRowList), Duration
|
||||
.ofMinutes(10));
|
||||
materialTypeImportResp.setImportKey(importKey);
|
||||
return materialTypeImportResp;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public MaterialTypeImportResp importMaterial(MaterialTypeImportReq req) {
|
||||
List<MaterialTypeImportRowReq> importMaterialTypeList;
|
||||
try {
|
||||
String data = RedisUtils.get(CacheConstants.DATA_IMPORT_KEY + req.getImportKey());
|
||||
importMaterialTypeList = JSONUtil.toList(data, MaterialTypeImportRowReq.class);
|
||||
CheckUtils.throwIf(CollUtil.isEmpty(importMaterialTypeList), "导入已过期,请重新上传");
|
||||
} catch (Exception e) {
|
||||
log.error("导入异常:", e);
|
||||
throw new BusinessException("导入已过期,请重新上传");
|
||||
}
|
||||
|
||||
List<String> existTypeName = listExistByField(importMaterialTypeList, MaterialTypeImportRowReq::getTypeName, MaterialTypeDO::getTypeName);
|
||||
CheckUtils.throwIf(isExitImportMaterialType(req, importMaterialTypeList, existTypeName), "数据不符合导入策略,已退出导入");
|
||||
|
||||
List<MaterialTypeDO> insertList = new ArrayList<>();
|
||||
List<MaterialTypeDO> updateList = new ArrayList<>();
|
||||
|
||||
for (MaterialTypeImportRowReq row : importMaterialTypeList) {
|
||||
if (isSkipImportMaterialType(req, row, existTypeName)) {
|
||||
continue;
|
||||
}
|
||||
MaterialTypeDO materialTypeDO = BeanUtil.toBeanIgnoreError(row, MaterialTypeDO.class);
|
||||
|
||||
if (UPDATE.validate(req.getDuplicateTypeName(), row.getTypeName(), existTypeName)) {
|
||||
materialTypeDO.setTypeName(row.getTypeName());
|
||||
materialTypeDO.setUpdateUser(UserContextHolder.getUserId());
|
||||
updateList.add(materialTypeDO);
|
||||
} else {
|
||||
insertList.add(materialTypeDO);
|
||||
}
|
||||
}
|
||||
|
||||
doImportMaterialType(insertList, updateList);
|
||||
RedisUtils.delete(CacheConstants.DATA_IMPORT_KEY + req.getImportKey());
|
||||
|
||||
int insertCount = insertList.size();
|
||||
int updateCount = updateList.size();
|
||||
int totalHandleCount = insertCount + updateCount;
|
||||
return new MaterialTypeImportResp(totalHandleCount, insertCount, updateCount);
|
||||
}
|
||||
|
||||
private int countExistByField(List<MaterialTypeImportRowReq> materialTypeRowList,
|
||||
Function<MaterialTypeImportRowReq, String> rowField,
|
||||
com.baomidou.mybatisplus.core.toolkit.support.SFunction<MaterialTypeDO, ?> dbField,
|
||||
boolean fieldEncrypt) {
|
||||
List<String> fieldValues = materialTypeRowList.stream().map(rowField).filter(Objects::nonNull).toList();
|
||||
if (fieldValues.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return (int)this.count(Wrappers.<MaterialTypeDO>lambdaQuery()
|
||||
.in(dbField, fieldValues));
|
||||
}
|
||||
|
||||
private List<MaterialTypeImportRowReq> filterImportData(List<MaterialTypeImportRowReq> importRowList) {
|
||||
return importRowList.stream().filter(row -> ValidationUtil.validate(row).isEmpty()).toList();
|
||||
}
|
||||
|
||||
private List<String> listExistByField(List<MaterialTypeImportRowReq> materialTypeRowList,
|
||||
Function<MaterialTypeImportRowReq, String> rowField,
|
||||
com.baomidou.mybatisplus.core.toolkit.support.SFunction<MaterialTypeDO, String> dbField) {
|
||||
List<String> fieldValues = materialTypeRowList.stream().map(rowField).filter(Objects::nonNull).toList();
|
||||
if (fieldValues.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<MaterialTypeDO> materialTypeDOList = baseMapper.selectList(Wrappers.<MaterialTypeDO>lambdaQuery()
|
||||
.in(dbField, fieldValues)
|
||||
.select(dbField));
|
||||
return materialTypeDOList.stream().map(dbField).filter(Objects::nonNull).toList();
|
||||
}
|
||||
|
||||
private boolean isExitImportMaterialType(MaterialTypeImportReq req,
|
||||
List<MaterialTypeImportRowReq> list,
|
||||
List<String> existTypeName) {
|
||||
return list.stream()
|
||||
.anyMatch(row -> EXIT.validate(req.getDuplicateTypeName(), row.getTypeName(), existTypeName));
|
||||
}
|
||||
|
||||
private boolean isSkipImportMaterialType(MaterialTypeImportReq req,
|
||||
MaterialTypeImportRowReq row,
|
||||
List<String> existTypeName) {
|
||||
return SKIP.validate(req.getDuplicateTypeName(), row.getTypeName(), existTypeName);
|
||||
}
|
||||
|
||||
private void doImportMaterialType(List<MaterialTypeDO> insertList,
|
||||
List<MaterialTypeDO> updateList) {
|
||||
if (CollUtil.isNotEmpty(insertList)) {
|
||||
baseMapper.insertBatch(insertList);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(updateList)) {
|
||||
for (MaterialTypeDO materialTypeDO : updateList) {
|
||||
baseMapper.update(materialTypeDO, Wrappers.<MaterialTypeDO>lambdaUpdate()
|
||||
.eq(MaterialTypeDO::getTypeName, materialTypeDO.getTypeName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,4 +102,10 @@ public class WorkOrderResp extends BaseDetailResp {
|
||||
@Schema(description = "任务工单详情信息列表")
|
||||
private List<WorkOrderInfoResp> workOrderInfos;
|
||||
|
||||
/**
|
||||
* 批次
|
||||
*/
|
||||
@Schema(description = "批次")
|
||||
private String batch;
|
||||
|
||||
}
|
||||
@@ -78,6 +78,7 @@ public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkO
|
||||
MaterialInfoDO materialInfoDO = materialInfoMapper.selectById(workOrderDO.getMaterialId());
|
||||
workOrderResp.setMaterialName(materialInfoDO.getMaterialName());
|
||||
workOrderResp.setEncoding(materialInfoDO.getEncoding());
|
||||
workOrderResp.setBatch(materialInfoDO.getBatch());
|
||||
}
|
||||
|
||||
return workOrderResp;
|
||||
|
||||
@@ -77,6 +77,39 @@
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<update id="updateBatchNull">
|
||||
UPDATE sys_material_info SET batch = null
|
||||
</update>
|
||||
|
||||
<update id="updateBatchByCode">
|
||||
UPDATE sys_material_info
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="list != null and list.size() > 0">
|
||||
batch = CASE
|
||||
<foreach collection="list" item="item" separator="">
|
||||
<if test="item.batch != null and item.batch != ''">
|
||||
WHEN encoding = #{item.encoding} THEN #{item.batch}
|
||||
</if>
|
||||
</foreach>
|
||||
ELSE batch
|
||||
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()
|
||||
</if>
|
||||
</trim>
|
||||
WHERE encoding IN
|
||||
<foreach collection="list" item="item" open="(" close=")" separator=",">
|
||||
#{item.encoding}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<select id="selectMaterialInfoPage" resultType="top.wms.admin.material.model.resp.MaterialInfoResp">
|
||||
SELECT
|
||||
mi.*,
|
||||
|
||||
Reference in New Issue
Block a user