完成了配方配置

plp
86158 4 weeks ago
parent a81cbeb113
commit 7673701808

@ -59,5 +59,6 @@ public interface ErrorCodeConstants {
ErrorCode RECIPE_CODE_DUPLICATE = new ErrorCode(1_003_000_004, "编码已存在");
ErrorCode RECIPE_CODE_EMPTY = new ErrorCode(1_003_000_005, "配方编码不能为空");
ErrorCode RECIPE_PLAN_DETAIL_NOT_EXISTS = new ErrorCode(1_003_000_006, "配方计划详情表(配方库)不存在");
ErrorCode RECIPE_POINT_RECORD_NOT_EXISTS = new ErrorCode(1_003_000_007, "IoT配方点位记录不存在");
ErrorCode RECIPE_DEVICE_RECORD_NOT_EXISTS = new ErrorCode(1_003_000_008, "设备点位采集值记录不存在");
}

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.iot.controller.admin.recipedeviceattribute;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
@ -28,6 +29,7 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.iot.controller.admin.recipedeviceattribute.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipedeviceattribute.RecipeDeviceAttributeDO;
import cn.iocoder.yudao.module.iot.service.recipedeviceattribute.RecipeDeviceAttributeService;
import cn.iocoder.yudao.module.iot.service.device.TDengineService;
@Tag(name = "管理后台 - 配方配置(关联采集设备模型-点位管理)")
@RestController
@ -37,6 +39,8 @@ public class RecipeDeviceAttributeController {
@Resource
private RecipeDeviceAttributeService recipeDeviceAttributeService;
@Resource
private TDengineService tDengineService;
@PostMapping("/create")
@Operation(summary = "创建配方配置(关联采集设备模型-点位管理)")
@ -105,4 +109,25 @@ public class RecipeDeviceAttributeController {
BeanUtils.toBean(list, RecipeDeviceAttributeRespVO.class));
}
@GetMapping("/singleDevice")
@Operation(summary = "设备运行参数最新值")
@PreAuthorize("@ss.hasPermission('iot:device-model-attribute:query')")
// 修正返回值类型为Service方法对应的Map结构
public CommonResult<Map<String, List<Map<String, Object>>>> operationAnalysisDetails(
@RequestParam("deviceId") Long deviceId) throws JsonProcessingException {
// 1. 注入RecipeDeviceAttributeService需确保类名和注入名称正确
// 注意这里假设你的Service类名为RecipeDeviceAttributeService需和实际类名一致
// 如果是通过@Autowired注入需在Controller类中先声明
// @Autowired
// private RecipeDeviceAttributeService recipeDeviceAttributeService;
// 2. 调用Service方法变量类型改为Map匹配返回值
Map<String, List<Map<String, Object>>> recipeDeviceAttribute = recipeDeviceAttributeService.singleDevice(deviceId);
// 3. 返回结果(参数类型匹配)
return success(recipeDeviceAttribute);
}
}

