import { useState, useEffect } from "react"; import { Radio, Button, Message } from "@arco-design/web-react"; import { IconEdit, IconSave, IconClose } from "@arco-design/web-react/icon"; import Modal from "@/components/Modal"; import * as resumeManager from '@/services/resumeManager'; import "./index.css"; export default ({ visible, onClose, data, initialVersion = "2" }) => { const [version, setVersion] = useState(initialVersion); // 使用传入的初始版本 const [isEditing, setIsEditing] = useState(false); const [editableData, setEditableData] = useState(null); const [customVersions, setCustomVersions] = useState([]); // 调试:检查接收到的数据 useEffect(() => { if (visible && data) { console.log('ResumeInfoModal接收到的数据:', { title: data.title, hasContent: !!data.content, contentType: typeof data.content, contentKeys: data.content ? Object.keys(data.content) : null, hasSelectedTemplate: !!data.selectedTemplate, selectedTemplateKeys: data.selectedTemplate ? Object.keys(data.selectedTemplate) : null }); if (data.content) { console.log('content详情:', { hasOriginal: !!data.content.original, hasModified: !!data.content.modified, originalType: typeof data.content.original, originalLength: data.content.original ? data.content.original.length : 0 }); } } }, [visible, data]); // 响应initialVersion变化 useEffect(() => { setVersion(initialVersion); }, [initialVersion]); // 加载个人修改版本 useEffect(() => { if (visible && data?.title) { const versions = resumeManager.getVersionsByPosition(data.title); setCustomVersions(versions); } }, [visible, data?.title]); const onRadioChange = (value, e) => { e?.stopPropagation(); setVersion(value); setIsEditing(false); // 切换版本时退出编辑模式 }; const handleCloseModal = () => { setIsEditing(false); setEditableData(null); onClose(); }; // 开始编辑 const handleEditClick = () => { // 获取当前显示的内容并解析 let currentContent = ''; if (version.startsWith('custom_')) { const customVersion = resumeManager.getVersionById(version.replace('custom_', '')); currentContent = customVersion?.content || ''; } else if (data?.content) { const hasModified = !!data.content.modified; // 如果没有modified版本,始终使用original currentContent = (version === "1" || !hasModified) ? data.content.original : data.content.modified; } const parsed = parseResumeMarkdown(currentContent); setEditableData(parsed); setIsEditing(true); }; // 保存编辑 const handleSaveEdit = async () => { if (!editableData) return; // 将编辑后的数据转换回markdown格式 const contentToSave = convertToMarkdown(editableData); if (!contentToSave.trim()) { Message.error('简历内容不能为空'); return; } // 创建一个新的个人修改版 const versionName = `个人版_${new Date().toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }).replace(/\//g, '-').replace(/:/g, '')}`; const result = await resumeManager.createCustomVersion({ name: versionName, content: contentToSave, positionTitle: data?.title || '未命名岗位', originalVersion: version }); if (result.success) { Message.success('已保存为个人修改版'); setIsEditing(false); // 刷新个人修改版列表 const versions = resumeManager.getVersionsByPosition(data?.title); setCustomVersions(versions); // 切换到新保存的版本 setVersion('custom_' + result.data.id); } else { Message.error(result.error || '保存失败'); } }; // 取消编辑 const handleCancelEdit = () => { setIsEditing(false); setEditableData(null); }; // 删除个人版本 const handleDeleteVersion = (versionId) => { const result = resumeManager.deleteCustomVersion(versionId); if (result.success) { Message.success('已删除'); const versions = resumeManager.getVersionsByPosition(data?.title); setCustomVersions(versions); // 如果删除的是当前版本,切换到原始版 if (version === `custom_${versionId}`) { setVersion("1"); } } }; // 将结构化数据转换回markdown格式 const convertToMarkdown = (data) => { if (!data) return ''; let markdown = `# 对应岗位:${data.personalInfo?.name || data?.title || '职位名称'}\n\n`; // 项目经历 if (data.projects && data.projects.length > 0) { markdown += '# 一、项目经历\n'; data.projects.forEach(proj => { markdown += `### (一)项目名称:${proj.name}\n`; markdown += `### (二)实习岗位:${proj.role || '参与者'}\n`; if (proj.period) markdown += `### (三)实习时间:${proj.period}\n`; if (proj.company) markdown += `### (四)实习单位:${proj.company}\n`; if (proj.responsibilities && proj.responsibilities.length > 0) { markdown += '### (五)岗位职责:\n'; proj.responsibilities.forEach((resp, idx) => { markdown += `${idx + 1}. ${resp}\n`; }); } else if (proj.description) { markdown += `### (五)岗位职责:\n${proj.description}\n`; } markdown += '\n'; }); } // 专业技能 if (data.skills) { markdown += '# 二、专业技能\n'; if (data.skills.core && data.skills.core.length > 0) { markdown += '## (一)核心技能\n'; data.skills.core.forEach((skill, idx) => { markdown += `${idx + 1}. ${skill}\n`; }); } if (data.skills.additional && data.skills.additional.length > 0) { markdown += '## (二)复合技能\n'; data.skills.additional.forEach((skill, idx) => { markdown += `${idx + 1}. ${skill}\n`; }); } } return markdown; }; // Markdown解析器 - 解析简历内容 const parseResumeMarkdown = (markdownContent) => { if (!markdownContent || typeof markdownContent !== 'string') { return null; } const result = { personalInfo: { name: "岗位名称" }, education: [{ school: '南阳医学高等专科学校', major: '药品生产技术', period: '2018.9-2021.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(/### (?:(三)|(四))实习单位:(.+)/); // 提取岗位职责内容 - 兼容有冒号和没有冒号的情况 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; } } // 提取个人评价/个人总结 - 兼容两种标题 const personalSummaryMatch = markdownContent.match(/# 三、(?:个人评价|个人总结)\s+([\s\S]*?)$/); if (personalSummaryMatch) { const summaryText = personalSummaryMatch[1].trim(); if (summaryText) { result.personalSummary = [summaryText]; } } return result; }; // 获取简历数据 - 支持新的数据结构 let resumeContent = {}; console.log('开始处理简历内容,当前版本:', version); console.log('data?.content存在:', !!data?.content); // 处理自定义版本 if (version.startsWith('custom_')) { const customVersion = resumeManager.getVersionById(version.replace('custom_', '')); if (customVersion?.content) { resumeContent = parseResumeMarkdown(customVersion.content) || {}; } } else if (data?.content) { console.log('处理data.content,结构:', { hasOriginal: !!data.content.original, hasModified: !!data.content.modified, originalType: typeof data.content.original }); // 新的数据结构 - 来自resume-interview页面 if (data.content.original) { // 有original字段,可能有或没有modified字段 const hasModified = !!data.content.modified; // 如果没有modified版本,始终使用original const selectedContent = (version === "1" || !hasModified) ? data.content.original : data.content.modified; console.log('选择的内容长度:', selectedContent ? selectedContent.length : 0); // 如果是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 { console.log('进入else分支,检查selectedTemplate'); // 旧的数据结构 - 兼容现有的company jobs页面 const currentTemplate = data?.selectedTemplate; const studentInfo = currentTemplate?.studentInfo; console.log('currentTemplate信息:', { hasCurrentTemplate: !!currentTemplate, hasContent: !!currentTemplate?.content, hasContentOriginal: !!currentTemplate?.content?.original, hasPosition: !!currentTemplate?.position, contentKeys: currentTemplate?.content ? Object.keys(currentTemplate.content) : null }); // 检查是否是来自resume-interview页面的数据 (有content.original字段) if (currentTemplate && currentTemplate.content && currentTemplate.content.original) { console.log('处理content.original结构'); // 处理有content.original的数据结构 const hasModified = !!currentTemplate.content.modified; // 如果没有modified版本,始终使用original const selectedContent = (version === "1" || !hasModified) ? currentTemplate.content.original : currentTemplate.content.modified; const parsedContent = parseResumeMarkdown(selectedContent); 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('最终resumeContent:', { hasResumeContent: !!resumeContent, keys: resumeContent ? Object.keys(resumeContent) : [], hasPersonalInfo: !!resumeContent?.personalInfo, isValidData }); // 如果数据无效,提供默认值防止渲染异常 if (!isValidData) { console.warn('ResumeInfoModal: Invalid resume data received', { data, resumeContent, dataKeys: data ? Object.keys(data) : null, hasContent: !!data?.content, hasSelectedTemplate: !!data?.selectedTemplate }); resumeContent = { personalInfo: { name: '数据加载中...' }, education: [], projects: [], skills: { core: [], additional: [] } }; } return ( <>
e.stopPropagation()}> {(data?.content?.original || customVersions.length > 0) && (
e.stopPropagation()} > 原始版 {data?.content?.modified && ( 个人修改版 )} {customVersions.map((v) => ( {v.name} {isEditing === false && ( { e.stopPropagation(); handleDeleteVersion(v.id); }} style={{ marginLeft: '5px', color: '#ff4d4f', cursor: 'pointer' }} > × )} ))}
)}

