1
This commit is contained in:
211
api/controller_front/task.js
Normal file
211
api/controller_front/task.js
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
const Framework = require("../../framework/node-core-framework.js");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务管理控制器(客户端接口)
|
||||||
|
* 提供客户端调用的任务相关接口
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /api/task/current:
|
||||||
|
* get:
|
||||||
|
* summary: 获取当前执行的任务
|
||||||
|
* description: 根据设备SN码获取当前正在执行的任务信息
|
||||||
|
* tags: [前端-任务管理]
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: sn_code
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: 设备SN码
|
||||||
|
* example: 'GHJU'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: 获取成功
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* code:
|
||||||
|
* type: integer
|
||||||
|
* description: 状态码,0表示成功
|
||||||
|
* example: 0
|
||||||
|
* message:
|
||||||
|
* type: string
|
||||||
|
* description: 响应消息
|
||||||
|
* example: 'success'
|
||||||
|
* data:
|
||||||
|
* type: object
|
||||||
|
* nullable: true
|
||||||
|
* description: 当前任务信息,null表示没有正在执行的任务
|
||||||
|
* properties:
|
||||||
|
* taskId:
|
||||||
|
* type: integer
|
||||||
|
* description: 任务ID
|
||||||
|
* taskName:
|
||||||
|
* type: string
|
||||||
|
* description: 任务名称
|
||||||
|
* taskType:
|
||||||
|
* type: string
|
||||||
|
* description: 任务类型
|
||||||
|
* status:
|
||||||
|
* type: string
|
||||||
|
* description: 任务状态(running-执行中)
|
||||||
|
* progress:
|
||||||
|
* type: integer
|
||||||
|
* description: 任务进度(0-100)
|
||||||
|
* currentStep:
|
||||||
|
* type: string
|
||||||
|
* description: 当前步骤
|
||||||
|
* startTime:
|
||||||
|
* type: string
|
||||||
|
* description: 开始时间
|
||||||
|
*/
|
||||||
|
'GET /task/current': async (ctx) => {
|
||||||
|
try { {
|
||||||
|
const { sn_code } = ctx.query || {};
|
||||||
|
|
||||||
|
if (!sn_code) {
|
||||||
|
return ctx.fail('请提供设备SN码');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { task_status, op } = await Framework.getModels();
|
||||||
|
|
||||||
|
// 查询当前正在执行的任务(status = 'running')
|
||||||
|
const currentTask = await task_status.findOne({
|
||||||
|
where: {
|
||||||
|
sn_code: sn_code,
|
||||||
|
status: 'running'
|
||||||
|
},
|
||||||
|
order: [['id', 'DESC']] // 获取最新的任务
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!currentTask) {
|
||||||
|
return ctx.success(null, '暂无执行中的任务');
|
||||||
|
}
|
||||||
|
|
||||||
|
const taskData = currentTask.toJSON();
|
||||||
|
|
||||||
|
return ctx.success({
|
||||||
|
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
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[任务管理] 获取当前任务失败:', error);
|
||||||
|
return ctx.fail('获取当前任务失败: ' + (error.message || '未知错误'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /api/task/pending:
|
||||||
|
* get:
|
||||||
|
* summary: 获取待执行的任务列表
|
||||||
|
* description: 根据设备SN码获取待执行的任务列表
|
||||||
|
* tags: [前端-任务管理]
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: sn_code
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: 设备SN码
|
||||||
|
* example: 'GHJU'
|
||||||
|
* - in: query
|
||||||
|
* name: limit
|
||||||
|
* required: false
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* default: 10
|
||||||
|
* description: 返回数量限制
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: 获取成功
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* code:
|
||||||
|
* type: integer
|
||||||
|
* description: 状态码,0表示成功
|
||||||
|
* example: 0
|
||||||
|
* message:
|
||||||
|
* type: string
|
||||||
|
* description: 响应消息
|
||||||
|
* example: 'success'
|
||||||
|
* data:
|
||||||
|
* type: array
|
||||||
|
* description: 待执行任务列表
|
||||||
|
* items:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* taskId:
|
||||||
|
* type: integer
|
||||||
|
* description: 任务ID
|
||||||
|
* taskName:
|
||||||
|
* type: string
|
||||||
|
* description: 任务名称
|
||||||
|
* taskType:
|
||||||
|
* type: string
|
||||||
|
* description: 任务类型
|
||||||
|
* status:
|
||||||
|
* type: string
|
||||||
|
* description: 任务状态(pending-待执行)
|
||||||
|
* scheduledTime:
|
||||||
|
* type: string
|
||||||
|
* description: 计划执行时间
|
||||||
|
* priority:
|
||||||
|
* type: integer
|
||||||
|
* description: 优先级
|
||||||
|
*/
|
||||||
|
'GET /task/pending': async (ctx) => {
|
||||||
|
try {
|
||||||
|
const { sn_code, limit = 10 } = ctx.query || {};
|
||||||
|
|
||||||
|
if (!sn_code) {
|
||||||
|
return ctx.fail('请提供设备SN码');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { task_status, op } = await Framework.getModels();
|
||||||
|
|
||||||
|
// 查询待执行的任务(status = 'pending')
|
||||||
|
const pendingTasks = await task_status.findAll({
|
||||||
|
where: {
|
||||||
|
sn_code: sn_code,
|
||||||
|
status: 'pending'
|
||||||
|
},
|
||||||
|
order: [
|
||||||
|
['priority', 'DESC'], // 按优先级降序
|
||||||
|
['id', 'ASC'] // 同优先级按ID升序
|
||||||
|
],
|
||||||
|
limit: parseInt(limit) || 10
|
||||||
|
});
|
||||||
|
|
||||||
|
const taskList = pendingTasks.map(task => {
|
||||||
|
const taskData = task.toJSON();
|
||||||
|
return {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return ctx.success(taskList);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[任务管理] 获取待执行任务失败:', error);
|
||||||
|
return ctx.fail('获取待执行任务失败: ' + (error.message || '未知错误'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@@ -582,6 +582,16 @@ class TaskQueue {
|
|||||||
{ where: { id: task.id } }
|
{ where: { id: task.id } }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 通知客户端任务状态变更
|
||||||
|
await this.notifyTaskStatusChange(task.sn_code, {
|
||||||
|
taskId: task.id,
|
||||||
|
taskName: task.taskName,
|
||||||
|
taskType: task.taskType,
|
||||||
|
status: 'running',
|
||||||
|
progress: 0,
|
||||||
|
startTime: task.startTime
|
||||||
|
});
|
||||||
|
|
||||||
// 使用注册的任务处理器执行任务
|
// 使用注册的任务处理器执行任务
|
||||||
const handler = this.taskHandlers.get(task.taskType);
|
const handler = this.taskHandlers.get(task.taskType);
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
@@ -617,6 +627,16 @@ class TaskQueue {
|
|||||||
{ where: { id: task.id } }
|
{ where: { id: task.id } }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 通知客户端任务状态变更
|
||||||
|
await this.notifyTaskStatusChange(task.sn_code, {
|
||||||
|
taskId: task.id,
|
||||||
|
taskName: task.taskName,
|
||||||
|
taskType: task.taskType,
|
||||||
|
status: 'completed',
|
||||||
|
progress: 100,
|
||||||
|
endTime: task.endTime
|
||||||
|
});
|
||||||
|
|
||||||
console.log(`[任务队列] 设备 ${task.sn_code} 任务执行成功: ${task.taskName} (耗时: ${task.duration}ms)`);
|
console.log(`[任务队列] 设备 ${task.sn_code} 任务执行成功: ${task.taskName} (耗时: ${task.duration}ms)`);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -650,6 +670,17 @@ class TaskQueue {
|
|||||||
},
|
},
|
||||||
{ where: { id: task.id } }
|
{ where: { id: task.id } }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 通知客户端任务状态变更
|
||||||
|
await this.notifyTaskStatusChange(task.sn_code, {
|
||||||
|
taskId: task.id,
|
||||||
|
taskName: task.taskName,
|
||||||
|
taskType: task.taskType,
|
||||||
|
status: 'failed',
|
||||||
|
progress: 0,
|
||||||
|
errorMessage: task.errorMessage,
|
||||||
|
endTime: task.endTime
|
||||||
|
});
|
||||||
} catch (dbError) {
|
} catch (dbError) {
|
||||||
console.error(`[任务队列] 更新任务失败状态到数据库失败:`, dbError);
|
console.error(`[任务队列] 更新任务失败状态到数据库失败:`, dbError);
|
||||||
}
|
}
|
||||||
@@ -994,6 +1025,35 @@ class TaskQueue {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知客户端任务状态变更
|
||||||
|
* @param {string} sn_code - 设备SN码
|
||||||
|
* @param {object} taskData - 任务数据
|
||||||
|
*/
|
||||||
|
async notifyTaskStatusChange(sn_code, taskData) {
|
||||||
|
try {
|
||||||
|
const mqttClient = await this.getMqttClient();
|
||||||
|
if (!mqttClient) {
|
||||||
|
return; // MQTT客户端不可用,静默失败
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过MQTT发布任务状态变更通知
|
||||||
|
// 主题格式: task_status_{sn_code}
|
||||||
|
const topic = `task_status_${sn_code}`;
|
||||||
|
const message = JSON.stringify({
|
||||||
|
action: 'task_status_update',
|
||||||
|
data: taskData,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
});
|
||||||
|
|
||||||
|
await mqttClient.publish(topic, message);
|
||||||
|
console.log(`[任务队列] 已通知客户端任务状态变更: ${sn_code} - ${taskData.taskName || taskData.taskType || '未知任务'} (${taskData.status})`);
|
||||||
|
} catch (error) {
|
||||||
|
// 通知失败不影响任务执行,只记录日志
|
||||||
|
console.warn(`[任务队列] 通知客户端任务状态变更失败:`, error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出单例
|
// 导出单例
|
||||||
|
|||||||
Reference in New Issue
Block a user