设备打卡

This commit is contained in:
zt
2025-10-17 21:15:44 +08:00
parent 2b4517760f
commit 31aa56d34b
6 changed files with 166 additions and 0 deletions

View File

@ -0,0 +1,118 @@
package org.dromara.project.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.web.core.BaseController;
import org.dromara.project.domain.BusAttendanceMachine;
import org.dromara.project.domain.dto.attendance.*;
import org.dromara.project.service.IBusAttendanceMachineService;
import org.dromara.project.service.IBusAttendanceService;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
/**
* 考勤
*
* @author Lion Li
* @date 2025-08-05
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping()
@Slf4j
public class BusAttendanceDeviceController extends BaseController {
private final IBusAttendanceService busAttendanceService;
private final IBusAttendanceMachineService busAttendanceMachineService;
@PostMapping("/api/v1/record/face")
@SaIgnore
public R<Boolean> punchCardByFace(@RequestBody DeviceDto dto) {
//打印接收数据
log.info("接收数据:{}", dto);
if (dto.getLogs().isEmpty()) {
return R.fail("没有数据");
}
Log first = dto.getLogs().getFirst();
Long userId = Long.valueOf(first.getUser_id());
BusAttendanceMachine one = busAttendanceMachineService.lambdaQuery()
.eq(BusAttendanceMachine::getSn, dto.getSn())
.last("limit 1")
.one();
if (one == null || one.getProjectId() == null) {
return R.fail("考勤机不存在或未关联项目");
}
String recogTime = first.getRecog_time();
LocalDateTime localDateTime = LocalDateTime.parse(recogTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
BusAttendancePunchCardByFaceReq req = new BusAttendancePunchCardByFaceReq();
DeviceLocation location = first.getLocation();
req.setLat(location.getLatitude());
req.setLng(location.getLongitude());
req.setProjectId(one.getProjectId());
req.setUserId(userId);
req.setPunchTime(localDateTime);
//打印req
log.info("请求参数:{}", req);
//base64转MultipartFile
try {
// 假设first.getImage()返回base64字符串且你有一个文件名
MultipartFile file = convert(first.getPhoto(), "face.jpg");
log.info("开始打卡");
return R.ok(busAttendanceService.punchCardByFace(file, req));
} catch (IOException e) {
return R.fail("文件转换失败");
}
}
public static MultipartFile convert(String base64String, String fileName) throws IOException {
// 先进行URL解码如果是URL编码过的数据
try {
base64String = java.net.URLDecoder.decode(base64String, "UTF-8");
} catch (Exception e) {
// 如果不是URL编码的数据直接跳过
}
// 去除base64前缀如data:image/png;base64,
if (base64String.contains(",")) {
base64String = base64String.split(",")[1];
}
// 解码base64字符串
byte[] decodedBytes = Base64.getDecoder().decode(base64String);
// 创建MultipartFile对象
return new MockMultipartFile(fileName, fileName, "image/jpeg", decodedBytes);
}
}

View File

@ -5,6 +5,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime;
/** /**
* @author lilemy * @author lilemy
@ -41,4 +42,9 @@ public class BusAttendancePunchCardByFaceReq implements Serializable {
*/ */
private Long userId; private Long userId;
/**
* 打卡时间
*/
private LocalDateTime punchTime;
} }

View File

@ -0,0 +1,14 @@
package org.dromara.project.domain.dto.attendance;
import lombok.Data;
import org.apache.poi.ss.formula.functions.Count;
import java.util.List;
@Data
public class DeviceDto {
private String sn;
private int Count;
private List<Log> logs;
}

View File

@ -0,0 +1,9 @@
package org.dromara.project.domain.dto.attendance;
import lombok.Data;
@Data
public class DeviceLocation {
private String longitude;
private String latitude;
}

View File

@ -0,0 +1,12 @@
package org.dromara.project.domain.dto.attendance;
import lombok.Data;
@Data
public class Log {
private String user_id;
private String recog_type;
private String recog_time;
private String photo;
private DeviceLocation location;
}

View File

@ -326,7 +326,11 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
} }
synchronized (userId.toString().intern()) { synchronized (userId.toString().intern()) {
// 记录当前打卡时间 // 记录当前打卡时间
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
if(req.getPunchTime() != null){
now = req.getPunchTime();
}
//打卡范围 //打卡范围
if (!checkInRange(req)) { if (!checkInRange(req)) {
@ -617,6 +621,9 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
public Boolean checkInRange(BusAttendancePunchCardByFaceReq req) { public Boolean checkInRange(BusAttendancePunchCardByFaceReq req) {
// 获取当前用户 // 获取当前用户
Long userId = LoginHelper.getUserId(); Long userId = LoginHelper.getUserId();
if (req.getUserId() != null) {
userId = req.getUserId();
}
Long projectId = req.getProjectId(); Long projectId = req.getProjectId();
SysUserVo sysUserVo = userService.queryById(userId); SysUserVo sysUserVo = userService.queryById(userId);