uniapp对接一键登录

前端代码

复制代码
<template>
	<view class="wrap" v-if="type === 1" :style="{backgroundImage: 'url('+ baseUrl +'static/images/login-1.png)'}">
		<view class="logo">LOGO</view>
		<view class="onekey" v-if="isOneKey" @click="oneKeyLogin()">本地手机号一键登录</view>
		<view class="onekey disabled" v-else>本地手机号一键登录</view>
		<view class="text">其他手机号登录</view>
		<view class="wx">
			<image :src="baseUrl + 'static/icon/icon-46.png'"></image>
			<text>微信</text>
		</view>
		<view class="xieyi flex-row align-items-center flex-center">
			<u-checkbox-group>
				<u-checkbox shape="circle" active-color="#5670FE" name="value" size="14"
					@change="checkboxChange"></u-checkbox>
			</u-checkbox-group>
			<text style="cursor: pointer;">
				我已阅读并同意<text style="color: #5288F5">《用户隐私协议》</text>、<text style="color: #5288F5">《健康隐私政策》</text>
			</text>
		</view>
	</view>
	<view class="wrap1" v-else :style="{backgroundImage: 'url('+ baseUrl +'static/images/login-2.png)'}">
		<view class="title">手机号注册</view>
		<view class="label">手机号</view>
		<view class="input mb15">
			<input style="width: 100%;" type="text" placeholder="请输入登录手机号" placeholder-class="ph" v-model="mobile">
		</view>
		<view class="label mt20">验证码</view>
		<view class="box input space-between">
			<input style="width: 200px;" type="text" placeholder="请输入" placeholder-class="ph" v-model="code">
			<text class="code-btn" v-if="isCode" @click="getCode">{{codeHit}}</text>
			<text class="code-btn" v-else>{{ codeHit }}</text>
		</view>
		<view class="submit" @click="login">
			登录
		</view>
	</view>
</template>

<script>
	import {
		error,
		jumpPage,
		isLogin,
		success
	} from "@/utils/tools"
	import {
		getSmsCode,
		login
	} from "@/utils/api/api"
	export default {
		data() {
			return {
				isOneKey: false,
				type: 2,
				jumpUrl: '',
				isAgree: false,
				isCode: true,
				baseUrl: getApp().globalData.baseUrl,
				mobile: '',
				codeHit: '获取验证码',
				countDown: 60,
				code: ''
			}
		},
		onLoad() {
			const _this = this
			if (isLogin()) {
				uni.redirectTo({
					url: '/pages/index/index'
				})
				return
			}
			uni.preLogin({
				provider: 'univerify',
				success(res) {
					_this.isOneKey = true
				},
				fail(res) {
					_this.isOneKey = false
				}
			})
		},
		methods: {
			getCode(){
				const _this = this
				if(_this.mobile.length === 0){
					error('请填写手机号')
					return false
				}
				
				if(!/^1\d{10}$/.test(_this.mobile)){
					error('手机号格式错误')
				  return false;
				}
				
				uni.showLoading({
					title:'获取中...'
				})
				getSmsCode({ mobile: _this.mobile, type: 'login' }).then(response => {
					setTimeout(function(){
						uni.hideLoading()
						if(response.errorCode === 0){
							success(response.errorInfo)
							_this.startCountDown()
						}else{
							error(response.errorInfo)
						}
						
					},1500)
				})
			},
			startCountDown() {
			    var _this = this
			    // 设置不可点击
			    _this.isCode = false
			    // 设置文本显示为倒计时的剩余秒数
			    _this.codeHit = _this.countDown + "重新发送"
			    // 每过1秒更新倒计时的剩余秒数
			    var timer = setInterval(function () {
			        _this.countDown--
			        // 更新按钮的文本显示为倒计时的剩余秒数
			        _this.codeHit = _this.countDown + "重新发送"
			        // 如果倒计时结束,清除定时器,并重置按钮状态
			        if (_this.countDown <= 0) {
			            clearInterval(timer);
			            _this.isCode = true
						_this.countDown = 60
			            _this.codeHit = "获取验证码"
			        }
			    }, 1000);
			},
			login(){
				const _this = this
				if(_this.mobile.length === 0){
					error('请输入手机号')
					return
				}
				
				if(!/^1\d{10}$/.test(_this.mobile)){
					error('手机号格式错误')
				  return false;
				}
				
				if(_this.code.length === 0){
					error('请输入验证码')
					return
				}
				
				uni.showLoading({
					title:'登录中...'
				})
				
				login({ mobile: _this.mobile, code: _this.code, type: 2 }).then(response =>{
					setTimeout(() =>{
						uni.hideLoading()
						if(response.errorCode === 0){
							const userInfo = response.data.userInfo
							uni.setStorageSync('token', response.data.token)
							uni.setStorageSync('userInfo', userInfo)
							uni.redirectTo({
								url:'/pages/index/index'
							})
						}else{
							error(response.errorInfo)
						}
					},1500)
				})
			},
			oneKeyLogin() {
				const _this = this
				if (!_this.isAgree) {
					error('请先同意相关协议')
					return
				}
				uni.login({
					provider: 'univerify',
					success(res) {
						_this.getPhoneNumber(res.authResult)
					},
					fail(res) {
						if(res.errorCode !== 30002 || res.errorCode !== 30003){
							error(res.errMsg)
						}
					}
				})
			},
			getPhoneNumber(data) {
				if (this.type === 1) {
					uniCloud.callFunction({
						name: 'getPhoneNumber',
						data: {
							'access_token': data.access_token,
							'openid': data.openid
						}
					}).then(res => {
						const result = res.result
						if(result.errorCode === 0){
							const params = { 
								openid: data.openid, 
								mobile: result.data, 
								type: 1,
							}
							login(params).then(response =>{
								uni.closeAuthView()
								if(response.errorCode === 0){
									uni.setStorageSync('token', response.data.token)
									uni.setStorageSync('userInfo', response.data.userInfo)
									uni.redirectTo({
										url:'/pages/index/index'
									})
								}else{
									error(response.errorInfo)
								}
							})
						}else{
							error('登录失败')
						}
					}).catch(err => {
						error('登录失败')
					})
				}

			},
			checkboxChange(e) {
				this.isAgree = e
			}
		}
	}
