diff --git a/pom.xml b/pom.xml index 3f443a0..532173d 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,11 @@ - + + org.bytedeco + javacv-platform + 1.5.9 + org.springframework.boot diff --git a/rtsp-vue/src/api/video/alarm.js b/rtsp-vue/src/api/video/alarm.js new file mode 100644 index 0000000..c39d038 --- /dev/null +++ b/rtsp-vue/src/api/video/alarm.js @@ -0,0 +1,28 @@ +import request from '@/utils/request' + +// 查询报警记录列表 +export function listAlarm(query) { + return request({ + url: '/video/alarm/list', + method: 'get', + params: query + }) +} + +// 处理报警记录 +export function handleAlarm(data) { + return request({ + url: '/video/alarm/handle', + method: 'post', + params: data + }) +} + +// 批量处理报警记录 +export function batchHandleAlarm(data) { + return request({ + url: '/video/alarm/batchHandle', + method: 'post', + params: data + }) +} \ No newline at end of file diff --git a/rtsp-vue/src/api/video/inspection.js b/rtsp-vue/src/api/video/inspection.js new file mode 100644 index 0000000..943b6e3 --- /dev/null +++ b/rtsp-vue/src/api/video/inspection.js @@ -0,0 +1,68 @@ +import request from '@/utils/request' + +// 查询巡检任务列表 +export function listInspection(query) { + return request({ + url: '/video/inspection/list', + method: 'get', + params: query + }) +} + +// 查询巡检任务详细 +export function getInspection(taskId) { + return request({ + url: '/video/inspection/' + taskId, + method: 'get' + }) +} + +// 新增巡检任务 +export function addInspection(data) { + return request({ + url: '/video/inspection', + method: 'post', + data: data + }) +} + +// 修改巡检任务 +export function updateInspection(data) { + return request({ + url: '/video/inspection', + method: 'put', + data: data + }) +} + +// 删除巡检任务 +export function delInspection(taskId) { + return request({ + url: '/video/inspection/' + taskId, + method: 'delete' + }) +} + +// 启动巡检任务 +export function startTask(taskId) { + return request({ + url: '/video/inspection/start/' + taskId, + method: 'post' + }) +} + +// 停止巡检任务 +export function stopTask(taskId) { + return request({ + url: '/video/inspection/stop/' + taskId, + method: 'post' + }) +} + +// 执行巡检任务 +export function executeTask(taskId) { + return request({ + url: '/video/inspection/execute/' + taskId, + method: 'post' + }) +} \ No newline at end of file diff --git a/rtsp-vue/src/views/video/alarm/index.vue b/rtsp-vue/src/views/video/alarm/index.vue new file mode 100644 index 0000000..7e3f180 --- /dev/null +++ b/rtsp-vue/src/views/video/alarm/index.vue @@ -0,0 +1,349 @@ + + + \ No newline at end of file diff --git a/rtsp-vue/src/views/video/inspection/index.vue b/rtsp-vue/src/views/video/inspection/index.vue new file mode 100644 index 0000000..a50aa7d --- /dev/null +++ b/rtsp-vue/src/views/video/inspection/index.vue @@ -0,0 +1,365 @@ + + + \ No newline at end of file diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 001cdff..37872e7 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -58,6 +58,15 @@ com.ruoyi ruoyi-video + + org.springframework + spring-context + + + org.bytedeco + javacv-platform + 1.5.9 + diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java index 0c384c6..b5aedd2 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java @@ -163,7 +163,7 @@ public class Constants /** * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加) */ - public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" }; + public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" ,"com.ruoyi.video"}; /** * 定时任务违规的字符 diff --git a/ruoyi-video/pom.xml b/ruoyi-video/pom.xml index 889f26a..907ade8 100644 --- a/ruoyi-video/pom.xml +++ b/ruoyi-video/pom.xml @@ -18,6 +18,11 @@ + + org.bytedeco + javacv-platform + 1.5.9 + com.ruoyi @@ -109,6 +114,12 @@ ffmpeg-platform 6.1.1-1.5.10 + + org.testng + testng + RELEASE + compile + \ No newline at end of file diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/controller/AlarmRecordController.java b/ruoyi-video/src/main/java/com/ruoyi/video/controller/AlarmRecordController.java new file mode 100644 index 0000000..671e01d --- /dev/null +++ b/ruoyi-video/src/main/java/com/ruoyi/video/controller/AlarmRecordController.java @@ -0,0 +1,90 @@ +package com.ruoyi.video.controller; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.video.domain.AlarmRecord; +import com.ruoyi.video.service.InspectionTaskService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletResponse; + + +import java.util.List; + +/** + * 报警记录Controller + * + * @Author: orange + * @CreateTime: 2025-01-16 + */ +@RestController +@RequestMapping("/video/alarm") +public class AlarmRecordController extends BaseController { + + @Autowired + private InspectionTaskService inspectionTaskService; + + /** + * 查询报警记录列表 + */ + @PreAuthorize("@ss.hasPermi('video:alarm:list')") + @GetMapping("/list") + public TableDataInfo list(AlarmRecord alarmRecord) { + startPage(); + List list = inspectionTaskService.selectAlarmRecordList(alarmRecord); + return getDataTable(list); + } + + /** + * 导出报警记录列表 + */ + @PreAuthorize("@ss.hasPermi('video:alarm:export')") + @Log(title = "报警记录", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, AlarmRecord alarmRecord) { + List list = inspectionTaskService.selectAlarmRecordList(alarmRecord); + ExcelUtil util = new ExcelUtil(AlarmRecord.class); + util.exportExcel(response, list, "报警记录数据"); + } + + /** + * 处理报警记录 + */ + @PreAuthorize("@ss.hasPermi('video:alarm:handle')") + @Log(title = "处理报警记录", businessType = BusinessType.UPDATE) + @PostMapping("/handle") + public AjaxResult handle(@RequestParam Long alarmId, + @RequestParam String handleStatus, + @RequestParam(required = false) String handleRemark) { + String handleBy = SecurityUtils.getUsername(); + int result = inspectionTaskService.handleAlarmRecord(alarmId, handleStatus, handleRemark, handleBy); + return toAjax(result); + } + + /** + * 批量处理报警记录 + */ + @PreAuthorize("@ss.hasPermi('video:alarm:handle')") + @Log(title = "批量处理报警记录", businessType = BusinessType.UPDATE) + @PostMapping("/batchHandle") + public AjaxResult batchHandle(@RequestParam Long[] alarmIds, + @RequestParam String handleStatus, + @RequestParam(required = false) String handleRemark) { + String handleBy = SecurityUtils.getUsername(); + int successCount = 0; + for (Long alarmId : alarmIds) { + int result = inspectionTaskService.handleAlarmRecord(alarmId, handleStatus, handleRemark, handleBy); + if (result > 0) { + successCount++; + } + } + return success("成功处理 " + successCount + " 条记录"); + } +} \ No newline at end of file diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/controller/InspectionTaskController.java b/ruoyi-video/src/main/java/com/ruoyi/video/controller/InspectionTaskController.java new file mode 100644 index 0000000..710e0bb --- /dev/null +++ b/ruoyi-video/src/main/java/com/ruoyi/video/controller/InspectionTaskController.java @@ -0,0 +1,126 @@ +package com.ruoyi.video.controller; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.video.domain.InspectionTask; +import com.ruoyi.video.service.InspectionTaskService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +/** + * 巡检任务Controller + * + * @Author: orange + * @CreateTime: 2025-01-16 + */ +@RestController +@RequestMapping("/video/inspection") +public class InspectionTaskController extends BaseController { + + @Autowired + private InspectionTaskService inspectionTaskService; + + /** + * 查询巡检任务列表 + */ + @PreAuthorize("@ss.hasPermi('video:inspection:list')") + @GetMapping("/list") + public TableDataInfo list(InspectionTask inspectionTask) { + startPage(); + List list = inspectionTaskService.selectInspectionTaskList(inspectionTask); + return getDataTable(list); + } + + /** + * 导出巡检任务列表 + */ + @PreAuthorize("@ss.hasPermi('video:inspection:export')") + @Log(title = "巡检任务", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, InspectionTask inspectionTask) { + List list = inspectionTaskService.selectInspectionTaskList(inspectionTask); + ExcelUtil util = new ExcelUtil(InspectionTask.class); + util.exportExcel(response, list, "巡检任务数据"); + } + + /** + * 获取巡检任务详细信息 + */ + @PreAuthorize("@ss.hasPermi('video:inspection:query')") + @GetMapping(value = "/{taskId}") + public AjaxResult getInfo(@PathVariable("taskId") Long taskId) { + return success(inspectionTaskService.selectInspectionTaskById(taskId)); + } + + /** + * 新增巡检任务 + */ + @PreAuthorize("@ss.hasPermi('video:inspection:add')") + @Log(title = "巡检任务", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody InspectionTask inspectionTask) { + return toAjax(inspectionTaskService.insertInspectionTask(inspectionTask)); + } + + /** + * 修改巡检任务 + */ + @PreAuthorize("@ss.hasPermi('video:inspection:edit')") + @Log(title = "巡检任务", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody InspectionTask inspectionTask) { + return toAjax(inspectionTaskService.updateInspectionTask(inspectionTask)); + } + + /** + * 删除巡检任务 + */ + @PreAuthorize("@ss.hasPermi('video:inspection:remove')") + @Log(title = "巡检任务", businessType = BusinessType.DELETE) + @DeleteMapping("/{taskIds}") + public AjaxResult remove(@PathVariable Long[] taskIds) { + return toAjax(inspectionTaskService.deleteInspectionTaskByIds(taskIds)); + } + + /** + * 启动巡检任务 + */ + @PreAuthorize("@ss.hasPermi('video:inspection:start')") + @Log(title = "启动巡检任务", businessType = BusinessType.UPDATE) + @PostMapping("/start/{taskId}") + public AjaxResult start(@PathVariable Long taskId) { + boolean result = inspectionTaskService.startInspectionTask(taskId); + return result ? success("启动成功") : error("启动失败"); + } + + /** + * 停止巡检任务 + */ + @PreAuthorize("@ss.hasPermi('video:inspection:stop')") + @Log(title = "停止巡检任务", businessType = BusinessType.UPDATE) + @PostMapping("/stop/{taskId}") + public AjaxResult stop(@PathVariable Long taskId) { + boolean result = inspectionTaskService.stopInspectionTask(taskId); + return result ? success("停止成功") : error("停止失败"); + } + + /** + * 手动执行巡检任务 + */ + @PreAuthorize("@ss.hasPermi('video:inspection:execute')") + @Log(title = "执行巡检任务", businessType = BusinessType.UPDATE) + @PostMapping("/execute/{taskId}") + public AjaxResult execute(@PathVariable Long taskId) { + inspectionTaskService.executeInspectionTask(taskId); + return success("任务已提交执行"); + } +} \ No newline at end of file diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/domain/AlarmRecord.java b/ruoyi-video/src/main/java/com/ruoyi/video/domain/AlarmRecord.java new file mode 100644 index 0000000..e7fc191 --- /dev/null +++ b/ruoyi-video/src/main/java/com/ruoyi/video/domain/AlarmRecord.java @@ -0,0 +1,234 @@ +package com.ruoyi.video.domain; + +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.util.Date; + +/** + * 报警记录对象 v_alarm_record + * + * @Author: orange + * @CreateTime: 2025-01-16 + */ +public class AlarmRecord extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 报警记录ID */ + private Long alarmId; + + /** 巡检任务ID */ + @Excel(name = "巡检任务ID") + private Long taskId; + + /** 任务名称 */ + @Excel(name = "任务名称") + private String taskName; + + /** 设备ID */ + @Excel(name = "设备ID") + private Long deviceId; + + /** 设备名称 */ + @Excel(name = "设备名称") + private String deviceName; + + /** 报警类型 */ + @Excel(name = "报警类型") + private String alarmType; + + /** 报警级别(1=低,2=中,3=高) */ + @Excel(name = "报警级别", readConverterExp = "1=低,2=中,3=高") + private String alarmLevel; + + /** 报警描述 */ + @Excel(name = "报警描述") + private String alarmDesc; + + /** 检测置信度 */ + @Excel(name = "检测置信度") + private Double confidence; + + /** 报警图片路径 */ + @Excel(name = "报警图片") + private String imagePath; + + /** 报警视频路径 */ + @Excel(name = "报警视频") + private String videoPath; + + /** 报警时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "报警时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date alarmTime; + + /** 处理状态(0=未处理,1=已处理,2=已忽略) */ + @Excel(name = "处理状态", readConverterExp = "0=未处理,1=已处理,2=已忽略") + private String handleStatus; + + /** 处理人 */ + @Excel(name = "处理人") + private String handleBy; + + /** 处理时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "处理时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date handleTime; + + /** 处理备注 */ + @Excel(name = "处理备注") + private String handleRemark; + + public AlarmRecord() {} + + public Long getAlarmId() { + return alarmId; + } + + public void setAlarmId(Long alarmId) { + this.alarmId = alarmId; + } + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getTaskName() { + return taskName; + } + + public void setTaskName(String taskName) { + this.taskName = taskName; + } + + public Long getDeviceId() { + return deviceId; + } + + public void setDeviceId(Long deviceId) { + this.deviceId = deviceId; + } + + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + public String getAlarmType() { + return alarmType; + } + + public void setAlarmType(String alarmType) { + this.alarmType = alarmType; + } + + public String getAlarmLevel() { + return alarmLevel; + } + + public void setAlarmLevel(String alarmLevel) { + this.alarmLevel = alarmLevel; + } + + public String getAlarmDesc() { + return alarmDesc; + } + + public void setAlarmDesc(String alarmDesc) { + this.alarmDesc = alarmDesc; + } + + public Double getConfidence() { + return confidence; + } + + public void setConfidence(Double confidence) { + this.confidence = confidence; + } + + public String getImagePath() { + return imagePath; + } + + public void setImagePath(String imagePath) { + this.imagePath = imagePath; + } + + public String getVideoPath() { + return videoPath; + } + + public void setVideoPath(String videoPath) { + this.videoPath = videoPath; + } + + public Date getAlarmTime() { + return alarmTime; + } + + public void setAlarmTime(Date alarmTime) { + this.alarmTime = alarmTime; + } + + public String getHandleStatus() { + return handleStatus; + } + + public void setHandleStatus(String handleStatus) { + this.handleStatus = handleStatus; + } + + public String getHandleBy() { + return handleBy; + } + + public void setHandleBy(String handleBy) { + this.handleBy = handleBy; + } + + public Date getHandleTime() { + return handleTime; + } + + public void setHandleTime(Date handleTime) { + this.handleTime = handleTime; + } + + public String getHandleRemark() { + return handleRemark; + } + + public void setHandleRemark(String handleRemark) { + this.handleRemark = handleRemark; + } + + @Override + public String toString() { + return "AlarmRecord{" + + "alarmId=" + alarmId + + ", taskId=" + taskId + + ", taskName='" + taskName + '\'' + + ", deviceId=" + deviceId + + ", deviceName='" + deviceName + '\'' + + ", alarmType='" + alarmType + '\'' + + ", alarmLevel='" + alarmLevel + '\'' + + ", alarmDesc='" + alarmDesc + '\'' + + ", confidence=" + confidence + + ", imagePath='" + imagePath + '\'' + + ", videoPath='" + videoPath + '\'' + + ", alarmTime=" + alarmTime + + ", handleStatus='" + handleStatus + '\'' + + ", handleBy='" + handleBy + '\'' + + ", handleTime=" + handleTime + + ", handleRemark='" + handleRemark + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/domain/InspectionTask.java b/ruoyi-video/src/main/java/com/ruoyi/video/domain/InspectionTask.java new file mode 100644 index 0000000..735e04d --- /dev/null +++ b/ruoyi-video/src/main/java/com/ruoyi/video/domain/InspectionTask.java @@ -0,0 +1,195 @@ +package com.ruoyi.video.domain; + +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.util.Date; + +/** + * 巡检任务对象 v_inspection_task + * + * @Author: orange + * @CreateTime: 2025-01-16 + */ +public class InspectionTask extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** 巡检任务ID */ + private Long taskId; + + /** 任务名称 */ + @Excel(name = "任务名称") + private String taskName; + + /** 设备ID */ + @Excel(name = "设备ID") + private Long deviceId; + + /** 设备名称 */ + @Excel(name = "设备名称") + private String deviceName; + + /** Cron表达式 */ + @Excel(name = "Cron表达式") + private String cronExpression; + + /** 巡检时长(秒) */ + @Excel(name = "巡检时长") + private Integer duration; + + /** 任务状态(0=启用,1=停用) */ + @Excel(name = "任务状态", readConverterExp = "0=启用,1=停用") + private String status; + + /** 是否启用检测(0=启用,1=停用) */ + @Excel(name = "启用检测", readConverterExp = "0=启用,1=停用") + private String enableDetection; + + /** 检测阈值 */ + @Excel(name = "检测阈值") + private Double threshold; + + /** 最后执行时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "最后执行时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date lastExecuteTime; + + /** 下次执行时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "下次执行时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date nextExecuteTime; + + /** 执行次数 */ + @Excel(name = "执行次数") + private Long executeCount; + + /** 报警次数 */ + @Excel(name = "报警次数") + private Long alarmCount; + + public InspectionTask() {} + + public Long getTaskId() { + return taskId; + } + + public void setTaskId(Long taskId) { + this.taskId = taskId; + } + + public String getTaskName() { + return taskName; + } + + public void setTaskName(String taskName) { + this.taskName = taskName; + } + + public Long getDeviceId() { + return deviceId; + } + + public void setDeviceId(Long deviceId) { + this.deviceId = deviceId; + } + + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + public String getCronExpression() { + return cronExpression; + } + + public void setCronExpression(String cronExpression) { + this.cronExpression = cronExpression; + } + + public Integer getDuration() { + return duration; + } + + public void setDuration(Integer duration) { + this.duration = duration; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getEnableDetection() { + return enableDetection; + } + + public void setEnableDetection(String enableDetection) { + this.enableDetection = enableDetection; + } + + public Double getThreshold() { + return threshold; + } + + public void setThreshold(Double threshold) { + this.threshold = threshold; + } + + public Date getLastExecuteTime() { + return lastExecuteTime; + } + + public void setLastExecuteTime(Date lastExecuteTime) { + this.lastExecuteTime = lastExecuteTime; + } + + public Date getNextExecuteTime() { + return nextExecuteTime; + } + + public void setNextExecuteTime(Date nextExecuteTime) { + this.nextExecuteTime = nextExecuteTime; + } + + public Long getExecuteCount() { + return executeCount; + } + + public void setExecuteCount(Long executeCount) { + this.executeCount = executeCount; + } + + public Long getAlarmCount() { + return alarmCount; + } + + public void setAlarmCount(Long alarmCount) { + this.alarmCount = alarmCount; + } + + @Override + public String toString() { + return "InspectionTask{" + + "taskId=" + taskId + + ", taskName='" + taskName + '\'' + + ", deviceId=" + deviceId + + ", deviceName='" + deviceName + '\'' + + ", cronExpression='" + cronExpression + '\'' + + ", duration=" + duration + + ", status='" + status + '\'' + + ", enableDetection='" + enableDetection + '\'' + + ", threshold=" + threshold + + ", lastExecuteTime=" + lastExecuteTime + + ", nextExecuteTime=" + nextExecuteTime + + ", executeCount=" + executeCount + + ", alarmCount=" + alarmCount + + '}'; + } +} \ No newline at end of file diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/mapper/AlarmRecordMapper.java b/ruoyi-video/src/main/java/com/ruoyi/video/mapper/AlarmRecordMapper.java new file mode 100644 index 0000000..42c4f36 --- /dev/null +++ b/ruoyi-video/src/main/java/com/ruoyi/video/mapper/AlarmRecordMapper.java @@ -0,0 +1,87 @@ +package com.ruoyi.video.mapper; + +import com.ruoyi.video.domain.AlarmRecord; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 报警记录Mapper接口 + * + * @author ruoyi + * @date 2025-01-16 + */ +@Mapper +public interface AlarmRecordMapper { + + /** + * 查询报警记录 + * + * @param alarmId 报警记录主键 + * @return 报警记录 + */ + public AlarmRecord selectAlarmRecordByAlarmId(Long alarmId); + + /** + * 查询报警记录列表 + * + * @param alarmRecord 报警记录 + * @return 报警记录集合 + */ + public List selectAlarmRecordList(AlarmRecord alarmRecord); + + /** + * 新增报警记录 + * + * @param alarmRecord 报警记录 + * @return 结果 + */ + public int insertAlarmRecord(AlarmRecord alarmRecord); + + /** + * 修改报警记录 + * + * @param alarmRecord 报警记录 + * @return 结果 + */ + public int updateAlarmRecord(AlarmRecord alarmRecord); + + /** + * 删除报警记录 + * + * @param alarmId 报警记录主键 + * @return 结果 + */ + public int deleteAlarmRecordByAlarmId(Long alarmId); + + /** + * 批量删除报警记录 + * + * @param alarmIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteAlarmRecordByAlarmIds(Long[] alarmIds); + + /** + * 处理报警记录 + * + * @param alarmId 报警ID + * @param handleStatus 处理状态 + * @param handleRemark 处理备注 + * @param handleBy 处理人 + * @return 结果 + */ + public int handleAlarmRecord(@Param("alarmId") Long alarmId, + @Param("handleStatus") String handleStatus, + @Param("handleRemark") String handleRemark, + @Param("handleBy") String handleBy); + + /** + * 根据任务ID统计报警数量 + * + * @param taskId 任务ID + * @return 报警数量 + */ + public Long countAlarmByTaskId(@Param("taskId") Long taskId); +} \ No newline at end of file diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/mapper/InspectionTaskMapper.java b/ruoyi-video/src/main/java/com/ruoyi/video/mapper/InspectionTaskMapper.java new file mode 100644 index 0000000..b3c6931 --- /dev/null +++ b/ruoyi-video/src/main/java/com/ruoyi/video/mapper/InspectionTaskMapper.java @@ -0,0 +1,84 @@ +package com.ruoyi.video.mapper; + +import com.ruoyi.video.domain.InspectionTask; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 巡检任务Mapper接口 + * + * @author ruoyi + * @date 2025-01-16 + */ +@Mapper +public interface InspectionTaskMapper { + + /** + * 查询巡检任务 + * + * @param taskId 巡检任务主键 + * @return 巡检任务 + */ + public InspectionTask selectInspectionTaskByTaskId(Long taskId); + + /** + * 查询巡检任务列表 + * + * @param inspectionTask 巡检任务 + * @return 巡检任务集合 + */ + public List selectInspectionTaskList(InspectionTask inspectionTask); + + /** + * 新增巡检任务 + * + * @param inspectionTask 巡检任务 + * @return 结果 + */ + public int insertInspectionTask(InspectionTask inspectionTask); + + /** + * 修改巡检任务 + * + * @param inspectionTask 巡检任务 + * @return 结果 + */ + public int updateInspectionTask(InspectionTask inspectionTask); + + /** + * 删除巡检任务 + * + * @param taskId 巡检任务主键 + * @return 结果 + */ + public int deleteInspectionTaskByTaskId(Long taskId); + + /** + * 批量删除巡检任务 + * + * @param taskIds 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteInspectionTaskByTaskIds(Long[] taskIds); + + /** + * 查询启用状态的巡检任务列表 + * + * @return 巡检任务集合 + */ + public List selectEnabledInspectionTaskList(); + + /** + * 更新任务执行信息 + * + * @param taskId 任务ID + * @param executeCount 执行次数 + * @param alarmCount 报警次数 + * @return 结果 + */ + public int updateTaskExecuteInfo(@Param("taskId") Long taskId, + @Param("executeCount") Long executeCount, + @Param("alarmCount") Long alarmCount); +} \ No newline at end of file diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/service/InspectionTaskService.java b/ruoyi-video/src/main/java/com/ruoyi/video/service/InspectionTaskService.java new file mode 100644 index 0000000..5added9 --- /dev/null +++ b/ruoyi-video/src/main/java/com/ruoyi/video/service/InspectionTaskService.java @@ -0,0 +1,78 @@ +package com.ruoyi.video.service; + +import com.ruoyi.video.domain.InspectionTask; +import com.ruoyi.video.domain.AlarmRecord; +import com.ruoyi.video.domain.Detection; +import org.springframework.scheduling.annotation.Async; + +import java.util.List; + +/** + * 巡检任务服务接口 + * + * @Author: orange + * @CreateTime: 2025-01-16 + */ +public interface InspectionTaskService { + + /** + * 查询巡检任务列表 + */ + List selectInspectionTaskList(InspectionTask inspectionTask); + + /** + * 根据ID查询巡检任务 + */ + InspectionTask selectInspectionTaskById(Long taskId); + + /** + * 新增巡检任务 + */ + int insertInspectionTask(InspectionTask inspectionTask); + + /** + * 修改巡检任务 + */ + int updateInspectionTask(InspectionTask inspectionTask); + + /** + * 删除巡检任务 + */ + int deleteInspectionTaskByIds(Long[] taskIds); + + /** + * 启动巡检任务 + */ + boolean startInspectionTask(Long taskId); + + /** + * 停止巡检任务 + */ + boolean stopInspectionTask(Long taskId); + + /** + * 执行单次巡检任务 + */ + @Async + void executeInspectionTask(Long taskId); + + /** + * 处理检测结果,如果有异常则生成报警 + */ + void handleDetectionResults(Long taskId, List detections, String imagePath); + + /** + * 保存报警记录 + */ + void saveAlarmRecord(AlarmRecord alarmRecord); + + /** + * 查询报警记录列表 + */ + List selectAlarmRecordList(AlarmRecord alarmRecord); + + /** + * 处理报警记录 + */ + int handleAlarmRecord(Long alarmId, String handleStatus, String handleRemark, String handleBy); +} \ No newline at end of file diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/service/impl/InspectionTaskServiceImpl.java b/ruoyi-video/src/main/java/com/ruoyi/video/service/impl/InspectionTaskServiceImpl.java new file mode 100644 index 0000000..0a2f639 --- /dev/null +++ b/ruoyi-video/src/main/java/com/ruoyi/video/service/impl/InspectionTaskServiceImpl.java @@ -0,0 +1,361 @@ +package com.ruoyi.video.service.impl; + +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.video.domain.*; +import com.ruoyi.video.domain.dto.CameraDto; +import com.ruoyi.video.mapper.InspectionTaskMapper; +import com.ruoyi.video.mapper.AlarmRecordMapper; +import com.ruoyi.video.service.IDeviceService; +import com.ruoyi.video.service.InspectionTaskService; +import com.ruoyi.video.thread.MediaTransferFlvByJavacv; +import com.ruoyi.video.common.ModelManager; +import com.ruoyi.video.thread.detector.YoloDetector; +import lombok.extern.slf4j.Slf4j; +import org.bytedeco.javacv.Frame; +import org.bytedeco.javacv.FrameGrabber; +import org.bytedeco.javacv.FFmpegFrameGrabber; +import org.bytedeco.javacv.OpenCVFrameConverter; +import org.bytedeco.opencv.opencv_core.Mat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 巡检任务服务实现 + * + * @Author: orange + * @CreateTime: 2025-01-16 + */ +@Slf4j +@Service +public class InspectionTaskServiceImpl implements InspectionTaskService { + + @Autowired + private IDeviceService deviceService; + + @Autowired + private InspectionTaskMapper inspectionTaskMapper; + + @Autowired + private AlarmRecordMapper alarmRecordMapper; + + // 运行状态缓存(避免重复执行) + private final Map runningTasks = new ConcurrentHashMap<>(); + + private ModelManager modelManager; + // 延迟初始化,避免启动时的依赖问题 + private OpenCVFrameConverter.ToMat toMat; + + @Override + public List selectInspectionTaskList(InspectionTask inspectionTask) { + return inspectionTaskMapper.selectInspectionTaskList(inspectionTask); + } + + @Override + public InspectionTask selectInspectionTaskById(Long taskId) { + return inspectionTaskMapper.selectInspectionTaskByTaskId(taskId); + } + + @Override + public int insertInspectionTask(InspectionTask inspectionTask) { + inspectionTask.setCreateTime(DateUtils.getNowDate()); + inspectionTask.setCreateBy(SecurityUtils.getUsername()); + inspectionTask.setExecuteCount(0L); + inspectionTask.setAlarmCount(0L); + + // 获取设备信息 + Device device = deviceService.selectDeviceByDeviceId(inspectionTask.getDeviceId()); + if (device != null) { + inspectionTask.setDeviceName(device.getIp()); + } + + return inspectionTaskMapper.insertInspectionTask(inspectionTask); + } + + @Override + public int updateInspectionTask(InspectionTask inspectionTask) { + inspectionTask.setUpdateTime(DateUtils.getNowDate()); + inspectionTask.setUpdateBy(SecurityUtils.getUsername()); + return inspectionTaskMapper.updateInspectionTask(inspectionTask); + } + + @Override + public int deleteInspectionTaskByIds(Long[] taskIds) { + for (Long taskId : taskIds) { + stopInspectionTask(taskId); + } + return inspectionTaskMapper.deleteInspectionTaskByTaskIds(taskIds); + } + + @Override + public boolean startInspectionTask(Long taskId) { + InspectionTask task = inspectionTaskMapper.selectInspectionTaskByTaskId(taskId); + if (task == null) { + return false; + } + + task.setStatus("0"); // 启用 + task.setUpdateTime(DateUtils.getNowDate()); + task.setUpdateBy(SecurityUtils.getUsername()); + inspectionTaskMapper.updateInspectionTask(task); + + runningTasks.put(taskId, true); + + // 这里应该集成到Quartz定时任务中 + log.info("启动巡检任务: {} - {}", taskId, task.getTaskName()); + return true; + } + + @Override + public boolean stopInspectionTask(Long taskId) { + InspectionTask task = inspectionTaskMapper.selectInspectionTaskByTaskId(taskId); + if (task == null) { + return false; + } + + task.setStatus("1"); // 停用 + task.setUpdateTime(DateUtils.getNowDate()); + task.setUpdateBy(SecurityUtils.getUsername()); + inspectionTaskMapper.updateInspectionTask(task); + + runningTasks.remove(taskId); + + log.info("停止巡检任务: {} - {}", taskId, task.getTaskName()); + return true; + } + + @Override + @Async + public void executeInspectionTask(Long taskId) { + InspectionTask task = inspectionTaskMapper.selectInspectionTaskByTaskId(taskId); + if (task == null || !"0".equals(task.getStatus())) { + return; + } + + log.info("开始执行巡检任务: {} - {}", taskId, task.getTaskName()); + + try { + // 更新执行信息 + task.setLastExecuteTime(new Date()); + task.setExecuteCount(task.getExecuteCount() + 1); + + // 获取设备信息 + Device device = deviceService.selectDeviceByDeviceId(task.getDeviceId()); + if (device == null) { + log.error("设备不存在: {}", task.getDeviceId()); + return; + } + + // 执行视频分析 + performVideoAnalysis(task, device); + + // 更新任务执行统计信息 + Long alarmCount = alarmRecordMapper.countAlarmByTaskId(taskId); + inspectionTaskMapper.updateTaskExecuteInfo(taskId, task.getExecuteCount(), alarmCount); + + } catch (Exception e) { + log.error("执行巡检任务失败: {} - {}", taskId, e.getMessage(), e); + } + } + + /** + * 执行视频分析 + */ + private void performVideoAnalysis(InspectionTask task, Device device) { + if (!"0".equals(task.getEnableDetection())) { + log.info("巡检任务未启用检测: {}", task.getTaskId()); + return; + } + + FFmpegFrameGrabber grabber = null; + try { + // 初始化模型管理器 + if (modelManager == null) { + modelManager = new ModelManager(); + URL json = getClass().getResource("/models/models.json"); + if (json != null) { + modelManager.load(json); + } + } + + // 创建视频抓取器 + grabber = new FFmpegFrameGrabber(device.getUrl()); + grabber.setOption("rtsp_transport", "tcp"); + grabber.setOption("stimeout", "5000000"); + grabber.start(); + + log.info("开始分析视频流: {}", device.getUrl()); + + // 分析指定时长的视频 + long startTime = System.currentTimeMillis(); + long duration = task.getDuration() * 1000L; // 转换为毫秒 + int frameCount = 0; + List allDetections = new ArrayList<>(); + + while (System.currentTimeMillis() - startTime < duration) { + Frame frame = grabber.grabImage(); + if (frame == null) continue; + + frameCount++; + + // 每隔一定帧数进行一次检测(避免过于频繁) + if (frameCount % 25 == 0) { // 假设25fps,每秒检测一次 + try { + // 延迟初始化转换器 + if (toMat == null) { + toMat = new OpenCVFrameConverter.ToMat(); + } + + Mat mat = toMat.convert(frame); + if (mat != null && !mat.empty()) { + List detections = performDetection(mat); + allDetections.addAll(detections); + + // 如果检测到异常,立即保存图片并记录报警 + if (!detections.isEmpty()) { + String imagePath = saveFrameAsImage(frame, task.getTaskId()); + handleDetectionResults(task.getTaskId(), detections, imagePath); + } + } + } catch (Exception e) { + log.error("帧处理失败: {}", e.getMessage()); + // 如果JavaCV有问题,跳过这一帧继续处理 + continue; + } + } + } + + log.info("巡检任务完成: {} - 分析帧数: {}, 检测结果: {}", + task.getTaskId(), frameCount, allDetections.size()); + + } catch (Exception e) { + log.error("视频分析失败: {}", e.getMessage(), e); + } finally { + if (grabber != null) { + try { + grabber.stop(); + grabber.release(); + } catch (Exception e) { + log.error("关闭视频抓取器失败", e); + } + } + } + } + + /** + * 执行目标检测 + */ + private List performDetection(Mat mat) { + try { + if (modelManager != null) { + YoloDetector detector = modelManager.get("person-helmet"); // 使用人员安全帽检测 + if (detector != null) { + return detector.detect(mat); + } + } + } catch (Exception e) { + log.error("目标检测失败: {}", e.getMessage(), e); + } + return Collections.emptyList(); + } + + /** + * 保存帧为图片 + */ + private String saveFrameAsImage(Frame frame, Long taskId) { + try { + // 创建保存目录 + String saveDir = "upload/alarm/" + DateUtils.dateTimeNow("yyyyMMdd"); + File dir = new File(saveDir); + if (!dir.exists()) { + dir.mkdirs(); + } + + // 生成文件名 + String fileName = "task_" + taskId + "_" + System.currentTimeMillis() + ".jpg"; + String filePath = saveDir + "/" + fileName; + + // 转换并保存图片 + BufferedImage bufferedImage = new org.bytedeco.javacv.Java2DFrameConverter().convert(frame); + ImageIO.write(bufferedImage, "jpg", new File(filePath)); + + return filePath; + } catch (IOException e) { + log.error("保存图片失败: {}", e.getMessage(), e); + return null; + } + } + + @Override + public void handleDetectionResults(Long taskId, List detections, String imagePath) { + InspectionTask task = inspectionTaskMapper.selectInspectionTaskByTaskId(taskId); + if (task == null || detections.isEmpty()) { + return; + } + + for (Detection detection : detections) { + // 检查置信度是否超过阈值 + if (detection.conf() >= task.getThreshold()) { + // 创建报警记录 + AlarmRecord alarmRecord = new AlarmRecord(); + alarmRecord.setTaskId(taskId); + alarmRecord.setTaskName(task.getTaskName()); + alarmRecord.setDeviceId(task.getDeviceId()); + alarmRecord.setDeviceName(task.getDeviceName()); + alarmRecord.setAlarmType(detection.cls()); + alarmRecord.setAlarmLevel(getAlarmLevel(detection.conf())); + alarmRecord.setAlarmDesc(String.format("检测到%s,置信度: %.2f", + detection.cls(), detection.conf())); + alarmRecord.setConfidence((double)detection.conf()); + alarmRecord.setImagePath(imagePath); + alarmRecord.setAlarmTime(new Date()); + alarmRecord.setHandleStatus("0"); // 未处理 + alarmRecord.setCreateBy(SecurityUtils.getUsername()); + + saveAlarmRecord(alarmRecord); + + log.warn("生成报警记录: 任务[{}] 检测到[{}] 置信度[{}]", + taskId, detection.cls(), detection.conf()); + } + } + } + + /** + * 根据置信度确定报警级别 + */ + private String getAlarmLevel(float confidence) { + if (confidence >= 0.9f) { + return "3"; // 高 + } else if (confidence >= 0.7f) { + return "2"; // 中 + } else { + return "1"; // 低 + } + } + + @Override + public void saveAlarmRecord(AlarmRecord alarmRecord) { + alarmRecord.setCreateTime(DateUtils.getNowDate()); + alarmRecordMapper.insertAlarmRecord(alarmRecord); + log.info("保存报警记录: {}", alarmRecord.getAlarmId()); + } + + @Override + public List selectAlarmRecordList(AlarmRecord alarmRecord) { + return alarmRecordMapper.selectAlarmRecordList(alarmRecord); + } + + @Override + public int handleAlarmRecord(Long alarmId, String handleStatus, String handleRemark, String handleBy) { + return alarmRecordMapper.handleAlarmRecord(alarmId, handleStatus, handleRemark, handleBy); + } +} \ No newline at end of file diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/task/InspectionTaskExecutor.java b/ruoyi-video/src/main/java/com/ruoyi/video/task/InspectionTaskExecutor.java new file mode 100644 index 0000000..96d6bda --- /dev/null +++ b/ruoyi-video/src/main/java/com/ruoyi/video/task/InspectionTaskExecutor.java @@ -0,0 +1,85 @@ +package com.ruoyi.video.task; + +import com.ruoyi.video.service.InspectionTaskService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 巡检任务执行器 + * 用于集成到若依的定时任务系统中 + * + * @Author: orange + * @CreateTime: 2025-01-16 + */ +@Slf4j +@Component("inspectionTaskExecutor") +public class InspectionTaskExecutor { + + @Autowired + private InspectionTaskService inspectionTaskService; + + /** + * 执行指定的巡检任务 + * 在定时任务中调用格式: inspectionTaskExecutor.executeTask(1L) + * + * @param taskId 巡检任务ID + */ + public void executeTask(Long taskId) { + log.info("定时任务触发巡检任务执行: {}", taskId); + try { + inspectionTaskService.executeInspectionTask(taskId); + } catch (Exception e) { + log.error("定时任务执行巡检任务失败: {} - {}", taskId, e.getMessage(), e); + } + } + + /** + * 执行指定的巡检任务(字符串参数版本) + * 在定时任务中调用格式: inspectionTaskExecutor.executeTaskByString('1') + * + * @param taskIdStr 巡检任务ID字符串 + */ + public void executeTaskByString(String taskIdStr) { + try { + Long taskId = Long.parseLong(taskIdStr); + executeTask(taskId); + } catch (NumberFormatException e) { + log.error("巡检任务ID格式错误: {}", taskIdStr); + } + } + + /** + * 批量执行多个巡检任务 + * 在定时任务中调用格式: inspectionTaskExecutor.executeBatchTasks('1,2,3') + * + * @param taskIdsStr 巡检任务ID列表,逗号分隔 + */ + public void executeBatchTasks(String taskIdsStr) { + log.info("定时任务触发批量巡检任务执行: {}", taskIdsStr); + try { + String[] taskIdArray = taskIdsStr.split(","); + for (String taskIdStr : taskIdArray) { + Long taskId = Long.parseLong(taskIdStr.trim()); + inspectionTaskService.executeInspectionTask(taskId); + } + } catch (Exception e) { + log.error("批量执行巡检任务失败: {} - {}", taskIdsStr, e.getMessage(), e); + } + } + + /** + * 执行所有启用的巡检任务 + * 在定时任务中调用格式: inspectionTaskExecutor.executeAllActiveTasks() + */ + public void executeAllActiveTasks() { + log.info("定时任务触发执行所有启用的巡检任务"); + try { + // 这里可以查询所有启用状态的任务并执行 + // 实际实现中需要查询数据库获取所有status='0'的任务 + log.info("执行所有启用的巡检任务完成"); + } catch (Exception e) { + log.error("执行所有启用的巡检任务失败: {}", e.getMessage(), e); + } + } +} \ No newline at end of file diff --git a/ruoyi-video/src/main/resources/mapper/video/AlarmRecordMapper.xml b/ruoyi-video/src/main/resources/mapper/video/AlarmRecordMapper.xml new file mode 100644 index 0000000..2ad8726 --- /dev/null +++ b/ruoyi-video/src/main/resources/mapper/video/AlarmRecordMapper.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select alarm_id, task_id, task_name, device_id, device_name, alarm_type, + alarm_level, alarm_desc, confidence, image_path, video_path, alarm_time, + handle_status, handle_by, handle_time, handle_remark, + create_by, create_time, update_by, update_time + from v_alarm_record + + + + + + + + + + insert into v_alarm_record + + task_id, + task_name, + device_id, + device_name, + alarm_type, + alarm_level, + alarm_desc, + confidence, + image_path, + video_path, + alarm_time, + handle_status, + create_by, + create_time + + + #{taskId}, + #{taskName}, + #{deviceId}, + #{deviceName}, + #{alarmType}, + #{alarmLevel}, + #{alarmDesc}, + #{confidence}, + #{imagePath}, + #{videoPath}, + #{alarmTime}, + #{handleStatus}, + #{createBy}, + sysdate() + + + + + update v_alarm_record + + task_id = #{taskId}, + task_name = #{taskName}, + device_id = #{deviceId}, + device_name = #{deviceName}, + alarm_type = #{alarmType}, + alarm_level = #{alarmLevel}, + alarm_desc = #{alarmDesc}, + confidence = #{confidence}, + image_path = #{imagePath}, + video_path = #{videoPath}, + alarm_time = #{alarmTime}, + handle_status = #{handleStatus}, + handle_by = #{handleBy}, + handle_time = #{handleTime}, + handle_remark = #{handleRemark}, + update_by = #{updateBy}, + update_time = sysdate() + + where alarm_id = #{alarmId} + + + + update v_alarm_record + set handle_status = #{handleStatus}, + handle_by = #{handleBy}, + handle_time = sysdate(), + handle_remark = #{handleRemark}, + update_time = sysdate() + where alarm_id = #{alarmId} + + + + delete from v_alarm_record where alarm_id = #{alarmId} + + + + delete from v_alarm_record where alarm_id in + + #{alarmId} + + + \ No newline at end of file diff --git a/ruoyi-video/src/main/resources/mapper/video/InspectionTaskMapper.xml b/ruoyi-video/src/main/resources/mapper/video/InspectionTaskMapper.xml new file mode 100644 index 0000000..71ae40a --- /dev/null +++ b/ruoyi-video/src/main/resources/mapper/video/InspectionTaskMapper.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + select task_id, task_name, device_id, device_name, cron_expression, duration, + threshold, enable_detection, status, execute_count, alarm_count, + last_execute_time, remark, create_by, create_time, update_by, update_time + from v_inspection_task + + + + + + + + + + insert into v_inspection_task + + task_name, + device_id, + device_name, + cron_expression, + duration, + threshold, + enable_detection, + status, + execute_count, + alarm_count, + last_execute_time, + remark, + create_by, + create_time + + + #{taskName}, + #{deviceId}, + #{deviceName}, + #{cronExpression}, + #{duration}, + #{threshold}, + #{enableDetection}, + #{status}, + #{executeCount}, + #{alarmCount}, + #{lastExecuteTime}, + #{remark}, + #{createBy}, + sysdate() + + + + + update v_inspection_task + + task_name = #{taskName}, + device_id = #{deviceId}, + device_name = #{deviceName}, + cron_expression = #{cronExpression}, + duration = #{duration}, + threshold = #{threshold}, + enable_detection = #{enableDetection}, + status = #{status}, + execute_count = #{executeCount}, + alarm_count = #{alarmCount}, + last_execute_time = #{lastExecuteTime}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where task_id = #{taskId} + + + + update v_inspection_task + set execute_count = #{executeCount}, + alarm_count = #{alarmCount}, + last_execute_time = sysdate(), + update_time = sysdate() + where task_id = #{taskId} + + + + delete from v_inspection_task where task_id = #{taskId} + + + + delete from v_inspection_task where task_id in + + #{taskId} + + + \ No newline at end of file diff --git a/sql/inspection_system.sql b/sql/inspection_system.sql new file mode 100644 index 0000000..80b0de8 --- /dev/null +++ b/sql/inspection_system.sql @@ -0,0 +1,83 @@ +-- 巡检任务表 +CREATE TABLE `v_inspection_task` ( + `task_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '巡检任务ID', + `task_name` varchar(100) NOT NULL COMMENT '任务名称', + `device_id` bigint(20) NOT NULL COMMENT '设备ID', + `device_name` varchar(100) DEFAULT NULL COMMENT '设备名称', + `cron_expression` varchar(100) NOT NULL COMMENT 'Cron表达式', + `duration` int(11) NOT NULL DEFAULT '300' COMMENT '巡检时长(秒)', + `status` char(1) NOT NULL DEFAULT '0' COMMENT '任务状态(0=启用,1=停用)', + `enable_detection` char(1) NOT NULL DEFAULT '0' COMMENT '是否启用检测(0=启用,1=停用)', + `threshold` decimal(3,2) NOT NULL DEFAULT '0.70' COMMENT '检测阈值', + `last_execute_time` datetime DEFAULT NULL COMMENT '最后执行时间', + `next_execute_time` datetime DEFAULT NULL COMMENT '下次执行时间', + `execute_count` bigint(20) DEFAULT '0' COMMENT '执行次数', + `alarm_count` bigint(20) DEFAULT '0' COMMENT '报警次数', + `create_by` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`task_id`), + KEY `idx_device_id` (`device_id`), + KEY `idx_status` (`status`), + KEY `idx_next_execute_time` (`next_execute_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='巡检任务表'; + +-- 报警记录表 +CREATE TABLE `v_alarm_record` ( + `alarm_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '报警记录ID', + `task_id` bigint(20) NOT NULL COMMENT '巡检任务ID', + `task_name` varchar(100) DEFAULT NULL COMMENT '任务名称', + `device_id` bigint(20) NOT NULL COMMENT '设备ID', + `device_name` varchar(100) DEFAULT NULL COMMENT '设备名称', + `alarm_type` varchar(50) NOT NULL COMMENT '报警类型', + `alarm_level` char(1) NOT NULL DEFAULT '1' COMMENT '报警级别(1=低,2=中,3=高)', + `alarm_desc` varchar(500) DEFAULT NULL COMMENT '报警描述', + `confidence` decimal(5,4) DEFAULT NULL COMMENT '检测置信度', + `image_path` varchar(500) DEFAULT NULL COMMENT '报警图片路径', + `video_path` varchar(500) DEFAULT NULL COMMENT '报警视频路径', + `alarm_time` datetime NOT NULL COMMENT '报警时间', + `handle_status` char(1) NOT NULL DEFAULT '0' COMMENT '处理状态(0=未处理,1=已处理,2=已忽略)', + `handle_by` varchar(64) DEFAULT NULL COMMENT '处理人', + `handle_time` datetime DEFAULT NULL COMMENT '处理时间', + `handle_remark` varchar(500) DEFAULT NULL COMMENT '处理备注', + `create_by` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`alarm_id`), + KEY `idx_task_id` (`task_id`), + KEY `idx_device_id` (`device_id`), + KEY `idx_alarm_time` (`alarm_time`), + KEY `idx_handle_status` (`handle_status`), + KEY `idx_alarm_level` (`alarm_level`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报警记录表'; + +-- 插入测试数据 +INSERT INTO `v_inspection_task` (`task_name`, `device_id`, `device_name`, `cron_expression`, `duration`, `status`, `enable_detection`, `threshold`, `create_time`) VALUES +('办公区域安全巡检', 1, '办公区摄像头', '0 0 8,12,18 * * ?', 600, '0', '0', 0.75, NOW()), +('停车场巡检任务', 2, '停车场摄像头', '0 0/30 * * * ?', 300, '0', '0', 0.70, NOW()), +('仓库区域夜间巡检', 3, '仓库摄像头', '0 0 22 * * ?', 1800, '1', '0', 0.80, NOW()); + +-- 菜单权限数据 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES +('视频巡检', 2000, 3, 'inspection', 'video/inspection/index', 1, 0, 'C', '0', '0', 'video:inspection:list', 'monitor', 'admin', NOW(), '', NULL, '视频巡检菜单'), +('报警记录', 2000, 4, 'alarm', 'video/alarm/index', 1, 0, 'C', '0', '0', 'video:alarm:list', 'bug', 'admin', NOW(), '', NULL, '报警记录菜单'); + +-- 巡检任务权限 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES +('巡检任务查询', (SELECT menu_id FROM sys_menu WHERE perms = 'video:inspection:list'), 1, '', '', 1, 0, 'F', '0', '0', 'video:inspection:query', '#', 'admin', NOW(), '', NULL, ''), +('巡检任务新增', (SELECT menu_id FROM sys_menu WHERE perms = 'video:inspection:list'), 2, '', '', 1, 0, 'F', '0', '0', 'video:inspection:add', '#', 'admin', NOW(), '', NULL, ''), +('巡检任务修改', (SELECT menu_id FROM sys_menu WHERE perms = 'video:inspection:list'), 3, '', '', 1, 0, 'F', '0', '0', 'video:inspection:edit', '#', 'admin', NOW(), '', NULL, ''), +('巡检任务删除', (SELECT menu_id FROM sys_menu WHERE perms = 'video:inspection:list'), 4, '', '', 1, 0, 'F', '0', '0', 'video:inspection:remove', '#', 'admin', NOW(), '', NULL, ''), +('巡检任务导出', (SELECT menu_id FROM sys_menu WHERE perms = 'video:inspection:list'), 5, '', '', 1, 0, 'F', '0', '0', 'video:inspection:export', '#', 'admin', NOW(), '', NULL, ''), +('巡检任务启动', (SELECT menu_id FROM sys_menu WHERE perms = 'video:inspection:list'), 6, '', '', 1, 0, 'F', '0', '0', 'video:inspection:start', '#', 'admin', NOW(), '', NULL, ''), +('巡检任务停止', (SELECT menu_id FROM sys_menu WHERE perms = 'video:inspection:list'), 7, '', '', 1, 0, 'F', '0', '0', 'video:inspection:stop', '#', 'admin', NOW(), '', NULL, ''), +('巡检任务执行', (SELECT menu_id FROM sys_menu WHERE perms = 'video:inspection:list'), 8, '', '', 1, 0, 'F', '0', '0', 'video:inspection:execute', '#', 'admin', NOW(), '', NULL, ''); + +-- 报警记录权限 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES +('报警记录查询', (SELECT menu_id FROM sys_menu WHERE perms = 'video:alarm:list'), 1, '', '', 1, 0, 'F', '0', '0', 'video:alarm:query', '#', 'admin', NOW(), '', NULL, ''), +('报警记录导出', (SELECT menu_id FROM sys_menu WHERE perms = 'video:alarm:list'), 2, '', '', 1, 0, 'F', '0', '0', 'video:alarm:export', '#', 'admin', NOW(), '', NULL, ''), +('报警记录处理', (SELECT menu_id FROM sys_menu WHERE perms = 'video:alarm:list'), 3, '', '', 1, 0, 'F', '0', '0', 'video:alarm:handle', '#', 'admin', NOW(), '', NULL, ''); \ No newline at end of file