@ -0,0 +1,312 @@
package cn.iocoder.yudao.module.iot.controller.admin.recipedevicerecord;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.iot.controller.admin.recipedevicerecord.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipedevicerecord.RecipeDeviceRecordDO;
import cn.iocoder.yudao.module.iot.service.recipedevicerecord.RecipeDeviceRecordService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.iot.controller.admin.recipedevicerecord.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipedevicerecord.RecipeDeviceRecordDO;
import cn.iocoder.yudao.module.iot.service.recipedevicerecord.RecipeDeviceRecordService;
// 新增必要的导入
import cn.iocoder.yudao.module.iot.service.recipedeviceattribute.RecipeDeviceAttributeService;
import cn.iocoder.yudao.module.iot.service.device.TDengineService;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipedeviceattribute.RecipeDeviceAttributeDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipepoint.RecipePointDO;
import cn.iocoder.yudao.module.iot.service.recipepoint.RecipePointService;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipepointrecord.RecipePointRecordDO;
import cn.iocoder.yudao.module.iot.service.recipepointrecord.RecipePointRecordService;
@Tag(name = "管理后台 - 设备点位采集值记录")
@RestController
@RequestMapping("/iot/recipe-device-record")
@Validated
public class RecipeDeviceRecordController {
@Resource
private RecipeDeviceRecordService recipeDeviceRecordService;
// 新增注入的服务
@Resource
private RecipeDeviceAttributeService recipeDeviceAttributeService;
@Resource
private TDengineService tDengineService;
@Resource
private RecipePointService recipePointService;
@Resource
private RecipePointRecordService recipePointRecordService;
@Resource
private ObjectMapper objectMapper;
@PostMapping("/create")
@Operation(summary = "创建设备点位采集值记录")
@PreAuthorize("@ss.hasPermission('iot:recipe-device-record:create')")
public CommonResult<Long> createRecipeDeviceRecord(@Valid @RequestBody RecipeDeviceRecordSaveReqVO createReqVO) {
return success(recipeDeviceRecordService.createRecipeDeviceRecord(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新设备点位采集值记录")
@PreAuthorize("@ss.hasPermission('iot:recipe-device-record:update')")
public CommonResult<Boolean> updateRecipeDeviceRecord(@Valid @RequestBody RecipeDeviceRecordSaveReqVO updateReqVO) {
recipeDeviceRecordService.updateRecipeDeviceRecord(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除设备点位采集值记录")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('iot:recipe-device-record:delete')")
public CommonResult<Boolean> deleteRecipeDeviceRecord(@RequestParam("id") Long id) {
recipeDeviceRecordService.deleteRecipeDeviceRecord(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得设备点位采集值记录")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:recipe-device-record:query')")
public CommonResult<RecipeDeviceRecordRespVO> getRecipeDeviceRecord(@RequestParam("id") Long id) {
RecipeDeviceRecordDO recipeDeviceRecord = recipeDeviceRecordService.getRecipeDeviceRecord(id);
return success(BeanUtils.toBean(recipeDeviceRecord, RecipeDeviceRecordRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得设备点位采集值记录分页")
@PreAuthorize("@ss.hasPermission('iot:recipe-device-record:query')")
public CommonResult<PageResult<RecipeDeviceRecordRespVO>> getRecipeDeviceRecordPage(@Valid RecipeDeviceRecordPageReqVO pageReqVO) {
PageResult<RecipeDeviceRecordDO> pageResult = recipeDeviceRecordService.getRecipeDeviceRecordPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, RecipeDeviceRecordRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出设备点位采集值记录 Excel")
@PreAuthorize("@ss.hasPermission('iot:recipe-device-record:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportRecipeDeviceRecordExcel(@Valid RecipeDeviceRecordPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<RecipeDeviceRecordDO> list = recipeDeviceRecordService.getRecipeDeviceRecordPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "设备点位采集值记录.xls", "数据", RecipeDeviceRecordRespVO.class,
BeanUtils.toBean(list, RecipeDeviceRecordRespVO.class));
}
//
//
// /**
// * 批量创建设备点位采集记录和配方点位记录
// * @param recipeId 配方ID
// * @param pointList 点位列表 [{id: 1, refer: "参考值1"}, {id: 2, refer: "参考值2"}]
// * @return 创建结果
// * @throws JsonProcessingException JSON处理异常
// */
// @PostMapping("/batch-create")
// @Operation(summary = "批量创建设备点位采集记录和配方点位记录")
// @PreAuthorize("@ss.hasPermission('iot:recipe-device-record:create')")
// public CommonResult<Boolean> batchCreateRecipeDeviceRecord(
// @RequestParam("recipeId") Long recipeId,
// @RequestBody List<PointReferVO> pointList) throws JsonProcessingException {
//
// // ========== 第一步:查询配方关联的点位属性信息 ==========
// // 1.1 根据recipeId查询iot_recipe_device_attribute表记录
// List<RecipeDeviceAttributeDO> attributeList = recipeDeviceAttributeService.getByRecipeId(recipeId);
// if (CollectionUtils.isEmpty(attributeList)) {
// return success(false); // 无关联属性,直接返回
// }
//
// // 1.2 构建attributeName -> (attributeId, dataUnit)的映射关系
// Map<String, AttributeInfo> attributeMap = new HashMap<>();
// for (RecipeDeviceAttributeDO attributeDO : attributeList) {
// // 根据attribute_id查询iot_device_contact_model表获取attribute_name和data_unit
// // 假设通过service方法获取需根据实际业务调整
// Map<String, String> modelAttr = recipeDeviceAttributeService.getDeviceContactModelAttr(attributeDO.getAttributeId());
// String attributeName = modelAttr.get("attributeName");
// String dataUnit = modelAttr.get("dataUnit");
//
// attributeMap.put(attributeName, new AttributeInfo(
// attributeDO.getId(), attributeName, dataUnit, attributeDO.getDeviceId()));
// }
//
// // ========== 第二步:获取设备运行参数并创建设备点位采集记录 ==========
// // 2.1 获取设备运行参数JSON数据复用singleDevice逻辑取第一个设备ID
// if (attributeList.isEmpty()) {
// return success(false);
// }
// Long deviceId = attributeList.get(0).getDeviceId();
// Map<String, List<Map<String, Object>>> deviceData = recipeDeviceAttributeService.singleDevice(deviceId);
//
// // 2.2 解析JSON数据并匹配属性名
// if (deviceData != null && deviceData.containsKey("data")) {
// // 解析嵌套的data节点适配示例JSON结构
// String dataJson = objectMapper.writeValueAsString(deviceData.get("data"));
// JsonNode dataNode = objectMapper.readTree(dataJson);
//
// // 遍历所有数据分类(设备基础数据、班次信息等)
// Iterator<Map.Entry<String, JsonNode>> categoryIterator = dataNode.fields();
// while (categoryIterator.hasNext()) {
// Map.Entry<String, JsonNode> categoryEntry = categoryIterator.next();
// JsonNode attrListNode = categoryEntry.getValue();
//
// // 遍历分类下的每个属性
// if (attrListNode.isArray()) {
// for (JsonNode attrNode : attrListNode) {
// String attributeName = attrNode.get("attributeName").asText();
// JsonNode addressValueNode = attrNode.get("addressValue");
// Object addressValue = addressValueNode.isNull() ? null :
// (addressValueNode.isNumber() ? addressValueNode.numberValue() : addressValueNode.textValue());
//
// // 匹配第一步的属性名,匹配成功则创建记录
// if (attributeMap.containsKey(attributeName)) {
// AttributeInfo attrInfo = attributeMap.get(attributeName);
//
// // 构建设备点位采集记录DO
// RecipeDeviceRecordDO recordDO = new RecipeDeviceRecordDO();
// recordDO.setRecipeId(recipeId);
// recordDO.setAttributeName(attributeName);
// recordDO.setAddressValue(addressValue != null ? addressValue.toString() : null);
// recordDO.setDataUnit(attrInfo.getDataUnit());
// recordDO.setDeviceId(deviceId);
//
// // 创建记录
// recipeDeviceRecordService.createRecipeDeviceRecord(recordDO);
// }
// }
// }
// }
// }
//
// // ========== 第三步:创建配方点位记录 ==========
// for (PointReferVO pointVO : pointList) {
// // 3.1 根据id查询iot_recipe_point表记录
// RecipePointDO pointDO = recipePointService.getRecipePoint(pointVO.getId());
// if (pointDO == null) {
// continue; // 点位不存在则跳过
// }
//
// // 3.2 构建配方点位记录DO
// RecipePointRecordDO pointRecordDO = new RecipePointRecordDO();
// pointRecordDO.setPointId(pointDO.getId());
// pointRecordDO.setName(pointDO.getName());
// pointRecordDO.setMax(pointDO.getMax());
// pointRecordDO.setMin(pointDO.getMin());
// pointRecordDO.setDataUnit(pointDO.getDataUnit());
// pointRecordDO.setRemark(pointDO.getRemark());
// pointRecordDO.setRefer(pointVO.getRefer()); // 入参的refer值
// pointRecordDO.setRecipeId(recipeId);
//
// // 3.3 创建配方点位记录
// recipePointRecordService.createRecipePointRecord(pointRecordDO);
// }
//
// return success(true);
// }
// ========== 内部辅助类 ==========
/**
* VO
*/
public static class PointReferVO {
private Long id; // 配方点位ID
private String refer; // 参考值
// getter/setter
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRefer() {
return refer;
}
public void setRefer(String refer) {
this.refer = refer;
}
}
/**
*
*/
private static class AttributeInfo {
private Long attributeId; // 属性ID
private String attributeName; // 属性名
private String dataUnit; // 数据单位
private Long deviceId; // 设备ID
public AttributeInfo(Long attributeId, String attributeName, String dataUnit, Long deviceId) {
this.attributeId = attributeId;
this.attributeName = attributeName;
this.dataUnit = dataUnit;
this.deviceId = deviceId;
}
// getter
public String getDataUnit() {
return dataUnit;
}
public Long getDeviceId() {
return deviceId;
}
}
}

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.iot.controller.admin.recipedevicerecord.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 设备点位采集值记录分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class RecipeDeviceRecordPageReqVO extends PageParam {
@Schema(description = "编码")
private String attributeCode;
@Schema(description = "名称", example = "张三")
private String attributeName;
@Schema(description = "类型", example = "2")
private String attributeType;
@Schema(description = "数据类型", example = "2")
private String dataType;
@Schema(description = "地址")
private String address;
@Schema(description = "单位")
private String dataUnit;
@Schema(description = "倍率")
private Double ratio;
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "设备id", example = "32535")
private Long deviceId;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "采集值")
private Double value;
}

@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.iot.controller.admin.recipedevicerecord.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 设备点位采集值记录 Response VO")
@Data
@ExcelIgnoreUnannotated
public class RecipeDeviceRecordRespVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "13509")
@ExcelProperty("id")
private Long id;
@Schema(description = "编码")
@ExcelProperty("编码")
private String attributeCode;
@Schema(description = "名称", example = "张三")
@ExcelProperty("名称")
private String attributeName;
@Schema(description = "类型", example = "2")
@ExcelProperty("类型")
private String attributeType;
@Schema(description = "数据类型", example = "2")
@ExcelProperty("数据类型")
private String dataType;
@Schema(description = "地址")
@ExcelProperty("地址")
private String address;
@Schema(description = "单位")
@ExcelProperty("单位")
private String dataUnit;
@Schema(description = "倍率")
@ExcelProperty("倍率")
private Double ratio;
@Schema(description = "备注", example = "随便")
@ExcelProperty("备注")
private String remark;
@Schema(description = "设备id", example = "32535")
@ExcelProperty("设备id")
private Long deviceId;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "采集值")
@ExcelProperty("采集值")
private Double value;
}

@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.iot.controller.admin.recipedevicerecord.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
@Schema(description = "管理后台 - 设备点位采集值记录新增/修改 Request VO")
@Data
public class RecipeDeviceRecordSaveReqVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "13509")
private Long id;
@Schema(description = "编码")
private String attributeCode;
@Schema(description = "名称", example = "张三")
private String attributeName;
@Schema(description = "类型", example = "2")
private String attributeType;
@Schema(description = "数据类型", example = "2")
private String dataType;
@Schema(description = "地址")
private String address;
@Schema(description = "单位")
private String dataUnit;
@Schema(description = "倍率")
private Double ratio;
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "设备id", example = "32535")
private Long deviceId;
@Schema(description = "采集值")
private Double value;
}

