1
This commit is contained in:
@@ -20,21 +20,20 @@ module.exports = {
|
|||||||
'GET /dashboard/overview': async (ctx) => {
|
'GET /dashboard/overview': async (ctx) => {
|
||||||
const models = Framework.getModels();
|
const models = Framework.getModels();
|
||||||
const {
|
const {
|
||||||
device_status,
|
pla_account,
|
||||||
task_status,
|
task_status,
|
||||||
job_postings,
|
job_postings,
|
||||||
apply_records,
|
apply_records,
|
||||||
chat_records,
|
chat_records,
|
||||||
op
|
op
|
||||||
} = models;
|
} = models;
|
||||||
|
const deviceManager = require('../../middleware/schedule/deviceManager');
|
||||||
|
|
||||||
|
// 设备统计(从 pla_account 和 deviceManager 获取)
|
||||||
// 设备统计
|
const totalDevices = await pla_account.count({ where: { is_delete: 0 } });
|
||||||
const [totalDevices, onlineDevices, runningDevices] = await Promise.all([
|
const deviceStatus = deviceManager.getAllDevicesStatus();
|
||||||
device_status.count(),
|
const onlineDevices = Object.values(deviceStatus).filter(d => d.isOnline).length;
|
||||||
device_status.count({ where: { isOnline: true } }),
|
const runningDevices = 0; // 不再维护运行状态
|
||||||
device_status.count({ where: { isRunning: true } })
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 任务统计
|
// 任务统计
|
||||||
const [totalTasks, runningTasks, completedTasks, failedTasks] = await Promise.all([
|
const [totalTasks, runningTasks, completedTasks, failedTasks] = await Promise.all([
|
||||||
@@ -211,45 +210,58 @@ return ctx.success({
|
|||||||
*/
|
*/
|
||||||
'GET /dashboard/device-performance': async (ctx) => {
|
'GET /dashboard/device-performance': async (ctx) => {
|
||||||
const models = Framework.getModels();
|
const models = Framework.getModels();
|
||||||
const { device_status } = models;
|
const { pla_account, task_status, job_postings, apply_records, chat_records } = models;
|
||||||
|
const deviceManager = require('../../middleware/schedule/deviceManager');
|
||||||
|
|
||||||
|
// 从 pla_account 获取所有账号
|
||||||
const devices = await device_status.findAll({
|
const accounts = await pla_account.findAll({
|
||||||
attributes: [
|
where: { is_delete: 0 },
|
||||||
'sn_code',
|
attributes: ['id', 'sn_code', 'name'],
|
||||||
'deviceName',
|
limit: 20
|
||||||
'totalTasksCompleted',
|
});
|
||||||
'totalTasksFailed',
|
|
||||||
'totalJobsSearched',
|
|
||||||
'totalApplies',
|
|
||||||
'totalChats',
|
|
||||||
'healthScore',
|
|
||||||
'onlineDuration'
|
|
||||||
],
|
|
||||||
order: [['totalTasksCompleted', 'DESC']],
|
|
||||||
limit: 20
|
|
||||||
});
|
|
||||||
|
|
||||||
const performanceData = devices.map(device => {
|
// 获取设备在线状态
|
||||||
const total = device.totalTasksCompleted + device.totalTasksFailed;
|
const deviceStatus = deviceManager.getAllDevicesStatus();
|
||||||
const successRate = total > 0 ? ((device.totalTasksCompleted / total) * 100).toFixed(2) : 0;
|
|
||||||
|
|
||||||
return {
|
|
||||||
sn_code: device.sn_code,
|
|
||||||
deviceName: device.deviceName,
|
|
||||||
tasksCompleted: device.totalTasksCompleted,
|
|
||||||
tasksFailed: device.totalTasksFailed,
|
|
||||||
jobsSearched: device.totalJobsSearched,
|
|
||||||
applies: device.totalApplies,
|
|
||||||
chats: device.totalChats,
|
|
||||||
successRate,
|
|
||||||
healthScore: device.healthScore,
|
|
||||||
onlineDuration: device.onlineDuration
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return ctx.success(performanceData);
|
// 为每个账号统计任务、岗位、投递、聊天数据
|
||||||
|
const performanceData = await Promise.all(accounts.map(async (account) => {
|
||||||
|
const snCode = account.sn_code;
|
||||||
|
const status = deviceStatus[snCode] || { isOnline: false };
|
||||||
|
|
||||||
|
// 统计任务
|
||||||
|
const [completedTasks, failedTasks] = await Promise.all([
|
||||||
|
task_status.count({ where: { sn_code: snCode, status: 'completed' } }),
|
||||||
|
task_status.count({ where: { sn_code: snCode, status: 'failed' } })
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 统计岗位、投递、聊天(如果有相关字段)
|
||||||
|
const [jobsSearched, applies, chats] = await Promise.all([
|
||||||
|
job_postings.count({ where: { sn_code: snCode } }).catch(() => 0),
|
||||||
|
apply_records.count({ where: { sn_code: snCode } }).catch(() => 0),
|
||||||
|
chat_records.count({ where: { sn_code: snCode } }).catch(() => 0)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const total = completedTasks + failedTasks;
|
||||||
|
const successRate = total > 0 ? ((completedTasks / total) * 100).toFixed(2) : 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
sn_code: snCode,
|
||||||
|
deviceName: account.name || snCode,
|
||||||
|
tasksCompleted: completedTasks,
|
||||||
|
tasksFailed: failedTasks,
|
||||||
|
jobsSearched,
|
||||||
|
applies,
|
||||||
|
chats,
|
||||||
|
successRate,
|
||||||
|
healthScore: status.isOnline ? 100 : 0,
|
||||||
|
onlineDuration: 0 // 不再维护在线时长
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 按完成任务数排序
|
||||||
|
performanceData.sort((a, b) => b.tasksCompleted - a.tasksCompleted);
|
||||||
|
|
||||||
|
return ctx.success(performanceData);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
'POST /device/detail': async (ctx) => {
|
'POST /device/detail': async (ctx) => {
|
||||||
const models = Framework.getModels();
|
const models = Framework.getModels();
|
||||||
const { device_status } = models;
|
const { pla_account } = models;
|
||||||
|
const deviceManager = require('../../middleware/schedule/deviceManager');
|
||||||
const body = ctx.getBody();
|
const body = ctx.getBody();
|
||||||
const { deviceSn } = body;
|
const { deviceSn } = body;
|
||||||
|
|
||||||
@@ -69,69 +70,97 @@ module.exports = {
|
|||||||
return ctx.fail('设备SN码不能为空');
|
return ctx.fail('设备SN码不能为空');
|
||||||
}
|
}
|
||||||
|
|
||||||
const device = await device_status.findOne({
|
// 从 pla_account 获取账号信息
|
||||||
|
const account = await pla_account.findOne({
|
||||||
where: { sn_code: deviceSn }
|
where: { sn_code: deviceSn }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!device) {
|
if (!account) {
|
||||||
return ctx.fail('设备不存在');
|
return ctx.fail('设备不存在');
|
||||||
}
|
}
|
||||||
|
|
||||||
const deviceData = device.toJSON();
|
const accountData = account.toJSON();
|
||||||
|
|
||||||
// 处理 JSON 字段
|
// 从 deviceManager 获取在线状态
|
||||||
if (deviceData.config) {
|
const deviceStatus = deviceManager.getAllDevicesStatus();
|
||||||
try {
|
const onlineStatus = deviceStatus[deviceSn] || { isOnline: false };
|
||||||
deviceData.config = typeof deviceData.config === 'string'
|
|
||||||
? JSON.parse(deviceData.config)
|
// 组合返回数据
|
||||||
: deviceData.config;
|
const deviceData = {
|
||||||
} catch (e) {
|
sn_code: accountData.sn_code,
|
||||||
console.error('解析设备配置失败:', e);
|
device_id: accountData.device_id,
|
||||||
deviceData.config = {};
|
deviceName: accountData.name || accountData.sn_code,
|
||||||
}
|
platform: accountData.platform_type,
|
||||||
}
|
isOnline: onlineStatus.isOnline || false,
|
||||||
|
isRunning: false, // 不再维护运行状态
|
||||||
|
lastHeartbeatTime: onlineStatus.lastHeartbeat ? new Date(onlineStatus.lastHeartbeat) : null,
|
||||||
|
accountName: accountData.name,
|
||||||
|
platform_type: accountData.platform_type,
|
||||||
|
is_enabled: accountData.is_enabled
|
||||||
|
};
|
||||||
|
|
||||||
return ctx.success(deviceData);
|
return ctx.success(deviceData);
|
||||||
},
|
},
|
||||||
|
|
||||||
'POST /device/list': async (ctx) => {
|
'POST /device/list': async (ctx) => {
|
||||||
const models = Framework.getModels();
|
const models = Framework.getModels();
|
||||||
const { device_status, op } = models;
|
const { pla_account, op } = models;
|
||||||
|
const deviceManager = require('../../middleware/schedule/deviceManager');
|
||||||
const body = ctx.getBody();
|
const body = ctx.getBody();
|
||||||
const { isOnline, healthStatus, platform, searchText} = ctx.getBody();
|
const { isOnline, healthStatus, platform, searchText} = ctx.getBody();
|
||||||
|
|
||||||
// 获取分页参数
|
// 获取分页参数
|
||||||
const { limit, offset } = ctx.getPageSize();
|
const { limit, offset } = ctx.getPageSize();
|
||||||
|
|
||||||
|
// 从 pla_account 查询账号
|
||||||
const where = {};
|
const where = { is_delete: 0 };
|
||||||
if (isOnline !== undefined) where.isOnline = isOnline;
|
if (platform) where.platform_type = platform;
|
||||||
if (healthStatus) where.healthStatus = healthStatus;
|
|
||||||
if (platform) where.platform = platform;
|
|
||||||
|
|
||||||
// 支持搜索设备名称或SN码
|
// 支持搜索设备名称或SN码
|
||||||
if (searchText) {
|
if (searchText) {
|
||||||
where[op.or] = [
|
where[op.or] = [
|
||||||
{ deviceName: { [op.like]: `%${searchText}%` } },
|
{ name: { [op.like]: `%${searchText}%` } },
|
||||||
{ sn_code: { [op.like]: `%${searchText}%` } }
|
{ sn_code: { [op.like]: `%${searchText}%` } }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await device_status.findAndCountAll({
|
const result = await pla_account.findAndCountAll({
|
||||||
where,
|
where,
|
||||||
limit,
|
limit,
|
||||||
offset,
|
offset,
|
||||||
order: [
|
order: [['id', 'DESC']]
|
||||||
['isOnline', 'DESC'],
|
});
|
||||||
['last_modify_time', 'DESC']
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
return ctx.success({
|
// 获取设备在线状态
|
||||||
total: result.count,
|
const deviceStatus = deviceManager.getAllDevicesStatus();
|
||||||
list: result.rows
|
|
||||||
});
|
// 组合数据并过滤在线状态
|
||||||
|
let list = result.rows.map(account => {
|
||||||
|
const accountData = account.toJSON();
|
||||||
|
const status = deviceStatus[accountData.sn_code] || { isOnline: false };
|
||||||
|
return {
|
||||||
|
sn_code: accountData.sn_code,
|
||||||
|
device_id: accountData.device_id,
|
||||||
|
deviceName: accountData.name || accountData.sn_code,
|
||||||
|
platform: accountData.platform_type,
|
||||||
|
isOnline: status.isOnline || false,
|
||||||
|
isRunning: false,
|
||||||
|
lastHeartbeatTime: status.lastHeartbeat ? new Date(status.lastHeartbeat) : null,
|
||||||
|
accountName: accountData.name,
|
||||||
|
platform_type: accountData.platform_type,
|
||||||
|
is_enabled: accountData.is_enabled
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果指定了在线状态筛选
|
||||||
|
if (isOnline !== undefined) {
|
||||||
|
list = list.filter(item => item.isOnline === isOnline);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.success({
|
||||||
|
total: list.length,
|
||||||
|
list: list.slice(0, limit)
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,56 +176,46 @@ return ctx.success({
|
|||||||
*/
|
*/
|
||||||
'GET /device/overview': async (ctx) => {
|
'GET /device/overview': async (ctx) => {
|
||||||
const models = Framework.getModels();
|
const models = Framework.getModels();
|
||||||
const { device_status, op } = models;
|
const { pla_account } = models;
|
||||||
|
const deviceManager = require('../../middleware/schedule/deviceManager');
|
||||||
|
|
||||||
|
// 从 pla_account 获取账号总数
|
||||||
const [
|
const totalDevices = await pla_account.count({ where: { is_delete: 0 } });
|
||||||
totalDevices,
|
|
||||||
onlineDevices,
|
|
||||||
runningDevices,
|
|
||||||
healthyDevices,
|
|
||||||
warningDevices,
|
|
||||||
errorDevices
|
|
||||||
] = await Promise.all([
|
|
||||||
device_status.count(),
|
|
||||||
device_status.count({ where: { isOnline: true } }),
|
|
||||||
device_status.count({ where: { isRunning: true } }),
|
|
||||||
device_status.count({ where: { healthStatus: 'healthy' } }),
|
|
||||||
device_status.count({ where: { healthStatus: 'warning' } }),
|
|
||||||
device_status.count({ where: { healthStatus: 'error' } })
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 计算平均健康分数
|
// 从 deviceManager 获取在线设备统计
|
||||||
const avgHealthScore = await device_status.findAll({
|
const deviceStatus = deviceManager.getAllDevicesStatus();
|
||||||
attributes: [
|
const onlineDevices = Object.values(deviceStatus).filter(d => d.isOnline).length;
|
||||||
[models.sequelize.fn('AVG', models.sequelize.col('healthScore')), 'avgScore']
|
const runningDevices = 0; // 不再维护运行状态
|
||||||
],
|
const healthyDevices = onlineDevices; // 简化处理,在线即健康
|
||||||
raw: true
|
const warningDevices = 0;
|
||||||
});
|
const errorDevices = 0;
|
||||||
|
|
||||||
// 获取最近离线的设备
|
// 获取最近离线的设备(从内存状态中获取)
|
||||||
const recentOffline = await device_status.findAll({
|
const offlineDevicesList = Object.entries(deviceStatus)
|
||||||
where: { isOnline: false },
|
.filter(([sn_code, status]) => !status.isOnline)
|
||||||
limit: 5,
|
.map(([sn_code, status]) => ({
|
||||||
order: [['lastOfflineTime', 'DESC']],
|
sn_code,
|
||||||
attributes: ['sn_code', 'deviceName', 'lastOfflineTime', 'lastError']
|
deviceName: sn_code,
|
||||||
});
|
lastOfflineTime: status.lastHeartbeat ? new Date(status.lastHeartbeat) : null,
|
||||||
|
lastError: ''
|
||||||
|
}))
|
||||||
|
.sort((a, b) => (b.lastOfflineTime?.getTime() || 0) - (a.lastOfflineTime?.getTime() || 0))
|
||||||
|
.slice(0, 5);
|
||||||
|
|
||||||
return ctx.success({
|
return ctx.success({
|
||||||
totalDevices,
|
totalDevices,
|
||||||
onlineDevices,
|
onlineDevices,
|
||||||
offlineDevices: totalDevices - onlineDevices,
|
offlineDevices: totalDevices - onlineDevices,
|
||||||
runningDevices,
|
runningDevices,
|
||||||
idleDevices: onlineDevices - runningDevices,
|
idleDevices: onlineDevices - runningDevices,
|
||||||
healthyDevices,
|
healthyDevices,
|
||||||
warningDevices,
|
warningDevices,
|
||||||
errorDevices,
|
errorDevices,
|
||||||
onlineRate: totalDevices > 0 ? ((onlineDevices / totalDevices) * 100).toFixed(2) : 0,
|
onlineRate: totalDevices > 0 ? ((onlineDevices / totalDevices) * 100).toFixed(2) : 0,
|
||||||
healthyRate: totalDevices > 0 ? ((healthyDevices / totalDevices) * 100).toFixed(2) : 0,
|
healthyRate: totalDevices > 0 ? ((healthyDevices / totalDevices) * 100).toFixed(2) : 0,
|
||||||
averageHealthScore: parseFloat(avgHealthScore[0]?.avgScore || 0).toFixed(2),
|
averageHealthScore: '100.00', // 简化处理
|
||||||
recentOffline
|
recentOffline: offlineDevicesList
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -228,7 +247,7 @@ return ctx.success({
|
|||||||
*/
|
*/
|
||||||
'POST /device/update-config': async (ctx) => {
|
'POST /device/update-config': async (ctx) => {
|
||||||
const models = Framework.getModels();
|
const models = Framework.getModels();
|
||||||
const { device_status } = models;
|
const { account_config } = models;
|
||||||
const body = ctx.getBody();
|
const body = ctx.getBody();
|
||||||
const { sn_code, config } = body;
|
const { sn_code, config } = body;
|
||||||
|
|
||||||
@@ -236,9 +255,19 @@ return ctx.success({
|
|||||||
return ctx.fail('设备SN码和配置数据不能为空');
|
return ctx.fail('设备SN码和配置数据不能为空');
|
||||||
}
|
}
|
||||||
|
|
||||||
await device_status.update({
|
// 从 pla_account 获取账号ID
|
||||||
config: JSON.stringify(config)
|
const { pla_account } = models;
|
||||||
}, { where: { sn_code } });
|
const account = await pla_account.findOne({ where: { sn_code } });
|
||||||
|
if (!account) {
|
||||||
|
return ctx.fail('设备不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新 account_config 表的配置
|
||||||
|
await account_config.upsert({
|
||||||
|
account_id: account.id,
|
||||||
|
platform_type: account.platform_type,
|
||||||
|
platform_config: config
|
||||||
|
});
|
||||||
|
|
||||||
return ctx.success({ message: '设备配置更新成功' });
|
return ctx.success({ message: '设备配置更新成功' });
|
||||||
},
|
},
|
||||||
@@ -267,25 +296,9 @@ return ctx.success({
|
|||||||
* description: 重置成功
|
* description: 重置成功
|
||||||
*/
|
*/
|
||||||
'POST /device/reset-error': async (ctx) => {
|
'POST /device/reset-error': async (ctx) => {
|
||||||
const models = Framework.getModels();
|
// device_status 表已移除,此功能暂时禁用
|
||||||
const { device_status } = models;
|
// 如果需要重置错误,可以在 account_config 表中添加错误信息字段
|
||||||
const body = ctx.getBody();
|
return ctx.success({ message: '设备错误重置功能已禁用(device_status 表已移除)' });
|
||||||
const { sn_code } = body;
|
|
||||||
|
|
||||||
if (!sn_code) {
|
|
||||||
return ctx.fail('设备SN码不能为空');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
await device_status.update({
|
|
||||||
lastError: '',
|
|
||||||
errorCount: 0,
|
|
||||||
healthStatus: 'healthy',
|
|
||||||
healthScore: 100
|
|
||||||
}, { where: { sn_code } });
|
|
||||||
|
|
||||||
return ctx.success({ message: '设备错误已重置' });
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -312,8 +325,10 @@ return ctx.success({ message: '设备错误已重置' });
|
|||||||
* description: 删除成功
|
* description: 删除成功
|
||||||
*/
|
*/
|
||||||
'POST /device/delete': async (ctx) => {
|
'POST /device/delete': async (ctx) => {
|
||||||
|
// device_status 表已移除,删除设备功能改为删除账号
|
||||||
|
// 如果需要删除设备,应该删除对应的 pla_account 记录
|
||||||
const models = Framework.getModels();
|
const models = Framework.getModels();
|
||||||
const { device_status } = models;
|
const { pla_account } = models;
|
||||||
const body = ctx.getBody();
|
const body = ctx.getBody();
|
||||||
const { sn_code } = body;
|
const { sn_code } = body;
|
||||||
|
|
||||||
@@ -321,15 +336,17 @@ return ctx.success({ message: '设备错误已重置' });
|
|||||||
return ctx.fail('设备SN码不能为空');
|
return ctx.fail('设备SN码不能为空');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 软删除账号(设置 is_delete = 1)
|
||||||
const result = await device_status.destroy({ where: { sn_code } });
|
const result = await pla_account.update(
|
||||||
|
{ is_delete: 1 },
|
||||||
|
{ where: { sn_code } }
|
||||||
|
);
|
||||||
|
|
||||||
if (result === 0) {
|
if (result[0] === 0) {
|
||||||
return ctx.fail('设备不存在');
|
return ctx.fail('设备不存在');
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.success({ message: '设备删除成功' });
|
return ctx.success({ message: '设备删除成功' });
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -189,17 +189,17 @@ class DeviceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查心跳状态(异步更新数据库)
|
* 检查心跳状态(仅更新内存状态,device_status 表已移除)
|
||||||
*/
|
*/
|
||||||
async checkHeartbeatStatus() {
|
async checkHeartbeatStatus() {
|
||||||
try {
|
try {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const device_status = db.getModel('device_status');
|
|
||||||
const offlineDevices = [];
|
const offlineDevices = [];
|
||||||
|
|
||||||
|
// 检查内存中的设备状态
|
||||||
for (const [sn_code, device] of this.devices.entries()) {
|
for (const [sn_code, device] of this.devices.entries()) {
|
||||||
if (now - device.lastHeartbeat > config.monitoring.heartbeatTimeout) {
|
if (now - device.lastHeartbeat > config.monitoring.heartbeatTimeout) {
|
||||||
// 如果之前是在线状态,现在检测到离线,需要更新数据库
|
// 如果之前是在线状态,现在检测到离线
|
||||||
if (device.isOnline) {
|
if (device.isOnline) {
|
||||||
device.isOnline = false;
|
device.isOnline = false;
|
||||||
offlineDevices.push(sn_code);
|
offlineDevices.push(sn_code);
|
||||||
@@ -207,49 +207,10 @@ class DeviceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量更新数据库中的离线设备状态
|
// 记录离线设备(仅日志,不再更新数据库)
|
||||||
if (offlineDevices.length > 0) {
|
if (offlineDevices.length > 0) {
|
||||||
await device_status.update(
|
console.log(`[设备管理器] 检测到 ${offlineDevices.length} 个设备心跳超时: ${offlineDevices.join(', ')}`);
|
||||||
{ isOnline: false },
|
// 注意:device_status 表已移除,设备状态仅在内存中维护
|
||||||
{
|
|
||||||
where: {
|
|
||||||
sn_code: {
|
|
||||||
[Sequelize.Op.in]: offlineDevices
|
|
||||||
},
|
|
||||||
isOnline: true // 只更新当前在线的设备,避免重复更新
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
console.log(`[设备管理器] 检测到 ${offlineDevices.length} 个设备心跳超时,已同步到数据库: ${offlineDevices.join(', ')}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 同时检查数据库中的设备状态(处理内存中没有但数据库中有心跳超时的情况)
|
|
||||||
const heartbeatTimeout = config.monitoring.heartbeatTimeout;
|
|
||||||
const heartbeatThreshold = new Date(now - heartbeatTimeout);
|
|
||||||
|
|
||||||
const timeoutDevices = await device_status.findAll({
|
|
||||||
where: {
|
|
||||||
isOnline: true,
|
|
||||||
lastHeartbeatTime: {
|
|
||||||
[Sequelize.Op.lt]: heartbeatThreshold
|
|
||||||
}
|
|
||||||
},
|
|
||||||
attributes: ['sn_code', 'lastHeartbeatTime']
|
|
||||||
});
|
|
||||||
|
|
||||||
if (timeoutDevices.length > 0) {
|
|
||||||
const timeoutSnCodes = timeoutDevices.map(dev => dev.sn_code);
|
|
||||||
await device_status.update(
|
|
||||||
{ isOnline: false },
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
sn_code: {
|
|
||||||
[Sequelize.Op.in]: timeoutSnCodes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
console.log(`[设备管理器] 从数据库检测到 ${timeoutSnCodes.length} 个心跳超时设备,已更新为离线: ${timeoutSnCodes.join(', ')}`);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[设备管理器] 检查心跳状态失败:', error);
|
console.error('[设备管理器] 检查心跳状态失败:', error);
|
||||||
|
|||||||
@@ -219,7 +219,18 @@ class TaskQueue {
|
|||||||
|
|
||||||
const enabledSnCodes = new Set(enabledAccounts.map(acc => acc.sn_code));
|
const enabledSnCodes = new Set(enabledAccounts.map(acc => acc.sn_code));
|
||||||
|
|
||||||
// 检查设备在线状态(需要同时满足:isOnline = true 且心跳未超时)
|
// 移除 device_status 依赖,不再检查设备在线状态
|
||||||
|
// 如果需要在线状态检查,可以从 deviceManager 获取
|
||||||
|
const deviceManager = require('./deviceManager');
|
||||||
|
const deviceStatus = deviceManager.getAllDevicesStatus();
|
||||||
|
const onlineSnCodes = new Set(
|
||||||
|
Object.entries(deviceStatus)
|
||||||
|
.filter(([sn_code, status]) => status.isOnline)
|
||||||
|
.map(([sn_code]) => sn_code)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 原有代码已移除,改为使用 deviceManager
|
||||||
|
/* 原有代码已注释
|
||||||
const device_status = db.getModel('device_status');
|
const device_status = db.getModel('device_status');
|
||||||
const heartbeatTimeout = require('./config.js').monitoring.heartbeatTimeout;
|
const heartbeatTimeout = require('./config.js').monitoring.heartbeatTimeout;
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
@@ -235,6 +246,7 @@ class TaskQueue {
|
|||||||
attributes: ['sn_code']
|
attributes: ['sn_code']
|
||||||
});
|
});
|
||||||
const onlineSnCodes = new Set(onlineDevices.map(dev => dev.sn_code));
|
const onlineSnCodes = new Set(onlineDevices.map(dev => dev.sn_code));
|
||||||
|
*/
|
||||||
|
|
||||||
let processedCount = 0;
|
let processedCount = 0;
|
||||||
let queuedCount = 0;
|
let queuedCount = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user