From 97df87eb06b7902f9546e7560d3e6ee06f1db9f4 Mon Sep 17 00:00:00 2001 From: liuzhu Date: Wed, 4 Mar 2026 18:01:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../material/mapper/MaterialInfoMapper.java | 5 +- .../model/req/MaterialImportRowReq.java | 45 +++ .../model/req/MaterialInfoImportReq.java | 47 +++ .../model/resp/MaterialImportParseResp.java | 55 ++++ .../model/resp/MaterialInfoImportResp.java | 35 +++ .../material/model/resp/MaterialInfoResp.java | 2 +- .../material/service/MaterialInfoService.java | 39 +++ .../service/impl/MaterialInfoServiceImpl.java | 292 +++++++++++++++++- .../system/mapper/RuleRelationMapper.java | 18 -- .../system/model/entity/RuleRelationDO.java | 37 --- .../system/model/req/RuleRelationReq.java | 52 ---- .../impl/PeopleEquipmentServiceImpl.java | 23 -- .../system/service/impl/UserServiceImpl.java | 3 + .../resources/mapper/MeterialInfoMapper.xml | 48 +++ .../resources/mapper/RuleRelationMapper.xml | 21 -- .../meterial/MaterialInfoController.java | 38 +++ .../controller/system/UserController.java | 4 +- .../import/consumePeopleDeposit.xlsx | Bin 8912 -> 0 bytes .../templates/import/materialInfo.xlsx | Bin 0 -> 9819 bytes .../resources/templates/import/people.xlsx | Bin 9493 -> 0 bytes 20 files changed, 608 insertions(+), 156 deletions(-) create mode 100644 wms-module-system/src/main/java/top/wms/admin/material/model/req/MaterialImportRowReq.java create mode 100644 wms-module-system/src/main/java/top/wms/admin/material/model/req/MaterialInfoImportReq.java create mode 100644 wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialImportParseResp.java create mode 100644 wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialInfoImportResp.java delete mode 100644 wms-module-system/src/main/java/top/wms/admin/system/mapper/RuleRelationMapper.java delete mode 100644 wms-module-system/src/main/java/top/wms/admin/system/model/entity/RuleRelationDO.java delete mode 100644 wms-module-system/src/main/java/top/wms/admin/system/model/req/RuleRelationReq.java delete mode 100644 wms-module-system/src/main/java/top/wms/admin/system/service/impl/PeopleEquipmentServiceImpl.java delete mode 100644 wms-module-system/src/main/resources/mapper/RuleRelationMapper.xml delete mode 100644 wms-webapi/src/main/resources/templates/import/consumePeopleDeposit.xlsx create mode 100644 wms-webapi/src/main/resources/templates/import/materialInfo.xlsx delete mode 100644 wms-webapi/src/main/resources/templates/import/people.xlsx diff --git a/wms-module-system/src/main/java/top/wms/admin/material/mapper/MaterialInfoMapper.java b/wms-module-system/src/main/java/top/wms/admin/material/mapper/MaterialInfoMapper.java index 1d1b791..dd54d25 100644 --- a/wms-module-system/src/main/java/top/wms/admin/material/mapper/MaterialInfoMapper.java +++ b/wms-module-system/src/main/java/top/wms/admin/material/mapper/MaterialInfoMapper.java @@ -4,6 +4,8 @@ import top.continew.starter.data.mp.base.BaseMapper; import top.wms.admin.material.model.entity.MaterialInfoDO; import org.springframework.stereotype.Repository; +import java.util.List; + /** * 物料信息 Mapper * @@ -12,5 +14,6 @@ import org.springframework.stereotype.Repository; */ @Repository public interface MaterialInfoMapper extends BaseMapper { - + public int updateByName(List list); + public int updateByCode(List list); } diff --git a/wms-module-system/src/main/java/top/wms/admin/material/model/req/MaterialImportRowReq.java b/wms-module-system/src/main/java/top/wms/admin/material/model/req/MaterialImportRowReq.java new file mode 100644 index 0000000..1b76cc1 --- /dev/null +++ b/wms-module-system/src/main/java/top/wms/admin/material/model/req/MaterialImportRowReq.java @@ -0,0 +1,45 @@ +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; +import java.math.BigDecimal; + +@Data +@Schema(description = "物料信息导入行数据") +public class MaterialImportRowReq implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + /** + * 物料名称 + */ + @Schema(description = "物料名称") + @NotBlank(message = "物料名称不能为空") + @Length(max = 255, message = "物料名称长度不能超过 {max} 个字符") + private String materialName; + + /** + * 物料编码 + */ + @Schema(description = "物料编码") + @NotBlank(message = "物料编码不能为空") + @Length(max = 255, message = "物料编码长度不能超过 {max} 个字符") + private String encoding; + + /** + * 物料单位重量(g) + */ + @Schema(description = "物料单位重量(g)") + private BigDecimal unitWeight; + + /* + * 物料规格 + * */ + @Schema(description = "物料规格") + private String materialSpec; +} diff --git a/wms-module-system/src/main/java/top/wms/admin/material/model/req/MaterialInfoImportReq.java b/wms-module-system/src/main/java/top/wms/admin/material/model/req/MaterialInfoImportReq.java new file mode 100644 index 0000000..2fc65c5 --- /dev/null +++ b/wms-module-system/src/main/java/top/wms/admin/material/model/req/MaterialInfoImportReq.java @@ -0,0 +1,47 @@ +package top.wms.admin.material.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.common.enums.DisEnableStatusEnum; +import top.wms.admin.system.enums.ImportPolicyEnum; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@Schema(description = "物料导入参数") +public class MaterialInfoImportReq 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 duplicateName; + + /** + * 重复编码策略 + */ + @Schema(description = "重复编码策略", example = "1") + @NotNull(message = "重复编码策略不能为空") + private ImportPolicyEnum duplicateCode; + + /** + * 默认状态 + */ + @Schema(description = "默认状态", example = "1") + private DisEnableStatusEnum defaultStatus; + +} diff --git a/wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialImportParseResp.java b/wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialImportParseResp.java new file mode 100644 index 0000000..c2f0cf9 --- /dev/null +++ b/wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialImportParseResp.java @@ -0,0 +1,55 @@ +package top.wms.admin.material.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; + +/** + * 物料导入解析结果 + * + * @author kils + * @since 2024/6/18 14:37 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Schema(description = "用户导入解析结果") +public class MaterialImportParseResp implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 导入会话 Key + */ + @Schema(description = "导入会话Key", example = "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed") + private String importKey; + + /** + * 总计行数 + */ + @Schema(description = "总计行数", example = "100") + private Integer totalRows; + + /** + * 有效行数 + */ + @Schema(description = "有效行数", example = "100") + private Integer validRows; + + /** + * 重复物料名行数 + */ + @Schema(description = "重复物料名行数", example = "100") + private Integer duplicateNameRows; + + /** + * 重复物料编码行数 + */ + @Schema(description = "重复物料编码行数", example = "100") + private Integer duplicateCodeRows; +} diff --git a/wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialInfoImportResp.java b/wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialInfoImportResp.java new file mode 100644 index 0000000..0ac98e8 --- /dev/null +++ b/wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialInfoImportResp.java @@ -0,0 +1,35 @@ +package top.wms.admin.material.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 MaterialInfoImportResp 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; +} diff --git a/wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialInfoResp.java b/wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialInfoResp.java index bb572ef..910ceba 100644 --- a/wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialInfoResp.java +++ b/wms-module-system/src/main/java/top/wms/admin/material/model/resp/MaterialInfoResp.java @@ -49,7 +49,7 @@ public class MaterialInfoResp extends BaseDetailResp { */ @Schema(description = "物料规格") @ExcelProperty(value = "物料规格") - private Double materialSpec; + private String materialSpec; /** * 物料照片地址 diff --git a/wms-module-system/src/main/java/top/wms/admin/material/service/MaterialInfoService.java b/wms-module-system/src/main/java/top/wms/admin/material/service/MaterialInfoService.java index 1841a66..1c394cf 100644 --- a/wms-module-system/src/main/java/top/wms/admin/material/service/MaterialInfoService.java +++ b/wms-module-system/src/main/java/top/wms/admin/material/service/MaterialInfoService.java @@ -1,10 +1,20 @@ package top.wms.admin.material.service; +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.entity.MaterialInfoDO; import top.wms.admin.material.model.query.MaterialInfoQuery; +import top.wms.admin.material.model.req.MaterialInfoImportReq; import top.wms.admin.material.model.req.MaterialInfoReq; +import top.wms.admin.material.model.resp.MaterialImportParseResp; +import top.wms.admin.material.model.resp.MaterialInfoImportResp; 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; /** * 物料信息业务接口 @@ -13,5 +23,34 @@ import top.wms.admin.material.model.resp.MaterialInfoResp; * @since 2026/02/27 14:19 */ public interface MaterialInfoService extends BaseService { + + /* + * + * 根据编码查询物料信息 + * */ public MaterialInfoDO getMaterialInfoByCode(String code); + + /** + * 下载导入模板 + * + * @param response 响应对象 + * @throws IOException / + */ + void downloadImportTemplate(HttpServletResponse response) throws IOException; + + /** + * 解析导入数据 + * + * @param file 导入文件 + * @return 解析结果 + */ + MaterialImportParseResp parseImport(MultipartFile file); + + /** + * 导入数据 + * + * @param req 导入信息 + * @return 导入结果 + */ + MaterialInfoImportResp importMaterial(MaterialInfoImportReq req); } diff --git a/wms-module-system/src/main/java/top/wms/admin/material/service/impl/MaterialInfoServiceImpl.java b/wms-module-system/src/main/java/top/wms/admin/material/service/impl/MaterialInfoServiceImpl.java index d0119a0..930d09f 100644 --- a/wms-module-system/src/main/java/top/wms/admin/material/service/impl/MaterialInfoServiceImpl.java +++ b/wms-module-system/src/main/java/top/wms/admin/material/service/impl/MaterialInfoServiceImpl.java @@ -1,20 +1,71 @@ package top.wms.admin.material.service.impl; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.resource.ResourceUtil; +import cn.hutool.core.lang.UUID; +import cn.hutool.core.math.MathUtil; +import cn.hutool.core.util.*; +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.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import me.ahoo.cosid.IdGenerator; +import me.ahoo.cosid.provider.DefaultIdGeneratorProvider; +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.util.SpringUtils; +import top.continew.starter.core.validation.CheckUtils; 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.common.enums.GenderEnum; +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.resp.MaterialImportParseResp; +import top.wms.admin.material.model.resp.MaterialInfoImportResp; import top.wms.admin.material.model.resp.MaterialInfoResp; import top.wms.admin.material.service.MaterialInfoService; +import top.wms.admin.system.model.entity.DeptDO; +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 java.io.IOException; +import java.math.BigDecimal; +import java.sql.Time; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static top.wms.admin.system.enums.ImportPolicyEnum.*; +import static top.wms.admin.system.enums.ImportPolicyEnum.SKIP; /** * 物料信息业务实现 @@ -34,4 +85,241 @@ public class MaterialInfoServiceImpl extends BaseServiceImpl importRowList; + // 读取表格数据 + try { + importRowList = EasyExcel.read(file.getInputStream()) + .head(MaterialImportRowReq.class) + .sheet() + .headRowNumber(1) + .doReadSync(); + } catch (Exception e) { + log.error("物料信息导入数据文件解析异常:{}", e); + throw new BusinessException("数据文件解析异常"); + } + // 总计行数 + materialImportResp.setTotalRows(importRowList.size()); + CheckUtils.throwIfEmpty(importRowList, "数据文件格式错误"); + // 有效行数:过滤无效(同名物料)数据 + List validRowList = this.filterImportData(importRowList); + materialImportResp.setValidRows(validRowList.size()); + CheckUtils.throwIfEmpty(validRowList, "数据文件格式错误"); + + // 检测表格内数据是否合法 + Set seenCode = new HashSet<>(); + boolean hasDuplicateEncoding = validRowList.stream() + .map(MaterialImportRowReq::getEncoding) + .anyMatch(encoding -> encoding != null && !seenCode.add(encoding)); + CheckUtils.throwIf(hasDuplicateEncoding, "存在重复物料编码,请检测数据"); + + // 查询重复用户 + materialImportResp + .setDuplicateNameRows(countExistByField(validRowList, MaterialImportRowReq::getMaterialName, MaterialInfoDO::getMaterialName, false)); + // 查询重复邮箱 + materialImportResp + .setDuplicateCodeRows(countExistByField(validRowList, MaterialImportRowReq::getEncoding, MaterialInfoDO::getEncoding, false)); + // 设置导入会话并缓存数据,有效期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 + @Transactional(rollbackFor = Exception.class) + public MaterialInfoImportResp importMaterial(MaterialInfoImportReq req) { + // 校验导入会话是否过期 + List importMaterialList; + try { + String data = RedisUtils.get(CacheConstants.DATA_IMPORT_KEY + req.getImportKey()); + importMaterialList = JSONUtil.toList(data, MaterialImportRowReq.class); + CheckUtils.throwIf(CollUtil.isEmpty(importMaterialList), "导入已过期,请重新上传"); + } catch (Exception e) { + log.error("导入异常:", e); + throw new BusinessException("导入已过期,请重新上传"); + } + // 已存在数据查询 + List existName = listExistByField(importMaterialList, MaterialImportRowReq::getMaterialName, MaterialInfoDO::getMaterialName); + List existCode = listExistByField(importMaterialList, MaterialImportRowReq::getEncoding, MaterialInfoDO::getEncoding); + CheckUtils + .throwIf(isExitImportMaterial(req, importMaterialList, existName, existCode), "数据不符合导入策略,已退出导入"); + // 批量操作数据库集合 + List insertList = new ArrayList<>(); + List updateByNameList = new ArrayList<>(); + List updateByCodeList = new ArrayList<>(); + // ID生成器 +// IdGenerator idGenerator = DefaultIdGeneratorProvider.INSTANCE.getShare(); + for (MaterialImportRowReq row : importMaterialList) { + if (isSkipMaterialImport(req, row, existName, existCode)) { + // 按规则跳过该行 + continue; + } + MaterialInfoDO materialDO = BeanUtil.toBeanIgnoreError(row, MaterialInfoDO.class); + materialDO.setUnitWeight(NumberUtil.isValidNumber(row.getUnitWeight())?row.getUnitWeight(): null); + materialDO.setMaterialSpec(StrUtil.isNotBlank(row.getMaterialSpec())?row.getMaterialSpec():null); + // 修改 or 新增 + if (UPDATE.validate(req.getDuplicateName(), row.getMaterialName(), existName)) { + materialDO.setMaterialName(row.getMaterialName()); + materialDO.setUpdateTime(LocalDateTime.now()); + materialDO.setUpdateUser(UserContextHolder.getUserId()); + updateByNameList.add(materialDO); + } else if (UPDATE.validate(req.getDuplicateCode(), row.getEncoding(), existCode)) { + materialDO.setEncoding(row.getEncoding()); + materialDO.setUpdateTime(LocalDateTime.now()); + materialDO.setUpdateUser(UserContextHolder.getUserId()); + updateByCodeList.add(materialDO); + } else { +// materialDO.setId(idGenerator.generate()); + insertList.add(materialDO); + } + } + doImportMaterial(insertList, updateByNameList, updateByCodeList); + RedisUtils.delete(CacheConstants.DATA_IMPORT_KEY + req.getImportKey()); + int insertCount = insertList.size(); + int updateByNameCount = updateByNameList.size(); + int updateByCodeCount = updateByCodeList.size(); + int totalUpdateCount = updateByNameCount + updateByCodeCount; + int totalHandleCount = insertCount + totalUpdateCount; + return new MaterialInfoImportResp( + totalHandleCount, // 总处理数 + insertCount, // 新增数 + totalUpdateCount // 更新总数 + ); + } + + + + + + /** + * 按指定数据集获取数据库已存在的数量 + * + * @param materialRowList 导入的数据源 + * @param rowField 导入数据的字段 + * @param dbField 对比数据库的字段 + * @return 存在的数量 + */ + private int countExistByField(List materialRowList, + Function rowField, + SFunction dbField, + boolean fieldEncrypt) { + List fieldValues = materialRowList.stream().map(rowField).filter(Objects::nonNull).toList(); + if (fieldValues.isEmpty()) { + return 0; + } + return (int)this.count(Wrappers.lambdaQuery() + .in(dbField, fieldEncrypt ? SecureUtils.encryptFieldByAes(fieldValues) : fieldValues)); + } + + + /** + * 过滤无效的导入用户数据(批量导入不严格校验数据) + * + * @param importRowList 导入数据 + */ + private List filterImportData(List importRowList) { + // 校验过滤 + List list = importRowList.stream() + .filter(row -> ValidationUtil.validate(row).isEmpty()) + .toList(); + // 物料名去重 + return list.stream() + .collect(Collectors.toMap(MaterialImportRowReq::getMaterialName, row -> row, (existing, replacement) -> existing)) + .values() + .stream() + .toList(); + } + + /** + * 按指定数据集获取数据库已存在内容 + * + * @param materialRowList 导入的数据源 + * @param rowField 导入数据的字段 + * @param dbField 对比数据库的字段 + * @return 存在的内容 + */ + private List listExistByField(List materialRowList, + Function rowField, + SFunction dbField) { + List fieldValues = materialRowList.stream().map(rowField).filter(Objects::nonNull).toList(); + if (fieldValues.isEmpty()) { + return Collections.emptyList(); + } + List materialDOList = baseMapper.selectList(Wrappers.lambdaQuery() + .in(dbField, fieldValues) + .select(dbField)); + return materialDOList.stream().map(dbField).filter(Objects::nonNull).toList(); + } + + /** + * 判断是否退出导入 + * + * @param req 导入参数 + * @param list 导入数据 + * @param existName 导入数据中已存在的物料名 + * @param existCode 导入数据中已存在的物料编号 + * @return 是否退出 + */ + private boolean isExitImportMaterial(MaterialInfoImportReq req, + List list, + List existName, + List existCode) { + return list.stream() + .anyMatch(row -> EXIT.validate(req.getDuplicateName(), row.getMaterialName(), existName) || EXIT.validate(req + .getDuplicateCode(), row.getEncoding(), existCode)); + } + + /** + * 判断是否跳过导入 + * + * @param req 导入参数 + * @param row 导入数据 + * @param existName 导入数据中已存在的物料名称 + * @param existCode 导入数据中已存在的物料编号 + * @return 是否跳过 + */ + private boolean isSkipMaterialImport(MaterialInfoImportReq req, + MaterialImportRowReq row, + List existName, + List existCode) { + return SKIP.validate(req.getDuplicateName(), row.getMaterialName(), existName) || SKIP.validate(req + .getDuplicateCode(), row.getEncoding(), existCode); + } + + /** + * 导入用户 + * + * @param insertList 新增用户 + * @param updateByNameList 修改用户 + * @param updateByCodeList 用户角色关联 + */ + private void doImportMaterial(List insertList, List updateByNameList, List updateByCodeList) { + if (CollUtil.isNotEmpty(insertList)) { + baseMapper.insertBatch(insertList); + } + if (CollUtil.isNotEmpty(updateByNameList)) { + baseMapper.updateByName(updateByNameList); + } + if (CollUtil.isNotEmpty(updateByCodeList)) { + baseMapper.updateByCode(updateByCodeList); + } + } } diff --git a/wms-module-system/src/main/java/top/wms/admin/system/mapper/RuleRelationMapper.java b/wms-module-system/src/main/java/top/wms/admin/system/mapper/RuleRelationMapper.java deleted file mode 100644 index 722b2ec..0000000 --- a/wms-module-system/src/main/java/top/wms/admin/system/mapper/RuleRelationMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package top.wms.admin.system.mapper; - -import org.springframework.stereotype.Repository; -import top.continew.starter.data.mp.base.BaseMapper; -import top.wms.admin.system.model.entity.RuleRelationDO; - -/** - * 通行规则-设备关联 Mapper - * - * @author zc - * @since 2025/12/22 17:16 - */ -@Repository -public interface RuleRelationMapper extends BaseMapper { - - int deleteByRuleId(RuleRelationDO ruleRelation); - -} diff --git a/wms-module-system/src/main/java/top/wms/admin/system/model/entity/RuleRelationDO.java b/wms-module-system/src/main/java/top/wms/admin/system/model/entity/RuleRelationDO.java deleted file mode 100644 index 2310d12..0000000 --- a/wms-module-system/src/main/java/top/wms/admin/system/model/entity/RuleRelationDO.java +++ /dev/null @@ -1,37 +0,0 @@ -package top.wms.admin.system.model.entity; - -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; - -import java.io.Serial; -import java.io.Serializable; - -/** - * 通行规则-设备关联实体 - * - * @author zc - * @since 2025/12/22 17:16 - */ -@Data -@TableName("equipment_rule_relation") -public class RuleRelationDO implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 平台侧规则ID(关联规则表主键) - */ - private Long ruleId; - - /** - * 设备ID(关联设备表主键) - */ - private Long equipmentId; - - /** - * 设备侧的规则ID(设备本地存储的规则标识) - */ - private String equipmentRuleId; - -} diff --git a/wms-module-system/src/main/java/top/wms/admin/system/model/req/RuleRelationReq.java b/wms-module-system/src/main/java/top/wms/admin/system/model/req/RuleRelationReq.java deleted file mode 100644 index 82518c8..0000000 --- a/wms-module-system/src/main/java/top/wms/admin/system/model/req/RuleRelationReq.java +++ /dev/null @@ -1,52 +0,0 @@ -package top.wms.admin.system.model.req; - -import jakarta.validation.constraints.*; - -import lombok.Data; - -import io.swagger.v3.oas.annotations.media.Schema; - -import org.hibernate.validator.constraints.Length; - -import java.io.Serial; -import java.io.Serializable; -import java.time.LocalDateTime; - -/** - * 创建或修改通行规则-设备关联参数 - * - * @author zc - * @since 2025/12/22 17:16 - */ -@Data -@Schema(description = "创建或修改通行规则-设备关联参数") -public class RuleRelationReq implements Serializable { - - @Serial - private static final long serialVersionUID = 1L; - - /** - * 平台侧规则ID(关联规则表主键) - */ - @Schema(description = "平台侧规则ID(关联规则表主键)") - @NotNull(message = "平台侧规则ID(关联规则表主键)不能为空") - private Long ruleId; - - /** - * 设备ID(关联设备表主键) - */ - @Schema(description = "设备ID(关联设备表主键)") - @NotNull(message = "设备ID(关联设备表主键)不能为空") - private Long equipmentId; - - /** - * 设备侧的规则ID(设备本地存储的规则标识) - */ - @Schema(description = "设备侧的规则ID(设备本地存储的规则标识)") - @NotBlank(message = "设备侧的规则ID(设备本地存储的规则标识)不能为空") - @Length(max = 64, message = "设备侧的规则ID(设备本地存储的规则标识)长度不能超过 {max} 个字符") - private String equipmentRuleId; - - @Schema(description = "创建时间") - private LocalDateTime createTime; -} diff --git a/wms-module-system/src/main/java/top/wms/admin/system/service/impl/PeopleEquipmentServiceImpl.java b/wms-module-system/src/main/java/top/wms/admin/system/service/impl/PeopleEquipmentServiceImpl.java deleted file mode 100644 index 6d6e18f..0000000 --- a/wms-module-system/src/main/java/top/wms/admin/system/service/impl/PeopleEquipmentServiceImpl.java +++ /dev/null @@ -1,23 +0,0 @@ -package top.wms.admin.system.service.impl; - -import lombok.RequiredArgsConstructor; - -import org.springframework.stereotype.Service; - -import top.continew.starter.extension.crud.service.BaseServiceImpl; -import top.wms.admin.system.mapper.PeopleEquipmentMapper; -import top.wms.admin.system.model.entity.PeopleEquipmentDO; -import top.wms.admin.system.model.query.PeopleEquipmentQuery; -import top.wms.admin.system.model.req.PeopleEquipmentReq; -import top.wms.admin.system.model.resp.PeopleEquipmentResp; -import top.wms.admin.system.service.PeopleEquipmentService; - -/** - * 人员设备下发信息业务实现 - * - * @author zc - * @since 2025/03/27 14:59 - */ -@Service -@RequiredArgsConstructor -public class PeopleEquipmentServiceImpl extends BaseServiceImpl implements PeopleEquipmentService {} \ No newline at end of file diff --git a/wms-module-system/src/main/java/top/wms/admin/system/service/impl/UserServiceImpl.java b/wms-module-system/src/main/java/top/wms/admin/system/service/impl/UserServiceImpl.java index 528d53c..35fe50c 100644 --- a/wms-module-system/src/main/java/top/wms/admin/system/service/impl/UserServiceImpl.java +++ b/wms-module-system/src/main/java/top/wms/admin/system/service/impl/UserServiceImpl.java @@ -36,6 +36,7 @@ import net.dreamlu.mica.core.result.R; import org.dromara.x.file.storage.core.FileInfo; import org.dromara.x.file.storage.core.FileStorageService; import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -131,6 +132,8 @@ public class UserServiceImpl extends BaseServiceImpl + + + + + UPDATE sys_material_info + SET + + encoding = #{item.encoding}, + + + unit_weight = #{item.unitWeight}, + + + material_spec = #{item.materialSpec}, + + + update_time = NOW(), + + + update_user = #{item.updateUser} + + WHERE material_name = #{item.materialName} + + + + + + UPDATE sys_material_info + SET + + material_name = #{item.materialName}, + + + unit_weight = #{item.unitWeight}, + + + material_spec = #{item.materialSpec}, + + + update_time = NOW(), + + + update_user = #{item.updateUser} + + WHERE encoding = #{item.encoding} + + + diff --git a/wms-module-system/src/main/resources/mapper/RuleRelationMapper.xml b/wms-module-system/src/main/resources/mapper/RuleRelationMapper.xml deleted file mode 100644 index ab80cba..0000000 --- a/wms-module-system/src/main/resources/mapper/RuleRelationMapper.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - DELETE FROM equipment_rule_relation - WHERE 1=1 - - - AND rule_id = #{ruleId} - - - AND equipment_id = #{equipmentId} - - - AND equipment_rule_id = #{equipmentRuleId} - - - - diff --git a/wms-webapi/src/main/java/top/wms/admin/controller/meterial/MaterialInfoController.java b/wms-webapi/src/main/java/top/wms/admin/controller/meterial/MaterialInfoController.java index 380b692..67751d7 100644 --- a/wms-webapi/src/main/java/top/wms/admin/controller/meterial/MaterialInfoController.java +++ b/wms-webapi/src/main/java/top/wms/admin/controller/meterial/MaterialInfoController.java @@ -1,5 +1,13 @@ package top.wms.admin.controller.meterial; +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; @@ -11,9 +19,17 @@ import top.continew.starter.extension.crud.annotation.CrudRequestMapping; import top.wms.admin.common.controller.BaseController; import top.wms.admin.material.model.entity.MaterialInfoDO; import top.wms.admin.material.model.query.MaterialInfoQuery; +import top.wms.admin.material.model.req.MaterialInfoImportReq; import top.wms.admin.material.model.req.MaterialInfoReq; +import top.wms.admin.material.model.resp.MaterialImportParseResp; +import top.wms.admin.material.model.resp.MaterialInfoImportResp; import top.wms.admin.material.model.resp.MaterialInfoResp; 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; /** * 物料信息管理 API @@ -33,4 +49,26 @@ public class MaterialInfoController extends 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 F{{a4sDN+Cc literal 0 HcmV?d00001 diff --git a/wms-webapi/src/main/resources/templates/import/people.xlsx b/wms-webapi/src/main/resources/templates/import/people.xlsx deleted file mode 100644 index 3c1fe9c2ce8256adca8d66ea1ec55f72f7558423..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9493 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 ScL4xo$j2W-oPN|lzx^Nl%$1J-