Summary of the work of wechat small program based on positioning to achieve the punch card function

Recently, a small task of my work is to realize a function similar to enterprise wechat to clock in and out of work in wechat mini program, and the main front-end work is to calculate location distance

1. Add the longitude and latitude of the store

First we need to add the longitude and latitude of the store

To add longitude and latitude, we can use a small program map plug-in provided by Tencent. First of all, log in the micro channel public number small program background, in the “Settings” column of “third-party Settings” at the bottom of a “plug-in management”, where you can choose to add plug-ins

Search for “Map selection” in the add plugin popup

Then choose to add “Tencent location service map selection” small program plug-in

Then click on the plugin details, which contains the development documentation, with detailed instructions on how to use this map selection

After all the configuration is complete, open the map selection plug-in in the small program and the following interface will appear

So far we have completed the key step of adding the longitude and latitude of the store

2. Obtain position positioning in wechat mini program

wx.getLocation(Object object)

wx.getLocation({
 type: 'wgs84',
 success (res) {
   const latitude = res.latitude
   const longitude = res.longitude
   const speed = res.speed
   const accuracy = res.accuracy
 }
})
Copy the code

The API provided by this wechat small program only gets longitude and latitude. If we want to know the specific information of the current location, for example, XX province, XX City, XX street, we also need to use the SDK provided by Tencent location service to perform parsing

3. Register Tencent location service account, configure information, and download SDK

First of all, we have to go to the official website of Tencent Location service to register an account of Tencent location service

Console –> My App –> Create App –> Fill in the name and category

Add key –> Check WebServiceAPI –> Check wechat applet –> Fill in your applet APPID –> Copy key (this is very important to use applet)

Head navigation –> Development Document –> wechat applets –> wechat applets JavaScript SDK

Then there are details about the micro channel small program location analysis of the relevant operations and code examples

Afraid of the picture is not too clear, the main I or excerpt listed

  1. Apply for developer key: Apply for a key

  2. To enable the webserviceAPI service, choose Application Management > My App > Add Key > Select webserviceAPI > Save

    (The small program SDK needs to use some services of webserviceAPI, so the KEY to use this function needs to have corresponding permissions.)

  3. Download JavaScriptSDK, JavaScriptSDK v1.1, JavaScriptSDK v1.2

  4. Set the secure domain name, in the small program management background -> Development -> Development Management -> Development Settings -> “Server Domain name” set the request legitimate domain name, add apis.map.qq.com

  5. Applets example

// Introduce SDK core classes, js files according to their own business, location can be placed by themselves
var QQMapWX = require('.. /.. /libs/qqmap-wx-jssdk.js');
var qqmapsdk;
Page({
 
    onLoad: function () {
        // Instantiate the API core class
        qqmapsdk = new QQMapWX({
            key: 'Application key'
        });
    },
    onShow: function () {
        // Call the interface
        qqmapsdk.search({
            keyword: 'hotel'.success: function (res) {
                console.log(res);
            },
            fail: function (res) {
                console.log(res);
            },
        complete: function (res) {
            console.log(res); }}); }})Copy the code
4. Key code implementation of latitude and longitude analysis
globalData = {
    getLocation: function () {
        return new Promise((resolve, reject) = > {
            // Instantiate the API core class
            const qqmapsdk = new QQMapWX({
                key: 'xxxxx'}); wx.getLocation({type: 'gcj02'.// Returns the latitude and longitude that can be used for wx.openLocation
                success(res) {
                    const latitude = res.latitude;
                    const longitude = res.longitude;
                    qqmapsdk.reverseGeocoder({
                        location: {
                            latitude,
                            longitude,
                        },
                        success(res) {
                            constlocationData = { ... res.result.address_component, latitude, longitude, };// Redux's data warehouse state management is used here
                                store.dispatch({
                                type: action.SET_CURRENT_LOACTION,
                                currentLocation: locationData,
                            });
                            resolve(locationData);
                        },
                        fail: function (error) {
                            console.error(error);
                            reject('Latitude and longitude resolution failed');
                        },
                        complete: function (res) {
                            console.log(res); }}); },fail: function (error) {
                    console.error(error); reject( failAuthDenyLocationEnum.FAIL_AUTH_DENY_LOCATION ); }}); }); }};Copy the code

