import fmt from "../../../utils/date.js"; import { getToken, getUserInfo } from "../../../../utils/auth.js"; import { securityFileUpload } from "../../../../utils/request.js"; // 导入文件上传工具 const app = getApp(); import { mobileAttendance } from "../../../../api/project.js"; import { calculateDistance } from "../../../../utils/location.js"; // 导入计算距离的工具函数 import config from "../../../../config.js"; Page({ /** * 页面的初始数据 */ data: { projectUserInfo: {}, projectUserInfo: {}, projectId: "", projectName: "", initData: {}, type: "", cfgData: null, arrSel: "in", mapMarkers: [], // 地图标记 mapCircles: [], // 地图圆圈(用于显示考勤范围) faceImage: "", // 人脸识别图片 faceImageUrl: "", // 上传后的人脸图片URL }, /** * 生命周期函数--监听页面加载 */ onLoad(options) { if (!getToken()) { wx.redirectTo({ url: "../../../pages/login/login", }); } const proUserInfo = getUserInfo(); // 根据当前时间设置arrSel的值:14点前为in,14点后为out const now = new Date(); const arrSel = now.getHours() < 14 ? "in" : "out"; this.setData({ projectUserInfo: proUserInfo.projectUserInfo, projectId: app.globalData.useProjectId, projectName: app.globalData.useProjectName, initData: { id: app.globalData.useProjectId, text: app.globalData.useProjectName, }, type: options.type, arrSel: arrSel, }); if (options.id) { this.loadData(options.id); } else { app.toast("参数错误!"); this.returnToPage(); } //todo 14点前 arrSel=in,之后arrSel=out }, loadData(id) { try { let cfgData = wx.getStorageSync("editAttCfg"); cfgData.attDate = fmt(new Date()).format("YYYY-MM-DD HH:mm:ss"); if (cfgData) { this.setData({ cfgData: cfgData, }); // 初始化地图标记 this.initMapMarkers(cfgData); } else { app.toast("参数错误!"); this.returnToPage(); } } catch (e) { app.toast("参数错误!"); this.returnToPage(); } }, // 初始化地图标记 initMapMarkers(cfgData) { // 考勤地点标记 const markers = []; const circles = []; // 用户当前位置标记(如果有的话) if (cfgData.attLongitude && cfgData.attLatitude) { markers.push({ id: 1, longitude: cfgData.attLongitude, latitude: cfgData.attLatitude, title: cfgData.attAddress || "当前位置", iconPath: "/images/location-marker.png", // 使用项目中已有的图标文件 width: 30, height: 30, callout: { content: cfgData.attAddress || "当前位置", display: "ALWAYS", fontSize: 12, borderRadius: 5, padding: 5, }, }); } // 考勤地点标记和范围圆圈 if (cfgData.longitude && cfgData.latitude) { // 考勤地点标记 markers.push({ id: 2, longitude: cfgData.longitude, latitude: cfgData.latitude, title: cfgData.address || "考勤地点", iconPath: "/images/location-marker.png", // 使用项目中已有的图标文件 width: 30, height: 30, callout: { content: cfgData.address || "考勤地点", display: "ALWAYS", fontSize: 12, borderRadius: 5, padding: 5, }, }); // 考勤范围圆圈(如果设置了范围) if (cfgData.range) { circles.push({ id: 1, longitude: cfgData.longitude, latitude: cfgData.latitude, radius: cfgData.range, // 范围半径(米) strokeWidth: 2, color: "#FF0000", // 红色边框,符合规范 fillColor: "#FF000033", // 带透明度的红色填充,符合规范 }); } } this.setData({ mapMarkers: markers, mapCircles: circles, }); }, // 打开摄像头进行人脸识别 openCamera() { const that = this; wx.chooseMedia({ count: 1, mediaType: ["image"], sourceType: ["camera"], camera: "front", // 前置摄像头 success(res) { console.log("chooseMedia success", res); // 获取到图片临时路径 const tempImagePath = res.tempFiles[0].tempFilePath; console.log("tempImagePath", tempImagePath); // 在iPhone上可能需要特殊处理图片路径 that.setData( { faceImage: tempImagePath, }, () => { // setData完成后的回调 console.log("faceImage set successfully"); } ); // 这里可以添加人脸识别的逻辑 // 由于项目中没有现成的人脸识别API,这里只是演示如何获取图片 // 实际项目中可能需要调用后端的人脸识别接口 //that.performFaceRecognition(tempImagePath); }, fail(err) { console.error("打开摄像头失败", err); app.toast("打开摄像头失败,请重试"); }, }); }, // 执行人脸识别(模拟) performFaceRecognition() { let imagePath = this.data.faceImage; // 这里应该调用实际的人脸识别API // 由于项目中没有现成的人脸识别功能,这里只是模拟 app.toast("正在识别中..."); // 上传图片到服务器 this.uploadFaceImage(); // 模拟识别过程 setTimeout(() => { // 模拟识别成功 app.toast("人脸识别成功"); // 可以在这里设置识别成功的状态 this.setData({ isFaceRecognized: true, }); }, 2000); }, // 上传人脸图片到服务器 uploadFaceImage(cb) { let imagePath = this.data.faceImage; app.toast("正在上传图片..."); securityFileUpload(imagePath) .then((res) => { console.log("图片上传成功", res); if (res.code == 200) { app.toast("图片上传成功"); // 保存上传后的图片URL this.setData({ faceImageUrl: res.data.url, }); cb && cb(); } else { app.toast("图片上传失败: " + res.msg); } }) .catch((err) => { console.error("图片上传失败", err); app.toast("图片上传失败"); }); }, doSave() { if (!this.data.faceImage) { app.toast("未获取到照片!"); return; } // 获取当前位置并计算距离 this.getCurrentLocationAndCalculateDistance(); }, // 获取当前位置并计算距离 getCurrentLocationAndCalculateDistance() { wx.getLocation({ type: "gcj02", // 使用国测局坐标系 success: (res) => { const { longitude, latitude } = res; const cfgData = this.data.cfgData; // 使用现有的工具函数计算距离 const distance = calculateDistance( longitude, latitude, cfgData.longitude, cfgData.latitude ); // 检查是否超出考勤范围 if (distance > cfgData.range) { app.toast("超出考勤范围!"); return; } // 更新考勤数据的位置信息 this.setData( { "cfgData.attLongitude": longitude, "cfgData.attLatitude": latitude, }, () => { // 在数据更新完成后,更新地图上的用户位置标记 this.updateUserLocationMarker(longitude, latitude); } ); // 继续执行打卡操作 this.uploadFaceImage(() => { this.doSaveAttendance(); }); }, fail: (err) => { console.error("获取位置失败", err); // 检查是否是权限问题 if (err.errMsg && err.errMsg.includes("auth deny")) { app.toast("请开启位置权限后再试"); // 引导用户开启权限 wx.showModal({ title: "提示", content: "需要获取您的位置信息才能进行考勤打卡,请在设置中开启位置权限", showCancel: true, confirmText: "去设置", success: (res) => { if (res.confirm) { wx.openSetting({ success: (setting) => { if (setting.authSetting["scope.userLocation"]) { // 用户开启了权限,重新获取位置 this.getCurrentLocationAndCalculateDistance(); } }, }); } }, }); } else { app.toast("获取位置失败,请检查定位权限"); } }, }); }, // 更新用户位置标记 updateUserLocationMarker(longitude, latitude) { // 创建新的标记数组 let markers = [...this.data.mapMarkers]; // 查找是否已存在用户位置标记(id为1) let userMarkerIndex = markers.findIndex((marker) => marker.id === 1); const userMarker = { id: 1, longitude: longitude, latitude: latitude, title: "当前位置", iconPath: "/images/location-marker.png", width: 30, height: 30, callout: { content: "当前位置", display: "ALWAYS", fontSize: 12, borderRadius: 5, padding: 5, }, }; if (userMarkerIndex !== -1) { // 如果已存在用户位置标记,则更新它 markers[userMarkerIndex] = userMarker; } else { // 如果不存在用户位置标记,则添加它 markers.push(userMarker); } // 更新地图标记 this.setData({ mapMarkers: markers, }); }, onProjectSelect(e) { let projectId = e.detail.id; let projectName = e.detail.text; app.globalData.useProjectId = projectId; app.globalData.useProjectName = projectName; this.onLoad(); }, returnToPage() { wx.redirectTo({ url: "../list/index", }); }, doSelectArr(e) { this.setData({ arrSel: e.currentTarget.dataset.set, "cfgData.attDate": fmt(new Date()).format("YYYY-MM-DD HH:mm:ss"), }); }, doSaveAttendance() { let cfgData = this.data.cfgData; let postData = { userPicture: app.globalData.subDeptUserData.userPicture, userId: app.globalData.subDeptUserData.userId, projectId: app.globalData.useProjectId, cfgId: cfgData.id, inOut: this.data.arrSel, longitude: cfgData.attLongitude, latitude: cfgData.attLatitude, 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); } }); }, });