input('lat','','trim'), 'lng' => input('lng','','trim'), 'address' => input('address','','trim'), 'device_sn' => input('deviceSn','','trim'), 'signtime' => date('Y-m-d H:i:s'), 'user_id' => input('userId/d',0), 'org_id' => input('orgId/d',0), 'remark' => input('remark','','trim'), ]; //检查是否绑定设备 $device = Db::name('user_info')->where('user_id',$data['user_id'])->value('device_sn'); if(!$device){ HelpHander::error('未绑定设备号'); } if($device != $data['device_sn']){ HelpHander::error('该设备与绑定设备不一致'); } // TODO::检查地点距离 $ret = $this->sign($data['device_sn'],$data['user_id'],$data['signtime'],1,$data['lat'],$data['lng'],$data['address'],$data['remark']); if(!$ret){ HelpHander::error($this->error); } return true; } public function lists($page,$size,$name,$startTime,$endTime,$orgId){ $map[] = ['ar.org_id','=',$orgId]; if($name != ''){ $map[] = ['ui.name','like','%'.$name.'%']; } if($startTime && $endTime){ $map[] = ['ar.create_time','>=',$startTime.' 00:00:00']; $map[] = ['ar.create_time','<=',$endTime.' 23:59:59']; } $lists = Db::name('attendance_record') ->alias('ar') ->join('user_info ui','ui.user_id = ar.user_id') ->where($map) ->field('ar.*,ui.name as user_name') ->page($page,$size) ->order('ar.id desc') ->select(); foreach ($lists as $k=>$v){ $lists[$k]['day'] = ''; $lists[$k]['group_name'] = ''; if($v['user_class_id'] > 0){ $lists[$k]['day'] = Db::name('attendance_user_class')->where('id',$v['user_class_id'])->value('day'); $lists[$k]['group_name'] = Db::name('attendance_group') ->alias('ag') ->join('attendance_user_class auc','auc.group_id = ag.id') ->where('auc.id',$v['user_class_id']) ->value('ag.name'); } } $total = Db::name('attendance_record') ->alias('ar') ->join('user_info ui','ui.user_id = ar.user_id') ->where($map)->count(); $data = [ 'total' => $total, 'list' => $lists?$lists:[] ]; return $data; } function unBundleDevice($uId){ $user = Db::name('user_info')->where('user_id',$uId)->find(); if(!$user){ HelpHander::error('记录不存在'); } $ret = Db::name('user_info')->where('user_id',$uId)->setField('device_sn',''); if(!$ret){ HelpHander::error('操作失败'); } return true; } function bundleDevice($userId,$deviceSn){ if(!$deviceSn){ HelpHander::error('参数错误'); } $user = Db::name('user_info')->where('user_id',$userId)->find(); if(!$user){ HelpHander::error('用户不存在'); } if($user['device_sn']){ HelpHander::error('该用户已绑定设备'); } $uinfo = Db::name('user_info')->where('device_sn',$deviceSn)->find(); if($uinfo){ HelpHander::error('该设备已绑定用户'); } $ret = Db::name('user_info')->where('user_id',$userId)->setField('device_sn',$deviceSn); if(!$ret){ HelpHander::error('操作失败'); } return true; } public function listByStaffId($page,$size,$orgId,$uid,$startTime,$endTime){ $map[] = ['ar.org_id','=',$orgId]; if($uid > 0){ $map[] = ['ar.user_id','=',$uid]; } if($startTime && $endTime){ $map[] = ['ar.create_time','>=',$startTime.' 00:00:00']; $map[] = ['ar.create_time','<=',$endTime.' 23:59:59']; } $lists = Db::name('attendance_record') ->alias('ar') ->join('user_info ui','ui.user_id = ar.user_id') ->where($map) ->field('ar.*,ui.name as user_name') ->page($page,$size) ->order('ar.id desc') ->select(); foreach ($lists as $k=>$v){ $lists[$k]['day'] = ''; $lists[$k]['group_name'] = ''; if($v['user_class_id'] > 0){ $lists[$k]['day'] = Db::name('attendance_user_class')->where('id',$v['user_class_id'])->value('day'); $lists[$k]['group_name'] = Db::name('attendance_group') ->alias('ag') ->join('attendance_user_class auc','auc.group_id = ag.id') ->where('auc.id',$v['user_class_id']) ->value('ag.name'); } } $total = Db::name('attendance_record') ->alias('ar') ->join('user_info ui','ui.user_id = ar.user_id') ->where($map)->count(); $data = [ 'total' => $total, 'list' => $lists?$lists:[] ]; return $data; } // 为跨天的需要加一个定时任务,使考勤组状态变更 public function sign_old($sn,$pin,$signdate,$type=3,$lat='',$lng='',$address=''){ //先检查这个时间点是否已记录在系统内 $res = Db::name('attendance_record')->where('user_id',$pin)->where('create_time',$signdate)->find(); if($res){ // 已存在返回已处理 return true; } //先检查今天是否已生成打卡记录,未生成打卡记录需要查询昨天的考勤是否有跨天情况,取出今天的排班情况 $day = date('Y-m-d'); $yday = date('Y-m-d',strtotime($day) - 1000); $nday = date('Y-m-d',strtotime($day) - 86400); $signtime = strtotime($signdate); $info = model('AttendanceUserClass')->info($pin,$day); if($info){ // 已有记录 $dates = $info['content']; foreach ($dates as $k=>$v){ if($v['sstatus'] == 0){ if($signtime < strtotime($v['etime']) - 2*60){ // 距离下班打卡2分钟外,均可上班打卡 // 打卡,直接结束上班打卡 $rdata = [ 'kq_time' => $v['stime'], 'user_id' => $pin, 'org_id' => $info['org_id'], 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '', 'create_time' => $signdate, 'user_class_id' => $info['id'], 'effective' => 1, 'status' => 0, 'cate' => 1, 'duration' => 0 ]; if($signtime <= strtotime($v['stime'])){ $rdata['result'] = '正常'; }else{ $rdata['result'] = '迟到'; $rdata['status'] = 1; $rdata['duration'] = strtotime($rdata['create_time']) - strtotime($rdata['kq_time']); } $dates[$k]['sstatus'] = 1; Db::startTrans(); try{ $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ \exception('操作失败'); } // 更新 foreach ($dates as $k=>$v){ // if(isset($v['slist'])){ // unset($dates[$k]['slist']); // } // if(isset($v['elist'])){ // unset($dates[$k]['elist']); // } if($v['stime'] == $rdata['kq_time']){ $dates[$k]['ssign'] = $rdata['create_time']; } } Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates)); Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Db::rollback(); return false; } }else{ $dates[$k]['sstatus'] = 1; } } if($v['estatus'] == 0){ if($signtime < strtotime($v['etime'])){ // TODO:: 提前打下班卡 $rdata = [ 'kq_time' => $v['etime'], 'user_id' => $pin, 'org_id' => $info['org_id'], 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '早退', 'create_time' => $signdate, 'user_class_id' => $info['id'], 'effective' => 1, 'status' => 2, 'cate' => 2, 'duration' => 0 ]; // 早退时间 $rdata['duration'] = strtotime($rdata['kq_time']) - strtotime($rdata['create_time']); Db::startTrans(); try{ // 更新其他当前点的记录为无效 Db::name('attendance_record') ->where('user_class_id',$info['id']) ->where('user_id',$pin) ->where('kq_time',$rdata['kq_time']) ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']); $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ \exception('操作失败'); } // 更新 foreach ($dates as $kk=>$vv){ // if(isset($v['slist'])){ // unset($dates[$kk]['slist']); // } // if(isset($v['elist'])){ // unset($dates[$kk]['elist']); // } if($v['etime'] == $rdata['kq_time']){ $dates[$k]['esign'] = $rdata['create_time']; } } Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates)); Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Db::rollback(); return false; } }else{ // 超过下班时间,如果接下啦无班次,可继续打卡到12点,若有班次,则打卡下班 if(!$v['esign'] && isset($dates[$k+1])){ $dates[$k]['estatus'] = 1; if($signtime < strtotime($dates[$k+1]['stime']) - 2*60){ // 距离上班打卡2分钟外,均可下班打卡 // TODO::打卡,直接结束下班打卡 $rdata = [ 'kq_time' => $v['etime'], 'user_id' => $pin, 'org_id' => $info['org_id'], 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '正常', 'create_time' => $signdate, 'user_class_id' => $info['id'], 'effective' => 1, 'status' => 0, 'cate' => 2, 'duration' => 0 ]; Db::startTrans(); try{ // 更新其他当前点的记录为无效 Db::name('attendance_record') ->where('user_class_id',$info['id']) ->where('user_id',$pin) ->where('kq_time',$rdata['kq_time']) ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']); $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ \exception('操作失败'); } // 更新 foreach ($dates as $kk=>$vv){ // if(isset($v['slist'])){ // unset($dates[$kk]['slist']); // } // if(isset($v['elist'])){ // unset($dates[$kk]['elist']); // } if($v['etime'] == $rdata['kq_time']){ $dates[$k]['esign'] = $rdata['create_time']; } } Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates)); Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Db::rollback(); return false; } } }else if(!isset($dates[$k+1])){ // 无班次可一直补卡到12点 //TODO:: 打下班卡 $rdata = [ 'kq_time' => $v['etime'], 'user_id' => $pin, 'org_id' => $info['org_id'], 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '正常', 'create_time' => $signdate, 'user_class_id' => $info['id'], 'effective' => 1, 'status' => 0, 'cate' => 2, 'duration' => 0 ]; Db::startTrans(); try{ // 更新其他当前点的记录为无效 Db::name('attendance_record') ->where('user_class_id',$info['id']) ->where('user_id',$pin) ->where('kq_time',$rdata['kq_time']) ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']); $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ \exception('操作失败'); } // 更新 foreach ($dates as $kk=>$vv){ // if(isset($v['slist'])){ // unset($dates[$kk]['slist']); // } // if(isset($v['elist'])){ // unset($dates[$kk]['elist']); // } if($v['etime'] == $rdata['kq_time']){ $dates[$k]['esign'] = $rdata['create_time']; } } Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates)); Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Db::rollback(); return false; } } else if ($v['esign'] && isset($dates[$k+1])){ $dates[$k]['estatus'] = 1; } } } } }else{ $yinfo = model('AttendanceUserClass')->info($pin,$yday); if($yinfo && $yinfo['next'] == 1 && $yinfo['status'] == 0){ // 昨天排班存在且跨天且进行中 $dates = $yinfo['content']; foreach ($dates as $k=>$v){ if($v['sstatus'] == 0){ if($signtime < strtotime($v['etime']) - 2*60){ // 距离下班打卡2分钟外,均可上班打卡 // TODO::打卡,直接结束上班打卡 $dates[$k]['sstatus'] = 1; // 打卡,直接结束上班打卡 $rdata = [ 'kq_time' => $v['stime'], 'user_id' => $pin, 'org_id' => $yinfo['org_id'], 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '', 'create_time' => $signdate, 'user_class_id' => $yinfo['id'], 'effective' => 1, 'status' => 0, 'cate' => 1, 'duration' => 0 ]; if($signtime <= strtotime($v['stime'])){ $rdata['result'] = '正常'; }else{ $rdata['result'] = '迟到'; $rdata['status'] = 1; $rdata['duration'] = strtotime($rdata['create_time']) - strtotime($rdata['kq_time']); } Db::startTrans(); try{ $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ \exception('操作失败'); } // 更新 foreach ($dates as $kk=>$vv){ // if(isset($v['slist'])){ // unset($dates[$kk]['slist']); // } // if(isset($v['elist'])){ // unset($dates[$kk]['elist']); // } if($v['stime'] == $rdata['kq_time']){ $dates[$k]['ssign'] = $rdata['create_time']; } } Db::name('attendance_user_class')->where('id',$yinfo['id'])->setField('content',json_encode($dates)); Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Db::rollback(); return false; } }else{ $dates[$k]['sstatus'] = 1; } }else if($v['estatus'] == 0){ if($signtime < strtotime($v['etime'])){ // TODO::提前打下班卡 $rdata = [ 'kq_time' => $v['etime'], 'user_id' => $pin, 'org_id' => $yinfo['org_id'], 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '早退', 'create_time' => $signdate, 'user_class_id' => $yinfo['id'], 'effective' => 1, 'status' => 2, 'cate' => 2, 'duration' => 0 ]; $rdata['duration'] = strtotime($rdata['kq_time']) - strtotime($rdata['create_time']); Db::startTrans(); try{ // 更新其他当前点的记录为无效 Db::name('attendance_record') ->where('user_class_id',$info['id']) ->where('user_id',$pin) ->where('kq_time',$rdata['kq_time']) ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']); $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ \exception('操作失败'); } // 更新 foreach ($dates as $kk=>$vv){ // if(isset($v['slist'])){ // unset($dates[$kk]['slist']); // } // if(isset($v['elist'])){ // unset($dates[$kk]['elist']); // } if($v['etime'] == $rdata['kq_time']){ $dates[$k]['esign'] = $rdata['create_time']; } } Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates)); Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Db::rollback(); return false; } }else{ if(!$v['esign'] && isset($dates[$k+1])){ // 有下个班次,则 if($signtime < strtotime($dates[$k+1]['stime']) - 2*60){ // 距离下班打卡2分钟外,均可下班打卡 // TODO::打卡,直接结束下班打卡 $dates[$k]['estatus'] = 1; $rdata = [ 'kq_time' => $v['etime'], 'user_id' => $pin, 'org_id' => $yinfo['org_id'], 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '正常', 'create_time' => $signdate, 'user_class_id' => $yinfo['id'], 'effective' => 1, 'status' => 0, 'cate' => 2, 'duration' => 0 ]; Db::startTrans(); try{ // 更新其他当前点的记录为无效 Db::name('attendance_record') ->where('user_class_id',$info['id']) ->where('user_id',$pin) ->where('kq_time',$rdata['kq_time']) ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']); $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ \exception('操作失败'); } // 更新 foreach ($dates as $kk=>$vv){ // if(isset($v['slist'])){ // unset($dates[$kk]['slist']); // } // if(isset($v['elist'])){ // unset($dates[$kk]['elist']); // } if($v['etime'] == $rdata['kq_time']){ $dates[$k]['esign'] = $rdata['create_time']; } } Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates)); Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Db::rollback(); return false; } } }else if(!$v['esign'] && !isset($dates[$k+1])){ $class = model('AttendanceGroupClass')->getClassByDay($pin); if($class){ // $content = json_decode($class['content'],true); $dates = $content['dates']; if($signtime < strtotime(date('Y-m-d').' '.$dates[0]['stime']) - 2*60){ // 距离下班打卡2分钟外,均可下班打卡 //TODO:: 打卡,直接结束下班打卡 $dates[$k]['estatus'] = 1; $rdata = [ 'kq_time' => $v['etime'], 'user_id' => $pin, 'org_id' => $yinfo['org_id'], 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '正常', 'create_time' => $signdate, 'user_class_id' => $yinfo['id'], 'effective' => 1, 'status' => 0, 'cate' => 2, 'duration' => 0 ]; Db::startTrans(); try{ // 更新其他当前点的记录为无效 Db::name('attendance_record') ->where('user_class_id',$info['id']) ->where('user_id',$pin) ->where('kq_time',$rdata['kq_time']) ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']); $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ \exception('操作失败'); } // 更新 foreach ($dates as $kk=>$vv){ // if(isset($v['slist'])){ // unset($dates[$kk]['slist']); // } // if(isset($v['elist'])){ // unset($dates[$kk]['elist']); // } if($v['etime'] == $rdata['kq_time']){ $dates[$k]['esign'] = $rdata['create_time']; } } Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates)); Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Db::rollback(); return false; } } }else{ //TODO:: 无班次打下班卡到24点 $rdata = [ 'kq_time' => $v['etime'], 'user_id' => $pin, 'org_id' => $yinfo['org_id'], 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '正常', 'create_time' => $signdate, 'user_class_id' => $yinfo['id'], 'effective' => 1, 'status' => 0, 'cate' => 2, 'duration' => 0 ]; Db::startTrans(); try{ // 更新其他当前点的记录为无效 Db::name('attendance_record') ->where('user_class_id',$info['id']) ->where('user_id',$pin) ->where('kq_time',$rdata['kq_time']) ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']); $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ \exception('操作失败'); } // 更新 foreach ($dates as $k=>$v){ // if(isset($v['slist'])){ // unset($dates[$k]['slist']); // } // if(isset($v['elist'])){ // unset($dates[$k]['elist']); // } if($v['etime'] == $rdata['kq_time']){ $dates[$k]['esign'] = $rdata['create_time']; } } Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates)); Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Db::rollback(); return false; } } } } } } }else{ // 昨天没跨天排班记录,获取今天班次并打卡 $class = model('AttendanceGroupClass')->getClassByDay($pin); if(empty($class)){ // TODO::外勤打卡 $org_id = Db::name('user') ->alias('u') ->join('user_roles ur','ur.user_id = u.id') ->join('roles r','r.id = ur.roles_id') ->where('u.id',$pin) ->where('r.type',3) ->value('r.org_id'); $rdata = [ 'user_id' => $pin, 'org_id' => $org_id?$org_id:0, 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '外勤', 'create_time' => $signdate, 'user_class_id' => 0, 'effective' => 1, 'status' => 0, 'cate' => 0, 'duration' => 0 ]; $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ $this->error = "操作失败"; return false; } return true; }else{ // 第一次打卡,外勤打卡不算其内 $content = json_decode($class['content'],true); $dates = $content['dates']; $newdates = []; //[{"stime":"2021-03-22 08:00:00","etime":"2021-03-22 18:00:00","sstatus":0,"estatus":0}] $next = 0; foreach ($dates as $k=>$v){ $newdates[] = [ "stime" => $v['snext'] > 0?$nday .' '.$v['stime'].':00':$day.' '.$v['stime'].':00', "etime" => $v['enext'] > 0?$nday .' '.$v['etime'].':00':$day.' '.$v['etime'].':00', "sstatus" => 0, "estatus" => 0, ]; if($v['snext'] == 1||$v['enext'] == 1){ $next = 1; } } $count = count($newdates); if($count == 1){ // 一个班次 if($signtime <= strtotime($newdates[0]['etime']) - 2*60){ $newdates[0]['sstatus'] = 1; // TODO::上班打卡 $kqtime = $newdates[0]['stime']; if($signtime <= strtotime($newdates[0]['stime'])){ $result = '正常'; }else{ $result = '迟到'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address); }else{ $newdates[0]['sstatus'] = 1; // TODO::下班打卡 $kqtime = $newdates[0]['etime']; if($signtime < strtotime($newdates[0]['etime'])){ $result = '早退'; }else{ $result = '正常'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address); } }else if($count == 2){ if($signtime <= strtotime($newdates[0]['etime']) - 2*60){ $newdates[0]['sstatus'] = 1; // TODO::上班打卡 $kqtime = $newdates[0]['stime']; if($signtime <= strtotime($newdates[0]['stime'])){ $result = '正常'; }else{ $result = '迟到'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address); }else if($signtime > (strtotime($newdates[0]['etime']) - 2*60) &&$signtime <= (strtotime($newdates[1]['stime']) - 2*60)){ // TODO::下班打卡 $newdates[0]['sstatus'] = 1; $kqtime = $newdates[0]['etime']; if($signtime < strtotime($newdates[0]['etime'])){ $result = '早退'; }else{ $result = '正常'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address); }else if($signtime > (strtotime($newdates[1]['stime']) - 2*60) &&$signtime <= (strtotime($newdates[1]['etime']) - 2*60)){ // TODO::二次上班打卡 $newdates[0]['sstatus'] = 1; $newdates[0]['estatus'] = 1; $newdates[1]['sstatus'] = 1; $kqtime = $newdates[1]['stime']; if($signtime <= strtotime($newdates[1]['stime'])){ $result = '正常'; }else{ $result = '迟到'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address); }else{ // TODO::二次下班打卡 $newdates[0]['sstatus'] = 1; $newdates[0]['estatus'] = 1; $newdates[1]['sstatus'] = 1; $kqtime = $newdates[0]['etime']; if($signtime < strtotime($newdates[1]['etime'])){ $result = '早退'; }else{ $result = '正常'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address); } }else{ if($signtime <= strtotime($newdates[0]['etime']) - 2*60){ $newdates[0]['sstatus'] = 1; // TODO::上班打卡 $kqtime = $newdates[0]['stime']; if($signtime <= strtotime($newdates[0]['stime'])){ $result = '正常'; }else{ $result = '迟到'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address); }else if($signtime > (strtotime($newdates[0]['etime']) - 2*60) &&$signtime <= (strtotime($newdates[1]['stime']) - 2*60)){ // TODO::下班打卡 $newdates[0]['sstatus'] = 1; $kqtime = $newdates[0]['etime']; if($signtime < strtotime($newdates[0]['etime'])){ $result = '早退'; }else{ $result = '正常'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address); }else if($signtime > (strtotime($newdates[1]['stime']) - 2*60) &&$signtime <= (strtotime($newdates[1]['etime']) - 2*60)){ // TODO::二次上班打卡 $newdates[0]['sstatus'] = 1; $newdates[0]['estatus'] = 1; $newdates[1]['sstatus'] = 1; $kqtime = $newdates[1]['stime']; if($signtime <= strtotime($newdates[1]['stime'])){ $result = '正常'; }else{ $result = '迟到'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address); }else if($signtime > (strtotime($newdates[1]['etime']) - 2*60) && $signtime <= (strtotime($newdates[2]['stime']) - 2*60)){ // TODO::二次下班打卡 $newdates[0]['sstatus'] = 1; $newdates[0]['estatus'] = 1; $newdates[1]['sstatus'] = 1; $kqtime = $newdates[1]['etime']; if($signtime < strtotime($newdates[1]['etime'])){ $result = '早退'; }else{ $result = '正常'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address); }else if($signtime > (strtotime($newdates[2]['stime']) - 2*60) && $signtime <= (strtotime($newdates[2]['etime']) - 2*60)){ // TODO::三次上班打卡 $newdates[0]['sstatus'] = 1; $newdates[0]['estatus'] = 1; $newdates[1]['sstatus'] = 1; $newdates[1]['estatus'] = 1; $newdates[2]['sstatus'] = 1; $kqtime = $newdates[2]['stime']; if($signtime <= strtotime($newdates[2]['stime'])){ $result = '正常'; }else{ $result = '迟到'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address); }else{ // TODO::三次下班打卡 $newdates[0]['sstatus'] = 1; $newdates[0]['estatus'] = 1; $newdates[1]['sstatus'] = 1; $newdates[1]['estatus'] = 1; $newdates[2]['sstatus'] = 1; $kqtime = $newdates[2]['etime']; if($signtime < strtotime($newdates[1]['etime'])){ $result = '早退'; }else{ $result = '正常'; } return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address); } } } } } } public function firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,$cate,$type,$lat,$lng,$address){ Db::startTrans(); try{ $rdata = [ 'kq_time' => $kqtime, 'user_id' => $pin, 'org_id' => $class['org_id'], 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => $result, 'create_time' => $signdate, 'effective' => 1, 'status' => 0, 'cate' => $cate, 'duration' => 0 ]; if($cate == 1){ // 上班 if($rdata['result'] == '迟到'){ $rdata['status'] = 1; $rdata['duration'] = strtotime($rdata['create_time']) - strtotime($rdata['kq_time']); } }else if($cate == 2){ // 下班 if($rdata['result'] == '早退'){ $rdata['status'] = 2; $rdata['duration'] = strtotime($rdata['kq_time']) - strtotime($rdata['create_time']); } } foreach ($newdates as $k=>$v){ if($cate == 1 && $v['stime'] == $rdata['kq_time']){ $newdates[$k]['ssign'] = $rdata['create_time']; $newdates[$k]['esign'] = ''; }else if($cate == 2 && $v['etime'] == $rdata['kq_time']){ $newdates[$k]['ssign'] = ''; $newdates[$k]['esign'] = $rdata['create_time']; } } $userData = [ 'user_id' => $pin, 'group_id' => $class['group_id'], 'class_id' => $class['class_id'], 'org_id' => $class['org_id'], 'content' => json_encode($newdates), 'create_time' => date('Y-m-d H:i:s'), 'day' => $day, 'next' => $next ]; $userClassId = Db::name('attendance_user_class')->insertGetId($userData); if(!$userClassId){ \exception('保存失败'); } $rdata['user_class_id'] = $userClassId; $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ $this->error = "操作失败"; return false; } Db::commit(); return true; }catch (Exception $e){ $this->error = "保存失败"; Db::rollback(); return false; } } // 补卡操作 public function reissue($userId,$orgId,$kq_time,$signtime){ $day = date('Y-m-d',strtotime($kq_time)); $info = Db::name('attendance_user_class') ->where('user_id',$userId) ->where('org_id',$orgId) ->where('day',$day) ->find(); if(!$info){ return true; // 数据不存在,默认操作成功 } $dates = json_decode($info['content'],true); $cate = 0; // 1=上班 2=下班 foreach ($dates as $k=>$v){ if($v['stime'] == $kq_time){ $cate = 1; }else if($v['etime'] == $kq_time){ $cate = 2; } } $status = 0; $duration = 0; $result = '补卡:正常'; if($cate == 0){ // 有变化,不再修改考勤记录 return true; }else if($cate == 1 && strtotime($signtime) > strtotime($kq_time)){ //1=上班 $duration = strtotime($signtime) - strtotime($kq_time); $status = 1; $result = '补卡:迟到'; }else if($cate == 2 && strtotime($signtime) < strtotime($kq_time)) { //2=下班 $duration = strtotime($kq_time) - strtotime($signtime); $status = 2; $result = '补卡:早退'; } $rdata = [ 'kq_time' => $kq_time, 'user_id' => $userId, 'org_id' => $info['org_id'], 'type' => 2, 'from' => '流程补卡', 'result' => $result, 'create_time' => $signtime, 'user_class_id' => $info['id'], 'effective' => 1, 'status' => $status, 'cate' => $cate, 'duration' => $duration ]; try{ // 更新其他当前点的记录为无效 Db::name('attendance_record') ->where('user_class_id',$info['id']) ->where('user_id',$userId) ->where('kq_time',$rdata['kq_time']) ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']); $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ \exception('操作失败'); } foreach ($dates as $k=>$v){ if($cate == 1 && $v['stime'] == $rdata['kq_time']){ $dates[$k]['ssign'] = $signtime; }else if($cate == 2 && $v['etime'] == $rdata['kq_time']){ $dates[$k]['esign'] = $signtime; } } $userClassId = Db::name('attendance_user_class')->where('id',$info['id'])->update(['content' => json_encode($dates)]); if(!$userClassId){ \exception('保存失败'); } return true; }catch (Exception $e){ return false; } } // 为跨天的需要加一个定时任务,使考勤组状态变更 public function sign($sn,$pin,$signdate,$type=3,$lat='',$lng='',$address='',$remark=''){ // 检查用户状态 $user = Db::name('user')->where('id',$pin)->where('del',0)->find(); if(!$user||$user['enable'] != 1){ return true; } //先检查这个时间点是否已记录在系统内 $res = Db::name('attendance_record')->where('user_id',$pin)->where('create_time',$signdate)->find(); if($res){ // 已存在返回已处理 return true; } $curTime = date('Y-m-d H:i:s'); $signtime = strtotime($signdate); // 检查当前打开时间是否有效 checkValid $ret = Db::name('attendance_record') ->alias('ar') ->join('attendance_user_class auc','auc.id = ar.user_class_id') ->where('ar.user_id',$pin) ->where('auc.status',1) ->where('ar.create_time','>',$signdate) ->field('ar.*') ->find(); if($ret){ // 时间无效,则标记为已处理 return true; } Db::startTrans(); try{ //先检查今天是否已生成打卡记录,未生成打卡记录需要查询昨天的考勤是否有跨天情况,取出今天的排班情况 $info = model('AttendanceUserClass')->getCurGroup($pin); if($info) { // 获取当前的班次,没有班次,当做外勤打卡 // 检查支持的考勤类型 $cate = Db::name('attendance_group')->where('id',$info['group_id'])->value('cate'); if($type == 1){ // 手机打开 if(!$cate){ trace('不支持手机打卡'); Db::commit(); return true; }else{ $cates = explode(',',$cate); if(!in_array(1,$cates)){ trace('不支持手机打卡'); Db::commit(); return true; } } }else if($type == 3){ //考勤机打卡 if(!$cate){ trace('不支持考勤机打卡'); Db::commit(); return true; }else{ $cates = explode(',',$cate); if(!in_array(2,$cates)){ trace('不支持考勤机打卡'); Db::commit(); return true; } } } if($info['day'] == date('Y-m-d') && $info['day'] != date('Y-m-d',$signtime)){ // 昨天的时间,今天的班次,不能使用 Db::commit(); return true; } $dates = json_decode($info['content'], true); $records = Db::name('attendance_record')->where('user_class_id', $info['id'])->order('create_time asc')->select(); $records = $records ? $records : []; $nrecords = []; $flag = false; $ndata = [ 'kq_time' => '', 'user_id' => $pin, 'org_id' => $info['org_id'], 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '', 'create_time' => date('Y-m-d H:i:s',$signtime), 'add_time' => $curTime, 'user_class_id' => $info['id'], 'effective' => 0, 'status' => 0, 'cate' => 0, 'duration' => 0, 'remark'=>$remark, ]; foreach ($records as $k => $v) { if (!$flag && strtotime($v['create_time']) > $signtime) { $nrecords[] = $ndata; $flag = true; } $nrecords[] = $v; } if(!$flag){ // 为最大值时 $nrecords[] = $ndata; } if (!$nrecords) { $nrecords[] = $ndata; } // 班次 $datearr = $dates; $lastret = $nrecords; foreach ($datearr as $key => $val){ // 给没一个考勤记录划分到合适的时间段 $sret = get_attentance_srecord($lastret,$val); $datearr[$key]['srecord'] = $sret['arr']; $nstime = ''; if(isset($datearr[$key + 1])){ $nstime = $datearr[$key + 1]['stime']; } $lastret = $sret['record']; $eret = get_attentance_erecord($lastret,$val,$nstime); $datearr[$key]['erecord'] = $eret['arr']; $lastret = $eret['record']; } $nums = 0; $nrecords2 = []; foreach ($datearr as $key => $val){ $nums += count($val['srecord']); if($nums == count($nrecords)){ // 没有后续的打卡记录-未结束 $dates[$key]['sstatus'] = 0; $dates[$key]['ssign'] = ''; }else{ // 有后续打卡--缺卡 $dates[$key]['sstatus'] = 1; $dates[$key]['ssign'] = ''; } if($val['srecord']){ // 有上班打卡记录 $dates[$key]['sstatus'] = 1; $dates[$key]['ssign'] = $val['srecord'][0]['create_time']; foreach ($val['srecord'] as $k=>$v){ $v['effective'] = 1; $v['kq_time'] = $val['stime']; if($v['status'] == 0){ $v['duration'] = 0; $v['result'] = '正常'; }else if($v['status'] == 1){ $v['duration'] = strtotime($v['create_time']) - strtotime($val['stime']); $v['result'] = '迟到'; } $nrecords2[] = $v; } } $nums += count($val['erecord']); if($nums == count($nrecords)){ // 没有后续的打卡记录-未结束 $dates[$key]['estatus'] = 0; $dates[$key]['esign'] = ''; }else{ // 有后续打卡--缺卡 $dates[$key]['estatus'] = 1; $dates[$key]['esign'] = ''; } if($val['erecord']) { // 有下班打卡记录 $dates[$key]['esign'] = $val['erecord'][count($val['erecord']) - 1]['create_time']; foreach ($val['erecord'] as $k=>$v){ $v['kq_time'] = $val['etime']; if($k == count($val['erecord']) - 1){ // 最后一个 $v['effective'] = 1; if($v['status'] == 0){ $v['duration'] = 0; $v['result'] = '正常'; }else if($v['status'] == 2){ $v['duration'] = strtotime($val['etime']) - strtotime($v['create_time']); $v['result'] = '早退'; } }else{ $v['effective'] = 0; $v['duration'] = 0; $v['result'] = '打卡无效:此记录已被更新'; } $nrecords2[] = $v; } } } /*$datecount = count($dates); if ($datecount == 1) { // 一天一个班次 foreach ($nrecords as $k => $v) { if ($k == 0) { // 上班 $nrecords[$k]['kq_time'] = $dates[0]['stime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 1; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[0]['sstatus'] = 1; $dates[0]['ssign'] = $v['create_time']; if (strtotime($v['create_time']) > strtotime($dates[0]['stime'])) { // 迟到 $nrecords[$k]['status'] = 1; $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[0]['stime']); $nrecords[$k]['result'] = '迟到'; } } else { // 下班 $nrecords[$k]['kq_time'] = $dates[0]['etime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 2; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[0]['estatus'] = 1; $dates[0]['esign'] = $v['create_time']; //判断是否是最后一条 if ($k + 1 == count($nrecords)) { // 是 if (strtotime($v['create_time']) < strtotime($dates[0]['etime'])) { // 早退 $nrecords[$k]['result'] = '早退'; $nrecords[$k]['status'] = 2; $nrecords[$k]['duration'] = strtotime($dates[0]['etime']) - strtotime($v['create_time']); } } else { // 否,无效记录 $nrecords[$k]['effective'] = 0; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '打卡无效:此记录已被更新'; } } } }else if($datecount == 2){ // 一天二个班次 foreach ($nrecords as $k => $v) { if ($k == 0) { // 1次上班 $nrecords[$k]['kq_time'] = $dates[0]['stime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 1; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[0]['sstatus'] = 1; $dates[0]['ssign'] = $v['create_time']; if (strtotime($v['create_time']) > strtotime($dates[0]['stime'])) { // 迟到 $nrecords[$k]['status'] = 1; $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[0]['stime']); $nrecords[$k]['result'] = '迟到'; } } else if ($k == 1){ // 1次下班 $nrecords[$k]['kq_time'] = $dates[0]['etime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 2; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[0]['estatus'] = 1; $dates[0]['esign'] = $v['create_time']; if (strtotime($v['create_time']) < strtotime($dates[0]['etime'])) { // 早退 $nrecords[$k]['result'] = '早退'; $nrecords[$k]['status'] = 2; $nrecords[$k]['duration'] = strtotime($dates[0]['etime']) - strtotime($v['create_time']); } } else if ($k == 2){ // 2次上班 $nrecords[$k]['kq_time'] = $dates[1]['stime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 1; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[1]['sstatus'] = 1; $dates[1]['ssign'] = $v['create_time']; if (strtotime($v['create_time']) > strtotime($dates[1]['stime'])) { // 迟到 $nrecords[$k]['status'] = 1; $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[1]['stime']); $nrecords[$k]['result'] = '迟到'; } } else { // 2次下班 $nrecords[$k]['kq_time'] = $dates[1]['etime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 2; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[1]['estatus'] = 1; $dates[1]['esign'] = $v['create_time']; //判断是否是最后一条 if ($k + 1 == count($nrecords)) { // 是 if (strtotime($v['create_time']) < strtotime($dates[1]['etime'])) { // 早退 $nrecords[$k]['result'] = '早退'; $nrecords[$k]['status'] = 2; $nrecords[$k]['duration'] = strtotime($dates[1]['etime']) - strtotime($v['create_time']); } } else { // 否,无效记录 $nrecords[$k]['effective'] = 0; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '打卡无效:此记录已被更新'; } } } }else if($datecount == 3){ // 一天三个班次 foreach ($nrecords as $k => $v) { if ($k == 0) { // 1次上班 $nrecords[$k]['kq_time'] = $dates[0]['stime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 1; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[0]['sstatus'] = 1; $dates[0]['ssign'] = $v['create_time']; if (strtotime($v['create_time']) > strtotime($dates[0]['stime'])) { // 迟到 $nrecords[$k]['status'] = 1; $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[0]['stime']); $nrecords[$k]['result'] = '迟到'; } } else if ($k == 1){ // 1次下班 $nrecords[$k]['kq_time'] = $dates[0]['etime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 2; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[0]['estatus'] = 1; $dates[0]['esign'] = $v['create_time']; if (strtotime($v['create_time']) < strtotime($dates[0]['etime'])) { // 早退 $nrecords[$k]['result'] = '早退'; $nrecords[$k]['status'] = 2; $nrecords[$k]['duration'] = strtotime($dates[0]['etime']) - strtotime($v['create_time']); } } else if ($k == 2){ // 2次上班 $nrecords[$k]['kq_time'] = $dates[1]['stime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 1; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[1]['sstatus'] = 1; $dates[1]['ssign'] = $v['create_time']; if (strtotime($v['create_time']) > strtotime($dates[1]['stime'])) { // 迟到 $nrecords[$k]['status'] = 1; $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[1]['stime']); $nrecords[$k]['result'] = '迟到'; } } else if ($k == 3){ // 2次下班 $nrecords[$k]['kq_time'] = $dates[1]['etime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 2; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[1]['estatus'] = 1; $dates[1]['esign'] = $v['create_time']; if (strtotime($v['create_time']) < strtotime($dates[1]['etime'])) { // 早退 $nrecords[$k]['result'] = '早退'; $nrecords[$k]['status'] = 2; $nrecords[$k]['duration'] = strtotime($dates[1]['etime']) - strtotime($v['create_time']); } } else if ($k == 4){ // 3次上班 $nrecords[$k]['kq_time'] = $dates[2]['stime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 1; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[2]['sstatus'] = 1; $dates[2]['ssign'] = $v['create_time']; if (strtotime($v['create_time']) > strtotime($dates[2]['stime'])) { // 迟到 $nrecords[$k]['status'] = 1; $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[2]['stime']); $nrecords[$k]['result'] = '迟到'; } } else { // 3次下班 $nrecords[$k]['kq_time'] = $dates[2]['etime']; $nrecords[$k]['effective'] = 1; $nrecords[$k]['cate'] = 2; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '正常'; $dates[2]['estatus'] = 1; $dates[2]['esign'] = $v['create_time']; //判断是否是最后一条 if ($k + 1 == count($nrecords)) { // 是 if (strtotime($v['create_time']) < strtotime($dates[2]['etime'])) { // 早退 $nrecords[$k]['result'] = '早退'; $nrecords[$k]['status'] = 2; $nrecords[$k]['duration'] = strtotime($dates[2]['etime']) - strtotime($v['create_time']); } } else { // 否,无效记录 $nrecords[$k]['effective'] = 0; $nrecords[$k]['status'] = 0; $nrecords[$k]['duration'] = 0; $nrecords[$k]['result'] = '打卡无效:此记录已被更新'; } } } }*/ // dump($datearr); // dump($dates); // halt($nrecords2); foreach ($nrecords2 as $k=>$v){ $v['update_time'] = date('Y-m-d H:i:s'); if(isset($v['id']) && $v['id'] > 0){ //修改记录 $ret = Db::name('attendance_record')->where('id',$v['id'])->update($v); }else{ // 新增记录 $ret = Db::name('attendance_record')->insert($v); } if(!$ret){ \exception('打卡失败'); } } $res = Db::name('attendance_user_class')->where('id',$info['id'])->update([ 'content' => json_encode($dates), 'update_time' => date('Y-m-d H:i:s') ]); if(!$res){ \exception('打卡失败'); } } else { // 外勤打卡 $org_id = Db::name('user') ->alias('u') ->join('user_roles ur','ur.user_id = u.id') ->join('roles r','r.id = ur.roles_id') ->where('u.id',$pin) ->where('r.type',3) ->value('r.org_id'); $rdata = [ 'user_id' => $pin, 'org_id' => $org_id?$org_id:0, 'type' => $type, 'lat' => $lat, 'lng' => $lng, 'address' => $address, 'from' => $sn, 'result' => '外勤', 'create_time' => date('Y-m-d H:i:s',$signtime), 'add_time' => date('Y-m-d H:i:s'), 'user_class_id' => 0, 'effective' => 1, 'status' => 0, 'cate' => 0, 'duration' => 0 ]; $ret = Db::name('attendance_record')->insert($rdata); if(!$ret){ \exception('打卡失败'); } } Db::commit(); }catch (Exception $e){ trace($e->getMessage()); $this->error = $e->getMessage(); Db::rollback(); return false; } return true; } }