AttendanceUserClass.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  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 AttendanceUserClass extends Model
  8. {
  9. // 获取当前排班班次
  10. public function getCurGroup($userId){
  11. $day = date('Y-m-d');
  12. $yday = date('Y-m-d',strtotime($day) - 1000);
  13. $info = Db::name('attendance_user_class')->where('user_id',$userId)->where('day',$day)->find();
  14. if($info){ // 当日班次存在直接返回
  15. return $info;
  16. }
  17. // 查看当日是否排班
  18. $class = model('AttendanceGroupClass')->getClassByDay($userId);
  19. // 当日不存在,获取昨日未结束班次,看看昨日班次是否跨天
  20. $info = Db::name('attendance_user_class')->where('user_id',$userId)->where('status',0)->where('next',1)->where('day',$yday)->find();
  21. if($info){
  22. // 检查此跨天班次是否已结束
  23. if(!$class){ // 今天没有班次
  24. return $info; // 存在昨日跨天班次,直接返回
  25. }
  26. // 获取昨天班次的最后下班时间
  27. $lcontent = json_decode($info['content'],true);
  28. $lastTime = strtotime($lcontent[count($lcontent)-1]['etime']);
  29. $content = json_decode($class['content'],true);
  30. $date = $content['dates'];
  31. $firstTime = strtotime(date('Y-m-d').$date[0]['stime']);
  32. $fgTime = $lastTime + ($firstTime - $lastTime)/2; // 间隔时间
  33. if($fgTime <= time()){ // 大于一半时间,结束上个班次,开启本班次
  34. // 结束上个班次
  35. $ycontent = json_decode($info['content'],true);
  36. foreach ($ycontent as $k=>$v){
  37. $ycontent[$k]['sstatus'] = 1;
  38. $ycontent[$k]['estatus'] = 1;
  39. }
  40. $res = Db::name('attendance_user_class')->where('id',$info['id'])->update([
  41. 'content' => json_encode($ycontent),
  42. 'status' => 1,
  43. 'update_time' => date('Y-m-d H:i:s')
  44. ]);
  45. if(!$res){ // 状态修改失败,直接抛出错误,终止程序
  46. \exception('状态修改失败');
  47. }
  48. // 添加今日班次
  49. $ret = $this->saveGroupClass($userId,$class);
  50. return $ret;
  51. }else{ // 昨天班次可继续打卡
  52. return $info;
  53. }
  54. }else{ // 添加今日班次
  55. if(!$class){ // 今天没有班次
  56. return false;
  57. }
  58. $ret = $this->saveGroupClass($userId,$class);
  59. return $ret;
  60. }
  61. }
  62. public function saveGroupClass($userId,$class){
  63. $day = date('Y-m-d');
  64. $nday = date('Y-m-d',strtotime($day) + 86400);
  65. // 只添加记录,不牵扯打卡
  66. $content = json_decode($class['content'],true);
  67. $dates = $content['dates'];
  68. $newdates = []; //[{"stime":"2021-03-22 08:00:00","etime":"2021-03-22 18:00:00","sstatus":0,"estatus":0,"ssign":"","esign":""}]
  69. $next = 0;
  70. foreach ($dates as $k=>$v){
  71. $newdates[] = [
  72. "stime" => $v['snext'] > 0?$nday .' '.$v['stime'].':00':$day.' '.$v['stime'].':00',
  73. "etime" => $v['enext'] > 0?$nday .' '.$v['etime'].':00':$day.' '.$v['etime'].':00',
  74. "sstatus" => 0,
  75. "estatus" => 0,
  76. "ssign" => "",
  77. "esign" => ""
  78. ];
  79. if($v['snext'] == 1||$v['enext'] == 1){
  80. $next = 1;
  81. }
  82. }
  83. $userData = [
  84. 'user_id' => $userId,
  85. 'group_id' => $class['group_id'],
  86. 'class_id' => $class['class_id'],
  87. 'org_id' => $class['org_id'],
  88. 'content' => json_encode($newdates),
  89. 'create_time' => date('Y-m-d H:i:s'),
  90. 'day' => $day,
  91. 'next' => $next,
  92. 'status' => 0,
  93. 'duration' => 0
  94. ];
  95. $userClassId = Db::name('attendance_user_class')->insertGetId($userData);
  96. if(!$userClassId){ // 添加失败,直接抛出错误,终止程序
  97. \exception('添加今日班次失败');
  98. }
  99. $userData['id'] = $userClassId;
  100. return $userData;
  101. }
  102. public function info($userId,$day){
  103. //content [{"stime":"2021-03-22 08:00:00","etime":"2021-03-22 18:00:00","sstatus":0,"estatus":0,"ssign":"","esign":""}] 0=未结束 1=已结束
  104. $info = Db::name('attendance_user_class')->where('user_id',$userId)->where('day',$day)->find();
  105. if($info){
  106. $info['content'] = json_decode($info['content'],true);
  107. }
  108. return $info;
  109. }
  110. public function info_old($userId,$day){
  111. //content [{"stime":"2021-03-22 08:00:00","etime":"2021-03-22 18:00:00","sstatus":0,"estatus":0,"ssign":"","esign":""}] 0=未结束 1=已结束
  112. $info = Db::name('attendance_user_class')->where('user_id',$userId)->where('day',$day)->find();
  113. if($info){
  114. $info['content'] = json_decode($info['content'],true);
  115. // $lists = Db::name('attendance_record')->where('user_class_id',$info['id'])->order('id asc')->select();
  116. // $lists = $lists?$lists:[];
  117. // foreach ($info['content'] as $k=>$v){
  118. // $sub = $eub = [];
  119. // foreach ($lists as $kk=>$vv){
  120. // if($vv['kq_time'] == $v['stime']){
  121. // $sub[] = $vv;
  122. // }else if($vv['kq_time'] == $v['etime']){
  123. // $eub[] = $vv;
  124. // }
  125. // }
  126. // $info['content'][$k]['slist'] = $sub;
  127. // $info['content'][$k]['elist'] = $eub;
  128. // }
  129. }
  130. return $info;
  131. }
  132. // 改变打卡状态
  133. public function changeAttendance($data,$orgId){
  134. $info = Db::name('attendance_user_class')->where('id',$data['id'])->find();
  135. if(!$info){
  136. HelpHander::error('参数错误');
  137. }
  138. if($info['status'] == 0){
  139. HelpHander::error('无权限操作');
  140. }
  141. if($data['cate'] == 1){ // 上班(正常上班/下班的记录是不可修改的)
  142. $ret = Db::name('attendance_record')
  143. ->where('user_id',$info['user_id'])
  144. ->where('create_time',$data['time'])
  145. ->where('cate',1)
  146. ->where('effective',1)
  147. ->where('status',0)
  148. ->find();
  149. if($ret){
  150. HelpHander::error('上班打卡为正常状态,不能修改');
  151. }
  152. }else if($data['cate'] == 2){// 下班
  153. $ret = Db::name('attendance_record')
  154. ->where('user_id',$info['user_id'])
  155. ->where('user_class_id',$data['id'])
  156. ->where('create_time',$data['time'])
  157. ->where('cate',2)
  158. ->where('effective',1)
  159. ->where('status',0)
  160. ->find();
  161. if($ret){
  162. HelpHander::error('下班打卡为正常状态,不能修改');
  163. }
  164. }
  165. if($data['type'] == 1){
  166. $data['min'] = 0;
  167. }
  168. $signdate = $data['time'];
  169. $status = 0;
  170. $result = '管理员修改为:正常';
  171. if($data['cate'] == 1 && $data['type'] == 2){ //上班
  172. $signdate = date('Y-m-d H:i:s',strtotime($data['time']) + $data['min']*60);
  173. $status = 1;
  174. $result = '管理员修改为:迟到';
  175. }else if($data['cate'] == 2 && $data['type'] == 2){
  176. $signdate = date('Y-m-d H:i:s',strtotime($data['time']) - $data['min']*60);
  177. $status = 2;
  178. $result = '管理员修改为:早退';
  179. }
  180. Db::startTrans();
  181. try{
  182. Db::name('attendance_record')
  183. ->where('user_class_id',$data['id'])
  184. ->where('user_id',$info['user_id'])
  185. ->where('kq_time',$data['time'])
  186. ->update(['effective' => 0,'result'=>"打卡无效:此记录已被更新"]);
  187. $rdata = [
  188. 'kq_time' => $data['time'],
  189. 'user_id' => $info['user_id'],
  190. 'org_id' => $info['org_id'],
  191. 'type' => 4,
  192. 'from' => '管理员修改',
  193. 'result' => $result,
  194. 'create_time' => $signdate,
  195. 'user_class_id' => $data['id'],
  196. 'effective' => 1,
  197. 'status' => $status,
  198. 'cate' => $data['cate'],
  199. 'duration' => $data['min']*60
  200. ];
  201. $ret = Db::name('attendance_record')->insert($rdata);
  202. if(!$ret){
  203. \exception('操作失败');
  204. }
  205. $dates = json_decode($info['content'],true);
  206. foreach ($dates as $k=>$v){
  207. if($rdata['cate'] == 1 && $v['stime'] == $rdata['kq_time']){
  208. $dates[$k]['ssign'] = $rdata['create_time'];
  209. }else if($rdata['cate'] == 2 && $v['etime'] == $rdata['kq_time']){
  210. $dates[$k]['esign'] = $rdata['create_time'];
  211. }
  212. }
  213. $userClassId = Db::name('attendance_user_class')->where('id',$info['id'])->update(['content' => json_encode($dates)]);
  214. if(!$userClassId){
  215. \exception('保存失败');
  216. }
  217. Db::commit();
  218. }catch (Exception $e){
  219. trace($e->getMessage());
  220. Db::rollback();
  221. HelpHander::error('操作失败'.$e->getMessage());
  222. }
  223. return true;
  224. }
  225. // 获取补卡记录
  226. public function reissueList($userId,$orgId){
  227. $reissue_day = config('reissue_day');
  228. $start_time = date('Y-m-d',time() - $reissue_day * 86400);
  229. $end_time = date('Y-m-d');
  230. $lists = Db::name('attendance_user_class')
  231. ->where('user_id',$userId)
  232. ->where('org_id',$orgId)
  233. ->where('day','>=',$start_time)
  234. ->where('day','<',$end_time)
  235. ->where('status',1)
  236. ->field('id,user_id,content')
  237. ->select();
  238. $nlist = [];
  239. foreach ($lists as $k=>$v){
  240. $dates = json_decode($v['content'],true);
  241. foreach ($dates as $kk=>$vv){
  242. $record1 = Db::name('attendance_record')
  243. ->where('user_id',$v['user_id'])
  244. ->where('user_class_id',$v['id'])
  245. ->where('effective',1)
  246. ->where('kq_time',$vv['stime'])
  247. ->find();
  248. if(!$record1){
  249. $nlist[] = [
  250. 'id' => $vv['stime'],
  251. 'title' => '上班:'.$vv['stime']
  252. ];
  253. }
  254. $record2 = Db::name('attendance_record')
  255. ->where('user_id',$v['user_id'])
  256. ->where('user_class_id',$v['id'])
  257. ->where('effective',1)
  258. ->where('kq_time',$vv['etime'])
  259. ->find();
  260. if(!$record2){
  261. $nlist[] = [
  262. 'id' => $vv['etime'],
  263. 'title' => '下班:'.$vv['etime']
  264. ];
  265. }
  266. }
  267. }
  268. return $nlist;
  269. }
  270. // 生成某天未打卡人员固定班制的记录
  271. public function attendanceReissueFixed($day){
  272. $nday = date('Y-m-d',strtotime($day) + 24*60*60); // 下一天
  273. // 已参与考勤人员
  274. $userIds2 = Db::name('attendance_user_class')
  275. ->where('day',$day)
  276. ->column('user_id');
  277. // 查询固定班制考勤组
  278. $groups = Db::name('attendance_group')->where('type',1)->where('del',0)->select();
  279. $w = date('w',strtotime($day)); // 是周几
  280. foreach ($groups as $key=>$val){
  281. $content = json_decode($val['content'],true);
  282. $week = $content['week'];
  283. $classId = 0;
  284. foreach ($week as $k=>$v){
  285. if($w == $v['week']){
  286. $classId = empty($v['class_id'])?0:$v['class_id'];
  287. }
  288. }
  289. // 今日是否有必打卡特殊日
  290. $sign = $content['sign']?$content['sign']:[];
  291. foreach ($sign as $k=>$v){
  292. if($day == $v['day']){
  293. $classId = empty($v['class_id'])?0:$v['class_id'];
  294. }
  295. }
  296. // 今日是否有不必打卡特殊日
  297. $unsign = $content['unsign']?$content['unsign']:[];
  298. foreach ($unsign as $k=>$v){
  299. if($day == $v['day']){
  300. $classId = 0;
  301. }
  302. }
  303. if($classId <= 0){
  304. continue;
  305. }
  306. $map[] = ['a.group_id','=',$val['id']];
  307. if($userIds2){
  308. $map[] = ['a.user_id','not in',$userIds2];
  309. }
  310. $map[] = ['b.enable','=',1];
  311. $map[] = ['b.del','=',0];
  312. $map[] = ['c.is_working','in',[0,1,2]];
  313. $uids = Db::name('attendance_group_user')
  314. ->alias('a')
  315. ->join('user b','b.id = a.user_id')
  316. ->join('user_info c','c.user_id = a.user_id')
  317. ->where($map)
  318. ->column('a.user_id');
  319. $class = Db::name('attendance_class')->where('id',$classId)->find();
  320. if(!$uids || !$class){
  321. continue;
  322. }
  323. $content = json_decode($class['content'],true);
  324. $dates = $content['dates'];
  325. $newdates = []; //[{"stime":"2021-03-22 08:00:00","etime":"2021-03-22 18:00:00","sstatus":0,"estatus":0,"ssign":"","esign":""}]
  326. $next = 0;
  327. foreach ($dates as $k=>$v){
  328. $newdates[] = [
  329. "stime" => $v['snext'] > 0?$nday .' '.$v['stime'].':00':$day.' '.$v['stime'].':00',
  330. "etime" => $v['enext'] > 0?$nday .' '.$v['etime'].':00':$day.' '.$v['etime'].':00',
  331. "sstatus" => 0,
  332. "estatus" => 0,
  333. "ssign" => '',
  334. "esign" => '',
  335. ];
  336. if($v['snext'] == 1||$v['enext'] == 1){
  337. $next = 1;
  338. }
  339. }
  340. if($next == 0){ // 不跨天
  341. foreach ($newdates as $k=>$v){
  342. $newdates[$k]['sstatus'] = 1;
  343. $newdates[$k]['estatus'] = 1;
  344. }
  345. $status = 1;
  346. }else{ // 跨天
  347. foreach ($newdates as $k=>$v){
  348. if($v['stime'] >= $nday.' 00:00:00'){
  349. $newdates[$k]['sstatus'] = 0;
  350. }else{
  351. $newdates[$k]['sstatus'] = 1;
  352. }
  353. if($v['etime'] >= $nday.' 00:00:00'){
  354. $newdates[$k]['estatus'] = 0;
  355. }else{
  356. $newdates[$k]['estatus'] = 1;
  357. }
  358. }
  359. $status = 0;
  360. }
  361. foreach ($uids as $k=>$v){
  362. Db::name('attendance_user_class')->insert([
  363. 'org_id' => $class['org_id'],
  364. 'user_id' => $v,
  365. 'class_id' => $class['id'],
  366. 'group_id' => $val['id'],
  367. 'content' => json_encode($newdates),
  368. 'day' => $day,
  369. 'next' => $next,
  370. 'status' => $status,
  371. 'create_time' => date('Y-m-d H:i:s'),
  372. 'update_time' => date('Y-m-d H:i:s')
  373. ]);
  374. }
  375. }
  376. }
  377. // 生成某天未打卡人员排班制的记录
  378. public function attendanceReissueClass($day){
  379. $nday = date('Y-m-d',strtotime($day) + 24*60*60); // 下一天
  380. // 已参与考勤人员
  381. $userIds2 = Db::name('attendance_user_class')
  382. ->where('day',$day)
  383. ->column('user_id');
  384. $map = [];
  385. $map[] = ['u.del','=',0];
  386. $map[] = ['u.enable','=',1];
  387. $map[] = ['g.del','=',0];
  388. $map[] = ['ui.is_working','in',[0,1,2]];
  389. $map[] = ['agc.day','=',$day];
  390. if($userIds2){
  391. $map[] = ['u.id','not in',$userIds2];
  392. }
  393. $lists = Db::name('attendance_group_user')
  394. ->alias('agu')
  395. ->join('attendance_group_class agc','agu.group_id = agc.group_id')
  396. ->join('user u','u.id = agu.user_id')
  397. ->join('user_info ui','ui.user_id = agu.user_id')
  398. ->join('attendance_group g','g.id = agu.group_id')
  399. ->join('attendance_class c','c.id = agc.class_id')
  400. ->where($map)
  401. ->field('agu.group_id,agu.user_id,agu.org_id,agc.class_id,c.content,agc.day')
  402. ->select();
  403. $lists = $lists?$lists:[];
  404. foreach ($lists as $key=>$val){
  405. $content = json_decode($val['content'],true);
  406. $dates = $content['dates'];
  407. $newdates = [];
  408. $next = 0;
  409. foreach ($dates as $k=>$v){
  410. $newdates[] = [
  411. "stime" => $v['snext'] > 0?$nday .' '.$v['stime'].':00':$day.' '.$v['stime'].':00',
  412. "etime" => $v['enext'] > 0?$nday .' '.$v['etime'].':00':$day.' '.$v['etime'].':00',
  413. "sstatus" => 0,
  414. "estatus" => 0,
  415. "ssign" => '',
  416. "esign" => '',
  417. ];
  418. if($v['snext'] == 1||$v['enext'] == 1){
  419. $next = 1;
  420. }
  421. }
  422. if($next == 0){ // 不跨天
  423. foreach ($newdates as $k=>$v){
  424. $newdates[$k]['sstatus'] = 1;
  425. $newdates[$k]['estatus'] = 1;
  426. }
  427. $status = 1;
  428. }else{ // 跨天
  429. foreach ($newdates as $k=>$v){
  430. if($v['stime'] >= $day.' 00:00:00'){
  431. $newdates[$k]['sstatus'] = 0;
  432. }else{
  433. $newdates[$k]['sstatus'] = 1;
  434. }
  435. if($v['etime'] >= $day.' 00:00:00'){
  436. $newdates[$k]['estatus'] = 0;
  437. }else{
  438. $newdates[$k]['estatus'] = 1;
  439. }
  440. }
  441. $status = 0;
  442. }
  443. Db::name('attendance_user_class')->insert([
  444. 'org_id' => $val['org_id'],
  445. 'user_id' => $val['user_id'],
  446. 'class_id' => $val['class_id'],
  447. 'group_id' => $val['group_id'],
  448. 'content' => json_encode($newdates),
  449. 'day' => $day,
  450. 'next' => $next,
  451. 'status' => $status,
  452. 'create_time' => date('Y-m-d H:i:s'),
  453. 'update_time' => date('Y-m-d H:i:s')
  454. ]);
  455. }
  456. }
  457. }