diff --git a/yanzhu-bigscreen/src/views/bimManage.vue b/yanzhu-bigscreen/src/views/bimManage.vue
index 1ad4c2a7..abdbb725 100644
--- a/yanzhu-bigscreen/src/views/bimManage.vue
+++ b/yanzhu-bigscreen/src/views/bimManage.vue
@@ -849,7 +849,7 @@ export default {
this.$message.error("暂无模型,请先关联模型");
} else {
bimTools.addModelList(window.bimMgrApi, this.bimCfg, this.models, (hideParts) => {
- console.log(":--->", hideParts); debugger
+ console.log(":--->", hideParts);
this.loadDevicePosition();
setTimeout(() => {
bimTools.setDefaultViewPoint(window.bimMgrApi, this.bimCfg, this.viewPoint)
diff --git a/yanzhu-common/yanzhu-common-core/src/main/java/com/yanzhu/common/core/utils/ImageSimilarityUtils.java b/yanzhu-common/yanzhu-common-core/src/main/java/com/yanzhu/common/core/utils/ImageSimilarityUtils.java
index 4a4fe306..de5994c9 100644
--- a/yanzhu-common/yanzhu-common-core/src/main/java/com/yanzhu/common/core/utils/ImageSimilarityUtils.java
+++ b/yanzhu-common/yanzhu-common-core/src/main/java/com/yanzhu/common/core/utils/ImageSimilarityUtils.java
@@ -34,15 +34,45 @@ public class ImageSimilarityUtils {
// OpenCV人脸检测器
private static CascadeClassifier faceDetector;
+ // OpenCV是否成功加载的标志
+ public static boolean openCVLoaded = false;
+
static {
try {
- // 加载OpenCV库(使用openpnp的OpenCV依赖)
+ // 尝试加载OpenCV库(使用openpnp的OpenCV依赖)
+ System.out.println("开始加载OpenCV库...");
nu.pattern.OpenCV.loadLocally();
- // 初始化人脸检测器(使用相对路径)
- String cascadePath = ImageSimilarityUtils.class.getClassLoader().getResource("opencv/haarcascade_frontalface_default.xml").getPath();
- faceDetector = new CascadeClassifier(cascadePath);
+ openCVLoaded = true;
+ System.out.println("OpenCV库加载成功");
+
+ try {
+ // 初始化人脸检测器(使用相对路径)
+ String cascadePath = ImageSimilarityUtils.class.getClassLoader().getResource("opencv/haarcascade_frontalface_default.xml").getPath();
+ System.out.println("人脸检测器模型路径: " + cascadePath);
+ faceDetector = new CascadeClassifier(cascadePath);
+
+ if (faceDetector.empty()) {
+ System.err.println("人脸检测器初始化失败,将使用基础相似度计算方法");
+ faceDetector = null;
+ } else {
+ System.out.println("人脸检测器初始化成功");
+ }
+ } catch (Exception e) {
+ System.err.println("人脸检测器初始化失败: " + e.getMessage());
+ faceDetector = null;
+ }
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("OpenCV库加载失败( UnsatisfiedLinkError),将使用基础相似度计算方法: " + e.getMessage());
+ openCVLoaded = false;
+ faceDetector = null;
} catch (Exception e) {
System.err.println("OpenCV加载失败,将使用基础相似度计算方法: " + e.getMessage());
+ openCVLoaded = false;
+ faceDetector = null;
+ } catch (Throwable t) {
+ System.err.println("OpenCV加载失败(未知错误),将使用基础相似度计算方法: " + t.getMessage());
+ t.printStackTrace();
+ openCVLoaded = false;
faceDetector = null;
}
}
@@ -190,6 +220,7 @@ public class ImageSimilarityUtils {
private static double calculateImageSimilarity(BufferedImage image1, BufferedImage image2) {
// 如果OpenCV初始化失败,直接使用基础方法
if (faceDetector == null) {
+ System.out.println("使用基础相似度计算方法");
return calculateImageSimilarityBasic(image1, image2);
}
@@ -272,6 +303,12 @@ public class ImageSimilarityUtils {
} catch (Exception e) {
e.printStackTrace();
// 发生异常时使用原始方法
+ System.out.println("OpenCV处理出现异常,使用基础相似度计算方法: " + e.getMessage());
+ return calculateImageSimilarityBasic(image1, image2);
+ } catch (UnsatisfiedLinkError e) {
+ e.printStackTrace();
+ // OpenCV链接错误时使用原始方法
+ System.out.println("OpenCV链接错误,使用基础相似度计算方法: " + e.getMessage());
return calculateImageSimilarityBasic(image1, image2);
}
}
@@ -306,6 +343,11 @@ public class ImageSimilarityUtils {
* @return 人脸区域矩形,如果未检测到人脸则返回null
*/
private static Rect detectFace(BufferedImage image) {
+ // 如果OpenCV未正确加载,直接返回null
+ if (faceDetector == null || !openCVLoaded) {
+ return null;
+ }
+
try {
// 将BufferedImage转换为OpenCV Mat
Mat mat = bufferedImageToMat(image);
@@ -335,9 +377,12 @@ public class ImageSimilarityUtils {
return largestFace;
}
+ return null;
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("OpenCV链接错误,无法检测人脸: " + e.getMessage());
return null;
} catch (Exception e) {
- e.printStackTrace();
+ System.err.println("人脸检测出现异常: " + e.getMessage());
return null;
}
}
diff --git a/yanzhu-common/yanzhu-common-mapper/src/main/java/com/yanzhu/manage/domain/ProMobileAttendanceData.java b/yanzhu-common/yanzhu-common-mapper/src/main/java/com/yanzhu/manage/domain/ProMobileAttendanceData.java
index 72b3cc94..c7e7184a 100644
--- a/yanzhu-common/yanzhu-common-mapper/src/main/java/com/yanzhu/manage/domain/ProMobileAttendanceData.java
+++ b/yanzhu-common/yanzhu-common-mapper/src/main/java/com/yanzhu/manage/domain/ProMobileAttendanceData.java
@@ -51,6 +51,16 @@ public class ProMobileAttendanceData extends BaseEntity
@Excel(name = "考勤时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date attDate;
+ private String basePath;
+
+ public String getBasePath() {
+ return basePath;
+ }
+
+ public void setBasePath(String basePath) {
+ this.basePath = basePath;
+ }
+
/** 考勤照片 */
@Excel(name = "考勤照片")
private String attImg;
diff --git a/yanzhu-common/yanzhu-common-mapper/src/main/resources/mapper/manage/AttendanceUbiDataMapper.xml b/yanzhu-common/yanzhu-common-mapper/src/main/resources/mapper/manage/AttendanceUbiDataMapper.xml
index b05e8d9a..74a74936 100644
--- a/yanzhu-common/yanzhu-common-mapper/src/main/resources/mapper/manage/AttendanceUbiDataMapper.xml
+++ b/yanzhu-common/yanzhu-common-mapper/src/main/resources/mapper/manage/AttendanceUbiDataMapper.xml
@@ -80,7 +80,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
and userId = #{userId}
and admitGuid = #{admitGuid}
and userName like concat('%', #{userName}, '%')
- and date(inTime) = date(#{inTime})
+
+ and (date(inTime) = date(#{inTime}) or date(outTime) = date(#{inTime}))
+
and date(outTime) = date(#{outTime})
and deviceNo = #{deviceNo}
diff --git a/yanzhu-modules/yanzhu-manage/pom.xml b/yanzhu-modules/yanzhu-manage/pom.xml
index 556fbaac..fbdb28ca 100644
--- a/yanzhu-modules/yanzhu-manage/pom.xml
+++ b/yanzhu-modules/yanzhu-manage/pom.xml
@@ -195,7 +195,6 @@
org.openpnp
opencv
- 4.5.1-2
diff --git a/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/controller/remoteAttendance/ProMobileAttendanceConfigController.java b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/controller/remoteAttendance/ProMobileAttendanceConfigController.java
index 5736545a..9bd29b5d 100644
--- a/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/controller/remoteAttendance/ProMobileAttendanceConfigController.java
+++ b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/controller/remoteAttendance/ProMobileAttendanceConfigController.java
@@ -13,6 +13,8 @@ import com.yanzhu.common.log.annotation.Log;
import com.yanzhu.common.log.enums.BusinessType;
import com.yanzhu.common.security.annotation.RequiresPermissions;
import com.yanzhu.manage.domain.ProMobileAttendanceData;
+import com.yanzhu.manage.service.IAttendanceUbiDataService;
+import com.yanzhu.manage.service.IProMobileAttendanceDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@@ -39,6 +41,10 @@ public class ProMobileAttendanceConfigController extends BaseController
@Autowired
private IProMobileAttendanceConfigService proMobileAttendanceConfigService;
+ @Autowired
+ private IAttendanceUbiDataService attendanceUbiDataService;
+ @Autowired
+ private IProMobileAttendanceDataService proMobileAttendanceDataService;
/**
* 查询移动端考勤配置列表
*/
@@ -123,21 +129,24 @@ public class ProMobileAttendanceConfigController extends BaseController
@PostMapping("/attendance")
public AjaxResult attendance(@RequestBody ProMobileAttendanceData attData){
//根据用户上传的照片与用户信息的照片计算相似度
- String userPicture=attData.getUserPicture();
- String attImg=attData.getAttImg();
+ String userPicture =attData.getBasePath()+ attData.getUserPicture();
+ String attImg=attData.getBasePath()+attData.getAttImg();
// 使用专门为人脸识别考勤优化的相似度计算
double similarity = ImageSimilarityUtils.calculateFaceSimilarity(userPicture, attImg);
- if (similarity>=0.8) {
- // 相似度达标,增加考勤数据
- // TODO: 增加考勤数据逻辑
- // TODO: 增加考勤历史记录逻辑
-
- return AjaxResult.success("考勤成功,人脸匹配");
+ // 根据是否使用OpenCV调整阈值
+ // OpenCV场景下阈值为0.8,基础算法场景下阈值为0.75
+ double threshold = ImageSimilarityUtils.openCVLoaded ? 0.8 : 0.75;
+
+ if (similarity >= threshold) {
+ // 相似度达标,允许考勤
+ int cnt=attendanceUbiDataService.addMobiileAttendanceData(attData);
+ cnt+=proMobileAttendanceDataService.insertProMobileAttendanceData(attData);
+ return AjaxResult.success("考勤成功,人脸匹配 (相似度: " + String.format("%.2f", similarity) + ")");
} else {
// 相似度不达标,拒绝考勤
- return AjaxResult.error("考勤失败,人脸不匹配");
+ return AjaxResult.error("考勤失败,人脸不匹配 (相似度: " + String.format("%.2f", similarity) + ", 阈值: " + threshold + ")");
}
}
}
\ No newline at end of file
diff --git a/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/service/IAttendanceUbiDataService.java b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/service/IAttendanceUbiDataService.java
index 681c9684..ae191859 100644
--- a/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/service/IAttendanceUbiDataService.java
+++ b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/service/IAttendanceUbiDataService.java
@@ -7,6 +7,7 @@ import java.util.Map;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.yanzhu.manage.domain.AttendanceUbiData;
+import com.yanzhu.manage.domain.ProMobileAttendanceData;
import com.yanzhu.manage.domain.ProProjectInfoSubdeptsUsers;
/**
@@ -116,4 +117,9 @@ public interface IAttendanceUbiDataService
* @return
*/
List getRealAttendance(Long prjId);
+
+ /**
+ * 增加移动端考勤数据
+ */
+ int addMobiileAttendanceData(ProMobileAttendanceData attData);
}
diff --git a/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/service/impl/AttendanceUbiDataServiceImpl.java b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/service/impl/AttendanceUbiDataServiceImpl.java
index 021c7101..44d994db 100644
--- a/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/service/impl/AttendanceUbiDataServiceImpl.java
+++ b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/service/impl/AttendanceUbiDataServiceImpl.java
@@ -12,10 +12,12 @@ import com.yanzhu.common.core.utils.DateUtils;
import com.yanzhu.common.core.utils.StringUtils;
import com.yanzhu.common.security.utils.SecurityUtils;
import com.yanzhu.manage.domain.AttendanceUbiData;
+import com.yanzhu.manage.domain.ProMobileAttendanceData;
import com.yanzhu.manage.domain.ProProjectInfoSubdeptsUsers;
import com.yanzhu.manage.mapper.AttendanceUbiDataMapper;
import com.yanzhu.manage.mapper.ProProjectInfoSubdeptsUsersMapper;
import com.yanzhu.manage.service.IAttendanceUbiDataService;
+import com.yanzhu.manage.service.IProProjectInfoSubdeptsUsersService;
import com.yanzhu.system.mapper.SysDictDataMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -42,6 +44,8 @@ public class AttendanceUbiDataServiceImpl implements IAttendanceUbiDataService
@Autowired
private ProProjectInfoSubdeptsUsersMapper proProjectInfoSubdeptsUsersMapper;
+ @Autowired
+ private IProProjectInfoSubdeptsUsersService proProjectInfoSubdeptsUsersService;
/**
* 查询考勤管理
*
@@ -309,5 +313,49 @@ public class AttendanceUbiDataServiceImpl implements IAttendanceUbiDataService
return attendanceUbiDataMapper.getRealAttendance(prjId);
}
+ @Override
+ public int addMobiileAttendanceData(ProMobileAttendanceData attData) {
+ AttendanceUbiData attendance = new AttendanceUbiData();
+ ProProjectInfoSubdeptsUsers user=proProjectInfoSubdeptsUsersService.findProSubDeptsUserInfo(attData.getProjectId(),attData.getUserId());
+ if(user==null){
+ return 0;
+ }
+ attendance.setProjectId(attData.getProjectId());
+ attendance.setUserId(user.getUserId());
+ attendance.setIsDel(0L);
+ attendance.setComId(user.getComId());
+ attendance.setComName(user.getComName());
+ attendance.setProjectName(user.getProjectName());
+ attendance.setSubDeptId(user.getSubDeptId());
+ attendance.setSubDeptName(user.getSubDeptName());
+ attendance.setUserName(user.getUserName());
+ attendance.setSubDeptGroup(user.getSubDeptGroup());
+ attendance.setSubDeptName(user.getSubDeptName());
+ attendance.setCraftType(user.getCraftType());
+ attendance.setCraftPost(user.getCraftPost());
+ attendance.setDeviceNo("mobile");
+ if("in".equals(attData.getInOut())){
+ attendance.setInTime(attData.getAttDate());
+ attendance.setInPhoto(attData.getAttImg());
+ }else{
+ attendance.setOutTime(attData.getAttDate());
+ attendance.setOutPhoto(attData.getAttImg());
+ }
+ attendance.setCreateBy(SecurityContextHolder.getUserName());
+ attendance.setCreateTime(DateUtils.getNowDate());
+
+ AttendanceUbiData where = new AttendanceUbiData();
+ where.setProjectId(attData.getProjectId());
+ where.setUserId(attData.getUserId());
+ where.setInTime(attData.getAttDate());
+ List list=queryAttendaceInfo(where);
+ if(list.size()>0){
+ attendance.setId(list.get(0).getId());
+ return updateAttendanceUbiData(attendance);
+ }else{
+ return insertAttendanceUbiData(attendance);
+ }
+ }
+
}
diff --git a/yanzhu-ui-app/miniprogram/api/project.js b/yanzhu-ui-app/miniprogram/api/project.js
index 35961ae3..107f5ffb 100644
--- a/yanzhu-ui-app/miniprogram/api/project.js
+++ b/yanzhu-ui-app/miniprogram/api/project.js
@@ -482,3 +482,14 @@ export function getMobileAttendanceConfigById(id) {
method: "get",
});
}
+
+/**
+ * 移动端考勤
+ */
+export function mobileAttendance(data) {
+ return request({
+ url: "/manage/mobileAttendConfig/attendance",
+ method: "post",
+ data: data,
+ });
+}
diff --git a/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/add/index.js b/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/add/index.js
index 20928fc6..37580e07 100644
--- a/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/add/index.js
+++ b/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/add/index.js
@@ -2,9 +2,9 @@ import fmt from "../../../utils/date.js";
import { getToken, getUserInfo } from "../../../../utils/auth.js";
import { securityFileUpload } from "../../../../utils/request.js"; // 导入文件上传工具
const app = getApp();
-import { getMobileAttendanceConfigById } from "../../../../api/project.js";
+import { mobileAttendance } from "../../../../api/project.js";
import { calculateDistance } from "../../../../utils/location.js"; // 导入计算距离的工具函数
-
+import config from "../../../../config.js";
Page({
/**
* 页面的初始数据
@@ -224,7 +224,6 @@ Page({
});
},
doSave() {
- debugger;
if (!this.data.faceImage) {
app.toast("未获取到照片!");
return;
@@ -374,6 +373,16 @@ Page({
attDate: cfgData.attDate,
attImg: this.data.faceImageUrl,
cfgInfo: cfgData,
+ basePath: config.baseImgUrl,
};
+ console.log("考勤数据", postData);
+ mobileAttendance(postData).then((res) => {
+ if (res.code == 200) {
+ app.toast("考勤成功");
+ this.returnToPage();
+ } else {
+ app.toast("考勤失败: " + res.msg);
+ }
+ });
},
});
diff --git a/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/add/index.wxml b/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/add/index.wxml
index a6e058da..12d4030e 100644
--- a/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/add/index.wxml
+++ b/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/add/index.wxml
@@ -53,7 +53,7 @@
{{cfgData.attAddress}}
-
diff --git a/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/list/index.js b/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/list/index.js
index a307dff4..3665c4f8 100644
--- a/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/list/index.js
+++ b/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/list/index.js
@@ -49,7 +49,6 @@ Page({
* 获取用户当前位置
*/
getUserLocation() {
- debugger;
wx.getLocation({
type: "gcj02", // 使用国测局坐标
success: (res) => {
diff --git a/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/list/index.wxml b/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/list/index.wxml
index d5cd6c3e..aaec85c7 100644
--- a/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/list/index.wxml
+++ b/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/list/index.wxml
@@ -72,11 +72,6 @@
-
-
- 当前位置:
- {{item.attAddress}}
-
diff --git a/yanzhu-ui-vue3/src/views/bim/bimSetting/Viewpoint.vue b/yanzhu-ui-vue3/src/views/bim/bimSetting/Viewpoint.vue
index c627392f..34cd0ccf 100644
--- a/yanzhu-ui-vue3/src/views/bim/bimSetting/Viewpoint.vue
+++ b/yanzhu-ui-vue3/src/views/bim/bimSetting/Viewpoint.vue
@@ -276,7 +276,7 @@ export default {
}
});
},
- DelViewpoint(item, index) {debugger
+ DelViewpoint(item, index) {
let that = this;
ElMessageBox.confirm(`确定要删除漫游 “${item.name}” 吗?`, "提示", {
confirmButtonText: "确定",