@ -71,12 +71,19 @@ public class RecipePlanDetailController {
return success(BeanUtils.toBean(recipePlanDetail, RecipePlanDetailRespVO.class));
}
// @GetMapping("/page")
// @Operation(summary = "获得配方计划详情表(配方库)分页")
// @PreAuthorize("@ss.hasPermission('iot:recipe-plan-detail:query')")
// public CommonResult<PageResult<RecipePlanDetailRespVO>> getRecipePlanDetailPage(@Valid RecipePlanDetailPageReqVO pageReqVO) {
// PageResult<RecipePlanDetailDO> pageResult = recipePlanDetailService.getRecipePlanDetailPage(pageReqVO);
// return success(BeanUtils.toBean(pageResult, RecipePlanDetailRespVO.class));
// }
@GetMapping("/page")
@Operation(summary = "获得配方计划详情表(配方库)分页")
@PreAuthorize("@ss.hasPermission('iot:recipe-plan-detail:query')")
public CommonResult<PageResult<RecipePlanDetailRespVO>> getRecipePlanDetailPage(@Valid RecipePlanDetailPageReqVO pageReqVO) {
PageResult<RecipePlanDetailDO> pageResult = recipePlanDetailService.getRecipePlanDetailPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, RecipePlanDetailRespVO.class));
@Operation(summary = "分页查询配方计划详情(含关联信息)")
public CommonResult<PageResult<RecipePlanDetailPageRespDTO>> pageRecipePlanDetail(RecipePlanDetailPageReqVO reqVO) {
PageResult<RecipePlanDetailPageRespDTO> pageResult = recipePlanDetailService.pageRecipePlanDetail(reqVO);
return CommonResult.success(pageResult);
}
@GetMapping("/export-excel")

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.iot.controller.admin.recipeplandetail.vo;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* DTO
*/
@Data
public class RecipePlanDetailPageRespDTO {
// 基础字段和iot_recipe_plan_detail表对应
private Long id;
private String code; // 编码
private String name; // 名称
private Long recipeId; // 关联配方ID
private Long planId; // 关联计划ID
private String source; // 来源(新增/生产中)
private Boolean isEnable; // 是否启用
private String creator; // 创建人
private Date createTime; // 创建时间
private String updater; // 更新人
private Date updateTime; // 更新时间
private Long tenantId; // 租户ID
// 关联字段(从其他表查询)
private String recipeName; // 配方名称来自iot_recipe表
private String planCode; // 计划编码来自mes_plan表
// private String creatorName;
private Long deviceId;
}

@ -49,4 +49,8 @@ public class RecipePlanDetailRespVO {
@ExcelProperty("创建时间")
private LocalDateTime createTime;
// @Schema(description = "创建人名字", example = "随便")
// @ExcelProperty("创建人名字")
// private String creatorName;
}

@ -32,7 +32,7 @@ public class RecipePlanDetailSaveReqVO {
private String source;
@Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "是否启用不能为空")
// @NotNull(message = "是否启用不能为空")
private Boolean isEnable;
}

@ -41,4 +41,7 @@ public class RecipePointPageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "参考值")
private BigDecimal refer;
}

@ -49,4 +49,8 @@ public class RecipePointRespVO {
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "参考值")
@ExcelProperty("参考值")
private BigDecimal refer;
}

