refactor axios.
This commit is contained in:
99
package-lock.json
generated
99
package-lock.json
generated
@@ -11,6 +11,7 @@
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"@monaco-editor/loader": "^1.3.2",
|
||||
"@vueuse/core": "^9.10.0",
|
||||
"@vueuse/integrations": "^9.10.0",
|
||||
"axios": "^1.2.2",
|
||||
"element-plus": "^2.2.28",
|
||||
"normalize.css": "^8.0.1",
|
||||
@@ -778,6 +779,86 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/integrations": {
|
||||
"version": "9.10.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vueuse/integrations/-/integrations-9.10.0.tgz",
|
||||
"integrity": "sha512-MLGVbN3i9gRq3pb8VRZXgPvbNJcUUvgR5pmbc1QZj4Z1vvsvxam159AwWEJdyX2I39a1E7EkmBujtiXtVckO5g==",
|
||||
"dependencies": {
|
||||
"@vueuse/core": "9.10.0",
|
||||
"@vueuse/shared": "9.10.0",
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"async-validator": "*",
|
||||
"axios": "*",
|
||||
"change-case": "*",
|
||||
"drauu": "*",
|
||||
"focus-trap": "*",
|
||||
"fuse.js": "*",
|
||||
"idb-keyval": "*",
|
||||
"jwt-decode": "*",
|
||||
"nprogress": "*",
|
||||
"qrcode": "*",
|
||||
"universal-cookie": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"async-validator": {
|
||||
"optional": true
|
||||
},
|
||||
"axios": {
|
||||
"optional": true
|
||||
},
|
||||
"change-case": {
|
||||
"optional": true
|
||||
},
|
||||
"drauu": {
|
||||
"optional": true
|
||||
},
|
||||
"focus-trap": {
|
||||
"optional": true
|
||||
},
|
||||
"fuse.js": {
|
||||
"optional": true
|
||||
},
|
||||
"idb-keyval": {
|
||||
"optional": true
|
||||
},
|
||||
"jwt-decode": {
|
||||
"optional": true
|
||||
},
|
||||
"nprogress": {
|
||||
"optional": true
|
||||
},
|
||||
"qrcode": {
|
||||
"optional": true
|
||||
},
|
||||
"universal-cookie": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/integrations/node_modules/vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vue/composition-api": "^1.0.0-rc.1",
|
||||
"vue": "^3.0.0-0 || ^2.6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vue/composition-api": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@vueuse/metadata": {
|
||||
"version": "9.10.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.10.0.tgz",
|
||||
@@ -2639,6 +2720,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vueuse/integrations": {
|
||||
"version": "9.10.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vueuse/integrations/-/integrations-9.10.0.tgz",
|
||||
"integrity": "sha512-MLGVbN3i9gRq3pb8VRZXgPvbNJcUUvgR5pmbc1QZj4Z1vvsvxam159AwWEJdyX2I39a1E7EkmBujtiXtVckO5g==",
|
||||
"requires": {
|
||||
"@vueuse/core": "9.10.0",
|
||||
"@vueuse/shared": "9.10.0",
|
||||
"vue-demi": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue-demi": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz",
|
||||
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vueuse/metadata": {
|
||||
"version": "9.10.0",
|
||||
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.10.0.tgz",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"@monaco-editor/loader": "^1.3.2",
|
||||
"@vueuse/core": "^9.10.0",
|
||||
"@vueuse/integrations": "^9.10.0",
|
||||
"axios": "^1.2.2",
|
||||
"element-plus": "^2.2.28",
|
||||
"normalize.css": "^8.0.1",
|
||||
|
||||
@@ -21,6 +21,7 @@ const routes = [
|
||||
{
|
||||
path: "problem/:problemID",
|
||||
component: () => import("./oj/problem/detail.vue"),
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: "status",
|
||||
@@ -30,6 +31,7 @@ const routes = [
|
||||
{
|
||||
path: "status/:statusID",
|
||||
component: () => import("./oj/status/detail.vue"),
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: "contest",
|
||||
@@ -39,6 +41,12 @@ const routes = [
|
||||
{
|
||||
path: "contest/:contestID",
|
||||
component: () => import("./oj/contest/detail.vue"),
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: "contest/:contestID/problem/:problemID",
|
||||
component: () => import("./oj/problem/detail.vue"),
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: "rank",
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { getACRate } from "./../utils/functions"
|
||||
import { DIFFICULTY } from "./../utils/constants"
|
||||
import { Problem, LANGUAGE } from "./../utils/types"
|
||||
import http from "./../utils/http"
|
||||
import { useAxios } from "@vueuse/integrations/useAxios"
|
||||
|
||||
function filterResult(result: any) {
|
||||
function filterResult(result: Problem) {
|
||||
const newResult: any = {
|
||||
displayID: result._id,
|
||||
_id: result._id,
|
||||
title: result.title,
|
||||
difficulty: DIFFICULTY[<"Low" | "Mid" | "High">result.difficulty],
|
||||
difficulty: DIFFICULTY[result.difficulty],
|
||||
tags: result.tags,
|
||||
submission: result.submission_number,
|
||||
rate: getACRate(result.accepted_number, result.submission_number),
|
||||
@@ -46,7 +48,7 @@ export async function getProblemList(
|
||||
}
|
||||
|
||||
export function getProblemTagList() {
|
||||
return http.get("problem/tags")
|
||||
return useAxios<{ id: number; name: string }[]>("problem/tags", http)
|
||||
}
|
||||
|
||||
export function getRandomProblemID() {
|
||||
@@ -54,11 +56,20 @@ export function getRandomProblemID() {
|
||||
}
|
||||
|
||||
export function getProblem(id: string) {
|
||||
return http.get("problem", {
|
||||
params: { problem_id: id },
|
||||
return useAxios<Problem>("problem", { params: { problem_id: id } }, http)
|
||||
}
|
||||
|
||||
export function getSubmission(id: string) {
|
||||
return http.get("submission", {
|
||||
params: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export function getWebsite() {
|
||||
return http.get("website")
|
||||
export function submitCode(data: {
|
||||
problem_id: number
|
||||
contest_id?: number
|
||||
language: LANGUAGE
|
||||
code: string
|
||||
}) {
|
||||
return http.post("submission", data)
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ onMounted(userStore.getMyProfile)
|
||||
<el-menu-item index="/status">提交</el-menu-item>
|
||||
<el-menu-item index="/rank">排名</el-menu-item>
|
||||
</el-menu>
|
||||
<div v-if="userStore.isLoaded && !userStore.isAuthed" class="actions">
|
||||
<div v-if="userStore.isFinished && !userStore.isAuthed" class="actions">
|
||||
<el-button @click="loginStore.show">登录</el-button>
|
||||
<el-button @click="signupStore.show">注册</el-button>
|
||||
</div>
|
||||
<div v-if="userStore.isLoaded && userStore.isAuthed" class="actions">
|
||||
<div v-if="userStore.isFinished && userStore.isAuthed" class="actions">
|
||||
<el-dropdown @command="handleDropdown">
|
||||
<el-button>{{ userStore.user.username }}</el-button>
|
||||
<template #dropdown>
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
<script lang="ts" setup>
|
||||
import loader, { Monaco } from "@monaco-editor/loader"
|
||||
import { ref, onBeforeUnmount, onMounted, watch, reactive } from "vue"
|
||||
import { ref, onBeforeUnmount, onMounted, watch, reactive, computed } from "vue"
|
||||
import {
|
||||
LANGUAGE,
|
||||
LANGUAGE_LABEL,
|
||||
LANGUAGE_VALUE,
|
||||
SOURCES,
|
||||
} from "../../../utils/constants"
|
||||
import { isMobile } from "../../../utils/breakpoints"
|
||||
import { submitCode } from "../../api"
|
||||
import { Problem } from "../../../utils/types"
|
||||
|
||||
const { problem } = defineProps<{
|
||||
problem: {
|
||||
languages: Array<LANGUAGE>
|
||||
template: { [key in LANGUAGE]?: string }
|
||||
}
|
||||
const { problem, contestID = "" } = defineProps<{
|
||||
contestID?: string
|
||||
problemID?: string
|
||||
problem: Problem
|
||||
}>()
|
||||
|
||||
const state = reactive({
|
||||
values: ref({ ...SOURCES }),
|
||||
language: problem.languages[0] || "C",
|
||||
isMobile,
|
||||
submissionId: "",
|
||||
})
|
||||
|
||||
const monacoEditorRef = ref()
|
||||
|
||||
let monaco: Monaco
|
||||
|
||||
function reset() {
|
||||
@@ -34,9 +33,7 @@ function reset() {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
onMounted(init)
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
monaco.editor.getModels().forEach((model) => model.dispose())
|
||||
@@ -77,6 +74,29 @@ async function init() {
|
||||
state.values[state.language] = monaco.editor.getModels()[0].getValue()
|
||||
})
|
||||
}
|
||||
|
||||
const submitDisabled = computed(() => {
|
||||
const code = state.values[state.language]
|
||||
return (
|
||||
code.trim() === "" ||
|
||||
code === problem.template[state.language] ||
|
||||
code === SOURCES[state.language]
|
||||
)
|
||||
})
|
||||
|
||||
async function submit() {
|
||||
const data = {
|
||||
problem_id: problem.id,
|
||||
language: state.language,
|
||||
code: state.values[state.language],
|
||||
}
|
||||
if (contestID) {
|
||||
//@ts-ignore
|
||||
data.contest_id = parseInt(contestID)
|
||||
}
|
||||
const res = await submitCode(data)
|
||||
state.submissionId = res.data.submission_id
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -107,7 +127,9 @@ async function init() {
|
||||
<el-form class="actions">
|
||||
<el-form-item>
|
||||
<el-button>运行</el-button>
|
||||
<el-button type="primary">提交</el-button>
|
||||
<el-button type="primary" :disabled="submitDisabled" @click="submit">
|
||||
提交
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
const { problem } = defineProps(["problem"])
|
||||
import { Problem } from "../../../utils/types"
|
||||
|
||||
const { problem } = defineProps<{ problem: Problem }>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { DIFFICULTY } from "../../../utils/constants"
|
||||
import { getACRate, getTagColor } from "../../../utils/functions"
|
||||
import { getACRate, getTagColor, parseTime } from "../../../utils/functions"
|
||||
import { isDesktop } from "../../../utils/breakpoints"
|
||||
import { Problem } from "../../../utils/types"
|
||||
|
||||
const { problem } = defineProps(["problem"])
|
||||
const { problem } = defineProps<{ problem: Problem }>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -14,19 +15,20 @@ const { problem } = defineProps(["problem"])
|
||||
<el-descriptions-item label="出题人">
|
||||
{{ problem.created_by.username }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="难度">
|
||||
<el-tag disable-transitions :type="getTagColor(problem.difficulty)">
|
||||
{{ DIFFICULTY[<"Low" | "Mid" | "High">problem.difficulty] }}
|
||||
</el-tag>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ parseTime(problem.create_time) }}
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="时间限制">
|
||||
{{ problem.time_limit }}毫秒
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="内存限制">
|
||||
{{ problem.memory_limit }}MB
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="类型">
|
||||
{{ problem.rule_type }}
|
||||
<el-descriptions-item label="难度">
|
||||
<el-tag disable-transitions :type="getTagColor(problem.difficulty)">
|
||||
{{ DIFFICULTY[problem.difficulty] }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="提交正确">
|
||||
|
||||
@@ -1,39 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue"
|
||||
import { useRoute } from "vue-router"
|
||||
import Editor from "./components/editor.vue"
|
||||
import ProblemContent from "./components/problem-content.vue"
|
||||
import ProblemInfo from "./components/problem-info.vue"
|
||||
import { getProblem } from "../api"
|
||||
import { isDesktop, isMobile } from "../../utils/breakpoints"
|
||||
|
||||
const route = useRoute()
|
||||
const contestID = route.params.contestID as string
|
||||
const problemID = route.params.problemID as string
|
||||
|
||||
const problem = ref({
|
||||
_id: "",
|
||||
created_by: {},
|
||||
io_mode: {},
|
||||
languages: [],
|
||||
samples: [],
|
||||
statistic_info: {},
|
||||
tags: [],
|
||||
template: {},
|
||||
})
|
||||
|
||||
async function init() {
|
||||
const res = await getProblem(problemID)
|
||||
problem.value = res.data
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
const { problemID = "", contestID = "" } = defineProps<{
|
||||
problemID?: string
|
||||
contestID?: string
|
||||
}>()
|
||||
const { data: problem, isFinished } = getProblem(problemID)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-row v-if="problem._id">
|
||||
<el-row v-if="isFinished && problem">
|
||||
<el-col :span="isDesktop ? 12 : 24">
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="题目描述">
|
||||
|
||||
@@ -17,9 +17,10 @@ const router = useRouter()
|
||||
const route = useRoute()
|
||||
const userStore = useUserStore()
|
||||
const problems = ref([])
|
||||
const tags = ref(<{ id: number; name: string }[]>[])
|
||||
const total = ref(0)
|
||||
|
||||
const { data: tags } = getProblemTagList()
|
||||
|
||||
const query = reactive({
|
||||
keyword: route.query.keyword || "",
|
||||
difficulty: route.query.difficulty || "",
|
||||
@@ -28,11 +29,6 @@ const query = reactive({
|
||||
limit: parseInt(<string>route.query.limit) || 10,
|
||||
})
|
||||
|
||||
async function listTags() {
|
||||
const res = await getProblemTagList()
|
||||
tags.value = res.data
|
||||
}
|
||||
|
||||
async function listProblems() {
|
||||
query.keyword = route.query.keyword || ""
|
||||
query.difficulty = route.query.difficulty || ""
|
||||
@@ -77,7 +73,7 @@ async function getRandom() {
|
||||
}
|
||||
|
||||
function goProblem(row: any) {
|
||||
router.push("/problem/" + row.displayID)
|
||||
router.push("/problem/" + row._id)
|
||||
}
|
||||
|
||||
watch(() => query.page, routePush)
|
||||
@@ -98,12 +94,9 @@ watch(
|
||||
)
|
||||
|
||||
// TODO: 这里会在登录时候执行两次,有BUG
|
||||
watch(() => userStore.isLoaded && userStore.isAuthed, listProblems)
|
||||
watch(() => userStore.isFinished && userStore.isAuthed, listProblems)
|
||||
|
||||
onMounted(() => {
|
||||
listTags()
|
||||
listProblems()
|
||||
})
|
||||
onMounted(listProblems)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -158,11 +151,7 @@ onMounted(() => {
|
||||
/></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="displayID"
|
||||
label="编号"
|
||||
:width="isDesktop ? 100 : 60"
|
||||
/>
|
||||
<el-table-column prop="_id" label="编号" :width="isDesktop ? 100 : 60" />
|
||||
<el-table-column prop="title" label="标题" />
|
||||
<el-table-column label="难度" width="100">
|
||||
<template #default="scope">
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { useAxios } from "@vueuse/integrations/useAxios"
|
||||
import http from "../utils/http"
|
||||
|
||||
export function login(data: { username: string; password: string }) {
|
||||
return http.post("login", data)
|
||||
return useAxios("login", { method: "post", data }, http, {
|
||||
immediate: false,
|
||||
})
|
||||
}
|
||||
|
||||
export function logout() {
|
||||
@@ -9,7 +12,7 @@ export function logout() {
|
||||
}
|
||||
|
||||
export function getUserInfo(username: string) {
|
||||
return http.get("profile", {
|
||||
params: { username },
|
||||
return useAxios("profile", { method: "get", params: { username } }, http, {
|
||||
immediate: false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineStore } from "pinia"
|
||||
import { computed, ref } from "vue"
|
||||
import { computed } from "vue"
|
||||
import {
|
||||
PROBLEM_PERMISSION,
|
||||
STORAGE_KEY,
|
||||
@@ -9,8 +9,7 @@ import storage from "../../utils/storage"
|
||||
import { getUserInfo } from "../api"
|
||||
|
||||
export const useUserStore = defineStore("user", () => {
|
||||
const profile = ref<any>({})
|
||||
const isLoaded = ref(false)
|
||||
const { data: profile, isFinished, execute } = getUserInfo("")
|
||||
const user = computed(() => profile.value.user || {})
|
||||
const isAuthed = computed(() => !!user.value.email)
|
||||
const isAdminRole = computed(
|
||||
@@ -26,10 +25,7 @@ export const useUserStore = defineStore("user", () => {
|
||||
)
|
||||
|
||||
async function getMyProfile() {
|
||||
isLoaded.value = false
|
||||
const res = await getUserInfo("")
|
||||
isLoaded.value = true
|
||||
profile.value = res.data || {}
|
||||
await execute()
|
||||
storage.set(STORAGE_KEY.AUTHED, !!user.value.email)
|
||||
}
|
||||
|
||||
@@ -39,7 +35,7 @@ export const useUserStore = defineStore("user", () => {
|
||||
}
|
||||
return {
|
||||
profile,
|
||||
isLoaded,
|
||||
isFinished,
|
||||
user,
|
||||
isAdminRole,
|
||||
isSuperAdmin,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { FormInstance } from "element-plus"
|
||||
import { reactive, ref } from "vue"
|
||||
import { computed, reactive, ref } from "vue"
|
||||
import { useSignupStore } from "../../oj/stores/signup"
|
||||
import { login } from "../../shared/api"
|
||||
import { useLoginStore } from "../stores/login"
|
||||
@@ -9,8 +9,6 @@ import { useUserStore } from "../stores/user"
|
||||
const loginStore = useLoginStore()
|
||||
const signupStore = useSignupStore()
|
||||
const userStore = useUserStore()
|
||||
const loading = ref(false)
|
||||
const errorMessage = ref("")
|
||||
const loginRef = ref<FormInstance>()
|
||||
const form = reactive({
|
||||
username: "",
|
||||
@@ -23,23 +21,19 @@ const rules = reactive({
|
||||
{ min: 6, max: 20, message: "长度在6到20位之间", trigger: "change" },
|
||||
],
|
||||
})
|
||||
const { isLoading, error, execute } = login(form)
|
||||
const msg = computed(() => error.value && "用户名或密码不正确")
|
||||
|
||||
async function submit() {
|
||||
if (!loginRef.value) return
|
||||
await loginRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
errorMessage.value = ""
|
||||
try {
|
||||
await login(form)
|
||||
loginStore.hide()
|
||||
await userStore.getMyProfile()
|
||||
} catch (err) {
|
||||
errorMessage.value = "用户名或密码不正确"
|
||||
}
|
||||
loading.value = false
|
||||
const valid = await loginRef.value.validate()
|
||||
if (valid) {
|
||||
await execute()
|
||||
if (!error.value) {
|
||||
loginStore.hide()
|
||||
userStore.getMyProfile()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function goSignup() {
|
||||
@@ -75,17 +69,12 @@ function goSignup() {
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="loading" @click="submit"
|
||||
>登录</el-button
|
||||
>
|
||||
<el-button type="primary" :loading="isLoading" @click="submit">
|
||||
登录
|
||||
</el-button>
|
||||
<el-button @click="goSignup">没有账号,立即注册</el-button>
|
||||
</el-form-item>
|
||||
<el-alert
|
||||
v-if="errorMessage"
|
||||
:title="errorMessage"
|
||||
show-icon
|
||||
type="error"
|
||||
/>
|
||||
<el-alert v-if="msg" :title="msg" show-icon type="error" />
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -196,8 +196,6 @@ export const LANGUAGE_LABEL = {
|
||||
Golang: "Go",
|
||||
}
|
||||
|
||||
export type LANGUAGE = keyof typeof LANGUAGE_LABEL
|
||||
|
||||
export const LANGUAGE_VALUE = {
|
||||
C: "c",
|
||||
"C++": "cpp",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useDateFormat } from "@vueuse/core"
|
||||
import { STORAGE_KEY } from "./constants"
|
||||
|
||||
export function getACRate(acCount: number, totalCount: number) {
|
||||
@@ -32,3 +33,8 @@ export function getTagColor(tag: string) {
|
||||
困难: "danger",
|
||||
}[tag]
|
||||
}
|
||||
|
||||
export function parseTime(utc: Date, format = "YYYY年M月D日") {
|
||||
const time = useDateFormat(utc, format, { locales: "zh-CN" })
|
||||
return time.value
|
||||
}
|
||||
|
||||
51
src/utils/types.ts
Normal file
51
src/utils/types.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
export type LANGUAGE =
|
||||
| "C"
|
||||
| "C++"
|
||||
| "Python2"
|
||||
| "Python3"
|
||||
| "Java"
|
||||
| "JavaScript"
|
||||
| "Golang"
|
||||
|
||||
export interface Problem {
|
||||
_id: string
|
||||
id: number
|
||||
tags: string[]
|
||||
created_by: {
|
||||
id: number
|
||||
username: string
|
||||
real_name: null
|
||||
}
|
||||
template: { [key in LANGUAGE]?: string }
|
||||
title: string
|
||||
description: string
|
||||
input_description: string
|
||||
output_description: string
|
||||
samples: {
|
||||
input: string
|
||||
output: string
|
||||
}[]
|
||||
hint: string
|
||||
languages: Array<LANGUAGE>
|
||||
create_time: Date
|
||||
last_update_time: null
|
||||
time_limit: number
|
||||
memory_limit: number
|
||||
io_mode: {
|
||||
input: string
|
||||
output: string
|
||||
io_mode: string
|
||||
}
|
||||
spj: boolean
|
||||
spj_language: null
|
||||
rule_type: string
|
||||
difficulty: "Low" | "Mid" | "High"
|
||||
source: string
|
||||
total_score: number
|
||||
submission_number: number
|
||||
accepted_number: number
|
||||
statistic_info: {}
|
||||
share_submission: boolean
|
||||
contest: null
|
||||
my_status: number
|
||||
}
|
||||
Reference in New Issue
Block a user