uniapp实现打卡功能
记录一下,已备不时之需
实现思路(核心):
1.页面加载调用 uni.getLocation接口 获取当前位置(经纬度)
2.调用uni.chooseLocation接口选择打卡地点,然后计算两个经纬度相差的距离,距离在设定的检查范围内,则视为打卡成功。
3.保存打卡信息。
<template>
<view class="container">
<privacy :showPrivacy="true" />
<view class="head">
<view class="head-left">拜访对象</view>
<view class="head-right">
<u-search placeholder="请选择拜访对象" v-model="searchName" actionText="选择" :animation="false"
@custom='searchClick' @search='searchClick'></u-search>
</view>
</view>
<view class="body">
<view class="imgView" @click="checkIn">
<view class="daka-text">{{countdown}}</view>
<view class="daka-tips">请在规定时间内完成打卡</view>
<image class="dakaImg" :src="$previewImage('uniapp/business/static/daka.png')" mode="aspectFit"></image>
</view>
<view class="addr">
<image class="addr-img" :src="$previewImage('uniapp/business/static/ads.png')" mode="aspectFit">
<view class="addr-text" @click="getChooseLocation">{{name}}</view>
</view>
</view>
<view class="foot">
<view class="common_btn">
<u-button color="#ff3f2a" shape="circle" text="返回" @click="goBack"></u-button>
</view>
<u-picker :show="pickerShow" :columns="columns" @cancel="pickerShow = false" @confirm="confirm"
keyName="name"></u-picker>
</view>
</view>
</template>
<script>
export default {
data() {
return {
totalSeconds: 180,
countdown: '打卡',
timer: null,
pickerShow: false,
columns: [],
checkDistance: 1000,
locationLatitude: null,
locationLongitude: null,
chooseLatitude: null,
chooseLongitude: null,
address: null,
name: "请选择地址",
checkStatus: true,
btnText: "打卡",
searchName: "",
objectId: null,
objectName: null,
objectType: null,
}
},
onReady() {
},
onShow() {
this.startCountdown();
},
onReachBottom() {
},
onLoad(option) {
wx.getPrivacySetting({
success: res => {
console.log(
res
)
if (res.needAuthorization) {
this.setData({
showPrivacy: true
})
} else {
}
},
fail: () => {},
complete: () => {}
})
this.getLocation();
},
onUnload(e) {
},
methods: {
loadingColumns() {
let that = this;
this.$request.request({
url: "/crmClockIn/getVisitObject",
data: {
userId: uni.getStorageSync('user').id,
name: this.searchName
},
method: "POST"
}).then(res => {
if (res.errorCode == 0) {
that.columns = [res.data];
that.pickerShow = true;
}
})
},
confirm(e) {
let value = e.value[0];
if (value) {
this.objectId = value.id;
this.objectName = value.name;
this.objectType = value.type;
this.searchName = value.name;
}
this.pickerShow = false;
},
getDistance(lat1, lng1, lat2, lng2) {
lat1 = lat1 || 0;
lng1 = lng1 || 0;
lat2 = lat2 || 0;
lng2 = lng2 || 0;
var rad1 = lat1 * Math.PI / 180.0;
var rad2 = lat2 * Math.PI / 180.0;
var a = rad1 - rad2;
var b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
var r = 6378137;
var distance = r * 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(rad1) * Math.cos(rad2) *
Math.pow(Math.sin(b / 2), 2)));
return distance;
},
getLocation() {
console.log("默认当前位置");
let that = this;
uni.getLocation({
type: 'gcj02',
highAccuracy: true,
success(res) {
console.log("getLocation响应", res);
that.locationLatitude = res.latitude
that.locationLongitude = res.longitude
},
fail: (err) => {
console.log("接口调用失败", err);
},
complete: (res) => {}
})
},
getChooseLocation() {
console.log("选择地址");
let that = this;
this.name = "请选择地址";
uni.chooseLocation({
success(res) {
console.log(res);
if (res.errMsg == "chooseLocation:ok") {
if (res.name == null || res.name == '') {
uni.showModal({
title: '提示',
content: "请选择地址",
showCancel: false,
success: function(res) {
if (res.confirm) {
} else {
}
}
})
return;
}
let distance = that.getDistance(res.latitude, res.longitude, that.locationLatitude,
that.locationLongitude);
console.log(that.checkDistance, "打卡范围");
console.log(distance, "实际距离");
if (distance > that.checkDistance) {
uni.showModal({
title: '提示',
content: "选择地址距离当前位置过远,无法打卡,请重新选择",
showCancel: false,
success: function(res) {
if (res.confirm) {
} else {
}
}
})
return;
}
that.chooseLatitude = res.latitude;
that.chooseLongitude = res.longitude;
that.address = res.address;
that.name = res.name;
} else {
console.log("调用失败!")
}
},
fail: function() {}
})
},
getSetting() {
uni.getSetting({
success: function(res) {
var statu = res.authSetting;
if (!statu['scope.userLocation']) {
uni.showModal({
title: '是否授权当前位置',
content: '需要获取您的地理位置,请确认授权,否则地图功能将无法使用',
success: function(tip) {
if (tip.confirm) {
uni.openSetting({
success: function(data) {
if (data.authSetting[
"scope.userLocation"] ===
true) {
uni.showToast({
title: '授权成功',
icon: 'success',
duration: 1000
})
} else {
uni.showToast({
title: '授权失败',
icon: 'success',
duration: 1000
})
}
}
})
}
}
})
}
},
fail: function(res) {
uni.showToast({
title: '调用授权窗口失败',
icon: 'success',
duration: 1000
})
}
})
},
check(){
if (!this.checkStatus) {
return false;
}
if (!this.objectName) {
uni.showModal({
title: '提示',
content: "请选择拜访对象!",
showCancel: false,
success: function(res) {
if (res.confirm) {
} else {
}
}
})
return false;
}
if (!this.chooseLatitude || !this.chooseLongitude ||!this.address || !this.name) {
uni.showModal({
title: '提示',
content: "请选择地址!",
showCancel: false,
success: function(res) {
if (res.confirm) {
} else {
}
}
})
return false;
}
return true;
},
checkIn() {
let flag = this.check();
console.log("打卡校验",flag);
if(!flag){
console.log("打卡校验未通过!");
return;
}
this.$request.request({
url: "/crmClockIn/save",
data: {
user_id: uni.getStorageSync('user').id,
name: this.name,
address: this.address,
latitude: this.chooseLatitude,
longitude: this.chooseLongitude,
business_type: this.objectType,
business_id: this.objectId,
business_name:this.objectName
},
method: "POST"
}).then(res => {
uni.showModal({
title: '提示',
content: "打卡成功!",
showCancel: false,
success: function(res) {
if (res.confirm) {
uni.navigateBack();
} else {
uni.navigateBack();
}
}
})
})
},
searchClick(e) {
this.loadingColumns();
},
startCountdown() {
this.clearCountdown();
this.timer = setInterval(() => {
if (this.totalSeconds <= 0) {
this.checkStatus = false;
this.clearCountdown();
this.countdown = "不可打卡";
this.goBack();
} else {
this.totalSeconds -= 1;
this.countdown = this.formatTime(this.totalSeconds);
}
}, 1000);
},
clearCountdown() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
formatTime(seconds) {
let m = Math.floor(seconds / 60);
let s = seconds % 60;
let sum = m * 60 + s;
return sum + "s";
},
goBack() {
uni.navigateBack();
},
}
}
</script>
<style lang="scss">
.container,
page {
background-color: #fff;
height: 100%;
}
.container {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.head {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 10px 20rpx;
align-items: center;
}
.imgView {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 40rpx;
}
.body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
flex: 1;
}
.dakaImg {
height: 400rpx;
width: 400rpx;
}
.common_btn {
width: 80%;
margin: 0 auto;
}
.foot {
padding-bottom: 10%;
}
.right {
width: 35px;
height: 35px;
}
.daka-text {
position: absolute;
color: #fff;
font-size: 50rpx;
font-weight: bold;
}
.daka-tips {
position: absolute;
margin-top: 100rpx;
font-size: 20rpx;
color: #ffffff7a;
}
.addr {
display: flex;
color: #999999;
padding: 0px 40rpx;
}
.addr-img {
height: 40rpx;
width: 40rpx;
margin-right: 10rpx;
}
.head-right {
display: flex;
align-items: center;
font-size: 26rpx;
color: #BDBDBD;
}
.head-left::before {
content: "*";
color: red;
margin-right: 4px;
}
.addr-text {
color: #409eff;
}
</style>