vue3 tp6 微信登录,支付,定位

vue3 pinia vite
tp6 easywechat
在router.js中

// 定义一个全局前置守卫,在所有路由变化之前执行
router.beforeEach(async (to, from, next) => {
    // 使用pinia或Vuex的store来获取用户信息和管理员信息
    const userStore = useUserStore()
    
    // 检查目标路由是否有requiresAuth元信息,即是否需要认证
    if (to.matched.some(record => record.meta.requiresAuth)) {
        // 检查是否是在微信浏览器中打开
        if (isWeChatBrowser()) {
            // 如果用户尚未登录(id为null或undefined)
            if (userStore.id === null || userStore.id === undefined) {
                // 对回调页URL进行编码,防止特殊字符引起问题
                const url = encodeURIComponent('回调页') // '回调页'应该替换为实际的回调地址
                const appid = 'appid' // 微信公众号的appid
                const response_type = 'code' // 授权类型
                const scope = 'snsapi_userinfo' // 获取用户的基本信息权限
                // 函数用来重定向到微信授权页面
                const wxlogin = () => {
                    // 通过window.location.href重定向到微信授权链接
                    window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${url}&response_type=${response_type}&scope=${scope}&state=STATE#wechat_redirect`
                }
                // 调用微信登录函数
                return wxlogin()
            } else {
                // 如果用户已登录,则继续导航到目标路由
                next()
            }
        } else {
            // 如果不是在微信浏览器中打开,则提示用户
            alert('请在微信中打开使用完整服务') 
        }
    } else {
        // 如果目标路由不需要认证,则直接放行
        next()
    }
})

回调页js

const callback = () => {
  const route = useRoute();
  const router = useRouter();
  const code = ref(route.query.code); // 获取 URL 中的 code 查询参数
  if (code.value !== undefined) {
    axios.post('url', {
      code: code.value

    }).then(res => {
数据处理,我这里是用pinia记录了用户状态和一些信息
      if () {
    
      } else {

      }
    }).catch(e => {
    })
  }
}
onMounted(() => {
  document.title = '登录中...'
  callback()
})


TP6后端使用了easywechat,这个库可以自行百度
user/WxLogin

    public function index(Request $request)
    {
        $code = $request->post('code');
        $config = [
            // 微信AppID和AppSecret等配置
            'app_id'     => 'appid',
            'secret'     => 'appsecret',
            'oauth' => [
                'scopes'   => ['snsapi_userinfo'],
                'callback' => '  ',
            ],
            // 其他配置...
        ];
        // 使用code换取用户信息
        $app = Factory::officialAccount($config);
        $oauth = $app->oauth;

        try {
            try {
                $user = $oauth->userFromCode($code)->toArray();
                $openid=$user['id'];
                //微信每天accesstoken有次数限制,定义一个cacheKey 之后用catch存储一下
                $cacheKey = $openid.'wechat_access_token';
                Cache($cacheKey,$user['access_token'], $result['expires_in'] - 60);
                //之后处理业务即可


            } catch (GuzzleException|AuthorizeFailedException $e) {
                return Response::create(['msg'=>$e->getMessage()], 'json');
            }

        } catch (\Exception $e) {
            // 错误处理
            return Response::create(['msg'=>$e->getMessage()], 'json');
        }
    }

微信支付JS

            let url = '';
            const href = window.location.href;
            url = href.split('#')[0];
            ax.post('/user/WxPay', {
              url: url,
              id: userStore.id,
              price: price.value,
            }).then((res) => {
              wx.config({
                debug: false,
                appId: 'appid',
                timestamp: res.data.timestamp,
                nonceStr: res.data.nonce_str,
                signature: res.data.signature,
                jsApiList: ['chooseWXPay', 'checkJsApi'] // 必填,需要使用的JS接口列表

              })
              wx.ready(() => {
                wx.checkJsApi({
                  jsApiList: ['chooseWXPay'],
                  success: function (res) {
                  },
                  fail: function (res) {
                  }
                })

                wx.chooseWXPay({
                  appId: 'appid',
                  timestamp: res.data.timestamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
                  nonceStr: res.data.nonce_str, // 支付签名随机串,不长于 32 位
                  package: res.data.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
                  signType: 'MD5', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
                  paySign: res.data.paySign, // 支付签名
                  success: function (payRes) {
                    ax.post('/user/Index/CreateOrder', {
                      id: userStore.user,
                      type: type,
                      price: price.value,
                      _id: id,
                      remake: remake.value,
                    }, {
                      headers: {
                        Token: userStore.token
                      }
                    }).then((res) => {
                      if (res.data.code === 200) {
                        alert(res.data.msg)
                      } else {
                        alert(res.data.msg)
                      }
                    })
                  },
                  cancel: function (payRes) {
                    alert.error('取消支付')
                  },
                  fail: function (payRes) {
                    alert.error('支付失败')
                  }
                })
              })
            })