Analytical results of normal latitude and longitude:

5. Get the latitude and longitude of the two points and calculate the distance

This is baidu code.

// Calculate the distance with the latitude and longitude of the first point respectively; The second point latitude, longitude
getDistance(lat1,lng1,lat2,lng2){
    // Convert latitude and longitude to distance
    function rad(d){
        return d * Math.PI / 180.0;// Convert latitude and longitude to trigonometric form.
    }
    const radLat1 = rad(lat1);
    const radLat2 = rad(lat2);
    const a = radLat1 - radLat2;
    const  b = rad(lng1) - rad(lng2);
    let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
                                    						        Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
    s = s *6378.137 ;
    console.log('s', s)
    // The output is km
    s = Math.round(s * 10000) / 10000;
    // The output is meters
    // s = Math.round(s * 10000000);
    // s = s.toFixed(4);
    return s;
}
Copy the code
6. Is it within the range of the punch card
countDistance() {
    if(!this.shopLat || !this.shopLng){
        this.locationInfo = 'The longitude and latitude Settings of the store are wrong, so it cannot be punched in'
        this.disableClockIn = true
        this.$apply();
        return
    }
    if(!this.userLat || !this.userLng){
        this.locationInfo = 'User location error'
        this.disableClockIn = true
        this.$apply();
        return
    }
    this.distance = this.getDistance(this.userLat, this.userLng, this.shopLat, this.shopLng)
    if(this.distance <= this.distanceClockIn){
        this.locationInfo = 'You are in the clock range'
        this.disableClockIn = false
    }
    if(this.distance > this.distanceClockIn){
        this.locationInfo = 'You are out of range'
        this.disableClockIn = true
    }
    this.$apply();
}
Copy the code
7. Monitor position changes in real time
wx.getSetting({
    success(res) {
        if(! res.authSetting['scope.userLocation']) {
            _this.locationInfo = 'You have refused to authorize location information'
            _this.failAuthDenyLocation = true
            _this.$apply()
        } else {
            // Calculate the distance every 10 seconds using wx.getLocation for now. Using wx.onLocationChange to listen for location changes is problematic
            _this.timer = setInterval(() = > {
                _this.getLocation().then(() = > {
                    _this.countDistance()
                    console.log('timer-distance', _this.distance)
                }).catch(err= > console.log(err))
            }, 10000); }}})Copy the code
// Clear the timer when the page unloads
onUnload() {
    clearInterval(this.timer)
}
Copy the code

At this point on the micro channel small program according to the positioning of the key steps to achieve the punch card function have been completed

8. Business process code

Finally attached is the business process code for this punch in function. I used WEpy

