guard()->user(); $time = $request->filled('time') ? Carbon::createFromFormat('Y-m', $request->input('time')) : now(); $list = EmployeeSign::where('employee_id', $user->id)->filter(['month' => $time->format('Y-m')])->get(); $data = []; $start = $time->copy()->startOfMonth(); $end = $time->copy()->endOfMonth(); do { $info = $list->where(fn($item) => $item->date->format('Y-m-d') == $start->format('Y-m-d'))->first(); array_push($data, [ 'date' => $start->format('Y-m-d'), 'sign_status' => $info ? $info->sign_status : null, 'first_time' => $info && $info->first_time ? $info->first_time->format('H:i') : '', 'last_time' => $info && $info->last_time ? $info->last_time->format('H:i') : '', ]); $start->addDay(); } while(!$end->isSameDay($start)); return $data; } public function info(Request $request, EmployeeSignService $service) { $user = $this->guard()->user(); $store = $user->store; if (!$store) { throw new RuntimeException('没有绑定门店'); } $date = now(); // 是否允许打卡 $enable = false; // 上班/下班 打卡, 当天是否打卡 $time = EmployeeSignLog::filter(['date' => $date->format('Y-m-d')])->exists() ? SignTime::Afternoon : SignTime::Morning; // 根据定位的距离判断, 是否外勤 $maxDistance = AdminSettingService::make()->arrayGet('sign', 'distance', 0); $type = SignType::Outside; $distance = null; $description = '请打开手机定位, 并给予APP获取位置信息权限'; if ($request->filled(['lon', 'lat'])) { $distance = $service->haversineDistance($request->input('lat'), $request->input('lon'), $store->lat, $store->lon); if ($distance <= $maxDistance) { $enable = true; $description = '已进入考勤范围: ' . $store->title; $type = SignType::Normal; } else { $description = '当前位置不在考勤范围内, 请选择外勤打卡'; } } return compact('enable', 'time', 'type', 'description', 'distance', 'maxDistance'); } public function store(Request $request, EmployeeSignService $service) { $request->validate([ 'type' => ['required', Rule::enum(SignType::class)], 'time' => ['required', Rule::enum(SignTime::class)], 'position' => ['required'], 'position.lon' => ['required'], 'position.lat' => ['required'], ], [ 'type.required' => __('employee_sign_log.sign_type') . '必填', 'time.required' => __('employee_sign_log.sign_time') . '必填', 'position.required' => __('employee_sign_log.position') . '必填', 'position.*.required' => __('employee_sign_log.position') . '必填', ]); $user = $this->guard()->user(); $store = $user->store; if (!$store) { throw new RuntimeException('没有绑定门店'); } $time = SignTime::from($request->input('time')); $type = SignType::from($request->input('type')); // 根据定位的距离判断, 是否需要外勤打卡 $maxDistance = AdminSettingService::make()->arrayGet('sign', 'distance', 0); $distance = $service->haversineDistance($request->input('position.lat'), $request->input('position.lon'), $store->lat, $store->lon); if ($distance > $maxDistance && $type == SignType::Normal) { throw new RuntimeException('当前位置不在考勤范围内, 请选择外勤打卡'); } try { DB::beginTransaction(); if (!$service->signDay($user, $time, now(), $request->only(['remarks', 'position', 'type']))) { throw new RuntimeException($service->getError()); } DB::commit(); return response('', Response::HTTP_OK); } catch (\Exception $e) { DB::rollBack(); throw new RuntimeException($e->getMessage()); } } }