借助参考:https://blog.csdn.net/zhanghao143lina/article/details/73369046
一、服务号配置
js安全接口,ip白名单
二、html部分
<!DOCTYPE html>
<html lang="en">
<head>
<title>附近门店列表</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<style type="text/css" media="screen">
body{background: #eee;}
.store-body{
display: flex;
flex-direction: column;
background:#FFF;
}
.s-box-t{
display:flex;
}
.s-box-l,.s-box-l img{
width: 100px;
height: 100px;
}
.s-box-l{
/*border: 1px solid #eee;*/
}
.s-box-r{
padding: 10px;
display: flex;
flex-direction: column;
font-size: 14px;
color: #111111;
}
.s-box-r span{
margin: 2px 0px;
}
.store-box{
border-bottom: 5px solid #eee;
margin-top: 10px;
text-decoration: none;
}
.jiazai{
text-align: center;
margin: 10px 0px;
}
</style>
</head>
<body>
<div class='store-body'>
</div>
<div class='jiazai' onclick='jiazai()'>加载更多</div>
</body>
</html>
<script src="__JS__/jquery.min.js" type="text/javascript" charset="utf-8" ></script>
<script src="__JS__/jweixin-1.2.0.js" type="text/javascript" charset="utf-8" ></script>
<script src="__STATIC__/index/layer_mobile/layer.js" type="text/javascript" charset="utf-8" ></script>
<script src="__STATIC__/admin/lib/layui/layui.js" charset="utf-8"></script>
<script src="__JS__/store.js" type="text/javascript" charset="utf-8" ></script>
三、js部分
var g_lat;
var g_long;
var page=1;
var l_index;
$(function(){
//loading带文字
l_index=layer.open({
type: 2
,content: '加载中'
});
start();
})
function start(){
var action='/get_wxsdk_param';
var post={};
$.post(action,post,success,'json');
function success(rdata){
//console.log(rdata)
if(rdata.code==0 || rdata.code==-1){
layer.close(l_index);
layer.open({
content:rdata.msg
,skin: 'msg'
,time: 1
});
toIndex();
}else{
//配置信息验证接口
wx.config({
debug: false,
appId:rdata.appid ,
timestamp: rdata.timestamp,
nonceStr: rdata.noncestr,
signature: rdata.signature,
jsApiList: [
// 所有要调用的 API 都要加到这个列表中
'checkJsApi',
'openLocation',
'getLocation'
]
});
wx.error(function(res){
layer.close(l_index);
console.log('error',res);
alert('配置错误!');
toIndex();
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
})
//验证之后进入该函数,所有需要加载页面时调用的接口都必须写在该里面
wx.ready(function () {
//基础接口判断当前客户端版本是否支持指定JS接口
wx.checkJsApi({
jsApiList: [
'getLocation'
],
success: function (res) {
// alert(JSON.stringify(res));
// alert(JSON.stringify(res.checkResult.getLocation));
if (res.checkResult.getLocation == false) {
alert('你的微信版本太低,不支持微信JS接口,请升级到最新的微信版本!');
toIndex();
return;
}
}
});
//微信获取地理位置并拉取用户列表(用户允许获取用户的经纬度)
wx.getLocation({
type: 'wgs84',
success: function (res) {
//console.log('latitude',res);
var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。
g_lat=res.latitude;
g_long=res.longitude;
//去数据库查询获取附近的门店
var action='/get_store_list';
var post={latitude:latitude,longitude:longitude,page:page};
$.post(action,post,success,'json');
function success(rrdata){
if(rrdata.code==1){
console.log('111');
page=Number(rrdata.page)+1;
var list=rrdata.list;
var len=list.length;
var html='';
for(var i=0;i<len;i++){
html+="<a href='/store_detail/id/"+list[i]['id']+".html' class='store-box'><div class='s-box-t'><div class='s-box-l'><img src='/public/uploads/store/"+list[i]['logo']+"'></div><div class='s-box-r'><span>"+list[i]['name']+"</span><span>"+list[i]['address']+"</span><span>"+list[i]['distance']+"公里</span></div></div> </a>";
}
$('.store-body').empty();
$('.store-body').append(html);
}else if(rrdata.code==-1){
console.log('222');
layer.open({
content:rrdata.msg
,skin: 'msg'
,time: 1
});
toIndex();
}else{
console.log('333');
layer.open({
content:rrdata.msg
,skin: 'msg'
,time: 1
});
}
layer.close(l_index);
}
},
fail: function (res) {
alert('获取地理位置失败,'+res.errMsg);
toIndex();
//console.log('getLocation-fail',res);
}
});
});
}
}
}
function jiazai(){
l_index=layer.open({
type: 2
,content: '加载中'
});
//去数据库查询获取附近的门店
var action='/get_store_list';
var post={latitude:g_lat,longitude:g_long,page:page};
$.post(action,post,success,'json');
function success(rrdata){
if(rrdata.code==1){
page=Number(rrdata.page)+1;
var list=rrdata.list;
var len=list.length;
var html='';
for(var i=0;i<len;i++){
html+="<a href='/store_detail/id/"+list[i]['id']+".html' class='store-box'><div class='s-box-t'><div class='s-box-l'><img src='/public/uploads/store/"+list[i]['logo']+"'></div><div class='s-box-r'><span>"+list[i]['name']+"</span><span>"+list[i]['address']+"</span><span>"+list[i]['distance']+"公里</span></div></div> </a>";
}
$('.store-body').append(html);
}else if(rrdata.code==-1){
layer.open({
content:rrdata.msg
,skin: 'msg'
,time: 1
});
toIndex();
}else{
layer.open({
content:rrdata.msg
,skin: 'msg'
,time: 1
});
}
layer.close(l_index);
}
}
function toIndex(){
setTimeout(function(){
location.href='/';
},1000);
}
四、后端-tp5.0
<?php
namespace app\index\controller;
use app\index\model\StoreModel;
use think\Session;
use think\Request;
use think\Db;
class Store extends LBase
{
/**
* [门店列表展示页面]
*
*/
public function store_list()
{
return $this->fetch();
}
/**
* [get_store_list 获取门店数据]
* @return @return [array] [按照最近排序]
*/
public function get_store_list(){
if (!Request::instance()->isAjax()){
return json(['code'=>0,'msg'=>'非法操作!']);
}
//判断是否是微信客户端
if(!isWeixin()){
return json(['code'=>-1,'msg'=>'抱歉,请在微信客户端打开!']);
}
$post = input();
$count=Db::name('store')->where(['status'=>1])->count();
$pageSize=1;
$page=isset($post['page'])&&$post['page']>1?$post['page']:1;
//$page=$page>($count/$pageSize)&&$count>0?($count/$pageSize):$page;
$pageStart=($page-1)*$pageSize;
$longitude = $post['longitude'];//经度信息
$latitude = $post['latitude'];//纬度信息
$sql = "select * from (select id,name,tel,address,logo,status, ROUND(6378.138*2*ASIN(SQRT(POW(SIN(($latitude*PI()/180-`latitude`*PI()/180)/2),2)+COS($latitude*PI()/180)*COS(`latitude`*PI()/180)*POW(SIN(($longitude*PI()/180-`longitude`*PI()/180)/2),2)))*1000) AS distance from think_store order by distance ) as a where a.status=1 limit $pageStart,$pageSize";
$list=Db::query($sql);
if(empty($list)){
$msg=$page>1?'没有更多数据了':'暂无数据!';
return json(['code'=>0,'msg'=>$msg]);
}
foreach($list as $k=>$val){
$list[$k]['distance']=sprintf("%.2f",(intval($val['distance'])/1000));
}
return json(['code'=>1,'page'=>$page,'list'=>$list]);
}
//获取js sdk 接口签名参数
public function get_wxsdk_param() {
if (!Request::instance()->isAjax()){
return json(['code'=>0,'msg'=>'非法操作!']);
}
//判断是否是微信客户端
if(!isWeixin()){
return json(['code'=>-1,'msg'=>'抱歉,请在微信客户端打开!']);
}
$post = input();
$uid=session('uid');
$wxconfig=[];
$wxconfig['appid']=Db::table('think_config')->where(['name'=>'gz_appid'])->value('value');
$wxconfig['appsecret']=Db::table('think_config')->where(['name'=>'gz_appsercet'])->value('value');
//return json_encode($wxconfig);
$jsapiTicket = $this->getJsApiTicket();
$url = 'http://'.$_SERVER['HTTP_HOST']."/store";
$timestamp = time();
$noncestr = $this->createNonceStr();
// 这里参数的顺序要按照 key 值 ASCII 码升序排序
//$string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url";
$string = 'jsapi_ticket='.$jsapiTicket.'&noncestr='.$noncestr.'×tamp='.$timestamp.'&url='.$url;
$signature = sha1($string);
if(false!=$signature || !$jsapiTicket || !$wxconfig['appid'] || !$noncestr || !$timestamp){
$signPackage = array(
'code'=>1,
"appid" => $wxconfig['appid'],
"noncestr" => $noncestr,
"timestamp" => $timestamp,
"signature" => $signature,
//"jsapiTicket"=>$jsapiTicket
);
}else{
$signPackage = array(
'code'=>0,
'msg'=>'获取参数错误',
"noncestr" => $noncestr,
"timestamp" => $timestamp,
"signature" => $signature,
);
}
return json($signPackage);
}
public function createNonceStr($length = 16) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
public function getJsApiTicket() {
error_reporting(0);
$accessToken = $this->getAccessToken();
$ticket='';
$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
$res = json_decode($this->httpGet($url),true);
$ticket = $res['ticket'];
return $ticket;
}
public function getAccessToken() {
$appid=Db::table('think_config')->where(['name'=>'gz_appid'])->value('value');
$appsecret=Db::table('think_config')->where(['name'=>'gz_appsercet'])->value('value');
$token_content=file_get_contents("token.txt");
if($token_content==''){
$access_token=$this->getNewToken($appid,$appsecret);
}else{
$token_arr=json_decode($token_content,true);
if(intval($token_arr['maxTime'])<time()){
$access_token=$this->getNewToken($appid,$appsecret);
}else{
$access_token=$token_arr['access_token'];
}
}
return $access_token;
}
public function getNewToken($appid,$appsecret){
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$appid&secret=$appsecret";
$j_res=$this->httpGet($url);
$res = json_decode($j_res,true);
$access_token =$res['access_token'];
$maxTime=time()+intval($res['expires_in']);
$access_arr=str_replace('}', ",\"maxTime\":".$maxTime."}", $j_res);
file_put_contents("token.txt",$access_arr);
return $access_token;
}
public function httpGet($url) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_TIMEOUT, 500);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_URL, $url);
$res = curl_exec($curl);
curl_close($curl);
return $res;
}
}