wxpay.php

​
    public function index(Request $request): Response
    {
        $data=$request->only(['price','id','url']);
        $config = [
            'app_id'             => 'appid',
            'mch_id'             => '商户',
            'key'                => 'apiv2密钥',   // API v2 密钥 (注意: 是v2密钥 是v2密钥 是v2密钥)
            'cert_path'          => dirname(__DIR__, 3).'/apiclient_cert.pem', // XXX: 绝对路径!!!!
            'key_path'           => dirname(__DIR__, 3).'/apiclient_key.pem',      // XXX: 绝对路径!!!!
            'notify_url'         => '',     // 你也可以在下单时单独设置来想覆盖它
        ];

        $app = Factory::payment($config);
        try {
            $result = $app->order->unify([
                'body' => '在线支付',
                'out_trade_no' => $this->generateOrderNo(),
                'total_fee' => $data['price']*100,
                'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
                'openid' => $data['id'],
            ]);
            if (isset($result['prepay_id'])){
                $prepayId = $result['prepay_id'];
                $package = 'prepay_id=' . $prepayId;
                $accessToken = $this->getAccessToken($data['id']);
                $ticket = $this->getJsapiTicket($data['id'],$accessToken);
                $nonceStr = $this->createNonceStr();
                $timestamp = time();
                $paySign=$this->paySign($nonceStr,$package,$timestamp);

                $signature = $this->createSignature($nonceStr, $timestamp, $data['url'], $ticket);

                return Response::create([
                    $result,
                    'url'=>$data['url'],
                    'signature'=>$signature,
                    'paySign'=>$paySign,
                    'nonce_str' => $nonceStr,
                    'prepay_id' => $prepayId,
                    'package' => 'prepay_id=' . $prepayId,
                    'timestamp' => $timestamp,
                    'sign_type' => 'MD5',
                ], 'json');
            }
            return Response::create(['msg'=>$result,'code'=>200], 'json');

        } catch (InvalidArgumentException|InvalidConfigException|GuzzleException $e) {
            return Response::create(['msg'=>$e->getMessage(),'code'=>201], 'json');
        }
    }

    function generateOrderNo(): string
    {
        // 获取当前时间的时间戳(精确到毫秒)
        $timestamp = date('YmdHis') . substr(str_replace(".", "", microtime()), 0, 3);
        // 生成四位随机数
        $randomPart = str_pad(mt_rand(1, 9999), 4, "0", STR_PAD_LEFT);
        // 拼接时间戳和随机数
        return $timestamp . $randomPart;
    }

    /**
     * @throws \Exception
     */
    private function getAccessToken($id)
    {
        $appId='appid';
        $appSecret ='appSecret ';
        $cacheKey = $id.'wechat_access_token';
        $accessToken=Cache($cacheKey);
        if (empty($accessToken)){
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appId}&secret={$appSecret}";
            $response = file_get_contents($url);
            $result = json_decode($response, true);
            if (!isset($result['access_token'])) {
                throw new \Exception('获取accesstoken失败'. $result['errmsg']);
            }
            $accessToken = $result['access_token'];
            Cache($cacheKey, $accessToken, $result['expires_in'] - 60);
        }
        return $accessToken;
    }
    public function AccessToken(Request $request): Response
    {
        $id = $request->post('id');  
        $appId='appId';
        $appSecret ='appSecret ';
        $cacheKey = $id.'wechat_access_token';
        $accessToken=Cache($cacheKey);
        if (empty($accessToken)){
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appId}&secret={$appSecret}";
            $response = file_get_contents($url);
            $result = json_decode($response, true);
            if (!isset($result['access_token'])) {
                throw new \Exception('获取accesstoken失败');
            }
            $accessToken = $result['access_token'];
            Cache($cacheKey, $accessToken, $result['expires_in'] - 60);
        }
        return Response::create(['ac'=>$accessToken,'code'=>200], 'json');

    }
    private function getJsapiTicket($id,$accessToken)
    {

        $cacheKey = $id.'wechat_jsapi_ticket';
        $ticket =Cache($cacheKey);
        if (empty($ticket)) {
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={$accessToken}&type=jsapi";
            $response = file_get_contents($url);
            $result = json_decode($response, true);
            if (!isset($result['ticket'])) {
                throw new \Exception('获取ticket失败');
            }
            $ticket = $result['ticket'];
            Cache($cacheKey, $ticket, $result['expires_in'] - 60);

        }

        return $ticket;
    }

    private function createNonceStr(): string
    {
        $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $nonceStr = '';

        $length = $length ?? 16; // 如果没有传入$length,则默认为16
        for ($i = 0; $i < $length; $i++) {
            $nonceStr .= $characters[rand(0, strlen($characters) - 1)];
        }

        return $nonceStr;
    }

    private function paySign($nonceStr, $package,$timestamp): string {
        $apikey = 'aslkdjlk238dalksjd193hkjahskjdf2';
        $params = [
            'appId' => 'appid',
            'timeStamp' => $timestamp,
            'nonceStr' => $nonceStr,
            'package' => $package,
            'signType' => 'MD5',
        ];
        ksort($params, SORT_STRING);

        $stringSignTemp = '';
        foreach ($params as $k => $v) {
            if ($v !== '') { // 排除空值
                $stringSignTemp .= $k . '=' . $v . '&';
            }
        }

        // 添加 API 密钥
        $stringSignTemp .= 'key=' . $apikey;

        // 使用MD5算法生成签名
        $sign = md5($stringSignTemp);
        // 转换为大写
//        return strtoupper($sign);
        return strtoupper($sign);
    }

