package com.ard.work.inspect.task;
|
|
import com.ard.common.core.constant.SecurityConstants;
|
import com.ard.common.core.domain.R;
|
import com.ard.common.core.utils.SpringUtils;
|
import com.ard.common.core.web.domain.AjaxResult;
|
import com.ard.system.api.RemoteConfigService;
|
import com.ard.work.api.domian.ArdWell;
|
import com.ard.work.api.domian.CameraCmd;
|
import com.ard.work.api.domian.PtzDto;
|
import com.ard.work.device.camera.service.IArdCameraService;
|
import com.ard.work.inspect.domain.ArdVideoInspectRecord;
|
import com.ard.work.inspect.domain.ArdVideoInspectTask;
|
import com.ard.work.inspect.domain.ArdVideoInspectTaskStep;
|
import com.ard.work.inspect.service.IArdVideoInspectRecordService;
|
import com.ard.work.api.domian.ArdWellGuideCamera;
|
import com.ard.work.point.well.service.IArdWellGuideCameraService;
|
import com.ard.work.point.well.service.IArdWellService;
|
import com.ard.work.sdk.service.CameraSDKService;
|
import com.ard.work.api.domian.Point;
|
import lombok.extern.slf4j.Slf4j;
|
|
import java.time.LocalTime;
|
import java.util.Date;
|
import java.util.List;
|
|
@Slf4j
|
public class TaskWrapper implements Runnable {
|
public volatile TaskStatus status = TaskStatus.RUNNING;
|
private final ArdVideoInspectTask task;
|
private ArdVideoInspectTaskStep currentStep;
|
private Date stepStartTime;
|
private final CameraSDKService cameraSDKService = SpringUtils.getBean(CameraSDKService.class);
|
private final IArdCameraService ardCameraService = SpringUtils.getBean(IArdCameraService.class);
|
private final IArdVideoInspectRecordService ardVideoInspectRecordService =
|
SpringUtils.getBean(IArdVideoInspectRecordService.class);
|
private final IArdWellService ardWellService = SpringUtils.getBean(IArdWellService.class);
|
private final IArdWellGuideCameraService ardWellGuideCameraService =
|
SpringUtils.getBean(IArdWellGuideCameraService.class);
|
private final RemoteConfigService remoteConfigService =
|
SpringUtils.getBean(RemoteConfigService.class);
|
public TaskWrapper(ArdVideoInspectTask task) {
|
this.task = task;
|
}
|
|
@Override
|
public void run() {
|
List<ArdVideoInspectTaskStep> steps = task.getArdVideoInspectTaskSteps();
|
if (steps.isEmpty()) return;
|
while (status != TaskStatus.CANCELED) { // 循环直到任务被取消
|
for (ArdVideoInspectTaskStep step : steps) {
|
if (status == TaskStatus.CANCELED) break;
|
|
currentStep = step;
|
stepStartTime = new Date(); // 记录当前步骤的开始时间
|
log.info("开始执行任务【{}】 的巡检步骤【{}】,时间:{}", step.getTaskId(), step.getId(), stepStartTime);
|
// 执行步骤
|
executeStep(step);
|
|
// 等待步骤完成
|
waitForStepCompletion(step);
|
}
|
}
|
log.info("任务被取消或完成");
|
}
|
|
//等待步骤完成
|
private void waitForStepCompletion(ArdVideoInspectTaskStep step) {
|
while (!isStepCompleted()) {
|
if (status == TaskStatus.CANCELED) {
|
handleCancellation(step);
|
return;
|
}
|
|
if (status == TaskStatus.PAUSED) {
|
handlePause(step);
|
}
|
try {
|
Thread.sleep(100); // 每 100 毫秒检查一次
|
} catch (InterruptedException e) {
|
Thread.currentThread().interrupt();
|
log.error("任务线程被中断");
|
return;
|
}
|
}
|
|
log.info("完成任务【{}】的巡检步骤【{}】", task.getId(), step.getId());
|
finalizeStep(step);
|
}
|
|
//处理暂停
|
private void handlePause(ArdVideoInspectTaskStep step) {
|
log.info("任务【{}】暂停,等待恢复...", task.getId());
|
synchronized (this) {
|
while (status == TaskStatus.PAUSED) {
|
try {
|
stopRecording(step);
|
wait(); // 暂停任务
|
} catch (InterruptedException e) {
|
Thread.currentThread().interrupt();
|
log.error("任务线程在暂停时被中断");
|
break;
|
}
|
}
|
}
|
}
|
|
//处理取消
|
private void handleCancellation(ArdVideoInspectTaskStep step) {
|
log.info("任务【{}】被取消,停止执行", task.getId());
|
stopRecording(step);
|
}
|
|
//处理完成
|
private void finalizeStep(ArdVideoInspectTaskStep step) {
|
stopRecording(step);
|
//recordStep(step, ""); // 提供空 URL 或根据需要调整
|
}
|
|
//执行任务
|
private void executeStep(ArdVideoInspectTaskStep step) {
|
log.info("执行任务 {} 的步骤 {}", step.getTaskId(), step.getId());
|
startRecording(step);
|
}
|
|
//步骤是否完成
|
private boolean isStepCompleted() {
|
long elapsedMillis = new Date().getTime() - stepStartTime.getTime();
|
long elapsedSeconds = elapsedMillis / 1000;
|
return elapsedSeconds >= currentStep.getRecordingTime();
|
}
|
|
//暂停
|
public void pause() {
|
this.status = TaskStatus.PAUSED;
|
}
|
|
//恢复
|
public void resume() {
|
this.status = TaskStatus.RUNNING;
|
synchronized (this) {
|
stepStartTime = new Date();
|
log.info("恢复执行任务【{}】 的巡检步骤【{}】,时间:{}", currentStep.getTaskId(), currentStep.getId(), stepStartTime);
|
// 执行步骤
|
executeStep(currentStep);
|
notifyAll(); // 唤醒所有在等待中的线程
|
}
|
}
|
|
//取消
|
public void cancel() {
|
this.status = TaskStatus.CANCELED;
|
synchronized (this) {
|
notifyAll(); // 唤醒所有在等待中的线程以便退出
|
}
|
}
|
|
//是否暂停
|
public boolean isPaused() {
|
return this.status == TaskStatus.PAUSED;
|
}
|
|
//是否取消
|
public boolean isCanceled() {
|
return this.status == TaskStatus.CANCELED;
|
}
|
|
//开始录像
|
private void startRecording(ArdVideoInspectTaskStep step) {
|
log.info("步骤 {} 开始 {} 录像", step.getId(), task.getCameraId() + "_" + task.getChanNo());
|
cameraSDKService.recordStart(new CameraCmd(task.getCameraId(), task.getChanNo()));//录像
|
try {
|
guideWell(step);//引导
|
} catch (Exception e) {
|
log.error("引导井异常,停止录像", e);
|
cameraSDKService.recordStop(new CameraCmd(task.getCameraId(), task.getChanNo(), "inspect"));//录像
|
}
|
}
|
|
//停止录像
|
private void stopRecording(ArdVideoInspectTaskStep step) {
|
log.info("步骤 {} 停止 {} 录像", step.getId(), task.getCameraId() + "_" + task.getChanNo());
|
String url = cameraSDKService.recordStop(new CameraCmd(task.getCameraId(), task.getChanNo(), "inspect"));
|
ArdVideoInspectRecord record = new ArdVideoInspectRecord();
|
record.setTaskId(task.getId());
|
record.setStepId(step.getId());
|
record.setStartTime(stepStartTime);
|
record.setEndTime(new Date());
|
ArdWell ardWell = ardWellService.selectArdWellById(step.getWellId());
|
record.setWellName(ardWell.getWellId());
|
record.setRecordUrl(url);
|
record.setTaskName(task.getTaskName());
|
ardVideoInspectRecordService.insertArdVideoInspectRecord(record);
|
}
|
|
//引导井
|
private void guideWell(ArdVideoInspectTaskStep step) {
|
log.info("控制相机{}通道{}引导井{}", task.getCameraId(), task.getChanNo(), step.getWellId());
|
//根据井id获取井的坐标
|
ArdWell ardWell = ardWellService.selectArdWellById(step.getWellId());
|
if (ardWell == null) {
|
return;
|
}
|
CameraCmd cmd = new CameraCmd();
|
cmd.setCameraId(task.getCameraId());
|
//根据日夜配置切换通道
|
Integer chanNo = switchChanByTime();
|
task.setChanNo(chanNo);
|
cmd.setChanNo(task.getChanNo());
|
cmd.setOperator("sys_patrol_inspect");
|
cmd.setExpired(step.getRecordingTime());
|
ardCameraService.controlLock(cmd);//锁定
|
Boolean res;
|
ArdWellGuideCamera guidePTZInfo = isPtzGuide(task.getCameraId(), task.getChanNo(), ardWell.getId());
|
if (guidePTZInfo != null) {
|
//使用ptz引导
|
cmd.setPtzDto(new PtzDto(guidePTZInfo.getP(), guidePTZInfo.getT(), guidePTZInfo.getZ()));
|
res = cameraSDKService.setPtz(cmd);
|
log.info("引导方式:ptz引导");
|
} else {
|
//使用坐标引导
|
cmd.setTargetPosition(new Point(ardWell.getLongitude(), ardWell.getLatitude(), ardWell.getAltitude()));
|
res = cameraSDKService.guideTargetPosition(cmd);
|
log.info("引导方式:坐标引导");
|
}
|
log.info("控制相机{}通道{}引导井{}结果{}", task.getCameraId(), task.getChanNo(), step.getWellId(), res);
|
}
|
|
//判断是否使用ptz引导
|
private ArdWellGuideCamera isPtzGuide(String cameraId, Integer chanNo, String wellId) {
|
ArdWellGuideCamera ardWellGuideCamera = new ArdWellGuideCamera();
|
ardWellGuideCamera.setWellId(wellId);
|
ardWellGuideCamera.setCameraId(cameraId);
|
ardWellGuideCamera.setChanNo(chanNo);
|
List<ArdWellGuideCamera> ardWellGuideCameras =
|
ardWellGuideCameraService.selectArdWellGuideCameraList(ardWellGuideCamera);
|
if (ardWellGuideCameras.isEmpty()) {
|
return null;
|
}
|
return ardWellGuideCameras.get(0);
|
}
|
|
// 通道日夜切换
|
public Integer switchChanByTime() {
|
R<String> result = remoteConfigService.getConfigKey("dayNight");
|
// 解析时间区间(示例:18:00-06:00)
|
if (result.getCode()==R.SUCCESS) {
|
String timeRange = result.getData();
|
return checkTimeRange(timeRange);
|
}
|
return 1;
|
}
|
|
/**
|
* 判断当前时间是否在时间区间内(支持跨天区间,如 18:00-06:00)
|
*
|
* @param timeRange 时间区间字符串,格式 "HH:mm-HH:mm"
|
* @return 1(在区间内) 或 2(不在区间内)
|
*/
|
public static int checkTimeRange(String timeRange) {
|
if (timeRange == null || !timeRange.matches("\\d{2}:\\d{2}-\\d{2}:\\d{2}")) {
|
throw new IllegalArgumentException("时间区间格式无效,应为 HH:mm-HH:mm");
|
}
|
|
String[] parts = timeRange.split("-");
|
LocalTime start = LocalTime.parse(parts[0]);
|
LocalTime end = LocalTime.parse(parts[1]);
|
LocalTime now = LocalTime.now();
|
|
if (start.isBefore(end)) {
|
// 普通区间(同一天内,如 09:00-18:00)
|
return (now.isAfter(start) && now.isBefore(end)) ? 1 : 2;
|
} else {
|
// 跨天区间(如 18:00-06:00)
|
return (now.isAfter(start) || now.isBefore(end)) ? 1 : 2;
|
}
|
}
|
}
|