contest info component.
This commit is contained in:
37
src/oj/contest/components/ContestInfo.vue
Normal file
37
src/oj/contest/components/ContestInfo.vue
Normal 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>
|
||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user