This commit is contained in:
2023-04-14 09:25:58 +08:00
parent 921ea417dd
commit 8da14bafef
10 changed files with 103 additions and 69 deletions

16
src/components.d.ts vendored
View File

@@ -11,21 +11,27 @@ declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
IEpBell: typeof import('~icons/ep/bell')['default'] IEpBell: typeof import('~icons/ep/bell')['default']
IEpCaretRight: typeof import('~icons/ep/caret-right')['default'] IEpCaretRight: typeof import('~icons/ep/caret-right')['default']
IEpFullScreen: typeof import('~icons/ep/full-screen')['default']
IEpGoldMedal: typeof import('~icons/ep/gold-medal')['default']
IEpGoldMetal: typeof import('~icons/ep/gold-metal')['default']
IEpInfoFilled: typeof import('~icons/ep/info-filled')['default']
IEpLoading: typeof import('~icons/ep/loading')['default'] IEpLoading: typeof import('~icons/ep/loading')['default']
IEpLock: typeof import('~icons/ep/lock')['default'] IEpLock: typeof import('~icons/ep/lock')['default']
IEpMedal: typeof import('~icons/ep/medal')['default']
IEpMoon: typeof import('~icons/ep/moon')['default'] IEpMoon: typeof import('~icons/ep/moon')['default']
IEpMoreFilled: typeof import('~icons/ep/more-filled')['default'] IEpMoreFilled: typeof import('~icons/ep/more-filled')['default']
IEpSunny: typeof import('~icons/ep/sunny')['default'] IEpSunny: typeof import('~icons/ep/sunny')['default']
IEpWarning: typeof import('~icons/ep/warning')['default']
NAlert: typeof import('naive-ui')['NAlert'] NAlert: typeof import('naive-ui')['NAlert']
NAvatar: typeof import('naive-ui')['NAvatar'] NAvatar: typeof import('naive-ui')['NAvatar']
NButton: typeof import('naive-ui')['NButton'] NButton: typeof import('naive-ui')['NButton']
NCard: typeof import('naive-ui')['NCard'] NCard: typeof import('naive-ui')['NCard']
NCheckbox: typeof import('naive-ui')['NCheckbox'] NCheckbox: typeof import('naive-ui')['NCheckbox']
NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup'] NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
NCode: typeof import('naive-ui')['NCode'] NCode: typeof import("naive-ui")["NCode"]
NConfigProvider: typeof import('naive-ui')['NConfigProvider'] NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDataTable: typeof import('naive-ui')['NDataTable'] NDataTable: typeof import('naive-ui')['NDataTable']
NDatePicker: typeof import('naive-ui')['NDatePicker'] NDatePicker: typeof import("naive-ui")["NDatePicker"]
NDescriptions: typeof import('naive-ui')['NDescriptions'] NDescriptions: typeof import('naive-ui')['NDescriptions']
NDescriptionsItem: typeof import('naive-ui')['NDescriptionsItem'] NDescriptionsItem: typeof import('naive-ui')['NDescriptionsItem']
NDropdown: typeof import('naive-ui')['NDropdown'] NDropdown: typeof import('naive-ui')['NDropdown']
@@ -33,9 +39,9 @@ declare module '@vue/runtime-core' {
NEmpty: typeof import('naive-ui')['NEmpty'] NEmpty: typeof import('naive-ui')['NEmpty']
NForm: typeof import('naive-ui')['NForm'] NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem'] NFormItem: typeof import('naive-ui')['NFormItem']
NFormItemGi: typeof import('naive-ui')['NFormItemGi'] NFormItemGi: typeof import("naive-ui")["NFormItemGi"]
NGi: typeof import('naive-ui')['NGi'] NGi: typeof import('naive-ui')['NGi']
NGradientText: typeof import('naive-ui')['NGradientText'] NGradientText: typeof import("naive-ui")["NGradientText"]
NGrid: typeof import('naive-ui')['NGrid'] NGrid: typeof import('naive-ui')['NGrid']
NIcon: typeof import('naive-ui')['NIcon'] NIcon: typeof import('naive-ui')['NIcon']
NInput: typeof import('naive-ui')['NInput'] NInput: typeof import('naive-ui')['NInput']
@@ -47,7 +53,7 @@ declare module '@vue/runtime-core' {
NMessageProvider: typeof import('naive-ui')['NMessageProvider'] NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NModal: typeof import('naive-ui')['NModal'] NModal: typeof import('naive-ui')['NModal']
NPagination: typeof import('naive-ui')['NPagination'] NPagination: typeof import('naive-ui')['NPagination']
NPopconfirm: typeof import('naive-ui')['NPopconfirm'] NPopconfirm: typeof import("naive-ui")["NPopconfirm"]
NPopover: typeof import('naive-ui')['NPopover'] NPopover: typeof import('naive-ui')['NPopover']
NScrollbar: typeof import('naive-ui')['NScrollbar'] NScrollbar: typeof import('naive-ui')['NScrollbar']
NSelect: typeof import('naive-ui')['NSelect'] NSelect: typeof import('naive-ui')['NSelect']

View File

@@ -14,7 +14,12 @@ const contestStore = useContestStore()
:show-arrow="false" :show-arrow="false"
> >
<template #trigger> <template #trigger>
<n-button>比赛信息</n-button> <n-button>
<template #icon>
<i-ep-warning />
</template>
比赛信息
</n-button>
</template> </template>
<div v-html="contestStore.contest.description"></div> <div v-html="contestStore.contest.description"></div>
<n-descriptions bordered label-placement="left" :column="1"> <n-descriptions bordered label-placement="left" :column="1">

View File

@@ -24,12 +24,11 @@ function getCurrentType(name: string): "primary" | "default" {
return "default" return "default"
} }
const options = computed<DropdownOption[]>(() => [ const options: DropdownOption[] = [
{ label: "比赛题目", key: "problems" }, { label: "比赛题目", key: "problems" },
{ label: "提交信息", key: "submissions" }, { label: "提交信息", key: "submissions" },
{ label: "比赛排名", key: "rank" }, { label: "比赛排名", key: "rank" },
{ label: "管理员助手", key: "helper", show: contestStore.isContestAdmin }, ]
])
</script> </script>
<template> <template>
<div v-if="contestMenuVisible"> <div v-if="contestMenuVisible">
@@ -46,13 +45,6 @@ const options = computed<DropdownOption[]>(() => [
<n-button :type="getCurrentType('rank')" @click="goto('rank')"> <n-button :type="getCurrentType('rank')" @click="goto('rank')">
比赛排名 比赛排名
</n-button> </n-button>
<n-button
v-if="contestStore.isContestAdmin"
:type="getCurrentType('helper')"
@click="goto('helper')"
>
管理员助手
</n-button>
</n-space> </n-space>
<n-dropdown v-else :options="options" trigger="click" @select="goto"> <n-dropdown v-else :options="options" trigger="click" @select="goto">
<n-button>菜单</n-button> <n-button>菜单</n-button>

View File

@@ -1,13 +0,0 @@
<script lang="ts" setup>
const columns: DataTableColumn[] = [
{ title: "AC 时间", key: "ac_time" },
{ title: "问题 ID", key: "problem_display_id" },
{ title: "一血", key: "is_first_ac" },
{ title: "用户名", key: "username" },
{ title: "状态", key: "status" },
{ title: "选项", key: "actions" },
]
</script>
<template>
<n-data-table :columns="columns"></n-data-table>
</template>

View File

@@ -17,17 +17,19 @@ code.language = props.problem.languages[0] || "C"
code.value = props.problem.template[code.language] || SOURCES[code.language] code.value = props.problem.template[code.language] || SOURCES[code.language]
const editorHeight = computed(() => const editorHeight = computed(() =>
isDesktop.value ? "calc(100vh - 150px)" : "calc(100vh - 200px)" isDesktop.value ? "calc(100vh - 133px)" : "calc(100vh - 180px)"
) )
</script> </script>
<template> <template>
<Form :problem="props.problem" /> <n-space vertical>
<CodeEditor <Form :problem="props.problem" />
v-model="code.value" <CodeEditor
:language="code.language" v-model="code.value"
:height="editorHeight" :language="code.language"
/> :height="editorHeight"
/>
</n-space>
</template> </template>
<style scoped></style> <style scoped></style>

View File

@@ -39,6 +39,7 @@ function goEdit() {
const menu: DropdownOption[] = [ const menu: DropdownOption[] = [
{ label: "重置", key: "reset" }, { label: "重置", key: "reset" },
{ label: "提交信息", key: "submissions" }, { label: "提交信息", key: "submissions" },
{ label: "自测猫", key: "testcat" },
] ]
const options: DropdownOption[] = props.problem.languages.map((it) => ({ const options: DropdownOption[] = props.problem.languages.map((it) => ({
@@ -65,22 +66,21 @@ function select(key: string) {
case "submissions": case "submissions":
goSubmissions() goSubmissions()
break break
case "testcat":
goTestCat()
break
} }
} }
</script> </script>
<template> <template>
<n-form inline label-placement="left"> <n-space>
<n-form-item> <n-select
<n-select class="language"
class="language" v-model:value="code.language"
v-model:value="code.language" :options="options"
:options="options" />
/> <Submit />
</n-form-item>
<n-form-item>
<Submit />
</n-form-item>
<n-dropdown <n-dropdown
v-if="isMobile" v-if="isMobile"
trigger="click" trigger="click"
@@ -95,17 +95,17 @@ function select(key: string) {
</template> </template>
</n-button> </n-button>
</n-dropdown> </n-dropdown>
<n-form-item v-if="isDesktop"> <n-button v-if="isDesktop" @click="reset">重置</n-button>
<n-space> <n-button v-if="isDesktop" @click="goSubmissions">提交信息</n-button>
<n-button @click="reset">重置</n-button> <n-button v-if="isDesktop" type="info" @click="goTestCat">自测猫</n-button>
<n-button @click="goSubmissions">提交信息</n-button> <n-button
<n-button type="info" @click="goTestCat">自测猫</n-button> type="warning"
<n-button type="warning" v-if="userStore.isSuperAdmin" @click="goEdit"> v-if="isDesktop && userStore.isSuperAdmin"
编辑 @click="goEdit"
</n-button> >
</n-space> 编辑
</n-form-item> </n-button>
</n-form> </n-space>
</template> </template>
<style scoped> <style scoped>

View File

@@ -91,6 +91,7 @@ function type(status: ProblemStatus) {
<template> <template>
<n-alert <n-alert
class="success"
v-if="problem.my_status === 0" v-if="problem.my_status === 0"
type="success" type="success"
title="🎉 本 题 已 经 被 你 解 决 啦" title="🎉 本 题 已 经 被 你 解 决 啦"
@@ -98,7 +99,7 @@ function type(status: ProblemStatus) {
<n-space align="center"> <n-space align="center">
<n-tag>{{ problem._id }}</n-tag> <n-tag>{{ problem._id }}</n-tag>
<h1>{{ problem.title }}</h1> <h1 class="problemTitle">{{ problem.title }}</h1>
</n-space> </n-space>
<p class="title" :style="style">描述</p> <p class="title" :style="style">描述</p>
<div class="content" v-html="problem.description"></div> <div class="content" v-html="problem.description"></div>
@@ -161,9 +162,13 @@ function type(status: ProblemStatus) {
</template> </template>
<style scoped> <style scoped>
.problemTitle {
margin: 0;
}
.title { .title {
font-size: 20px; font-size: 20px;
margin: 24px 0 16px 0; margin: 12px 0;
} }
.testcaseTitle { .testcaseTitle {
@@ -179,4 +184,8 @@ function type(status: ProblemStatus) {
font-size: 14px; font-size: 14px;
white-space: pre; white-space: pre;
} }
.success {
margin-bottom: 8px;
}
</style> </style>

View File

@@ -0,0 +1,38 @@
<script lang="ts" setup>
interface Props {
page: number
limit: number
index: number
}
const props = defineProps<Props>()
const index = computed(() => props.index + (props.page - 1) * props.limit + 1)
const color = computed(() => {
if (index.value === 1) return "#FFD700"
if (index.value === 2) return "#C0C0C0"
if (index.value === 3) return "rgb(191,173,111)"
return ""
})
const tooltip = computed(() => {
if (index.value === 1) return "🏅 金牌"
if (index.value === 2) return "🥈 银牌"
if (index.value === 3) return "🥉 铜牌"
return ""
})
</script>
<template>
<span v-if="index > 3">{{ index }}</span>
<n-tooltip v-else>
<template #trigger>
<n-icon class="icon" size="20">
<i-ep-medal :color="color" />
</n-icon>
</template>
{{ tooltip }}
</n-tooltip>
</template>
<style scoped>
.icon {
transform: translateY(4px);
}
</style>

View File

@@ -5,6 +5,7 @@ import Pagination from "~/shared/Pagination.vue"
import { Rank } from "utils/types" import { Rank } from "utils/types"
import { getRank } from "oj/api" import { getRank } from "oj/api"
import { getACRate } from "utils/functions" import { getACRate } from "utils/functions"
import Index from "./components/Index.vue"
const router = useRouter() const router = useRouter()
const data = ref<Rank[]>([]) const data = ref<Rank[]>([])
@@ -29,9 +30,10 @@ const columns: DataTableColumn<Rank>[] = [
{ {
title: "排名", title: "排名",
key: "index", key: "index",
width: 100, width: 80,
align: "center",
render: (_, index) => render: (_, index) =>
h("span", {}, index + (query.page - 1) * query.limit + 1), h(Index, { index, page: query.page, limit: query.limit }),
}, },
{ {
title: "用户", title: "用户",

View File

@@ -56,13 +56,6 @@ export const routes: RouteRecordRaw[] = [
meta: { requiresAuth: true }, meta: { requiresAuth: true },
name: "contest rank", name: "contest rank",
}, },
{
path: "helper",
component: () => import("~/oj/contest/pages/helper.vue"),
props: true,
meta: { requiresAuth: true },
name: "contest helper",
},
], ],
}, },
{ {