From 114c3d78ff8be7ceb9880ab236e81c24ca6d256f Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Sat, 25 Apr 2026 10:33:45 +0800
Subject: [PATCH] feat: 配置微信小程序隐私协议
---
src/pages/login/index.vue | 31 +++++++
src/manifest.json | 3
src/components/GetPrivacy.vue | 199 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 231 insertions(+), 2 deletions(-)
diff --git a/src/components/GetPrivacy.vue b/src/components/GetPrivacy.vue
new file mode 100644
index 0000000..8ab4609
--- /dev/null
+++ b/src/components/GetPrivacy.vue
@@ -0,0 +1,199 @@
+<template>
+ <view v-if="showPrivacy" :class="privacyClass">
+ <view :class="contentClass">
+ <view class="title">用户隐私保护指引</view>
+ <view class="des">
+ 感谢您选择使用掌控智飞小程序,我们非常重视您的个人信息安全和隐私保护。使用我们的产品前,请您仔细阅读“
+ <text class="link" @tap="openPrivacyContract">{{privacyContractName}} </text>”,
+ 如您同意此隐私保护指引,请点击同意按钮,开始使用此小程序,我们将尽全力保护您的个人信息及合法权益,感谢您的信任!<br />
+ </view>
+ <view class="btns">
+ <button class="item reject" @click="exitMiniProgram">拒绝</button>
+ <button id="agree-btn" class="item agree" open-type="agreePrivacyAuthorization"
+ @agreeprivacyauthorization="handleAgreePrivacyAuthorization">同意</button>
+ </view>
+ </view>
+ </view>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from 'vue';
+
+const props = defineProps({
+ position: {
+ type: String,
+ default: 'center'
+ }
+});
+
+const emit = defineEmits(['allowPrivacy']);
+
+const isRead = ref(false);
+const showPrivacy = ref(false);
+const privacyContractName = ref('');
+const resolvePrivacyAuthorization = ref(null);
+
+const privacyClass = computed(() => {
+ return props.position === 'bottom' ? 'privacy privacy-bottom' : 'privacy';
+});
+
+const contentClass = computed(() => {
+ return props.position === 'bottom' ? 'content content-bottom' : 'content';
+});
+
+onMounted(() => {
+ if (uni.onNeedPrivacyAuthorization) {
+ uni.onNeedPrivacyAuthorization((resolve) => {
+ resolvePrivacyAuthorization.value = resolve;
+ });
+ }
+
+ if (uni.getPrivacySetting) {
+ uni.getPrivacySetting({
+ success: (res) => {
+ if (res.needAuthorization) {
+ privacyContractName.value = res.privacyContractName;
+ showPrivacy.value = true;
+ } else {
+ console.log('已经同意隐私授权,不需要再次授权')
+ showPrivacy.value = false;
+ }
+ },
+ });
+ }
+});
+
+const openPrivacyContract = () => {
+ uni.openPrivacyContract({
+ success: () => {
+ isRead.value = true;
+ },
+ fail: () => {
+ uni.showToast({
+ title: '遇到错误',
+ icon: 'error',
+ });
+ },
+ });
+};
+
+const exitMiniProgram = () => {
+ wx.exitMiniProgram();
+};
+
+const handleAgreePrivacyAuthorization = () => {
+ showPrivacy.value = false;
+ emit('allowPrivacy');
+ if (typeof resolvePrivacyAuthorization.value === 'function') {
+ resolvePrivacyAuthorization.value({
+ buttonId: 'agree-btn',
+ event: 'agree',
+ });
+ }
+};
+
+const closePrivacy = () => {
+ showPrivacy.value = false;
+};
+
+// 暴露给父组件使用
+defineExpose({
+ closePrivacy
+});
+</script>
+
+<style scoped>
+.privacy {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ background: rgba(0, 0, 0, .5);
+ z-index: 9999999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.privacy-bottom {
+ align-items: flex-end;
+}
+
+.content {
+ width: 632rpx;
+ padding: 48rpx;
+ box-sizing: border-box;
+ background: #fff;
+ border-radius: 16rpx;
+}
+
+.content-bottom {
+ position: absolute;
+ bottom: 0;
+ width: 96%;
+ padding: 36rpx;
+ border-radius: 16rpx 16rpx 0 0;
+}
+
+.content .title {
+ text-align: center;
+ color: #333;
+ font-weight: bold;
+ font-size: 32rpx;
+}
+
+.content .des {
+ font-size: 26rpx;
+ color: #666;
+ margin-top: 40rpx;
+ text-align: justify;
+ line-height: 1.6;
+}
+
+.content .des .link {
+ color: #1989ff;
+ text-decoration: underline;
+}
+
+.btns {
+ margin-top: 48rpx;
+ margin-bottom: 12rpx;
+ display: flex;
+}
+
+.btns .item {
+ width: 200rpx;
+ height: 72rpx;
+ overflow: visible;
+ display: flex;
+ align-items: center;
+
+ justify-content: center;
+ /* border-radius: 16rpx; */
+ box-sizing: border-box;
+ border: none !important;
+}
+
+.btns .reject {
+ background: #f4f4f5;
+ color: #1989ff;
+ font-size: 14px;
+ background: #edf5fe;
+ font-weight: 300;
+ margin-right: 16rpx;
+}
+
+.btns .agree {
+ width: 200rpx;
+ background: #1989ff;
+ color: #fff;
+ font-size: 16px;
+
+}
+
+.privacy-bottom .btns .agree {
+ width: 440rpx;
+
+}
+</style>
diff --git a/src/manifest.json b/src/manifest.json
index 8e1964b..4ae1e30 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -79,7 +79,8 @@
"setting" : {
"urlCheck" : false
},
- "usingComponents" : true
+ "usingComponents" : true,
+ "__usePrivacyCheck__" : true
},
"mp-alipay" : {
"usingComponents" : true
diff --git a/src/pages/login/index.vue b/src/pages/login/index.vue
index 318b8a6..6964069 100644
--- a/src/pages/login/index.vue
+++ b/src/pages/login/index.vue
@@ -30,6 +30,10 @@
<button class="login-btn" :style="[inputStyle]" @tap="submit">登录</button>
<image class="lowerRightCorner" :src="droneSvg" />
+
+ <!-- #ifdef MP-WEIXIN -->
+ <GetPrivacy ref="privacyComponent" position="center" @allowPrivacy="allowPrivacy"/>
+ <!-- #endif -->
</view>
</template>
@@ -38,7 +42,9 @@
import md5 from "js-md5";
import { loginByUsername } from "@/api/user/index.js";
import { useUserStore } from "@/store/index.js";
-
+// #ifdef MP-WEIXIN
+import GetPrivacy from '@/components/GetPrivacy.vue'
+// #endif
import { HOME_PATH, LOGIN_PATH, removeQueryString } from "@/router";
import { onMounted } from "vue";
@@ -147,6 +153,29 @@
redirect = decodeURIComponent(options.redirect);
}
});
+
+// #ifdef MP-WEIXIN
+const allowPrivacy = () =>{
+
+ // 同意隐私协议触发事件,有些接口需要同意授权后才能执行,比如获取手机号授权接口,可以在同意隐私协议后,再执行授权获取手机号接口,如果不需要可以不添加该方法
+ console.log('同意隐私授权')
+}
+const privacyComponent =ref(null)
+onShow(() =>{
+ wx.getPrivacySetting({
+ success: res => {
+ console.log(res)
+ if (!res.needAuthorization) {
+ privacyComponent?.value?.closePrivacy()
+ // 查询授权,针对有tab切换的页面,可以在onshow中查询隐私授权状态,判断在tab切换后是否需要关闭授权弹框
+ console.log('已经同意隐私授权,不需要再次授权')
+ }
+ },
+ fail: () => {},
+ complete: () => {}
+ })
+})
+// #endif
</script>
<style lang="scss" scoped>
--
Gitblit v1.9.3