人脸对接

This commit is contained in:
zt
2025-10-20 19:24:36 +08:00
parent 99f0026552
commit 037016fc13
5 changed files with 199 additions and 51 deletions

View File

@ -0,0 +1,89 @@
package org.dromara.common.utils.attendance;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class FaceUtil {
private static final String FACE_URL = "http://192.168.110.5:1224";
/**
* 创建人脸记录 post
* @param name 姓名
* @param card 身份证
* @param path 人脸图片HTTP地址需可公开访问
*/
public static void createFaceRecord(String name, String card, String path) {
String url = FACE_URL+"/api/faces";
HashMap<String, Object> param = new HashMap<>() {{
put("name", name);
put("card", card);
put("path", path);
}};
HttpUtil.post(url, param);
}
/**
* 人脸检测
* @param path 图片HTTP地址需可公开访问
*/
public static Map<String, String> faceDetect(String path) {
String url = FACE_URL+"/api/faces/detect";
HashMap<String, Object> param = new HashMap<>() {{
put("path", path);
put("similarity_threshold", 0.8);
}};
//转成json
String post = HttpUtil.post(url, param);
Map<String, String> map = new HashMap<>();
// 遍历检测到的人脸数据
try {
// 解析返回的JSON数据
JSONObject response = JSON.parseObject(post);
JSONObject data = response.getJSONObject("data");
JSONArray detectedFaces = data.getJSONArray("detected_faces");
for (int i = 0; i < detectedFaces.size(); i++) {
JSONObject face = detectedFaces.getJSONObject(i);
JSONObject matchInfo = face.getJSONObject("match_info");
// 检查相似度是否大于等于阈值
double similarity = matchInfo.getDoubleValue("similarity");
double threshold = matchInfo.getDoubleValue("threshold");
if (similarity >= threshold) {
// 提取用户信息
JSONObject userInfo = face.getJSONObject("user_info");
String name = userInfo.getString("name");
String idCard = userInfo.getString("id_card");
map.put(idCard, name);
}
}
}catch (Exception e){
log.error("人脸检测失败",e);
}
return map;
}
public static void main(String[] args) {
// Map<String, String> map = faceDetect("http://xny.yj-3d.com:9000/xinnengyuan-dev/2025/10/12/9688ce2474ad47e7bf59c641848cdf8f.jpg");
// System.out.println(map);
// createFaceRecord("石志强","513022111145632652","http://xny.yj-3d.com:9000/xinnengyuan-dev/2025/10/12/9688ce2474ad47e7bf59c641848cdf8f.jpg");
}
}

View File

