Filter for list, add average grade
This commit is contained in:
parent
b7231fb1b7
commit
29c42f3512
|
|
@ -4,27 +4,53 @@ import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
||||||
import { useTranslation } from "i18next-vue";
|
import { useTranslation } from "i18next-vue";
|
||||||
import type { StatisticsCourseSessionPropertiesType } from "@/gql/graphql";
|
import type { StatisticsCourseSessionPropertiesType } from "@/gql/graphql";
|
||||||
import type { StatisticsFilterItem } from "@/types";
|
import type { StatisticsFilterItem } from "@/types";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
items: StatisticsFilterItem[];
|
items: StatisticsFilterItem[];
|
||||||
courseSessionProperties: StatisticsCourseSessionPropertiesType;
|
courseSessionProperties: StatisticsCourseSessionPropertiesType;
|
||||||
|
hideCircleFilter?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
defineExpose({ getFilteredItems });
|
defineExpose({ getFilteredItems });
|
||||||
|
|
||||||
|
const regionFilter = computed(() => {
|
||||||
|
const regions = _.uniq(
|
||||||
|
props.courseSessionProperties.sessions.map((session) => session.region)
|
||||||
|
);
|
||||||
|
const f = regions.map((region) => ({
|
||||||
|
name: `Region: ${region}`,
|
||||||
|
id: region,
|
||||||
|
}));
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: `${t("Region")}: ${t("a.Alle")}`,
|
||||||
|
id: "_all",
|
||||||
|
},
|
||||||
|
...f,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
const sessionFilter = computed(() => {
|
const sessionFilter = computed(() => {
|
||||||
const f = props.courseSessionProperties.sessions.map((session) => ({
|
let values = props.courseSessionProperties.sessions.map((session) => ({
|
||||||
name: `${t("a.Durchfuehrung")}: ${session.name}`,
|
name: session.name,
|
||||||
|
region: session.region,
|
||||||
id: session.id,
|
id: session.id,
|
||||||
}));
|
}));
|
||||||
return [{ name: t("a.AlleDurchführungen"), id: "_all" }, ...f];
|
|
||||||
|
// filter by selected region
|
||||||
|
if (regionFilterValue.value.id !== "_all") {
|
||||||
|
values = values.filter((cs) => cs.region === regionFilterValue.value.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [{ name: t("a.AlleDurchführungen"), id: "_all" }, ...values];
|
||||||
});
|
});
|
||||||
|
|
||||||
const generationFilter = computed(() => {
|
const generationFilter = computed(() => {
|
||||||
const f = props.courseSessionProperties.generations.map((generation) => ({
|
const f = props.courseSessionProperties.generations.map((generation) => ({
|
||||||
name: `${t("a.Generation")}: ${generation}`,
|
name: generation,
|
||||||
id: generation,
|
id: generation,
|
||||||
}));
|
}));
|
||||||
return [{ name: t("a.AlleGenerationen"), id: "_all" }, ...f];
|
return [{ name: t("a.AlleGenerationen"), id: "_all" }, ...f];
|
||||||
|
|
@ -32,12 +58,13 @@ const generationFilter = computed(() => {
|
||||||
|
|
||||||
const circleFilter = computed(() => {
|
const circleFilter = computed(() => {
|
||||||
const f = props.courseSessionProperties.circles.map((circle) => ({
|
const f = props.courseSessionProperties.circles.map((circle) => ({
|
||||||
name: `Circle: ${circle.name}`,
|
name: circle.name,
|
||||||
id: circle.id,
|
id: circle.id,
|
||||||
}));
|
}));
|
||||||
return [{ name: t("a.AlleCircle"), id: "_all" }, ...f];
|
return [{ name: t("a.AlleCircle"), id: "_all" }, ...f];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const regionFilterValue = ref(regionFilter.value[0]);
|
||||||
const sessionFilterValue = ref(sessionFilter.value[0]);
|
const sessionFilterValue = ref(sessionFilter.value[0]);
|
||||||
const generationFilterValue = ref(generationFilter.value[0]);
|
const generationFilterValue = ref(generationFilter.value[0]);
|
||||||
const circleFilterValue = ref(circleFilter.value[0]);
|
const circleFilterValue = ref(circleFilter.value[0]);
|
||||||
|
|
@ -48,12 +75,21 @@ watch(
|
||||||
sessionFilterValue.value = sessionFilter.value[0];
|
sessionFilterValue.value = sessionFilter.value[0];
|
||||||
generationFilterValue.value = generationFilter.value[0];
|
generationFilterValue.value = generationFilter.value[0];
|
||||||
circleFilterValue.value = circleFilter.value[0];
|
circleFilterValue.value = circleFilter.value[0];
|
||||||
|
regionFilterValue.value = regionFilter.value[0];
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(regionFilterValue, () => {
|
||||||
|
console.log("regionFilterValue", regionFilterValue.value);
|
||||||
|
sessionFilterValue.value = sessionFilter.value[0];
|
||||||
|
});
|
||||||
|
|
||||||
const filteredItems = computed(() => {
|
const filteredItems = computed(() => {
|
||||||
return props.items.filter((item) => {
|
return props.items.filter((item) => {
|
||||||
|
const regionMatch =
|
||||||
|
regionFilterValue.value.id === "_all" ||
|
||||||
|
item.region === regionFilterValue.value.id;
|
||||||
const sessionMatch =
|
const sessionMatch =
|
||||||
sessionFilterValue.value.id === "_all" ||
|
sessionFilterValue.value.id === "_all" ||
|
||||||
item.course_session_id === sessionFilterValue.value.id;
|
item.course_session_id === sessionFilterValue.value.id;
|
||||||
|
|
@ -64,7 +100,7 @@ const filteredItems = computed(() => {
|
||||||
circleFilterValue.value.id === "_all" ||
|
circleFilterValue.value.id === "_all" ||
|
||||||
item.circle_id === circleFilterValue.value.id;
|
item.circle_id === circleFilterValue.value.id;
|
||||||
|
|
||||||
return sessionMatch && generationMatch && circleMatch;
|
return regionMatch && sessionMatch && generationMatch && circleMatch;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -75,30 +111,45 @@ function getFilteredItems() {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex flex-col space-x-2 lg:flex-row">
|
<div class="flex flex-col space-x-2 lg:flex-row border-b">
|
||||||
|
<ItDropdownSelect
|
||||||
|
v-if="regionFilter.length > 2"
|
||||||
|
v-model="regionFilterValue"
|
||||||
|
class="min-w-[12rem]"
|
||||||
|
:items="regionFilter"
|
||||||
|
borderless
|
||||||
|
></ItDropdownSelect>
|
||||||
<ItDropdownSelect
|
<ItDropdownSelect
|
||||||
v-model="sessionFilterValue"
|
v-model="sessionFilterValue"
|
||||||
class="min-w-[18rem]"
|
class="min-w-[12rem]"
|
||||||
:items="sessionFilter"
|
:items="sessionFilter"
|
||||||
borderless
|
borderless
|
||||||
></ItDropdownSelect>
|
></ItDropdownSelect>
|
||||||
<ItDropdownSelect
|
<ItDropdownSelect
|
||||||
v-model="generationFilterValue"
|
v-model="generationFilterValue"
|
||||||
class="min-w-[18rem]"
|
class="min-w-[12rem]"
|
||||||
:items="generationFilter"
|
:items="generationFilter"
|
||||||
borderless
|
borderless
|
||||||
></ItDropdownSelect>
|
></ItDropdownSelect>
|
||||||
<ItDropdownSelect
|
<ItDropdownSelect
|
||||||
|
v-if="!props.hideCircleFilter"
|
||||||
v-model="circleFilterValue"
|
v-model="circleFilterValue"
|
||||||
class="min-w-[18rem]"
|
class="min-w-[12rem]"
|
||||||
:items="circleFilter"
|
:items="circleFilter"
|
||||||
borderless
|
borderless
|
||||||
></ItDropdownSelect>
|
></ItDropdownSelect>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="item in filteredItems" :key="item._id" class="px-5">
|
<slot name="header"></slot>
|
||||||
<div class="border-t border-gray-500 py-4">
|
<section>
|
||||||
|
<div
|
||||||
|
v-for="item in filteredItems"
|
||||||
|
:key="item._id"
|
||||||
|
class="mx-6 border-t border-gray-500 first:border-t-0"
|
||||||
|
>
|
||||||
|
<div class="py-4">
|
||||||
<slot :item="item"></slot>
|
<slot :item="item"></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -52,9 +52,11 @@ type AssignmentStatisticsRecordType {
|
||||||
course_session_assignment_id: ID!
|
course_session_assignment_id: ID!
|
||||||
circle_id: ID!
|
circle_id: ID!
|
||||||
generation: String!
|
generation: String!
|
||||||
|
region: String!
|
||||||
assignment_type_translation_key: String!
|
assignment_type_translation_key: String!
|
||||||
assignment_title: String!
|
assignment_title: String!
|
||||||
deadline: DateTime!
|
deadline: DateTime!
|
||||||
|
course_session_title: String
|
||||||
competence_certificate_id: ID
|
competence_certificate_id: ID
|
||||||
competence_certificate_title: String
|
competence_certificate_title: String
|
||||||
metrics: AssignmentCompletionMetricsType!
|
metrics: AssignmentCompletionMetricsType!
|
||||||
|
|
@ -98,6 +100,7 @@ type StatisticsCourseSessionPropertiesType {
|
||||||
type StatisticsCourseSessionDataType {
|
type StatisticsCourseSessionDataType {
|
||||||
id: ID!
|
id: ID!
|
||||||
name: String!
|
name: String!
|
||||||
|
region: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatisticsCircleDataType {
|
type StatisticsCircleDataType {
|
||||||
|
|
@ -122,6 +125,7 @@ type PresenceRecordStatisticsType {
|
||||||
_id: ID!
|
_id: ID!
|
||||||
course_session_id: ID!
|
course_session_id: ID!
|
||||||
generation: String!
|
generation: String!
|
||||||
|
region: String!
|
||||||
circle_id: ID!
|
circle_id: ID!
|
||||||
due_date: DateTime!
|
due_date: DateTime!
|
||||||
participants_present: Int!
|
participants_present: Int!
|
||||||
|
|
@ -145,6 +149,7 @@ type FeedbackStatisticsRecordType {
|
||||||
_id: ID!
|
_id: ID!
|
||||||
course_session_id: ID!
|
course_session_id: ID!
|
||||||
generation: String!
|
generation: String!
|
||||||
|
region: String!
|
||||||
circle_id: ID!
|
circle_id: ID!
|
||||||
satisfaction_average: Float!
|
satisfaction_average: Float!
|
||||||
satisfaction_max: Int!
|
satisfaction_max: Int!
|
||||||
|
|
@ -175,6 +180,7 @@ type CompetenceRecordStatisticsType {
|
||||||
_id: ID!
|
_id: ID!
|
||||||
course_session_id: ID!
|
course_session_id: ID!
|
||||||
generation: String!
|
generation: String!
|
||||||
|
region: String!
|
||||||
title: String!
|
title: String!
|
||||||
circle_id: ID!
|
circle_id: ID!
|
||||||
success_count: Int!
|
success_count: Int!
|
||||||
|
|
|
||||||
|
|
@ -370,6 +370,7 @@ export const DASHBOARD_COURSE_STATISTICS = graphql(`
|
||||||
sessions {
|
sessions {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
region
|
||||||
}
|
}
|
||||||
generations
|
generations
|
||||||
circles {
|
circles {
|
||||||
|
|
@ -390,6 +391,7 @@ export const DASHBOARD_COURSE_STATISTICS = graphql(`
|
||||||
_id
|
_id
|
||||||
course_session_id
|
course_session_id
|
||||||
generation
|
generation
|
||||||
|
region
|
||||||
circle_id
|
circle_id
|
||||||
due_date
|
due_date
|
||||||
participants_present
|
participants_present
|
||||||
|
|
@ -408,6 +410,7 @@ export const DASHBOARD_COURSE_STATISTICS = graphql(`
|
||||||
_id
|
_id
|
||||||
course_session_id
|
course_session_id
|
||||||
generation
|
generation
|
||||||
|
region
|
||||||
circle_id
|
circle_id
|
||||||
experts
|
experts
|
||||||
satisfaction_average
|
satisfaction_average
|
||||||
|
|
@ -436,6 +439,7 @@ export const DASHBOARD_COURSE_STATISTICS = graphql(`
|
||||||
course_session_assignment_id
|
course_session_assignment_id
|
||||||
circle_id
|
circle_id
|
||||||
generation
|
generation
|
||||||
|
region
|
||||||
assignment_title
|
assignment_title
|
||||||
assignment_type_translation_key
|
assignment_type_translation_key
|
||||||
competence_certificate_title
|
competence_certificate_title
|
||||||
|
|
@ -465,6 +469,7 @@ export const DASHBOARD_COURSE_STATISTICS = graphql(`
|
||||||
_id
|
_id
|
||||||
course_session_id
|
course_session_id
|
||||||
generation
|
generation
|
||||||
|
region
|
||||||
circle_id
|
circle_id
|
||||||
title
|
title
|
||||||
success_count
|
success_count
|
||||||
|
|
@ -490,6 +495,7 @@ export const DASHBOARD_MENTOR_COMPETENCE_SUMMARY = graphql(`
|
||||||
sessions {
|
sessions {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
region
|
||||||
}
|
}
|
||||||
generations
|
generations
|
||||||
circles {
|
circles {
|
||||||
|
|
@ -510,8 +516,10 @@ export const DASHBOARD_MENTOR_COMPETENCE_SUMMARY = graphql(`
|
||||||
_id
|
_id
|
||||||
course_session_id
|
course_session_id
|
||||||
course_session_assignment_id
|
course_session_assignment_id
|
||||||
|
course_session_title
|
||||||
circle_id
|
circle_id
|
||||||
generation
|
generation
|
||||||
|
region
|
||||||
assignment_title
|
assignment_title
|
||||||
assignment_type_translation_key
|
assignment_type_translation_key
|
||||||
competence_certificate_id
|
competence_certificate_id
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, type Ref, ref } from "vue";
|
||||||
import {
|
import {
|
||||||
courseIdForCourseSlug,
|
courseIdForCourseSlug,
|
||||||
fetchMentorCompetenceSummary,
|
fetchMentorCompetenceSummary,
|
||||||
|
|
@ -10,6 +10,8 @@ import { useDashboardStore } from "@/stores/dashboard";
|
||||||
import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
|
import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { percentToRoundedGrade } from "@/services/assignmentService";
|
import { percentToRoundedGrade } from "@/services/assignmentService";
|
||||||
|
import StatisticFilterList from "@/components/dashboard/StatisticFilterList.vue";
|
||||||
|
import type { StatisticsFilterItem } from "@/types";
|
||||||
|
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
|
||||||
|
|
@ -32,6 +34,22 @@ const courseSessionName = (courseSessionId: string) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const statisticFilter: Ref<typeof StatisticFilterList | null> = ref(null);
|
||||||
|
const filteredItems = computed(() => {
|
||||||
|
if (!statisticFilter.value) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return statisticFilter.value.getFilteredItems();
|
||||||
|
});
|
||||||
|
const totalAverageGrade = computed(() => {
|
||||||
|
return percentToRoundedGrade(
|
||||||
|
_.sumBy(filteredItems.value, (i) => {
|
||||||
|
return (i as GroupedAssignmentEntry).averageEvaluationPercent ?? 0;
|
||||||
|
}) / filteredItems.value.length,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await dashboardStore.loadDashboardDetails();
|
await dashboardStore.loadDashboardDetails();
|
||||||
courseId.value = courseIdForCourseSlug(
|
courseId.value = courseIdForCourseSlug(
|
||||||
|
|
@ -53,26 +71,31 @@ onMounted(async () => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
type GroupedAssignments = {
|
interface GroupedAssignmentEntry extends StatisticsFilterItem {
|
||||||
competenceCertificateId: string;
|
competenceCertificateId: string;
|
||||||
competenceCertificateTitle: string;
|
competenceCertificateTitle: string;
|
||||||
generation: string;
|
course_session_title: string;
|
||||||
courseSessionId: string;
|
|
||||||
assignments: AssignmentStatisticsRecordType[];
|
assignments: AssignmentStatisticsRecordType[];
|
||||||
sumAverageEvaluationPercent: number;
|
sumAverageEvaluationPercent: number;
|
||||||
averageEvaluationPercent: number | null;
|
averageEvaluationPercent: number | null;
|
||||||
averageGrade: number | null;
|
averageGrade: number | null;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
function isGroupedAssignmentEntry(
|
||||||
|
item: StatisticsFilterItem
|
||||||
|
): item is GroupedAssignmentEntry {
|
||||||
|
return (item as GroupedAssignmentEntry).competenceCertificateId !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const courseSessionCompetenceAssignments = computed(() => {
|
const courseSessionCompetenceAssignments = computed(() => {
|
||||||
let resultArray = [] as GroupedAssignments[];
|
let resultArray = [] as GroupedAssignmentEntry[];
|
||||||
|
|
||||||
// group assignments by competence and course session
|
// group assignments by competence and course session
|
||||||
for (const assignment of agentAssignmentData.value?.assignments.records ?? []) {
|
for (const assignment of agentAssignmentData.value?.assignments.records ?? []) {
|
||||||
const entry = resultArray.find(
|
const entry = resultArray.find(
|
||||||
(r) =>
|
(r) =>
|
||||||
r.competenceCertificateId === assignment.competence_certificate_id &&
|
r.competenceCertificateId === assignment.competence_certificate_id &&
|
||||||
r.courseSessionId === assignment.course_session_id
|
r.course_session_id === assignment.course_session_id
|
||||||
);
|
);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
if (assignment.metrics.ranking_completed) {
|
if (assignment.metrics.ranking_completed) {
|
||||||
|
|
@ -80,14 +103,18 @@ const courseSessionCompetenceAssignments = computed(() => {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const newEntry = {
|
const newEntry = {
|
||||||
|
_id: `${assignment.competence_certificate_id}-${assignment.course_session_id}`,
|
||||||
competenceCertificateId: assignment.competence_certificate_id ?? "",
|
competenceCertificateId: assignment.competence_certificate_id ?? "",
|
||||||
competenceCertificateTitle: assignment.competence_certificate_title ?? "",
|
competenceCertificateTitle: assignment.competence_certificate_title ?? "",
|
||||||
generation: assignment.generation ?? "",
|
generation: assignment.generation ?? "",
|
||||||
courseSessionId: assignment.course_session_id ?? "",
|
region: assignment.region ?? "",
|
||||||
|
course_session_id: assignment.course_session_id ?? "",
|
||||||
|
course_session_title: assignment.course_session_title ?? "",
|
||||||
assignments: [] as AssignmentStatisticsRecordType[],
|
assignments: [] as AssignmentStatisticsRecordType[],
|
||||||
sumAverageEvaluationPercent: 0,
|
sumAverageEvaluationPercent: 0,
|
||||||
averageEvaluationPercent: null,
|
averageEvaluationPercent: null,
|
||||||
averageGrade: null,
|
averageGrade: null,
|
||||||
|
circle_id: assignment.circle_id ?? "",
|
||||||
};
|
};
|
||||||
if (assignment && assignment.metrics.ranking_completed) {
|
if (assignment && assignment.metrics.ranking_completed) {
|
||||||
newEntry.assignments.push(assignment);
|
newEntry.assignments.push(assignment);
|
||||||
|
|
@ -114,7 +141,11 @@ const courseSessionCompetenceAssignments = computed(() => {
|
||||||
});
|
});
|
||||||
entry.averageGrade = percentToRoundedGrade(entry.averageEvaluationPercent, false);
|
entry.averageGrade = percentToRoundedGrade(entry.averageEvaluationPercent, false);
|
||||||
}
|
}
|
||||||
return resultArray;
|
return _.orderBy(
|
||||||
|
resultArray,
|
||||||
|
["course_session_title", "competenceCertificateTitle"],
|
||||||
|
["asc", "asc"]
|
||||||
|
);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -129,48 +160,61 @@ const courseSessionCompetenceAssignments = computed(() => {
|
||||||
<span>{{ $t("general.back") }}</span>
|
<span>{{ $t("general.back") }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
<div>
|
<div>
|
||||||
<h2>{{ $t("a.Kompetenznachweise") }}</h2>
|
<h2 class="mb-8">{{ $t("a.Kompetenznachweise") }}</h2>
|
||||||
|
|
||||||
<div class="bg-white px-4 py-2">
|
<div class="bg-white py-2">
|
||||||
<section
|
<StatisticFilterList
|
||||||
class="flex flex-col space-x-0 border-b bg-white lg:flex-row lg:space-x-3"
|
v-if="
|
||||||
></section>
|
agentAssignmentData?.course_session_properties &&
|
||||||
|
courseSessionCompetenceAssignments?.length
|
||||||
|
"
|
||||||
|
ref="statisticFilter"
|
||||||
|
:course-session-properties="agentAssignmentData?.course_session_properties"
|
||||||
|
:items="courseSessionCompetenceAssignments"
|
||||||
|
:hide-circle-filter="true"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<div class="heading-3 border-b px-6 py-4">
|
||||||
|
{{ $t("a.Durchschnittsnote") }}: {{ totalAverageGrade }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="{ item: item }">
|
||||||
<div
|
<div
|
||||||
v-for="entry in courseSessionCompetenceAssignments"
|
v-if="isGroupedAssignmentEntry(item)"
|
||||||
:key="entry.courseSessionId"
|
class="flex flex-col justify-between gap-4 border-b last:border-b-0 md:flex-row md:items-center md:justify-between md:gap-16"
|
||||||
:data-cy="`entry-${entry.courseSessionId}`"
|
|
||||||
class="flex flex-col justify-between gap-4 border-b p-2 last:border-b-0 md:flex-row md:items-center md:justify-between md:gap-16"
|
|
||||||
>
|
>
|
||||||
<div class="w-full flex-auto md:w-1/2">
|
<div class="w-full flex-auto md:w-1/2">
|
||||||
{{ entry.competenceCertificateTitle }}
|
<span class="text-bold">
|
||||||
|
{{ item.competenceCertificateTitle }}
|
||||||
|
</span>
|
||||||
<br />
|
<br />
|
||||||
{{ $t("a.Durchführung") }} «{{
|
{{ $t("a.Durchführung") }} «{{
|
||||||
courseSessionName(entry.courseSessionId)
|
courseSessionName(item.course_session_id)
|
||||||
}}»
|
}}»
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-auto items-center gap-2 md:w-1/4">
|
<div class="flex flex-auto items-center gap-2 md:w-1/4">
|
||||||
<div>{{ $t("a.Durchschnittsnote") }}:</div>
|
<div>{{ $t("a.Durchschnittsnote") }}:</div>
|
||||||
<div class="min-w-12 text-center">
|
<div class="min-w-12 text-center">
|
||||||
<div
|
<div
|
||||||
class="rounded px-2 py-1 font-bold"
|
class="rounded px-2 py-1 font-bold"
|
||||||
:class="{ 'bg-red-400': (entry.averageGrade ?? 4) < 4 }"
|
:class="{ 'bg-red-400': (item.averageGrade ?? 4) < 4 }"
|
||||||
>
|
>
|
||||||
{{ entry.averageGrade }}
|
{{ item.averageGrade }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full flex-auto items-end md:w-1/4 md:text-end">
|
<div class="w-full flex-auto items-end md:w-1/4 md:text-end">
|
||||||
<router-link
|
<router-link
|
||||||
class="underline"
|
class="underline"
|
||||||
:to="`/statistic/${props.agentRole}/${props.courseSlug}/competence-grade/${entry.courseSessionId}/${entry.competenceCertificateId}`"
|
:to="`/statistic/${props.agentRole}/${props.courseSlug}/competence-grade/${item.course_session_id}/${item.competenceCertificateId}`"
|
||||||
data-cy="basebox.detailsLink"
|
data-cy="basebox.detailsLink"
|
||||||
>
|
>
|
||||||
{{ $t("a.Details anschauen") }}
|
{{ $t("a.Details anschauen") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
</StatisticFilterList>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -623,6 +623,7 @@ export type DashboardPersonsPageMode = "default" | "competenceMetrics";
|
||||||
export interface StatisticsFilterItem {
|
export interface StatisticsFilterItem {
|
||||||
_id: string;
|
_id: string;
|
||||||
course_session_id: string;
|
course_session_id: string;
|
||||||
|
region: string;
|
||||||
generation: string;
|
generation: string;
|
||||||
circle_id: string;
|
circle_id: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,11 @@ class AssignmentStatisticsRecordType(graphene.ObjectType):
|
||||||
course_session_assignment_id = graphene.ID(required=True)
|
course_session_assignment_id = graphene.ID(required=True)
|
||||||
circle_id = graphene.ID(required=True)
|
circle_id = graphene.ID(required=True)
|
||||||
generation = graphene.String(required=True)
|
generation = graphene.String(required=True)
|
||||||
|
region = graphene.String(required=True)
|
||||||
assignment_type_translation_key = graphene.String(required=True)
|
assignment_type_translation_key = graphene.String(required=True)
|
||||||
assignment_title = graphene.String(required=True)
|
assignment_title = graphene.String(required=True)
|
||||||
deadline = graphene.DateTime(required=True)
|
deadline = graphene.DateTime(required=True)
|
||||||
|
course_session_title = graphene.String()
|
||||||
competence_certificate_id = graphene.ID()
|
competence_certificate_id = graphene.ID()
|
||||||
competence_certificate_title = graphene.String()
|
competence_certificate_title = graphene.String()
|
||||||
metrics = graphene.Field(AssignmentCompletionMetricsType, required=True)
|
metrics = graphene.Field(AssignmentCompletionMetricsType, required=True)
|
||||||
|
|
@ -171,9 +173,11 @@ def create_record(
|
||||||
# make sure it's unique, across all types of assignments!
|
# make sure it's unique, across all types of assignments!
|
||||||
_id=f"{course_session_assignment._meta.model_name}#{course_session_assignment.id}@{urql_id_postfix}", # noqa
|
_id=f"{course_session_assignment._meta.model_name}#{course_session_assignment.id}@{urql_id_postfix}", # noqa
|
||||||
course_session_id=str(course_session_assignment.course_session.id), # noqa
|
course_session_id=str(course_session_assignment.course_session.id), # noqa
|
||||||
|
course_session_title=course_session_assignment.course_session.title, # noqa
|
||||||
circle_id=learning_content.get_circle().id, # noqa
|
circle_id=learning_content.get_circle().id, # noqa
|
||||||
course_session_assignment_id=str(course_session_assignment.id), # noqa
|
course_session_assignment_id=str(course_session_assignment.id), # noqa
|
||||||
generation=course_session_assignment.course_session.generation, # noqa
|
generation=course_session_assignment.course_session.generation, # noqa
|
||||||
|
region=course_session_assignment.course_session.region, # noqa
|
||||||
assignment_type_translation_key=due_date.assignment_type_translation_key, # noqa
|
assignment_type_translation_key=due_date.assignment_type_translation_key, # noqa
|
||||||
competence_certificate_id=str(competence_certificate.id), # noqa
|
competence_certificate_id=str(competence_certificate.id), # noqa
|
||||||
competence_certificate_title=competence_certificate.title, # noqa
|
competence_certificate_title=competence_certificate.title, # noqa
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ class PresenceRecordStatisticsType(graphene.ObjectType):
|
||||||
_id = graphene.ID(required=True)
|
_id = graphene.ID(required=True)
|
||||||
course_session_id = graphene.ID(required=True)
|
course_session_id = graphene.ID(required=True)
|
||||||
generation = graphene.String(required=True)
|
generation = graphene.String(required=True)
|
||||||
|
region = graphene.String(required=True)
|
||||||
circle_id = graphene.ID(required=True)
|
circle_id = graphene.ID(required=True)
|
||||||
due_date = graphene.DateTime(required=True)
|
due_date = graphene.DateTime(required=True)
|
||||||
participants_present = graphene.Int(required=True)
|
participants_present = graphene.Int(required=True)
|
||||||
|
|
@ -83,6 +84,7 @@ def attendance_day_presences(
|
||||||
_id=f"{urql_id}:attendance_day:{attendance_day.id}", # noqa
|
_id=f"{urql_id}:attendance_day:{attendance_day.id}", # noqa
|
||||||
course_session_id=course_session.id, # noqa
|
course_session_id=course_session.id, # noqa
|
||||||
generation=course_session.generation, # noqa
|
generation=course_session.generation, # noqa
|
||||||
|
region=course_session.region, # noqa
|
||||||
circle_id=circle.id, # noqa
|
circle_id=circle.id, # noqa
|
||||||
due_date=attendance_day.due_date.end, # noqa
|
due_date=attendance_day.due_date.end, # noqa
|
||||||
participants_present=participants_present, # noqa
|
participants_present=participants_present, # noqa
|
||||||
|
|
@ -98,7 +100,9 @@ def attendance_day_presences(
|
||||||
)
|
)
|
||||||
|
|
||||||
return AttendanceDayPresencesStatisticsType(
|
return AttendanceDayPresencesStatisticsType(
|
||||||
summary=summary, records=records, _id=course_id # noqa
|
summary=summary,
|
||||||
|
records=records,
|
||||||
|
_id=course_id, # noqa
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ class CompetenceRecordStatisticsType(graphene.ObjectType):
|
||||||
_id = graphene.ID(required=True)
|
_id = graphene.ID(required=True)
|
||||||
course_session_id = graphene.ID(required=True)
|
course_session_id = graphene.ID(required=True)
|
||||||
generation = graphene.String(required=True)
|
generation = graphene.String(required=True)
|
||||||
|
region = graphene.String(required=True)
|
||||||
title = graphene.String(required=True)
|
title = graphene.String(required=True)
|
||||||
circle_id = graphene.ID(required=True)
|
circle_id = graphene.ID(required=True)
|
||||||
success_count = graphene.Int(required=True)
|
success_count = graphene.Int(required=True)
|
||||||
|
|
@ -80,6 +81,7 @@ def competences(
|
||||||
title=learning_unit.title, # noqa
|
title=learning_unit.title, # noqa
|
||||||
course_session_id=completion.course_session.id, # noqa
|
course_session_id=completion.course_session.id, # noqa
|
||||||
generation=completion.course_session.generation, # noqa
|
generation=completion.course_session.generation, # noqa
|
||||||
|
region=completion.course_session.region, # noqa
|
||||||
circle_id=circle.id, # noqa
|
circle_id=circle.id, # noqa
|
||||||
success_count=0, # noqa
|
success_count=0, # noqa
|
||||||
fail_count=0, # noqa
|
fail_count=0, # noqa
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ from vbv_lernwelt.learnpath.models import Circle
|
||||||
class StatisticsCourseSessionDataType(graphene.ObjectType):
|
class StatisticsCourseSessionDataType(graphene.ObjectType):
|
||||||
id = graphene.ID(required=True)
|
id = graphene.ID(required=True)
|
||||||
name = graphene.String(required=True)
|
name = graphene.String(required=True)
|
||||||
|
region = graphene.String(required=True)
|
||||||
|
|
||||||
|
|
||||||
class StatisticsCircleDataType(graphene.ObjectType):
|
class StatisticsCircleDataType(graphene.ObjectType):
|
||||||
|
|
@ -129,6 +130,7 @@ class BaseStatisticsType(graphene.ObjectType):
|
||||||
StatisticsCourseSessionDataType(
|
StatisticsCourseSessionDataType(
|
||||||
id=course_session.id, # noqa
|
id=course_session.id, # noqa
|
||||||
name=course_session.title, # noqa
|
name=course_session.title, # noqa
|
||||||
|
region=course_session.region, # noqa
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
generations.add(course_session.generation)
|
generations.add(course_session.generation)
|
||||||
|
|
@ -199,7 +201,8 @@ class CourseStatisticsType(BaseStatisticsType):
|
||||||
records, success_total, fail_total = competences(
|
records, success_total, fail_total = competences(
|
||||||
course_slug=str(root.course_slug),
|
course_slug=str(root.course_slug),
|
||||||
course_session_selection_ids=[
|
course_session_selection_ids=[
|
||||||
str(cs) for cs in root.course_session_selection_ids # noqa
|
str(cs)
|
||||||
|
for cs in root.course_session_selection_ids # noqa
|
||||||
],
|
],
|
||||||
user_selection_ids=user_selection_ids, # noqa
|
user_selection_ids=user_selection_ids, # noqa
|
||||||
circle_ids=root.get_circle_ids(info), # noqa
|
circle_ids=root.get_circle_ids(info), # noqa
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ class FeedbackStatisticsRecordType(graphene.ObjectType):
|
||||||
_id = graphene.ID(required=True)
|
_id = graphene.ID(required=True)
|
||||||
course_session_id = graphene.ID(required=True)
|
course_session_id = graphene.ID(required=True)
|
||||||
generation = graphene.String(required=True)
|
generation = graphene.String(required=True)
|
||||||
|
region = graphene.String(required=True)
|
||||||
circle_id = graphene.ID(required=True)
|
circle_id = graphene.ID(required=True)
|
||||||
satisfaction_average = graphene.Float(required=True)
|
satisfaction_average = graphene.Float(required=True)
|
||||||
satisfaction_max = graphene.Int(required=True)
|
satisfaction_max = graphene.Int(required=True)
|
||||||
|
|
@ -68,6 +69,7 @@ def feedback_responses(
|
||||||
feedbacks=fbs,
|
feedbacks=fbs,
|
||||||
course_session_id=course_session.id,
|
course_session_id=course_session.id,
|
||||||
generation=course_session.generation,
|
generation=course_session.generation,
|
||||||
|
region=course_session.region,
|
||||||
course_slug=str(course_slug),
|
course_slug=str(course_slug),
|
||||||
urql_id_postfix=urql_id,
|
urql_id_postfix=urql_id,
|
||||||
)
|
)
|
||||||
|
|
@ -96,6 +98,7 @@ def circle_feedback_average(
|
||||||
feedbacks: List[FeedbackResponse],
|
feedbacks: List[FeedbackResponse],
|
||||||
course_session_id,
|
course_session_id,
|
||||||
generation: str,
|
generation: str,
|
||||||
|
region: str,
|
||||||
course_slug: str,
|
course_slug: str,
|
||||||
urql_id_postfix: str = "",
|
urql_id_postfix: str = "",
|
||||||
):
|
):
|
||||||
|
|
@ -128,6 +131,7 @@ def circle_feedback_average(
|
||||||
_id=f"circle:{circle_id}-course_session:{course_session_id}@{urql_id_postfix}", # noqa
|
_id=f"circle:{circle_id}-course_session:{course_session_id}@{urql_id_postfix}", # noqa
|
||||||
course_session_id=course_session_id, # noqa
|
course_session_id=course_session_id, # noqa
|
||||||
generation=generation, # noqa
|
generation=generation, # noqa
|
||||||
|
region=region, # noqa
|
||||||
circle_id=circle_id, # noqa
|
circle_id=circle_id, # noqa
|
||||||
satisfaction_average=data["total"] / data["count"], # noqa
|
satisfaction_average=data["total"] / data["count"], # noqa
|
||||||
satisfaction_max=4, # noqa
|
satisfaction_max=4, # noqa
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue