Skip to content

Commit

Permalink
feat: question
Browse files Browse the repository at this point in the history
  • Loading branch information
dest1n1s committed Aug 26, 2023
1 parent 64b602f commit 6645d30
Show file tree
Hide file tree
Showing 11 changed files with 326 additions and 164 deletions.
2 changes: 1 addition & 1 deletion .router/typed-router.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ declare module 'vue-router/auto/routes' {
'/login/password': RouteRecordInfo<'/login/password', '/login/password', Record<never, never>, Record<never, never>>,
'/online': RouteRecordInfo<'/online', '/online', Record<never, never>, Record<never, never>>,
'/question/': RouteRecordInfo<'/question/', '/question', Record<never, never>, Record<never, never>>,
'/question/[id]': RouteRecordInfo<'/question/[id]', '/question/:id', { id: ParamValue<true> }, { id: ParamValue<false> }>,
'/question/[index]': RouteRecordInfo<'/question/[index]', '/question/:index', { index: ParamValue<true> }, { index: ParamValue<false> }>,
'/register': RouteRecordInfo<'/register', '/register', Record<never, never>, Record<never, never>>,
'/register/': RouteRecordInfo<'/register/', '/register', Record<never, never>, Record<never, never>>,
'/register/email': RouteRecordInfo<'/register/email', '/register/email', Record<never, never>, Record<never, never>>,
Expand Down
37 changes: 27 additions & 10 deletions src/apis/question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,36 @@ export const getTest = async (version?: number): Promise<Test> => {
return TestSchema.parse(response.data)
}

export const answerTest = async (testAnswer: TestAnswer) => {
export const submitTestAnswer = async (testAnswer: TestAnswer) => {
const response = await authRequest.post('/register/questions/_answer', testAnswer)
const data = z
.object({
message: z.string(),
access: z.string(),
refresh: z.string(),
correct: z.boolean(),
wrongQuestionIds: z.array(z.number())
.discriminatedUnion('correct', [
z.object({
correct: z.literal(true),
access: z.string(),
refresh: z.string(),
message: z.string()
}),
z.object({
correct: z.literal(false),
message: z.string(),
wrongQuestionIds: z.array(z.number().int())
})
])
.transform((data) => {
if (data.correct) {
return {
wrongQuestionIds: [],
...data
}
}
return data
})
.parse(response.data)
const { access, refresh } = useJwtTokens()
access.value = data.access
refresh.value = data.refresh
if (data.correct) {
const { access, refresh } = useJwtTokens()
access.value = data.access
refresh.value = data.refresh
}
return data
}
3 changes: 3 additions & 0 deletions src/globalErrorHandler.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { useNotification } from '@/composables/notification'
import { AxiosError } from 'axios'
import { ZodError } from 'zod'

export const globalErrorHandler = (err: any) => {
const not = useNotification()
if (err instanceof Error) {
if (err instanceof AxiosError) {
not.error(err.response?.data?.message ?? err.message)
} else if (err instanceof ZodError) {
not.error(err.issues[0].message)
} else not.error(err.message)
}
console.error(err)
Expand Down
84 changes: 0 additions & 84 deletions src/pages/question/[id].vue

This file was deleted.

56 changes: 0 additions & 56 deletions src/pages/question/[id]@side.vue

This file was deleted.

156 changes: 156 additions & 0 deletions src/pages/question/[index].vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<template>
<v-card-title> 入站答题 </v-card-title>
<v-card-text
v-if="currentQuestion"
class="text-left"
>
<b> {{ index }}. {{ currentQuestion.question }} </b>
<v-radio-group
v-if="currentQuestion.type === 'single-selection' || currentQuestion.type === 'true-or-false'"
:model-value="currentQuestion.answer.length > 0 && currentQuestion.answer[0]"
column
class="ml-n1 my-1"
color="red"
@update:model-value="updateRadioGroup"
>
<v-radio
v-for="item in currentQuestion.options"
:key="item"
:label="item"
:value="item"
>
</v-radio>
</v-radio-group>
<template v-else-if="currentQuestion.type === 'multi-selection'">
<v-checkbox
v-for="item in currentQuestion.options"
:key="item"
:model-value="currentQuestion.answer"
:label="item"
:value="item"
@update:model-value="updateCheckboxGroup"
>
</v-checkbox>
</template>
</v-card-text>
<v-card-text style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr))">
<div class="d-flex justify-start">
<v-btn
v-if="index > 1"
variant="text"
color="secondary"
@click="router.push(`/question/${index - 1}`)"
>
上一题
</v-btn>
</div>

<div class="d-flex justify-center">
<v-btn
v-if="mobile"
variant="text"
color="secondary"
@click="side = !side"
>
目录
</v-btn>
</div>
<div class="d-flex justify-end">
<v-btn
v-if="index < total"
variant="flat"
color="secondary"
@click="router.push(`/question/${index + 1}`)"
>
下一题
</v-btn>
<v-btn
v-else
variant="flat"
color="secondary"
@click="onSubmit"
>
交卷
</v-btn>
</div>
</v-card-text>
</template>

<script setup lang="ts">
import { useDisplay } from 'vuetify'
import { useSide } from '@/composables/side'
import { useRouter } from 'vue-router/auto'
import { useRouteParams } from '@vueuse/router'
import { computed, onBeforeMount } from 'vue'
import { useQuestionStore } from '@/stores/question'
import { useLoading } from '@/composables/loading'
import { submitTestAnswer } from '@/apis/question'
import { TestAnswerSchema } from '@/types/question'
import { useNotification } from '@/composables/notification'
const { mobile } = useDisplay()
const { side } = useSide()
const { load } = useLoading()
const not = useNotification()
const router = useRouter()
const questionStore = useQuestionStore()
const indexParam = useRouteParams('index')
const index = computed(() => Number(indexParam.value))
const total = computed(() => questionStore.questions.length)
const currentQuestion = computed(() =>
questionStore.questions.find((_, i) => i + 1 === index.value)
)
const updateRadioGroup = (value: string) => {
currentQuestion.value!.answer = [value]
currentQuestion.value!.status = 'answered'
}
const updateCheckboxGroup: any = (values: string[]) => {
currentQuestion.value!.answer = values
if (values.length === 0) currentQuestion.value!.status = 'not-answered'
else currentQuestion.value!.status = 'answered'
}
const onSubmit = async () => {
const { message, correct, wrongQuestionIds } = await load(
submitTestAnswer(
TestAnswerSchema.parse({
answers: questionStore.questions,
version: questionStore.test!.version
})
)
)
if (correct) {
not.success(message)
router.push('/online')
} else {
not.error(message)
for (const question of questionStore.questions) {
if (wrongQuestionIds.includes(question.id)) {
question.status = 'wrong'
} else {
question.status = 'correct'
}
}
router.push(`/question/${wrongQuestionIds[0]}`)
}
}
onBeforeMount(() => {
if (!questionStore.test) {
router.push('/question/')
} else if (!currentQuestion.value) {
router.push(`/question/1`)
}
})
</script>

<route lang="json">
{
"meta": {
"side": true
}
}
</route>
Loading

0 comments on commit 6645d30

Please sign in to comment.