Files
teach_sys_Demo/src/pages/CompanyJobsPage/components/ResumeInfoModal/index.jsx

371 lines
15 KiB
React
Raw Normal View History

import { useState, useEffect } from "react";
import { Radio } from "@arco-design/web-react";
import Modal from "@/components/Modal";
import "./index.css";
export default ({ visible, onClose, data, initialVersion = "2" }) => {
const [version, setVersion] = useState(initialVersion); // 使用传入的初始版本
// 响应initialVersion变化
useEffect(() => {
setVersion(initialVersion);
}, [initialVersion]);
const onRadioChange = (value, e) => {
e?.stopPropagation();
setVersion(value);
};
const handleCloseModal = () => {
onClose();
};
// Markdown解析器 - 解析简历内容
const parseResumeMarkdown = (markdownContent) => {
if (!markdownContent || typeof markdownContent !== 'string') {
return null;
}
const result = {
personalInfo: { name: "岗位名称" },
education: [{
school: '苏州信息职业技术学院',
major: '旅游管理',
period: '2020.9-2023.6'
}],
projects: [],
skills: { core: [], additional: [] },
personalSummary: []
};
// 提取岗位名称
const positionMatch = markdownContent.match(/# 对应岗位:(.+)/);
if (positionMatch) {
result.personalInfo.name = positionMatch[1].trim();
}
// 提取项目经历
const projectSectionMatch = markdownContent.match(/# 一、项目经历\s+([\s\S]*?)(?=# 二、专业技能|$)/);
if (projectSectionMatch) {
const projectContent = projectSectionMatch[1];
// 提取项目名称
const projectNameMatch = projectContent.match(/### (一)项目名称:(.+)/);
const roleMatch = projectContent.match(/### (二)实习岗位:(.+)/);
const timeMatch = projectContent.match(/### (三)实习时间:(.+)/);
const companyMatch = projectContent.match(/### (四)实习单位:(.+)/);
// 提取岗位职责内容 - 从"### (五)岗位职责:"开始到下一个section
const responsibilityMatch = projectContent.match(/### (五)岗位职责:\s+([\s\S]*?)$/);
if (projectNameMatch) {
result.projects = [{
name: projectNameMatch[1].trim(),
role: roleMatch ? roleMatch[1].trim() : "参与者",
period: timeMatch ? timeMatch[1].trim() : "",
company: companyMatch ? companyMatch[1].trim() : "",
description: responsibilityMatch ? responsibilityMatch[1].trim() : ""
}];
}
}
// 提取专业技能
const skillsSectionMatch = markdownContent.match(/# 二、专业技能\s+([\s\S]*?)$/);
if (skillsSectionMatch) {
const skillsContent = skillsSectionMatch[1];
// 提取核心能力
const coreSkillsMatch = skillsContent.match(/### (一)核心能力\s+([\s\S]*?)(?=### (二)复合能力|$)/);
if (coreSkillsMatch) {
const coreSkills = coreSkillsMatch[1]
.split(/\d+\.\s+/)
.filter(skill => skill.trim())
.map(skill => skill.trim().replace(/\s*$/, ''));
result.skills.core = coreSkills;
}
// 提取复合能力
const additionalSkillsMatch = skillsContent.match(/### (二)复合能力\s+([\s\S]*?)$/);
if (additionalSkillsMatch) {
const additionalSkills = additionalSkillsMatch[1]
.split(/\d+\.\s+/)
.filter(skill => skill.trim())
.map(skill => skill.trim().replace(/。\s*$/, ''));
result.skills.additional = additionalSkills;
}
}
return result;
};
// 获取简历数据 - 支持新的数据结构
let resumeContent = {};
if (data?.content) {
// 新的数据结构 - 来自resume-interview页面
if (data.content.original) {
// 有original字段可能有或没有modified字段
const hasModified = !!data.content.modified;
const selectedContent = (!hasModified || version === "1") ? data.content.original : data.content.modified;
// 如果是markdown格式的字符串使用解析器
if (typeof selectedContent === 'string') {
resumeContent = parseResumeMarkdown(selectedContent);
} else if (selectedContent.personalInfo) {
// 如果已经是结构化数据
resumeContent = selectedContent;
}
} else if (data.content.personalInfo) {
// 兼容旧的数据结构(单一版本)
resumeContent = data.content;
} else if (typeof data.content === 'string') {
// 如果content直接是markdown字符串
resumeContent = parseResumeMarkdown(data.content);
}
} else {
// 旧的数据结构 - 兼容现有的company jobs页面
const currentTemplate = data?.selectedTemplate;
const studentInfo = currentTemplate?.studentInfo;
// 检查是否是来自resume-interview页面的数据 (有content和personal_summary字段)
if (currentTemplate && currentTemplate.content && currentTemplate.position) {
// 来自resume-interview页面的新数据结构
const parsedContent = parseResumeMarkdown(currentTemplate.content);
if (parsedContent) {
resumeContent = parsedContent;
// 添加个人总结 - 检查多个可能的位置
if (currentTemplate.personal_summary) {
resumeContent.personalSummary = [currentTemplate.personal_summary];
} else if (currentTemplate.studentInfo?.personalSummary) {
resumeContent.personalSummary = [currentTemplate.studentInfo.personalSummary];
} else if (currentTemplate.studentInfo?.personal_summary) {
resumeContent.personalSummary = [currentTemplate.studentInfo.personal_summary];
}
// 更新岗位名称
resumeContent.personalInfo.name = currentTemplate.position;
}
} else if (studentInfo) {
// 构造兼容格式
resumeContent = {
personalInfo: { name: currentTemplate?.position || "岗位名称" },
education: [{
school: studentInfo.education?.university || '苏州信息职业技术学院',
major: '旅游管理',
period: studentInfo.education?.period || '2020.9-2023.6'
}],
projects: [],
skills: { core: [], additional: [] },
personalSummary: [studentInfo.personalSummary || studentInfo.personal_summary || "具有扎实的专业基础和实践经验"]
};
// 处理项目经历
if (studentInfo.projectExperience) {
resumeContent.projects = [{
name: "项目经历",
role: "参与者",
period: "",
description: studentInfo.projectExperience
}];
} else if (studentInfo.project_experience) {
if (Array.isArray(studentInfo.project_experience)) {
resumeContent.projects = studentInfo.project_experience.map(proj => ({
name: proj.name || "实习项目",
role: proj.role || "参与者",
period: proj.period || "",
description: proj.description || "参与项目实施"
}));
} else if (typeof studentInfo.project_experience === 'object') {
const proj = studentInfo.project_experience;
resumeContent.projects = [{
name: proj.project_name || proj.position || "实习项目",
role: proj.role || "参与者",
period: proj.period || "",
description: proj.description || "参与项目实施"
}];
}
}
// 处理专业技能
if (studentInfo.skills) {
// 新格式skills是字符串转换为数组
const skillsArray = studentInfo.skills.split('\n').filter(s => s.trim());
const midPoint = Math.ceil(skillsArray.length / 2);
resumeContent.skills = {
core: skillsArray.slice(0, midPoint),
additional: skillsArray.slice(midPoint)
};
} else {
resumeContent.skills = {
core: studentInfo.core_skills || [],
additional: studentInfo.compound_skills || []
};
}
}
}
// 数据校验:确保必要字段存在
const isValidData = resumeContent && Object.keys(resumeContent).length > 0 && resumeContent.personalInfo;
// 调试日志 (可以移除)
// console.log('ResumeInfoModal Debug:', { data, resumeContent });
// 如果数据无效,提供默认值防止渲染异常
if (!isValidData) {
console.warn('ResumeInfoModal: Invalid resume data received', { data, resumeContent });
resumeContent = {
personalInfo: { name: '数据加载中...' },
education: [],
projects: [],
skills: { core: [], additional: [] }
};
}
return (
<>
<Modal visible={visible} onClose={handleCloseModal}>
<div className="resume-info-modal" onClick={(e) => e.stopPropagation()}>
<i className="close-icon" onClick={handleCloseModal} />
{data?.content?.original && (
<div className="resume-info-modal-header">
<Radio.Group
type="button"
name="position"
className="resume-info-modal-radio-group"
value={version}
onChange={onRadioChange}
onClick={(e) => e.stopPropagation()}
>
<Radio value="1">原始版</Radio>
{data?.content?.modified && (
<Radio value="2">个人修改版</Radio>
)}
</Radio.Group>
</div>
)}
<p className="resume-info-modal-title">
{data?.title || resumeContent.personalInfo?.name || "职位名称"}
</p>
{/* 统一使用结构化样式展示所有岗位 */}
<ul className="resume-info-moda-list">
{/* 教育经历 */}
<li className="resume-info-moda-item">
<p className="resume-info-moda-item-title">教育经历</p>
<ul className="educational-experience-list">
{resumeContent.education?.map((edu, index) => (
<li key={index} className="educational-experience-list-item">
<p className="school-name">
{edu.school} - {edu.major}
</p>
<p className="study-time">{edu.period}</p>
</li>
))}
</ul>
</li>
{/* 项目经历 */}
<li className="resume-info-moda-item">
<p className="resume-info-moda-item-title">项目经历</p>
<ul className="project-experience-list">
{resumeContent.projects?.map((project, index) => (
<li key={index} className="project-experience-list-item">
<div className="project-info-wrapper">
<div className="project-info">
<p className="project-name">{project.name}</p>
<p className="project-company">
{project.company && `${project.company} - `}角色{project.role}
</p>
</div>
<p className="project-time">{project.period}</p>
</div>
<p className="project-desc" style={{ whiteSpace: 'pre-wrap', lineHeight: '1.6' }}>
{project.description}
</p>
{project.highlights && (
<ul className="job-responsibilities-list">
<p>主要成果</p>
{project.highlights.map((highlight, idx) => (
<li key={idx}>{highlight}</li>
))}
</ul>
)}
</li>
))}
</ul>
</li>
{/* 专业技能 */}
<li className="resume-info-moda-item">
<p className="resume-info-moda-item-title">专业技能</p>
<ul className="professional-skills-list">
{resumeContent.skills?.core && (
<li className="professional-skills-list-item">
<p className="skill-name">核心能力</p>
<div className="core-capabilities-list">
{resumeContent.skills.core.map((skill, index) => (
<p key={index} className="core-capabilities-list-item">
{index + 1}. {skill}
</p>
))}
</div>
</li>
)}
{resumeContent.skills?.additional && (
<li className="professional-skills-list-item">
<p className="skill-name">复合技能</p>
<div className="core-capabilities-list">
{resumeContent.skills.additional.map((skill, index) => (
<p key={index} className="core-capabilities-list-item">
{index + 1}. {skill}
</p>
))}
</div>
</li>
)}
</ul>
</li>
{/* 个人总结 */}
{(resumeContent.personalSummary && resumeContent.personalSummary.length > 0) ||
(resumeContent.personalSummary && typeof resumeContent.personalSummary === 'string') ? (
<li className="resume-info-moda-item">
<p className="resume-info-moda-item-title">个人总结</p>
<div className="personal-summary-content">
{Array.isArray(resumeContent.personalSummary) ? (
<ul className="personal-summary-list">
{resumeContent.personalSummary.map((summary, index) => (
<li key={index} style={{ whiteSpace: 'pre-wrap', lineHeight: '1.6' }}>
{summary}
</li>
))}
</ul>
) : (
<p style={{ whiteSpace: 'pre-wrap', lineHeight: '1.6' }}>
{resumeContent.personalSummary}
</p>
)}
</div>
</li>
) : null}
{/* 对应课程单元 - 暂时保留静态展示,后续可根据需要动态化 */}
{resumeContent.courses && (
<li className="resume-info-moda-item">
<p className="resume-info-moda-item-title">对应课程单元</p>
<ul className="corresponding-course-units-list">
<li className="corresponding-course-units-list-item">
<div className="tag">相关课程</div>
<ul className="course-units-list">
{resumeContent.courses.map((course, index) => (
<li key={index} className="course-units-list-item">
{course}
</li>
))}
</ul>
</li>
</ul>
</li>
)}
</ul>
</div>
</Modal>
</>
);
};