2024年8月21日 15:59 by wst
小程序登陆注册是一个系统最基本的功能,今天花了一点时间把这个两个功能实现了。
1.登陆方式为手机号登陆,可以密码登录或者验证码登录;
2.验证码发送完60秒内不能在发送第二次;
3.只有前端部分的实现,开发框架为uniapp;
登录
<template>
<view class="content">
<view class="topBox">
<view class="tit">
欢迎登陆
</view>
<view class="desc">
没有账号?
<navigator
url="/pages/register/register"
open-type="navigate"
hover-class="navigator-hover"
>
去注册
</navigator>
</view>
</view>
<view class="bottomBox">
<view class="item">
<view class="label">
账号
</view>
<input type="text" v-model="phone" placeholder="请输入您的手机号码" />
</view>
<view class="item" v-if="login_type==1">
<view class="label">
密码
</view>
<input type="password" v-model="password" placeholder="请输入您的密码" />
</view>
<view class="item" v-if="login_type==2">
<view class="label">
验证码
</view>
<view class="yzmBox">
<input type="text" v-model="checkcode" placeholder="请输入验证码" />
<view class="yzm" @click="send">
{{ login_VerifyCode }}
</view>
</view>
</view>
<button type="default" @click="submit">登陆</button>
</view>
<view class="agree" v-if="login_type==1">
<text>忘记密码?采用验</text>
<view class="protocol" @click="changeType">证码登陆</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
const phone = ref();
const password = ref();
const checkcode = ref();
const login_type = ref(1); // 默认密码登陆
const login_VerifyCode = ref("获取验证码"); //发送验证码按钮显示文字
const login_timer = ref(false); //验证码计时器
const timer = ref(); // 计时器
function send() {
// 检测输入-手机号
var {flag, msg} = checkPhone(phone.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
if(login_VerifyCode.value == '获取验证码' || login_VerifyCode.value == '重新发送'){
// todo 发送验证码给后台
let code = 1;
if(code == 1){
uni.showToast({
title: "发送验证码"
})
login_timer.value = true
var total_micro_second = 60;
// 验证码倒计时
count_down(total_micro_second);
} else {
uni.showToast({
title: "发送错误",
icon: "error"
})
}
}
}
/**
* 倒计时 验证码
* @param {*} total_micro_second
* @returns
*/
function count_down(total_micro_second) { //发送验证码按钮
if (total_micro_second <= 0) {
login_VerifyCode.value = "重新发送"
// timeout则跳出递归
return false;
} else {
// 渲染倒计时时钟
login_VerifyCode.value = total_micro_second + "s"
total_micro_second--;
if (login_timer.value == true) {
timer = setTimeout(function () {
count_down(total_micro_second);
}, 1000)
} else {
login_VerifyCode.value = "获取验证码"
}
}
}
function checkPhone(val) {
if (!/^1((34[0-8])|(8\d{2})|(([35][0-35-9]|4[579]|66|7[35678]|9[1389])\d{1}))\d{7}$/.test(val)) {
return {flag:false, msg:"请输入正确的手机号"}
} else {
return {flag: true, msg: "手机号正确"}
}
}
function checkPassword(val){
var pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z]).{8,30}');
if(!pwdRegex.test(val)){
return {flag: false, msg: '您的密码复杂度太低(密码中必须包含字母、数字),请及时修改密码!'}
} else {
return {flag: true, msg: "密码格式正确"}
}
}
function checkInputCode(val){
var checkRegex = new RegExp('[0-9]{6}');
if(!checkRegex.test(val)){
return {flag: false, msg: '验证码错误'}
} else {
return {flag: true, msg: "验证码格式正确"}
}
}
function submit() {
console.log("phone:", phone.value, "password:", password.value, "checkcode:", checkcode.value)
// 检测输入-手机号
var {flag, msg} = checkPhone(phone.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
// 检测输入-密码
var {flag, msg} = checkPassword(password.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
// 检测输入-验证码
var {flag, msg} = checkInputCode(checkcode.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
// 提交给后台 todo
console.log("submit success")
uni.navigateTo({
url:"/pages/register/register"
})
}
/**修改登陆类型 */
function changeType(){
login_type.value = 2; // 验证码登陆
}
</script>
<style lang="scss" scoped>
.content {
min-height: 100vh;
}
.topBox {
position: relative;
height: 400rpx;
background-color: #00aaff;
}
.tit {
width: 90%;
font-size: 60rpx;
color: #ffffff;
position: absolute;
bottom: 40%;
left: 50%;
transform: translateX(-50%);
font-weight: 600;
}
.desc {
width: 90%;
font-size: 30rpx;
color: #f8f8f8;
position: absolute;
bottom: 25%;
left: 50%;
transform: translateX(-50%);
display: flex;
navigator {
font-weight: 800;
}
}
.bottomBox {
margin-top: 20rpx;
min-height: 500rpx;
padding: 50rpx;
}
.item {
margin-bottom: 60rpx;
border-bottom: 1px solid #ccc;
}
.item .label {
font-size: 32rpx;
color: #00aaff;
font-weight: 600;
margin-bottom: 20rpx;
}
.item input {
height: 70rpx;
padding-bottom: 20rpx;
font-size: 32rpx;
color: #333;
}
.uni-input-placeholder {
color: #bebebe;
}
.yzmBox {
display: flex;
justify-content: space-between;
align-items: center;
}
.yzm {
color: #ffffff;
font-size: 28rpx;
padding: 5rpx 8rpx;
background-color: #00aaff;
}
button {
line-height: 85rpx;
text-align: center;
background: rgb(0, 170, 255);
color: #fff;
margin-top: 100rpx;
}
.agree {
position: fixed;
bottom: 60rpx;
left: 20%;
text-align: center;
width: 100%;
color: #919191;
font-size: 30rpx;
display: flex;
.protocol{
color: #00aaff;
}
}
</style>
注册
<template>
<view class="content">
<view class="topBox">
<view class="tit">
新用户注册
</view>
<view class="desc">
已有账号?
<navigator
url="/pages/login/login"
open-type="navigate"
hover-class="navigator-hover"
>
去登录
</navigator>
</view>
</view>
<view class="bottomBox">
<view class="item">
<view class="label">
账号
</view>
<input type="text" v-model="phone" placeholder="请输入您的手机号码" />
</view>
<view class="item">
<view class="label">
密码
</view>
<input type="password" v-model="password" placeholder="请输入您的密码" />
</view>
<view class="item">
<view class="label">
验证码
</view>
<view class="yzmBox">
<input type="text" v-model="checkcode" placeholder="请输入验证码" />
<view class="yzm" @click="send">
{{ login_VerifyCode }}
</view>
</view>
</view>
<button type="default" @click="submit">注册</button>
</view>
<view class="agree">
注册代表您同意
<text class="protocol">用户隐私协议</text>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
const phone = ref();
const password = ref();
const checkcode = ref();
const login_VerifyCode = ref("获取验证码"); //发送验证码按钮显示文字
const login_timer = ref(false); //验证码计时器
const timer = ref(); // 计时器
function send() {
// 检测输入-手机号
var {flag, msg} = checkPhone(phone.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
if(login_VerifyCode.value == '获取验证码' || login_VerifyCode.value == '重新发送'){
// todo 发送验证码给后台
let code = 1;
if(code == 1){
uni.showToast({
title: "发送验证码"
})
login_timer.value = true
var total_micro_second = 60;
// 验证码倒计时
count_down(total_micro_second);
} else {
uni.showToast({
title: "发送错误",
icon: "error"
})
}
}
}
/**
* 倒计时 验证码
* @param {*} total_micro_second
* @returns
*/
function count_down(total_micro_second) { //发送验证码按钮
if (total_micro_second <= 0) {
login_VerifyCode.value = "重新发送"
// timeout则跳出递归
return false;
} else {
// 渲染倒计时时钟
login_VerifyCode.value = total_micro_second + "s"
total_micro_second--;
if (login_timer.value == true) {
timer = setTimeout(function () {
count_down(total_micro_second);
}, 1000)
} else {
login_VerifyCode.value = "获取验证码"
}
}
}
function checkPhone(val) {
if (!/^1((34[0-8])|(8\d{2})|(([35][0-35-9]|4[579]|66|7[35678]|9[1389])\d{1}))\d{7}$/.test(val)) {
return {flag:false, msg:"请输入正确的手机号"}
} else {
return {flag: true, msg: "手机号正确"}
}
}
function checkPassword(val){
var pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z]).{8,30}');
if(!pwdRegex.test(val)){
return {flag: false, msg: '您的密码复杂度太低(密码中必须包含字母、数字),请及时修改密码!'}
} else {
return {flag: true, msg: "密码格式正确"}
}
}
function checkInputCode(val){
var checkRegex = new RegExp('[0-9]{6}');
if(!checkRegex.test(val)){
return {flag: false, msg: '验证码错误'}
} else {
return {flag: true, msg: "验证码格式正确"}
}
}
function submit() {
console.log("phone:", phone.value, "password:", password.value, "checkcode:", checkcode.value)
// 检测输入-手机号
var {flag, msg} = checkPhone(phone.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
// 检测输入-密码
var {flag, msg} = checkPassword(password.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
// 检测输入-验证码
var {flag, msg} = checkInputCode(checkcode.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
// 提交给后台 todo
console.log("submit success")
uni.navigateTo({
url:"/pages/register/register"
})
}
</script>
<style lang="scss" scoped>
.content {
min-height: 100vh;
}
.topBox {
position: relative;
height: 400rpx;
background-color: #00aaff;
}
.tit {
width: 90%;
font-size: 60rpx;
color: #ffffff;
position: absolute;
bottom: 40%;
left: 50%;
transform: translateX(-50%);
font-weight: 600;
}
.desc {
width: 90%;
font-size: 30rpx;
color: #f8f8f8;
position: absolute;
bottom: 25%;
left: 50%;
transform: translateX(-50%);
display: flex;
navigator {
font-weight: 800;
}
}
.bottomBox {
margin-top: 20rpx;
min-height: 500rpx;
padding: 50rpx;
}
.item {
margin-bottom: 60rpx;
border-bottom: 1px solid #ccc;
}
.item .label {
font-size: 32rpx;
color: #00aaff;
font-weight: 600;
margin-bottom: 20rpx;
}
.item input {
height: 70rpx;
padding-bottom: 20rpx;
font-size: 32rpx;
color: #333;
}
.uni-input-placeholder {
color: #bebebe;
}
.yzmBox {
display: flex;
justify-content: space-between;
align-items: center;
}
.yzm {
color: #ffffff;
font-size: 28rpx;
padding: 5rpx 8rpx;
background-color: #00aaff;
}
button {
line-height: 85rpx;
text-align: center;
background: rgb(0, 170, 255);
color: #fff;
margin-top: 100rpx;
}
.agree {
position: fixed;
bottom: 60rpx;
left: 0;
text-align: center;
width: 100%;
color: #919191;
font-size: 30rpx;
.protocol{
color: #00aaff;
}
}
</style>
修改密码
<template>
<view class="content">
<view class="topBox">
<view class="tit">
重置密码
</view>
</view>
<view class="bottomBox">
<view class="item">
<view class="label">
账号
</view>
<input type="text" v-model="phone" placeholder="请输入您的手机号码" />
</view>
<view class="item">
<view class="label">
新密码
</view>
<view class="uni-input-wrapper">
<input class="uni-input" placeholder="请输入新密码" :password="showPassword" />
<uni-icons :type="showPassword?'smallcircle-filled':'smallcircle'" size="30" @click="changePassword"></uni-icons>
</view>
</view>
<view class="item">
<view class="label">
验证码
</view>
<view class="yzmBox">
<input type="text" v-model="checkcode" placeholder="请输入验证码" />
<view class="yzm" @click="send">
{{ login_VerifyCode }}
</view>
</view>
</view>
<button type="default" @click="submit">确定</button>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { BASE_URL } from '../../config';
const phone = ref();
const password = ref();
const checkcode = ref();
const login_VerifyCode = ref("获取验证码"); //发送验证码按钮显示文字
const login_timer = ref(false); //验证码计时器
const timer = ref(); // 计时器
const showPassword = ref(true); // 密码是否显示
/**切换是否显示密码 */
function changePassword() {
showPassword.value = !showPassword.value;
}
function send() {
// 检测输入-手机号
var {flag, msg} = checkPhone(phone.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
if(login_VerifyCode.value == '获取验证码' || login_VerifyCode.value == '重新发送'){
// 发送验证码给后台
console.log("start send check code.")
uni.request({
url:BASE_URL+'/admin/change/ck',
data:{phone: phone.value},
success:(success)=>{
console.log("ck-res:", success.data)
if(success.data.code == 1){
uni.showToast({
title: "发送成功"
})
} else {
uni.showToast({
title: success.data.message,
icon: "error"
})
}
},
fail:(fail)=>{
uni.showToast({
title: "发送错误",
icon: "error"
})
},
complete:(complete)=>{
console.log("complete:", complete)
login_timer.value = true
var total_micro_second = 60;
// 验证码倒计时
count_down(total_micro_second);
},
})
}
}
/**
* 倒计时 验证码
* @param {*} total_micro_second
* @returns
*/
function count_down(total_micro_second) { //发送验证码按钮
if (total_micro_second <= 0) {
login_VerifyCode.value = "重新发送"
// timeout则跳出递归
return false;
} else {
// 渲染倒计时时钟
login_VerifyCode.value = total_micro_second + "s"
total_micro_second--;
if (login_timer.value == true) {
timer = setTimeout(function () {
count_down(total_micro_second);
}, 1000)
} else {
login_VerifyCode.value = "获取验证码"
}
}
}
function checkPhone(val) {
if (!/^1((34[0-8])|(8\d{2})|(([35][0-35-9]|4[579]|66|7[35678]|9[1389])\d{1}))\d{7}$/.test(val)) {
return {flag:false, msg:"请输入正确的手机号"}
} else {
return {flag: true, msg: "手机号正确"}
}
}
function checkPassword(val){
var pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z]).{8,30}');
if(!pwdRegex.test(val)){
return {flag: false, msg: '您的密码复杂度太低(密码中必须包含字母、数字),请及时修改密码!'}
} else {
return {flag: true, msg: "密码格式正确"}
}
}
function checkInputCode(val){
var checkRegex = new RegExp('[0-9]{6}');
if(!checkRegex.test(val)){
return {flag: false, msg: '验证码错误'}
} else {
return {flag: true, msg: "验证码格式正确"}
}
}
function submit() {
console.log("phone:", phone.value, "password:", password.value, "checkcode:", checkcode.value)
// 检测输入-手机号
var {flag, msg} = checkPhone(phone.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
// 检测输入-密码
var {flag, msg} = checkPassword(password.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
// 检测输入-验证码
var {flag, msg} = checkInputCode(checkcode.value)
if(!flag){
uni.showToast({
title: msg,
icon: "error"
})
return false
}
// 提交给后台
uni.request({
url:BASE_URL+'/admin/change/password',
method:'POST',
header:{'content-type':'application/x-www-form-urlencoded; charset=UTF-8'},
data:{phone:phone.value, password: password.value, check_code: checkcode.value},
success:(success)=>{
console.log("res-register:", success.data)
if(success.data.code == 1){
uni.showToast({
title: '密码修改成功',
icon: 'success'
})
uni.switchTab({
url:"/pages/login/login"
})
} else {
uni.showToast({
title: '密码修改失败',
icon: 'error'
})
}
},
})
console.log("submit success")
}
</script>
<style lang="scss" scoped>
.content {
min-height: 100vh;
}
.topBox {
position: relative;
height: 400rpx;
background-color: #00aaff;
}
.tit {
width: 90%;
font-size: 60rpx;
color: #ffffff;
position: absolute;
bottom: 40%;
left: 50%;
transform: translateX(-50%);
font-weight: 600;
}
.desc {
width: 90%;
font-size: 30rpx;
color: #f8f8f8;
position: absolute;
bottom: 25%;
left: 50%;
transform: translateX(-50%);
display: flex;
navigator {
font-weight: 800;
}
}
.bottomBox {
margin-top: 20rpx;
min-height: 500rpx;
padding: 50rpx;
}
.item {
margin-bottom: 60rpx;
border-bottom: 1px solid #ccc;
}
.item .label {
font-size: 32rpx;
color: #00aaff;
font-weight: 600;
margin-bottom: 20rpx;
}
.item input {
height: 70rpx;
padding-bottom: 20rpx;
font-size: 32rpx;
color: #333;
}
.uni-input-wrapper{
display: flex;
align-items: center;
justify-content: space-between;
}
.uni-input-placeholder {
color: #bebebe;
}
.yzmBox {
display: flex;
justify-content: space-between;
align-items: center;
}
.yzm {
width: 30%;
text-align: center;
color: #ffffff;
font-size: 28rpx;
padding: 5rpx 8rpx;
background-color: #00aaff;
}
button {
line-height: 85rpx;
text-align: center;
background: rgb(0, 170, 255);
color: #fff;
margin-top: 100rpx;
}
.agree {
position: fixed;
bottom: 60rpx;
left: 0;
text-align: center;
width: 100%;
color: #919191;
font-size: 30rpx;
.protocol{
color: #00aaff;
}
}
</style>