- 修复"长安幻夜"和"水墨苏乡"项目对应单元无法显示的问题 - 使用模板字符串处理包含中文双引号的项目名称键 - 调整JobInfoModal弹窗最大宽度为860px 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
384 lines
15 KiB
JavaScript
384 lines
15 KiB
JavaScript
import { useState, useCallback, useEffect } from "react";
|
||
import { useSelector } from "react-redux";
|
||
import { Input, Select } from "@arco-design/web-react";
|
||
import Modal from "@/components/Modal";
|
||
import InfiniteScroll from "@/components/InfiniteScroll";
|
||
import toast from "@/components/Toast";
|
||
import FILEICON from "@/assets/images/CompanyJobsPage/file_icon.png";
|
||
import ResumeInfoModal from "../ResumeInfoModal";
|
||
import PermissionModal from "../PermissionModal";
|
||
import { getResumesList, submitResume, getPageData } from "@/services";
|
||
import "./index.css";
|
||
|
||
const InputSearch = Input.Search;
|
||
const PAGE_SIZE = 10;
|
||
|
||
export default ({ visible, onClose, data, directToResume = false, hideDeliverButton = false }) => {
|
||
const studentInfo = useSelector((state) => state.student.studentInfo);
|
||
const [resumeModalShow, setResumeModalShow] = useState(directToResume);
|
||
const [resumeInfoModalShow, setResumeInfoModalShow] = useState(false);
|
||
const [resumeInfoData, setResumeInfoData] = useState(null);
|
||
const [currentResumeId, setCurrentResumeId] = useState(null); // 当前查看的简历ID
|
||
const [resumeList, setResumeList] = useState([]); // 简历列表
|
||
const [listPage, setListPage] = useState(1);
|
||
const [listHasMore, setListHasMore] = useState(true);
|
||
const [permissionModalVisible, setPermissionModalVisible] = useState(false);
|
||
const [selectedVersions, setSelectedVersions] = useState({}); // 每个简历的版本选择,使用简历ID作为key
|
||
|
||
// 处理directToResume参数变化
|
||
useEffect(() => {
|
||
if (visible && directToResume) {
|
||
setResumeModalShow(true);
|
||
} else if (visible && !directToResume) {
|
||
setResumeModalShow(false);
|
||
}
|
||
}, [visible, directToResume]);
|
||
|
||
const handleCloseModal = () => {
|
||
setResumeModalShow(false);
|
||
setResumeList([]); // 清空简历列表
|
||
setListPage(1); // 重置分页
|
||
setListHasMore(true); // 重置加载更多状态
|
||
onClose();
|
||
};
|
||
|
||
const queryResumeList = useCallback(async () => {
|
||
const res = await getResumesList({
|
||
page: listPage,
|
||
pageSize: PAGE_SIZE,
|
||
studentId: studentInfo?.id
|
||
});
|
||
if (res.success) {
|
||
setResumeList((prevList) => {
|
||
const newList = [...prevList, ...res.data];
|
||
if (res.total === newList?.length) {
|
||
setListHasMore(false);
|
||
} else {
|
||
setListPage((prevPage) => prevPage + 1);
|
||
}
|
||
return newList;
|
||
});
|
||
}
|
||
}, [listPage, studentInfo?.id]);
|
||
|
||
// 点击立即投递
|
||
const handleClickDeliverBtn = (e) => {
|
||
e.stopPropagation();
|
||
setResumeModalShow(true);
|
||
};
|
||
|
||
|
||
|
||
// 选择简历投递
|
||
const userResumesClick = async (item) => {
|
||
// 显示权限提示弹窗
|
||
setPermissionModalVisible(true);
|
||
|
||
// 原投递逻辑暂时注释,实际使用时可根据用户权限判断
|
||
/*
|
||
try {
|
||
// 调用投递服务
|
||
const result = await submitResume({
|
||
resumeId: item.id,
|
||
jobId: data?.id,
|
||
studentId: studentInfo?.id,
|
||
resumeTitle: item.title,
|
||
jobPosition: data?.position,
|
||
company: data?.company,
|
||
resumeVersion: selectedVersions[item.id] || "2" // 添加版本信息
|
||
});
|
||
|
||
if (result.success) {
|
||
// 投递成功,显示成功提示
|
||
const versionText = (selectedVersions[item.id] || "2") === "1" ? "原始版" : "个人修改版";
|
||
toast.success(`简历"${item.title}"(${versionText})投递成功!`);
|
||
|
||
// 关闭模态框
|
||
handleCloseModal();
|
||
|
||
// 输出投递成功信息
|
||
console.log('投递成功', {
|
||
applicationId: result.data.applicationId,
|
||
resumeId: item.id,
|
||
jobId: data?.id,
|
||
resumeTitle: item.title,
|
||
jobPosition: data?.position,
|
||
submittedAt: result.data.submittedAt
|
||
});
|
||
} else {
|
||
toast.error(result.message || '投递失败,请重试');
|
||
}
|
||
|
||
} catch (error) {
|
||
toast.error('投递失败,请重试');
|
||
console.error('投递失败:', error);
|
||
}
|
||
*/
|
||
};
|
||
|
||
// 点击简历详情
|
||
const userResumesBtnClick = async (e, item) => {
|
||
e.stopPropagation();
|
||
|
||
try {
|
||
// 获取岗位与面试题页面的数据
|
||
const pageDataResponse = await getPageData();
|
||
|
||
if (pageDataResponse.success) {
|
||
const pageData = pageDataResponse.data;
|
||
|
||
// 找到对应的行业信息
|
||
const matchedIndustry = pageData.industries?.find(industry =>
|
||
industry.name === item.industry
|
||
);
|
||
|
||
// 从resumeTemplates中查找对应岗位的模板
|
||
const industryTemplates = pageData.resumeTemplates?.[item.industry] || [];
|
||
const positionTemplate = industryTemplates.find(template =>
|
||
template.position === item.position
|
||
);
|
||
|
||
// 添加调试日志
|
||
console.log('查找简历模板:', {
|
||
industryName: item.industry,
|
||
positionTitle: item.position,
|
||
templatesCount: industryTemplates.length,
|
||
templatePositions: industryTemplates.map(t => t.position),
|
||
templatesStructure: industryTemplates.slice(0, 2).map(t => ({
|
||
position: t.position,
|
||
hasContent: !!t.content,
|
||
hasStudentInfo: !!t.studentInfo,
|
||
keys: Object.keys(t)
|
||
}))
|
||
});
|
||
|
||
if (positionTemplate) {
|
||
console.log('找到的模板:', {
|
||
position: positionTemplate.position,
|
||
hasContent: !!positionTemplate.content,
|
||
hasContentOriginal: !!positionTemplate.content?.original,
|
||
hasStudentInfo: !!positionTemplate.studentInfo,
|
||
templateKeys: Object.keys(positionTemplate),
|
||
contentKeys: positionTemplate.content ? Object.keys(positionTemplate.content) : null
|
||
});
|
||
} else {
|
||
console.warn('未找到简历模板:', item.position);
|
||
}
|
||
|
||
// 构造简历数据,使用与ResumeInterviewPage相同的格式
|
||
const resumeData = {
|
||
title: item.position, // 使用岗位名称作为标题
|
||
content: positionTemplate?.content || null, // 这里包含原始版和修改版数据
|
||
selectedTemplate: positionTemplate, // 添加selectedTemplate字段
|
||
studentResume: pageData.myResume
|
||
};
|
||
|
||
console.log('加载简历数据:', {
|
||
resumeTitle: item.title,
|
||
position: item.position,
|
||
industry: item.industry,
|
||
selectedVersion: selectedVersions[item.id] || "2",
|
||
hasContent: !!positionTemplate?.content,
|
||
hasOriginal: !!positionTemplate?.content?.original,
|
||
hasModified: !!positionTemplate?.content?.modified
|
||
});
|
||
|
||
setResumeInfoData(resumeData);
|
||
setCurrentResumeId(item.id); // 记录当前简历ID
|
||
setResumeInfoModalShow(true);
|
||
} else {
|
||
toast.error('加载简历数据失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('获取简历数据失败:', error);
|
||
toast.error('加载简历数据失败');
|
||
}
|
||
};;;
|
||
|
||
return (
|
||
<>
|
||
<Modal visible={visible} onClose={handleCloseModal}>
|
||
<div className="job-info-modal-content">
|
||
{resumeModalShow ? (
|
||
<>
|
||
|
||
{
|
||
<InfiniteScroll
|
||
loadMore={queryResumeList}
|
||
hasMore={listHasMore}
|
||
empty={resumeList.length === 0}
|
||
className={`${
|
||
resumeList.length
|
||
? "job-info-modal-user-resumes-list"
|
||
: "empty-data-wrapper"
|
||
}`}
|
||
>
|
||
{resumeList.map((item) => (
|
||
<li
|
||
key={item.id}
|
||
className="list-item"
|
||
onClick={(e) => userResumesBtnClick(e, item)}
|
||
>
|
||
<div className="list-item-info">
|
||
<img src={FILEICON} className="file-icon" />
|
||
<div className="file-info">
|
||
<p className="file-info-targetPosition">
|
||
{item.title}
|
||
</p>
|
||
<div className="version-selector">
|
||
<Select
|
||
placeholder="选择版本"
|
||
value={selectedVersions[item.id] || "2"}
|
||
style={{ width: 120, fontSize: '12px' }}
|
||
onChange={(value) => {
|
||
setSelectedVersions(prev => ({
|
||
...prev,
|
||
[item.id]: value
|
||
}));
|
||
}}
|
||
onClick={(e) => e.stopPropagation()}
|
||
>
|
||
<Select.Option value="1">原始版</Select.Option>
|
||
<Select.Option value="2">个人修改版</Select.Option>
|
||
</Select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div
|
||
className="info-btn"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
userResumesClick(item);
|
||
}}
|
||
>
|
||
投递
|
||
</div>
|
||
</li>
|
||
))}
|
||
</InfiniteScroll>
|
||
}
|
||
</>
|
||
) : (
|
||
<>
|
||
<div className="job-info-modal-content-position-info">
|
||
<span className="job-info-modal-content-position-info-position">
|
||
{data?.position}
|
||
</span>
|
||
{/* 岗位相关标签 */}
|
||
{(data?.jobCategoryTag || data?.jobCategory) && (
|
||
<span
|
||
className="job-category-tag"
|
||
data-category={data?.jobCategoryTag || data?.jobCategory}
|
||
>
|
||
{data?.jobCategoryTag || data?.jobCategory}
|
||
</span>
|
||
)}
|
||
|
||
{/* 岗位剩余量 - 仅未投递岗位显示 */}
|
||
{!data?.isDelivered && data?.remainingPositions && (
|
||
<span className="job-remaining-positions">
|
||
<i className="warning-icon">!</i>
|
||
岗位招聘数量仅剩{data?.remainingPositions}名
|
||
</span>
|
||
)}
|
||
|
||
<span className="job-info-modal-content-position-info-salary">
|
||
{data?.salary}
|
||
</span>
|
||
</div>
|
||
{data?.tags?.length > 0 && (
|
||
<ul className="job-info-modal-info-tags">
|
||
{data?.tags?.map((tag, index) => (
|
||
<li key={index} className="job-info-modal-info-tag">
|
||
{tag}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
)}
|
||
{data?.details?.description && (
|
||
<div className="job-info-modal-content-position-info-description">
|
||
<p className="description-title">
|
||
<img className="title-icon" src="https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/teach_sys_icon/recuW0XRVB1bpV.png" alt="" />
|
||
岗位描述
|
||
</p>
|
||
<div className="description-content">
|
||
{data?.details?.description.split(/\d+\.\s*/).filter(item => item.trim()).map((item, index) => (
|
||
<div key={index} className="description-item">
|
||
<span className="description-number">{index + 1}.</span>
|
||
<span className="description-text">{item.trim()}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
{(data?.details?.requirements?.length > 0 || data?.details?.requirementsText) && (
|
||
<div className="job-info-modal-content-position-info-requirements">
|
||
<p className="requirements-title">
|
||
<img className="title-icon" src="https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/teach_sys_icon/recuW0XRVB1bpV.png" alt="" />
|
||
岗位要求
|
||
</p>
|
||
<div className="requirements-content">
|
||
{data?.details?.requirements ? (
|
||
data?.details?.requirements?.map((item, index) => (
|
||
<div key={index} className="requirements-item">
|
||
<span className="requirement-number">{index + 1}.</span>
|
||
<span className="requirement-text">{item}</span>
|
||
</div>
|
||
))
|
||
) : (
|
||
data?.details?.requirementsText?.split(/\d+\.\s*/).filter(item => item.trim()).map((item, index) => (
|
||
<div key={index} className="requirements-item">
|
||
<span className="requirement-number">{index + 1}.</span>
|
||
<span className="requirement-text">{item.trim()}</span>
|
||
</div>
|
||
))
|
||
)}
|
||
</div>
|
||
</div>
|
||
)}
|
||
{data?.details?.companyInfo && (
|
||
<div className="job-info-modal-content-position-info-companyInfo">
|
||
<p className="companyInfo-title">
|
||
<img className="title-icon" src="https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/teach_sys_icon/recuW0XRVB1bpV.png" alt="" />
|
||
公司介绍
|
||
</p>
|
||
<div className="companyInfo-content">
|
||
{data?.details?.companyInfo.split('\n').map((paragraph, index) => (
|
||
<p key={index} className="company-paragraph">
|
||
{paragraph}
|
||
</p>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
{!hideDeliverButton && (
|
||
<div
|
||
className="job-info-modal-btn"
|
||
onClick={handleClickDeliverBtn}
|
||
>
|
||
<i />
|
||
<span>立即投递</span>
|
||
</div>
|
||
)}
|
||
</>
|
||
)}
|
||
</div>
|
||
</Modal>
|
||
<ResumeInfoModal
|
||
visible={resumeInfoModalShow}
|
||
data={resumeInfoData}
|
||
initialVersion={selectedVersions[currentResumeId] || "2"}
|
||
onClose={() => {
|
||
setResumeInfoModalShow(false);
|
||
setResumeInfoData(null);
|
||
setCurrentResumeId(null);
|
||
}}
|
||
/>
|
||
<PermissionModal
|
||
visible={permissionModalVisible}
|
||
onClose={() => setPermissionModalVisible(false)}
|
||
/>
|
||
</>
|
||
);
|
||
};
|