feat: show student course and assessment progress on batch page

This commit is contained in:
Jannat Patel
2024-12-13 10:44:56 +05:30
parent 0beffc3083
commit fdacab66f7
4 changed files with 104 additions and 55 deletions

View File

@@ -110,6 +110,7 @@ const openCourseModal = () => {
}
const getCoursesColumns = () => {
console.log(courses.data)
return [
{
label: 'Title',
@@ -118,13 +119,13 @@ const getCoursesColumns = () => {
},
{
label: 'Lessons',
key: 'lesson_count',
key: 'lessons',
align: 'right',
},
{
label: 'Enrollments',
align: 'right',
key: 'enrollment_count',
key: 'enrollments',
},
]
}

View File

@@ -20,10 +20,10 @@
>
<ListHeaderItem :item="item" v-for="item in getStudentColumns()">
<template #prefix="{ item }">
<component
<FeatherIcon
v-if="item.icon"
:is="item.icon"
class="h-4 w-4 stroke-1.5 ml-4"
:name="item.icon"
class="h-4 w-4 stroke-1.5"
/>
</template>
</ListHeaderItem>
@@ -42,9 +42,19 @@
/>
</div>
</template>
<div>
<div v-if="column.key == 'courses'">
{{ row[column.key] }}
</div>
<div v-else-if="column.icon == 'book-open'">
{{ Math.ceil(row.courses[column.key]) }}
</div>
<Badge
v-else-if="column.icon == 'help-circle'"
:theme="getStatusTheme(row.assessments[column.key])"
class="text-xs"
>
{{ row.assessments[column.key] }}
</Badge>
</ListRowItem>
</template>
</ListRow>
@@ -74,7 +84,11 @@
</template>
<script setup>
import {
Avatar,
Badge,
Button,
createResource,
FeatherIcon,
ListHeader,
ListHeaderItem,
ListSelectBanner,
@@ -82,8 +96,6 @@ import {
ListRows,
ListView,
ListRowItem,
Avatar,
Button,
} from 'frappe-ui'
import { Trash2, Plus } from 'lucide-vue-next'
import { ref } from 'vue'
@@ -109,27 +121,38 @@ const students = createResource({
})
const getStudentColumns = () => {
return [
let columns = [
{
label: 'Full Name',
key: 'full_name',
width: 2,
},
{
label: 'Courses Done',
key: 'courses_completed',
align: 'center',
},
{
label: 'Assessments Done',
key: 'assessments_completed',
align: 'center',
},
{
label: 'Last Active',
key: 'last_active',
width: 1,
},
]
if (students.data?.[0].courses) {
Object.keys(students.data?.[0].courses).forEach((course) => {
columns.push({
label: `${course} (%)`,
key: course,
width: 1,
icon: 'book-open',
align: 'center',
})
})
}
if (students.data?.[0].assessments) {
Object.keys(students.data?.[0].assessments).forEach((assessment) => {
columns.push({
label: assessment,
key: assessment,
width: 1,
icon: 'help-circle',
align: 'left',
})
})
}
return columns
}
const openStudentModal = () => {
@@ -160,4 +183,14 @@ const removeStudents = (selections, unselectAll) => {
}
)
}
const getStatusTheme = (status) => {
if (status === 'Pass') {
return 'green'
} else if (status == 'Not Graded') {
return 'orange'
} else {
return 'red'
}
}
</script>

View File

@@ -28,6 +28,7 @@
import { Dialog, createResource } from 'frappe-ui'
import { ref } from 'vue'
import Link from '@/components/Controls/Link.vue'
import { showToast } from '@/utils'
const students = defineModel('reloadStudents')
const student = ref()
@@ -61,8 +62,11 @@ const addStudent = (close) => {
{
onSuccess() {
students.value.reload()
close()
student.value = null
close()
},
onError(err) {
showToast(__('Error'), __(err.messages?.[0] || err), 'x')
},
}
)

View File

@@ -874,26 +874,6 @@ def is_onboarding_complete():
}
def has_submitted_assessment(assessment, type, member=None):
if not member:
member = frappe.session.user
doctype = (
"LMS Assignment Submission" if type == "LMS Assignment" else "LMS Quiz Submission"
)
docfield = "assignment" if type == "LMS Assignment" else "quiz"
filters = {}
filters[docfield] = assessment
filters["member"] = member
return frappe.db.exists(doctype, filters)
def has_graded_assessment(submission):
status = frappe.db.get_value("LMS Assignment Submission", submission, "status")
return False if status == "Not Graded" else True
def get_evaluator(course, batch):
evaluator = None
evaluator = frappe.db.get_value(
@@ -1459,13 +1439,11 @@ def get_quiz_details(assessment, member):
@frappe.whitelist()
def get_batch_students(batch):
students = []
students_list = frappe.get_all(
"Batch Student", filters={"parent": batch}, fields=["student", "name"]
)
batch_courses = frappe.get_all("Batch Course", {"parent": batch}, pluck="course")
batch_courses = frappe.get_all("Batch Course", {"parent": batch}, ["course", "title"])
assessments = frappe.get_all(
"LMS Assessment",
filters={"parent": batch},
@@ -1483,29 +1461,62 @@ def get_batch_students(batch):
)
detail.last_active = format_datetime(detail.last_active, "dd MMM YY")
detail.name = student.name
students.append(detail)
detail.courses = frappe._dict()
detail.assessments = frappe._dict()
""" Iterate through courses and track their progress """
for course in batch_courses:
progress = frappe.db.get_value(
"LMS Enrollment", {"course": course, "member": student.student}, "progress"
"LMS Enrollment", {"course": course.course, "member": student.student}, "progress"
)
detail.courses[course.title] = progress
if progress == 100:
courses_completed += 1
detail.courses_completed = courses_completed
""" Iterate through assessments and track their progress """
for assessment in assessments:
if has_submitted_assessment(
title = frappe.db.get_value("LMS Assignment", assessment.assessment_name, "title")
status = has_submitted_assessment(
assessment.assessment_name, assessment.assessment_type, student.student
):
)
detail.assessments[title] = status
if status not in ["Not Attempted", 0]:
assessments_completed += 1
detail.courses_completed = courses_completed
detail.assessments_completed = assessments_completed
students.append(detail)
return students
def has_submitted_assessment(assessment, assessment_type, member=None):
if not member:
member = frappe.session.user
if assessment_type == "LMS Assignment":
doctype = "LMS Assignment Submission"
docfield = "assignment"
fields = ["status"]
not_attempted = "Not Attempted"
elif assessment_type == "LMS Quiz":
doctype = "LMS Quiz Submission"
docfield = "quiz"
fields = ["score"]
not_attempted = 0
filters = {}
filters[docfield] = assessment
filters["member"] = member
attempt = frappe.db.exists(doctype, filters)
if attempt:
attempt_details = frappe.db.get_value(doctype, filters, fields)
return attempt_details
else:
return not_attempted
@frappe.whitelist()
def get_discussion_topics(doctype, docname, single_thread):
if single_thread: