This commit is contained in:
2024-01-25 14:17:10 +08:00
parent 87fcb12960
commit 6464a1eee6
16 changed files with 191 additions and 148 deletions

View File

@@ -102,7 +102,12 @@ watch(
<span>我猜你要</span>
<n-button @click="router.push('/admin/problem/create')">新题目</n-button>
<n-button @click="router.push('/admin/contest/create')">新比赛</n-button>
<n-input clearable v-model:value="query.username" placeholder="班级前缀" />
<n-input
clearable
@change="listRanks"
v-model:value="query.username"
placeholder="班级前缀"
/>
<n-button @click="listRanks">用户排名</n-button>
<Pagination
class="pagination"

1
src/components.d.ts vendored
View File

@@ -23,6 +23,7 @@ declare module 'vue' {
NDropdown: typeof import('naive-ui')['NDropdown']
NDynamicTags: typeof import('naive-ui')['NDynamicTags']
NEmpty: typeof import('naive-ui')['NEmpty']
NFlex: typeof import('naive-ui')['NFlex']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem']
NFormItemGi: typeof import('naive-ui')['NFormItemGi']

View File

@@ -10,7 +10,6 @@ const contestStore = useContestStore()
<template>
<n-popover
v-if="contestStore.contest"
trigger="click"
placement="bottom-end"
:show-arrow="false"
>

View File

@@ -46,7 +46,7 @@ const options: DropdownOption[] = [
比赛排名
</n-button>
</n-space>
<n-dropdown v-else :options="options" trigger="click" @select="goto">
<n-dropdown v-else :options="options" @select="goto">
<n-button>菜单</n-button>
</n-dropdown>
</div>

View File

@@ -91,12 +91,20 @@ function clear() {
onMounted(listContests)
watch(() => query.page, routerPush)
watch(
() => [query.limit, query.keyword, query.status],
() => [query.limit, query.status],
() => {
query.page = 1
routerPush()
},
)
watchDebounced(
() => [query.keyword],
() => {
query.page = 1
routerPush()
},
{ debounce: 500, maxWait: 1000 },
)
watch(
() => route.name === "contests" && route.query,
(newVal) => {
@@ -129,7 +137,11 @@ function rowProps(row: Contest) {
/>
</n-form-item>
<n-form-item>
<n-input clearable @change="search" placeholder="比赛标题" />
<n-input
clearable
v-model:value="query.keyword"
placeholder="比赛标题"
/>
</n-form-item>
</n-form>
<n-form :show-feedback="false" label-placement="left" inline>

View File

@@ -203,7 +203,6 @@ watch(
<template>
<n-popover
trigger="click"
placement="bottom-end"
scrollable
:show-arrow="false"

View File

@@ -19,7 +19,6 @@ function clear() {
</script>
<template>
<n-popover
trigger="click"
placement="bottom-end"
scrollable
:show-arrow="false"

View File

@@ -110,15 +110,21 @@ async function getRandom() {
}
watch(() => query.page, routerPush)
watch(
() => [query.tag, query.difficulty, query.limit, query.keyword],
() => [query.tag, query.difficulty, query.limit],
() => {
query.page = 1
routerPush()
},
)
watchDebounced(
() => [query.keyword],
() => {
query.page = 1
routerPush()
},
{ debounce: 500, maxWait: 1000 },
)
watch(
() => query.tag,
() => {
@@ -128,7 +134,6 @@ watch(
}))
},
)
watch(
() => route.path === "/" && route.query,
(newVal) => {
@@ -199,7 +204,11 @@ function rowProps(row: ProblemFiltered) {
/>
</n-form-item>
<n-form-item>
<n-input clearable @change="search" placeholder="题号或者标题" />
<n-input
clearable
v-model:value="query.keyword"
placeholder="题号或者标题"
/>
</n-form-item>
</n-form>
<n-form :show-feedback="false" inline label-placement="left">

View File

@@ -0,0 +1,17 @@
<script lang="ts" setup>
import Filter from "~/shared/icons/Filter.vue"
defineEmits(["click", "search"])
</script>
<template>
<n-flex align="center">
<n-button text type="info" @click="$emit('click')"><slot></slot></n-button>
<n-button text @click="$emit('search')">
<template #icon>
<n-icon color="#ccc">
<Filter />
</n-icon>
</template>
</n-button>
</n-flex>
</template>

View File

@@ -13,6 +13,7 @@ import { adminRejudge, getSubmissions } from "oj/api"
import { isDesktop } from "~/shared/composables/breakpoints"
import { useUserStore } from "~/shared/store/user"
import { LANGUAGE_SHOW_VALUE } from "~/utils/constants"
import ButtonWithSearch from "./components/ButtonWithSearch.vue"
interface Query {
username: string
@@ -81,14 +82,6 @@ function routerPush() {
})
}
function searchUser(value: string) {
query.username = value
}
function searchProblem(value: string) {
query.problem = value
}
function search(username: string, problem: string) {
query.username = username
query.problem = problem
@@ -107,22 +100,38 @@ async function rejudge(submissionID: string) {
listSubmissions()
}
function problemClicked(row: Submission) {
if (route.name === "contest submissions") {
router.push({
name: "contest problem",
params: {
problemID: row.problem,
},
})
} else {
router.push("/problem/" + row.problem)
}
}
watch(() => query.page, routerPush)
watch(
() => [
query.limit,
query.myself,
query.username,
query.result,
query.problem,
],
() => [query.limit, query.myself, query.result],
() => {
query.page = 1
routerPush()
},
)
watchDebounced(
() => [query.username, query.problem],
() => {
query.page = 1
routerPush()
},
{ debounce: 500, maxWait: 1000 },
)
watch(
() =>
(route.name === "submissions" || route.name === "contest submissions") &&
@@ -176,22 +185,10 @@ const columns = computed(() => {
width: 120,
render: (row) =>
h(
NButton,
ButtonWithSearch,
{
text: true,
type: "info",
onClick: () => {
if (route.name === "contest submissions") {
router.push({
name: "contest problem",
params: {
problemID: row.problem,
},
})
} else {
router.push("/problem/" + row.problem)
}
},
onClick: () => problemClicked(row),
onSearch: () => (query.problem = row.problem),
},
() => row.problem,
),
@@ -220,11 +217,10 @@ const columns = computed(() => {
minWidth: 120,
render: (row) =>
h(
NButton,
ButtonWithSearch,
{
text: true,
type: "info",
onClick: () => router.push("/user?name=" + row.username),
onSearch: () => (query.username = row.username),
},
() => row.username,
),
@@ -267,10 +263,14 @@ const columns = computed(() => {
</n-form>
<n-form :show-feedback="false" inline label-placement="left">
<n-form-item>
<n-input clearable @change="searchUser" placeholder="用户" />
<n-input
clearable
v-model:value="query.username"
placeholder="用户"
/>
</n-form-item>
<n-form-item>
<n-input clearable @change="searchProblem" placeholder="题号" />
<n-input clearable v-model:value="query.problem" placeholder="题号" />
</n-form-item>
</n-form>
<n-form :show-feedback="false" inline label-placement="left">

View File

@@ -39,15 +39,15 @@ const menus = computed<MenuOption[]>(() => [
label: () => h(RouterLink, { to: "/" }, { default: () => "题库" }),
key: "problem",
},
{
label: () => h(RouterLink, { to: "/contest" }, { default: () => "比赛" }),
key: "contest",
},
{
label: () =>
h(RouterLink, { to: "/submission" }, { default: () => "提交" }),
key: "submission",
},
{
label: () => h(RouterLink, { to: "/contest" }, { default: () => "比赛" }),
key: "contest",
},
{
label: () => h(RouterLink, { to: "/rank" }, { default: () => "排名" }),
key: "rank",
@@ -109,7 +109,7 @@ function goHome() {
/>
</n-space>
<n-space align="center">
<n-dropdown v-if="isMobile" :options="menus" trigger="click">
<n-dropdown v-if="isMobile" :options="menus">
<n-button>菜单</n-button>
</n-dropdown>
<n-button
@@ -122,11 +122,7 @@ function goHome() {
{{ screenSwitchLabel }}
</n-button>
<div v-if="userStore.isFinished">
<n-dropdown
v-if="userStore.isAuthed"
:options="options"
trigger="click"
>
<n-dropdown v-if="userStore.isAuthed" :options="options">
<n-button>{{ userStore.user!.username }}</n-button>
</n-dropdown>
<n-space align="center" v-else>

View File

@@ -0,0 +1,13 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M11 20q-.425 0-.712-.288T10 19v-6L4.2 5.6q-.375-.5-.112-1.05T5 4h14q.65 0 .913.55T19.8 5.6L14 13v6q0 .425-.288.713T13 20z"
></path>
</svg>
</template>

View File

@@ -1,13 +0,0 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 0 0 1.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 0 0-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 0 0 5.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0c.41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5S14 7.01 14 9.5S11.99 14 9.5 14z"
></path>
</svg>
</template>

View File

@@ -218,7 +218,7 @@ export interface Submission {
ip: string
// TODO: 这里不知道是什么
contest: null
problem: number
problem: string
can_unshare: boolean
}
@@ -346,4 +346,4 @@ export interface AnnouncementEdit {
title: string
content: string
visible: boolean
}
}