lrf402788946 4 years ago
parent
commit
047ccd022b
1 changed files with 250 additions and 29 deletions
  1. 250 29
      src/views/train-plan/attendance.vue

+ 250 - 29
src/views/train-plan/attendance.vue

@@ -19,11 +19,38 @@
           <el-button type="primary" size="mini" @click="onsearch()"> 查询</el-button>
         </el-form-item>
       </el-form>
-      <data-table :fields="fields" :data="list"> </data-table>
+      <!-- <data-table :fields="fields" :data="list"> </data-table> -->
+      <el-table :data="list" border stripe height="600px" v-if="headList.length > 0">
+        <el-table-column align="center" v-for="(h, hindex) in headList" :key="`col-${hindex}`" :label="h.label" :prop="h.prop">
+          <template v-if="h.prop !== 'name'">
+            <el-table-column align="center" label="上午">
+              <template v-slot="{ row }">
+                {{ getTableContent(row, h.label, 'am') }}
+              </template>
+            </el-table-column>
+            <el-table-column align="center" label="下午">
+              <template v-slot="{ row }">
+                {{ getTableContent(row, h.label, 'pm') }}
+              </template>
+            </el-table-column>
+            <el-table-column align="center" label="寝室">
+              <template v-slot="{ row }">
+                {{ getTableContent(row, h.label, 'bd') }}
+              </template>
+            </el-table-column>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-card v-else>
+        <el-row type="flex" align="middle" style="height:600px; font-size:18px; text-align:center">
+          <el-col :span="24">请选择班级后进行查询</el-col>
+        </el-row>
+      </el-card>
     </list-frame>
   </div>
 </template>
 <script>
+const moment = require('moment');
 import _ from 'lodash';
 import listFrame from '@frame/layout/admin/list-frame';
 import dataTable from '@frame/components/data-table';
@@ -32,14 +59,14 @@ const { mapActions: attendance } = createNamespacedHelpers('attendance');
 const { mapActions: student } = createNamespacedHelpers('student');
 const { mapActions: trainplan } = createNamespacedHelpers('trainplan');
 const { mapActions: classes } = createNamespacedHelpers('classes');
