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

news2024/11/16 1:26:47

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

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');
    }

在这里插入图片描述

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2043309.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

燃气综合管理解决方案:构建安全可靠的燃气供应网络

无论是繁华的都市中心还是宁静的郊区&#xff0c;地下深处都隐藏着错综复杂的燃气管道网络&#xff0c;这些管网为千家万户输送着生活必需的能源。尽管这些管道由高强度和耐腐蚀材料制成&#xff0c;但长期暴露于自然环境中仍会逐渐老化和磨损。一旦发生破损或因人为错误导致管…

eNSP 华为单臂路由实现VLAN间通信

华为单臂路由实现VLAN间通信 SW&#xff1a; <Huawei>sys <Huawei>system-view [Huawei]sysname SW [SW]VLAN batch 10 20 //批量划分VLAN [SW]int g0/0/1 [SW-GigabitEthernet0/0/1]port link-type trunk [SW-GigabitEthernet0/0/1]port trunk allow-pa…

LabVIEW光纤水听器闭环系统

开发了一种利用LabVIEW软件开发的干涉型光纤水听器闭环工作点控制系统。该系统通过调节光源频率和非平衡干涉仪的光程差&#xff0c;实现了工作点的精确控制&#xff0c;从而提高系统的稳定性和检测精度&#xff0c;避免了使用压电陶瓷&#xff0c;使操作更加简便。 项目背景 …

安卓平板电脑定制方案_MTK联发科智能终端方案开发

基于联发科MT8788八核2.0GHz处理器的平板电脑方案&#xff0c;这款平板电脑不仅支持4G和Wi-Fi 5高速网络&#xff0c;还搭载了Android12.0系统&#xff0c;可带来流畅的多任务处理和广泛兼容性。其6GB运行内存和128GB内置存储&#xff0c;再加上支持TF卡扩展&#xff0c;确保了…

【微信小程序】WXS脚本

概述 1. 什么是 wxs WXS&#xff08;WeiXin Script&#xff09;是小程序独有的一套脚本语言&#xff0c;结合 WXML&#xff0c;可以构建出页面的结构。 2. wxs 的应用场景 3. wxs 和 JavaScript 的关系* 基础语法 1. 内嵌 wxs 脚本 2. 定义外联的 wxs 脚本 3. 使用外联的 w…

【Qt菜鸟笔记】QLCDNumber控件

1.QLCDNumber控件简介&#xff08;Qt6.5.3版&#xff09; QLCDNumber控件显示带有类似 LCD 数字的数字。它可以显示十进制、十六进制、八进制或二进制数。 头文件引入#include<QLCDNumber>CMake配置:find_package(Qt6 REQUIRED COMPONENTS Widgets) target_link_librar…

ffmpeg的基础命令

文章目录 ffmpeg/ffplay/ffprobe区别ffmpeg 的作用ffplay的作用ffprobe的作用 ffmpeg使用概述功能概述转码过程简单使用FFMPEG -i常用的 -i例子 ff***工具之间共享的选项ffmpeg主要选项ffmpeg提取音视频数据ffmpeg命令修改原有的视频格式ffmpeg命令裁剪和合并视频拼接视频的方式…

【二叉树OJ】常见面试题

