This commit is contained in:
zt
2025-05-13 16:35:09 +08:00
parent 88cd11228b
commit ee9fd26068
8 changed files with 149 additions and 4 deletions

View File

@ -140,6 +140,15 @@ public class BgtProjectRecruit implements Serializable {
@ApiModelProperty("下班时间")
private LocalTime endWorkTime;
@ApiModelProperty("中心点经度")
private Double centralLongitude;
@ApiModelProperty("'中心点纬度'")
private Double centralLatitude;
@ApiModelProperty("'半径'")
private Double rangeRadius;
@ApiModelProperty("工种")
private String typeOfWork;

View File

@ -119,4 +119,13 @@ public class BgtProjectRecruitDetailVO implements Serializable {
@ApiModelProperty("招工状态(1-进行中2-已招满3-已过期)")
private String status;
@ApiModelProperty("中心点经度")
private Double centralLongitude;
@ApiModelProperty("'中心点纬度'")
private Double centralLatitude;
@ApiModelProperty("'半径'")
private Double rangeRadius;
}

View File

@ -0,0 +1,68 @@
package com.ruoyi.common.util;
import com.ruoyi.common.exception.BaseException;
public class LocationUtils {
private static final double EARTH_RADIUS = 6371000;
/**
* 计算两点间的球面距离Haversine 公式)
* @throws IllegalArgumentException 如果任何参数为 null
*/
public static double haversine(Double lat1, Double lon1, Double lat2, Double lon2) {
validateCoordinates(lat1, lon1, lat2, lon2);
double lat1Rad = Math.toRadians(lat1);
double lon1Rad = Math.toRadians(lon1);
double lat2Rad = Math.toRadians(lat2);
double lon2Rad = Math.toRadians(lon2);
double dLat = lat2Rad - lat1Rad;
double dLon = lon2Rad - lon1Rad;
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1Rad) * Math.cos(lat2Rad) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return EARTH_RADIUS * c;
}
/**
* 判断当前坐标是否在打卡范围内
* @throws IllegalArgumentException 如果中心点坐标或范围为 null
*/
public static boolean isInRange(Double centerLat, Double centerLon,
Double currentLat, Double currentLon,
Double rangeMeters) {
if (rangeMeters == null || rangeMeters < 0) {
throw new BaseException("打卡范围不能为空且必须为正数");
}
if (currentLat == null || currentLon == null) {
return false; // 当前位置为 null 时视为不在范围内
}
validateCoordinates(centerLat, centerLon);
double distance = haversine(centerLat, centerLon, currentLat, currentLon);
return distance <= rangeMeters;
}
// 参数校验方法
private static void validateCoordinates(Double... coords) {
for (Double coord : coords) {
if (coord == null) {
throw new BaseException("经纬度坐标不能为空");
}
}
}
public static void main(String[] args) {
double haversine = haversine(29.623956, 106.508291, 29.623906, 106.508314);
System.out.println(haversine);
}
}

View File

@ -1,6 +1,5 @@
package com.ruoyi.wgz.bo.req;
import com.ruoyi.common.annotation.Excel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -26,4 +25,14 @@ public class WgzAppSubmitTheClockReq implements Serializable {
@ApiModelProperty("打卡位置")
@NotBlank(message = "打卡位置不能为空")
private String pnchOsition;
@ApiModelProperty("当前位置纬度")
@NotNull(message = "当前位置纬度不能为空")
private Double currentLat;
@ApiModelProperty("当前位置经度")
@NotNull(message = "当前位置经度不能为空")
private Double currentLon;
}

View File

@ -0,0 +1,18 @@
package com.ruoyi.wgz.bo.res;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class WgzAppUserClockRangeRes {
@ApiModelProperty("中心点经度")
private Double centralLongitude;
@ApiModelProperty("'中心点纬度'")
private Double centralLatitude;
@ApiModelProperty("'半径'")
private Double rangeRadius;
}

View File

@ -18,6 +18,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.BaseException;
import com.ruoyi.common.util.DataUtil;
import com.ruoyi.common.util.LocalDateToChineseWeekday;
import com.ruoyi.common.util.LocationUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
@ -172,6 +173,7 @@ public class WgzAttendanceServiceImpl extends ServicePlusImpl<WgzAttendanceMappe
}
//3、根据工地id得到完整的工地信息
BgtProjectRecruit appById = iBgtProjectRecruitService.getAppById(by.getRecruitId());
//4、在进场时间时才能打卡如果有退场记录就不允许打卡
if (by.getEntryTime() == null || !by.getStatus().equals("5")) {
throw new RuntimeException("需要进场才能实现打卡操作!");
@ -179,6 +181,10 @@ public class WgzAttendanceServiceImpl extends ServicePlusImpl<WgzAttendanceMappe
if (by.getLeaveTime() != null) {
throw new RuntimeException("您已离场,无法进行打卡操作!");
}
//验证打卡范围
if (!LocationUtils.isInRange(appById.getCentralLatitude(), appById.getCentralLongitude(), req.getCurrentLat(), req.getCurrentLon(), appById.getRangeRadius())) {
throw new RuntimeException("打卡位置不在工地范围内,请重新打卡!");
}
//5、查看当前人、当前工地、当天的打卡记录
String formattedDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
WgzAttendance we = publicFindByUserIdWait(appUserId, by.getRecruitId(), formattedDate);