Files
autoAiWorkSys/api/middleware/schedule/tasks/autoDeliverTask.js
张成 914999c9fc 1
2025-12-30 16:45:09 +08:00

329 lines
11 KiB
JavaScript

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) {
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('../notifiers/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();