{data?.title || resumeContent.personalInfo?.name || "职位名称"}

{!isEditing ? ( ) : ( <>
非学员与导师无修改权限
)}
{/* 统一使用结构化样式展示所有岗位 */}
    {/* 教育经历 */}
  • 教育经历

      {(isEditing && editableData ? editableData.education : resumeContent.education)?.map((edu, index) => (
    • { if (isEditing && editableData) { const text = e.target.innerText; const parts = text.split(' - '); const newEdu = { ...editableData.education[index] }; newEdu.school = parts[0] || edu.school; newEdu.major = parts[1] || edu.major; const newEducation = [...editableData.education]; newEducation[index] = newEdu; setEditableData({ ...editableData, education: newEducation }); } }} style={isEditing ? {border: '1px dashed #d9d9d9', padding: '2px 6px', borderRadius: '4px', cursor: 'text'} : {}} > {edu.school} - {edu.major}

      { if (isEditing && editableData) { const newEducation = [...editableData.education]; newEducation[index] = { ...newEducation[index], period: e.target.innerText }; setEditableData({ ...editableData, education: newEducation }); } }} style={isEditing ? {border: '1px dashed #d9d9d9', padding: '2px 6px', borderRadius: '4px', cursor: 'text'} : {}}> {edu.period}

    • ))}
  • {/* 项目经历 */}
  • 项目经历

      {(isEditing && editableData ? editableData.projects : resumeContent.projects)?.map((project, index) => (
    • { if (isEditing && editableData) { const newProjects = [...editableData.projects]; newProjects[index] = { ...newProjects[index], name: e.target.innerText }; setEditableData({ ...editableData, projects: newProjects }); } }} style={isEditing ? {border: '1px dashed #d9d9d9', padding: '2px 6px', borderRadius: '4px', cursor: 'text'} : {}}> {project.name}

      { if (isEditing && editableData) { const text = e.target.innerText; const newProjects = [...editableData.projects]; if (text.includes('角色:')) { const parts = text.split(' - 角色:'); newProjects[index] = { ...newProjects[index], company: parts[0] || '', role: parts[1] || project.role }; } else { newProjects[index] = { ...newProjects[index], role: text }; } setEditableData({ ...editableData, projects: newProjects }); } }} style={isEditing ? {border: '1px dashed #d9d9d9', padding: '2px 6px', borderRadius: '4px', cursor: 'text'} : {}}> {project.company && `${project.company} - `}角色:{project.role}

      { if (isEditing && editableData) { const newProjects = [...editableData.projects]; newProjects[index] = { ...newProjects[index], period: e.target.innerText }; setEditableData({ ...editableData, projects: newProjects }); } }} style={isEditing ? {border: '1px dashed #d9d9d9', padding: '2px 6px', borderRadius: '4px', cursor: 'text'} : {}}> {project.period}

      { if (isEditing && editableData) { const newProjects = [...editableData.projects]; newProjects[index] = { ...newProjects[index], description: e.target.innerText }; setEditableData({ ...editableData, projects: newProjects }); } }}> {project.description}

      {project.highlights && (

        主要成果

        {project.highlights.map((highlight, idx) => (
      • {highlight}
      • ))}
      )}
    • ))}
  • {/* 专业技能 */}
  • 专业技能

      {(isEditing && editableData ? editableData.skills?.core : resumeContent.skills?.core) && (
    • 核心能力

      {(isEditing && editableData ? editableData.skills.core : resumeContent.skills.core).map((skill, index) => (

      { if (isEditing && editableData) { const newSkills = { ...editableData.skills }; const text = e.target.innerText; // Remove numbering if present newSkills.core[index] = text.replace(/^[0-9]+\.\s*/, ''); setEditableData({ ...editableData, skills: newSkills }); } }} style={isEditing ? {border: '1px dashed #d9d9d9', padding: '2px 6px', borderRadius: '4px', cursor: 'text'} : {}}> {index + 1}. {skill}

      ))}
    • )} {(isEditing && editableData ? editableData.skills?.additional : resumeContent.skills?.additional) && (
    • 复合技能

      {(isEditing && editableData ? editableData.skills.additional : resumeContent.skills.additional).map((skill, index) => (

      { if (isEditing && editableData) { const newSkills = { ...editableData.skills }; const text = e.target.innerText; // Remove numbering if present newSkills.additional[index] = text.replace(/^[0-9]+\.\s*/, ''); setEditableData({ ...editableData, skills: newSkills }); } }} style={isEditing ? {border: '1px dashed #d9d9d9', padding: '2px 6px', borderRadius: '4px', cursor: 'text'} : {}}> {index + 1}. {skill}

      ))}
    • )}
  • {/* 个人总结 */} {(resumeContent.personalSummary && resumeContent.personalSummary.length > 0) || (resumeContent.personalSummary && typeof resumeContent.personalSummary === 'string') ? (
  • 个人总结

    {Array.isArray(resumeContent.personalSummary) ? (
      {resumeContent.personalSummary.map((summary, index) => (
    • {summary}
    • ))}
    ) : (

    {resumeContent.personalSummary}

    )}
  • ) : null} {/* 对应课程单元 - 暂时保留静态展示,后续可根据需要动态化 */} {resumeContent.courses && (
  • 对应课程单元

    • 相关课程
        {resumeContent.courses.map((course, index) => (
      • {course}
      • ))}
  • )}
); };