import wepy from 'wepy';
import { connect } from 'wepy-redux';
import util from '.. /.. /utils/util';
import api from '.. /.. /utils/api';
import { failAuthDenyLocationEnum } from '.. /.. /utils/constant';
@connect({
	userInfo(state) {
		return state.user.userInfo;
	},
	currentLocation(state) {
		return state.user.currentLocation;
	},
	okUser(state) {
		returnstate.user.ok; }})export default class ClerkClockIn extends wepy.page {
	config = {
		navigationBarTitleText: 'Shop assistant closes shift'.navigationBarBackgroundColor: '#EA1717'.navigationBarTextStyle: 'white'}; components = { }; mixins = []; data = {client: {},
		key: ' '.nowTime: ' '.timer: null.shopLat: ' '.shopLng: ' '.userLat: ' '.userLng: ' '.distance: ' '.locationInfo: ' '.disableClockIn: true.distanceClockIn: 3.// Clocking distance 1 means one kilometer
		failAuthDenyLocation: false.// Whether to reject authorization location information
	};

	computed = {};

	methods = {
		clerkClockIn() {
			if(!this.disableClockIn){
				if(this.clerkPrisonLogData) {
					api.shop.clerkPrisonLogOut({shopId: this.shopId}).then(r= > {
						if(r.status === 'OK'){
							util.toast('Clocked in successfully')
							setTimeout(() = > {
								this.query()
							}, 500)
						}
					}).catch(err= > console.log(err))
				}else{
					api.shop.clerkPrisonLogIn({shopId: this.shopId}).then(r= > {
						if(r.status === 'OK'){
							util.toast('Clocked in successfully')
							setTimeout(() = > {
								this.query()
							}, 500)
						}
					}).catch(err= > console.log(err))
				}
			}
		},
		// Obtain authorization again
		openConfirm: function () {
			wx.showModal({
				content: 'Detect that you do not have location permission on this applet, do you want to set it to open? '.confirmText: "Confirm".cancelText: "Cancel".success: function (res) {
					console.log(res);
					// Click "OK" to open the Settings page
					if (res.confirm) {
						console.log('User clicks OK')
						wx.openSetting({
							success: (res) = >{}})}else {
						console.log('User hit Cancel')}}})},}; watch = {}// Calculate the distance with the latitude and longitude of the first point respectively; The second point latitude, longitude
    getDistance(lat1,lng1,lat2,lng2){
		// Convert latitude and longitude to distance
		function rad(d){
			return d * Math.PI / 180.0;// Convert latitude and longitude to trigonometric form.
		}
        const radLat1 = rad(lat1);
        const radLat2 = rad(lat2);
        const a = radLat1 - radLat2;
        const  b = rad(lng1) - rad(lng2);
        let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
        Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
        s = s *6378.137 ;
		console.log('s', s)
		// The output is km
        s = Math.round(s * 10000) / 10000;
		// The output is meters
		// s = Math.round(s * 10000000);
        // s = s.toFixed(4);
        return s;
    }
	// Is it within the range of the clock
	countDistance() {
		if(!this.shopLat || !this.shopLng){
			this.locationInfo = 'The longitude and latitude Settings of the store are wrong, so it cannot be punched in'
			this.disableClockIn = true
			this.$apply();
			return
		}
		if(!this.userLat || !this.userLng){
			this.locationInfo = 'User location error'
			this.disableClockIn = true
			this.$apply();
			return
		}
		this.distance = this.getDistance(this.userLat, this.userLng, this.shopLat, this.shopLng)
		if(this.distance <= this.distanceClockIn){
			this.locationInfo = 'You are in the clock range'
			this.disableClockIn = false
		}
		if(this.distance > this.distanceClockIn){
			this.locationInfo = 'You are out of range'
			this.disableClockIn = true
		}
		this.$apply();
	}

	getLocation() {
		return new Promise((resolve, reject) = > {
			this.$parent.globalData.getLocation().then(({latitude, longitude}) = > {
				if(latitude && longitude){
					this.userLat = latitude
					this.userLng = longitude
					this.failAuthDenyLocation = false
					this.$apply()
					resolve()
				}
			}).catch(err= > {
				console.log(err)
				if(err === failAuthDenyLocationEnum.FAIL_AUTH_DENY_LOCATION){ } reject(err) }); })}// Monitor position changes in real time
	onShow() {
		this.getLocation().then(() = > {
			this.countDistance()
		}).catch(err= > console.log(err))
		const _this = this
		wx.getSetting({
			success(res) {
			  if(! res.authSetting['scope.userLocation']) {
				  _this.locationInfo = 'You have refused to authorize location information'
				  _this.failAuthDenyLocation = true
				  _this.$apply()
			  } else {
				// Calculate the distance every 10 seconds using wx.getLocation for now. Using wx.onLocationChange to listen for location changes is problematic
				_this.timer = setInterval(() = > {
					_this.getLocation().then(() = > {
						_this.countDistance()
						console.log('timer-distance', _this.distance)
					}).catch(err= > console.log(err))
				}, 10000); }}})this.$apply();
	}

	onReady() {
		api.common.queryClientInfo().then((r) = > {
			this.client = r;
			this.$apply();
		});
	}
	//
	onLoad(options) {
		console.log('currentLocation'.this.currentLocation)
		this.shopId = options.shopId ? Number(options.shopId) : ' '
		this.shopLat = options.shopLat ? Number(options.shopLat) : ' '
		this.shopLng = options.shopLng ? Number(options.shopLng) : ' '
		this.userLat = this.currentLocation.latitude
		this.userLng = this.currentLocation.longitude
		this.$apply();
	}
	onUnload() {
		clearInterval(this.timer)
	}
	onShareAppMessage(rest){}}Copy the code