diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/recipe/vo/RecipePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/recipe/vo/RecipePageReqVO.java index ddeabd2d35..b68dfc3848 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/recipe/vo/RecipePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/recipe/vo/RecipePageReqVO.java @@ -15,25 +15,19 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @ToString(callSuper = true) public class RecipePageReqVO extends PageParam { - @Schema(description = "配方名称", example = "赵六") + @Schema(description = "配方名称", example = "李四") private String name; @Schema(description = "配方编码") private String recipeCode; - @Schema(description = "配方类型(关联配方类型表code)", example = "2") + @Schema(description = "关联配方类型", example = "2") private String recipeType; - @Schema(description = "关联产品名称", example = "李四") + @Schema(description = "关联产品名字", example = "赵六") private String productName; - @Schema(description = "关联设备ID(关联iot_device.id)", example = "14725") - private Long machineId; - - @Schema(description = "关联设备编码(冗余字段)") - private String machineCode; - - @Schema(description = "关联设备名称(冗余字段)", example = "芋艿") + @Schema(description = "关联设备名字", example = "赵六") private String machineName; @Schema(description = "配方描述") @@ -49,4 +43,8 @@ public class RecipePageReqVO extends PageParam { @Schema(description = "数据单位") private String dataUnit; + // 新增:多选导出的ids字段(逗号分隔的id字符串,如"1,2,3") + @Schema(description = "多选导出ID集合(逗号分隔)", example = "1,2,3") + private String ids; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/recipe/vo/RecipeRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/recipe/vo/RecipeRespVO.java index 82beec1173..80dec1c437 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/recipe/vo/RecipeRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/recipe/vo/RecipeRespVO.java @@ -12,11 +12,11 @@ import com.alibaba.excel.annotation.*; @ExcelIgnoreUnannotated public class RecipeRespVO { - @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "6587") - @ExcelProperty("主键ID") + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "631") +// @ExcelProperty("主键ID") private Long id; - @Schema(description = "配方名称", example = "赵六") + @Schema(description = "配方名称", example = "李四") @ExcelProperty("配方名称") private String name; @@ -24,40 +24,36 @@ public class RecipeRespVO { @ExcelProperty("配方编码") private String recipeCode; - @Schema(description = "配方类型(关联配方类型表code)", example = "2") - @ExcelProperty("配方类型(关联配方类型表code)") + @Schema(description = "关联配方类型", example = "2") + @ExcelProperty("配方类型") private String recipeType; - @Schema(description = "关联产品名称", example = "李四") - @ExcelProperty("关联产品名称") + @Schema(description = "关联产品名字", example = "赵六") + @ExcelProperty("关联产品") private String productName; - @Schema(description = "关联设备ID(关联iot_device.id)", example = "14725") - @ExcelProperty("关联设备ID(关联iot_device.id)") - private Long machineId; - - @Schema(description = "关联设备编码(冗余字段)") - @ExcelProperty("关联设备编码(冗余字段)") - private String machineCode; - - @Schema(description = "关联设备名称(冗余字段)", example = "芋艿") - @ExcelProperty("关联设备名称(冗余字段)") + @Schema(description = "关联设备名字", example = "赵六") + @ExcelProperty("关联设备") private String machineName; @Schema(description = "配方描述") - @ExcelProperty("配方描述") + @ExcelProperty("备注") private String recipeDesc; @Schema(description = "是否启用(0-禁用,1-启用)", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("是否启用(0-禁用,1-启用)") +// @ExcelProperty("是否启用(0-禁用,1-启用)") private Boolean isEnable; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") +// @ExcelProperty("创建时间") private LocalDateTime createTime; @Schema(description = "数据单位") - @ExcelProperty("数据单位") +// @ExcelProperty("数据单位") private String dataUnit; + @Schema(description = "关联设备ID", example = "1001") +// @ExcelProperty("关联设备ID") + private Long deviceId; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/recipe/RecipeMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/recipe/RecipeMapper.java index 7bdca08e36..680c84cb8e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/recipe/RecipeMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/recipe/RecipeMapper.java @@ -1,13 +1,16 @@ package cn.iocoder.yudao.module.iot.dal.mysql.recipe; import java.util.*; +import java.util.stream.Collectors; +import com.alibaba.excel.util.StringUtils; import cn.iocoder.yudao.framework.common.pojo.PageResult; +//import cn.iocoder.yudao.framework.common.util.StringUtils; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.iot.dal.dataobject.recipe.RecipeDO; import org.apache.ibatis.annotations.Mapper; -import cn.iocoder.yudao.module.iot.controller.admin.recipe.vo.*; +import cn.iocoder.yudao.module.iot.controller.admin.recipe.vo.RecipePageReqVO; /** * 配方管理主 Mapper @@ -18,19 +21,33 @@ import cn.iocoder.yudao.module.iot.controller.admin.recipe.vo.*; public interface RecipeMapper extends BaseMapperX { default PageResult selectPage(RecipePageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() + // 1. 先创建查询条件对象 + LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX() + // 原有所有查询条件(保留不变) .likeIfPresent(RecipeDO::getName, reqVO.getName()) - .eqIfPresent(RecipeDO::getRecipeCode, reqVO.getRecipeCode()) + .likeIfPresent(RecipeDO::getRecipeCode, reqVO.getRecipeCode()) .eqIfPresent(RecipeDO::getRecipeType, reqVO.getRecipeType()) .likeIfPresent(RecipeDO::getProductName, reqVO.getProductName()) - .eqIfPresent(RecipeDO::getMachineId, reqVO.getMachineId()) - .eqIfPresent(RecipeDO::getMachineCode, reqVO.getMachineCode()) .likeIfPresent(RecipeDO::getMachineName, reqVO.getMachineName()) .eqIfPresent(RecipeDO::getRecipeDesc, reqVO.getRecipeDesc()) .eqIfPresent(RecipeDO::getIsEnable, reqVO.getIsEnable()) .betweenIfPresent(RecipeDO::getCreateTime, reqVO.getCreateTime()) .eqIfPresent(RecipeDO::getDataUnit, reqVO.getDataUnit()) - .orderByDesc(RecipeDO::getId)); + .orderByDesc(RecipeDO::getId); + + // 2. 新增:处理ids多选导出条件(和参考代码逻辑一致) + if (StringUtils.isNotBlank(reqVO.getIds())) { + // 将逗号分隔的ids字符串转为Long类型的List + List idList = Arrays.stream(reqVO.getIds().split(",")) + .map(String::trim) // 去除空格,避免空字符导致转换失败 + .map(Long::valueOf) // 转为Long类型 + .collect(Collectors.toList()); + // 添加idIn条件,只查询指定ids的记录 + queryWrapper.in(RecipeDO::getId, idList); + } + + // 3. 执行分页查询 + return selectPage(reqVO, queryWrapper); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/recipe/RecipeServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/recipe/RecipeServiceImpl.java index 6a4733a301..3cf1757593 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/recipe/RecipeServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/recipe/RecipeServiceImpl.java @@ -1,21 +1,129 @@ +//package cn.iocoder.yudao.module.iot.service.recipe; +// +//import cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants; +//import org.springframework.stereotype.Service; +//import javax.annotation.Resource; +//import org.springframework.validation.annotation.Validated; +//import org.springframework.transaction.annotation.Transactional; +// +//import java.util.*; +//import cn.iocoder.yudao.module.iot.controller.admin.recipe.vo.*; +//import cn.iocoder.yudao.module.iot.dal.dataobject.recipe.RecipeDO; +//import cn.iocoder.yudao.framework.common.pojo.PageResult; +//import cn.iocoder.yudao.framework.common.pojo.PageParam; +//import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +// +//import cn.iocoder.yudao.module.iot.dal.mysql.recipe.RecipeMapper; +//import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceMapper; +// +//import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +//import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +// +//import cn.iocoder.yudao.framework.common.exception.ServiceException; +//import cn.hutool.core.util.StrUtil; +//import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +//import cn.iocoder.yudao.framework.common.exception.ServiceException; +// +//import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO; // 引入现有DeviceDO +//import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceMapper; // 引入现有DeviceMapper +// +///** +// * 配方管理主 Service 实现类 +// * +// * @author 内蒙必硕 +// */ +//@Service +//@Validated +//public class RecipeServiceImpl implements RecipeService { +// +// @Resource +// private RecipeMapper recipeMapper; +// +//// @Override +//// public Long createRecipe(RecipeSaveReqVO createReqVO) { +//// // 插入 +//// RecipeDO recipe = BeanUtils.toBean(createReqVO, RecipeDO.class); +//// recipeMapper.insert(recipe); +//// // 返回 +//// return recipe.getId(); +//// } +//@Override +//public Long createRecipe(RecipeSaveReqVO createReqVO) { +// String recipeCode = createReqVO.getRecipeCode(); +// +// // 1. 校验recipeCode不为空(使用新增的RECIPE_CODE_EMPTY错误码) +// if (StrUtil.isBlank(recipeCode)) { +// throw new ServiceException(ErrorCodeConstants.RECIPE_CODE_EMPTY); +// } +// +// // 2. 校验recipeCode是否重复(使用新增的RECIPE_CODE_DUPLICATE错误码) +// boolean exists = recipeMapper.exists( +// new LambdaQueryWrapperX().eq(RecipeDO::getRecipeCode, recipeCode) +// ); +// if (exists) { +// throw new ServiceException(ErrorCodeConstants.RECIPE_CODE_DUPLICATE); +// } +// +// // ========== 原有逻辑保持不变 ========== +// RecipeDO recipe = BeanUtils.toBean(createReqVO, RecipeDO.class); +// recipeMapper.insert(recipe); +// return recipe.getId(); +//} +// +// @Override +// public void updateRecipe(RecipeSaveReqVO updateReqVO) { +// // 校验存在 +// validateRecipeExists(updateReqVO.getId()); +// // 更新 +// RecipeDO updateObj = BeanUtils.toBean(updateReqVO, RecipeDO.class); +// recipeMapper.updateById(updateObj); +// } +// +// @Override +// public void deleteRecipe(Long id) { +// // 校验存在 +// validateRecipeExists(id); +// // 删除 +// recipeMapper.deleteById(id); +// } +// +// private void validateRecipeExists(Long id) { +// if (recipeMapper.selectById(id) == null) { +// throw exception(RECIPE_NOT_EXISTS); +// } +// } +// +// @Override +// public RecipeDO getRecipe(Long id) { +// return recipeMapper.selectById(id); +// } +// +//} package cn.iocoder.yudao.module.iot.service.recipe; -import org.springframework.stereotype.Service; -import javax.annotation.Resource; -import org.springframework.validation.annotation.Validated; -import org.springframework.transaction.annotation.Transactional; - -import java.util.*; -import cn.iocoder.yudao.module.iot.controller.admin.recipe.vo.*; +import cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.iot.controller.admin.recipe.vo.RecipePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.recipe.vo.RecipeRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.recipe.vo.RecipeSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.recipe.RecipeDO; +import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceMapper; +import cn.iocoder.yudao.module.iot.dal.mysql.recipe.RecipeMapper; +import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.hutool.core.util.StrUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; -import cn.iocoder.yudao.module.iot.dal.mysql.recipe.RecipeMapper; +import javax.annotation.Resource; +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.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.RECIPE_NOT_EXISTS; /** * 配方管理主 Service 实现类 @@ -28,30 +136,37 @@ public class RecipeServiceImpl implements RecipeService { @Resource private RecipeMapper recipeMapper; + @Resource + private DeviceMapper deviceMapper; // 注入现有DeviceMapper + // ========== 原有方法保持不变 ========== @Override public Long createRecipe(RecipeSaveReqVO createReqVO) { - // 插入 + String recipeCode = createReqVO.getRecipeCode(); + if (StrUtil.isBlank(recipeCode)) { + throw new ServiceException(ErrorCodeConstants.RECIPE_CODE_EMPTY); + } + boolean exists = recipeMapper.exists( + new LambdaQueryWrapperX().eq(RecipeDO::getRecipeCode, recipeCode) + ); + if (exists) { + throw new ServiceException(ErrorCodeConstants.RECIPE_CODE_DUPLICATE); + } RecipeDO recipe = BeanUtils.toBean(createReqVO, RecipeDO.class); recipeMapper.insert(recipe); - // 返回 return recipe.getId(); } @Override public void updateRecipe(RecipeSaveReqVO updateReqVO) { - // 校验存在 validateRecipeExists(updateReqVO.getId()); - // 更新 RecipeDO updateObj = BeanUtils.toBean(updateReqVO, RecipeDO.class); recipeMapper.updateById(updateObj); } @Override public void deleteRecipe(Long id) { - // 校验存在 validateRecipeExists(id); - // 删除 recipeMapper.deleteById(id); } @@ -71,4 +186,65 @@ public class RecipeServiceImpl implements RecipeService { return recipeMapper.selectPage(pageReqVO); } + // ========== 新增带deviceId的方法(改为public,供Controller直接调用) ========== + /** + * 分页查询配方,包含deviceId字段 + */ + public PageResult getRecipePageWithDeviceId(RecipePageReqVO pageReqVO) { + // 1. 查询配方分页数据 + PageResult recipePage = recipeMapper.selectPage(pageReqVO); + List recipeList = recipePage.getList(); + if (recipeList.isEmpty()) { + return PageResult.empty(recipePage.getTotal()); + } + + // 2. 提取所有machineName,批量查询deviceId(避免N+1查询) + List machineNames = recipeList.stream() + .map(RecipeDO::getMachineName) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + + // 调用现有DeviceMapper查询设备名称->ID映射 + List deviceList = deviceMapper.selectList( + new LambdaQueryWrapperX().in(DeviceDO::getDeviceName, machineNames) + ); + // 构建设备名称到ID的映射(处理重复名称,取第一个) + Map deviceName2IdMap = new HashMap<>(); + for (DeviceDO device : deviceList) { + deviceName2IdMap.putIfAbsent(device.getDeviceName(), device.getId()); + } + + // 3. 转换为VO并设置deviceId + List respVOList = new ArrayList<>(); + for (RecipeDO recipe : recipeList) { + RecipeRespVO respVO = BeanUtils.toBean(recipe, RecipeRespVO.class); + // 根据machineName关联设置deviceId + respVO.setDeviceId(deviceName2IdMap.get(recipe.getMachineName())); + respVOList.add(respVO); + } + + return new PageResult<>(respVOList, recipePage.getTotal()); + } + + /** + * 查询单个配方,包含deviceId字段 + */ + public RecipeRespVO getRecipeWithDeviceId(Long id) { + RecipeDO recipe = getRecipe(id); + if (recipe == null) { + return null; + } + RecipeRespVO respVO = BeanUtils.toBean(recipe, RecipeRespVO.class); + // 关联查询deviceId + if (recipe.getMachineName() != null) { + DeviceDO device = deviceMapper.selectOne( + new LambdaQueryWrapperX().eq(DeviceDO::getDeviceName, recipe.getMachineName()) + ); + if (device != null) { + respVO.setDeviceId(device.getId()); + } + } + return respVO; + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/recipetype/RecipeTypeServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/recipetype/RecipeTypeServiceImpl.java index 3850a65627..92f1f09e04 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/recipetype/RecipeTypeServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/recipetype/RecipeTypeServiceImpl.java @@ -73,8 +73,15 @@ public class RecipeTypeServiceImpl implements RecipeTypeService { @Override public PageResult getRecipeTypeAll(RecipeTypePageReqVO pageReqVO) { - // 调用Mapper查询全部数据(复用原有分页的查询条件,只是不分页) - List list = recipeTypeMapper.selectList(pageReqVO); + // 使用QueryWrapper构建查询条件 + com.baomidou.mybatisplus.core.conditions.query.QueryWrapper queryWrapper = + new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<>(); + + // 根据pageReqVO的条件进行查询(需要根据实际字段进行条件设置) + // 例如:queryWrapper.like(StringUtils.hasText(pageReqVO.getName()), "name", pageReqVO.getName()); + + List list = recipeTypeMapper.selectList(queryWrapper); + // 封装成PageResult返回(总数=列表长度,保持返回格式和分页接口一致) return new PageResult<>(list, (long) list.size()); }