@ -34,4 +34,7 @@ public class RecipePointSaveReqVO {
@Schema(description = "备注", example = "你说的对")
private String remark;
@Schema(description = "参考值")
private BigDecimal refer;
}

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.iot.controller.admin.recipepointrecord;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.iot.controller.admin.recipepointrecord.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipepointrecord.RecipePointRecordDO;
import cn.iocoder.yudao.module.iot.service.recipepointrecord.RecipePointRecordService;
@Tag(name = "管理后台 - IoT配方点位记录")
@RestController
@RequestMapping("/iot/recipe-point-record")
@Validated
public class RecipePointRecordController {
@Resource
private RecipePointRecordService recipePointRecordService;
@PostMapping("/create")
@Operation(summary = "创建IoT配方点位记录")
@PreAuthorize("@ss.hasPermission('iot:recipe-point-record:create')")
public CommonResult<Long> createRecipePointRecord(@Valid @RequestBody RecipePointRecordSaveReqVO createReqVO) {
return success(recipePointRecordService.createRecipePointRecord(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新IoT配方点位记录")
@PreAuthorize("@ss.hasPermission('iot:recipe-point-record:update')")
public CommonResult<Boolean> updateRecipePointRecord(@Valid @RequestBody RecipePointRecordSaveReqVO updateReqVO) {
recipePointRecordService.updateRecipePointRecord(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除IoT配方点位记录")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('iot:recipe-point-record:delete')")
public CommonResult<Boolean> deleteRecipePointRecord(@RequestParam("id") Long id) {
recipePointRecordService.deleteRecipePointRecord(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得IoT配方点位记录")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:recipe-point-record:query')")
public CommonResult<RecipePointRecordRespVO> getRecipePointRecord(@RequestParam("id") Long id) {
RecipePointRecordDO recipePointRecord = recipePointRecordService.getRecipePointRecord(id);
return success(BeanUtils.toBean(recipePointRecord, RecipePointRecordRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得IoT配方点位记录分页")
@PreAuthorize("@ss.hasPermission('iot:recipe-point-record:query')")
public CommonResult<PageResult<RecipePointRecordRespVO>> getRecipePointRecordPage(@Valid RecipePointRecordPageReqVO pageReqVO) {
PageResult<RecipePointRecordDO> pageResult = recipePointRecordService.getRecipePointRecordPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, RecipePointRecordRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出IoT配方点位记录 Excel")
@PreAuthorize("@ss.hasPermission('iot:recipe-point-record:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportRecipePointRecordExcel(@Valid RecipePointRecordPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<RecipePointRecordDO> list = recipePointRecordService.getRecipePointRecordPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "IoT配方点位记录.xls", "数据", RecipePointRecordRespVO.class,
BeanUtils.toBean(list, RecipePointRecordRespVO.class));
}
}

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.iot.controller.admin.recipepointrecord.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import java.math.BigDecimal;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - IoT配方点位记录分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class RecipePointRecordPageReqVO extends PageParam {
@Schema(description = "配方ID", example = "3078")
private Long recipeId;
@Schema(description = "名字", example = "张三")
private String name;
@Schema(description = "最大值")
private BigDecimal max;
@Schema(description = "最小值")
private BigDecimal min;
@Schema(description = "数据类型", example = "2")
private String dataType;
@Schema(description = "单位")
private String dataUnit;
@Schema(description = "备注", example = "你说的对")
private String remark;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "参考值")
private BigDecimal refer;
}

@ -0,0 +1,56 @@
package cn.iocoder.yudao.module.iot.controller.admin.recipepointrecord.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - IoT配方点位记录 Response VO")
@Data
@ExcelIgnoreUnannotated
public class RecipePointRecordRespVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19126")
@ExcelProperty("id")
private Long id;
@Schema(description = "配方ID", example = "3078")
@ExcelProperty("配方ID")
private Long recipeId;
@Schema(description = "名字", example = "张三")
@ExcelProperty("名字")
private String name;
@Schema(description = "最大值")
@ExcelProperty("最大值")
private BigDecimal max;
@Schema(description = "最小值")
@ExcelProperty("最小值")
private BigDecimal min;
@Schema(description = "数据类型", example = "2")
@ExcelProperty("数据类型")
private String dataType;
@Schema(description = "单位")
@ExcelProperty("单位")
private String dataUnit;
@Schema(description = "备注", example = "你说的对")
@ExcelProperty("备注")
private String remark;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "参考值")
@ExcelProperty("参考值")
private BigDecimal refer;
}

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.iot.controller.admin.recipepointrecord.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
import java.math.BigDecimal;
@Schema(description = "管理后台 - IoT配方点位记录新增/修改 Request VO")
@Data
public class RecipePointRecordSaveReqVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19126")
private Long id;
@Schema(description = "配方ID", example = "3078")
private Long recipeId;
@Schema(description = "名字", example = "张三")
private String name;
@Schema(description = "最大值")
private BigDecimal max;
@Schema(description = "最小值")
private BigDecimal min;
@Schema(description = "数据类型", example = "2")
private String dataType;
@Schema(description = "单位")
private String dataUnit;
@Schema(description = "备注", example = "你说的对")
private String remark;
@Schema(description = "参考值")
private BigDecimal refer;
}

@ -0,0 +1,71 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.recipedevicerecord;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* DO
*
* @author
*/
@TableName("iot_recipe_device_record")
@KeySequence("iot_recipe_device_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RecipeDeviceRecordDO extends BaseDO {
/**
* id
*/
@TableId
private Long id;
/**
*
*/
private String attributeCode;
/**
*
*/
private String attributeName;
/**
*
*/
private String attributeType;
/**
*
*/
private String dataType;
/**
*
*/
private String address;
/**
*
*/
private String dataUnit;
/**
*
*/
private Double ratio;
/**
*
*/
private String remark;
/**
* id
*/
private Long deviceId;
/**
*
*/
private Double value;
}

@ -1,21 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.recipeplandetail;
import lombok.Data;
import java.time.LocalDateTime;
/**
* DO
*/
@Data
public class RecipePlanDetailWithRelationsDO {
private Long id;
private String code;
private String name;
private Long recipeId;
private String recipeName; // 来自iot_recipe表
private Long planId;
private String planCode; // 来自mes_plan表
private String source;
private Boolean isEnable;
private LocalDateTime createTime;
}

@ -57,5 +57,9 @@ public class RecipePointDO extends BaseDO {
*
*/
private String remark;
/**
*
*/
private BigDecimal refer;
}

@ -0,0 +1,66 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.recipepointrecord;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* IoT DO
*
* @author
*/
@TableName("iot_recipe_point_record")
@KeySequence("iot_recipe_point_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RecipePointRecordDO extends BaseDO {
/**
* id
*/
@TableId
private Long id;
/**
* ID
*/
private Long recipeId;
/**
*
*/
private String name;
/**
*
*/
private BigDecimal max;
/**
*
*/
private BigDecimal min;
/**
*
*/
private String dataType;
/**
*
*/
private String dataUnit;
/**
*
*/
private String remark;
/**
*
*/
private BigDecimal refer;
}

@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.devicemodelattribute.DeviceMod
import cn.iocoder.yudao.module.iot.dal.devicecontactmodel.DeviceContactModelDO;
import com.alibaba.excel.util.StringUtils;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import cn.iocoder.yudao.module.iot.controller.admin.devicecontactmodel.vo.*;
/**
@ -63,4 +64,12 @@ public interface DeviceContactModelMapper extends BaseMapperX<DeviceContactModel
return deviceContactModelDOPageResult;
}
/**
* ID
* @param id ID
* @return attribute_namedata_unitMap
*/
Map<String, String> selectAttributeNameAndUnitById(@Param("id") Long id);
}

@ -73,7 +73,7 @@ public interface RecipeDeviceAttributeMapper extends BaseMapperX<RecipeDeviceAtt
// 修复后关联分页查询符合MyBatis-Plus分页规范
@Select({
"<script>",
"SELECT rda.id, rda.attribute_id, dcm.attribute_name, dcm.attribute_type, dcm.data_type, dcm.data_unit",
"SELECT rda.id, rda.attribute_id, dcm.attribute_name, dcm.attribute_type, dcm.data_type, dcm.data_unit, dcm.address",
"FROM iot_recipe_device_attribute rda",
"LEFT JOIN iot_device_contact_model dcm ON rda.attribute_id = dcm.id",
"WHERE 1=1",
@ -98,4 +98,16 @@ public interface RecipeDeviceAttributeMapper extends BaseMapperX<RecipeDeviceAtt
return new PageResult<>(list, page.getTotal());
}
/**
* ID
* @param recipeId ID
* @return
*/
List<RecipeDeviceAttributeDO> selectByRecipeId(@Param("recipeId") Long recipeId);
// 分页关联查询
PageResult<RecipeDeviceAttributePageRespDTO> selectPageWithAttribute(RecipeDeviceAttributePageReqVO reqVO);
// 根据RecipeId删除
int deleteByRecipeId(@Param("recipeId") Long recipeId);
}

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.iot.dal.mysql.recipedevicerecord;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.recipedevicerecord.RecipeDeviceRecordDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.iot.controller.admin.recipedevicerecord.vo.*;
/**
* Mapper
*
* @author
*/
@Mapper
public interface RecipeDeviceRecordMapper extends BaseMapperX<RecipeDeviceRecordDO> {
default PageResult<RecipeDeviceRecordDO> selectPage(RecipeDeviceRecordPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<RecipeDeviceRecordDO>()
.eqIfPresent(RecipeDeviceRecordDO::getAttributeCode, reqVO.getAttributeCode())
.likeIfPresent(RecipeDeviceRecordDO::getAttributeName, reqVO.getAttributeName())
.eqIfPresent(RecipeDeviceRecordDO::getAttributeType, reqVO.getAttributeType())
.eqIfPresent(RecipeDeviceRecordDO::getDataType, reqVO.getDataType())
.eqIfPresent(RecipeDeviceRecordDO::getAddress, reqVO.getAddress())
.eqIfPresent(RecipeDeviceRecordDO::getDataUnit, reqVO.getDataUnit())
.eqIfPresent(RecipeDeviceRecordDO::getRatio, reqVO.getRatio())
.eqIfPresent(RecipeDeviceRecordDO::getRemark, reqVO.getRemark())
.eqIfPresent(RecipeDeviceRecordDO::getDeviceId, reqVO.getDeviceId())
.betweenIfPresent(RecipeDeviceRecordDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(RecipeDeviceRecordDO::getValue, reqVO.getValue())
.orderByDesc(RecipeDeviceRecordDO::getId));
}
}

@ -5,9 +5,14 @@ import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipeplandetail.RecipePlanDetailDO;
import cn.iocoder.yudao.module.iot.controller.admin.recipeplandetail.vo.RecipePlanDetailPageRespDTO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.iot.controller.admin.recipeplandetail.vo.*;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* Mapper
@ -28,8 +33,49 @@ public interface RecipePlanDetailMapper extends BaseMapperX<RecipePlanDetailDO>
.betweenIfPresent(RecipePlanDetailDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(RecipePlanDetailDO::getId));
}
// 核心:联表分页查询(包含配方名称、计划编码)
@Select({
"<script>",
"SELECT rpd.*, ",
" r.name AS recipeName, ", // 关联iot_recipe表的名称
" p.code AS planCode, ", // 关联mes_plan表的编码
" d.id AS deviceId ", // 新增关联iot_device表的id作为deviceId
"FROM iot_recipe_plan_detail rpd",
"LEFT JOIN iot_recipe r ON rpd.recipe_id = r.id ", // 左关联配方表避免配方ID不存在时数据丢失
"LEFT JOIN mes_plan p ON rpd.plan_id = p.id ", // 左关联计划表
"LEFT JOIN iot_device d ON r.machine_name = d.device_name ", // 新增左关联设备表通过machine_name匹配device_name
"WHERE rpd.deleted = 0 ", // 过滤已删除数据
"<if test='reqVO.code != null and reqVO.code != \"\"'>",
" AND rpd.code LIKE CONCAT('%', #{reqVO.code}, '%')",
"</if>",
"<if test='reqVO.name != null and reqVO.name != \"\"'>",
" AND rpd.name LIKE CONCAT('%', #{reqVO.name}, '%')",
"</if>",
"<if test='reqVO.recipeId != null'>",
" AND rpd.recipe_id = #{reqVO.recipeId}",
"</if>",
"<if test='reqVO.planId != null'>",
" AND rpd.plan_id = #{reqVO.planId}",
"</if>",
"<if test='reqVO.source != null and reqVO.source != \"\"'>",
" AND rpd.source = #{reqVO.source}",
"</if>",
"<if test='reqVO.isEnable != null'>",
" AND rpd.is_enable = #{reqVO.isEnable}",
"</if>",
"ORDER BY rpd.id DESC",
"</script>"
})
List<RecipePlanDetailPageRespDTO> selectPageWithRelations(
Page<RecipePlanDetailPageRespDTO> page, // MyBatis-Plus分页插件自动填充页码/页大小
@Param("reqVO") RecipePlanDetailPageReqVO reqVO);
// 封装成芋道框架的PageResult复用框架分页逻辑
default PageResult<RecipePlanDetailPageRespDTO> selectPageWithRelationsWrap(RecipePlanDetailPageReqVO reqVO) {
Page<RecipePlanDetailPageRespDTO> page = new Page<>(reqVO.getPageNo(), reqVO.getPageSize());
List<RecipePlanDetailPageRespDTO> list = selectPageWithRelations(page, reqVO);
return new PageResult<>(list, page.getTotal());
}
// 新增关联查询分页方法
// PageResult<RecipePlanDetailWithRelationsDO> selectPageWithRelations(@Param("req") RecipePlanDetailPageReqVO reqVO);
}

@ -27,6 +27,7 @@ public interface RecipePointMapper extends BaseMapperX<RecipePointDO> {
.eqIfPresent(RecipePointDO::getDataUnit, reqVO.getDataUnit())
.eqIfPresent(RecipePointDO::getRemark, reqVO.getRemark())
.betweenIfPresent(RecipePointDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(RecipePointDO::getRefer, reqVO.getRefer())
.orderByDesc(RecipePointDO::getId));
}

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.iot.dal.mysql.recipepointrecord;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.recipepointrecord.RecipePointRecordDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.iot.controller.admin.recipepointrecord.vo.*;
/**
* IoT Mapper
*
* @author
*/
@Mapper
public interface RecipePointRecordMapper extends BaseMapperX<RecipePointRecordDO> {
default PageResult<RecipePointRecordDO> selectPage(RecipePointRecordPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<RecipePointRecordDO>()
.eqIfPresent(RecipePointRecordDO::getRecipeId, reqVO.getRecipeId())
.likeIfPresent(RecipePointRecordDO::getName, reqVO.getName())
.eqIfPresent(RecipePointRecordDO::getMax, reqVO.getMax())
.eqIfPresent(RecipePointRecordDO::getMin, reqVO.getMin())
.eqIfPresent(RecipePointRecordDO::getDataType, reqVO.getDataType())
.eqIfPresent(RecipePointRecordDO::getDataUnit, reqVO.getDataUnit())
.eqIfPresent(RecipePointRecordDO::getRemark, reqVO.getRemark())
.betweenIfPresent(RecipePointRecordDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(RecipePointRecordDO::getRefer, reqVO.getRefer())
.orderByDesc(RecipePointRecordDO::getId));
}
}

@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.recipedeviceattribute.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipedeviceattribute.RecipeDeviceAttributeDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import com.fasterxml.jackson.core.JsonProcessingException;
/**
* - Service
@ -54,11 +55,33 @@ public interface RecipeDeviceAttributeService {
Boolean createRecipeDeviceAttributeBatch(RecipeDeviceAttributeSaveReqVO createReqVO);
PageResult<RecipeDeviceAttributePageRespDTO> selectPageWithAttribute(RecipeDeviceAttributePageReqVO reqVO);
Boolean updateRecipeDeviceAttribute(RecipeDeviceAttributeUpdateReqVO reqVO);
// public List<Map<String, Object>> operationAnalysisDetails(Long deviceId, String collectionStartTime, String collectionEndTime);
Map<String, List<Map<String, Object>>> singleDevice(Long deviceId) throws JsonProcessingException;
// ========== 扩展方法(需实现) ==========
/**
* ID
* @param recipeId ID
* @return
*/
List<RecipeDeviceAttributeDO> getByRecipeId(Long recipeId);
/**
* ID
* @param attributeId ID
* @return attributeNamedataUnitMap
*/
Map<String, String> getDeviceContactModelAttr(Long attributeId);
/**
*
* @param reqVO
* @return
*/
PageResult<RecipeDeviceAttributePageRespDTO> selectPageWithAttribute(RecipeDeviceAttributePageReqVO reqVO);
}

