This commit is contained in:
张成
2025-12-30 15:46:18 +08:00
parent d14f89e008
commit 65833dd32d
29 changed files with 2416 additions and 1048 deletions

View File

@@ -0,0 +1,242 @@
const dayjs = require('dayjs');
const Sequelize = require('sequelize');
const db = require('../../dbProxy');
const config = require('../infrastructure/config');
const utils = require('../utils/scheduleUtils');
/**
* 设备管理器(简化版)
* 合并了 Monitor 和 Strategy 的核心功能
*/
class DeviceManager {
constructor() {
// 设备状态 { sn_code: { isOnline, lastHeartbeat, lastSearch, lastApply, lastChat, dailyCounts } }
this.devices = new Map();
// 系统统计
this.stats = {
totalDevices: 0,
onlineDevices: 0,
totalTasks: 0,
completedTasks: 0,
failedTasks: 0,
startTime: new Date()
};
}
/**
* 初始化
*/
async init() {
console.log('[设备管理器] 初始化中...');
await this.loadStats();
console.log('[设备管理器] 初始化完成');
}
/**
* 加载统计数据
*/
async loadStats() {
try {
const devices = await db.getModel('pla_account').findAll();
this.stats.totalDevices = devices.length;
const completedCount = await db.getModel('task_status').count({
where: { status: 'completed' }
});
const failedCount = await db.getModel('task_status').count({
where: { status: 'failed' }
});
this.stats.completedTasks = completedCount;
this.stats.failedTasks = failedCount;
this.stats.totalTasks = completedCount + failedCount;
} catch (error) {
console.error('[设备管理器] 加载统计失败:', error);
}
}
/**
* 记录心跳
*/
async recordHeartbeat(sn_code, heartbeatData = {}) {
const now = Date.now();
if (!this.devices.has(sn_code)) {
this.devices.set(sn_code, {
isOnline: true,
isLoggedIn: heartbeatData.isLoggedIn || false,
lastHeartbeat: now,
dailyCounts: { date: utils.getTodayString(), searchCount: 0, applyCount: 0, chatCount: 0 }
});
console.log(`[设备管理器] 新设备 ${sn_code} 初始化 - isLoggedIn: ${heartbeatData.isLoggedIn}`);
}
const device = this.devices.get(sn_code);
device.isOnline = true;
device.lastHeartbeat = now;
// 更新登录状态
if (heartbeatData.isLoggedIn !== undefined) {
device.isLoggedIn = heartbeatData.isLoggedIn;
console.log(`[设备管理器] 设备 ${sn_code} 登录状态更新 - isLoggedIn: ${device.isLoggedIn}`);
}
}
/**
* 检查设备是否在线
*/
isDeviceOnline(sn_code) {
const device = this.devices.get(sn_code);
if (!device) return false;
const elapsed = Date.now() - device.lastHeartbeat;
if (elapsed > config.monitoring.heartbeatTimeout) {
device.isOnline = false;
return false;
}
return device.isOnline;
}
/**
* 检查是否可以执行操作
*/
canExecuteOperation(sn_code, operation_type) {
// 检查日限制(频率限制已由各任务使用账号配置中的间隔时间,不再使用全局配置)
const device = this.devices.get(sn_code);
if (device && device.dailyCounts) {
const today = utils.getTodayString();
if (device.dailyCounts.date !== today) {
device.dailyCounts = { date: today, searchCount: 0, applyCount: 0, chatCount: 0 };
}
const countKey = `${operation_type}Count`;
const current = device.dailyCounts[countKey] || 0;
const max = config.getDailyLimit(operation_type);
if (current >= max) {
return { allowed: false, reason: `今日${operation_type}操作已达上限` };
}
}
return { allowed: true };
}
/**
* 记录操作
*/
recordOperation(sn_code, operation_type) {
const device = this.devices.get(sn_code) || {};
device[`last${operation_type.charAt(0).toUpperCase() + operation_type.slice(1)}`] = Date.now();
if (device.dailyCounts) {
const countKey = `${operation_type}Count`;
device.dailyCounts[countKey] = (device.dailyCounts[countKey] || 0) + 1;
}
this.devices.set(sn_code, device);
}
/**
* 记录任务开始
*/
recordTaskStart(sn_code, task) {
// 简化实现,只记录日志
console.log(`[设备管理器] 设备 ${sn_code} 开始执行任务: ${task.taskName}`);
}
/**
* 记录任务完成
*/
recordTaskComplete(sn_code, task, success, duration) {
if (success) {
this.stats.completedTasks++;
} else {
this.stats.failedTasks++;
}
this.stats.totalTasks++;
console.log(`[设备管理器] 设备 ${sn_code} 任务${success ? '成功' : '失败'}: ${task.taskName} (${duration}ms)`);
}
/**
* 获取系统统计
*/
getSystemStats() {
const onlineCount = Array.from(this.devices.values()).filter(d => d.isOnline).length;
return {
...this.stats,
onlineDevices: onlineCount,
uptime: utils.formatDuration(Date.now() - this.stats.startTime.getTime())
};
}
/**
* 获取所有设备状态
*/
getAllDevicesStatus() {
const result = {};
for (const [sn_code, device] of this.devices.entries()) {
result[sn_code] = {
isOnline: device.isOnline,
isLoggedIn: device.isLoggedIn || false,
lastHeartbeat: device.lastHeartbeat,
dailyCounts: device.dailyCounts || {}
};
}
return result;
}
/**
* 检查心跳状态仅更新内存状态device_status 表已移除)
*/
async checkHeartbeatStatus() {
try {
const now = Date.now();
const offlineDevices = [];
// 检查内存中的设备状态
for (const [sn_code, device] of this.devices.entries()) {
if (now - device.lastHeartbeat > config.monitoring.heartbeatTimeout) {
// 如果之前是在线状态,现在检测到离线
if (device.isOnline) {
device.isOnline = false;
offlineDevices.push(sn_code);
}
}
}
// 记录离线设备(仅日志,不再更新数据库)
if (offlineDevices.length > 0) {
console.log(`[设备管理器] 检测到 ${offlineDevices.length} 个设备心跳超时: ${offlineDevices.join(', ')}`);
// 注意device_status 表已移除,设备状态仅在内存中维护
}
} catch (error) {
console.error('[设备管理器] 检查心跳状态失败:', error);
}
}
/**
* 重置所有日计数器
*/
resetAllDailyCounters() {
const today = utils.getTodayString();
for (const device of this.devices.values()) {
if (device.dailyCounts && device.dailyCounts.date !== today) {
device.dailyCounts = { date: today, searchCount: 0, applyCount: 0, chatCount: 0 };
}
}
}
/**
* 清理离线设备
*/
cleanupOfflineDevices(threshold = 3600000) {
const now = Date.now();
for (const [sn_code, device] of this.devices.entries()) {
if (now - device.lastHeartbeat > threshold) {
this.devices.delete(sn_code);
}
}
}
}
// 导出单例
const deviceManager = new DeviceManager();
module.exports = deviceManager;