package com.mes.task.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.mes.device.entity.DeviceConfig; import com.mes.device.entity.DeviceGroupConfig; import com.mes.device.mapper.DeviceGroupRelationMapper; import com.mes.device.service.DeviceGroupConfigService; import com.mes.task.dto.MultiDeviceTaskQuery; import com.mes.task.dto.MultiDeviceTaskRequest; import com.mes.task.dto.TaskParameters; import com.mes.task.entity.MultiDeviceTask; import com.mes.task.entity.TaskStepDetail; import com.mes.task.mapper.MultiDeviceTaskMapper; import com.mes.task.mapper.TaskStepDetailMapper; import com.mes.task.model.TaskExecutionResult; import com.mes.task.service.MultiDeviceTaskService; import com.mes.task.service.TaskExecutionEngine; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Locale; /** * 多设备任务服务实现 */ @Slf4j @Service @RequiredArgsConstructor public class MultiDeviceTaskServiceImpl extends ServiceImpl implements MultiDeviceTaskService { private final DeviceGroupConfigService deviceGroupConfigService; private final DeviceGroupRelationMapper deviceGroupRelationMapper; private final TaskStepDetailMapper taskStepDetailMapper; private final TaskExecutionEngine taskExecutionEngine; private final ObjectMapper objectMapper; @Override @Transactional(rollbackFor = Exception.class) public MultiDeviceTask startTask(MultiDeviceTaskRequest request) { DeviceGroupConfig groupConfig = deviceGroupConfigService.getDeviceGroupById(request.getGroupId()); if (groupConfig == null) { throw new IllegalArgumentException("设备组不存在: " + request.getGroupId()); } if (groupConfig.getStatus() != DeviceGroupConfig.Status.ENABLED) { throw new IllegalStateException("设备组未启用,无法执行任务"); } List devices = deviceGroupRelationMapper.getOrderedDeviceConfigs(groupConfig.getId()); if (CollectionUtils.isEmpty(devices)) { throw new IllegalStateException("设备组未配置任何设备,无法执行任务"); } TaskParameters parameters = request.getParameters(); if (parameters == null || CollectionUtils.isEmpty(parameters.getGlassIds())) { throw new IllegalArgumentException("至少需要配置一条玻璃ID"); } MultiDeviceTask task = new MultiDeviceTask(); task.setTaskId(generateTaskId(groupConfig)); task.setGroupId(String.valueOf(groupConfig.getId())); task.setProjectId(String.valueOf(groupConfig.getProjectId())); task.setStatus(MultiDeviceTask.Status.PENDING.name()); task.setCurrentStep(0); task.setTotalSteps(devices.size()); task.setStartTime(new Date()); save(task); try { TaskExecutionResult result = taskExecutionEngine.execute(task, groupConfig, devices, parameters); task.setStatus(result.isSuccess() ? MultiDeviceTask.Status.COMPLETED.name() : MultiDeviceTask.Status.FAILED.name()); task.setErrorMessage(result.isSuccess() ? null : result.getMessage()); task.setEndTime(new Date()); task.setResultData(writeJson(result.getData())); updateById(task); return task; } catch (Exception ex) { log.error("多设备任务执行异常, taskId={}", task.getTaskId(), ex); task.setStatus(MultiDeviceTask.Status.FAILED.name()); task.setErrorMessage(ex.getMessage()); task.setEndTime(new Date()); updateById(task); throw new RuntimeException("多设备任务执行失败: " + ex.getMessage(), ex); } } @Override public MultiDeviceTask getTaskByTaskId(String taskId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(MultiDeviceTask::getTaskId, taskId); return getOne(wrapper); } @Override public List getTaskSteps(String taskId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(TaskStepDetail::getTaskId, taskId); wrapper.orderByAsc(TaskStepDetail::getStepOrder); return taskStepDetailMapper.selectList(wrapper); } @Override public boolean cancelTask(String taskId) { MultiDeviceTask task = getTaskByTaskId(taskId); if (task == null) { return false; } if (!MultiDeviceTask.Status.RUNNING.name().equals(task.getStatus())) { return false; } task.setStatus(MultiDeviceTask.Status.CANCELLED.name()); task.setEndTime(new Date()); return updateById(task); } @Override public Page queryTasks(MultiDeviceTaskQuery query) { int page = query.getPage() != null && query.getPage() > 0 ? query.getPage() : 1; int size = query.getSize() != null && query.getSize() > 0 ? query.getSize() : 10; Page pageParam = new Page<>(page, size); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); if (query.getGroupId() != null) { wrapper.eq(MultiDeviceTask::getGroupId, String.valueOf(query.getGroupId())); } if (StringUtils.hasText(query.getStatus())) { wrapper.eq(MultiDeviceTask::getStatus, query.getStatus().toUpperCase(Locale.ROOT)); } wrapper.orderByDesc(MultiDeviceTask::getCreatedTime); return page(pageParam, wrapper); } private String generateTaskId(DeviceGroupConfig groupConfig) { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA); return "TASK_" + groupConfig.getId() + "_" + sdf.format(new Date()); } private String writeJson(Object data) { if (data == null) { return "{}"; } try { return objectMapper.writeValueAsString(data); } catch (JsonProcessingException e) { return "{}"; } } }