学生端实训页面按钮统一:TrainingTaskToolbar新增保存当前进度按钮(优先触发页面内保存,fallback快照SAVE与提交区分),25个缺失页面批量接入统一工具栏,所有实训页面具备保存+提交两个按钮

fix/exam-question-access-material-excel-delete-draft
陈沅 2 weeks ago
parent 1e251d7169
commit 4319e2c980

@ -1,5 +1,6 @@
<template> <template>
<div class="five"> <div class="five">
<TrainingTaskToolbar />
<el-scrollbar :height="`${height - 100}px`"> <el-scrollbar :height="`${height - 100}px`">
<TrainingIntro title="五维四率模型"> <TrainingIntro title="五维四率模型">
<template #background> <template #background>
@ -177,6 +178,7 @@ import TrainingIntro from '@/views/components/TrainingIntro.vue';
import useUserStore from "@/store/modules/user"; import useUserStore from "@/store/modules/user";
const userStore = useUserStore(); const userStore = useUserStore();
import * as analysisAPI from "@/api/market-demand-mining.js"; import * as analysisAPI from "@/api/market-demand-mining.js";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const height = ref(800); const height = ref(800);
const liveRoomDataWithConversion = [ const liveRoomDataWithConversion = [

@ -1,5 +1,6 @@
<template> <template>
<div class="kano"> <div class="kano">
<TrainingTaskToolbar />
<el-scrollbar :height="`${height - 100}px`"> <el-scrollbar :height="`${height - 100}px`">
<TrainingIntro title="KANO模型"> <TrainingIntro title="KANO模型">
<template #background> <template #background>
@ -320,6 +321,7 @@ import useUserStore from "@/store/modules/user";
const userStore = useUserStore(); const userStore = useUserStore();
import * as analysisAPI from "@/api/market-demand-mining.js"; import * as analysisAPI from "@/api/market-demand-mining.js";
import { ref } from "vue"; import { ref } from "vue";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const height = ref(800); const height = ref(800);
const form = ref({ const form = ref({

@ -8,6 +8,7 @@
--> -->
<template> <template>
<div class="market"> <div class="market">
<TrainingTaskToolbar />
<el-scrollbar :height="`${height - 100}px`"> <el-scrollbar :height="`${height - 100}px`">
<TrainingIntro title="市场机会矩阵"> <TrainingIntro title="市场机会矩阵">
<template #background> <template #background>
@ -215,6 +216,7 @@ import TrainingIntro from '@/views/components/TrainingIntro.vue';
import useUserStore from "@/store/modules/user"; import useUserStore from "@/store/modules/user";
const userStore = useUserStore(); const userStore = useUserStore();
import * as analysisAPI from "@/api/market-demand-mining.js"; import * as analysisAPI from "@/api/market-demand-mining.js";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const height = ref(800); const height = ref(800);
const salesData = [ const salesData = [

@ -8,6 +8,7 @@
--> -->
<template> <template>
<div class="traffic"> <div class="traffic">
<TrainingTaskToolbar />
<el-scrollbar :height="`${height - 100}px`"> <el-scrollbar :height="`${height - 100}px`">
<TrainingIntro title="流量问题诊断"> <TrainingIntro title="流量问题诊断">
<template #background> <template #background>
@ -107,6 +108,7 @@ import TrainingIntro from '@/views/components/TrainingIntro.vue';
import useUserStore from "@/store/modules/user"; import useUserStore from "@/store/modules/user";
const userStore = useUserStore(); const userStore = useUserStore();
import * as analysisAPI from "@/api/market-demand-mining.js"; import * as analysisAPI from "@/api/market-demand-mining.js";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const height = ref(800); const height = ref(800);
const from = ref({ const from = ref({

@ -1,5 +1,6 @@
<template> <template>
<div class="channel student-training-shell"> <div class="channel student-training-shell">
<TrainingTaskToolbar />
<main class="training-core"> <main class="training-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -199,6 +200,7 @@ import pandas as pd
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import matplotlib as mpl import matplotlib as mpl
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
from sklearn.linear_model import LinearRegression from sklearn.linear_model import LinearRegression
mpl.rcParams['font.sans-serif'] = ['SimHei']#SimHeri是中文字体名称 mpl.rcParams['font.sans-serif'] = ['SimHei']#SimHeri是中文字体名称
mpl.rcParams['axes.unicode_minus'] = False mpl.rcParams['axes.unicode_minus'] = False

@ -8,6 +8,7 @@
--> -->
<template> <template>
<div class="purchase-page student-training-shell"> <div class="purchase-page student-training-shell">
<TrainingTaskToolbar />
<main class="purchase-core"> <main class="purchase-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -142,6 +143,7 @@ import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue";
import * as analysisAPI from "@/api/market-demand-mining.js"; import * as analysisAPI from "@/api/market-demand-mining.js";
import * as echarts from "echarts"; import * as echarts from "echarts";
import useUserStore from "@/store/modules/user"; import useUserStore from "@/store/modules/user";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const userStore = useUserStore(); const userStore = useUserStore();
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const briefOpen = ref(false); const briefOpen = ref(false);

@ -1,5 +1,6 @@
<template> <template>
<div class="supplier-page student-training-shell" v-loading="loading"> <div class="supplier-page student-training-shell" v-loading="loading">
<TrainingTaskToolbar />
<main class="supplier-core"> <main class="supplier-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -220,6 +221,7 @@ import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue";
import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue"; import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue";
import { getTrainingTaskByKey } from "@/api/trainingTask"; import { getTrainingTaskByKey } from "@/api/trainingTask";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
import { import {
getStudentTrainingAnswer, getStudentTrainingAnswer,
saveStudentTrainingAnswer, saveStudentTrainingAnswer,

@ -10,6 +10,9 @@
:ai-manual-name="resolvedAiManual.name" :ai-manual-name="resolvedAiManual.name"
:ai-manual-url="resolvedAiManual.url" :ai-manual-url="resolvedAiManual.url"
/> />
<el-button class="task-toolbar-button task-toolbar-button--save" :loading="savingProgress" @click="triggerExistingAction('save')">
<el-icon><CircleCheck /></el-icon>保存当前进度
</el-button>
<el-button class="task-toolbar-button task-toolbar-button--submit" @click="triggerExistingAction('submit')"> <el-button class="task-toolbar-button task-toolbar-button--submit" @click="triggerExistingAction('submit')">
<el-icon><CircleCheck /></el-icon>提交任务 <el-icon><CircleCheck /></el-icon>提交任务
</el-button> </el-button>
@ -60,6 +63,7 @@ const loadedMaterial = ref({
}); });
const loadedTask = ref(null); const loadedTask = ref(null);
const exporting = ref(false); const exporting = ref(false);
const savingProgress = ref(false);
const resolvedTaskKey = computed(() => resolveTrainingTaskKey(route, props.taskKey)); const resolvedTaskKey = computed(() => resolveTrainingTaskKey(route, props.taskKey));
const resolvedMaterial = computed(() => ({ const resolvedMaterial = computed(() => ({
name: String(props.materialName || loadedMaterial.value.name || ""), name: String(props.materialName || loadedMaterial.value.name || ""),
@ -139,6 +143,11 @@ function triggerExistingAction(action) {
reset: props.onReset, reset: props.onReset,
}; };
if (action === "save") {
saveProgress();
return;
}
if (directActions[action]) { if (directActions[action]) {
directActions[action](); directActions[action]();
return; return;
@ -201,6 +210,50 @@ function collectLegacyFields() {
})); }));
} }
async function saveProgress() {
if (savingProgress.value) return;
// 优先触发页面自身的保存逻辑(保留各页面的校验与状态文案)
const saveLabelPriority = [[/保存当前进度/], [/保存进度/], [/保存(?!成功|失败|中)/]];
const buttons = getCurrentTaskActionButtons();
const target = saveLabelPriority
.map((matchers) => buttons.find((button) => matchers.some((matcher) => matcher.test(button.innerText || ""))))
.find(Boolean);
if (target) {
savingProgress.value = true;
try {
target.click();
await new Promise((resolve) => setTimeout(resolve, 600));
ElMessage.success("进度已保存");
} finally {
savingProgress.value = false;
}
return;
}
// 页面没有保存按钮时保存表单快照(SAVE 不等于提交)
if (!resolvedTaskKey.value) {
ElMessage.warning("当前任务暂未配置,无法保存。");
return;
}
savingProgress.value = true;
try {
await saveStudentTrainingAnswer(resolvedTaskKey.value, {
saveAction: "SAVE",
currentStep: 1,
step1Answer: JSON.stringify({
type: "legacy-training-snapshot-v3",
route: route.path,
savedAt: new Date().toISOString(),
fields: collectLegacyFields(),
}),
});
ElMessage.success("进度已保存");
} catch {
ElMessage.error("保存失败,请稍后重试。");
} finally {
savingProgress.value = false;
}
}
async function saveLegacyTraining() { async function saveLegacyTraining() {
if (!resolvedTaskKey.value) { if (!resolvedTaskKey.value) {
ElMessage.warning("当前任务暂未配置,无法提交。"); ElMessage.warning("当前任务暂未配置,无法提交。");
@ -263,6 +316,8 @@ function exportLegacyTraining() {
.training-task-toolbar { display:flex; flex-wrap:wrap; align-items:center; justify-content:flex-end; gap:8px; } .training-task-toolbar { display:flex; flex-wrap:wrap; align-items:center; justify-content:flex-end; gap:8px; }
.task-toolbar-button { min-height:34px; height:34px; padding:0 14px; border-color:rgba(37,99,235,.35); border-radius:8px; color:#2563eb; background:#fff; font-size:13px; font-weight:600; } .task-toolbar-button { min-height:34px; height:34px; padding:0 14px; border-color:rgba(37,99,235,.35); border-radius:8px; color:#2563eb; background:#fff; font-size:13px; font-weight:600; }
.task-toolbar-button:hover { border-color:#2563eb; color:#1d4ed8; background:#eff6ff; } .task-toolbar-button:hover { border-color:#2563eb; color:#1d4ed8; background:#eff6ff; }
.task-toolbar-button--save { border-color:rgba(43,164,113,.45); color:#2ba471; }
.task-toolbar-button--save:hover { border-color:#2ba471; color:#1f8f62; background:#f0fbf6; }
.task-toolbar-button--submit { border-color:#2563eb; color:#fff; background:#2563eb; } .task-toolbar-button--submit { border-color:#2563eb; color:#fff; background:#2563eb; }
.task-toolbar-button--submit:hover { border-color:#1d4ed8; color:#fff; background:#1d4ed8; } .task-toolbar-button--submit:hover { border-color:#1d4ed8; color:#fff; background:#1d4ed8; }
@media (max-width:768px) { .training-task-toolbar { justify-content:stretch; } .training-task-toolbar > * { flex:1 1 auto; } } @media (max-width:768px) { .training-task-toolbar { justify-content:stretch; } .training-task-toolbar > * { flex:1 1 auto; } }

@ -1,5 +1,6 @@
<template> <template>
<div class="feasibility-page student-training-shell"> <div class="feasibility-page student-training-shell">
<TrainingTaskToolbar />
<main class="feasibility-core"> <main class="feasibility-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -379,6 +380,7 @@ import { getTrainingTaskByKey } from "@/api/trainingTask"
import { parseTrainingArray } from "@/views/training/taskKeyMap" import { parseTrainingArray } from "@/views/training/taskKeyMap"
import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue" import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue"
import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue" import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue"
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "business-feasibility" const TASK_KEY = "business-feasibility"
const DEFAULT_STEPS = ["商业可行性论证", "项目初步决策", "可行性论证报告", "决策结论"] const DEFAULT_STEPS = ["商业可行性论证", "项目初步决策", "可行性论证报告", "决策结论"]

@ -1,5 +1,6 @@
<template> <template>
<div class="consumer-behavior-page student-training-shell"> <div class="consumer-behavior-page student-training-shell">
<TrainingTaskToolbar />
<main class="training-core"> <main class="training-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -303,6 +304,7 @@ import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vu
import { getTrainingTaskByKey } from "@/api/trainingTask"; import { getTrainingTaskByKey } from "@/api/trainingTask";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import { checkConsumerBehaviorStepOne, checkConsumerBehaviorStepTwo, checkConsumerBehaviorStepThree, checkConsumerBehaviorStepFour, getStudentTrainingAnswer, previewConsumerBehaviorQuestionnaireWord, saveStudentTrainingAnswer, uploadStudentTrainingFile } from "@/api/studentTrainingAnswer"; import { checkConsumerBehaviorStepOne, checkConsumerBehaviorStepTwo, checkConsumerBehaviorStepThree, checkConsumerBehaviorStepFour, getStudentTrainingAnswer, previewConsumerBehaviorQuestionnaireWord, saveStudentTrainingAnswer, uploadStudentTrainingFile } from "@/api/studentTrainingAnswer";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "consumer-behavior"; const TASK_KEY = "consumer-behavior";
const QUESTIONNAIRE_TEMPLATE_URL = "/file/training-materials/consumer-behavior/9.问卷调查报告模板.docx"; const QUESTIONNAIRE_TEMPLATE_URL = "/file/training-materials/consumer-behavior/9.问卷调查报告模板.docx";

@ -1,5 +1,6 @@
<template> <template>
<div class="consumer-scenario-page student-training-shell"> <div class="consumer-scenario-page student-training-shell">
<TrainingTaskToolbar />
<main class="consumer-scenario-core"> <main class="consumer-scenario-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -279,6 +280,7 @@ import { getTrainingTaskByKey } from "@/api/trainingTask";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import { checkConsumerScenarioStepOne, checkConsumerScenarioStepTwo, checkConsumerScenarioStepThree, checkConsumerScenarioStepFour, getStudentTrainingAnswer, saveStudentTrainingAnswer, uploadStudentTrainingFile } from "@/api/studentTrainingAnswer"; import { checkConsumerScenarioStepOne, checkConsumerScenarioStepTwo, checkConsumerScenarioStepThree, checkConsumerScenarioStepFour, getStudentTrainingAnswer, saveStudentTrainingAnswer, uploadStudentTrainingFile } from "@/api/studentTrainingAnswer";
import { isStudentDemo } from "@/utils/studentDemo"; import { isStudentDemo } from "@/utils/studentDemo";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "consumer-scenario"; const TASK_KEY = "consumer-scenario";
const JOURNEY_TEMPLATE_URL = "/file/training-materials/consumer-scenario/10.用户购买旅程模版.pptx"; const JOURNEY_TEMPLATE_URL = "/file/training-materials/consumer-scenario/10.用户购买旅程模版.pptx";

@ -1,5 +1,6 @@
<template> <template>
<div class="competitive-page student-training-shell"> <div class="competitive-page student-training-shell">
<TrainingTaskToolbar />
<main class="training-core"> <main class="training-core">
<section class="task-header"> <section class="task-header">
<h1 class="task-title">{{ taskTitle }}</h1> <h1 class="task-title">{{ taskTitle }}</h1>
@ -149,6 +150,7 @@ import { getTrainingTaskByKey } from "@/api/trainingTask";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import { getStudentTrainingAnswer, saveStudentTrainingAnswer } from "@/api/studentTrainingAnswer"; import { getStudentTrainingAnswer, saveStudentTrainingAnswer } from "@/api/studentTrainingAnswer";
import { ArrowLeft, ArrowRight, CircleCheck, Download } from "@element-plus/icons-vue"; import { ArrowLeft, ArrowRight, CircleCheck, Download } from "@element-plus/icons-vue";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "competitive-environment-analysis"; const TASK_KEY = "competitive-environment-analysis";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();

@ -1,5 +1,6 @@
<template> <template>
<div class="industry-demand-page student-training-shell"> <div class="industry-demand-page student-training-shell">
<TrainingTaskToolbar />
<main class="training-core"> <main class="training-core">
<section class="task-header"> <section class="task-header">
<h1 class="task-title">{{ taskTitle }}</h1> <h1 class="task-title">{{ taskTitle }}</h1>
@ -137,6 +138,7 @@ import { getTrainingTaskByKey } from "@/api/trainingTask";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import { getStudentTrainingAnswer, saveStudentTrainingAnswer } from "@/api/studentTrainingAnswer"; import { getStudentTrainingAnswer, saveStudentTrainingAnswer } from "@/api/studentTrainingAnswer";
import { ArrowLeft, ArrowRight, CircleCheck, Download } from "@element-plus/icons-vue"; import { ArrowLeft, ArrowRight, CircleCheck, Download } from "@element-plus/icons-vue";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "industry-demand-analysis"; const TASK_KEY = "industry-demand-analysis";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();

@ -1,5 +1,6 @@
<template> <template>
<div class="target-profile-page student-training-shell"> <div class="target-profile-page student-training-shell">
<TrainingTaskToolbar />
<main class="training-core"> <main class="training-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -378,6 +379,7 @@ import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vu
import { getTrainingTaskByKey } from "@/api/trainingTask" import { getTrainingTaskByKey } from "@/api/trainingTask"
import { parseTrainingArray } from "@/views/training/taskKeyMap" import { parseTrainingArray } from "@/views/training/taskKeyMap"
import { checkTargetUserProfileStepFive, checkTargetUserProfileStepFour, checkTargetUserProfileStepOne, checkTargetUserProfileStepThree, checkTargetUserProfileStepTwo, getStudentTrainingAnswer, saveStudentTrainingAnswer, uploadStudentTrainingFile } from "@/api/studentTrainingAnswer" import { checkTargetUserProfileStepFive, checkTargetUserProfileStepFour, checkTargetUserProfileStepOne, checkTargetUserProfileStepThree, checkTargetUserProfileStepTwo, getStudentTrainingAnswer, saveStudentTrainingAnswer, uploadStudentTrainingFile } from "@/api/studentTrainingAnswer"
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "target-user-profile" const TASK_KEY = "target-user-profile"
const RFM_INSTRUCTIONS_URL = "/file/training-materials/target-user-profile/8.实训操作说明.docx" const RFM_INSTRUCTIONS_URL = "/file/training-materials/target-user-profile/8.实训操作说明.docx"

@ -8,6 +8,7 @@
--> -->
<template> <template>
<div class="rgzn_top app-container2 student-training-shell legacy-training-page" v-loading="loading" element-loading-text="Loading..." :element-loading-spinner="svg" element-loading-svg-view-box="-10, -10, 50, 50" element-loading-background="rgba(122, 122, 122, 0.8)"> <div class="rgzn_top app-container2 student-training-shell legacy-training-page" v-loading="loading" element-loading-text="Loading..." :element-loading-spinner="svg" element-loading-svg-view-box="-10, -10, 50, 50" element-loading-background="rgba(122, 122, 122, 0.8)">
<TrainingTaskToolbar />
<div class="top_item"> <div class="top_item">
<div> <div>
<template v-for="(item, index) in tabsList" :key="item.id"> <template v-for="(item, index) in tabsList" :key="item.id">
@ -59,6 +60,7 @@ import { getAssetsFile, isModuleUnique } from "@/utils/index.js";
import useAlgorithmStore from "@/store/modules/algorithm.js"; import useAlgorithmStore from "@/store/modules/algorithm.js";
import { getUserInfo } from "@/utils/auth"; import { getUserInfo } from "@/utils/auth";
import { onMounted } from "vue"; import { onMounted } from "vue";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const algorithmStore = useAlgorithmStore(); const algorithmStore = useAlgorithmStore();
const userInfo = JSON.parse(getUserInfo()); const userInfo = JSON.parse(getUserInfo());

@ -1,5 +1,6 @@
<template> <template>
<div class="product-factors student-training-shell"> <div class="product-factors student-training-shell">
<TrainingTaskToolbar />
<main class="factors-core"> <main class="factors-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -162,6 +163,7 @@ import { checkProductDevelopmentFactorsStepOne, checkProductDevelopmentFactorsSt
import useUserStore from "@/store/modules/user"; import useUserStore from "@/store/modules/user";
import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue"; import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue";
import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue"; import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const TASK_KEY = "product-development-factors"; const TASK_KEY = "product-development-factors";

@ -1,5 +1,6 @@
<template> <template>
<div class="product-process student-training-shell"> <div class="product-process student-training-shell">
<TrainingTaskToolbar />
<main class="process-core"> <main class="process-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -196,6 +197,7 @@ import { isExternal } from "@/utils/validate";
import useUserStore from "@/store/modules/user"; import useUserStore from "@/store/modules/user";
import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue"; import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue";
import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue"; import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const userStore = useUserStore(); const userStore = useUserStore();

@ -1,5 +1,6 @@
<template> <template>
<div class="after-sales-page student-training-shell"> <div class="after-sales-page student-training-shell">
<TrainingTaskToolbar />
<main class="after-sales-core"> <main class="after-sales-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -256,6 +257,7 @@ import { checkAfterSalesServiceStepOne, checkAfterSalesServiceStepTwo, checkAfte
import { getTrainingTaskByKey } from "@/api/trainingTask"; import { getTrainingTaskByKey } from "@/api/trainingTask";
import { getStudentTrainingPage } from "@/views/training/studentTrainingPages"; import { getStudentTrainingPage } from "@/views/training/studentTrainingPages";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "after-sales-service"; const TASK_KEY = "after-sales-service";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();

@ -1,5 +1,6 @@
<template> <template>
<div class="product-positioning-page student-training-shell"> <div class="product-positioning-page student-training-shell">
<TrainingTaskToolbar />
<main class="product-positioning-core"> <main class="product-positioning-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -277,6 +278,7 @@ import { getTrainingTaskByKey } from "@/api/trainingTask";
import { checkProductValuePositioningStepOne, checkProductValuePositioningStepTwo, checkProductValuePositioningStepThree, checkProductValuePositioningStepFour, getStudentTrainingAnswer, saveStudentTrainingAnswer, uploadStudentTrainingFile } from "@/api/studentTrainingAnswer"; import { checkProductValuePositioningStepOne, checkProductValuePositioningStepTwo, checkProductValuePositioningStepThree, checkProductValuePositioningStepFour, getStudentTrainingAnswer, saveStudentTrainingAnswer, uploadStudentTrainingFile } from "@/api/studentTrainingAnswer";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import { isStudentDemo } from "@/utils/studentDemo"; import { isStudentDemo } from "@/utils/studentDemo";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "product-value-positioning"; const TASK_KEY = "product-value-positioning";
const VALUE_PROPOSITION_CANVAS_TEMPLATE_URL = "/file/training-materials/product-value-positioning/12.产品价值主张画布模版.pptx"; const VALUE_PROPOSITION_CANVAS_TEMPLATE_URL = "/file/training-materials/product-value-positioning/12.产品价值主张画布模版.pptx";

@ -1,5 +1,6 @@
<template> <template>
<div class="hardware-cost-page student-training-shell"> <div class="hardware-cost-page student-training-shell">
<TrainingTaskToolbar />
<main class="hardware-core"> <main class="hardware-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -332,6 +333,7 @@ import { getTrainingTaskByKey } from "@/api/trainingTask";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import { getStudentTrainingAnswer, saveStudentTrainingAnswer, uploadStudentTrainingFile, validateHardwareCostStepOne, validateHardwareCostStepTwo, validateHardwareCostStepThree, validateHardwareCostStepFour } from "@/api/studentTrainingAnswer"; import { getStudentTrainingAnswer, saveStudentTrainingAnswer, uploadStudentTrainingFile, validateHardwareCostStepOne, validateHardwareCostStepTwo, validateHardwareCostStepThree, validateHardwareCostStepFour } from "@/api/studentTrainingAnswer";
import { isStudentDemo } from "@/utils/studentDemo"; import { isStudentDemo } from "@/utils/studentDemo";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "hardware-cost"; const TASK_KEY = "hardware-cost";
const HARDWARE_COST_GUIDE_URL = "/file/training-materials/hardware-cost/16.饼图制作操作说明.docx"; const HARDWARE_COST_GUIDE_URL = "/file/training-materials/hardware-cost/16.饼图制作操作说明.docx";

@ -1,5 +1,6 @@
<template> <template>
<div class="market-selection-page student-training-shell"> <div class="market-selection-page student-training-shell">
<TrainingTaskToolbar />
<main class="training-core"> <main class="training-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -228,6 +229,7 @@ import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vu
import { getTrainingTaskByKey } from "@/api/trainingTask"; import { getTrainingTaskByKey } from "@/api/trainingTask";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import { getStudentTrainingAnswer, saveStudentTrainingAnswer } from "@/api/studentTrainingAnswer"; import { getStudentTrainingAnswer, saveStudentTrainingAnswer } from "@/api/studentTrainingAnswer";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "market-opportunity-selection"; const TASK_KEY = "market-opportunity-selection";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();

@ -1,5 +1,6 @@
<template> <template>
<div class="price-page student-training-shell"> <div class="price-page student-training-shell">
<TrainingTaskToolbar />
<main class="price-core"> <main class="price-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -485,6 +486,7 @@ import {
import { getTrainingTaskByKey } from "@/api/trainingTask"; import { getTrainingTaskByKey } from "@/api/trainingTask";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import { isStudentDemo } from "@/utils/studentDemo"; import { isStudentDemo } from "@/utils/studentDemo";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "product-pricing"; const TASK_KEY = "product-pricing";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();

@ -1,5 +1,6 @@
<template> <template>
<div class="requirements-doc-page student-training-shell"> <div class="requirements-doc-page student-training-shell">
<TrainingTaskToolbar />
<main class="requirements-core"> <main class="requirements-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -232,6 +233,7 @@ import { checkRequirementsDocumentStepOne, getStudentTrainingAnswer, previewRequ
import { getTrainingTaskByKey } from "@/api/trainingTask"; import { getTrainingTaskByKey } from "@/api/trainingTask";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import { isStudentDemo } from "@/utils/studentDemo"; import { isStudentDemo } from "@/utils/studentDemo";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "requirements-doc"; const TASK_KEY = "requirements-doc";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();

@ -1,5 +1,6 @@
<template> <template>
<div class="architecture-page student-training-shell"> <div class="architecture-page student-training-shell">
<TrainingTaskToolbar />
<main class="architecture-core"> <main class="architecture-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -173,6 +174,7 @@ import { parseTrainingArray } from "@/views/training/taskKeyMap";
import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue"; import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue";
import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue"; import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue";
import { SCENARIO_FIELDS, getCompletedScenarioCount, getRowsForScenarioValidation, getScenarioValidationMessage } from "./productArchitectureScenarioValidation.mjs"; import { SCENARIO_FIELDS, getCompletedScenarioCount, getRowsForScenarioValidation, getScenarioValidationMessage } from "./productArchitectureScenarioValidation.mjs";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const TASK_KEY = "product-structure"; const TASK_KEY = "product-structure";

@ -1,5 +1,6 @@
<template> <template>
<div class="release-channel-page student-training-shell"> <div class="release-channel-page student-training-shell">
<TrainingTaskToolbar />
<main class="release-channel-core"> <main class="release-channel-core">
<section class="task-header"> <section class="task-header">
<div class="task-head-main"> <div class="task-head-main">
@ -198,6 +199,7 @@ import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vu
import { getTrainingTaskByKey } from "@/api/trainingTask"; import { getTrainingTaskByKey } from "@/api/trainingTask";
import { getStudentTrainingAnswer, saveStudentTrainingAnswer, validateReleaseChannelEvaluationStepOne, validateReleaseChannelEvaluationStepTwo, validateReleaseChannelEvaluationStepThree, validateReleaseChannelEvaluationStepFour } from "@/api/studentTrainingAnswer"; import { getStudentTrainingAnswer, saveStudentTrainingAnswer, validateReleaseChannelEvaluationStepOne, validateReleaseChannelEvaluationStepTwo, validateReleaseChannelEvaluationStepThree, validateReleaseChannelEvaluationStepFour } from "@/api/studentTrainingAnswer";
import { parseTrainingArray } from "@/views/training/taskKeyMap"; import { parseTrainingArray } from "@/views/training/taskKeyMap";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const TASK_KEY = "release-channel-evaluation"; const TASK_KEY = "release-channel-evaluation";
const RELEASE_CHANNEL_GUIDE_URL = "/file/training-materials/release-channel-evaluation/21.实训操作说明.docx"; const RELEASE_CHANNEL_GUIDE_URL = "/file/training-materials/release-channel-evaluation/21.实训操作说明.docx";

@ -8,6 +8,7 @@
--> -->
<template> <template>
<div class="marketing app-container student-training-shell legacy-training-page"> <div class="marketing app-container student-training-shell legacy-training-page">
<TrainingTaskToolbar />
<TrainingIntro title="四象限法则"> <TrainingIntro title="四象限法则">
<template #background> <template #background>
<p> <p>
@ -103,6 +104,7 @@ import popModel from "@/views/components/popModal.vue";
import * as analysisAPI from "@/api/market-demand-mining.js"; import * as analysisAPI from "@/api/market-demand-mining.js";
import * as echarts from "echarts"; import * as echarts from "echarts";
import { onMounted } from "vue"; import { onMounted } from "vue";
import TrainingTaskToolbar from "@/views/components/TrainingTaskToolbar.vue";
const textarea = ref(""); const textarea = ref("");
const dialogVisible = ref(false); const dialogVisible = ref(false);
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();

Loading…
Cancel
Save