import React, { useState, useEffect, useMemo } from 'react'; import { useParams, history, useLocation } from '@umijs/max'; import { Card, Typography, Row, Col, Tag, Space, Button, Progress, Divider, Avatar, message } from 'antd'; import { ArrowLeftOutlined, HeartOutlined, HeartFilled, EnvironmentOutlined, ClockCircleOutlined, UserOutlined, TrophyOutlined, FireOutlined, StarOutlined } from '@ant-design/icons'; import { Radar } from '@ant-design/charts'; import JobPortalHeader from '@/components/JobPortalHeader'; import './index.less'; import { getJobCompetitiveness, getEmptyCompetitivenessRadar, } from '@/services/jobportal/competitiveness'; import { isJobPortalLoggedIn } from '@/utils/jobPortalAuth'; import { favoriteJob, unfavoriteJob, applyJob } from '@/services/jobportal/user'; import { ensureJobPortalLogin, PORTAL_LOGIN_URL } from '@/utils/jobPortalAuth'; import { getDictLabel, findTreeLabelById } from '@/utils/jobPortalDict'; import { getDictValueEnum } from '@/services/system/dict'; import { getCmsIndustryTreeList } from '@/services/classify/industry'; import type { DictValueEnumObj } from '@/components/DictTag'; const { Title, Text, Paragraph } = Typography; // 学历字典映射 const educationMap: { [key: string]: string } = { '1': '大专', '2': '本科', '3': '硕士', '4': '博士', '0': '不限' }; // 工作经验字典映射 const experienceMap: { [key: string]: string } = { '1': '1年以下', '2': '1-3年', '3': '3-5年', '4': '5-10年', '5': '10年以上', '0': '不限' }; // 从缓存获取用户信息 const getUserIdFromCache = (): number | null => { try { const cached = localStorage.getItem('userInfo'); if (cached) { const userInfo = JSON.parse(cached); return userInfo?.userId || null; } } catch (error) { console.error('读取缓存用户信息失败:', error); } return null; }; // 格式化薪资显示 const formatSalary = (minSalary: number, maxSalary: number) => { if (minSalary && maxSalary) { return `${(minSalary / 1000).toFixed(0)}k-${(maxSalary / 1000).toFixed(0)}k`; } else if (minSalary) { return `${(minSalary / 1000).toFixed(0)}k+`; } else if (maxSalary) { return `面议-${(maxSalary / 1000).toFixed(0)}k`; } return '面议'; }; // 数据转换函数 const transformJobData = (jobData: any) => { return { id: jobData.jobId || jobData.id, title: jobData.jobTitle || jobData.title, company: jobData.companyName || jobData.company, companyLogo: jobData.companyLogo || 'https://via.placeholder.com/80', salary: jobData.minSalary && jobData.maxSalary ? formatSalary(jobData.minSalary, jobData.maxSalary) : (jobData.salary || '面议'), location: jobData.jobLocation || jobData.location, experience: jobData.experience ? experienceMap[jobData.experience] || jobData.experience : '不限', education: jobData.education ? educationMap[jobData.education] || jobData.education : '不限', tags: jobData.tags || ['五险一金', '带薪年假', '年终奖'], publishTime: jobData.publishTime || new Date().toISOString().split('T')[0], description: jobData.description || `

职位职责:

1. 负责相关业务系统的设计与开发;

2. 参与系统架构设计和技术选型;

3. 与团队协作完成项目开发;

任职要求:

1. 具备相关工作经验;

2. 熟悉相关技术栈;

3. 具备良好的团队协作能力;

`, companyInfo: { name: jobData.companyName || jobData.company || jobData.companyVo?.name, scale: jobData.companyVo?.scale ?? jobData.scale ?? '', industry: jobData.companyVo?.industry ?? jobData.industry ?? '', description: jobData.companyVo?.companyDescription || jobData.companyDescription || '暂无公司描述信息', }, competitiveness: { overall: 75, requirements: 70, salary: 80, company: 75, benefits: 80 }, marketTrend: [ { name: 'Java', demand: 85, salary: 90 }, { name: 'Spring Boot', demand: 75, salary: 85 }, { name: 'MySQL', demand: 70, salary: 75 }, { name: 'Redis', demand: 75, salary: 80 } ] }; }; // 职位详情数据(模拟数据) const mockJobDetail = { id: 1, title: 'Java高级开发工程师', company: '青岛科技发展有限公司', companyLogo: 'https://via.placeholder.com/80', salary: '15k-25k', location: '青岛·李沧区', experience: '3-5年', education: '本科', tags: ['五险一金', '带薪年假', '年终奖', '定期体检'], publishTime: '2024-03-15', description: `

