436 lines
11 KiB
Vue
436 lines
11 KiB
Vue
<template>
|
||
<div class="page-body">
|
||
<div >
|
||
<div class="uni-flex today" >
|
||
<image src="/static/images/puching/time.png" mode="aspectFit" class="uni-icon-timefill"></image>
|
||
<text class="date-text ml-1">{{signin.day}} {{$util.cutDate(nowDay,"YYYY年MM月DD日")}}</text>
|
||
</div>
|
||
<div class="company-title">我的位置:{{signin.nowAddress}}</div>
|
||
<div class="map-box" v-if="workLocale.ClockLat">
|
||
<map style="width: 100%; height: 200rpx;" id="myMap"
|
||
:latitude="workLocale.ClockLat" :longitude="workLocale.ClockLng" show-location="true"
|
||
:markers="mudi" :circles="circles"></map>
|
||
</div>
|
||
<div>
|
||
<div class="punching-date-box">
|
||
<div class="title"><div class="circle" :class="{'now': workLocale.ClockType==1000}"></div>上班时间 <span class="ml-1" v-if="workLocale"> {{workLocale.AMStarttime}}</span></div>
|
||
<!-- 是否是上午打卡 -->
|
||
<div class="date-text" v-if="workLocale.isAmclock"> {{pageMsg ? pageMsg.ClockIn+' 已打卡' : '未打卡'}}</div>
|
||
<div class="date-text" v-else-if="pageMsg && pageMsg.ClockIn">{{pageMsg.ClockIn}} 已打卡<span class="clockState" v-if="pageMsg.ClockInResult!==1000">{{pageMsg.ClockInResultText}}</span></div>
|
||
<div class="date-text" v-else>缺卡</div>
|
||
</div>
|
||
<div class="punching-date-box" v-if="!workLocale.isAmclock">
|
||
<div class="title"><div class="circle" :class="{'now': workLocale.ClockType==2000}"></div>下班时间 <span class="ml-1" v-if="workLocale">{{workLocale.PMEndtime}}</span></div>
|
||
<div class="date-text" v-if="pageMsg && pageMsg.ClockOut">{{pageMsg.ClockOut}} 已打卡<span class="clockState" v-if="pageMsg.ClockOutResult!==1000"> {{ pageMsg.ClockOutResultText}}</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="btn-box" >
|
||
|
||
<div class="btn" :class="{'bg-gray':!signin.isAble}" @click="takePhoto">
|
||
<div class="fs-14">{{!workLocale.isAmclock ? '下班打卡': '上班打卡'}}</div>
|
||
<div class="fs-52">{{signin.time}}</div>
|
||
</div>
|
||
<div class="uni-flex able-text">
|
||
<image src="/static/images/puching/in.png" mode="aspectFit" v-if="signin.isAble"></image>
|
||
<image src="/static/images/puching/out.png" mode="aspectFit" v-else></image>
|
||
<span>{{signin.isAble ? '已进入考勤范围' : '当前位置超出打卡范围'}}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<uniPopup type="middle" :show="showPop">
|
||
<div class="pop-body">
|
||
<image src="/static/images/puching/succes.png" mode="aspectFill"></image>
|
||
<div class="tip-time">{{clockDate}}</div>
|
||
<div class="tip-text">打卡成功!</div>
|
||
<div class="pop-btn" @click="showPop=!showPop">知道了</div>
|
||
</div>
|
||
</uniPopup>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import uniPopup from '@/components/uni-popup'
|
||
// import { mapMutations } from 'vuex';
|
||
|
||
export default{
|
||
data(){
|
||
const nowday = this.$util.cutDate(new Date())
|
||
return {
|
||
loading: true,
|
||
clockDate:'',
|
||
nowDay: nowday,
|
||
mudi: [],
|
||
circles: [{
|
||
latitude: 37.775006,
|
||
longitude: 112.616312,
|
||
color:"#b0d0e7",
|
||
fillColor: "#b0d0e730",
|
||
strokeWidth: 1,
|
||
radius: 100
|
||
}],
|
||
signinTime:'',
|
||
signin:{
|
||
time:'',
|
||
nowAddress:'',
|
||
day: '',
|
||
latitude:'',
|
||
longitude: '',
|
||
isAble:false
|
||
},
|
||
pageMsg: null,
|
||
showPop: false,
|
||
mapCtx: null,
|
||
workLocale: null,
|
||
userPhoto: '' //用户打卡头像
|
||
}
|
||
},
|
||
// computed:{
|
||
// ...mapState({
|
||
// 'userPhoto':(state)=>{return state.userPhoto}
|
||
// })
|
||
// },
|
||
components:{
|
||
uniPopup
|
||
},
|
||
methods: {
|
||
// ...mapMutations(['setPhoto']),
|
||
getLocation(){
|
||
let _this = this
|
||
uni.getLocation({
|
||
type: 'gcj02', //返回可以用于uni.openLocation的经纬度
|
||
altitude: true, // 高精度定位
|
||
success: function (res) {
|
||
_this.signin.latitude = res.latitude;
|
||
_this.signin.longitude = res.longitude;
|
||
const latitude = res.latitude
|
||
const longitude = res.longitude
|
||
let { ClockLng,ClockLat } = _this.workLocale
|
||
|
||
_this.$util.calculateDistance(
|
||
{latitude:latitude, longitude:longitude},
|
||
{latitude: ClockLat, longitude: ClockLng})
|
||
.then(data => {
|
||
let distance = data.result.elements[0].distance
|
||
_this.signin.isAble = (distance!=-1 && distance<100) ? true :false
|
||
})
|
||
wx.request({
|
||
url: `https://apis.map.qq.com/ws/geocoder/v1/?location=${latitude},${longitude}&key=SVKBZ-P6QCJ-NH7F7-KOPJW-CBNEV-FUBRT`,
|
||
success: res => {
|
||
_this.signin.nowAddress = res.data.result.address
|
||
}
|
||
})
|
||
}
|
||
})
|
||
},
|
||
// 获取当前时间时分秒
|
||
getTime (time) {
|
||
time = time ? new Date(time) : new Date()
|
||
this.signin.time = this.$util.cutDate(time,'hh:mm:ss')
|
||
},
|
||
getDay (){
|
||
|
||
var a = new Array("日", "一", "二", "三", "四", "五", "六");
|
||
var week = new Date().getDay();
|
||
this.signin.day = "星期"+ a[week];
|
||
},
|
||
getWorkLocale(){ //获取 考勤地址、坐标,打卡范围,上、下班时间
|
||
let _this= this
|
||
let nowDay = this.nowDay
|
||
this.$request.$get('GetWorkLocale',{}).then(res =>{
|
||
if(res.Result_Code==100) {
|
||
if( res.Data){
|
||
let msg = res.Data
|
||
let [ClockLng,ClockLat] = _this.$util.bMapToQQMap(msg.ClockLng,msg.ClockLat)
|
||
msg.ClockLng =ClockLng
|
||
msg.ClockLat = ClockLat
|
||
_this.mudi = [{
|
||
id: "sx1",
|
||
latitude: ClockLat,
|
||
longitude: ClockLng,
|
||
title: msg.ClockAddress,
|
||
}]
|
||
|
||
_this.circles[0].latitude = ClockLat
|
||
_this.circles[0].longitude = ClockLng
|
||
_this.circles[0].radius = msg.ClockRange
|
||
|
||
let am = new Date(nowDay+' '+msg.AMEndtime+':00')
|
||
msg.isAmclock = am.getTime()-(new Date()).getTime() >0 ? true: false
|
||
_this.workLocale = msg
|
||
_this.loading = false
|
||
_this.getLocation()
|
||
}
|
||
|
||
}else {
|
||
uni.showModal({
|
||
title:'温馨提示',
|
||
content: res.Result_Desc,
|
||
showCancel:false
|
||
})
|
||
}
|
||
})
|
||
},
|
||
getMsg(){ // 更新用户当前打卡时间
|
||
let _this= this
|
||
let nowDay = this.nowDay
|
||
this.$request.$get('GetWorkTimeRecord',{
|
||
startDate: nowDay,
|
||
endDate: nowDay
|
||
}).then(res =>{
|
||
if(res.Result_Code==100) {
|
||
if( res.Data.List.length>0){
|
||
let msg = res.Data.List[0]
|
||
_this.pageMsg = msg
|
||
|
||
}
|
||
|
||
}
|
||
})
|
||
},
|
||
faceClock(){ // 提交打卡
|
||
let _this= this
|
||
let location = this.signin
|
||
|
||
if(!this.signin.isAble) return
|
||
_this.signinTime = this.signin.time
|
||
uni.showLoading({
|
||
title: "正在识别人脸,请稍后",
|
||
mask:true,
|
||
})
|
||
this.$request.$post('FaceClock',{
|
||
clockLat: location.latitude,
|
||
clockLng: location.longitude,
|
||
photo: this.userPhoto || ''
|
||
}).then(res =>{
|
||
_this.loading = false
|
||
|
||
uni.hideLoading()
|
||
if(res.Result_Code==100) {
|
||
_this.clockDate = res.Data.ClockDate
|
||
_this.getMsg()
|
||
_this.showPop = true
|
||
|
||
}else{
|
||
uni.showModal({
|
||
content:'打卡失败:'+res.Result_Desc
|
||
})
|
||
}
|
||
_this.userPhoto=null
|
||
})
|
||
},
|
||
clearTime (){
|
||
clearInterval(this.setTime)
|
||
this.setTime = null
|
||
},
|
||
takePhoto() { // 跳转页面拍照
|
||
let _this = this
|
||
if(!this.signin.isAble) return // 是否可以打卡
|
||
if(this.loading ) return // 是否正在上传
|
||
|
||
uni.navigateTo({
|
||
url:'/pages/additionalFeatures/takePhoto'
|
||
})
|
||
},
|
||
photoTobase64(photoPath){ // 把图片转为base64
|
||
|
||
let _this= this
|
||
uni.getFileSystemManager().readFile({
|
||
filePath: photoPath, //选择图片返回的相对路径
|
||
encoding: 'base64', //编码格式
|
||
success: res => { //
|
||
let base64 = res.data.replace(/\+/ig,'%2B') //不加上这串字符,在页面无法显示的哦
|
||
|
||
_this.userPhoto = base64
|
||
_this.faceClock()
|
||
}
|
||
})
|
||
|
||
}
|
||
},
|
||
onLoad() {
|
||
let _this = this
|
||
this.getWorkLocale()
|
||
|
||
_this.setTime = setInterval(function(){_this.getTime()},1000)
|
||
_this.getMsg()
|
||
uni.$on('addUserPhoto',function(data){ // 监听打卡拍照的数据,接收拍照的照片地址
|
||
_this.photoTobase64(data)
|
||
// console.log(data)
|
||
// uni.$off('addUserPhoto')
|
||
})
|
||
},
|
||
onPullDownRefresh() {
|
||
let _this = this
|
||
_this.getLocation()
|
||
|
||
setTimeout(function() {
|
||
uni.stopPullDownRefresh()
|
||
|
||
}, 1000)
|
||
},
|
||
|
||
onUnload() {
|
||
// console.log(1)
|
||
uni.$off('addUserPhoto')
|
||
this.clearTime()
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.fs-14 {
|
||
font-size: 28rpx;
|
||
}
|
||
.fs-52 {
|
||
font-size: 52rpx;
|
||
}
|
||
.ml-1 {
|
||
margin-left: 4rpx;
|
||
}
|
||
.uni-icon {
|
||
font-size: 28rpx;
|
||
}
|
||
.uni-icon-timefill {
|
||
color: #CCCCCC;
|
||
width: 26rpx;
|
||
height: 26rpx;
|
||
}
|
||
.page-body {
|
||
padding: 0 24rpx;
|
||
background-color: #fff;
|
||
height: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
.today {
|
||
padding: 20rpx 0;
|
||
align-items: center;
|
||
}
|
||
.date-text {
|
||
color: #A3A3A3;
|
||
|
||
font-size: 22rpx;
|
||
/* line-height: 50rpx; */
|
||
/* margin-left: 8rpx; */
|
||
}
|
||
.company-title {
|
||
font-size: 28rpx;
|
||
line-height: 1.5;
|
||
font-weight: bolder;
|
||
padding-top: 32rpx;
|
||
padding-bottom: 20rpx;
|
||
border-top: 2rpx solid #edeef2;
|
||
}
|
||
.map-box {
|
||
margin-bottom: 40rpx;
|
||
}
|
||
.punching-date-box {
|
||
padding-left: 30rpx;
|
||
position: relative;
|
||
}
|
||
.punching-date-box:nth-child(2)::before {
|
||
content: '';
|
||
position: absolute;
|
||
height: 190rpx;
|
||
width: 2rpx;
|
||
display: block;
|
||
background-color: #e0e0e0;
|
||
top: -172rpx;
|
||
left: 36rpx;
|
||
z-index: 0;
|
||
}
|
||
.punching-date-box + .punching-date-box {
|
||
margin-top: 96rpx;
|
||
}
|
||
.punching-date-box .circle {
|
||
background-color: #b2b2b2;
|
||
width: 16rpx;
|
||
height: 16rpx;
|
||
border-radius: 50%;
|
||
margin-right: 8rpx;
|
||
}
|
||
.punching-date-box .circle.now {
|
||
background-color: #57AAEE;
|
||
}
|
||
.punching-date-box .title {
|
||
font-size: 28rpx;
|
||
color: #9EA2A4;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.punching-date-box .clockState {
|
||
color: #FF8556;
|
||
margin-left: 12rpx;
|
||
font-size: 24rpx;
|
||
font-weight: 700;
|
||
}
|
||
.punching-date-box .date-text {
|
||
color: #353638;
|
||
font-size: 30rpx;
|
||
padding-left: 30rpx;
|
||
line-height: 60rpx;
|
||
}
|
||
.btn-box {
|
||
margin-top: 80rpx;
|
||
}
|
||
.btn {
|
||
border-radius: 50%;
|
||
margin: 0 auto;
|
||
width: 252rpx;
|
||
height: 252rpx;
|
||
color: #fff;
|
||
text-align: center;
|
||
padding-top: 42rpx;
|
||
background: linear-gradient(#65bef9 0%, #50a0e8 100%);
|
||
box-sizing: border-box;
|
||
}
|
||
.bg-gray.btn {
|
||
background:linear-gradient(#cdd4d8 0%, #ADB2BF 100%);
|
||
}
|
||
.able-text {
|
||
color: #8B8D8E;
|
||
font-size: 22rpx;
|
||
margin-top: 32rpx;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
.able-text image {
|
||
width: 24rpx;
|
||
height: 24rpx;
|
||
margin-right: 8rpx;
|
||
}
|
||
.pop-body {
|
||
height: 664rpx;
|
||
width: 564rpx;
|
||
position: relative;
|
||
}
|
||
.pop-body image {
|
||
width: 497rpx;
|
||
height: 363rpx;
|
||
position: absolute;
|
||
top: -46px;
|
||
transform: translateX(-48%);
|
||
margin: 0 50%;
|
||
}
|
||
.tip-text {
|
||
|
||
font-size: 46rpx;
|
||
text-align: center;
|
||
color: #7B95A9;
|
||
}
|
||
.tip-time {
|
||
text-align: center;
|
||
color: #5EB4F3;
|
||
font-size: 72rpx;
|
||
margin-top: 260rpx;
|
||
}
|
||
.pop-btn {
|
||
border-top: 2rpx solid #ececec;
|
||
font-size: 28rpx;
|
||
height: 90rpx;
|
||
line-height: 90rpx;
|
||
text-align: center;
|
||
color: #56A8ED;
|
||
margin-top: 120rpx;
|
||
}
|
||
</style>
|