1 parent
23844ae301
commit
d25b5dbe6d
268 files changed
+3684
-8861
No files matched your search
@@ -8,11 +8,7 @@ const contestStore = useContestStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-popover
|
||||
v-if="contestStore.contest"
|
||||
placement="bottom-end"
|
||||
:show-arrow="false"
|
||||
>
|
||||
<n-popover v-if="contestStore.contest" placement="bottom-end" :show-arrow="false">
|
||||
<template #trigger>
|
||||
<n-button>
|
||||
<template #icon>
|
||||
|
||||
@@ -35,18 +35,11 @@ const options: DropdownOption[] = [
|
||||
<template>
|
||||
<div v-if="contestMenuVisible">
|
||||
<n-flex v-if="isDesktop">
|
||||
<n-button :type="getCurrentType('problems')" @click="goto('problems')">
|
||||
比赛题目
|
||||
</n-button>
|
||||
<n-button
|
||||
:type="getCurrentType('submissions')"
|
||||
@click="goto('submissions')"
|
||||
>
|
||||
<n-button :type="getCurrentType('problems')" @click="goto('problems')"> 比赛题目 </n-button>
|
||||
<n-button :type="getCurrentType('submissions')" @click="goto('submissions')">
|
||||
提交信息
|
||||
</n-button>
|
||||
<n-button :type="getCurrentType('rank')" @click="goto('rank')">
|
||||
比赛排名
|
||||
</n-button>
|
||||
<n-button :type="getCurrentType('rank')" @click="goto('rank')"> 比赛排名 </n-button>
|
||||
</n-flex>
|
||||
<n-dropdown v-else :options="options" @select="goto">
|
||||
<n-button>菜单</n-button>
|
||||
|
||||
@@ -17,15 +17,7 @@ import {
|
||||
} from "chart.js"
|
||||
import type { ContestRank } from "utils/types"
|
||||
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
)
|
||||
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend)
|
||||
|
||||
interface Props {
|
||||
ranks: ContestRank[]
|
||||
|
||||
@@ -17,10 +17,7 @@ const { isDesktop } = useBreakpoints()
|
||||
const password = ref("")
|
||||
|
||||
async function check() {
|
||||
const error = await contestStore.checkPassword(
|
||||
props.contestID,
|
||||
password.value,
|
||||
)
|
||||
const error = await contestStore.checkPassword(props.contestID, password.value)
|
||||
if (error === "too-many-password-attempts") {
|
||||
message.error("密码错误次数太多,请 10 分钟后再试")
|
||||
} else if (!contestStore.access) {
|
||||
@@ -44,10 +41,7 @@ onMounted(() => {
|
||||
onBeforeUnmount(contestStore.clear)
|
||||
|
||||
const passwordFormVisible = computed(
|
||||
() =>
|
||||
contestStore.isPrivate &&
|
||||
!contestStore.access &&
|
||||
!contestStore.isContestAdmin,
|
||||
() => contestStore.isPrivate && !contestStore.access && !contestStore.isContestAdmin,
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -70,17 +64,9 @@ const passwordFormVisible = computed(
|
||||
<ContestMenu />
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
<n-form
|
||||
:inline="isDesktop"
|
||||
label-placement="left"
|
||||
v-if="passwordFormVisible"
|
||||
>
|
||||
<n-form :inline="isDesktop" label-placement="left" v-if="passwordFormVisible">
|
||||
<n-form-item label="需要输入密码才能看到题目">
|
||||
<n-input
|
||||
name="ContestPassword"
|
||||
type="password"
|
||||
v-model:value="password"
|
||||
/>
|
||||
<n-input name="ContestPassword" type="password" v-model:value="password" />
|
||||
</n-form-item>
|
||||
<n-form-item>
|
||||
<n-button @click="check" :disabled="!password">确认</n-button>
|
||||
|
||||
@@ -134,18 +134,10 @@ function rowProps(row: Contest) {
|
||||
<n-space>
|
||||
<n-form :show-feedback="false" label-placement="left" inline>
|
||||
<n-form-item label="比赛状态">
|
||||
<n-select
|
||||
style="width: 120px"
|
||||
:options="options"
|
||||
v-model:value="query.status"
|
||||
/>
|
||||
<n-select style="width: 120px" :options="options" v-model:value="query.status" />
|
||||
</n-form-item>
|
||||
<n-form-item label="标签">
|
||||
<n-select
|
||||
style="width: 120px"
|
||||
:options="tags"
|
||||
v-model:value="query.tag"
|
||||
/>
|
||||
<n-select style="width: 120px" :options="tags" v-model:value="query.tag" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-form :show-feedback="false" label-placement="left" inline>
|
||||
@@ -165,16 +157,7 @@ function rowProps(row: Contest) {
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-space>
|
||||
<n-data-table
|
||||
:bordered="false"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:row-props="rowProps"
|
||||
/>
|
||||
<n-data-table :bordered="false" :columns="columns" :data="data" :row-props="rowProps" />
|
||||
</n-flex>
|
||||
<Pagination
|
||||
v-model:limit="query.limit"
|
||||
v-model:page="query.page"
|
||||
:total="total"
|
||||
/>
|
||||
<Pagination v-model:limit="query.limit" v-model:page="query.page" :total="total" />
|
||||
</template>
|
||||
@@ -53,10 +53,7 @@ const columns = ref<DataTableColumn<ContestRank>[]>([
|
||||
render: (_, index) => index + (query.page - 1) * query.limit + 1,
|
||||
},
|
||||
{
|
||||
title: renderTableTitle(
|
||||
"用户",
|
||||
"streamline-emojis:smiling-face-with-sunglasses",
|
||||
),
|
||||
title: renderTableTitle("用户", "streamline-emojis:smiling-face-with-sunglasses"),
|
||||
key: "username",
|
||||
width: 120,
|
||||
fixed: "left",
|
||||
@@ -73,10 +70,7 @@ const columns = ref<DataTableColumn<ContestRank>[]>([
|
||||
),
|
||||
},
|
||||
{
|
||||
title: renderTableTitle(
|
||||
"正确数/总提交",
|
||||
"streamline-ultimate-color:color-palette",
|
||||
),
|
||||
title: renderTableTitle("正确数/总提交", "streamline-ultimate-color:color-palette"),
|
||||
key: "submission",
|
||||
width: 140,
|
||||
align: "center",
|
||||
@@ -147,16 +141,9 @@ async function addColumns() {
|
||||
]
|
||||
}
|
||||
if (status.error_number) {
|
||||
errorNumber = h(
|
||||
"span",
|
||||
{ style: "margin: 0" },
|
||||
`(-${status.error_number})`,
|
||||
)
|
||||
errorNumber = h("span", { style: "margin: 0" }, `(-${status.error_number})`)
|
||||
}
|
||||
return h("div", { class: "oj-time-with-modal" }, [
|
||||
acTime,
|
||||
errorNumber,
|
||||
])
|
||||
return h("div", { class: "oj-time-with-modal" }, [acTime, errorNumber])
|
||||
}
|
||||
},
|
||||
cellProps: (row) => {
|
||||
@@ -244,10 +231,7 @@ async function downloadExcel() {
|
||||
level = "一等奖"
|
||||
} else if (rank1 <= exportForm.first + exportForm.second) {
|
||||
level = "二等奖"
|
||||
} else if (
|
||||
rank1 <=
|
||||
exportForm.first + exportForm.second + exportForm.third
|
||||
) {
|
||||
} else if (rank1 <= exportForm.first + exportForm.second + exportForm.third) {
|
||||
level = "三等奖"
|
||||
} else {
|
||||
level = "参与奖"
|
||||
@@ -255,8 +239,7 @@ async function downloadExcel() {
|
||||
return { 用户名: rank.user.username, 等级: level }
|
||||
})
|
||||
|
||||
const csv =
|
||||
"用户名,等级\n" + rows.map((r) => `${r.用户名},${r.等级}`).join("\n")
|
||||
const csv = "用户名,等级\n" + rows.map((r) => `${r.用户名},${r.等级}`).join("\n")
|
||||
const blob = new Blob(["" + csv], { type: "text/csv;charset=utf-8" })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement("a")
|
||||
@@ -294,13 +277,7 @@ onMounted(() => {
|
||||
<LineChart :ranks="chart" :problems="problems" v-if="chart.length > 0" />
|
||||
|
||||
<!-- 排名表格 -->
|
||||
<n-data-table
|
||||
striped
|
||||
:single-line="false"
|
||||
:scroll-x="1200"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
/>
|
||||
<n-data-table striped :single-line="false" :scroll-x="1200" :columns="columns" :data="data" />
|
||||
<n-space justify="end" align="center">
|
||||
<n-form
|
||||
label-placement="left"
|
||||
@@ -347,9 +324,7 @@ onMounted(() => {
|
||||
</n-form>
|
||||
<template #action>
|
||||
<n-button @click="showExportModal = false">取消</n-button>
|
||||
<n-button type="primary" :loading="exportLoading" @click="downloadExcel">
|
||||
下载 CSV
|
||||
</n-button>
|
||||
<n-button type="primary" :loading="exportLoading" @click="downloadExcel"> 下载 CSV </n-button>
|
||||
</template>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
Reference in new issue
Block a user