uniapp实现用户隐私协议授权

1,949 阅读3分钟

先贴个效果图:

838e9330f82bf2370b62bfcc874808c.png
这里弹框我单独封装成了组件,哪里用哪里拿就行
(需要从向父组件一个参数visible,这个参数是用于当用户点击同意/不同意 都需要关闭弹窗)

<template>
    <view class="comp-container">
            <view class="dialog">
                    <view class="title">用户隐私保护提示</view>
                          <view class="desc">
                              感谢您使用本小程序,在使用前您应当阅读并同意<text class="privacy" @click="handleOpenPrivacyContract">《用户隐私保护指引》</text>,当点击同意,即表示您已理解并同意该条款内容,该条款将对您产生法律约束力;如您不同意,将无法继续使用小程序相关功能。
                          </view>
				<view class="footer">
					<button type="default" class="btn disagree" @click="handleDisagree">不同意</button>
					<button type="default" open-type="agreePrivacyAuthorization" class="btn agree" @agreeprivacyauthorization="handleAgree">同意</button>
                           </view>
			</view>
		</view>
</template>

<script setup>
import { defineEmits } from 'vue'
const emit = defineEmits(['getVisible'])
	const visible = null;
	function handleDisagree() {
		// 处理用户不同意隐私协议的逻辑
		 emit('getVisible',false); 
		uni.exitMiniProgram()
	}
	function handleAgree() {
		// 处理用户同意隐私协议的逻辑
		emit('getVisible',false); 
	}
	function handleOpenPrivacyContract(){
		uni.openPrivacyContract()
	}
</script>
<style lang="scss" scoped>
.comp-container {
		position: fixed;
		top: 0;
		right: 0;
		left: 0;
		bottom: 0;
		background-color: rgba(0, 0, 0, 0.6);
		z-index: 999;
	}

	.dialog {
		color: #333;
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		background-color: #fff;
		border-radius: 20rpx;
		padding: 50rpx 40rpx;
		width: 560rpx;
		box-sizing: border-box;

		.title {
			width: 100%;
			color: #000;
			text-align: center;
			font-size: 32rpx;
			font-weight: 650;
			box-sizing: border-box;
		}

		.desc {
			line-height: 40rpx;
			box-sizing: border-box;
			margin-top: 50rpx;
			font-size: 26rpx;

			.privacy {
				color: #2f80ed;
			}
		}

		.footer {
			width: 100%;
			display: flex;
			align-items: center;
			justify-content: space-between;
			margin-top: 30rpx;

			.btn {
				display: flex;
				align-items: center;
				color: #FFF;
				font-size: 28rpx;
				font-weight: 500;
				line-height: 80rpx;
				text-align: center;
				height: 80rpx;
				border-radius: 10rpx;
				border: none;
				background: #07c160;
				flex: 1;
				justify-content: center;

				&:nth-last-child(1) {
					margin-left: 30rpx;
				}

				&.disagree {
					color: #333;
					background: #f2f2f2;
				}
			}
		}

	}

</style>

为了方便小白食用,附上组件使用的页面,需要的自取(一般都在登录页用)

<template>
	<view class="content">
		<!-- <img src="../../static/image/logo.png" alt="" class="logo"/> -->
		<view class='form'>
			<text class="login-title">账号登录</text>
			<uni-forms ref="formRef" :modelValue="formData" :rules="formRules" validate-trigger="submit">
				<uni-forms-item class="input-item" name="UserName">
					<view class="iconfont icon-yonghuming"></view>
					<input type="text" v-model="formData.UserName" placeholder="请输入用户名" />
				</uni-forms-item>
				
				<uni-forms-item class="input-item" name="PassWord">
					<view class="iconfont icon-mima"></view>
					<input type="text" v-model="formData.PassWord" placeholder="请输入密码" :password="showPassword"/>
					<text class="iconfont" :class="[!showPassword ? 'icon-yanjing_xianshi' : 'icon-yanjing_yincang']"
					@click="changePassword"></text>
				</uni-forms-item>
				<uni-forms-item class="input-item" name="isChecked">
				<view class="checkbox">
					<uni-data-checkbox multiple v-model="formData.isChecked" :localdata="hobby" class="checkbox-box"></uni-data-checkbox>
					<text class="agreement-title" @click='openAgreement'>《用户服务协议》</text>
					<text></text>
					<text class="agreement-title" @click='openAgreement'>《用户隐私协议》</text>
					<PrivacyDialog v-if='visible' @getVisible='getVisible'/>
				</view>
				</uni-forms-item>
			</uni-forms>
			<button @click="submit" class="button">登录</button>
		</view>
	</view>
