我们在微信小程序项目比如签到功能中可能需要用到位置对比和人脸识别,而小程序自带的人脸识别接口不好申请(作为学生来说),而就可以让后端写几个接口进行对接完成位置对比和人脸识别。下面开始介绍前端部分的实现。
因为涉及个人信息,所以后端需要对每个用户赋予不同的id进行识别,用户访问后端接口都需要上传自己的id,而这部分信息我们通过token上传,但是因为app.js和其他页面的jsfang访问速度后端不一样,通常是其他页面的js访问的快一些,所以在app.js里面获取token可能造成错误的现象,所以在app.js内设置回调函数,其他页面在onShow或onLoad里面先检查是否已获得token,如果没有则访问回调函数去获取token。
app.js
App({
globalData:{
taskid:'',
Token:"",
userid:'',
userInfo: null,
user:{},
},
onLaunch() {
// 展示本地存储能力
const logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
var that=this
// 登录
wx.showLoading({
title: '加载中',
})
wx.login({
success: res => {
console.log(res.code)
wx.request({
url:'http://43.142.99.39:99/api/wechatLogin/'+res.code, //必填,其他的都可以不填
data:{
},
// header:{
// 'content-type':'application/json',
// },
method:'GET',
// dataType:'JSON',
// responseType:'text',
success(res){
console.log(res.data.item)
var userid=res.data.item.user.id;
//console.log(res.data)
var token=res.data.item.token;
that.globalData.userid=userid;
that.globalData.Token=token;
that.globalData.user=res.data.item.user;
console.log('success');
//console.log(userid,token)
//console.log(that.globalData.Token)
wx.hideLoading({
success: (res) => {},
})
//回调函数
if(that.userInfoCallback&&typeof that.userInfoCallback=='function'){
that.userInfoCallback()
}
wx.showToast({
title: '发布成功',
icon: 'success',
duration: 1000//持续的时间
});
setTimeout(()=>{wx.reLaunch({
url: 'test?id=1'
})
},600 );
},
fail(){
console.log('fail')
},
complete(){
console.log('complete')
}
})
}
})
},
})
用户需要先上传签到的位置和个人的照片。
上传签到的位置:
需要先添加微信小程序使用地图的js文件
在utils文件夹内添加两份js文件
下载的链接:https://pan.baidu.com/s/1XgPj17-yBE93qmOFUspwAw
提取码:k0g6
add_location.wxml
<map id="myMap" style="width: 100%; height: 580px;"
longitude="{
{longitude}}" latitude="{
{latitude}}"
scale='16' polyline="{
{polyline}}" show-location>
</map>
<button class="choose_loc" bindtap='getLocation'>选择宿舍位置</button>
add_location.js
var QQMapWX = require('../../utils/qqmap-wx-jssdk.min.js');
var app=getApp()
// 实例化API核心类
var qqmapsdk = new QQMapWX({
key: 'JTPBZ-6AFK6-MTASH-E24LJ-RSNSH-F5BUB' // 必填
});
Page({
data:{
token:'',
id:'',
//默认经纬度
distance:[],
name: '',
address: '',
latitude:26.05248089096305,
longitude:119.19106543064117,
latitude_t:'',
longitude_t:'',
},
onShow(e){
//此时需要判断全局数据是否获取到
var that=this
//如果已经获取到,则直接使用
if(app.globalData.Token){
console.log(app.globalData.Token)
//如果此处的逻辑较多可以提炼为一个函数
that.setData({
token:app.globalData.Token,
userid:app.globalData.userid
})
}else{
//如果还未请求到数据,则创建一个回调函数,等待数据获取完成后调用
app.userInfoCallback = res => {
that.setData({
token:app.globalData.Token,
userid:app.globalData.userid
})
//console.log(that.data.token)
}
}
//var that=this
wx.getLocation({
type:"gcj02",
// altitude: 'altitude',
success(res){
//console.log(res)
that.setData({
latitude:res.latitude,
longitude:res.longitude,
})
}
})
},
getLocation: function () {
var token=this.data.token
var id=this.data.id
var _this = this;
wx.chooseLocation({
success: function (res) {
//console.log(res.address)
console.log(res)
var name = res.name
var address = res.address
var latitude = res.latitude
var longitude = res.longitude
_this.setData({
name: name,
address: address,
latitude_t: latitude,
longitude_t: longitude
})
wx.request({
url: 'https://www.web4j.top/location/insert',//这部分就是后端需要完成的内容,后端需要提供一个上传的接口
data:{
latitude:res.latitude,
longitude:res.longitude
},
header:{
'content-type':'application/json',
'Access-Token':token
},
method:"POST",
success(res){
console.log(res)
},
fail(){
console.log('fail')
}
})
},
complete(r){
console.log('complete')
//console.log(222)
}
})
},
address(e){
qqmapsdk.geocoder({
address: e.detail.value, //用户输入的地址(注:地址中请包含城市名称,否则会影响解析效果),如:'北京市海淀区彩和坊路海淀西大街74号'
complete: res => {
console.log(res.result.location); //经纬度对象
} ,
// else{
// console.log('无法定位到该地址,请确认地址信息!');
// }
})
}
})
上传照片:
add_face.wxml
<view>
<view class="camera">
<image wx:if="{
{flag_c==0}}" class="whitephoto" src="{
{src}}"/>
<camera class="camera_c" wx:if="{
{flag_c==1}}" device-position="front" flash="on"></camera>
</view>
<button wx:if="{
{flag_f==1}}" bindtap="showcamera" type="primary" >开始上传照片</button>
<button wx:if="{
{flag_s==1}}" bindtap="takePhoto" type="primary" >确定</button>
</view>
add_face.wxss
/* pages/face-recognition/face-recognition.wxss */
.camera{
height: 600px;
width: 100%;
display: flex;
justify-content: center;
background-color: rgb(218, 214, 214);
}
.camera_c{
margin-top: 30px;
border-radius: 50%;
height: 300px;
width: 300px;
}
.whitephoto{
margin-top: 30px;
border-radius: 50%;
height: 300px;
width: 300px;
}
add_face.js
var app=getApp()
// const token=app.globalData.Token;
// const user=app.globalData.user;
Page({
/**
* 页面的初始数据
*/
data: {
userid:'',
token:'',
src:'https://gss0.baidu.com/-Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/902397dda144ad34ea5205bdd3a20cf431ad851f.jpg',
flag_c:0,
flag_f:1,
flag_s:0,
photo:'',
},
showcamera(){
this.setData({
flag_c:1,
flag_f:0,
flag_s:1
})
},
takePhoto() {
var id=this.data.userid
var token=this.data.token
// console.log(token)
var that=this
const ctx = wx.createCameraContext()
ctx.takePhoto({
quality: 'high',
success: (res) => {
var path=res.tempImagePath
console.log(path)
this.setData({
src: res.tempImagePath,
flag_c:0
})
// console.log(path)
wx.uploadFile({
url: 'https://www.web4j.top/face-information/uploadPhoto',//这部分就是后端需要完成的内容,后端需要提供一个上传的接口
filePath: path,
name: 'file',
header: {
'content-type':'application/json',
'Access-Token':token
},
// formData: {
// 'filename': 'img', //参数名
// 'method':'post'
// },
success: (result) => {
var records=JSON.parse(result.data);
var photopath=records.item.filePath
console.log(result.data);
console.log(photopath);
console.log('success');
that.setData({
photo:photopath
})
wx.request({
url: 'https://www.web4j.top/face-information/insert',
data:{
userid:id,
picture:photopath
},
header:{
'content-type':'application/json',
'Access-Token':token
},
method:"POST",
success(res){
console.log(res)
},
fail(){
console.log('fail')
}
})
},
fail(){
console.log('fail');
}
})
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
//此时需要判断全局数据是否获取到
var that=this
//如果已经获取到,则直接使用
if(app.globalData.Token){
console.log(app.globalData.Token)
//如果此处的逻辑较多可以提炼为一个函数
that.setData({
token:app.globalData.Token,
userid:app.globalData.userid
})
}else{
//如果还未请求到数据,则创建一个回调函数,等待数据获取完成后调用
app.userInfoCallback = res => {
that.setData({
token:app.globalData.Token,
userid:app.globalData.userid
})
//console.log(that.data.token)
}
}
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
上传之后根据用户所处的位置与之前上传的位置(比如公司位置,宿舍位置,教学楼位置等)进行对比,如果在这范围内在进行人脸识别,否则无法进行人脸识别即也无法完成签到。
location_compare.wxml
<map id="myMap" style="width: 100%; height: 100vh;"
longitude="{
{longitude}}" latitude="{
{latitude}}"
scale='16' polyline="{
{polyline}}" show-location>
</map>
location_compare.js
var app=getApp();
var QQMapWX = require('../../utils/qqmap-wx-jssdk.min.js');
// 实例化API核心类
var qqmapsdk = new QQMapWX({
key: 'JTPBZ-6AFK6-MTASH-E24LJ-RSNSH-F5BUB' // 必填
});
Page({
data:{
token:"",
//默认经纬度
distance:[],
name: '',
address: '',
latitude:26.05248089096305,
longitude:119.19106543064117,
latitude_t:'',
longitude_t:'',
},
onShow(e){
//此时需要判断全局数据是否获取到
var that=this
//如果已经获取到,则直接使用
if(app.globalData.Token){
// console.log(app.globalData.Token)
//如果此处的逻辑较多可以提炼为一个函数
that.setData({
token:app.globalData.Token
})
var token=app.globalData.Token
wx.getLocation({
type:"gcj02",
// altitude: 'altitude',
success(res){
console.log(res)
that.setData({
latitude:res.latitude,
longitude:res.longitude,
})
wx.request({
url: 'https://www.web4j.top/location/compareLocation',
data:{
latitude:res.latitude,
longitude:res.longitude
},
header:{
'content-type':'application/json',
'Access-Token':token
},
method:"POST",
success(res){
console.log(res.data.success)
if(res.data.success){
wx.showModal({
title: '已在签到范围内',
content: '是否进行人脸识别',
success (res) {
if (res.confirm) {
wx.navigateTo({
url: '../face-recognition/face-recognition',
})
} else if (res.cancel) {
// wx.navigateTo({
// url: '../face-recognition/face-recognition',
// })
}
}
})
}
else{
wx.showToast({
title: '未在签到范围内',
icon: 'error',
duration: 2000
})
}
},
fail(){
console.log('fail')
}
})
},
fail(){
console.log('fail');
}
})
}else{
//如果还未请求到数据,则创建一个回调函数,等待数据获取完成后调用
app.userInfoCallback = res => {
that.setData({
token:app.globalData.Token
})
// console.log(that.data.token)
var token=app.globalData.Token
wx.getLocation({
type:"gcj02",
// altitude: 'altitude',
success(res){
console.log(res)
that.setData({
latitude:res.latitude,
longitude:res.longitude,
})
wx.request({
url: 'https://www.web4j.top/location/compareLocation',
data:{
latitude:res.latitude,
longitude:res.longitude
},
header:{
'content-type':'application/json',
'Access-Token':token
},
method:"POST",
success(res){
console.log(res.data.success)
if(res.data.success){
wx.showModal({
title: '已在签到范围内',
content: '是否进行人脸识别',
success (res) {
if (res.confirm) {
wx.navigateTo({
url: '../face-recognition/face-recognition',
})
} else if (res.cancel) {
// wx.navigateTo({
// url: '../face-recognition/face-recognition',
// })
}
}
})
}
else{
wx.showToast({
title: '未在签到范围内',
icon: 'error',
duration: 2000
})
}
},
fail(){
console.log('fail')
}
})
},
fail(){
console.log('fail');
}
})
}
}
},
})
face-recognition.wxml
<view>
<view class="camera">
<image wx:if="{
{flag_c==0}}" class="whitephoto" src="{
{src}}"/>
<camera class="camera_c" wx:if="{
{flag_c==1}}" device-position="front" flash="on"></camera>
</view>
<button wx:if="{
{flag_f==1}}" bindtap="showcamera" type="primary" >开始人脸识别</button>
<button wx:if="{
{flag_s==1}}" bindtap="takePhoto" type="primary" >确定</button>
</view>
face-recognition.wxss
/* pages/face-recognition/face-recognition.wxss */
.camera{
height: 600px;
width: 100%;
display: flex;
justify-content: center;
background-color: rgb(218, 214, 214);
}
.camera_c{
margin-top: 30px;
border-radius: 50%;
height: 300px;
width: 300px;
}
.whitephoto{
margin-top: 30px;
border-radius: 50%;
height: 300px;
width: 300px;
}
face-recognition.js
// pages/face-recognition/face-recognition.js
var app=getApp()
// const token=app.globalData.Token;
// const user=app.globalData.user;
Page({
/**
* 页面的初始数据
*/
data: {
taskid:'',
token:'',
src:'https://gss0.baidu.com/-Po3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/902397dda144ad34ea5205bdd3a20cf431ad851f.jpg',
flag_c:0,
flag_f:1,
flag_s:0,
photo:''
},
showcamera(){
this.setData({
flag_c:1,
flag_f:0,
flag_s:1
})
},
takePhoto() {
var taskid=this.data.taskid
var token=this.data.token
console.log(taskid)
var that=this
const ctx = wx.createCameraContext()
ctx.takePhoto({
quality: 'high',
success: (res) => {
var path=res.tempImagePath
this.setData({
src: res.tempImagePath,
flag_c:0
})
// console.log(path)
wx.uploadFile({
url: 'https://www.web4j.top/face-information/uploadPhoto',
filePath: path,
name: 'file',
header: {
'content-type':'application/json',
'Access-Token':token
},
// formData: {
// 'filename': 'img', //参数名
// 'method':'post'
// },
success: (result) => {
var records=JSON.parse(result.data);
var filepath=records.item.filePath
console.log(taskid);
console.log(filepath);
console.log('success');
this.setData({
photo:filepath
})
wx.request({
url: 'https://www.web4j.top/face-information/compareFace',
data:{
picture:filepath,
taskId:taskid
},
header:{
'content-type':'application/json',
'Access-Token':token
},
method:"POST",
success(res){
console.log(res)
if(res.data.success)
{
wx.showToast({
title: '签到成功!',
icon: 'success',
duration: 1000//持续的时间
});
setTimeout(()=>{
wx.navigateTo({
url: "../roll_call_details/roll_call_details?id="+taskid,
})
},600);
}
else{
wx.showToast({
title: '人脸识别失败!',
icon: 'success',
duration: 1000//持续的时间
});
setTimeout(()=>{
wx.navigateTo({
url: "../face-recognition/face-recognition",
})
},600);
}
},
fail(){
console.log('fail')
}
})
},
fail(){
console.log('fail');
}
})
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
//此时需要判断全局数据是否获取到
var that=this
//如果已经获取到,则直接使用
if(app.globalData.Token){
console.log(app.globalData.Token)
//如果此处的逻辑较多可以提炼为一个函数
that.setData({
token:app.globalData.Token,
taskid:app.globalData.taskid
})
}else{
//如果还未请求到数据,则创建一个回调函数,等待数据获取完成后调用
app.userInfoCallback = res => {
that.setData({
token:app.globalData.Token,
taskid:app.globalData.taskid
})
console.log(that.data.token)
}
}
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
用户上传人脸识别照片后,同样需要后端与之前上传的个人照片进行对比,如果识别成功则签到成功,同样需要后端更改用户在该签名活动中的状态,比如从0->1,从未签到更改为已签到。