From f1a2a2493999adf6e2262e4b97ee13e6b367f742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=89=8D=E7=AB=AF=E4=BA=BA=E7=BB=9D=E4=B8=8D=E4=B8=BA?= =?UTF-8?q?=E5=A5=B4?= Date: Wed, 20 Aug 2025 18:05:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=86=85=E6=8E=A8=E5=B2=97=E4=BD=8D=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/InfiniteScroll/index.jsx | 37 ++-- src/main.jsx | 10 +- .../components/JobList/index.jsx | 2 +- src/pages/CompanyJobsPage/index.css | 2 + src/pages/CompanyJobsPage/index.jsx | 209 +++++++++--------- src/pages/ProjectLibraryPage/index.jsx | 20 +- src/services/companyJobs.js | 10 + src/services/global.js | 6 + src/services/index.js | 11 +- 9 files changed, 168 insertions(+), 139 deletions(-) create mode 100644 src/services/companyJobs.js create mode 100644 src/services/global.js diff --git a/src/components/InfiniteScroll/index.jsx b/src/components/InfiniteScroll/index.jsx index 6bd7e1b..96df6ca 100644 --- a/src/components/InfiniteScroll/index.jsx +++ b/src/components/InfiniteScroll/index.jsx @@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from "react"; import { Empty } from "@arco-design/web-react"; import { useSelector } from "react-redux"; import { useDispatch } from "react-redux"; -import { setLoadingTrue, setLoadingFalse } from "@/store/slices/loadingSlice"; +import { setLoadingFalse } from "@/store/slices/loadingSlice"; const InfiniteScroll = ({ loadMore, @@ -13,22 +13,25 @@ const InfiniteScroll = ({ }) => { const dispatch = useDispatch(); const containerRef = useRef(null); - const loading = useSelector((state) => state.loading.value); + const globalLoading = useSelector((state) => state.loading.value); + const [loading, setLoading] = useState(false); + + const handleScroll = () => { + if (loading) return; + setLoading(true); + if (!containerRef.current || globalLoading || !hasMore) return; + + const { scrollTop, scrollHeight, clientHeight } = containerRef.current; + + if (scrollTop + clientHeight >= scrollHeight - threshold) { + loadMore().finally(() => { + dispatch(setLoadingFalse()); + setLoading(false); + }); + } + }; useEffect(() => { - const handleScroll = () => { - if (!containerRef.current || loading || !hasMore) return; - - const { scrollTop, scrollHeight, clientHeight } = containerRef.current; - - if (scrollTop + clientHeight >= scrollHeight - threshold) { - dispatch(setLoadingTrue()); - loadMore().finally(() => { - dispatch(setLoadingFalse()); - }); - } - }; - const container = containerRef.current; if (container) { container.addEventListener("scroll", handleScroll); @@ -41,7 +44,7 @@ const InfiniteScroll = ({ container.removeEventListener("scroll", handleScroll); } }; - }, [loadMore, hasMore, threshold, loading]); + }, [loadMore, hasMore, threshold, globalLoading]); return (
{children} - {!hasMore && !loading && } + {!hasMore && !globalLoading && }
); }; diff --git a/src/main.jsx b/src/main.jsx index e44155d..f3341c3 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -1,13 +1,11 @@ -import { StrictMode } from "react"; +// import { StrictMode } from "react"; // 重复请求只会在 开发环境 下发生,生产环境中StrictMode不会导致重复渲染 import { createRoot } from "react-dom/client"; import { Provider } from "react-redux"; import store from "./store"; import App from "./App.jsx"; createRoot(document.getElementById("root")).render( - - - - - + + + ); diff --git a/src/pages/CompanyJobsPage/components/JobList/index.jsx b/src/pages/CompanyJobsPage/components/JobList/index.jsx index bb139c6..9871b01 100644 --- a/src/pages/CompanyJobsPage/components/JobList/index.jsx +++ b/src/pages/CompanyJobsPage/components/JobList/index.jsx @@ -40,7 +40,7 @@ export default ({ className = "", data = [], backgroundColor = "#FFFFFF" }) => { ))}

- 岗位招聘数量仅剩9名 + 岗位招聘数量仅剩{item?.remainingPositions}名

diff --git a/src/pages/CompanyJobsPage/index.css b/src/pages/CompanyJobsPage/index.css index 8ab7e55..c39d7f4 100644 --- a/src/pages/CompanyJobsPage/index.css +++ b/src/pages/CompanyJobsPage/index.css @@ -11,6 +11,7 @@ justify-content: space-between; align-items: center; position: relative; + .company-jobs-page-title { width: 100%; height: 42px; @@ -51,6 +52,7 @@ .company-jobs-page-left-list-wrapper { width: 496px; height: 760px; + overflow: auto; } } diff --git a/src/pages/CompanyJobsPage/index.jsx b/src/pages/CompanyJobsPage/index.jsx index c18c583..669c131 100644 --- a/src/pages/CompanyJobsPage/index.jsx +++ b/src/pages/CompanyJobsPage/index.jsx @@ -1,70 +1,78 @@ -import { useState, useEffect, useCallback } from "react"; +import { useState } from "react"; import { useNavigate } from "react-router-dom"; -import { jobAPI, interviewAPI, studentAPI } from "@/services/api"; import { mapJobList, mapInterviewList } from "@/utils/dataMapper"; import JobList from "./components/JobList"; -import { useDispatch } from "react-redux"; -import { setLoadingTrue, setLoadingFalse } from "@/store/slices/loadingSlice"; -// 从Redux store中获取loading状态 +import { getJobsList, getInterviewsList, getCurrentStudent } from "@/services"; +import InfiniteScroll from "@/components/InfiniteScroll"; + import "./index.css"; +const PAGE_SIZE = 10; const CompanyJobsPage = () => { - const dispatch = useDispatch(); - - const [jobs, setJobs] = useState([]); - const [interviews, setInterviews] = useState([]); const [isExpand, setIsExpand] = useState(false); // 是否展开 - + const [jobs, setJobs] = useState([]); + const [jobsListPage, setJobsListPage] = useState(1); + const [joblistHasMore, setJobsListHasMore] = useState(true); + const [interviews, setInterviews] = useState([]); + const [interviewsPage, setInterviewsPage] = useState(1); + const [interviewsHasMore, setInterviewsHasMore] = useState(true); const navigate = useNavigate(); - const fetchData = async () => { + // 获取面试信息 + const fetchInterviewsData = async () => { try { - dispatch(setLoadingTrue()); - // Get current user's student ID from API let studentId = null; - try { - const currentStudent = await studentAPI.getCurrentStudent(); - studentId = currentStudent?.id; - } catch (err) { - console.log("Could not get current student:", err); - } - - // Fetch jobs (and interviews if we have a student ID) - const jobsData = await jobAPI.getList({ - page: 1, - pageSize: 10, - isActive: true, - }); - - let interviewsData = { data: [] }; + const currentStudent = await getCurrentStudent(); + studentId = currentStudent?.id; if (studentId) { - try { - interviewsData = await interviewAPI.getList({ - studentId: studentId, - status: "SCHEDULED", + const res = await getInterviewsList({ + page: interviewsPage, + pageSize: PAGE_SIZE, + studentId: studentId, + status: "SCHEDULED", + }); + if (res.success) { + const mappedInterviews = mapInterviewList(res.data || []); + setInterviews((prevList) => { + const newList = [...prevList, ...mappedInterviews]; + if (res.total === newList?.length) { + setInterviewsHasMore(false); + } else { + setInterviewsPage((prevPage) => prevPage + 1); + } + return newList; }); - } catch (err) { - console.log("No interviews found or API error"); } } - - // Map data to frontend format - const mappedJobs = mapJobList(jobsData.data || jobsData); - const mappedInterviews = mapInterviewList( - interviewsData.data || interviewsData - ); - - setJobs(mappedJobs); - setInterviews(mappedInterviews); } catch (error) { - dispatch(setLoadingFalse()); - console.error("Failed to fetch data:", error); - // Fallback to empty data - setJobs([]); setInterviews([]); - } finally { - dispatch(setLoadingFalse()); + } + }; + + // 获取企业内推岗位 + const fetchJobsList = async () => { + try { + const res = await getJobsList({ + page: jobsListPage, + pageSize: PAGE_SIZE, + isActive: true, + }); + if (res.success) { + const mappedJobs = mapJobList(res.data); + setJobs((prevList) => { + const newList = [...prevList, ...mappedJobs]; + if (res.total === newList?.length) { + setJobsListHasMore(false); + } else { + setJobsListPage((prevPage) => prevPage + 1); + } + return newList; + }); + } + } catch (error) { + console.error("Failed to fetch data:", error); + setJobs([]); } }; @@ -72,18 +80,18 @@ const CompanyJobsPage = () => { navigate("/company-jobs-list"); }; - useEffect(() => { - fetchData(); - }, []); - return (

企业内推岗位库

-
+ -
+
{ }`} >

内推岗位面试

-
    - {interviews.length > 0 ? ( - interviews.map((item) => ( -
  • -
    -

    - {item.position} -

    - {item.job?.tags?.length > 0 ? ( -
      - {item.job.tags.map((tag) => ( -
    • - {tag} -
    • - ))} -
    - ) : null} - - {item.job?.salary || "面议"} - + + {interviews.map((item) => ( +
  • +
    +

    + {item.position} +

    + {item.job?.tags?.length > 0 ? ( +
      + {item.job.tags.map((tag) => ( +
    • + {tag} +
    • + ))} +
    + ) : null} + + {item.job?.salary || "面议"} + +
    +
    + {item.interviewTime} +
    + {item.statusText}
    -
    - {item.interviewTime} -
    - {item.statusText} -
    -
    -
  • - )) - ) : ( -
  • -

    - 暂无面试安排 -

    +
- )} - + ))} +
{ const fetchProjects = async (searchValue = "", pageNum) => { try { // 这里使用真实API替换模拟数据 - const response = await getProjectsList({ + const res = await getProjectsList({ search: searchValue, page: pageNum ?? page, pageSize: PAGE_SIZE, }); - if (response.success) { - setProjectList((prevList) => [...prevList, ...response.data]); - setHasMore(response?.data.length === PAGE_SIZE); - setPage((prevPage) => prevPage + 1); + if (res.success) { + setProjectList((prevList) => { + const newList = [...prevList, ...res.data]; + if (res.total === newList?.length) { + setHasMore(false); + } else { + setPage((prevPage) => prevPage + 1); + } + return newList; + }); } } catch (error) { console.error("Failed to fetch projects:", error); diff --git a/src/services/companyJobs.js b/src/services/companyJobs.js new file mode 100644 index 0000000..b23c6d5 --- /dev/null +++ b/src/services/companyJobs.js @@ -0,0 +1,10 @@ +import request from "@/utils/request"; + +// 获取企业内推岗位 +export async function getJobsList(params) { + return request.get("/api/jobs", { params }); +} +// 获取企业内推岗位面试 +export async function getInterviewsList(params) { + return request.get("/api/interviews", { params }); +} diff --git a/src/services/global.js b/src/services/global.js new file mode 100644 index 0000000..477a82b --- /dev/null +++ b/src/services/global.js @@ -0,0 +1,6 @@ +import request from "@/utils/request"; + +// 获取学生信息 +export async function getCurrentStudent() { + return request.get("/api/students/me"); +} diff --git a/src/services/index.js b/src/services/index.js index 7a4aadc..51cda8b 100644 --- a/src/services/index.js +++ b/src/services/index.js @@ -3,5 +3,14 @@ import { getLearningProgressSummary, } from "./dashboard"; import { getProjectsList } from "./projectLibrary"; +import { getJobsList, getInterviewsList } from "./companyJobs"; +import { getCurrentStudent } from "./global"; -export { getDashboardStatistics, getLearningProgressSummary, getProjectsList }; +export { + getDashboardStatistics, + getLearningProgressSummary, + getProjectsList, + getJobsList, + getInterviewsList, + getCurrentStudent, +};