mahjong_group/pages/me/login.vue
2025-09-08 12:47:02 +08:00

551 lines
10 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="bg-decoration">
<!-- 云朵装饰 -->
<view class="cloud cloud-1"></view>
<view class="cloud cloud-2"></view>
<view class="cloud cloud-3"></view>
<!-- 小鸟装饰 -->
<view class="bird bird-1"></view>
<view class="bird bird-2"></view>
</view>
<!-- 头部区域 -->
<view class="header">
<image src="@@:app/static/Logo.jpg" class="logo" mode="aspectFit"></image>
<text class="welcome-text">欢迎登录</text>
</view>
<!-- 登录表单 -->
<view class="login-form">
<!-- 一键登录按钮 -->
<view class="one-click-login">
<button v-if="agreedToTerms && isMobile" class="quick-login-btn" :class="{ disabled: loading }"
open-type="getPhoneNumber" @getphonenumber="mobileClickLogin">
<text>{{ loading ? '登录中...' : '一键登录' }}</text>
</button>
<button v-if="!agreedToTerms" class="quick-login-btn" :class="{ disabled: loading }"
@click="agreementClickLogin">
<text>{{ loading ? '登录中...' : '一键登录' }}</text>
</button>
<button v-if="agreedToTerms && !isMobile" class="quick-login-btn" :class="{ disabled: loading }"
@click="anonymousLoginClickLogin">
<text>{{ loading ? '登录中...' : '一键登录' }}</text>
</button>
</view>
<!-- 用户协议同意 -->
<view class="agreement-section">
<view class="agreement-checkbox" @click="toggleAgreement">
<checkbox :value="agreedToTerms" :checked="agreedToTerms"
style="transform:scale(0.5);margin-top: -8rpx;" />
<text class="agreement-text">
我已阅读并同意
<text class="agreement-link" @click.stop="showUserAgreement">《用户协议》</text>
<text class="agreement-link" @click.stop="showPrivacyPolicy">《隐私政策》</text>
</text>
</view>
</view>
<!-- 暂不登录按钮 -->
<view class="skip-login-btn" @click="skipLogin">
<text>暂不登录</text>
</view>
</view>
</view>
</template>
<script setup>
import {
ref,
reactive,
computed
} from 'vue'
import { useLogin } from '@/common/com'
import { getAnonymousLogin, ueWxPhoneNumberLogin, useWxAnonymousLogin } from '@/common/server/interface/user'
import { userInfo, loadUserInfo } from '@/common/server/user'
// 响应式数据
const loading = ref(false)
const agreedToTerms = ref(false)
// 方法
const toggleAgreement = () => {
agreedToTerms.value = !agreedToTerms.value
}
const agreementClickLogin = async () => {
if (loading.value) return
if (!agreedToTerms.value) {
uni.showToast({
title: '请先同意用户协议和隐私政策',
icon: 'none'
})
return
}
}
const mobileClickLogin = async (e) => {
console.log(e) // 动态令牌
console.log(e.detail.code) // 动态令牌
var code = e.detail.code;
loading.value = true
try {
// 这里调用一键登录API如运营商一键登录
// const response = await oneClickLoginApi()
var response = await ueWxPhoneNumberLogin(code, sessionAuthId);
if (response == null) {
uni.showToast({
title: '登录失败,请重试',
icon: 'error'
})
return;
}
uni.setStorageSync("tokenInfo", response);
await loadUserInfo();
uni.showToast({
title: '登录成功',
icon: 'success'
});
// 延迟跳转
setTimeout(() => {
uni.navigateBack()
}, 1500)
} catch (error) {
console.error('一键登录失败:', error)
uni.showToast({
title: '登录失败,请重试',
icon: 'error'
})
} finally {
loading.value = false
}
}
const anonymousLoginClickLogin = async (e) => {
console.log('aaa');
loading.value = true
try {
// 这里调用一键登录API如运营商一键登录
// const response = await oneClickLoginApi()
var response = await useWxAnonymousLogin(sessionAuthId);
if (response == null) {
uni.showToast({
title: '登录失败,请重试',
icon: 'error'
})
return;
}
uni.setStorageSync("tokenInfo", response);
await loadUserInfo();
uni.showToast({
title: '登录成功',
icon: 'success'
});
// 延迟跳转
setTimeout(() => {
uni.navigateBack()
}, 1500)
} catch (error) {
console.error('一键登录失败:', error)
uni.showToast({
title: '登录失败,请重试',
icon: 'error'
})
} finally {
loading.value = false
}
}
const skipLogin = () => {
uni.navigateBack()
}
const showUserAgreement = () => {
com.navigateToAgreement('userAgreement');
}
const showPrivacyPolicy = () => {
com.navigateToAgreement('privacyPolicy');
}
let isMobile = ref(false);
let sessionAuthId = null;
async function AnonymousLogin() {
var code = await useLogin();
console.log("res", code);
var res = await getAnonymousLogin(code);
if (res.user == 0) {
isMobile.value = true;
}
sessionAuthId = res.sessionAuthId;
}
onLoad(() => {
AnonymousLogin();
/* uni.login({
}) */
})
</script>
<style lang="scss" scoped>
.login-container {
min-height: 100vh;
background: linear-gradient(180deg, #87CEEB 0%, #98FB98 50%, #F0E68C 100%);
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.bg-decoration {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
// 云朵样式
.cloud {
position: absolute;
background: rgba(255, 255, 255, 0.8);
border-radius: 50rpx;
&::before,
&::after {
content: '';
position: absolute;
background: rgba(255, 255, 255, 0.8);
border-radius: 50%;
}
&.cloud-1 {
width: 120rpx;
height: 40rpx;
top: 15%;
left: 10%;
&::before {
width: 50rpx;
height: 50rpx;
top: -25rpx;
left: 10rpx;
}
&::after {
width: 60rpx;
height: 60rpx;
top: -30rpx;
right: 10rpx;
}
}
&.cloud-2 {
width: 100rpx;
height: 35rpx;
top: 25%;
right: 15%;
&::before {
width: 40rpx;
height: 40rpx;
top: -20rpx;
left: 8rpx;
}
&::after {
width: 50rpx;
height: 50rpx;
top: -25rpx;
right: 8rpx;
}
}
&.cloud-3 {
width: 80rpx;
height: 30rpx;
top: 70%;
left: 20%;
&::before {
width: 35rpx;
height: 35rpx;
top: -17rpx;
left: 6rpx;
}
&::after {
width: 40rpx;
height: 40rpx;
top: -20rpx;
right: 6rpx;
}
}
}
// 小鸟样式
.bird {
position: absolute;
width: 20rpx;
height: 15rpx;
background: #8B4513;
border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
&::before {
content: '';
position: absolute;
width: 8rpx;
height: 6rpx;
background: #8B4513;
border-radius: 50%;
top: 2rpx;
left: -5rpx;
transform: rotate(-20deg);
}
&.bird-1 {
top: 20%;
right: 25%;
animation: fly 3s ease-in-out infinite;
}
&.bird-2 {
top: 60%;
left: 15%;
animation: fly 4s ease-in-out infinite reverse;
}
}
// 花朵样式
.flower {
position: absolute;
width: 30rpx;
height: 30rpx;
&::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: radial-gradient(circle, #FFB6C1 30%, #FF69B4 70%);
border-radius: 50%;
}
&::after {
content: '';
position: absolute;
width: 6rpx;
height: 20rpx;
background: #228B22;
border-radius: 3rpx;
bottom: -20rpx;
left: 50%;
transform: translateX(-50%);
}
&.flower-1 {
top: 40%;
left: 8%;
animation: sway 2s ease-in-out infinite;
}
&.flower-2 {
top: 80%;
right: 10%;
animation: sway 2.5s ease-in-out infinite reverse;
}
&.flower-3 {
top: 50%;
right: 30%;
animation: sway 3s ease-in-out infinite;
}
}
// 动画效果
@keyframes fly {
0%,
100% {
transform: translateX(0) translateY(0);
}
25% {
transform: translateX(10rpx) translateY(-5rpx);
}
50% {
transform: translateX(20rpx) translateY(0);
}
75% {
transform: translateX(10rpx) translateY(5rpx);
}
}
@keyframes sway {
0%,
100% {
transform: rotate(0deg);
}
25% {
transform: rotate(2deg);
}
50% {
transform: rotate(0deg);
}
75% {
transform: rotate(-2deg);
}
}
@keyframes shine {
0% {
transform: translateX(-100%) translateY(-100%) rotate(45deg);
}
100% {
transform: translateX(100%) translateY(100%) rotate(45deg);
}
}
.header {
text-align: center;
margin-bottom: 80rpx;
.logo {
width: 200rpx;
height: 200rpx;
border-radius: 50%;
margin-bottom: 30rpx;
border: 8rpx solid #FFE4B5;
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.1);
}
.app-name {
display: block;
font-size: 48rpx;
font-weight: bold;
color: #8B4513;
margin-bottom: 20rpx;
text-shadow: 2rpx 2rpx 4rpx rgba(0, 0, 0, 0.1);
}
.welcome-text {
display: block;
font-size: 28rpx;
color: #228B22;
font-weight: 500;
}
}
.login-form {
padding: 0 60rpx;
width: 100%;
max-width: 600rpx;
}
.one-click-login {
margin: 40rpx 0;
.quick-login-btn {
background: linear-gradient(135deg, #F36903 0%, #E55A00 100%);
color: white;
height: 100rpx;
border-radius: 50rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
font-weight: bold;
box-shadow: 0 8rpx 20rpx rgba(243, 105, 3, 0.3);
border: 4rpx solid #FFE4B5;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transform: rotate(45deg);
transition: all 0.5s;
}
&:active::before {
animation: shine 0.6s ease-in-out;
}
&.disabled {
background: linear-gradient(135deg, #D3D3D3 0%, #A9A9A9 100%);
color: #666;
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.1);
}
.quick-login-icon {
width: 40rpx;
height: 40rpx;
margin-right: 15rpx;
}
}
}
.agreement-section {
margin: 30rpx 0;
.agreement-checkbox {
display: flex;
align-items: flex-start;
.checkbox {
width: 30rpx;
height: 30rpx;
margin-right: 15rpx;
margin-top: 5rpx;
flex-shrink: 0;
}
.agreement-text {
font-size: 24rpx;
color: #8B4513;
line-height: 1.5;
.agreement-link {
color: blue;
text-decoration: underline;
font-weight: 500;
}
}
}
}
.skip-login-btn {
text-align: center;
margin: 40rpx 0;
text {
font-size: 28rpx;
color: #8B4513;
text-decoration: underline;
font-weight: 500;
}
}
</style>