add leaderboard
Some checks failed
Deploy / deploy (build, debian, 22) (push) Has been cancelled
Deploy / deploy (build:staging, school, 8822) (push) Has been cancelled

This commit is contained in:
2026-03-09 20:00:11 +08:00
parent 9c577f9bc1
commit a7aa4f63ac
8 changed files with 173 additions and 3 deletions

46
src/pages/Leaderboard.vue Normal file
View File

@@ -0,0 +1,46 @@
<template>
<div class="container">
<n-flex justify="space-between" align="center" style="margin-bottom: 16px">
<n-button secondary @click="$router.back()">返回</n-button>
<span style="font-weight: bold; font-size: 18px">排行榜</span>
<div style="width: 60px" />
</n-flex>
<n-data-table :columns="columns" :data="data" :loading="loading" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, h } from "vue"
import { Account } from "../api"
import type { DataTableColumn } from "naive-ui"
const data = ref<{ rank: number; username: string; total_score: number }[]>([])
const loading = ref(false)
const columns: DataTableColumn<(typeof data.value)[0]>[] = [
{ title: "排名", key: "rank", width: 70 },
{ title: "用户名", key: "username" },
{
title: "总分",
key: "total_score",
render: (row) => h("span", { style: "font-weight: bold" }, row.total_score.toFixed(2)),
},
]
onMounted(async () => {
loading.value = true
try {
data.value = await Account.leaderboard()
} finally {
loading.value = false
}
})
</script>
<style scoped>
.container {
max-width: 600px;
margin: 40px auto;
padding: 0 16px;
}
</style>

64
src/pages/MyScores.vue Normal file
View File

@@ -0,0 +1,64 @@
<template>
<div class="container">
<n-flex justify="space-between" align="center" style="margin-bottom: 16px">
<n-button secondary @click="$router.back()">返回</n-button>
<span style="font-weight: bold; font-size: 18px">我的成绩</span>
<div style="width: 60px" />
</n-flex>
<n-empty v-if="!loading && !data.length" description="暂无评分记录" />
<n-data-table v-else :columns="columns" :data="data" :loading="loading" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, h } from "vue"
import { Submission } from "../api"
import type { DataTableColumn } from "naive-ui"
import { parseTime } from "../utils/helper"
type MyScore = {
task_id: number
task_display: number
task_title: string
score: number
created: string
}
const data = ref<MyScore[]>([])
const loading = ref(false)
const columns: DataTableColumn<MyScore>[] = [
{ title: "题号", key: "task_display", width: 70 },
{ title: "标题", key: "task_title" },
{
title: "最高得分",
key: "score",
render: (row) =>
row.score > 0
? h("span", { style: { fontWeight: "bold", color: "#18a058" } }, row.score.toFixed(2))
: h("span", { style: { color: "#999" } }, "未评分"),
},
{
title: "提交时间",
key: "created",
render: (row) => parseTime(row.created, "YYYY-MM-DD HH:mm"),
},
]
onMounted(async () => {
loading.value = true
try {
data.value = await Submission.myScores()
} finally {
loading.value = false
}
})
</script>
<style scoped>
.container {
max-width: 700px;
margin: 40px auto;
padding: 0 16px;
}
</style>

View File

@@ -393,6 +393,8 @@ watch(
init()
},
)
onMounted(init)
onUnmounted(() => {
submission.value = {