generated from liutk/owl-admin-base
155 lines
5.5 KiB
PHP
155 lines
5.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\Hr;
|
|
|
|
use App\Http\Controllers\Api\Controller;
|
|
use App\Models\{EmployeeSign, EmployeeSignLog};
|
|
use Illuminate\Http\{Request, Response};
|
|
use App\Exceptions\RuntimeException;
|
|
use Illuminate\Support\Facades\DB;
|
|
use App\Admin\Services\EmployeeSignService;
|
|
use App\Enums\{SignTime, SignType, SignStatus};
|
|
use Carbon\Carbon;
|
|
use Slowlyo\OwlAdmin\Services\AdminSettingService;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
/**
|
|
* 考勤打卡
|
|
*/
|
|
class SignController extends Controller
|
|
{
|
|
public function index(Request $request)
|
|
{
|
|
$user = $this->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();
|
|
|
|
// 上班/下班 打卡, 当天是否打卡
|
|
$time = SignTime::Morning;
|
|
if (
|
|
EmployeeSignLog::filter([
|
|
'employee_id' => $user->id,
|
|
'date' => $date->format('Y-m-d'),
|
|
])->exists()
|
|
) {
|
|
$time = SignTime::Afternoon;
|
|
}
|
|
|
|
// 根据定位的距离判断, 是否外勤
|
|
$maxDistance = (int) AdminSettingService::make()->arrayGet('sign', 'distance', 0);
|
|
|
|
$data = [
|
|
'time' => $time,
|
|
'enable' => false,
|
|
'type' => SignType::Normal,
|
|
'distance' => null,
|
|
'description' => '请打开手机定位, 并给予APP获取位置信息权限',
|
|
'maxDistance' => $maxDistance,
|
|
];
|
|
|
|
// 如果开启定位
|
|
if ($request->filled(['lon', 'lat'])) {
|
|
// 计算距离
|
|
$distance = $service->haversineDistance(
|
|
$request->input('lat'),
|
|
$request->input('lon'),
|
|
$store->lat,
|
|
$store->lon,
|
|
);
|
|
|
|
if ($maxDistance > 0 && $distance > $maxDistance) {
|
|
$data = array_merge($data, [
|
|
'enable' => true,
|
|
'type' => SignType::Outside,
|
|
'distance' => $distance,
|
|
'description' => '当前位置不在考勤范围内, 请选择外勤打卡',
|
|
]);
|
|
} else {
|
|
$data = array_merge($data, [
|
|
'enable' => true,
|
|
'distance' => $distance,
|
|
'description' => '已进入考勤范围: ' . $store->title,
|
|
]);
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
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 = (int) AdminSettingService::make()->arrayGet('sign', 'distance');
|
|
|
|
if ($maxDistance > 0 && $type == SignType::Normal) {
|
|
$distance = $service->haversineDistance(
|
|
$request->input('position.lat'),
|
|
$request->input('position.lon'),
|
|
$store->lat,
|
|
$store->lon,
|
|
);
|
|
|
|
if ($distance > $maxDistance) {
|
|
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());
|
|
}
|
|
}
|
|
}
|