AttendanceRecord.php 76 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567
  1. <?php
  2. namespace app\common\model;
  3. use app\hander\HelpHander;
  4. use think\Db;
  5. use think\Exception;
  6. use think\Model;
  7. class AttendanceRecord extends Model
  8. {
  9. public function sjsign(){
  10. $data = [
  11. 'lat' => input('lat','','trim'),
  12. 'lng' => input('lng','','trim'),
  13. 'address' => input('address','','trim'),
  14. 'device_sn' => input('deviceSn','','trim'),
  15. 'signtime' => date('Y-m-d H:i:s'),
  16. 'user_id' => input('userId/d',0),
  17. 'org_id' => input('orgId/d',0),
  18. 'remark' => input('remark','','trim'),
  19. ];
  20. //检查是否绑定设备
  21. $device = Db::name('user_info')->where('user_id',$data['user_id'])->value('device_sn');
  22. if(!$device){
  23. HelpHander::error('未绑定设备号');
  24. }
  25. if($device != $data['device_sn']){
  26. HelpHander::error('该设备与绑定设备不一致');
  27. }
  28. // TODO::检查地点距离
  29. $ret = $this->sign($data['device_sn'],$data['user_id'],$data['signtime'],1,$data['lat'],$data['lng'],$data['address'],$data['remark']);
  30. if(!$ret){
  31. HelpHander::error($this->error);
  32. }
  33. return true;
  34. }
  35. public function lists($page,$size,$name,$startTime,$endTime,$orgId){
  36. $map[] = ['ar.org_id','=',$orgId];
  37. if($name != ''){
  38. $map[] = ['ui.name','like','%'.$name.'%'];
  39. }
  40. if($startTime && $endTime){
  41. $map[] = ['ar.create_time','>=',$startTime.' 00:00:00'];
  42. $map[] = ['ar.create_time','<=',$endTime.' 23:59:59'];
  43. }
  44. $lists = Db::name('attendance_record')
  45. ->alias('ar')
  46. ->join('user_info ui','ui.user_id = ar.user_id')
  47. ->where($map)
  48. ->field('ar.*,ui.name as user_name')
  49. ->page($page,$size)
  50. ->order('ar.id desc')
  51. ->select();
  52. foreach ($lists as $k=>$v){
  53. $lists[$k]['day'] = '';
  54. $lists[$k]['group_name'] = '';
  55. if($v['user_class_id'] > 0){
  56. $lists[$k]['day'] = Db::name('attendance_user_class')->where('id',$v['user_class_id'])->value('day');
  57. $lists[$k]['group_name'] = Db::name('attendance_group')
  58. ->alias('ag')
  59. ->join('attendance_user_class auc','auc.group_id = ag.id')
  60. ->where('auc.id',$v['user_class_id'])
  61. ->value('ag.name');
  62. }
  63. }
  64. $total = Db::name('attendance_record')
  65. ->alias('ar')
  66. ->join('user_info ui','ui.user_id = ar.user_id')
  67. ->where($map)->count();
  68. $data = [
  69. 'total' => $total,
  70. 'list' => $lists?$lists:[]
  71. ];
  72. return $data;
  73. }
  74. function unBundleDevice($uId){
  75. $user = Db::name('user_info')->where('user_id',$uId)->find();
  76. if(!$user){
  77. HelpHander::error('记录不存在');
  78. }
  79. $ret = Db::name('user_info')->where('user_id',$uId)->setField('device_sn','');
  80. if(!$ret){
  81. HelpHander::error('操作失败');
  82. }
  83. return true;
  84. }
  85. function bundleDevice($userId,$deviceSn){
  86. if(!$deviceSn){
  87. HelpHander::error('参数错误');
  88. }
  89. $user = Db::name('user_info')->where('user_id',$userId)->find();
  90. if(!$user){
  91. HelpHander::error('用户不存在');
  92. }
  93. if($user['device_sn']){
  94. HelpHander::error('该用户已绑定设备');
  95. }
  96. $uinfo = Db::name('user_info')->where('device_sn',$deviceSn)->find();
  97. if($uinfo){
  98. HelpHander::error('该设备已绑定用户');
  99. }
  100. $ret = Db::name('user_info')->where('user_id',$userId)->setField('device_sn',$deviceSn);
  101. if(!$ret){
  102. HelpHander::error('操作失败');
  103. }
  104. return true;
  105. }
  106. public function listByStaffId($page,$size,$orgId,$uid,$startTime,$endTime){
  107. $map[] = ['ar.org_id','=',$orgId];
  108. if($uid > 0){
  109. $map[] = ['ar.user_id','=',$uid];
  110. }
  111. if($startTime && $endTime){
  112. $map[] = ['ar.create_time','>=',$startTime.' 00:00:00'];
  113. $map[] = ['ar.create_time','<=',$endTime.' 23:59:59'];
  114. }
  115. $lists = Db::name('attendance_record')
  116. ->alias('ar')
  117. ->join('user_info ui','ui.user_id = ar.user_id')
  118. ->where($map)
  119. ->field('ar.*,ui.name as user_name')
  120. ->page($page,$size)
  121. ->order('ar.id desc')
  122. ->select();
  123. foreach ($lists as $k=>$v){
  124. $lists[$k]['day'] = '';
  125. $lists[$k]['group_name'] = '';
  126. if($v['user_class_id'] > 0){
  127. $lists[$k]['day'] = Db::name('attendance_user_class')->where('id',$v['user_class_id'])->value('day');
  128. $lists[$k]['group_name'] = Db::name('attendance_group')
  129. ->alias('ag')
  130. ->join('attendance_user_class auc','auc.group_id = ag.id')
  131. ->where('auc.id',$v['user_class_id'])
  132. ->value('ag.name');
  133. }
  134. }
  135. $total = Db::name('attendance_record')
  136. ->alias('ar')
  137. ->join('user_info ui','ui.user_id = ar.user_id')
  138. ->where($map)->count();
  139. $data = [
  140. 'total' => $total,
  141. 'list' => $lists?$lists:[]
  142. ];
  143. return $data;
  144. }
  145. // 为跨天的需要加一个定时任务,使考勤组状态变更
  146. public function sign_old($sn,$pin,$signdate,$type=3,$lat='',$lng='',$address=''){
  147. //先检查这个时间点是否已记录在系统内
  148. $res = Db::name('attendance_record')->where('user_id',$pin)->where('create_time',$signdate)->find();
  149. if($res){ // 已存在返回已处理
  150. return true;
  151. }
  152. //先检查今天是否已生成打卡记录,未生成打卡记录需要查询昨天的考勤是否有跨天情况,取出今天的排班情况
  153. $day = date('Y-m-d');
  154. $yday = date('Y-m-d',strtotime($day) - 1000);
  155. $nday = date('Y-m-d',strtotime($day) - 86400);
  156. $signtime = strtotime($signdate);
  157. $info = model('AttendanceUserClass')->info($pin,$day);
  158. if($info){ // 已有记录
  159. $dates = $info['content'];
  160. foreach ($dates as $k=>$v){
  161. if($v['sstatus'] == 0){
  162. if($signtime < strtotime($v['etime']) - 2*60){ // 距离下班打卡2分钟外,均可上班打卡
  163. // 打卡,直接结束上班打卡
  164. $rdata = [
  165. 'kq_time' => $v['stime'],
  166. 'user_id' => $pin,
  167. 'org_id' => $info['org_id'],
  168. 'type' => $type,
  169. 'lat' => $lat,
  170. 'lng' => $lng,
  171. 'address' => $address,
  172. 'from' => $sn,
  173. 'result' => '',
  174. 'create_time' => $signdate,
  175. 'user_class_id' => $info['id'],
  176. 'effective' => 1,
  177. 'status' => 0,
  178. 'cate' => 1,
  179. 'duration' => 0
  180. ];
  181. if($signtime <= strtotime($v['stime'])){
  182. $rdata['result'] = '正常';
  183. }else{
  184. $rdata['result'] = '迟到';
  185. $rdata['status'] = 1;
  186. $rdata['duration'] = strtotime($rdata['create_time']) - strtotime($rdata['kq_time']);
  187. }
  188. $dates[$k]['sstatus'] = 1;
  189. Db::startTrans();
  190. try{
  191. $ret = Db::name('attendance_record')->insert($rdata);
  192. if(!$ret){
  193. \exception('操作失败');
  194. }
  195. // 更新
  196. foreach ($dates as $k=>$v){
  197. // if(isset($v['slist'])){
  198. // unset($dates[$k]['slist']);
  199. // }
  200. // if(isset($v['elist'])){
  201. // unset($dates[$k]['elist']);
  202. // }
  203. if($v['stime'] == $rdata['kq_time']){
  204. $dates[$k]['ssign'] = $rdata['create_time'];
  205. }
  206. }
  207. Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates));
  208. Db::commit();
  209. return true;
  210. }catch (Exception $e){
  211. $this->error = $e->getMessage();
  212. Db::rollback();
  213. return false;
  214. }
  215. }else{
  216. $dates[$k]['sstatus'] = 1;
  217. }
  218. }
  219. if($v['estatus'] == 0){
  220. if($signtime < strtotime($v['etime'])){
  221. // TODO:: 提前打下班卡
  222. $rdata = [
  223. 'kq_time' => $v['etime'],
  224. 'user_id' => $pin,
  225. 'org_id' => $info['org_id'],
  226. 'type' => $type,
  227. 'lat' => $lat,
  228. 'lng' => $lng,
  229. 'address' => $address,
  230. 'from' => $sn,
  231. 'result' => '早退',
  232. 'create_time' => $signdate,
  233. 'user_class_id' => $info['id'],
  234. 'effective' => 1,
  235. 'status' => 2,
  236. 'cate' => 2,
  237. 'duration' => 0
  238. ];
  239. // 早退时间
  240. $rdata['duration'] = strtotime($rdata['kq_time']) - strtotime($rdata['create_time']);
  241. Db::startTrans();
  242. try{
  243. // 更新其他当前点的记录为无效
  244. Db::name('attendance_record')
  245. ->where('user_class_id',$info['id'])
  246. ->where('user_id',$pin)
  247. ->where('kq_time',$rdata['kq_time'])
  248. ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']);
  249. $ret = Db::name('attendance_record')->insert($rdata);
  250. if(!$ret){
  251. \exception('操作失败');
  252. }
  253. // 更新
  254. foreach ($dates as $kk=>$vv){
  255. // if(isset($v['slist'])){
  256. // unset($dates[$kk]['slist']);
  257. // }
  258. // if(isset($v['elist'])){
  259. // unset($dates[$kk]['elist']);
  260. // }
  261. if($v['etime'] == $rdata['kq_time']){
  262. $dates[$k]['esign'] = $rdata['create_time'];
  263. }
  264. }
  265. Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates));
  266. Db::commit();
  267. return true;
  268. }catch (Exception $e){
  269. $this->error = $e->getMessage();
  270. Db::rollback();
  271. return false;
  272. }
  273. }else{ // 超过下班时间,如果接下啦无班次,可继续打卡到12点,若有班次,则打卡下班
  274. if(!$v['esign'] && isset($dates[$k+1])){
  275. $dates[$k]['estatus'] = 1;
  276. if($signtime < strtotime($dates[$k+1]['stime']) - 2*60){ // 距离上班打卡2分钟外,均可下班打卡
  277. // TODO::打卡,直接结束下班打卡
  278. $rdata = [
  279. 'kq_time' => $v['etime'],
  280. 'user_id' => $pin,
  281. 'org_id' => $info['org_id'],
  282. 'type' => $type,
  283. 'lat' => $lat,
  284. 'lng' => $lng,
  285. 'address' => $address,
  286. 'from' => $sn,
  287. 'result' => '正常',
  288. 'create_time' => $signdate,
  289. 'user_class_id' => $info['id'],
  290. 'effective' => 1,
  291. 'status' => 0,
  292. 'cate' => 2,
  293. 'duration' => 0
  294. ];
  295. Db::startTrans();
  296. try{
  297. // 更新其他当前点的记录为无效
  298. Db::name('attendance_record')
  299. ->where('user_class_id',$info['id'])
  300. ->where('user_id',$pin)
  301. ->where('kq_time',$rdata['kq_time'])
  302. ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']);
  303. $ret = Db::name('attendance_record')->insert($rdata);
  304. if(!$ret){
  305. \exception('操作失败');
  306. }
  307. // 更新
  308. foreach ($dates as $kk=>$vv){
  309. // if(isset($v['slist'])){
  310. // unset($dates[$kk]['slist']);
  311. // }
  312. // if(isset($v['elist'])){
  313. // unset($dates[$kk]['elist']);
  314. // }
  315. if($v['etime'] == $rdata['kq_time']){
  316. $dates[$k]['esign'] = $rdata['create_time'];
  317. }
  318. }
  319. Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates));
  320. Db::commit();
  321. return true;
  322. }catch (Exception $e){
  323. $this->error = $e->getMessage();
  324. Db::rollback();
  325. return false;
  326. }
  327. }
  328. }else if(!isset($dates[$k+1])){ // 无班次可一直补卡到12点
  329. //TODO:: 打下班卡
  330. $rdata = [
  331. 'kq_time' => $v['etime'],
  332. 'user_id' => $pin,
  333. 'org_id' => $info['org_id'],
  334. 'type' => $type,
  335. 'lat' => $lat,
  336. 'lng' => $lng,
  337. 'address' => $address,
  338. 'from' => $sn,
  339. 'result' => '正常',
  340. 'create_time' => $signdate,
  341. 'user_class_id' => $info['id'],
  342. 'effective' => 1,
  343. 'status' => 0,
  344. 'cate' => 2,
  345. 'duration' => 0
  346. ];
  347. Db::startTrans();
  348. try{
  349. // 更新其他当前点的记录为无效
  350. Db::name('attendance_record')
  351. ->where('user_class_id',$info['id'])
  352. ->where('user_id',$pin)
  353. ->where('kq_time',$rdata['kq_time'])
  354. ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']);
  355. $ret = Db::name('attendance_record')->insert($rdata);
  356. if(!$ret){
  357. \exception('操作失败');
  358. }
  359. // 更新
  360. foreach ($dates as $kk=>$vv){
  361. // if(isset($v['slist'])){
  362. // unset($dates[$kk]['slist']);
  363. // }
  364. // if(isset($v['elist'])){
  365. // unset($dates[$kk]['elist']);
  366. // }
  367. if($v['etime'] == $rdata['kq_time']){
  368. $dates[$k]['esign'] = $rdata['create_time'];
  369. }
  370. }
  371. Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates));
  372. Db::commit();
  373. return true;
  374. }catch (Exception $e){
  375. $this->error = $e->getMessage();
  376. Db::rollback();
  377. return false;
  378. }
  379. } else if ($v['esign'] && isset($dates[$k+1])){
  380. $dates[$k]['estatus'] = 1;
  381. }
  382. }
  383. }
  384. }
  385. }else{
  386. $yinfo = model('AttendanceUserClass')->info($pin,$yday);
  387. if($yinfo && $yinfo['next'] == 1 && $yinfo['status'] == 0){ // 昨天排班存在且跨天且进行中
  388. $dates = $yinfo['content'];
  389. foreach ($dates as $k=>$v){
  390. if($v['sstatus'] == 0){
  391. if($signtime < strtotime($v['etime']) - 2*60){ // 距离下班打卡2分钟外,均可上班打卡
  392. // TODO::打卡,直接结束上班打卡
  393. $dates[$k]['sstatus'] = 1;
  394. // 打卡,直接结束上班打卡
  395. $rdata = [
  396. 'kq_time' => $v['stime'],
  397. 'user_id' => $pin,
  398. 'org_id' => $yinfo['org_id'],
  399. 'type' => $type,
  400. 'lat' => $lat,
  401. 'lng' => $lng,
  402. 'address' => $address,
  403. 'from' => $sn,
  404. 'result' => '',
  405. 'create_time' => $signdate,
  406. 'user_class_id' => $yinfo['id'],
  407. 'effective' => 1,
  408. 'status' => 0,
  409. 'cate' => 1,
  410. 'duration' => 0
  411. ];
  412. if($signtime <= strtotime($v['stime'])){
  413. $rdata['result'] = '正常';
  414. }else{
  415. $rdata['result'] = '迟到';
  416. $rdata['status'] = 1;
  417. $rdata['duration'] = strtotime($rdata['create_time']) - strtotime($rdata['kq_time']);
  418. }
  419. Db::startTrans();
  420. try{
  421. $ret = Db::name('attendance_record')->insert($rdata);
  422. if(!$ret){
  423. \exception('操作失败');
  424. }
  425. // 更新
  426. foreach ($dates as $kk=>$vv){
  427. // if(isset($v['slist'])){
  428. // unset($dates[$kk]['slist']);
  429. // }
  430. // if(isset($v['elist'])){
  431. // unset($dates[$kk]['elist']);
  432. // }
  433. if($v['stime'] == $rdata['kq_time']){
  434. $dates[$k]['ssign'] = $rdata['create_time'];
  435. }
  436. }
  437. Db::name('attendance_user_class')->where('id',$yinfo['id'])->setField('content',json_encode($dates));
  438. Db::commit();
  439. return true;
  440. }catch (Exception $e){
  441. $this->error = $e->getMessage();
  442. Db::rollback();
  443. return false;
  444. }
  445. }else{
  446. $dates[$k]['sstatus'] = 1;
  447. }
  448. }else if($v['estatus'] == 0){
  449. if($signtime < strtotime($v['etime'])){
  450. // TODO::提前打下班卡
  451. $rdata = [
  452. 'kq_time' => $v['etime'],
  453. 'user_id' => $pin,
  454. 'org_id' => $yinfo['org_id'],
  455. 'type' => $type,
  456. 'lat' => $lat,
  457. 'lng' => $lng,
  458. 'address' => $address,
  459. 'from' => $sn,
  460. 'result' => '早退',
  461. 'create_time' => $signdate,
  462. 'user_class_id' => $yinfo['id'],
  463. 'effective' => 1,
  464. 'status' => 2,
  465. 'cate' => 2,
  466. 'duration' => 0
  467. ];
  468. $rdata['duration'] = strtotime($rdata['kq_time']) - strtotime($rdata['create_time']);
  469. Db::startTrans();
  470. try{
  471. // 更新其他当前点的记录为无效
  472. Db::name('attendance_record')
  473. ->where('user_class_id',$info['id'])
  474. ->where('user_id',$pin)
  475. ->where('kq_time',$rdata['kq_time'])
  476. ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']);
  477. $ret = Db::name('attendance_record')->insert($rdata);
  478. if(!$ret){
  479. \exception('操作失败');
  480. }
  481. // 更新
  482. foreach ($dates as $kk=>$vv){
  483. // if(isset($v['slist'])){
  484. // unset($dates[$kk]['slist']);
  485. // }
  486. // if(isset($v['elist'])){
  487. // unset($dates[$kk]['elist']);
  488. // }
  489. if($v['etime'] == $rdata['kq_time']){
  490. $dates[$k]['esign'] = $rdata['create_time'];
  491. }
  492. }
  493. Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates));
  494. Db::commit();
  495. return true;
  496. }catch (Exception $e){
  497. $this->error = $e->getMessage();
  498. Db::rollback();
  499. return false;
  500. }
  501. }else{
  502. if(!$v['esign'] && isset($dates[$k+1])){ // 有下个班次,则
  503. if($signtime < strtotime($dates[$k+1]['stime']) - 2*60){ // 距离下班打卡2分钟外,均可下班打卡
  504. // TODO::打卡,直接结束下班打卡
  505. $dates[$k]['estatus'] = 1;
  506. $rdata = [
  507. 'kq_time' => $v['etime'],
  508. 'user_id' => $pin,
  509. 'org_id' => $yinfo['org_id'],
  510. 'type' => $type,
  511. 'lat' => $lat,
  512. 'lng' => $lng,
  513. 'address' => $address,
  514. 'from' => $sn,
  515. 'result' => '正常',
  516. 'create_time' => $signdate,
  517. 'user_class_id' => $yinfo['id'],
  518. 'effective' => 1,
  519. 'status' => 0,
  520. 'cate' => 2,
  521. 'duration' => 0
  522. ];
  523. Db::startTrans();
  524. try{
  525. // 更新其他当前点的记录为无效
  526. Db::name('attendance_record')
  527. ->where('user_class_id',$info['id'])
  528. ->where('user_id',$pin)
  529. ->where('kq_time',$rdata['kq_time'])
  530. ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']);
  531. $ret = Db::name('attendance_record')->insert($rdata);
  532. if(!$ret){
  533. \exception('操作失败');
  534. }
  535. // 更新
  536. foreach ($dates as $kk=>$vv){
  537. // if(isset($v['slist'])){
  538. // unset($dates[$kk]['slist']);
  539. // }
  540. // if(isset($v['elist'])){
  541. // unset($dates[$kk]['elist']);
  542. // }
  543. if($v['etime'] == $rdata['kq_time']){
  544. $dates[$k]['esign'] = $rdata['create_time'];
  545. }
  546. }
  547. Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates));
  548. Db::commit();
  549. return true;
  550. }catch (Exception $e){
  551. $this->error = $e->getMessage();
  552. Db::rollback();
  553. return false;
  554. }
  555. }
  556. }else if(!$v['esign'] && !isset($dates[$k+1])){
  557. $class = model('AttendanceGroupClass')->getClassByDay($pin);
  558. if($class){ //
  559. $content = json_decode($class['content'],true);
  560. $dates = $content['dates'];
  561. if($signtime < strtotime(date('Y-m-d').' '.$dates[0]['stime']) - 2*60){ // 距离下班打卡2分钟外,均可下班打卡
  562. //TODO:: 打卡,直接结束下班打卡
  563. $dates[$k]['estatus'] = 1;
  564. $rdata = [
  565. 'kq_time' => $v['etime'],
  566. 'user_id' => $pin,
  567. 'org_id' => $yinfo['org_id'],
  568. 'type' => $type,
  569. 'lat' => $lat,
  570. 'lng' => $lng,
  571. 'address' => $address,
  572. 'from' => $sn,
  573. 'result' => '正常',
  574. 'create_time' => $signdate,
  575. 'user_class_id' => $yinfo['id'],
  576. 'effective' => 1,
  577. 'status' => 0,
  578. 'cate' => 2,
  579. 'duration' => 0
  580. ];
  581. Db::startTrans();
  582. try{
  583. // 更新其他当前点的记录为无效
  584. Db::name('attendance_record')
  585. ->where('user_class_id',$info['id'])
  586. ->where('user_id',$pin)
  587. ->where('kq_time',$rdata['kq_time'])
  588. ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']);
  589. $ret = Db::name('attendance_record')->insert($rdata);
  590. if(!$ret){
  591. \exception('操作失败');
  592. }
  593. // 更新
  594. foreach ($dates as $kk=>$vv){
  595. // if(isset($v['slist'])){
  596. // unset($dates[$kk]['slist']);
  597. // }
  598. // if(isset($v['elist'])){
  599. // unset($dates[$kk]['elist']);
  600. // }
  601. if($v['etime'] == $rdata['kq_time']){
  602. $dates[$k]['esign'] = $rdata['create_time'];
  603. }
  604. }
  605. Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates));
  606. Db::commit();
  607. return true;
  608. }catch (Exception $e){
  609. $this->error = $e->getMessage();
  610. Db::rollback();
  611. return false;
  612. }
  613. }
  614. }else{
  615. //TODO:: 无班次打下班卡到24点
  616. $rdata = [
  617. 'kq_time' => $v['etime'],
  618. 'user_id' => $pin,
  619. 'org_id' => $yinfo['org_id'],
  620. 'type' => $type,
  621. 'lat' => $lat,
  622. 'lng' => $lng,
  623. 'address' => $address,
  624. 'from' => $sn,
  625. 'result' => '正常',
  626. 'create_time' => $signdate,
  627. 'user_class_id' => $yinfo['id'],
  628. 'effective' => 1,
  629. 'status' => 0,
  630. 'cate' => 2,
  631. 'duration' => 0
  632. ];
  633. Db::startTrans();
  634. try{
  635. // 更新其他当前点的记录为无效
  636. Db::name('attendance_record')
  637. ->where('user_class_id',$info['id'])
  638. ->where('user_id',$pin)
  639. ->where('kq_time',$rdata['kq_time'])
  640. ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']);
  641. $ret = Db::name('attendance_record')->insert($rdata);
  642. if(!$ret){
  643. \exception('操作失败');
  644. }
  645. // 更新
  646. foreach ($dates as $k=>$v){
  647. // if(isset($v['slist'])){
  648. // unset($dates[$k]['slist']);
  649. // }
  650. // if(isset($v['elist'])){
  651. // unset($dates[$k]['elist']);
  652. // }
  653. if($v['etime'] == $rdata['kq_time']){
  654. $dates[$k]['esign'] = $rdata['create_time'];
  655. }
  656. }
  657. Db::name('attendance_user_class')->where('id',$info['id'])->setField('content',json_encode($dates));
  658. Db::commit();
  659. return true;
  660. }catch (Exception $e){
  661. $this->error = $e->getMessage();
  662. Db::rollback();
  663. return false;
  664. }
  665. }
  666. }
  667. }
  668. }
  669. }
  670. }else{ // 昨天没跨天排班记录,获取今天班次并打卡
  671. $class = model('AttendanceGroupClass')->getClassByDay($pin);
  672. if(empty($class)){
  673. // TODO::外勤打卡
  674. $org_id = Db::name('user')
  675. ->alias('u')
  676. ->join('user_roles ur','ur.user_id = u.id')
  677. ->join('roles r','r.id = ur.roles_id')
  678. ->where('u.id',$pin)
  679. ->where('r.type',3)
  680. ->value('r.org_id');
  681. $rdata = [
  682. 'user_id' => $pin,
  683. 'org_id' => $org_id?$org_id:0,
  684. 'type' => $type,
  685. 'lat' => $lat,
  686. 'lng' => $lng,
  687. 'address' => $address,
  688. 'from' => $sn,
  689. 'result' => '外勤',
  690. 'create_time' => $signdate,
  691. 'user_class_id' => 0,
  692. 'effective' => 1,
  693. 'status' => 0,
  694. 'cate' => 0,
  695. 'duration' => 0
  696. ];
  697. $ret = Db::name('attendance_record')->insert($rdata);
  698. if(!$ret){
  699. $this->error = "操作失败";
  700. return false;
  701. }
  702. return true;
  703. }else{ // 第一次打卡,外勤打卡不算其内
  704. $content = json_decode($class['content'],true);
  705. $dates = $content['dates'];
  706. $newdates = []; //[{"stime":"2021-03-22 08:00:00","etime":"2021-03-22 18:00:00","sstatus":0,"estatus":0}]
  707. $next = 0;
  708. foreach ($dates as $k=>$v){
  709. $newdates[] = [
  710. "stime" => $v['snext'] > 0?$nday .' '.$v['stime'].':00':$day.' '.$v['stime'].':00',
  711. "etime" => $v['enext'] > 0?$nday .' '.$v['etime'].':00':$day.' '.$v['etime'].':00',
  712. "sstatus" => 0,
  713. "estatus" => 0,
  714. ];
  715. if($v['snext'] == 1||$v['enext'] == 1){
  716. $next = 1;
  717. }
  718. }
  719. $count = count($newdates);
  720. if($count == 1){ // 一个班次
  721. if($signtime <= strtotime($newdates[0]['etime']) - 2*60){
  722. $newdates[0]['sstatus'] = 1;
  723. // TODO::上班打卡
  724. $kqtime = $newdates[0]['stime'];
  725. if($signtime <= strtotime($newdates[0]['stime'])){
  726. $result = '正常';
  727. }else{
  728. $result = '迟到';
  729. }
  730. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address);
  731. }else{
  732. $newdates[0]['sstatus'] = 1;
  733. // TODO::下班打卡
  734. $kqtime = $newdates[0]['etime'];
  735. if($signtime < strtotime($newdates[0]['etime'])){
  736. $result = '早退';
  737. }else{
  738. $result = '正常';
  739. }
  740. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address);
  741. }
  742. }else if($count == 2){
  743. if($signtime <= strtotime($newdates[0]['etime']) - 2*60){
  744. $newdates[0]['sstatus'] = 1;
  745. // TODO::上班打卡
  746. $kqtime = $newdates[0]['stime'];
  747. if($signtime <= strtotime($newdates[0]['stime'])){
  748. $result = '正常';
  749. }else{
  750. $result = '迟到';
  751. }
  752. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address);
  753. }else if($signtime > (strtotime($newdates[0]['etime']) - 2*60) &&$signtime <= (strtotime($newdates[1]['stime']) - 2*60)){
  754. // TODO::下班打卡
  755. $newdates[0]['sstatus'] = 1;
  756. $kqtime = $newdates[0]['etime'];
  757. if($signtime < strtotime($newdates[0]['etime'])){
  758. $result = '早退';
  759. }else{
  760. $result = '正常';
  761. }
  762. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address);
  763. }else if($signtime > (strtotime($newdates[1]['stime']) - 2*60) &&$signtime <= (strtotime($newdates[1]['etime']) - 2*60)){
  764. // TODO::二次上班打卡
  765. $newdates[0]['sstatus'] = 1;
  766. $newdates[0]['estatus'] = 1;
  767. $newdates[1]['sstatus'] = 1;
  768. $kqtime = $newdates[1]['stime'];
  769. if($signtime <= strtotime($newdates[1]['stime'])){
  770. $result = '正常';
  771. }else{
  772. $result = '迟到';
  773. }
  774. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address);
  775. }else{
  776. // TODO::二次下班打卡
  777. $newdates[0]['sstatus'] = 1;
  778. $newdates[0]['estatus'] = 1;
  779. $newdates[1]['sstatus'] = 1;
  780. $kqtime = $newdates[0]['etime'];
  781. if($signtime < strtotime($newdates[1]['etime'])){
  782. $result = '早退';
  783. }else{
  784. $result = '正常';
  785. }
  786. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address);
  787. }
  788. }else{
  789. if($signtime <= strtotime($newdates[0]['etime']) - 2*60){
  790. $newdates[0]['sstatus'] = 1;
  791. // TODO::上班打卡
  792. $kqtime = $newdates[0]['stime'];
  793. if($signtime <= strtotime($newdates[0]['stime'])){
  794. $result = '正常';
  795. }else{
  796. $result = '迟到';
  797. }
  798. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address);
  799. }else if($signtime > (strtotime($newdates[0]['etime']) - 2*60) &&$signtime <= (strtotime($newdates[1]['stime']) - 2*60)){
  800. // TODO::下班打卡
  801. $newdates[0]['sstatus'] = 1;
  802. $kqtime = $newdates[0]['etime'];
  803. if($signtime < strtotime($newdates[0]['etime'])){
  804. $result = '早退';
  805. }else{
  806. $result = '正常';
  807. }
  808. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address);
  809. }else if($signtime > (strtotime($newdates[1]['stime']) - 2*60) &&$signtime <= (strtotime($newdates[1]['etime']) - 2*60)){
  810. // TODO::二次上班打卡
  811. $newdates[0]['sstatus'] = 1;
  812. $newdates[0]['estatus'] = 1;
  813. $newdates[1]['sstatus'] = 1;
  814. $kqtime = $newdates[1]['stime'];
  815. if($signtime <= strtotime($newdates[1]['stime'])){
  816. $result = '正常';
  817. }else{
  818. $result = '迟到';
  819. }
  820. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address);
  821. }else if($signtime > (strtotime($newdates[1]['etime']) - 2*60) && $signtime <= (strtotime($newdates[2]['stime']) - 2*60)){
  822. // TODO::二次下班打卡
  823. $newdates[0]['sstatus'] = 1;
  824. $newdates[0]['estatus'] = 1;
  825. $newdates[1]['sstatus'] = 1;
  826. $kqtime = $newdates[1]['etime'];
  827. if($signtime < strtotime($newdates[1]['etime'])){
  828. $result = '早退';
  829. }else{
  830. $result = '正常';
  831. }
  832. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address);
  833. }else if($signtime > (strtotime($newdates[2]['stime']) - 2*60) && $signtime <= (strtotime($newdates[2]['etime']) - 2*60)){
  834. // TODO::三次上班打卡
  835. $newdates[0]['sstatus'] = 1;
  836. $newdates[0]['estatus'] = 1;
  837. $newdates[1]['sstatus'] = 1;
  838. $newdates[1]['estatus'] = 1;
  839. $newdates[2]['sstatus'] = 1;
  840. $kqtime = $newdates[2]['stime'];
  841. if($signtime <= strtotime($newdates[2]['stime'])){
  842. $result = '正常';
  843. }else{
  844. $result = '迟到';
  845. }
  846. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,1,$type,$lat,$lng,$address);
  847. }else{
  848. // TODO::三次下班打卡
  849. $newdates[0]['sstatus'] = 1;
  850. $newdates[0]['estatus'] = 1;
  851. $newdates[1]['sstatus'] = 1;
  852. $newdates[1]['estatus'] = 1;
  853. $newdates[2]['sstatus'] = 1;
  854. $kqtime = $newdates[2]['etime'];
  855. if($signtime < strtotime($newdates[1]['etime'])){
  856. $result = '早退';
  857. }else{
  858. $result = '正常';
  859. }
  860. return $this->firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,2,$type,$lat,$lng,$address);
  861. }
  862. }
  863. }
  864. }
  865. }
  866. }
  867. public function firstAdd($sn,$pin,$signdate,$class,$kqtime,$newdates,$day,$next,$result,$cate,$type,$lat,$lng,$address){
  868. Db::startTrans();
  869. try{
  870. $rdata = [
  871. 'kq_time' => $kqtime,
  872. 'user_id' => $pin,
  873. 'org_id' => $class['org_id'],
  874. 'type' => $type,
  875. 'lat' => $lat,
  876. 'lng' => $lng,
  877. 'address' => $address,
  878. 'from' => $sn,
  879. 'result' => $result,
  880. 'create_time' => $signdate,
  881. 'effective' => 1,
  882. 'status' => 0,
  883. 'cate' => $cate,
  884. 'duration' => 0
  885. ];
  886. if($cate == 1){ // 上班
  887. if($rdata['result'] == '迟到'){
  888. $rdata['status'] = 1;
  889. $rdata['duration'] = strtotime($rdata['create_time']) - strtotime($rdata['kq_time']);
  890. }
  891. }else if($cate == 2){ // 下班
  892. if($rdata['result'] == '早退'){
  893. $rdata['status'] = 2;
  894. $rdata['duration'] = strtotime($rdata['kq_time']) - strtotime($rdata['create_time']);
  895. }
  896. }
  897. foreach ($newdates as $k=>$v){
  898. if($cate == 1 && $v['stime'] == $rdata['kq_time']){
  899. $newdates[$k]['ssign'] = $rdata['create_time'];
  900. $newdates[$k]['esign'] = '';
  901. }else if($cate == 2 && $v['etime'] == $rdata['kq_time']){
  902. $newdates[$k]['ssign'] = '';
  903. $newdates[$k]['esign'] = $rdata['create_time'];
  904. }
  905. }
  906. $userData = [
  907. 'user_id' => $pin,
  908. 'group_id' => $class['group_id'],
  909. 'class_id' => $class['class_id'],
  910. 'org_id' => $class['org_id'],
  911. 'content' => json_encode($newdates),
  912. 'create_time' => date('Y-m-d H:i:s'),
  913. 'day' => $day,
  914. 'next' => $next
  915. ];
  916. $userClassId = Db::name('attendance_user_class')->insertGetId($userData);
  917. if(!$userClassId){
  918. \exception('保存失败');
  919. }
  920. $rdata['user_class_id'] = $userClassId;
  921. $ret = Db::name('attendance_record')->insert($rdata);
  922. if(!$ret){
  923. $this->error = "操作失败";
  924. return false;
  925. }
  926. Db::commit();
  927. return true;
  928. }catch (Exception $e){
  929. $this->error = "保存失败";
  930. Db::rollback();
  931. return false;
  932. }
  933. }
  934. // 补卡操作
  935. public function reissue($userId,$orgId,$kq_time,$signtime){
  936. $day = date('Y-m-d',strtotime($kq_time));
  937. $info = Db::name('attendance_user_class')
  938. ->where('user_id',$userId)
  939. ->where('org_id',$orgId)
  940. ->where('day',$day)
  941. ->find();
  942. if(!$info){
  943. return true; // 数据不存在,默认操作成功
  944. }
  945. $dates = json_decode($info['content'],true);
  946. $cate = 0; // 1=上班 2=下班
  947. foreach ($dates as $k=>$v){
  948. if($v['stime'] == $kq_time){
  949. $cate = 1;
  950. }else if($v['etime'] == $kq_time){
  951. $cate = 2;
  952. }
  953. }
  954. $status = 0;
  955. $duration = 0;
  956. $result = '补卡:正常';
  957. if($cate == 0){ // 有变化,不再修改考勤记录
  958. return true;
  959. }else if($cate == 1 && strtotime($signtime) > strtotime($kq_time)){ //1=上班
  960. $duration = strtotime($signtime) - strtotime($kq_time);
  961. $status = 1;
  962. $result = '补卡:迟到';
  963. }else if($cate == 2 && strtotime($signtime) < strtotime($kq_time)) { //2=下班
  964. $duration = strtotime($kq_time) - strtotime($signtime);
  965. $status = 2;
  966. $result = '补卡:早退';
  967. }
  968. $rdata = [
  969. 'kq_time' => $kq_time,
  970. 'user_id' => $userId,
  971. 'org_id' => $info['org_id'],
  972. 'type' => 2,
  973. 'from' => '流程补卡',
  974. 'result' => $result,
  975. 'create_time' => $signtime,
  976. 'user_class_id' => $info['id'],
  977. 'effective' => 1,
  978. 'status' => $status,
  979. 'cate' => $cate,
  980. 'duration' => $duration
  981. ];
  982. try{
  983. // 更新其他当前点的记录为无效
  984. Db::name('attendance_record')
  985. ->where('user_class_id',$info['id'])
  986. ->where('user_id',$userId)
  987. ->where('kq_time',$rdata['kq_time'])
  988. ->update(['effective'=>0,'result'=>'打卡无效:此记录已被更新']);
  989. $ret = Db::name('attendance_record')->insert($rdata);
  990. if(!$ret){
  991. \exception('操作失败');
  992. }
  993. foreach ($dates as $k=>$v){
  994. if($cate == 1 && $v['stime'] == $rdata['kq_time']){
  995. $dates[$k]['ssign'] = $signtime;
  996. }else if($cate == 2 && $v['etime'] == $rdata['kq_time']){
  997. $dates[$k]['esign'] = $signtime;
  998. }
  999. }
  1000. $userClassId = Db::name('attendance_user_class')->where('id',$info['id'])->update(['content' => json_encode($dates)]);
  1001. if(!$userClassId){
  1002. \exception('保存失败');
  1003. }
  1004. return true;
  1005. }catch (Exception $e){
  1006. return false;
  1007. }
  1008. }
  1009. // 为跨天的需要加一个定时任务,使考勤组状态变更
  1010. public function sign($sn,$pin,$signdate,$type=3,$lat='',$lng='',$address='',$remark=''){
  1011. // 检查用户状态
  1012. $user = Db::name('user')->where('id',$pin)->where('del',0)->find();
  1013. if(!$user||$user['enable'] != 1){
  1014. return true;
  1015. }
  1016. //先检查这个时间点是否已记录在系统内
  1017. $res = Db::name('attendance_record')->where('user_id',$pin)->where('create_time',$signdate)->find();
  1018. if($res){ // 已存在返回已处理
  1019. return true;
  1020. }
  1021. $curTime = date('Y-m-d H:i:s');
  1022. $signtime = strtotime($signdate);
  1023. // 检查当前打开时间是否有效 checkValid
  1024. $ret = Db::name('attendance_record')
  1025. ->alias('ar')
  1026. ->join('attendance_user_class auc','auc.id = ar.user_class_id')
  1027. ->where('ar.user_id',$pin)
  1028. ->where('auc.status',1)
  1029. ->where('ar.create_time','>',$signdate)
  1030. ->field('ar.*')
  1031. ->find();
  1032. if($ret){ // 时间无效,则标记为已处理
  1033. return true;
  1034. }
  1035. Db::startTrans();
  1036. try{
  1037. //先检查今天是否已生成打卡记录,未生成打卡记录需要查询昨天的考勤是否有跨天情况,取出今天的排班情况
  1038. $info = model('AttendanceUserClass')->getCurGroup($pin);
  1039. if($info) { // 获取当前的班次,没有班次,当做外勤打卡
  1040. // 检查支持的考勤类型
  1041. $cate = Db::name('attendance_group')->where('id',$info['group_id'])->value('cate');
  1042. if($type == 1){ // 手机打开
  1043. if(!$cate){
  1044. trace('不支持手机打卡');
  1045. Db::commit();
  1046. return true;
  1047. }else{
  1048. $cates = explode(',',$cate);
  1049. if(!in_array(1,$cates)){
  1050. trace('不支持手机打卡');
  1051. Db::commit();
  1052. return true;
  1053. }
  1054. }
  1055. }else if($type == 3){ //考勤机打卡
  1056. if(!$cate){
  1057. trace('不支持考勤机打卡');
  1058. Db::commit();
  1059. return true;
  1060. }else{
  1061. $cates = explode(',',$cate);
  1062. if(!in_array(2,$cates)){
  1063. trace('不支持考勤机打卡');
  1064. Db::commit();
  1065. return true;
  1066. }
  1067. }
  1068. }
  1069. if($info['day'] == date('Y-m-d') && $info['day'] != date('Y-m-d',$signtime)){ // 昨天的时间,今天的班次,不能使用
  1070. Db::commit();
  1071. return true;
  1072. }
  1073. $dates = json_decode($info['content'], true);
  1074. $records = Db::name('attendance_record')->where('user_class_id', $info['id'])->order('create_time asc')->select();
  1075. $records = $records ? $records : [];
  1076. $nrecords = [];
  1077. $flag = false;
  1078. $ndata = [
  1079. 'kq_time' => '',
  1080. 'user_id' => $pin,
  1081. 'org_id' => $info['org_id'],
  1082. 'type' => $type,
  1083. 'lat' => $lat,
  1084. 'lng' => $lng,
  1085. 'address' => $address,
  1086. 'from' => $sn,
  1087. 'result' => '',
  1088. 'create_time' => date('Y-m-d H:i:s',$signtime),
  1089. 'add_time' => $curTime,
  1090. 'user_class_id' => $info['id'],
  1091. 'effective' => 0,
  1092. 'status' => 0,
  1093. 'cate' => 0,
  1094. 'duration' => 0,
  1095. 'remark'=>$remark,
  1096. ];
  1097. foreach ($records as $k => $v) {
  1098. if (!$flag && strtotime($v['create_time']) > $signtime) {
  1099. $nrecords[] = $ndata;
  1100. $flag = true;
  1101. }
  1102. $nrecords[] = $v;
  1103. }
  1104. if(!$flag){ // 为最大值时
  1105. $nrecords[] = $ndata;
  1106. }
  1107. if (!$nrecords) {
  1108. $nrecords[] = $ndata;
  1109. }
  1110. // 班次
  1111. $datearr = $dates;
  1112. $lastret = $nrecords;
  1113. foreach ($datearr as $key => $val){ // 给没一个考勤记录划分到合适的时间段
  1114. $sret = get_attentance_srecord($lastret,$val);
  1115. $datearr[$key]['srecord'] = $sret['arr'];
  1116. $nstime = '';
  1117. if(isset($datearr[$key + 1])){
  1118. $nstime = $datearr[$key + 1]['stime'];
  1119. }
  1120. $lastret = $sret['record'];
  1121. $eret = get_attentance_erecord($lastret,$val,$nstime);
  1122. $datearr[$key]['erecord'] = $eret['arr'];
  1123. $lastret = $eret['record'];
  1124. }
  1125. $nums = 0;
  1126. $nrecords2 = [];
  1127. foreach ($datearr as $key => $val){
  1128. $nums += count($val['srecord']);
  1129. if($nums == count($nrecords)){ // 没有后续的打卡记录-未结束
  1130. $dates[$key]['sstatus'] = 0;
  1131. $dates[$key]['ssign'] = '';
  1132. }else{ // 有后续打卡--缺卡
  1133. $dates[$key]['sstatus'] = 1;
  1134. $dates[$key]['ssign'] = '';
  1135. }
  1136. if($val['srecord']){ // 有上班打卡记录
  1137. $dates[$key]['sstatus'] = 1;
  1138. $dates[$key]['ssign'] = $val['srecord'][0]['create_time'];
  1139. foreach ($val['srecord'] as $k=>$v){
  1140. $v['effective'] = 1;
  1141. $v['kq_time'] = $val['stime'];
  1142. if($v['status'] == 0){
  1143. $v['duration'] = 0;
  1144. $v['result'] = '正常';
  1145. }else if($v['status'] == 1){
  1146. $v['duration'] = strtotime($v['create_time']) - strtotime($val['stime']);
  1147. $v['result'] = '迟到';
  1148. }
  1149. $nrecords2[] = $v;
  1150. }
  1151. }
  1152. $nums += count($val['erecord']);
  1153. if($nums == count($nrecords)){ // 没有后续的打卡记录-未结束
  1154. $dates[$key]['estatus'] = 0;
  1155. $dates[$key]['esign'] = '';
  1156. }else{ // 有后续打卡--缺卡
  1157. $dates[$key]['estatus'] = 1;
  1158. $dates[$key]['esign'] = '';
  1159. }
  1160. if($val['erecord']) { // 有下班打卡记录
  1161. $dates[$key]['esign'] = $val['erecord'][count($val['erecord']) - 1]['create_time'];
  1162. foreach ($val['erecord'] as $k=>$v){
  1163. $v['kq_time'] = $val['etime'];
  1164. if($k == count($val['erecord']) - 1){ // 最后一个
  1165. $v['effective'] = 1;
  1166. if($v['status'] == 0){
  1167. $v['duration'] = 0;
  1168. $v['result'] = '正常';
  1169. }else if($v['status'] == 2){
  1170. $v['duration'] = strtotime($val['etime']) - strtotime($v['create_time']);
  1171. $v['result'] = '早退';
  1172. }
  1173. }else{
  1174. $v['effective'] = 0;
  1175. $v['duration'] = 0;
  1176. $v['result'] = '打卡无效:此记录已被更新';
  1177. }
  1178. $nrecords2[] = $v;
  1179. }
  1180. }
  1181. }
  1182. /*$datecount = count($dates);
  1183. if ($datecount == 1) { // 一天一个班次
  1184. foreach ($nrecords as $k => $v) {
  1185. if ($k == 0) { // 上班
  1186. $nrecords[$k]['kq_time'] = $dates[0]['stime'];
  1187. $nrecords[$k]['effective'] = 1;
  1188. $nrecords[$k]['cate'] = 1;
  1189. $nrecords[$k]['status'] = 0;
  1190. $nrecords[$k]['duration'] = 0;
  1191. $nrecords[$k]['result'] = '正常';
  1192. $dates[0]['sstatus'] = 1;
  1193. $dates[0]['ssign'] = $v['create_time'];
  1194. if (strtotime($v['create_time']) > strtotime($dates[0]['stime'])) { // 迟到
  1195. $nrecords[$k]['status'] = 1;
  1196. $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[0]['stime']);
  1197. $nrecords[$k]['result'] = '迟到';
  1198. }
  1199. } else { // 下班
  1200. $nrecords[$k]['kq_time'] = $dates[0]['etime'];
  1201. $nrecords[$k]['effective'] = 1;
  1202. $nrecords[$k]['cate'] = 2;
  1203. $nrecords[$k]['status'] = 0;
  1204. $nrecords[$k]['duration'] = 0;
  1205. $nrecords[$k]['result'] = '正常';
  1206. $dates[0]['estatus'] = 1;
  1207. $dates[0]['esign'] = $v['create_time'];
  1208. //判断是否是最后一条
  1209. if ($k + 1 == count($nrecords)) { // 是
  1210. if (strtotime($v['create_time']) < strtotime($dates[0]['etime'])) { // 早退
  1211. $nrecords[$k]['result'] = '早退';
  1212. $nrecords[$k]['status'] = 2;
  1213. $nrecords[$k]['duration'] = strtotime($dates[0]['etime']) - strtotime($v['create_time']);
  1214. }
  1215. } else { // 否,无效记录
  1216. $nrecords[$k]['effective'] = 0;
  1217. $nrecords[$k]['status'] = 0;
  1218. $nrecords[$k]['duration'] = 0;
  1219. $nrecords[$k]['result'] = '打卡无效:此记录已被更新';
  1220. }
  1221. }
  1222. }
  1223. }else if($datecount == 2){ // 一天二个班次
  1224. foreach ($nrecords as $k => $v) {
  1225. if ($k == 0) { // 1次上班
  1226. $nrecords[$k]['kq_time'] = $dates[0]['stime'];
  1227. $nrecords[$k]['effective'] = 1;
  1228. $nrecords[$k]['cate'] = 1;
  1229. $nrecords[$k]['status'] = 0;
  1230. $nrecords[$k]['duration'] = 0;
  1231. $nrecords[$k]['result'] = '正常';
  1232. $dates[0]['sstatus'] = 1;
  1233. $dates[0]['ssign'] = $v['create_time'];
  1234. if (strtotime($v['create_time']) > strtotime($dates[0]['stime'])) { // 迟到
  1235. $nrecords[$k]['status'] = 1;
  1236. $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[0]['stime']);
  1237. $nrecords[$k]['result'] = '迟到';
  1238. }
  1239. } else if ($k == 1){ // 1次下班
  1240. $nrecords[$k]['kq_time'] = $dates[0]['etime'];
  1241. $nrecords[$k]['effective'] = 1;
  1242. $nrecords[$k]['cate'] = 2;
  1243. $nrecords[$k]['status'] = 0;
  1244. $nrecords[$k]['duration'] = 0;
  1245. $nrecords[$k]['result'] = '正常';
  1246. $dates[0]['estatus'] = 1;
  1247. $dates[0]['esign'] = $v['create_time'];
  1248. if (strtotime($v['create_time']) < strtotime($dates[0]['etime'])) { // 早退
  1249. $nrecords[$k]['result'] = '早退';
  1250. $nrecords[$k]['status'] = 2;
  1251. $nrecords[$k]['duration'] = strtotime($dates[0]['etime']) - strtotime($v['create_time']);
  1252. }
  1253. } else if ($k == 2){ // 2次上班
  1254. $nrecords[$k]['kq_time'] = $dates[1]['stime'];
  1255. $nrecords[$k]['effective'] = 1;
  1256. $nrecords[$k]['cate'] = 1;
  1257. $nrecords[$k]['status'] = 0;
  1258. $nrecords[$k]['duration'] = 0;
  1259. $nrecords[$k]['result'] = '正常';
  1260. $dates[1]['sstatus'] = 1;
  1261. $dates[1]['ssign'] = $v['create_time'];
  1262. if (strtotime($v['create_time']) > strtotime($dates[1]['stime'])) { // 迟到
  1263. $nrecords[$k]['status'] = 1;
  1264. $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[1]['stime']);
  1265. $nrecords[$k]['result'] = '迟到';
  1266. }
  1267. } else { // 2次下班
  1268. $nrecords[$k]['kq_time'] = $dates[1]['etime'];
  1269. $nrecords[$k]['effective'] = 1;
  1270. $nrecords[$k]['cate'] = 2;
  1271. $nrecords[$k]['status'] = 0;
  1272. $nrecords[$k]['duration'] = 0;
  1273. $nrecords[$k]['result'] = '正常';
  1274. $dates[1]['estatus'] = 1;
  1275. $dates[1]['esign'] = $v['create_time'];
  1276. //判断是否是最后一条
  1277. if ($k + 1 == count($nrecords)) { // 是
  1278. if (strtotime($v['create_time']) < strtotime($dates[1]['etime'])) { // 早退
  1279. $nrecords[$k]['result'] = '早退';
  1280. $nrecords[$k]['status'] = 2;
  1281. $nrecords[$k]['duration'] = strtotime($dates[1]['etime']) - strtotime($v['create_time']);
  1282. }
  1283. } else { // 否,无效记录
  1284. $nrecords[$k]['effective'] = 0;
  1285. $nrecords[$k]['status'] = 0;
  1286. $nrecords[$k]['duration'] = 0;
  1287. $nrecords[$k]['result'] = '打卡无效:此记录已被更新';
  1288. }
  1289. }
  1290. }
  1291. }else if($datecount == 3){ // 一天三个班次
  1292. foreach ($nrecords as $k => $v) {
  1293. if ($k == 0) { // 1次上班
  1294. $nrecords[$k]['kq_time'] = $dates[0]['stime'];
  1295. $nrecords[$k]['effective'] = 1;
  1296. $nrecords[$k]['cate'] = 1;
  1297. $nrecords[$k]['status'] = 0;
  1298. $nrecords[$k]['duration'] = 0;
  1299. $nrecords[$k]['result'] = '正常';
  1300. $dates[0]['sstatus'] = 1;
  1301. $dates[0]['ssign'] = $v['create_time'];
  1302. if (strtotime($v['create_time']) > strtotime($dates[0]['stime'])) { // 迟到
  1303. $nrecords[$k]['status'] = 1;
  1304. $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[0]['stime']);
  1305. $nrecords[$k]['result'] = '迟到';
  1306. }
  1307. } else if ($k == 1){ // 1次下班
  1308. $nrecords[$k]['kq_time'] = $dates[0]['etime'];
  1309. $nrecords[$k]['effective'] = 1;
  1310. $nrecords[$k]['cate'] = 2;
  1311. $nrecords[$k]['status'] = 0;
  1312. $nrecords[$k]['duration'] = 0;
  1313. $nrecords[$k]['result'] = '正常';
  1314. $dates[0]['estatus'] = 1;
  1315. $dates[0]['esign'] = $v['create_time'];
  1316. if (strtotime($v['create_time']) < strtotime($dates[0]['etime'])) { // 早退
  1317. $nrecords[$k]['result'] = '早退';
  1318. $nrecords[$k]['status'] = 2;
  1319. $nrecords[$k]['duration'] = strtotime($dates[0]['etime']) - strtotime($v['create_time']);
  1320. }
  1321. } else if ($k == 2){ // 2次上班
  1322. $nrecords[$k]['kq_time'] = $dates[1]['stime'];
  1323. $nrecords[$k]['effective'] = 1;
  1324. $nrecords[$k]['cate'] = 1;
  1325. $nrecords[$k]['status'] = 0;
  1326. $nrecords[$k]['duration'] = 0;
  1327. $nrecords[$k]['result'] = '正常';
  1328. $dates[1]['sstatus'] = 1;
  1329. $dates[1]['ssign'] = $v['create_time'];
  1330. if (strtotime($v['create_time']) > strtotime($dates[1]['stime'])) { // 迟到
  1331. $nrecords[$k]['status'] = 1;
  1332. $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[1]['stime']);
  1333. $nrecords[$k]['result'] = '迟到';
  1334. }
  1335. } else if ($k == 3){ // 2次下班
  1336. $nrecords[$k]['kq_time'] = $dates[1]['etime'];
  1337. $nrecords[$k]['effective'] = 1;
  1338. $nrecords[$k]['cate'] = 2;
  1339. $nrecords[$k]['status'] = 0;
  1340. $nrecords[$k]['duration'] = 0;
  1341. $nrecords[$k]['result'] = '正常';
  1342. $dates[1]['estatus'] = 1;
  1343. $dates[1]['esign'] = $v['create_time'];
  1344. if (strtotime($v['create_time']) < strtotime($dates[1]['etime'])) { // 早退
  1345. $nrecords[$k]['result'] = '早退';
  1346. $nrecords[$k]['status'] = 2;
  1347. $nrecords[$k]['duration'] = strtotime($dates[1]['etime']) - strtotime($v['create_time']);
  1348. }
  1349. } else if ($k == 4){ // 3次上班
  1350. $nrecords[$k]['kq_time'] = $dates[2]['stime'];
  1351. $nrecords[$k]['effective'] = 1;
  1352. $nrecords[$k]['cate'] = 1;
  1353. $nrecords[$k]['status'] = 0;
  1354. $nrecords[$k]['duration'] = 0;
  1355. $nrecords[$k]['result'] = '正常';
  1356. $dates[2]['sstatus'] = 1;
  1357. $dates[2]['ssign'] = $v['create_time'];
  1358. if (strtotime($v['create_time']) > strtotime($dates[2]['stime'])) { // 迟到
  1359. $nrecords[$k]['status'] = 1;
  1360. $nrecords[$k]['duration'] = strtotime($v['create_time']) - strtotime($dates[2]['stime']);
  1361. $nrecords[$k]['result'] = '迟到';
  1362. }
  1363. } else { // 3次下班
  1364. $nrecords[$k]['kq_time'] = $dates[2]['etime'];
  1365. $nrecords[$k]['effective'] = 1;
  1366. $nrecords[$k]['cate'] = 2;
  1367. $nrecords[$k]['status'] = 0;
  1368. $nrecords[$k]['duration'] = 0;
  1369. $nrecords[$k]['result'] = '正常';
  1370. $dates[2]['estatus'] = 1;
  1371. $dates[2]['esign'] = $v['create_time'];
  1372. //判断是否是最后一条
  1373. if ($k + 1 == count($nrecords)) { // 是
  1374. if (strtotime($v['create_time']) < strtotime($dates[2]['etime'])) { // 早退
  1375. $nrecords[$k]['result'] = '早退';
  1376. $nrecords[$k]['status'] = 2;
  1377. $nrecords[$k]['duration'] = strtotime($dates[2]['etime']) - strtotime($v['create_time']);
  1378. }
  1379. } else { // 否,无效记录
  1380. $nrecords[$k]['effective'] = 0;
  1381. $nrecords[$k]['status'] = 0;
  1382. $nrecords[$k]['duration'] = 0;
  1383. $nrecords[$k]['result'] = '打卡无效:此记录已被更新';
  1384. }
  1385. }
  1386. }
  1387. }*/
  1388. // dump($datearr);
  1389. // dump($dates);
  1390. // halt($nrecords2);
  1391. foreach ($nrecords2 as $k=>$v){
  1392. $v['update_time'] = date('Y-m-d H:i:s');
  1393. if(isset($v['id']) && $v['id'] > 0){ //修改记录
  1394. $ret = Db::name('attendance_record')->where('id',$v['id'])->update($v);
  1395. }else{ // 新增记录
  1396. $ret = Db::name('attendance_record')->insert($v);
  1397. }
  1398. if(!$ret){
  1399. \exception('打卡失败');
  1400. }
  1401. }
  1402. $res = Db::name('attendance_user_class')->where('id',$info['id'])->update([
  1403. 'content' => json_encode($dates),
  1404. 'update_time' => date('Y-m-d H:i:s')
  1405. ]);
  1406. if(!$res){
  1407. \exception('打卡失败');
  1408. }
  1409. } else { // 外勤打卡
  1410. $org_id = Db::name('user')
  1411. ->alias('u')
  1412. ->join('user_roles ur','ur.user_id = u.id')
  1413. ->join('roles r','r.id = ur.roles_id')
  1414. ->where('u.id',$pin)
  1415. ->where('r.type',3)
  1416. ->value('r.org_id');
  1417. $rdata = [
  1418. 'user_id' => $pin,
  1419. 'org_id' => $org_id?$org_id:0,
  1420. 'type' => $type,
  1421. 'lat' => $lat,
  1422. 'lng' => $lng,
  1423. 'address' => $address,
  1424. 'from' => $sn,
  1425. 'result' => '外勤',
  1426. 'create_time' => date('Y-m-d H:i:s',$signtime),
  1427. 'add_time' => date('Y-m-d H:i:s'),
  1428. 'user_class_id' => 0,
  1429. 'effective' => 1,
  1430. 'status' => 0,
  1431. 'cate' => 0,
  1432. 'duration' => 0
  1433. ];
  1434. $ret = Db::name('attendance_record')->insert($rdata);
  1435. if(!$ret){
  1436. \exception('打卡失败');
  1437. }
  1438. }
  1439. Db::commit();
  1440. }catch (Exception $e){
  1441. trace($e->getMessage());
  1442. $this->error = $e->getMessage();
  1443. Db::rollback();
  1444. return false;
  1445. }
  1446. return true;
  1447. }
  1448. }