Compare commits
2 Commits
bc0b782443
...
47a43b9880
| Author | SHA1 | Date | |
|---|---|---|---|
| 47a43b9880 | |||
| 6ac458e6f3 |
@@ -57,7 +57,7 @@ export async function evaluateFlowchart(job: FlowchartJobData) {
|
||||
}).where(eq(schema.flowchartSubmission.id, row.flowchart.id))
|
||||
await publishFlowchartUpdate(row.flowchart.userId, flowchartUpdateSchema.parse({
|
||||
type: "flowchart_evaluation_completed",
|
||||
submission_id: row.flowchart.id,
|
||||
submissionId: row.flowchart.id,
|
||||
score: result.score,
|
||||
grade: result.grade,
|
||||
feedback: result.feedback,
|
||||
@@ -69,7 +69,7 @@ export async function evaluateFlowchart(job: FlowchartJobData) {
|
||||
await db.update(schema.flowchartSubmission).set({ status: 3 }).where(eq(schema.flowchartSubmission.id, row.flowchart.id))
|
||||
await publishFlowchartUpdate(row.flowchart.userId, flowchartUpdateSchema.parse({
|
||||
type: "flowchart_evaluation_failed",
|
||||
submission_id: row.flowchart.id,
|
||||
submissionId: row.flowchart.id,
|
||||
error: message,
|
||||
}))
|
||||
throw error
|
||||
|
||||
@@ -317,10 +317,9 @@ async function markSystemError(submissionId: string, userId: number, error: unkn
|
||||
if (updated.length > 0) {
|
||||
await publishSubmissionUpdate(userId, {
|
||||
type: "submission_update",
|
||||
submission_id: submissionId,
|
||||
submissionId,
|
||||
result: JudgeStatus.SYSTEM_ERROR,
|
||||
status: "error",
|
||||
err_info: message,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -353,7 +352,7 @@ export async function judgeSubmission(job: JudgeJobData) {
|
||||
.where(eq(schema.submission.id, row.submission.id))
|
||||
await publishSubmissionUpdate(row.submission.userId, {
|
||||
type: "submission_update",
|
||||
submission_id: row.submission.id,
|
||||
submissionId: row.submission.id,
|
||||
result: JudgeStatus.JUDGING,
|
||||
status: "judging",
|
||||
})
|
||||
@@ -463,17 +462,9 @@ export async function judgeSubmission(job: JudgeJobData) {
|
||||
|
||||
await publishSubmissionUpdate(row.submission.userId, {
|
||||
type: "submission_update",
|
||||
submission_id: row.submission.id,
|
||||
submissionId: row.submission.id,
|
||||
result,
|
||||
status: "finished",
|
||||
time_cost:
|
||||
typeof statisticInfo.time_cost === "number"
|
||||
? statisticInfo.time_cost
|
||||
: undefined,
|
||||
memory_cost:
|
||||
typeof statisticInfo.memory_cost === "number"
|
||||
? statisticInfo.memory_cost
|
||||
: undefined,
|
||||
score:
|
||||
typeof statisticInfo.score === "number" ? statisticInfo.score : undefined,
|
||||
})
|
||||
|
||||
@@ -67,7 +67,7 @@ async function handleMessage(
|
||||
return
|
||||
}
|
||||
|
||||
let message: { type?: unknown; timestamp?: unknown; submission_id?: unknown }
|
||||
let message: { type?: unknown; timestamp?: unknown; submissionId?: unknown }
|
||||
try {
|
||||
message = JSON.parse(raw) as typeof message
|
||||
} catch {
|
||||
@@ -79,7 +79,7 @@ async function handleMessage(
|
||||
ws.send(JSON.stringify({ type: "pong", timestamp: message.timestamp }))
|
||||
return
|
||||
}
|
||||
if (message.type !== "subscribe" || typeof message.submission_id !== "string") {
|
||||
if (message.type !== "subscribe" || typeof message.submissionId !== "string") {
|
||||
ws.send(JSON.stringify({ type: "error", message: "Invalid message" }))
|
||||
return
|
||||
}
|
||||
@@ -93,7 +93,7 @@ async function handleMessage(
|
||||
.from(schema.submission)
|
||||
.where(
|
||||
and(
|
||||
eq(schema.submission.id, message.submission_id),
|
||||
eq(schema.submission.id, message.submissionId),
|
||||
eq(schema.submission.userId, ws.data.userId),
|
||||
),
|
||||
)
|
||||
@@ -103,17 +103,17 @@ async function handleMessage(
|
||||
const [flowchart] = await db
|
||||
.select({ id: schema.flowchartSubmission.id, status: schema.flowchartSubmission.status, score: schema.flowchartSubmission.aiScore, grade: schema.flowchartSubmission.aiGrade })
|
||||
.from(schema.flowchartSubmission)
|
||||
.where(and(eq(schema.flowchartSubmission.id, message.submission_id), eq(schema.flowchartSubmission.userId, ws.data.userId)))
|
||||
.where(and(eq(schema.flowchartSubmission.id, message.submissionId), eq(schema.flowchartSubmission.userId, ws.data.userId)))
|
||||
.limit(1)
|
||||
if (!flowchart) {
|
||||
ws.send(JSON.stringify({ type: "error", message: "Submission not found" }))
|
||||
return
|
||||
}
|
||||
const replay = flowchart.status === 2
|
||||
? { type: "flowchart_evaluation_completed", submission_id: flowchart.id, score: flowchart.score ?? undefined, grade: flowchart.grade ?? undefined }
|
||||
? { type: "flowchart_evaluation_completed", submissionId: flowchart.id, score: flowchart.score ?? undefined, grade: flowchart.grade ?? undefined }
|
||||
: flowchart.status === 3
|
||||
? { type: "flowchart_evaluation_failed", submission_id: flowchart.id, error: "Evaluation failed" }
|
||||
: { type: "flowchart_evaluation_update", submission_id: flowchart.id }
|
||||
? { type: "flowchart_evaluation_failed", submissionId: flowchart.id, error: "Evaluation failed" }
|
||||
: { type: "flowchart_evaluation_update", submissionId: flowchart.id }
|
||||
ws.send(JSON.stringify(flowchartUpdateSchema.parse(replay)))
|
||||
return
|
||||
}
|
||||
@@ -129,13 +129,10 @@ async function handleMessage(
|
||||
: "finished"
|
||||
const parsed = submissionUpdateSchema.safeParse({
|
||||
type: "submission_update",
|
||||
submission_id: submission.id,
|
||||
submissionId: submission.id,
|
||||
result: submission.result,
|
||||
status,
|
||||
time_cost: statistics.time_cost,
|
||||
memory_cost: statistics.memory_cost,
|
||||
score: statistics.score,
|
||||
err_info: statistics.err_info,
|
||||
})
|
||||
if (parsed.success) ws.send(JSON.stringify(parsed.data))
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ export function useSubmissionMonitor() {
|
||||
|
||||
console.log("[SubmissionMonitor] 收到WebSocket更新:", data)
|
||||
|
||||
if (data.submission_id !== submissionId.value) {
|
||||
if (data.submissionId !== submissionId.value) {
|
||||
console.log("[SubmissionMonitor] 提交ID不匹配,忽略")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -64,6 +64,31 @@ const todayCount = ref(0)
|
||||
// 没有它的话,等接口这段时间表格就是一片空白,连转圈都没有
|
||||
const loading = ref(false)
|
||||
|
||||
/**
|
||||
* 转圈圈延迟出现。翻页、切筛选大多在一百毫秒内就回来了,直接切数据比「闪一下
|
||||
* 转圈再切」看着稳;只有真的慢到 300ms 以上才值得给个反馈。
|
||||
*
|
||||
* 注意是**单向**延迟:只推迟「显示」,一旦请求结束立刻收掉,不留尾巴。
|
||||
*
|
||||
* 为什么不用 n-spin 的 delay:n-data-table 压根不走 n-spin,它渲染的是内部的
|
||||
* _internal/loading,直接由 loading 控制、没有 delay 参数。要用内置的就得把表格
|
||||
* 包进 <n-spin :show :delay> 再去掉 :loading —— 那会换掉加载样式,还会丢掉
|
||||
* loading 时锁住排序/分页交互(DataTable 里那个 `disabled: this.loading`)。
|
||||
* 下面这几行就是 n-spin 内部同样的写法(watchEffect + setTimeout + 清理)。
|
||||
*/
|
||||
const LOADING_DELAY = 300
|
||||
const showLoading = ref(false)
|
||||
let loadingTimer: ReturnType<typeof setTimeout> | undefined
|
||||
watch(loading, (value) => {
|
||||
clearTimeout(loadingTimer)
|
||||
if (!value) {
|
||||
showLoading.value = false
|
||||
return
|
||||
}
|
||||
loadingTimer = setTimeout(() => (showLoading.value = true), LOADING_DELAY)
|
||||
})
|
||||
onUnmounted(() => clearTimeout(loadingTimer))
|
||||
|
||||
// 使用分页 composable
|
||||
const { query, clearQuery } = usePagination<SubmissionQuery>({
|
||||
username: useRouteQuery("username", "").value,
|
||||
@@ -506,14 +531,14 @@ const flowchartColumns = computed(() => {
|
||||
:bordered="false"
|
||||
:columns="flowchartColumns"
|
||||
:data="flowcharts"
|
||||
:loading="loading"
|
||||
:loading="showLoading"
|
||||
/>
|
||||
<n-data-table
|
||||
v-else
|
||||
:bordered="false"
|
||||
:columns="columns"
|
||||
:data="submissions"
|
||||
:loading="loading"
|
||||
:loading="showLoading"
|
||||
/>
|
||||
</n-flex>
|
||||
<Pagination
|
||||
|
||||
@@ -287,13 +287,10 @@ export class BaseWebSocket<T extends WebSocketMessage = WebSocketMessage> {
|
||||
*/
|
||||
export interface SubmissionUpdate extends WebSocketMessage {
|
||||
type: "submission_update"
|
||||
submission_id: string
|
||||
submissionId: string
|
||||
result: number
|
||||
status: "pending" | "judging" | "finished" | "error"
|
||||
time_cost?: number
|
||||
memory_cost?: number
|
||||
score?: number
|
||||
err_info?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,7 +311,7 @@ class SubmissionWebSocket extends BaseWebSocket<SubmissionUpdate> {
|
||||
this.pendingSubmissionId = submissionId
|
||||
const success = this.send({
|
||||
type: "subscribe",
|
||||
submission_id: submissionId,
|
||||
submissionId,
|
||||
})
|
||||
if (success) this.pendingSubmissionId = ""
|
||||
}
|
||||
@@ -325,7 +322,7 @@ class SubmissionWebSocket extends BaseWebSocket<SubmissionUpdate> {
|
||||
if (
|
||||
this.send({
|
||||
type: "subscribe",
|
||||
submission_id: submissionId,
|
||||
submissionId,
|
||||
})
|
||||
) {
|
||||
this.pendingSubmissionId = ""
|
||||
@@ -429,7 +426,7 @@ export interface FlowchartEvaluationUpdate extends WebSocketMessage {
|
||||
| "flowchart_evaluation_completed"
|
||||
| "flowchart_evaluation_failed"
|
||||
| "flowchart_evaluation_update"
|
||||
submission_id: string
|
||||
submissionId: string
|
||||
score?: number
|
||||
grade?: string
|
||||
feedback?: string
|
||||
@@ -453,7 +450,7 @@ class FlowchartWebSocket extends BaseWebSocket<FlowchartEvaluationUpdate> {
|
||||
subscribe(submissionId: string) {
|
||||
const success = this.send({
|
||||
type: "subscribe",
|
||||
submission_id: submissionId,
|
||||
submissionId,
|
||||
})
|
||||
if (!success) {
|
||||
console.error("[Flowchart WebSocket] 订阅失败: 连接未就绪")
|
||||
|
||||
@@ -78,7 +78,7 @@ export const flowchartUpdateSchema = z.object({
|
||||
"flowchart_evaluation_failed",
|
||||
"flowchart_evaluation_update",
|
||||
]),
|
||||
submission_id: z.string(),
|
||||
submissionId: z.string(),
|
||||
score: z.number().optional(),
|
||||
grade: z.string().optional(),
|
||||
feedback: z.string().optional(),
|
||||
|
||||
@@ -68,15 +68,20 @@ export const embeddedSubmissionSchema = submissionDetailSchema
|
||||
// 站内信页面拿它拼 `/problem/<题号>` 链接,给数字 id 会拼出打不开的地址。
|
||||
.extend({ problem: z.string() })
|
||||
|
||||
/**
|
||||
* 判题进度推送。**只带前端真正要用的东西**:靠 submissionId 认领、靠 result /
|
||||
* status 决定是继续等还是去拉详情。
|
||||
*
|
||||
* 这里曾经还带着 time_cost / memory_cost / err_info —— 从 statistic_info 原样
|
||||
* 抄一份出来,前端一处都没读过。耗时和错误信息在提交详情里本来就有,判完了去
|
||||
* 拉一次就是了,不必让推送顺带背一份 JSONB 的形状。
|
||||
*/
|
||||
export const submissionUpdateSchema = z.object({
|
||||
type: z.literal("submission_update"),
|
||||
submission_id: z.string(),
|
||||
submissionId: z.string(),
|
||||
result: judgeStatusSchema,
|
||||
status: z.enum(["pending", "judging", "finished", "error"]),
|
||||
time_cost: z.number().optional(),
|
||||
memory_cost: z.number().optional(),
|
||||
score: z.number().optional(),
|
||||
err_info: z.string().optional(),
|
||||
})
|
||||
|
||||
export const submissionListItemSchema = z.object({
|
||||
|
||||
Reference in New Issue
Block a user