Commit 275b17e4fb007f8a0fbc8457eb390fbc5dcda635

Authored by Shikha Mishra
1 parent c301facad4
Exists in master and in 1 other branch ui-design

Integrated new functionality of course attendance and Show attendance for a part…

…icular course of students
... ... @@ -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',
... ...