fix: render student training step names

dev-QQq
chenyuan 4 weeks ago
parent 1df7b1781a
commit 4296341202

@ -83,7 +83,7 @@ import useSettingsStore from "@/store/modules/settings";
import * as indexApi from "@/api/teacher";
import { listTrainingTasks } from "@/api/trainingTask";
import { getStudentDemoSession, isStudentDemo } from "@/utils/studentDemo";
import studentTrainingNavigation from "@/utils/studentTrainingNavigation.cjs";
import { getComprehensiveTopTask } from "@/utils/studentTrainingNavigation";
const { proxy } = getCurrentInstance();
const router = useRouter();
const appStore = useAppStore();
@ -92,7 +92,6 @@ const settingsStore = useSettingsStore();
const showModel = ref(false);
const form = ref({});
const role = computed(() => Number(userStore.userInfo.roleId));
const { getComprehensiveTopTask } = studentTrainingNavigation;
const studentTopTask = ref(null);
const mentList = ref([
{

@ -69,7 +69,7 @@ import usePermissionStore from "@/store/modules/permission";
import { constantRoutes, dynamicRoutes, teacherRoutes, platformAdminRoutes, schoolAdminRoutes } from "@/router/index.js";
import useUserStore from "@/store/modules/user";
import { listTrainingTasks } from "@/api/trainingTask";
import studentTrainingNavigation from "@/utils/studentTrainingNavigation.cjs";
import { buildStudentTaskSections } from "@/utils/studentTrainingNavigation";
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
@ -78,7 +78,6 @@ const router = useRouter();
const appStore = useAppStore();
const settingsStore = useSettingsStore();
const permissionStore = usePermissionStore();
const { buildStudentTaskSections } = studentTrainingNavigation;
const sidebarRouters = ref([...constantRoutes]);
const visibleSidebarRouters = computed(() => filterRoutesByOrganizationMode(sidebarRouters.value));
const sidebarMenuKey = computed(() => visibleSidebarRouters.value.map((route) => route.path).join("|"));

@ -1,6 +1,6 @@
const COMPREHENSIVE_TASK_KEY = "comprehensive-case-training";
const KNOWN_TASK_PATHS = Object.freeze({
const knownTaskPaths = Object.freeze({
"new-product-survey": "/foundation/new-product-survey",
"product-development-factors": "/foundation/product-development-factors",
"product-development-process": "/foundation/product-development-process",
@ -26,18 +26,17 @@ const KNOWN_TASK_PATHS = Object.freeze({
"product-diagnosis-iteration": "/assessment/diagnosis",
});
function taskSort(task) {
const sort = Number(task?.sort);
return Number.isFinite(sort) ? sort : Number.MAX_SAFE_INTEGER;
function taskPath(taskKey) {
return knownTaskPaths[taskKey] || `/training/task/${encodeURIComponent(taskKey)}`;
}
function taskPath(taskKey) {
return KNOWN_TASK_PATHS[taskKey] || `/training/task/${encodeURIComponent(taskKey)}`;
function taskSort(task) {
return Number.isFinite(Number(task?.sort)) ? Number(task.sort) : Number.MAX_SAFE_INTEGER;
}
function buildStudentTaskSections(tasks) {
export function buildStudentTaskSections(tasks = []) {
const sections = new Map();
[...(tasks || [])]
[...tasks]
.filter((task) => task?.taskKey && task.taskKey !== COMPREHENSIVE_TASK_KEY)
.sort((left, right) => taskSort(left) - taskSort(right))
.forEach((task) => {
@ -51,17 +50,9 @@ function buildStudentTaskSections(tasks) {
return [...sections.values()];
}
function getComprehensiveTopTask(tasks) {
const task = (tasks || []).find((item) => item?.taskKey === COMPREHENSIVE_TASK_KEY);
if (!task) return null;
return {
title: task.taskName || "综合实训",
path: "/comprehensive/index",
activePrefix: "/comprehensive",
};
export function getComprehensiveTopTask(tasks = []) {
const task = tasks.find((item) => item?.taskKey === COMPREHENSIVE_TASK_KEY);
return task
? { title: task.taskName || "综合实训", path: "/comprehensive/index", activePrefix: "/comprehensive" }
: null;
}
module.exports = {
buildStudentTaskSections,
getComprehensiveTopTask,
};

@ -265,6 +265,7 @@ import {
import { getTrainingTaskByKey } from "@/api/trainingTask";
import { getStudentTrainingAnswer, saveStudentTrainingAnswer } from "@/api/studentTrainingAnswer";
import useUserStore from "@/store/modules/user";
import { extractTrainingStepNames } from "@/views/training/taskKeyMap";
import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue";
import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue";
import TrainingTaskBrief from "@/views/components/TrainingTaskBrief.vue";
@ -305,7 +306,7 @@ const taskRequirement = computed(
);
const steps = computed(() => {
const configured = parseArray(taskConfig.value?.steps, defaultSteps.map((item) => item.name)).slice(0, 4);
const configured = extractTrainingStepNames(taskConfig.value?.steps, defaultSteps.map((item) => item.name)).slice(0, 4);
return defaultSteps.map((step, index) => ({
...step,
name: configured[index] || step.name,

@ -60,3 +60,7 @@ export function parseTrainingArray(value, fallback = []) {
.filter(Boolean);
return result.length ? result : fallback;
}
export function extractTrainingStepNames(value, fallback = []) {
return parseTrainingArray(value, fallback);
}

@ -0,0 +1,26 @@
import assert from "node:assert/strict";
import { buildStudentTaskSections, getComprehensiveTopTask } from "../src/utils/studentTrainingNavigation.js";
const sections = buildStudentTaskSections([
{
taskKey: "teacher-added-task",
taskName: "教师新增任务",
projectName: "市场洞察与需求分析",
sort: 1,
},
]);
assert.deepEqual(sections, [
{
title: "市场洞察与需求分析",
children: [{ title: "教师新增任务", path: "/training/task/teacher-added-task" }],
},
]);
assert.deepEqual(getComprehensiveTopTask([{ taskKey: "comprehensive-case-training", taskName: "综合实训" }]), {
title: "综合实训",
path: "/comprehensive/index",
activePrefix: "/comprehensive",
});
console.log("student training navigation ESM contract passed");

@ -1,48 +0,0 @@
const assert = require("assert");
const {
buildStudentTaskSections,
getComprehensiveTopTask,
} = require("../src/utils/studentTrainingNavigation.cjs");
const tasks = [
{ taskKey: "comprehensive-case-training", taskName: "综合案例实训", projectName: "综合实训", sort: 1 },
{ taskKey: "market-task", taskName: "需求访谈", projectName: "市场洞察与需求分析", sort: 3 },
{ taskKey: "new-product-survey", taskName: "新产品调查与分析", projectName: "互联网产品开发基础认知", sort: 2 },
{ taskKey: "teacher-added-task", taskName: "教师新增任务", projectName: "市场洞察与需求分析", sort: 4 },
];
const sections = buildStudentTaskSections(tasks);
assert.deepStrictEqual(sections, [
{
title: "互联网产品开发基础认知",
children: [{ title: "新产品调查与分析", path: "/foundation/new-product-survey" }],
},
{
title: "市场洞察与需求分析",
children: [
{ title: "需求访谈", path: "/training/task/market-task" },
{ title: "教师新增任务", path: "/training/task/teacher-added-task" },
],
},
]);
assert.deepStrictEqual(getComprehensiveTopTask(tasks), {
title: "综合案例实训",
path: "/comprehensive/index",
activePrefix: "/comprehensive",
});
const fs = require("fs");
const path = require("path");
const frontendRoot = path.resolve(__dirname, "..");
const sidebarSource = fs.readFileSync(path.join(frontendRoot, "src/layout/components/Sidebar/index.vue"), "utf8");
const navbarSource = fs.readFileSync(path.join(frontendRoot, "src/layout/components/Navbar.vue"), "utf8");
const routerSource = fs.readFileSync(path.join(frontendRoot, "src/router/index.js"), "utf8");
assert(sidebarSource.includes("loadStudentTaskNavigation"), "student sidebar must load its task navigation from the task API");
assert(sidebarSource.includes("studentTaskSections"), "student sidebar must render dynamic task sections");
assert(navbarSource.includes("getComprehensiveTopTask"), "top navigation must derive comprehensive training from the task API");
assert(navbarSource.includes("studentTopTask"), "top navigation must hold the published comprehensive task");
assert(routerSource.includes('path: "task/:pageKey"'), "teacher-added tasks must have a generic student route");
console.log("student training navigation contract passed");

@ -0,0 +1,9 @@
import assert from "node:assert/strict";
import { extractTrainingStepNames } from "../src/views/training/taskKeyMap.js";
assert.deepEqual(
extractTrainingStepNames('[{"id":"custom-123","kind":"builtin","name":"电商产品调研"}]'),
["电商产品调研"]
);
console.log("training step names contract passed");
Loading…
Cancel
Save