From 5f39ec4fd2e2fd1210553f166f62cf5c758cadc2 Mon Sep 17 00:00:00 2001
From: xuyue <517252939@qq.com>
Date: Thu, 9 Feb 2023 20:23:11 +0800
Subject: [PATCH] add contest rank.
---
src/oj/api.ts | 13 ++
src/oj/contest/components/AcAndSubmission.vue | 12 ++
src/oj/contest/pages/rank.vue | 170 +++++++++++++++++-
src/oj/rank/components/Chart.vue | 2 +-
src/oj/rank/list.vue | 6 +-
src/oj/submission/detail.vue | 2 +-
src/shared/Pagination.vue | 8 +-
src/utils/functions.ts | 10 ++
src/utils/types.ts | 43 +++--
9 files changed, 243 insertions(+), 23 deletions(-)
create mode 100644 src/oj/contest/components/AcAndSubmission.vue
diff --git a/src/oj/api.ts b/src/oj/api.ts
index 2cf8580..f7091df 100644
--- a/src/oj/api.ts
+++ b/src/oj/api.ts
@@ -10,6 +10,7 @@ import {
function filterResult(result: Problem) {
const newResult = {
+ id: result.id,
_id: result._id,
title: result.title,
difficulty: DIFFICULTY[result.difficulty],
@@ -131,3 +132,15 @@ export async function getContestProblems(contestID: string) {
})
return res.data.map(filterResult)
}
+
+export function getContestRank(
+ contestID: string,
+ query: { limit: number; offset: number }
+) {
+ return http.get("contest_rank", {
+ params: {
+ contest_id: contestID,
+ ...query,
+ },
+ })
+}
diff --git a/src/oj/contest/components/AcAndSubmission.vue b/src/oj/contest/components/AcAndSubmission.vue
new file mode 100644
index 0000000..8a14a4c
--- /dev/null
+++ b/src/oj/contest/components/AcAndSubmission.vue
@@ -0,0 +1,12 @@
+
+
+
+ {{ rank.accepted_number }} /
+ {{ rank.submission_number }}
+
+
+
diff --git a/src/oj/contest/pages/rank.vue b/src/oj/contest/pages/rank.vue
index b0b0c66..50a8ec5 100644
--- a/src/oj/contest/pages/rank.vue
+++ b/src/oj/contest/pages/rank.vue
@@ -1,5 +1,171 @@
-
+
+
+
+
+
+
diff --git a/src/oj/rank/components/Chart.vue b/src/oj/rank/components/Chart.vue
index 879b4d7..88c723b 100644
--- a/src/oj/rank/components/Chart.vue
+++ b/src/oj/rank/components/Chart.vue
@@ -71,7 +71,7 @@ const data = computed(() => ({
const options = ref({
plugins: {
title: {
- text: "全校前十名的提交者(不包括超管)",
+ text: "全校前十名的用户(不包括超管)",
display: true,
font: { size: 20 },
},
diff --git a/src/oj/rank/list.vue b/src/oj/rank/list.vue
index 62c89e4..f42ed5a 100644
--- a/src/oj/rank/list.vue
+++ b/src/oj/rank/list.vue
@@ -12,7 +12,7 @@ const query = reactive({
limit: 10,
page: 1,
})
-const rankData = ref([])
+const chart = ref([])
async function listRanks() {
const offset = (query.page - 1) * query.limit
@@ -20,7 +20,7 @@ async function listRanks() {
data.value = res.data.results
total.value = res.data.total
if (query.page === 1) {
- rankData.value = data.value
+ chart.value = data.value
}
}
@@ -67,7 +67,7 @@ onMounted(listRanks)
-
+
提交时间:{{ parseTime(submission.create_time) }}
语言:{{ submission.language }}
- 用户 {{ submission.username }}
+ 用户:{{ submission.username }}
diff --git a/src/shared/Pagination.vue b/src/shared/Pagination.vue
index 2b6711b..7cf9e3e 100644
--- a/src/shared/Pagination.vue
+++ b/src/shared/Pagination.vue
@@ -14,8 +14,14 @@ const props = withDefaults(defineProps(), {
const emit = defineEmits(["update:limit", "update:page"])
+const route = useRoute()
+
const limit = ref(props.limit)
const page = ref(props.page)
+const sizes = computed(() => {
+ if (route.name === "contest rank") return [10, 30, 50]
+ return [10, 20, 30]
+})
watch(limit, () => emit("update:limit", limit))
watch(page, () => emit("update:page", page))
@@ -28,7 +34,7 @@ watch(page, () => emit("update:page", page))
:item-count="props.total"
v-model:page="page"
v-model:page-size="limit"
- :page-sizes="[10, 20, 30]"
+ :page-sizes="sizes"
:page-slot="isDesktop ? 7 : 5"
show-size-picker
/>
diff --git a/src/utils/functions.ts b/src/utils/functions.ts
index 4eeec94..f0f54bb 100644
--- a/src/utils/functions.ts
+++ b/src/utils/functions.ts
@@ -65,6 +65,16 @@ export function duration(start: Date, end: Date): string {
return result
}
+export function secondsToDuration(seconds: number): string {
+ const epoch = new Date(0)
+ const secondsAfterEpoch = new Date(seconds * 1000)
+ const duration = intervalToDuration({
+ start: epoch,
+ end: secondsAfterEpoch,
+ })
+ return [duration.hours, duration.minutes, duration.seconds].join(":")
+}
+
export function submissionMemoryFormat(memory: number | string | undefined) {
if (memory === undefined) return "--"
// 1048576 = 1024 * 1024
diff --git a/src/utils/types.ts b/src/utils/types.ts
index 75bd410..8c44943 100644
--- a/src/utils/types.ts
+++ b/src/utils/types.ts
@@ -59,15 +59,17 @@ export type SUBMISSION_RESULT = -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
export type ProblemStatus = "passed" | "failed" | "not_test"
+interface SampleUser {
+ id: number
+ username: string
+ real_name: string | null
+}
+
export interface Problem {
_id: string
id: number
tags: string[]
- created_by: {
- id: number
- username: string
- real_name: null
- }
+ created_by: SampleUser
template: { [key in LANGUAGE]?: string }
title: string
description: string
@@ -104,6 +106,7 @@ export interface Problem {
export interface ProblemFiltered {
_id: string
+ id: number
title: string
difficulty: "简单" | "中等" | "困难"
tags: string[]
@@ -177,11 +180,7 @@ export interface SubmissionListPayload {
export interface Rank {
id: number
- user: {
- id: number
- username: string
- real_name: null
- }
+ user: SampleUser
acm_problems_status: {
problems: {
[key: string]: {
@@ -214,11 +213,7 @@ export interface Rank {
export interface Contest {
id: number
- created_by: {
- id: number
- username: string
- real_name: null
- }
+ created_by: SampleUser
status: ContestStatus
contest_type: ContestType
title: string
@@ -230,3 +225,21 @@ export interface Contest {
create_time: Date
last_update_time: Date
}
+
+interface SubmissionInfo {
+ is_ac: boolean
+ ac_time: number
+ is_first_ac: boolean
+ error_number: number
+ checked?: boolean
+}
+
+export interface ContestRank {
+ id: number
+ user: SampleUser
+ submission_number: number
+ accepted_number: number
+ total_time: number
+ submission_info: { [key: string]: SubmissionInfo }
+ contest: number
+}