Vue+Element-UI 电商后台管理系统详细总结

一、概述

基于 VueElement-UI 的电商后台管理系统

1.1 实现功能

  • 用户登录/退出

  • 用户管理

    • 用户列表
      • 实现用户的增删改查、分页查询以及分配角色功能
  • 权限管理

    • 角色列表
      • 实现角色的增删改查以及分配权限、删除权限功能
    • 权限列表
      • 展示所有权限以及权限等级
  • 商品管理

    • 商品列表
      • 实现商品的增删改、分页查询
    • 分类参数
      • 实现分类参数的增删改
    • 商品分类
      • 实现商品分类的增删改以及查看该分类下的所有子分类
  • 订单管理

    • 订单列表
      • 实现修改地址
      • 实现查看物流进度
  • 数据统计

    • 数据报表

1.2 前端技术栈

电商后台管理里系统整体采用前后端分离的开发模式,其中前端是基于 Vue 技术栈的 SPA 项目

  • vue
  • vue-router
  • Element-UI
  • Axios
  • Echarts

1.3 前端项目初始化步骤

  1. 安装 Vue 脚手架
  2. 通过 Vue 脚手架创建项目
  3. 配置 Vue 路由
  4. 配置 Element-UI 组件库
  5. 配置 axios
  6. 初始化 git 远程仓库
  7. 将本地项目托管到 Gitee

二、登录与退出

2.1 登录布局

布局代码

<template>
  <div class="login_container">
    <!-- 登录区域 -->
    <div class="login_box">
      <div class="logo_box">
        <img src="../assets/logo.png" alt="">
      </div>
      <!-- 表单区域 -->
      <el-form class="login_form" ref="loginFormRef" :model="loginForm" :rules="loginFormRules" label-width="0px">
        <!-- 用户名 -->
        <el-form-item prop="username">
          <el-input prefix-icon="el-icon-user" v-model="loginForm.username"></el-input>
        </el-form-item>
        <!-- 密码 -->
        <el-form-item prop="password">
          <el-input prefix-icon="el-icon-lock" v-model="loginForm.password" type="password"></el-input>
        </el-form-item>
        <!-- 按钮 -->
        <el-form-item class="btns">
          <el-button type="primary" @click="login">登录</el-button>
          <el-button type="info" @click="resetLoginForm">重置</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<style lang="less" scoped>
  .login_container {
    background-color: #2b4b6b;
    height: 100%;
  }

  // 登录部分
  .login_box {
      width: 450px;
      height: 300px;
      background-color: #fff;
      border-radius: 3px;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);

      // 图表盒子
      .logo_box {
        height: 130px;
        width: 130px;
        border: 1px solid #eee;
        border-radius: 50%;
        padding: 10px;
        box-shadow: 0 0 10px #ddd;
        position: absolute;
        left: 50%;
        transform: translate(-50%, -50%);
        background-color: #fff;
        img {
          width: 100%;
          height: 100%;
          border-radius: 50%;
          background-color: #eee;
        }
      }

      // 表单
      .login_form {
        position: absolute;
        bottom: 0;
        width: 100%;
        padding: 0 20px;
        box-sizing: border-box;

        // 按钮
        .btns {
          display: flex;
          justify-content: flex-end;
        }
      }
    }
</style>

实现页面


2.2 登录业务逻辑

2.2.1 表单预验证

用户在输入账号和密码后,点击登录时表单会进行预验证,判断用户输入的账号和密码是否符合规范,验证通过后向服务器发送 axios 请求

验证规则

