Completion data in Performance Criteria view
This commit is contained in:
parent
dc3b1a4ca6
commit
46ad6cab36
|
|
@ -3,7 +3,7 @@ import type { PerformanceCriteria } from "@/types";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
criteria: PerformanceCriteria;
|
criteria: PerformanceCriteria;
|
||||||
showState: boolean;
|
showState?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
|
|
||||||
|
|
@ -1,95 +1,20 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { default as PerformanceCriteriaRow } from "@/components/competences/PerformanceCriteriaRow.vue";
|
import { default as PerformanceCriteriaRow } from "@/components/competences/PerformanceCriteriaRow.vue";
|
||||||
import { useCompetenceStore } from "@/stores/competence";
|
import { useCompetenceStore } from "@/stores/competence";
|
||||||
|
import type { CourseCompletionStatus } from "@/types";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { computed, Ref, ref } from "vue";
|
import { computed, Ref, ref } from "vue";
|
||||||
|
|
||||||
log.debug("CompetencesMainView created");
|
log.debug("CompetencesMainView created");
|
||||||
|
|
||||||
enum UserCriteriaState {
|
|
||||||
Open = "open",
|
|
||||||
Done = "done",
|
|
||||||
Nok = "notDone",
|
|
||||||
}
|
|
||||||
|
|
||||||
const competenceStore = useCompetenceStore();
|
const competenceStore = useCompetenceStore();
|
||||||
|
|
||||||
const data = {
|
const activeState: Ref<CourseCompletionStatus> = ref("fail");
|
||||||
id: 340,
|
|
||||||
title: "Kompetenzprofil",
|
|
||||||
slug: "versicherungsvermittlerin-competence",
|
|
||||||
type: "competence.CompetenceProfilePage",
|
|
||||||
translation_key: "a3adb9ac-606d-42fd-b115-842af3706926",
|
|
||||||
course: {
|
|
||||||
id: -1,
|
|
||||||
title: "Versicherungsvermittler/in",
|
|
||||||
category_name: "Handlungsfeld",
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 341,
|
|
||||||
title:
|
|
||||||
"Innerhalb des Handlungsfelds «Fahrzeug» bin ich fähig, die Ziele und Pläne des Kunden zu ergründen (SOLL).",
|
|
||||||
slug: "kompetenzprofil-crit-innerhalb-des-handlungsfelds-fahrzeug-bin-ich-fähig-die-ziele-und-pläne-des-kunden-zu-ergründen-soll",
|
|
||||||
type: "competence.PerformanceCriteria",
|
|
||||||
translation_key: "e4aeeb81-0730-44f5-9c70-cec84d162569",
|
|
||||||
pc_id: "B1.3 Fahrzeug",
|
|
||||||
learning_unit: {
|
|
||||||
id: 123,
|
|
||||||
title: "Auto verkaufen",
|
|
||||||
slug: "versicherungsvermittlerin-lp-circle-analyse-lu-fahrzeug",
|
|
||||||
type: "learnpath.LearningUnit",
|
|
||||||
translation_key: "c4797663-90c3-493f-9f21-e95ad0a37eb2",
|
|
||||||
},
|
|
||||||
circle: "Analyse",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 342,
|
|
||||||
title:
|
|
||||||
"Innerhalb des Handlungsfelds «Fahrzeug» bin ich fähig, die IST-Situation des Kunden mit der geeigneten Gesprächs-/Fragetechnik zu erfassen.",
|
|
||||||
slug: "kompetenzprofil-crit-innerhalb-des-handlungsfelds-fahrzeug-bin-ich-fähig-die-ist-situation-des-kunden-mit-der-geeigneten-gesprächs-fragetechnik-zu-erfassen",
|
|
||||||
type: "competence.PerformanceCriteria",
|
|
||||||
translation_key: "25d56b74-4151-49bd-ac1f-5e706a660aae",
|
|
||||||
pc_id: "B2.1 Fahrzeug",
|
|
||||||
learning_unit: {
|
|
||||||
id: 123,
|
|
||||||
title: "Auto verkaufen",
|
|
||||||
slug: "versicherungsvermittlerin-lp-circle-analyse-lu-fahrzeug",
|
|
||||||
type: "learnpath.LearningUnit",
|
|
||||||
translation_key: "c4797663-90c3-493f-9f21-e95ad0a37eb2",
|
|
||||||
},
|
|
||||||
circle: "Analyse",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 343,
|
|
||||||
title:
|
|
||||||
"Innerhalb des Handlungsfelds «Fahrzeug» bin ich fähig, die Risiken aufzuzeigen.",
|
|
||||||
slug: "kompetenzprofil-crit-innerhalb-des-handlungsfelds-fahrzeug-bin-ich-fähig-die-risiken-aufzuzeigen",
|
|
||||||
type: "competence.PerformanceCriteria",
|
|
||||||
translation_key: "71bfb708-70c7-4e50-a424-104fe10ab7bc",
|
|
||||||
pc_id: "B2.2 Fahrzeug",
|
|
||||||
learning_unit: {
|
|
||||||
id: 123,
|
|
||||||
title: "Auto verkaufen",
|
|
||||||
slug: "versicherungsvermittlerin-lp-circle-analyse-lu-fahrzeug",
|
|
||||||
type: "learnpath.LearningUnit",
|
|
||||||
translation_key: "c4797663-90c3-493f-9f21-e95ad0a37eb2",
|
|
||||||
},
|
|
||||||
circle: "Analyse",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const userProgress = {
|
|
||||||
341: "open",
|
|
||||||
342: "notDone",
|
|
||||||
343: "done",
|
|
||||||
};
|
|
||||||
|
|
||||||
const activeState: Ref<UserCriteriaState> = ref(UserCriteriaState.Nok);
|
|
||||||
|
|
||||||
const shownCriteria = computed(() => {
|
const shownCriteria = computed(() => {
|
||||||
return competenceStore.flatPerformanceCriteria;
|
return competenceStore.flatPerformanceCriteria.filter((criteria) => {
|
||||||
|
return criteria.completion_status === activeState.value;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -112,25 +37,25 @@ const shownCriteria = computed(() => {
|
||||||
class="border-b border-gray-500 flex flex-col lg:flex-row lg:items-center pb-4 mb-4"
|
class="border-b border-gray-500 flex flex-col lg:flex-row lg:items-center pb-4 mb-4"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Nok }"
|
:class="{ 'bg-gray-200': activeState === 'fail' }"
|
||||||
class="flex flex-row items-center py-4 px-2 mr-6"
|
class="flex flex-row items-center py-4 px-2 mr-6"
|
||||||
@click="activeState = UserCriteriaState.Nok"
|
@click="activeState = 'fail'"
|
||||||
>
|
>
|
||||||
<span class="inline-block mr-2">«Das muss ich nochmals anschauen»</span>
|
<span class="inline-block mr-2">«Das muss ich nochmals anschauen»</span>
|
||||||
<span><it-icon-smiley-thinking></it-icon-smiley-thinking></span>
|
<span><it-icon-smiley-thinking></it-icon-smiley-thinking></span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Done }"
|
:class="{ 'bg-gray-200': activeState === 'success' }"
|
||||||
class="flex flex-row items-center py-4 px-2 mr-6"
|
class="flex flex-row items-center py-4 px-2 mr-6"
|
||||||
@click="activeState = UserCriteriaState.Done"
|
@click="activeState = 'success'"
|
||||||
>
|
>
|
||||||
<span class="inline-block mr-2">«Ja, ich kann das»</span>
|
<span class="inline-block mr-2">«Ja, ich kann das»</span>
|
||||||
<span><it-icon-smiley-happy></it-icon-smiley-happy></span>
|
<span><it-icon-smiley-happy></it-icon-smiley-happy></span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
:class="{ 'bg-gray-200': activeState === UserCriteriaState.Open }"
|
:class="{ 'bg-gray-200': activeState === 'unknown' }"
|
||||||
class="flex flex-row items-center py-4 px-2"
|
class="flex flex-row items-center py-4 px-2"
|
||||||
@click="activeState = UserCriteriaState.Open"
|
@click="activeState = 'unknown'"
|
||||||
>
|
>
|
||||||
<span class="inline-block mr-2">Nicht eingeschätzt</span>
|
<span class="inline-block mr-2">Nicht eingeschätzt</span>
|
||||||
<span><it-icon-smiley-neutral></it-icon-smiley-neutral></span>
|
<span><it-icon-smiley-neutral></it-icon-smiley-neutral></span>
|
||||||
|
|
@ -139,10 +64,13 @@ const shownCriteria = computed(() => {
|
||||||
<ul class="mb-6">
|
<ul class="mb-6">
|
||||||
<li
|
<li
|
||||||
v-for="criteria in shownCriteria"
|
v-for="criteria in shownCriteria"
|
||||||
:key="criteria.title"
|
:key="criteria.id"
|
||||||
class="mb-4 pb-4 border-b border-gray-500"
|
class="mb-4 pb-4 border-b border-gray-500"
|
||||||
>
|
>
|
||||||
<PerformanceCriteriaRow :criteria="criteria"> </PerformanceCriteriaRow>
|
<PerformanceCriteriaRow
|
||||||
|
:criteria="criteria"
|
||||||
|
:show-state="true"
|
||||||
|
></PerformanceCriteriaRow>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
|
|
||||||
import { defineStore } from "pinia";
|
|
||||||
|
|
||||||
import { itPost } from "@/fetchHelpers";
|
|
||||||
import type { Circle } from "@/services/circle";
|
import type { Circle } from "@/services/circle";
|
||||||
|
import { useCompletionStore } from "@/stores/completion";
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import type {
|
import type {
|
||||||
CourseCompletionStatus,
|
CourseCompletionStatus,
|
||||||
|
|
@ -11,6 +9,7 @@ import type {
|
||||||
LearningUnit,
|
LearningUnit,
|
||||||
LearningUnitPerformanceCriteria,
|
LearningUnitPerformanceCriteria,
|
||||||
} from "@/types";
|
} from "@/types";
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
export type CircleStoreState = {
|
export type CircleStoreState = {
|
||||||
circle: Circle | undefined;
|
circle: Circle | undefined;
|
||||||
|
|
@ -89,12 +88,11 @@ export const useCircleStore = defineStore({
|
||||||
page: LearningContent | LearningUnitPerformanceCriteria,
|
page: LearningContent | LearningUnitPerformanceCriteria,
|
||||||
completion_status: CourseCompletionStatus = "success"
|
completion_status: CourseCompletionStatus = "success"
|
||||||
) {
|
) {
|
||||||
|
const completionStore = useCompletionStore();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
page.completion_status = completion_status;
|
page.completion_status = completion_status;
|
||||||
const completionData = await itPost("/api/course/completion/mark/", {
|
const completionData = await completionStore.markPage(page);
|
||||||
page_key: page.translation_key,
|
|
||||||
completion_status: page.completion_status,
|
|
||||||
});
|
|
||||||
if (this.circle) {
|
if (this.circle) {
|
||||||
this.circle.parseCompletionData(completionData);
|
this.circle.parseCompletionData(completionData);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { itGet } from "@/fetchHelpers";
|
import { itGet } from "@/fetchHelpers";
|
||||||
|
import { useCompletionStore } from "@/stores/completion";
|
||||||
import type { CompetenceProfilePage } from "@/types";
|
import type { CompetenceProfilePage } from "@/types";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
@ -38,6 +39,7 @@ export const useCompetenceStore = defineStore({
|
||||||
actions: {
|
actions: {
|
||||||
async loadCompetenceProfilePage(slug: string, reload = false) {
|
async loadCompetenceProfilePage(slug: string, reload = false) {
|
||||||
if (this.competenceProfilePage && !reload) {
|
if (this.competenceProfilePage && !reload) {
|
||||||
|
await this.parseCompletionData();
|
||||||
return this.competenceProfilePage;
|
return this.competenceProfilePage;
|
||||||
}
|
}
|
||||||
const competenceProfilePageData = await itGet(`/api/course/page/${slug}/`);
|
const competenceProfilePageData = await itGet(`/api/course/page/${slug}/`);
|
||||||
|
|
@ -47,7 +49,32 @@ export const useCompetenceStore = defineStore({
|
||||||
}
|
}
|
||||||
|
|
||||||
this.competenceProfilePage = competenceProfilePageData;
|
this.competenceProfilePage = competenceProfilePageData;
|
||||||
|
await this.parseCompletionData();
|
||||||
|
|
||||||
return this.competenceProfilePage;
|
return this.competenceProfilePage;
|
||||||
},
|
},
|
||||||
|
async parseCompletionData() {
|
||||||
|
if (this.competenceProfilePage) {
|
||||||
|
const completionStore = useCompletionStore();
|
||||||
|
const completionData = await completionStore.loadCompletionData(
|
||||||
|
this.competenceProfilePage.course.id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (completionData) {
|
||||||
|
this.competenceProfilePage.children.forEach((competence) => {
|
||||||
|
competence.children.forEach((performanceCriteria) => {
|
||||||
|
const completion = completionData.find(
|
||||||
|
(c) => c.page_key === performanceCriteria.translation_key
|
||||||
|
);
|
||||||
|
if (completion) {
|
||||||
|
performanceCriteria.completion_status = completion.completion_status;
|
||||||
|
} else {
|
||||||
|
performanceCriteria.completion_status = "unknown";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { itGet, itPost } from "@/fetchHelpers";
|
||||||
|
import type { CourseCompletion, CourseWagtailPage } from "@/types";
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
|
export type CompletionStoreState = {
|
||||||
|
completionData: CourseCompletion[] | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCompletionStore = defineStore({
|
||||||
|
id: "completion",
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
completionData: undefined,
|
||||||
|
} as CompletionStoreState;
|
||||||
|
},
|
||||||
|
getters: {},
|
||||||
|
actions: {
|
||||||
|
async loadCompletionData(courseId: number, reload = false) {
|
||||||
|
if (this.completionData && !reload) {
|
||||||
|
return this.completionData;
|
||||||
|
}
|
||||||
|
const completionData = await itGet(`/api/course/completion/${courseId}/`);
|
||||||
|
|
||||||
|
if (!completionData) {
|
||||||
|
throw `No completionData found with: ${courseId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.completionData = completionData;
|
||||||
|
return this.completionData || [];
|
||||||
|
},
|
||||||
|
async markPage(page: CourseWagtailPage) {
|
||||||
|
const completionData = await itPost("/api/course/completion/mark/", {
|
||||||
|
page_key: page.translation_key,
|
||||||
|
completion_status: page.completion_status,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (completionData) {
|
||||||
|
this.completionData = completionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.completionData || [];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { itGet } from "@/fetchHelpers";
|
import { itGet } from "@/fetchHelpers";
|
||||||
import { LearningPath } from "@/services/learningPath";
|
import { LearningPath } from "@/services/learningPath";
|
||||||
|
import { useCompletionStore } from "@/stores/completion";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
export type LearningPathStoreState = {
|
export type LearningPathStoreState = {
|
||||||
|
|
@ -18,12 +19,13 @@ export const useLearningPathStore = defineStore({
|
||||||
getters: {},
|
getters: {},
|
||||||
actions: {
|
actions: {
|
||||||
async loadLearningPath(slug: string, reload = false) {
|
async loadLearningPath(slug: string, reload = false) {
|
||||||
|
const completionStore = useCompletionStore();
|
||||||
if (this.learningPath && !reload) {
|
if (this.learningPath && !reload) {
|
||||||
return this.learningPath;
|
return this.learningPath;
|
||||||
}
|
}
|
||||||
const learningPathData = await itGet(`/api/course/page/${slug}/`);
|
const learningPathData = await itGet(`/api/course/page/${slug}/`);
|
||||||
const completionData = await itGet(
|
const completionData = await completionStore.loadCompletionData(
|
||||||
`/api/course/completion/${learningPathData.course.id}/`
|
learningPathData.course.id
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!learningPathData) {
|
if (!learningPathData) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue