fix admin.
This commit is contained in:
47
src/admin/api.ts
Normal file
47
src/admin/api.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import http from "utils/http"
|
||||||
|
import { DIFFICULTY } from "~/utils/constants"
|
||||||
|
import { getACRate } from "~/utils/functions"
|
||||||
|
import { Problem } from "~/utils/types"
|
||||||
|
|
||||||
|
function filterResult(result: Problem) {
|
||||||
|
const newResult = {
|
||||||
|
id: result.id,
|
||||||
|
_id: result._id,
|
||||||
|
title: result.title,
|
||||||
|
difficulty: DIFFICULTY[result.difficulty],
|
||||||
|
tags: result.tags,
|
||||||
|
submission: result.submission_number,
|
||||||
|
rate: getACRate(result.accepted_number, result.submission_number),
|
||||||
|
status: "",
|
||||||
|
}
|
||||||
|
if (result.my_status === null || result.my_status === undefined) {
|
||||||
|
newResult.status = "not_test"
|
||||||
|
} else if (result.my_status === 0) {
|
||||||
|
newResult.status = "passed"
|
||||||
|
} else {
|
||||||
|
newResult.status = "failed"
|
||||||
|
}
|
||||||
|
return newResult
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getProblemList(
|
||||||
|
offset = 0,
|
||||||
|
limit = 10,
|
||||||
|
searchParams: any = {}
|
||||||
|
) {
|
||||||
|
let params: any = {
|
||||||
|
paging: true,
|
||||||
|
offset,
|
||||||
|
limit,
|
||||||
|
}
|
||||||
|
Object.keys(searchParams).forEach((element) => {
|
||||||
|
if (searchParams[element]) {
|
||||||
|
params[element] = searchParams[element]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const res = await http.get("admin/problem", { params })
|
||||||
|
return {
|
||||||
|
results: res.data.results.map(filterResult),
|
||||||
|
total: res.data.total,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<script setup lang="ts"></script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="container">1213</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.container {
|
|
||||||
height: 200vh;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,7 +1,40 @@
|
|||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
import { getProblemList } from "../api"
|
||||||
|
import Pagination from "~/shared/Pagination.vue"
|
||||||
|
import { DataTableColumn } from "naive-ui"
|
||||||
|
import { ProblemFiltered } from "~/utils/types"
|
||||||
|
|
||||||
|
const total = ref(0)
|
||||||
|
const problems = ref([])
|
||||||
|
const query = reactive({
|
||||||
|
limit: 10,
|
||||||
|
page: 1,
|
||||||
|
keyword: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns: DataTableColumn<ProblemFiltered>[] = [
|
||||||
|
{ title: "编号", key: "_id", width: 100 },
|
||||||
|
]
|
||||||
|
|
||||||
|
async function listProblems() {
|
||||||
|
const offset = (query.page - 1) * query.limit
|
||||||
|
const res = await getProblemList(offset, query.limit, {
|
||||||
|
keyword: query.keyword,
|
||||||
|
})
|
||||||
|
total.value = res.total
|
||||||
|
problems.value = res.results
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(listProblems)
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>problem list</div>
|
<n-data-table :columns="columns" :data="problems" />
|
||||||
|
<Pagination
|
||||||
|
:total="total"
|
||||||
|
v-model:limit="query.limit"
|
||||||
|
v-model:page="query.page"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
7
src/admin/setting/home.vue
Normal file
7
src/admin/setting/home.vue
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
92
src/components.d.ts
vendored
92
src/components.d.ts
vendored
@@ -7,52 +7,52 @@ import '@vue/runtime-core'
|
|||||||
|
|
||||||
export {}
|
export {}
|
||||||
|
|
||||||
declare module '@vue/runtime-core' {
|
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"]
|
||||||
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"]
|
||||||
IEpMenu: typeof import('~icons/ep/menu')['default']
|
IEpMenu: typeof import("~icons/ep/menu")["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"]
|
||||||
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"]
|
||||||
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"]
|
||||||
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"]
|
||||||
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"]
|
||||||
NGi: typeof import('naive-ui')['NGi']
|
NGi: typeof import("naive-ui")["NGi"]
|
||||||
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"]
|
||||||
NLayout: typeof import('naive-ui')['NLayout']
|
NLayout: typeof import("naive-ui")["NLayout"]
|
||||||
NLayoutContent: typeof import('naive-ui')['NLayoutContent']
|
NLayoutContent: typeof import("naive-ui")["NLayoutContent"]
|
||||||
NLayoutHeader: typeof import('naive-ui')['NLayoutHeader']
|
NLayoutHeader: typeof import("naive-ui")["NLayoutHeader"]
|
||||||
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
|
NLayoutSider: typeof import("naive-ui")["NLayoutSider"]
|
||||||
NMenu: typeof import('naive-ui')['NMenu']
|
NMenu: typeof import("naive-ui")["NMenu"]
|
||||||
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"]
|
||||||
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"]
|
||||||
NSpace: typeof import('naive-ui')['NSpace']
|
NSpace: typeof import("naive-ui")["NSpace"]
|
||||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
NSwitch: typeof import("naive-ui")["NSwitch"]
|
||||||
NTabPane: typeof import('naive-ui')['NTabPane']
|
NTabPane: typeof import("naive-ui")["NTabPane"]
|
||||||
NTabs: typeof import('naive-ui')['NTabs']
|
NTabs: typeof import("naive-ui")["NTabs"]
|
||||||
NTag: typeof import('naive-ui')['NTag']
|
NTag: typeof import("naive-ui")["NTag"]
|
||||||
NTooltip: typeof import('naive-ui')['NTooltip']
|
NTooltip: typeof import("naive-ui")["NTooltip"]
|
||||||
NUpload: typeof import('naive-ui')['NUpload']
|
NUpload: typeof import("naive-ui")["NUpload"]
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import("vue-router")["RouterLink"]
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import("vue-router")["RouterView"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,9 +44,7 @@ export async function getProblemList(
|
|||||||
params[element] = searchParams[element]
|
params[element] = searchParams[element]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const res = await http.get("problem", {
|
const res = await http.get("problem", { params })
|
||||||
params,
|
|
||||||
})
|
|
||||||
return {
|
return {
|
||||||
results: res.data.results.map(filterResult),
|
results: res.data.results.map(filterResult),
|
||||||
total: res.data.total,
|
total: res.data.total,
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { RouteRecordRaw } from "vue-router"
|
import { RouteRecordRaw } from "vue-router"
|
||||||
import { getProfile } from "./shared/api"
|
import { getProfile } from "./shared/api"
|
||||||
import { loadChart } from "./shared/composables/chart"
|
import { loadChart } from "./shared/composables/chart"
|
||||||
import { USER_TYPE } from "./utils/constants"
|
import { STORAGE_KEY, USER_TYPE } from "./utils/constants"
|
||||||
|
import storage from "./utils/storage"
|
||||||
|
|
||||||
export const routes: RouteRecordRaw[] = [
|
export const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
@@ -97,13 +98,17 @@ export const routes: RouteRecordRaw[] = [
|
|||||||
{
|
{
|
||||||
path: "/admin",
|
path: "/admin",
|
||||||
component: () => import("~/shared/layout/admin.vue"),
|
component: () => import("~/shared/layout/admin.vue"),
|
||||||
meta: { requiresAuth: true },
|
|
||||||
beforeEnter: async () => {
|
beforeEnter: async () => {
|
||||||
|
if (!storage.get(STORAGE_KEY.AUTHED)) return "/"
|
||||||
const res = await getProfile()
|
const res = await getProfile()
|
||||||
if (res.data.user.admin_type === USER_TYPE.REGULAR_USER) return "/"
|
if (res.data.user.admin_type === USER_TYPE.REGULAR_USER) return "/"
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{ path: "", name: "home", component: () => import("admin/index.vue") },
|
{
|
||||||
|
path: "",
|
||||||
|
name: "home",
|
||||||
|
component: () => import("~/admin/setting/home.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "config",
|
path: "config",
|
||||||
name: "config",
|
name: "config",
|
||||||
@@ -120,7 +125,7 @@ export const routes: RouteRecordRaw[] = [
|
|||||||
component: () => import("admin/user/list.vue"),
|
component: () => import("admin/user/list.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "user/import",
|
path: "user/importing",
|
||||||
name: "user importing",
|
name: "user importing",
|
||||||
component: () => import("admin/user/import.vue"),
|
component: () => import("admin/user/import.vue"),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { MenuOption } from "naive-ui"
|
import { MenuOption } from "naive-ui"
|
||||||
import { RouterLink } from "vue-router"
|
import { RouterLink } from "vue-router"
|
||||||
import Login from "../Login.vue"
|
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const options: MenuOption[] = [
|
const options: MenuOption[] = [
|
||||||
|
{
|
||||||
|
label: () => h(RouterLink, { to: "/" }, { default: () => "返回 OJ" }),
|
||||||
|
key: "return to OJ",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: () => h(RouterLink, { to: "/admin" }, { default: () => "首页" }),
|
label: () => h(RouterLink, { to: "/admin" }, { default: () => "首页" }),
|
||||||
key: "home",
|
key: "home",
|
||||||
@@ -42,7 +45,7 @@ const options: MenuOption[] = [
|
|||||||
label: () =>
|
label: () =>
|
||||||
h(
|
h(
|
||||||
RouterLink,
|
RouterLink,
|
||||||
{ to: "/admin/user/import" },
|
{ to: "/admin/user/importing" },
|
||||||
{ default: () => "导入用户" }
|
{ default: () => "导入用户" }
|
||||||
),
|
),
|
||||||
key: "user importing",
|
key: "user importing",
|
||||||
@@ -91,15 +94,10 @@ const active = computed(() => (route.name as string) || "home")
|
|||||||
<n-layout-sider bordered :native-scrollbar="false">
|
<n-layout-sider bordered :native-scrollbar="false">
|
||||||
<n-menu :options="options" :value="active" />
|
<n-menu :options="options" :value="active" />
|
||||||
</n-layout-sider>
|
</n-layout-sider>
|
||||||
<n-layout-content :native-scrollbar="false">
|
<n-layout-content :native-scrollbar="false" content-style="padding: 16px">
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</n-layout-content>
|
</n-layout-content>
|
||||||
<Login />
|
|
||||||
</n-layout>
|
</n-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
.content {
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import Header from "../Header.vue"
|
|||||||
<n-layout-header bordered class="header">
|
<n-layout-header bordered class="header">
|
||||||
<Header />
|
<Header />
|
||||||
</n-layout-header>
|
</n-layout-header>
|
||||||
<n-layout-content class="content">
|
<n-layout-content content-style="padding: 16px">
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</n-layout-content>
|
</n-layout-content>
|
||||||
<Login />
|
<Login />
|
||||||
@@ -21,7 +21,4 @@ import Header from "../Header.vue"
|
|||||||
.header {
|
.header {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
.content {
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user