From 6151f002bdb9f784c4a53eee1e80172b5d3b8abb Mon Sep 17 00:00:00 2001
From: yuetsh <517252939@qq.com>
Date: Tue, 7 Oct 2025 21:57:54 +0800
Subject: [PATCH] update
---
.../problem/components/SubmissionResult.vue | 100 ++++++
src/oj/problem/components/Submit.vue | 314 ++++--------------
.../composables/useSubmissionMonitor.ts | 172 ++++++++++
3 files changed, 338 insertions(+), 248 deletions(-)
create mode 100644 src/oj/problem/components/SubmissionResult.vue
create mode 100644 src/oj/problem/composables/useSubmissionMonitor.ts
diff --git a/src/oj/problem/components/SubmissionResult.vue b/src/oj/problem/components/SubmissionResult.vue
new file mode 100644
index 0000000..d207772
--- /dev/null
+++ b/src/oj/problem/components/SubmissionResult.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+ {{ msg }}
+
+
+
+
+
+
+
diff --git a/src/oj/problem/components/Submit.vue b/src/oj/problem/components/Submit.vue
index 0db1e2f..fc669a2 100644
--- a/src/oj/problem/components/Submit.vue
+++ b/src/oj/problem/components/Submit.vue
@@ -1,213 +1,88 @@
+
-
-
-
+
{{ submitLabel }}
-
-
-
-
- {{ msg }}
-
-
+
+
+
+
+
-
diff --git a/src/oj/problem/composables/useSubmissionMonitor.ts b/src/oj/problem/composables/useSubmissionMonitor.ts
new file mode 100644
index 0000000..4344d56
--- /dev/null
+++ b/src/oj/problem/composables/useSubmissionMonitor.ts
@@ -0,0 +1,172 @@
+import { ref } from "vue"
+import { getSubmission } from "oj/api"
+import { SubmissionStatus } from "utils/constants"
+import type { Submission } from "utils/types"
+import {
+ useSubmissionWebSocket,
+ type SubmissionUpdate,
+} from "shared/composables/websocket"
+
+/**
+ * 判题监控 Composable
+ * 负责通过 WebSocket + 轮询双保险机制监控判题结果
+ */
+export function useSubmissionMonitor() {
+ // ==================== 状态 ====================
+ const submissionId = ref("")
+ const submission = ref()
+
+ // ==================== 轮询机制 ====================
+ const { pause: pausePolling, resume: resumePolling } = useIntervalFn(
+ async () => {
+ if (!submissionId.value) return
+
+ try {
+ const res = await getSubmission(submissionId.value)
+ submission.value = res.data
+
+ const result = res.data.result
+ // 判题完成,停止轮询
+ if (
+ result !== SubmissionStatus.judging &&
+ result !== SubmissionStatus.pending
+ ) {
+ pausePolling()
+ }
+ } catch (error) {
+ console.error("[SubmissionMonitor] 轮询失败:", error)
+ pausePolling()
+ }
+ },
+ 2000,
+ { immediate: false }
+ )
+
+ // ==================== WebSocket 处理 ====================
+ const handleSubmissionUpdate = (data: SubmissionUpdate) => {
+ console.log("[SubmissionMonitor] 收到WebSocket更新:", data)
+
+ if (data.submission_id !== submissionId.value) {
+ console.log("[SubmissionMonitor] 提交ID不匹配,忽略")
+ return
+ }
+
+ if (!submission.value) {
+ submission.value = {} as Submission
+ }
+
+ submission.value.result = data.result as Submission["result"]
+
+ // 判题完成或出错,获取完整详情
+ if (data.status === "finished" || data.status === "error") {
+ console.log(
+ `[SubmissionMonitor] 判题${data.status === "finished" ? "完成" : "出错"}`
+ )
+
+ // 停止轮询(WebSocket已成功)
+ pausePolling()
+
+ getSubmission(submissionId.value).then((res) => {
+ submission.value = res.data
+ // 15分钟无新提交则断开WebSocket(节省资源)
+ scheduleDisconnect(15 * 60 * 1000)
+ })
+ }
+ }
+
+ // 初始化 WebSocket
+ const {
+ connect,
+ subscribe,
+ scheduleDisconnect,
+ cancelScheduledDisconnect,
+ status: wsStatus,
+ } = useSubmissionWebSocket(handleSubmissionUpdate)
+
+ // ==================== 轮询保底启动 ====================
+ const { start: startPollingFallback } = useTimeoutFn(
+ () => {
+ if (
+ submission.value &&
+ (submission.value.result === SubmissionStatus.judging ||
+ submission.value.result === SubmissionStatus.pending ||
+ submission.value.result === 9) // 9 = submitting
+ ) {
+ console.log("[SubmissionMonitor] WebSocket未及时响应,启动轮询保底")
+ resumePolling()
+ }
+ },
+ 5000,
+ { immediate: false }
+ )
+
+ // ==================== 启动监控 ====================
+ const startMonitoring = (id: string) => {
+ submissionId.value = id
+ submission.value = { result: 9 } as Submission // 9 = submitting
+
+ // 取消之前的断开计划
+ cancelScheduledDisconnect()
+
+ // 如果WebSocket未连接,先连接
+ if (wsStatus.value !== "connected") {
+ console.log("[SubmissionMonitor] 启动WebSocket连接...")
+ connect()
+ }
+
+ // 等待WebSocket连接并订阅
+ const unwatch = watch(
+ wsStatus,
+ (status) => {
+ if (status === "connected") {
+ console.log("[SubmissionMonitor] WebSocket已连接,订阅提交:", id)
+ subscribe(id)
+ unwatch() // 订阅成功后停止监听
+ }
+ },
+ { immediate: true }
+ )
+
+ // 5秒后启动轮询保底(防止WebSocket失败)
+ startPollingFallback()
+ }
+
+ // ==================== 计算属性 ====================
+ const judging = computed(
+ () => submission.value?.result === SubmissionStatus.judging
+ )
+
+ const pending = computed(
+ () => submission.value?.result === SubmissionStatus.pending
+ )
+
+ const submitting = computed(
+ () => submission.value?.result === SubmissionStatus.submitting
+ )
+
+ const isProcessing = computed(() => {
+ return judging.value || pending.value || submitting.value
+ })
+
+ // ==================== 清理 ====================
+ onUnmounted(() => {
+ pausePolling()
+ })
+
+ return {
+ // 状态
+ submissionId,
+ submission,
+
+ // 计算属性
+ judging,
+ pending,
+ submitting,
+ isProcessing,
+
+ // 方法
+ startMonitoring,
+ pausePolling,
+ }
+}
+