380 lines
11 KiB
JavaScript
380 lines
11 KiB
JavaScript
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 { calculateDistance } from "../../../../utils/location.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() {
|
||
debugger;
|
||
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,
|
||
};
|
||
},
|
||
});
|