66 <div class =" pixel-snake" ></div >
77 </div >
88
9+ <!-- 截止时间与倒计时提示 -->
10+ <div class =" deadline-banner pixel-border" :class =" { passed: isPastDeadline }" >
11+ <template v-if =" ! isPastDeadline " >
12+ <span class =" deadline-text" >提交截止倒计时:</span >
13+ <span class =" deadline-timer" >{{ countdownText }}</span >
14+ <span class =" deadline-note" >(截止时间:{{ DEADLINE_LABEL }})</span >
15+ </template >
16+ <template v-else >
17+ <span class =" deadline-text" >提交已截止</span >
18+ <span class =" deadline-note" >(截止时间:{{ DEADLINE_LABEL }})</span >
19+ </template >
20+ </div >
21+
922 <div class =" submit-content" >
1023 <div v-if =" !isCompilingUI && !hasResult" class =" upload-section" >
1124 <label for =" codeFile" class =" file-label pixel-border"
3750
3851 <div class =" submit-actions" >
3952 <button @click =" handleSubmit" class =" pixel-button"
40- :disabled =" isUploading || !selectedFile || rateLimitCountdown > 0" >
41- {{ isUploading ? '上传中...' : rateLimitCountdown > 0 ? `等待${rateLimitCountdown}秒` : '提交代码' }}
53+ :disabled =" isUploading || !selectedFile || rateLimitCountdown > 0 || isPastDeadline " >
54+ {{ isPastDeadline ? '已截止' : ( isUploading ? '上传中...' : rateLimitCountdown > 0 ? `等待${rateLimitCountdown}秒` : '提交代码') }}
4255 </button >
4356 </div >
4457
4558 <!-- 显示所有上传阶段的错误(文件类型、大小、429等) -->
4659 <div v-if =" error" :class =" ['error-message', { 'rate-limit-error': rateLimitCountdown > 0 }]" >
4760 {{ rateLimitCountdown > 0 ? `请求频率过高,请${rateLimitCountdown}秒后重试` : error }}
4861 </div >
62+ <div v-if =" isPastDeadline" class =" deadline-hint" >已超过截止时间,禁止提交。</div >
4963 </div >
5064
5165 <!-- 编译/结果区域:在上传完成后或 SUBMITTED 后进入显示(统一使用状态条样式) -->
102116</template >
103117
104118<script setup lang="ts">
105- import { ref , onUnmounted , computed , nextTick } from ' vue' ;
119+ import { ref , onUnmounted , onMounted , computed , nextTick } from ' vue' ;
106120import { sandboxService } from ' ../services/sandboxService' ;
107121import { useAuth } from ' ../stores/auth' ;
108122import { SSE } from ' sse.js' ;
109123import { RateLimitError } from ' ../types/RateLimitError' ;
124+ import { DEADLINE_TS , DEADLINE_LABEL , getRemainingMs , isPastDeadline as pastDeadlineFn , formatCountdown } from ' ../utils/deadline' ;
110125
111126const { state } = useAuth ();
112127
@@ -125,6 +140,12 @@ const jobId = ref<string | null>(null);
125140const rateLimitCountdown = ref <number >(0 );
126141const rateLimitTimer = ref <number | null >(null );
127142
143+ // 截止时间与倒计时
144+ const nowMs = ref <number >(Date .now ());
145+ const isPastDeadline = computed (() => pastDeadlineFn (nowMs .value ));
146+ const countdownText = computed (() => formatCountdown (getRemainingMs (nowMs .value )));
147+ let deadlineTimer: number | null = null ;
148+
128149const statusBarClass = computed (() => {
129150 if (hasResult .value && compilationStatus .value ) {
130151 return ` status-${compilationStatus .value } ` ;
@@ -361,6 +382,11 @@ const handleSubmit = async () => {
361382 return ;
362383 }
363384
385+ if (isPastDeadline .value ) {
386+ error .value = ' 已超过截止时间,无法提交' ;
387+ return ;
388+ }
389+
364390 // 重置状态
365391 closeSSEConnection ();
366392 isUploading .value = true ;
@@ -429,9 +455,21 @@ const formatDate = (timestamp: number): string => {
429455};
430456
431457// 组件卸载时清理SSE连接和定时器
458+ onMounted (() => {
459+ // 倒计时更新
460+ if (deadlineTimer ) clearInterval (deadlineTimer );
461+ deadlineTimer = setInterval (() => {
462+ nowMs .value = Date .now ();
463+ }, 1000 ) as unknown as number ;
464+ });
465+
432466onUnmounted (() => {
433467 closeSSEConnection ();
434468 clearRateLimitTimer ();
469+ if (deadlineTimer ) {
470+ clearInterval (deadlineTimer );
471+ deadlineTimer = null ;
472+ }
435473});
436474 </script >
437475
@@ -451,6 +489,37 @@ onUnmounted(() => {
451489 overflow-y : auto ;
452490}
453491
492+ /* 截止时间提示条 */
493+ .deadline-banner {
494+ display : flex ;
495+ align-items : center ;
496+ gap : 8px ;
497+ padding : 10px 12px ;
498+ margin-bottom : 16px ;
499+ background : var (--input-bg );
500+ border : 2px solid var (--border-color );
501+ }
502+ .deadline-banner.passed {
503+ border-color : var (--error-color );
504+ background : rgba (239 , 68 , 68 , 0.08 );
505+ }
506+ .deadline-text {
507+ font-weight : 600 ;
508+ color : var (--text-color );
509+ }
510+ .deadline-timer {
511+ font-family : monospace ;
512+ color : var (--accent-color );
513+ }
514+ .deadline-note {
515+ color : var (--border-color );
516+ font-size : 12px ;
517+ }
518+ .deadline-hint {
519+ text-align : center ;
520+ color : var (--error-color );
521+ }
522+
454523/* 自定义滚动条样式 */
455524.submit-card ::-webkit-scrollbar {
456525 width : 12px ;
0 commit comments