完成了登录模块

This commit is contained in:
2025-05-17 23:17:14 +08:00
parent c10a348001
commit e5e3f5b38d
33 changed files with 2860 additions and 115 deletions

View File

@ -0,0 +1,181 @@
// pages/login/login.js
const { baseUrl } = require('../../../request');
const { validate } = require('../../../utils/validate');
Page({
data: {
loginType: 'password', // 'password' 或 'sms'
phone: '',
credential: '',
isAgree: false, // 用户协议是否勾选
countdown: 0, // 剩余秒数
codeButtonText: '获取验证码',
_timer: null
},
// 切换到“密码登录”,只清空表单字段
switchToPassword() {
this.setData({
loginType: 'password',
phone: '',
credential: ''
// 不清除 countdown、codeButtonText、_timer
});
},
// 切换到“验证码登录”,只清空表单字段
switchToSms() {
this.setData({
loginType: 'sms',
phone: '',
credential: ''
// 不清除 countdown、codeButtonText、_timer
});
},
// 手机号输入
onPhoneInput(e) {
this.setData({ phone: e.detail.value });
},
// 密码/验证码输入
onCredentialInput(e) {
this.setData({ credential: e.detail.value });
},
// 协议勾选
onAgreeChange(e) {
this.setData({ isAgree: e.detail.value.includes('agree') });
},
// 获取验证码(仅校验手机号)
getSmsCode() {
const { phone } = this.data;
// 1. 非空校验
if (!validate(this.data, { phone: '请输入手机号' })) {
return;
}
// 2. 格式校验
if (!/^1\d{10}$/.test(phone)) {
return wx.showToast({ title: '手机号格式不正确', icon: 'none' });
}
// 3. 发送验证码请求
wx.request({
url: baseUrl + '/userInfo/code',
method: 'POST',
data: { templateString: phone },
success: () => {
wx.showToast({ title: '验证码已发送', icon: 'none' });
this._startCountdown(60);
},
fail: () => {
wx.showToast({ title: '发送失败,请重试', icon: 'none' });
}
});
},
// 开始倒计时
_startCountdown(seconds) {
this.setData({
countdown: seconds,
codeButtonText: `${seconds}s后重试`
});
// 如果已有定时器,不重复创建
if (this.data._timer) return;
this.data._timer = setInterval(() => {
const cd = this.data.countdown - 1;
if (cd <= 0) {
this._clearTimer();
this.setData({
countdown: 0,
codeButtonText: '获取验证码'
});
} else {
this.setData({
countdown: cd,
codeButtonText: `${cd}s后重试`
});
}
}, 1000);
},
// 清除倒计时定时器
_clearTimer() {
if (this.data._timer) {
clearInterval(this.data._timer);
this.data._timer = null;
}
},
// 登录
onLogin() {
const { loginType, phone, credential, isAgree } = this.data;
// 非空校验(手机号、密码/验证码、协议)
if (!validate(this.data, {
phone: '请输入手机号',
credential: loginType === 'password' ? '请输入密码' : '请输入验证码',
isAgree: '请先同意用户协议'
})) {
return;
}
// 手机号格式校验
if (!/^1\d{10}$/.test(phone)) {
return wx.showToast({ title: '手机号格式不正确', icon: 'none' });
}
// 组装请求
const url = loginType === 'password'
? baseUrl + '/userInfo/mini/pwd/login'
: baseUrl + '/userInfo/mini/vcd/login';
const payload = loginType === 'password'
? { phoneNumber: phone, userPassword: credential }
: { phoneNumber: phone, verificationCode: credential };
wx.request({
url,
method: 'POST',
data: payload,
success: res => {
if (res.data.code === 1) {
// ← 新增:从返回数据中取出 token
const token = res.data.data.token || res.data.data;
// ← 新增:将 token 存到本地缓存
wx.setStorageSync('token', token);
wx.showToast({ title: '登录成功', icon: 'success' });
wx.navigateTo({
url: '/pages/projectModule/projectList/projectList'
});
} else {
wx.showToast({
title: res.data.message || '登录失败',
icon: 'none'
});
}
},
fail: () => {
wx.showToast({ title: '网络错误,请重试', icon: 'none' });
}
});
},
gotoForgetPwd() {
wx.navigateTo({
url: '/pages/loginModule/forgetPwd/forgetPwd',
})
},
gotoRegister() {
wx.navigateTo({
url: '/pages/loginModule/register/register',
})
},
// 页面卸载时清理定时器
onUnload() {
this._clearTimer();
}
});

View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

View File

