2025-09-03 13:26:13 +08:00
|
|
|
import { useState, useCallback, useEffect } from "react";
|
|
|
|
|
import { useSelector } from "react-redux";
|
|
|
|
|
import { Input } 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";
|
2025-09-08 06:13:48 +08:00
|
|
|
import PermissionModal from "../PermissionModal";
|
2025-09-03 13:26:13 +08:00
|
|
|
import { getResumesList, submitResume, getPageData } from "@/services";
|
|
|
|
|
import "./index.css";
|
|
|
|
|
|
|
|
|
|
const InputSearch = Input.Search;
|
|
|
|
|
const PAGE_SIZE = 10;
|
|
|
|
|
|
2025-09-08 11:00:54 +08:00
|
|
|
export default ({ visible, onClose, data, directToResume = false, hideDeliverButton = false }) => {
|
2025-09-03 13:26:13 +08:00
|
|
|
const studentInfo = useSelector((state) => state.student.studentInfo);
|
|
|
|
|
const [resumeModalShow, setResumeModalShow] = useState(directToResume);
|
|
|
|
|
const [resumeInfoModalShow, setResumeInfoModalShow] = useState(false);
|
|
|
|
|
const [resumeInfoData, setResumeInfoData] = useState(null);
|
|
|
|
|
const [resumeList, setResumeList] = useState([]); // 简历列表
|
|
|
|
|
const [listPage, setListPage] = useState(1);
|
|
|
|
|
const [listHasMore, setListHasMore] = useState(true);
|
2025-09-08 06:13:48 +08:00
|
|
|
const [permissionModalVisible, setPermissionModalVisible] = useState(false);
|
2025-09-03 13:26:13 +08:00
|
|
|
|
|
|
|
|
// 处理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);
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-05 20:46:03 +08:00
|
|
|
|
2025-09-03 13:26:13 +08:00
|
|
|
|
|
|
|
|
// 选择简历投递
|
|
|
|
|
const userResumesClick = async (item) => {
|
2025-09-08 06:13:48 +08:00
|
|
|
// 显示权限提示弹窗
|
|
|
|
|
setPermissionModalVisible(true);
|
|
|
|
|
|
|
|
|
|
// 原投递逻辑暂时注释,实际使用时可根据用户权限判断
|
|
|
|
|
/*
|
2025-09-03 13:26:13 +08:00
|
|
|
try {
|
|
|
|
|
// 调用投递服务
|
|
|
|
|
const result = await submitResume({
|
|
|
|
|
resumeId: item.id,
|
|
|
|
|
jobId: data?.id,
|
|
|
|
|
studentId: studentInfo?.id,
|
|
|
|
|
resumeTitle: item.title,
|
|
|
|
|
jobPosition: data?.position,
|
|
|
|
|
company: data?.company
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (result.success) {
|
|
|
|
|
// 投递成功,显示成功提示
|
|
|
|
|
toast.success(`简历"${item.title}"投递成功!`);
|
|
|
|
|
|
|
|
|
|
// 关闭模态框
|
|
|
|
|
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);
|
|
|
|
|
}
|
2025-09-08 06:13:48 +08:00
|
|
|
*/
|
2025-09-03 13:26:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 点击简历详情
|
|
|
|
|
const userResumesBtnClick = async (e, item) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 获取岗位与面试题页面的数据
|
|
|
|
|
const pageDataResponse = await getPageData();
|
|
|
|
|
|
|
|
|
|
if (pageDataResponse.success) {
|
|
|
|
|
const pageData = pageDataResponse.data;
|
|
|
|
|
|
|
|
|
|
// 直接使用简历列表中的模板数据
|
|
|
|
|
const selectedTemplate = item.template;
|
|
|
|
|
|
|
|
|
|
// 找到对应的行业信息
|
|
|
|
|
const matchedIndustry = pageData.industries?.find(industry =>
|
|
|
|
|
industry.name === item.industry
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// 传递数据给 ResumeInfoModal
|
|
|
|
|
const resumeData = {
|
|
|
|
|
selectedTemplate,
|
|
|
|
|
studentResume: pageData.myResume,
|
|
|
|
|
industry: matchedIndustry,
|
|
|
|
|
jobPosition: item.position
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
console.log('加载简历数据:', {
|
|
|
|
|
resumeTitle: item.title,
|
|
|
|
|
position: item.position,
|
|
|
|
|
industry: item.industry
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setResumeInfoData(resumeData);
|
|
|
|
|
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 ? (
|
|
|
|
|
<>
|
2025-09-05 20:46:03 +08:00
|
|
|
|
2025-09-03 13:26:13 +08:00
|
|
|
{
|
|
|
|
|
<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"
|
2025-09-05 20:46:03 +08:00
|
|
|
onClick={(e) => userResumesBtnClick(e, item)}
|
2025-09-03 13:26:13 +08:00
|
|
|
>
|
|
|
|
|
<div className="list-item-info">
|
|
|
|
|
<img src={FILEICON} className="file-icon" />
|
|
|
|
|
<div className="file-info">
|
|
|
|
|
<p className="file-info-targetPosition">
|
|
|
|
|
{item.title}
|
|
|
|
|
</p>
|
|
|
|
|
{item?.skills?.length > 0 && (
|
|
|
|
|
<p className="file-info-skills">
|
|
|
|
|
{item?.skills?.join("/")}
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
className="info-btn"
|
2025-09-05 20:46:03 +08:00
|
|
|
onClick={(e) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
userResumesClick(item);
|
|
|
|
|
}}
|
2025-09-03 13:26:13 +08:00
|
|
|
>
|
2025-09-05 20:46:03 +08:00
|
|
|
投递
|
2025-09-03 13:26:13 +08:00
|
|
|
</div>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</InfiniteScroll>
|
|
|
|
|
}
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<div className="job-info-modal-content-position-info">
|
|
|
|
|
<span className="job-info-modal-content-position-info-position">
|
|
|
|
|
{data?.position}
|
|
|
|
|
</span>
|
2025-09-08 06:13:48 +08:00
|
|
|
{/* 岗位相关标签 */}
|
|
|
|
|
{(data?.jobCategoryTag || data?.jobCategory) && (
|
|
|
|
|
<span className="job-category-tag">
|
|
|
|
|
{data?.jobCategoryTag || data?.jobCategory}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
2025-09-03 13:26:13 +08:00
|
|
|
<span className="job-info-modal-content-position-info-num">
|
|
|
|
|
该岗位仅剩{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">岗位描述</p>
|
2025-09-08 06:13:48 +08:00
|
|
|
<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>
|
2025-09-03 13:26:13 +08:00
|
|
|
))}
|
2025-09-08 06:13:48 +08:00
|
|
|
</div>
|
2025-09-03 13:26:13 +08:00
|
|
|
</div>
|
|
|
|
|
)}
|
2025-09-08 06:13:48 +08:00
|
|
|
{(data?.details?.requirements?.length > 0 || data?.details?.requirementsText) && (
|
2025-09-03 13:26:13 +08:00
|
|
|
<div className="job-info-modal-content-position-info-requirements">
|
|
|
|
|
<p className="requirements-title">岗位要求</p>
|
2025-09-08 06:13:48 +08:00
|
|
|
<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>
|
|
|
|
|
))
|
|
|
|
|
) : (
|
2025-09-08 11:00:54 +08:00
|
|
|
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>
|
2025-09-08 06:13:48 +08:00
|
|
|
))
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2025-09-03 13:26:13 +08:00
|
|
|
</div>
|
2025-09-08 06:13:48 +08:00
|
|
|
)}
|
2025-09-03 13:26:13 +08:00
|
|
|
{data?.details?.companyInfo && (
|
|
|
|
|
<div className="job-info-modal-content-position-info-companyInfo">
|
|
|
|
|
<p className="companyInfo-title">公司介绍</p>
|
2025-09-08 06:13:48 +08:00
|
|
|
<div className="companyInfo-content">
|
|
|
|
|
{data?.details?.companyInfo.split('\n').map((paragraph, index) => (
|
|
|
|
|
<p key={index} className="company-paragraph">
|
|
|
|
|
{paragraph}
|
|
|
|
|
</p>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
2025-09-03 13:26:13 +08:00
|
|
|
</div>
|
|
|
|
|
)}
|
2025-09-08 11:00:54 +08:00
|
|
|
{!hideDeliverButton && (
|
|
|
|
|
<div
|
|
|
|
|
className="job-info-modal-btn"
|
|
|
|
|
onClick={handleClickDeliverBtn}
|
|
|
|
|
>
|
|
|
|
|
<i />
|
|
|
|
|
<span>立即投递</span>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2025-09-03 13:26:13 +08:00
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</Modal>
|
|
|
|
|
<ResumeInfoModal
|
|
|
|
|
visible={resumeInfoModalShow}
|
|
|
|
|
data={resumeInfoData}
|
|
|
|
|
onClose={() => {
|
|
|
|
|
setResumeInfoModalShow(false);
|
|
|
|
|
setResumeInfoData(null);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
2025-09-08 06:13:48 +08:00
|
|
|
<PermissionModal
|
|
|
|
|
visible={permissionModalVisible}
|
|
|
|
|
onClose={() => setPermissionModalVisible(false)}
|
|
|
|
|
/>
|
2025-09-03 13:26:13 +08:00
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
};
|