@ -1,5 +1,11 @@
package cn.iocoder.yudao.module.iot.service.recipedeviceattribute;
import cn.iocoder.yudao.module.iot.dal.dataobject.deviceattributetype.DeviceAttributeTypeDO;
import cn.iocoder.yudao.module.iot.service.device.TDengineService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@ -7,6 +13,8 @@ import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import cn.iocoder.yudao.module.iot.controller.admin.recipedeviceattribute.vo.*;
@ -43,10 +51,12 @@ public class RecipeDeviceAttributeServiceImpl implements RecipeDeviceAttributeSe
@Resource
private RecipeDeviceAttributeMapper recipeDeviceAttributeMapper;
@Resource
private TDengineService tdengineService;
// @Override
// @Override
// public Long createRecipeDeviceAttribute(RecipeDeviceAttributeSaveReqVO createReqVO) {
// // 插入
// RecipeDeviceAttributeDO recipeDeviceAttribute = BeanUtils.toBean(createReqVO, RecipeDeviceAttributeDO.class);
@ -80,7 +90,7 @@ public class RecipeDeviceAttributeServiceImpl implements RecipeDeviceAttributeSe
return insertSuccess;
}
// @Override
// @Override
// public void updateRecipeDeviceAttribute(RecipeDeviceAttributeSaveReqVO updateReqVO) {
// // 校验存在
// validateRecipeDeviceAttributeExists(updateReqVO.getId());
@ -88,38 +98,38 @@ public class RecipeDeviceAttributeServiceImpl implements RecipeDeviceAttributeSe
// RecipeDeviceAttributeDO updateObj = BeanUtils.toBean(updateReqVO, RecipeDeviceAttributeDO.class);
// recipeDeviceAttributeMapper.updateById(updateObj);
// }
@Override
@Transactional(rollbackFor = Exception.class) // 事务保证原子性
public Boolean updateRecipeDeviceAttribute(RecipeDeviceAttributeUpdateReqVO reqVO) {
// 1. 非空校验recipeId不能为空和create保持一致的校验风格
if (reqVO.getRecipeId() == null) {
throw new IllegalArgumentException("更新失败配方IDrecipeId不能为空");
}
@Override
@Transactional(rollbackFor = Exception.class) // 事务保证原子性
public Boolean updateRecipeDeviceAttribute(RecipeDeviceAttributeUpdateReqVO reqVO) {
// 1. 非空校验recipeId不能为空和create保持一致的校验风格
if (reqVO.getRecipeId() == null) {
throw new IllegalArgumentException("更新失败配方IDrecipeId不能为空");
}
// 步骤1删除该recipeId下的所有旧记录
LambdaQueryWrapper<RecipeDeviceAttributeDO> deleteWrapper = new LambdaQueryWrapper<>();
deleteWrapper.eq(RecipeDeviceAttributeDO::getRecipeId, reqVO.getRecipeId());
recipeDeviceAttributeMapper.delete(deleteWrapper);
// 步骤1删除该recipeId下的所有旧记录
LambdaQueryWrapper<RecipeDeviceAttributeDO> deleteWrapper = new LambdaQueryWrapper<>();
deleteWrapper.eq(RecipeDeviceAttributeDO::getRecipeId, reqVO.getRecipeId());
recipeDeviceAttributeMapper.delete(deleteWrapper);
// 步骤2如果ids不为空批量创建新记录复用create的Bean拷贝+流式处理风格)
Boolean insertSuccess = true; // 默认成功无ids时直接返回成功
if (!CollectionUtils.isEmpty(reqVO.getIds())) {
List<RecipeDeviceAttributeDO> attributeList = reqVO.getIds().stream()
.map(attributeId -> {
// 复用create的Bean拷贝逻辑保持代码风格一致
RecipeDeviceAttributeDO attributeDO = BeanUtils.toBean(reqVO, RecipeDeviceAttributeDO.class);
attributeDO.setAttributeId(attributeId);
return attributeDO;
})
.collect(Collectors.toList());
// 步骤2如果ids不为空批量创建新记录复用create的Bean拷贝+流式处理风格)
Boolean insertSuccess = true; // 默认成功无ids时直接返回成功
if (!CollectionUtils.isEmpty(reqVO.getIds())) {
List<RecipeDeviceAttributeDO> attributeList = reqVO.getIds().stream()
.map(attributeId -> {
// 复用create的Bean拷贝逻辑保持代码风格一致
RecipeDeviceAttributeDO attributeDO = BeanUtils.toBean(reqVO, RecipeDeviceAttributeDO.class);
attributeDO.setAttributeId(attributeId);
return attributeDO;
})
.collect(Collectors.toList());
// 复用create的批量插入逻辑返回插入结果
insertSuccess = recipeDeviceAttributeMapper.insertBatch(attributeList);
}
// 复用create的批量插入逻辑返回插入结果
insertSuccess = recipeDeviceAttributeMapper.insertBatch(attributeList);
}
// 返回最终结果(删除必成功,插入结果决定最终返回值)
return insertSuccess;
}
// 返回最终结果(删除必成功,插入结果决定最终返回值)
return insertSuccess;
}
@Override
public void deleteRecipeDeviceAttribute(Long id) {
@ -150,4 +160,157 @@ public Boolean updateRecipeDeviceAttribute(RecipeDeviceAttributeUpdateReqVO reqV
return recipeDeviceAttributeMapper.selectPageWithAttributeWrap(reqVO);
}
}
// @Override
// public List<Map<String, Object>> operationAnalysisDetails(Long deviceId, String collectionStartTime, String collectionEndTime) {
// // 1. 入参校验仅校验deviceId
// if (deviceId == null) {
// throw exception(DEVICE_ID_DOES_NOT_EXIST);
// }
//
// List<Map<String, Object>> resultList = new ArrayList<>();
//
// try {
// // 2. 获取设备数据列表(按时间倒序)
// List<Map<String, Object>> deviceDataList = tdengineService.getstDeviceDataOrderByTimeDesc(
// deviceId, collectionStartTime, collectionEndTime);
//
// // 3. 遍历每个时间点的数据
// for (Map<String, Object> deviceData : deviceDataList) {
// String queryDataJson = (String) deviceData.get("queryData");
// Timestamp timestamp = (Timestamp) deviceData.get("timestamp");
//
// // 时间格式化(保持原有格式)
// SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
// String formattedTime = sdf.format(timestamp);
//
// // 仅处理有效数据JSON非空 + 时间戳非空)
// if (StringUtils.isNotBlank(queryDataJson) && timestamp != null) {
// // 解析JSON为结构化数据
// List<Map<String, Object>> dataList = new ObjectMapper().readValue(
// queryDataJson,
// new TypeReference<List<Map<String, Object>>>() {}
// );
//
// // 按属性类型分组保留LinkedHashMap保证顺序
// Map<String, List<Map<String, Object>>> groupedData = new LinkedHashMap<>();
// for (Map<String, Object> data : dataList) {
// // 移除modelId过滤逻辑处理所有数据
// String attributeTypeName = "其他";
// String typeStr = (String) data.get("attributeType");
// if (typeStr != null) {
// try {
// attributeTypeName = typeStr;
// } catch (Exception e) {
// attributeTypeName = "未知";
// }
// }
//
// // 简化数据结构(仅保留核心字段)
// Map<String, Object> simplifiedData = new HashMap<>();
// simplifiedData.put("addressValue", data.get("addressValue"));
// simplifiedData.put("attributeName", data.get("attributeName"));
//
// // 按属性类型分组存储
// groupedData.computeIfAbsent(attributeTypeName, k -> new ArrayList<>()).add(simplifiedData);
// }
//
// // 构建当前时间点的最终数据
// Map<String, Object> timePointData = new LinkedHashMap<>();
// // 添加分组后的属性数据
// for (Map.Entry<String, List<Map<String, Object>>> entry : groupedData.entrySet()) {
// timePointData.put(entry.getKey(), entry.getValue());
// }
// // 添加格式化的采集时间
// timePointData.put("collectTime", formattedTime);
//
// resultList.add(timePointData);
// }
// }
// } catch (Exception e) {
// throw new RuntimeException("处理设备数据时发生异常", e);
// }
//
// return resultList;
// }
@Override
public Map<String, List<Map<String, Object>>> singleDevice(Long deviceId) throws JsonProcessingException {
Map<String, List<Map<String, Object>>> resultMap = new LinkedHashMap<>();
try {
// 1. 获取设备数据列表
List<Map<String, Object>> deviceDataList = tdengineService.getNewestDeviceDataOrderByTimeDesc(deviceId);
// 3. 遍历并处理
for (Map<String, Object> deviceData : deviceDataList) {
String queryDataJson = (String) deviceData.get("queryData");
if (StringUtils.isNotBlank(queryDataJson)) {
// 使用TypeReference解析为List<Map>而不是具体的DO对象
List<Map<String, Object>> dataList = new ObjectMapper().readValue(
queryDataJson,
new TypeReference<List<Map<String, Object>>>() {}
);
for (Map<String, Object> data : dataList) {
// 获取属性类型名称
String attributeTypeName = "其他";
String typeStr = (String) data.get("attributeType");
if (typeStr != null) {
try {
attributeTypeName = typeStr;
} catch (Exception e) {
attributeTypeName = "未知";
}
}
// 提取需要的字段
Map<String, Object> simplifiedData = new HashMap<>();
simplifiedData.put("addressValue", data.get("addressValue"));
simplifiedData.put("attributeName", data.get("attributeName"));
resultMap
.computeIfAbsent(attributeTypeName, k -> new ArrayList<>())
.add(simplifiedData);
}
}
}
} catch (Exception e) {
System.out.println("处理设备数据时发生异常: " + e.getMessage());
}
return resultMap;
}
@Override
public List<RecipeDeviceAttributeDO> getByRecipeId(Long recipeId) {
if (recipeId == null) {
return Collections.emptyList();
}
return recipeDeviceAttributeMapper.selectByRecipeId(recipeId);
}
@Override
public Map<String, String> getDeviceContactModelAttr(Long attributeId) {
Map<String, String> resultMap = new HashMap<>(2);
if (attributeId == null) {
resultMap.put("attributeName", "");
resultMap.put("dataUnit", "");
return resultMap;
}
// 查询设备触点模型记录
// Map<String, String> modelMap = deviceContactModelMapper.selectAttributeNameAndUnitById(attributeId);
// if (modelMap == null) {
// resultMap.put("attributeName", "");
// resultMap.put("dataUnit", "");
// return resultMap;
// }
// // 封装返回结果
// resultMap.put("attributeName", modelMap.getOrDefault("attribute_name", ""));
// resultMap.put("dataUnit", modelMap.getOrDefault("data_unit", ""));
return resultMap;
}
}

