Commit 275b17e4fb007f8a0fbc8457eb390fbc5dcda635
1 parent
c301facad4
Exists in
master
and in
1 other branch
Integrated new functionality of course attendance and Show attendance for a part…
…icular course of students
Showing
5 changed files
with
532 additions
and
0 deletions
Show diff stats
src/api/menu.js
... | ... | @@ -64,6 +64,7 @@ const adminMenu = [ |
64 | 64 | items: [ |
65 | 65 | { name: 'StudentAttendence', title: 'Student Attendance', component: 'Student Attendence', action: '', }, |
66 | 66 | { name: 'TeacherAttendence', title: 'Teacher Attendance', component: 'Teacher Attendence', action: '', }, |
67 | + { name: 'courseAttendance', title: 'Course Attendance', component: 'Course Attendance', action: '', }, | |
67 | 68 | // { name: 'userAttendence', title: 'User Attendance', component: 'User Attendence', action: '', }, |
68 | 69 | ] |
69 | 70 | }, |
... | ... | @@ -350,6 +351,7 @@ const teacherMenu = [{ |
350 | 351 | items: [ |
351 | 352 | { name: 'StudentAttendence', title: 'Student Attendance', component: 'Student Attendence', action: '', }, |
352 | 353 | { name: 'TeacherAttendence', title: 'Teacher Attendance', component: 'Teacher Attendence', action: '', }, |
354 | + { name: 'courseAttendance', title: 'Course Attendance', component: 'Course Attendance', action: '', }, | |
353 | 355 | // { name: 'userAttendence', title: 'User Attendance', component: 'User Attendence', action: '', }, |
354 | 356 | ] |
355 | 357 | }, | ... | ... |
src/pages/Attendence/courseAttendance.vue
... | ... | @@ -0,0 +1,200 @@ |
1 | +<template> | |
2 | + <v-container fluid class="body-color"> | |
3 | + <v-toolbar color="transparent" flat> | |
4 | + <v-spacer></v-spacer> | |
5 | + <v-flex xs12 sm4 md2> | |
6 | + <v-select | |
7 | + small | |
8 | + :items="classList" | |
9 | + label="Select Class" | |
10 | + v-model="getAttendance.classId" | |
11 | + item-text="classNum" | |
12 | + item-value="_id" | |
13 | + name="Select Class" | |
14 | + class="px-2" | |
15 | + @change="getSection(getAttendance.classId)" | |
16 | + required | |
17 | + ></v-select> | |
18 | + </v-flex> | |
19 | + <v-flex xs12 sm4 md2> | |
20 | + <v-select | |
21 | + small | |
22 | + :items="addSection" | |
23 | + label="Select Section" | |
24 | + v-model="getAttendance.sectionId" | |
25 | + item-text="name" | |
26 | + item-value="_id" | |
27 | + name="Select Section" | |
28 | + @change="getStudentsDetail(getAttendance.sectionId)" | |
29 | + class="px-2" | |
30 | + required | |
31 | + ></v-select> | |
32 | + </v-flex> | |
33 | + </v-toolbar> | |
34 | + <v-data-table | |
35 | + :headers="headers" | |
36 | + :items="studentsData" | |
37 | + :pagination.sync="pagination" | |
38 | + :search="search" | |
39 | + > | |
40 | + <template slot="items" slot-scope="props"> | |
41 | + <tr class="tr"> | |
42 | + <td class="td td-row">{{ props.index + 1}}</td> | |
43 | + <td class="text-xs-center td td-row"> | |
44 | + <v-avatar size="40"> | |
45 | + <img :src="props.item.profilePicUrl" v-if="props.item.profilePicUrl" /> | |
46 | + <img src="/static/icon/user.png" v-else-if="!props.item.profilePicUrl" /> | |
47 | + </v-avatar> | |
48 | + </td> | |
49 | + <td class="text-xs-center td td-row">{{ props.item.name}}</td> | |
50 | + <td class="text-xs-center td td-row">{{ props.item.fatherCellNo}}</td> | |
51 | + <td class="text-xs-center td td-row">{{ props.item.email }}</td> | |
52 | + <td class="text-xs-center td td-row"> | |
53 | + <router-link :to="{ name:'View Course Attendance',params: { id:props.item._id } }"> | |
54 | + <v-tooltip top> | |
55 | + <img | |
56 | + slot="activator" | |
57 | + style="cursor:pointer; width:20px; height:25px; " | |
58 | + class="mr-3" | |
59 | + src="/static/icon/view.png" | |
60 | + /> | |
61 | + <span>View</span> | |
62 | + </v-tooltip> | |
63 | + </router-link> | |
64 | + </td> | |
65 | + </tr> | |
66 | + </template> | |
67 | + </v-data-table> | |
68 | + <v-snackbar | |
69 | + :timeout="timeout" | |
70 | + :top="y === 'top'" | |
71 | + :right="x === 'right'" | |
72 | + :vertical="mode === 'vertical'" | |
73 | + v-model="snackbar" | |
74 | + color="color" | |
75 | + >{{ text }}</v-snackbar> | |
76 | + </v-container> | |
77 | +</template> | |
78 | + | |
79 | +<script> | |
80 | +import http from "@/Services/http.js"; | |
81 | +import moment from "moment"; | |
82 | + | |
83 | +export default { | |
84 | + data: () => ({ | |
85 | + snackbar: false, | |
86 | + y: "top", | |
87 | + x: "right", | |
88 | + mode: "", | |
89 | + timeout: 3000, | |
90 | + text: "", | |
91 | + color: "", | |
92 | + show: true, | |
93 | + | |
94 | + classList: [], | |
95 | + addSection: [], | |
96 | + studentsData: [], | |
97 | + | |
98 | + pagination: { | |
99 | + rowsPerPage: 10, | |
100 | + }, | |
101 | + | |
102 | + role: "", | |
103 | + schoolRole: "", | |
104 | + search: "", | |
105 | + getAttendance: {}, | |
106 | + headers: [ | |
107 | + { | |
108 | + text: "No", | |
109 | + align: "", | |
110 | + sortable: false, | |
111 | + value: "index", | |
112 | + }, | |
113 | + { | |
114 | + text: "Profile Pic", | |
115 | + value: "profilprofilePicUrlePicUrl", | |
116 | + sortable: false, | |
117 | + align: "center", | |
118 | + }, | |
119 | + { text: "Name", value: "name", sortable: false, align: "center" }, | |
120 | + { | |
121 | + text: "Mobile No", | |
122 | + value: "fatherCellNo", | |
123 | + sortable: false, | |
124 | + align: "center", | |
125 | + }, | |
126 | + { text: "Email", value: "email", sortable: false, align: "center" }, | |
127 | + { text: "Attendance", value: "", sortable: false, align: "center" }, | |
128 | + ], | |
129 | + }), | |
130 | + methods: { | |
131 | + getAllClass() { | |
132 | + http() | |
133 | + .get("/getClassesList", { | |
134 | + headers: { Authorization: "Bearer " + this.token }, | |
135 | + }) | |
136 | + .then((response) => { | |
137 | + this.classList = response.data.data; | |
138 | + }) | |
139 | + .catch((error) => { | |
140 | + this.snackbar = true; | |
141 | + this.color = "error"; | |
142 | + this.text = error.response.data.message; | |
143 | + }); | |
144 | + }, | |
145 | + getSection(_id) { | |
146 | + this.showLoader = true; | |
147 | + this.studentsData = []; | |
148 | + http() | |
149 | + .get( | |
150 | + "/getSectionsList", | |
151 | + { params: { classId: _id } }, | |
152 | + { | |
153 | + headers: { Authorization: "Bearer " + this.token }, | |
154 | + } | |
155 | + ) | |
156 | + .then((response) => { | |
157 | + this.addSection = response.data.data; | |
158 | + this.showLoader = false; | |
159 | + }) | |
160 | + .catch((err) => { | |
161 | + this.showLoader = false; | |
162 | + this.snackbar = true; | |
163 | + this.color = "error"; | |
164 | + this.text = error.response.data.message; | |
165 | + // console.log("err====>", err); | |
166 | + }); | |
167 | + }, | |
168 | + getStudentsDetail(_id) { | |
169 | + this.showLoader = true; | |
170 | + http() | |
171 | + .get("/getStudentWithClass", { | |
172 | + params: { | |
173 | + classId: this.getAttendance.classId, | |
174 | + sectionId: this.getAttendance.sectionId, | |
175 | + }, | |
176 | + }) | |
177 | + .then((response) => { | |
178 | + this.studentsData = response.data.data; | |
179 | + this.showLoader = false; | |
180 | + var attendance = ""; | |
181 | + for (let i = 0; i < this.studentsData.length; i++) { | |
182 | + this.studentsData[i].attendance = true; | |
183 | + } | |
184 | + }) | |
185 | + .catch((error) => { | |
186 | + // console.log("err====>", error); | |
187 | + this.showLoader = false; | |
188 | + this.snackbar = true; | |
189 | + this.color = "error"; | |
190 | + this.text = error.response.data.message; | |
191 | + }); | |
192 | + }, | |
193 | + }, | |
194 | + mounted() { | |
195 | + this.token = this.$store.state.token; | |
196 | + this.getAllClass(); | |
197 | + this.role = this.$store.state.role; | |
198 | + }, | |
199 | +}; | |
200 | +</script> | |
0 | 201 | \ No newline at end of file | ... | ... |
src/pages/Attendence/viewCourseAttendance.vue
... | ... | @@ -0,0 +1,283 @@ |
1 | +<template> | |
2 | + <v-container fluid grid-list-md class="body-color"> | |
3 | + <v-dialog v-model="viewCourseAttendance" max-width="1000" scrollable persistent> | |
4 | + <v-card flat class="pa-3"> | |
5 | + <v-layout> | |
6 | + <v-flex xs12> | |
7 | + <label class="title text-xs-center">Course Attendance</label> | |
8 | + <v-icon size="24" class="right" @click="viewCourseAttendance = false">cancel</v-icon> | |
9 | + </v-flex> | |
10 | + </v-layout> | |
11 | + <v-card-text> | |
12 | + <v-data-table :headers="headers" :items="courseAttendanceList"> | |
13 | + <template slot="items" slot-scope="props"> | |
14 | + <tr class="tr"> | |
15 | + <td class="text-xs-center td td-row">{{ props.item.courseId.courseName}}</td> | |
16 | + <td class="text-xs-center td td-row">{{ props.item.startTime}}</td> | |
17 | + <td class="text-xs-center td td-row">{{ props.item.endTime }}</td> | |
18 | + </tr> | |
19 | + </template> | |
20 | + </v-data-table> | |
21 | + </v-card-text> | |
22 | + </v-card> | |
23 | + </v-dialog> | |
24 | + <div> | |
25 | + <v-layout wrap> | |
26 | + <v-flex xs12 sm12 md4> | |
27 | + <v-card flat> | |
28 | + <h3 class="py-2 text-xs-center card-style white--text">Profile</h3> | |
29 | + <v-card-text> | |
30 | + <v-container> | |
31 | + <v-layout wrap> | |
32 | + <v-flex xs12> | |
33 | + <v-layout> | |
34 | + <v-flex | |
35 | + xs12 | |
36 | + class="text-xs-center text-sm-center text-md-center text-lg-center" | |
37 | + > | |
38 | + <v-avatar size="80px"> | |
39 | + <img src="/static/icon/user.png" v-if="!studentData.profilePicUrl" /> | |
40 | + <img | |
41 | + :src="studentData.profilePicUrl" | |
42 | + v-else-if="studentData.profilePicUrl" | |
43 | + /> | |
44 | + </v-avatar> | |
45 | + </v-flex> | |
46 | + </v-layout> | |
47 | + <v-layout> | |
48 | + <v-flex xs12 sm12> | |
49 | + <h3 class="text-xs-center"> | |
50 | + <b>{{ studentData.name }}</b> | |
51 | + </h3> | |
52 | + <p class="text-xs-center grey--text">Student</p> | |
53 | + </v-flex> | |
54 | + </v-layout> | |
55 | + <v-layout style="border: 1px solid lightgrey;"> | |
56 | + <v-flex xs6 sm6 class="pa-0"> | |
57 | + <h4 class="right"> | |
58 | + <b>Roll No :</b> | |
59 | + </h4> | |
60 | + </v-flex> | |
61 | + <v-flex sm6 xs6 class="pa-0"> | |
62 | + <h4>{{ studentData.rollNo }}</h4> | |
63 | + </v-flex> | |
64 | + </v-layout> | |
65 | + <v-layout style="border: 1px solid lightgrey;"> | |
66 | + <v-flex xs6 sm6 class="pa-0"> | |
67 | + <h4 class="right"> | |
68 | + <b>Class :</b> | |
69 | + </h4> | |
70 | + </v-flex> | |
71 | + <v-flex sm6 xs6 class="right pa-0"> | |
72 | + <h4>{{ studentData.classId.classNum }}</h4> | |
73 | + </v-flex> | |
74 | + </v-layout> | |
75 | + <v-layout style="border: 1px solid lightgrey;"> | |
76 | + <v-flex xs6 sm6 class="right pa-0"> | |
77 | + <h4 class="right"> | |
78 | + <b>Section :</b> | |
79 | + </h4> | |
80 | + </v-flex> | |
81 | + <v-flex sm6 xs6 class="right pa-0"> | |
82 | + <h4>{{ studentData.sectionId.name}}</h4> | |
83 | + </v-flex> | |
84 | + </v-layout> | |
85 | + </v-flex> | |
86 | + </v-layout> | |
87 | + </v-container> | |
88 | + </v-card-text> | |
89 | + </v-card> | |
90 | + </v-flex> | |
91 | + <v-flex xs12 sm12 md8> | |
92 | + <v-card flat> | |
93 | + <h3 class="py-2 text-xs-center card-style white--text">Attendence</h3> | |
94 | + <YearCalendar | |
95 | + v-model="year" | |
96 | + :activeDates="activeDates" | |
97 | + prefixClass="your_customized_wrapper_class" | |
98 | + :activeClass="activeClass" | |
99 | + @toggleDate="toggleDate" | |
100 | + ></YearCalendar> | |
101 | + </v-card> | |
102 | + </v-flex> | |
103 | + </v-layout> | |
104 | + </div> | |
105 | + <img :src="output" v-show="false" /> | |
106 | + <div class="loader" v-if="showLoader"> | |
107 | + <v-progress-circular indeterminate color="white"></v-progress-circular> | |
108 | + </div> | |
109 | + </v-container> | |
110 | +</template> | |
111 | + | |
112 | +<script lang="js"> | |
113 | +import moment from "moment"; | |
114 | +import http from "@/Services/http.js"; | |
115 | +import YearCalendar from "vue-material-year-calendar"; | |
116 | +import jsPDF from 'jspdf'; | |
117 | + // eslint-disable-next-line | |
118 | +import autoTable from 'jspdf-autotable'; | |
119 | + | |
120 | +export default { | |
121 | + components: { YearCalendar }, | |
122 | + data() { | |
123 | + return { | |
124 | + output:null, | |
125 | + showLoader: false, | |
126 | + token: "", | |
127 | + year: new Date().getFullYear(), | |
128 | + activeDates: [], | |
129 | + activeClass: "", | |
130 | + studentData: { | |
131 | + classId: { | |
132 | + classNum: "" | |
133 | + }, | |
134 | + sectionId: { | |
135 | + name: "" | |
136 | + }, | |
137 | + }, | |
138 | + courseAttendanceData:{}, | |
139 | + courseAttendanceList: [], | |
140 | + viewCourseAttendance: false, | |
141 | + headers: [ | |
142 | + { text: "Course Name", value: "courseName", sortable: false, align: "center" }, | |
143 | + { | |
144 | + text: "Start Time", | |
145 | + value: "startTime", | |
146 | + sortable: false, | |
147 | + align: "center", | |
148 | + }, | |
149 | + { text: "End Time", value: "endTime", sortable: false, align: "center" }, | |
150 | + ], | |
151 | + selectedDates: [], | |
152 | + }; | |
153 | + }, | |
154 | + mounted() { | |
155 | + this.token = this.$store.state.token; | |
156 | + this.getStudentAttendence(); | |
157 | + this.getStudentData(); | |
158 | + }, | |
159 | + methods: { | |
160 | + toggleDate (dateInfo) { | |
161 | + if (this.selectedDates.includes(dateInfo.date)) { | |
162 | + this.viewCourseAttendance = true; | |
163 | + } | |
164 | + }, | |
165 | + dates: function(date) { | |
166 | + return moment(date).format("MMMM DD, YYYY"); | |
167 | + }, | |
168 | + getStudentAttendence() { | |
169 | + this.showLoader = true; | |
170 | + http() | |
171 | + .get( | |
172 | + "/studentAttendance", | |
173 | + { params: { studentId: this.$route.params.id } }, | |
174 | + { | |
175 | + headers: { Authorization: "Bearer " + this.token } | |
176 | + } | |
177 | + ) | |
178 | + .then(response => { | |
179 | + this.showLoader = false; | |
180 | + }) | |
181 | + .catch(error => { | |
182 | + this.showLoader = false; | |
183 | + if (error.response.status === 401) { | |
184 | + this.$router.replace({ path: "/" }); | |
185 | + this.$store.dispatch("setToken", null); | |
186 | + this.$store.dispatch("Id", null); | |
187 | + this.$store.dispatch("Role", null); | |
188 | + } | |
189 | + }); | |
190 | + }, | |
191 | + getStudentData() { | |
192 | + http() | |
193 | + .get( | |
194 | + "/getParticularStudentDetail", | |
195 | + { params: { studentId: this.$route.params.id } }, | |
196 | + { | |
197 | + headers: { Authorization: "Bearer " + this.token } | |
198 | + } | |
199 | + ) | |
200 | + .then(response => { | |
201 | + this.studentData = response.data.data; | |
202 | + this.getCourseAttendance(response.data.data.classId._id); | |
203 | + }) | |
204 | + .catch(err => { | |
205 | + // console.log("err====>", err); | |
206 | + this.snackbar = true; | |
207 | + this.color = "error"; | |
208 | + this.text = error.response.data.message; | |
209 | + // this.$router.replace({ path: '/' }); | |
210 | + }); | |
211 | + }, | |
212 | + getCourseAttendance(classId) { | |
213 | + http() | |
214 | + .get( | |
215 | + "/getStudentCourseAttendance", | |
216 | + { params: { studentId: this.$route.params.id, | |
217 | + classId: classId } | |
218 | + }, | |
219 | + { | |
220 | + headers: { Authorization: "Bearer " + this.token } | |
221 | + } | |
222 | + ) | |
223 | + .then(response => { | |
224 | + this.courseAttendanceData = response.data.data; | |
225 | + this.courseAttendanceList = response.data.data[0].studentAttendance; | |
226 | + // console.log("===this.courseAttendanceList===", this.courseAttendanceList) | |
227 | + let array = []; | |
228 | + for (let i = 0; i < this.courseAttendanceData.length; i++) { | |
229 | + if (this.courseAttendanceData[i].date) { | |
230 | + this.selectedDates.push(this.courseAttendanceData[i].date) | |
231 | + array.push({ | |
232 | + date: this.courseAttendanceData[i].date, | |
233 | + className: "green" | |
234 | + }); | |
235 | + } | |
236 | + } | |
237 | + this.activeDates = array; | |
238 | + }) | |
239 | + .catch(err => { | |
240 | + this.snackbar = true; | |
241 | + this.color = "error"; | |
242 | + this.text = error.response.data.message; | |
243 | + }); | |
244 | + }, | |
245 | + profile(item) { | |
246 | + this.viewCourseAttendance = true; | |
247 | + }, | |
248 | + } | |
249 | +}; | |
250 | +</script> | |
251 | + | |
252 | +<style lang="stylus"> | |
253 | +.your_customized_wrapper_class { | |
254 | + background-color: #0aa; | |
255 | + color: white; | |
256 | + | |
257 | + &.red { | |
258 | + background-color: red; | |
259 | + color: white; | |
260 | + | |
261 | + &:after { | |
262 | + background-size: 100% 100%; | |
263 | + } | |
264 | + } | |
265 | + | |
266 | + &.blue { | |
267 | + background-color: #0000aa; | |
268 | + color: white; | |
269 | + } | |
270 | + | |
271 | + &.your_customized_classname { | |
272 | + background-color: yellow; | |
273 | + color: black; | |
274 | + } | |
275 | +} | |
276 | +</style> | |
277 | +<style scoped> | |
278 | +.card-style { | |
279 | + background: #7f62f8 !important; | |
280 | + border-color: #7f62f8 !important; | |
281 | + border-radius: 12px; | |
282 | +} | |
283 | +</style> | |
0 | 284 | \ No newline at end of file | ... | ... |
src/pages/Dashboard/LiveOnlineClass.vue
... | ... | @@ -165,6 +165,7 @@ export default { |
165 | 165 | appLink: "", |
166 | 166 | showStartSessionButton: true, |
167 | 167 | showJoinSessionButton: true, |
168 | + courseAttendanceId: {}, | |
168 | 169 | }; |
169 | 170 | }, |
170 | 171 | methods: { |
... | ... | @@ -373,6 +374,8 @@ export default { |
373 | 374 | http() |
374 | 375 | .post("/createCourseAttendance", attendenceData) |
375 | 376 | .then((response) => { |
377 | + this.courseAttendanceId = response.data.data._id; | |
378 | + this.updateCourseAttendance(); | |
376 | 379 | this.loading = false; |
377 | 380 | // this.snackbar = true; |
378 | 381 | // this.color = "green"; |
... | ... | @@ -397,6 +400,22 @@ export default { |
397 | 400 | this.showLoader = false; |
398 | 401 | }); |
399 | 402 | }, |
403 | + updateCourseAttendance() { | |
404 | + this.showLoader = true; | |
405 | + var payloadData = { | |
406 | + courseAttendanceId: this.courseAttendanceId, | |
407 | + liveClassId: this.attendenceLiveClassId, | |
408 | + endTime: this.formatAMPM(new Date()), | |
409 | + }; | |
410 | + http() | |
411 | + .put("/updateCourseAttendance", payloadData) | |
412 | + .then((response) => { | |
413 | + this.showLoader = false; | |
414 | + }) | |
415 | + .catch((error) => { | |
416 | + this.showLoader = false; | |
417 | + }); | |
418 | + }, | |
400 | 419 | async studentClasses() { |
401 | 420 | this.liveLink = ""; |
402 | 421 | this.room = ""; | ... | ... |
src/router/paths.js
... | ... | @@ -486,6 +486,20 @@ export default [{ |
486 | 486 | ) |
487 | 487 | }, |
488 | 488 | { |
489 | + path: '/AttendanceCourse', | |
490 | + meta: {}, | |
491 | + name: 'Course Attendance', | |
492 | + props: (route) => ({ | |
493 | + type: route.query.type | |
494 | + }), | |
495 | + component: () => | |
496 | + import( | |
497 | + /* webpackChunkName: "routes" */ | |
498 | + /* webpackMode: "lazy-once" */ | |
499 | + `@/pages/Attendence/courseAttendance.vue` | |
500 | + ) | |
501 | +}, | |
502 | +{ | |
489 | 503 | path: '/salaryTemplate', |
490 | 504 | meta: {}, |
491 | 505 | name: 'Salary Template', |
... | ... | @@ -712,6 +726,20 @@ export default [{ |
712 | 726 | ) |
713 | 727 | }, |
714 | 728 | { |
729 | + path: '/CourseAttendance/:id', | |
730 | + meta: {}, | |
731 | + name: 'View Course Attendance', | |
732 | + props: (route) => ({ | |
733 | + type: route.query.type | |
734 | + }), | |
735 | + component: () => | |
736 | + import( | |
737 | + /* webpackChunkName: "routes" */ | |
738 | + /* webpackMode: "lazy-once" */ | |
739 | + `@/pages/Attendence/viewCourseAttendance.vue` | |
740 | + ) | |
741 | +}, | |
742 | +{ | |
715 | 743 | path: '/viewInvoice/:viewInvoiceId', |
716 | 744 | meta: {}, |
717 | 745 | name: 'View Invoice', | ... | ... |