</template>

<script setup>
	import {login} from '../../request/api.js'
	import {alert} from '../../components/msg/msgPrompt.js'
	import PrivacyDialog from '../../components/privacyDialog/index.vue'
	import {ref, reactive, nextTick } from "vue"
	import {onLoad,onReady} from "@dcloudio/uni-app"
	const visible = ref(false);
	const formData=reactive({
			UserName:'123456',
			PassWord:'123456',
			isChecked:[],
			})
	const hobby=reactive([{text: '',value: 0}])
	const checkbox1=reactive( [0])
	const showPassword=ref(true)
	const formRef = ref(null)
	// 校验规则
	function setFormRules(){
		return {
			UserName: {
				rules: [{
					required: true,
					errorMessage: '用户名不能为空'
					}]
				},
			PassWord: {
				rules: [{
					required: true,
					errorMessage: '密码不能为空'
					}]
			},
			isChecked: {
				rules: [{
					required: true,
					errorMessage: '请先勾选用户协议'
                                },{
                                        validateFunction:function(rule,value,data,callback){
								if (value.length !==1) {
									callback('请先勾选用户协议')
								}
								return true
								}
							}]
						}
					}
		  
	}
	const formRules = setFormRules();
	// 设置校验规则
	onReady(() => {
	    formRef.value.setRules(formRules);
	    })
	// 密码显示与隐藏
	 function changePassword() {
		showPassword.value = !showPassword.value;
	}
	onLoad(()=>{
			uni.getPrivacySetting({
				success: res => {
					//用户之前同意过隐私协议则会返回false;如果开发者声明了隐私收集,且用户还没同意过则返回true
					if (res.needAuthorization) {
						//需要显示隐私协议弹框
						visible.value = true;
					} else {
						//不需要显示隐私协议弹框
						visible.value = false;
							}
					},
					fail: () => {
					}
				})
	})
	function getVisible(visib){
		visible.value = visib;
	}
	function openAgreement(){
		uni.openPrivacyContract()
	}
	function submit(ref) {
			formRef.value.validate().then(result => {
					const params={
						 "password": result.PassWord,
						 "userName": result.UserName
					}
					login(params).then( res => {
						if(res.code === 200){
							uni.navigateTo({
								url:'/pages/index/index'
							});
							const id = {
								"id":res.data.id
							}
							uni.setStorageSync('userInfo', {...params,...id});
							uni.setStorageSync('token',res.data.token);
						}else if(res.code === 201){
							alert(res.message);
						}
					}).catch(err => {
						console.log(err);
					});
				}).catch(err => {
					console.log('表单校验失败', err);
				})
			}
</script>

<style lang="scss">
.content{
	background:linear-gradient(180deg, #F1FAEE 0%, #1b9fff   80%);
	height: 100vh;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	.logo{
		width: 150rpx;
		height: 150rpx;
		margin-bottom: 100rpx;
		margin-top: 20rpx;
	}
	.form{
		width: 70%;
		background-color: #fff;
		padding: 40rpx 20rpx 40rpx;
		display: flex;
		flex-direction: column;
		align-items: center;
		border-radius: 80rpx;
		box-shadow: 10px 10px 10px 3px rgba(100,100,100, 0.75);
		.uni-data-checklist{
			width: 10rpx;
			padding-right: 15rpx;
		}
	}
	.agreement-title{
		color: #1b9fff;
		cursor: pointer;
	}
	.checkbox{
		display: flex;
		align-items: center;
		font-size: 24rpx;
		.checkbox-box{
			margin-right: 10rpx;
		}
		
	}
	.login-title{
		font-size: 44rpx;
		margin-bottom: 60rpx;
		margin-top: 0;
	}
	.uni-forms{
		width: 100%;
		.uni-forms-item__content{
			display: flex;
			align-items: center;
			gap: 16rpx;
			padding: 0 20rpx;
			border-bottom: #fff solid 1px;
			height: 80rpx;
			input{
				flex: 1;
			}
		.iconfont{
			font-size: 36rpx;
		}
	}	
	/* #ifdef H5 */ 
	::v-deep .uni-forms-item__content{
		display: flex;
		align-items: center;
		gap: 8px;
		padding: 0 10px;
		border-bottom: #fff solid 1px;
		height: 60px;
		input{
			flex: 1;
		}
		.iconfont{
			font-size: 18px;
		}
	}
	/* #endif */
	
	}
	
	.button{
		color: #fff;
		height: 30;
		width: 80%;
		border-radius: 40rpx;
		background-color: #1b9fff;
	}
}
</style>