feat(backend): Overzicht over submissions toegevoegd.
This commit is contained in:
		
							parent
							
								
									cc92727a09
								
							
						
					
					
						commit
						4dc880c2f7
					
				
					 9 changed files with 165 additions and 39 deletions
				
			
		|  | @ -76,6 +76,12 @@ | |||
|     "failed": "fehlgeschlagen", | ||||
|     "wrong": "etwas ist schief gelaufen", | ||||
|     "created": "erstellt", | ||||
|     "submit": "Einreichen", | ||||
|     "markAsDone": "Als fertig markieren" | ||||
|     "submitSolution": "Lösung einreichen", | ||||
|     "submitNewSolution": "Neue Lösung einreichen", | ||||
|     "markAsDone": "Als fertig markieren", | ||||
|     "groupSubmissions": "Einreichungen dieser Gruppe", | ||||
|     "taskCompleted": "Aufgabe erledigt.", | ||||
|     "submittedBy": "Eingereicht von", | ||||
|     "timestamp": "Zeitpunkt", | ||||
|     "loadSubmission": "Einladen" | ||||
| } | ||||
|  |  | |||
|  | @ -76,6 +76,12 @@ | |||
|     "failed": "failed", | ||||
|     "wrong": "something went wrong", | ||||
|     "created": "created", | ||||
|     "submit": "Submit", | ||||
|     "markAsDone": "Mark as done" | ||||
|     "submitSolution": "Submit solution", | ||||
|     "submitNewSolution": "Submit new solution", | ||||
|     "markAsDone": "Mark as completed", | ||||
|     "groupSubmissions": "This group's submissions", | ||||
|     "taskCompleted": "Task completed.", | ||||
|     "submittedBy": "Submitted by", | ||||
|     "timestamp": "Timestamp", | ||||
|     "loadSubmission": "Load" | ||||
| } | ||||
|  |  | |||
|  | @ -75,5 +75,13 @@ | |||
|     "sent": "envoyé", | ||||
|     "failed": "échoué", | ||||
|     "wrong": "quelque chose n'a pas fonctionné", | ||||
|     "created": "créé" | ||||
|     "created": "créé", | ||||
|     "submitSolution": "Soumettre la solution", | ||||
|     "submitNewSolution": "Soumettre une nouvelle solution", | ||||
|     "markAsDone": "Marquer comme terminé", | ||||
|     "groupSubmissions": "Soumissions de ce groupe", | ||||
|     "taskCompleted": "Tâche terminée.", | ||||
|     "submittedBy": "Soumis par", | ||||
|     "timestamp": "Horodatage", | ||||
|     "loadSubmission": "Charger" | ||||
| } | ||||
|  |  | |||
|  | @ -76,6 +76,12 @@ | |||
|     "failed": "mislukt", | ||||
|     "wrong": "er ging iets verkeerd", | ||||
|     "created": "gecreëerd", | ||||
|     "submit": "Indienen", | ||||
|     "markAsDone": "Markeren als afgewerkt" | ||||
|     "submitSolution": "Oplossing indienen", | ||||
|     "submitNewSolution": "Nieuwe oplossing indienen", | ||||
|     "markAsDone": "Markeren als afgewerkt", | ||||
|     "groupSubmissions": "Indieningen van deze groep", | ||||
|     "taskCompleted": "Taak afgewerkt.", | ||||
|     "submittedBy": "Ingediend door", | ||||
|     "timestamp": "Tijdstip", | ||||
|     "loadSubmission": "Inladen" | ||||
| } | ||||
|  |  | |||
|  | @ -1,29 +1,29 @@ | |||
| <script setup lang="ts"> | ||||
| import { Language } from "@/data-objects/language.ts"; | ||||
| import type { UseQueryReturnType } from "@tanstack/vue-query"; | ||||
| import { useLearningObjectHTMLQuery } from "@/queries/learning-objects.ts"; | ||||
| import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||
| import {computed, ref} from "vue"; | ||||
| import authService from "@/services/auth/auth-service.ts"; | ||||
| import type {SubmissionData} from "@/views/learning-paths/learning-object/submission-data"; | ||||
| import LearningObjectContentView from "@/views/learning-paths/learning-object/content/LearningObjectContentView.vue"; | ||||
| import LearningObjectSubmissionsView from "@/views/learning-paths/learning-object/submissions/LearningObjectSubmissionsView.vue"; | ||||
|     import { Language } from "@/data-objects/language.ts"; | ||||
|     import type { UseQueryReturnType } from "@tanstack/vue-query"; | ||||
|     import { useLearningObjectHTMLQuery } from "@/queries/learning-objects.ts"; | ||||
|     import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||
|     import {computed, ref} from "vue"; | ||||
|     import authService from "@/services/auth/auth-service.ts"; | ||||
|     import type {SubmissionData} from "@/views/learning-paths/learning-object/submission-data"; | ||||
|     import LearningObjectContentView from "@/views/learning-paths/learning-object/content/LearningObjectContentView.vue"; | ||||
|     import LearningObjectSubmissionsView from "@/views/learning-paths/learning-object/submissions/LearningObjectSubmissionsView.vue"; | ||||
| 
 | ||||