@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.iot.service.recipedevicerecord;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.module.iot.controller.admin.recipedevicerecord.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipedevicerecord.RecipeDeviceRecordDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* Service
*
* @author
*/
public interface RecipeDeviceRecordService {
/**
*
*
* @param createReqVO
* @return
*/
Long createRecipeDeviceRecord(@Valid RecipeDeviceRecordSaveReqVO createReqVO);
/**
*
*
* @param updateReqVO
*/
void updateRecipeDeviceRecord(@Valid RecipeDeviceRecordSaveReqVO updateReqVO);
/**
*
*
* @param id
*/
void deleteRecipeDeviceRecord(Long id);
/**
*
*
* @param id
* @return
*/
RecipeDeviceRecordDO getRecipeDeviceRecord(Long id);
/**
*
*
* @param pageReqVO
* @return
*/
PageResult<RecipeDeviceRecordDO> getRecipeDeviceRecordPage(RecipeDeviceRecordPageReqVO pageReqVO);
}

@ -0,0 +1,74 @@
package cn.iocoder.yudao.module.iot.service.recipedevicerecord;
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.recipedevicerecord.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipedevicerecord.RecipeDeviceRecordDO;
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.recipedevicerecord.RecipeDeviceRecordMapper;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
/**
* Service
*
* @author
*/
@Service
@Validated
public class RecipeDeviceRecordServiceImpl implements RecipeDeviceRecordService {
@Resource
private RecipeDeviceRecordMapper recipeDeviceRecordMapper;
@Override
public Long createRecipeDeviceRecord(RecipeDeviceRecordSaveReqVO createReqVO) {
// 插入
RecipeDeviceRecordDO recipeDeviceRecord = BeanUtils.toBean(createReqVO, RecipeDeviceRecordDO.class);
recipeDeviceRecordMapper.insert(recipeDeviceRecord);
// 返回
return recipeDeviceRecord.getId();
}
@Override
public void updateRecipeDeviceRecord(RecipeDeviceRecordSaveReqVO updateReqVO) {
// 校验存在
validateRecipeDeviceRecordExists(updateReqVO.getId());
// 更新
RecipeDeviceRecordDO updateObj = BeanUtils.toBean(updateReqVO, RecipeDeviceRecordDO.class);
recipeDeviceRecordMapper.updateById(updateObj);
}
@Override
public void deleteRecipeDeviceRecord(Long id) {
// 校验存在
validateRecipeDeviceRecordExists(id);
// 删除
recipeDeviceRecordMapper.deleteById(id);
}
private void validateRecipeDeviceRecordExists(Long id) {
if (recipeDeviceRecordMapper.selectById(id) == null) {
throw exception(RECIPE_DEVICE_RECORD_NOT_EXISTS);
}
}
@Override
public RecipeDeviceRecordDO getRecipeDeviceRecord(Long id) {
return recipeDeviceRecordMapper.selectById(id);
}
@Override
public PageResult<RecipeDeviceRecordDO> getRecipeDeviceRecordPage(RecipeDeviceRecordPageReqVO pageReqVO) {
return recipeDeviceRecordMapper.selectPage(pageReqVO);
}
}