​

微信定位+高德获取地理逆编码
js
 

const setLocation = async () => {
  let url = '';
  const href = window.location.href;
  url = href.split('#')[0];//截取当前地址栏的URL,(不带#hash部分)
  let res = await axios.post('user/Location', {
    url: url,
    id: userStore.id
  });//通过接口获取微信配置所需信息
  if (res.data.code === 200) {
    alert.success('请求成功')
    wx.config({
      debug: false, 
      appId: res.data.appid, // 必填,公众号的唯一标识
      timestamp: res.data.timestamp, // 必填,生成签名的时间戳
      nonceStr: res.data.noncestr, // 必填,生成签名的随机串
      signature: res.data.signature, // 必填,签名
      jsApiList: ['getLocation'],//必填,需要使用的JS接口列表,如我要用的是wx.getLocation,那么我的jsApiList里的就是getLocation
    });
    wx.ready(function () {
      wx.getLocation({
        type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
        success: function (res) {
          const latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
          const longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。
          AMap.plugin('AMap.Geocoder', function () {
            const geocoder = new AMap.Geocoder({
              // city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
              city: '全国',
              radius: 100 //范围,默认:500
            });

            const lnglat = [longitude, latitude];

            geocoder.getAddress(lnglat, function (status, result) {
              if (status === 'complete' && result.info === 'OK') {

                selectedOptions.value = [result.regeocode.addressComponent.province, result.regeocode.addressComponent.city, result.regeocode.addressComponent.district]
                detail.value = result.regeocode.formattedAddress
                alert.success('定位成功!')
              } else {
                alert('定位失败!')
              }
            })
          })

          // 获取定位位置信息成功,可以进行后续操作
        },
        fail: function (err) {
          alert("获取定位位置信息失败!")
        },
        cancel: function (res) {
          alert('用户拒绝授权获取地理位置');
        }
      });
    });
  } else {
    alert("获取失败")
  }
}

定位wx.ready那几个参数生成与之前的类似
main.js内配置
 

initAMapApiLoader({
    key: '',
    plugins: ['AMap.Geocoder'],
    securityJsCode: ''
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

。。。。。。。。。..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值