From a493f2773c47e6e5c6f8f60048d49aad4ac780e6 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 23:56:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E4=BA=86redux=E7=94=A8=E4=BA=8E=E5=85=A8=E5=B1=80=E8=87=AA?= =?UTF-8?q?=E5=8A=A8loading?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Layout/index.jsx | 6 +- src/pages/CompanyJobsPage/index.jsx | 3 +- src/services/api.js | 485 +++++++++++++++++++++------- src/services/companyJobs.js | 12 +- src/services/dashboard.js | 15 +- src/services/global.js | 6 +- src/services/index.js | 1 + src/services/personalProfile.js | 5 +- src/services/projectLibrary.js | 6 +- src/store/slices/loadingSlice.js | 34 +- src/utils/request.js | 54 +++- 11 files changed, 477 insertions(+), 150 deletions(-) diff --git a/src/components/Layout/index.jsx b/src/components/Layout/index.jsx index 5f87092..996f98e 100644 --- a/src/components/Layout/index.jsx +++ b/src/components/Layout/index.jsx @@ -9,7 +9,9 @@ import "./index.css"; const Layout = ({ children }) => { const dispatch = useDispatch(); const [isCollapsed, setIsCollapsed] = useState(true); - const loading = useSelector((state) => state.loading.value); + const globalLoading = useSelector( + (state) => state?.loading?.effect?.globalLoading + ); const studentInfo = useSelector((state) => state.student.studentInfo); const queryLoginStudentInfo = async () => { @@ -27,7 +29,7 @@ const Layout = ({ children }) => { return (
- +
{children}
diff --git a/src/pages/CompanyJobsPage/index.jsx b/src/pages/CompanyJobsPage/index.jsx index c4ff752..f1f93aa 100644 --- a/src/pages/CompanyJobsPage/index.jsx +++ b/src/pages/CompanyJobsPage/index.jsx @@ -57,7 +57,8 @@ const CompanyJobsPage = () => { pageSize: PAGE_SIZE, isActive: true, }); - if (res.success) { + + if (res?.success) { const mappedJobs = mapJobList(res.data); setJobs((prevList) => { const newList = [...prevList, ...mappedJobs]; diff --git a/src/services/api.js b/src/services/api.js index 35c94da..b248fd1 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -1,211 +1,464 @@ -import request from '@/utils/request'; +import request from "@/utils/request"; // Student API export const studentAPI = { // Get current logged-in student - getCurrentStudent: () => request.get('/api/students/me'), - + getCurrentStudent: async () => + request({ + url: "/api/students/me", + method: "GET", + }), + // Get student list - getList: (params) => request.get('/api/students', { params }), - + getList: async (params) => + request({ + url: "/api/students", + method: "GET", + params, + }), + // Get student detail - getDetail: (id) => request.get(`/api/students/${id}`), - + getDetail: async (id) => + request({ + url: `/api/students/${id}`, + method: "GET", + }), + // Create student - create: (data) => request.post('/api/students', data), - + create: async (data) => + request({ + url: "/api/students", + method: "POST", + data, + }), + // Update student - update: (id, data) => request.put(`/api/students/${id}`, data), - + update: async (id, data) => + request({ + url: `/api/students/${id}`, + method: "PUT", + data, + }), + // Get student progress - getProgress: (id) => request.get(`/api/students/${id}/progress`), + getProgress: async (id) => + request({ + url: `/api/students/${id}/progress`, + method: "GET", + }), }; // Course API export const courseAPI = { // Get course list - getList: (params) => request.get('/api/courses', { params }), - + getList: async (params) => + request({ + url: "/api/courses", + method: "GET", + params, + }), + // Get course detail - getDetail: (id) => request.get(`/api/courses/${id}`), - + getDetail: async (id) => + request({ + url: `/api/courses/${id}`, + method: "GET", + }), + // Create course - create: (data) => request.post('/api/courses', data), - + create: async (data) => + request({ + url: "/api/courses", + method: "POST", + data, + }), + // Update course - update: (id, data) => request.put(`/api/courses/${id}`, data), - + update: async (id, data) => + request({ + url: `/api/courses/${id}`, + method: "PUT", + data, + }), + // Enroll student in course - enroll: (courseId, studentId) => - request.post(`/api/courses/${courseId}/enroll`, { studentId }), - + enroll: async (courseId, studentId) => + request({ + url: `/api/courses/${courseId}/enroll`, + method: "POST", + data: { studentId }, + }), + // Update enrollment progress - updateEnrollment: (courseId, enrollmentId, data) => - request.put(`/api/courses/${courseId}/enrollment/${enrollmentId}`, data), - + updateEnrollment: async (courseId, enrollmentId, data) => + request({ + url: `/api/courses/${courseId}/enrollment/${enrollmentId}`, + method: "PUT", + data, + }), + // Get course students - getStudents: (id) => request.get(`/api/courses/${id}/students`), + getStudents: async (id) => + request({ + url: `/api/courses/${id}/students`, + method: "GET", + }), }; // Job API export const jobAPI = { // Get job list - getList: (params) => request.get('/api/jobs', { params }), - + getList: async (params) => + request({ + url: "/api/jobs", + method: "GET", + params, + }), + // Get job detail - getDetail: (id) => request.get(`/api/jobs/${id}`), - + getDetail: async (id) => + request({ + url: `/api/jobs/${id}`, + method: "GET", + }), + // Create job - create: (data) => request.post('/api/jobs', data), - + create: async (data) => + request({ + url: "/api/jobs", + method: "POST", + data, + }), + // Update job - update: (id, data) => request.put(`/api/jobs/${id}`, data), - + update: async (id, data) => + request({ + url: `/api/jobs/${id}`, + method: "PUT", + data, + }), + // Get recommended jobs for student - getRecommended: (studentId) => request.get(`/api/jobs/recommend/${studentId}`), + getRecommended: async (studentId) => + request({ + url: `/api/jobs/recommend/${studentId}`, + method: "GET", + }), }; // Company API export const companyAPI = { // Get company list - getList: (params) => request.get('/api/companies', { params }), - + getList: async (params) => + request({ + url: "/api/companies", + method: "GET", + params, + }), + // Get company detail - getDetail: (id) => request.get(`/api/companies/${id}`), - + getDetail: async (id) => + request({ + url: `/api/companies/${id}`, + method: "GET", + }), + // Create company - create: (data) => request.post('/api/companies', data), - + create: async (data) => + request({ + url: "/api/companies", + method: "POST", + data, + }), + // Update company - update: (id, data) => request.put(`/api/companies/${id}`, data), - + update: async (id, data) => + request({ + url: `/api/companies/${id}`, + method: "PUT", + data, + }), + // Get company jobs - getJobs: (id) => request.get(`/api/companies/${id}/jobs`), + getJobs: async (id) => + request({ + url: `/api/companies/${id}/jobs`, + method: "GET", + }), }; // Resume API export const resumeAPI = { // Get resume list - getList: (params) => request.get('/api/resumes', { params }), - + getList: async (params) => + request({ + url: "/api/resumes", + method: "GET", + params, + }), + // Get resume detail - getDetail: (id) => request.get(`/api/resumes/${id}`), - + getDetail: async (id) => + request({ + url: `/api/resumes/${id}`, + method: "GET", + }), + // Create resume - create: (data) => request.post('/api/resumes', data), - + create: async (data) => + request({ + url: "/api/resumes", + method: "POST", + data, + }), + // Update resume - update: (id, data) => request.put(`/api/resumes/${id}`, data), - + update: async (id, data) => + request({ + url: `/api/resumes/${id}`, + method: "PUT", + data, + }), + // Delete resume - delete: (id) => request.delete(`/api/resumes/${id}`), - + delete: async (id) => + request({ + url: `/api/resumes/${id}`, + method: "DELETE", + }), + // Get student's active resume - getStudentActive: (studentId) => - request.get(`/api/resumes/student/${studentId}/active`), + getStudentActive: async (studentId) => + request({ + url: `/api/resumes/student/${studentId}/active`, + method: "GET", + }), }; // Interview API export const interviewAPI = { // Get interview list - getList: (params) => request.get('/api/interviews', { params }), - + getList: async (params) => + request({ + url: "/api/interviews", + method: "GET", + params, + }), + // Get interview detail - getDetail: (id) => request.get(`/api/interviews/${id}`), - + getDetail: async (id) => + request({ + url: `/api/interviews/${id}`, + method: "GET", + }), + // Schedule interview - schedule: (data) => request.post('/api/interviews', data), - + schedule: async (data) => + request({ + url: "/api/interviews", + method: "POST", + data, + }), + // Update interview - update: (id, data) => request.put(`/api/interviews/${id}`, data), - + update: async (id, data) => + request({ + url: `/api/interviews/${id}`, + method: "PUT", + data, + }), + // Cancel interview - cancel: (id, reason) => - request.post(`/api/interviews/${id}/cancel`, { reason }), - + cancel: async (id, reason) => + request({ + url: `/api/interviews/${id}/cancel`, + method: "POST", + data: { reason }, + }), + // Submit feedback - submitFeedback: (id, data) => - request.post(`/api/interviews/${id}/feedback`, data), - + submitFeedback: async (id, data) => + request({ + url: `/api/interviews/${id}/feedback`, + method: "POST", + data, + }), + // Get student interview history - getStudentHistory: (studentId) => - request.get(`/api/interviews/student/${studentId}/history`), + getStudentHistory: async (studentId) => + request({ + url: `/api/interviews/student/${studentId}/history`, + method: "GET", + }), }; // Class API export const classAPI = { // Get class list - getList: (params) => request.get('/api/classes', { params }), - + getList: async (params) => + request({ + url: "/api/classes", + method: "GET", + params, + }), + // Get class detail - getDetail: (id) => request.get(`/api/classes/${id}`), - + getDetail: async (id) => + request({ + url: `/api/classes/${id}`, + method: "GET", + }), + // Create class - create: (data) => request.post('/api/classes', data), - + create: async (data) => + request({ + url: "/api/classes", + method: "POST", + data, + }), + // Update class - update: (id, data) => request.put(`/api/classes/${id}`, data), - + update: async (id, data) => + request({ + url: `/api/classes/${id}`, + method: "PUT", + data, + }), + // Get class students - getStudents: (id) => request.get(`/api/classes/${id}/students`), - + getStudents: async (id) => + request({ + url: `/api/classes/${id}/students`, + method: "GET", + }), + // Add student to class - addStudent: (classId, studentId) => - request.post(`/api/classes/${classId}/students`, { studentId }), - + addStudent: async (classId, studentId) => + request({ + url: `/api/classes/${classId}/students`, + method: "POST", + data: { studentId }, + }), + // Remove student from class - removeStudent: (classId, studentId) => - request.delete(`/api/classes/${classId}/students/${studentId}`), - + removeStudent: async (classId, studentId) => + request({ + url: `/api/classes/${classId}/students/${studentId}`, + method: "DELETE", + }), + // Get class statistics - getStats: (id) => request.get(`/api/classes/${id}/stats`), + getStats: async (id) => + request({ + url: `/api/classes/${id}/stats`, + method: "GET", + }), }; // Learning Stage API export const stageAPI = { // Get all stages - getList: () => request.get('/api/stages'), - + getList: async () => + request({ + url: "/api/stages", + method: "GET", + }), + // Get stage detail - getDetail: (id) => request.get(`/api/stages/${id}`), - + getDetail: async (id) => + request({ + url: `/api/stages/${id}`, + method: "GET", + }), + // Create stage - create: (data) => request.post('/api/stages', data), - + create: async (data) => + request({ + url: "/api/stages", + method: "POST", + data, + }), + // Update stage - update: (id, data) => request.put(`/api/stages/${id}`, data), - + update: async (id, data) => + request({ + url: `/api/stages/${id}`, + method: "PUT", + data, + }), + // Delete stage - delete: (id) => request.delete(`/api/stages/${id}`), - + delete: async (id) => + request({ + url: `/api/stages/${id}`, + method: "DELETE", + }), + // Get stage courses - getCourses: (id) => request.get(`/api/stages/${id}/courses`), - + getCourses: async (id) => + request({ + url: `/api/stages/${id}/courses`, + method: "GET", + }), + // Get stage students - getStudents: (id) => request.get(`/api/stages/${id}/students`), - + getStudents: async (id) => + request({ + url: `/api/stages/${id}/students`, + method: "GET", + }), + // Advance student to next stage - advanceStudent: (stageId, studentId) => - request.post(`/api/stages/${stageId}/advance/${studentId}`), + advanceStudent: async (stageId, studentId) => + request({ + url: `/api/stages/${stageId}/advance/${studentId}`, + method: "POST", + }), }; // Auth API export const authAPI = { // Login - login: (data) => request.post('/api/auth/login', data), - + login: async (data) => + request({ + url: "/api/auth/login", + method: "POST", + data, + }), + // Register - register: (data) => request.post('/api/auth/register', data), - + register: async (data) => + request({ + url: "/api/auth/register", + method: "POST", + data, + }), + // Logout - logout: () => request.post('/api/auth/logout'), - + logout: async () => + request({ + url: "/api/auth/logout", + method: "POST", + }), + // Get current user - getCurrentUser: () => request.get('/api/auth/me'), + getCurrentUser: async () => + request({ + url: "/api/auth/me", + method: "GET", + }), }; // Health Check export const healthAPI = { - check: () => request.get('/health'), - checkDB: () => request.get('/health/db'), -}; \ No newline at end of file + check: async () => + request({ + url: "/health", + method: "GET", + }), + checkDB: async () => + request({ + url: "/health/db", + method: "GET", + }), +}; diff --git a/src/services/companyJobs.js b/src/services/companyJobs.js index b23c6d5..d4b308a 100644 --- a/src/services/companyJobs.js +++ b/src/services/companyJobs.js @@ -2,9 +2,17 @@ import request from "@/utils/request"; // 获取企业内推岗位 export async function getJobsList(params) { - return request.get("/api/jobs", { params }); + return request({ + url: `/api/jobs`, + method: "GET", + params, + }); } // 获取企业内推岗位面试 export async function getInterviewsList(params) { - return request.get("/api/interviews", { params }); + return request({ + url: `/api/interviews`, + method: "GET", + params, + }); } diff --git a/src/services/dashboard.js b/src/services/dashboard.js index 5dc7e5f..7c705b4 100644 --- a/src/services/dashboard.js +++ b/src/services/dashboard.js @@ -1,14 +1,23 @@ import request from "@/utils/request"; // 获取主页信息 export async function getDashboardStatistics(studentId) { - return request.get(`/api/dashboard/stats/${studentId}`); + return request({ + url: `/api/dashboard/stats/${studentId}`, + method: "GET", + }); } // 获取学习进度 export async function getLearningProgressSummary(studentId) { - return request.get(`/api/dashboard/learning-summary/${studentId}`); + return request({ + url: `/api/dashboard/learning-summary/${studentId}`, + method: "GET", + }); } // 获取班级排名 export async function getClassRanking(classId) { - return request.get(`/api/rankings/class/${classId}`); + return request({ + url: `/api/rankings/class/${classId}`, + method: "GET", + }); } diff --git a/src/services/global.js b/src/services/global.js index f7e056b..c122f35 100644 --- a/src/services/global.js +++ b/src/services/global.js @@ -2,5 +2,9 @@ import request from "@/utils/request"; // 获取当前登录学生信息 export async function getLoginStudentInfo() { - return request.get("/api/students/me"); + return request({ + url: `/api/students/me`, + method: "GET", + namespace: "globalLoading", + }); } diff --git a/src/services/index.js b/src/services/index.js index d40f283..59893b4 100644 --- a/src/services/index.js +++ b/src/services/index.js @@ -1,3 +1,4 @@ +// 此处是已经调试的api import { getDashboardStatistics, getLearningProgressSummary, diff --git a/src/services/personalProfile.js b/src/services/personalProfile.js index 7fa6bff..f389ecc 100644 --- a/src/services/personalProfile.js +++ b/src/services/personalProfile.js @@ -2,5 +2,8 @@ import request from "@/utils/request"; // 获取当前登录学生学习进度 export async function getLoginStudentProgress(id) { - return request.get(`/api/students/${id}/progress`); + return request({ + url: `/api/students/${id}/progress`, + method: "GET", + }); } diff --git a/src/services/projectLibrary.js b/src/services/projectLibrary.js index f5f2c14..2f1b33f 100644 --- a/src/services/projectLibrary.js +++ b/src/services/projectLibrary.js @@ -1,5 +1,9 @@ import request from "@/utils/request"; // 获取项目列表 export async function getProjectsList(params) { - return request.get(`/api/projects`, { params }); + return request({ + url: `/api/projects`, + method: "GET", + params, + }); } diff --git a/src/store/slices/loadingSlice.js b/src/store/slices/loadingSlice.js index 0bab42c..833ef8a 100644 --- a/src/store/slices/loadingSlice.js +++ b/src/store/slices/loadingSlice.js @@ -1,25 +1,31 @@ +// 导入 Redux Toolkit 的 createSlice import { createSlice } from "@reduxjs/toolkit"; -// 创建slice +// 定义初始状态 +const initialState = { + effect: {}, // 全局加载状态对象 +}; + +// 创建 loading slice const loadingSlice = createSlice({ - name: "loading", - initialState: { - value: false, - }, + name: "loading", // slice 名称 + initialState, reducers: { - // 设置loading状态为true - setLoadingTrue: (state) => { - state.value = true; + // 显示全局加载状态 + showGlobalLoading: (state, action) => { + const { namespace } = action.payload; + state.effect[namespace] = true; }, - // 设置loading状态为false - setLoadingFalse: (state) => { - state.value = false; + // 隐藏全局加载状态 + hideGlobalLoading: (state, action) => { + const { namespace } = action.payload; + state.effect[namespace] = false; }, }, }); -// 导出actions -export const { setLoadingTrue, setLoadingFalse } = loadingSlice.actions; +// 导出 action creators +export const { showGlobalLoading, hideGlobalLoading } = loadingSlice.actions; -// 导出reducer +// 导出 reducer export default loadingSlice.reducer; diff --git a/src/utils/request.js b/src/utils/request.js index 117dd6d..d4e2ca4 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -1,9 +1,24 @@ // 引入axios import axios from "axios"; +import store from "@/store/index"; +import { + showGlobalLoading, + hideGlobalLoading, +} from "@/store/slices/loadingSlice"; +const baseURL = import.meta.env.VITE_API_BASE_URL || "http://localhost:3000"; +// 全局加载状态loading,基于redux +const handleGlobalLoading = (namespace, type) => { + if (!namespace) return; + store.dispatch( + type === "show" + ? showGlobalLoading({ namespace }) + : hideGlobalLoading({ namespace }) + ); +}; // 创建axios实例 -const service = axios.create({ - baseURL: import.meta.env.VITE_API_BASE_URL || "http://localhost:3000", // 基础URL +const axiosInstance = axios.create({ + baseURL, // 基础URL timeout: 10000, // 请求超时时间 headers: { "Content-Type": "application/json;charset=utf-8", @@ -11,12 +26,12 @@ const service = axios.create({ }); // 请求拦截器 -service.interceptors.request.use( +axiosInstance.interceptors.request.use( (config) => { // 开发阶段使用固定的 x-user-id // 这个ID对应种子数据中的开发默认用户 config.headers["x-user-id"] = "dev-user-id"; - + // 后续对接飞书后使用token // const token = localStorage.getItem("token"); // if (token) { @@ -30,11 +45,11 @@ service.interceptors.request.use( ); // 响应拦截器 -service.interceptors.response.use( +axiosInstance.interceptors.response.use( (response) => { // 处理响应数据 const res = response.data; - + // 后端统一返回格式 {success, data, message} if (res.success !== undefined) { if (res.success) { @@ -50,17 +65,38 @@ service.interceptors.response.use( return Promise.reject(new Error(res.message || "请求失败")); } } - + // 兼容直接返回数据的情况 return res; }, (error) => { // 处理响应错误 console.error("请求错误:", error); - const message = error.response?.data?.message || error.message || "网络错误"; + const message = + error.response?.data?.message || error.message || "网络错误"; return Promise.reject(new Error(message)); } ); // 导出请求方法 -export default service; +export default function request({ + url, + apiUrl, + namespace, + method = "get", + data, + params, + headers = {}, +}) { + handleGlobalLoading(namespace, "show"); + // 返回Promise对象 + return axiosInstance({ + method, + url: `${apiUrl ? apiUrl : baseURL}${url}`, + data, + params, + headers, + }).finally(() => { + handleGlobalLoading(namespace, "hide"); + }); +}