UI
This commit is contained in:
@@ -510,7 +510,7 @@ watch(
|
|||||||
<n-grid :cols="2" x-gap="20">
|
<n-grid :cols="2" x-gap="20">
|
||||||
<n-gi>
|
<n-gi>
|
||||||
<n-form>
|
<n-form>
|
||||||
<n-form-item label="本题参考答案(用于 AI 分析,不会泄露)">
|
<n-form-item label="本题参考答案(选填,用于 AI 分析,不会泄露)">
|
||||||
<n-tabs
|
<n-tabs
|
||||||
type="segment"
|
type="segment"
|
||||||
default-value="Python3"
|
default-value="Python3"
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ function rowProps(row: Contest) {
|
|||||||
<n-form :show-feedback="false" label-placement="left" inline>
|
<n-form :show-feedback="false" label-placement="left" inline>
|
||||||
<n-form-item label="比赛状态">
|
<n-form-item label="比赛状态">
|
||||||
<n-select
|
<n-select
|
||||||
class="select"
|
style="width: 120px"
|
||||||
:options="options"
|
:options="options"
|
||||||
v-model:value="query.status"
|
v-model:value="query.status"
|
||||||
/>
|
/>
|
||||||
@@ -146,7 +146,7 @@ function rowProps(row: Contest) {
|
|||||||
<n-form :show-feedback="false" label-placement="left" inline>
|
<n-form :show-feedback="false" label-placement="left" inline>
|
||||||
<n-form-item>
|
<n-form-item>
|
||||||
<n-input
|
<n-input
|
||||||
class="input"
|
style="width: 200px"
|
||||||
clearable
|
clearable
|
||||||
v-model:value="query.keyword"
|
v-model:value="query.keyword"
|
||||||
placeholder="比赛标题"
|
placeholder="比赛标题"
|
||||||
@@ -173,13 +173,3 @@ function rowProps(row: Contest) {
|
|||||||
:total="total"
|
:total="total"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.select {
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import storage from "~/utils/storage"
|
|||||||
import { LANGUAGE } from "~/utils/types"
|
import { LANGUAGE } from "~/utils/types"
|
||||||
import Submit from "./Submit.vue"
|
import Submit from "./Submit.vue"
|
||||||
import StatisticsPanel from "~/shared/components/StatisticsPanel.vue"
|
import StatisticsPanel from "~/shared/components/StatisticsPanel.vue"
|
||||||
|
import {Icon} from "@iconify/vue"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
storageKey: string
|
storageKey: string
|
||||||
@@ -144,8 +145,10 @@ function showStatisticsPanel() {
|
|||||||
<n-dropdown size="large" :options="menu" @select="select">
|
<n-dropdown size="large" :options="menu" @select="select">
|
||||||
<n-button :size="isDesktop ? 'medium' : 'small'">操作</n-button>
|
<n-button :size="isDesktop ? 'medium' : 'small'">操作</n-button>
|
||||||
</n-dropdown>
|
</n-dropdown>
|
||||||
<n-button v-if="isDesktop && userStore.isSuperAdmin" @click="goEdit">
|
<n-button circle v-if="isDesktop && userStore.isSuperAdmin" @click="goEdit">
|
||||||
编辑
|
<template #icon>
|
||||||
|
<Icon icon="streamline-ultimate-color:file-code-edit" />
|
||||||
|
</template>
|
||||||
</n-button>
|
</n-button>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ onMounted(getBeatRate)
|
|||||||
<n-gi v-for="item in numbers" :key="item.content">
|
<n-gi v-for="item in numbers" :key="item.content">
|
||||||
<n-card hoverable>
|
<n-card hoverable>
|
||||||
<n-flex align="center">
|
<n-flex align="center">
|
||||||
<Icon :icon="item.icon" width="40" />
|
<Icon v-if="isDesktop" :icon="item.icon" width="40" />
|
||||||
<div>
|
<div>
|
||||||
<n-h2 class="number">
|
<n-h2 class="number">
|
||||||
<n-number-animation
|
<n-number-animation
|
||||||
|
|||||||
@@ -1,15 +1,48 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Icon } from "@iconify/vue"
|
import { Icon } from "@iconify/vue"
|
||||||
|
|
||||||
defineEmits(["click", "search"])
|
interface Props {
|
||||||
|
type: "题目" | "用户"
|
||||||
|
username?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
const emits = defineEmits(["click", "search", "filterClass"])
|
||||||
|
|
||||||
|
const showFilterClass = computed(() => {
|
||||||
|
return props.type === "用户" && props.username?.startsWith("ks")
|
||||||
|
})
|
||||||
|
|
||||||
|
function filterClass() {
|
||||||
|
const match = props.username!.match(/^ks\d{3,4}/)
|
||||||
|
const classname = match ? match[0] : ""
|
||||||
|
if (!classname) return
|
||||||
|
emits("filterClass", classname)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<n-flex align="center">
|
<n-flex align="center">
|
||||||
<n-button text type="info" @click="$emit('click')"><slot></slot></n-button>
|
<n-button text type="info" @click="$emit('click')"><slot></slot></n-button>
|
||||||
<n-button text @click="$emit('search')">
|
<n-tooltip>
|
||||||
<template #icon>
|
<template #trigger>
|
||||||
<Icon icon="streamline-emojis:magnifying-glass-tilted-left"></Icon>
|
<n-button text @click="$emit('search')">
|
||||||
|
<template #icon>
|
||||||
|
<Icon icon="streamline-emojis:magnifying-glass-tilted-left"></Icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
</template>
|
</template>
|
||||||
</n-button>
|
{{ "搜索" + props.type}}
|
||||||
|
</n-tooltip>
|
||||||
|
<n-tooltip v-if="showFilterClass">
|
||||||
|
<template #trigger>
|
||||||
|
<n-button text @click="filterClass">
|
||||||
|
<template #icon>
|
||||||
|
<Icon icon="openmoji:filter"></Icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
筛选班级
|
||||||
|
</n-tooltip>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -3,11 +3,16 @@
|
|||||||
<n-button text type="info" @click="$emit('showCode')">
|
<n-button text type="info" @click="$emit('showCode')">
|
||||||
{{ props.submission.id.slice(0, 12) }}
|
{{ props.submission.id.slice(0, 12) }}
|
||||||
</n-button>
|
</n-button>
|
||||||
<n-button text @click="goto">
|
<n-tooltip>
|
||||||
<template #icon>
|
<template #trigger>
|
||||||
<Icon icon="streamline-emojis:backhand-index-pointing-right-1"></Icon>
|
<n-button text @click="goto">
|
||||||
|
<template #icon>
|
||||||
|
<Icon icon="catppuccin:folder-debug"></Icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
</template>
|
</template>
|
||||||
</n-button>
|
查看测试详情
|
||||||
|
</n-tooltip>
|
||||||
</n-flex>
|
</n-flex>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
{{ props.submission.id.slice(0, 12) }}
|
{{ props.submission.id.slice(0, 12) }}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { parseTime } from "utils/functions"
|
|||||||
import { LANGUAGE, SubmissionListItem } from "utils/types"
|
import { LANGUAGE, SubmissionListItem } from "utils/types"
|
||||||
import Pagination from "~/shared/components/Pagination.vue"
|
import Pagination from "~/shared/components/Pagination.vue"
|
||||||
import SubmissionResultTag from "~/shared/components/SubmissionResultTag.vue"
|
import SubmissionResultTag from "~/shared/components/SubmissionResultTag.vue"
|
||||||
import { isDesktop } from "~/shared/composables/breakpoints"
|
import { isDesktop, isMobile } from "~/shared/composables/breakpoints"
|
||||||
import { usePagination } from "~/shared/composables/pagination"
|
import { usePagination } from "~/shared/composables/pagination"
|
||||||
import { useUserStore } from "~/shared/store/user"
|
import { useUserStore } from "~/shared/store/user"
|
||||||
import { LANGUAGE_SHOW_VALUE } from "~/utils/constants"
|
import { LANGUAGE_SHOW_VALUE } from "~/utils/constants"
|
||||||
@@ -15,6 +15,7 @@ import ButtonWithSearch from "./components/ButtonWithSearch.vue"
|
|||||||
import StatisticsPanel from "~/shared/components/StatisticsPanel.vue"
|
import StatisticsPanel from "~/shared/components/StatisticsPanel.vue"
|
||||||
import SubmissionLink from "./components/SubmissionLink.vue"
|
import SubmissionLink from "./components/SubmissionLink.vue"
|
||||||
import SubmissionDetail from "./detail.vue"
|
import SubmissionDetail from "./detail.vue"
|
||||||
|
import { Icon } from "@iconify/vue"
|
||||||
|
|
||||||
interface SubmissionQuery {
|
interface SubmissionQuery {
|
||||||
username: string
|
username: string
|
||||||
@@ -180,6 +181,7 @@ const columns = computed(() => {
|
|||||||
h(
|
h(
|
||||||
ButtonWithSearch,
|
ButtonWithSearch,
|
||||||
{
|
{
|
||||||
|
type: "题目",
|
||||||
onClick: () => problemClicked(row),
|
onClick: () => problemClicked(row),
|
||||||
onSearch: () => (query.problem = row.problem),
|
onSearch: () => (query.problem = row.problem),
|
||||||
},
|
},
|
||||||
@@ -206,8 +208,11 @@ const columns = computed(() => {
|
|||||||
h(
|
h(
|
||||||
ButtonWithSearch,
|
ButtonWithSearch,
|
||||||
{
|
{
|
||||||
|
type: "用户",
|
||||||
|
username: row.username,
|
||||||
onClick: () => window.open("/user?name=" + row.username, "_blank"),
|
onClick: () => window.open("/user?name=" + row.username, "_blank"),
|
||||||
onSearch: () => (query.username = row.username),
|
onSearch: () => (query.username = row.username),
|
||||||
|
onFilterClass: (classname: string) => (query.username = classname),
|
||||||
},
|
},
|
||||||
() => row.username,
|
() => row.username,
|
||||||
),
|
),
|
||||||
@@ -237,6 +242,13 @@ const columns = computed(() => {
|
|||||||
<n-flex vertical size="large">
|
<n-flex vertical size="large">
|
||||||
<n-space>
|
<n-space>
|
||||||
<n-form :show-feedback="false" inline label-placement="left">
|
<n-form :show-feedback="false" inline label-placement="left">
|
||||||
|
<n-form-item v-if="isDesktop && userStore.isAuthed" label="只看自己">
|
||||||
|
<n-switch
|
||||||
|
v-model:value="query.myself"
|
||||||
|
checked-value="1"
|
||||||
|
unchecked-value="0"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
<n-form-item label="提交状态">
|
<n-form-item label="提交状态">
|
||||||
<n-select
|
<n-select
|
||||||
class="select"
|
class="select"
|
||||||
@@ -269,27 +281,31 @@ const columns = computed(() => {
|
|||||||
placeholder="题号"
|
placeholder="题号"
|
||||||
/>
|
/>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item v-if="userStore.isAuthed" label="只看自己">
|
</n-form>
|
||||||
|
<n-form :show-feedback="false" inline label-placement="left">
|
||||||
|
<n-form-item v-if="isMobile && userStore.isAuthed" label="只看自己">
|
||||||
<n-switch
|
<n-switch
|
||||||
v-model:value="query.myself"
|
v-model:value="query.myself"
|
||||||
checked-value="1"
|
checked-value="1"
|
||||||
unchecked-value="0"
|
unchecked-value="0"
|
||||||
/>
|
/>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
</n-form>
|
|
||||||
<n-form :show-feedback="false" inline label-placement="left">
|
|
||||||
<n-form-item>
|
<n-form-item>
|
||||||
<n-button @click="search(query.username, query.problem)">
|
<n-button @click="search(query.username, query.problem)">
|
||||||
搜索
|
搜索
|
||||||
</n-button>
|
</n-button>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
|
<n-form-item>
|
||||||
|
<n-button @click="clear" quaternary>重置</n-button>
|
||||||
|
</n-form-item>
|
||||||
<n-form-item
|
<n-form-item
|
||||||
v-if="userStore.isSuperAdmin && route.name === 'submissions'"
|
v-if="userStore.isSuperAdmin && route.name === 'submissions'"
|
||||||
>
|
>
|
||||||
<n-button @click="toggleStatisticPanel(true)">数据统计</n-button>
|
<n-button circle @click="toggleStatisticPanel(true)">
|
||||||
</n-form-item>
|
<template #icon>
|
||||||
<n-form-item>
|
<Icon icon="streamline-emojis:bar-chart" />
|
||||||
<n-button @click="clear" quaternary>重置</n-button>
|
</template>
|
||||||
|
</n-button>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item v-if="todayCount > 0">
|
<n-form-item v-if="todayCount > 0">
|
||||||
<component :is="isDesktop ? NH2 : NText" class="todayCount">
|
<component :is="isDesktop ? NH2 : NText" class="todayCount">
|
||||||
|
|||||||
Reference in New Issue
Block a user