195 lines
5.6 KiB
Vue
195 lines
5.6 KiB
Vue
<template>
|
|
<div class="md:max-w-[720px] mx-auto">
|
|
<n-card segmented>
|
|
<template #header>
|
|
<n-page-header @back="navigateTo('/')">
|
|
<template #title>Challenge #{{ challenge?.id }}</template>
|
|
<template #subtitle>
|
|
<div class="flex items-center gap-2">
|
|
<n-tag size="small" class="case-capital">{{ challenge?.status?.replaceAll("-", " ") }}</n-tag>
|
|
</div>
|
|
</template>
|
|
</n-page-header>
|
|
</template>
|
|
|
|
<div id="answering-content" v-if="challenge?.status === 'in-progress'">
|
|
<problem-solution-program
|
|
v-if="problem.type === 'programming'"
|
|
v-model:answers="answers"
|
|
:challenge="challenge"
|
|
:problem="problem"
|
|
/>
|
|
</div>
|
|
|
|
<div id="preview-challenge" class="flex flex-col gap-4" v-else>
|
|
<div>
|
|
<div class="font-bold">状态</div>
|
|
<div class="case-capital">{{ challenge?.status?.replaceAll("-", " ") }}</div>
|
|
</div>
|
|
<div>
|
|
<div class="font-bold">问题</div>
|
|
<div>
|
|
<nuxt-link target="_blank" :to="`/problems/${challenge.problem}`">
|
|
#{{ challenge?.problem }} | {{ problem?.title }}
|
|
</nuxt-link>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="font-bold">答案</div>
|
|
<client-only>
|
|
<div class="mt-2 mx-[-4px]">
|
|
<problem-preview-program
|
|
v-if="problem.type === 'programming'"
|
|
:answers="answers"
|
|
:challenge="challenge"
|
|
:problem="problem"
|
|
/>
|
|
</div>
|
|
</client-only>
|
|
</div>
|
|
<div>
|
|
<div class="font-bold">结果</div>
|
|
<n-card embedded class="mt-2 mx-[-4px]">
|
|
<div v-if="challenge?.details?.cases"></div>
|
|
<n-empty v-else description="未进行判题,暂无挑战结果" />
|
|
</n-card>
|
|
</div>
|
|
</div>
|
|
|
|
<template #action>
|
|
<div v-if="challenge?.status === 'in-progress'" id="answering-widgets" class="w-full flex justify-between">
|
|
<div class="flex gap-2">
|
|
<n-button secondary circle class="rounded-[4px]" type="warning" :disabled="submitting" @click="save">
|
|
<template #icon>
|
|
<n-icon :component="Save" />
|
|
</template>
|
|
</n-button>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<n-button secondary type="error" :disabled="submitting" @click="abandon">放弃</n-button>
|
|
<n-button type="primary" :disabled="submitting" @click="submit">提交</n-button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</n-card>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { NButton, NCard, NPageHeader, NTag, NIcon, NEmpty, useDialog, useMessage } from "naive-ui";
|
|
import { Save } from "@vicons/carbon";
|
|
|
|
const route = useRoute();
|
|
const client = useSupabaseClient();
|
|
const message = useMessage();
|
|
const dialog = useDialog();
|
|
|
|
const submitting = ref(false);
|
|
|
|
const { data: challenge } = await client
|
|
.from("challenges")
|
|
.select<any, any>("*")
|
|
.eq("id", route.params.id)
|
|
.single();
|
|
|
|
const { data: problem } = await client
|
|
.from("problems")
|
|
.select<any, any>("*")
|
|
.eq("id", challenge?.problem)
|
|
.single();
|
|
|
|
useHead({
|
|
title: challenge ? `挑战 #${challenge.id}` : "挑战 #404"
|
|
});
|
|
|
|
const answers = ref(challenge?.answers ?? {});
|
|
|
|
async function save() {
|
|
submitting.value = true;
|
|
const instance = message.loading("正在保存,请稍后……");
|
|
|
|
const { error } = await client
|
|
.from("challenges")
|
|
// @ts-ignore
|
|
.update<any>({
|
|
answers: answers.value
|
|
})
|
|
.eq("id", challenge.id);
|
|
|
|
if (error != null) {
|
|
message.error(`Something went wrong... ${error.message}`);
|
|
}
|
|
|
|
instance.destroy();
|
|
submitting.value = false;
|
|
}
|
|
|
|
onMounted(() => {
|
|
document.addEventListener("keydown", (event) => {
|
|
const prefixKey = navigator.platform.indexOf("Mac") == 0 ? event.metaKey : event.ctrlKey;
|
|
if (prefixKey && event.key == "s") {
|
|
event.preventDefault();
|
|
save();
|
|
}
|
|
});
|
|
});
|
|
|
|
function abandon() {
|
|
const instance = dialog.warning({
|
|
title: "警告",
|
|
content: "你确定要放弃该次挑战?这会让该挑战立刻转化为放弃状态,并且扣除 5 点社会信用点,三思而后行!",
|
|
positiveText: "确定",
|
|
negativeText: "再试试",
|
|
onPositiveClick: async () => {
|
|
await client
|
|
.from("challenges")
|
|
// @ts-ignore
|
|
.update<any>({ status: "abandoned" })
|
|
.eq("id", challenge.id);
|
|
|
|
const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
|
|
|
|
instance.loading = true;
|
|
message.info("已放弃挑战该题");
|
|
|
|
await delay(1850);
|
|
window.close();
|
|
}
|
|
});
|
|
}
|
|
|
|
async function submit() {
|
|
await save();
|
|
|
|
const instance = dialog.warning({
|
|
title: "警告",
|
|
content: "你确定要提交吗?确认提交后无法再次修改答案,等待判题可能需要一段时间。",
|
|
positiveText: "确定",
|
|
negativeText: "不确定",
|
|
onPositiveClick: async () => {
|
|
instance.loading = true;
|
|
|
|
const inst = message.loading("正在提交中,请稍后……");
|
|
|
|
const { error } = await client
|
|
.from("challenges")
|
|
// @ts-ignore
|
|
.update<any>({ status: "submitted" })
|
|
.eq("id", challenge.id);
|
|
|
|
if (error != null) {
|
|
message.error(`Something went wrong... ${error.message}`);
|
|
}
|
|
|
|
inst.destroy();
|
|
message.success("提交成功!即将跳转结果页面……");
|
|
|
|
const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
|
|
|
|
await delay(1850);
|
|
reloadNuxtApp();
|
|
}
|
|
});
|
|
}
|
|
</script>
|