From 38a785c8bb875524865622f7651ea83395f16316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Tue, 16 Dec 2025 13:46:08 +0800 Subject: [PATCH] 1 --- api/middleware/schedule/scheduledJobs.js | 47 +++++++++- api/middleware/schedule/taskQueue.js | 107 +++++++++++++++++++++++ 2 files changed, 153 insertions(+), 1 deletion(-) diff --git a/api/middleware/schedule/scheduledJobs.js b/api/middleware/schedule/scheduledJobs.js index 744a01a..c97690d 100644 --- a/api/middleware/schedule/scheduledJobs.js +++ b/api/middleware/schedule/scheduledJobs.js @@ -4,7 +4,7 @@ const config = require('./config.js'); const deviceManager = require('./deviceManager.js'); const command = require('./command.js'); const db = require('../dbProxy'); - +const Framework = require("../../../framework/node-core-framework.js"); /** * 检查当前时间是否在指定的时间范围内 * @param {Object} timeRange - 时间范围配置 {start_time: '09:00', end_time: '18:00', workdays_only: 1} @@ -99,6 +99,16 @@ class ScheduledJobs { this.jobs.push(timeoutCheckJob); console.log('[定时任务] 已启动任务超时检查任务'); + // 启动任务状态摘要同步定时任务(每10秒发送一次) + const taskSummaryJob = node_schedule.scheduleJob('*/10 * * * * *', async () => { + await this.syncTaskStatusSummary().catch(error => { + console.error('[定时任务] 同步任务状态摘要失败:', error); + }); + }); + + this.jobs.push(taskSummaryJob); + console.log('[定时任务] 已启动任务状态摘要同步任务'); + // 执行自动投递任务 const autoDeliverJob = node_schedule.scheduleJob(config.schedules.autoDeliver, () => { @@ -275,6 +285,41 @@ class ScheduledJobs { } } + /** + * 同步任务状态摘要到客户端 + * 定期向所有在线设备发送任务状态摘要(当前任务、待执行任务、下次执行时间等) + */ + async syncTaskStatusSummary() { + try { + const { pla_account } = await Framework.getModels(); + + // 获取所有启用的账号 + const accounts = await pla_account.findAll({ + where: { + is_delete: 0, + is_enabled: 1 + }, + attributes: ['sn_code'] + }); + + if (!accounts || accounts.length === 0) { + return; + } + + // 为每个设备发送任务状态摘要 + for (const account of accounts) { + const sn_code = account.sn_code; + try { + await this.taskQueue.sendTaskStatusSummary(sn_code); + } catch (error) { + console.error(`[任务状态同步] 设备 ${sn_code} 同步失败:`, error.message); + } + } + } catch (error) { + console.error('[任务状态同步] 执行失败:', error); + } + } + /** * 检查任务超时并强制标记为失败 * 检测长时间运行的任务(可能是卡住的),强制标记为失败,释放资源 diff --git a/api/middleware/schedule/taskQueue.js b/api/middleware/schedule/taskQueue.js index 0d5ba78..b821574 100644 --- a/api/middleware/schedule/taskQueue.js +++ b/api/middleware/schedule/taskQueue.js @@ -1054,6 +1054,113 @@ class TaskQueue { console.warn(`[任务队列] 通知客户端任务状态变更失败:`, error.message); } } + + /** + * 获取任务状态摘要(用于同步到客户端) + * @param {string} sn_code - 设备SN码 + * @returns {Promise} 任务状态摘要 + */ + async getTaskStatusSummary(sn_code) { + try { + const queue = this.deviceQueues.get(sn_code); + const status = this.deviceStatus.get(sn_code) || { + isRunning: false, + currentTask: null, + runningCount: 0 + }; + + // 获取当前执行的任务 + let currentTask = null; + if (status.currentTask) { + const taskData = status.currentTask; + currentTask = { + taskId: taskData.id, + taskName: taskData.taskName || taskData.task_name || taskData.taskType || taskData.task_type || '未知任务', + taskType: taskData.taskType || taskData.task_type, + status: 'running', + progress: taskData.progress || 0, + currentStep: taskData.currentStep || taskData.current_step || '', + startTime: taskData.startTime || taskData.start_time || taskData.created_time + }; + } + + // 获取待执行任务列表(最多10个) + const pendingTasks = []; + if (queue && queue.size() > 0) { + const queueArray = queue.toArray(); + for (const task of queueArray.slice(0, 10)) { + const taskData = task; + pendingTasks.push({ + taskId: taskData.id, + taskName: taskData.taskName || taskData.task_name || taskData.taskType || taskData.task_type || '未知任务', + taskType: taskData.taskType || taskData.task_type, + status: 'pending', + scheduledTime: taskData.scheduledTime || taskData.scheduled_time || taskData.created_time, + priority: taskData.priority || 0 + }); + } + } + + // 计算下次任务执行时间(队列中第一个任务的计划时间) + let nextTaskTime = null; + if (queue && queue.size() > 0) { + const firstTask = queue.peek(); + if (firstTask && (firstTask.scheduledTime || firstTask.scheduled_time)) { + nextTaskTime = firstTask.scheduledTime || firstTask.scheduled_time; + } + } + + return { + sn_code, + currentTask, + pendingTasks, + nextTaskTime, + pendingCount: queue ? queue.size() : 0, + mqttTopic: `task_status_${sn_code}`, + timestamp: new Date().toISOString() + }; + } catch (error) { + console.error(`[任务队列] 获取任务状态摘要失败:`, error, { sn_code }); + return { + sn_code, + currentTask: null, + pendingTasks: [], + nextTaskTime: null, + pendingCount: 0, + mqttTopic: `task_status_${sn_code}`, + timestamp: new Date().toISOString() + }; + } + } + + /** + * 向客户端发送任务状态摘要 + * @param {string} sn_code - 设备SN码 + */ + async sendTaskStatusSummary(sn_code) { + try { + const mqttClient = await this.getMqttClient(); + if (!mqttClient) { + return; // MQTT客户端不可用,静默失败 + } + + const summary = await this.getTaskStatusSummary(sn_code); + + // 通过MQTT发布任务状态摘要 + // 主题格式: task_status_{sn_code} + const topic = `task_status_${sn_code}`; + const message = JSON.stringify({ + action: 'task_status_summary', + data: summary, + timestamp: new Date().toISOString() + }); + + await mqttClient.publish(topic, message); + } catch (error) { + // 通知失败不影响任务执行,只记录日志 + console.warn(`[任务队列] 发送任务状态摘要失败:`, error.message); + } + } } // 导出单例