@ -69,6 +69,7 @@ public class BusAttendanceDeviceController extends BaseController {
req.setProjectId(one.getProjectId());
req.setUserId(userId);
req.setPunchTime(localDateTime);
req.setSource("1");
//打印req
log.info("请求参数:{}", req);
//base64转MultipartFile

View File

@ -113,4 +113,9 @@ public class BusAttendance extends BaseEntity {
* 代打卡人员Id
*/
private Long replaceId;
/**
* 来源
*/
private String source;
}

View File

@ -47,4 +47,10 @@ public class BusAttendancePunchCardByFaceReq implements Serializable {
*/
private LocalDateTime punchTime;
/**
* 来源 0-app,1-考勤机
*/
private String source;
}

View File

@ -391,63 +391,105 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
List<BusAttendance> outAttendances = attendances.stream().filter(attendance ->
BusAttendanceCommuterEnum.CLOCKOUT.getValue().equals(attendance.getClockType())).toList();
if (clockTypeByTime == 1 && CollectionUtils.isEmpty(inAttendances)) {
BusAttendance attendance = new BusAttendance();
// 上班打卡
attendance.setClockType(BusAttendanceCommuterEnum.CLOCKIN.getValue());
//打卡时间
attendance.setRuleTime(busAttendanceRuleVo.getClockInTime());
// 判断是否为迟到
if (isLate(now, busAttendanceRuleVo)) {
attendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue());
attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime()));
} else {
attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
}
//只要请假,直接归为请假
LocalDateTime localDateTime = localDate.atTime(busAttendanceRuleVo.getClockInTime());
if (leaveService.isLeave(localDateTime, userId)) {
attendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVE.getValue());
}
// 填充信息
attendance.setUserId(userId);
attendance.setProjectId(req.getProjectId());
attendance.setClockDate(localDate);
attendance.setClockTime(now);
attendance.setUserName(constructionUser.getUserName());
attendance.setReplaceId(replaceId);
// 记录打卡坐标
attendance.setLat(req.getLat());
attendance.setLng(req.getLng());
try {
attendance.setClockLocation(JSTUtil.getLocationName(req.getLat(), req.getLng()));
} catch (Exception e) {
log.error("获取打卡位置失败", e);
}
// 上传人脸照
SysOssVo upload = ossService.upload(file);
attendance.setFacePic(upload.getOssId().toString());
Long finalUserId = userId;
CompletableFuture.runAsync(() -> {
try {
chatServerHandler.sendSystemMessageToUser(finalUserId, "打卡成功", "1");
} catch (Exception e) {
log.error("异步发送系统消息失败用户ID: {}, 消息: {}", finalUserId, "打卡成功", e);
if (clockTypeByTime == 1) {
if(CollectionUtils.isEmpty(inAttendances)){
BusAttendance attendance = new BusAttendance();
// 上班打卡
attendance.setClockType(BusAttendanceCommuterEnum.CLOCKIN.getValue());
//打卡时间
attendance.setRuleTime(busAttendanceRuleVo.getClockInTime());
// 判断是否为迟到
if (isLate(now, busAttendanceRuleVo)) {
attendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue());
attendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime()));
} else {
attendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
}
});
//计算工资
attendance.setSalary(computeSalary(constructionUser, inAttendances));
return this.save(attendance);
//只要请假,直接归为请假
LocalDateTime localDateTime = localDate.atTime(busAttendanceRuleVo.getClockInTime());
if (leaveService.isLeave(localDateTime, userId)) {
attendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVE.getValue());
}
// 填充信息
attendance.setUserId(userId);
attendance.setProjectId(req.getProjectId());
attendance.setClockDate(localDate);
attendance.setClockTime(now);
attendance.setUserName(constructionUser.getUserName());
attendance.setReplaceId(replaceId);
if(req.getSource() != null){
attendance.setSource(req.getSource());
}
// 记录打卡坐标
attendance.setLat(req.getLat());
attendance.setLng(req.getLng());
try {
attendance.setClockLocation(JSTUtil.getLocationName(req.getLat(), req.getLng()));
} catch (Exception e) {
log.error("获取打卡位置失败", e);
}
// 上传人脸照
SysOssVo upload = ossService.upload(file);
attendance.setFacePic(upload.getOssId().toString());
Long finalUserId = userId;
CompletableFuture.runAsync(() -> {
try {
chatServerHandler.sendSystemMessageToUser(finalUserId, "打卡成功", "1");
} catch (Exception e) {
log.error("异步发送系统消息失败用户ID: {}, 消息: {}", finalUserId, "打卡成功", e);
}
});
//计算工资
attendance.setSalary(computeSalary(constructionUser, inAttendances));
return this.save(attendance);
}
//考勤机打卡会有历史记录,需要更新状态
if(CollectionUtil.isNotEmpty(outAttendances) && "1".equals(req.getSource())){
BusAttendance busAttendance = outAttendances.getFirst();
String oldStatus = busAttendance.getClockStatus();
//更新打卡时间
busAttendance.setClockTime(now);
// 判断是否为迟到
if (isLate(now, busAttendanceRuleVo)) {
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.LATE.getValue());
busAttendance.setMinuteCount(getMinutesDifference(now, busAttendanceRuleVo.getClockInTime()));
} else {
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.NORMAL.getValue());
}
//只要请假,直接归为请假
LocalDateTime localDateTime = localDate.atTime(busAttendanceRuleVo.getClockInTime());
if (leaveService.isLeave(localDateTime, userId)) {
busAttendance.setClockStatus(BusAttendanceClockStatusEnum.LEAVE.getValue());
}
busAttendance.setSource(req.getSource());
//如果是缺卡需要上传人脸
if(oldStatus.equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())){
SysOssVo upload = ossService.upload(file);
busAttendance.setFacePic(upload.getOssId().toString());
}
updateById(busAttendance);
}
} else if (clockTypeByTime == 2 || CollectionUtils.isNotEmpty(inAttendances)) {
if (CollectionUtil.isNotEmpty(outAttendances)) {
BusAttendance busAttendance = outAttendances.getFirst();
if (busAttendance.getClockStatus().equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())) {
throw new ServiceException("下班缺卡记录已生成,不能更新");
if("1".equals(req.getSource())){
busAttendance.setSource(req.getSource());
if(busAttendance.getClockStatus().equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())){
SysOssVo upload = ossService.upload(file);
busAttendance.setFacePic(upload.getOssId().toString());
}
}else {
if (busAttendance.getClockStatus().equals(BusAttendanceClockStatusEnum.UNCLOCK.getValue())) {
throw new ServiceException("下班缺卡记录已生成,不能更新");
}
}
//更新打卡时间
busAttendance.setClockTime(now);
// 判断是否为早退
@ -488,6 +530,9 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
attendance.setClockTime(now);
attendance.setUserName(constructionUser.getUserName());
attendance.setReplaceId(replaceId);
if(req.getSource() != null){
attendance.setSource(req.getSource());
}
// 记录打卡坐标
attendance.setLat(req.getLat());
attendance.setLng(req.getLng());
@ -1109,7 +1154,9 @@ public class BusAttendanceServiceImpl extends ServiceImpl<BusAttendanceMapper, B
// 过滤有效考勤记录并按日期分组
Map<LocalDate, List<BusAttendanceVo>> dateAttendanceMap = attendanceList.stream()
.filter(a -> validStatusList.contains(a.getClockStatus()))
.collect(Collectors.groupingBy(BusAttendanceVo::getClockDate));
.collect(Collectors.groupingBy(BusAttendanceVo::getClockDate,
LinkedHashMap::new,
Collectors.toList()));
List<AttendanceUserDataDetailVo> workList = new ArrayList<>();
for (Map.Entry<LocalDate, List<BusAttendanceVo>> entry : dateAttendanceMap.entrySet()) {
LocalDate key = entry.getKey();