YZProjectCloud/yanzhu-ui-app/miniprogram/pageage/mobile_attendance/attendance/add/index.js

400 lines
11 KiB
JavaScript
Raw Normal View History

2025-09-03 15:36:22 +08:00
import fmt from "../../../utils/date.js";
import { getToken, getUserInfo } from "../../../../utils/auth.js";
2025-09-03 15:36:22 +08:00
import { securityFileUpload } from "../../../../utils/request.js"; // 导入文件上传工具
const app = getApp();
2025-09-04 17:46:13 +08:00
import { mobileAttendance } from "../../../../api/project.js";
2025-09-03 15:36:22 +08:00
import { calculateDistance } from "../../../../utils/location.js"; // 导入计算距离的工具函数
2025-09-04 17:46:13 +08:00
import config from "../../../../config.js";
Page({
/**
* 页面的初始数据
*/
data: {
projectUserInfo: {},
projectUserInfo: {},
projectId: "",
projectName: "",
initData: {},
type: "",
cfgData: null,
2025-09-02 17:55:02 +08:00
arrSel: "in",
2025-09-03 15:36:22 +08:00
mapMarkers: [], // 地图标记
mapCircles: [], // 地图圆圈(用于显示考勤范围)
faceImage: "", // 人脸识别图片
faceImageUrl: "", // 上传后的人脸图片URL
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
if (!getToken()) {
wx.redirectTo({
url: "../../../pages/login/login",
});
}
const proUserInfo = getUserInfo();
2025-09-02 17:55:02 +08:00
// 根据当前时间设置arrSel的值14点前为in14点后为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,
2025-09-02 17:55:02 +08:00
arrSel: arrSel,
});
if (options.id) {
this.loadData(options.id);
} else {
app.toast("参数错误!");
this.returnToPage();
}
2025-09-02 17:55:02 +08:00
//todo 14点前 arrSel=in,之后arrSel=out
},
loadData(id) {
2025-09-02 17:55:02 +08:00
try {
let cfgData = wx.getStorageSync("editAttCfg");
2025-09-03 15:36:22 +08:00
cfgData.attDate = fmt(new Date()).format("YYYY-MM-DD HH:mm:ss");
2025-09-02 17:55:02 +08:00
if (cfgData) {
this.setData({
2025-09-02 17:55:02 +08:00
cfgData: cfgData,
});
2025-09-03 15:36:22 +08:00
// 初始化地图标记
this.initMapMarkers(cfgData);
} else {
app.toast("参数错误!");
this.returnToPage();
}
2025-09-02 17:55:02 +08:00
} catch (e) {
app.toast("参数错误!");
this.returnToPage();
}
},
2025-09-03 15:36:22 +08:00
// 初始化地图标记
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(() => {
2025-09-03 17:30:23 +08:00
this.doSaveAttendance();
2025-09-03 15:36:22 +08:00
});
},
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);
2025-09-03 15:36:22 +08:00
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",
});
},
2025-09-03 15:36:22 +08:00
doSelectArr(e) {
this.setData({
arrSel: e.currentTarget.dataset.set,
"cfgData.attDate": fmt(new Date()).format("YYYY-MM-DD HH:mm:ss"),
});
},
2025-09-03 17:30:23 +08:00
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,
2025-09-04 17:46:13 +08:00
basePath: config.baseImgUrl,
2025-09-03 17:30:23 +08:00
};
2025-09-04 17:46:13 +08:00
console.log("考勤数据", postData);
mobileAttendance(postData).then((res) => {
if (res.code == 200) {
app.toast("考勤成功");
this.returnToPage();
} else {
// 显示确认框,提供更友好的错误提示
wx.showModal({
title: "考勤失败",
content: res.msg || "考勤提交失败,请稍后重试",
showCancel: false, // 只显示确定按钮
confirmColor: "#ff0000", // 深色确认按钮
confirmText: "确定",
success: function (res) {
// 用户点击确定按钮后返回考勤列表页面
this.returnToPage();
}.bind(this),
});
2025-09-04 17:46:13 +08:00
}
});
2025-09-03 17:30:23 +08:00
},
});