Ai_GirlFriend/xuniYou/pages/login/index.vue

798 lines
18 KiB
Vue
Raw Normal View History

2026-01-31 19:15:41 +08:00
<template>
<view>
<uni-nav-bar fixed statusBar background-color="transparent" :border="false" @clickLeft="back"></uni-nav-bar>
<view class="back"></view>
<view class="body">
<image class="logo"
src="https://nvlovers.oss-cn-qingdao.aliyuncs.com/uploads/20251226/7d4ea9bb621e68e9fc641fa3c357f678.png"
mode="aspectFill"></image>
<view class="list">
<view class="list_content">
<view class="list_module fa">
<image src="/static/images/login_phone.png" mode="widthFix"></image>
<input class="f1" v-model="form.mobile" placeholder="请输入手机号" placeholder-class="list_input" />
</view>
<!-- <view class="list_detail faj">
<image src="/static/images/login_errors.png" mode="widthFix"></image>
<view class="list_errors">手机号输入错误请重新输入</view>
</view> -->
</view>
2026-02-01 10:03:21 +08:00
<view class="list_content" v-if="!isDev">
2026-01-31 19:15:41 +08:00
<view class="list_module fa">
<image src="/static/images/login_password.png" mode="widthFix"></image>
<input type="password" class="f1" v-model="form.password" placeholder="请输入密码"
placeholder-class="list_input" />
</view>
<!-- <view class="list_detail faj">
<image src="/static/images/login_errors.png" mode="widthFix"></image>
<view class="list_errors">密码输入错误请重新输入</view>
</view> -->
</view>
2026-02-01 10:03:21 +08:00
<!-- 开发模式提示 -->
<view v-if="isDev" class="dev-tip">
<text>🔧 开发模式只需输入手机号即可登录</text>
</view>
2026-02-01 13:59:38 +08:00
<!-- 邀请码输入框 -->
<view class="list_content">
<view class="list_module fa">
<image src="/static/images/login_code.png" mode="widthFix"></image>
<input class="f1" v-model="inviteCode" placeholder="邀请码(选填)"
placeholder-class="list_input" />
</view>
<view v-if="inviteCode" class="invite-tip">
<text> 使用邀请码可获得5金币奖励</text>
</view>
</view>
2026-01-31 19:15:41 +08:00
<!-- <view class="list_content">
<view class="list_module fa">
<image src="/static/images/login_code.png" mode="widthFix"></image>
<input class="f1" v-model="form.captcha" placeholder="请输入手机验证码"
placeholder-class="list_input" />
<view class="list_obtain faj" @click="codeClick()">获取验证码</view>
</view>
<view class="list_detail faj">
<image src="/static/images/login_errors.png" mode="widthFix"></image>
<view class="list_errors">验证码输入错误请重新输入</view>
</view>
</view> -->
<view class="list_logo faj" :class="{ 'active': isInputFilled }" @click="submit()">立即登录</view>
<view class="list_prompt fa sb">
<view class="list_text">首次登录即为注册</view>
<view class="list_forgotPassword" @click="toforgotPassword()">忘记密码?</view>
</view>
</view>
<view class="module fa sb">
<view class="module_content f1 faj fc">
<!-- #ifdef MP-WEIXIN -->
<button class="module_weixin faj fc" v-if="dataLogin.id == 0" open-type="getPhoneNumber"
@getphonenumber="getPhoneNumber" :plain="true" hover-class="none">
<image src="/static/images/login_weixin.png" mode="widthFix"></image>
<view class="module_title">微信登录</view>
</button>
<view v-else class="f1 faj fc" @click="wxphoneloginClcik">
<image src="/static/images/login_weixin.png" mode="widthFix"></image>
<view class="module_title">微信登录</view>
</view>
<!-- #endif -->
<!-- #ifdef APP -->
<view class="f1 faj fc" @click="wxphoneloginClcik1">
<image src="/static/images/login_weixin.png" mode="widthFix"></image>
<view class="module_title">微信登录</view>
</view>
<!-- #endif -->
</view>
<view class="module_content f1 faj fc" @click="tiktokLogin()">
<image src="/static/images/login_douyin.png" mode="widthFix"></image>
<view class="module_title">抖音登录</view>
</view>
</view>
<view class="opt">
<view class="opt_content">
<view class="opt_module faj">
<view class="opt_select faj" @click="selectClick()">
<image :src="selectStats ? '/static/images/selectA.png' : '/static/images/select.png'"
mode="widthFix"></image>
</view>
<view class="opt_text">
<view class="opt_name">阅读并同意<text>运营商认证服务协议</text></view>
<view class="opt_name"><text>软件许可及服务协议</text><text>隐私协议</text></view>
</view>
<view class="opt_prompt faj">
<view class="opt_tip faj"><text></text>请先勾选协议</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
Mobilelogin,
Wxapplogin,
Send,
WxappGetPhone,
AppLoginWx
} from '@/utils/api.js'
import {
isPhone,
getWxCode
} from '@/utils/utils.js'
import notHave from '@/components/not-have.vue';
import topSafety from '@/components/top-safety.vue';
export default {
components: {
notHave,
topSafety,
},
data() {
return {
2026-02-01 10:03:21 +08:00
isDev: true, // 开发模式开关,上线时改为 false
2026-01-31 19:15:41 +08:00
statusBarHeight: uni.getWindowInfo().statusBarHeight,
form: {
mobile: '',
password: '',
captcha: 223344,
wxapp_code: '',
},
formregister: {
mobile: '',
event: 'register',
},
dataLogin: [],
selectStats: false,
2026-02-01 13:59:38 +08:00
inviteCode: '', // 邀请码
baseURLPy: 'http://127.0.0.1:8000',
2026-01-31 19:15:41 +08:00
}
},
computed: {
isInputFilled() {
return this.form.mobile.trim() !== '' && this.form.password.trim() !== '';
}
},
2026-02-01 13:59:38 +08:00
onLoad(options) {
console.log('登录页面')
// 从 URL 参数获取邀请码
if (options && options.invite) {
this.inviteCode = options.invite;
uni.showToast({
title: '已自动填入邀请码',
icon: 'success'
});
}
2026-01-31 19:15:41 +08:00
// #ifdef MP
this.Login()
// #endif
},
methods: {
async Login() {
console.log('Login',)
let code = await getWxCode();
Wxapplogin({
code: code
}).then(res => {
console.log('code换取',res)
this.dataLogin = res.data
console.log(this.dataLogin)
}).catch(err => {
uni.showToast({
title: "登录失败,请重试",
icon: 'none',
position: 'top'
})
})
},
// 微信手机号登录
getPhoneNumber(e) {
if (!this.selectStats) {
uni.showToast({
title: "请阅读并同意协议",
icon: 'none',
position: 'top'
})
return;
}
WxappGetPhone({
code: e.detail.code,
login_token: this.dataLogin.login_token,
}).then(res => {
console.log(res)
console.log(res.code)
console.log(res.msg)
if (res.code == 1) {
uni.setStorageSync("token", res.data.userinfo.token)
uni.setStorageSync("userinfo", res.data.userinfo)
uni.showToast({
title: res.msg,
icon: 'success',
position: 'top'
})
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index'
})
}, 1000)
} else {
uni.showToast({
title: res.msg,
icon: 'none',
position: 'top'
})
}
}).catch(err => {
uni.showToast({
title: "登录失败,请重试",
icon: 'none',
position: 'top'
})
})
},
wxphoneloginClcik1() {
let that = this;
uni.getProvider({
service: 'oauth',
success: function(res) {
console.log('是否安装了微信', res.provider);
},
fail(e) {
uni.showToast({ title:e.errMsg, icon:'none' })
}
});
if (!this.selectStats) {
uni.showToast({
title: "请阅读并同意协议",
icon: 'none',
position: 'top'
})
return;
}
uni.showLoading({
title:'登录中...',
mask:true
})
uni.login({
provider: 'weixin',
success: (res) => {
console.log('微信登陆', res)
uni.getUserInfo({
provider: 'weixin',
success: (infoRes) => {
console.log('infoRes', infoRes)
let userInfo = infoRes.userInfo
console.log('openid:', userInfo.openId, 'unionid:', userInfo.unionId)
// uni.showLoading({ title: "登录中", mask: true })
// 利用微信授权获取到的用户信息 请求登录
// 判断是否注册
// that.upImage(userInfo);
that.app_login(userInfo)
}
})
},
fail: (err) => {
uni.hideLoading()
console.log('微信登陆失败', err)
if (err.code == -2) {
this.setShowToast(err.errMsg)
}
if (err.code == '-100') {
// requestPayment:fail [payment支付宝:62001]用户中途取消支付操作
this.setShowToast(err.errMsg)
}
}
})
},
app_login(userInfo){
console.log('userInfo',userInfo)
AppLoginWx({
openid: userInfo.openId,//'oRrdQt41cXAihKalNnuulzIVGMEs',//
}).then(res => {
console.log('APP微信登录',res)
let data = res.data
if(res.code == 1){
this.dataLogin = data
if(data.id == 0){
uni.showToast({
title:'继续绑定手机号登录',
icon:'none'
})
}else{
this.wxphoneloginClcik()
}
uni.hideLoading()
}
}).catch(err => {
uni.showToast({
title: "登录失败,请重试",
icon: 'none',
position: 'top'
})
})
},
wxphoneloginClcik() {
if (!this.selectStats) {
uni.showToast({
title: "请阅读并同意协议",
icon: 'none',
position: 'top'
})
return;
}
uni.setStorageSync("token", this.dataLogin.userinfo.token)
uni.setStorageSync("userinfo", this.dataLogin.userinfo)
uni.showToast({
title: '登录成功',
icon: 'success',
position: 'top'
})
setTimeout(() => {
uni.reLaunch({
url: '/pages/index/index'
})
}, 1000)
},
tiktokLogin() {
// TODO: 实现抖音登录逻辑
uni.showToast({
title: '抖音登录功能即将开放',
icon: 'none'
});
},
codeClick() {
// 验证手机号
if (this.form.mobile == '') {
uni.showToast({
title: "请输入手机号",
icon: 'none',
position: 'top'
})
return;
} else if (!isPhone(this.form.mobile)) {
uni.showToast({
icon: "none",
title: "请输入正确手机号"
})
return;
}
this.formregister.mobile = this.form.mobile;
this.send();
},
send() {
Send(this.formregister).then(res => {
if (res.code == 1) {
uni.showToast({
title: res.msg,
icon: 'none',
position: 'top'
})
} else {
uni.showToast({
title: res.msg,
icon: 'none',
position: 'top'
})
}
}).catch(err => {
uni.showToast({
title: "验证码发送失败",
icon: 'none',
position: 'top'
})
})
},
async mobilelogin() {
// #ifdef mp-weixin
let code = await getWxCode();
this.form.wxapp_code = loginRes.code
// #endif
// #ifdef APP
if(this.dataLogin.id == 0 && this.dataLogin.login_token){
this.form.login_token = this.dataLogin.login_token
}
// #endif
Mobilelogin(this.form).then(res => {
if (res.code == 1) {
uni.showToast({
title: res.msg,
icon: 'none',
position: 'top'
})
uni.setStorageSync("token", res.data.userinfo.token)
uni.setStorageSync("userinfo", res.data.userinfo)
2026-02-01 13:59:38 +08:00
// 如果有邀请码,尝试使用
if (this.inviteCode && this.inviteCode.trim()) {
this.applyInviteCode();
} else {
setTimeout(() => {
uni.navigateTo({
url: '/pages/index/index'
})
}, 1000);
}
2026-01-31 19:15:41 +08:00
} else if (res.code == 0) {
console.log('提示错误信息')
console.log(res)
uni.showToast({
title: res.msg,
icon: 'none',
position: 'top'
})
}
})
},
2026-02-01 13:59:38 +08:00
// 使用邀请码
applyInviteCode() {
uni.request({
url: this.baseURLPy + '/config/invite/apply',
method: 'POST',
header: {
'Content-Type': 'application/json',
'token': uni.getStorageSync("token") || "",
},
data: {
invite_code: this.inviteCode
},
success: (res) => {
if (res.data.code === 1) {
uni.showToast({
title: res.data.data.message,
icon: 'success'
});
} else {
// 邀请码使用失败,不影响登录
console.log('邀请码使用失败:', res.data.message);
}
},
fail: (err) => {
console.error('邀请码请求失败:', err);
},
complete: () => {
// 无论成功失败,都跳转到首页
setTimeout(() => {
uni.navigateTo({
url: '/pages/index/index'
})
}, 1500);
}
});
},
2026-01-31 19:15:41 +08:00
selectClick() {
if (this.selectStats) {
this.selectStats = false
} else {
this.selectStats = true
}
},
submit() {
2026-02-01 10:03:21 +08:00
// 使用 data 中的开发模式开关
2026-01-31 19:15:41 +08:00
if (!this.selectStats) {
uni.showToast({
title: "请阅读并同意协议",
icon: 'none',
position: 'top'
})
2026-02-01 10:03:21 +08:00
return;
}
if (this.form.mobile == '') {
2026-01-31 19:15:41 +08:00
uni.showToast({
title: "请输入手机号",
icon: 'none',
position: 'top'
})
2026-02-01 10:03:21 +08:00
return;
}
if (!isPhone(this.form.mobile)) {
2026-01-31 19:15:41 +08:00
uni.showToast({
icon: "none",
title: "请输入正确手机号"
})
2026-02-01 10:03:21 +08:00
return;
}
// 开发环境:跳过密码和验证码验证
if (this.isDev) {
console.log('开发模式:跳过密码验证');
// 自动填充密码和验证码
this.form.password = this.form.password || '123456';
this.form.captcha = this.form.captcha || 223344;
this.mobilelogin();
return;
}
// 生产环境:正常验证
if (this.form.password == '') {
2026-01-31 19:15:41 +08:00
uni.showToast({
title: "请输入密码",
icon: 'none',
position: 'top'
})
2026-02-01 10:03:21 +08:00
return;
}
if (this.form.captcha == '') {
2026-01-31 19:15:41 +08:00
uni.showToast({
title: "请输入验证码",
icon: 'none',
position: 'top'
})
2026-02-01 10:03:21 +08:00
return;
2026-01-31 19:15:41 +08:00
}
2026-02-01 10:03:21 +08:00
this.mobilelogin();
2026-01-31 19:15:41 +08:00
},
back() {
uni.navigateBack({
delta: 1,
});
},
toforgotPassword() {
uni.navigateTo({
url: '/pages/login/password'
})
}
}
}
</script>
<style>
.body {
position: relative;
}
.back {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 436rpx;
background: linear-gradient(180deg, #EAD6FF 0%, rgba(255, 255, 255, 0) 100%);
}
.body {
position: relative;
padding: 0 60rpx;
}
.logo {
position: relative;
margin: 136rpx auto 0 auto;
width: 166rpx;
height: 166rpx;
border-radius: 28rpx;
display: block;
}
.list {
position: relative;
margin: 124rpx 0 0 0;
}
.list_content {
position: relative;
margin: 72rpx 0 0 0;
}
2026-02-01 10:03:21 +08:00
/* 开发模式提示 */
.dev-tip {
margin: 30rpx 0;
padding: 20rpx 30rpx;
background: linear-gradient(90deg, #FFF3E0, #FFE0B2);
border-radius: 12rpx;
border-left: 6rpx solid #FF9800;
}
.dev-tip text {
font-size: 26rpx;
color: #E65100;
line-height: 40rpx;
}
2026-02-01 13:59:38 +08:00
/* 邀请码提示 */
.invite-tip {
margin-top: 10rpx;
padding: 10rpx 20rpx;
background: #E8F5E9;
border-radius: 8rpx;
}
.invite-tip text {
font-size: 24rpx;
color: #2E7D32;
}
2026-01-31 19:15:41 +08:00
.list_module {
position: relative;
padding: 20rpx 30rpx;
background: #F9F9F9;
border-radius: 16rpx;
}
.list_module image {
margin: 0 20rpx 0 0;
width: 48rpx;
height: 48rpx;
}
.list_module input {
font-weight: 500;
font-size: 30rpx;
color: #000000;
line-height: 42rpx;
}
.list_logo.active {
color: #FFFFFF;
background: #9F47FF;
}
.list_content:nth-child(3) .list_module {
padding: 12rpx 30rpx;
}
.list_input {
color: #9E9E9E;
}
.list_detail {
position: absolute;
left: 0;
bottom: -60rpx;
padding: 8rpx 12rpx 6rpx 12rpx;
font-weight: 400;
font-size: 28rpx;
color: #FF0A1F;
line-height: 42rpx;
background: #FFF6F7;
border-radius: 4rpx;
}
.list_detail image {
margin: 0 14rpx 0 0;
width: 28rpx;
height: 28rpx;
}
.list_obtain {
padding: 8rpx 20rpx;
font-weight: 400;
font-size: 28rpx;
color: #9F47FF;
line-height: 42rpx;
background: #F3E9FF;
border-radius: 16rpx;
}
.list_logo {
position: relative;
margin: 66rpx 0 0 0;
padding: 24rpx 0;
font-weight: 500;
font-size: 30rpx;
color: #9E9E9E;
line-height: 42rpx;
background: #F9F9F9;
border-radius: 16rpx;
}
.list_prompt {
position: relative;
margin: 30rpx 0 0 0;
font-weight: 400;
font-size: 28rpx;
color: #9E9E9E;
line-height: 42rpx;
}
.module {
position: relative;
margin: 76rpx 0 0 0;
}
.module_content {
position: relative;
}
.module_weixin {
border: none !important;
}
.module_content image {
width: 88rpx;
height: 88rpx;
display: block;
border-radius: 100rpx;
}
.module_title {
margin: 20rpx 0 0 0;
font-weight: 400;
font-size: 28rpx;
color: #9E9E9E;
line-height: 50rpx;
}
.opt {
position: fixed;
bottom: 30rpx;
left: 0;
right: 0;
margin: 0 auto;
}
.opt_content {
position: relative;
}
.opt_module {
position: relative;
}
.opt_select {
position: relative;
}
.opt_select image {
margin: 0 24rpx 0 0;
width: 32rpx;
height: 32rpx;
}
.opt_prompt {
position: absolute;
left: 0;
right: 0;
top: -100rpx;
margin: 0 auto;
}
.opt_tip {
position: relative;
padding: 14rpx 0;
width: 222rpx;
font-weight: 400;
font-size: 30rpx;
color: #FFFFFF;
line-height: 42rpx;
background: #9F47FF;
border-radius: 12rpx;
}
.opt_tip::after {
content: '';
position: absolute;
bottom: -8rpx;
left: 50%;
transform: translateX(-50%);
width: 16rpx;
height: 16rpx;
background: #9F47FF;
border-radius: 0 0 4rpx 0;
transform: translateX(-50%) rotate(45deg);
}
.opt_text {
font-weight: 500;
font-size: 26rpx;
color: #9E9E9E;
line-height: 42rpx;
}
.opt_text text {
color: #9F85FA;
}
.opt_name {
text-align: center;
}
</style>