uni-app 实现多点打卡功能,定位打卡考勤
代码如下:
<template>
<view class="lwming_ClockIn">
<view class="ClockIn_conten">
<view class="header"><view class="header_Type" @click="Tabs_Type">打卡</view></view>
<view class="container">
<!-- 公司打卡 -->
<view class="item_In">
<view class="address">{{ ClockInObj.address }}</view>
<image class="img" :src="IS_Range === true ? '../../static/ok.png' : '../../static/warn.png'" mode=""></image>
<view class="IS_Range" :class="{ IS_Range_No: IS_Range === false }">{{ IS_Range_Content }}</view>
</view>
<!-- 打卡按钮 -->
<view v-if="!isClock" class="item_Button" :class="[ClockInObj.IsSuccess ? 'item_Button_Click' : '']">
<view class="ring" @click="Submit">
<view class="time">{{ time }}</view>
<view class="time">打卡</view>
</view>
</view>
<view v-if="isClock">
<view class="ring" @click="Submit" style="margin-top: 60rpx;">
<image class="img" src="../../static/sus.png" style="width: 160rpx;height: 160rpx;"></image>
</view>
</view>
</view>
</view>
<map :latitude="lat_current" :longitude="lng_current" :markers="covers"></map>
</view>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
var _href;
export default {
data() {
return {
IsChange: false, //控制“添加备注”
autoBool: false, //textarea自动聚焦
keycode: '', //输入框的值
conBoll: true,
ImgArr: [],
covers: [],
activeType: false,
isClock: false,
time: '',
ClockInObj: {
street: '',
Details: '',
IsSuccess: false,
address: '' //打卡类型
},
lat_current: 0, //当前位置
lng_current: 0, //当前位置
positionList: [],
Distance_In: 0.1, //公司打卡半径范围
IS_Range: true, //是否在范围内
IS_Range_Content: '你已在打卡范围内',
clockData: {}
};
},
computed: {
...mapState(['hasLogin', 'userInfo'])
},
onShow() {
let user = uni.getStorageSync('userInfo');
_href = this;
_href.clockData.pid = user.proId;
_href.clockData.gid = user.groupId;
_href.clockData.uid = user.userId;
_href.clockData.openid = user.openid;
_href.positionList = [];
uni.request({
url: 'https://kunzhou.chunquanxy.com/index.php/index/get_project/pid/' + user.proId,
success: res => {
if (res.data.status === 1) {
//获取设定好的地址坐标(经纬度)
console.log(res.data, '打卡位置');
let position = {};
position.lng_In = res.data.y;
position.lat_In = res.data.x;
_href.positionList.push(position);
}
}
});
this.getMaxLongitudeLatitude();
// 获取当前时间
setInterval(() => {
var date = new Date();
var hour = date.getHours();
var minute = date.getMinutes() >= 10 ? date.getMinutes() : '0' + date.getMinutes();
this.time = hour + ':' + minute;
}, 1000);
},
onLoad() {
this.GetCurrentAddress();
},
methods: {
Submit() {
_href = this;
let address = this.ClockInObj.Details;
if (this.IS_Range === false) {
this.showToast_Tips('你已超出公司打卡范围', 'none');
return false;
}
_href.ClockInObj.IsSuccess = true;
uni.request({
url:
'https://kunzhou.chunquanxy.com/index.php/index/clockin/' +
'/openid/' +
this.clockData.openid +
'/pid/' +
this.clockData.pid +
'/gid/' +
this.clockData.gid +
'/uid/' +
this.clockData.uid,
success: res => {
console.log(res, '打卡返回');
if (res.data.status === 1) {
_href.ClockInObj.IsSuccess = false;
_href.isClock = true;
}
if (res.data.status === 2) {
this.showToast_Tips(res.data.info, 'none');
}
if (res.data.status === 0) {
this.showToast_Tips('打卡失败', 'none');
}
}
});
//调用打卡方法todo
},
//提示
showToast_Tips(title, icon) {
uni.showToast({
title: title,
duration: 2000,
icon: icon
});
},
//点击确定
quedingFunc() {
if (this.keycode != '') {
setTimeout(() => {
this.IsChange = false;
this.conBoll = false;
}, 300);
} else {
this.showToast_Tips('请输入内容', 'none');
}
},
// 点击取消
quxiaoFunc() {
setTimeout(() => {
this.IsChange = false;
}, 300);
},
//添加备注功能
AddRemarks() {
this.IsChange = !this.IsChange;
this.autoBool = true;
},
//获取当前地址
GetCurrentAddress() {
uni.showLoading({
title: '加载中'
});
let _this = this;
uni.authorize({
scope: 'scope.userLocation',
success() {
uni.getLocation({
type: 'gcj02',
success: res => {
_this.lat_current = res.latitude;
_this.lng_current = res.longitude;
_this.getMaxLongitudeLatitude();
let Position = {
latitude: res.latitude,
longitude: res.longitude
};
console.log(Position, '√');
_this.covers.push(Position);
let URL = 'https://apis.map.qq.com/ws/geocoder/v1/?location=';
let key = 'OTLBZ-F46E3-KE63T-3MMRS-SWCDV-M4FIC'; //你申请的开发者密钥(Key) 一般放在后台获取过来
let getAddressUrl = URL + _this.lat_current + ',' + _this.lng_current + `&key=${key}`;
wx.request({
url: getAddressUrl,
success: result => {
let Res_Data = result.data.result;
_this.ClockInObj.street = Res_Data.address;
_this.ClockInObj.Details = Res_Data.formatted_addresses.recommend;
_this.ClockInObj.address = Res_Data.address + '(' + Res_Data.formatted_addresses.recommend + ')';
setTimeout(() => {
uni.hideLoading();
}, 300);
}
});
}
});
}
});
},
//公司地址范围限制
getMaxLongitudeLatitude(res) {
let L = 0,
T = 0,
Max_L = 0,
Max_T = 0;
//公司地址范围限制
L = this.lng_current; //当前经度
T = this.lat_current; //当前纬度
//循环打卡位置中心
if (this.positionList.length) {
for (let i in this.positionList) {
Max_L = this.positionList[i].lng_In; //选择的位置 中心点
Max_T = this.positionList[i].lat_In; //选择的位置 中心点
let X_T = Max_T - T;
let X_L = Max_L - L;
let X_square = Math.pow(X_T, 2);
let Y_square = Math.pow(X_L, 2);
let XY_square = X_square + Y_square;
let Limit_R = Math.sqrt(XY_square);
if (Limit_R <= this.Distance_In) {
this.IS_Range = true;
this.IS_Range_Content = '你已在打卡范围内';
return;
} else {
this.IS_Range = false;
this.IS_Range_Content = '你已超出打卡范围';
}
}
}
},
Tabs_Type() {
this.activeType = !this.activeType;
}
}
};
</script>
<style lang="scss">
.lwming_ClockIn {
height: 100vh;
position: relative;
.ClockIn_conten {
position: absolute;
width: 100%;
background-color: #fff;
z-index: 50;
opacity: 0.9;
height: 100vh;
}
map {
position: absolute;
width: 100%;
height: 100vh;
z-index: -50;
}
.header {
display: flex;
justify-content: center;
align-items: center;
padding: 15rpx 0;
&_Type {
width: 40%;
font-size: 28rpx;
color: #333;
text-align: center;
position: relative;
padding-bottom: 25rpx;
&::before {
content: '';
position: absolute;
left: 0;
bottom: 0;
right: 0;
margin: auto;
width: 75%;
height: 3px;
background-color: #fff;
transform: scale3d(0, 1, 1);
transform-origin: center;
transition: all 0.5s;
}
&.choose {
color: #1890ff;
&::before {
transform: scale3d(1, 1, 1);
background-color: #1890ff;
}
}
}
}
.container {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin-top: 100rpx;
.item_In {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.img {
width: 110rpx;
height: 160rpx;
object-fit: cover;
padding: 30rpx 0;
}
.address {
padding: 8rpx 0;
}
.IS_Range {
font-size: 34upx;
font-weight: 600;
padding: 20upx 0;
}
.IS_Range_No {
color: #ff4949;
}
.Add_Notes {
margin-top: 100upx;
font-size: 26upx;
}
.contet_box {
width: 100%;
margin: 20rpx auto;
.txt {
margin-bottom: 20rpx;
width: 90%;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #444;
}
.img_box_right {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
.image_ {
margin: 0 15rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
object-fit: cover;
}
}
}
}
.item_Button {
width: 200rpx;
height: 200rpx;
text-align: center;
border-radius: 50%;
margin-top: 40rpx;
color: #ffffff;
font-size: 32rpx;
background-image: linear-gradient(125deg, #e4ffcd, #029fff, #0166ff, #e4ffcd);
background-size: 400%;
animation: bganimation 15s infinite;
display: flex;
justify-content: center;
align-items: center;
@keyframes bganimation {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
}
.item_Button_Click {
color: #ffffff;
background-image: linear-gradient(125deg, #ff4e50, #00c75d, #ff4e50, #e4ffcd);
}
}
}
.remarkBigWarp {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 999;
top: 0;
left: 0;
.remarkWarp {
width: 90%;
background-color: #ffffff;
position: absolute;
top: 100rpx;
left: 50%;
transform: translateX(-50%);
z-index: 100;
border-radius: 16rpx;
.remarkWarpBox {
width: 90%;
margin: 0 auto;
padding: 10rpx 0;
.textTile {
width: 100%;
height: 150rpx;
caret-color: #4cd964;
}
.photoBox {
width: 100%;
display: flex;
flex-wrap: wrap;
}
}
.btnWrap {
display: flex;
color: #4cd964;
width: 100%;
border-top: 1rpx solid #cccccc;
.cancel {
width: 100%;
text-align: center;
padding: 20rpx 0;
font-size: 30rpx;
letter-spacing: 2rpx;
}
.cancel:active {
background-color: rgba(0, 0, 0, 0.2);
transition: all 0.2s ease-in;
}
}
}
}
</style>