@ -0,0 +1,87 @@
<view class="flex-col page">
<image
class="self-center image"
src="https://ide.code.fun/api/image?token=6827630f4ae84d00122fd0c8&name=f8bf0cb3ec8201f89a31727a655c0709.png"
/>
<text class="self-center text">欢迎登陆—青橙校园</text>
<view class="flex-col self-stretch group">
<!-- 切换登录方式 -->
<view class="flex-row">
<text
class="font switch {{loginType==='password'?'active':'inactive'}} text_2"
bindtap="switchToPassword"
>密码登录</text>
<text
class="font switch {{loginType==='sms'?'active':'inactive'}} text_3 ml-8"
bindtap="switchToSms"
>验证码登录</text>
</view>
<view class="flex-col group_1 mt-20">
<!-- 手机号输入 -->
<view class="flex-col self-stretch">
<view class="flex-col justify-start relative section">
<input
class="flex-col justify-start items-start text-wrapper view input"
placeholder="请输入手机号"
maxlength="11"
model:value="{{phone}}"
bindinput="onPhoneInput"
/>
</view>
<!-- 密码 / 验证码 输入 + 获取验证码按钮 -->
<view class="flex-row items-center section_2 mt-21">
<input
class="flex-col justify-start items-start text-wrapper_2 view_2 input_1"
placeholder="{{ loginType==='password' ? '请输入密码' : '请输入验证码' }}"
password="{{ loginType==='password' }}"
model:value="{{credential}}"
bindinput="onCredentialInput"
/>
<text
wx:if="{{loginType==='sms'}}"
class="text_6 ml-10 get-code {{ countdown>0 ? 'disabled' : '' }}"
bindtap="{{ countdown>0 ? '' : 'getSmsCode' }}"
>{{ codeButtonText }}</text>
</view>
</view>
<text class="self-end font_3 text_7" bindtap="gotoForgetPwd">忘记密码</text>
<!-- 登录按钮 -->
<view
class="flex-col justify-start items-center self-stretch text-wrapper_3 login-button"
bindtap="onLogin"
>
<text class="text_8">登录</text>
</view>
<!-- 用户协议勾选 -->
<view class="flex-row items-center self-stretch group_2">
<checkbox-group bindchange="onAgreeChange">
<checkbox
class="checkbox"
value="agree"
checked="{{isAgree}}"
bindchange="onAgreeChange"
color="#FF8D1A"
/>
</checkbox-group>
<view class="group_3 ml-12">
<text class="font_4 text_9">登录代表您已同意</text>
<text class="font_4">《用户协议》</text>
<text class="text_10">&</text>
<text class="font_4">《隐私协议》</text>
</view>
</view>
<view class="self-center group_4">
<text class="font_3 text_11">没有账号?</text>
<text class="font_4 text_12" bindtap="gotoRegister">去注册→</text>
</view>
</view>
</view>
</view>

View File

@ -0,0 +1,163 @@
/* 切换按钮样式 */
.switch {
font-size: 30rpx; /* 基础字体大小 */
font-family: SourceHanSansCN;
}
.switch.active {
font-size: 36rpx; /* 激活时更大 */
font-weight: bold; /* 加粗 */
color: #1c2023;
}
.switch.inactive {
color: #888888; /* 不活跃时灰色 */
}
/* 其它原来样式保持不变 */
.mt-21 {
margin-top: 39.38rpx;
}
.page {
padding: 105rpx 45.69rpx 381.68rpx 49.76rpx;
background-color: #ffffff;
width: 100%;
overflow: hidden;
height: 100%;
}
.image {
width: 232.5rpx;
height: 232.5rpx;
}
.text {
margin-top: 35.14rpx;
color: #1c2023;
font-size: 37.5rpx;
font-family: AlibabaPuHuiTi;
line-height: 35.21rpx;
}
.group {
margin-top: 145.01rpx;
}
.font {
font-size: 30rpx;
font-family: SourceHanSansCN;
line-height: 27.69rpx;
color: #1c2023;
}
.text_2 {
line-height: 28.29rpx;
}
.text_3 {
line-height: 28.2rpx;
}
.group_1 {
padding-left: 2.74rpx;
}
.section {
margin-right: 4.93rpx;
padding: 20.63rpx 0 18.75rpx;
background-color: #ffffff;
border-radius: 9.38rpx;
box-shadow: 0rpx 3.75rpx 11.25rpx #00000040;
}
.text-wrapper {
margin-left: 16.88rpx;
margin-right: 16.88rpx;
}
.view {
padding: 15.92rpx 0 12.64rpx;
background-color: #ffffff00;
}
.section_2 {
margin-right: 4.93rpx;
padding: 20.63rpx 16.88rpx 18.75rpx;
background-color: #ffffff;
border-radius: 9.38rpx;
box-shadow: 0rpx 3.75rpx 7.5rpx #00000040;
}
.text-wrapper_2 {
flex: 1 1 0;
}
.view_2 {
padding: 11.96rpx 0 16.43rpx;
background-color: #ffffff00;
height: 76.25rpx;
}
.text_6 {
margin-right: 14.72rpx;
color: #f7810a;
font-size: 26.25rpx;
font-family: AlibabaPuHuiTi;
line-height: 23.94rpx;
}
.get-code {
/* 可根据需求再调样式 */
}
.font_3 {
font-size: 26.25rpx;
font-family: SourceHanSansCN;
line-height: 24.49rpx;
color: #383838;
}
.text_7 {
margin-top: 28.76rpx;
line-height: 24.36rpx;
}
.text-wrapper_3 {
margin-right: 4.93rpx;
margin-top: 46.26rpx;
padding: 36.73rpx 0 34.16rpx;
background-color: #ff8d1a;
border-radius: 9.38rpx;
}
.text_8 {
color: #ffffff;
font-size: 30rpx;
font-family: AlibabaPuHuiTi;
line-height: 26.61rpx;
}
.group_2 {
margin-top: 48.75rpx;
}
.group_3 {
line-height: 24.49rpx;
height: 24.56rpx;
}
.font_4 {
font-size: 26.25rpx;
font-family: SourceHanSansCN;
line-height: 24.49rpx;
color: #ff5e00;
}
.text_9 {
color: #1c2023;
line-height: 24.43rpx;
}
.text_10 {
color: #1c2023;
font-size: 26.25rpx;
font-family: SourceHanSansCN;
line-height: 19.93rpx;
}
.group_4 {
margin-top: 43.91rpx;
line-height: 24.41rpx;
}
.text_11 {
line-height: 24.28rpx;
}
.text_12 {
line-height: 24.41rpx;
}
.input {
padding: 15rpx 16.26rpx 13.13rpx 16.26rpx;
}
.input_1 {
padding: 15rpx 16.26rpx 13.13rpx 16.26rpx;
}
.checkbox {
flex-shrink: 0;
}
.checkbox .wx-checkbox-input {
width: 37.5rpx;
height: 37.5rpx;
}