@ -1,11 +1,9 @@
package cn.iocoder.yudao.module.iot.service.recipeplandetail;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.module.iot.controller.admin.recipeplandetail.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipeplandetail.RecipePlanDetailDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* Service
@ -52,4 +50,6 @@ public interface RecipePlanDetailService {
*/
PageResult<RecipePlanDetailDO> getRecipePlanDetailPage(RecipePlanDetailPageReqVO pageReqVO);
PageResult<RecipePlanDetailPageRespDTO> pageRecipePlanDetail(RecipePlanDetailPageReqVO reqVO);
}

@ -3,13 +3,10 @@ package cn.iocoder.yudao.module.iot.service.recipeplandetail;
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.recipeplandetail.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipeplandetail.RecipePlanDetailDO;
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.recipeplandetail.RecipePlanDetailMapper;
@ -17,6 +14,7 @@ import cn.iocoder.yudao.module.iot.dal.mysql.recipeplandetail.RecipePlanDetailMa
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
/**
* Service
*
@ -71,4 +69,10 @@ public class RecipePlanDetailServiceImpl implements RecipePlanDetailService {
return recipePlanDetailMapper.selectPage(pageReqVO);
}
@Override
public PageResult<RecipePlanDetailPageRespDTO> pageRecipePlanDetail(RecipePlanDetailPageReqVO reqVO) {
// 直接调用Mapper的联表分页方法无需手动拼接关联字段
return recipePlanDetailMapper.selectPageWithRelationsWrap(reqVO);
}
}

@ -52,4 +52,6 @@ public interface RecipePointService {
*/
PageResult<RecipePointDO> getRecipePointPage(RecipePointPageReqVO pageReqVO);
}

