This commit is contained in:
张成
2025-12-12 17:13:00 +08:00
parent 4686a24522
commit c083494fce
3 changed files with 309 additions and 2 deletions

View File

@@ -57,7 +57,8 @@ class ScheduleConfig {
this.schedules = {
dailyReset: '0 0 * * *', // 每天凌晨重置统计
monitoringInterval: '*/1 * * * *', // 监控检查间隔1分钟
autoDeliver: '0 */1 * * * *' // 自动投递任务:每5分钟执行一次
autoDeliver: '0 */1 * * * *', // 自动投递任务:每1分钟执行一次
autoChat: '0 */15 * * * *' // 自动沟通任务每15分钟执行一次
};
}

View File

@@ -4,6 +4,51 @@ const config = require('./config.js');
const deviceManager = require('./deviceManager.js');
const command = require('./command.js');
const db = require('../dbProxy');
/**
* 检查当前时间是否在指定的时间范围内
* @param {Object} timeRange - 时间范围配置 {start_time: '09:00', end_time: '18:00', workdays_only: 1}
* @returns {Object} {allowed: boolean, reason: string}
*/
function checkTimeRange(timeRange) {
if (!timeRange || !timeRange.start_time || !timeRange.end_time) {
return { allowed: true, reason: '未配置时间范围' };
}
const now = new Date();
const currentHour = now.getHours();
const currentMinute = now.getMinutes();
const currentTime = currentHour * 60 + currentMinute; // 转换为分钟数
// 解析开始时间和结束时间
const [startHour, startMinute] = timeRange.start_time.split(':').map(Number);
const [endHour, endMinute] = timeRange.end_time.split(':').map(Number);
const startTime = startHour * 60 + startMinute;
const endTime = endHour * 60 + endMinute;
// 检查是否仅工作日
if (timeRange.workdays_only === 1) {
const dayOfWeek = now.getDay(); // 0=周日, 1=周一, ..., 6=周六
if (dayOfWeek === 0 || dayOfWeek === 6) {
return { allowed: false, reason: '当前是周末,不在允许的时间范围内' };
}
}
// 检查当前时间是否在时间范围内
if (startTime <= endTime) {
// 正常情况09:00 - 18:00
if (currentTime < startTime || currentTime >= endTime) {
return { allowed: false, reason: `当前时间 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` };
}
} else {
// 跨天情况22:00 - 06:00
if (currentTime < startTime && currentTime >= endTime) {
return { allowed: false, reason: `当前时间 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` };
}
}
return { allowed: true, reason: '在允许的时间范围内' };
}
/**
* 定时任务管理器(简化版)
* 管理所有定时任务的创建和销毁
@@ -66,6 +111,17 @@ class ScheduledJobs {
this.jobs.push(autoDeliverJob);
console.log('[定时任务] 已启动自动投递任务');
// 执行自动沟通任务
const autoChatJob = node_schedule.scheduleJob(config.schedules.autoChat || '0 */15 * * * *', () => {
this.autoChatTask();
});
// 立即执行一次自动沟通任务
this.autoChatTask();
this.jobs.push(autoChatJob);
console.log('[定时任务] 已启动自动沟通任务');
}
@@ -356,7 +412,15 @@ class ScheduledJobs {
}
// 获取投递配置,如果不存在则使用默认值
const deliver_config = userData.deliver_config || {
let deliver_config = userData.deliver_config;
if (typeof deliver_config === 'string') {
try {
deliver_config = JSON.parse(deliver_config);
} catch (e) {
deliver_config = {};
}
}
deliver_config = deliver_config || {
deliver_interval: 30,
min_salary: 0,
max_salary: 0,
@@ -366,6 +430,15 @@ class ScheduledJobs {
exclude_keywords: []
};
// 检查投递时间范围
if (deliver_config.time_range) {
const timeCheck = checkTimeRange(deliver_config.time_range);
if (!timeCheck.allowed) {
console.log(`[自动投递] 设备 ${userData.sn_code} ${timeCheck.reason}`);
continue;
}
}
// 检查投递间隔时间
const deliver_interval = deliver_config.deliver_interval || 30; // 默认30分钟
const interval_ms = deliver_interval * 60 * 1000; // 转换为毫秒
@@ -421,6 +494,132 @@ class ScheduledJobs {
console.error('[自动投递] 执行失败:', error);
}
}
/**
* 自动沟通任务
*/
async autoChatTask() {
const now = new Date();
console.log(`[自动沟通] ${now.toLocaleString()} 开始执行自动沟通任务`);
// 检查是否在工作时间
if (!config.isWorkingHours()) {
console.log(`[自动沟通] 非工作时间,跳过执行`);
return;
}
try {
// 从 device_status 查询所有在线且已登录的设备
const models = db.models;
const { device_status, pla_account, op } = models;
const onlineDevices = await device_status.findAll({
where: {
isOnline: true,
isLoggedIn: true
},
attributes: ['sn_code', 'accountName', 'platform']
});
if (!onlineDevices || onlineDevices.length === 0) {
console.log('[自动沟通] 没有在线且已登录的设备');
return;
}
// 获取这些在线设备对应的账号配置(只获取启用且开启自动沟通的账号)
const snCodes = onlineDevices.map(device => device.sn_code);
const pla_users = await pla_account.findAll({
where: {
sn_code: { [op.in]: snCodes },
is_delete: 0,
is_enabled: 1, // 只获取启用的账号
auto_chat: 1
}
});
if (!pla_users || pla_users.length === 0) {
console.log('[自动沟通] 没有启用且开启自动沟通的账号');
return;
}
console.log(`[自动沟通] 找到 ${pla_users.length} 个可用账号`);
// 获取 task_status 模型用于查询上次沟通时间
const { task_status } = models;
// 为每个设备添加自动沟通任务到队列
for (const pl_user of pla_users) {
const userData = pl_user.toJSON();
// 检查设备调度策略
const canExecute = deviceManager.canExecuteOperation(userData.sn_code, 'chat');
if (!canExecute.allowed) {
console.log(`[自动沟通] 设备 ${userData.sn_code} 不满足执行条件: ${canExecute.reason}`);
continue;
}
// 获取沟通策略配置
let chatStrategy = {};
if (userData.chat_strategy) {
chatStrategy = typeof userData.chat_strategy === 'string'
? JSON.parse(userData.chat_strategy)
: userData.chat_strategy;
}
// 检查沟通时间范围
if (chatStrategy.time_range) {
const timeCheck = checkTimeRange(chatStrategy.time_range);
if (!timeCheck.allowed) {
console.log(`[自动沟通] 设备 ${userData.sn_code} ${timeCheck.reason}`);
continue;
}
}
// 检查沟通间隔时间
const chat_interval = chatStrategy.chat_interval || 30; // 默认30分钟
const interval_ms = chat_interval * 60 * 1000; // 转换为毫秒
// 查询该账号最近一次成功完成的自动沟通任务
const lastChatTask = await task_status.findOne({
where: {
sn_code: userData.sn_code,
taskType: 'auto_chat',
status: 'completed'
},
order: [['endTime', 'DESC']],
attributes: ['endTime']
});
// 如果存在上次沟通记录,检查是否已经过了间隔时间
if (lastChatTask && lastChatTask.endTime) {
const lastChatTime = new Date(lastChatTask.endTime);
const elapsedTime = now.getTime() - lastChatTime.getTime();
if (elapsedTime < interval_ms) {
const remainingMinutes = Math.ceil((interval_ms - elapsedTime) / (60 * 1000));
console.log(`[自动沟通] 设备 ${userData.sn_code} 距离上次沟通仅 ${Math.round(elapsedTime / (60 * 1000))} 分钟,还需等待 ${remainingMinutes} 分钟(间隔: ${chat_interval} 分钟)`);
continue;
}
}
// 添加自动沟通任务到队列
await this.taskQueue.addTask(userData.sn_code, {
taskType: 'auto_chat',
taskName: `自动沟通 - ${userData.name || '默认'}`,
taskParams: {
platform: userData.platform_type || 'boss'
},
priority: config.getTaskPriority('auto_chat') || 6
});
console.log(`[自动沟通] 已为设备 ${userData.sn_code} 添加自动沟通任务,沟通间隔: ${chat_interval} 分钟`);
}
console.log('[自动沟通] 任务添加完成');
} catch (error) {
console.error('[自动沟通] 执行失败:', error);
}
}
}
module.exports = ScheduledJobs;

