fixup result, add totaltime in exam, add todo in readme
This commit is contained in:
parent
2d3854a4fe
commit
cf868f7d65
8 changed files with 125 additions and 53 deletions
12
README.md
12
README.md
|
@ -8,7 +8,17 @@ This project utilizes `pnpm`, thus it is recommended
|
||||||
pnpm install
|
pnpm install
|
||||||
```
|
```
|
||||||
|
|
||||||
More information about setting up database will come here later
|
# To-do:
|
||||||
|
|
||||||
|
- [ ] re-forge database structure, script for processing, share appropriate files
|
||||||
|
- [ ] choose category
|
||||||
|
- [ ] beautify website
|
||||||
|
- [ ] better answer click recognition
|
||||||
|
- [ ] come up with how to show results appropriately
|
||||||
|
- [ ] i18n - pl, en, de, ua (not all questions are not available in ua, api handle)
|
||||||
|
- [ ] exam (maybe also results?) warning leave message on exit (refresh)
|
||||||
|
- [ ] lazy loading
|
||||||
|
- [ ] question timers, and at end of total timer show a message for a while before immediatly navigating to results (maybe sth similar also when normally ending exam)
|
||||||
|
|
||||||
## Development Server
|
## Development Server
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,19 @@ defineProps<{
|
||||||
<div
|
<div
|
||||||
class="select-none z-[-1] flex-1 flex items-stretch w-full justify-center *:object-contain"
|
class="select-none z-[-1] flex-1 flex items-stretch w-full justify-center *:object-contain"
|
||||||
>
|
>
|
||||||
<img :src="cdnUrl + media.ogName" alt="" v-if="media.fileType == 'jpg'" />
|
<!-- Reserved for getting to know the question (20s) in basic questions section
|
||||||
<video v-else-if="media.fileType == 'wmv'" :key="media.fileName" autoplay>
|
src="~/public/placeholder.svg" -->
|
||||||
|
<img
|
||||||
|
:src="cdnUrl + media.ogName"
|
||||||
|
alt=""
|
||||||
|
v-if="media.fileType == 'jpg'"
|
||||||
|
:key="`${media.ogName}-photo`"
|
||||||
|
/>
|
||||||
|
<video
|
||||||
|
v-else-if="media.fileType == 'wmv'"
|
||||||
|
:key="`${media.ogName}-video`"
|
||||||
|
autoplay
|
||||||
|
>
|
||||||
<source
|
<source
|
||||||
:src="cdnUrl + [media.fileName, 'mp4'].join('.')"
|
:src="cdnUrl + [media.fileName, 'mp4'].join('.')"
|
||||||
type="video/mp4"
|
type="video/mp4"
|
||||||
|
|
|
@ -23,18 +23,21 @@ const emit = defineEmits<{
|
||||||
>
|
>
|
||||||
<h1 class="text-[1.5rem]">{{ title }}</h1>
|
<h1 class="text-[1.5rem]">{{ title }}</h1>
|
||||||
<div class="*:inline">Punkty: <slot name="points" /> / 74</div>
|
<div class="*:inline">Punkty: <slot name="points" /> / 74</div>
|
||||||
<div class="*:inline">Wynik: pozytywny/negatywny</div>
|
<div class="*:inline">Wynik: <slot name="resultTrueFalse" /></div>
|
||||||
<div
|
<div
|
||||||
class="flex flex-row gap-2 *:py-1 *:px-3 *:border *:border-1 *:border-slate-300 *:rounded-md *:bg-slate-100"
|
class="flex flex-row gap-2 *:py-1 *:px-3 *:border *:border-1 *:border-slate-300 *:rounded-md *:bg-slate-100"
|
||||||
>
|
>
|
||||||
<button class="text-slate-600" @click="emit('homepage')">
|
<button
|
||||||
|
class="!border-slate-200 text-slate-600"
|
||||||
|
@click="emit('homepage')"
|
||||||
|
>
|
||||||
Wróć na stronę główną
|
Wróć na stronę główną
|
||||||
</button>
|
</button>
|
||||||
<button class="border-slate-200 bg-slate-50" @click="emit('newExam')">
|
<button class="!bg-slate-200 text-slate-800" @click="emit('newExam')">
|
||||||
Rozpocznij jeszcze raz
|
Rozpocznij jeszcze raz
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="!border-slate-500 !bg-slate-700 text-white"
|
class="!border-2 !border-slate-200 !bg-slate-700 text-white"
|
||||||
@click="emit('close')"
|
@click="emit('close')"
|
||||||
>
|
>
|
||||||
Przejrzyj odpowiedzi
|
Przejrzyj odpowiedzi
|
||||||
|
@ -42,14 +45,3 @@ const emit = defineEmits<{
|
||||||
</div>
|
</div>
|
||||||
</VueFinalModal>
|
</VueFinalModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
|
||||||
.confirm-modal-content button {
|
|
||||||
padding: 0 8px;
|
|
||||||
border: 1px solid;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
}
|
|
||||||
.dark .confirm-modal-content {
|
|
||||||
background: #000;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import * as _ from "lodash";
|
import { range } from "lodash";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
// result: ResultEndType;
|
result: ResultEndType;
|
||||||
countBasic: number;
|
countBasic: number;
|
||||||
countAdvanced: number;
|
countAdvanced: number;
|
||||||
question: BasicQuestion | AdvancedQuestion | undefined;
|
question: BasicQuestion | AdvancedQuestion | undefined;
|
||||||
|
@ -13,34 +13,48 @@ const props = defineProps<{
|
||||||
|
|
||||||
const isBasic = computed(() => props.now == "basic");
|
const isBasic = computed(() => props.now == "basic");
|
||||||
const isAdvanced = computed(() => props.now == "advanced");
|
const isAdvanced = computed(() => props.now == "advanced");
|
||||||
|
|
||||||
|
const boxesAmount = computed(() => {
|
||||||
|
if (isBasic.value) {
|
||||||
|
return 20 + 1;
|
||||||
|
} else if (isAdvanced.value) {
|
||||||
|
return 12 + 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col items-center p-4 gap-10 border-l border-slate-300 bg-slate-100"
|
class="flex flex-col items-center p-4 gap-6 border-l border-slate-300 bg-slate-100"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<button @click="$emit('end-exam')" class="btn-major">
|
<button @click="" class="btn-major">Wróć na stronę główną</button>
|
||||||
Wróć na stronę główną
|
<button @click="" class="btn-major">Rozpocznij jeszcze raz</button>
|
||||||
</button>
|
|
||||||
<button @click="$emit('end-exam')" class="btn-major">
|
|
||||||
Rozpocznij jeszcze raz
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row gap-6 *:flex-1 w-full">
|
<div class="flex flex-row gap-6 *:flex-1 w-full">
|
||||||
<button class="text-md text-white bg-blue-400">Pytania podstawowe</button>
|
<button
|
||||||
<button class="text-md text-white bg-blue-400">
|
class="text-md text-white bg-blue-400"
|
||||||
|
@click="$emit('change-now', 'basic')"
|
||||||
|
>
|
||||||
|
Pytania podstawowe
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="text-md text-white bg-blue-400"
|
||||||
|
@click="$emit('change-now', 'advanced')"
|
||||||
|
>
|
||||||
Pytania specjalistyczne
|
Pytania specjalistyczne
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full flex justify-center items-center">
|
<div
|
||||||
<div class="flex flex-row flex-wrap gap-2 items-stretch !w-max">
|
class="grid grid-cols-[repeat(auto-fit,50px)] gap-2 justify-around w-full"
|
||||||
<div
|
>
|
||||||
v-for="num in _.range(1, 21)"
|
<div
|
||||||
class="p-1 bg-blue-500 text-white w-8 aspect-square text-center"
|
v-for="num in range(1, boxesAmount)"
|
||||||
>
|
class="p-1 bg-blue-500 text-white text-center"
|
||||||
{{ num }}
|
>
|
||||||
</div>
|
{{ num }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row gap-6 *:flex-1 w-full">
|
<div class="flex flex-row gap-6 *:flex-1 w-full">
|
||||||
|
@ -51,7 +65,10 @@ const isAdvanced = computed(() => props.now == "advanced");
|
||||||
Pokaż poprawną odpowiedź
|
Pokaż poprawną odpowiedź
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
Poprawna odpowiedź
|
||||||
|
<br />
|
||||||
|
Zaznaczona odpowiedź
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- <style></style> -->
|
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{
|
import type { Duration } from "date-fns";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
points: number | undefined;
|
points: number | undefined;
|
||||||
category: string | undefined;
|
category: string | undefined;
|
||||||
timeRemaining?: string | undefined;
|
timeRemaining?: Duration | undefined;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const timeRemainingFriendly = computed(() => {
|
||||||
|
if (typeof props.timeRemaining !== "undefined") {
|
||||||
|
let seconds = props.timeRemaining.seconds ?? 0;
|
||||||
|
return `${props.timeRemaining.minutes ?? 0}:${
|
||||||
|
seconds >= 0 && seconds < 10 ? 0 : ""
|
||||||
|
}${seconds ?? 0}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -20,9 +31,11 @@ defineProps<{
|
||||||
<span class="block">Aktualna kategoria (implement)</span>
|
<span class="block">Aktualna kategoria (implement)</span>
|
||||||
<div class="info-little-box">{{ category }}</div>
|
<div class="info-little-box">{{ category }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="typeof timeRemaining === 'string'">
|
<div v-if="typeof timeRemaining !== 'undefined'">
|
||||||
<span class="block">Czas do końca egzaminu (implement)</span>
|
<span class="block">Czas do końca egzaminu</span>
|
||||||
<div class="info-little-box">{{ timeRemaining }}</div>
|
<div class="info-little-box w-18 text-center">
|
||||||
|
{{ timeRemainingFriendly }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -6,6 +6,29 @@ definePageMeta({
|
||||||
import "7.css/dist/7.scoped.css";
|
import "7.css/dist/7.scoped.css";
|
||||||
import { useExamStore } from "~/store/examResults";
|
import { useExamStore } from "~/store/examResults";
|
||||||
|
|
||||||
|
import { intervalToDuration, addMinutes, addSeconds, isEqual } from "date-fns";
|
||||||
|
|
||||||
|
const nowTime = ref(new Date());
|
||||||
|
const timeEnd = addMinutes(new Date(), 25);
|
||||||
|
|
||||||
|
const timeRemainingTotal = computed(() =>
|
||||||
|
intervalToDuration({
|
||||||
|
start: nowTime.value,
|
||||||
|
end: timeEnd,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
// const timeRemainingQuestion - to implement
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const endInterval = setInterval(() => {
|
||||||
|
nowTime.value = addSeconds(nowTime.value, 1);
|
||||||
|
if (isEqual(nowTime.value, timeEnd)) {
|
||||||
|
clearInterval(endInterval);
|
||||||
|
endExam();
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
const examStore = useExamStore();
|
const examStore = useExamStore();
|
||||||
|
|
||||||
examStore.resetExam();
|
examStore.resetExam();
|
||||||
|
@ -90,7 +113,7 @@ function endExam() {
|
||||||
next();
|
next();
|
||||||
examStore.result = result.value;
|
examStore.result = result.value;
|
||||||
examStore.end = true;
|
examStore.end = true;
|
||||||
return navigateTo("/result");
|
return navigateTo("/result", { replace: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const questionBasic = computed<BasicQuestion | undefined>(() =>
|
const questionBasic = computed<BasicQuestion | undefined>(() =>
|
||||||
|
@ -133,7 +156,7 @@ const result: Ref<ResultEndType> = ref({
|
||||||
<TopBar
|
<TopBar
|
||||||
:points="question?.liczba_pkt"
|
:points="question?.liczba_pkt"
|
||||||
:category="`B`"
|
:category="`B`"
|
||||||
:time-remaining="`25:00`"
|
:time-remaining="timeRemainingTotal"
|
||||||
/>
|
/>
|
||||||
<Media :media="media" />
|
<Media :media="media" />
|
||||||
<BasicQuestionBlock
|
<BasicQuestionBlock
|
||||||
|
|
|
@ -8,26 +8,26 @@ definePageMeta({
|
||||||
|
|
||||||
const examStore = useExamStore();
|
const examStore = useExamStore();
|
||||||
|
|
||||||
const points = ref<number>();
|
const points = ref<number>(0);
|
||||||
|
|
||||||
if (!examStore.end) {
|
if (!examStore.end) {
|
||||||
examStore.resetExam();
|
examStore.resetExam();
|
||||||
await navigateTo("/");
|
await navigateTo("/");
|
||||||
} else {
|
} else {
|
||||||
let sum = 0;
|
|
||||||
examStore.result.basic.forEach((answer) => {
|
examStore.result.basic.forEach((answer) => {
|
||||||
if (answer.chosen_is_correct) {
|
if (answer.chosen_is_correct) {
|
||||||
sum += answer.question?.liczba_pkt ?? 0;
|
points.value += answer.question?.liczba_pkt ?? 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
examStore.result.advanced.forEach((answer) => {
|
examStore.result.advanced.forEach((answer) => {
|
||||||
if (answer.chosen_is_correct) {
|
if (answer.chosen_is_correct) {
|
||||||
sum += answer.question?.liczba_pkt ?? 0;
|
points.value += answer.question?.liczba_pkt ?? 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
points.value = sum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resultTrueFalse = ref(points.value >= 68 ? "pozytywny" : "negatywny");
|
||||||
|
|
||||||
const countBasic = ref(0);
|
const countBasic = ref(0);
|
||||||
const countAdvanced = ref(0);
|
const countAdvanced = ref(0);
|
||||||
|
|
||||||
|
@ -89,9 +89,14 @@ const { open, close } = useModal({
|
||||||
},
|
},
|
||||||
slots: {
|
slots: {
|
||||||
points: `${points.value}`,
|
points: `${points.value}`,
|
||||||
|
resultTrueFalse: resultTrueFalse,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
open();
|
open();
|
||||||
|
|
||||||
|
function changeNow(to: string) {
|
||||||
|
now.value = to;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -117,15 +122,15 @@ open();
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<RightBarResult
|
<RightBarResult
|
||||||
|
:result="examStore.result"
|
||||||
:question="question"
|
:question="question"
|
||||||
:question-basic="questionBasic"
|
:question-basic="questionBasic"
|
||||||
:question-advanced="questionAdvanced"
|
:question-advanced="questionAdvanced"
|
||||||
:count-basic="countBasic"
|
:count-basic="countBasic"
|
||||||
:count-advanced="countAdvanced"
|
:count-advanced="countAdvanced"
|
||||||
:now="now"
|
:now="now"
|
||||||
|
@change-now="changeNow"
|
||||||
/>
|
/>
|
||||||
<!-- :result="result" -->
|
|
||||||
<!-- @next-question="next()" -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
1
public/placeholder.svg
Normal file
1
public/placeholder.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="680.764" height="528.354" viewBox="0 0 180.119 139.794"><g transform="translate(-13.59 -66.639)" paint-order="fill markers stroke"><path fill="#d0d0d0" d="M13.591 66.639H193.71v139.794H13.591z"/><path d="m118.507 133.514-34.249 34.249-15.968-15.968-41.938 41.937H178.726z" opacity=".675" fill="#fff"/><circle cx="58.217" cy="108.555" r="11.773" opacity=".675" fill="#fff"/><path fill="none" d="M26.111 77.634h152.614v116.099H26.111z"/></g></svg>
|
After Width: | Height: | Size: 492 B |
Loading…
Add table
Reference in a new issue