diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 4a1d273a87..6ad5e4bbe9 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -9,7 +9,6 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; */ public interface ErrorCodeConstants { - // ========== GoView 模块 1-003-000-000 ========== ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_003_000_000, "设备不存在"); ErrorCode DEVICE_ATTRIBUTE_NOT_EXISTS = new ErrorCode(1_003_000_000, "设备属性不存在"); ErrorCode FORMULA_NOT_EXISTS = new ErrorCode(1_003_000_000, "公式不存在"); @@ -29,4 +28,6 @@ public interface ErrorCodeConstants { ErrorCode FEEDBACK_NOT_EXISTS = new ErrorCode(1_003_000_001, "用户反馈不存在"); ErrorCode MQTT_DATA_RECORD_NOT_EXISTS = new ErrorCode(1_003_000_003, "设备数据记录不存在"); + ErrorCode ALERT_NOT_EXISTS = new ErrorCode(1_003_000_003, "告警配置不存在"); + ErrorCode ALERT_RECORD_NOT_EXISTS = new ErrorCode(1_003_000_003, "告警记录不存在"); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/AlertController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/AlertController.java new file mode 100644 index 0000000000..95b9068865 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/AlertController.java @@ -0,0 +1,139 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert; + +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.alert.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.AlertDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alertrecord.AlertRecordDO; +import cn.iocoder.yudao.module.iot.service.alert.AlertService; + +@Tag(name = "管理后台 - 告警配置") +@RestController +@RequestMapping("/iot/alert") +@Validated +public class AlertController { + + @Resource + private AlertService alertService; + + @PostMapping("/create") + @Operation(summary = "创建告警配置") + @PreAuthorize("@ss.hasPermission('iot:alert:create')") + public CommonResult createAlert(@Valid @RequestBody AlertSaveReqVO createReqVO) { + return success(alertService.createAlert(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新告警配置") + @PreAuthorize("@ss.hasPermission('iot:alert:update')") + public CommonResult updateAlert(@Valid @RequestBody AlertSaveReqVO updateReqVO) { + alertService.updateAlert(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除告警配置") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:alert:delete')") + public CommonResult deleteAlert(@RequestParam("id") Long id) { + alertService.deleteAlert(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得告警配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:alert:query')") + public CommonResult getAlert(@RequestParam("id") Long id) { + AlertDO alert = alertService.getAlert(id); + return success(BeanUtils.toBean(alert, AlertRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得告警配置分页") + @PreAuthorize("@ss.hasPermission('iot:alert:query')") + public CommonResult> getAlertPage(@Valid AlertPageReqVO pageReqVO) { + PageResult pageResult = alertService.getAlertPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, AlertRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出告警配置 Excel") + @PreAuthorize("@ss.hasPermission('iot:alert:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportAlertExcel(@Valid AlertPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = alertService.getAlertPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "告警配置.xls", "数据", AlertRespVO.class, + BeanUtils.toBean(list, AlertRespVO.class)); + } + + // ==================== 子表(告警记录) ==================== + + @GetMapping("/alert-record/page") + @Operation(summary = "获得告警记录分页") + @Parameter(name = "alertId", description = "告警ID") + @PreAuthorize("@ss.hasPermission('iot:alert:query')") + public CommonResult> getAlertRecordPage(PageParam pageReqVO, + @RequestParam("alertId") Long alertId) { + return success(alertService.getAlertRecordPage(pageReqVO, alertId)); + } + + @PostMapping("/alert-record/create") + @Operation(summary = "创建告警记录") + @PreAuthorize("@ss.hasPermission('iot:alert:create')") + public CommonResult createAlertRecord(@Valid @RequestBody AlertRecordDO alertRecord) { + return success(alertService.createAlertRecord(alertRecord)); + } + + @PutMapping("/alert-record/update") + @Operation(summary = "更新告警记录") + @PreAuthorize("@ss.hasPermission('iot:alert:update')") + public CommonResult updateAlertRecord(@Valid @RequestBody AlertRecordDO alertRecord) { + alertService.updateAlertRecord(alertRecord); + return success(true); + } + + @DeleteMapping("/alert-record/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除告警记录") + @PreAuthorize("@ss.hasPermission('iot:alert:delete')") + public CommonResult deleteAlertRecord(@RequestParam("id") Long id) { + alertService.deleteAlertRecord(id); + return success(true); + } + + @GetMapping("/alert-record/get") + @Operation(summary = "获得告警记录") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:alert:query')") + public CommonResult getAlertRecord(@RequestParam("id") Long id) { + return success(alertService.getAlertRecord(id)); + } + +} \ 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/alert/vo/AlertPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/AlertPageReqVO.java new file mode 100644 index 0000000000..ebd0c0e48c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/AlertPageReqVO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert.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 AlertPageReqVO extends PageParam { + + @Schema(description = "编码") + private String alertCode; + + @Schema(description = "名称", example = "李四") + private String alertName; + + @Schema(description = "告警类型", example = "2") + private String alertType; + + @Schema(description = "告警等级") + private String alertLevel; + + @Schema(description = "告警内容") + private String content; + + @Schema(description = "告警条件") + private String condition; + + @Schema(description = "逻辑表达式") + private String conditionFormula; + + @Schema(description = "告警音频") + private String alertAudio; + + @Schema(description = "重复告警") + private Boolean isRepeat; + + @Schema(description = "不重复间隔") + private Long noRepeatDuration; + + @Schema(description = "是否启用") + private Boolean isEnable; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ 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/alert/vo/AlertRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/AlertRespVO.java new file mode 100644 index 0000000000..298b9c72a5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/AlertRespVO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 告警配置 Response VO") +@Data +@ExcelIgnoreUnannotated +public class AlertRespVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "28840") + @ExcelProperty("ID") + private Long id; + + @Schema(description = "编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("编码") + private String alertCode; + + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("名称") + private String alertName; + + @Schema(description = "告警类型", example = "2") + @ExcelProperty(value = "告警类型", converter = DictConvert.class) + @DictFormat("iot_alert_type") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private String alertType; + + @Schema(description = "告警等级") + @ExcelProperty(value = "告警等级", converter = DictConvert.class) + @DictFormat("iot_alert_level") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private String alertLevel; + + @Schema(description = "告警内容") + @ExcelProperty("告警内容") + private String content; + + @Schema(description = "告警条件") + @ExcelProperty("告警条件") + private String condition; + + @Schema(description = "逻辑表达式") + @ExcelProperty("逻辑表达式") + private String conditionFormula; + + @Schema(description = "告警音频", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("告警音频") + private String alertAudio; + + @Schema(description = "重复告警", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty(value = "重复告警", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean isRepeat; + + @Schema(description = "不重复间隔", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("不重复间隔") + private Long noRepeatDuration; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty(value = "是否启用", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean isEnable; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ 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/alert/vo/AlertSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/AlertSaveReqVO.java new file mode 100644 index 0000000000..df0d72cc91 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/AlertSaveReqVO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.alertrecord.AlertRecordDO; + +@Schema(description = "管理后台 - 告警配置新增/修改 Request VO") +@Data +public class AlertSaveReqVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "28840") + private Long id; + + @Schema(description = "编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "编码不能为空") + private String alertCode; + + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @NotEmpty(message = "名称不能为空") + private String alertName; + + @Schema(description = "告警类型", example = "2") + private String alertType; + + @Schema(description = "告警等级") + private String alertLevel; + + @Schema(description = "告警内容") + private String content; + + @Schema(description = "告警条件") + private String condition; + + @Schema(description = "逻辑表达式") + private String conditionFormula; + + @Schema(description = "告警音频", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "告警音频不能为空") + private String alertAudio; + + @Schema(description = "重复告警", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "重复告警不能为空") + private Boolean isRepeat; + + @Schema(description = "不重复间隔", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "不重复间隔不能为空") + private Long noRepeatDuration; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "是否启用不能为空") + private Boolean isEnable; + +} \ 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/alertrecord/AlertRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alertrecord/AlertRecordController.java new file mode 100644 index 0000000000..84e420b267 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alertrecord/AlertRecordController.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alertrecord; + +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.alertrecord.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.alertrecord.AlertRecordDO; +import cn.iocoder.yudao.module.iot.service.alertrecord.AlertRecordService; + +@Tag(name = "管理后台 - 告警记录") +@RestController +@RequestMapping("/iot/alert-record") +@Validated +public class AlertRecordController { + + @Resource + private AlertRecordService alertRecordService; + + @PostMapping("/create") + @Operation(summary = "创建告警记录") + @PreAuthorize("@ss.hasPermission('iot:alert-record:create')") + public CommonResult createAlertRecord(@Valid @RequestBody AlertRecordSaveReqVO createReqVO) { + return success(alertRecordService.createAlertRecord(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新告警记录") + @PreAuthorize("@ss.hasPermission('iot:alert-record:update')") + public CommonResult updateAlertRecord(@Valid @RequestBody AlertRecordSaveReqVO updateReqVO) { + alertRecordService.updateAlertRecord(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除告警记录") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:alert-record:delete')") + public CommonResult deleteAlertRecord(@RequestParam("id") Long id) { + alertRecordService.deleteAlertRecord(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得告警记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:alert-record:query')") + public CommonResult getAlertRecord(@RequestParam("id") Long id) { + AlertRecordDO alertRecord = alertRecordService.getAlertRecord(id); + return success(BeanUtils.toBean(alertRecord, AlertRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得告警记录分页") + @PreAuthorize("@ss.hasPermission('iot:alert-record:query')") + public CommonResult> getAlertRecordPage(@Valid AlertRecordPageReqVO pageReqVO) { + PageResult pageResult = alertRecordService.getAlertRecordPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, AlertRecordRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出告警记录 Excel") + @PreAuthorize("@ss.hasPermission('iot:alert-record:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportAlertRecordExcel(@Valid AlertRecordPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = alertRecordService.getAlertRecordPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "告警记录.xls", "数据", AlertRecordRespVO.class, + BeanUtils.toBean(list, AlertRecordRespVO.class)); + } + +} \ 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/alertrecord/vo/AlertRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alertrecord/vo/AlertRecordPageReqVO.java new file mode 100644 index 0000000000..ffd83d16dc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alertrecord/vo/AlertRecordPageReqVO.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alertrecord.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 AlertRecordPageReqVO extends PageParam { + + @Schema(description = "编码") + private String alertCode; + + @Schema(description = "名称", example = "赵六") + private String alertName; + + @Schema(description = "告警类型", example = "2") + private String alertType; + + @Schema(description = "告警等级") + private String alertLevel; + + @Schema(description = "告警内容") + private String content; + + @Schema(description = "告警条件") + private String condition; + + @Schema(description = "逻辑表达式") + private String conditionFormula; + + @Schema(description = "数据值") + private String dataValue; + + @Schema(description = "数据类型", example = "1") + private String dataType; + + @Schema(description = "单位") + private String dataUnit; + + @Schema(description = "描述", example = "你说的对") + private String dataTypeRemark; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "告警ID", example = "16965") + private Long alertId; + + @Schema(description = "告警音频") + private String alertAudio; + + @Schema(description = "重复告警") + private Boolean isRepeat; + + @Schema(description = "不重复间隔") + private Long noRepeatDuration; + + @Schema(description = "来源ID", example = "19268") + private Long dataId; + + @Schema(description = "来源编码") + private String dataCode; + + @Schema(description = "来源名称", example = "芋艿") + private String dataName; + +} \ 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/alertrecord/vo/AlertRecordRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alertrecord/vo/AlertRecordRespVO.java new file mode 100644 index 0000000000..fa8b0c3a92 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alertrecord/vo/AlertRecordRespVO.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alertrecord.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 告警记录 Response VO") +@Data +@ExcelIgnoreUnannotated +public class AlertRecordRespVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "31176") + @ExcelProperty("ID") + private Long id; + + @Schema(description = "编码", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("编码") + private String alertCode; + + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @ExcelProperty("名称") + private String alertName; + + @Schema(description = "告警类型", example = "2") + @ExcelProperty(value = "告警类型", converter = DictConvert.class) + @DictFormat("iot_alert_type") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private String alertType; + + @Schema(description = "告警等级") + @ExcelProperty(value = "告警等级", converter = DictConvert.class) + @DictFormat("iot_alert_level") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private String alertLevel; + + @Schema(description = "告警内容") + @ExcelProperty("告警内容") + private String content; + + @Schema(description = "告警条件") + @ExcelProperty("告警条件") + private String condition; + + @Schema(description = "逻辑表达式") + @ExcelProperty("逻辑表达式") + private String conditionFormula; + + @Schema(description = "数据值") + @ExcelProperty("数据值") + private String dataValue; + + @Schema(description = "数据类型", example = "1") + @ExcelProperty(value = "数据类型", converter = DictConvert.class) + @DictFormat("iot_device_data_type") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private String dataType; + + @Schema(description = "单位") + @ExcelProperty("单位") + private String dataUnit; + + @Schema(description = "描述", example = "你说的对") + @ExcelProperty("描述") + private String dataTypeRemark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "告警ID", example = "16965") + @ExcelProperty("告警ID") + private Long alertId; + + @Schema(description = "告警音频") + @ExcelProperty("告警音频") + private String alertAudio; + + @Schema(description = "重复告警") + @ExcelProperty(value = "重复告警", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean isRepeat; + + @Schema(description = "不重复间隔") + @ExcelProperty("不重复间隔") + private Long noRepeatDuration; + + @Schema(description = "来源ID", example = "19268") + @ExcelProperty("来源ID") + private Long dataId; + + @Schema(description = "来源编码") + @ExcelProperty("来源编码") + private String dataCode; + + @Schema(description = "来源名称", example = "芋艿") + @ExcelProperty("来源名称") + private String dataName; + +} \ 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/alertrecord/vo/AlertRecordSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alertrecord/vo/AlertRecordSaveReqVO.java new file mode 100644 index 0000000000..d6a483abe8 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alertrecord/vo/AlertRecordSaveReqVO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alertrecord.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 AlertRecordSaveReqVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "31176") + private Long id; + + @Schema(description = "编码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "编码不能为空") + private String alertCode; + + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "名称不能为空") + private String alertName; + + @Schema(description = "告警类型", example = "2") + private String alertType; + + @Schema(description = "告警等级") + private String alertLevel; + + @Schema(description = "告警内容") + private String content; + + @Schema(description = "告警条件") + private String condition; + + @Schema(description = "逻辑表达式") + private String conditionFormula; + + @Schema(description = "数据值") + private String dataValue; + + @Schema(description = "数据类型", example = "1") + private String dataType; + + @Schema(description = "单位") + private String dataUnit; + + @Schema(description = "描述", example = "你说的对") + private String dataTypeRemark; + + @Schema(description = "告警ID", example = "16965") + private Long alertId; + + @Schema(description = "告警音频") + private String alertAudio; + + @Schema(description = "重复告警") + private Boolean isRepeat; + + @Schema(description = "不重复间隔") + private Long noRepeatDuration; + + @Schema(description = "来源ID", example = "19268") + private Long dataId; + + @Schema(description = "来源编码") + private String dataCode; + + @Schema(description = "来源名称", example = "芋艿") + private String dataName; + +} \ 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/device/DeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java new file mode 100644 index 0000000000..225926df56 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/DeviceController.java @@ -0,0 +1,139 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device; + +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.device.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.deviceattribute.DeviceAttributeDO; +import cn.iocoder.yudao.module.iot.service.device.DeviceService; + +@Tag(name = "管理后台 - 物联设备") +@RestController +@RequestMapping("/iot/device") +@Validated +public class DeviceController { + + @Resource + private DeviceService deviceService; + + @PostMapping("/create") + @Operation(summary = "创建物联设备") + @PreAuthorize("@ss.hasPermission('iot:device:create')") + public CommonResult createDevice(@Valid @RequestBody DeviceSaveReqVO createReqVO) { + return success(deviceService.createDevice(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新物联设备") + @PreAuthorize("@ss.hasPermission('iot:device:update')") + public CommonResult updateDevice(@Valid @RequestBody DeviceSaveReqVO updateReqVO) { + deviceService.updateDevice(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除物联设备") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:device:delete')") + public CommonResult deleteDevice(@RequestParam("id") Long id) { + deviceService.deleteDevice(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得物联设备") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:device:query')") + public CommonResult getDevice(@RequestParam("id") Long id) { + DeviceDO device = deviceService.getDevice(id); + return success(BeanUtils.toBean(device, DeviceRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得物联设备分页") + @PreAuthorize("@ss.hasPermission('iot:device:query')") + public CommonResult> getDevicePage(@Valid DevicePageReqVO pageReqVO) { + PageResult pageResult = deviceService.getDevicePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, DeviceRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出物联设备 Excel") + @PreAuthorize("@ss.hasPermission('iot:device:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDeviceExcel(@Valid DevicePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = deviceService.getDevicePage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "物联设备.xls", "数据", DeviceRespVO.class, + BeanUtils.toBean(list, DeviceRespVO.class)); + } + + // ==================== 子表(设备属性) ==================== + + @GetMapping("/device-attribute/page") + @Operation(summary = "获得设备属性分页") + @Parameter(name = "deviceId", description = "设备id") + @PreAuthorize("@ss.hasPermission('iot:device:query')") + public CommonResult> getDeviceAttributePage(PageParam pageReqVO, + @RequestParam("deviceId") Long deviceId) { + return success(deviceService.getDeviceAttributePage(pageReqVO, deviceId)); + } + + @PostMapping("/device-attribute/create") + @Operation(summary = "创建设备属性") + @PreAuthorize("@ss.hasPermission('iot:device:create')") + public CommonResult createDeviceAttribute(@Valid @RequestBody DeviceAttributeDO deviceAttribute) { + return success(deviceService.createDeviceAttribute(deviceAttribute)); + } + + @PutMapping("/device-attribute/update") + @Operation(summary = "更新设备属性") + @PreAuthorize("@ss.hasPermission('iot:device:update')") + public CommonResult updateDeviceAttribute(@Valid @RequestBody DeviceAttributeDO deviceAttribute) { + deviceService.updateDeviceAttribute(deviceAttribute); + return success(true); + } + + @DeleteMapping("/device-attribute/delete") + @Parameter(name = "id", description = "编号", required = true) + @Operation(summary = "删除设备属性") + @PreAuthorize("@ss.hasPermission('iot:device:delete')") + public CommonResult deleteDeviceAttribute(@RequestParam("id") Long id) { + deviceService.deleteDeviceAttribute(id); + return success(true); + } + + @GetMapping("/device-attribute/get") + @Operation(summary = "获得设备属性") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:device:query')") + public CommonResult getDeviceAttribute(@RequestParam("id") Long id) { + return success(deviceService.getDeviceAttribute(id)); + } + +} \ 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/device/vo/DevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DevicePageReqVO.java new file mode 100644 index 0000000000..418c1abc28 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DevicePageReqVO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.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 DevicePageReqVO extends PageParam { + + @Schema(description = "设备编号") + private String deviceCode; + + @Schema(description = "设备名称", example = "赵六") + private String deviceName; + + @Schema(description = "设备类型", example = "2") + private String deviceType; + + @Schema(description = "状态", example = "1") + private String status; + + @Schema(description = "读主题") + private String readTopic; + + @Schema(description = "写主题") + private String writeTopic; + + @Schema(description = "网关id", example = "16311") + private Long gatewayId; + + @Schema(description = "设备品牌id", example = "24731") + private Long deviceBrandId; + + @Schema(description = "离线间隔") + private Long offLineDuration; + + @Schema(description = "最后上线时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] lastOnlineTime; + + @Schema(description = "备注", example = "你说的对") + private String remark; + + @Schema(description = "是否启用") + private Boolean isEnable; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ 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/device/vo/DeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceRespVO.java new file mode 100644 index 0000000000..6c58c1eba9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceRespVO.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 物联设备 Response VO") +@Data +@ExcelIgnoreUnannotated +public class DeviceRespVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26404") + @ExcelProperty("ID") + private Long id; + + @Schema(description = "设备编号") + @ExcelProperty("设备编号") + private String deviceCode; + + @Schema(description = "设备名称", example = "赵六") + @ExcelProperty("设备名称") + private String deviceName; + + @Schema(description = "设备类型", example = "2") + @ExcelProperty(value = "设备类型", converter = DictConvert.class) + @DictFormat("iot_device_type") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private String deviceType; + + @Schema(description = "状态", example = "1") + @ExcelProperty(value = "状态", converter = DictConvert.class) + @DictFormat("iot_gateway_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private String status; + + @Schema(description = "读主题") + @ExcelProperty("读主题") + private String readTopic; + + @Schema(description = "写主题") + @ExcelProperty("写主题") + private String writeTopic; + + @Schema(description = "网关id", requiredMode = Schema.RequiredMode.REQUIRED, example = "16311") + @ExcelProperty("网关id") + private Long gatewayId; + + @Schema(description = "设备品牌id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24731") + @ExcelProperty("设备品牌id") + private Long deviceBrandId; + + @Schema(description = "离线间隔", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("离线间隔") + private Long offLineDuration; + + @Schema(description = "最后上线时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("最后上线时间") + private LocalDateTime lastOnlineTime; + + @Schema(description = "备注", example = "你说的对") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty(value = "是否启用", converter = DictConvert.class) + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Boolean isEnable; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ 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/device/vo/DeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceSaveReqVO.java new file mode 100644 index 0000000000..be31fb6233 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/DeviceSaveReqVO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import cn.iocoder.yudao.module.iot.dal.dataobject.deviceattribute.DeviceAttributeDO; + +@Schema(description = "管理后台 - 物联设备新增/修改 Request VO") +@Data +public class DeviceSaveReqVO { + + @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26404") + private Long id; + + @Schema(description = "设备编号") + private String deviceCode; + + @Schema(description = "设备名称", example = "赵六") + private String deviceName; + + @Schema(description = "设备类型", example = "2") + private String deviceType; + + @Schema(description = "状态", example = "1") + private String status; + + @Schema(description = "读主题") + private String readTopic; + + @Schema(description = "写主题") + private String writeTopic; + + @Schema(description = "网关id", requiredMode = Schema.RequiredMode.REQUIRED, example = "16311") + @NotNull(message = "网关id不能为空") + private Long gatewayId; + + @Schema(description = "设备品牌id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24731") + @NotNull(message = "设备品牌id不能为空") + private Long deviceBrandId; + + @Schema(description = "离线间隔", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "离线间隔不能为空") + private Long offLineDuration; + + @Schema(description = "最后上线时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "最后上线时间不能为空") + private LocalDateTime lastOnlineTime; + + @Schema(description = "备注", example = "你说的对") + private String remark; + + @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "是否启用不能为空") + private Boolean isEnable; + +} \ 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/dataobject/alert/AlertDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/AlertDO.java new file mode 100644 index 0000000000..78613b6bc4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/AlertDO.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.alert; + +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_alert") +@KeySequence("iot_alert_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AlertDO extends BaseDO { + + /** + * ID + */ + @TableId + private Long id; + /** + * 编码 + */ + private String alertCode; + /** + * 名称 + */ + private String alertName; + /** + * 告警类型 + * + * 枚举 {@link TODO iot_alert_type 对应的类} + */ + private String alertType; + /** + * 告警等级 + * + * 枚举 {@link TODO iot_alert_level 对应的类} + */ + private String alertLevel; + /** + * 告警内容 + */ + private String content; + /** + * 告警条件 + */ + private String condition; + /** + * 逻辑表达式 + */ + private String conditionFormula; + /** + * 告警音频 + */ + private String alertAudio; + /** + * 重复告警 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean isRepeat; + /** + * 不重复间隔 + */ + private Long noRepeatDuration; + /** + * 是否启用 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean isEnable; + +} \ 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/dataobject/alertrecord/AlertRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alertrecord/AlertRecordDO.java new file mode 100644 index 0000000000..78d36a72cb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alertrecord/AlertRecordDO.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.alertrecord; + +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_alert_record") +@KeySequence("iot_alert_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AlertRecordDO extends BaseDO { + + /** + * ID + */ + @TableId + private Long id; + /** + * 编码 + */ + private String alertCode; + /** + * 名称 + */ + private String alertName; + /** + * 告警类型 + * + * 枚举 {@link TODO iot_alert_type 对应的类} + */ + private String alertType; + /** + * 告警等级 + * + * 枚举 {@link TODO iot_alert_level 对应的类} + */ + private String alertLevel; + /** + * 告警内容 + */ + private String content; + /** + * 告警条件 + */ + private String condition; + /** + * 逻辑表达式 + */ + private String conditionFormula; + /** + * 数据值 + */ + private String dataValue; + /** + * 数据类型 + * + * 枚举 {@link TODO iot_device_data_type 对应的类} + */ + private String dataType; + /** + * 单位 + */ + private String dataUnit; + /** + * 描述 + */ + private String dataTypeRemark; + /** + * 告警ID + */ + private Long alertId; + /** + * 告警音频 + */ + private String alertAudio; + /** + * 重复告警 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean isRepeat; + /** + * 不重复间隔 + */ + private Long noRepeatDuration; + /** + * 来源ID + */ + private Long dataId; + /** + * 来源编码 + */ + private String dataCode; + /** + * 来源名称 + */ + private String dataName; + +} \ 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/dataobject/device/DeviceAttributeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/DeviceAttributeDO.java new file mode 100644 index 0000000000..6e5ad3e75c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/DeviceAttributeDO.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.deviceattribute; + +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_device_attribute") +@KeySequence("iot_device_attribute_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DeviceAttributeDO extends BaseDO { + + /** + * ID + */ + @TableId + private Long id; + /** + * 属性编码 + */ + private String attributeCode; + /** + * 属性名称 + */ + private String attributeName; + /** + * PLC点位地址 + */ + private String address; + /** + * 地址描述 + */ + private String description; + /** + * 地址类型 + * + * 枚举 {@link TODO mes_data_type 对应的类} + */ + private String attributeType; + /** + * 读写方式 + * + * 枚举 {@link TODO iot_attribute_io_type 对应的类} + */ + private String ioType; + /** + * 数据类型 + * + * 枚举 {@link TODO iot_device_data_type 对应的类} + */ + private String dataType; + /** + * 类型描述 + */ + private String dataTypeRemark; + /** + * 单位 + */ + private String dataUnit; + /** + * 数据计算公式 + */ + private String dataFormula; + /** + * 网关id + */ + private Long gatewayId; + /** + * 设备id + */ + private Long deviceId; + /** + * 告警id + */ + private Long alertId; + /** + * 备注 + */ + private String remark; + /** + * 是否启用 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean isEnable; + +} \ 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/dataobject/device/DeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/DeviceDO.java new file mode 100644 index 0000000000..310e29b2d6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/DeviceDO.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.device; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +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_device") +@KeySequence("iot_device_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DeviceDO extends BaseDO { + + /** + * ID + */ + @TableId + private Long id; + /** + * 设备编号 + */ + private String deviceCode; + /** + * 设备名称 + */ + private String deviceName; + /** + * 设备类型 + * + * 枚举 {@link TODO iot_device_type 对应的类} + */ + private String deviceType; + /** + * 状态 + * + * 枚举 {@link TODO iot_gateway_status 对应的类} + */ + private String status; + /** + * 读主题 + */ + private String readTopic; + /** + * 写主题 + */ + private String writeTopic; + /** + * 网关id + */ + private Long gatewayId; + /** + * 设备品牌id + */ + private Long deviceBrandId; + /** + * 离线间隔 + */ + private Long offLineDuration; + /** + * 最后上线时间 + */ + private LocalDateTime lastOnlineTime; + /** + * 备注 + */ + private String remark; + /** + * 是否启用 + * + * 枚举 {@link TODO infra_boolean_string 对应的类} + */ + private Boolean isEnable; + +} \ 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/alert/AlertMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/AlertMapper.java new file mode 100644 index 0000000000..85c630ee6e --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/AlertMapper.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.alert; + +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.alert.AlertDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.*; + +/** + * 告警配置 Mapper + * + * @author 内蒙必硕 + */ +@Mapper +public interface AlertMapper extends BaseMapperX { + + default PageResult selectPage(AlertPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(AlertDO::getAlertCode, reqVO.getAlertCode()) + .likeIfPresent(AlertDO::getAlertName, reqVO.getAlertName()) + .eqIfPresent(AlertDO::getAlertType, reqVO.getAlertType()) + .eqIfPresent(AlertDO::getAlertLevel, reqVO.getAlertLevel()) + .eqIfPresent(AlertDO::getContent, reqVO.getContent()) + .eqIfPresent(AlertDO::getCondition, reqVO.getCondition()) + .eqIfPresent(AlertDO::getConditionFormula, reqVO.getConditionFormula()) + .eqIfPresent(AlertDO::getAlertAudio, reqVO.getAlertAudio()) + .eqIfPresent(AlertDO::getIsRepeat, reqVO.getIsRepeat()) + .eqIfPresent(AlertDO::getNoRepeatDuration, reqVO.getNoRepeatDuration()) + .eqIfPresent(AlertDO::getIsEnable, reqVO.getIsEnable()) + .betweenIfPresent(AlertDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(AlertDO::getId)); + } + +} \ 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/alertrecord/AlertRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alertrecord/AlertRecordMapper.java new file mode 100644 index 0000000000..e225a619f0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alertrecord/AlertRecordMapper.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.alertrecord; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.alertrecord.vo.AlertRecordPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alertrecord.AlertRecordDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 告警记录 Mapper + * + * @author 内蒙必硕 + */ +@Mapper +public interface AlertRecordMapper extends BaseMapperX { + + default PageResult selectPage(AlertRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(AlertRecordDO::getAlertCode, reqVO.getAlertCode()) + .likeIfPresent(AlertRecordDO::getAlertName, reqVO.getAlertName()) + .eqIfPresent(AlertRecordDO::getAlertType, reqVO.getAlertType()) + .eqIfPresent(AlertRecordDO::getAlertLevel, reqVO.getAlertLevel()) + .eqIfPresent(AlertRecordDO::getContent, reqVO.getContent()) + .eqIfPresent(AlertRecordDO::getCondition, reqVO.getCondition()) + .eqIfPresent(AlertRecordDO::getConditionFormula, reqVO.getConditionFormula()) + .eqIfPresent(AlertRecordDO::getDataValue, reqVO.getDataValue()) + .eqIfPresent(AlertRecordDO::getDataType, reqVO.getDataType()) + .eqIfPresent(AlertRecordDO::getDataUnit, reqVO.getDataUnit()) + .eqIfPresent(AlertRecordDO::getDataTypeRemark, reqVO.getDataTypeRemark()) + .betweenIfPresent(AlertRecordDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(AlertRecordDO::getAlertId, reqVO.getAlertId()) + .eqIfPresent(AlertRecordDO::getAlertAudio, reqVO.getAlertAudio()) + .eqIfPresent(AlertRecordDO::getIsRepeat, reqVO.getIsRepeat()) + .eqIfPresent(AlertRecordDO::getNoRepeatDuration, reqVO.getNoRepeatDuration()) + .eqIfPresent(AlertRecordDO::getDataId, reqVO.getDataId()) + .eqIfPresent(AlertRecordDO::getDataCode, reqVO.getDataCode()) + .likeIfPresent(AlertRecordDO::getDataName, reqVO.getDataName()) + .orderByDesc(AlertRecordDO::getId)); + } + default PageResult selectPage(PageParam reqVO, Long alertId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(AlertRecordDO::getAlertId, alertId) + .orderByDesc(AlertRecordDO::getId)); + } + + default int deleteByAlertId(Long alertId) { + return delete(AlertRecordDO::getAlertId, alertId); + } +} \ 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/device/DeviceAttributeMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceAttributeMapper.java new file mode 100644 index 0000000000..48f71e63e9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceAttributeMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.deviceattribute; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +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.deviceattribute.DeviceAttributeDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 设备属性 Mapper + * + * @author 内蒙必硕 + */ +@Mapper +public interface DeviceAttributeMapper extends BaseMapperX { + + default PageResult selectPage(PageParam reqVO, Long deviceId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(DeviceAttributeDO::getDeviceId, deviceId) + .orderByDesc(DeviceAttributeDO::getId)); + } + + default int deleteByDeviceId(Long deviceId) { + return delete(DeviceAttributeDO::getDeviceId, 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/device/DeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java new file mode 100644 index 0000000000..32ed4b4a27 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/DeviceMapper.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.device; + +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.device.DeviceDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*; + +/** + * 物联设备 Mapper + * + * @author 内蒙必硕 + */ +@Mapper +public interface DeviceMapper extends BaseMapperX { + + default PageResult selectPage(DevicePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(DeviceDO::getDeviceCode, reqVO.getDeviceCode()) + .likeIfPresent(DeviceDO::getDeviceName, reqVO.getDeviceName()) + .eqIfPresent(DeviceDO::getDeviceType, reqVO.getDeviceType()) + .eqIfPresent(DeviceDO::getStatus, reqVO.getStatus()) + .eqIfPresent(DeviceDO::getReadTopic, reqVO.getReadTopic()) + .eqIfPresent(DeviceDO::getWriteTopic, reqVO.getWriteTopic()) + .eqIfPresent(DeviceDO::getGatewayId, reqVO.getGatewayId()) + .eqIfPresent(DeviceDO::getDeviceBrandId, reqVO.getDeviceBrandId()) + .eqIfPresent(DeviceDO::getOffLineDuration, reqVO.getOffLineDuration()) + .betweenIfPresent(DeviceDO::getLastOnlineTime, reqVO.getLastOnlineTime()) + .eqIfPresent(DeviceDO::getRemark, reqVO.getRemark()) + .eqIfPresent(DeviceDO::getIsEnable, reqVO.getIsEnable()) + .betweenIfPresent(DeviceDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(DeviceDO::getId)); + } + +} \ 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/alert/AlertService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/AlertService.java new file mode 100644 index 0000000000..808d9f26f8 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/AlertService.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.iot.service.alert; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.AlertDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alertrecord.AlertRecordDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 告警配置 Service 接口 + * + * @author 内蒙必硕 + */ +public interface AlertService { + + /** + * 创建告警配置 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createAlert(@Valid AlertSaveReqVO createReqVO); + + /** + * 更新告警配置 + * + * @param updateReqVO 更新信息 + */ + void updateAlert(@Valid AlertSaveReqVO updateReqVO); + + /** + * 删除告警配置 + * + * @param id 编号 + */ + void deleteAlert(Long id); + + /** + * 获得告警配置 + * + * @param id 编号 + * @return 告警配置 + */ + AlertDO getAlert(Long id); + + /** + * 获得告警配置分页 + * + * @param pageReqVO 分页查询 + * @return 告警配置分页 + */ + PageResult getAlertPage(AlertPageReqVO pageReqVO); + + // ==================== 子表(告警记录) ==================== + + /** + * 获得告警记录分页 + * + * @param pageReqVO 分页查询 + * @param alertId 告警ID + * @return 告警记录分页 + */ + PageResult getAlertRecordPage(PageParam pageReqVO, Long alertId); + + /** + * 创建告警记录 + * + * @param alertRecord 创建信息 + * @return 编号 + */ + Long createAlertRecord(@Valid AlertRecordDO alertRecord); + + /** + * 更新告警记录 + * + * @param alertRecord 更新信息 + */ + void updateAlertRecord(@Valid AlertRecordDO alertRecord); + + /** + * 删除告警记录 + * + * @param id 编号 + */ + void deleteAlertRecord(Long id); + + /** + * 获得告警记录 + * + * @param id 编号 + * @return 告警记录 + */ + AlertRecordDO getAlertRecord(Long id); + +} \ 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/alert/AlertServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/AlertServiceImpl.java new file mode 100644 index 0000000000..0aa6d3df84 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/AlertServiceImpl.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.iot.service.alert; + +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.alert.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.AlertDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alertrecord.AlertRecordDO; +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.alert.AlertMapper; +import cn.iocoder.yudao.module.iot.dal.mysql.alertrecord.AlertRecordMapper; + +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 AlertServiceImpl implements AlertService { + + @Resource + private AlertMapper alertMapper; + @Resource + private AlertRecordMapper alertRecordMapper; + + @Override + public Long createAlert(AlertSaveReqVO createReqVO) { + // 插入 + AlertDO alert = BeanUtils.toBean(createReqVO, AlertDO.class); + alertMapper.insert(alert); + // 返回 + return alert.getId(); + } + + @Override + public void updateAlert(AlertSaveReqVO updateReqVO) { + // 校验存在 + validateAlertExists(updateReqVO.getId()); + // 更新 + AlertDO updateObj = BeanUtils.toBean(updateReqVO, AlertDO.class); + alertMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteAlert(Long id) { + // 校验存在 + validateAlertExists(id); + // 删除 + alertMapper.deleteById(id); + + // 删除子表 + deleteAlertRecordByAlertId(id); + } + + private void validateAlertExists(Long id) { + if (alertMapper.selectById(id) == null) { + throw exception(ALERT_NOT_EXISTS); + } + } + + @Override + public AlertDO getAlert(Long id) { + return alertMapper.selectById(id); + } + + @Override + public PageResult getAlertPage(AlertPageReqVO pageReqVO) { + return alertMapper.selectPage(pageReqVO); + } + + // ==================== 子表(告警记录) ==================== + + @Override + public PageResult getAlertRecordPage(PageParam pageReqVO, Long alertId) { + return alertRecordMapper.selectPage(pageReqVO, alertId); + } + + @Override + public Long createAlertRecord(AlertRecordDO alertRecord) { + alertRecordMapper.insert(alertRecord); + return alertRecord.getId(); + } + + @Override + public void updateAlertRecord(AlertRecordDO alertRecord) { + // 校验存在 + validateAlertRecordExists(alertRecord.getId()); + // 更新 + alertRecordMapper.updateById(alertRecord); + } + + @Override + public void deleteAlertRecord(Long id) { + // 校验存在 + validateAlertRecordExists(id); + // 删除 + alertRecordMapper.deleteById(id); + } + + @Override + public AlertRecordDO getAlertRecord(Long id) { + return alertRecordMapper.selectById(id); + } + + private void validateAlertRecordExists(Long id) { + if (alertRecordMapper.selectById(id) == null) { + throw exception(ALERT_RECORD_NOT_EXISTS); + } + } + + private void deleteAlertRecordByAlertId(Long alertId) { + alertRecordMapper.deleteByAlertId(alertId); + } + +} \ 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/alertrecord/AlertRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alertrecord/AlertRecordService.java new file mode 100644 index 0000000000..88743cd206 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alertrecord/AlertRecordService.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.iot.service.alertrecord; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.iot.controller.admin.alertrecord.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.alertrecord.AlertRecordDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 告警记录 Service 接口 + * + * @author 内蒙必硕 + */ +public interface AlertRecordService { + + /** + * 创建告警记录 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createAlertRecord(@Valid AlertRecordSaveReqVO createReqVO); + + /** + * 更新告警记录 + * + * @param updateReqVO 更新信息 + */ + void updateAlertRecord(@Valid AlertRecordSaveReqVO updateReqVO); + + /** + * 删除告警记录 + * + * @param id 编号 + */ + void deleteAlertRecord(Long id); + + /** + * 获得告警记录 + * + * @param id 编号 + * @return 告警记录 + */ + AlertRecordDO getAlertRecord(Long id); + + /** + * 获得告警记录分页 + * + * @param pageReqVO 分页查询 + * @return 告警记录分页 + */ + PageResult getAlertRecordPage(AlertRecordPageReqVO pageReqVO); + +} \ 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/alertrecord/AlertRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alertrecord/AlertRecordServiceImpl.java new file mode 100644 index 0000000000..0c97703a06 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alertrecord/AlertRecordServiceImpl.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.iot.service.alertrecord; + +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.alertrecord.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.alertrecord.AlertRecordDO; +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.alertrecord.AlertRecordMapper; + +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 AlertRecordServiceImpl implements AlertRecordService { + + @Resource + private AlertRecordMapper alertRecordMapper; + + @Override + public Long createAlertRecord(AlertRecordSaveReqVO createReqVO) { + // 插入 + AlertRecordDO alertRecord = BeanUtils.toBean(createReqVO, AlertRecordDO.class); + alertRecordMapper.insert(alertRecord); + // 返回 + return alertRecord.getId(); + } + + @Override + public void updateAlertRecord(AlertRecordSaveReqVO updateReqVO) { + // 校验存在 + validateAlertRecordExists(updateReqVO.getId()); + // 更新 + AlertRecordDO updateObj = BeanUtils.toBean(updateReqVO, AlertRecordDO.class); + alertRecordMapper.updateById(updateObj); + } + + @Override + public void deleteAlertRecord(Long id) { + // 校验存在 + validateAlertRecordExists(id); + // 删除 + alertRecordMapper.deleteById(id); + } + + private void validateAlertRecordExists(Long id) { + if (alertRecordMapper.selectById(id) == null) { + throw exception(ALERT_RECORD_NOT_EXISTS); + } + } + + @Override + public AlertRecordDO getAlertRecord(Long id) { + return alertRecordMapper.selectById(id); + } + + @Override + public PageResult getAlertRecordPage(AlertRecordPageReqVO pageReqVO) { + return alertRecordMapper.selectPage(pageReqVO); + } + +} \ 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/device/DeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceService.java new file mode 100644 index 0000000000..80f6430475 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceService.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.iot.service.device; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.deviceattribute.DeviceAttributeDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 物联设备 Service 接口 + * + * @author 内蒙必硕 + */ +public interface DeviceService { + + /** + * 创建物联设备 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDevice(@Valid DeviceSaveReqVO createReqVO); + + /** + * 更新物联设备 + * + * @param updateReqVO 更新信息 + */ + void updateDevice(@Valid DeviceSaveReqVO updateReqVO); + + /** + * 删除物联设备 + * + * @param id 编号 + */ + void deleteDevice(Long id); + + /** + * 获得物联设备 + * + * @param id 编号 + * @return 物联设备 + */ + DeviceDO getDevice(Long id); + + /** + * 获得物联设备分页 + * + * @param pageReqVO 分页查询 + * @return 物联设备分页 + */ + PageResult getDevicePage(DevicePageReqVO pageReqVO); + + // ==================== 子表(设备属性) ==================== + + /** + * 获得设备属性分页 + * + * @param pageReqVO 分页查询 + * @param deviceId 设备id + * @return 设备属性分页 + */ + PageResult getDeviceAttributePage(PageParam pageReqVO, Long deviceId); + + /** + * 创建设备属性 + * + * @param deviceAttribute 创建信息 + * @return 编号 + */ + Long createDeviceAttribute(@Valid DeviceAttributeDO deviceAttribute); + + /** + * 更新设备属性 + * + * @param deviceAttribute 更新信息 + */ + void updateDeviceAttribute(@Valid DeviceAttributeDO deviceAttribute); + + /** + * 删除设备属性 + * + * @param id 编号 + */ + void deleteDeviceAttribute(Long id); + + /** + * 获得设备属性 + * + * @param id 编号 + * @return 设备属性 + */ + DeviceAttributeDO getDeviceAttribute(Long id); + +} \ 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/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java new file mode 100644 index 0000000000..a3395d9a75 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java @@ -0,0 +1,126 @@ +package cn.iocoder.yudao.module.iot.service.device; + +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.device.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.deviceattribute.DeviceAttributeDO; +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.device.DeviceMapper; +import cn.iocoder.yudao.module.iot.dal.mysql.deviceattribute.DeviceAttributeMapper; + +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 DeviceServiceImpl implements DeviceService { + + @Resource + private DeviceMapper deviceMapper; + @Resource + private DeviceAttributeMapper deviceAttributeMapper; + + @Override + public Long createDevice(DeviceSaveReqVO createReqVO) { + // 插入 + DeviceDO device = BeanUtils.toBean(createReqVO, DeviceDO.class); + deviceMapper.insert(device); + // 返回 + return device.getId(); + } + + @Override + public void updateDevice(DeviceSaveReqVO updateReqVO) { + // 校验存在 + validateDeviceExists(updateReqVO.getId()); + // 更新 + DeviceDO updateObj = BeanUtils.toBean(updateReqVO, DeviceDO.class); + deviceMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteDevice(Long id) { + // 校验存在 + validateDeviceExists(id); + // 删除 + deviceMapper.deleteById(id); + + // 删除子表 + deleteDeviceAttributeByDeviceId(id); + } + + private void validateDeviceExists(Long id) { + if (deviceMapper.selectById(id) == null) { + throw exception(DEVICE_NOT_EXISTS); + } + } + + @Override + public DeviceDO getDevice(Long id) { + return deviceMapper.selectById(id); + } + + @Override + public PageResult getDevicePage(DevicePageReqVO pageReqVO) { + return deviceMapper.selectPage(pageReqVO); + } + + // ==================== 子表(设备属性) ==================== + + @Override + public PageResult getDeviceAttributePage(PageParam pageReqVO, Long deviceId) { + return deviceAttributeMapper.selectPage(pageReqVO, deviceId); + } + + @Override + public Long createDeviceAttribute(DeviceAttributeDO deviceAttribute) { + deviceAttributeMapper.insert(deviceAttribute); + return deviceAttribute.getId(); + } + + @Override + public void updateDeviceAttribute(DeviceAttributeDO deviceAttribute) { + // 校验存在 + validateDeviceAttributeExists(deviceAttribute.getId()); + // 更新 + deviceAttributeMapper.updateById(deviceAttribute); + } + + @Override + public void deleteDeviceAttribute(Long id) { + // 校验存在 + validateDeviceAttributeExists(id); + // 删除 + deviceAttributeMapper.deleteById(id); + } + + @Override + public DeviceAttributeDO getDeviceAttribute(Long id) { + return deviceAttributeMapper.selectById(id); + } + + private void validateDeviceAttributeExists(Long id) { + if (deviceAttributeMapper.selectById(id) == null) { + throw exception(DEVICE_ATTRIBUTE_NOT_EXISTS); + } + } + + private void deleteDeviceAttributeByDeviceId(Long deviceId) { + deviceAttributeMapper.deleteByDeviceId(deviceId); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/alert/AlertMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/alert/AlertMapper.xml new file mode 100644 index 0000000000..87f2249aab --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/alert/AlertMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/alertrecord/AlertRecordMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/alertrecord/AlertRecordMapper.xml new file mode 100644 index 0000000000..35dca42c7c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/alertrecord/AlertRecordMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/DeviceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/DeviceMapper.xml new file mode 100644 index 0000000000..548b593d61 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/DeviceMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/alert/AlertServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/alert/AlertServiceImplTest.java new file mode 100644 index 0000000000..08908b7321 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/alert/AlertServiceImplTest.java @@ -0,0 +1,174 @@ +package cn.iocoder.yudao.module.iot.service.alert; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.AlertDO; +import cn.iocoder.yudao.module.iot.dal.mysql.alert.AlertMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link AlertServiceImpl} 的单元测试类 + * + * @author 内蒙必硕 + */ +@Import(AlertServiceImpl.class) +public class AlertServiceImplTest extends BaseDbUnitTest { + + @Resource + private AlertServiceImpl alertService; + + @Resource + private AlertMapper alertMapper; + + @Test + public void testCreateAlert_success() { + // 准备参数 + AlertSaveReqVO createReqVO = randomPojo(AlertSaveReqVO.class).setId(null); + + // 调用 + Long alertId = alertService.createAlert(createReqVO); + // 断言 + assertNotNull(alertId); + // 校验记录的属性是否正确 + AlertDO alert = alertMapper.selectById(alertId); + assertPojoEquals(createReqVO, alert, "id"); + } + + @Test + public void testUpdateAlert_success() { + // mock 数据 + AlertDO dbAlert = randomPojo(AlertDO.class); + alertMapper.insert(dbAlert);// @Sql: 先插入出一条存在的数据 + // 准备参数 + AlertSaveReqVO updateReqVO = randomPojo(AlertSaveReqVO.class, o -> { + o.setId(dbAlert.getId()); // 设置更新的 ID + }); + + // 调用 + alertService.updateAlert(updateReqVO); + // 校验是否更新正确 + AlertDO alert = alertMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, alert); + } + + @Test + public void testUpdateAlert_notExists() { + // 准备参数 + AlertSaveReqVO updateReqVO = randomPojo(AlertSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> alertService.updateAlert(updateReqVO), ALERT_NOT_EXISTS); + } + + @Test + public void testDeleteAlert_success() { + // mock 数据 + AlertDO dbAlert = randomPojo(AlertDO.class); + alertMapper.insert(dbAlert);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbAlert.getId(); + + // 调用 + alertService.deleteAlert(id); + // 校验数据不存在了 + assertNull(alertMapper.selectById(id)); + } + + @Test + public void testDeleteAlert_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> alertService.deleteAlert(id), ALERT_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetAlertPage() { + // mock 数据 + AlertDO dbAlert = randomPojo(AlertDO.class, o -> { // 等会查询到 + o.setAlertCode(null); + o.setAlertName(null); + o.setAlertType(null); + o.setAlertLevel(null); + o.setContent(null); + o.setCondition(null); + o.setConditionFormula(null); + o.setAlertAudio(null); + o.setIsRepeat(null); + o.setNoRepeatDuration(null); + o.setIsEnable(null); + o.setCreateTime(null); + }); + alertMapper.insert(dbAlert); + // 测试 alertCode 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setAlertCode(null))); + // 测试 alertName 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setAlertName(null))); + // 测试 alertType 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setAlertType(null))); + // 测试 alertLevel 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setAlertLevel(null))); + // 测试 content 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setContent(null))); + // 测试 condition 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setCondition(null))); + // 测试 conditionFormula 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setConditionFormula(null))); + // 测试 alertAudio 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setAlertAudio(null))); + // 测试 isRepeat 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setIsRepeat(null))); + // 测试 noRepeatDuration 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setNoRepeatDuration(null))); + // 测试 isEnable 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setIsEnable(null))); + // 测试 createTime 不匹配 + alertMapper.insert(cloneIgnoreId(dbAlert, o -> o.setCreateTime(null))); + // 准备参数 + AlertPageReqVO reqVO = new AlertPageReqVO(); + reqVO.setAlertCode(null); + reqVO.setAlertName(null); + reqVO.setAlertType(null); + reqVO.setAlertLevel(null); + reqVO.setContent(null); + reqVO.setCondition(null); + reqVO.setConditionFormula(null); + reqVO.setAlertAudio(null); + reqVO.setIsRepeat(null); + reqVO.setNoRepeatDuration(null); + reqVO.setIsEnable(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = alertService.getAlertPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbAlert, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/alertrecord/AlertRecordServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/alertrecord/AlertRecordServiceImplTest.java new file mode 100644 index 0000000000..ac64594ca4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/alertrecord/AlertRecordServiceImplTest.java @@ -0,0 +1,202 @@ +package cn.iocoder.yudao.module.iot.service.alertrecord; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.iot.controller.admin.alertrecord.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.alertrecord.AlertRecordDO; +import cn.iocoder.yudao.module.iot.dal.mysql.alertrecord.AlertRecordMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link AlertRecordServiceImpl} 的单元测试类 + * + * @author 内蒙必硕 + */ +@Import(AlertRecordServiceImpl.class) +public class AlertRecordServiceImplTest extends BaseDbUnitTest { + + @Resource + private AlertRecordServiceImpl alertRecordService; + + @Resource + private AlertRecordMapper alertRecordMapper; + + @Test + public void testCreateAlertRecord_success() { + // 准备参数 + AlertRecordSaveReqVO createReqVO = randomPojo(AlertRecordSaveReqVO.class).setId(null); + + // 调用 + Long alertRecordId = alertRecordService.createAlertRecord(createReqVO); + // 断言 + assertNotNull(alertRecordId); + // 校验记录的属性是否正确 + AlertRecordDO alertRecord = alertRecordMapper.selectById(alertRecordId); + assertPojoEquals(createReqVO, alertRecord, "id"); + } + + @Test + public void testUpdateAlertRecord_success() { + // mock 数据 + AlertRecordDO dbAlertRecord = randomPojo(AlertRecordDO.class); + alertRecordMapper.insert(dbAlertRecord);// @Sql: 先插入出一条存在的数据 + // 准备参数 + AlertRecordSaveReqVO updateReqVO = randomPojo(AlertRecordSaveReqVO.class, o -> { + o.setId(dbAlertRecord.getId()); // 设置更新的 ID + }); + + // 调用 + alertRecordService.updateAlertRecord(updateReqVO); + // 校验是否更新正确 + AlertRecordDO alertRecord = alertRecordMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, alertRecord); + } + + @Test + public void testUpdateAlertRecord_notExists() { + // 准备参数 + AlertRecordSaveReqVO updateReqVO = randomPojo(AlertRecordSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> alertRecordService.updateAlertRecord(updateReqVO), ALERT_RECORD_NOT_EXISTS); + } + + @Test + public void testDeleteAlertRecord_success() { + // mock 数据 + AlertRecordDO dbAlertRecord = randomPojo(AlertRecordDO.class); + alertRecordMapper.insert(dbAlertRecord);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbAlertRecord.getId(); + + // 调用 + alertRecordService.deleteAlertRecord(id); + // 校验数据不存在了 + assertNull(alertRecordMapper.selectById(id)); + } + + @Test + public void testDeleteAlertRecord_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> alertRecordService.deleteAlertRecord(id), ALERT_RECORD_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetAlertRecordPage() { + // mock 数据 + AlertRecordDO dbAlertRecord = randomPojo(AlertRecordDO.class, o -> { // 等会查询到 + o.setAlertCode(null); + o.setAlertName(null); + o.setAlertType(null); + o.setAlertLevel(null); + o.setContent(null); + o.setCondition(null); + o.setConditionFormula(null); + o.setDataValue(null); + o.setDataType(null); + o.setDataUnit(null); + o.setDataTypeRemark(null); + o.setCreateTime(null); + o.setAlertId(null); + o.setAlertAudio(null); + o.setIsRepeat(null); + o.setNoRepeatDuration(null); + o.setDataId(null); + o.setDataCode(null); + o.setDataName(null); + }); + alertRecordMapper.insert(dbAlertRecord); + // 测试 alertCode 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setAlertCode(null))); + // 测试 alertName 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setAlertName(null))); + // 测试 alertType 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setAlertType(null))); + // 测试 alertLevel 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setAlertLevel(null))); + // 测试 content 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setContent(null))); + // 测试 condition 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setCondition(null))); + // 测试 conditionFormula 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setConditionFormula(null))); + // 测试 dataValue 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setDataValue(null))); + // 测试 dataType 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setDataType(null))); + // 测试 dataUnit 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setDataUnit(null))); + // 测试 dataTypeRemark 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setDataTypeRemark(null))); + // 测试 createTime 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setCreateTime(null))); + // 测试 alertId 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setAlertId(null))); + // 测试 alertAudio 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setAlertAudio(null))); + // 测试 isRepeat 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setIsRepeat(null))); + // 测试 noRepeatDuration 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setNoRepeatDuration(null))); + // 测试 dataId 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setDataId(null))); + // 测试 dataCode 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setDataCode(null))); + // 测试 dataName 不匹配 + alertRecordMapper.insert(cloneIgnoreId(dbAlertRecord, o -> o.setDataName(null))); + // 准备参数 + AlertRecordPageReqVO reqVO = new AlertRecordPageReqVO(); + reqVO.setAlertCode(null); + reqVO.setAlertName(null); + reqVO.setAlertType(null); + reqVO.setAlertLevel(null); + reqVO.setContent(null); + reqVO.setCondition(null); + reqVO.setConditionFormula(null); + reqVO.setDataValue(null); + reqVO.setDataType(null); + reqVO.setDataUnit(null); + reqVO.setDataTypeRemark(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setAlertId(null); + reqVO.setAlertAudio(null); + reqVO.setIsRepeat(null); + reqVO.setNoRepeatDuration(null); + reqVO.setDataId(null); + reqVO.setDataCode(null); + reqVO.setDataName(null); + + // 调用 + PageResult pageResult = alertRecordService.getAlertRecordPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbAlertRecord, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java new file mode 100644 index 0000000000..51608c9342 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java @@ -0,0 +1,178 @@ +package cn.iocoder.yudao.module.iot.service.device; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO; +import cn.iocoder.yudao.module.iot.dal.mysql.device.DeviceMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link DeviceServiceImpl} 的单元测试类 + * + * @author 内蒙必硕 + */ +@Import(DeviceServiceImpl.class) +public class DeviceServiceImplTest extends BaseDbUnitTest { + + @Resource + private DeviceServiceImpl deviceService; + + @Resource + private DeviceMapper deviceMapper; + + @Test + public void testCreateDevice_success() { + // 准备参数 + DeviceSaveReqVO createReqVO = randomPojo(DeviceSaveReqVO.class).setId(null); + + // 调用 + Long deviceId = deviceService.createDevice(createReqVO); + // 断言 + assertNotNull(deviceId); + // 校验记录的属性是否正确 + DeviceDO device = deviceMapper.selectById(deviceId); + assertPojoEquals(createReqVO, device, "id"); + } + + @Test + public void testUpdateDevice_success() { + // mock 数据 + DeviceDO dbDevice = randomPojo(DeviceDO.class); + deviceMapper.insert(dbDevice);// @Sql: 先插入出一条存在的数据 + // 准备参数 + DeviceSaveReqVO updateReqVO = randomPojo(DeviceSaveReqVO.class, o -> { + o.setId(dbDevice.getId()); // 设置更新的 ID + }); + + // 调用 + deviceService.updateDevice(updateReqVO); + // 校验是否更新正确 + DeviceDO device = deviceMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, device); + } + + @Test + public void testUpdateDevice_notExists() { + // 准备参数 + DeviceSaveReqVO updateReqVO = randomPojo(DeviceSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> deviceService.updateDevice(updateReqVO), DEVICE_NOT_EXISTS); + } + + @Test + public void testDeleteDevice_success() { + // mock 数据 + DeviceDO dbDevice = randomPojo(DeviceDO.class); + deviceMapper.insert(dbDevice);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDevice.getId(); + + // 调用 + deviceService.deleteDevice(id); + // 校验数据不存在了 + assertNull(deviceMapper.selectById(id)); + } + + @Test + public void testDeleteDevice_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> deviceService.deleteDevice(id), DEVICE_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetDevicePage() { + // mock 数据 + DeviceDO dbDevice = randomPojo(DeviceDO.class, o -> { // 等会查询到 + o.setDeviceCode(null); + o.setDeviceName(null); + o.setDeviceType(null); + o.setStatus(null); + o.setReadTopic(null); + o.setWriteTopic(null); + o.setGatewayId(null); + o.setDeviceBrandId(null); + o.setOffLineDuration(null); + o.setLastOnlineTime(null); + o.setRemark(null); + o.setIsEnable(null); + o.setCreateTime(null); + }); + deviceMapper.insert(dbDevice); + // 测试 deviceCode 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceCode(null))); + // 测试 deviceName 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceName(null))); + // 测试 deviceType 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceType(null))); + // 测试 status 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setStatus(null))); + // 测试 readTopic 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setReadTopic(null))); + // 测试 writeTopic 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setWriteTopic(null))); + // 测试 gatewayId 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setGatewayId(null))); + // 测试 deviceBrandId 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceBrandId(null))); + // 测试 offLineDuration 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setOffLineDuration(null))); + // 测试 lastOnlineTime 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLastOnlineTime(null))); + // 测试 remark 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setRemark(null))); + // 测试 isEnable 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setIsEnable(null))); + // 测试 createTime 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setCreateTime(null))); + // 准备参数 + DevicePageReqVO reqVO = new DevicePageReqVO(); + reqVO.setDeviceCode(null); + reqVO.setDeviceName(null); + reqVO.setDeviceType(null); + reqVO.setStatus(null); + reqVO.setReadTopic(null); + reqVO.setWriteTopic(null); + reqVO.setGatewayId(null); + reqVO.setDeviceBrandId(null); + reqVO.setOffLineDuration(null); + reqVO.setLastOnlineTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setRemark(null); + reqVO.setIsEnable(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = deviceService.getDevicePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbDevice, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/resources/sql/clean.sql b/yudao-module-iot/yudao-module-iot-biz/src/test/resources/sql/clean.sql index 4e34a441ad..c14873bd71 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/resources/sql/clean.sql +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/resources/sql/clean.sql @@ -1,28 +1,15 @@ --- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 -DELETE FROM "iot_device"; - -- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 DELETE FROM "iot_formula"; - --- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 -DELETE FROM "iot_device_attribute"; - --- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 DELETE FROM "iot_formula_detail"; --- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 DELETE FROM "iot_gateway"; --- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 DELETE FROM "iot_iot_organization"; --- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 DELETE FROM "iot_kanban"; --- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 DELETE FROM "iot_formula_record"; --- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 DELETE FROM "iot_mqtt_record"; -- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 @@ -35,5 +22,10 @@ DELETE FROM "iot_frpc_proxy_server"; -- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 DELETE FROM "iot_feedback"; --- 将该删表 SQL 语句,添加到 yudao-module-iot-biz 模块的 test/resources/sql/clean.sql 文件里 -DELETE FROM "iot_mqtt_data_record"; \ No newline at end of file +DELETE FROM "iot_mqtt_data_record"; + +DELETE FROM "iot_device"; +DELETE FROM "iot_alert_record"; +DELETE FROM "iot_alert"; + +DELETE FROM "iot_device_attribute"; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/resources/sql/create_tables.sql b/yudao-module-iot/yudao-module-iot-biz/src/test/resources/sql/create_tables.sql index 4cffce270b..9e402dd154 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/resources/sql/create_tables.sql @@ -1,49 +1,3 @@ -CREATE TABLE IF NOT EXISTS "iot_device" -( - "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, - "device_config_id" varchar, - "device_code" varchar, - "device_name" varchar, - "device_type" varchar, - "siemens_series" varchar, - "siemens_connect_param" varchar, - "read_cron_type" varchar, - "read_repeat_value" int, - "read_repeat_unit" varchar, - "read_cron" varchar, - "write_cron_type" varchar, - "write_repeat_value" int, - "write_repeat_unit" varchar, - "write_cron" varchar, - "local_persistent" varchar, - "upload_rate" varchar, - "rate_count" int, - "modbus_protocol" varchar, - "modbus_pattern" varchar, - "port_name" varchar, - "modbus_connect_param" varchar, - "modbus_read_addr_gap" varchar, - "is_upload" varchar, - "gateway_id" bigint NOT NULL, - "org_id" bigint NOT NULL, - "remark" varchar, - "is_enable" bit NOT NULL, - "creator" varchar DEFAULT '', - "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updater" varchar DEFAULT '', - "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - "deleted" bit NOT NULL DEFAULT FALSE, - "tenant_id" bigint, - "device_use_type" varchar, - "ap_ip" varchar, - "gate_bridge_ip" varchar, - "com_server_ip" varchar, - "com_server_port" varchar, - "plc_controller_ip" varchar, - "plc_screen_ip" varchar, - "org_machine_id" bigint, - PRIMARY KEY ("id") -) COMMENT '物联设备表'; CREATE TABLE IF NOT EXISTS "iot_formula" ( "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, @@ -63,52 +17,7 @@ CREATE TABLE IF NOT EXISTS "iot_formula" "tenant_id" bigint, PRIMARY KEY ("id") ) COMMENT '计算公式'; -CREATE TABLE IF NOT EXISTS "iot_device_attribute" -( - "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, - "attribute_code" varchar NOT NULL, - "address" varchar, - "attribute_name" varchar NOT NULL, - "description" varchar, - "address_type" varchar, - "address_offset" varchar, - "address2_type" varchar, - "address2_offset" varchar, - "group_name" varchar, - "group_id" int, - "security_type" varchar, - "io_status" varchar, - "is_linear_transfer" varchar, - "data_type" varchar, - "unit" varchar, - "in_min_value" varchar, - "in_max_value" varchar, - "out_min_value" varchar, - "out_max_value" varchar, - "out_data_type" varchar, - "siemens_field_precision" int, - "modbus_slave_id" varchar, - "modbus_field_address" varchar, - "modbus_address_type" varchar, - "modbus_field_size" varchar, - "modbus_field_precision" varchar, - "modbus_field_order" varchar, - "source_data_type" varchar, - "transfer_data_type" varchar, - "factor" varchar, - "gateway_id" bigint NOT NULL, - "device_id" bigint NOT NULL, - "org_id" bigint NOT NULL, - "remark" varchar, - "is_enable" bit NOT NULL, - "creator" varchar DEFAULT '', - "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updater" varchar DEFAULT '', - "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - "deleted" bit NOT NULL DEFAULT FALSE, - "tenant_id" bigint, - PRIMARY KEY ("id") -) COMMENT '设备属性表'; + CREATE TABLE IF NOT EXISTS "iot_formula_detail" ( "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, @@ -302,3 +211,104 @@ CREATE TABLE IF NOT EXISTS "iot_mqtt_data_record" PRIMARY KEY ("id") ) COMMENT '设备数据记录'; +CREATE TABLE IF NOT EXISTS "iot_alert" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "alert_code" varchar NOT NULL, + "alert_name" varchar NOT NULL, + "alert_type" varchar, + "alert_level" varchar, + "content" varchar, + "condition" varchar, + "condition_formula" varchar, + "alert_audio" varchar NOT NULL, + "is_repeat" bit NOT NULL, + "no_repeat_duration" bigint NOT NULL, + "is_enable" bit NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint, + PRIMARY KEY ("id") +) COMMENT '告警配置'; +CREATE TABLE IF NOT EXISTS "iot_alert_record" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "alert_code" varchar NOT NULL, + "alert_name" varchar NOT NULL, + "alert_type" varchar, + "alert_level" varchar, + "content" varchar, + "condition" varchar, + "condition_formula" varchar, + "data_value" varchar, + "data_type" varchar, + "data_unit" varchar, + "data_type_remark" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint, + "alert_id" bigint, + "alert_audio" varchar, + "is_repeat" bit, + "no_repeat_duration" bigint, + "data_id" bigint, + "data_code" varchar, + "data_name" varchar, + PRIMARY KEY ("id") +) COMMENT '告警记录'; +CREATE TABLE IF NOT EXISTS "iot_device" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "device_code" varchar, + "device_name" varchar, + "device_type" varchar, + "status" varchar, + "read_topic" varchar, + "write_topic" varchar, + "gateway_id" bigint NOT NULL, + "device_brand_id" bigint NOT NULL, + "off_line_duration" bigint NOT NULL, + "last_online_time" varchar NOT NULL, + "remark" varchar, + "is_enable" bit NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint, + PRIMARY KEY ("id") +) COMMENT '物联设备表'; + +CREATE TABLE IF NOT EXISTS "iot_device_attribute" +( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "attribute_code" varchar NOT NULL, + "attribute_name" varchar NOT NULL, + "address" varchar, + "description" varchar, + "attribute_type" varchar, + "io_type" varchar, + "data_type" varchar, + "data_type_remark" varchar, + "data_unit" varchar, + "data_formula" varchar, + "gateway_id" bigint, + "device_id" bigint, + "alert_id" bigint, + "remark" varchar, + "is_enable" bit NOT NULL, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + "tenant_id" bigint, + PRIMARY KEY ("id") +) COMMENT '设备属性表';