fmt
Some checks failed
Deploy / deploy (build, debian, 22, /root/OJDeploy/data/clientnext) (push) Has been cancelled
Deploy / deploy (build:staging, school, 8822, /root/OJ/data/dist) (push) Has been cancelled

This commit is contained in:
2026-07-03 09:59:15 -06:00
parent 47281029ec
commit 1cac0d01f8
10 changed files with 79 additions and 44 deletions

View File

@@ -871,7 +871,10 @@ const radarChartOptions = {
class="stat-avg-ac"
>
<template #suffix>
<Icon icon="streamline-ultimate-color:analytics-pie-2" width="20" />
<Icon
icon="streamline-ultimate-color:analytics-pie-2"
width="20"
/>
</template>
</n-statistic>
</n-gi>
@@ -883,7 +886,10 @@ const radarChartOptions = {
class="stat-median-ac"
>
<template #suffix>
<Icon icon="streamline-ultimate-color:cursor-target-1" width="20" />
<Icon
icon="streamline-ultimate-color:cursor-target-1"
width="20"
/>
</template>
</n-statistic>
</n-gi>
@@ -895,7 +901,10 @@ const radarChartOptions = {
class="stat-total-submission"
>
<template #suffix>
<Icon icon="streamline-ultimate-color:common-file-text" width="20" />
<Icon
icon="streamline-ultimate-color:common-file-text"
width="20"
/>
</template>
</n-statistic>
</n-gi>

View File

@@ -1,8 +1,7 @@
import type { Exercise } from "utils/types"
type Segment =
| { type: "md"; content: string }
| { type: "exercise"; exercise: Exercise }
{ type: "md"; content: string } | { type: "exercise"; exercise: Exercise }
export function parseExercises(
content: string,

View File

@@ -195,13 +195,6 @@ onMounted(() => {
/>
</template>
<IconButton
v-if="isDesktop && userStore.isSuperAdmin"
icon="streamline-ultimate-color:common-file-edit"
tip="编辑题目"
@click="goEdit"
/>
<template v-if="showSyncFeature">
<IconButton
:icon="
@@ -231,6 +224,13 @@ onMounted(() => {
</n-tag>
</template>
</template>
<IconButton
v-if="isDesktop && userStore.isSuperAdmin"
icon="streamline-ultimate-color:common-file-edit"
tip="编辑题目"
@click="goEdit"
/>
</n-flex>
<n-modal

View File

@@ -77,10 +77,7 @@ const columns: DataTableColumn<Submission>[] = [
render: (row) => h(SubmissionResultTag, { result: row.result }),
},
{
title: renderTableTitle(
"语言",
"streamline-ultimate-color:earth-pin-2",
),
title: renderTableTitle("语言", "streamline-ultimate-color:earth-pin-2"),
key: "language",
width: 100,
render: (row) => LANGUAGE_SHOW_VALUE[row.language],

View File

@@ -160,12 +160,18 @@ const baseColumns: DataTableColumn<ProblemFiltered>[] = [
render: (row) => h(ProblemStatus, { status: row.status }),
},
{
title: renderTableTitle("编号", "streamline-ultimate-color:board-game-dice-1"),
title: renderTableTitle(
"编号",
"streamline-ultimate-color:board-game-dice-1",
),
key: "_id",
width: 100,
},
{
title: renderTableTitle("题目", "streamline-ultimate-color:fruit-watermelon"),
title: renderTableTitle(
"题目",
"streamline-ultimate-color:fruit-watermelon",
),
key: "title",
minWidth: 200,
render: (row) => h(ProblemListTitle, { problem: row }),

View File

@@ -110,7 +110,11 @@ async function analyzeSingleClassWithAI() {
if (event === "end" && !hasStarted) classDetailAiLoading.value = false
},
onMessage(payload) {
const parsed = payload as { type?: string; content?: string; message?: string }
const parsed = payload as {
type?: string
content?: string
message?: string
}
if (parsed.type === "delta" && parsed.content) {
if (!hasStarted) {
hasStarted = true
@@ -221,7 +225,10 @@ const columns: DataTableColumn<Rank>[] = [
align: "center",
},
{
title: renderTableTitle("提交数", "streamline-ultimate-color:space-rocket-earth"),
title: renderTableTitle(
"提交数",
"streamline-ultimate-color:space-rocket-earth",
),
key: "submission_number",
width: 120,
align: "center",
@@ -606,7 +613,10 @@ watch(
class="stat-avg-ac"
>
<template #suffix>
<Icon icon="streamline-ultimate-color:analytics-pie-2" width="20" />
<Icon
icon="streamline-ultimate-color:analytics-pie-2"
width="20"
/>
</template>
</n-statistic>
</n-gi>
@@ -618,7 +628,10 @@ watch(
class="stat-median-ac"
>
<template #suffix>
<Icon icon="streamline-ultimate-color:cursor-target-1" width="20" />
<Icon
icon="streamline-ultimate-color:cursor-target-1"
width="20"
/>
</template>
</n-statistic>
</n-gi>
@@ -630,7 +643,10 @@ watch(
class="stat-total-submission"
>
<template #suffix>
<Icon icon="streamline-ultimate-color:common-file-text" width="20" />
<Icon
icon="streamline-ultimate-color:common-file-text"
width="20"
/>
</template>
</n-statistic>
</n-gi>
@@ -736,7 +752,12 @@ watch(
</n-space>
</n-card>
<n-flex justify="center" align="center" :size="12" style="margin-top: 12px">
<n-flex
justify="center"
align="center"
:size="12"
style="margin-top: 12px"
>
<n-tag type="success" size="large">
综合分: {{ classDetailData.composite_score.toFixed(1) }}
</n-tag>
@@ -769,7 +790,10 @@ watch(
>
<n-spin :show="classDetailAiLoading" :delay="50">
<div style="min-height: 200px">
<MdPreview v-if="classDetailAiContent" :model-value="classDetailAiContent" />
<MdPreview
v-if="classDetailAiContent"
:model-value="classDetailAiContent"
/>
<n-flex
v-else-if="!classDetailAiLoading"
align="center"

View File

@@ -267,10 +267,7 @@ const columns = computed(() => {
),
},
{
title: renderTableTitle(
"语言",
"streamline-ultimate-color:earth-pin-2",
),
title: renderTableTitle("语言", "streamline-ultimate-color:earth-pin-2"),
key: "language",
minWidth: 120,
render: (row) => LANGUAGE_SHOW_VALUE[row.language],
@@ -347,7 +344,10 @@ const flowchartColumns = computed(() => {
),
},
{
title: renderTableTitle("评分", "streamline-ultimate-color:analytics-bars-3d"),
title: renderTableTitle(
"评分",
"streamline-ultimate-color:analytics-bars-3d",
),
key: "ai_score",
render: (row) => h(Grade, { score: row.ai_score, grade: row.ai_grade }),
},

View File

@@ -7,7 +7,11 @@ interface Props {
page: number
}
const { total, limit: initialLimit = 10, page: initialPage = 1 } = defineProps<Props>()
const {
total,
limit: initialLimit = 10,
page: initialPage = 1,
} = defineProps<Props>()
const emit = defineEmits(["update:limit", "update:page"])

View File

@@ -23,27 +23,26 @@ export const SYNC_ERROR_CODES = {
// 界面和通知文案
export const SYNC_MESSAGES = {
// 超管离开
SUPER_ADMIN_LEFT: (name: string) => `👋 超管 ${name} 已离开`,
SUPER_ADMIN_LEFT: (name: string) => `超管 ${name} 已离开`,
// 缺少超管
MISSING_SUPER_ADMIN: "⚠️ 协同编辑需要超管",
MISSING_SUPER_ADMIN: "协同编辑需要超管",
// 连接成功
SYNC_ACTIVE: "协同编辑已激活!",
SYNC_ACTIVE: "协同编辑已激活!",
// 连接断开
CONNECTION_LOST: "⚠️ 协同编辑已断开",
CONNECTION_LOST: "协同编辑已断开",
// 等待相关
WAITING_STUDENT: "正在等待学生加入...",
WAITING_ADMIN: "正在等待超管加入...",
WAITING_STUDENT: "正在等待学生加入...",
WAITING_ADMIN: "正在等待超管加入...",
// Form.vue 界面文案
SYNC_ON: "断开同步",
SYNC_OFF: "开启同步",
SYNCING_WITH: (name: string) => `🔗 ${name} 同步中`,
STUDENT_LEFT: (name?: string) =>
name ? `💡 ${name}已离开` : "💡 可以关闭同步",
SYNCING_WITH: (name: string) => `${name} 同步中`,
STUDENT_LEFT: (name?: string) => (name ? `${name}已离开` : "可以关闭同步"),
} as const
// 类型定义

View File

@@ -4,10 +4,7 @@ import { ref, onUnmounted, type Ref } from "vue"
* WebSocket 连接状态
*/
export type ConnectionStatus =
| "disconnected"
| "connecting"
| "connected"
| "error"
"disconnected" | "connecting" | "connected" | "error"
/**
* WebSocket 消息类型