| const isStudent = computed(() => authService.authState.activeRole === "student"); | ||||
|     const isStudent = computed(() => authService.authState.activeRole === "student"); | ||||
| 
 | ||||
| const props = defineProps<{ | ||||
|     hruid: string; | ||||
|     language: Language; | ||||
|     version: number, | ||||
|     group?: {forGroup: number, assignmentNo: number, classId: string} | ||||
| }>(); | ||||
|     const props = defineProps<{ | ||||
|         hruid: string; | ||||
|         language: Language; | ||||
|         version: number, | ||||
|         group?: {forGroup: number, assignmentNo: number, classId: string} | ||||
|     }>(); | ||||
| 
 | ||||
| const learningObjectHtmlQueryResult: UseQueryReturnType<Document, Error> = useLearningObjectHTMLQuery( | ||||
|     () => props.hruid, | ||||
|     () => props.language, | ||||
|     () => props.version, | ||||
| ); | ||||
| const currentSubmission = ref<SubmissionData>([]); | ||||
|     const learningObjectHtmlQueryResult: UseQueryReturnType<Document, Error> = useLearningObjectHTMLQuery( | ||||
|         () => props.hruid, | ||||
|         () => props.language, | ||||
|         () => props.version, | ||||
|     ); | ||||
|     const currentSubmission = ref<SubmissionData>([]); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|  |  | |||
|  | @ -38,7 +38,6 @@ | |||
|     } | ||||
| 
 | ||||