View File

@@ -166,6 +166,25 @@ class TaskHandlers {
const accountConfig = account.toJSON();
const resumeInfo = resume.toJSON();
// 检查投递时间范围
if (accountConfig.deliver_config) {
const deliverConfig = typeof accountConfig.deliver_config === 'string'
? JSON.parse(accountConfig.deliver_config)
: accountConfig.deliver_config;
if (deliverConfig.time_range) {
const timeCheck = this.checkTimeRange(deliverConfig.time_range);
if (!timeCheck.allowed) {
console.log(`[任务处理器] 自动投递任务 - ${timeCheck.reason}`);
return {
success: true,
deliveredCount: 0,
message: timeCheck.reason
};
}
}
}
// 获取职位类型配置
let jobTypeConfig = null;
if (accountConfig.job_type_id) {
@@ -471,6 +490,51 @@ class TaskHandlers {
}
}
/**
* 检查当前时间是否在指定的时间范围内
* @param {Object} timeRange - 时间范围配置 {start_time: '09:00', end_time: '18:00', workdays_only: 1}
* @returns {Object} {allowed: boolean, reason: string}
*/
checkTimeRange(timeRange) {
if (!timeRange || !timeRange.start_time || !timeRange.end_time) {
return { allowed: true, reason: '未配置时间范围' };
}
const now = new Date();
const currentHour = now.getHours();
const currentMinute = now.getMinutes();
const currentTime = currentHour * 60 + currentMinute; // 转换为分钟数
// 解析开始时间和结束时间
const [startHour, startMinute] = timeRange.start_time.split(':').map(Number);
const [endHour, endMinute] = timeRange.end_time.split(':').map(Number);
const startTime = startHour * 60 + startMinute;
const endTime = endHour * 60 + endMinute;
// 检查是否仅工作日
if (timeRange.workdays_only === 1) {
const dayOfWeek = now.getDay(); // 0=周日, 1=周一, ..., 6=周六
if (dayOfWeek === 0 || dayOfWeek === 6) {
return { allowed: false, reason: '当前是周末,不在允许的时间范围内' };
}
}
// 检查当前时间是否在时间范围内
if (startTime <= endTime) {
// 正常情况09:00 - 18:00
if (currentTime < startTime || currentTime >= endTime) {
return { allowed: false, reason: `当前时间 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` };
}
} else {
// 跨天情况22:00 - 06:00
if (currentTime < startTime && currentTime >= endTime) {
return { allowed: false, reason: `当前时间 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')} 不在允许的时间范围内 (${timeRange.start_time} - ${timeRange.end_time})` };
}
}
return { allowed: true, reason: '在允许的时间范围内' };
}
/**
* 处理自动沟通任务(待实现)
* 功能自动与HR进行沟通回复消息等
@@ -483,6 +547,49 @@ class TaskHandlers {
const startTime = Date.now();
try {
// 获取账号配置
const pla_account = db.getModel('pla_account');
const account = await pla_account.findOne({
where: { sn_code: sn_code }
});
if (!account) {
throw new Error(`账号不存在: ${sn_code}`);
}
const accountData = account.toJSON();
// 检查是否开启自动沟通
if (!accountData.auto_chat) {
console.log(`[任务处理器] 设备 ${sn_code} 未开启自动沟通`);
return {
success: true,
message: '未开启自动沟通',
chatCount: 0
};
}
// 解析沟通策略配置
let chatStrategy = {};
if (accountData.chat_strategy) {
chatStrategy = typeof accountData.chat_strategy === 'string'
? JSON.parse(accountData.chat_strategy)
: accountData.chat_strategy;
}
// 检查沟通时间范围
if (chatStrategy.time_range) {
const timeCheck = this.checkTimeRange(chatStrategy.time_range);
if (!timeCheck.allowed) {
console.log(`[任务处理器] 自动沟通任务 - ${timeCheck.reason}`);
return {
success: true,
message: timeCheck.reason,
chatCount: 0
};
}
}
// TODO: 实现自动沟通逻辑
// 1. 获取待回复的聊天列表
// 2. 根据消息内容生成回复