import request from "@/utils/request"; import { getUserInfo } from "@/utils/auth"; import { getTrainingReviewPreviewContext } from "@/utils/trainingReviewPreview"; // 学生页面和全局“补充步骤”导航会在同一轮路由渲染中读取同一任务配置。 // 仅合并进行中的请求:教师保存后下一次读取仍会获得最新配置,不引入陈旧缓存。 const pendingTaskRequests = new Map(); const pendingStudentTaskListRequests = new Map(); const STUDENT_TASK_NAVIGATION_CACHE_PREFIX = "student-training-task-navigation:v1:"; function notifyStudentTaskConfigLoading(taskKey, loading) { if (typeof window === "undefined") return; window.dispatchEvent(new CustomEvent("student-task-config-loading", { detail: { taskKey, loading } })); } export function listTrainingTasks(params) { return request({ url: "/api/training-tasks", method: "get", params, }); } function getStudentTaskNavigationCacheKey() { try { const userInfo = JSON.parse(getUserInfo() || "{}"); const userId = userInfo.userId || userInfo.user_id || userInfo.username || userInfo.userName; return userId ? `${STUDENT_TASK_NAVIGATION_CACHE_PREFIX}${userId}` : ""; } catch (error) { return ""; } } export function getCachedStudentTrainingTasks() { const cacheKey = getStudentTaskNavigationCacheKey(); if (!cacheKey || typeof window === "undefined") return []; try { const cached = JSON.parse(window.sessionStorage.getItem(cacheKey) || "[]"); return Array.isArray(cached) ? cached : []; } catch (error) { return []; } } /** * The navigation and top bar both need the same enabled task list. Reuse one * in-flight request and retain the last successful response for immediate menu rendering. */ export function loadStudentTrainingTasks() { const cacheKey = getStudentTaskNavigationCacheKey() || "anonymous"; if (pendingStudentTaskListRequests.has(cacheKey)) { return pendingStudentTaskListRequests.get(cacheKey); } const requestPromise = listTrainingTasks({ enabledOnly: true }).then((res) => { const tasks = Array.isArray(res?.data) ? res.data : []; if (cacheKey !== "anonymous" && typeof window !== "undefined") { window.sessionStorage.setItem(cacheKey, JSON.stringify(tasks)); } return { ...res, data: tasks }; }); pendingStudentTaskListRequests.set(cacheKey, requestPromise); requestPromise.then( () => pendingStudentTaskListRequests.delete(cacheKey), () => pendingStudentTaskListRequests.delete(cacheKey) ); return requestPromise; } export function getTrainingTaskByKey(taskKey) { const normalizedTaskKey = String(taskKey || "").trim(); const preview = getTrainingReviewPreviewContext(); if (preview) { if (preview.taskKey !== normalizedTaskKey) { return Promise.resolve({ code: 200, data: null }); } if (!preview.taskConfig) { return Promise.reject(new Error("评阅案例配置未加载,不能展示通用案例")); } return Promise.resolve({ code: 200, data: preview.taskConfig }); } if (pendingTaskRequests.has(normalizedTaskKey)) { return pendingTaskRequests.get(normalizedTaskKey); } notifyStudentTaskConfigLoading(normalizedTaskKey, true); const requestPromise = request({ url: `/api/training-tasks/key/${normalizedTaskKey}`, method: "get", }); pendingTaskRequests.set(normalizedTaskKey, requestPromise); requestPromise.then( () => { pendingTaskRequests.delete(normalizedTaskKey); notifyStudentTaskConfigLoading(normalizedTaskKey, false); }, () => { pendingTaskRequests.delete(normalizedTaskKey); notifyStudentTaskConfigLoading(normalizedTaskKey, false); } ); return requestPromise; } export function updateTrainingTask(id, data) { return request({ url: `/api/training-tasks/${id}`, method: "put", data, }); } export function createTrainingTask(data) { return request({ url: "/api/training-tasks", method: "post", data, }); } export function importTrainingTasks(file) { const data = new FormData(); data.append("file", file); return request({ url: "/api/training-tasks/import", method: "post", data, headers: { "Content-Type": "multipart/form-data" }, }); } export function downloadTrainingTaskTemplate() { return request({ url: "/api/training-tasks/template", method: "get", responseType: "blob", }); } export function uploadTrainingTaskMaterial(data) { return request({ url: "/common/upload", method: "post", data, headers: { "Content-Type": "multipart/form-data", repeatSubmit: false, }, }); } export function listClassTrainingTasks(teachingClassId, params) { return request({ url: `/api/training-tasks/classes/${teachingClassId}`, method: "get", params, }); } export function getClassTrainingTaskByKey(teachingClassId, taskKey) { return request({ url: `/api/training-tasks/classes/${teachingClassId}/key/${taskKey}`, method: "get", }); } export function saveClassTrainingTask(teachingClassId, taskKey, data) { return request({ url: `/api/training-tasks/classes/${teachingClassId}/${taskKey}`, method: "put", data, }); } export function restoreClassTrainingTaskDefault(teachingClassId, taskKey) { return request({ url: `/api/training-tasks/classes/${teachingClassId}/${taskKey}/override`, method: "delete", }); } export function restoreClassTrainingTasksDefaults(teachingClassId) { return request({ url: `/api/training-tasks/classes/${teachingClassId}/overrides`, method: "delete", }); }