From 97b8d5dab9fc1b99a385246fbe316ac0a4032dce Mon Sep 17 00:00:00 2001 From: NetMan <13informatyka14@gmail.com> Date: Mon, 15 Dec 2025 20:14:54 +0100 Subject: [PATCH] question timers, little fixes to nav/store --- README.md | 2 +- components/MediaBox.vue | 27 +++++- components/ResultModal.vue | 6 +- components/bar/right/Exam.vue | 53 ++++++----- components/bar/right/Result.vue | 25 +++-- package.json | 1 + pages/anomaly.vue | 11 ++- pages/exam.vue | 163 ++++++++++++++++++++++---------- pages/index.vue | 6 +- pages/result.vue | 11 ++- pnpm-lock.yaml | 34 +++++++ store/examStore.ts | 10 +- 12 files changed, 242 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index 4e36209..fcd1e0b 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,8 @@ You also need the exam media files from the (Ministry of Infrasture)[https://www - [x] beautify website (good for now) - [x] Fixed? Needs testing, but should be fine question-mark? - fix pinia middleware between pages, MAJOR ISSUE - finishing exam sometimes redirects to homepage instead of results, help appreciated - [x] (scrapped - lazy loading) +- [x] question timers - [ ] exam (& results?) warning leave message on exit and timer end (and definitely on refresh) -- [ ] question timers - [ ] i18n - pl, en, de, ua (not all questions are available in ua, api handle) - UI i18n - db: examstore add language field, api handle languages diff --git a/components/MediaBox.vue b/components/MediaBox.vue index 58f7c58..7cc0c59 100644 --- a/components/MediaBox.vue +++ b/components/MediaBox.vue @@ -6,8 +6,11 @@ const cdnUrl = runtimeConfig.public.cdn_url; const route = useRoute(); +const emit = defineEmits(['mediaload']); + const props = defineProps<{ mediaPath: string | null | undefined; + phase: string; }>(); const media = computed(() => { @@ -21,6 +24,21 @@ const media = computed(() => { } return { name: dotSplit?.join('.'), type }; }); + +const video = ref(); + +function onVideoLoad() { + if (route.path === '/exam') { + video.value.play(); + let duration = video.value.duration; + if (isNaN(duration) || duration == Infinity) { + duration = 0; + } + setTimeout(() => { + emit('mediaload'); + }, duration * 1000); + } +} @@ -28,23 +46,26 @@ const media = computed(() => { class="select-none flex-auto w-full *:object-contain *:w-full *:h-full *:max-h-full relative *:absolute" :class="route.path === '/exam' ? 'z-[-1]' : ''" > + Brak mediówPytanie bez wizualizacji diff --git a/components/ResultModal.vue b/components/ResultModal.vue index 65e4b7c..cd97fe9 100644 --- a/components/ResultModal.vue +++ b/components/ResultModal.vue @@ -5,7 +5,7 @@ onMounted(() => { myModal.value?.showModal(); }); -defineEmits(['again']); +defineEmits(['again', 'home']); @@ -21,7 +21,9 @@ defineEmits(['again']); Punkty: / 74 Wynik: - Wróć na stronę główną + + Wróć na stronę główną + Rozpocznij jeszcze raz diff --git a/components/bar/right/Exam.vue b/components/bar/right/Exam.vue index ed31d10..9ebeb90 100644 --- a/components/bar/right/Exam.vue +++ b/components/bar/right/Exam.vue @@ -4,11 +4,15 @@ defineProps<{ countAdvanced: number; now: string | null | undefined; ending: boolean; + setBasic: boolean; + time: number; + phase: string; }>(); const emit = defineEmits<{ endExam: []; nextQuestion: []; + nextTime: []; }>(); @@ -36,38 +40,45 @@ const emit = defineEmits<{ - + Czas na zapoznanie się z pytaniem - START + START - 20s + :value="time" + max="20" + > + + {{ time >= 0 ? time : 0 }}s + - + Czas na udzielenie odpowiedzi - 15s + :value="time" + :max="phase == 'start-basic' ? 15 : 45" + > + + {{ time >= 0 ? time : 0 }}s + - + Następne pytanie @@ -76,16 +87,12 @@ const emit = defineEmits<{ diff --git a/components/bar/right/Result.vue b/components/bar/right/Result.vue index e07b057..277793f 100644 --- a/components/bar/right/Result.vue +++ b/components/bar/right/Result.vue @@ -12,6 +12,7 @@ const emit = defineEmits<{ changeNow: [value: string]; changeCount: [num: number]; again: []; + home: []; }>(); @@ -19,9 +20,9 @@ const emit = defineEmits<{ - + Wróć na stronę główną - + Pytania podstawowe @@ -38,10 +39,12 @@ const emit = defineEmits<{ class="btn btn-md" name="chooser" :class="`${ - result.basic[num].question?.correct_answer === - result.basic[num].chosen_answer - ? 'btn-success' - : 'btn-error' + result.basic[num].chosen_answer == '' + ? 'btn-warning' + : result.basic[num].question?.correct_answer === + result.basic[num].chosen_answer + ? 'btn-success' + : 'btn-error' } ${now === 'basic' && countBasic === num ? 'outline-set-solid outline-2' : ''}`" :checked="now === 'basic' ? countBasic === num : false" @click=" @@ -66,10 +69,12 @@ const emit = defineEmits<{ class="btn btn-md" name="chooser" :class="`${ - result.advanced[num].question?.correct_answer === - result.advanced[num].chosen_answer - ? 'btn-success' - : 'btn-error' + result.advanced[num].chosen_answer == '' + ? 'btn-warning' + : result.advanced[num].question?.correct_answer === + result.advanced[num].chosen_answer + ? 'btn-success' + : 'btn-error' } ${now === 'advanced' && countAdvanced === num ? 'outline-set-solid outline-2' : ''}`" :checked="now === 'advanced' ? countAdvanced === num : false" @click=" diff --git a/package.json b/package.json index 6c8d648..553781e 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@nuxt/image": "1.10.0", "@nuxtjs/tailwindcss": "6.13.2", "@pinia/nuxt": "0.11.0", + "@vueuse/core": "^14.1.0", "array-shuffle": "^3.0.0", "daisyui": "^5.0.27", "date-fns": "^4.1.0", diff --git a/pages/anomaly.vue b/pages/anomaly.vue index 4e5a00b..e1dd3fd 100644 --- a/pages/anomaly.vue +++ b/pages/anomaly.vue @@ -8,10 +8,15 @@ const advancedStore = useAdvancedStore(); Nastąpiła anomalia - Kategoria: {{ examStore.category != '' ? examStore.category : '""' }} + Przekierowanie z: {{ useRoute().redirectedFrom ?? '""' }} + Kategoria: + {{ examStore.category != '' ? examStore.category : '""' }} + Koniec: {{ examStore.end }} - Pytania podstawowe: {{ basicStore.basic }} - Pytania specjalistyczne: {{ advancedStore.advanced }} + Pytania podstawowe: {{ basicStore.basic }} + + Pytania specjalistyczne: + {{ advancedStore.advanced }} Wróć na stronę główną diff --git a/pages/exam.vue b/pages/exam.vue index b332a9a..1d91480 100644 --- a/pages/exam.vue +++ b/pages/exam.vue @@ -1,21 +1,14 @@ - + Egzamin teorytyczny {{ examStore.category }} {{ points }} @@ -108,7 +114,7 @@ async function again() { - + {{ points }} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index af1dd98..023b3ac 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@pinia/nuxt': specifier: 0.11.0 version: 0.11.0(magicast@0.3.5)(pinia@3.0.2(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3))) + '@vueuse/core': + specifier: ^14.1.0 + version: 14.1.0(vue@3.5.13(typescript@5.8.3)) array-shuffle: specifier: ^3.0.0 version: 3.0.0 @@ -1273,6 +1276,9 @@ packages: '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -1498,6 +1504,19 @@ packages: '@vue/shared@3.5.13': resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + '@vueuse/core@14.1.0': + resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/metadata@14.1.0': + resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==} + + '@vueuse/shared@14.1.0': + resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==} + peerDependencies: + vue: ^3.5.0 + abbrev@3.0.1: resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} engines: {node: ^18.17.0 || >=20.5.0} @@ -6187,6 +6206,8 @@ snapshots: '@types/resolve@1.20.2': {} + '@types/web-bluetooth@0.0.21': {} + '@types/ws@8.18.1': dependencies: '@types/node': 22.14.1 @@ -6484,6 +6505,19 @@ snapshots: '@vue/shared@3.5.13': {} + '@vueuse/core@14.1.0(vue@3.5.13(typescript@5.8.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 14.1.0 + '@vueuse/shared': 14.1.0(vue@3.5.13(typescript@5.8.3)) + vue: 3.5.13(typescript@5.8.3) + + '@vueuse/metadata@14.1.0': {} + + '@vueuse/shared@14.1.0(vue@3.5.13(typescript@5.8.3))': + dependencies: + vue: 3.5.13(typescript@5.8.3) + abbrev@3.0.1: {} abort-controller@3.0.0: diff --git a/store/examStore.ts b/store/examStore.ts index 96a4c24..ae8a14b 100644 --- a/store/examStore.ts +++ b/store/examStore.ts @@ -38,16 +38,10 @@ export const useExamStore = defineStore('examStore', { async setEnd(end: boolean) { this.end = end; }, - async setBasic(basic: ResultType[]) { - useBasicStore().set(basic); - }, - async setAdvanced(advanced: ResultType[]) { - useAdvancedStore().set(advanced); - }, async mildReset() { this.end = false; - this.setBasic([]); - this.setAdvanced([]); + useBasicStore().set([]); + useAdvancedStore().set([]); }, async resetExam() { this.category = '';
{{ basicStore.basic }}
{{ advancedStore.advanced }}