diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java index 2956cd602..f1f005ff1 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java @@ -28,9 +28,12 @@ import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.multipart.MaxUploadSizeExceededException; +import org.springframework.web.multipart.MultipartException; import org.springframework.web.servlet.NoHandlerFoundException; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import javax.validation.ValidationException; @@ -385,4 +388,90 @@ public class GlobalExceptionHandler { return null; } + /** + * 处理文件上传大小超出限制异常 + */ + @ExceptionHandler(MaxUploadSizeExceededException.class) + public CommonResult handleMaxUploadSizeExceededException( + MaxUploadSizeExceededException e, + HttpServletRequest request, + HttpServletResponse response) { + + log.error("文件上传大小超出限制: {}", request.getRequestURI(), e); + + // 从异常信息中提取实际大小和限制大小 + String errorMessage = extractSizeInfo(e); + + return CommonResult.error(400, + String.format("文件大小超出限制。%s 请上传小于500MB的文件", errorMessage) + ); + } + + /** + * 处理 Multipart 异常 + */ + @ExceptionHandler(MultipartException.class) + public CommonResult handleMultipartException( + MultipartException e, + HttpServletRequest request) { + + log.error("文件上传异常: {}", request.getRequestURI(), e); + + if (e.getMessage().contains("SizeLimitExceededException")) { + return CommonResult.error(400, "文件大小超出限制,请上传小于500MB的文件"); + } else if (e.getMessage().contains("FileSizeLimitExceededException")) { + return CommonResult.error(400, "单个文件大小超出限制,请上传小于500MB的文件"); + } else if (e.getMessage().contains("临时文件夹")) { + return CommonResult.error(400, "临时文件夹不可用,请检查磁盘空间"); + } + + return CommonResult.error(400, "文件上传失败:" + e.getMessage()); + } + + /** + * 从异常信息中提取大小信息 + */ + private String extractSizeInfo(MaxUploadSizeExceededException e) { + String message = e.getMessage(); + + try { + // 解析异常信息,提取大小数据 + if (message.contains("exceeds the configured maximum")) { + // 格式: ... size (367254613) exceeds the configured maximum (104857600) + String sizePart = message.substring(message.indexOf("size (") + 6); + String actualSizeStr = sizePart.substring(0, sizePart.indexOf(")")); + + String maxPart = message.substring(message.indexOf("maximum (") + 9); + String maxSizeStr = maxPart.substring(0, maxPart.indexOf(")")); + + long actualSize = Long.parseLong(actualSizeStr); + long maxSize = Long.parseLong(maxSizeStr); + + return String.format("实际大小: %s, 限制大小: %s", + formatFileSize(actualSize), + formatFileSize(maxSize) + ); + } + } catch (Exception ex) { + log.error("解析文件大小信息失败", ex); + } + + return "请检查文件大小"; + } + + /** + * 格式化文件大小 + */ + private String formatFileSize(long size) { + if (size < 1024) { + return size + " B"; + } else if (size < 1024 * 1024) { + return String.format("%.2f KB", size / 1024.0); + } else if (size < 1024 * 1024 * 1024) { + return String.format("%.2f MB", size / (1024.0 * 1024.0)); + } else { + return String.format("%.2f GB", size / (1024.0 * 1024.0 * 1024.0)); + } + } + } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java index 87610030d..6d98252cb 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.product; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; @@ -10,26 +11,33 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitRespVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitSaveReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitImportExcelVO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductUnitMapper; import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService; +import cn.iocoder.yudao.module.system.enums.common.SexEnum; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; +import java.util.Arrays; import java.util.List; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.IMPORT_LIST_IS_EMPTY; @Tag(name = "管理后台 - ERP 产品单位") @RestController @@ -129,4 +137,30 @@ public class ErpProductUnitController { } + @GetMapping("/get-import-template") + @Operation(summary = "获得导入单位模板") + public void importTemplate(HttpServletResponse response) throws IOException { + // 手动创建导出 demo + List list = Arrays.asList( + ErpProductUnitImportExcelVO.builder().name("件").primaryFlag("N").primaryName("个").changeRate(0.02) + .status(CommonStatusEnum.ENABLE.getStatus()).build() + ); + // 输出 + ExcelUtils.write(response, "单位导入模板.xls", "单位列表", ErpProductUnitImportExcelVO.class, list); + } + + @PostMapping("/import") + @Operation(summary = "导入单位") + @Parameters({ + @Parameter(name = "file", description = "Excel 文件", required = true), + @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") + }) + @PreAuthorize("@ss.hasPermission('system:user:import')") + public CommonResult importExcel(@RequestParam("file") MultipartFile file, + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception { + List list = ExcelUtils.read(file, ErpProductUnitImportExcelVO.class); + productUnitService.importUnitList(list, updateSupport); + return success("导入成功"); + } + } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitImportExcelVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitImportExcelVO.java new file mode 100644 index 000000000..9eca14638 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitImportExcelVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * 单位 Excel 导入 VO + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题 +public class ErpProductUnitImportExcelVO { + + @ExcelProperty("单位名称") + private String name; + + @ExcelProperty(value = "是否主单位", converter = DictConvert.class) + @DictFormat("primary_flag") + private String primaryFlag; + + private Long primaryId; + + @ExcelProperty("关联主单位") + private String primaryName; + + @ExcelProperty("换算比例") + private Double changeRate; + + @ExcelProperty(value ="单位状态", converter = DictConvert.class) + @DictFormat("common_status") + private Integer status; + + +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java index 181c867b0..adc822c03 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.erp.service.product; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitImportExcelVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitRespVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitSaveReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; @@ -106,4 +108,6 @@ public interface ErpProductUnitService { * @return 产品单位 */ ErpProductUnitDO getProductUnitByName(String name); + + void importUnitList(List list, Boolean updateSupport); } \ No newline at end of file diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java index 0b6c2f936..48305c285 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java @@ -1,9 +1,15 @@ package cn.iocoder.yudao.module.erp.service.product; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitImportExcelVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitRespVO; import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitSaveReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductUnitMapper; @@ -12,14 +18,17 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.google.common.annotations.VisibleForTesting; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import java.util.Collection; -import java.util.List; +import javax.validation.ConstraintViolationException; +import java.util.*; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; /** * ERP 产品单位 Service 实现类 @@ -131,10 +140,45 @@ public class ErpProductUnitServiceImpl implements ErpProductUnitService { public ErpProductUnitDO getProductUnitByName(String name) { return productUnitMapper.selectByName(name); } + + @Override public List getProductUnitListByFlag() { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("primary_flag", "Y"); return productUnitMapper.selectList(wrapper); } + + @Override + @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入 + public void importUnitList(List list, Boolean updateSupport) { + // 1.1 参数校验 + if (CollUtil.isEmpty(list)) { + throw exception(IMPORT_LIST_IS_EMPTY); + } + + // 1.2 查询主单位数据 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("primary_flag", "Y"); + List erpProductUnitDOS = productUnitMapper.selectList(wrapper); + Map> map = erpProductUnitDOS.stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy( + ErpProductUnitDO::getName, + Collectors.toList() + )); + List erpProductUnitDOs = new ArrayList<>(); + list.stream().forEach(importUser -> { + if(importUser.getPrimaryName()!=null){ + List erpProductUnitDOS1 = map.get(importUser.getPrimaryName()); + if (CollUtil.isEmpty(erpProductUnitDOS1)) { + importUser.setPrimaryId(null); + } else { + importUser.setPrimaryId(erpProductUnitDOS1.get(0).getId()); + } + } + ErpProductUnitDO erpProductUnitDO = BeanUtils.toBean(importUser, ErpProductUnitDO.class); + erpProductUnitDOs.add(erpProductUnitDO); + }); + CollUtil.isNotEmpty(erpProductUnitDOs);productUnitMapper.insertBatch(erpProductUnitDOs); + } } \ No newline at end of file diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerServiceImpl.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerServiceImpl.java index 93c9771f2..ed35bd072 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerServiceImpl.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/deviceledger/DeviceLedgerServiceImpl.java @@ -174,6 +174,8 @@ public class DeviceLedgerServiceImpl implements DeviceLedgerService { } // 更新 DeviceLedgerDO updateObj = BeanUtils.toBean(updateReqVO, DeviceLedgerDO.class); + updateObj.setComponentId(updateObj.getComponentId()==null?"":updateObj.getComponentId()); + updateObj.setBeijianId(updateObj.getBeijianId()==null?"":updateObj.getBeijianId()); deviceLedgerMapper.updateById(updateObj); } diff --git a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/planmaintenance/PlanMaintenanceServiceImpl.java b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/planmaintenance/PlanMaintenanceServiceImpl.java index c0bb55160..2fb83767b 100644 --- a/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/planmaintenance/PlanMaintenanceServiceImpl.java +++ b/yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/planmaintenance/PlanMaintenanceServiceImpl.java @@ -105,6 +105,8 @@ public class PlanMaintenanceServiceImpl implements PlanMaintenanceService { .collect(Collectors.toList()); //更新关联表 updateSubjectPlan(updateObj.getId(),idList); + }else{ + subjectPlanMapper.deleteByPlanId(updateObj.getId()); } } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index 96052dc72..4345cee13 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -163,4 +163,6 @@ public interface ErrorCodeConstants { // ========== 站内信发送 1-002-028-000 ========== ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_028_000, "模板参数({})缺失"); + ErrorCode IMPORT_LIST_IS_EMPTY = new ErrorCode(1_002_029_000, "导入数据不能为空!"); + }