|
|
|
@ -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; } }
|
|
|
|
|