文章目录 1.[单值二叉树](https://leetcode.cn/problems/univalued-binary-tree/description/)1.2 题目要求1.3 深度优先搜索 2.[相同的树](https://leetcode.cn/problems/same-tree/)2.1 题目要求2.2 深度优先遍历 3.[对称二叉树](https://leetcode.cn/problems/symmetric-tre…

热敏打印机ESC指令封装-SAAS本地化及未来之窗行业应用跨平台架构

一热敏打印机ESC指令 它包含了一系列的控制指令&#xff0c;通过这些指令可以实现对打印内容的格式设置&#xff0c;如字体大小、加粗、下划线、对齐方式等。还能够控制打印的位置、纸张进纸、切纸等操作。 例如&#xff0c;在商业零售场景中&#xff0c;收银小票打印机就是基…

刷到好听的音频怎么办

在短视频平台上&#xff0c;我们常常会刷到那些好听得让人陶醉的视频&#xff0c;可却无法直接下载保存其中的音频&#xff0c;是不是感觉很遗憾&#xff1f; 比如刷到林俊杰这首前奏超好听的《江南》&#xff0c;却禁止下载无法直接下载保存。 别担心&#xff0c;下面就为您揭…

html页面缩放自适应

html页面缩放自适应 一、为什么页面要进行缩放自适应 在我们一般web端进行页面拼接完成后&#xff0c;在web端的显示正常&#xff08;毕竟我们是按照web端进行页面拼接完成的&#xff09;&#xff0c;那么要是用其他设备打开呢&#xff0c;比如手机或者平板&#xff0c;这时候…

聚鼎科技:新手做装饰画生意卖什么比较好

在艺术的广阔天地里&#xff0c;装饰画以其独特的魅力逐渐成为室内装饰不可或缺的元素。对于刚入行的新手而言&#xff0c;选择合适的装饰画产品至关重要&#xff0c;它关系到业务的成功与否。以下是一些关于新手做装饰画生意卖什么比较好的建议。 考虑到市场需求的多样性&…

宝兰德荣获openEuler项目群青铜捐赠人称号,共筑开源生态繁荣新篇章

近日&#xff0c;开放原子开源基金会正式公布了新增捐赠人名单&#xff0c;宝兰德凭借在开源领域的卓越贡献与深厚实力&#xff0c;被授予openEuler项目群青铜捐赠人称号。 开放原子开源基金会是致力于推动全球开源事业发展的非营利机构&#xff0c;于2020年6月在北京成立。开放…

Vue3+Vite项目从零搭建+安装依赖+配置按需导入

环境准备 Vscode/HBuilder等任何一种前端开发工具node.js&npm本地开发环境 源代码管理&#xff1a;Git 技术栈 项目构建 创建项目 npm create vite依次运行最后三行出现&#xff0c;成功启动项目在浏览器输入 http://localhost:5173/ 可以显示页面 src别名的配置 在…

xcode14.2学习笔记 swift5开发macos网络程序笔记

1. .frame(width: 200.0, height: 200.0) 控制默认窗体大小 2.去除Metal API Validation提示 Product->Scheme > Edit Scheme... > Run > Diagnostics > Metal API Validation. 3.本地安装git依赖资源&#xff08;可能有的时候并不好用&#xff0c;显示不出自…

星露谷模组开发教程#6 烹饪和制造配方

首发于Enaium的个人博客 在上篇文章中我们添加了一个新的食物&#xff0c;但是这个食物并没有配方&#xff0c;所以我们今天来添加一个配方。 烹饪配方 我们在Data/CookingRecipes.json中可以看到所有的食物配方&#xff0c;所以我们需要修改这个配置文件来添加我们的食物配方…

基于Vue2使用x2js将JSON转换成XML、将XML转换成JSON

x2js源码地址GitHub - abdolence/x2js: x2js - XML to JSON and back for JavaScriptx2js - XML to JSON and back for JavaScript. Contribute to abdolence/x2js development by creating an account on GitHub.https://github.com/abdolence/x2js import x2js from x2js;//…

go语言后端开发学习(四) —— 在go项目中使用Zap日志库

一.前言 在之前的文章中我们已经介绍过如何使用logrus包来作为我们在gin框架中使用的日志中间件&#xff0c;而今天我们要介绍的就是我们如何在go项目中如何集成Zap来作为日志中间件 二.Zap的安装与快速使用 和安装其他第三方包没什么区别&#xff0c;我们下载Zap包只需要执…

Github Actions自动发布release

目录 说明正文1.设置仓库密钥2.打开仓库权限3.配置自动化文件4.写在最后 说明 GitHub Actions 是 GitHub 的持续集成服务&#xff0c;于2018年10月推出。通过Github Actions可以实现诸多自动化功能&#xff0c;比如自动打包&#xff0c;自动发布Release等等。除此之外&#xf…

实验10-3 递归计算Ackermenn函数

本题要求实现Ackermenn函数的计算&#xff0c;其函数定义如下&#xff1a; 函数接口定义&#xff1a; int Ack( int m, int n ); 其中m和n是用户传入的非负整数。函数Ack返回Ackermenn函数的相应值。题目保证输入输出都在长整型范围内。 输入样例&#xff1a; 2 3输出样例&am…