Initial commit
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
<template>
|
||||
<view class="login-container">
|
||||
<scroll-view class="content-scroll" direction="vertical">
|
||||
<!-- Logo区域 -->
|
||||
<view class="logo-section">
|
||||
<image class="logo" src="/static/logo.png" mode="aspectFit"></image>
|
||||
<text class="app-title">家长学情</text>
|
||||
<text class="app-subtitle">陪伴孩子的每一次进步</text>
|
||||
</view>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<view class="form-section">
|
||||
<text class="form-title">登录家长端</text>
|
||||
<text class="form-subtitle">使用注册的手机号与密码登录,查看孩子学情</text>
|
||||
|
||||
<!-- 手机号输入 -->
|
||||
<view class="input-wrapper">
|
||||
<input
|
||||
class="input-field"
|
||||
type="number"
|
||||
v-model="form.phone"
|
||||
placeholder="请输入手机号"
|
||||
maxlength="11"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 密码输入 -->
|
||||
<view class="input-wrapper">
|
||||
<input
|
||||
class="input-field"
|
||||
type="password"
|
||||
v-model="form.password"
|
||||
placeholder="请输入密码"
|
||||
maxlength="20"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 记住密码和忘记密码 -->
|
||||
<view class="option-row">
|
||||
<view class="remember-row" @tap="form.remember = !form.remember">
|
||||
<view :class="form.remember ? 'checkbox-checked' : 'checkbox'"></view>
|
||||
<text class="remember-text">记住密码</text>
|
||||
</view>
|
||||
<text class="forgot-text" @tap="handleForgotPassword">忘记密码?</text>
|
||||
</view>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<view
|
||||
class="btn-login"
|
||||
:class="canSubmit ? 'btn-login-active' : 'btn-login-disabled'"
|
||||
@tap="handleLogin"
|
||||
>
|
||||
<text class="btn-text">登录</text>
|
||||
</view>
|
||||
|
||||
<!-- 切换验证码登录 -->
|
||||
<text class="switch-text" @tap="handleSwitchToCodeLogin">验证码登录</text>
|
||||
</view>
|
||||
|
||||
<!-- 底部注册入口 -->
|
||||
<view class="footer-section">
|
||||
<text class="footer-text">还没有账号? </text>
|
||||
<text class="register-text" @tap="handleRegister">注册</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { apiLogin } from '../../api/auth'
|
||||
import { setUserInfo, saveRememberInfo, getRememberInfo } from '../../store/user'
|
||||
|
||||
type LoginForm = {
|
||||
phone: string
|
||||
password: string
|
||||
remember: boolean
|
||||
}
|
||||
|
||||
const form = reactive<LoginForm>({
|
||||
phone: '',
|
||||
password: '',
|
||||
remember: false
|
||||
})
|
||||
|
||||
// 计算是否可以提交
|
||||
const canSubmit = computed((): boolean => {
|
||||
const phoneReg = /^1[3-9]\d{9}$/
|
||||
return phoneReg.test(form.phone) && form.password.length >= 6
|
||||
})
|
||||
|
||||
onLoad(() => {
|
||||
// 加载记住的密码信息
|
||||
const rememberInfo = getRememberInfo()
|
||||
if (rememberInfo.remember) {
|
||||
form.phone = rememberInfo.phone
|
||||
form.password = rememberInfo.password
|
||||
form.remember = true
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 登录
|
||||
*/
|
||||
async function handleLogin() {
|
||||
if (!canSubmit.value) return
|
||||
|
||||
const res = await apiLogin({
|
||||
phone: form.phone,
|
||||
password: form.password,
|
||||
remember: form.remember
|
||||
})
|
||||
|
||||
if (res && res.data) {
|
||||
// 保存用户信息
|
||||
setUserInfo(res.data)
|
||||
|
||||
// 保存记住密码信息
|
||||
saveRememberInfo(form.phone, form.password, form.remember)
|
||||
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 跳转首页
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换到验证码登录
|
||||
*/
|
||||
function handleSwitchToCodeLogin() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/verify-code'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 忘记密码
|
||||
*/
|
||||
function handleForgotPassword() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/forgot-password'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
function handleRegister() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/register/index'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.login-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.content-scroll {
|
||||
flex: 1;
|
||||
padding: 24px 24px calc(24px + var(--uni-safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
/* Logo区域 */
|
||||
.logo-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.app-title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #1F2937;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.app-subtitle {
|
||||
font-size: 14px;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
/* 表单区域 */
|
||||
.form-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #1F2937;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.form-subtitle {
|
||||
font-size: 14px;
|
||||
color: #6B7280;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
/* 输入框 */
|
||||
.input-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
height: 52px;
|
||||
background-color: #F9FAFB;
|
||||
border-radius: 12px;
|
||||
padding: 0 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
flex: 1;
|
||||
font-size: 16px;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
/* 选项行 */
|
||||
.option-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.remember-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 2px solid #D1D5DB;
|
||||
border-radius: 4px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.checkbox-checked {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-color: #6C63FF;
|
||||
border-radius: 4px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.remember-text {
|
||||
font-size: 14px;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.forgot-text {
|
||||
font-size: 14px;
|
||||
color: #6C63FF;
|
||||
}
|
||||
|
||||
/* 登录按钮 */
|
||||
.btn-login {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 52px;
|
||||
border-radius: 26px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.btn-login-active {
|
||||
background-color: #6C63FF;
|
||||
}
|
||||
|
||||
.btn-login-disabled {
|
||||
background-color: #E5E7EB;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
/* 切换文字 */
|
||||
.switch-text {
|
||||
font-size: 14px;
|
||||
color: #6C63FF;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 底部区域 */
|
||||
.footer-section {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: auto;
|
||||
padding-top: 24px;
|
||||
}
|
||||
|
||||
.footer-text {
|
||||
font-size: 14px;
|
||||
color: #6B7280;
|
||||
}
|
||||
|
||||
.register-text {
|
||||
font-size: 14px;
|
||||
color: #6C63FF;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user