✨ Challenges Modification
This commit is contained in:
		| @@ -1,11 +1,70 @@ | ||||
| <template> | ||||
|   <client-only> | ||||
|     <vue-monaco-editor | ||||
|       :options="options" | ||||
|       :language="answers.language ?? 'text'" | ||||
|       v-model:value="answers.code" | ||||
|       class="min-h-[360px] code-editor" | ||||
|     /> | ||||
|   </client-only> | ||||
|  | ||||
|   <n-divider class="mx-[-24px] w-[calc(100%+48px)] divider-below-code" /> | ||||
|  | ||||
|   <section> | ||||
|     <n-space> | ||||
|       <n-select | ||||
|         :options="languages" | ||||
|         v-model:value="answers.language" | ||||
|         placeholder="Programming Language" | ||||
|         class="w-120" | ||||
|       /> | ||||
|     </n-space> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { NDivider, NSpace, NSelect } from "naive-ui"; | ||||
| import { VueMonacoEditor } from "@guolao/vue-monaco-editor"; | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   challenge: any, | ||||
|   problem: any, | ||||
|   answers: any, | ||||
| }>(); | ||||
| const emits = defineEmits(["update:answers"]); | ||||
|  | ||||
| const answers = ref(props.challenge?.answers ?? {}); | ||||
|  | ||||
| watch(answers, (v) => { | ||||
|   emits("update:answers", v); | ||||
| }); | ||||
|  | ||||
| const options = { | ||||
|   minimap: { enabled: false } | ||||
| }; | ||||
|  | ||||
| const languageWhitelist: string[] = props.problem?.languageWhitelist ?? []; | ||||
| const languageBlacklist: string[] = props.problem?.languageBlacklist ?? []; | ||||
|  | ||||
| const languages = [ | ||||
|   { label: "C", value: "c" }, | ||||
|   { label: "C++", value: "cpp" }, | ||||
|   { label: "JSON", value: "json" }, // Huh? | ||||
| ].filter((item) => { | ||||
|   return languageWhitelist.filter((x) => new RegExp(x, item.value)).length > 0 || | ||||
|     !(languageBlacklist.filter((x) => new RegExp(x, item.value)).length > 0); | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| .code-editor { | ||||
|   min-width: calc(100% + 48px); | ||||
|   margin-top: -20px; | ||||
|   margin-left: -24px; | ||||
|   margin-right: -24px; | ||||
| } | ||||
|  | ||||
| </style> | ||||
| .divider-below-code { | ||||
|   margin-top: 0 !important; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -12,15 +12,14 @@ | ||||
|         </n-page-header> | ||||
|       </template> | ||||
|  | ||||
|       <client-only> | ||||
|         <vue-monaco-editor | ||||
|           :options="options" | ||||
|           v-model:value="answer.code" | ||||
|           class="min-h-[360px] code-editor" | ||||
|       <section> | ||||
|         <problem-solution-program | ||||
|           v-if="problem.type === 'programming'" | ||||
|           v-model:answers="answers" | ||||
|           :challenge="challenge" | ||||
|           :problem="problem" | ||||
|         /> | ||||
|       </client-only> | ||||
|  | ||||
|       <n-divider class="mx-[-24px] w-[calc(100%+48px)] divider-below-code" /> | ||||
|       </section> | ||||
|  | ||||
|       <template #action> | ||||
|         <div class="w-full flex justify-between"> | ||||
| @@ -42,8 +41,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { NButton, NCard, NDivider, NPageHeader, NTag, NIcon, useDialog, useMessage } from "naive-ui"; | ||||
| import { VueMonacoEditor } from "@guolao/vue-monaco-editor"; | ||||
| import { NButton, NCard, NPageHeader, NTag, NIcon, useDialog, useMessage } from "naive-ui"; | ||||
| import { Save } from "@vicons/carbon"; | ||||
|  | ||||
| const route = useRoute(); | ||||
| @@ -51,10 +49,6 @@ const client = useSupabaseClient(); | ||||
| const message = useMessage(); | ||||
| const dialog = useDialog(); | ||||
|  | ||||
| const options = { | ||||
|   minimap: { enabled: false } | ||||
| }; | ||||
|  | ||||
| const submitting = ref(false); | ||||
|  | ||||
| const { data: challenge } = await client | ||||
| @@ -63,16 +57,48 @@ const { data: challenge } = await client | ||||
|   .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 answer = ref(challenge?.answer ?? {}); | ||||
| 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: "警告", | ||||
| @@ -88,7 +114,7 @@ function abandon() { | ||||
|  | ||||
|       const delay = (ms: number) => new Promise(res => setTimeout(res, ms)); | ||||
|  | ||||
|       instance.loading = true | ||||
|       instance.loading = true; | ||||
|       message.info("已放弃挑战该题"); | ||||
|  | ||||
|       await delay(1850); | ||||
| @@ -101,16 +127,3 @@ async function submit() { | ||||
|  | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| .code-editor { | ||||
|   min-width: calc(100% + 48px); | ||||
|   margin-top: -20px; | ||||
|   margin-left: -24px; | ||||
|   margin-right: -24px; | ||||
| } | ||||
|  | ||||
| .divider-below-code { | ||||
|   margin-top: 0 !important; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -32,5 +32,5 @@ policy "Enable update access for users' own items" on "public"."challenges" | ||||
| as permissive for | ||||
| update | ||||
|     to public | ||||
|     using (author = auth.uid()) | ||||
|     using (author = auth.uid() and status = 'in-progress') | ||||
| with check (author = auth.uid()) | ||||
		Reference in New Issue
	
	Block a user