YNUtdPlatform/pages/realName/workAttendance/tempClock/index.vue

566 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page">
<u-navbar class="u-navbar" title="考勤打卡" placeholder @leftClick="leftClick" leftIconColor="#fff" bgColor="#00337A" :titleStyle="{ color: '#FFF', fontSize: '32rpx' }"/>
<scroll-view class="content" scroll-y="true">
<view class="view-box">
<view style="display: flex;flex-direction: column;padding: 20rpx;">
<text style="font-size: 24rpx;color: red;"></text>
<text style="font-size: 24rpx;color: red;">
1.临时人员只可打卡7天;
</text>
<text style="font-size: 24rpx;color: red;">
2. 临时人员不生成工资册;
</text>
<text style="font-size: 24rpx;color: red;">
3. 上下班打卡间隔2小时;
</text>
</view>
<view class="view-item">{{proName}}</view>
<!-- <view class="view-item">
<view>{{longitude}},{{latitude}}</view>
</view> -->
<view class="view-item">
<view class="button-box" style="margin-left: 20rpx;" @click="goList">临时人员名单</view>
<view class="button-box" style="margin-left: 60rpx;" @click="goOverList()">已超过七天人员名单</view>
</view>
<view class="view-item">
<view>{{timeStr}}</view>
<view class="button-box" style="margin-left: 60rpx;" @click="goList">打卡记录</view>
</view>
</view>
<view class="view-box">
<view class="title-view">
上班打卡
</view>
<view class="img-box" @click="handleAttendance(1)">
<view class="img-item upload-btn">
<image class="img" src="../../../../static/realName/tianjia-img.png" mode=""></image>
</view>
</view>
<view class="title-view">
下班打卡
</view>
<view class="img-box" @click="handleAttendance(2)">
<view class="img-item upload-btn">
<image class="img" src="../../../../static/realName/tianjia-img.png" mode=""></image>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
import { pathToBase64, base64ToPath } from 'image-tools';
import config from '@/config'
export default {
data() {
return {
userId:uni.getStorageSync('realNameUser').userId,
userName:uni.getStorageSync('realNameUser').userName,
idNumber:"",
proId:uni.getStorageSync('realNameUser').proId,
teamId:uni.getStorageSync('realNameUser').teamId,
teamList:[],//打卡点列表
userData:{},
proName:"",
rangeName:"",
longitude:"",
latitude:"",
timeStr:"",
isToWork:"",
isOffWork:"",
type:1,//1上班2下班
faceData:{},
photoPath:'',
attendanceImgUrl:'',
}
},
onLoad(option) {
this.getLocation();//获取定位
this.Time();//定时器
this.getPro()
// this.getWork()
// this.getTeamList()
},
onShow() {
},
methods: {
// 获取工程名称
getPro(){
let param={
id:this.proId,
subId:-1
}
uni.request({
url: config.realAppUrl + '/offLine/getPro',
method: 'post',
data: param,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: uni.getStorageSync('realNameToken')
},
success: res => {
res = res.data;
if(res.code==200){
console.log(res)
this.proName = res.data[0].abbreviation||"";
}
},
fail: err => {
console.log(err)
}
})
},
// 获取打卡点列表
getTeamList(){
let param={
teamId:this.teamId
}
uni.request({
url: config.realAppUrl + '/offLine/getSubTeam',
method: 'post',
data: param,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: uni.getStorageSync('realNameToken')
},
success: res => {
res = res.data;
if(res.code==200){
this.teamList=res.data;
if(this.teamList.length>0){
this.teamList.forEach((item,index)=>{
let distance=this.getDistance(this.latitude,this.longitude,item.lat,item.lon)
// console.log(distance)
item.distance=distance;
})
this.teamList.sort((a, b) => { return a.distance - b.distance; });
this.rangeName=this.teamList[0].rangeName;
}
}
},
fail: err => {
console.log(err)
}
})
},
// 定时器
Time() {
setTimeout(()=>{
this.getLocation();//获取定位
},1000)
this.timme = setInterval(() => {
this.timeStr=this.timeFormat(null,'yyyy-mm-dd hh:MM:ss')
}, 1000);
},
//获取定位
getLocation(){
uni.getLocation({
type: "gcj02", //默认为 wgs84 返回 gps 坐标
isHighAccuracy: true, // 开启高精度定位
success: e => {
this.longitude=e.longitude;
this.latitude=e.latitude;
},fail:e=>{
}
});
},
//查看列表
goList(){
uni.navigateTo({
url: `/pages/realName/workAttendance/tempClock/tempPeopleList`
})
},
goOverList(){
uni.navigateTo({
url: `/pages/realName/workAttendance/tempClock/tempPeopleList?isOver=1`
})
},
//计算距离
getDistance(lat1, lon1, lat2, lon2) {
const R = 6371; // 地球半径,单位为千米
const toRadians = (degree) => degree * Math.PI / 180; // 角度转弧度
const deltaLat = toRadians(lat2 - lat1); // 纬度差
const deltaLon = toRadians(lon2 - lon1); // 经度差
const a = Math.sin(deltaLat / 2) ** 2 +
Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
Math.sin(deltaLon / 2) ** 2;
const c = 2 * Math.asin(Math.sqrt(a));
const distance = R * c; // 距离,单位为千米
return distance.toFixed(2);
},
//打卡
handleAttendance(type){
this.type=type;
this.getLocation()//重新获取定位
// var index = this.teamList.findIndex(item => {return item.distance < 6})
// if(index<0){//存在-在考勤范围内
// uni.$u.toast('不在考勤范围内!');
// }
this.distinguish()//打开人脸识别
},
//获取人员信息(打卡时间)
getWork(){
let param={
proId:this.proId
}
uni.request({
url: config.realAppUrl + '/BasePerson/downloadTemporaryWorkPerson',
method: 'post',
data: param,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: uni.getStorageSync('realNameToken')
},
success: res => {
res = res.data;
if(res.code==200){
console.log(res)
if(res.data.length>0){
let userIndex = res.data.findIndex(v=>v.idNumber==this.idNumber)
console.log(userIndex)
if(userIndex>-1){
this.userData=res.data[userIndex]
console.log(this.userData)
if(this.userData.isToWork!="0"){
this.isToWork=this.userData.isToWork;
}
if(this.userData.isOffWork!="0"){
this.isOffWork=this.userData.isOffWork;
}
this.proId = this.userData.proId
let costTime=this.getTimeDiff(this.userData.isToWork,this.timeStr);
if(this.type==2&&this.userData.isToWork==0){
uni.$u.toast('还未打上班卡!');
}
// else if(this.type==1&&this.userData.isToWork!=0){
// uni.$u.toast('已打过上班卡!');
// }else if(this.type==2&&this.userData.isOffWork!=0){
// uni.$u.toast('已打过下班卡!');
// }
else if(this.type==2&&costTime<2){
uni.$u.toast('上下班打卡间隔2小时');
}else if(this.userData.lightStatus==0&&this.userData.attDayNum>7){
uni.$u.toast('红灯人员只能打7天卡');
}else if(this.userData.isFurloughPerson==1){
uni.$u.toast('暂退人员无法打卡!');
}else if(this.userData.workerType==1||this.userData.workerType==2){
uni.$u.toast('只有临时人员可在当前页面打卡!');
}else{
this.uploadAttendance()
}
}else{
uni.$u.toast('打卡人员不存在当前工程!');
}
}else{
uni.$u.toast('不存在临时人员!');
}
}
},
fail: err => {
console.log(err)
}
})
},
//人脸识别采集
distinguish(){
console.log('人脸识别采集')
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['camera'],
success: res => {
console.log('?? ~ res-拍照:', res)
this.imgToBase64(res.tempFilePaths[0]).then(base64 => {
// console.log(base64)
//上传考勤图片
uni.uploadFile({
url: config.realFileUrl+`file/upload`, //服务器地址
fileType:"image",//ZFB必填,不然报错
filePath: res.tempFilePaths[0],//这个就是我们上面拍照返回或者先中照片返回的数组
name: "imgFile",
formData: {
photoType:'attendance',
},
success: (uploadFileRes) => {
console.log(uploadFileRes)
if(uploadFileRes.statusCode==200){
this.photoPath=JSON.parse(uploadFileRes.data).data.url;
}else{
uni.$u.toast('上传失败');
}
},
fail: err => {
uni.$u.toast('上传失败');
console.log(err)
}
});
//人脸验证
uni.uploadFile({
url: config.realFileUrl+'file/getFaceRecognition', //服务器地址
fileType:"image",//ZFB必填,不然报错
filePath: res.tempFilePaths[0],//这个就是我们上面拍照返回或者先中照片返回的数组
formData: {
file:base64,
photoType:'face',
},
success: (uploadFileRes) => {
console.log(uploadFileRes)
if(uploadFileRes.statusCode==200){
uploadFileRes=JSON.parse(uploadFileRes.data)
console.log(uploadFileRes)
if(uploadFileRes.code==200){
if(uploadFileRes.data.face){
this.faceData=JSON.parse(uploadFileRes.data.personData)
if(this.faceData){
this.idNumber=this.faceData.idNumber;
this.getWork()
this.userName=this.faceData.name;
// }else{
// uni.$u.toast('不是本人!');
// }
}else{
uni.$u.toast('识别失败');
}
}else{
uni.$u.toast(uploadFileRes.msg);
}
}else{
uni.$u.toast(uploadFileRes.msg);
}
}else{
uni.$u.toast('识别失败');
}
},
fail: err => {
uni.$u.toast('识别失败');
console.log(err)
}
});
})
},
fail: err => {
console.log('?? ~ err:', err)
}
})
},
//打卡接口
uploadAttendance(){
let param={
"name": this.userName,
"idNumber": this.idNumber,
"proId": this.proId,
"imei": this.idNumber,
"userId": this.userId,
"currentDay": this.timeFormat(null,'yyyy-mm-dd'),
"addTime": this.timeFormat(null,'yyyy-mm-dd hh:MM:ss'),
"photoPath": this.photoPath,
"uploadType": this.type,
"lon": this.longitude,
"lat": this.latitude,
}
console.log(param)
uni.request({
url: config.realAppUrl + '/BasePerson/uploadFaceAttendance',
method: 'post',
data: param,
header: {
'Content-Type': 'application/json',
Authorization: uni.getStorageSync('realNameToken')
},
success: res => {
console.log(res)
res = res.data;
if(res.code==200){
uni.$u.toast('打卡成功!');
}else{
uni.$u.toast('打卡失败!');
}
},
fail: err => {
uni.$u.toast('打卡失败!');
console.log(err)
}
})
},
goDayPlan(){//准入信息查询
uni.navigateTo({
url: `/pages/realName/workbench/dayPlan/index`
})
},
leftClick() {
console.log('返回')
uni.navigateBack({
delta: 1 // 返回
});
},
imgToBase64(data) {
return new Promise((resolve, reject) => {
pathToBase64(data)
.then(base64 => {
resolve(base64)
})
.catch(error => {
console.error(error)
reject(error)
})
})
},
timeFormat(dateTime = null, formatStr = 'yyyy-mm-dd') {
let date
// 若传入时间为假值,则取当前时间
if (!dateTime) {
date = new Date()
}
// 若为unix秒时间戳则转为毫秒时间戳逻辑有点奇怪但不敢改以保证历史兼容
else if (/^\d{10}$/.test(dateTime?.toString().trim())) {
date = new Date(dateTime * 1000)
}
// 若用户传入字符串格式时间戳new Date无法解析需做兼容
else if (typeof dateTime === 'string' && /^\d+$/.test(dateTime.trim())) {
date = new Date(Number(dateTime))
}
// 处理平台性差异在Safari/Webkit中new Date仅支持/作为分割符的字符串时间
// 处理 '2022-07-10 01:02:03',跳过 '2022-07-10T01:02:03'
else if (typeof dateTime === 'string' && dateTime.includes('-') && !dateTime.includes('T')) {
date = new Date(dateTime.replace(/-/g, '/'))
}
// 其他都认为符合 RFC 2822 规范
else {
date = new Date(dateTime)
}
const timeSource = {
'y': date.getFullYear().toString(), // 年
'm': (date.getMonth() + 1).toString().padStart(2, '0'), // 月
'd': date.getDate().toString().padStart(2, '0'), // 日
'h': date.getHours().toString().padStart(2, '0'), // 时
'M': date.getMinutes().toString().padStart(2, '0'), // 分
's': date.getSeconds().toString().padStart(2, '0') // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
}
for (const key in timeSource) {
const [ret] = new RegExp(`${key}+`).exec(formatStr) || []
if (ret) {
// 年可能只需展示两位
const beginIndex = key === 'y' && ret.length === 2 ? 2 : 0
formatStr = formatStr.replace(ret, timeSource[key].slice(beginIndex))
}
}
return formatStr
},
getTimeDiff(startTime, endTime) {
var start = new Date(startTime);
var end = new Date(endTime);
var diff = end.getTime() - start.getTime(); // 返回时间差的毫秒数
// 转换为天、小时、分钟和秒
// var days = Math.floor(diff / (1000 * 60 * 60 * 24));
var hours = ((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)).toFixed(2);
// var minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
// var seconds = Math.floor((diff % (1000 * 60)) / 1000);
return hours;
}
},
destroyed() {
clearInterval(this.timme);
}
}
</script>
<style lang="scss">
.page {
width: 100vw;
height: 100vh;
background-color: #EFEFEF;
box-sizing: border-box;
// padding: 0 20px;
.content{
width: 100%;
height: 90vh;
margin-top: 20rpx;
padding-bottom: 80rpx;
background-color: #EFEFEF;
}
.view-box{
width: 94%;
margin: 20rpx auto;
background-color: #FFF;
border-radius: 10rpx;
padding-top: 20rpx;
.title-view{
font-weight: 600;
color: #757575;
margin-left: 20rpx;
}
}
.view-item{
width: 94%;
margin: 0rpx auto;
padding:20rpx;
display: flex;
align-items: center;
border-bottom: 1rpx solid #EFEFEF;
font-size: 28rpx;
font-weight: bold;
color: #757575;
}
.button-box{
padding: 15rpx 30rpx;
border: 1rpx solid #00337A;
border-radius: 10rpx;
color: #00337A;
margin-left: 20rpx;
}
.img-box{
width: 94%;
height: auto;
margin: 0rpx auto;
padding:20rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border-bottom: 1rpx solid #EFEFEF;
.img-item {
width: 200upx;
height: 200upx;
border: 1px solid #ddd;
position: relative;
box-sizing: border-box;
background: #eee;
.img {
display: block;
width: 100%;
height: 100%;
}
}
.upload-btn {
display: flex;
justify-content: center;
align-items: center;
.img {
width: 60upx;
height: 60upx;
margin: unset;
}
}
}
}
</style>