feat:完成工单管理定时任务

main
HuangHuiKang 3 weeks ago
parent e30f19360c
commit e0e7462273

@ -0,0 +1,60 @@
// TaskTypeEnum.java
package cn.iocoder.yudao.module.iot.controller.admin.device.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum TaskTypeEnum {
DEVICE("DEVICE", "设备数据采集"),
WORK_ORDER("WORK_ORDER", "工单生成");
/**
*
*/
private final String code;
/**
*
*/
private final String name;
/**
*
*/
public static TaskTypeEnum getByCode(String code) {
for (TaskTypeEnum type : values()) {
if (type.getCode().equals(code)) {
return type;
}
}
return null;
}
/**
*
*/
public static boolean contains(String code) {
return getByCode(code) != null;
}
/**
* ID
*/
public Long generateTaskId(Long baseId) {
if (baseId == null) {
baseId = 0L;
}
switch (this) {
case DEVICE:
return 1000000L + baseId;
case WORK_ORDER:
return 2000000L + baseId;
default:
return 9000000L + baseId;
}
}
}

@ -13,11 +13,16 @@ public class SchedulerConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(20); // 设置线程池大小
scheduler.setThreadNamePrefix("scheduled-task-"); // 线程名前缀
scheduler.setAwaitTerminationSeconds(60); // 等待任务完成的秒数
scheduler.setWaitForTasksToCompleteOnShutdown(true); // 关闭时等待任务完成
scheduler.initialize(); // 初始化
scheduler.setPoolSize(50); // 增加线程数
scheduler.setThreadNamePrefix("scheduled-task-");
scheduler.setAwaitTerminationSeconds(60);
scheduler.setWaitForTasksToCompleteOnShutdown(true);
// 设置队列容量
scheduler.setPoolSize(50);
scheduler.setThreadPriority(Thread.NORM_PRIORITY);
scheduler.setDaemon(false);
scheduler.initialize();
return scheduler;
}
}