</script>

<style lang="scss">
	.wrap {
		width: 100%;
		height: 100vh;
		background-size: 100% 100vh;
		display: flex;
		flex-direction: column;
		align-items: center;
		padding-top: 77px;

		.logo {
			font-size: 46px;
			font-weight: 900;
			line-height: normal;
			text-transform: uppercase;
			letter-spacing: 0em;
			color: #FFFFFF;
		}

		.onekey {
			width: 308px;
			height: 45px;
			border-radius: 109px;
			display: flex;
			flex-direction: row;
			justify-content: center;
			align-items: center;
			gap: 4px;
			background: linear-gradient(107deg, #5EBBFF 21%, #5670FE 68%);
			box-shadow: 0px 4px 10px 0px #9DBBF7;
			margin-top: 368px;
			font-size: 16px;
			font-weight: bold;
			color: #FFFFFF;

		}

		.disabled {
			background: #909399 !important;
		}

		.text {
			font-size: 16px;
			font-weight: bold;
			color: #5288F5;
			margin-top: 30px;
		}

		.wx {
			display: flex;
			flex-direction: column;
			align-items: center;
			margin-top: 50px;

			image {
				width: 34px;
				height: 34px;
			}

			text {
				font-size: 12px;
				font-weight: 500;
				color: #272727;
				margin-top: 6px;
			}
		}

		.xieyi {
			width: 100%;
			margin-top: 35px;
			font-size: 12px;
			font-weight: 500;
			color: #121212;
		}
	}

	.wrap1 {
		width: 100%;
		height: 100vh;
		background-size: 100% 100vh;
		display: flex;
		flex-direction: column;
		padding: 106px 30px 0px;

		.title {
			font-size: 24px;
			font-weight: 900;
			line-height: normal;
			letter-spacing: -0.33px;
			color: #121212;
			margin-bottom: 130px;
		}

		.label {
			font-size: 14px;
			font-weight: 500;
			letter-spacing: 0em;
			color: #333333;
			margin-bottom: 12px;
		}

		.box {
			position: relative;
			height: 96rpx;
			display: flex;
			align-items: center;

			.code-btn {
				width: 113px;
				height: 37px;
				border-radius: 50px;
				display: flex;
				flex-direction: row;
				justify-content: center;
				align-items: center;
				font-size: 14px;
				font-weight: 500;
				color: #FFFFFF;
				margin-left: 12px;
				background: linear-gradient(124deg, #5EBBFF 19%, #5670FE 72%), linear-gradient(0deg, #5BADA6, #5BADA6), #81D8D0;
			}
		}

		input {
			width: 100%;
			height: 80rpx;
			border-radius: 100rpx;
			display: flex;
			font-size: 28rpx;
			font-weight: 500;
			flex-direction: row;
			align-items: center;
			padding-left: 30rpx;
			padding-right: 30rpx;
			color: rgba(23, 31, 7, 0.4);
			background-color: #FFFFFF;
			box-sizing: border-box;
			border: 2rpx solid #EEEEEE;
			line-height: normal;
			letter-spacing: 0em;
		}

		.ph {
			font-size: 28rpx;
			font-weight: 500;
			line-height: normal;
			letter-spacing: 0em;
			color: rgba(23, 31, 7, 0.4);
		}

		.submit {
			width: 100%;
			height: 48px;
			border-radius: 50px;
			display: flex;
			flex-direction: row;
			justify-content: center;
			align-items: center;
			font-size: 16px;
			font-weight: 900;
			color: #FFFFFF;
			margin-top: 70px;
			background: linear-gradient(107deg, #5EBBFF 21%, #5670FE 68%), linear-gradient(0deg, #5BADA6, #5BADA6), #81D8D0;
		}
	}
</style>

云函数部分

复制代码
'use strict';
exports.main = async (event, context) => {
	const res = await uniCloud.getPhoneNumber({
		appid: '__UNI__456561', // 替换成自己开通一键登录的应用的DCloud appid
		provider: 'univerify',
		access_token: event.access_token,
		openid: event.openid
	})
	if (res.errCode === 0) {
		return {
			errorCode: 0,
			errorInfo: '获取手机号成功',
			data: res.phoneNumber
		}
	} else {
		return {
			errorCode: 1,
			errorInfo: '获取手机号失败',
			data: null
		}
	}
};