美文网首页
vue 单页面

vue 单页面

作者: wxw_威 | 来源:发表于2022-11-04 16:36 被阅读0次
    因为自己要写一个单页面去完成一个考勤报表计算的需求,所以通过一个html去完成此需求,再次记录遇到的问题(忽略乱七八糟的命名)。

    1、下载对应的插件到本地,import引用。
    2、前端通过xlsx 导入表格,获取对应的json,计算考勤数据。
    3、导出功能以后在完善。

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <meta name="renderer" content="webkit" />
        <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
        <title>考勤计算</title>
        <!-- https://unpkg.com/element-ui/lib/theme-chalk/index.css -->
        <link rel="stylesheet" href="css/index.css">
        <!-- https://cdn.jsdelivr.net/npm/vue@2.7.10 -->
        <script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
        <!-- https://unpkg.com/element-ui/lib/index.js -->
        <script src="js/elementUI.js" type="text/javascript" charset="utf-8"></script>
        <!-- https://unpkg.com/dayjs@1.8.21/dayjs.min.js -->
        <script src="js/dayjs.js" type="text/javascript" charset="utf-8"></script>
        <!-- https://cdn.jsdelivr.net/npm/xlsx@0.16.9/dist/xlsx.full.min.js -->
        <script src="js/xlsx.js" type="text/javascript" charset="utf-8"></script>
        <style>
          #app {
            font-family: Avenir, Helvetica, Arial, sans-serif;
            -webkit-font-smoothing: antialiased;
            -moz-osx-font-smoothing: grayscale;
            text-align: center;
            color: #2c3e50;
            display: flex;
          }
          body {
            margin: 0;
          }
          .log {
            display: flex;
            justify-content: center;
            border: 1px solid #F2F2F2;
          }
          p {
            width: 100px;
            margin: 0;
            padding: 8px 4px;
            border-right: 1px solid #F2F2F2;
          }
        </style>
      </head>
      <body>
        <div id="app" style="display: flex;">
          <div style="display: flex;flex-direction: column;">
            <h3>考勤表</h3>
            <el-upload
              class="upload-demo"
              drag
              action
              :auto-upload="false"
              :on-change="uploadImport"
              :limit="1">
              <i class="el-icon-upload"></I>
              <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
              <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
            </el-upload>
      
            <h3>打卡表</h3>
            <el-upload
              class="upload-demo"
              drag
              action
              :auto-upload="false"
              :on-change="uploadImport2"
              :limit="1">
              <i class="el-icon-upload"></I>
              <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
              <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
            </el-upload>
      
            <el-button style="margin-top: 32px;" @click="handleCalculate">计算</el-button>
          </div>
          <div style="flex: 1;padding-left: 32px;">
            <h1>log日志</h1>
            <div class="log">
              <p>考勤</p>
              <p style="width: 160px;">职位</p>
              <p>工号</p>
              <p>姓名</p>
              <p style="width: 150px;">时间</p>
              <p style="flex: 1;">备注</p>
            </div>
            <div style="height:calc(100vh - 150px);overflow-y: auto;">
              <div class="log" v-for="(item, index) in resultList">
                <p>{{item.kq}}</p>
                <p style="width: 160px;">职位:{{item.job}}</p>
                <p>{{item.number}}</p>
                <p>{{item.name}}</p>
                <p style="width: 150px;">{{item.time}}</p>
                <p style="flex: 1;">{{item.remark}}</p>
              </div>
            </div>
          </div>
        </div>
        <script type="text/javascript">
          var app = new Vue({
            el: '#app',
            data: {
              kqList: [],
              dkList: [],
    
              resultList: [],
              defaultTimeString: '',
            },
            methods: {
              handleCalculate() {
                const year = dayjs(this.defaultTimeString).year()
                const month = dayjs(this.defaultTimeString).month() + 1
                const yearMonth = year + '-' + month
                const days = dayjs(yearMonth).daysInMonth()
                this.kqList.forEach((kqItem, kqIndex) => {
                  for(let i = 1; i <= days; i++) {
                    let day = (i + '').padStart(2, 0)
                    let kqTime = yearMonth + '-' + day
                    if (['调岗','休', '轮休', '年假', '婚假', '丧假', '育儿假', '病假', '工伤', '产假', '陪产假', '事假', '新员工', '离职', '旷工'].indexOf(kqItem[kqTime]) > -1) {
                      this.printLog(kqItem[kqTime], kqItem['岗位'], kqItem['工号'], kqItem['姓名'], kqTime)
                    } else if (kqItem[kqTime] === '早' || kqItem[kqTime] === '双早') {
                      // 默认8h
                      this.calculateTimeLengthWithZao(kqItem, kqTime, 8)
                    } else if (kqItem[kqTime].indexOf('早') > -1) {
                      // 包含早
                      let arr = kqItem[kqTime].split('早')
                      this.calculateTimeLengthWithZao(kqItem, kqTime, arr[1])
                    } else if (kqItem[kqTime] === '夜' || kqItem[kqTime] === '双夜') {
                      // 默认8h
                      this.calculateTimeLengthWithYe(kqItem, kqTime, 8)
                    } else if (kqItem[kqTime].indexOf('夜') > -1) {
                      // 包含夜
                      let arr = kqItem[kqTime].split('夜')
                      this.calculateTimeLengthWithYe(kqItem, kqTime, arr[1])
                    }
                  }
                })
              },
              // 计算时长  --   夜班
              calculateTimeLengthWithYe(kqItem, kqTime, timeLength) {
                let kqString = kqItem[kqTime]           // 考勤
                let job = kqItem['岗位']
                let userNumber = kqItem['工号']         // 工号
                let userName = kqItem['姓名']           // 姓名
                let remark = ''                         // 备注
    
                // 上班对象
                let startItem = null
                // 下班对象
                let endItem = null
                // 获取上班打卡记录
                let startSiftArr = []
                startSiftArr = this.dkList.filter((dkItem) => {
                  return kqTime == dkItem['打卡日期2'] && kqItem['姓名'] == dkItem['姓名'] && dkItem['员工编码'] == kqItem['工号']
                })
    
                // 判断是否漏打上班卡
                if (startSiftArr && startSiftArr.length > 0) {
                  startSiftArr = this.sortData(startSiftArr)
                  let sbTimeArr = startSiftArr.filter((item) => {
                    return this.compareDate(item['打卡日期2'] + ' ' + item['打卡时间'], item['打卡日期2'] + ' 12:00:00')
                  })
                  // startItem = sbTimeArr
                  if (sbTimeArr && sbTimeArr.length > 0) {
                    startItem = sbTimeArr[0]
                  } else {
                    return this.printLog(kqString, job, userNumber, userName, kqTime, '漏打上班卡')
                    // remark = '漏打上班卡'
                  }
                } else {
                  return this.printLog(kqString, job, userNumber, userName, kqTime, '漏打上班卡')
                  // remark = '漏打上班卡'
                }
    
                // 获取下班打卡记录
                let endDKDate = dayjs(kqTime).add(1, 'day')
                let endTime = dayjs(endDKDate).format("YYYY-MM-DD")
                let endSiftArr = []
                endSiftArr = this.dkList.filter((dkItem) => {
                  return endTime == dkItem['打卡日期2'] && kqItem['姓名'] == dkItem['姓名'] && dkItem['员工编码'] == kqItem['工号']
                })
    
                // 判断是否漏打下班卡
                if (endSiftArr && endSiftArr.length > 0) {
                  endSiftArr = this.sortData(endSiftArr)
                  let xbTimeArr = endSiftArr.filter((item) => {
                    return this.compareDate(item['打卡日期2'] + ' 12:00:00', item['打卡日期2'] + ' ' + item['打卡时间'])
                  })
    
                  if (xbTimeArr && xbTimeArr.length > 0) {
                    endItem = xbTimeArr[xbTimeArr.length - 1]
                  } else {
                    return this.printLog(kqString, job, userNumber, userName, kqTime, '漏打下班卡')
                    // remark = remark ? remark + '漏打下班卡' :  '漏打下班卡'
                  }
                } else {
                  return this.printLog(kqString, job, userNumber, userName, kqTime, '漏打下班卡')
                  // remark = remark ? remark + '漏打下班卡' :  '漏打下班卡'
                }
                
                let sjStartTime = startItem['打卡日期2'] + ' ' + startItem['打卡时间']
                let sjEndTime = endItem['打卡日期2'] + ' ' + endItem['打卡时间']
    
                let gdStartTime = startItem['打卡日期2']
                let gdEndTime = endItem['打卡日期2']
    
                if (startItem['打卡位置'].indexOf('XX') > -1) {
                  gdStartTime = gdStartTime + ' ' + '20:00:00'
                } else {
                  gdStartTime = gdStartTime + ' ' + '20:00:00'
                }
    
                if (endItem['打卡位置'].indexOf('XX') > -1) {
                  gdEndTime = gdEndTime + ' ' + '8:00:00'
                } else {
                  gdEndTime = gdEndTime + ' ' + '8:00:00'
                }
    
                if (this.compareDate(sjStartTime, gdStartTime)) {
                  // 打卡时间 > 规定时间
                  remark = '上班迟到'
                }
    
                if (this.compareDate(gdEndTime, sjEndTime)) {
                  // 下班打卡时间 > 下班规定时间
                  remark = remark ? `${remark},下班早退` : '下班早退'
                }
    
                // 计算工时
                let t1 = new Date(sjStartTime).getTime()
                let t2 = new Date(sjEndTime).getTime()
                let resultV = (t2 - t1 - 1000 * 60 * 60 * 0.5) / (1000 * 60 * 60)
                if (resultV >= parseFloat(timeLength)) {
                  remark = remark ? `${remark},满足${timeLength}h` : `满足${timeLength}h`
                } else {
                  // 计算缺少的分钟数
                  let qsfz = (t2 - t1 - 1000 * 60 * 60 * 0.5 - (1000 * 60 * 60 * timeLength)) / (1000 * 60)
                  remark = remark ? `${remark},不满足${timeLength}h(缺少:${(Math.abs(qsfz)).toFixed(2)}分钟)` : `不满足${timeLength}h(缺少:${(Math.abs(qsfz)).toFixed(2)}分钟)`
                }
    
                this.printLog(kqString, job, userNumber, userName, kqTime, remark)
              },
              // 计算时长  --   早班
              calculateTimeLengthWithZao(kqItem, kqTime, timeLength) {
                let kqString = kqItem[kqTime]           // 考勤
                let job = kqItem['岗位']
                let userNumber = kqItem['工号']         // 工号
                let userName = kqItem['姓名']           // 姓名
                let remark = ''             // 备注
    
                let siftArr = []
                siftArr = this.dkList.filter((dkItem) => {
                  return kqTime == dkItem['打卡日期2'] && kqItem['姓名'] == dkItem['姓名'] && dkItem['员工编码'] == kqItem['工号']
                })
                if (siftArr && siftArr.length > 1) {
                  // 排序
                  siftArr = this.sortData(siftArr)
                  
                  // 上班对象
                  let startItem = siftArr[0]
                  // 下班对象
                  let endItem = siftArr[siftArr.length - 1]
    
                  let sjStartTime = startItem['打卡日期2'] + ' ' + startItem['打卡时间']
                  let sjEndTime = endItem['打卡日期2'] + ' ' + endItem['打卡时间']
    
                  let gdStartTime = startItem['打卡日期2']
                  let gdEndTime = endItem['打卡日期2']
                  if (startItem['打卡位置'].indexOf('XX') > -1) {
                    gdStartTime = gdStartTime + ' ' + '08:30:00'
                  } else {
                    gdStartTime = gdStartTime + ' ' + '08:00:00'
                  }
    
                  if (endItem['打卡位置'].indexOf('XX') > -1) {
                    gdEndTime = gdEndTime + ' ' + '17:00:00'
                  } else {
                    gdEndTime = gdEndTime + ' ' + '16:30:00'
                  }
    
                  if (this.compareDate(sjStartTime, gdStartTime)) {
                    // 打卡时间 > 规定时间
                    remark = '上班迟到'
                  }
    
                  if (this.compareDate(gdEndTime, sjEndTime)) {
                    // 下班打卡时间 > 下班规定时间
                    remark = remark ? `${remark},下班早退` : '下班早退'
                  }
    
                  // 计算工时
                  let t1 = new Date(sjStartTime).getTime()
                  let t2 = new Date(sjEndTime).getTime()
                  let resultV = (t2 - t1 - 1000 * 60 * 60 * 0.5) / (1000 * 60 * 60)
                  if (resultV >= parseFloat(timeLength)) {
                    remark = remark ? `${remark},满足${timeLength}h` : `满足${timeLength}h`
                  } else {
                    // 计算缺少的分钟数
                    let qsfz = (t2 - t1 - 1000 * 60 * 60 * 0.5 - (1000 * 60 * 60 * timeLength)) / (1000 * 60)
                    remark = remark ? `${remark},不满足${timeLength}h(缺少:${(Math.abs(qsfz)).toFixed(2)}分钟)` : `不满足${timeLength}h(缺少:${(Math.abs(qsfz)).toFixed(2)}分钟)`
                  }
    
                  this.printLog(kqString, job, userNumber, userName, kqTime, remark)
                } else {
                  // 早班 - 只有一个时间的
                  this.printLog(kqString, job, userNumber, userName, kqTime, '漏打卡')
                }
              },
              // 按照时间排序
              sortData(arr) {
                arr.sort((a, b) => {
                  let obj1 = a['打卡日期2'] + ' ' + a['打卡时间']
                  let obj2 = b['打卡日期2'] + ' ' + b['打卡时间']
                  let v1 = Math.floor(new Date(obj1).getTime() / 1000)
                  let v2 = Math.floor(new Date(obj2).getTime() / 1000)
                  return v1 - v2
                })
                return arr
              },
              // 比较时间大小
              compareDate(date1, date2) {
                let _date1 = new Date(date1)
                let _date2 = new Date(date2)
                if (_date1.getTime() > _date2.getTime()) {
                  return true
                } else {
                  return false
                }
              },
              // 打印日志
              printLog(kq, job, number, name, time, remark='无') {
                console.log('考勤',kq,'职位',job, '工号', number, '姓名', name, '时间', time, '备注', remark)
                this.resultList.push({
                  kq,
                  job,
                  number,
                  name,
                  time,
                  remark
                })
              },
              async uploadImport(file) {
                // 读取文件
                let dataBinary = await this.readFile(file.raw);
                let workBook = XLSX.read(dataBinary, { type: "binary", cellDates: true });
                let workSheet = workBook.Sheets[workBook.SheetNames[0]];
                let data = XLSX.utils.sheet_to_json(workSheet);
                console.log(data)
                this.kqList = data
              },
              async uploadImport2(file) {
                // 读取文件
                let dataBinary = await this.readFile(file.raw);
                let workBook = XLSX.read(dataBinary, { type: "binary", cellDates: true });
                let workSheet = workBook.Sheets[workBook.SheetNames[0]];
                let data = XLSX.utils.sheet_to_json(workSheet);
                data.forEach((item, index) => {
                  item['打卡日期2'] = dayjs(dayjs(item['打卡日期']).add(1, 'day').$d).format("YYYY-MM-DD")
                  if (index == 1) {
                    this.defaultTimeString = item['打卡日期2']
                  }
                })
                console.log(data)
                this.dkList = data
              },
              readFile(file) {
                return new Promise(resolve => {
                  let reader = new FileReader();
                  reader.readAsBinaryString(file);
                  reader.onload = ev => { 
                    resolve(ev.target.result); 
                  }
                })
              }
            }
          })
        </script>
      </body>
    </html>
    

    遇到的问题:
    1、将elementUI 和对应的css 文件下载本地后,页面出现错误

    截屏2022-11-04 下午4.37.45.png
    处理:elementUI提供icons.woff,element-icons.ttf 下载路径,通过添加下载,把这两个文件放到对应的css 文件夹下就可以了。

    相关文章

      网友评论

          本文标题:vue 单页面

          本文链接:https://www.haomeiwen.com/subject/lhcutdtx.html