Files
ALL-teach_sys/frontend_大健康/src/pages/CompanyJobsPage/components/ResumeInfoModal/index.jsx
KQL 38350dca36 更新12个教务系统并优化项目大小
主要更新:
- 更新所有12个产业的教务系统数据和功能
- 删除所有 node_modules 文件夹(节省3.7GB)
- 删除所有 .yoyo 缓存文件夹(节省1.2GB)
- 删除所有 dist 构建文件(节省55MB)

项目优化:
- 项目大小从 8.1GB 减少到 3.2GB(节省60%空间)
- 保留完整的源代码和配置文件
- .gitignore 已配置,防止再次提交大文件

启动脚本:
- start-industry.sh/bat/ps1 脚本会自动检测并安装依赖
- 首次启动时自动运行 npm install
- 支持单个或批量启动产业系统

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-17 14:36:25 +08:00

795 lines
34 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 (
<>
<Modal visible={visible} onClose={handleCloseModal}>
<div className="resume-info-modal" onClick={(e) => e.stopPropagation()}>
<i className="close-icon" onClick={handleCloseModal} />
{(data?.content?.original || customVersions.length > 0) && (
<div className="resume-info-modal-header" style={{ marginBottom: '20px' }}>
<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>
)}
{customVersions.map((v) => (
<Radio key={v.id} value={`custom_${v.id}`}>
{v.name}
{isEditing === false && (
<span
onClick={(e) => {
e.stopPropagation();
handleDeleteVersion(v.id);
}}
style={{ marginLeft: '5px', color: '#ff4d4f', cursor: 'pointer' }}
>
×
</span>
)}
</Radio>
))}
</Radio.Group>
</div>
)}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '15px' }}>
<p className="resume-info-modal-title" style={{ margin: 0 }}>
{data?.title || resumeContent.personalInfo?.name || "职位名称"}
</p>
<div style={{ display: 'flex', gap: '8px' }}>
{!isEditing ? (
<Button
size="small"
icon={<IconEdit />}
onClick={handleEditClick}
style={{
backgroundColor: '#fff',
color: '#1890ff',
border: '1px solid #1890ff',
borderRadius: '4px'
}}
>
编辑
</Button>
) : (
<>
<div className="save-button-wrapper">
<Button
type="primary"
size="small"
icon={<IconSave />}
disabled={true}
style={{
borderRadius: '4px',
backgroundColor: '#d9d9d9',
borderColor: '#d9d9d9',
color: '#ffffff',
cursor: 'not-allowed',
opacity: 0.5
}}
>
保存
</Button>
<div
style={{
position: 'absolute',
top: '-35px',
left: '50%',
transform: 'translateX(-50%)',
backgroundColor: 'rgba(0, 0, 0, 0.75)',
color: '#fff',
padding: '6px 12px',
borderRadius: '4px',
fontSize: '12px',
whiteSpace: 'nowrap',
pointerEvents: 'none',
opacity: 0,
transition: 'opacity 0.3s',
zIndex: 1000
}}
className="save-button-tooltip"
>
非学员与导师无修改权限
</div>
</div>
<Button
size="small"
icon={<IconClose />}
onClick={handleCancelEdit}
style={{
borderRadius: '4px'
}}
>
取消
</Button>
</>
)}
</div>
</div>
{/* 统一使用结构化样式展示所有岗位 */}
<ul className="resume-info-moda-list">
{/* 教育经历 */}
<li className="resume-info-moda-item">
<p className="resume-info-moda-item-title">
<img src="https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/teach_sys_icon/recuW0XRVB1bpV.png" alt="" style={{ width: '28px', height: '28px', marginRight: '10px', verticalAlign: 'middle' }} />
教育经历
</p>
<ul className="educational-experience-list">
{(isEditing && editableData ? editableData.education : resumeContent.education)?.map((edu, index) => (
<li key={index} className="educational-experience-list-item">
<p className="school-name"
contentEditable={isEditing}
suppressContentEditableWarning={true}
onBlur={(e) => {
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}
</p>
<p className="study-time"
contentEditable={isEditing}
suppressContentEditableWarning={true}
onBlur={(e) => {
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}
</p>
</li>
))}
</ul>
</li>
{/* 项目经历 */}
<li className="resume-info-moda-item">
<p className="resume-info-moda-item-title">
<img src="https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/teach_sys_icon/recuW0XRVB1bpV.png" alt="" style={{ width: '28px', height: '28px', marginRight: '10px', verticalAlign: 'middle' }} />
项目经历
</p>
<ul className="project-experience-list">
{(isEditing && editableData ? editableData.projects : 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"
contentEditable={isEditing}
suppressContentEditableWarning={true}
onBlur={(e) => {
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}
</p>
<p className="project-company"
contentEditable={isEditing}
suppressContentEditableWarning={true}
onBlur={(e) => {
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}
</p>
</div>
<p className="project-time"
contentEditable={isEditing}
suppressContentEditableWarning={true}
onBlur={(e) => {
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}
</p>
</div>
<p className="project-desc"
style={{ whiteSpace: 'pre-wrap', lineHeight: '1.6', ...(isEditing ? {border: '1px dashed #d9d9d9', padding: '6px', borderRadius: '4px', cursor: 'text', minHeight: '60px'} : {}) }}
contentEditable={isEditing}
suppressContentEditableWarning={true}
onBlur={(e) => {
if (isEditing && editableData) {
const newProjects = [...editableData.projects];
newProjects[index] = { ...newProjects[index], description: e.target.innerText };
setEditableData({ ...editableData, projects: newProjects });
}
}}>
{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">
<img src="https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/teach_sys_icon/recuW0XRVB1bpV.png" alt="" style={{ width: '28px', height: '28px', marginRight: '10px', verticalAlign: 'middle' }} />
专业技能
</p>
<ul className="professional-skills-list">
{(isEditing && editableData ? editableData.skills?.core : resumeContent.skills?.core) && (
<li className="professional-skills-list-item">
<p className="skill-name">核心能力</p>
<div className="core-capabilities-list">
{(isEditing && editableData ? editableData.skills.core : resumeContent.skills.core).map((skill, index) => (
<p key={index} className="core-capabilities-list-item"
contentEditable={isEditing}
suppressContentEditableWarning={true}
onBlur={(e) => {
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}
</p>
))}
</div>
</li>
)}
{(isEditing && editableData ? editableData.skills?.additional : resumeContent.skills?.additional) && (
<li className="professional-skills-list-item">
<p className="skill-name">复合技能</p>
<div className="core-capabilities-list">
{(isEditing && editableData ? editableData.skills.additional : resumeContent.skills.additional).map((skill, index) => (
<p key={index} className="core-capabilities-list-item"
contentEditable={isEditing}
suppressContentEditableWarning={true}
onBlur={(e) => {
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}
</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">
<img src="https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/teach_sys_icon/recuW0XRVB1bpV.png" alt="" style={{ width: '28px', height: '28px', marginRight: '10px', verticalAlign: 'middle' }} />
个人总结
</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">
<img src="https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/teach_sys_icon/recuW0XRVB1bpV.png" alt="" style={{ width: '28px', height: '28px', marginRight: '10px', verticalAlign: 'middle' }} />
对应课程单元
</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>
</>
);
};