@ -2,6 +2,7 @@
package cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.coretask;
import cn.iocoder.yudao.framework.common.util.opc.OpcUtils;
import cn.iocoder.yudao.module.iot.controller.admin.device.enums.TaskTypeEnum;
import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.core.Task;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.DeviceDO;
import cn.iocoder.yudao.module.iot.dal.devicecontactmodel.DeviceContactModelDO;
@ -37,7 +38,7 @@ public class DeviceTask implements Task {
@Override
public String getTaskType() {
return "DEVICE";
return TaskTypeEnum.DEVICE.getCode();
}
@Override
@ -67,8 +68,10 @@ public class DeviceTask implements Task {
/**
*
*/
private void executeDeviceLogic(Long deviceId, String param) {
logger.info("执行设备 {} 的具体逻辑,参数: {}", deviceId, param);
private void executeDeviceLogic(Long sourceDeviceId, String param) {
logger.info("执行设备 {} 的具体逻辑,参数: {}", sourceDeviceId, param);
Long deviceId = sourceDeviceId - 1000000L;
logger.info("处理后id{} ", deviceId );
// 1. 参数校验
if (deviceId == null){

@ -1,49 +0,0 @@
// DataSyncTask.java - 数据同步任务
package cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.coretask;
import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.core.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class GenerateWorkOrderTask implements Task {
private static final Logger logger = LoggerFactory.getLogger(GenerateWorkOrderTask.class);
@Override
public String getTaskType() {
return "WORK_ORDER";
}
@Override
public void execute(Long taskId, String taskParam) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String currentTime = sdf.format(new Date());
logger.info("执行数据同步任务任务ID: {}, 参数: {}, 时间: {}",
taskId, taskParam, currentTime);
// 解析同步参数
// 格式示例: "source:target" 或 "table:condition"
syncData(taskParam);
} catch (Exception e) {
logger.error("执行数据同步任务异常任务ID: {}", taskId, e);
}
}
private void syncData(String param) {
// TODO: 数据同步逻辑
logger.info("开始同步数据,参数: {}", param);
// 示例:
// 1. 从源数据库读取数据
// 2. 转换数据格式
// 3. 写入目标数据库
// 4. 记录同步日志
}
}

@ -1,6 +1,7 @@
// TaskSchedulerManager.java
package cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.scheduler;
import cn.iocoder.yudao.module.iot.controller.admin.device.enums.TaskTypeEnum;
import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.core.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -220,11 +221,63 @@ public class TaskSchedulerManager {
}
}
// /**
// * 原设备任务方法(保持兼容性)
// */
// public boolean startDeviceTask(Long deviceId, String deviceCode, String cronExpression) {
// String taskParam = deviceId + ":" + deviceCode;
// return startCronTask(deviceId, TaskTypeEnum.DEVICE.getCode(), taskParam, cronExpression);
// }
/**
*
*/
public boolean startDeviceTask(Long deviceId, String cronExpression) {
Long taskId = TaskTypeEnum.DEVICE.generateTaskId(deviceId);
return startCronTask(taskId, TaskTypeEnum.DEVICE.getCode(),
"device:" + deviceId, cronExpression);
}
/**
*
*
*/
public boolean startDeviceTask(Long deviceId, String deviceCode, String cronExpression) {
String taskParam = deviceId + ":" + deviceCode;
return startCronTask(deviceId, "DEVICE", taskParam, cronExpression);
public boolean stopDeviceTask(Long deviceId) {
if (deviceId == null) {
logger.warn("设备ID不能为空");
return false;
}
// 生成与启动时相同的任务ID
Long taskId = TaskTypeEnum.DEVICE.generateTaskId(deviceId);
logger.info("停止设备任务设备ID: {}, 生成的任务ID: {}", deviceId, taskId);
return stopTask(taskId);
}
/**
*
*/
public boolean startWorkOrderTask(Long configId, String cronExpression) {
Long taskId = TaskTypeEnum.WORK_ORDER.generateTaskId(configId);
return startCronTask(taskId, TaskTypeEnum.WORK_ORDER.getCode(),
"workOrder:" + configId, cronExpression);
}
/**
*
*/
public boolean stopWorkOrderTask(Long configId) {
if (configId == null) {
logger.warn("工单配置ID不能为空");
return false;
}
// 生成与启动时相同的任务ID
Long taskId = TaskTypeEnum.WORK_ORDER.generateTaskId(configId);
logger.info("停止工单任务配置ID: {}, 生成的任务ID: {}", configId, taskId);
return stopTask(taskId);
}
}

@ -410,7 +410,6 @@ public class DeviceServiceImpl implements DeviceService {
taskSchedulerManager.startDeviceTask(
deviceDO.getId(),
deviceDO.getDeviceCode(),
cronExpression
);
@ -423,7 +422,7 @@ public class DeviceServiceImpl implements DeviceService {
if (disconnect){
deviceDO.setStatus(String.valueOf(DeviceConnectionStatusEnum.DISCONNECTED.getStatus()));
deviceMapper.updateById(deviceDO);
taskSchedulerManager.stopTask(deviceDO.getId());
taskSchedulerManager.stopDeviceTask(deviceDO.getId());
}else {
throw exception(OPC_CLOSE_CONNECT_FAILURE);
}
@ -431,15 +430,6 @@ public class DeviceServiceImpl implements DeviceService {
throw exception(OPC_PARAMETER_DOES_NOT_EXIST);
}
return Boolean.TRUE;
}
@ -695,7 +685,6 @@ public class DeviceServiceImpl implements DeviceService {
// 2. 启动定时任务
boolean success = taskSchedulerManager.startDeviceTask(
deviceDO.getId(),
deviceDO.getDeviceCode(),
cronExpression
);
@ -714,7 +703,7 @@ public class DeviceServiceImpl implements DeviceService {
public Boolean scheduledStop(Long id) {
try {
// 1. 停止定时任务
taskSchedulerManager.stopTask(id);
taskSchedulerManager.stopDeviceTask(id);
return true;

@ -121,15 +121,23 @@ public class TaskManagementController {
return success(true);
}
@PutMapping("/update-enabled")
@Operation(summary = "更新任务管理启用状态")
@PreAuthorize("@ss.hasPermission('mes:task-management:update')")
public CommonResult<Boolean> updateTaskManagementEnabled(@Valid @RequestBody TaskManagementUpdateEnabledReqVO updateEnabledReqVO) {
taskManagementService.updateTaskManagementEnabled(updateEnabledReqVO);
return success(true);
}
private PageResult<TaskManagementRespVO> buildPageCreatorName(PageResult<TaskManagementRespVO> planMaintenanceRespVOPageResult) {
for (TaskManagementRespVO planMaintenanceRespVO : planMaintenanceRespVOPageResult.getList()) {
AdminUserRespDTO user = adminUserApi.getUser(Long.valueOf(planMaintenanceRespVO.getCreator()));
planMaintenanceRespVO.setCreatorName( "(" + user.getUsername()+ ")" + user.getNickname());
if (user!=null){
planMaintenanceRespVO.setCreatorName( "(" + user.getUsername()+ ")" + user.getNickname());
}
}
return planMaintenanceRespVOPageResult;
}

@ -0,0 +1,143 @@
// DataSyncTask.java - 数据同步任务
package cn.iocoder.yudao.module.mes.controller.admin.taskmanagement.scheduled.coretask;
import cn.iocoder.yudao.module.iot.controller.admin.device.enums.TaskTypeEnum;
import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.core.Task;
import cn.iocoder.yudao.module.iot.service.device.TDengineService;
import cn.iocoder.yudao.module.mes.dal.dataobject.deviceledger.DeviceLedgerDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.dvsubject.DvSubjectDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.subjectplan.SubjectPlanDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.taskmanagement.TaskManagementDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.ticketmanagement.TicketManagementDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.ticketresults.TicketResultsDO;
import cn.iocoder.yudao.module.mes.dal.mysql.deviceledger.DeviceLedgerMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.dvsubject.DvSubjectMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.subjectplan.SubjectPlanMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.taskmanagement.TaskManagementMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.ticketmanagement.TicketManagementMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.ticketresults.TicketResultsMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@Component
public class GenerateWorkOrderTask implements Task {
private static final Logger logger = LoggerFactory.getLogger(GenerateWorkOrderTask.class);
@Resource
private TaskManagementMapper taskManagementMapper;
@Resource
private DeviceLedgerMapper deviceLedgerMapper;
@Resource
private TicketManagementMapper ticketManagementMapper;
@Resource
private SubjectPlanMapper subjectPlanMapper;
@Resource
private DvSubjectMapper dvSubjectMapper;
@Resource
private TicketResultsMapper ticketResultsMapper;
@Override
public String getTaskType() {
return TaskTypeEnum.WORK_ORDER.getCode();
}
@Override
public void execute(Long taskId, String taskParam) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String currentTime = sdf.format(new Date());
logger.info("执行数据同步任务任务ID: {}, 参数: {}, 时间: {}",
taskId, taskParam, currentTime);
// 解析同步参数
// 格式示例: "source:target" 或 "table:condition"
generateWorkOrder(taskId);
} catch (Exception e) {
logger.error("执行数据同步任务异常任务ID: {}", taskId, e);
}
}
private void generateWorkOrder(Long taskId) {
logger.info("开始同步数据id: {}", taskId);
Long id = taskId -2000000L;
logger.info("处理后id{} ", id );
//检验数据是否存在
taskManagementMapper.selectById(id);
TaskManagementDO taskManagementDO = taskManagementMapper.selectById(id);
if (taskManagementDO == null){
return;
}
// 将逗号分隔的字符串转换为Long类型的List
List<Long> idList = Arrays.stream(taskManagementDO.getDeviceList().split(","))
.map(String::trim) // 去除可能存在的空格
.map(Long::valueOf)
.collect(Collectors.toList());
for (Long deviceId : idList) {
TicketManagementDO ticketManagementDO = new TicketManagementDO();
DeviceLedgerDO deviceLedgerDO = deviceLedgerMapper.selectById(deviceId);
ticketManagementDO.setTaskId(taskManagementDO.getId());
ticketManagementDO.setPlanNo(generatePrefixedOrderNo());
ticketManagementDO.setPlanId(taskManagementDO.getProjectForm());
ticketManagementDO.setDeviceName(deviceLedgerDO.getDeviceName());
ticketManagementDO.setPlanType(taskManagementDO.getTaskType());
ticketManagementDO.setConfigName(taskManagementDO.getName());
ticketManagementDO.setTaskEndTime(taskManagementDO.getEndDate().atStartOfDay());
// TODO 默认为内置管理员Id
ticketManagementDO.setCreator("1");
ticketManagementDO.setUpdater("1");
ticketManagementMapper.insert(ticketManagementDO);
List<SubjectPlanDO> subjectPlanDOList = subjectPlanMapper.selectList(Wrappers.<SubjectPlanDO>lambdaQuery().eq(SubjectPlanDO::getPlanId, ticketManagementDO.getPlanId()));
for (SubjectPlanDO subjectPlanDO : subjectPlanDOList) {
DvSubjectDO dvSubjectDO = dvSubjectMapper.selectById(subjectPlanDO.getSubjectId());
TicketResultsDO ticketResultsDO = new TicketResultsDO();
ticketResultsDO.setInspectionItemName(dvSubjectDO.getSubjectName());
ticketResultsDO.setInspectionMethod(dvSubjectDO.getInspectionMethod());
ticketResultsDO.setJudgmentCriteria(dvSubjectDO.getJudgmentCriteria());
ticketResultsDO.setManagementId(ticketManagementDO.getId());
ticketResultsDO.setDeviceId(deviceId);
// TODO 默认为内置管理员Id
ticketResultsDO.setCreator("1");
ticketResultsDO.setUpdater("1");
ticketResultsMapper.insert(ticketResultsDO);
}
}
}
/**
*
*/
public static String generatePrefixedOrderNo() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String date = sdf.format(new Date());
String randomNum = String.format("%06d", new Random().nextInt(1000000));
return "E" + date + randomNum;
}
}

@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.mes.controller.admin.taskmanagement.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Schema(description = "任务管理 - 更新启用状态 Request VO")
@Data
public class TaskManagementUpdateEnabledReqVO {
@Schema(description = "任务ID", required = true, example = "1024")
@NotNull(message = "任务ID不能为空")
private Long id;
@Schema(description = "是否启用", required = true, example = "true")
@NotNull(message = "启用状态不能为空")
private Boolean enabled;
}

@ -115,8 +115,10 @@ public class TicketManagementController {
private PageResult<TicketManagementRespVO> buildPageCreatorName(PageResult<TicketManagementRespVO> ticketManagementRespVOPageResult) {
for (TicketManagementRespVO ticketManagementRespVO : ticketManagementRespVOPageResult.getList()) {
AdminUserRespDTO user = adminUserApi.getUser(Long.valueOf(ticketManagementRespVO.getCreator()));
ticketManagementRespVO.setCreatorName( "(" + user.getUsername()+ ")" + user.getNickname());
if (ticketManagementRespVO.getCreator()!=null){
AdminUserRespDTO user = adminUserApi.getUser(Long.valueOf(ticketManagementRespVO.getCreator()));
ticketManagementRespVO.setCreatorName( "(" + user.getUsername()+ ")" + user.getNickname());
}
if (ticketManagementRespVO.getOperator()!=null){
AdminUserRespDTO operator = adminUserApi.getUser(Long.valueOf(ticketManagementRespVO.getOperator()));
ticketManagementRespVO.setOperatorName("(" + operator.getUsername()+ ")" + operator.getNickname());

@ -33,7 +33,7 @@ public interface TicketManagementMapper extends BaseMapperX<TicketManagementDO>
.likeIfPresent(TicketManagementDO::getConfigName, reqVO.getConfigName())
.eqIfPresent(TicketManagementDO::getJobStatus, reqVO.getJobStatus())
.eqIfPresent(TicketManagementDO::getJobResult, reqVO.getJobResult())
.orderByDesc(TicketManagementDO::getCreateTime);
.orderByDesc(TicketManagementDO::getId);
// 单独处理 ids 条件

@ -53,4 +53,6 @@ public interface TaskManagementService {
PageResult<TaskManagementDO> getTaskManagementPage(TaskManagementPageReqVO pageReqVO);
void createTicket(Long id);
void updateTaskManagementEnabled(TaskManagementUpdateEnabledReqVO updateEnabledReqVO);
}

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.mes.service.taskmanagement;
import cn.iocoder.yudao.module.iot.controller.admin.device.enums.TaskTypeEnum;
import cn.iocoder.yudao.module.iot.controller.admin.device.scheduled.scheduler.TaskSchedulerManager;
import cn.iocoder.yudao.module.mes.dal.dataobject.deviceledger.DeviceLedgerDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.dvsubject.DvSubjectDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.planmaintenance.PlanMaintenanceDO;
@ -12,7 +14,9 @@ import cn.iocoder.yudao.module.mes.dal.mysql.planmaintenance.PlanMaintenanceMapp
import cn.iocoder.yudao.module.mes.dal.mysql.subjectplan.SubjectPlanMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.ticketmanagement.TicketManagementMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.ticketresults.TicketResultsMapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
@ -40,6 +44,7 @@ import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
*/
@Service
@Validated
@Slf4j
public class TaskManagementServiceImpl implements TaskManagementService {
@Resource
@ -60,10 +65,12 @@ public class TaskManagementServiceImpl implements TaskManagementService {
@Resource
private SubjectPlanMapper subjectPlanMapper;
@Resource
private DvSubjectMapper dvSubjectMapper;
@Resource
private TaskSchedulerManager taskSchedulerManager;
@Override
public Long createTaskManagement(TaskManagementSaveReqVO createReqVO) {
// 插入
@ -121,8 +128,6 @@ public class TaskManagementServiceImpl implements TaskManagementService {
@Override
public void createTicket(Long id) {
List<TicketManagementDO> ticketManagementDOS = new ArrayList<>();
//检验数据是否存在
validateTaskManagementExists(id);
TaskManagementDO taskManagementDO = taskManagementMapper.selectById(id);
@ -136,7 +141,6 @@ public class TaskManagementServiceImpl implements TaskManagementService {
.map(Long::valueOf)
.collect(Collectors.toList());
for (Long deviceId : idList) {
TicketManagementDO ticketManagementDO = new TicketManagementDO();
DeviceLedgerDO deviceLedgerDO = deviceLedgerMapper.selectById(deviceId);
@ -149,7 +153,6 @@ public class TaskManagementServiceImpl implements TaskManagementService {
ticketManagementDO.setTaskEndTime(taskManagementDO.getEndDate().atStartOfDay());
ticketManagementMapper.insert(ticketManagementDO);
List<DvSubjectDO> dvSubjectDOList = new ArrayList<>();
List<SubjectPlanDO> subjectPlanDOList = subjectPlanMapper.selectList(Wrappers.<SubjectPlanDO>lambdaQuery().eq(SubjectPlanDO::getPlanId, ticketManagementDO.getPlanId()));
for (SubjectPlanDO subjectPlanDO : subjectPlanDOList) {
DvSubjectDO dvSubjectDO = dvSubjectMapper.selectById(subjectPlanDO.getSubjectId());
@ -167,6 +170,95 @@ public class TaskManagementServiceImpl implements TaskManagementService {
}
@Override
public void updateTaskManagementEnabled(TaskManagementUpdateEnabledReqVO updateEnabledReqVO) {
// 1. 校验任务是否存在
TaskManagementDO task = taskManagementMapper.selectById(updateEnabledReqVO.getId());
if (task == null) {
throw exception(TASK_MANAGEMENT_NOT_EXISTS);
}
// 2. 如果状态没有变化,直接返回
if (Objects.equals(task.getEnabled(), updateEnabledReqVO.getEnabled())) {
return;
}
// 3. 执行状态更新操作
executeEnableUpdate(task, updateEnabledReqVO.getEnabled());
}
/**
* /
*/
private void executeEnableUpdate(TaskManagementDO task, Boolean enabled) {
// 更新数据库状态
updateTaskStatusInDB(task.getId(), enabled);
// 处理定时任务
if (enabled) {
enableTaskSchedule(task);
} else {
disableTaskSchedule(task);
}
}
/**
*
*/
private void enableTaskSchedule(TaskManagementDO task) {
// 验证Cron表达式
if (StringUtils.isBlank(task.getCronExpression())) {
log.warn("任务{}没有配置Cron表达式无法启用调度", task.getId());
return;
}
// 启动定时任务
try {
boolean success = taskSchedulerManager.startWorkOrderTask(
task.getId(),
task.getCronExpression()
);
if (success) {
log.info("任务{}调度启动成功", task.getId());
} else {
log.error("任务{}调度启动失败", task.getId());
// 可以记录失败日志或发送通知
}
} catch (Exception e) {
log.error("任务{}调度启动异常", task.getId(), e);
// 可以考虑回滚数据库状态
}
}
/**
*
*/
private void disableTaskSchedule(TaskManagementDO task) {
try {
boolean success = taskSchedulerManager.stopWorkOrderTask(task.getId());
if (success) {
log.info("任务{}调度停止成功", task.getId());
} else {
log.warn("任务{}调度停止失败,可能任务不存在或已停止", task.getId());
}
} catch (Exception e) {
log.error("任务{}调度停止异常", task.getId(), e);
}
}
/**
*
*/
private void updateTaskStatusInDB(Long taskId, Boolean enabled) {
TaskManagementDO updateObj = new TaskManagementDO();
updateObj.setId(taskId);
updateObj.setEnabled(enabled);
taskManagementMapper.updateById(updateObj);
}
/**
*

Loading…
Cancel
Save