From da47230005ae841eb62fd0868230f32b52b8887e Mon Sep 17 00:00:00 2001 From: liutong <836164388@qq.com> Date: Tue, 27 May 2025 17:46:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(api):=20=E5=A2=9E=E5=8A=A0=E6=89=93?= =?UTF-8?q?=E5=8D=A1=E8=8C=83=E5=9B=B4=E9=99=90=E5=88=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 Attendance 控制器中添加了打卡范围验证逻辑 - 在 CommonService 中新增 isInCheckRange 方法,用于判断是否在打卡范围内 - 当用户签到或签退时,系统会检查其位置是否在指定校区的 1500 米范围内 - 如果超出范围,将返回错误提示信息 --- .../controller/apiController/Attendance.php | 20 ++++++++++++ .../service/api/apiService/CommonService.php | 32 +++++++++++++++++++ 2 files changed, 52 insertions(+) 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=超出打卡范围 + } + + }