从0开始搭建vue + flask 旅游景点数据分析系统(十一):登录、注册页面、未登录拦截、注销逻辑

这一期已经到了系列教程的尾声了,下面来搭建登录、注册页面,处理登录拦截和注销的逻辑

1 建表

先把数据库表用户相关的数据库表建立一下:

sql 复制代码
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里,因为这两个是不用布局文件的!

sql 复制代码
{
        path: '/login',
        component:()=> import('@/views/Login'),
        name: 'Login'
    },
    {
        path: '/register',
        component:()=> import('@/views/Register'),
        name: 'Register'
    },

3 开发Login页面

先把登录页面布局写好,再进行后端的对接:

jsx 复制代码
<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页面

先把登录页面布局写好,再进行后端的对接:

jsx 复制代码
<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 开发后端接口

开发登录和注册接口

python 复制代码
# 用户注册接口
@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文件

jsx 复制代码
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方法,然后修改一下处理注册的逻辑就行了。

jsx 复制代码
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 :

jsx 复制代码
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:

jsx 复制代码
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')
    }
  },

另外要形成闭环,还需要修改注销的逻辑:

jsx 复制代码
 <el-button type="text"  @click="handleLogout">退出</el-button>

handleLogout(){
      // 清除用户信息和登录状态
      localStorage.removeItem('user');
      localStorage.removeItem('isLogin');
      this.$router.push('/login');
    }

这样如果未登录,是访问不到这个页面的,如果登录了,那右上角的用户名显示的是数据中的用户名,点击退出,则清除登录信息和用户信息。

相关推荐
这个需求建议不做1 分钟前
vue3打包配置 vite、router、nginx配置
前端·nginx·vue
QGC二次开发6 分钟前
Vue3 : Pinia的性质与作用
前端·javascript·vue.js·typescript·前端框架·vue
云草桑17 分钟前
逆向工程 反编译 C# net core
前端·c#·反编译·逆向工程
布丁椰奶冻23 分钟前
解决使用nvm管理node版本时提示npm下载失败的问题
前端·npm·node.js
Leyla1 小时前
【代码重构】好的重构与坏的重构
前端
影子落人间1 小时前
已解决npm ERR! request to https://registry.npm.taobao.org/@vant%2farea-data failed
前端·npm·node.js
世俗ˊ1 小时前
CSS入门笔记
前端·css·笔记
子非鱼9211 小时前
【前端】ES6:Set与Map
前端·javascript·es6
6230_1 小时前
git使用“保姆级”教程1——简介及配置项设置
前端·git·学习·html·web3·学习方法·改行学it
想退休的搬砖人1 小时前
vue选项式写法项目案例(购物车)
前端·javascript·vue.js