HomeLease/pages/login/login.vue
2025-08-19 09:44:40 +08:00

516 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="login-container">
<view class="logo-section">
<image :src="CommonEnum.LOGIN_SRC" class="logo-image"></image>
</view>
<view class="main-content">
<!-- 登录按钮 -->
<button :disabled="loginLoading" class="login-btn" @click="getPhoneNumber">
<text class="btn-text">{{ loginLoading ? '登录中...' : '微信用户一键登录' }}</text>
</button>
</view>
<!-- 底部协议 -->
<view class="agreement-section">
<view class="agreement-checkbox" @click="toggleAgreement">
<view :class="{ checked: hasAgreed }" class="checkbox">
<text v-if="hasAgreed" class="checkmark">✓</text>
</view>
</view>
<text class="agreement-text">我已阅读并同意</text>
<text class="agreement-link" @click="showServiceTerms">《服务协议》</text>
<text class="agreement-text">与</text>
<text class="agreement-link" @click="showPrivacyPolicy">《隐私政策》</text>
</view>
<!-- 服务条款弹窗 -->
<view v-if="showServiceTermsPopup" class="popup-overlay" @click="closeServiceTermsPopup">
<view class="popup-content" @click.stop>
<view class="popup-header">
<text class="popup-title">服务条款</text>
<text class="popup-close" @click="closeServiceTermsPopup">×</text>
</view>
<scroll-view
:scroll-top="scrollTop"
class="popup-body"
scroll-y="true"
show-scrollbar="true"
>
<view class="terms-content">
<rich-text :nodes="serviceTermsContent"></rich-text>
</view>
</scroll-view>
<view class="popup-footer">
<text class="popup-tip">请仔细阅读服务条款,阅读完毕后点击同意</text>
<button class="popup-btn" @click="agreeServiceTerms">同意</button>
</view>
</view>
</view>
<!-- 隐私政策弹窗 -->
<view v-if="showPrivacyPolicyPopup" class="popup-overlay" @click="closePrivacyPolicyPopup">
<view class="popup-content" @click.stop>
<view class="popup-header">
<text class="popup-title">隐私政策</text>
<text class="popup-close" @click="closePrivacyPolicyPopup">×</text>
</view>
<scroll-view
:scroll-top="scrollTop"
class="popup-body"
scroll-y="true"
show-scrollbar="true"
>
<view class="terms-content">
<rich-text :nodes="privacyPolicyContent"></rich-text>
</view>
</scroll-view>
<view class="popup-footer">
<text class="popup-tip">请仔细阅读隐私政策阅读完毕后点击同意</text>
<button class="popup-btn" @click="agreePrivacyPolicy">同意</button>
</view>
</view>
</view>
</view>
</template>
<script>
import { navigateToPage } from '@/utils/router.js'
import { wxLogin } from '@/api/auth/auth.js'
import { forceHideLoading, AutoLoadingManager } from '@/utils/request.js'
import { getServiceTerms, getPrivacyPolicy } from '@/api/article/article.js'
import { commonEnum } from '../../enum/commonEnum'
export default {
data() {
return {
loginLoading: false,
hasAgreed: false,
hasReadServiceTerms: false,
hasReadPrivacyPolicy: false,
showServiceTermsPopup: false,
showPrivacyPolicyPopup: false,
serviceTermsContent: '',
privacyPolicyContent: '',
scrollTop: 0,
}
},
computed: {
CommonEnum() {
return commonEnum
},
},
onLoad() {
this.pageLoading = new AutoLoadingManager()
},
onUnload() {
forceHideLoading()
if (this.pageLoading) {
this.pageLoading.destroy()
}
},
methods: {
toggleAgreement() {
if (this.hasReadServiceTerms && this.hasReadPrivacyPolicy) {
this.hasAgreed = !this.hasAgreed
} else {
uni.showToast({
title: '请先阅读服务条款和隐私政策',
icon: 'none',
})
}
},
async showServiceTerms() {
try {
const res = await getServiceTerms()
if (res.code === 200 && res.data) {
let content = res.data.content || '暂无服务条款内容'
content = content.replace(/\n/g, '<br/>')
content = `<div style="word-wrap: break-word; word-break: break-all; line-height: 1.8; font-size: 28rpx; color: #333; padding: 0; margin: 0;">${content}</div>`
this.serviceTermsContent = content
this.showServiceTermsPopup = true
this.scrollTop = 0
} else {
uni.showToast({
title: '获取服务条款失败',
icon: 'none',
})
}
} catch (error) {
console.error('获取服务条款失败:', error)
uni.showToast({
title: '获取服务条款失败',
icon: 'none',
})
}
},
async showPrivacyPolicy() {
try {
const res = await getPrivacyPolicy()
if (res.code === 200 && res.data) {
let content = res.data.content || '暂无隐私政策内容'
content = content.replace(/\n/g, '<br/>')
content = `<div style="word-wrap: break-word; word-break: break-all; line-height: 1.8; font-size: 28rpx; color: #333; padding: 0; margin: 0;">${content}</div>`
this.privacyPolicyContent = content
this.showPrivacyPolicyPopup = true
this.scrollTop = 0
} else {
uni.showToast({
title: '获取隐私政策失败',
icon: 'none',
})
}
} catch (error) {
console.error('获取隐私政策失败:', error)
uni.showToast({
title: '获取隐私政策失败',
icon: 'none',
})
}
},
closeServiceTermsPopup() {
this.showServiceTermsPopup = false
},
closePrivacyPolicyPopup() {
this.showPrivacyPolicyPopup = false
},
async agreeServiceTerms() {
this.hasReadServiceTerms = true
this.closeServiceTermsPopup()
this.checkAgreementStatus()
if (!this.hasReadPrivacyPolicy) {
setTimeout(() => {
this.showPrivacyPolicy()
}, 500)
}
},
async agreePrivacyPolicy() {
this.hasReadPrivacyPolicy = true
this.closePrivacyPolicyPopup()
this.checkAgreementStatus()
if (!this.hasReadServiceTerms) {
setTimeout(() => {
this.showServiceTerms()
}, 500)
}
},
checkAgreementStatus() {
if (this.hasReadServiceTerms && this.hasReadPrivacyPolicy) {
this.hasAgreed = true
}
},
async showUnreadTerms() {
if (!this.hasReadServiceTerms) {
await this.showServiceTerms()
return
}
if (!this.hasReadPrivacyPolicy) {
await this.showPrivacyPolicy()
}
},
getPhoneNumber() {
if (!this.hasReadServiceTerms || !this.hasReadPrivacyPolicy) {
uni.showToast({
title: '请先阅读服务条款和隐私政策',
icon: 'none',
duration: 2000,
})
this.showUnreadTerms()
return
}
const that = this
uni.login({
success(res) {
if (res.code) {
console.log('登录!', res)
const data = {
loginCode: res.code,
}
if (that.pageLoading) {
that.pageLoading.show('登录中...')
}
wxLogin(data)
.then(res => {
if (that.pageLoading) {
that.pageLoading.hide()
}
forceHideLoading()
if (res.code == 200) {
console.log(res, 'resres')
uni.setStorageSync('token', res.token)
uni.showToast({
title: '登录成功',
icon: 'success',
duration: 1500,
})
setTimeout(() => {
that.ceshi()
}, 1500)
} else {
uni.showToast({
title: res.msg || '登录失败',
icon: 'none',
})
}
})
.catch(error => {
if (that.pageLoading) {
that.pageLoading.hide()
}
forceHideLoading()
console.error('登录失败:', error)
uni.showToast({
title: '登录失败',
icon: 'none',
})
})
}
},
fail(err) {
console.error('微信登录失败:', err)
uni.showToast({
title: '微信登录失败',
icon: 'none',
})
},
})
},
async ceshi() {
if (this.pageLoading) {
this.pageLoading.hide()
}
forceHideLoading()
navigateToPage('index')
},
},
}
</script>
<style lang="scss" scoped>
page {
background: #ffffff;
}
.login-container {
padding-bottom: 40rpx;
max-width: 750rpx;
background: #ffffff;
}
.logo-section {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 80rpx;
width: 100%;
margin-top: 330rpx;
//border:green 1px solid;
}
.logo-image {
width: 276rpx;
height: 276rpx;
}
.main-content {
padding: 0 53rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 654rpx;
//border: red 1px solid;
}
.login-btn {
width: 100%;
height: 98rpx;
background: #f15a04;
border-radius: 10rpx;
border: none;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
box-shadow: 0 4rpx 12rpx rgba(255, 107, 53, 0.3);
}
.login-btn:active {
transform: translateY(2rpx);
box-shadow: 0 2rpx 8rpx rgba(255, 107, 53, 0.3);
}
.login-btn:disabled {
background: #ccc;
box-shadow: none;
}
.btn-text {
font-size: 32rpx;
font-weight: 600;
color: #fff;
}
.agreement-section {
display: flex;
align-items: center;
justify-content: center;
gap: 8rpx;
padding: 30rpx;
margin-top: 40rpx;
flex-wrap: wrap;
}
.agreement-checkbox {
display: flex;
align-items: center;
}
.checkbox {
width: 28rpx;
height: 28rpx;
border: 2rpx solid #ff6b35;
border-radius: 6rpx;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
transition: all 0.3s ease;
}
.checkbox.checked {
background: #ff6b35;
border-color: #ff6b35;
}
.checkmark {
color: #fff;
font-size: 18rpx;
font-weight: bold;
}
.agreement-text {
font-size: 24rpx;
color: #666;
}
.agreement-link {
font-size: 24rpx;
color: #ff6b35;
text-decoration: underline;
}
.popup-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx;
box-sizing: border-box;
}
.popup-content {
background: #fff;
border-radius: 20rpx;
overflow: hidden;
display: flex;
flex-direction: column;
width: 100%;
max-width: 680rpx;
height: 85vh;
max-height: 900rpx;
min-height: 600rpx;
margin: 0;
}
.popup-header {
padding: 30rpx;
border-bottom: 1rpx solid #eee;
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
}
.popup-title {
font-size: 32rpx;
font-weight: 500;
color: #333;
}
.popup-close {
font-size: 40rpx;
color: #999;
cursor: pointer;
padding: 10rpx;
}
.popup-body {
flex: 1;
padding: 30rpx;
overflow: hidden;
position: relative;
height: 0;
}
.terms-content {
line-height: 1.8;
font-size: 28rpx;
color: #333;
word-wrap: break-word;
word-break: break-all;
padding-bottom: 20rpx;
}
.popup-footer {
padding: 30rpx;
border-top: 1rpx solid #eee;
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
}
.popup-tip {
font-size: 24rpx;
color: #999;
margin-bottom: 20rpx;
text-align: center;
}
.popup-btn {
width: 200rpx;
height: 70rpx;
background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
border-radius: 35rpx;
font-size: 28rpx;
color: #ffffff;
border: none;
}
</style>