diff --git a/src/api/trainingTask.js b/src/api/trainingTask.js index 73f2d86..e99eda6 100644 --- a/src/api/trainingTask.js +++ b/src/api/trainingTask.js @@ -4,6 +4,11 @@ import request from "@/utils/request"; // 仅合并进行中的请求:教师保存后下一次读取仍会获得最新配置,不引入陈旧缓存。 const pendingTaskRequests = new Map(); +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", @@ -17,14 +22,21 @@ export function getTrainingTaskByKey(taskKey) { 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), - () => pendingTaskRequests.delete(normalizedTaskKey) + () => { + pendingTaskRequests.delete(normalizedTaskKey); + notifyStudentTaskConfigLoading(normalizedTaskKey, false); + }, + () => { + pendingTaskRequests.delete(normalizedTaskKey); + notifyStudentTaskConfigLoading(normalizedTaskKey, false); + } ); return requestPromise; } diff --git a/src/layout/components/AppMain.vue b/src/layout/components/AppMain.vue index e16f200..626ffe9 100644 --- a/src/layout/components/AppMain.vue +++ b/src/layout/components/AppMain.vue @@ -11,10 +11,19 @@
演示模式:{{ demoClassName }}
- + - + +
+
+ 正在加载当前实训配置 + + + + +
+
@@ -33,6 +42,8 @@ const tagsViewStore = useTagsViewStore(); const route = useRoute(); const router = useRouter(); const role = ref(JSON.parse(getUserInfo()).roleId); +const studentTaskLoading = ref(false); +const currentStudentTaskKey = computed(() => Number(role.value) === 4 ? String(route.meta?.pageKey || "") : ""); const isDemo = computed(() => isStudentDemo()); const demoClassName = computed(() => getStudentDemoSession()?.userInfo?.className || "教学班"); function exitDemo() { @@ -48,6 +59,16 @@ const mainClass = computed(() => { if (Number(role.value) === 3) return "teacher-main"; return "app-main2"; }); +function handleStudentTaskConfigLoading(event) { + const detail = event?.detail || {}; + if (!currentStudentTaskKey.value || detail.taskKey !== currentStudentTaskKey.value) return; + studentTaskLoading.value = Boolean(detail.loading); +} +watch(currentStudentTaskKey, (taskKey) => { + studentTaskLoading.value = Boolean(taskKey); +}, { immediate: true }); +onMounted(() => window.addEventListener("student-task-config-loading", handleStudentTaskConfigLoading)); +onBeforeUnmount(() => window.removeEventListener("student-task-config-loading", handleStudentTaskConfigLoading)); const module = ["市场需求挖掘", "产品规划", "产品投放测试", "供应渠道管理", "产品评估与考核"]; // 全局监听路由进入和离开 onBeforeRouteUpdate((to, from) => { @@ -169,6 +190,7 @@ router.beforeEach((to, from, next) => { background-size: 100% 100%; } .student-demo-banner{position:sticky;top:0;z-index:30;display:flex;justify-content:space-between;padding:8px 18px;color:#fff;background:#b45309}.student-demo-banner button{border:0;border-radius:4px;padding:3px 10px;cursor:pointer} +.student-task-loading{position:fixed;inset:50px 0 0;z-index:90;display:grid;place-items:start center;padding-top:96px;background:linear-gradient(135deg,rgba(2,15,26,.985),rgba(4,31,47,.985));}.student-task-loading__panel{display:grid;gap:18px;width:min(820px,calc(100vw - 72px));padding:32px;border:1px solid rgba(66,201,250,.34);border-radius:18px;background:rgba(4,27,42,.8);box-shadow:0 22px 52px rgba(0,0,0,.32)}.student-task-loading__label{color:#bdefff;font-weight:700;letter-spacing:.04em}.student-task-loading__line{display:block;height:18px;border-radius:99px;background:linear-gradient(90deg,rgba(26,107,143,.32),rgba(88,208,255,.58),rgba(26,107,143,.32));background-size:200% 100%;animation:student-task-loading-shimmer 1.2s linear infinite}.student-task-loading__line--title{width:42%;height:30px}.student-task-loading__line--short{width:68%}@keyframes student-task-loading-shimmer{to{background-position:-200% 0}} .app-main2 { min-height: calc(100vh - 50px); width: 100%;