11
This commit is contained in:
126
api/middleware/schedule/utils/salaryParser.js
Normal file
126
api/middleware/schedule/utils/salaryParser.js
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* 薪资解析工具
|
||||
* 统一处理职位薪资和期望薪资的解析逻辑
|
||||
*/
|
||||
class SalaryParser {
|
||||
/**
|
||||
* 解析薪资范围字符串
|
||||
* @param {string} salaryDesc - 薪资描述 (如 "15-20K", "8000-12000元")
|
||||
* @returns {{ min: number, max: number }} 薪资范围(单位:元)
|
||||
*/
|
||||
static parse(salaryDesc) {
|
||||
if (!salaryDesc || typeof salaryDesc !== 'string') {
|
||||
return { min: 0, max: 0 };
|
||||
}
|
||||
|
||||
// 尝试各种格式
|
||||
return this.parseK(salaryDesc)
|
||||
|| this.parseYuan(salaryDesc)
|
||||
|| this.parseMixed(salaryDesc)
|
||||
|| { min: 0, max: 0 };
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 K 格式薪资 (如 "15-20K", "8-12k")
|
||||
*/
|
||||
static parseK(desc) {
|
||||
const kMatch = desc.match(/(\d+)[-~](\d+)[kK千]/);
|
||||
if (kMatch) {
|
||||
return {
|
||||
min: parseInt(kMatch[1]) * 1000,
|
||||
max: parseInt(kMatch[2]) * 1000
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析元格式薪资 (如 "8000-12000元", "15000-20000")
|
||||
*/
|
||||
static parseYuan(desc) {
|
||||
const yuanMatch = desc.match(/(\d+)[-~](\d+)元?/);
|
||||
if (yuanMatch) {
|
||||
return {
|
||||
min: parseInt(yuanMatch[1]),
|
||||
max: parseInt(yuanMatch[2])
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析混合格式 (如 "8k-12000元")
|
||||
*/
|
||||
static parseMixed(desc) {
|
||||
const mixedMatch = desc.match(/(\d+)[kK千][-~](\d+)元?/);
|
||||
if (mixedMatch) {
|
||||
return {
|
||||
min: parseInt(mixedMatch[1]) * 1000,
|
||||
max: parseInt(mixedMatch[2])
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查职位薪资是否在期望范围内
|
||||
* @param {object} jobSalary - 职位薪资 { min, max }
|
||||
* @param {number} minExpected - 期望最低薪资
|
||||
* @param {number} maxExpected - 期望最高薪资
|
||||
*/
|
||||
static isWithinRange(jobSalary, minExpected, maxExpected) {
|
||||
if (!jobSalary || jobSalary.min === 0) {
|
||||
return true; // 无法判断时默认通过
|
||||
}
|
||||
|
||||
// 职位最高薪资 >= 期望最低薪资
|
||||
if (minExpected > 0 && jobSalary.max < minExpected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 职位最低薪资 <= 期望最高薪资
|
||||
if (maxExpected > 0 && jobSalary.min > maxExpected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算薪资匹配度(用于职位评分)
|
||||
* @param {object} jobSalary - 职位薪资
|
||||
* @param {object} expectedSalary - 期望薪资
|
||||
* @returns {number} 匹配度 0-1
|
||||
*/
|
||||
static calculateMatch(jobSalary, expectedSalary) {
|
||||
if (!jobSalary || !expectedSalary || jobSalary.min === 0 || expectedSalary.min === 0) {
|
||||
return 0.5; // 无法判断时返回中性值
|
||||
}
|
||||
|
||||
const jobAvg = (jobSalary.min + jobSalary.max) / 2;
|
||||
const expectedAvg = (expectedSalary.min + expectedSalary.max) / 2;
|
||||
|
||||
const diff = Math.abs(jobAvg - expectedAvg);
|
||||
const range = (jobSalary.max - jobSalary.min + expectedSalary.max - expectedSalary.min) / 2;
|
||||
|
||||
// 差距越小,匹配度越高
|
||||
return Math.max(0, 1 - diff / (range || 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化薪资显示
|
||||
* @param {object} salary - 薪资对象 { min, max }
|
||||
* @returns {string} 格式化字符串
|
||||
*/
|
||||
static format(salary) {
|
||||
if (!salary || salary.min === 0) {
|
||||
return '面议';
|
||||
}
|
||||
|
||||
const minK = (salary.min / 1000).toFixed(0);
|
||||
const maxK = (salary.max / 1000).toFixed(0);
|
||||
return `${minK}-${maxK}K`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SalaryParser;
|
||||
Reference in New Issue
Block a user