这一期已经到了系列教程的尾声了,下面来搭建登录、注册页面,处理登录拦截和注销的逻辑
1 建表
先把数据库表用户相关的数据库表建立一下:
CREATE TABLE `tb_user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
`realname` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`username` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`password` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`avatar` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`phone` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`email` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`age` int DEFAULT NULL,
`intro` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`addr` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT '江苏省',
`idno` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '身份证号',
`gender` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT 'M',
`job` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT '学生',
`roles` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL,
`deleted` int DEFAULT '0',
`status` int DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='用户表';
2 新建vue文件
先在views下新建 Login.vue 和 Register.vue
然后router.js中把路由先添加上,注意,这两个不能添加在children里,因为这两个是不用布局文件的!
{
path: '/login',
component:()=> import('@/views/Login'),
name: 'Login'
},
{
path: '/register',
component:()=> import('@/views/Register'),
name: 'Register'
},
3 开发Login页面
先把登录页面布局写好,再进行后端的对接:
<template>
<div id="login-page">
<el-container>
<el-header>
<h1>🏝 旅游分析系统登录</h1>
</el-header>
<el-main class="main-content">
<div class="login-container">
<el-form :model="form" class="login-form" status-icon>
<el-form-item
prop="username"
:rules="[{ required: true, message: '请输入用户名', trigger: 'blur' }]"
>
<el-input v-model="form.username" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item
prop="password"
:rules="[{ required: true, message: '请输入密码', trigger: 'blur' }]"
>
<el-input
v-model="form.password"
placeholder="密码"
type="password"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleLogin">登录</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
<div class="register-link">
<span>还没有账号?</span>
<el-button type="text" @click="goToRegister">去注册</el-button>
</div>
</div>
</el-main>
</el-container>
</div>
</template>
<script>
export default {
data() {
return {
form: {
username: '',
password: ''
}
};
},
methods: {
handleLogin() {
console.log('登录', this.form);
// 这里可以添加登录逻辑
},
resetForm() {
this.form.username = '';
this.form.password = '';
},
goToRegister() {
// 这里可以添加跳转到注册页面的逻辑
this.$router.push('/register'); // 假设你的路由设置了注册页面的路径
}
}
};
</script>
<style scoped>
#login-page {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: #f5f5f5;
}
.login-container {
width: 100%;
max-width: 400px;
padding: 20px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.main-content {
display: flex;
align-items: center;
justify-content: center;
height: 100%; /* 使主内容区域占满剩余高度 */
}
.el-header {
text-align: center;
font-size: 24px;
margin-bottom: 20px;
}
.register-link {
text-align: center;
margin-top: 20px;
}
</style>
4 开发Register页面
先把登录页面布局写好,再进行后端的对接:
<template>
<div id="login-page">
<el-container>
<el-header>
<h1>🏝 旅游分析系统注册</h1>
</el-header>
<el-main class="main-content">
<div class="login-container">
<el-form :model="form" class="login-form" status-icon>
<el-form-item
prop="username"
:rules="[{ required: true, message: '请输入用户名', trigger: 'blur' }]"
>
<el-input v-model="form.username" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item
prop="password"
:rules="[{ required: true, message: '请输入密码', trigger: 'blur' }]"
>
<el-input
v-model="form.password"
placeholder="密码"
type="password"
></el-input>
</el-form-item>
<el-form-item
prop="password2"
:rules="[{ required: true, message: '再次请输入密码', trigger: 'blur' }]"
>
<el-input
v-model="form.password2"
placeholder="再次输入密码"
type="password"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleRegister">注册</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
<div class="register-link">
<span>已有账号?</span>
<el-button type="text" @click="goToLogin">去登录</el-button>
</div>
</div>
</el-main>
</el-container>
</div>
</template>
<script>
export default {
data() {
return {
form: {
username: '',
password: '',
password2: '',
}
};
},
methods: {
handleRegister() {
console.log('注册', this.form);
// 这里可以添加登录逻辑
},
resetForm() {
this.form.username = '';
this.form.password = '';
},
goToLogin() {
// 这里可以添加跳转到注册页面的逻辑
this.$router.push('/login'); // 假设你的路由设置了注册页面的路径
}
}
};
</script>
<style scoped>
#login-page {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: #f5f5f5;
}
.login-container {
width: 100%;
max-width: 400px;
padding: 20px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.main-content {
display: flex;
align-items: center;
justify-content: center;
height: 100%; /* 使主内容区域占满剩余高度 */
}
.el-header {
text-align: center;
font-size: 24px;
margin-bottom: 20px;
}
.register-link {
text-align: center;
margin-top: 20px;
}
</style>
5 开发后端接口
开发登录和注册接口
# 用户注册接口
@main.route('/register', methods=['POST'])
def register():
data = request.json
username = data.get('username')
password = data.get('password')
if User.query.filter_by(username=username).first():
return make_response(code=1, message='用户名已存在')
hashed_password = generate_password_hash(password)
new_user = User(username=username, password=hashed_password)
db.session.add(new_user)
db.session.commit()
return make_response(code=0, message='注册成功', data=user_schema.dump(new_user))
# 用户登录接口
@main.route('/login', methods=['POST'])
def login():
data = request.json
username = data.get('username')
password = data.get('password')
user = User.query.filter_by(username=username).first()
if not user or not check_password_hash(user.password, password):
return make_response(code=1, message='用户名或者密码错误')
return make_response(code=0, message='登录成功', data=user_schema.dump(user))
6 对接注册页面
添加user.js文件
import request from '@/api/request'
// 登录
export function login(data) {
return request({
url: '/login',
method: 'post',
data
})
}
// 注册
export function register(data) {
return request({
url: '/register',
method: 'post',
data
})
}
然后去修改Register,引入register方法,然后修改一下处理注册的逻辑就行了。
import {register} from "@/api/user";
handleRegister() {
// 检查两个密码是否相等
if (this.form.password !== this.form.password2) {
this.$message('两次输入的密码不一致', 'error'); //上一期中封装的消息插件
return
}
console.log('注册', this.form);
register(this.form).then((res)=>{
this.$message(res) //上一期中封装的消息插件
})
},
7 对接登录页面
登录页面的处理不同之处在于保存登录状态和用户信息,修改Login.vue :
handleLogin() {
console.log('登录', this.form);
login(this.form).then(res=>{
this.$message(res) //上一期中封装的消息插件
// 假设 res.data 包含用户信息
if (res.data && res.data.code==0) {
// 保存用户信息和登录状态
localStorage.setItem('user', JSON.stringify(res.data.data)); // 保存用户信息
localStorage.setItem('isLogin', 'true'); // 标记用户为已登录
// 跳转到主页
this.$router.push('/');
}
})
},
8 未登录拦截处理 && 注销处理
然后还有几个部分要修改,一个是登录完了之后会定向到布局文件,修改其中的逻辑,如果用户在没有登录的情况下,访问到了Layout.vue下的任意文件,都应该重新定向回login页面,如果用户已经登录的情况下,那应该在右上方,显示用户名,修改下Layout.vue:
data() {
return {
activeIndex: '/dashboard',
username: '未登录', // 替换为实际用户名
// avatarUrl: 'https://via.placeholder.com/40' // 替换为实际头像 URL
avatarUrl: require("@/assets/avatar.png") // 也可以使用 require 语法引入图片
};
},
created() {
const user = JSON.parse(localStorage.getItem('user'));
const isLoggedIn = localStorage.getItem('isLogin') === 'true'; // 转换为布尔值
if (isLoggedIn) {
console.log('用户已登录:', user);
this.username = user.username
// 这里可以设置用户状态到组件的 data 中
} else {
this.$message('用户未登录', 'error');
this.$router.push('/login')
}
},
另外要形成闭环,还需要修改注销的逻辑:
<el-button type="text" @click="handleLogout">退出</el-button>
handleLogout(){
// 清除用户信息和登录状态
localStorage.removeItem('user');
localStorage.removeItem('isLogin');
this.$router.push('/login');
}
这样如果未登录,是访问不到这个页面的,如果登录了,那右上角的用户名显示的是数据中的用户名,点击退出,则清除登录信息和用户信息。