Files
MiddlePlatform/maibu-netty-server/src/main/java/com/maibu/service/DeviceTaskService.java
2026-09-10 14:35:02 +08:00

588 lines
25 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.maibu.service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import com.maibu.memory.DeviceSessionManager;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maibu.core.business.Device;
import com.maibu.core.business.DevicePlan;
import com.maibu.core.business.DevicePlanTask;
import com.maibu.core.business.DeviceTaskPlanRule;
import com.maibu.core.business.WorkRecord;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.business.dto.DeviceTaskCommandDTO;
import com.maibu.core.domain.entity.SysRegion;
import com.maibu.core.domain.entity.SysSite;
import com.maibu.core.domain.model.LoginUser;
import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.dto.DevicePlanStatisticsDTO;
import com.maibu.dto.DevicePlanTaskStatisticsDTO;
import com.maibu.dto.DeviceTaskQueryDTO;
import com.maibu.dto.DeviceWorkStatisticsDTO;
import com.maibu.mapper.DeviceMapper;
import com.maibu.mapper.DevicePlanMapper;
import com.maibu.mapper.DevicePlanTaskMapper;
import com.maibu.mapper.SysRegionMapper;
import com.maibu.mapper.SysSiteMapper;
import com.maibu.mapper.WorkRecordMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import lombok.extern.slf4j.Slf4j;
@Service
@Slf4j
public class DeviceTaskService {
@Autowired
private DevicePlanMapper devicePlanMapper;
@Autowired
private DevicePlanTaskMapper devicePlanTaskMapper;
@Autowired
private DeviceMapper deviceMapper;
@Autowired
private WorkRecordMapper workRecordMapper;
@Autowired
private DeviceSessionManager deviceSessionManager;
@Autowired
private SysSiteMapper sysSiteMapper;
@Autowired
private SysRegionMapper sysRegionMapper;
public int insertOrUpdate(DevicePlan devicePlan, LoginUser loginUser) {
Long id = devicePlan.getId();
SiteMemory siteMemory = GlobalMemory.getSiteMemory(devicePlan.getOrgId(), devicePlan.getSiteId());
if (id != null) {
devicePlan.setUpdateBy(loginUser.getUsername());
devicePlan.setUpdateTime(LocalDateTime.now());
transferDays(devicePlan);
int i = devicePlanMapper.updateById(devicePlan);
siteMemory.addDevicePlan(devicePlan);
return i;
} else {
devicePlan.setTaskStaus(DeviceTaskStaus.NEW);
devicePlan.setCreateTime(LocalDateTime.now());
devicePlan.setCreateBy(loginUser.getUsername());
transferDays(devicePlan);
int i = devicePlanMapper.insert(devicePlan);
siteMemory.addDevicePlan(devicePlan);
return i;
}
}
public void transferDays(DevicePlan devicePlan) {
DeviceTaskPlanRule deviceTaskPlanRules = devicePlan.getDeviceTaskPlanRules();
if (deviceTaskPlanRules != null && !CollectionUtils.isEmpty(deviceTaskPlanRules.getDays())) {
List<String> days = new ArrayList<>();
deviceTaskPlanRules.getDays().forEach(x -> {
String day = null;
switch (x) {
case MONDAY:
day = "周一";
break;
case TUESDAY:
day = "周二";
break;
case WEDNESDAY:
day = "周三";
break;
case THURSDAY:
day = "周四";
break;
case FRIDAY:
day = "周五";
break;
case SATURDAY:
day = "周六";
break;
case SUNDAY:
day = "周日";
break;
}
days.add(day);
});
devicePlan.getDeviceTaskPlanRules().setDaysTranslate(days);
}
}
public List<DevicePlan> getDeviceTaskByUser(Long userId) {
if (userId != null) {
LambdaQueryWrapper<DevicePlan> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DevicePlan::getUserId, userId);
return transferDevicePlanData(devicePlanMapper.selectList(queryWrapper));
} else {
return new ArrayList<>();
}
}
public List<DevicePlan> getSiteDevicePlan(Long siteId, LocalDate startTime, LocalDate endTime, String deviceId,
DeviceTaskStaus taskStaus) {
if (siteId != null) {
LambdaQueryWrapper<DevicePlan> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DevicePlan::getSiteId, siteId);
if (taskStaus != null) {
queryWrapper.eq(DevicePlan::getTaskStaus, taskStaus);
}
if (!StringUtils.isEmpty(deviceId)) {
queryWrapper.eq(DevicePlan::getDeviceId, deviceId);
}
if (startTime != null && endTime != null) {
queryWrapper.between(DevicePlan::getCreateTime, startTime, endTime);
}
return transferDevicePlanData(devicePlanMapper.selectList(queryWrapper));
} else {
return new ArrayList<>();
}
}
public List<DevicePlan> getDeviceTask(DeviceTaskQueryDTO dto) {
if (dto != null) {
LambdaQueryWrapper<DevicePlan> queryWrapper = new LambdaQueryWrapper<>();
if (dto.getUserId() != null) {
queryWrapper.eq(DevicePlan::getUserId, dto.getUserId());
}
if (!StringUtils.isEmpty(dto.getDeviceId())) {
queryWrapper.eq(DevicePlan::getDeviceId, dto.getDeviceId());
}
if (dto.getTaskStaus() != null) {
queryWrapper.eq(DevicePlan::getTaskStaus, dto.getTaskStaus());
}
if (dto.getOrgId() != null) {
queryWrapper.eq(DevicePlan::getOrgId, dto.getOrgId());
}
if (dto.getSiteId() != null) {
queryWrapper.eq(DevicePlan::getSiteId, dto.getSiteId());
}
if (!StringUtils.isEmpty(dto.getPlanName())) {
queryWrapper.like(DevicePlan::getPlanName, dto.getPlanName());
}
queryWrapper.eq(DevicePlan::getDelFlag, 0);
List<DevicePlan> list = devicePlanMapper.selectList(queryWrapper);
if (!CollectionUtils.isEmpty(list)) {
list.forEach(x -> {
Device device = deviceMapper.selectDeviceBySerialNumber(x.getDeviceId());
if (device != null) {
x.setDeviceAlias(device.getDeviceAlias());
}
});
}
return transferDevicePlanData(list);
} else {
return new ArrayList<>();
}
}
public int delete(Long id) {
DevicePlan planTask = devicePlanMapper.selectById(id);
if (planTask != null) {
if (planTask.getOrgId() == null) {
SysSite site = sysSiteMapper.selectById(planTask.getSiteId());
if (site != null) {
planTask.setOrgId(site.getOrgId());
}
}
SiteMemory siteMemory = GlobalMemory.getSiteMemory(planTask.getOrgId(), planTask.getSiteId());
if (siteMemory != null) {
siteMemory.removeDevicePlan(planTask);
}
return devicePlanMapper.deleteById(id);
}
return 0;
}
public void start(Long id, LoginUser loginUser) {
if (id != null) {
DevicePlan planTask = devicePlanMapper.selectById(id);
if (planTask != null) {
planTask.setTaskStaus(DeviceTaskStaus.EXECUTING);
planTask.setUpdateTime(LocalDateTime.now());
planTask.setUpdateBy(loginUser.getUsername());
devicePlanMapper.updateById(planTask);
}
}
}
public List<DevicePlanStatisticsDTO> getDevicePlanStatistics(Long userId) {
List<DevicePlanStatisticsDTO> list = new ArrayList<>();
LocalDate today = LocalDate.now();
LocalDateTime monthStart = LocalDateTime.of(
today.getYear(), // 当前年
today.getMonth(), // 当前月
1, // 当月第一天
0, 0, 0, 0 // 时:分:秒:纳秒(00:00:00.000)
);
LocalDate lastDayOfMonth = today.withDayOfMonth(today.lengthOfMonth()); // 获取当月最后一天
LocalDateTime monthEnd = LocalDateTime.of(
lastDayOfMonth.getYear(),
lastDayOfMonth.getMonth(),
lastDayOfMonth.getDayOfMonth(),
23, 59, 59, 999_999_999 // 时:分:秒:纳秒(23:59:59.999)
);
LambdaQueryWrapper<DevicePlan> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.ge(DevicePlan::getCreateTime, monthStart)
.le(DevicePlan::getCreateTime, monthEnd)
.eq(DevicePlan::getUserId, userId);
List<DevicePlan> devicePlans = transferDevicePlanData(devicePlanMapper.selectList(queryWrapper));
if (!CollectionUtils.isEmpty(devicePlans)) {
List<LocalDate> dates = getMonthDays();
for (LocalDate date : dates) {
List<DevicePlan> plans = devicePlans.stream().filter(x -> x.getCreateTime().toLocalDate().equals(date))
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(plans)) {
DevicePlanStatisticsDTO dto = new DevicePlanStatisticsDTO();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M.d");
dto.setName(formatter.format(date));
long count = plans.stream().filter(x -> DeviceTaskStaus.FINISH.equals(x.getTaskStaus())).count();
dto.setCompleted((int) count);
dto.setPlanned(plans.size());
list.add(dto);
}
}
}
return list;
}
public List<LocalDate> getMonthDays() {
LocalDate today = LocalDate.now();
int totalDays = today.lengthOfMonth();
LocalDate firstDayOfMonth = LocalDate.of(today.getYear(), today.getMonth(), 1);
List<LocalDate> allDaysOfCurrentMonth = new ArrayList<>();
for (int i = 0; i < totalDays; i++) {
// 每次累加1天,获取当月每一天
LocalDate currentDay = firstDayOfMonth.plusDays(i);
allDaysOfCurrentMonth.add(currentDay);
}
return allDaysOfCurrentMonth;
}
public List<DevicePlanTaskStatisticsDTO> getDevicePlanTaskStatistics(Long userId) {
List<DevicePlanTaskStatisticsDTO> list = new ArrayList<>();
// 1. 获取当前日期
LocalDate today = LocalDate.now();
// 2. 构造当前月份的起始时间:当月第一天 00:00:00
LocalDateTime monthStart = LocalDateTime.of(
today.getYear(), // 当前年
today.getMonth(), // 当前月
1, // 当月第一天
0, 0, 0, 0 // 时:分:秒:纳秒(00:00:00.000)
);
// 3. 构造当前月份的结束时间:当月最后一天 23:59:59.999
LocalDate lastDayOfMonth = today.withDayOfMonth(today.lengthOfMonth()); // 获取当月最后一天
LocalDateTime monthEnd = LocalDateTime.of(
lastDayOfMonth.getYear(),
lastDayOfMonth.getMonth(),
lastDayOfMonth.getDayOfMonth(),
23, 59, 59, 999_999_999 // 时:分:秒:纳秒(23:59:59.999)
);
// 4. 构建 LambdaQueryWrapper 进行范围查询
LambdaQueryWrapper<DevicePlan> query = new LambdaQueryWrapper<>();
query.eq(DevicePlan::getUserId, userId);
List<DevicePlan> devicePlans = transferDevicePlanData(devicePlanMapper.selectList(query));
if (CollectionUtils.isEmpty(devicePlans))
return new ArrayList<>();
List<Long> planIds = devicePlans.stream().map(DevicePlan::getId).collect(Collectors.toList());
if (CollectionUtils.isEmpty(planIds))
return new ArrayList<>();
LambdaQueryWrapper<DevicePlanTask> queryWrapper = new LambdaQueryWrapper<>();
// 核心:筛选 createTime 大于等于起始时间,且小于等于结束时间
queryWrapper.ge(DevicePlanTask::getCreateTime, monthStart)
.le(DevicePlanTask::getCreateTime, monthEnd)
.in(DevicePlanTask::getPlanId, planIds);
List<DevicePlanTask> devicePlanTasks = transferDeviceTaskData(devicePlanTaskMapper.selectList(queryWrapper));
if (!CollectionUtils.isEmpty(devicePlanTasks)) {
List<LocalDate> dates = getMonthDays();
for (LocalDate date : dates) {
List<DevicePlanTask> planTasks = devicePlanTasks.stream()
.filter(x -> x.getCreateTime().toLocalDate().equals(date)).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(planTasks)) {
DevicePlanTaskStatisticsDTO dto = new DevicePlanTaskStatisticsDTO();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M.d");
dto.setDate(formatter.format(date));
long finishCount = planTasks.stream().filter(x -> DeviceTaskStaus.FINISH.equals(x.getTaskStaus()))
.count();
dto.setSuccess((int) finishCount);
long failedCount = planTasks.stream().filter(x -> DeviceTaskStaus.FAILED.equals(x.getTaskStaus()))
.count();
dto.setFailed((int) failedCount);
long pauseCount = planTasks.stream().filter(x -> DeviceTaskStaus.PAUSE.equals(x.getTaskStaus()))
.count();
dto.setPaused((int) pauseCount);
list.add(dto);
}
}
}
return list;
}
public WorkRecord concurrentDevicePlanTask(String deviceId) {
LambdaQueryWrapper<DevicePlanTask> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DevicePlanTask::getDeviceId, deviceId)
.eq(DevicePlanTask::getTaskStaus, DeviceTaskStaus.EXECUTING);
List<DevicePlanTask> devicePlanTasks = devicePlanTaskMapper.selectList(queryWrapper);
Long routId = CollectionUtils.isEmpty(devicePlanTasks) ? null : devicePlanTasks.get(0).getRouteId();
return routId == null ? null : workRecordMapper.selectById(routId);
}
public List<DeviceWorkStatisticsDTO> workStatistics(Long userId) {
// todo update
List<DeviceWorkStatisticsDTO> result = new ArrayList<>();
Random random = new Random();
int times = random.nextInt(100);
int s = random.nextInt(1000);
DeviceWorkStatisticsDTO dto = new DeviceWorkStatisticsDTO();
dto.setLabel("割草次数");
dto.setValue(times);
DeviceWorkStatisticsDTO dto2 = new DeviceWorkStatisticsDTO();
dto2.setLabel("割草时长(s)");
dto2.setValue(s);
DeviceWorkStatisticsDTO dto3 = new DeviceWorkStatisticsDTO();
dto3.setLabel("割草面积(m2)");
dto3.setValue(s * 5);
result.add(dto);
result.add(dto2);
result.add(dto3);
return result;
}
public List<DevicePlanTask> deviceTaskPool(DeviceTaskQueryDTO dto) {
List<DevicePlanTask> list = new ArrayList<>();
if (dto.getOrgId() == null) {
SysSite site = sysSiteMapper.selectById(dto.getSiteId());
if (site != null) {
dto.setOrgId(site.getOrgId());
}
}
SiteMemory siteMemory = GlobalMemory.getSiteMemory(dto.getOrgId(), dto.getSiteId());
siteMemory.devicePlanTaskPrepareMap.values().forEach(list::addAll);
list.addAll(SiteMemory.devicePlanTaskExecuteMap.values());
if (dto.getTaskStaus() != null) {
list = list.stream().filter(x -> x.getTaskStaus().equals(dto.getTaskStaus())).collect(Collectors.toList());
}
if (!StringUtils.isEmpty(dto.getDeviceId())) {
list = list.stream().filter(x -> x.getDeviceId().equals(dto.getDeviceId())).collect(Collectors.toList());
}
if (dto.getPlanId() != null) {
list = list.stream().filter(x -> x.getPlanId().equals(dto.getPlanId())).collect(Collectors.toList());
}
if (dto.getSiteId() != null) {
list = list.stream().filter(x -> x.getSiteId().equals(dto.getSiteId())).collect(Collectors.toList());
}
if (dto.getOrgId() != null) {
list = list.stream().filter(x -> x.getOrgId().equals(dto.getOrgId())).collect(Collectors.toList());
}
if (!StringUtils.isEmpty(dto.getDeviceId())) {
list = list.stream().filter(x -> x.getDeviceId().equals(dto.getDeviceId())).collect(Collectors.toList());
}
if (dto.getStartTime() != null) {
list = list.stream()
.filter(x -> x.getCreateTime() != null
&& !x.getCreateTime().isBefore(dto.getStartTime()))
.collect(Collectors.toList());
}
if (dto.getEndTime() != null) {
list = list.stream()
.filter(x -> x.getCreateTime() != null
&& !x.getCreateTime().isAfter(dto.getEndTime()))
.collect(Collectors.toList());
}
return transferDeviceTaskData(list);
}
public List<DevicePlanTask> getSiteDeviceTaskHistory(DeviceTaskQueryDTO dto) {
LambdaQueryWrapper<DevicePlanTask> queryWrapper = new LambdaQueryWrapper<>();
if (dto.getSiteId() != null) {
queryWrapper.eq(DevicePlanTask::getSiteId, dto.getSiteId());
}
if (dto.getOrgId() != null) {
queryWrapper.eq(DevicePlanTask::getOrgId, dto.getOrgId());
}
if (dto.getTaskStaus() != null) {
queryWrapper.eq(DevicePlanTask::getTaskStaus, dto.getTaskStaus());
}
if (dto.getPlanId() != null) {
queryWrapper.eq(DevicePlanTask::getPlanId, dto.getPlanId());
}
if (!StringUtils.isEmpty(dto.getDeviceId())) {
queryWrapper.eq(DevicePlanTask::getDeviceId, dto.getDeviceId());
}
if (dto.getStartTime() != null) {
queryWrapper.ge(DevicePlanTask::getCreateTime, dto.getStartTime());
}
if (dto.getEndTime() != null) {
queryWrapper.le(DevicePlanTask::getCreateTime, dto.getEndTime());
}
return transferDeviceTaskData(devicePlanTaskMapper.selectList(queryWrapper));
}
public List<DevicePlan> transferDevicePlanData(List<DevicePlan> list) {
if (CollectionUtils.isEmpty(list))
return list;
list.forEach(x -> {
DeviceTaskStaus taskStaus = x.getTaskStaus();
x.setTaskStausTranslate(taskStaus.getDescription());
});
return list;
}
public List<DevicePlanTask> transferDeviceTaskData(List<DevicePlanTask> list) {
if (CollectionUtils.isEmpty(list))
return list;
list.forEach(x -> {
DeviceTaskStaus taskStaus = x.getTaskStaus();
x.setTaskStausTranslate(taskStaus.getDescription());
});
list.sort(
Comparator.comparing(DevicePlanTask::getFinishTime,
Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing(DevicePlanTask::getCreateTime,
Comparator.nullsLast(Comparator.reverseOrder())));
return list;
}
public Long createDeviceTask(DeviceTaskCommandDTO dto, String username) {
DevicePlanTask task = new DevicePlanTask();
task.setOrgId(dto.getOrgId());
task.setSiteId(dto.getSiteId());
task.setTaskStaus(DeviceTaskStaus.NEW);
task.setDeviceId(dto.getDeviceId());
task.setCreateBy(username);
task.setCreateTime(LocalDateTime.now());
task.setRouteId(dto.getRouteId());
task.setStartTime(dto.getStartTime());
devicePlanTaskMapper.saveOrUpdate(task);
if (dto.getOrgId() == null) {
SysSite site = sysSiteMapper.selectById(dto.getSiteId());
if (site != null) {
dto.setOrgId(site.getOrgId());
}
}
SiteMemory siteMemory = GlobalMemory.getSiteMemory(task.getOrgId(), task.getSiteId());
siteMemory.addDevicePlanPrepare(task);
return task.getId();
}
public Long createRegionDeviceTask(DeviceTaskCommandDTO dto, String username) {
LambdaQueryWrapper<SysRegion> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysRegion::getId, dto.getRegionId());
SysRegion region = sysRegionMapper.selectOne(queryWrapper);
if (region == null || region.getBindRoute() == null) {
throw new RuntimeException("区域未绑定线路!");
}
DevicePlanTask task = new DevicePlanTask();
task.setRouteId(region.getBindRoute());
task.setOrgId(dto.getOrgId());
task.setSiteId(dto.getSiteId());
task.setTaskStaus(DeviceTaskStaus.NEW);
task.setDeviceId(dto.getDeviceId());
task.setCreateBy(username);
task.setCreateTime(LocalDateTime.now());
task.setStartTime(dto.getStartTime());
devicePlanTaskMapper.saveOrUpdate(task);
if (dto.getOrgId() == null) {
SysSite site = sysSiteMapper.selectById(dto.getSiteId());
if (site != null) {
dto.setOrgId(site.getOrgId());
}
}
SiteMemory siteMemory = GlobalMemory.getSiteMemory(task.getOrgId(), task.getSiteId());
siteMemory.addDevicePlanPrepare(task);
return task.getId();
}
public boolean cancelTask(DeviceTaskCommandDTO dto) throws MqttException {
String deviceId = dto.getDeviceId();
DevicePlanTask devicePlanTask = null;
if (StringUtils.isEmpty(dto.getDeviceId())) {
Long taskId = dto.getTaskId();
devicePlanTask = devicePlanTaskMapper.selectById(taskId);
if (devicePlanTask != null) {
deviceId = devicePlanTask.getDeviceId();
}
}
NettyDevice device = deviceSessionManager.getDevice(deviceId);
if (device != null && device.getTask() != null) {
if (dto.isForceCancel()) {
return device.canceledTask();
} else {
return device.cancelingTask();
}
} else {
if (devicePlanTask != null) {
devicePlanTask.setTaskStaus(DeviceTaskStaus.CANCELED);
devicePlanTask.setUpdateTime(LocalDateTime.now());
devicePlanTaskMapper.saveOrUpdate(devicePlanTask);
SiteMemory siteMemory = GlobalMemory.getSiteMemory(devicePlanTask.getOrgId(),
devicePlanTask.getSiteId());
siteMemory.removeDevicePlanPrepare(devicePlanTask);
siteMemory.removeDevicePlanExecute(devicePlanTask.getDeviceId());
return true;
} else {
return false;
}
}
}
// todo 完善
public boolean pauseTask(DeviceTaskCommandDTO dto, String username) {
if (!StringUtils.isEmpty(dto.getDeviceId())) {
NettyDevice device = deviceSessionManager.getDevice(dto.getDeviceId());
if (device != null) {
return device.pauseTask();
}
} else {
Long taskId = dto.getTaskId();
DevicePlanTask devicePlanTask = devicePlanTaskMapper.selectById(taskId);
if (devicePlanTask != null) {
NettyDevice device = deviceSessionManager.getDevice(devicePlanTask.getDeviceId());
if (device != null) {
return device.pauseTask();
}
}
}
return false;
}
// todo 完善
public boolean recoveryTask(DeviceTaskCommandDTO dto, String username) throws InterruptedException {
if (!StringUtils.isEmpty(dto.getDeviceId())) {
NettyDevice device = deviceSessionManager.getDevice(dto.getDeviceId());
if (device != null) {
return device.recoveryTask();
}
} else {
Long taskId = dto.getTaskId();
DevicePlanTask devicePlanTask = devicePlanTaskMapper.selectById(taskId);
if (devicePlanTask != null) {
NettyDevice device = deviceSessionManager.getDevice(devicePlanTask.getDeviceId());
if (device != null) {
return device.recoveryTask();
}
}
}
return false;
}
}