职位职责:

1. 负责后端系统架构设计与优化,提升系统性能和稳定性;

2. 参与核心业务模块的设计与开发,使用Java、Spring Boot等框架;

3. 协作完成微服务架构,解决分布式系统相关问题;

4. 进行代码审查,确保代码质量和规范性;

5. 与前端、产品、测试等团队协作,推动项目快速迭代;

任职要求:

1. 本科及以上学历,计算机相关专业,3年以上Java开发经验;

2. 扎实的Java基础,熟悉Spring、Spring Boot、MyBatis等框架;

3. 熟悉MySQL、Redis等数据库,具备SQL优化能力;

4. 了解分布式系统设计,有微服务开发经验;

5. 具备良好的团队协作能力和学习能力;

`, companyInfo: { name: '青岛科技发展有限公司', scale: '500-999人', industry: '计算机/互联网', description: '青岛科技发展有限公司是一家专注于软件开发、技术服务的科技企业。公司致力于为客户提供优质的IT解决方案,业务涵盖企业信息化、移动应用开发等领域。我们拥有一支年轻、专业的团队,注重技术创新和人才培养,为员工提供良好的发展平台。' }, competitiveness: { overall: 75, requirements: 70, salary: 80, company: 75, benefits: 80 }, marketTrend: [ { name: 'Java', demand: 85, salary: 90 }, { name: 'Spring Boot', demand: 75, salary: 85 }, { name: 'MySQL', demand: 70, salary: 75 }, { name: 'Redis', demand: 75, salary: 80 } ] }; const JobDetailPage: React.FC = () => { const { id } = useParams<{ id: string }>(); const location = useLocation(); const [jobDetail, setJobDetail] = useState(mockJobDetail); const [loading, setLoading] = useState(false); const [isFavorited, setIsFavorited] = useState(false); const [originalJobData, setOriginalJobData] = useState(null); // 保存原始数据引用 const [overallScore, setOverallScore] = useState(0); const [radarData, setRadarData] = useState<{ item: string; score: number }[]>([ { item: '技能', score: 0 }, { item: '工作经验', score: 0 }, { item: '学历', score: 0 }, { item: '薪资', score: 0 }, { item: '年龄', score: 0 }, { item: '工作地', score: 0 } ]); const [scaleEnum, setScaleEnum] = useState({}); const [industryTree, setIndustryTree] = useState([]); useEffect(() => { Promise.all([ getDictValueEnum('scale', true, true), getCmsIndustryTreeList(), ]).then(([scaleData, industryRes]) => { setScaleEnum(scaleData); if (industryRes?.code === 200 && industryRes?.data) { setIndustryTree(industryRes.data); } }); }, []); const companyMetaItems = useMemo(() => { const company = originalJobData?.companyVo || {}; const rawScale = company.scale ?? originalJobData?.scale ?? jobDetail.companyInfo?.scale; const rawIndustry = company.industry ?? originalJobData?.industry ?? jobDetail.companyInfo?.industry; const items: string[] = []; const scaleLabel = getDictLabel(scaleEnum, rawScale) || rawScale; const industryLabel = findTreeLabelById(industryTree, rawIndustry) || rawIndustry; if (scaleLabel) items.push(scaleLabel); if (industryLabel) items.push(industryLabel); return items; }, [originalJobData, jobDetail.companyInfo, scaleEnum, industryTree]); useEffect(() => { // 首先尝试从传递的数据中获取职位信息 const passedJobData = (location.state as any)?.jobData; if (passedJobData) { // 保存原始数据引用 setOriginalJobData(passedJobData); // 将传递过来的数据转换为详情页面需要的格式 const transformedJobData = transformJobData(passedJobData); setJobDetail(transformedJobData); // 根据 isCollection 字段设置收藏状态 // isCollection 为 null 或 0 表示未收藏,其他值表示已收藏 setIsFavorited(passedJobData?.isCollection !== null && passedJobData?.isCollection !== 0 && passedJobData?.isCollection !== undefined); } else { // 如果没有传递数据,则根据id从API获取数据 // fetchJobDetail(id); // 默认未收藏 setOriginalJobData(null); setIsFavorited(false); } }, [id, location.state]); // 基于详情中的 id 再拉一次(避免从路由未传 id 的情况) useEffect(() => { const jobIdNum = Number((jobDetail as any)?.id); if (!Number.isNaN(jobIdNum) && jobIdNum) { fetchCompetitiveness(jobIdNum); } }, [jobDetail?.id]); const fetchCompetitiveness = async (jobIdNum: number) => { if (!isJobPortalLoggedIn()) { setOverallScore(0); setRadarData(getEmptyCompetitivenessRadar()); return; } try { const res = await getJobCompetitiveness(jobIdNum); const data = res as any; if (!data) { setOverallScore(0); setRadarData(getEmptyCompetitivenessRadar()); return; } if (typeof data.matchScore === 'number') { const clamped = Math.max(0, Math.min(100, data.matchScore)); setOverallScore(clamped); } else { setOverallScore(0); } if (data.radarChart) { const r = data.radarChart as any; const mapped = [ { item: '技能', score: r.skill ?? 0 }, { item: '工作经验', score: r.experience ?? 0 }, { item: '学历', score: r.education ?? 0 }, { item: '薪资', score: r.salary ?? 0 }, { item: '年龄', score: r.age ?? 0 }, { item: '工作地', score: r.location ?? 0 } ].map(d => ({ ...d, score: Math.max(0, Math.min(100, d.score)) })); setRadarData(mapped); } else { setRadarData(getEmptyCompetitivenessRadar()); } } catch (e) { setOverallScore(0); setRadarData(getEmptyCompetitivenessRadar()); } }; const handleCollect = async () => { if (!ensureJobPortalLogin('收藏职位')) { return; } // 如果是取消收藏,调用取消收藏接口 if (isFavorited) { const userId = getUserIdFromCache(); if (!userId) { message.warning('无法获取用户信息,请重新登录'); window.location.href = PORTAL_LOGIN_URL; return; } // 获取职位ID(从原始数据或转换后的数据中获取) const jobId = originalJobData?.jobId || originalJobData?.id || (jobDetail as any)?.id || id; if (!jobId) { message.error('职位信息不完整,无法取消收藏'); return; } try { const response = await unfavoriteJob({ jobId: Number(jobId), userId }); if (response?.code === 200) { setIsFavorited(false); // 更新原始数据的 isCollection 字段 if (originalJobData) { setOriginalJobData({ ...originalJobData, isCollection: 0 }); } message.success('取消收藏成功'); } else { message.error(response?.msg || '取消收藏失败'); } } catch (error) { console.error('取消收藏失败:', error); message.error('取消收藏失败,请重试'); } return; } const userId = getUserIdFromCache(); if (!userId) { message.warning('无法获取用户信息,请重新登录'); window.location.href = PORTAL_LOGIN_URL; return; } // 获取职位ID const jobId = originalJobData?.jobId || originalJobData?.id || (jobDetail as any)?.id || id; if (!jobId) { message.error('职位信息不完整'); return; } try { const response = await favoriteJob({ jobId: Number(jobId), userId }); if (response?.code === 200) { setIsFavorited(true); // 更新原始数据的 isCollection 字段 if (originalJobData) { setOriginalJobData({ ...originalJobData, isCollection: 1 }); } message.success('收藏成功'); } else { message.error(response?.msg || '收藏失败'); } } catch (error) { console.error('收藏操作失败:', error); message.error('收藏操作失败,请重试'); } }; const handleApply = async () => { if (!ensureJobPortalLogin('申请职位')) { return; } const userId = getUserIdFromCache(); if (!userId) { message.warning('无法获取用户信息,请重新登录'); window.location.href = PORTAL_LOGIN_URL; return; } // 获取职位ID(从原始数据或转换后的数据中获取) const jobId = originalJobData?.jobId || originalJobData?.id || (jobDetail as any)?.id || id; if (!jobId) { message.error('职位信息不完整,无法申请'); return; } try { const response = await applyJob({ jobId: String(jobId), userId: String(userId) }); if (response?.code === 200) { message.success('申请成功'); } else { message.error(response?.msg || '申请失败'); } } catch (error) { console.error('申请失败:', error); message.error('申请失败,请重试'); } }; return (
{/* 职位头部信息 */}
{jobDetail.title} {jobDetail.salary}
{jobDetail.location} {jobDetail.experience} {jobDetail.education} {jobDetail.tags.map((tag, index) => ( {tag} ))}
{/* 左侧内容区 */} {/* 职位描述 */}
{/* 公司信息 */}
{jobDetail.companyInfo.name} }> {companyMetaItems.map((label) => ( {label} ))}
{jobDetail.companyInfo.description}
{/* 右侧侧边栏 */} {/* 竞争力分析 */} 竞争力分析 } className="competitiveness-card" >
{overallScore}
综合评分
); }; export default JobDetailPage;