This commit is contained in:
zc
2026-04-12 18:28:02 +08:00
parent 371daf2eee
commit e6a12aaeb2
25 changed files with 661 additions and 29 deletions

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -52,9 +52,9 @@ public class MaterialImportRowReq implements Serializable {
private Double materialSpec;
/**
* 物料类名称
* 物料类名称
*/
@Schema(description = "物料类名称")
@Schema(description = "物料类名称")
private String typeName;
/**

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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()));
}
}
}
}

View File

@@ -102,4 +102,10 @@ public class WorkOrderResp extends BaseDetailResp {
@Schema(description = "任务工单详情信息列表")
private List<WorkOrderInfoResp> workOrderInfos;
/**
* 批次
*/
@Schema(description = "批次")
private String batch;
}

View File

@@ -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;

View File

@@ -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.*,

View File

@@ -1,5 +1,13 @@
package top.wms.admin.controller.materialType;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotNull;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
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;
@@ -12,10 +20,14 @@ 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.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 top.wms.admin.materialType.service.MaterialTypeService;
import java.io.IOException;
import java.util.List;
/**
@@ -35,4 +47,28 @@ public class MaterialTypeController extends BaseController<MaterialTypeService,
public List<LabelValueResp> getSelectList() {
return baseService.getSelectList();
}
@Log(ignore = true)
@Operation(summary = "下载导入模板", description = "下载导入模板")
@SaCheckPermission("admin:materialType:import")
@GetMapping(value = "/importTemplate", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
baseService.downloadImportTemplate(response);
}
@Log(ignore = true)
@Operation(summary = "解析导入数据", description = "解析导入数据")
@SaCheckPermission("admin:materialType:import")
@PostMapping("/parseImport")
public MaterialTypeImportParseResp parseImport(@NotNull(message = "文件不能为空") MultipartFile file) {
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
return baseService.parseImport(file);
}
@Operation(summary = "导入数据", description = "导入数据")
@SaCheckPermission("admin:materialType:import")
@PostMapping(value = "/import")
public MaterialTypeImportResp importMaterial(@Validated @RequestBody MaterialTypeImportReq req) {
return baseService.importMaterial(req);
}
}

View File

@@ -22,6 +22,7 @@ import top.continew.starter.log.annotation.Log;
import top.continew.starter.web.model.R;
import top.wms.admin.common.controller.BaseController;
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;
@@ -100,4 +101,28 @@ public class MaterialInfoController extends BaseController<MaterialInfoService,
CheckUtils.throwIfEmpty(file, "照片抓取失败,请重新抓取");
return baseService.catchPhoto(file);
}
@Log(ignore = true)
@Operation(summary = "批次下载导入模板", description = "批次下载导入模板")
@SaCheckPermission("admin:materialInfo:import")
@GetMapping(value = "/batch/import/template", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void downloadBatchImportTemplate(HttpServletResponse response) throws IOException {
baseService.downloadBatchImportTemplate(response);
}
@Log(ignore = true)
@Operation(summary = "批次解析导入数据", description = "批次解析导入数据")
@SaCheckPermission("admin:materialInfo:import")
@PostMapping("/batch/import/parse")
public MaterialImportParseResp parseBatchImport(@NotNull(message = "文件不能为空") MultipartFile file) {
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
return baseService.parseBatchImport(file);
}
@Operation(summary = "批次导入数据", description = "批次导入数据")
@SaCheckPermission("admin:materialInfo:import")
@PostMapping(value = "/batch/import")
public MaterialInfoImportResp importBatchUser(@Validated @RequestBody BatchImportReq req) {
return baseService.importBatchMaterial(req);
}
}

View File

@@ -215,13 +215,12 @@ public class AHDZCConnect {
// 解析数据,提取数字和重量单位
String weightStr = data.trim();
// 使用正则表达式提取数字(包括小数点)
Pattern pattern = java.util.regex.Pattern.compile("[-+]?\\d*\\.?\\d+");
Pattern pattern = Pattern.compile("[-+]?\\d*\\.?\\d+");
Matcher matcher = pattern.matcher(weightStr);
if (matcher.find()) {
try {
String weightWithUnit = matcher.group().trim();
log.info("[解析后] 重量: {}", weightWithUnit);
// 发送提取的数字和重量单位给前端
ScaleWebSocketHandler.sendMessage(weightWithUnit);
} catch (NumberFormatException e) {

View File

@@ -155,14 +155,14 @@ public class NetCommon {
// 设置通道为1
ChannelID = 1;
if (StrUtil.isBlank(strPicPath)) {
strPicPath = "D:\\test\\ys\\carousel";
strPicPath = "E:\\img\\ys\\carousel";
// 创建保存目录
File picDir = new File("D:\\test\\ys");
File picDir = new File("E:\\img\\ys");
if (!picDir.exists()) {
picDir.mkdir();
}
} else {
File picDir = new File("D:\\test\\ys\\workOrder");
File picDir = new File("E:\\img\\ys\\workOrder");
if (!picDir.exists()) {
picDir.mkdir();
}

View File

@@ -90,7 +90,7 @@ public class ysNetController {
// 执行抓图
long l = System.currentTimeMillis();
imgName = imgName + "_" + l;
boolean success = NetCommon.captureImage("D:\\test\\ys\\workOrder\\" + imgName);
boolean success = NetCommon.captureImage("E:\\img\\ys\\workOrder\\" + imgName);
if (success) {
return R.ok("http://localhost:6609/file/ys/workOrder/" + imgName + ".jpg");
} else {