diff --git a/src/views/Competition.vue b/src/views/Competition.vue index 82599c4..b1c0564 100644 --- a/src/views/Competition.vue +++ b/src/views/Competition.vue @@ -21,7 +21,13 @@
@@ -107,8 +113,14 @@ show-icon style="margin-top:12px" title="组内作品唯一:本组已有成员上传,您无法再上传" - description="如需替换作品,请联系上传者本人操作(仅首个上传者可在截止前替换)。" + description="如需替换作品,请联系上传者本人操作(仅首个上传者可在截止前替换)。您本人无需提交,可直接返回工作台。" /> + +
+ 返回工作台 + 本组作品已由队友提交,您无需任何操作。 +
@@ -405,7 +417,7 @@ import { ref, computed, onMounted, onUnmounted, watch } from 'vue' import { useRouter, onBeforeRouteLeave } from 'vue-router' import { ElMessage, ElMessageBox, ElNotification } from 'element-plus' -import { Timer, UploadFilled } from '@element-plus/icons-vue' +import { Timer, UploadFilled, Back } from '@element-plus/icons-vue' import { useAuthStore } from '@/stores/auth' import { useExamStore } from '@/stores/exam' import * as examApi from '@/api/exam' @@ -516,6 +528,36 @@ function clearUploadFiles() { uploadRef.value?.clearFiles?.() } +/** + * 返回工作台(R192)—— 上传模式的统一出口。 + * + * 🔴 必须先 resetExam() 再 push,理由有三条: + * ① 不清 `examStarted` ⇒ `onBeforeRouteLeave` 会再弹一次「离开页面将丢失当前提交进度」。 + * 上传模式下用户常常只是放弃提交(甚至被组锁、本机根本没有可提交内容), + * 这句文案既失真又构成二次打扰; + * ② 不清 timer ⇒ store 是全局单例,回到工作台后倒计时仍在跑,下次进入会看到陈旧剩余时间; + * ③ 用 resetExam(而非只 stopExam)与 `onBeforeRouteLeave` 里确认离开后的清理**同一口径**, + * ⛔ 不留「按钮退出」与「路由守卫退出」两套清理逻辑(漏项会以「下次进入状态诡异」的形式出现)。 + * + * 只有「待上传列表里有已选文件」才算真有内容会丢,此时才确认一次。 + * 组锁用户的上传控件是 disabled 的,选不出文件 ⇒ 不弹确认,直接离开。 + */ +async function leaveCompetition() { + if (!teamLocked.value && uploadFileList.value.length > 0) { + try { + await ElMessageBox.confirm( + '已选择的文件尚未上传,离开后需要重新选择。确定返回工作台吗?', + '提示', + { confirmButtonText: '返回工作台', cancelButtonText: '继续上传', type: 'warning' } + ) + } catch { + return + } + } + examStore.resetExam() + router.push('/dashboard') +} + async function submitUploadFiles() { const files = pendingUploadFiles.value if (!files.length) return @@ -1031,7 +1073,13 @@ function preventKeyboard(e) { // 路由离开警告 onBeforeRouteLeave((to, from, next) => { - if (examStore.examStarted && !examStore.isTimeUp) { + // 🔴 组锁用户不弹:上传控件 disabled、无交卷动作 ⇒ 本机没有任何可丢的内容。 + // 对这类用户弹「离开将丢失提交进度」是假警告(体验反馈:被锁成员被困在提交页)。 + // 判定写成「上传模式 && teamLocked」而不是只看 teamLocked:后者当前虽等价 + // (客观题模式不拉 uploadStatus),但语义上把考试组也纳入了豁免面,将来一旦 + // 考试组也拉 status,就会静默取消「交卷前离开」的确认 —— 这是不可接受的放松。 + const lockedNoContent = isUploadMode.value && teamLocked.value + if (examStore.examStarted && !examStore.isTimeUp && !lockedNoContent) { const verb = isUploadMode.value ? '提交' : '答题' ElMessageBox.confirm( `离开页面将丢失当前${verb}进度,确定要离开吗?`, @@ -1579,6 +1627,28 @@ onUnmounted(() => { justify-content: space-between; } +/* ==================== R192:上传页出口(组锁 / 主动放弃提交) ==================== */ +/* 本页无全局导航(App.vue 只有 router-view)⇒ 出口按钮必须常驻,否则被组锁的 + 成员只能靠浏览器后退离开(移动端/内嵌浏览器常常退不出去)。 */ +.upload-header { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 0.75rem; +} +.team-locked-actions { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 0.75rem; + margin-top: 0.75rem; +} +.team-locked-hint { + font-size: 0.85rem; + color: #909399; +} + /* ==================== R190:小组作品状态面板 ==================== */ .team-status-panel { border: 1px solid #c6e2ff;