|     function attachQuestionListeners(): void { | ||||
|         let counter = 0; | ||||
|         forEachQuestion((index, _name, type, element) => { | ||||
|             getGiftAdapterForType(type)?.installListener( | ||||
|                 element, | ||||
|  | @ -46,7 +45,6 @@ | |||
|                     submissionData.value = copyArrayWith(index, newAnswer, submissionData.value ?? []) | ||||
|                 } | ||||
|             ); | ||||
|             counter++; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | @ -62,7 +60,12 @@ | |||
|         submissionData.value = answers; | ||||
|     } | ||||
| 
 | ||||
|     onMounted(() => nextTick(() => attachQuestionListeners())); | ||||
|     onMounted(() => | ||||
|         nextTick(() => { | ||||
|             attachQuestionListeners() | ||||
|             setAnswers(props.submissionData ?? []); | ||||
|         }) | ||||
|     ); | ||||
| 
 | ||||
|     watch(() => props.learningObjectContent, async () => { | ||||
|         await nextTick(); | ||||
|  |  | |||
|  | @ -0,0 +1,55 @@ | |||
| <script setup lang="ts"> | ||||
|     import type {SubmissionDTO} from "@dwengo-1/common/interfaces/submission"; | ||||
|     import {computed} from "vue"; | ||||
|     import {useI18n} from "vue-i18n"; | ||||
| 
 | ||||
|     const { t } = useI18n(); | ||||
| 
 | ||||
|     const props = defineProps<{ | ||||
|         allSubmissions: SubmissionDTO[] | ||||
|     }>(); | ||||
|     const emit = defineEmits<{ | ||||
|         (e: "submission-selected", submission: SubmissionDTO): void | ||||
|     }>(); | ||||
| 
 | ||||
|     const headers = computed(() => [ | ||||
|         { title: "#", value: "submissionNo", width: "50px" }, | ||||
|         { title: t("submittedBy"), value: "submittedBy" }, | ||||
|         { title: t("timestamp"), value: "timestamp"}, | ||||
|         { title: "", key: "action", width: "70px", sortable: false }, | ||||
|     ]); | ||||
| 
 | ||||
|     const data = computed(() => props.allSubmissions.map(submission => ({ | ||||
|         submissionNo: submission.submissionNumber, | ||||
|         submittedBy: `${submission.submitter.firstName} ${submission.submitter.lastName}`, | ||||
|         timestamp: submission.time ? new Date(submission.time).toLocaleString(): "-", | ||||
|         dto: submission | ||||
|     }))); | ||||
| 
 | ||||
|     function selectSubmission(submission: SubmissionDTO) { | ||||
|         emit('submission-selected', submission); | ||||
|     } | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|     <v-card> | ||||
|         <v-card-title>{{ t("groupSubmissions") }}</v-card-title> | ||||
|         <v-card-text> | ||||
|             <v-data-table :headers="headers" | ||||
|                           :items="data" | ||||
|                           density="compact" | ||||
|                           hide-default-footer | ||||
|             > | ||||
|                 <template v-slot:item.action="{ item }"> | ||||
|                     <v-btn density="compact" variant="plain" @click="selectSubmission(item.dto)"> | ||||
|                         {{ t("loadSubmission") }} | ||||
|                     </v-btn> | ||||
|                 </template> | ||||
|             </v-data-table> | ||||
|         </v-card-text> | ||||
|     </v-card> | ||||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
| 
 | ||||
| </style> | ||||
|  | @ -5,7 +5,12 @@ | |||
|     import {useSubmissionsQuery} from "@/queries/submissions.ts"; | ||||
|     import UsingQueryResult from "@/components/UsingQueryResult.vue"; | ||||
|     import SubmitButton from "@/views/learning-paths/learning-object/submissions/SubmitButton.vue"; | ||||
|     import {watch} from "vue"; | ||||
|     import {computed, watch} from "vue"; | ||||
|     import LearningObjectSubmissionsTable | ||||
|         from "@/views/learning-paths/learning-object/submissions/LearningObjectSubmissionsTable.vue"; | ||||
|     import {useI18n} from "vue-i18n"; | ||||
| 
 | ||||
|     const { t } = useI18n(); | ||||
| 
 | ||||
|     const props = defineProps<{ | ||||
|         submissionData?: SubmissionData, | ||||
|  | @ -28,17 +33,38 @@ | |||
|         () => true | ||||
|     ); | ||||
| 
 | ||||
|     function loadSubmission(submission: SubmissionDTO) { | ||||
|         emit("update:submissionData", JSON.parse(submission.content)); | ||||
|         console.log(`emitted: ${JSON.parse(submission.content)}`); | ||||
|     function emitSubmissionData(submissionData: SubmissionData) { | ||||
|         emit("update:submissionData", submissionData); | ||||
|     } | ||||
| 
 | ||||
|     function emitSubmission(submission: SubmissionDTO) { | ||||
|         emitSubmissionData(JSON.parse(submission.content)); | ||||
|     } | ||||
| 
 | ||||
|     watch(submissionQuery.data, () => { | ||||
|         const submissions = submissionQuery.data.value; | ||||
|         if (submissions && submissions.length > 0) { | ||||
|             loadSubmission(submissions[submissions.length - 1]); | ||||
|             emitSubmission(submissions[submissions.length - 1]); | ||||
|         } else { | ||||
|             emitSubmissionData([]); | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     const lastSubmission = computed<SubmissionData>(() => { | ||||
|         const submissions = submissionQuery.data.value; | ||||
|         if (!submissions || submissions.length === 0) { | ||||
|             return undefined; | ||||
|         } | ||||
|         return JSON.parse(submissions[submissions.length - 1].content); | ||||
|     }); | ||||
| 
 | ||||
|     const showSubmissionTable = computed(() => | ||||
|         props.submissionData !== undefined && props.submissionData.length > 0 | ||||
|     ); | ||||
| 
 | ||||
|     const showIsDoneMessage = computed(() => | ||||
|         lastSubmission.value !== undefined && lastSubmission.value.length === 0 | ||||
|     ); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|  | @ -51,8 +77,24 @@ | |||
|             :submission-data="props.submissionData" | ||||
|             :submissions="submissions.data" | ||||
|         /> | ||||
|         <div class="submit-submissions-spacer"></div> | ||||
|         <v-alert icon="mdi-check" | ||||
|                  :text="t('taskCompleted')" | ||||
|                  type="success" | ||||
|                  variant="tonal" | ||||
|                  density="compact" | ||||
|                  v-if="showIsDoneMessage" | ||||
|         ></v-alert> | ||||
|         <learning-object-submissions-table | ||||
|             v-if="submissionQuery.data && showSubmissionTable" | ||||
|             :all-submissions="submissions.data" | ||||
|             @submission-selected="emitSubmission" | ||||
|         /> | ||||
|     </using-query-result> | ||||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
| .submit-submissions-spacer { | ||||
|     height: 20px; | ||||
| } | ||||
| </style> | ||||
|  |  | |||
|  | @ -81,12 +81,12 @@ | |||
|         if (props.submissionData && props.submissionData.length === 0) { | ||||
|             return t("markAsDone"); | ||||
|         } | ||||
|         return t("submit"); | ||||
|         return t(props.submissions.length > 0 ? "submitNewSolution" : "submitSolution"); | ||||
|     }); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|     <v-btn v-if="isStudent" | ||||
|     <v-btn v-if="isStudent && !isSubmitDisabled" | ||||
|            prepend-icon="mdi-check" | ||||
|            variant="elevated" | ||||
|            :loading="submissionIsPending" | ||||
|  |  | |||
		Reference in a new issue
	
	 Gerald Schmittinger
						Gerald Schmittinger