1
This commit is contained in:
@@ -772,20 +772,57 @@ class JobManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析期望薪资
|
||||
* @param {string} expectedSalary - 期望薪资描述
|
||||
* @returns {number|null} 期望薪资数值(元)
|
||||
* 解析期望薪资(返回平均值)
|
||||
* @param {string} expectedSalary - 期望薪资描述(如 "20-30K"、"5000-6000元/月")
|
||||
* @returns {number|null} 期望薪资数值(元),如果是范围则返回平均值
|
||||
*/
|
||||
parse_expected_salary(expectedSalary) {
|
||||
if (!expectedSalary) return null;
|
||||
|
||||
// 匹配数字+K格式(如:20K)
|
||||
const match = expectedSalary.match(/(\d+)[kK千]/);
|
||||
if (match) {
|
||||
return parseInt(match[1]) * 1000;
|
||||
// 1. 匹配K格式范围:20-30K
|
||||
const kRangeMatch = expectedSalary.match(/(\d+)[-~](\d+)[kK千]/);
|
||||
if (kRangeMatch) {
|
||||
const min = parseInt(kRangeMatch[1]) * 1000;
|
||||
const max = parseInt(kRangeMatch[2]) * 1000;
|
||||
return (min + max) / 2; // 返回平均值
|
||||
}
|
||||
|
||||
// 匹配纯数字(如:20000)
|
||||
// 2. 匹配单个K值:25K
|
||||
const kMatch = expectedSalary.match(/(\d+)[kK千]/);
|
||||
if (kMatch) {
|
||||
return parseInt(kMatch[1]) * 1000;
|
||||
}
|
||||
|
||||
// 3. 匹配元/月格式范围:5000-6000元/月
|
||||
const yuanRangeMatch = expectedSalary.match(/(\d+)[-~](\d+)[元万]/);
|
||||
if (yuanRangeMatch) {
|
||||
const min = parseInt(yuanRangeMatch[1]);
|
||||
const max = parseInt(yuanRangeMatch[2]);
|
||||
if (expectedSalary.includes('万')) {
|
||||
return ((min + max) / 2) * 10000;
|
||||
} else {
|
||||
return (min + max) / 2; // 返回平均值
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 匹配单个元/月值:5000元/月
|
||||
const yuanMatch = expectedSalary.match(/(\d+)[元万]/);
|
||||
if (yuanMatch) {
|
||||
const value = parseInt(yuanMatch[1]);
|
||||
if (expectedSalary.includes('万')) {
|
||||
return value * 10000;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 匹配纯数字范围(如:20000-30000)
|
||||
const numRangeMatch = expectedSalary.match(/(\d+)[-~](\d+)/);
|
||||
if (numRangeMatch) {
|
||||
return (parseInt(numRangeMatch[1]) + parseInt(numRangeMatch[2])) / 2; // 返回平均值
|
||||
}
|
||||
|
||||
// 6. 匹配纯数字(如:20000)
|
||||
const numMatch = expectedSalary.match(/(\d+)/);
|
||||
if (numMatch) {
|
||||
return parseInt(numMatch[1]);
|
||||
@@ -834,28 +871,64 @@ class JobManager {
|
||||
|
||||
/**
|
||||
* 解析薪资范围
|
||||
* @param {string} salaryDesc - 薪资描述(如 "15-25K·14薪")
|
||||
* @returns {object} 薪资范围 { min, max }
|
||||
* @param {string} salaryDesc - 薪资描述(如 "15-25K·14薪"、"5000-6000元/月")
|
||||
* @returns {object} 薪资范围 { min, max },单位:元
|
||||
*/
|
||||
parse_salary_range(salaryDesc) {
|
||||
if (!salaryDesc) return { min: 0, max: 0 };
|
||||
|
||||
// 匹配常见格式:15-25K, 15K-25K, 15-25k·14薪
|
||||
const match = salaryDesc.match(/(\d+)[-~](\d+)[kK]/);
|
||||
if (match) {
|
||||
// 1. 匹配K格式:40-60K, 30-40K·18薪(忽略后面的薪数)
|
||||
const kMatch = salaryDesc.match(/(\d+)[-~](\d+)[kK千]/);
|
||||
if (kMatch) {
|
||||
return {
|
||||
min: parseInt(match[1]) * 1000,
|
||||
max: parseInt(match[2]) * 1000
|
||||
min: parseInt(kMatch[1]) * 1000,
|
||||
max: parseInt(kMatch[2]) * 1000
|
||||
};
|
||||
}
|
||||
|
||||
// 匹配单个数值:25K
|
||||
const singleMatch = salaryDesc.match(/(\d+)[kK]/);
|
||||
if (singleMatch) {
|
||||
const value = parseInt(singleMatch[1]) * 1000;
|
||||
// 2. 匹配单个K值:25K
|
||||
const singleKMatch = salaryDesc.match(/(\d+)[kK千]/);
|
||||
if (singleKMatch) {
|
||||
const value = parseInt(singleKMatch[1]) * 1000;
|
||||
return { min: value, max: value };
|
||||
}
|
||||
|
||||
// 3. 匹配元/月格式:5000-6000元/月
|
||||
const yuanMatch = salaryDesc.match(/(\d+)[-~](\d+)[元万]/);
|
||||
if (yuanMatch) {
|
||||
const min = parseInt(yuanMatch[1]);
|
||||
const max = parseInt(yuanMatch[2]);
|
||||
// 判断单位(万或元)
|
||||
if (salaryDesc.includes('万')) {
|
||||
return {
|
||||
min: min * 10000,
|
||||
max: max * 10000
|
||||
};
|
||||
} else {
|
||||
return { min, max };
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 匹配单个元/月值:5000元/月
|
||||
const singleYuanMatch = salaryDesc.match(/(\d+)[元万]/);
|
||||
if (singleYuanMatch) {
|
||||
const value = parseInt(singleYuanMatch[1]);
|
||||
if (salaryDesc.includes('万')) {
|
||||
return { min: value * 10000, max: value * 10000 };
|
||||
} else {
|
||||
return { min: value, max: value };
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 匹配纯数字格式(如:20000-30000)
|
||||
const numMatch = salaryDesc.match(/(\d+)[-~](\d+)/);
|
||||
if (numMatch) {
|
||||
return {
|
||||
min: parseInt(numMatch[1]),
|
||||
max: parseInt(numMatch[2])
|
||||
};
|
||||
}
|
||||
|
||||
return { min: 0, max: 0 };
|
||||
}
|
||||
|
||||
|
||||
@@ -472,46 +472,119 @@ class JobFilterService {
|
||||
|
||||
/**
|
||||
* 解析薪资范围
|
||||
* @param {string} salaryDesc - 薪资描述(如 "15-25K·14薪")
|
||||
* @returns {object|null} 薪资范围 { min, max }
|
||||
* @param {string} salaryDesc - 薪资描述(如 "15-25K·14薪"、"5000-6000元/月")
|
||||
* @returns {object|null} 薪资范围 { min, max },单位:元
|
||||
*/
|
||||
parseSalaryRange(salaryDesc) {
|
||||
if (!salaryDesc) return null;
|
||||
|
||||
// 匹配 "15-25K" 或 "15K-25K" 格式
|
||||
const match = salaryDesc.match(/(\d+)[-~](\d+)[Kk千]/);
|
||||
if (match) {
|
||||
// 1. 匹配K格式:40-60K, 30-40K·18薪(忽略后面的薪数)
|
||||
const kMatch = salaryDesc.match(/(\d+)[-~](\d+)[Kk千]/);
|
||||
if (kMatch) {
|
||||
return {
|
||||
min: parseInt(match[1]) * 1000,
|
||||
max: parseInt(match[2]) * 1000
|
||||
min: parseInt(kMatch[1]) * 1000,
|
||||
max: parseInt(kMatch[2]) * 1000
|
||||
};
|
||||
}
|
||||
|
||||
// 匹配单个数字 "20K"
|
||||
const singleMatch = salaryDesc.match(/(\d+)[Kk千]/);
|
||||
if (singleMatch) {
|
||||
const value = parseInt(singleMatch[1]) * 1000;
|
||||
// 2. 匹配单个K值:25K
|
||||
const singleKMatch = salaryDesc.match(/(\d+)[Kk千]/);
|
||||
if (singleKMatch) {
|
||||
const value = parseInt(singleKMatch[1]) * 1000;
|
||||
return { min: value, max: value };
|
||||
}
|
||||
|
||||
// 3. 匹配元/月格式:5000-6000元/月
|
||||
const yuanMatch = salaryDesc.match(/(\d+)[-~](\d+)[元万]/);
|
||||
if (yuanMatch) {
|
||||
const min = parseInt(yuanMatch[1]);
|
||||
const max = parseInt(yuanMatch[2]);
|
||||
// 判断单位(万或元)
|
||||
if (salaryDesc.includes('万')) {
|
||||
return {
|
||||
min: min * 10000,
|
||||
max: max * 10000
|
||||
};
|
||||
} else {
|
||||
return { min, max };
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 匹配单个元/月值:5000元/月
|
||||
const singleYuanMatch = salaryDesc.match(/(\d+)[元万]/);
|
||||
if (singleYuanMatch) {
|
||||
const value = parseInt(singleYuanMatch[1]);
|
||||
if (salaryDesc.includes('万')) {
|
||||
return { min: value * 10000, max: value * 10000 };
|
||||
} else {
|
||||
return { min: value, max: value };
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 匹配纯数字格式(如:20000-30000)
|
||||
const numMatch = salaryDesc.match(/(\d+)[-~](\d+)/);
|
||||
if (numMatch) {
|
||||
return {
|
||||
min: parseInt(numMatch[1]),
|
||||
max: parseInt(numMatch[2])
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析期望薪资
|
||||
* @param {string} expectedSalary - 期望薪资描述
|
||||
* @returns {number|null} 期望薪资数值
|
||||
* 解析期望薪资(返回平均值)
|
||||
* @param {string} expectedSalary - 期望薪资描述(如 "20-30K"、"5000-6000元/月")
|
||||
* @returns {number|null} 期望薪资数值(元),如果是范围则返回平均值
|
||||
*/
|
||||
parseExpectedSalary(expectedSalary) {
|
||||
if (!expectedSalary) return null;
|
||||
|
||||
// 匹配数字+K格式
|
||||
const match = expectedSalary.match(/(\d+)[Kk千]/);
|
||||
if (match) {
|
||||
return parseInt(match[1]) * 1000;
|
||||
// 1. 匹配K格式范围:20-30K
|
||||
const kRangeMatch = expectedSalary.match(/(\d+)[-~](\d+)[Kk千]/);
|
||||
if (kRangeMatch) {
|
||||
const min = parseInt(kRangeMatch[1]) * 1000;
|
||||
const max = parseInt(kRangeMatch[2]) * 1000;
|
||||
return (min + max) / 2; // 返回平均值
|
||||
}
|
||||
|
||||
// 匹配纯数字
|
||||
// 2. 匹配单个K值:25K
|
||||
const kMatch = expectedSalary.match(/(\d+)[Kk千]/);
|
||||
if (kMatch) {
|
||||
return parseInt(kMatch[1]) * 1000;
|
||||
}
|
||||
|
||||
// 3. 匹配元/月格式范围:5000-6000元/月
|
||||
const yuanRangeMatch = expectedSalary.match(/(\d+)[-~](\d+)[元万]/);
|
||||
if (yuanRangeMatch) {
|
||||
const min = parseInt(yuanRangeMatch[1]);
|
||||
const max = parseInt(yuanRangeMatch[2]);
|
||||
if (expectedSalary.includes('万')) {
|
||||
return ((min + max) / 2) * 10000;
|
||||
} else {
|
||||
return (min + max) / 2; // 返回平均值
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 匹配单个元/月值:5000元/月
|
||||
const yuanMatch = expectedSalary.match(/(\d+)[元万]/);
|
||||
if (yuanMatch) {
|
||||
const value = parseInt(yuanMatch[1]);
|
||||
if (expectedSalary.includes('万')) {
|
||||
return value * 10000;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 匹配纯数字范围(如:20000-30000)
|
||||
const numRangeMatch = expectedSalary.match(/(\d+)[-~](\d+)/);
|
||||
if (numRangeMatch) {
|
||||
return (parseInt(numRangeMatch[1]) + parseInt(numRangeMatch[2])) / 2; // 返回平均值
|
||||
}
|
||||
|
||||
// 6. 匹配纯数字(如:20000)
|
||||
const numMatch = expectedSalary.match(/(\d+)/);
|
||||
if (numMatch) {
|
||||
return parseInt(numMatch[1]);
|
||||
|
||||
@@ -230,15 +230,56 @@ class TaskHandlers {
|
||||
? JSON.parse(jobTypeConfig.excludeKeywords)
|
||||
: jobTypeConfig.excludeKeywords)
|
||||
: [];
|
||||
const taskExcludeKeywords = filterRules.excludeKeywords || [];
|
||||
let taskExcludeKeywords = filterRules.excludeKeywords || [];
|
||||
|
||||
// 如果 filterRules 中没有,尝试从 accountConfig.deliver_config 获取
|
||||
if ((!taskExcludeKeywords || taskExcludeKeywords.length === 0) && accountConfig.deliver_config) {
|
||||
const deliverConfig = typeof accountConfig.deliver_config === 'string'
|
||||
? JSON.parse(accountConfig.deliver_config)
|
||||
: accountConfig.deliver_config;
|
||||
if (deliverConfig.exclude_keywords) {
|
||||
taskExcludeKeywords = Array.isArray(deliverConfig.exclude_keywords)
|
||||
? deliverConfig.exclude_keywords
|
||||
: (typeof deliverConfig.exclude_keywords === 'string'
|
||||
? JSON.parse(deliverConfig.exclude_keywords)
|
||||
: []);
|
||||
}
|
||||
}
|
||||
const excludeKeywords = [...jobTypeExcludeKeywords, ...taskExcludeKeywords];
|
||||
|
||||
// 获取过滤关键词(用于优先匹配)
|
||||
const filterKeywords = filterRules.keywords || [];
|
||||
// 获取过滤关键词(用于优先匹配或白名单过滤)
|
||||
let filterKeywords = filterRules.keywords || [];
|
||||
|
||||
// 获取薪资范围过滤
|
||||
const minSalary = filterRules.minSalary || 0;
|
||||
const maxSalary = filterRules.maxSalary || 0;
|
||||
// 如果 filterRules 中没有,尝试从 accountConfig.deliver_config 获取
|
||||
if ((!filterKeywords || filterKeywords.length === 0) && accountConfig.deliver_config) {
|
||||
const deliverConfig = typeof accountConfig.deliver_config === 'string'
|
||||
? JSON.parse(accountConfig.deliver_config)
|
||||
: accountConfig.deliver_config;
|
||||
if (deliverConfig.filter_keywords) {
|
||||
filterKeywords = Array.isArray(deliverConfig.filter_keywords)
|
||||
? deliverConfig.filter_keywords
|
||||
: (typeof deliverConfig.filter_keywords === 'string'
|
||||
? JSON.parse(deliverConfig.filter_keywords)
|
||||
: []);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[任务处理器] 过滤关键词配置 - 包含关键词: ${JSON.stringify(filterKeywords)}, 排除关键词: ${JSON.stringify(excludeKeywords)}`);
|
||||
|
||||
// 获取薪资范围过滤(优先从 filterRules,如果没有则从 accountConfig.deliver_config 获取)
|
||||
let minSalary = filterRules.minSalary || 0;
|
||||
let maxSalary = filterRules.maxSalary || 0;
|
||||
|
||||
// 如果 filterRules 中没有,尝试从 accountConfig.deliver_config 获取
|
||||
if (minSalary === 0 && maxSalary === 0 && accountConfig.deliver_config) {
|
||||
const deliverConfig = typeof accountConfig.deliver_config === 'string'
|
||||
? JSON.parse(accountConfig.deliver_config)
|
||||
: accountConfig.deliver_config;
|
||||
minSalary = deliverConfig.min_salary || 0;
|
||||
maxSalary = deliverConfig.max_salary || 0;
|
||||
}
|
||||
|
||||
console.log(`[任务处理器] 薪资过滤配置 - 最低: ${minSalary}元, 最高: ${maxSalary}元`);
|
||||
|
||||
// 获取一个月内已投递的公司列表(用于过滤)
|
||||
// 注意:apply_records 和 Sequelize 已在方法开头定义
|
||||
@@ -263,27 +304,75 @@ class TaskHandlers {
|
||||
|
||||
// 薪资范围过滤
|
||||
if (minSalary > 0 || maxSalary > 0) {
|
||||
const jobSalaryMin = jobData.salaryMin || 0;
|
||||
const jobSalaryMax = jobData.salaryMax || 0;
|
||||
// 解析职位薪资字符串(如 "20-30K")
|
||||
const jobSalaryRange = this.parseSalaryRange(jobData.salary || '');
|
||||
const jobSalaryMin = jobSalaryRange.min || 0;
|
||||
const jobSalaryMax = jobSalaryRange.max || 0;
|
||||
|
||||
// 如果职位没有薪资信息,跳过
|
||||
if (jobSalaryMin === 0 && jobSalaryMax === 0) {
|
||||
console.log(`[任务处理器] 跳过无薪资信息的职位: ${jobData.jobTitle} @ ${jobData.companyName}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果职位薪资范围与过滤范围没有交集,则跳过
|
||||
if (minSalary > 0 && jobSalaryMax > 0 && minSalary > jobSalaryMax) {
|
||||
console.log(`[任务处理器] 跳过薪资过低职位: ${jobData.jobTitle} @ ${jobData.companyName}, 职位薪资: ${jobData.salary}, 要求最低: ${minSalary}`);
|
||||
continue;
|
||||
}
|
||||
if (maxSalary > 0 && jobSalaryMin > 0 && maxSalary < jobSalaryMin) {
|
||||
console.log(`[任务处理器] 跳过薪资过高职位: ${jobData.jobTitle} @ ${jobData.companyName}, 职位薪资: ${jobData.salary}, 要求最高: ${maxSalary}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果配置了简历期望薪资,也要与职位薪资进行比较
|
||||
if (resumeInfo && resumeInfo.expectedSalary) {
|
||||
const expectedSalaryRange = this.parseExpectedSalary(resumeInfo.expectedSalary);
|
||||
if (expectedSalaryRange) {
|
||||
const jobSalaryRange = this.parseSalaryRange(jobData.salary || '');
|
||||
const jobSalaryMin = jobSalaryRange.min || 0;
|
||||
const jobSalaryMax = jobSalaryRange.max || 0;
|
||||
|
||||
// 如果职位薪资明显低于期望薪资范围,跳过
|
||||
// 期望薪资是 "20-30K",职位薪资应该至少接近或高于期望薪资的最低值
|
||||
if (jobSalaryMax > 0 && expectedSalaryRange.min > 0 && jobSalaryMax < expectedSalaryRange.min * 0.8) {
|
||||
console.log(`[任务处理器] 跳过薪资低于期望的职位: ${jobData.jobTitle} @ ${jobData.companyName}, 职位薪资: ${jobData.salary}, 期望薪资: ${resumeInfo.expectedSalary}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 排除关键词过滤
|
||||
if (Array.isArray(excludeKeywords) && excludeKeywords.length > 0) {
|
||||
const jobText = `${jobData.jobTitle} ${jobData.companyName} ${jobData.jobDescription || ''}`.toLowerCase();
|
||||
const hasExcluded = excludeKeywords.some(kw => jobText.includes(kw.toLowerCase()));
|
||||
if (hasExcluded) {
|
||||
const matchedExcludeKeywords = excludeKeywords.filter(kw => {
|
||||
const keyword = kw ? kw.toLowerCase().trim() : '';
|
||||
return keyword && jobText.includes(keyword);
|
||||
});
|
||||
if (matchedExcludeKeywords.length > 0) {
|
||||
console.log(`[任务处理器] 跳过包含排除关键词的职位: ${jobData.jobTitle} @ ${jobData.companyName}, 匹配: ${matchedExcludeKeywords.join(', ')}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤关键词(白名单模式):如果设置了过滤关键词,只投递包含这些关键词的职位
|
||||
if (Array.isArray(filterKeywords) && filterKeywords.length > 0) {
|
||||
const jobText = `${jobData.jobTitle} ${jobData.companyName} ${jobData.jobDescription || ''}`.toLowerCase();
|
||||
const matchedKeywords = filterKeywords.filter(kw => {
|
||||
const keyword = kw ? kw.toLowerCase().trim() : '';
|
||||
return keyword && jobText.includes(keyword);
|
||||
});
|
||||
|
||||
if (matchedKeywords.length === 0) {
|
||||
// 如果没有匹配到任何过滤关键词,跳过该职位(白名单模式)
|
||||
console.log(`[任务处理器] 跳过未匹配过滤关键词的职位: ${jobData.jobTitle} @ ${jobData.companyName}, 过滤关键词: ${filterKeywords.join(', ')}`);
|
||||
continue;
|
||||
} else {
|
||||
console.log(`[任务处理器] 职位匹配过滤关键词: ${jobData.jobTitle} @ ${jobData.companyName}, 匹配: ${matchedKeywords.join(', ')}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查该公司是否在一个月内已投递过
|
||||
if (jobData.companyName && recentCompanyNames.has(jobData.companyName)) {
|
||||
console.log(`[任务处理器] 跳过一个月内已投递的公司: ${jobData.companyName}`);
|
||||
@@ -299,11 +388,14 @@ class TaskHandlers {
|
||||
priorityWeights
|
||||
);
|
||||
|
||||
// 如果配置了过滤关键词,给包含这些关键词的职位加分
|
||||
// 如果配置了过滤关键词,给包含这些关键词的职位加分(额外奖励)
|
||||
let keywordBonus = 0;
|
||||
if (Array.isArray(filterKeywords) && filterKeywords.length > 0) {
|
||||
const jobText = `${jobData.jobTitle} ${jobData.companyName} ${jobData.jobDescription || ''}`.toLowerCase();
|
||||
const matchedKeywords = filterKeywords.filter(kw => jobText.includes(kw.toLowerCase()));
|
||||
const matchedKeywords = filterKeywords.filter(kw => {
|
||||
const keyword = kw ? kw.toLowerCase().trim() : '';
|
||||
return keyword && jobText.includes(keyword);
|
||||
});
|
||||
if (matchedKeywords.length > 0) {
|
||||
// 每匹配一个关键词加5分,最多加20分
|
||||
keywordBonus = Math.min(matchedKeywords.length * 5, 20);
|
||||
@@ -448,6 +540,132 @@ class TaskHandlers {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析职位薪资范围
|
||||
* @param {string} salaryDesc - 薪资描述(如 "20-30K"、"30-40K·18薪"、"5000-6000元/月")
|
||||
* @returns {object} 薪资范围 { min, max },单位:元
|
||||
*/
|
||||
parseSalaryRange(salaryDesc) {
|
||||
if (!salaryDesc) return { min: 0, max: 0 };
|
||||
|
||||
// 1. 匹配K格式:40-60K, 30-40K·18薪(忽略后面的薪数)
|
||||
const kMatch = salaryDesc.match(/(\d+)[-~](\d+)[kK千]/);
|
||||
if (kMatch) {
|
||||
return {
|
||||
min: parseInt(kMatch[1]) * 1000,
|
||||
max: parseInt(kMatch[2]) * 1000
|
||||
};
|
||||
}
|
||||
|
||||
// 2. 匹配单个K值:25K
|
||||
const singleKMatch = salaryDesc.match(/(\d+)[kK千]/);
|
||||
if (singleKMatch) {
|
||||
const value = parseInt(singleKMatch[1]) * 1000;
|
||||
return { min: value, max: value };
|
||||
}
|
||||
|
||||
// 3. 匹配元/月格式:5000-6000元/月
|
||||
const yuanMatch = salaryDesc.match(/(\d+)[-~](\d+)[元万]/);
|
||||
if (yuanMatch) {
|
||||
const min = parseInt(yuanMatch[1]);
|
||||
const max = parseInt(yuanMatch[2]);
|
||||
// 判断单位(万或元)
|
||||
if (salaryDesc.includes('万')) {
|
||||
return {
|
||||
min: min * 10000,
|
||||
max: max * 10000
|
||||
};
|
||||
} else {
|
||||
return { min, max };
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 匹配单个元/月值:5000元/月
|
||||
const singleYuanMatch = salaryDesc.match(/(\d+)[元万]/);
|
||||
if (singleYuanMatch) {
|
||||
const value = parseInt(singleYuanMatch[1]);
|
||||
if (salaryDesc.includes('万')) {
|
||||
return { min: value * 10000, max: value * 10000 };
|
||||
} else {
|
||||
return { min: value, max: value };
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 匹配纯数字格式(如:20000-30000)
|
||||
const numMatch = salaryDesc.match(/(\d+)[-~](\d+)/);
|
||||
if (numMatch) {
|
||||
return {
|
||||
min: parseInt(numMatch[1]),
|
||||
max: parseInt(numMatch[2])
|
||||
};
|
||||
}
|
||||
|
||||
return { min: 0, max: 0 };
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析期望薪资范围
|
||||
* @param {string} expectedSalary - 期望薪资描述(如 "20-30K"、"5000-6000元/月")
|
||||
* @returns {object|null} 期望薪资范围 { min, max },单位:元
|
||||
*/
|
||||
parseExpectedSalary(expectedSalary) {
|
||||
if (!expectedSalary) return null;
|
||||
|
||||
// 1. 匹配K格式:20-30K
|
||||
const kMatch = expectedSalary.match(/(\d+)[-~](\d+)[kK千]/);
|
||||
if (kMatch) {
|
||||
return {
|
||||
min: parseInt(kMatch[1]) * 1000,
|
||||
max: parseInt(kMatch[2]) * 1000
|
||||
};
|
||||
}
|
||||
|
||||
// 2. 匹配单个K值:25K
|
||||
const singleKMatch = expectedSalary.match(/(\d+)[kK千]/);
|
||||
if (singleKMatch) {
|
||||
const value = parseInt(singleKMatch[1]) * 1000;
|
||||
return { min: value, max: value };
|
||||
}
|
||||
|
||||
// 3. 匹配元/月格式:5000-6000元/月
|
||||
const yuanMatch = expectedSalary.match(/(\d+)[-~](\d+)[元万]/);
|
||||
if (yuanMatch) {
|
||||
const min = parseInt(yuanMatch[1]);
|
||||
const max = parseInt(yuanMatch[2]);
|
||||
// 判断单位(万或元)
|
||||
if (expectedSalary.includes('万')) {
|
||||
return {
|
||||
min: min * 10000,
|
||||
max: max * 10000
|
||||
};
|
||||
} else {
|
||||
return { min, max };
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 匹配单个元/月值:5000元/月
|
||||
const singleYuanMatch = expectedSalary.match(/(\d+)[元万]/);
|
||||
if (singleYuanMatch) {
|
||||
const value = parseInt(singleYuanMatch[1]);
|
||||
if (expectedSalary.includes('万')) {
|
||||
return { min: value * 10000, max: value * 10000 };
|
||||
} else {
|
||||
return { min: value, max: value };
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 匹配纯数字格式(如:20000-30000)
|
||||
const numMatch = expectedSalary.match(/(\d+)[-~](\d+)/);
|
||||
if (numMatch) {
|
||||
return {
|
||||
min: parseInt(numMatch[1]),
|
||||
max: parseInt(numMatch[2])
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TaskHandlers;
|
||||
|
||||
Reference in New Issue
Block a user