checkHardRequirements($position, $resume); if (!$hardCheck['passed']) { return 0; // 硬性条件不满足,直接返回0分 } // 第二步:计算软性条件匹配度(100分制) $softCheck = $this->calculateSoftRequirements($position, $resume); return $softCheck['score']; } /** * 批量匹配查询(基于数据库) * @param int $userId 用户ID * @param int $page 页码,从1开始 * @param int $pageSize 每页数量 * @param bool $filterZero 是否过滤0分岗位 * @return array */ public function batchMatchFromDb(int $userId, int $page = 1, int $pageSize = 20, bool $filterZero = false): array { // 1. 从数据库获取用户简历信息 $resume = $this->getUserResumeFromDb($userId); if (empty($resume)) { return [ 'list' => [], 'pagination' => [ 'page' => $page, 'page_size' => $pageSize, 'total' => 0, 'total_pages' => 0 ] ]; } // 2. 从数据库获取所有岗位 $filteredPositions = $this->filterPositionsFromDb($resume); if (empty($filteredPositions)) { return [ 'list' => [], 'pagination' => [ 'page' => $page, 'page_size' => $pageSize, 'total' => 0, 'total_pages' => 0 ] ]; } // 3. 计算匹配度 $results = []; foreach ($filteredPositions as $position) { try { $score = $this->calculateMatchScore($position, $resume); if ($filterZero && $score == 0) { continue; // 过滤0分岗位 } $results[] = [ 'position_id' => $position['id'] ?? 0, 'match_score' => $score, 'position' => $position ]; } catch (\Exception $e) { // 如果计算出错,继续处理其他岗位 continue; } } // 4. 按匹配度降序排序 usort($results, function($a, $b) { return $b['match_score'] - $a['match_score']; }); // 5. 分页 $total = count($results); $totalPages = (int)ceil($total / $pageSize); $offset = ($page - 1) * $pageSize; $paginatedList = array_slice($results, $offset, $pageSize); return [ 'list' => $paginatedList, 'pagination' => [ 'page' => $page, 'page_size' => $pageSize, 'total' => $total, 'total_pages' => $totalPages, 'has_more' => $page < $totalPages ] ]; } /** * 从数据库获取用户简历信息 * @param int $userId 用户ID * @return array */ private function getUserResumeFromDb(int $userId): array { // 1. 获取用户基本信息(t_user表) // 尝试不同的主键字段名 $user = null; try { $user = Db::name('t_user')->where('uid', $userId)->find(); } catch (\Exception $e) { // ignore and fallback below } // 如果按 uid 没有查到,再按 id 尝试(即使没有异常也尝试,以防字段是 id) if (empty($user)) { try { $user = Db::name('t_user')->where('id', $userId)->find(); } catch (\Exception $e2) { // 忽略错误 } } if (empty($user)) { return []; } // 转换为数组(如果返回的是对象) if (is_object($user)) { $user = $user->toArray(); } // 2. 获取用户简历信息(t_user_curriculum_vitae表) // 尝试使用uid或user_id字段 $curriculumVitae = null; try { $curriculumVitae = Db::name('t_user_curriculum_vitae') ->where('uid', $userId) ->find(); } catch (\Exception $e) { // ignore and fallback below } // 如果按 uid 没查到,再按 user_id 查一次 if (empty($curriculumVitae)) { try { $curriculumVitae = Db::name('t_user_curriculum_vitae') ->where('user_id', $userId) ->find(); } catch (\Exception $e2) { // 如果都不存在,curriculumVitae保持为null } } // 转换为数组 if (is_object($curriculumVitae)) { $curriculumVitae = $curriculumVitae->toArray(); } elseif ($curriculumVitae === null) { $curriculumVitae = []; } // 3. 获取用户教育经历(t_user_education表) // 尝试使用uid或user_id字段 $educations = []; try { $educations = Db::name('t_user_education') ->where('uid', $userId) ->order('education_level desc') // 按学历等级降序,最高学历在前 ->select() ->toArray(); } catch (\Exception $e) { // ignore and fallback below } // 如果按 uid 没查到,再按 user_id 查一次(即使没有异常也尝试,以防字段是 user_id) if (empty($educations)) { try { $educations = Db::name('t_user_education') ->where('user_id', $userId) ->order('education_level desc') ->select() ->toArray(); } catch (\Exception $e2) { // 如果都不存在,educations保持为空数组 } } // 3.1 如果教育经历里有专业代码,预先加载专业表(da_majors)以便解析专业名称 $majorCodeMap = []; $majorCodes = []; foreach ($educations as $education) { // 收集所有可能的专业代码字段 $codeFields = ['major_code', 'majors_code', 'code', 'major_id', 'majors_id', 'major_no', 'id']; foreach ($codeFields as $field) { if (!empty($education[$field])) { $majorCodes[] = $education[$field]; } } } $majorCodes = array_values(array_unique($majorCodes)); if (!empty($majorCodes)) { try { // 尝试多种可能的查询字段:id, code, major_code, majors_id $majors = []; $queryFields = ['id', 'code', 'major_code', 'majors_id', 'major_id']; foreach ($queryFields as $queryField) { try { $majors = Db::name('da_majors') ->whereIn($queryField, $majorCodes) ->select() ->toArray(); if (!empty($majors)) { break; // 找到匹配的字段,退出循环 } } catch (\Exception $e) { // 字段不存在,继续尝试下一个 continue; } } // 构建专业代码映射表 foreach ($majors as $major) { // 尝试多种可能的代码字段 $code = $major['id'] ?? $major['code'] ?? $major['major_code'] ?? $major['majors_id'] ?? $major['major_id'] ?? null; if (!$code) { continue; } // 尝试多种可能的名称字段 $name = $major['major_name'] ?? $major['name'] ?? $major['title'] ?? $major['full_name'] ?? $major['major_full_name'] ?? $major['专业名称'] ?? $major['专业名称全称'] ?? ''; // 尝试多种可能的类别字段 $category = $major['category_name'] ?? $major['category'] ?? $major['category_full'] ?? $major['major_category'] ?? $major['major_category_name'] ?? $major['专业类别'] ?? $major['学科类别'] ?? ''; $majorCodeMap[$code] = [ 'name' => $name, 'category' => $category, ]; } } catch (\Exception $e) { // 忽略错误 } } // 构建简历数据结构 $resume = [ 'user_id' => $userId, // 从用户表获取基本信息 'birth_date' => $user['birth_date'] ?? $curriculumVitae['birth_date'] ?? '', 'gender' => $user['gender'] ?? $curriculumVitae['gender'] ?? '', 'ethnicity' => $user['ethnicity'] ?? $curriculumVitae['ethnicity'] ?? '', 'political_status' => $user['political_status'] ?? $curriculumVitae['political_status'] ?? '', // 从简历表获取工作经历等信息 'work_experience' => $curriculumVitae['work_experience'] ?? $user['work_experience'] ?? '', // 教育经历从t_user_education表获取 'education' => [] ]; // 处理教育经历数据,确保字段名正确 foreach ($educations as $education) { // 尝试多种可能的专业字段名 $majorName = ''; $possibleMajorFields = [ 'majors_name', 'major_name', 'major', 'major_field', 'specialty', 'profession', 'discipline', 'subject', '专业名称', '专业', '学科专业', '专业类别' ]; foreach ($possibleMajorFields as $field) { if (!empty($education[$field])) { $majorName = $education[$field]; break; } } // 如果有专业代码但没有名称,尝试从 da_majors 映射获取 if (empty($majorName)) { $codeFields = ['major_code', 'majors_code', 'code', 'major_id', 'majors_id', 'major_no', 'id']; foreach ($codeFields as $field) { if (!empty($education[$field])) { $codeValue = $education[$field]; // 尝试直接匹配 if (isset($majorCodeMap[$codeValue])) { $majorName = $majorCodeMap[$codeValue]['name'] ?? ''; $education['major_category'] = $majorCodeMap[$codeValue]['category'] ?? ''; if (!empty($majorName)) { break; } } } } } // 保存专业代码,便于后续调试 $majorCode = ''; foreach (['major_code', 'majors_code', 'code', 'major_id', 'majors_id', 'major_no'] as $field) { if (!empty($education[$field])) { $majorCode = $education[$field]; break; } } $resume['education'][] = [ 'education_level' => $education['education_level'] ?? $education['education'] ?? $education['学历'] ?? '', 'degree' => $education['degree'] ?? $education['学位'] ?? '', 'majors_name' => $majorName, 'majors_code' => $majorCode, 'majors_category' => $education['major_category'] ?? $education['专业类别'] ?? '', 'school_name' => $education['school_name'] ?? $education['school'] ?? $education['学校名称'] ?? '', 'graduation_date' => $education['graduation_date'] ?? $education['毕业时间'] ?? '', ]; } return $resume; } /** * 从数据库获取所有岗位(用于匹配) * @param array $resume 简历信息(用于可选的快速过滤) * @return array */ private function filterPositionsFromDb(array $resume): array { // 获取所有未删除的岗位(no_notice_position表) // 注意:根据用户要求,需要匹配所有岗位,所以这里不做严格过滤 // 只排除已删除的岗位,其他过滤在详细匹配时进行 $query = Db::name('no_notice_position'); // 排除已删除的岗位(如果表中有deleted_at字段) // 使用where条件,如果字段不存在,SQL会报错,但我们可以通过查询表结构来判断 // 为了安全,先尝试查询,如果失败则查询所有记录 try { // 尝试添加deleted_at条件 $query->whereNull('deleted_at'); $positions = $query->select()->toArray(); } catch (\Exception $e) { // 如果字段不存在或其他错误,查询所有记录 try { $query = Db::name('no_notice_position'); $positions = $query->select()->toArray(); } catch (\Exception $e2) { $positions = []; } } // 解析JSON字段,构建position_require结构 foreach ($positions as &$position) { // 处理position_other_require字段(可能是JSON格式) $otherRequire = []; if (!empty($position['position_other_require'])) { if (is_string($position['position_other_require'])) { $otherRequire = json_decode($position['position_other_require'], true) ?: []; } else { $otherRequire = $position['position_other_require']; } } // 构建统一的position_require结构 $position['position_require'] = [ '学历要求' => $position['education_require'] ?? '', '学位要求' => $position['degree_require'] ?? '', '年龄要求' => $position['age_require'] ?? '', '性别要求' => $position['sex_require'] ?? '', '专业(学科)类别' => $otherRequire['专业(学科)类别'] ?? '', '专业-本科' => $otherRequire['专业-本科'] ?? '', '专业-硕士' => $otherRequire['专业-硕士'] ?? '', '其他资格条件' => $otherRequire['其他资格条件'] ?? '', '专业资格条件' => $otherRequire['专业资格条件'] ?? '', ]; } return $positions; } /** * 检查硬性条件(一票否决机制) * @param array $position 岗位信息 * @param array $resume 简历信息 * @return array */ private function checkHardRequirements(array $position, array $resume): array { $positionRequire = $position['position_require'] ?? []; $result = [ 'passed' => true, 'rejection_reasons' => [], 'details' => [] ]; // 1. 学历要求(硬性) if (!empty($positionRequire['学历要求'])) { $educationCheck = $this->checkEducation($positionRequire['学历要求'], $resume); $result['details']['学历要求'] = $educationCheck; if (!$educationCheck['passed']) { $result['passed'] = false; $result['rejection_reasons'][] = $educationCheck['reason']; } } // 2. 学位要求(硬性) if (!empty($positionRequire['学位要求'])) { $degreeCheck = $this->checkDegree($positionRequire['学位要求'], $resume); $result['details']['学位要求'] = $degreeCheck; if (!$degreeCheck['passed']) { $result['passed'] = false; $result['rejection_reasons'][] = $degreeCheck['reason']; } } // 3. 年龄要求(硬性) $ageRequire = $positionRequire['年龄要求'] ?? ''; if (!empty($ageRequire) && trim($ageRequire) !== '' && trim($ageRequire) !== '无' && trim($ageRequire) !== '不限制') { $ageCheck = $this->checkAge($ageRequire, $resume); $result['details']['年龄要求'] = $ageCheck; if (!$ageCheck['passed']) { $result['passed'] = false; $result['rejection_reasons'][] = $ageCheck['reason']; } } // 4. 专业要求(硬性) // 支持多种专业字段格式:专业(学科)类别、专业-本科、专业-硕士 $majorRequire = $this->getMajorRequirement($positionRequire, $resume); if (!empty($majorRequire)) { $majorCheck = $this->checkMajor($majorRequire, $resume); $result['details']['专业要求'] = $majorCheck; if (!$majorCheck['passed']) { $result['passed'] = false; $result['rejection_reasons'][] = $majorCheck['reason']; } } // 5. 性别要求(硬性,如果明确要求) // 优先检查 sex_require 字段 $sexRequire = $positionRequire['性别要求'] ?? ''; if (!empty($sexRequire) && $sexRequire !== '不限制' && $sexRequire !== '无') { $genderCheck = $this->checkGender($sexRequire, $resume); $result['details']['性别要求'] = $genderCheck; if (!$genderCheck['passed']) { $result['passed'] = false; $result['rejection_reasons'][] = $genderCheck['reason']; } } // 如果 sex_require 字段没有明确要求,再检查其他资格条件 if (empty($sexRequire) || $sexRequire === '不限制' || $sexRequire === '无') { $otherConditions = $positionRequire['其他资格条件'] ?? ''; if (preg_match('/适合(男|女)性/u', $otherConditions, $matches)) { $genderCheck = $this->checkGender($matches[1], $resume); $result['details']['性别要求'] = $genderCheck; if (!$genderCheck['passed']) { $result['passed'] = false; $result['rejection_reasons'][] = $genderCheck['reason']; } } } return $result; } /** * 计算软性条件匹配度(100分制) * @param array $position 岗位信息 * @param array $resume 简历信息 * @return array */ private function calculateSoftRequirements(array $position, array $resume): array { $positionRequire = $position['position_require'] ?? []; $score = 0; $details = []; $maxScore = 100; // 1. 专业匹配度(40分)- 即使专业类别符合,也可以根据专业相关性打分 $majorScore = $this->scoreMajorMatch($positionRequire['专业(学科)类别'] ?? '', $resume); $score += $majorScore['score']; $details['专业匹配度'] = $majorScore; // 2. 学历层次匹配度(20分)- 超过要求的学历可以加分 $educationScore = $this->scoreEducationLevel($positionRequire['学历要求'] ?? '', $resume); $score += $educationScore['score']; $details['学历层次匹配度'] = $educationScore; // 3. 专业资格条件(20分)- 竞赛获奖等 $qualificationScore = $this->scoreQualification($positionRequire['专业资格条件'] ?? '', $resume); $score += $qualificationScore['score']; $details['专业资格条件'] = $qualificationScore; // 4. 基层工作经历(10分) $workExpScore = $this->scoreWorkExperience($resume); $score += $workExpScore['score']; $details['基层工作经历'] = $workExpScore; // 5. 其他条件匹配(10分)- 如政治面貌、特殊身份等 $otherScore = $this->scoreOtherConditions($positionRequire['其他资格条件'] ?? '', $resume); $score += $otherScore['score']; $details['其他条件'] = $otherScore; return [ 'score' => min(100, $score), 'max_score' => $maxScore, 'details' => $details ]; } // ==================== 硬性条件检查方法 ==================== /** * 检查学历要求(硬性) */ private function checkEducation(string $requirement, array $resume): array { $educations = $resume['education'] ?? []; if (empty($educations)) { return [ 'passed' => false, 'reason' => '未提供学历信息', 'required' => $requirement, 'actual' => null ]; } $highestEducation = $this->getHighestEducation($educations); if (empty($highestEducation)) { return [ 'passed' => false, 'reason' => '无法识别最高学历', 'required' => $requirement, 'actual' => null ]; } $educationLevel = $highestEducation['education_level'] ?? ''; $educationLevels = [ '普通本科' => 3, '本科' => 3, '大学本科' => 3, '本科学历' => 3, '硕士研究生' => 4, '硕士' => 4, '研究生' => 4, '博士研究生' => 5, '博士' => 5, ]; $requireLevel = $this->parseEducationRequire($requirement); $actualLevel = $educationLevels[$educationLevel] ?? 0; if ($actualLevel >= $requireLevel) { return [ 'passed' => true, 'required' => $requirement, 'actual' => $educationLevel ]; } return [ 'passed' => false, 'reason' => "学历不符合要求:需要{$requirement},实际为{$educationLevel}", 'required' => $requirement, 'actual' => $educationLevel ]; } /** * 检查学位要求(硬性) */ private function checkDegree(string $requirement, array $resume): array { $educations = $resume['education'] ?? []; if (empty($educations)) { return [ 'passed' => false, 'reason' => '未提供学位信息', 'required' => $requirement, 'actual' => null ]; } $highestEducation = $this->getHighestEducation($educations); $degree = $highestEducation['degree'] ?? ''; $degreeLevels = [ '学士' => 1, '硕士' => 2, '博士' => 3, ]; $requireLevel = $this->parseDegreeRequire($requirement); $actualLevel = $degreeLevels[$degree] ?? 0; if ($actualLevel >= $requireLevel) { return [ 'passed' => true, 'required' => $requirement, 'actual' => $degree ]; } return [ 'passed' => false, 'reason' => "学位不符合要求:需要{$requirement},实际为{$degree}", 'required' => $requirement, 'actual' => $degree ]; } /** * 检查年龄要求(硬性) */ private function checkAge(string $requirement, array $resume): array { // 如果年龄要求为空或"无",直接通过 $requirement = trim($requirement); if (empty($requirement) || $requirement === '无' || $requirement === '不限制') { return [ 'passed' => true, 'required' => $requirement ?: '无要求', 'actual' => '无要求' ]; } $birthDate = $resume['birth_date'] ?? ''; if (empty($birthDate)) { return [ 'passed' => false, 'reason' => '未提供出生日期', 'required' => $requirement, 'actual' => null ]; } $age = $this->calculateAge($birthDate); if (preg_match('/(\d+)周岁以上.*?(\d+)周岁以下/u', $requirement, $matches)) { $minAge = (int)$matches[1]; $maxAge = (int)$matches[2]; if ($age >= $minAge && $age <= $maxAge) { return [ 'passed' => true, 'required' => $requirement, 'actual' => "{$age}岁" ]; } return [ 'passed' => false, 'reason' => "年龄不符合要求:需要{$minAge}-{$maxAge}岁,实际为{$age}岁", 'required' => $requirement, 'actual' => "{$age}岁" ]; } return [ 'passed' => false, 'reason' => '无法解析年龄要求格式', 'required' => $requirement, 'actual' => "{$age}岁" ]; } /** * 检查专业要求(硬性) */ private function checkMajor(string $requirement, array $resume): array { $educations = $resume['education'] ?? []; if (empty($educations)) { return [ 'passed' => false, 'reason' => '未提供专业信息', 'required' => $requirement, 'actual' => null ]; } $matchedMajors = []; foreach ($educations as $education) { // 尝试多种可能的专业字段名 $majorName = $education['majors_name'] ?? $education['major_name'] ?? $education['major'] ?? $education['major_field'] ?? $education['specialty'] ?? $education['profession'] ?? $education['majors_category'] ?? ''; if (!empty($majorName) && $this->isMajorCategoryMatch($majorName, $requirement)) { $matchedMajors[] = $majorName; } } if (!empty($matchedMajors)) { return [ 'passed' => true, 'required' => $requirement, 'actual' => implode('、', $matchedMajors) ]; } // 收集所有专业名称用于错误信息 $actualMajors = []; foreach ($educations as $edu) { $majorName = $edu['majors_name'] ?? $edu['major_name'] ?? $edu['major'] ?? $edu['major_field'] ?? $edu['specialty'] ?? $edu['profession'] ?? $edu['majors_category'] ?? ''; if (!empty($majorName)) { $actualMajors[] = $majorName; } } return [ 'passed' => false, 'reason' => "专业不符合要求:需要{$requirement},实际为" . implode('、', $actualMajors), 'required' => $requirement, 'actual' => implode('、', $actualMajors) ]; } /** * 检查性别要求(硬性) */ private function checkGender(string $requireGender, array $resume): array { $gender = $resume['gender'] ?? ''; if ($gender === $requireGender) { return [ 'passed' => true, 'required' => $requireGender, 'actual' => $gender ]; } return [ 'passed' => false, 'reason' => "性别不符合要求:需要{$requireGender},实际为{$gender}", 'required' => $requireGender, 'actual' => $gender ]; } // ==================== 软性条件评分方法 ==================== /** * 专业匹配度评分(40分) */ private function scoreMajorMatch(string $requirement, array $resume): array { if (empty($requirement)) { return ['score' => 40, 'reason' => '无专业要求']; } $educations = $resume['education'] ?? []; if (empty($educations)) { return ['score' => 0, 'reason' => '无专业信息']; } $maxScore = 0; foreach ($educations as $education) { $majorName = $education['majors_name'] ?? ''; $score = $this->calculateMajorRelevanceScore($majorName, $requirement); $maxScore = max($maxScore, $score); } return [ 'score' => min(40, $maxScore), 'max_score' => 40, 'reason' => $maxScore >= 40 ? '专业高度匹配' : '专业部分匹配' ]; } /** * 学历层次匹配度评分(20分) */ private function scoreEducationLevel(string $requirement, array $resume): array { $educations = $resume['education'] ?? []; if (empty($educations)) { return ['score' => 0, 'reason' => '无学历信息']; } $highestEducation = $this->getHighestEducation($educations); $educationLevel = $highestEducation['education_level'] ?? ''; $educationLevels = [ '普通本科' => 3, '本科' => 3, '大学本科' => 3, '本科学历' => 3, '硕士研究生' => 4, '硕士' => 4, '研究生' => 4, '博士研究生' => 5, '博士' => 5, ]; $requireLevel = $this->parseEducationRequire($requirement); $actualLevel = $educationLevels[$educationLevel] ?? 0; // 刚好满足要求:15分,超过一级:20分,超过两级及以上:20分 if ($actualLevel == $requireLevel) { return ['score' => 15, 'max_score' => 20, 'reason' => '刚好满足要求']; } elseif ($actualLevel > $requireLevel) { $exceed = $actualLevel - $requireLevel; return [ 'score' => 15 + min(5, $exceed * 5), 'max_score' => 20, 'reason' => "超过要求{$exceed}级" ]; } return ['score' => 0, 'reason' => '未达到要求']; } /** * 专业资格条件评分(20分) */ private function scoreQualification(string $requirement, array $resume): array { if (empty($requirement)) { return [ 'score' => 20, 'max_score' => 20, 'reason' => '无专业资格要求' ]; } // 这里可以根据简历中的证书、获奖等信息来评分 // 由于当前简历数据结构中没有这些字段,暂时返回基础分数 // 实际应用中需要扩展简历数据结构 return [ 'score' => 0, 'max_score' => 20, 'reason' => '未提供专业资格证明材料(需扩展简历数据结构)' ]; } /** * 基层工作经历评分(10分) */ private function scoreWorkExperience(array $resume): array { $workExperience = $resume['work_experience'] ?? ''; if (empty($workExperience) || strpos($workExperience, '无') !== false) { return [ 'score' => 0, 'max_score' => 10, 'reason' => '无基层工作经历' ]; } // 可以根据工作年限进一步细化评分 return [ 'score' => 10, 'max_score' => 10, 'reason' => '有基层工作经历' ]; } /** * 其他条件评分(10分) */ private function scoreOtherConditions(string $requirement, array $resume): array { if (empty($requirement)) { return ['score' => 10, 'reason' => '无其他条件要求']; } $score = 0; $maxScore = 10; // 政治面貌等可以根据岗位要求评分 // 当前暂不实现,返回基础分数 return [ 'score' => 10, 'max_score' => $maxScore, 'reason' => '其他条件匹配(需根据具体岗位要求细化)' ]; } // ==================== 辅助方法 ==================== /** * 计算年龄 */ private function calculateAge(string $birthDate): int { $birthTimestamp = strtotime($birthDate); $currentTimestamp = time(); $age = date('Y', $currentTimestamp) - date('Y', $birthTimestamp); if (date('md', $currentTimestamp) < date('md', $birthTimestamp)) { $age--; } return $age; } /** * 获取最高学历 */ private function getHighestEducation(array $educations): ?array { if (empty($educations)) { return null; } $educationLevels = [ '普通本科' => 3, '本科' => 3, '大学本科' => 3, '本科学历' => 3, '硕士研究生' => 4, '硕士' => 4, '研究生' => 4, '博士研究生' => 5, '博士' => 5, ]; $highest = null; $highestLevel = 0; foreach ($educations as $education) { $level = $educationLevels[$education['education_level'] ?? ''] ?? 0; if ($level > $highestLevel) { $highestLevel = $level; $highest = $education; } } return $highest; } /** * 解析学历要求 */ private function parseEducationRequire(string $require): int { if (strpos($require, '本科') !== false) { return 3; } if (strpos($require, '硕士') !== false) { return 4; } if (strpos($require, '博士') !== false) { return 5; } return 0; } /** * 解析学位要求 */ private function parseDegreeRequire(string $require): int { if (strpos($require, '学士') !== false) { return 1; } if (strpos($require, '硕士') !== false) { return 2; } if (strpos($require, '博士') !== false) { return 3; } return 0; } /** * 获取专业要求(支持多种格式) */ private function getMajorRequirement(array $positionRequire, array $resume): string { // 优先使用 专业(学科)类别 if (!empty($positionRequire['专业(学科)类别'])) { return $positionRequire['专业(学科)类别']; } // 根据最高学历选择对应的专业要求 $educations = $resume['education'] ?? []; if (!empty($educations)) { $highestEducation = $this->getHighestEducation($educations); $educationLevel = $highestEducation['education_level'] ?? ''; // 判断学历等级 $isUndergraduate = in_array($educationLevel, ['普通本科', '本科', '大学本科', '本科学历']); $isGraduate = in_array($educationLevel, ['硕士研究生', '硕士', '研究生', '博士研究生', '博士']); if ($isUndergraduate && !empty($positionRequire['专业-本科'])) { return $positionRequire['专业-本科']; } if ($isGraduate && !empty($positionRequire['专业-硕士'])) { return $positionRequire['专业-硕士']; } // 如果没有对应学历的专业要求,尝试使用另一个 if ($isGraduate && !empty($positionRequire['专业-本科'])) { return $positionRequire['专业-本科']; } } return ''; } /** * 判断专业类别是否匹配(硬性检查) */ private function isMajorCategoryMatch(string $majorName, string $majorRequire): bool { if (empty($majorName) || empty($majorRequire)) { return false; } // 支持多种分隔符:,、、 $requireCategories = preg_split('/[,、,]/u', $majorRequire); foreach ($requireCategories as $category) { $category = trim($category); // 直接匹配专业名称 if ($majorName === $category || strpos($majorName, $category) !== false || strpos($category, $majorName) !== false) { return true; } // 计算机科学与技术类 if (strpos($category, '计算机') !== false) { $computerKeywords = ['计算机', '软件', '网络', '信息', '数据', '人工智能', '大数据', '网络安全', '信息安全']; foreach ($computerKeywords as $keyword) { if (strpos($majorName, $keyword) !== false) { return true; } } } // 电气、电子及自动化类 if (strpos($category, '电气') !== false || strpos($category, '电子') !== false || strpos($category, '自动化') !== false) { $electronicsKeywords = ['电气', '电子', '自动化', '通信', '电信', '电子信息']; foreach ($electronicsKeywords as $keyword) { if (strpos($majorName, $keyword) !== false) { return true; } } } // 教育学类 if (strpos($category, '教育') !== false) { if (strpos($majorName, '教育') !== false) { return true; } } // 心理学类 if (strpos($category, '心理') !== false) { if (strpos($majorName, '心理') !== false) { return true; } } } return false; } /** * 计算专业相关性分数(软性评分) */ private function calculateMajorRelevanceScore(string $majorName, string $majorRequire): int { if ($this->isMajorCategoryMatch($majorName, $majorRequire)) { return 40; // 完全匹配 } // 可以根据专业相似度进一步细化评分 // 这里简单返回0分 return 0; } }