diff --git a/src/oj/api.ts b/src/oj/api.ts index e0e30d3..d6449ea 100644 --- a/src/oj/api.ts +++ b/src/oj/api.ts @@ -341,9 +341,21 @@ export function joinProblemSet(problemSetId: number) { export function updateProblemSetProgress( problemSetId: number, problemId: number, + submissionId: string, ) { return http.put("problemset/progress", { problemset_id: problemSetId, problem_id: problemId, + submission_id: submissionId, }) } + +// 获取用户徽章列表 +export function getUserBadges() { + return http.get("user/badges") +} + +// 获取题单徽章列表 +export function getProblemSetBadges(problemSetId: number) { + return http.get(`problemset/${problemSetId}/badges`) +} diff --git a/src/oj/problem/components/SubmitCode.vue b/src/oj/problem/components/SubmitCode.vue index 51f67e8..fc438b9 100644 --- a/src/oj/problem/components/SubmitCode.vue +++ b/src/oj/problem/components/SubmitCode.vue @@ -101,10 +101,6 @@ async function submit() { if (contestID) { data.contest_id = parseInt(contestID) } - if (problemSetId) { - data.problemset_id = parseInt(problemSetId) - } - // 2. 提交代码到后端 const res = await submitCode(data) console.log(`[Submit] 代码已提交: ID=${res.data.submission_id}`) @@ -123,11 +119,14 @@ watch( // 1. 刷新题目状态 problem.value!.my_status = 0 - // 2. 更新题单进度 + // 2. 创建ProblemSetSubmission记录,更新题单进度 if (problemSetId) { - console.log(problemSetId, "problemSetId") try { - await updateProblemSetProgress(Number(problemSetId), problem.value!.id) + await updateProblemSetProgress( + Number(problemSetId), + problem.value!.id, + submission.value!.id, + ) } catch (error) { console.error("更新题单进度失败:", error) } diff --git a/src/oj/problem/detail.vue b/src/oj/problem/detail.vue index 8b279a8..c4d9807 100644 --- a/src/oj/problem/detail.vue +++ b/src/oj/problem/detail.vue @@ -33,12 +33,12 @@ const ProblemFlowchart = defineAsyncComponent( interface Props { problemID: string contestID?: string - problemSetID?: string + problemSetId?: string } const props = withDefaults(defineProps(), { contestID: "", - problemSetID: "", + problemSetId: "", }) const errMsg = ref("无数据") diff --git a/src/oj/problemset/detail.vue b/src/oj/problemset/detail.vue index c64ea52..11e76cb 100644 --- a/src/oj/problemset/detail.vue +++ b/src/oj/problemset/detail.vue @@ -4,12 +4,13 @@ import { getProblemSetDetail, getProblemSetProblems, joinProblemSet, + getUserBadges, } from "../api" import { getTagColor, getACRate } from "utils/functions" -import { ProblemSet, ProblemSetProblem } from "utils/types" -import ProblemStatus from "../problem/components/ProblemStatus.vue" +import { ProblemSet, ProblemSetProblem, UserBadge as UserBadgeType } from "utils/types" import { DIFFICULTY } from "utils/constants" import { useBreakpoints } from "shared/composables/breakpoints" +import UserBadge from "shared/components/UserBadge.vue" const route = useRoute() const router = useRouter() @@ -23,6 +24,8 @@ const problemSet = ref(null) const problems = ref([]) const isJoined = ref(false) const isJoining = ref(false) +const userBadges = ref([]) +const isLoadingBadges = ref(false) // 刷新题单详情的函数 async function refreshProblemSetDetail() { @@ -50,22 +53,9 @@ function getDifficultyTag(difficulty: string) { } function goToProblem(problemId: string) { - // 使用新的路由结构:/problemset/{id}/problem/{problem_id} router.push(`/problemset/${problemSetId.value}/problem/${problemId}`) } -function getProblemStatus( - myStatus: number | null | undefined, -): "not_test" | "passed" | "failed" { - if (myStatus === null || myStatus === undefined) { - return "not_test" - } else if (myStatus === 0) { - return "passed" - } else { - return "failed" - } -} - function getProgressPercentage() { if (!problemSet.value) return 0 return Math.round( @@ -93,6 +83,23 @@ async function loadProblems() { } } +async function loadUserBadges() { + if (!isJoined.value) return + + isLoadingBadges.value = true + try { + const res = await getUserBadges() + // 只显示当前题单的徽章 + userBadges.value = res.data.filter((badge: UserBadgeType) => + badge.badge.problemset === problemSetId.value + ) + } catch (err: any) { + console.error("加载用户徽章失败:", err) + } finally { + isLoadingBadges.value = false + } +} + async function handleJoinProblemSet() { if (isJoining.value) return @@ -101,8 +108,8 @@ async function handleJoinProblemSet() { await joinProblemSet(problemSetId.value) isJoined.value = true message.success("成功加入题单!") - // 不需要重新加载详情,因为我们已经更新了本地状态 - // await loadProblemSetDetail() + // 加入题单后加载用户徽章 + await loadUserBadges() } catch (err: any) { message.error("加入题单失败:" + (err.data || "未知错误")) } finally { @@ -112,6 +119,10 @@ async function handleJoinProblemSet() { onMounted(async () => { await Promise.all([loadProblemSetDetail(), loadProblems()]) + // 如果已加入题单,加载用户徽章 + if (isJoined.value) { + await loadUserBadges() + } }) // 监听路由变化,当从题单题目页面返回时刷新题单详情 @@ -125,6 +136,8 @@ watch( isJoined.value ) { refreshProblemSetDetail() + // 刷新用户徽章 + loadUserBadges() } }, ) @@ -152,13 +165,15 @@ watch( - + + 完成进度 {{ problemSet.completed_count }} / {{ problemSet.problems_count }} + + + + + + + + - - - #{{ index + 1 }}. + + - - - - {{ DIFFICULTY[problemSetProblem.problem.difficulty] }} - - - {{ problemSetProblem.problem.title }} - - - - - - 分数:{{ problemSetProblem.score }} - - (选做) - - 通过率 - {{ - getACRate( - problemSetProblem.problem.accepted_number, - problemSetProblem.problem.submission_number, - ) - }} - - + + + #{{ index + 1 }} + + + {{ problemSetProblem.problem.title }} + - - - - - - + + + {{ DIFFICULTY[problemSetProblem.problem.difficulty] }} + + + 分数:{{ problemSetProblem.score }} + + + (选做) + + diff --git a/src/shared/components/UserBadge.vue b/src/shared/components/UserBadge.vue new file mode 100644 index 0000000..e7bdced --- /dev/null +++ b/src/shared/components/UserBadge.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/src/utils/types.ts b/src/utils/types.ts index f524d7f..0ddf1df 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -231,6 +231,7 @@ export interface ProblemSetProblem { is_required: boolean score: number hint: string + is_completed: boolean } export interface ProblemSetBadge { @@ -243,6 +244,13 @@ export interface ProblemSetBadge { condition_value: number } +export interface UserBadge { + id: number + user: number + badge: ProblemSetBadge + earned_time: Date +} + export interface ProblemSetProgress { id: number problemset: ProblemSetList @@ -280,7 +288,6 @@ export interface SubmitCodePayload { language: LANGUAGE code: string contest_id?: number - problemset_id?: number } // ==================== 流程图相关类型 ====================