generated from liutk/owl-admin-base
167 lines
5.5 KiB
PHP
167 lines
5.5 KiB
PHP
<?php
|
|
|
|
namespace App\Admin\Services;
|
|
|
|
use App\Admin\Filters\EmployeeSignFilter;
|
|
use App\Enums\SignStatus;
|
|
use App\Enums\SignTime;
|
|
use App\Enums\SignType;
|
|
use App\Models\Employee;
|
|
use App\Models\EmployeeRest;
|
|
use App\Models\EmployeeSign;
|
|
use App\Models\EmployeeSignLog;
|
|
use Carbon\Carbon;
|
|
|
|
class EmployeeSignService extends BaseService
|
|
{
|
|
protected array $withRelationships = ['employee', 'store'];
|
|
|
|
protected string $modelName = EmployeeSign::class;
|
|
|
|
protected string $modelFilterName = EmployeeSignFilter::class;
|
|
|
|
/**
|
|
* 整理昨天的打卡流水, 生成对应的打卡记录
|
|
*/
|
|
public function signResult()
|
|
{
|
|
$date = now()->subDay();
|
|
$start = $date->copy()->startOfDay();
|
|
$end = $date->copy()->endOfDay();
|
|
// 打卡日志
|
|
$list = EmployeeSignLog::whereBetween('time', [$start, $end])->get();
|
|
// 休息的员工
|
|
$restEmployeeIds = EmployeeRest::whereBetWeen('date', [$start, $end])->pluck('employee_id');
|
|
// 需要打卡的员工
|
|
$employees = Employee::where('store_id', '>', 0)->whereNotIn('id', $restEmployeeIds)->get();
|
|
foreach ($employees as $employee) {
|
|
$logs = $list->where('employee_id', $employee->id);
|
|
// 状态: 两个打卡=正常, 一次打卡 = 缺卡, 两次未打=旷工
|
|
$status = 0;
|
|
// 外勤打卡-事由
|
|
$remarks = null;
|
|
// 上班打卡
|
|
$firstTime = null;
|
|
if ($item = $logs->where('sign_time', SignTime::Morning)->sortBy('time')->first()) {
|
|
$firstTime = $item->time;
|
|
$status++;
|
|
if ($item->sign_type == SignType::Outside) {
|
|
$remarks = $item->remarks;
|
|
}
|
|
}
|
|
// 下班打卡
|
|
$lastTime = null;
|
|
if ($item = $logs->where('sign_time', SignTime::Afternoon)->sortByDesc('time')->first()) {
|
|
$lastTime = $item->time;
|
|
$status++;
|
|
if ($item->sign_type == SignType::Outside) {
|
|
$remarks = $item->remarks;
|
|
}
|
|
}
|
|
// 打卡类型
|
|
$type = SignType::None;
|
|
if ($status > 0) {
|
|
$type = $logs->where('sign_type', SignType::Outside)->count() > 0 ? SignType::Outside : SignType::Normal;
|
|
}
|
|
$attributes = [
|
|
'sign_type' => $type,
|
|
'first_time' => $firstTime,
|
|
'last_time' => $lastTime,
|
|
'sign_status' => match ($status) {
|
|
0 => SignStatus::Absent,
|
|
1 => SignStatus::Lose,
|
|
2 => SignStatus::Normal,
|
|
},
|
|
'remarks' => $remarks,
|
|
];
|
|
$employee->signs()->updateOrCreate([
|
|
'date' => $date,
|
|
'store_id' => $employee->store_id,
|
|
], $attributes);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 打卡
|
|
*
|
|
* @param Employee $user 用户
|
|
* @param SignTime $time 上班/下班 打卡
|
|
* @param mixed $date 打卡时间
|
|
* @param array $options {type: 正常/外勤 打卡, remarks: 备注, position: 位置}
|
|
* @return boolean
|
|
*/
|
|
public function signDay(Employee $user, SignTime $time, $date = '', array $options = [])
|
|
{
|
|
$date = $date ?: now();
|
|
$log = EmployeeSignLog::create([
|
|
'store_id' => $user->store_id,
|
|
'employee_id' => $user->id,
|
|
'sign_time' => $time,
|
|
'time' => $date,
|
|
'sign_type' => data_get($options, 'type'),
|
|
'remarks' => data_get($options, 'remarks'),
|
|
'position' => data_get($options, 'position'),
|
|
'is_repair' => data_get($options, 'is_repair') ? 1 : 0,
|
|
'outside_remarks' => data_get($options, 'outside_remarks'),
|
|
'repair_id' => data_get($options, 'repair_id'),
|
|
]);
|
|
|
|
// 更新打卡情况
|
|
$sign = EmployeeSign::firstOrCreate([
|
|
'date' => $date->format('Y-m-d'),
|
|
'store_id' => $user->store_id,
|
|
'employee_id' => $user->id,
|
|
]);
|
|
$sign->sign_type = $log->sign_type;
|
|
if ($time == SignTime::Morning) {
|
|
$sign->first_time = $log->time;
|
|
} else if ($time == SignTime::Afternoon) {
|
|
$sign->last_time = $log->time;
|
|
}
|
|
$sign->sign_status = SignStatus::Lose;
|
|
if ($sign->first_time && $sign->last_time) {
|
|
$sign->sign_status = SignStatus::Normal;
|
|
}
|
|
$sign->remarks = $log->remarks;
|
|
|
|
$sign->save();
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 判断员工某天是否休息
|
|
*/
|
|
public function hasRest(Employee $user, $date = '')
|
|
{
|
|
$date = $date ?: now();
|
|
return EmployeeRest::where('employee_id', $user->id)->where('date', $date)->exists();
|
|
}
|
|
|
|
/**
|
|
* 计算两点之间的距离(千米)
|
|
*/
|
|
public function haversineDistance($lat1, $lon1, $lat2, $lon2)
|
|
{
|
|
// 地球半径(千米)
|
|
$R = 6371;
|
|
|
|
// 将角度转换为弧度
|
|
$lat1 = deg2rad($lat1);
|
|
$lon1 = deg2rad($lon1);
|
|
$lat2 = deg2rad($lat2);
|
|
$lon2 = deg2rad($lon2);
|
|
|
|
// 经纬度差值
|
|
$dlon = $lon2 - $lon1;
|
|
$dlat = $lat2 - $lat1;
|
|
|
|
// Calculate the Haversine formula
|
|
$a = pow(sin($dlat/2), 2) + cos($lat1) * cos($lat2) * pow(sin($dlon/2), 2);
|
|
$c = 2 * atan2(sqrt($a), sqrt(1-$a));
|
|
$distance = $R * $c;
|
|
|
|
return floor($distance * 1000) / 1000;
|
|
}
|
|
}
|