Calculate average grade in Berufsbildner

This commit is contained in:
Daniel Egger 2024-07-26 15:23:33 +02:00
parent eef166575f
commit f4fbe1a894
7 changed files with 170 additions and 8 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -78,6 +78,7 @@ type AssignmentCompletionMetricsType {
ranking_completed: Boolean! ranking_completed: Boolean!
average_passed: Float! average_passed: Float!
average_evaluation_percent: Float average_evaluation_percent: Float
competence_certificate_weight: Float
} }
type AssignmentStatisticsSummaryType { type AssignmentStatisticsSummaryType {

View File

@ -481,6 +481,7 @@ export const DASHBOARD_COURSE_STATISTICS = graphql(`
ranking_completed ranking_completed
average_evaluation_percent average_evaluation_percent
average_passed average_passed
competence_certificate_weight
} }
} }
} }
@ -555,6 +556,7 @@ export const DASHBOARD_MENTOR_COMPETENCE_SUMMARY = graphql(`
failed_count failed_count
unranked_count unranked_count
ranking_completed ranking_completed
competence_certificate_weight
average_evaluation_percent average_evaluation_percent
average_passed average_passed
} }

View File

@ -0,0 +1,149 @@
<script setup lang="ts">
import log from "loglevel";
import { computed, onMounted, ref } from "vue";
import {
courseIdForCourseSlug,
fetchMentorCompetenceSummary,
} from "@/services/dashboard";
import type { AssignmentStatisticsRecordType, BaseStatisticsType } from "@/gql/graphql";
import { useDashboardStore } from "@/stores/dashboard";
import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
import _ from "lodash";
import { percentToRoundedGrade } from "@/services/assignmentService";
import { a } from "vitest/dist/suite-BWgaIsVn";
const dashboardStore = useDashboardStore();
const props = defineProps<{
agentRole: string;
courseSlug: string;
}>();
log.debug("AgentStatisticParentPage created", props);
const loading = ref(true);
const courseId = ref<string | undefined>(undefined);
const agentAssignmentData = ref<BaseStatisticsType | null>(null);
const courseSessionName = (courseSessionId: string) => {
return (
agentAssignmentData.value?.course_session_properties?.sessions.find(
(session) => session.id === courseSessionId
)?.name ?? ""
);
};
const circleMeta = (circleId: string) => {
return agentAssignmentData.value?.course_session_properties.circles.find(
(circle) => circle.id === circleId
);
};
onMounted(async () => {
await dashboardStore.loadDashboardDetails();
courseId.value = courseIdForCourseSlug(
dashboardStore.dashboardConfigsv2,
props.courseSlug
);
if (!courseId.value) {
log.error("CourseId not found for courseSlug", props.courseSlug);
return;
}
log.debug("courseId", courseId.value);
agentAssignmentData.value = await fetchMentorCompetenceSummary(
courseId.value,
props.agentRole
);
loading.value = false;
});
type GroupedAssignments = {
competenceCertificateId: string;
competenceCertificateTitle: string;
generation: string;
courseSessionId: string;
assignments: AssignmentStatisticsRecordType[];
sumAverageEvaluationPercent: number;
averageEvaluationPercent: number | null;
averageGrade: number | null;
};
const courseSessionCompetenceAssignments = computed(() => {
let resultArray = [] as GroupedAssignments[];
// group assignments by competence and course session
for (const assignment of agentAssignmentData.value?.assignments.records ?? []) {
const entry = resultArray.find(
(r) =>
r.competenceCertificateId === assignment.competence_certificate_id &&
r.courseSessionId === assignment.course_session_id
);
if (entry) {
if (assignment.metrics.ranking_completed) {
entry.assignments.push(assignment);
}
} else {
const newEntry = {
competenceCertificateId: assignment.competence_certificate_id ?? "",
competenceCertificateTitle: assignment.competence_certificate_title ?? "",
generation: assignment.generation ?? "",
courseSessionId: assignment.course_session_id ?? "",
assignments: [] as AssignmentStatisticsRecordType[],
sumAverageEvaluationPercent: 0,
averageEvaluationPercent: null,
averageGrade: null,
};
if (assignment && assignment.metrics.ranking_completed) {
newEntry.assignments.push(assignment);
}
resultArray.push(newEntry);
}
}
// filter out entries without assignments
resultArray = resultArray.filter((entry) => entry.assignments.length > 0);
// calculate average grade
for (const entry of resultArray) {
entry.sumAverageEvaluationPercent = _.sumBy(entry.assignments, (a) => {
return (
(a.metrics.average_evaluation_percent ?? 0) *
(a.metrics.competence_certificate_weight ?? 1)
);
});
entry.averageEvaluationPercent =
entry.sumAverageEvaluationPercent /
_.sumBy(entry.assignments, (a) => {
return a.metrics.competence_certificate_weight ?? 1;
});
entry.averageGrade = percentToRoundedGrade(entry.averageEvaluationPercent, false);
}
return resultArray;
});
</script>
<template>
<div class="bg-gray-200">
<div v-if="loading" class="m-8 flex justify-center">
<LoadingSpinner />
</div>
<div v-else class="container-large flex flex-col space-y-8">
<router-link class="btn-text inline-flex items-center pl-0" to="/">
<it-icon-arrow-left />
<span>{{ $t("general.back") }}</span>
</router-link>
<div>
<h2 class="text-2xl font-bold">{{ $t("a.Statistik") }}</h2>
<p class="text-gray-800">
{{ $t("a.Statistik für alle Lernenden") }}
</p>
<pre>
{{ courseSessionCompetenceAssignments }}
</pre>
</div>
</div>
</div>
</template>

View File

@ -339,6 +339,7 @@ const router = createRouter({
}, },
], ],
}, },
{ {
path: "/statistic/:agentRole/:courseSlug/assignment", path: "/statistic/:agentRole/:courseSlug/assignment",
props: true, props: true,
@ -351,6 +352,12 @@ const router = createRouter({
component: () => component: () =>
import("@/pages/dashboard/agentAssignment/AgentAssignmentDetailPage.vue"), import("@/pages/dashboard/agentAssignment/AgentAssignmentDetailPage.vue"),
}, },
{
path: "/statistic/:agentRole/:courseSlug/competence-grade",
props: true,
component: () =>
import("@/pages/dashboard/agentAssignment/AgentCompetenceGradePage.vue"),
},
{ {
path: "/shop", path: "/shop",

View File

@ -27,6 +27,7 @@ class AssignmentCompletionMetricsType(graphene.ObjectType):
ranking_completed = graphene.Boolean(required=True) ranking_completed = graphene.Boolean(required=True)
average_passed = graphene.Float(required=True) average_passed = graphene.Float(required=True)
average_evaluation_percent = graphene.Float() average_evaluation_percent = graphene.Float()
competence_certificate_weight = graphene.Float()
class AssignmentStatisticsRecordType(graphene.ObjectType): class AssignmentStatisticsRecordType(graphene.ObjectType):
@ -149,6 +150,7 @@ def get_assignment_completion_metrics(
ranking_completed=(passed_count > 0 or failed_count > 0), # noqa ranking_completed=(passed_count > 0 or failed_count > 0), # noqa
average_passed=average_passed, # noqa average_passed=average_passed, # noqa
average_evaluation_percent=average_evaluation_percent, # noqa average_evaluation_percent=average_evaluation_percent, # noqa
competence_certificate_weight=assignment.competence_certificate_weight, # noqa
) )