优化用户重置密码加密+物料照片批量导入
This commit is contained in:
@@ -19,4 +19,4 @@
|
|||||||
<artifactId>wms-common</artifactId>
|
<artifactId>wms-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -15,5 +15,6 @@ import java.util.List;
|
|||||||
@Repository
|
@Repository
|
||||||
public interface MaterialInfoMapper extends BaseMapper<MaterialInfoDO> {
|
public interface MaterialInfoMapper extends BaseMapper<MaterialInfoDO> {
|
||||||
public int updateByName(List<MaterialInfoDO> list);
|
public int updateByName(List<MaterialInfoDO> list);
|
||||||
|
|
||||||
public int updateByCode(List<MaterialInfoDO> list);
|
public int updateByCode(List<MaterialInfoDO> list);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package top.wms.admin.material.model.resp;
|
package top.wms.admin.material.model.resp;
|
||||||
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|||||||
@@ -10,9 +10,6 @@ import top.wms.admin.material.model.req.MaterialInfoReq;
|
|||||||
import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
||||||
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
||||||
import top.wms.admin.material.model.resp.MaterialInfoResp;
|
import top.wms.admin.material.model.resp.MaterialInfoResp;
|
||||||
import top.wms.admin.system.model.req.user.UserImportReq;
|
|
||||||
import top.wms.admin.system.model.resp.user.UserImportParseResp;
|
|
||||||
import top.wms.admin.system.model.resp.user.UserImportResp;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -24,33 +21,38 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
public interface MaterialInfoService extends BaseService<MaterialInfoResp, MaterialInfoResp, MaterialInfoQuery, MaterialInfoReq> {
|
public interface MaterialInfoService extends BaseService<MaterialInfoResp, MaterialInfoResp, MaterialInfoQuery, MaterialInfoReq> {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* 根据编码查询物料信息
|
* 根据编码查询物料信息
|
||||||
* */
|
* */
|
||||||
public MaterialInfoDO getMaterialInfoByCode(String code);
|
public MaterialInfoDO getMaterialInfoByCode(String code);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载导入模板
|
* 下载导入模板
|
||||||
*
|
*
|
||||||
* @param response 响应对象
|
* @param response 响应对象
|
||||||
* @throws IOException /
|
* @throws IOException /
|
||||||
*/
|
*/
|
||||||
void downloadImportTemplate(HttpServletResponse response) throws IOException;
|
void downloadImportTemplate(HttpServletResponse response) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析导入数据
|
* 解析导入数据
|
||||||
*
|
*
|
||||||
* @param file 导入文件
|
* @param file 导入文件
|
||||||
* @return 解析结果
|
* @return 解析结果
|
||||||
*/
|
*/
|
||||||
MaterialImportParseResp parseImport(MultipartFile file);
|
MaterialImportParseResp parseImport(MultipartFile file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入数据
|
* 导入数据
|
||||||
*
|
*
|
||||||
* @param req 导入信息
|
* @param req 导入信息
|
||||||
* @return 导入结果
|
* @return 导入结果
|
||||||
*/
|
*/
|
||||||
MaterialInfoImportResp importMaterial(MaterialInfoImportReq req);
|
MaterialInfoImportResp importMaterial(MaterialInfoImportReq req);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 照片批量上传处理
|
||||||
|
* */
|
||||||
|
void uploadMaterialPhotos(MultipartFile file);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,40 +2,35 @@ package top.wms.admin.material.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.date.DateUnit;
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.io.resource.ResourceUtil;
|
import cn.hutool.core.io.resource.ResourceUtil;
|
||||||
import cn.hutool.core.lang.UUID;
|
import cn.hutool.core.lang.UUID;
|
||||||
import cn.hutool.core.math.MathUtil;
|
|
||||||
import cn.hutool.core.util.*;
|
import cn.hutool.core.util.*;
|
||||||
import cn.hutool.extra.validation.ValidationUtil;
|
import cn.hutool.extra.validation.ValidationUtil;
|
||||||
import cn.hutool.http.ContentType;
|
import cn.hutool.http.ContentType;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.alibaba.excel.EasyExcel;
|
import com.alibaba.excel.EasyExcel;
|
||||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import me.ahoo.cosid.IdGenerator;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.ahoo.cosid.provider.DefaultIdGeneratorProvider;
|
|
||||||
import net.dreamlu.mica.core.result.R;
|
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.stereotype.Service;
|
||||||
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||||
import top.continew.starter.core.exception.BusinessException;
|
import top.continew.starter.core.exception.BusinessException;
|
||||||
import top.continew.starter.core.util.SpringUtils;
|
|
||||||
import top.continew.starter.core.validation.CheckUtils;
|
import top.continew.starter.core.validation.CheckUtils;
|
||||||
import top.continew.starter.extension.crud.service.BaseServiceImpl;
|
import top.continew.starter.extension.crud.service.BaseServiceImpl;
|
||||||
import top.continew.starter.web.util.FileUploadUtils;
|
import top.continew.starter.web.util.FileUploadUtils;
|
||||||
import top.wms.admin.common.constant.CacheConstants;
|
import top.wms.admin.common.constant.CacheConstants;
|
||||||
import top.wms.admin.common.context.UserContextHolder;
|
import top.wms.admin.common.context.UserContextHolder;
|
||||||
import top.wms.admin.common.enums.GenderEnum;
|
|
||||||
import top.wms.admin.common.util.SecureUtils;
|
import top.wms.admin.common.util.SecureUtils;
|
||||||
import top.wms.admin.material.mapper.MaterialInfoMapper;
|
import top.wms.admin.material.mapper.MaterialInfoMapper;
|
||||||
import top.wms.admin.material.model.entity.MaterialInfoDO;
|
import top.wms.admin.material.model.entity.MaterialInfoDO;
|
||||||
@@ -47,23 +42,19 @@ import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
|||||||
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
||||||
import top.wms.admin.material.model.resp.MaterialInfoResp;
|
import top.wms.admin.material.model.resp.MaterialInfoResp;
|
||||||
import top.wms.admin.material.service.MaterialInfoService;
|
import top.wms.admin.material.service.MaterialInfoService;
|
||||||
import top.wms.admin.system.model.entity.DeptDO;
|
import top.wms.admin.system.service.FileService;
|
||||||
import top.wms.admin.system.model.entity.RoleDO;
|
|
||||||
import top.wms.admin.system.model.entity.UserDO;
|
|
||||||
import top.wms.admin.system.model.entity.UserRoleDO;
|
|
||||||
import top.wms.admin.system.model.req.user.UserImportReq;
|
|
||||||
import top.wms.admin.system.model.req.user.UserImportRowReq;
|
|
||||||
import top.wms.admin.system.model.resp.user.UserImportParseResp;
|
|
||||||
import top.wms.admin.system.model.resp.user.UserImportResp;
|
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.sql.Time;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
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.*;
|
||||||
import static top.wms.admin.system.enums.ImportPolicyEnum.SKIP;
|
import static top.wms.admin.system.enums.ImportPolicyEnum.SKIP;
|
||||||
@@ -76,13 +67,18 @@ import static top.wms.admin.system.enums.ImportPolicyEnum.SKIP;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper, MaterialInfoDO, MaterialInfoResp, MaterialInfoResp, MaterialInfoQuery, MaterialInfoReq> implements MaterialInfoService {
|
public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper, MaterialInfoDO, MaterialInfoResp, MaterialInfoResp, MaterialInfoQuery, MaterialInfoReq> implements MaterialInfoService {
|
||||||
|
|
||||||
|
private static final Set<String> IMAGE_EXTENSIONS = Set.of("jpg", "jpeg", "png", "gif", "bmp");
|
||||||
|
|
||||||
|
private final FileService fileService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MaterialInfoDO getMaterialInfoByCode(String code) {
|
public MaterialInfoDO getMaterialInfoByCode(String code) {
|
||||||
if(StrUtil.isNotBlank(code)){
|
if (StrUtil.isNotBlank(code)) {
|
||||||
return baseMapper.lambdaQuery().eq(MaterialInfoDO::getEncoding, code).one();
|
return baseMapper.lambdaQuery().eq(MaterialInfoDO::getEncoding, code).one();
|
||||||
}else{
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,7 +86,8 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
|||||||
@Override
|
@Override
|
||||||
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
|
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
|
||||||
try {
|
try {
|
||||||
FileUploadUtils.download(response, ResourceUtil.getStream("templates/import/materialInfo.xlsx"), "物料信息导入模板.xlsx");
|
FileUploadUtils.download(response, ResourceUtil
|
||||||
|
.getStream("templates/import/materialInfo.xlsx"), "物料信息导入模板.xlsx");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("下载用户导入模板失败:{}", e);
|
log.error("下载用户导入模板失败:{}", e);
|
||||||
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
||||||
@@ -106,10 +103,10 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
|||||||
// 读取表格数据
|
// 读取表格数据
|
||||||
try {
|
try {
|
||||||
importRowList = EasyExcel.read(file.getInputStream())
|
importRowList = EasyExcel.read(file.getInputStream())
|
||||||
.head(MaterialImportRowReq.class)
|
.head(MaterialImportRowReq.class)
|
||||||
.sheet()
|
.sheet()
|
||||||
.headRowNumber(1)
|
.headRowNumber(1)
|
||||||
.doReadSync();
|
.doReadSync();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("物料信息导入数据文件解析异常:{}", e);
|
log.error("物料信息导入数据文件解析异常:{}", e);
|
||||||
throw new BusinessException("数据文件解析异常");
|
throw new BusinessException("数据文件解析异常");
|
||||||
@@ -125,25 +122,24 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
|||||||
// 检测表格内数据是否合法
|
// 检测表格内数据是否合法
|
||||||
Set<String> seenCode = new HashSet<>();
|
Set<String> seenCode = new HashSet<>();
|
||||||
boolean hasDuplicateEncoding = validRowList.stream()
|
boolean hasDuplicateEncoding = validRowList.stream()
|
||||||
.map(MaterialImportRowReq::getEncoding)
|
.map(MaterialImportRowReq::getEncoding)
|
||||||
.anyMatch(encoding -> encoding != null && !seenCode.add(encoding));
|
.anyMatch(encoding -> encoding != null && !seenCode.add(encoding));
|
||||||
CheckUtils.throwIf(hasDuplicateEncoding, "存在重复物料编码,请检测数据");
|
CheckUtils.throwIf(hasDuplicateEncoding, "存在重复物料编码,请检测数据");
|
||||||
|
|
||||||
// 查询重复用户
|
// 查询重复用户
|
||||||
materialImportResp
|
materialImportResp
|
||||||
.setDuplicateNameRows(countExistByField(validRowList, MaterialImportRowReq::getMaterialName, MaterialInfoDO::getMaterialName, false));
|
.setDuplicateNameRows(countExistByField(validRowList, MaterialImportRowReq::getMaterialName, MaterialInfoDO::getMaterialName, false));
|
||||||
// 查询重复邮箱
|
// 查询重复邮箱
|
||||||
materialImportResp
|
materialImportResp
|
||||||
.setDuplicateCodeRows(countExistByField(validRowList, MaterialImportRowReq::getEncoding, MaterialInfoDO::getEncoding, false));
|
.setDuplicateCodeRows(countExistByField(validRowList, MaterialImportRowReq::getEncoding, MaterialInfoDO::getEncoding, false));
|
||||||
// 设置导入会话并缓存数据,有效期10分钟
|
// 设置导入会话并缓存数据,有效期10分钟
|
||||||
String importKey = UUID.fastUUID().toString(true);
|
String importKey = UUID.fastUUID().toString(true);
|
||||||
RedisUtils.set(CacheConstants.DATA_IMPORT_KEY + importKey, JSONUtil.toJsonStr(validRowList), Duration
|
RedisUtils.set(CacheConstants.DATA_IMPORT_KEY + importKey, JSONUtil.toJsonStr(validRowList), Duration
|
||||||
.ofMinutes(10));
|
.ofMinutes(10));
|
||||||
materialImportResp.setImportKey(importKey);
|
materialImportResp.setImportKey(importKey);
|
||||||
return materialImportResp;
|
return materialImportResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public MaterialInfoImportResp importMaterial(MaterialInfoImportReq req) {
|
public MaterialInfoImportResp importMaterial(MaterialInfoImportReq req) {
|
||||||
@@ -160,22 +156,21 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
|||||||
// 已存在数据查询
|
// 已存在数据查询
|
||||||
List<String> existName = listExistByField(importMaterialList, MaterialImportRowReq::getMaterialName, MaterialInfoDO::getMaterialName);
|
List<String> existName = listExistByField(importMaterialList, MaterialImportRowReq::getMaterialName, MaterialInfoDO::getMaterialName);
|
||||||
List<String> existCode = listExistByField(importMaterialList, MaterialImportRowReq::getEncoding, MaterialInfoDO::getEncoding);
|
List<String> existCode = listExistByField(importMaterialList, MaterialImportRowReq::getEncoding, MaterialInfoDO::getEncoding);
|
||||||
CheckUtils
|
CheckUtils.throwIf(isExitImportMaterial(req, importMaterialList, existName, existCode), "数据不符合导入策略,已退出导入");
|
||||||
.throwIf(isExitImportMaterial(req, importMaterialList, existName, existCode), "数据不符合导入策略,已退出导入");
|
|
||||||
// 批量操作数据库集合
|
// 批量操作数据库集合
|
||||||
List<MaterialInfoDO> insertList = new ArrayList<>();
|
List<MaterialInfoDO> insertList = new ArrayList<>();
|
||||||
List<MaterialInfoDO> updateByNameList = new ArrayList<>();
|
List<MaterialInfoDO> updateByNameList = new ArrayList<>();
|
||||||
List<MaterialInfoDO> updateByCodeList = new ArrayList<>();
|
List<MaterialInfoDO> updateByCodeList = new ArrayList<>();
|
||||||
// ID生成器
|
// ID生成器
|
||||||
// IdGenerator idGenerator = DefaultIdGeneratorProvider.INSTANCE.getShare();
|
// IdGenerator idGenerator = DefaultIdGeneratorProvider.INSTANCE.getShare();
|
||||||
for (MaterialImportRowReq row : importMaterialList) {
|
for (MaterialImportRowReq row : importMaterialList) {
|
||||||
if (isSkipMaterialImport(req, row, existName, existCode)) {
|
if (isSkipMaterialImport(req, row, existName, existCode)) {
|
||||||
// 按规则跳过该行
|
// 按规则跳过该行
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
MaterialInfoDO materialDO = BeanUtil.toBeanIgnoreError(row, MaterialInfoDO.class);
|
MaterialInfoDO materialDO = BeanUtil.toBeanIgnoreError(row, MaterialInfoDO.class);
|
||||||
materialDO.setUnitWeight(NumberUtil.isValidNumber(row.getUnitWeight())?row.getUnitWeight(): null);
|
materialDO.setUnitWeight(NumberUtil.isValidNumber(row.getUnitWeight()) ? row.getUnitWeight() : null);
|
||||||
materialDO.setMaterialSpec(StrUtil.isNotBlank(row.getMaterialSpec())?row.getMaterialSpec():null);
|
materialDO.setMaterialSpec(StrUtil.isNotBlank(row.getMaterialSpec()) ? row.getMaterialSpec() : null);
|
||||||
// 修改 or 新增
|
// 修改 or 新增
|
||||||
if (UPDATE.validate(req.getDuplicateName(), row.getMaterialName(), existName)) {
|
if (UPDATE.validate(req.getDuplicateName(), row.getMaterialName(), existName)) {
|
||||||
materialDO.setMaterialName(row.getMaterialName());
|
materialDO.setMaterialName(row.getMaterialName());
|
||||||
@@ -188,7 +183,7 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
|||||||
materialDO.setUpdateUser(UserContextHolder.getUserId());
|
materialDO.setUpdateUser(UserContextHolder.getUserId());
|
||||||
updateByCodeList.add(materialDO);
|
updateByCodeList.add(materialDO);
|
||||||
} else {
|
} else {
|
||||||
// materialDO.setId(idGenerator.generate());
|
// materialDO.setId(idGenerator.generate());
|
||||||
insertList.add(materialDO);
|
insertList.add(materialDO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,23 +194,18 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
|||||||
int updateByCodeCount = updateByCodeList.size();
|
int updateByCodeCount = updateByCodeList.size();
|
||||||
int totalUpdateCount = updateByNameCount + updateByCodeCount;
|
int totalUpdateCount = updateByNameCount + updateByCodeCount;
|
||||||
int totalHandleCount = insertCount + totalUpdateCount;
|
int totalHandleCount = insertCount + totalUpdateCount;
|
||||||
return new MaterialInfoImportResp(
|
return new MaterialInfoImportResp(totalHandleCount, // 总处理数
|
||||||
totalHandleCount, // 总处理数
|
insertCount, // 新增数
|
||||||
insertCount, // 新增数
|
totalUpdateCount // 更新总数
|
||||||
totalUpdateCount // 更新总数
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按指定数据集获取数据库已存在的数量
|
* 按指定数据集获取数据库已存在的数量
|
||||||
*
|
*
|
||||||
* @param materialRowList 导入的数据源
|
* @param materialRowList 导入的数据源
|
||||||
* @param rowField 导入数据的字段
|
* @param rowField 导入数据的字段
|
||||||
* @param dbField 对比数据库的字段
|
* @param dbField 对比数据库的字段
|
||||||
* @return 存在的数量
|
* @return 存在的数量
|
||||||
*/
|
*/
|
||||||
private int countExistByField(List<MaterialImportRowReq> materialRowList,
|
private int countExistByField(List<MaterialImportRowReq> materialRowList,
|
||||||
@@ -227,10 +217,9 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return (int)this.count(Wrappers.<MaterialInfoDO>lambdaQuery()
|
return (int)this.count(Wrappers.<MaterialInfoDO>lambdaQuery()
|
||||||
.in(dbField, fieldEncrypt ? SecureUtils.encryptFieldByAes(fieldValues) : fieldValues));
|
.in(dbField, fieldEncrypt ? SecureUtils.encryptFieldByAes(fieldValues) : fieldValues));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 过滤无效的导入用户数据(批量导入不严格校验数据)
|
* 过滤无效的导入用户数据(批量导入不严格校验数据)
|
||||||
*
|
*
|
||||||
@@ -239,22 +228,23 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
|||||||
private List<MaterialImportRowReq> filterImportData(List<MaterialImportRowReq> importRowList) {
|
private List<MaterialImportRowReq> filterImportData(List<MaterialImportRowReq> importRowList) {
|
||||||
// 校验过滤
|
// 校验过滤
|
||||||
List<MaterialImportRowReq> list = importRowList.stream()
|
List<MaterialImportRowReq> list = importRowList.stream()
|
||||||
.filter(row -> ValidationUtil.validate(row).isEmpty())
|
.filter(row -> ValidationUtil.validate(row).isEmpty())
|
||||||
.toList();
|
.toList();
|
||||||
// 物料名去重
|
// 物料名去重
|
||||||
return list.stream()
|
return list.stream()
|
||||||
.collect(Collectors.toMap(MaterialImportRowReq::getMaterialName, row -> row, (existing, replacement) -> existing))
|
.collect(Collectors.toMap(MaterialImportRowReq::getMaterialName, row -> row, (existing,
|
||||||
.values()
|
replacement) -> existing))
|
||||||
.stream()
|
.values()
|
||||||
.toList();
|
.stream()
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按指定数据集获取数据库已存在内容
|
* 按指定数据集获取数据库已存在内容
|
||||||
*
|
*
|
||||||
* @param materialRowList 导入的数据源
|
* @param materialRowList 导入的数据源
|
||||||
* @param rowField 导入数据的字段
|
* @param rowField 导入数据的字段
|
||||||
* @param dbField 对比数据库的字段
|
* @param dbField 对比数据库的字段
|
||||||
* @return 存在的内容
|
* @return 存在的内容
|
||||||
*/
|
*/
|
||||||
private List<String> listExistByField(List<MaterialImportRowReq> materialRowList,
|
private List<String> listExistByField(List<MaterialImportRowReq> materialRowList,
|
||||||
@@ -265,54 +255,56 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
List<MaterialInfoDO> materialDOList = baseMapper.selectList(Wrappers.<MaterialInfoDO>lambdaQuery()
|
List<MaterialInfoDO> materialDOList = baseMapper.selectList(Wrappers.<MaterialInfoDO>lambdaQuery()
|
||||||
.in(dbField, fieldValues)
|
.in(dbField, fieldValues)
|
||||||
.select(dbField));
|
.select(dbField));
|
||||||
return materialDOList.stream().map(dbField).filter(Objects::nonNull).toList();
|
return materialDOList.stream().map(dbField).filter(Objects::nonNull).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断是否退出导入
|
* 判断是否退出导入
|
||||||
*
|
*
|
||||||
* @param req 导入参数
|
* @param req 导入参数
|
||||||
* @param list 导入数据
|
* @param list 导入数据
|
||||||
* @param existName 导入数据中已存在的物料名
|
* @param existName 导入数据中已存在的物料名
|
||||||
* @param existCode 导入数据中已存在的物料编号
|
* @param existCode 导入数据中已存在的物料编号
|
||||||
* @return 是否退出
|
* @return 是否退出
|
||||||
*/
|
*/
|
||||||
private boolean isExitImportMaterial(MaterialInfoImportReq req,
|
private boolean isExitImportMaterial(MaterialInfoImportReq req,
|
||||||
List<MaterialImportRowReq> list,
|
List<MaterialImportRowReq> list,
|
||||||
List<String> existName,
|
List<String> existName,
|
||||||
List<String> existCode) {
|
List<String> existCode) {
|
||||||
return list.stream()
|
return list.stream()
|
||||||
.anyMatch(row -> EXIT.validate(req.getDuplicateName(), row.getMaterialName(), existName) || EXIT.validate(req
|
.anyMatch(row -> EXIT.validate(req.getDuplicateName(), row.getMaterialName(), existName) || EXIT
|
||||||
.getDuplicateCode(), row.getEncoding(), existCode));
|
.validate(req.getDuplicateCode(), row.getEncoding(), existCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断是否跳过导入
|
* 判断是否跳过导入
|
||||||
*
|
*
|
||||||
* @param req 导入参数
|
* @param req 导入参数
|
||||||
* @param row 导入数据
|
* @param row 导入数据
|
||||||
* @param existName 导入数据中已存在的物料名称
|
* @param existName 导入数据中已存在的物料名称
|
||||||
* @param existCode 导入数据中已存在的物料编号
|
* @param existCode 导入数据中已存在的物料编号
|
||||||
* @return 是否跳过
|
* @return 是否跳过
|
||||||
*/
|
*/
|
||||||
private boolean isSkipMaterialImport(MaterialInfoImportReq req,
|
private boolean isSkipMaterialImport(MaterialInfoImportReq req,
|
||||||
MaterialImportRowReq row,
|
MaterialImportRowReq row,
|
||||||
List<String> existName,
|
List<String> existName,
|
||||||
List<String> existCode) {
|
List<String> existCode) {
|
||||||
return SKIP.validate(req.getDuplicateName(), row.getMaterialName(), existName) || SKIP.validate(req
|
return SKIP.validate(req.getDuplicateName(), row.getMaterialName(), existName) || SKIP.validate(req
|
||||||
.getDuplicateCode(), row.getEncoding(), existCode);
|
.getDuplicateCode(), row.getEncoding(), existCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入用户
|
* 导入用户
|
||||||
*
|
*
|
||||||
* @param insertList 新增用户
|
* @param insertList 新增用户
|
||||||
* @param updateByNameList 修改用户
|
* @param updateByNameList 修改用户
|
||||||
* @param updateByCodeList 用户角色关联
|
* @param updateByCodeList 用户角色关联
|
||||||
*/
|
*/
|
||||||
private void doImportMaterial(List<MaterialInfoDO> insertList, List<MaterialInfoDO> updateByNameList, List<MaterialInfoDO> updateByCodeList) {
|
private void doImportMaterial(List<MaterialInfoDO> insertList,
|
||||||
|
List<MaterialInfoDO> updateByNameList,
|
||||||
|
List<MaterialInfoDO> updateByCodeList) {
|
||||||
if (CollUtil.isNotEmpty(insertList)) {
|
if (CollUtil.isNotEmpty(insertList)) {
|
||||||
baseMapper.insertBatch(insertList);
|
baseMapper.insertBatch(insertList);
|
||||||
}
|
}
|
||||||
@@ -323,4 +315,102 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper,
|
|||||||
baseMapper.updateByCode(updateByCodeList);
|
baseMapper.updateByCode(updateByCodeList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uploadMaterialPhotos(MultipartFile zipFile) {
|
||||||
|
// 1. 初始化物料编码-照片地址Map
|
||||||
|
Map<String, String> codeUrlMap = new HashMap<>();
|
||||||
|
// 物料照片存储路径(自定义,比如按日期分目录)
|
||||||
|
String photoStoragePath = "/" + DateUtil.today() + "/";
|
||||||
|
|
||||||
|
try (ZipInputStream zipInputStream = new ZipInputStream(zipFile.getInputStream())) {
|
||||||
|
ZipEntry zipEntry;
|
||||||
|
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
||||||
|
// 跳过目录、非图片文件
|
||||||
|
if (zipEntry.isDirectory() || !isImageFile(zipEntry.getName())) {
|
||||||
|
zipInputStream.closeEntry();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 2. 提取物料编码(照片名 = 物料编码,去掉后缀)
|
||||||
|
String fileName = zipEntry.getName();
|
||||||
|
log.info("正在处理的照片:" + fileName);
|
||||||
|
//去除windows或linux环境下 可能存在的多层级目录
|
||||||
|
if (fileName.contains("/")) {
|
||||||
|
fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
|
||||||
|
}
|
||||||
|
if (fileName.contains("\\")) {
|
||||||
|
fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
|
||||||
|
}
|
||||||
|
String materialCode = fileName.substring(0, fileName.lastIndexOf("."));
|
||||||
|
// 3. 读取ZIP中的图片为BufferedImage
|
||||||
|
BufferedImage image = ImageIO.read(zipInputStream);
|
||||||
|
if (ObjectUtil.isEmpty(image)) {
|
||||||
|
log.warn("无法读取图片: {}", fileName);
|
||||||
|
zipInputStream.closeEntry();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 4. 将BufferedImage转为字节流
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
String imageExt = getImageExtension(fileName);
|
||||||
|
ImageIO.write(image, imageExt, baos);
|
||||||
|
byte[] imageBytes = baos.toByteArray();
|
||||||
|
|
||||||
|
// 5. 转换为MultipartFile(使用MockMultipartFile)
|
||||||
|
MultipartFile singleImageFile = new MockMultipartFile("file", fileName, "image/" + (imageExt
|
||||||
|
.equals("jpg") ? "jpeg" : imageExt), imageBytes);
|
||||||
|
|
||||||
|
// 6. 调用upload方法上传图片
|
||||||
|
FileInfo fileInfo = fileService.upload(singleImageFile, photoStoragePath, null, true, true);
|
||||||
|
|
||||||
|
// 7. 将物料编码和图片URL存入Map
|
||||||
|
codeUrlMap.put(materialCode, fileInfo.getUrl());
|
||||||
|
|
||||||
|
zipInputStream.closeEntry();
|
||||||
|
}
|
||||||
|
setPhotosByCode(codeUrlMap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new BusinessException("照片批量导入失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isImageFile(String fileName) {
|
||||||
|
if (fileName == null || !fileName.contains("."))
|
||||||
|
return false;
|
||||||
|
String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
|
||||||
|
return IMAGE_EXTENSIONS.contains(ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getImageExtension(String fileName) {
|
||||||
|
String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
|
||||||
|
return "jpeg".equals(ext) ? "jpg" : ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPhotosByCode(Map<String, String> codeUrlMap) {
|
||||||
|
CheckUtils.throwIfEmpty(codeUrlMap, "照片为空,请重新上传");
|
||||||
|
List<MaterialInfoDO> existList = baseMapper.selectList(Wrappers.<MaterialInfoDO>lambdaQuery()
|
||||||
|
.in(MaterialInfoDO::getEncoding, codeUrlMap.keySet()));
|
||||||
|
if (existList.isEmpty()) {
|
||||||
|
log.warn("未找到任何匹配的物料编码");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<MaterialInfoDO> updateList = existList.stream().map(exist -> {
|
||||||
|
MaterialInfoDO updateDO = new MaterialInfoDO();
|
||||||
|
updateDO.setId(exist.getId());
|
||||||
|
updateDO.setPhotoUrl(codeUrlMap.get(exist.getEncoding()));
|
||||||
|
return updateDO;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
if (!updateList.isEmpty()) {
|
||||||
|
baseMapper.updateBatchById(updateList);
|
||||||
|
log.info("成功更新 {} 个物料的照片", updateList.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
//记录未找到的物料编码(可选,方便排查问题)
|
||||||
|
Set<String> existCodes = existList.stream().map(MaterialInfoDO::getEncoding).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
codeUrlMap.keySet()
|
||||||
|
.stream()
|
||||||
|
.filter(code -> !existCodes.contains(code))
|
||||||
|
.forEach(code -> log.warn("物料编码 [{}] 不存在,照片更新失败", code));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
|||||||
String phone = req.getPhone();
|
String phone = req.getPhone();
|
||||||
CheckUtils.throwIf(StrUtil.isNotBlank(phone) && this.isPhoneExists(phone, null), errorMsgTemplate, phone);
|
CheckUtils.throwIf(StrUtil.isNotBlank(phone) && this.isPhoneExists(phone, null), errorMsgTemplate, phone);
|
||||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
||||||
req.setPassword("{bcrypt}"+encoder.encode(req.getPassword()));
|
req.setPassword("{bcrypt}" + encoder.encode(req.getPassword()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||||
|
import top.continew.starter.web.model.R;
|
||||||
import top.wms.admin.common.controller.BaseController;
|
import top.wms.admin.common.controller.BaseController;
|
||||||
import top.wms.admin.material.model.entity.MaterialInfoDO;
|
import top.wms.admin.material.model.entity.MaterialInfoDO;
|
||||||
import top.wms.admin.material.model.query.MaterialInfoQuery;
|
import top.wms.admin.material.model.query.MaterialInfoQuery;
|
||||||
@@ -25,9 +26,6 @@ import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
|||||||
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
||||||
import top.wms.admin.material.model.resp.MaterialInfoResp;
|
import top.wms.admin.material.model.resp.MaterialInfoResp;
|
||||||
import top.wms.admin.material.service.MaterialInfoService;
|
import top.wms.admin.material.service.MaterialInfoService;
|
||||||
import top.wms.admin.system.model.req.user.UserImportReq;
|
|
||||||
import top.wms.admin.system.model.resp.user.UserImportParseResp;
|
|
||||||
import top.wms.admin.system.model.resp.user.UserImportResp;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -45,8 +43,8 @@ import java.io.IOException;
|
|||||||
public class MaterialInfoController extends BaseController<MaterialInfoService, MaterialInfoResp, MaterialInfoResp, MaterialInfoQuery, MaterialInfoReq> {
|
public class MaterialInfoController extends BaseController<MaterialInfoService, MaterialInfoResp, MaterialInfoResp, MaterialInfoQuery, MaterialInfoReq> {
|
||||||
|
|
||||||
@GetMapping("/code/{code}")
|
@GetMapping("/code/{code}")
|
||||||
public MaterialInfoDO getMaterialInfoByCode(@PathVariable String code) {
|
public MaterialInfoDO getMaterialInfoByCode(@PathVariable String code) {
|
||||||
return baseService.getMaterialInfoByCode(code);
|
return baseService.getMaterialInfoByCode(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "下载导入模板", description = "下载导入模板")
|
@Operation(summary = "下载导入模板", description = "下载导入模板")
|
||||||
@@ -70,4 +68,15 @@ public class MaterialInfoController extends BaseController<MaterialInfoService,
|
|||||||
public MaterialInfoImportResp importUser(@Validated @RequestBody MaterialInfoImportReq req) {
|
public MaterialInfoImportResp importUser(@Validated @RequestBody MaterialInfoImportReq req) {
|
||||||
return baseService.importMaterial(req);
|
return baseService.importMaterial(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "照片批量导入", description = "照片批量导入")
|
||||||
|
@SaCheckPermission("admin:materialInfo:import")
|
||||||
|
@PostMapping("/import/uploadMaterialPhotos")
|
||||||
|
public R uploadMaterialPhotos(@RequestParam("zipFile") @NotNull(message = "文件不能为空") MultipartFile zipFile) {
|
||||||
|
ValidationUtils.throwIf(zipFile::isEmpty, "文件不能为空");
|
||||||
|
String originalFilename = zipFile.getOriginalFilename();
|
||||||
|
ValidationUtils.throwIf(() -> originalFilename == null || !originalFilename.endsWith(".zip"), "仅支持上传ZIP格式文件");
|
||||||
|
baseService.uploadMaterialPhotos(zipFile);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public class UserController extends BaseController<UserService, UserResp, UserDe
|
|||||||
ValidationUtils.throwIf(!ReUtil
|
ValidationUtils.throwIf(!ReUtil
|
||||||
.isMatch(RegexConstants.PASSWORD, rawNewPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字");
|
.isMatch(RegexConstants.PASSWORD, rawNewPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字");
|
||||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
||||||
req.setNewPassword("{bcrypt}"+encoder.encode(rawNewPassword));
|
req.setNewPassword("{bcrypt}" + encoder.encode(rawNewPassword));
|
||||||
baseService.resetPassword(req, id);
|
baseService.resetPassword(req, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user