-
+const { mapActions: leave } = createNamespacedHelpers('leave');
 export default {
   metaInfo: { title: '考勤管理' },
   name: 'attendance',
   props: {},
   components: {
     listFrame,
-    dataTable,
+    // dataTable,
   },
   data: () => ({
     classList: [],
@@ -54,7 +81,7 @@ export default {
         label: '类型',
         prop: 'type',
         format: item => {
-          return item === '0' ? '上课考勤' : item === '1' ? '上课考勤' : '';
+          return item === '0' ? '上课考勤' : item === '1' ? '寝室考勤' : '';
         },
       },
       {
@@ -66,6 +93,9 @@ export default {
       },
     ],
     form: {},
+    headList: [],
+    attendList: [],
+    leaveList: [],
     list: [],
     total: 0,
   }),
@@ -78,6 +108,8 @@ export default {
     ...student({ stuquery: 'query' }),
     ...trainplan({ planfetch: 'fetch' }),
     ...classes({ classesquery: 'query' }),
+    ...leave({ studentLeave: 'query' }),
+    // 找到指定范围的学生,找到这些学生的签单信息,找到这些学生的班级信息
     async searchinfo() {
       const res = await this.planfetch(this.defaultOption.planid);
       let terms = res.data.termnum;
@@ -87,49 +119,238 @@ export default {
         this.getClasses(this.form.termid);
       }
     },
-    getBatch(termid) {
-      let batchs = this.termList.filter(f => f._id === termid);
-      if (batchs.length > 0) {
-        let { batchnum } = batchs[0];
-        this.$set(this, `batchList`, batchnum);
-      }
-    },
     async getClasses(termid) {
       const res = await this.classesquery({ termid });
       var arr = res.data.filter(item => item.type == '0');
       this.$set(this, `classList`, arr);
     },
     async onsearch({ skip = 0, limit = 10, ...info } = {}) {
-      const res = await this.query({ termid: this.form.termid, classid: this.form.classid, ...info });
-      const newdatas = [];
-      if (this.form.name) {
-        var arr = res.data.filter(item => item.stuname == this.form.name);
-        for (const data of arr) {
-          for (const attend of data.attend) {
-            let newdata = { stuname: data.stuname, ...attend };
-            newdatas.push(newdata);
-          }
+      // 首先整理表头,如果没有选择班级,就是说,要看这期的考勤,需要将这期的日期都列出来坐表头
+      const headColumn = this.getColumn();
+      if (!headColumn) return;
+      this.$set(this, `headList`, headColumn);
+      // 找到相关信息
+      this.getStudent();
+      this.getAttendance();
+      this.getLeave();
+    },
+    // 获取表格内容,
+    getTableContent(...data) {
+      const res = this.getPersonAttend(...data);
+      if (!res) return;
+      const { type } = res;
+      const { word } = this.chageWord(type);
+      return word;
+    },
+    /**
+     * 获取表格内容的通用方法
+     * @param stu 学生信息
+     * @param date 日期
+     * @param type 类型: am=>上午;pm=>下午;bd=>寝室(晚上)
+     * @description 因为 文字 与 颜色 都可以根据这个方法取对应的值,所以把这个方法单抽出来
+     * @property toReturn.type 返回结果: ok:正常签到;late:迟到;nosign:没签到;leave:请假;exit:退出
+     */
+    getPersonAttend(stu, date, type) {
+      let toReturn = {};
+      // 先找有没有请假/退出,退出直接返回GG
+      const { id: studentid } = stu;
+      const les = this.leaveList.filter(f => f.studentid === studentid && f.status === '1');
+      // 查看是否有退出且审核的记录
+      const isExit = les.find(f => f.type == '1');
+      if (isExit) {
+        toReturn = { type: 'exit' };
+        return toReturn;
+      }
+      // 查看请假在不在这个时间里
+      // 先获得考勤要求时间
+      const { start, end } = this.getThisDayAttendTime(date, type);
+      if (!start || !end) return;
+      // 在请假里找,如果有符合条件的请假信息,说明本单元格内容是请假范围内的
+      const lr = les.find(l => {
+        const { starttime, endtime } = l;
+        if (starttime && endtime) {
+          const r1 = moment(starttime).isSameOrBefore(end);
+          const r2 = moment(endtime).isAfter(start);
+          return r1 && r2;
         }
+      });
+      if (lr) {
+        toReturn = { type: 'leave' };
+        return toReturn;
+      }
+      // 下面就该找考勤了,分为:签没签到=>签到了=>迟没迟到:1,没签到,2正常到位,3迟到
+      const stuAtt = this.attendList.find(f => f.studentid === studentid);
+      if (!stuAtt) {
+        toReturn = { type: 'nosign' };
+        return toReturn;
+      }
+      const { attend } = stuAtt;
+      if (!_.isArray(attend)) {
+        toReturn = { type: 'nosign' };
+        return toReturn;
+      }
+      // 过滤出该天的签到记录
+      let thisday = attend.filter(f => f.date === date);
+      if (thisday.length <= 0) {
+        toReturn = { type: 'nosign' };
+        return toReturn;
+      }
+      // 找到该天,该签到时间
+      // TODO这里做的不是很好,数据关系不强,没法定下哪个记录就是上午,哪个记录就是下午,只能靠时间决定
+      // 应该以下个检查开始时间为节点去过滤,am使用pm的开始时间为节点,pm使用bd的开始时间为节点,bd使用自己的开始时间往后查
+      thisday = thisday.map(i => ({ ...i, toCompare: `${i.date} ${i.time}` }));
+      thisday = _.orderBy(thisday, ['toCompare'], ['asc']);
+      let attTime;
+      const { pm_start, bd_start } = this.defaultOption;
+      if (type === 'am') attTime = `${date} ${pm_start}`;
+      else attTime = `${date} ${bd_start}`;
+      // 找到在上述3个时间点前的记录,然后看记录是迟到还是正常到位
+      const r = thisday.find(f => {
+        if (type === 'am' || type === 'pm') return moment(f.toCompare).isSameOrBefore(attTime);
+        else return moment(f.toCompare).isSameOrAfter(attTime);
+      });
+      if (!r) {
+        toReturn = { type: 'nosign' };
+        return toReturn;
+      }
+      const { status } = r;
+      if (status == '1') {
+        toReturn = { type: 'ok' };
       } else {
-        for (const data of res.data) {
-          for (const attend of data.attend) {
-            let newdata = { stuname: data.stuname, ...attend };
-            newdatas.push(newdata);
-          }
+        toReturn = { type: 'late' };
+      }
+      return toReturn;
+    },
+
+    // 获取对应签到时间
+    getThisDayAttendTime(date, type) {
+      let start = _.get(this.defaultOption, `${type}_start`);
+      let end = _.get(this.defaultOption, `${type}_end`);
+      if (!start || !end) {
+        console.warn('未找到系统设置的考勤时间');
+        return {};
+      }
+      start = `${date} ${start}`;
+      end = `${date} ${end}`;
+      return { start, end };
+    },
+    /**
+     * 获取表头,使用form中的termid和classid制作表头
+     */
+    getColumn() {
+      let head = [{ label: '学生', prop: 'name' }];
+      const { termid, classid } = this.form;
+      if (classid) {
+        // 有classid,就一定有classList否则数据也不能出现
+        const cla = this.classList.find(f => f.id === classid);
+        if (!cla) {
+          this.tip('数据错误: 未找到指定班级!', 'error');
+          return;
+        }
+        const { startdate, enddate } = cla;
+        if (!(startdate && enddate)) {
+          this.tip('数据错误: 未找到开始,结束日期', 'error');
+          return;
         }
+        let dayList = this.getDayList(startdate, enddate);
+        return [...head, ...dayList];
+      } else {
+        this.tip('请选择班级', 'warning');
+        return;
+      }
+    },
+    /**
+     * 获取天列表
+     * @param start 开始日期
+     * @param end 结束日期
+     */
+    getDayList(start, end) {
+      const day = moment(end).diff(moment(start), 'days');
+      let arr = [];
+      for (let d = 0; d <= day; d++) {
+        const ad = moment(start)
+          .add(d, 'days')
+          .format('YYYY-MM-DD');
+        let obj = { label: ad, prop: `day${d}` };
+        arr.push(obj);
+      }
+      return arr;
+    },
+    // 获取学生
+    async getStudent() {
+      const { classid } = this.form;
+      if (!classid) {
+        this.tip('请选择班级', 'warning');
+        return;
+      }
+      const res = await this.stuquery({ classid });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+      }
+    },
+    // 获取考勤
+    async getAttendance() {
+      const { classid } = this.form;
+      if (!classid) {
+        this.tip('请选择班级', 'warning');
+        return;
       }
+      const res = await this.query({ classid });
       if (this.$checkRes(res)) {
-        this.$set(this, `total`, newdatas.length);
-        let _newdatas = newdatas.splice(skip, skip + limit);
-        this.$set(this, `list`, _newdatas);
+        this.$set(this, 'attendList', res.data);
+      }
+    },
+    // 获取请假
+    async getLeave() {
+      const { classid } = this.form;
+      if (!classid) {
+        this.tip('请选择班级', 'warning');
+        return;
+      }
+      const res = await this.studentLeave({ classid });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'leaveList', res.data);
+      }
+    },
+    /**
+     * 提示通用,本页面测试使用
+     * @param message 提示信息
+     * @param type 提示类型 success/error/warning/info
+     * @param duration 持续时间,默认3000;0为不消失
+     */
+    tip(message, type, duration = 3000) {
+      this.$message({ type, message, duration });
+    },
+    chageWord(type) {
+      let word;
+      switch (type) {
+        case 'ok':
+          word = '签到';
+          break;
+        case 'late':
+          word = '迟到';
+          break;
+        case 'nosign':
+          word = '';
+          break;
+        case 'leave':
+          word = '请假';
+          break;
+        case 'exit':
+          word = '退出';
+          break;
+
+        default:
+          word = '';
+          break;
       }
+      return { word };
     },
   },
   watch: {
     defaultOption: {
       handler(val) {
         this.form.termid = this.defaultOption.termid;
-        this.getBatch(this.form.termid);
       },
       deep: true,
     },