add countdown.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { DropdownOption } from "naive-ui"
|
||||
import { useContestStore } from "oj/store/contest"
|
||||
import { isDesktop } from "~/shared/composables/breakpoints"
|
||||
import { ContestStatus } from "~/utils/constants"
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@@ -10,7 +11,7 @@ const contestStore = useContestStore()
|
||||
const contestMenuVisible = computed(() => {
|
||||
if (contestStore.isContestAdmin) return true
|
||||
if (!contestStore.isPrivate) {
|
||||
// TODO:这里没有完成
|
||||
return contestStore.contestStatus !== ContestStatus.not_started
|
||||
}
|
||||
return contestStore.access
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { Contest } from "~/utils/types"
|
||||
import { ContestType } from "~/utils/constants"
|
||||
import { Contest } from "utils/types"
|
||||
import { ContestType } from "utils/constants"
|
||||
|
||||
defineProps<{ contest: Contest }>()
|
||||
</script>
|
||||
@@ -8,6 +8,7 @@ defineProps<{ contest: Contest }>()
|
||||
<n-space>
|
||||
<span>{{ contest.title }}</span>
|
||||
<n-icon
|
||||
size="medium"
|
||||
class="lockIcon"
|
||||
v-if="contest.contest_type === ContestType.private"
|
||||
>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { CONTEST_STATUS } from "utils/constants"
|
||||
import { CONTEST_STATUS, ContestStatus } from "utils/constants"
|
||||
import { isDesktop } from "~/shared/composables/breakpoints"
|
||||
import { useContestStore } from "../store/contest"
|
||||
import ContestInfo from "./components/ContestInfo.vue"
|
||||
@@ -12,7 +12,13 @@ const contestStore = useContestStore()
|
||||
|
||||
const password = ref("")
|
||||
|
||||
onMounted(() => contestStore.init(props.contestID))
|
||||
onMounted(() => {
|
||||
contestStore.init(props.contestID)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
contestStore.clear()
|
||||
})
|
||||
|
||||
const passwordFormVisible = computed(
|
||||
() =>
|
||||
@@ -26,15 +32,15 @@ const passwordFormVisible = computed(
|
||||
<div v-if="contestStore.contest">
|
||||
<n-space class="title" align="center" justify="space-between">
|
||||
<n-space align="center">
|
||||
<n-tag :type="CONTEST_STATUS[contestStore.contest.status]['type']">
|
||||
{{ CONTEST_STATUS[contestStore.contest.status]["name"] }}
|
||||
</n-tag>
|
||||
<h2 class="contestTitle">{{ contestStore.contest.title }}</h2>
|
||||
<n-icon v-if="contestStore.isPrivate" class="lockIcon">
|
||||
<n-icon size="large" v-if="contestStore.isPrivate" class="lockIcon">
|
||||
<i-ep-lock />
|
||||
</n-icon>
|
||||
<n-tag :type="CONTEST_STATUS[contestStore.contestStatus]['type']">
|
||||
{{ contestStore.countdown }}
|
||||
</n-tag>
|
||||
</n-space>
|
||||
<n-space>
|
||||
<n-space align="center">
|
||||
<ContestInfo />
|
||||
<ContestMenu />
|
||||
</n-space>
|
||||
|
||||
@@ -35,11 +35,9 @@ function rowProps(row: ProblemFiltered) {
|
||||
<n-data-table
|
||||
striped
|
||||
size="small"
|
||||
class="problems"
|
||||
:data="contestStore.problems"
|
||||
:columns="problemsColumns"
|
||||
:row-props="rowProps"
|
||||
v-if="contestStore.problems?.length"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { formatISO, getTime, intervalToDuration, parseISO } from "date-fns"
|
||||
import { useUserStore } from "~/shared/store/user"
|
||||
import { ContestType } from "~/utils/constants"
|
||||
import { ContestStatus, ContestType } from "~/utils/constants"
|
||||
import { duration } from "~/utils/functions"
|
||||
import { Contest, Problem } from "~/utils/types"
|
||||
import {
|
||||
getContest,
|
||||
@@ -11,27 +13,58 @@ import {
|
||||
export const useContestStore = defineStore("contest", () => {
|
||||
const userStore = useUserStore()
|
||||
const message = useMessage()
|
||||
const [access, toggleAccess] = useToggle()
|
||||
const contest = ref<Contest>()
|
||||
const [access, toggleAccess] = useToggle(false)
|
||||
const contest = ref<Contest | null>(null)
|
||||
const problems = ref<Problem[]>([])
|
||||
const now = ref(0)
|
||||
|
||||
const contestStatus = computed(() => {
|
||||
return false
|
||||
let timer = 0
|
||||
|
||||
const contestStatus = computed<ContestStatus>(() => {
|
||||
const start = getTime(parseISO(contest.value!.start_time.toString()))
|
||||
const end = getTime(parseISO(contest.value!.end_time.toString()))
|
||||
if (start > now.value) {
|
||||
return ContestStatus.not_started
|
||||
} else if (end < now.value) {
|
||||
return ContestStatus.finished
|
||||
} else {
|
||||
return ContestStatus.underway
|
||||
}
|
||||
})
|
||||
|
||||
const countdown = computed(() => {
|
||||
if (contestStatus.value === ContestStatus.finished) {
|
||||
return "已结束"
|
||||
} else if (contestStatus.value === ContestStatus.not_started) {
|
||||
const d = duration(formatISO(now.value), contest.value!.start_time, true)
|
||||
return "距离比赛开始 " + d
|
||||
} else {
|
||||
const d = duration(formatISO(now.value), contest.value!.end_time, true)
|
||||
return "距离比赛结束 " + d
|
||||
}
|
||||
})
|
||||
|
||||
const isContestAdmin = computed(
|
||||
() =>
|
||||
userStore.isSuperAdmin ||
|
||||
(userStore.isAuthed && contest.value?.created_by.id === userStore.user.id)
|
||||
(userStore.isAuthed &&
|
||||
contest.value?.created_by.id === userStore.user!.id)
|
||||
)
|
||||
|
||||
const isPrivate = computed(
|
||||
() => contest.value?.contest_type === ContestType.private
|
||||
() => contest.value!.contest_type === ContestType.private
|
||||
)
|
||||
|
||||
async function init(contestID: string) {
|
||||
problems.value = []
|
||||
const res = await getContest(contestID)
|
||||
contest.value = res.data
|
||||
now.value = getTime(parseISO(res.data.now))
|
||||
if (contestStatus.value !== ContestStatus.finished) {
|
||||
timer = setInterval(() => {
|
||||
now.value = now.value + 1000
|
||||
}, 1000)
|
||||
}
|
||||
if (contest.value?.contest_type === ContestType.private) {
|
||||
const res = await getContestAccess(contestID)
|
||||
toggleAccess(res.data.access)
|
||||
@@ -39,6 +72,14 @@ export const useContestStore = defineStore("contest", () => {
|
||||
_getProblems(contestID)
|
||||
}
|
||||
|
||||
function clear() {
|
||||
contest.value = null
|
||||
problems.value = []
|
||||
toggleAccess(false)
|
||||
now.value = 0
|
||||
if (timer) clearInterval(timer)
|
||||
}
|
||||
|
||||
async function checkPassword(contestID: string, password: string) {
|
||||
try {
|
||||
const res = await checkContestPassword(contestID, password)
|
||||
@@ -53,7 +94,6 @@ export const useContestStore = defineStore("contest", () => {
|
||||
}
|
||||
|
||||
async function _getProblems(contestID: string) {
|
||||
problems.value = []
|
||||
try {
|
||||
problems.value = await getContestProblems(contestID)
|
||||
} catch (err) {
|
||||
@@ -69,7 +109,9 @@ export const useContestStore = defineStore("contest", () => {
|
||||
access,
|
||||
problems,
|
||||
isPrivate,
|
||||
countdown,
|
||||
init,
|
||||
clear,
|
||||
checkPassword,
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user