博客项目全栈开发 后台管理系统 第三章:用户系统

#『技术文档』写作方法征文挑战赛#

前言

首先介绍下用户系统。用户系统是后台管理系统的核心功能之一,它负责处理用户的身份认证、权限控制等关键功能。一个完善的用户系统能够确保系统的安全性和可用性。

### 一、功能

1. **登录注册**
   - 用户登录
   - 用户注册
   - 记住密码
   - 验证码功能

2. **用户认证**
   - JWT Token 认证
   - 用户信息管理
   - 登录状态维护

3. **权限控制**
   - 角色管理
   - 权限验证
   - 访问控制

### 二、技术方案

1. **前端实现**
   - Vue Router 路由守卫
   - Pinia 状态管理
   - Element Plus UI 组件
   - Axios 请求封装

2. **后端接口**
   - 用户认证接口
   - 用户信息接口
   - 权限验证接口

前置修改

创建工具函数src/utils/auth.js

const TOKEN_KEY = 'token'

export function getToken() {
  return localStorage.getItem(TOKEN_KEY)
}

export function setToken(token) {
  return localStorage.setItem(TOKEN_KEY, token)
}

export function removeToken() {
  return localStorage.removeItem(TOKEN_KEY)
}

状态管理文件修改src/stores/user.js

import { defineStore } from 'pinia'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { login, getUserInfo } from '@/api/user'

export const useUserStore = defineStore('user', {
  state: () => ({
    token: getToken(),
    userInfo: null
  }),

  actions: {
    // 登录
    async login(userInfo) {
      try {
        const { data } = await login(userInfo)
        setToken(data.token)
        this.token = data.token
        return Promise.resolve()
      } catch (error) {
        return Promise.reject(error)
      }
    },

    // 获取用户信息
    async getUserInfo() {
      try {
        const { data } = await getUserInfo()
        this.userInfo = data
        return Promise.resolve(data)
      } catch (error) {
        return Promise.reject(error)
      }
    },

    // 退出登录
    logout() {
      this.token = null
      this.userInfo = null
      removeToken()
    }
  }
})

其他的环境准备阶段在第一章已经写好了。我们暂时不用修改。然后这里我知道很多人是把token操作放到store里面的。说一下改成功工具函数的好处哈。
首先职责不同
stores/user.js 是状态管理,负责:

  • 管理用户状态(token、用户信息等)
  • 处理用户相关的业务逻辑(登录、获取用户信息等)
  • 与后端 API 交互

utils/auth.js 是工具函数,负责:

  • 提供 token 的存取方法
  • 不涉及业务逻辑
  • 可以被其他模块复用

为什么要分离

  • 工具函数可以被多个模块使用
  • 如果需要修改 token 的存储方式(比如改用 sessionStorage)可以直接修改工具函数。也就是扩展性
  • 一个逻辑一个工具函数,各司其职

实现登录功能

登录页面src/views/login/index.vue,先简单实现一下哈,大家嫌弃的话?自己改!!!

<script setup>
import { ref, reactive } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'

const router = useRouter()
const route = useRoute()
const userStore = useUserStore()

// 表单数据
const loginForm = reactive({
  username: '',
  password: '',
  remember: false
})

// 表单校验规则
const rules = {
  username: [
    { required: true, message: '请输入用户名', trigger: 'blur' },
    { min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' }
  ],
  password: [
    { required: true, message: '请输入密码', trigger: 'blur' },
    { min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' }
  ]
}

// 表单引用
const loginFormRef = ref(null)

// 登录方法
const handleLogin = async () => {
  if (!loginFormRef.value) return
  
  try {
    // 表单验证
    await loginFormRef.value.validate()
    
    // 调用登录接口
    await userStore.login(loginForm)
    
    // 获取用户信息
    await userStore.getUserInfo()
    
    ElMessage.success('登录成功')
    
    // 跳转到之前的页面或首页
    const redirect = route.query.redirect || '/'
    router.push(redirect)
  } catch (error) {
    console.error('登录失败:', error)
  }
}
</script>

<template>
  <div class="login-container">
    <div class="login-box">
      <div class="title">
        <h2>博客管理系统</h2>
      </div>
      
      <el-form
        ref="loginFormRef"
        :model="loginForm"
        :rules="rules"
        class="login-form"
      >
        <el-form-item prop="username">
          <el-input
            v-model="loginForm.username"
            placeholder="用户名"
            prefix-icon="User"
          />
        </el-form-item>
        
        <el-form-item prop="password">
          <el-input
            v-model="loginForm.password"
            type="password"
            placeholder="密码"
            prefix-icon="Lock"
            show-password
          />
        </el-form-item>
        
        <el-form-item>
          <el-checkbox v-model="loginForm.remember">记住密码</el-checkbox>
        </el-form-item>
        
        <el-form-item>
          <el-button
            type="primary"
            :loading="loading"
            class="login-button"
            @click="handleLogin"
          >
            登录
          </el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.login-container {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #f0f2f5;
  
  .login-box {
    width: 400px;
    padding: 40px;
    background: #fff;
    border-radius: 4px;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    
    .title {
      text-align: center;
      margin-bottom: 30px;
      
      h2 {
        font-size: 24px;
        color: #303133;
      }
    }
    
    .login-form {
      .login-button {
        width: 100%;
      }
    }
  }
}
</style>

先发出来。我要测试一下。给一下测试方法

npm run dev
打开浏览器,访问http://localhost:5173/login

OK,说一下我这里遇到的问题

[plugin:vite:import-analysis] Failed to resolve import "@/views/dashboard/index.vue" from "src/router/index.js". Does the file exist?

这个错误是指页面没有创建,那我们创建一下。src/views/dashboard/index.vue

<script setup>

</script>

<template>
  <div class="dashboard">
    <h1>Dashboard</h1>
  </div>
</template>

<style>
</style>

最简单的一个页面。然后我这才发现第一章的token操作全在pinia里,所以我们要去修改一下请求,路由这些地方的代码。嗯,我就不写出来了。我非常相信大家的实力,你们包能自己换的。=.= 给代码太麻烦了,嘻嘻

最后修改你的src/App.vue

<script setup></script>
<template>
  <router-view />
</template>

<style></style>

按照测试方法运行,页面显示下列信息,那么前面的步骤算是OK了。我们继续下一步,否则就检查代码,实在不行就留言给我把。
在这里插入图片描述

OK,明天在来写了。大家晚安

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值