diff --git a/niucloud/app/api/controller/apiController/Attendance.php b/niucloud/app/api/controller/apiController/Attendance.php index 3524d828..704874cf 100644 --- a/niucloud/app/api/controller/apiController/Attendance.php +++ b/niucloud/app/api/controller/apiController/Attendance.php @@ -12,7 +12,9 @@ namespace app\api\controller\apiController; use app\Request; +use app\service\admin\campus\CampusService; use app\service\api\apiService\AttendanceService; +use app\service\api\apiService\CommonService; use core\base\BaseApiService; /** @@ -50,6 +52,8 @@ class Attendance extends BaseApiService $coordinate = '';//坐标 if(!empty($longitude) && !empty($latitude)){ $coordinate = "{$longitude},{$latitude}"; + }else{ + return fail('缺少定位坐标'); } if(empty($campus_id) || empty($attendance_date) || empty($status)){ @@ -59,6 +63,22 @@ class Attendance extends BaseApiService return fail('状态类型不正确'); } + //获取校区的经纬度坐标 + $campus_data = (new CampusService)->getInfo($campus_id);//查校区详情 + $campus_lng = $campus_data['campus_coordinates']['lng'];//校区经度坐标 + $campus_lat = $campus_data['campus_coordinates']['lat'];//校区纬度坐标 + $radius = 1500.0;//打卡半径(米) + + //判断签到+签退时是否超出打卡范围 + if(in_array($status,['present','sign_out'])){ + $isInCheckRange = (new CommonService())->isInCheckRange((float)$campus_lng, (float)$campus_lat, (float)$longitude, (float)$latitude, (float)$radius); + if(!$isInCheckRange){ + return fail("超出打卡范围,规定打卡范围({$radius}米)"); + } + } + + + //查询数据是否存在,一天一个校区同一个人只能产生一条数据 $date_h = date('H:i:s'); diff --git a/niucloud/app/service/api/apiService/CommonService.php b/niucloud/app/service/api/apiService/CommonService.php index 66ebc2a0..26654fd4 100644 --- a/niucloud/app/service/api/apiService/CommonService.php +++ b/niucloud/app/service/api/apiService/CommonService.php @@ -80,4 +80,36 @@ class CommonService extends BaseApiService ]; } + /** + * 判断是否在打卡范围内 + * @param float $campusLat 地理围栏中心纬度 + * @param float $campusLng 地理围栏中心经度 + * @param float $checkLat 打卡纬度 + * @param float $checkLng 打卡经度 + * @param float $radius 地理围栏半径(单位:米) + * @return bool 返回是否在范围内的布尔值 + */ + public function isInCheckRange(float $campusLat, float $campusLng, float $checkLat, float $checkLng, float $radius = 3000.0): bool + { + // 使用 Haversine 公式计算两点之间的距离 + $earthRadius = 6371000; // 地球半径,单位为米 + + $latFrom = deg2rad($campusLat); + $lngFrom = deg2rad($campusLng); + $latTo = deg2rad($checkLat); + $lngTo = deg2rad($checkLng); + + $latDelta = $latTo - $latFrom; + $lngDelta = $lngTo - $lngFrom; + + $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) + + cos($latFrom) * cos($latTo) * pow(sin($lngDelta / 2), 2))); + + $distance = $angle * $earthRadius; + + // 判断计算出的距离是否小于等于设定的围栏半径 + return $distance <= $radius;//false=超出打卡范围 + } + + }