@ -62,13 +62,17 @@ public class RecipePointServiceImpl implements RecipePointService {
}
@Override
public RecipePointDO getRecipePoint(Long id) {
return recipePointMapper.selectById(id);
public PageResult<RecipePointDO> getRecipePointPage(RecipePointPageReqVO pageReqVO) {
return recipePointMapper.selectPage(pageReqVO);
}
@Override
public PageResult<RecipePointDO> getRecipePointPage(RecipePointPageReqVO pageReqVO) {
return recipePointMapper.selectPage(pageReqVO);
public RecipePointDO getRecipePoint(Long id) {
if (id == null) {
return null;
}
return Optional.ofNullable(recipePointMapper.selectById(id))
.orElse(null);
}
}

@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.iot.service.recipepointrecord;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.module.iot.controller.admin.recipepointrecord.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipepointrecord.RecipePointRecordDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* IoT Service
*
* @author
*/
public interface RecipePointRecordService {
/**
* IoT
*
* @param createReqVO
* @return
*/
Long createRecipePointRecord(@Valid RecipePointRecordSaveReqVO createReqVO);
/**
* IoT
*
* @param updateReqVO
*/
void updateRecipePointRecord(@Valid RecipePointRecordSaveReqVO updateReqVO);
/**
* IoT
*
* @param id
*/
void deleteRecipePointRecord(Long id);
/**
* IoT
*
* @param id
* @return IoT
*/
RecipePointRecordDO getRecipePointRecord(Long id);
/**
* IoT
*
* @param pageReqVO
* @return IoT
*/
PageResult<RecipePointRecordDO> getRecipePointRecordPage(RecipePointRecordPageReqVO pageReqVO);
}

@ -0,0 +1,74 @@
package cn.iocoder.yudao.module.iot.service.recipepointrecord;
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.recipepointrecord.vo.*;
import cn.iocoder.yudao.module.iot.dal.dataobject.recipepointrecord.RecipePointRecordDO;
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.recipepointrecord.RecipePointRecordMapper;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
/**
* IoT Service
*
* @author
*/
@Service
@Validated
public class RecipePointRecordServiceImpl implements RecipePointRecordService {
@Resource
private RecipePointRecordMapper recipePointRecordMapper;
@Override
public Long createRecipePointRecord(RecipePointRecordSaveReqVO createReqVO) {
// 插入
RecipePointRecordDO recipePointRecord = BeanUtils.toBean(createReqVO, RecipePointRecordDO.class);
recipePointRecordMapper.insert(recipePointRecord);
// 返回
return recipePointRecord.getId();
}
@Override
public void updateRecipePointRecord(RecipePointRecordSaveReqVO updateReqVO) {
// 校验存在
validateRecipePointRecordExists(updateReqVO.getId());
// 更新
RecipePointRecordDO updateObj = BeanUtils.toBean(updateReqVO, RecipePointRecordDO.class);
recipePointRecordMapper.updateById(updateObj);
}
@Override
public void deleteRecipePointRecord(Long id) {
// 校验存在
validateRecipePointRecordExists(id);
// 删除
recipePointRecordMapper.deleteById(id);
}
private void validateRecipePointRecordExists(Long id) {
if (recipePointRecordMapper.selectById(id) == null) {
throw exception(RECIPE_POINT_RECORD_NOT_EXISTS);
}
}
@Override
public RecipePointRecordDO getRecipePointRecord(Long id) {
return recipePointRecordMapper.selectById(id);
}
@Override
public PageResult<RecipePointRecordDO> getRecipePointRecordPage(RecipePointRecordPageReqVO pageReqVO) {
return recipePointRecordMapper.selectPage(pageReqVO);
}
}

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.iot.dal.mysql.devicecontactmodel.DeviceContactModelMapper">
<select id="selectAttributeNameAndUnitById" resultType="java.util.Map">
SELECT attribute_name, data_unit
FROM iot_device_contact_model
WHERE id = #{id}
</select>
</mapper>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.iot.dal.mysql.recipedevicerecord.RecipeDeviceRecordMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.iot.dal.mysql.recipepointrecord.RecipePointRecordMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>
Loading…
Cancel
Save