const BaseTask = require('./baseTask'); const db = require('../../dbProxy'); const config = require('../infrastructure/config'); const authorizationService = require('../../../services/authorization_service'); /** * 自动投递任务 * 从数据库读取职位列表并进行自动投递 */ class AutoDeliverTask extends BaseTask { constructor() { super('auto_deliver', { defaultInterval: 30, // 默认30分钟 defaultPriority: 7, // 高优先级 requiresLogin: true, // 需要登录 conflictsWith: [ // 与这些任务冲突 'auto_search', // 搜索任务 'auto_active_account' // 活跃账号任务 ] }); } /** * 验证任务参数 */ validateParams(params) { // 投递任务需要的参数 if (!params.keyword && !params.jobIds) { return { valid: false, reason: '缺少必要参数: keyword 或 jobIds' }; } return { valid: true }; } /** * 获取任务名称 */ getTaskName(params) { return `自动投递 - ${params.keyword || '指定职位'}`; } /** * 执行自动投递任务 */ async execute(sn_code, params) { console.log(`[自动投递] 设备 ${sn_code} 开始执行投递任务`); // 1. 获取账号信息 const account = await this.getAccountInfo(sn_code); if (!account) { throw new Error(`账号 ${sn_code} 不存在`); } // 2. 检查授权 const authorization = await authorizationService.checkAuthorization(sn_code); if (!authorization.is_authorized) { throw new Error('授权天数不足'); } // 3. 获取投递配置 const deliverConfig = this.parseDeliverConfig(account.deliver_config); // 4. 检查日投递限制 const dailyLimit = config.platformDailyLimits[account.platform_type] || 50; const todayDelivered = await this.getTodayDeliveredCount(sn_code); if (todayDelivered >= dailyLimit) { throw new Error(`今日投递已达上限 (${todayDelivered}/${dailyLimit})`); } // 5. 获取可投递的职位列表 const jobs = await this.getDeliverableJobs(sn_code, account, deliverConfig); if (!jobs || jobs.length === 0) { console.log(`[自动投递] 设备 ${sn_code} 没有可投递的职位`); return { success: true, delivered: 0, message: '没有可投递的职位' }; } console.log(`[自动投递] 设备 ${sn_code} 找到 ${jobs.length} 个可投递职位`); // 6. 执行投递(这里需要调用实际的投递逻辑) const deliverResult = { success: true, delivered: jobs.length, jobs: jobs.map(j => ({ id: j.id, title: j.job_title, company: j.company_name })) }; return deliverResult; } /** * 获取账号信息 */ async getAccountInfo(sn_code) { const { pla_account } = db.models; const account = await pla_account.findOne({ where: { sn_code: sn_code, is_delete: 0, is_enabled: 1 } }); return account ? account.toJSON() : null; } /** * 解析投递配置 */ parseDeliverConfig(deliver_config) { if (typeof deliver_config === 'string') { try { deliver_config = JSON.parse(deliver_config); } catch (e) { deliver_config = {}; } } return { deliver_interval: deliver_config?.deliver_interval || 30, min_salary: deliver_config?.min_salary || 0, max_salary: deliver_config?.max_salary || 0, page_count: deliver_config?.page_count || 3, max_deliver: deliver_config?.max_deliver || 10, filter_keywords: deliver_config?.filter_keywords || [], exclude_keywords: deliver_config?.exclude_keywords || [], time_range: deliver_config?.time_range || null }; } /** * 获取今日已投递数量 */ async getTodayDeliveredCount(sn_code) { const { task_status } = db.models; const Sequelize = require('sequelize'); const today = new Date(); today.setHours(0, 0, 0, 0); const count = await task_status.count({ where: { sn_code: sn_code, taskType: 'auto_deliver', status: 'completed', endTime: { [Sequelize.Op.gte]: today } } }); return count; } /** * 获取可投递的职位列表 */ async getDeliverableJobs(sn_code, account, deliverConfig) { const { job_postings } = db.models; const Sequelize = require('sequelize'); // 构建查询条件 const where = { sn_code: sn_code, platform: account.platform_type, is_delivered: 0, // 未投递 is_filtered: 0 // 未被过滤 }; // 薪资范围过滤 if (deliverConfig.min_salary > 0) { where.salary_min = { [Sequelize.Op.gte]: deliverConfig.min_salary }; } if (deliverConfig.max_salary > 0) { where.salary_max = { [Sequelize.Op.lte]: deliverConfig.max_salary }; } // 查询职位 const jobs = await job_postings.findAll({ where: where, limit: deliverConfig.max_deliver, order: [['create_time', 'DESC']] }); return jobs.map(j => j.toJSON()); } /** * 添加投递任务到队列 * 这是外部调用的入口,会进行所有冲突检查 */ async addToQueue(sn_code, taskQueue, customParams = {}) { const now = new Date(); console.log(`[自动投递] ${now.toLocaleString()} 尝试为设备 ${sn_code} 添加任务`); try { // 1. 获取账号信息 const account = await this.getAccountInfo(sn_code); if (!account) { console.log(`[自动投递] 账号 ${sn_code} 不存在或未启用`); return { success: false, reason: '账号不存在或未启用' }; } // 2. 检查是否开启了自动投递 if (!account.auto_deliver) { console.log(`[自动投递] 设备 ${sn_code} 未开启自动投递`); return { success: false, reason: '未开启自动投递' }; } // 3. 获取投递配置 const deliverConfig = this.parseDeliverConfig(account.deliver_config); // 4. 检查时间范围 if (deliverConfig.time_range) { const timeCheck = this.checkTimeRange(deliverConfig.time_range); if (!timeCheck.allowed) { console.log(`[自动投递] 设备 ${sn_code} ${timeCheck.reason}`); return { success: false, reason: timeCheck.reason }; } } // 5. 执行所有层级的冲突检查 const conflictCheck = await this.canExecuteTask(sn_code, taskQueue); if (!conflictCheck.allowed) { console.log(`[自动投递] 设备 ${sn_code} 冲突检查未通过: ${conflictCheck.reason}`); return { success: false, reason: conflictCheck.reason }; } // 6. 检查投递间隔 const intervalCheck = await this.checkExecutionInterval( sn_code, deliverConfig.deliver_interval ); if (!intervalCheck.allowed) { console.log(`[自动投递] 设备 ${sn_code} ${intervalCheck.reason}`); // 推送等待状态到客户端 await this.notifyWaitingStatus(sn_code, intervalCheck, taskQueue); return { success: false, reason: intervalCheck.reason }; } // 7. 构建任务参数 const taskParams = { keyword: account.keyword || '', platform: account.platform_type || 'boss', pageCount: deliverConfig.page_count, maxCount: deliverConfig.max_deliver, filterRules: { minSalary: deliverConfig.min_salary, maxSalary: deliverConfig.max_salary, keywords: deliverConfig.filter_keywords, excludeKeywords: deliverConfig.exclude_keywords }, ...customParams }; // 8. 验证参数 const validation = this.validateParams(taskParams); if (!validation.valid) { return { success: false, reason: validation.reason }; } // 9. 添加任务到队列 await taskQueue.addTask(sn_code, { taskType: this.taskType, taskName: this.getTaskName(taskParams), taskParams: taskParams, priority: this.config.defaultPriority }); console.log(`[自动投递] 已为设备 ${sn_code} 添加投递任务,间隔: ${deliverConfig.deliver_interval} 分钟`); // 10. 释放任务锁 this.releaseTaskLock(sn_code); return { success: true }; } catch (error) { console.error(`[自动投递] 添加任务失败:`, error); this.releaseTaskLock(sn_code); return { success: false, reason: error.message }; } } /** * 推送等待状态到客户端 */ async notifyWaitingStatus(sn_code, intervalCheck, taskQueue) { try { const deviceWorkStatusNotifier = require('../deviceWorkStatusNotifier'); // 获取当前任务状态摘要 const taskStatusSummary = taskQueue.getTaskStatusSummary(sn_code); // 添加等待消息到工作状态 await deviceWorkStatusNotifier.sendDeviceWorkStatus(sn_code, taskStatusSummary, { waitingMessage: { type: 'deliver_interval', message: intervalCheck.reason, remainingMinutes: intervalCheck.remainingMinutes, nextDeliverTime: intervalCheck.nextExecutionTime?.toISOString() } }); } catch (error) { console.warn(`[自动投递] 推送等待消息失败:`, error.message); } } } // 导出单例 module.exports = new AutoDeliverTask();