// 用户名的验证规则
username: [
    {
    required: true, message: '请输入用户名称', trigger: 'blur' },
    {
    min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
],
// 密码的验证规则
password: [
    {
    required: true, message: '请输入用户密码', trigger: 'blur' },
    {
    min: 6, max: 16, message: '长度在 6 到 16 个字符', trigger: 'blur' }
]

实现效果


2.2.2 关于 Token

在登录成功后,服务器会向我们返回一个 token,我们需要将这个 token 保存到客户端的 sessionStorage

发送请求并保存 token

<script>
    const { data: res } = await this.$http.post('login', this.loginForm)
    if (res.meta.status === 200) {
        this.$msg.success('登录成功')
        window.sessionStorage.setItem('token', res.data.token)
        this.$router.push('/home')
    } else {
        this.$msg.error('用户名或密码输入错误')
    }
</script>

注意

  • 为什么要保存 token
    • 因为项目中除了登录之外的其他 API 接口必须在登录之后才能访问,在访问的时候携带这个 token 就证明我们已经登录了
  • 为什么要将 token 保存在 sessionStorage
    • 因为 sessionStorage 是会话期间的存储机制,关闭浏览器过后, sessionStorage 就会被清空,token只应在当前网站打开期间生效,所以将 token 保存在 sessionStorage

2.2.3 路由导航守卫

如果用户没有登录,但是直接通过 URL 访问特定页面,需要重新导航到登录页面。

index.js 中挂载路由导航守卫

// 挂载路由导航守卫
// to 代表将要访问的页面路径,from 代表从哪个页面路径跳转而来,next 代表一个放行的函数
router.beforeEach((to, from, next) => {
   
    // 如果用户访问的是登录页,那么直接放行
  if (to.path === '/login') return next()
  // 获取 token
  const tokenStr = window.sessionStorage.getItem('token')
  // 没有 token,强制跳转到登录页面
  if (!tokenStr) return next('/login')
  next()
})

2.3 退出功能

基于 token 的方式在退出时需要销毁本地的 token 。这样,后续的请求就不会携带 token,必须重新登录生成一个新的 token 之后才可以访问页面。

退出代码

logout() {
   
    // 销毁本地 token
    window.sessionStorage.removeItem('token')
    // 通过编程式导航返回到上一页
    this.$router.go(-1)
}

三、主页部分

3.1 主页布局

引入 Element-UI 中的 Header Aside Main 组件

样式代码

<style lang="less" scoped>
  .home_container {
    height: 100%;
  }

  // 头部区域
  .el-header {
    display: flex;
    justify-content: space-between;
    background-color: #373d41;

    .el-button {
      align-self: center;
    }
  }

  // 侧边栏区域
  .el-aside {
    background-color: #333744;
    .el-menu {
      border-right: none
    }
  }

  // 主题内容区域
  .el-main {
    background-color: #eaedf1;
  }

  .toggle-button {
    background-color: #4a5064;
    font-size: 10px;
    line-height: 24px;
    color: #fff;
    text-align: center;
    letter-spacing: 0.2em;
    cursor: pointer;
  }
</style>

实现效果

3.2 菜单部分

向服务器发送 axios 请求获取菜单数据

注意

  • 需要授权的 API 必须在请求头中使用 Authorization 字段提供的 token 令牌,那些授权的 API 才能被正常调用
  • 如何在每一个的 API 请求头中添加 Authorization 字段
    • 通过 axios 请求拦截器添加 token,保证拥有获取数据的权限

main.js 中添加拦截器

// axios 请求拦截
axios.interceptors.request.use(config => {
   
  // 为请求头对象,添加 Token 验证的 Authorization 字段
  config.headers.Authorization = window.sessionStorage.getItem('token')
  // 最后必须 return config
  return config
})

发起请求获取所有菜单数据

<script>
    methods: {
        // 获取所有菜单数据
        async getMenuList() {
            const { data: res } = await this.$http.get('menus')
            if (res.meta.status !== 200) return this.$msg.error('获取菜单列表失败')
            this.menulist = res.data
        }
    },
    created() {
        this.getMenuList()
    }
</script>

渲染到页面

<el-menu
         background-color="#333744"
         text-color="#fff"
         active-text-color="#409Eff"
         <!-- 只保持一个子菜单的展开 -->
         unique-opened
		<!-- 水平折叠收起菜单 -->
         :collapse="isCollapse"
         :collapse-transition="false"
         router
         :default-active="activePath">
    <!-- 一级菜单 -->
    <!-- index 只接收字符串,所以在后面拼接一个空字符串 -->
    <el-submenu :index="item.id + ''" v-for="item in menulist" :key="item.id">
        <template slot="title">
            <i :class="iconObj[item.id]"></i>
            <span>{
  { item.authName }}</span>
        </template>
        <!-- 二级菜单 -->
        <el-menu-item :index="'/' + secitem.path" v-for="secitem in item.children" :key="secitem.id" 		 			@click="savaNavState('/' + secitem.path)">
            <i class="el-icon-menu"></i>
            <span>{
  { secitem.authName }}</span>
        </el-menu-item>
    </el-submenu>
</el-menu>

通过 Element-UI 为菜单名称添加图标

实现效果

3.3 用户管理模块

3.3.1 用户列表

1、渲染用户列表

引入 Element-UI 中的 Breadcrumb, BreadcrumbItem, Card, Row, Col 组件,实现面包屑导航和卡片视图

样式代码

<!-- 面包屑导航区域 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
    <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
    <el-breadcrumb-item>用户管理</el-breadcrumb-item>
    <el-breadcrumb-item>用户列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片区域 -->
<el-card>
</el-card>

<style>  
.el-breadcrumb {
     
  margin-bottom: 15px;
  font-size: 12px;
}

.el-card {
     
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1) !important;
}
</style>

实现效果

向服务器发送请求获取用户数据列表

<script>
    data() {
        return {
            // 查询参数,实现分页
            queryInfo: {
                // 查询字段
                query: '',
                // 当前页码
                ./pagenum: 1,
                // 每页显示的条数
                ./pagesize: 5
            }
        }
    }
    methods: {
        // 获取用户列表
        async getUserList() {
          const { data: res } = await this.$http.get('users', { params: this.queryInfo })
          if (res.meta.status !== 200) {
            return this.$msg.error('获取用户列表失败')
          }
          this.userTable = res.data.users
          this.total = res.data.total
        },
        // 每页显示条数发生变化触发此事件
        handleSizeChange(val) {
          this.queryInfo../pagesize = val
          this.getUserList()
        },
        // 页码值发生变化触发此事件
        handleCurrentChange(val) {
          this.queryInfo../pagenum = val
          this.getUserList()
        }
    },
    created() {
        this.getUserList()
    }
</script>

引入 Table, TableColumn 将用户数据渲染到表格中,引入 Pagination 实现分页效果

实现效果

2、 实现用户的增删改查
  • 添加用户

引入 Dialog 结合表单展示一个添加用户的对话框

实现效果

为表单添加验证规则

<script>
  data() {
    // 自定义校验规则
    // 邮箱验证
    var checkEmail = (rule, val, cb) => {
      const regEmail = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
      if (regEmail.test(val)) return cb()
      cb(new Error('请输入合法的邮箱'))
    }
    // 
  • 17
    点赞
  • 138
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值