Skip to content

Commit 3a1c32d

Browse files
Merge pull request #6281 from christianbeeznest/fide-22571-3
Attendance: Various improvements in student view, export, and signatures - refs BT#22571
2 parents d0aec4f + 5eae5de commit 3a1c32d

File tree

12 files changed

+1109
-397
lines changed

12 files changed

+1109
-397
lines changed

assets/vue/components/attendance/AttendanceForm.vue

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,14 @@ import LayoutFormButtons from "../../components/layout/LayoutFormButtons.vue"
9292
import BaseButton from "../../components/basecomponents/BaseButton.vue"
9393
import BaseAdvancedSettingsButton from "../../components/basecomponents/BaseAdvancedSettingsButton.vue"
9494
import BaseInputText from "../basecomponents/BaseInputText.vue"
95-
import { useRoute } from "vue-router"
95+
import { useRoute, useRouter } from "vue-router"
9696
import { RESOURCE_LINK_PUBLISHED } from "../../constants/entity/resourcelink"
9797
import { useCidReq } from "../../composables/cidReq"
9898
import gradebookService from "../../services/gradebookService"
9999
100100
const { t } = useI18n()
101101
const route = useRoute()
102+
const router = useRouter()
102103
const { sid, cid } = useCidReq()
103104
const emit = defineEmits(["backPressed"])
104105
const props = defineProps({
@@ -194,10 +195,22 @@ const submitForm = async () => {
194195
try {
195196
if (props.initialData?.id) {
196197
await attendanceService.updateAttendance(props.initialData.id, postData)
198+
emit("backPressed", route.query)
197199
} else {
198-
await attendanceService.createAttendance(postData)
200+
const created = await attendanceService.createAttendance(postData)
201+
router.push({
202+
name: "AddCalendarEvent",
203+
params: {
204+
node: parentResourceNodeId.value,
205+
id: created.id,
206+
},
207+
query: {
208+
cid: route.query.cid,
209+
sid: route.query.sid,
210+
gid: route.query.gid,
211+
},
212+
})
199213
}
200-
emit("backPressed", route.query)
201214
} catch (error) {
202215
console.error("Error submitting attendance:", error)
203216
}

assets/vue/components/attendance/AttendanceTable.vue

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,20 @@
5252

5353
<!-- Column for # attended -->
5454
<Column
55-
field="results.length"
55+
field="doneCalendars"
5656
header="# attended"
5757
sortable
5858
>
5959
<template #body="slotProps">
60-
<center>{{ slotProps.data.results ? slotProps.data.results.length : 0 }}</center>
60+
<center>{{ slotProps.data.doneCalendars ?? 0 }}</center>
6161
</template>
6262
</Column>
6363

6464
<!-- Column for Detail -->
65-
<Column header="Detail">
65+
<Column
66+
v-if="isAdminOrTeacher"
67+
header="Detail"
68+
>
6669
<template #body="slotProps">
6770
<div class="flex gap-2 justify-center">
6871
<Button

assets/vue/components/basecomponents/ChamiloIcons.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export const chamiloIconToClass = {
6060
"file-text": "mdi mdi-file-document",
6161
"file-upload": "mdi mdi-file-upload",
6262
"file-video": "mdi mdi-file-video",
63+
"file-excel": "mdi mdi-file-excel-box",
6364
"filter": "mdi mdi-filter",
6465
"file-replace": "mdi mdi-file-replace",
6566
"fit-to-screen": "",
@@ -140,4 +141,6 @@ export const chamiloIconToClass = {
140141
"account-cancel": "mdi mdi-account-cancel",
141142
"zip-pack": "mdi mdi-archive",
142143
"zip-unpack": "mdi mdi-archive-arrow-down",
144+
"clear-all": "mdi mdi-broom",
145+
"qrcode": "mdi mdi-qrcode",
143146
}

assets/vue/services/attendanceService.js

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,9 @@ export default {
164164
}
165165
},
166166

167-
/**
168-
* Fetches users related to attendance based on course, session, or group.
169-
* @param {Object} params - Object with courseId, sessionId, and/or groupId.
170-
* @returns {Promise<Array>} - List of users.
171-
*/
172-
getAttendanceSheetUsers: async (params) => {
167+
getAttendanceSheetUsers: async (attendanceId, params) => {
173168
try {
174-
const response = await axios.get(`/attendance/users/context`, { params })
169+
const response = await axios.get(`/attendance/${attendanceId}/users/context`, { params })
175170
return response.data
176171
} catch (error) {
177172
console.error("Error fetching attendance sheet users:", error)
@@ -215,27 +210,36 @@ export default {
215210
return response.data
216211
},
217212

218-
/**
219-
* Exports an attendance list to PDF format.
220-
* @param {Number|String} attendanceId - ID of the attendance list.
221-
* @returns {Promise<Blob>} - PDF file of the attendance list.
222-
*/
223-
exportAttendanceToPdf: async (attendanceId) => {
224-
const response = await axios.get(`${ENTRYPOINT}attendances/${attendanceId}/export/pdf`, {
225-
responseType: "blob",
226-
})
213+
exportAttendanceToPdf: async (attendanceId, { cid, sid, gid }) => {
214+
const response = await axios.get(
215+
`/attendance/${attendanceId}/export/pdf`,
216+
{
217+
params: { cid, sid, gid },
218+
responseType: "blob",
219+
}
220+
)
227221
return response.data
228222
},
229223

230-
/**
231-
* Exports an attendance list to XLS format.
232-
* @param {Number|String} attendanceId - ID of the attendance list.
233-
* @returns {Promise<Blob>} - XLS file of the attendance list.
234-
*/
235-
exportAttendanceToXls: async (attendanceId) => {
236-
const response = await axios.get(`${ENTRYPOINT}attendances/${attendanceId}/export/xls`, {
237-
responseType: "blob",
238-
})
224+
exportAttendanceToXls: async (attendanceId, { cid, sid, gid }) => {
225+
const response = await axios.get(
226+
`/attendance/${attendanceId}/export/xls`,
227+
{
228+
params: { cid, sid, gid },
229+
responseType: "blob",
230+
}
231+
)
232+
return response.data
233+
},
234+
235+
generateQrCode: async (attendanceId, { cid, sid, gid }) => {
236+
const response = await axios.get(
237+
`/attendance/${attendanceId}/qrcode`,
238+
{
239+
params: { cid, sid, gid },
240+
responseType: "blob",
241+
}
242+
)
239243
return response.data
240244
},
241245

@@ -250,4 +254,19 @@ export default {
250254
throw error
251255
}
252256
},
257+
258+
getAttendancesWithDoneCount: async (params) => {
259+
const response = await axios.get(`/attendance/list_with_done_count`, { params });
260+
return response.data;
261+
},
262+
263+
getStudentAttendanceData: async (attendanceId) => {
264+
try {
265+
const response = await axios.get(`/attendance/${attendanceId}/student-dates`)
266+
return response.data
267+
} catch (error) {
268+
console.error("Error fetching student attendance data:", error)
269+
throw error
270+
}
271+
},
253272
}

assets/vue/views/attendance/AttendanceCalendarAdd.vue

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
<template>
22
<LayoutFormGeneric>
3+
<div class="bg-blue-100 text-blue-800 p-4 rounded border border-blue-300">
4+
<strong>{{ t("Information") }}:</strong>
5+
<span v-if="attendanceTitle">
6+
{{ t("You are adding calendar events for attendance") }}: <strong>{{ attendanceTitle }}</strong
7+
>.
8+
</span>
9+
<span>
10+
{{
11+
t(
12+
"The attendance calendar allows you to register attendance lists (one per real session the students need to attend). Add new attendance lists here.",
13+
)
14+
}}
15+
</span>
16+
</div>
17+
318
<template #header>
419
<BaseIcon icon="calendar-plus" />
520
{{ t("Add Attendance Calendar") }}
@@ -15,10 +30,22 @@ import { useI18n } from "vue-i18n"
1530
import LayoutFormGeneric from "../../components/layout/LayoutFormGeneric.vue"
1631
import BaseIcon from "../../components/basecomponents/BaseIcon.vue"
1732
import AttendanceCalendarForm from "../../components/attendance/AttendanceCalendarForm.vue"
33+
import attendanceService from "../../services/attendanceService"
34+
import { onMounted, ref } from "vue"
1835
1936
const { t } = useI18n()
2037
const router = useRouter()
2138
const route = useRoute()
39+
const attendanceTitle = ref("")
40+
41+
onMounted(async () => {
42+
try {
43+
const attendance = await attendanceService.getAttendance(route.params.id)
44+
attendanceTitle.value = attendance.title
45+
} catch (error) {
46+
console.error("Error fetching attendance:", error)
47+
}
48+
})
2249
2350
const goBack = () => {
2451
router.push({

assets/vue/views/attendance/AttendanceCalendarList.vue

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,29 @@
22
<div class="p-4">
33
<!-- Toolbar -->
44
<BaseToolbar>
5-
<BaseButton
6-
:label="t('Back to Attendance Sheet')"
7-
icon="back"
8-
type="info"
9-
@click="redirectToAttendanceSheet"
10-
/>
11-
<BaseButton
12-
:label="t('Add Calendar Event')"
13-
icon="plus"
14-
type="success"
15-
@click="redirectToAddCalendarEvent"
16-
/>
17-
18-
<BaseButton
19-
:label="t('Clear All')"
20-
icon="delete"
21-
type="error"
22-
@click="clearAllEvents"
23-
/>
5+
<template #start>
6+
<BaseButton
7+
icon="back"
8+
size="normal"
9+
type="black"
10+
@click="redirectToAttendanceSheet"
11+
:title="t('Back to Attendance Sheet')"
12+
/>
13+
<BaseButton
14+
icon="plus"
15+
size="normal"
16+
type="black"
17+
@click="redirectToAddCalendarEvent"
18+
:title="t('Add Calendar Event')"
19+
/>
20+
<BaseButton
21+
icon="clear-all"
22+
size="normal"
23+
type="black"
24+
@click="clearAllEvents"
25+
:title="t('Clear All')"
26+
/>
27+
</template>
2428
</BaseToolbar>
2529

2630
<!-- Informative Message -->

assets/vue/views/attendance/AttendanceList.vue

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
<template>
22
<div>
33
<BaseToolbar>
4-
<BaseButton
5-
:label="t('Add Attendance')"
6-
icon="plus"
7-
type="black"
8-
@click="redirectToCreateAttendance"
9-
/>
4+
<template #start>
5+
<BaseButton
6+
v-if="!isStudent"
7+
icon="file-add"
8+
size="normal"
9+
type="black"
10+
:title="t('Add Attendance')"
11+
@click="redirectToCreateAttendance"
12+
/>
13+
</template>
1014
</BaseToolbar>
11-
1215
<AttendanceTable
1316
:attendances="attendances"
1417
:loading="isLoading"
@@ -113,6 +116,7 @@ const fetchAttendances = async ({ page = 1, rows = 10 } = {}) => {
113116
resourceLinkListFromEntity: item.resourceLinkListFromEntity,
114117
attendanceQualifyTitle: item.attendanceQualifyTitle,
115118
attendanceWeight: item.attendanceWeight,
119+
doneCalendars: item.doneCalendars,
116120
}))
117121
118122
if (isStudent.value) {

0 commit comments

Comments
 (0)