完整的教务系统前端项目 - 包含所有修复和9月份数据
This commit is contained in:
222
src/pages/ResumeInterviewPage/index.jsx
Normal file
222
src/pages/ResumeInterviewPage/index.jsx
Normal file
@@ -0,0 +1,222 @@
|
||||
import { useRef, useState, useEffect } from "react";
|
||||
import { Spin, Empty } from "@arco-design/web-react";
|
||||
import toast from "@/components/Toast";
|
||||
import InterviewQuestionsModal from "./components/InterviewQuestionsModal";
|
||||
import ResumeInfoModal from "@/pages/CompanyJobsPage/components/ResumeInfoModal";
|
||||
import { getPageData } from "@/services/resumeInterview";
|
||||
|
||||
import "./index.css";
|
||||
|
||||
const ResumeInterviewPage = () => {
|
||||
const [activeIndustry, setActiveIndustry] = useState("frontend");
|
||||
const [interviewModalVisible, setInterviewModalVisible] = useState(false);
|
||||
const [resumeModalVisible, setResumeModalVisible] = useState(false);
|
||||
const [interviewModalData, setInterviewModalData] = useState(undefined);
|
||||
const [resumeModalData, setResumeModalData] = useState(undefined);
|
||||
const [pageData, setPageData] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const sectionsRef = useRef({});
|
||||
|
||||
// 导航到指定行业段落
|
||||
const handleNavClick = (industryId) => {
|
||||
setActiveIndustry(industryId);
|
||||
sectionsRef.current[industryId]?.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "start",
|
||||
});
|
||||
};
|
||||
|
||||
// 面试题点击处理
|
||||
const handleQuestionClick = (item) => {
|
||||
if (item) {
|
||||
setInterviewModalVisible(true);
|
||||
setInterviewModalData(item);
|
||||
} else {
|
||||
toast.error("加载数据失败");
|
||||
}
|
||||
};
|
||||
|
||||
// 职位点击处理
|
||||
const handlePositionClick = (position, industry) => {
|
||||
// Find resume templates for this industry
|
||||
const templates = pageData.resumeTemplates[industry.name] || [];
|
||||
// 首先根据岗位名称精确匹配
|
||||
const selectedTemplate =
|
||||
templates.find((t) => t.position === position.title) ||
|
||||
templates.find((t) => t.level === position.level) ||
|
||||
templates[0];
|
||||
|
||||
setResumeModalData({
|
||||
selectedTemplate,
|
||||
studentResume: pageData.myResume,
|
||||
});
|
||||
setResumeModalVisible(true);
|
||||
};
|
||||
|
||||
const handleCloseInterviewModal = () => {
|
||||
setInterviewModalVisible(false);
|
||||
setInterviewModalData(undefined);
|
||||
};
|
||||
|
||||
const handleCloseResumeModal = () => {
|
||||
setResumeModalVisible(false);
|
||||
setResumeModalData(undefined);
|
||||
};
|
||||
|
||||
const filterPositions = (positions) => {
|
||||
return positions.filter((position) => position.title?.toLowerCase());
|
||||
};
|
||||
|
||||
// 获取页面数据
|
||||
useEffect(() => {
|
||||
const fetchPageData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await getPageData();
|
||||
if (response.success) {
|
||||
console.log('页面数据加载成功:', response.data);
|
||||
setPageData(response.data);
|
||||
// 设置默认选中第一个行业
|
||||
if (response.data.industries && response.data.industries.length > 0) {
|
||||
setActiveIndustry(response.data.industries[0].id);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch page data:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchPageData();
|
||||
}, []);
|
||||
|
||||
// 监听滚动位置更新导航状态
|
||||
useEffect(() => {
|
||||
if (!pageData?.industries) return;
|
||||
|
||||
const handleScroll = () => {
|
||||
const scrollPosition = window.scrollY + 200;
|
||||
|
||||
pageData.industries.forEach((industry) => {
|
||||
const section = sectionsRef.current[industry.id];
|
||||
if (section) {
|
||||
const sectionTop = section.offsetTop;
|
||||
const sectionBottom = sectionTop + section.offsetHeight;
|
||||
|
||||
if (scrollPosition >= sectionTop && scrollPosition < sectionBottom) {
|
||||
setActiveIndustry(industry.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
return () => window.removeEventListener("scroll", handleScroll);
|
||||
}, [pageData?.industries]);
|
||||
|
||||
// 添加鼠标滚轮横向滚动功能
|
||||
useEffect(() => {
|
||||
const navigation = document.querySelector('.resume-interview-navigation');
|
||||
if (!navigation) return;
|
||||
|
||||
const handleWheel = (e) => {
|
||||
const tabs = navigation.querySelector('.navigation-tabs');
|
||||
if (!tabs) return;
|
||||
|
||||
// 检查是否在导航栏区域
|
||||
if (e.currentTarget === navigation || navigation.contains(e.target)) {
|
||||
if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
|
||||
e.preventDefault();
|
||||
tabs.scrollLeft += e.deltaY * 0.5; // 减慢滚动速度使其更平滑
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
navigation.addEventListener('wheel', handleWheel, { passive: false });
|
||||
return () => navigation.removeEventListener('wheel', handleWheel);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="resume-interview-page">
|
||||
{loading ? (
|
||||
<Spin size={80} className="resume-interview-spin" />
|
||||
) : pageData ? (
|
||||
<>
|
||||
<ul className="resume-interview-navigation">
|
||||
<div className="navigation-tabs">
|
||||
{pageData.industries.map((industry) => (
|
||||
<li
|
||||
key={industry.id}
|
||||
className={`resume-interview-navigation-item ${
|
||||
activeIndustry === industry.id ? "active" : ""
|
||||
}`}
|
||||
onClick={() => handleNavClick(industry.id)}
|
||||
>
|
||||
{industry.name}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
</ul>
|
||||
<ul className="resume-interview-content-wrapper">
|
||||
{pageData.industries.map((item) => (
|
||||
<li
|
||||
className="resume-interview-content-item-wrapper"
|
||||
key={item.id}
|
||||
ref={(el) => (sectionsRef.current[item.id] = el)}
|
||||
>
|
||||
<p className="item-title">{item.name}</p>
|
||||
<p className="item-subtitle">简历与面试题</p>
|
||||
<div className="item-content-wrapper">
|
||||
<ul className="jobs-list">
|
||||
{filterPositions(item.positions).map((position) => (
|
||||
<li
|
||||
className="job-item job-item-change"
|
||||
key={position.id}
|
||||
onClick={() => handlePositionClick(position, item)}
|
||||
>
|
||||
<span>{position.level}</span>
|
||||
<div className="job-name">
|
||||
<p>{position.title}</p>
|
||||
<span>详情 ></span>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<ul className="resumes-list">
|
||||
{item.questions.map((question) => (
|
||||
<li
|
||||
key={question.id}
|
||||
className="resume-item"
|
||||
onClick={() =>
|
||||
handleQuestionClick({ ...item, questions: question.subQuestions || [question] })
|
||||
}
|
||||
>
|
||||
<p>{question.question}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
) : (
|
||||
<Empty description="暂无数据" className="empty-data" />
|
||||
)}
|
||||
|
||||
<InterviewQuestionsModal
|
||||
visible={interviewModalVisible}
|
||||
onClose={handleCloseInterviewModal}
|
||||
data={interviewModalData}
|
||||
/>
|
||||
<ResumeInfoModal
|
||||
visible={resumeModalVisible}
|
||||
onClose={handleCloseResumeModal}
|
||||
data={resumeModalData}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResumeInterviewPage;
|
||||
Reference in New Issue
Block a user