13404089107
2026-04-29 3347da28f144928ba0280845f639357682b8d5e7
feat(login): 添加用户协议勾选与校验逻辑

- 在登录页面增加协议勾选框,包含《用户服务协议》和《隐私协议》链接
- 新增 `isAgreed` 状态变量和 `goProtocol` 方法用于跳转协议详情页
- 在微信登录、密码登录和验证码登录前调用 `ensureAgreementAccepted` 进行校验
- 用户未勾选协议时弹出提示并阻止登录操作
- 添加相关样式定义
1个文件已修改
62 ■■■■■ 已修改文件
traditionalApp/pages/login/login.vue 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traditionalApp/pages/login/login.vue
@@ -27,6 +27,15 @@
            </view>
        </view>
        <view class="agreement">
            <radio class="radio" :checked="isAgreed" color="#C63520" @tap="isAgreed = !isAgreed" />
            <text class="agreement-text">
                <text @tap="isAgreed = !isAgreed">我已阅读并同意</text>
                <text class="link" @tap="goProtocol('user')">《用户服务协议》</text>
                <text class="link" @tap="goProtocol('privacy')">《隐私协议》</text>
            </text>
        </view>
        <view class="login-btn" @tap="handleLogin">{{ loading ? '登录中...' : '登录' }}</view>
        <view class="action-links"
@@ -56,6 +65,7 @@
    const loginType = ref<'code' | 'password'>('code')
    const phone = ref('')
    const credential = ref('')
    const isAgreed = ref(false)
    const countdown = ref(0)
    const loading = ref(false)
    const inviteUserId = ref('')
@@ -202,10 +212,22 @@
    }
    /**
     * 打开协议详情页。
     */
    const goProtocol = (type : string) => {
        uni.navigateTo({
            url: `/pages/protocol/protocol?type=${type}`
        })
    }
    /**
     * 执行微信登录,优先将微信授权结果交给后端拉取昵称和头像。
     */
    const handleWechatLogin = async () => {
        if (loading.value) {
            return
        }
        if (!ensureAgreementAccepted()) {
            return
        }
        // #ifdef APP-PLUS
@@ -263,6 +285,9 @@
     */
    const handleAppleLogin = async () => {
        if (loading.value) {
            return
        }
        if (!ensureAgreementAccepted()) {
            return
        }
        // #ifdef APP-PLUS
@@ -547,6 +572,9 @@
        if (loading.value) {
            return
        }
        if (!ensureAgreementAccepted()) {
            return
        }
        const normalizedPhone = normalizePhone()
        if (!normalizedPhone) {
            return
@@ -683,6 +711,20 @@
            return ''
        }
        return value.trim()
    }
    /**
     * 登录前校验是否已阅读并同意协议。
     */
    const ensureAgreementAccepted = () => {
        if (isAgreed.value) {
            return true
        }
        uni.showToast({
            title: '请先阅读并同意相关协议',
            icon: 'none'
        })
        return false
    }
    /**
@@ -833,6 +875,26 @@
        margin-top: 48rpx;
    }
    .agreement {
        display: flex;
        align-items: center;
        margin-top: 40rpx;
        .radio {
            transform: scale(0.667);
            margin-right: 6rpx;
        }
        .agreement-text {
            font-size: 24rpx;
            color: #868686;
            .link {
                color: #333333;
            }
        }
    }
    .action-links {
        margin-top: 88rpx;
        display: flex;