1
This commit is contained in:
@@ -143,6 +143,256 @@ class JobManager {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多条件搜索职位列表(新指令)
|
||||
* @param {string} sn_code - 设备SN码
|
||||
* @param {object} mqttClient - MQTT客户端
|
||||
* @param {object} params - 搜索参数
|
||||
* @returns {Promise<object>} 搜索结果
|
||||
*/
|
||||
async search_jobs_with_params(sn_code, mqttClient, params = {}) {
|
||||
const {
|
||||
keyword = '前端',
|
||||
platform = 'boss',
|
||||
city = '',
|
||||
cityName = '',
|
||||
salary = '',
|
||||
experience = '',
|
||||
education = '',
|
||||
industry = '',
|
||||
companySize = '',
|
||||
financingStage = '',
|
||||
page = 1,
|
||||
pageSize = 20,
|
||||
pageCount = 3
|
||||
} = params;
|
||||
|
||||
console.log(`[工作管理] 开始多条件搜索设备 ${sn_code} 的职位,关键词: ${keyword}, 城市: ${cityName || city}`);
|
||||
|
||||
// 构建完整的搜索参数对象
|
||||
const searchData = {
|
||||
keyword,
|
||||
pageCount
|
||||
};
|
||||
|
||||
// 添加可选搜索条件
|
||||
if (city) searchData.city = city;
|
||||
if (cityName) searchData.cityName = cityName;
|
||||
if (salary) searchData.salary = salary;
|
||||
if (experience) searchData.experience = experience;
|
||||
if (education) searchData.education = education;
|
||||
if (industry) searchData.industry = industry;
|
||||
if (companySize) searchData.companySize = companySize;
|
||||
if (financingStage) searchData.financingStage = financingStage;
|
||||
if (page) searchData.page = page;
|
||||
if (pageSize) searchData.pageSize = pageSize;
|
||||
|
||||
// 通过MQTT指令获取岗位列表(使用新的action)
|
||||
const response = await mqttClient.publishAndWait(sn_code, {
|
||||
platform,
|
||||
action: "search_job_list", // 新的搜索action
|
||||
data: searchData
|
||||
});
|
||||
|
||||
if (!response || response.code !== 200) {
|
||||
console.error(`[工作管理] 多条件搜索职位失败:`, response);
|
||||
throw new Error('多条件搜索职位失败');
|
||||
}
|
||||
|
||||
// 处理职位列表数据
|
||||
let jobs = [];
|
||||
if (Array.isArray(response.data)) {
|
||||
for (const item of response.data) {
|
||||
if (item.data?.zpData?.jobList && Array.isArray(item.data.zpData.jobList)) {
|
||||
jobs = jobs.concat(item.data.zpData.jobList);
|
||||
}
|
||||
}
|
||||
} else if (response.data?.data?.zpData?.jobList) {
|
||||
jobs = response.data.data.zpData.jobList || [];
|
||||
} else if (response.data?.zpData?.jobList) {
|
||||
jobs = response.data.zpData.jobList || [];
|
||||
}
|
||||
|
||||
console.log(`[工作管理] 成功获取岗位数据,共 ${jobs.length} 个岗位`);
|
||||
|
||||
// 保存职位到数据库
|
||||
try {
|
||||
await this.saveJobsToDatabase(sn_code, platform, keyword, jobs);
|
||||
} catch (error) {
|
||||
console.error(`[工作管理] 保存职位到数据库失败:`, error);
|
||||
}
|
||||
|
||||
return {
|
||||
jobs: jobs,
|
||||
keyword: keyword,
|
||||
platform: platform,
|
||||
count: jobs.length
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索并投递职位(新指令)
|
||||
* @param {string} sn_code - 设备SN码
|
||||
* @param {object} mqttClient - MQTT客户端
|
||||
* @param {object} params - 参数
|
||||
* @returns {Promise<object>} 执行结果
|
||||
*/
|
||||
async search_and_deliver(sn_code, mqttClient, params = {}) {
|
||||
const {
|
||||
keyword,
|
||||
searchParams = {},
|
||||
pageCount = 3,
|
||||
filterRules = {},
|
||||
maxCount = 10,
|
||||
platform = 'boss'
|
||||
} = params;
|
||||
|
||||
console.log(`[工作管理] 开始搜索并投递职位,设备: ${sn_code}, 关键词: ${keyword}`);
|
||||
|
||||
// 1. 先执行搜索
|
||||
const searchResult = await this.search_jobs_with_params(sn_code, mqttClient, {
|
||||
keyword,
|
||||
platform,
|
||||
...searchParams,
|
||||
pageCount
|
||||
});
|
||||
|
||||
if (!searchResult || searchResult.count === 0) {
|
||||
return {
|
||||
success: true,
|
||||
jobCount: 0,
|
||||
deliveredCount: 0,
|
||||
message: '未找到职位'
|
||||
};
|
||||
}
|
||||
|
||||
// 2. 等待数据保存完成
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
// 3. 从数据库获取刚搜索到的职位
|
||||
const job_postings = db.getModel('job_postings');
|
||||
const searchedJobs = await job_postings.findAll({
|
||||
where: {
|
||||
sn_code: sn_code,
|
||||
platform: platform,
|
||||
applyStatus: 'pending',
|
||||
keyword: keyword
|
||||
},
|
||||
order: [['create_time', 'DESC']],
|
||||
limit: 1000
|
||||
});
|
||||
|
||||
if (searchedJobs.length === 0) {
|
||||
return {
|
||||
success: true,
|
||||
jobCount: searchResult.count,
|
||||
deliveredCount: 0,
|
||||
message: '未找到待投递的职位'
|
||||
};
|
||||
}
|
||||
|
||||
// 4. 获取简历信息用于匹配
|
||||
const resume_info = db.getModel('resume_info');
|
||||
const resume = await resume_info.findOne({
|
||||
where: {
|
||||
sn_code: sn_code,
|
||||
platform: platform,
|
||||
isActive: true
|
||||
},
|
||||
order: [['last_modify_time', 'DESC']]
|
||||
});
|
||||
|
||||
if (!resume) {
|
||||
return {
|
||||
success: true,
|
||||
jobCount: searchResult.count,
|
||||
deliveredCount: 0,
|
||||
message: '未找到活跃简历,无法投递'
|
||||
};
|
||||
}
|
||||
|
||||
// 5. 获取账号配置
|
||||
const pla_account = db.getModel('pla_account');
|
||||
const account = await pla_account.findOne({
|
||||
where: { sn_code, platform_type: platform }
|
||||
});
|
||||
|
||||
if (!account) {
|
||||
throw new Error('账号不存在');
|
||||
}
|
||||
|
||||
const accountConfig = account.toJSON();
|
||||
const resumeData = resume.toJSON();
|
||||
|
||||
// 6. 使用过滤方法进行职位匹配
|
||||
const matchedJobs = await this.filter_jobs_by_rules(searchedJobs, {
|
||||
minSalary: filterRules.minSalary || 0,
|
||||
maxSalary: filterRules.maxSalary || 0,
|
||||
keywords: filterRules.keywords || [],
|
||||
excludeKeywords: filterRules.excludeKeywords || [],
|
||||
accountConfig: accountConfig,
|
||||
resumeInfo: resumeData
|
||||
});
|
||||
|
||||
// 7. 限制投递数量
|
||||
const jobsToDeliver = matchedJobs.slice(0, maxCount);
|
||||
console.log(`[工作管理] 匹配到 ${matchedJobs.length} 个职位,将投递 ${jobsToDeliver.length} 个`);
|
||||
|
||||
// 8. 执行投递
|
||||
let deliveredCount = 0;
|
||||
const apply_records = db.getModel('apply_records');
|
||||
|
||||
for (let i = 0; i < jobsToDeliver.length; i++) {
|
||||
const job = jobsToDeliver[i];
|
||||
const jobData = job.toJSON ? job.toJSON() : job;
|
||||
|
||||
try {
|
||||
// 从原始数据中获取 securityId
|
||||
let securityId = jobData.securityId || '';
|
||||
try {
|
||||
if (jobData.originalData) {
|
||||
const originalData = typeof jobData.originalData === 'string'
|
||||
? JSON.parse(jobData.originalData)
|
||||
: jobData.originalData;
|
||||
securityId = originalData.securityId || securityId;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`[工作管理] 解析职位原始数据失败:`, e);
|
||||
}
|
||||
|
||||
// 执行投递
|
||||
const deliverResult = await this.applyJob(sn_code, mqttClient, {
|
||||
jobId: jobData.jobId,
|
||||
encryptBossId: jobData.encryptBossId || '',
|
||||
securityId: securityId,
|
||||
brandName: jobData.companyName || '',
|
||||
jobTitle: jobData.jobTitle || '',
|
||||
companyName: jobData.companyName || '',
|
||||
platform: platform
|
||||
});
|
||||
|
||||
if (deliverResult && deliverResult.success) {
|
||||
deliveredCount++;
|
||||
}
|
||||
|
||||
// 投递间隔控制
|
||||
if (i < jobsToDeliver.length - 1) {
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[工作管理] 投递职位失败:`, error);
|
||||
// 继续投递下一个职位
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
jobCount: searchResult.count,
|
||||
deliveredCount: deliveredCount,
|
||||
message: `搜索完成,找到 ${searchResult.count} 个职位,成功投递 ${deliveredCount} 个`
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取岗位列表
|
||||
* @param {string} sn_code - 设备SN码
|
||||
|
||||
@@ -24,6 +24,11 @@ class TaskHandlers {
|
||||
return await this.handleAutoDeliverTask(task);
|
||||
});
|
||||
|
||||
// 搜索职位列表任务(新功能)
|
||||
taskQueue.registerHandler('search_jobs', async (task) => {
|
||||
return await this.handleSearchJobListTask(task);
|
||||
});
|
||||
|
||||
// 自动沟通任务(待实现)
|
||||
taskQueue.registerHandler('auto_chat', async (task) => {
|
||||
return await this.handleAutoChatTask(task);
|
||||
@@ -547,6 +552,180 @@ class TaskHandlers {
|
||||
return { allowed: true, reason: '在允许的时间范围内' };
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理搜索职位列表任务(新功能)
|
||||
* 支持多条件搜索和可选投递
|
||||
* @param {object} task - 任务对象
|
||||
* @returns {Promise<object>} 执行结果
|
||||
*/
|
||||
async handleSearchJobListTask(task) {
|
||||
const { sn_code, taskParams } = task;
|
||||
const {
|
||||
keyword,
|
||||
searchParams = {},
|
||||
pageCount = 3,
|
||||
autoDeliver = false,
|
||||
filterRules = {},
|
||||
maxCount = 10
|
||||
} = taskParams;
|
||||
|
||||
console.log(`[任务处理器] 搜索职位列表任务 - 设备: ${sn_code}, 关键词: ${keyword}, 自动投递: ${autoDeliver}`);
|
||||
|
||||
// 检查授权状态
|
||||
const authorizationService = require('../../services/authorization_service');
|
||||
const authCheck = await authorizationService.checkAuthorization(sn_code, 'sn_code');
|
||||
if (!authCheck.is_authorized) {
|
||||
console.log(`[任务处理器] 搜索职位列表任务 - 设备: ${sn_code} 授权检查失败: ${authCheck.message}`);
|
||||
return {
|
||||
success: false,
|
||||
jobCount: 0,
|
||||
deliveredCount: 0,
|
||||
message: authCheck.message
|
||||
};
|
||||
}
|
||||
|
||||
deviceManager.recordTaskStart(sn_code, task);
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
const job_postings = db.getModel('job_postings');
|
||||
const pla_account = db.getModel('pla_account');
|
||||
const resume_info = db.getModel('resume_info');
|
||||
const apply_records = db.getModel('apply_records');
|
||||
const Sequelize = require('sequelize');
|
||||
|
||||
// 1. 获取账号配置
|
||||
const account = await pla_account.findOne({
|
||||
where: { sn_code, platform_type: taskParams.platform || 'boss' }
|
||||
});
|
||||
|
||||
if (!account) {
|
||||
throw new Error('账号不存在');
|
||||
}
|
||||
|
||||
const accountConfig = account.toJSON();
|
||||
|
||||
// 2. 从账号配置中读取搜索条件
|
||||
const searchConfig = accountConfig.search_config
|
||||
? (typeof accountConfig.search_config === 'string'
|
||||
? JSON.parse(accountConfig.search_config)
|
||||
: accountConfig.search_config)
|
||||
: {};
|
||||
|
||||
// 3. 构建完整的搜索参数(任务参数优先,其次账号配置)
|
||||
const searchCommandParams = {
|
||||
sn_code: sn_code,
|
||||
platform: taskParams.platform || accountConfig.platform_type || 'boss',
|
||||
keyword: keyword || accountConfig.keyword || searchConfig.keyword || '',
|
||||
city: searchParams.city || accountConfig.city || searchConfig.city || '',
|
||||
cityName: searchParams.cityName || accountConfig.cityName || searchConfig.cityName || '',
|
||||
salary: searchParams.salary || searchConfig.defaultSalary || '',
|
||||
experience: searchParams.experience || searchConfig.defaultExperience || '',
|
||||
education: searchParams.education || searchConfig.defaultEducation || '',
|
||||
industry: searchParams.industry || searchConfig.industry || '',
|
||||
companySize: searchParams.companySize || searchConfig.companySize || '',
|
||||
financingStage: searchParams.financingStage || searchConfig.financingStage || '',
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
pageCount: pageCount
|
||||
};
|
||||
|
||||
// 4. 根据是否投递选择不同的指令
|
||||
let searchCommand;
|
||||
if (autoDeliver) {
|
||||
// 使用搜索并投递指令
|
||||
searchCommand = {
|
||||
command_type: 'search_and_deliver',
|
||||
command_name: '搜索并投递职位',
|
||||
command_params: JSON.stringify({
|
||||
keyword: searchCommandParams.keyword,
|
||||
searchParams: {
|
||||
city: searchCommandParams.city,
|
||||
cityName: searchCommandParams.cityName,
|
||||
salary: searchCommandParams.salary,
|
||||
experience: searchCommandParams.experience,
|
||||
education: searchCommandParams.education,
|
||||
industry: searchCommandParams.industry,
|
||||
companySize: searchCommandParams.companySize,
|
||||
financingStage: searchCommandParams.financingStage,
|
||||
page: searchCommandParams.page,
|
||||
pageSize: searchCommandParams.pageSize,
|
||||
pageCount: searchCommandParams.pageCount
|
||||
},
|
||||
filterRules: filterRules,
|
||||
maxCount: maxCount,
|
||||
platform: searchCommandParams.platform
|
||||
}),
|
||||
priority: config.getTaskPriority('search_and_deliver') || 5,
|
||||
sequence: 1
|
||||
};
|
||||
} else {
|
||||
// 使用多条件搜索指令
|
||||
searchCommand = {
|
||||
command_type: 'search_jobs_with_params',
|
||||
command_name: '多条件搜索职位列表',
|
||||
command_params: JSON.stringify(searchCommandParams),
|
||||
priority: config.getTaskPriority('search_jobs_with_params') || 5,
|
||||
sequence: 1
|
||||
};
|
||||
}
|
||||
|
||||
// 5. 执行指令
|
||||
const commandResult = await command.executeCommands(task.id, [searchCommand], this.mqttClient);
|
||||
|
||||
// 6. 处理执行结果
|
||||
let jobCount = 0;
|
||||
let deliveredCount = 0;
|
||||
|
||||
if (autoDeliver) {
|
||||
// 如果使用 search_and_deliver 指令,结果中已包含投递信息
|
||||
if (commandResult && commandResult.results && commandResult.results.length > 0) {
|
||||
const result = commandResult.results[0].result;
|
||||
if (result) {
|
||||
jobCount = result.jobCount || 0;
|
||||
deliveredCount = result.deliveredCount || 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果使用 search_jobs_with_params 指令,等待搜索完成并从数据库获取结果
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
const searchedJobs = await job_postings.findAll({
|
||||
where: {
|
||||
sn_code: sn_code,
|
||||
platform: searchCommandParams.platform,
|
||||
applyStatus: 'pending',
|
||||
keyword: searchCommandParams.keyword
|
||||
},
|
||||
order: [['create_time', 'DESC']],
|
||||
limit: 1000
|
||||
});
|
||||
|
||||
jobCount = searchedJobs.length;
|
||||
}
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
deviceManager.recordTaskComplete(sn_code, task, true, duration);
|
||||
|
||||
console.log(`[任务处理器] 搜索职位列表任务完成 - 设备: ${sn_code}, 找到 ${jobCount} 个职位, 投递 ${deliveredCount} 个, 耗时: ${duration}ms`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
jobCount: jobCount,
|
||||
deliveredCount: deliveredCount,
|
||||
message: autoDeliver
|
||||
? `搜索完成,找到 ${jobCount} 个职位,成功投递 ${deliveredCount} 个`
|
||||
: `搜索完成,找到 ${jobCount} 个职位`
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
const duration = Date.now() - startTime;
|
||||
deviceManager.recordTaskComplete(sn_code, task, false, duration);
|
||||
console.error(`[任务处理器] 搜索职位列表任务失败 - 设备: ${sn_code}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理自动沟通任务(待实现)
|
||||
* 功能:自动与HR进行沟通,回复消息等
|
||||
|
||||
Reference in New Issue
Block a user