contest info component.

This commit is contained in:
2023-02-09 13:28:54 +08:00
parent 532a9991d2
commit 6f5a4d7e66
2 changed files with 94 additions and 74 deletions

View File

@@ -0,0 +1,37 @@
<script setup lang="ts">
import { parseTime } from "utils/functions"
import { useContestStore } from "oj/store/contest"
import ContestTypeVue from "./ContestType.vue"
import { isDesktop } from "~/shared/composables/breakpoints"
const contestStore = useContestStore()
</script>
<template>
<n-popover
v-if="contestStore.contest"
trigger="click"
placement="bottom-end"
:show-arrow="false"
>
<template #trigger>
<n-button>比赛信息</n-button>
</template>
<n-descriptions bordered :column="isDesktop ? 4 : 1">
<n-descriptions-item label="开始时间">
{{
parseTime(contestStore.contest.start_time, "YYYY年M月D日 hh:mm:ss")
}}
</n-descriptions-item>
<n-descriptions-item label="结束时间">
{{ parseTime(contestStore.contest.end_time, "YYYY年M月D日 hh:mm:ss") }}
</n-descriptions-item>
<n-descriptions-item label="比赛类型">
<ContestTypeVue :contest="contestStore.contest" />
</n-descriptions-item>
<n-descriptions-item label="发起人">
{{ contestStore.contest.created_by.username }}
</n-descriptions-item>
</n-descriptions>
</n-popover>
</template>

View File

@@ -1,9 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { CONTEST_STATUS, ContestStatus, ContestType } from "utils/constants" import { CONTEST_STATUS, ContestType } from "utils/constants"
import { parseTime } from "utils/functions"
import { isDesktop } from "~/shared/composables/breakpoints" import { isDesktop, isMobile } from "~/shared/composables/breakpoints"
import ContestTypeVue from "./components/ContestType.vue"
import { useContestStore } from "../store/contest" import { useContestStore } from "../store/contest"
import { DropdownOption } from "naive-ui"
import ContestInfo from "./components/ContestInfo.vue"
const props = defineProps<{ const props = defineProps<{
contestID: string contestID: string
@@ -38,41 +39,33 @@ function getCurrentType(name: string): "primary" | "default" {
if (route.name === "contest " + name) return "primary" if (route.name === "contest " + name) return "primary"
return "default" return "default"
} }
const options = computed<DropdownOption[]>(() => [
{ label: "比赛题目", key: "problems" },
{ label: "提交信息", key: "submissions" },
{ label: "比赛排名", key: "rank" },
{ label: "管理员助手", key: "helper", show: contestStore.isContestAdmin },
])
</script> </script>
<template> <template>
<div v-if="contestStore.contest"> <div v-if="contestStore.contest">
<n-space align="center"> <n-space align="center" justify="space-between">
<n-tag :type="CONTEST_STATUS[contestStore.contest.status]['type']"> <n-space align="center">
{{ CONTEST_STATUS[contestStore.contest.status]["name"] }} <n-tag :type="CONTEST_STATUS[contestStore.contest.status]['type']">
</n-tag> {{ CONTEST_STATUS[contestStore.contest.status]["name"] }}
<h2 class="contestTitle">{{ contestStore.contest.title }}</h2> </n-tag>
<n-icon <h2 class="contestTitle">{{ contestStore.contest.title }}</h2>
v-if="contestStore.contest.contest_type === ContestType.private" <n-icon
class="lockIcon" v-if="contestStore.contest.contest_type === ContestType.private"
> class="lockIcon"
<i-ep-lock />
</n-icon>
</n-space>
<div v-html="contestStore.contest.description"></div>
<n-form :inline="isDesktop" label-placement="left">
<n-form-item v-if="passwordFormVisible" label="需要输入密码才能看到题目">
<n-input
name="ContestPassword"
type="password"
v-model:value="password"
/>
</n-form-item>
<n-form-item v-if="passwordFormVisible">
<n-button
@click="contestStore.checkPassword(contestID, password)"
:disabled="!password"
> >
确认 <i-ep-lock />
</n-button> </n-icon>
</n-form-item> </n-space>
<n-form-item v-if="contestMenuVisible"> <n-space v-if="contestMenuVisible">
<n-space> <ContestInfo />
<n-space v-if="isDesktop">
<n-button <n-button
:type="getCurrentType('problems')" :type="getCurrentType('problems')"
@click="goto('problems')" @click="goto('problems')"
@@ -96,44 +89,38 @@ function getCurrentType(name: string): "primary" | "default" {
管理员助手 管理员助手
</n-button> </n-button>
</n-space> </n-space>
<n-dropdown
v-if="isMobile"
:options="options"
trigger="click"
@select="goto"
>
<n-button>菜单</n-button>
</n-dropdown>
</n-space>
</n-space>
<div v-html="contestStore.contest.description"></div>
<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-form-item>
<n-form-item>
<n-button
@click="contestStore.checkPassword(contestID, password)"
:disabled="!password"
>
确认
</n-button>
</n-form-item> </n-form-item>
</n-form> </n-form>
<n-descriptions class="bottom" bordered :column="isDesktop ? 5 : 2">
<n-descriptions-item
:span="isDesktop ? 1 : 2"
v-if="contestStore.contest.status !== ContestStatus.finished"
>
<template #label>
<span
v-if="contestStore.contest.status === ContestStatus.not_started"
>
距离比赛开始还有
</span>
<span v-if="contestStore.contest.status === ContestStatus.underway">
距离比赛结束还有
</span>
</template>
<n-space align="center">
<n-tag :type="CONTEST_STATUS[contestStore.contest.status]['type']">
<n-countdown :duration="500000" />
</n-tag>
</n-space>
</n-descriptions-item>
<n-descriptions-item label="开始时间">
{{
parseTime(contestStore.contest.start_time, "YYYY年M月D日 hh:mm:ss")
}}
</n-descriptions-item>
<n-descriptions-item label="结束时间">
{{ parseTime(contestStore.contest.end_time, "YYYY年M月D日 hh:mm:ss") }}
</n-descriptions-item>
<n-descriptions-item label="比赛类型">
<ContestTypeVue :contest="contestStore.contest" />
</n-descriptions-item>
<n-descriptions-item label="发起人">
{{ contestStore.contest.created_by.username }}
</n-descriptions-item>
</n-descriptions>
<router-view></router-view> <router-view></router-view>
</div> </div>
</template> </template>
@@ -146,8 +133,4 @@ function getCurrentType(name: string): "primary" | "default" {
.lockIcon { .lockIcon {
transform: translateY(2px); transform: translateY(2px);
} }
.bottom {
margin-bottom: 24px;
}
</style> </style>