feat: add feedback list
This commit is contained in:
parent
62c3aaf849
commit
e2a346caed
|
|
@ -1,8 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from "vue";
|
||||
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
||||
import { useTranslation } from "i18next-vue";
|
||||
import type { StatisticsCourseSessionPropertiesType } from "@/gql/graphql";
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
interface Item {
|
||||
_id: string;
|
||||
course_session_id: string;
|
||||
|
|
@ -17,18 +20,18 @@ const props = defineProps<{
|
|||
|
||||
const sessionFilter = computed(() => {
|
||||
const f = props.courseSessionProperties.sessions.map((session) => ({
|
||||
name: `Durchführung: ${session.name}`,
|
||||
name: `${t("a.Durchfuehrung")}: ${session.name}`,
|
||||
id: session.id,
|
||||
}));
|
||||
return [{ name: "Durchführung: Alle", id: "_all" }, ...f];
|
||||
return [{ name: t("a.AlleDurchführungen"), id: "_all" }, ...f];
|
||||
});
|
||||
|
||||
const generationFilter = computed(() => {
|
||||
const f = props.courseSessionProperties.generations.map((generation) => ({
|
||||
name: `Generation: ${generation}`,
|
||||
name: `${t("a.Generation")}: ${generation}`,
|
||||
id: generation,
|
||||
}));
|
||||
return [{ name: "Generation: Alle", id: "_all" }, ...f];
|
||||
return [{ name: t("a.AlleGenerationen"), id: "_all" }, ...f];
|
||||
});
|
||||
|
||||
const circleFilter = computed(() => {
|
||||
|
|
@ -36,7 +39,7 @@ const circleFilter = computed(() => {
|
|||
name: `Circle: ${circle.name}`,
|
||||
id: circle.id,
|
||||
}));
|
||||
return [{ name: "Circle: Alle", id: "_all" }, ...f];
|
||||
return [{ name: t("a.AlleCircle"), id: "_all" }, ...f];
|
||||
});
|
||||
|
||||
const sessionFilterValue = ref(sessionFilter.value[0]);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import type { CourseStatisticsType } from "@/gql/graphql";
|
||||
import { graphqlClient } from "@/graphql/client";
|
||||
import { COURSE_QUERY, COURSE_SESSION_DETAIL_QUERY } from "@/graphql/queries";
|
||||
import {
|
||||
|
|
@ -7,6 +8,7 @@ import {
|
|||
} from "@/services/circle";
|
||||
import { useCompletionStore } from "@/stores/completion";
|
||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||
import { useDashboardStore } from "@/stores/dashboard";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import type {
|
||||
ActionCompetence,
|
||||
|
|
@ -411,3 +413,25 @@ export function useCourseDataWithCompletion(
|
|||
nextLearningContent,
|
||||
};
|
||||
}
|
||||
|
||||
export function useCourseStatistics() {
|
||||
const dashboardStore = useDashboardStore();
|
||||
|
||||
const statistics = computed(() => {
|
||||
return dashboardStore.currentDashBoardData as CourseStatisticsType;
|
||||
});
|
||||
|
||||
const courseSessionName = (courseSessionId: string) => {
|
||||
return statistics.value.course_session_properties.sessions.find(
|
||||
(session) => session.id === courseSessionId
|
||||
)?.name;
|
||||
};
|
||||
|
||||
const circleMeta = (circleId: string) => {
|
||||
return statistics.value.course_session_properties.circles.find(
|
||||
(circle) => circle.id === circleId
|
||||
);
|
||||
};
|
||||
|
||||
return { courseSessionName, circleMeta };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -493,7 +493,7 @@ export type FeedbackStatisticsRecordType = {
|
|||
export type FeedbackStatisticsResponsesType = {
|
||||
__typename?: 'FeedbackStatisticsResponsesType';
|
||||
_id: Scalars['ID']['output'];
|
||||
records: Array<Maybe<FeedbackStatisticsRecordType>>;
|
||||
records: Array<FeedbackStatisticsRecordType>;
|
||||
summary: FeedbackStatisticsSummaryType;
|
||||
};
|
||||
|
||||
|
|
@ -1203,7 +1203,7 @@ export type CourseStatisticsQueryVariables = Exact<{
|
|||
}>;
|
||||
|
||||
|
||||
export type CourseStatisticsQuery = { __typename?: 'Query', course_statistics?: { __typename?: 'CourseStatisticsType', _id: string, course_id: string, course_title: string, course_slug: string, course_session_selection_ids: Array<string | null>, course_session_properties: { __typename?: 'StatisticsCourseSessionPropertiesType', _id: string, generations: Array<string>, sessions: Array<{ __typename?: 'StatisticsCourseSessionDataType', id: string, name: string }>, circles: Array<{ __typename?: 'StatisticsCircleDataType', id: string, name: string, experts: Array<string | null> }> }, course_session_selection_metrics: { __typename?: 'StatisticsCourseSessionsSelectionMetricType', _id: string, session_count: number, participant_count: number, expert_count: number }, attendance_day_presences: { __typename?: 'AttendanceDayPresencesStatisticsType', _id: string, records: Array<{ __typename?: 'PresenceRecordStatisticsType', _id: string, course_session_id: string, generation: string, circle_id: string, due_date: string, participants_present: number, participants_total: number, details_url: string }>, summary: { __typename?: 'AttendanceSummaryStatisticsType', _id: string, days_completed: number, participants_present: number } }, feedback_responses: { __typename?: 'FeedbackStatisticsResponsesType', _id: string, records: Array<{ __typename?: 'FeedbackStatisticsRecordType', _id: string, course_session_id: string, generation: string, circle_id: string, satisfaction_average: number, satisfaction_max: number, details_url: string } | null>, summary: { __typename?: 'FeedbackStatisticsSummaryType', _id: string, satisfaction_average: number, satisfaction_max: number, total_responses: number } }, assignments: { __typename?: 'AssignmentsStatisticsType', _id: string, summary: { __typename?: 'AssignmentStatisticsSummaryType', _id: string, completed_count: number, average_passed: number }, records: Array<{ __typename?: 'AssignmentStatisticsRecordType', _id: string, course_session_id: string, course_session_assignment_id: string, circle_id: string, generation: string, assignment_title: string, assignment_type_translation_key: string, details_url: string, deadline: string, metrics: { __typename?: 'AssignmentCompletionMetricsType', _id: string, passed_count: number, failed_count: number, unranked_count: number, ranking_completed: boolean, average_passed: number } } | null> }, competences: { __typename?: 'CompetencesStatisticsType', _id: string, summary: { __typename?: 'CompetencePerformanceStatisticsSummaryType', _id: string, success_total: number, fail_total: number }, performances: Array<{ __typename?: 'CompetencePerformanceStatisticsType', _id: string, course_session_id: string, generation: string, circle_id: string, success_count: number, fail_count: number, details_url: string } | null> } } | null };
|
||||
export type CourseStatisticsQuery = { __typename?: 'Query', course_statistics?: { __typename?: 'CourseStatisticsType', _id: string, course_id: string, course_title: string, course_slug: string, course_session_selection_ids: Array<string | null>, course_session_properties: { __typename?: 'StatisticsCourseSessionPropertiesType', _id: string, generations: Array<string>, sessions: Array<{ __typename?: 'StatisticsCourseSessionDataType', id: string, name: string }>, circles: Array<{ __typename?: 'StatisticsCircleDataType', id: string, name: string, experts: Array<string | null> }> }, course_session_selection_metrics: { __typename?: 'StatisticsCourseSessionsSelectionMetricType', _id: string, session_count: number, participant_count: number, expert_count: number }, attendance_day_presences: { __typename?: 'AttendanceDayPresencesStatisticsType', _id: string, records: Array<{ __typename?: 'PresenceRecordStatisticsType', _id: string, course_session_id: string, generation: string, circle_id: string, due_date: string, participants_present: number, participants_total: number, details_url: string }>, summary: { __typename?: 'AttendanceSummaryStatisticsType', _id: string, days_completed: number, participants_present: number } }, feedback_responses: { __typename?: 'FeedbackStatisticsResponsesType', _id: string, records: Array<{ __typename?: 'FeedbackStatisticsRecordType', _id: string, course_session_id: string, generation: string, circle_id: string, satisfaction_average: number, satisfaction_max: number, details_url: string }>, summary: { __typename?: 'FeedbackStatisticsSummaryType', _id: string, satisfaction_average: number, satisfaction_max: number, total_responses: number } }, assignments: { __typename?: 'AssignmentsStatisticsType', _id: string, summary: { __typename?: 'AssignmentStatisticsSummaryType', _id: string, completed_count: number, average_passed: number }, records: Array<{ __typename?: 'AssignmentStatisticsRecordType', _id: string, course_session_id: string, course_session_assignment_id: string, circle_id: string, generation: string, assignment_title: string, assignment_type_translation_key: string, details_url: string, deadline: string, metrics: { __typename?: 'AssignmentCompletionMetricsType', _id: string, passed_count: number, failed_count: number, unranked_count: number, ranking_completed: boolean, average_passed: number } } | null> }, competences: { __typename?: 'CompetencesStatisticsType', _id: string, summary: { __typename?: 'CompetencePerformanceStatisticsSummaryType', _id: string, success_total: number, fail_total: number }, performances: Array<{ __typename?: 'CompetencePerformanceStatisticsType', _id: string, course_session_id: string, generation: string, circle_id: string, success_count: number, fail_count: number, details_url: string } | null> } } | null };
|
||||
|
||||
export type SendFeedbackMutationMutationVariables = Exact<{
|
||||
courseSessionId: Scalars['ID']['input'];
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ type AttendanceSummaryStatisticsType {
|
|||
|
||||
type FeedbackStatisticsResponsesType {
|
||||
_id: ID!
|
||||
records: [FeedbackStatisticsRecordType]!
|
||||
records: [FeedbackStatisticsRecordType!]!
|
||||
summary: FeedbackStatisticsSummaryType!
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { computed } from "vue";
|
|||
import type { CourseStatisticsType, PresenceRecordStatisticsType } from "@/gql/graphql";
|
||||
import StatisticFilterList from "@/components/dashboard/StatisticFilterList.vue";
|
||||
import ItProgress from "@/components/ui/ItProgress.vue";
|
||||
import { useCourseStatistics } from "@/composables";
|
||||
|
||||
const dashboardStore = useDashboardStore();
|
||||
|
||||
|
|
@ -12,17 +13,7 @@ const statistics = computed(() => {
|
|||
return dashboardStore.currentDashBoardData as CourseStatisticsType;
|
||||
});
|
||||
|
||||
const courseSessionName = (courseSessionId: string) => {
|
||||
return statistics.value.course_session_properties.sessions.find(
|
||||
(session) => session.id === courseSessionId
|
||||
)?.name;
|
||||
};
|
||||
|
||||
const circleMeta = (circleId: string) => {
|
||||
return statistics.value.course_session_properties.circles.find(
|
||||
(circle) => circle.id === circleId
|
||||
);
|
||||
};
|
||||
const { courseSessionName, circleMeta } = useCourseStatistics();
|
||||
|
||||
const attendanceStats = (present: number, total: number) => {
|
||||
return {
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
<script setup lang="ts">
|
||||
import { useDashboardStore } from "@/stores/dashboard";
|
||||
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
||||
import { computed } from "vue";
|
||||
import type {
|
||||
CourseStatisticsType,
|
||||
FeedbackStatisticsRecordType,
|
||||
PresenceRecordStatisticsType,
|
||||
} from "@/gql/graphql";
|
||||
import StatisticFilterList from "@/components/dashboard/StatisticFilterList.vue";
|
||||
import { useCourseStatistics } from "@/composables";
|
||||
|
||||
const dashboardStore = useDashboardStore();
|
||||
|
||||
const statistics = computed(() => {
|
||||
return dashboardStore.currentDashBoardData as CourseStatisticsType;
|
||||
});
|
||||
|
||||
const { courseSessionName, circleMeta } = useCourseStatistics();
|
||||
|
||||
const attendanceStats = (present: number, total: number) => {
|
||||
return {
|
||||
SUCCESS: present,
|
||||
FAIL: total - present,
|
||||
UNKNOWN: 0,
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main v-if="statistics">
|
||||
<div class="mb-10 flex items-center justify-between">
|
||||
<h3>{{ $t("a.Feedback Teilnehmer") }}</h3>
|
||||
<ItDropdownSelect
|
||||
:model-value="dashboardStore.currentDashboardConfig"
|
||||
class="mt-4 w-full lg:mt-0 lg:w-96"
|
||||
:items="dashboardStore.dashboardConfigs"
|
||||
@update:model-value="dashboardStore.switchAndLoadDashboardConfig"
|
||||
></ItDropdownSelect>
|
||||
</div>
|
||||
<div v-if="statistics.feedback_responses.records" class="mt-8 bg-white">
|
||||
<StatisticFilterList
|
||||
:course-session-properties="statistics.course_session_properties"
|
||||
:items="statistics.feedback_responses.records"
|
||||
>
|
||||
<template #default="{ item }">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<h4 class="font-bold">
|
||||
Feedback: Circle «{{ circleMeta(item.circle_id)?.name }}»
|
||||
</h4>
|
||||
<div>
|
||||
Durchführung «{{ courseSessionName(item.course_session_id) }}» -
|
||||
Trainer: {{ circleMeta(item.circle_id)?.experts[0] }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-4 flex items-center space-x-2">
|
||||
<div
|
||||
class="flex items-center justify-center rounded bg-green-500 px-2 py-1"
|
||||
>
|
||||
<span class="font-bold">
|
||||
{{ (item as FeedbackStatisticsRecordType).satisfaction_average }}
|
||||
</span>
|
||||
von
|
||||
<span>
|
||||
{{ (item as FeedbackStatisticsRecordType).satisfaction_max }}
|
||||
</span>
|
||||
</div>
|
||||
<span>
|
||||
{{ $t("a.Allgemeine Zufriedenheit") }}
|
||||
</span>
|
||||
</div>
|
||||
<router-link
|
||||
class="underline"
|
||||
:to="(item as PresenceRecordStatisticsType).details_url"
|
||||
>
|
||||
{{ $t("a.Details anschauen") }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</StatisticFilterList>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
|
@ -181,26 +181,22 @@ const router = createRouter({
|
|||
{
|
||||
path: "attendance",
|
||||
props: true,
|
||||
component: () =>
|
||||
import("@/pages/dashboard/statistic/AttendanceDayPresences.vue"),
|
||||
component: () => import("@/pages/dashboard/statistic/AttendanceList.vue"),
|
||||
},
|
||||
{
|
||||
path: "assignment",
|
||||
props: true,
|
||||
component: () =>
|
||||
import("@/pages/dashboard/statistic/AttendanceDayPresences.vue"),
|
||||
component: () => import("@/pages/dashboard/statistic/AttendanceList.vue"),
|
||||
},
|
||||
{
|
||||
path: "competence",
|
||||
props: true,
|
||||
component: () =>
|
||||
import("@/pages/dashboard/statistic/AttendanceDayPresences.vue"),
|
||||
component: () => import("@/pages/dashboard/statistic/AttendanceList.vue"),
|
||||
},
|
||||
{
|
||||
path: "feedback",
|
||||
props: true,
|
||||
component: () =>
|
||||
import("@/pages/dashboard/statistic/AttendanceDayPresences.vue"),
|
||||
component: () => import("@/pages/dashboard/statistic/FeedbackList.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ class FeedbackStatisticsRecordType(graphene.ObjectType):
|
|||
|
||||
class FeedbackStatisticsResponsesType(graphene.ObjectType):
|
||||
_id = graphene.ID(required=True)
|
||||
records = graphene.List(FeedbackStatisticsRecordType, required=True)
|
||||
records = graphene.List(
|
||||
graphene.NonNull(FeedbackStatisticsRecordType), required=True
|
||||
)
|
||||
summary = graphene.Field(FeedbackStatisticsSummaryType, required=True)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue