基于Element-ui和vue的电商管理项目+建立码云仓库+git

电商后台管理系统项目学习

附:B站学习视频前端vue电商后台管理项目_哔哩哔哩_bilibili

码云源码地址vue_shop_yfh: 基于vue和element-ui的电商后台管理项目 (gitee.com)

1. 项目概述

1.1 电商后台管理系统的开发模式(前后端分离)

 

 

后端:操作数据库、向前端暴露api 接口

前端:制作页面,利用ajax调用后端api接口

前后端分离开发模式:后端写接口,前端调接口

前端技术栈

  • vue

  • vue-router

  • Element-UI 前端UI组件库

  • Axios 发起网络数据请求

  • Echarts 绘制报表

后端技术栈

  • Node.js

  • Express

  • Jwt 状态保持工具 模拟登陆记录功能

  • Mysql

  • Sequelize 操作数据库的框架

2. 项目初始化

2.1 前端项目初始化步骤

  1. 安装Vue脚手架

  2. 通过脚手架构建项目

  • vue ui 可视化创建vue项目

  • 项目手动配置:手动配置 -Linter(语法格式校验保证代码风格一致)使用配置文件 babal

  1. 配置Vue路由

  2. 配置Element-UI组件库 可视化添加插件

  3. 配置axios库 可视化添加依赖 运行依赖 

2.2 后台项目的环境安装配置

  1. 安装Mysql

在Navicat中导入mydb.sql 命名为vue_shop_yfh

  1. 安装Node.js环境

  2. 配置项目相关信息

  3. 启动项目

  4. 使用postman测试后台项目接口是否正常

  • vue_api_server 中装有项目的依赖包,

  • shift 右键打开PowerShell,其中npm install安装 cls清空

  • 在power shell 中 node .\app.js 启动后端服务

  • postman 中传递参数在body→x-www.form-urlencoded(普通表单数据格式 → 后端与数据库连接成功

 

配置数据库信息

  • token 用来登录状态保存 (相当于node中的session,客户端与服务区之间的状态保存机制)

 

3 登录/退出功能

3.1 登录概述

  1. 登录业务流程

    • 在登录页面输入用户名和密码

    • 调用后台接口进行验证

    • 通过验证之后,根据后台的响应状态跳转到项目主页

  2. 登录业务的相关技术点

    • http是无状态的

    • 通过cookie在客户端记录状态(node)、通过session在服务端记录状态(node)

    • 通过token方式维持状态

此vue项目运行在一个新的端口号,服务器可能与前端vue项目之间有跨域问题(协议 域名 端口号有不一致)

如果前端与后台接口之间不存在跨域问题,推荐cookie和session来记录登录状态

如果前端与后端存在跨域问题,则用token维持登录状态

3.2 登录-token原理分析

token完成客户端与服务器端身份验证(身份令牌)

3.3 登录功能实现

1 登录页面的布局

  • el-form

  • el-form-item(3个)

  • el-input

  • el-button

  • 字体图标

2 梳理项目结构

查看项目运行效果→ 打开vue ui →任务→运行启动app

项目代码 →src →main.js(项目入口文件)

App.vue 项目根组件

3 渲染Login组件并实现路由重定向

comp onents新建 →router/index.js 中导入,定义路由规则→在App.vue中放路由占位符<router-view>

通过路由匹配的组件都会渲染到router-view中

路由定义时候 因为eslint影响,常报错

  { path: '/login', component: Login }   //括号里前后各有空格,冒号后有空格
<style lang="less" scoped>    //支持less 语法格式  scoped为vue指令控制组件样式生效的区间,加上scope样式只在当前组件生效,否则回全局生效(样式冲突)

创建登陆组件,通过路由的形式将登录组件渲染到App根组件中,通过路由重定向redirect让用户在访问/根页面时候自动跳转到登录页面

4 设置背景色并在屏幕中央绘制登陆盒子

可视化安装开发依赖:less-loader\less

  • 让背景色充满页面→在页面中检查元素 看哪些标签需要撑满屏幕→定义全局样式表html\body\#app→在入口文件中导入全局样式

    为登录组件设置背景颜色,在登陆组件中放入一个盒子,设置好宽高,背景色,盒子放正中央

5 绘制默认头像

6 绘制登录表单区域

  • 需要element-ui哪些组件 →plugins/element.js中按需导入→Vue.use()注册为全局可用的组件

7 绘制带icon的input输入框

  • input输入框找icon怎么写:添加prefix-icon属性(前置小图标)(suffix-icon后置小图标)

  • element-ui/第三方图标库阿里图标库

  • 步骤:

    • 将fonts复制到assets中

    • 一:导入图表样式表:到入口文件main.js中导入字体图标

    • 二:对应组件中添加iconfont基础类+具体使用图标名

      import './assets/fonts/iconfont.css'                       // 导入字体图标
      import './assets/css/global.css'                   // 导入全局样式表
    • <el-input prefix-icon="iconfont icon-user"></el-input>      
      // 到demo_fontclass找用法

8 实现表单的数据绑定

  • v-model数据绑定

    ★ ①el-form用:model 属性进行数据绑定,值是一个数据对象(在data中做定义)

    ②子组件el-form-item用v-model(绑定到数据对象上具体的属性中),否则显示不了

  • 设置密码框 type="password" 隐藏密码

9 表单数据验证

在防止用户犯错的前提下,尽可能让用户更早地发现并纠正错误

  • 为el-form属性绑定 ,添加 :rules='rules' 绑定验证规则对象

  • 在data中定义校验对象rules,其中每个属性就是验证规则

  • 为el-form-item通过prop指定不同验证规则进行表单验证

    • trigger: 'blur/change' 鼠标失去焦点,触发此次验证

10 表单重置

拿到表单实例对象(给el-form添加 ref 引用)调用resetFields函数

  1. 给表单添加ref引用对象

  2. methods:添加重置表单方法,通过this 访问$refs.loginFormRef ,调用resetFields()

    this.$refs.loginFormRef.resetFields()

11 登陆前表单数据的预验证

获取表单的引用对象,调用validate函数,在validate中接收回调函数,其中第一个形参是验证的结果为布尔值

如果箭头函数只有一个形参,可以省略()

this.$refs.loginFormRef.validate(valid => {             // validate((valid) => {
console.log(valid)
})

valid(xx,xx)=>{}

12 配置axios发起登录请求(根据验证的结果是否发起具体的请求)

  1. 到main.js对axios进行全局配置:

    • 先导入,接着将axios包挂载到原型对象上。如此每一个vue组件都可以通过this直接访问到$http,从而去发起axios请求。

    • 为axios设置请求的根路径

    Vue.prototype.$http = axios
    axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/'
  2. 运行mysql .powershell中运行node .\app.js(vue_api_server在这个文件夹里!)

  3. 如果某个方法的返回值是promise,可以用await简化promise操作

    • 注意:await只能用在被修饰的async方法中,所以接下来应将紧挨着await的那个方法修饰成异步的async方法

    •  

    • 这返回的六个属性都是axios封装好的,只有data才是服务器返回的真实数据,所以从result中将data解构赋值出来,将data重命名为res,从而打印真实的服务器数据

      const { data: res } = await this.$http.post('login', this.loginForm)
  4. 账号admin/123456 是已经存在的

先判断valid是否为true,为true则直接发起请求,如果不等于true直接return.验证通过了去配置axios,挂载到原型对象上设置请求根路径,如此在组件中就可以直接用this来发起登录请求。post返回值是promise,为了简化这次promise操作,可用async.await来优化,await只能用在被async修饰的方法中,所以将await外面的箭头函数修饰成异步的函数,如此就可直接拿到服务器返回的数据。返回6个属性,拿到data服务器返回数据,从result数据对象中解构复制出data属性并重命名为res对象,根据res的meta属性打印

13 配置message全局弹框组件

  1. 在element.js中导入弹框提示组件,message的配置方式和其他不一样,需要全局挂载,挂载为vue原型上的一个属性,起名为message

    Vue.prototype.$message = Message
    

    $message是自定义属性,可任意改名。

    将弹框组件挂载到vue的原型组件上,如此每一个组件都可通过this访问$message,进行弹框提示,有success,error函数...

14 完善登录成功之后操作

  1. 将登陆成功之后服务器分配的token(身份令牌),保存到客户端的sessionStorage中

    why:

    • 项目中除了登陆之外的其他API接口,必须在登录之后(有了身份令牌)才能访问

    • token只应在当前网站打开期间生效,所以将token保存在sessionStorage中,而不是localstorage

      (localstorage是持久化的存储机制,sessionStorage是会话期间的存储机制)

  2. 通过编程式导航跳转到后台主页($router.push),路由地址是/home

    window.sessionStorage.setItem('token', res.data.token)
    // 将token保存到sessionStorage中
            
    // 2 通过编程式导航跳转到后台主页($router.push),路由地址是/home
    this.$router.push('/home')
步骤
  • 打印res,出现token

     

  • F12→application→storage→SessionStorage

  • 建立Home.vue

  • router →index.js 导入home

15 路由导航守卫控制页面访问权限

  1. F12→application→storage→SessionStorage→登陆后清除token,表示未登录home页→刷新home页面,仍能进入,表示不满足需求(home页面属于有权限页面,登录下才能访问)

  2.  

  • to将要访问的路径 from从哪个路径跳转而来

  • next是一个函数,表示放行

    • next() 放行 next('/login') 强制跳转

  1. router/index.js→定义路由后挂载路由导航守卫再export default默认导出

  2.  

  

16 退出

实现原理:基于token的方式实现退出比较简单,只需要销毁本地的token即可。这样,后续的请求就不会携带token,必须重新登录生成一个新的token之后才可以访问页面。

 

 

3.4 语法处理

1 ESLin语法报错(禁用严格模式不报错)

在项目根目录中创建一个配置文件,告诉编辑器在格式化代码时候如何进行相关代码格式化

  • 格式化快捷键Ctrl + Alt + L在根目录中创建,prettierrc json格式文件,在里面修改规则

  • 到eslint.js中rule规则中禁用

 

4 主页

4.1 基本布局

  1. 现在element中导入基本布局组件,注册全局组件

  2. 取色工具fscapture 复制十六进制HEX

  3. element-ui中组件名就是类名

  4. 页面主题区域撑满屏幕→检查元素,看需要拿个元素撑满全全屏,再自定义类名,取设置样式

4.2 header区域

左右放东西,用flex布局

span 文本标签

<i> 图标项

el-header补充学习:菜鸟教程中css3弹性盒子

display: flex;
justify-content //设置弹性盒子元素在主轴(横轴)方向上的对齐方式。
align-items: center; //设置弹性盒子元素在侧轴(纵轴)方向上的对齐方式。

css中嵌套> div {

4.3 导航菜单基本结构

  1. 到element-ui中找导航菜单

  2. 到element.js中注册组件

  3. 更改背景颜色

    <el-menu
    background-color="#333744"
    
  4. 梳理结构

4.4 axios拦截器添加token验证

通过接口获取菜单数据

  • 除了登录接口之外,其他所有接口必须授权才能正常调用

  • 通过axios请求拦截器添加token,保证拥有获取数据的权限

  • 到main.js中设置

 

使用use函数为请求拦截器挂载一个回调函数,只要你向服务器端通过axios发一次数据请求,那么必然会在发送请求期间优先调用use回调函数,比如请求在到达服务器之前,先会调用回调函数对咱们请求做预处理,return config 代表我们已经把这个请求头做了预处理。经处理后请求才会发送到服务器处理

请求拦截器相当于预处理请求过程,这样有权限的API就可以正常调用成功

  • 接口文档要求:需要授权的 API ,必须在请求头中使用 Authorization 字段提供 token 令牌

  • main.js中添加→F12 →network→Authorization: null(因为是登陆,再登陆其他接口,就是token)

4.5 获取左侧菜单数据

  1. 接口文档 1.4权限管理1.4.2

  2. home.vue定义生命周期函数created() {} :页面一加载的时候就应立即获得左侧菜单

  3. async getMenuList () {
      const { data: res } = await this.$http.get('menus')
      console.log(res)
    }
    

    网络请求返回的函数都是promise函数,因为get返回promise,为简化使用await、async ,解构赋值 重命名data为res,打印的res结果

 

  • 数据拿到之后,为了在页面中能渲染出来,将获取到的数据立刻挂载在自己的data中

  1. 为el-submenu指定唯一的index,每一个菜单应该有独属自己的index值,动态绑定index

  2.  

    index="1"  改为  :index="item.id + ''"
    

4.6 渲染左侧菜单数据

获取的菜单数据存在menulist中,5个一级菜单,children属性下二级菜单

console.log(res)

  • 外层for循环渲染一级菜单,内层for循环渲染二级菜单

    1. 每一个v-for提供一个唯一的key属性

    2. 每一个菜单都有独属自己的index,绑定动态id,index只接受字符串不接受数值,所以

      :index="item.id+''" 加一个空字符串 (循环加:)

 

4.7 为选中项设置字体颜色、分类图标

  1. 点击后文本颜色改变

active-text-color="#409FFF"
  1. 二级菜单图标

<i class="el-icon-menu"></i>
  1. 一级菜单选用第三方字体图标库(assets-demo_fontclass.html找合适的)

  • 定义图标对象iconObj

  • 每循环一项就有独有id

    <i :class="iconObj[item.id]"></i>
    
  1. 设置图标与文本间距

 

在页面中挑选元素

4.8 每次只打开一个边框项并解决边框问题

  1. 每次只能展开一个菜单项

    • 到element-ui 找menu对应的属性住

unique-opened="true"
  1. 优化菜单右侧边框线

    • F12 找到对应修改的样式

4.9 实现首页路由的重定向

  1. 定义welcome组件

  2. 导入,将welcome作为home子路由规则

  3. home重定向welcome

  4. 在Home的main主体区域放路由占位符,在此展示welcome子组件

4.10 实现侧边栏路由链接的改造

  1. 为侧边栏开启路由模式router ,

  2. 跳转地址为 对应:index 因为后端返回的path没有/,需要手动添加

5 用户列表

5.1通过路由的形式展示用户列表组件

点击用户列表链接,在右侧主体区域展示对应的组件

5.1 在sessionStorage中保存左侧菜单的激活状态

  1. default-activate,值为对应index

  2. 将需要激活的链接保存在sessionStorage 中,动态赋值给default-activate

点击链接的时候,把对应的地址保存到sessionStorage 中,当下次刷新页面时候,即home组件刚被创建时候,将值取出来赋值给左侧菜单

  • 为每一个二级菜单绑定单击事件

@click="saveNavState('/' + subItem.path)"
  • methods中定义存储状态事件

    saveNavState (activePath) {
      window.sessionStorage.setItem('activePath', activePath)
      this.activePath = activePath    //点击其他链接时更新activePath ,实现高亮效果的动态切换
    }
    
  • data中定义数据,保存激活链接

activePath: ''
  • 将此值动态绑定到<el-menu>中的:default-activate(属性前加: 代表属性绑定)

:default-active="activePath"
  • 动态赋值,when?整个home组件一被创建的时候(create())

F12->Application->sessionStorage

5.2 绘制列表组件的基本布局结构

  • 头部 ——面包屑导航区域

在\assets\css 中定义样式

box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15) !important;

默认情况下,卡片自带样式权重比较高,要自己的样式覆盖他的样式最好!important

  • 栅格系统绘制(Layout)

  • 卡片视图组件

    el-row(gutter属性指定每一栏之间的间隔) el-col(整个一行宽度是24个格子 :span表示宽度)

5.3 获取用户列表数据

  1. 发起当前组件的首屏数据请求

created () {
  this.getUserList()
},

类似获取左侧菜单数据

5.4 使用el-able组件渲染基本的用户列表,添加表格索引列

  • :data=" " 绑定数据源

<el-table :data="userlist" border stripe>  //添加边框 隔行变色属性
  • 模板列 label指定当前页标题,prop当前这一列指向的数据

  • <el-table-column type="index"></el-table-column>
    

5.5 自定义状态列的显示效果

  • 作用域插槽(将共性抽取到组件中,将不同暴露为插槽。

<template slot-scope="scope">
  <el-switch v-model="scope.row.mg_state" @change="userStateChanged(scope.row)">
  </el-switch>
</template>
  • switch开关

通过作用域插槽来渲染 状态这一列:

  1. 在状态这一列中定义一个作用域插槽

  2. 通过scope.row获取当前这一行的数据

通过作用域插槽来渲染 操作列:

  • Tooltip文字提示

  • :enterable="false"
    

false是布尔值,因此在enterable前面加冒号表示数据绑定

  • 利用slot-scope接受这个"scope"作用域的数据

5.6 实现分页效果Pagination

// 监听 pagesize 改变的事件
handleSizeChange (newSize) {
  // console.log(newSize)
  this.queryInfo.pagesize = newSize
  this.getUserList()
},
// 监听 页码值 改变的事件
handleCurrentChange (newPage) {
  console.log(newPage)
  this.queryInfo.pagenum = newPage
  this.getUserList()
  // 重新获取页表数据
},

定义事件,监听数据是否改变,去发送数据请求。不同属性配置页码条

5.7 修改用户状态

  1. 监听switch开关的change事件的改变,拿到改变数据

  2. 发送ajax请求,调用API接口,保存到数据库中

请求路径:users/:uId/state/:type 冒号开头的一般都是参数

// 监听 switch 开关状态的改变
async userStateChanged (userinfo) {
  console.log(userinfo)
  const { data: res } = await this.$http.put(
    `users/${userinfo.id}/state/${userinfo.mg_state}`  //` `模板字符串以拼接动态参数
  )
  if (res.meta.status !== 200) {
    userinfo.mg_state = !userinfo.mg_state     // 因为没有更改数据库里的状态但是页面上被用户修改了,因此需要取反
    return this.$message.error('更新用户状态失败!')
  }
  this.$message.success('更新用户状态成功!')
},

5.8 实现搜索功能

  1. 将文本框将data数据作双向绑定

  2. 查询函数 (后端写的)

  3. input输入框自带功能 清空

    clearable @clear="getUserList" 

6 添加用户

6.1 添加用户的对话框Dialog对话框

  1. title 标题

  2. 控制对话框的显示与隐藏

:visible.sync="addDialogVisible"

6.2 渲染添加用户的表单 Form表单

prop -验证规则属性

  1. 粘贴 el-form、el-form-item

  2. el-form :model 数据绑定对象、:rules 验证规则对象、ref 引用对象、label-width文本宽度

  3. el-form-item label 文本、prop 具体的校验规则(在rules做具体定义)

  4. el-input v-model做数据双向绑定

<el-dialog title="添加用户" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed">
  <!-- 内容主体区域 -->
  <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="70px">
    <el-form-item label="用户名" prop="username">
      <el-input v-model="addForm.username"></el-input>
    </el-form-item>

 

6.3 自定义校验规则Form表单

  1. 在data中定义一个箭头函数,代表校验规则

  2. 在具体的规则中用validator使用自定义规则,trigger定义校验时机

6.4 实现添加表单的重置操作

每次打开都是全新的表单

  1. 监听对话框的close关闭事件

  2. 在关闭事件中重置表单(用到$ref引用对象,调用resetFields)

addDialogClosed () {
  this.$refs.addFormRef.resetFields()
}

6.5 表单预校验 调用API接口完成添加用户操作

  1. 也要拿到整个表单的引用对象

    预校验通过,可以发起真正的添加用户的网络请求

  2. addUser () {
      this.$refs.addFormRef.validate(async valid => {
        if (!valid) return
        // 可以发起添加用户的网络请求
        const { data: res } = await this.$http.post('users', this.addForm)
    
        if (res.meta.status !== 201) {
          this.$message.error('添加用户失败!')
        }
    
        this.$message.success('添加用户成功!')
        // 隐藏添加用户的对话框
        this.addDialogVisible = false
        // 重新获取用户列表数据
        this.getUserList()
      })
    },
    

7 修改用户

7.1 根据ID查询对应的用户信息

根据ID查询对应的用户信息,保存供我们在表单填充

  1. @click="showEditDialog(scope.row.id)"
    
  2. 接收到ID,调用API接口,查询到用户信息

  3. 将查询到的信息保存到editform表单数据对象上

// 展示编辑用户的对话框
async showEditDialog (id) {
  // console.log(id)
  const { data: res } = await this.$http.get('users/' + id)

  if (res.meta.status !== 200) {
    return this.$message.error('查询用户信息失败!')
  }

  this.editForm = res.data
  this.editDialogVisible = true
},

7.2 提交表单完成用户信息

editUserInfo () {
  this.$refs.editFormRef.validate(async valid => {
    if (!valid) return
    // 发起修改用户信息的数据请求
    const { data: res } = await this.$http.put(
      'users/' + this.editForm.id,
      {
        email: this.editForm.email,
        mobile: this.editForm.mobile
      }
    )
    if (res.meta.status !== 200) {
      return this.$message.error('更新用户信息失败!')
    }

    // 关闭对话框
    this.editDialogVisible = false
    // 刷新数据列表
    this.getUserList()
    // 提示修改成功
    this.$message.success('更新用户信息成功!')
  })
}

今后修改成功都有 关闭对话框、刷新数据列表、提示修改成功三行代码

7.3 删除用户 MessageBox弹框、调用API 删除

  1. 按需导入,原型挂载将Message.confirm函数挂载到Vue的原型对象上,名字为$confirm

    Vue.prototype.$confirm = MessageBox.confirm
    
  2. 在每一个vue组件中都可以通过this.$confirm来弹出一个确认消息的提示框,通过async await简化promise操作,结果定义为confirmResult接受到用户的操作结果

    async removeUserById (id) {
      // 弹框询问用户是否删除数据
      const confirmResult = await this.$confirm(
        '此操作将永久删除该用户, 是否继续?',
        '提示',
        {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }
      ).catch(err => err)
    
    3.对confirmResult进行if判断
    
      // 如果用户确认删除,则返回值为字符串 confirm
      // 如果用户取消了删除,则返回值为字符串 cancel
      // console.log(confirmResult)
      if (confirmResult !== 'confirm') {
        return this.$message.info('已取消删除')
      }
    // 发送网络请求:参数已经通过removeUserById (id)函数接接收到
      const { data: res } = await this.$http.delete('users/' + id)
    //处理相应结果
      if (res.meta.status !== 200) {
        return this.$message.error('删除用户失败!')
      }
    
      this.$message.success('删除用户成功!')
      //成功之后刷新数据列表
      this.getUserList()
    },
    

8 权限列表

  1. 创建组件->定义对应路由规则

  2. 什么时候发起data()请求?生命周期函数created中发起这次数据请求

  3. 渲染全写列表UI结构 border-表格纵向边框线 stripe-隔行变色

<el-table :data="rightsList" border stripe>
  1. el-tag 自定义权限等级这一列渲染成什么样子

    • 作用域插槽形式来自定义输出格式,用scope接收所有数据

    • 注册el-tag标签为全局可用

    • 按需展示标签 v-if /v-else-if/v-else判断

<el-table-column label="权限等级" prop="level">
  <template slot-scope="scope">
    <el-tag v-if="scope.row.level === '0'">一级</el-tag>
    <el-tag type="success" v-else-if="scope.row.level === '1'">二级</el-tag>
    <el-tag type="warning" v-else>三级</el-tag>
  </template>
</el-table-column>

9 角色列表

通过权限管理模块控制不同的用户可以进行哪些操作,具体可以通过角色的方式进行控制,即每个用户分配一个特定的角色,角色包括不同的功能权限

  1. 通过路由展示角色列表组件

  2. 绘制基本布局结构并获取列表数据

  3. 渲染角色列表数据,设置展开列

    <el-table-column type="expand">
    
  4. 通过三次for循环渲染三级权限

  5. 栅格系统布局 el-row

    <el-col :span="5">   //占5列
    <el-col :span="19">   //占19列
    
  6. 美化一级权限的UI结构

将底边框绑定给每一行
<el-row :class="['bdbottom', i1 === 0 ? 'bdtop' : '', 'vcenter']" v-for="(item1, i1) in scope.row.children" :key="item1.id">
 
:class="[]"  //加冒号代表动态数据绑定
i1           //代表索引
  1. 美化ui结构

    • min-width: 1366px;   //当页面不足1366时候,会强制屏幕宽为1366px,不会出现强制换行的问题
      
    • 居中对其:在el-row中添加 display:flex align-item 纵向对齐justify-content 横向对齐

    • 点击删除权限按钮弹出确认提示框

  2. 删除角色下指定权限的功能

    // this.getRolesList()            //删除权限之后 整个下拉菜单会自动合起来
    role.children = res.data     //服务器返回的最新的权限赋值给角色的children属性
    

10 分配权限 Tree 树形控件

  1. 弹出分配权限对话框并请求权限数据

  2. 初步配置并使用el-tree树形控件

  3. 优化树形控件的展示效果

  4. 加载当前角色已有的权限:

    1. 在点击分配权限按钮的同时,将当前角色身上所有三级权限的id获取出来放到一个数组中,并且把这个数组通过属性绑定交给:default-checked-keys

    2. 递归函数获取所有三级节点的Id

    3. 点击分配权限按钮的时候 弹出对话框且获取所有三级节点Id

    4. 在关闭对话框时重置defKeys数组

    5. 调用API完成分配权限的功能

    const keys = [
      ...this.$refs.treeRef.getCheckedKeys(),           
      // 扩展运算符 将一个数组转为用逗号分隔的参数序列,对数组进行解包
      ...this.$refs.treeRef.getHalfCheckedKeys()
    ]
    
    • 点击分配权限按钮时,立刻将当前角色id保存在data中 供我们后续使用

    • 在点击确定按钮时候,先获取整个树形结构中半选和全选状态的id值,将他们合并为一个完整的数组

    • 接着将得到的数组做了一次字符串的拼接

    • 发送网络请求

    • 刷新角色列表 关闭分配权限的对话框

    • async allotRights () {
        const keys = [
          ...this.$refs.treeRef.getCheckedKeys(),
          ...this.$refs.treeRef.getHalfCheckedKeys()
        ]
      
        const idStr = keys.join(',')
      
        const { data: res } = await this.$http.post(
          `roles/${this.roleId}/rights`,
          { rids: idStr }
        )
      
        if (res.meta.status !== 200) {
          return this.$message.error('分配权限失败!')
        }
      
        this.$message.success('分配权限成功!')
        this.getRolesList()
        this.setRightDialogVisible = false
      }
      
  5. 渲染角色列表的 select下拉菜单

 

 

 

 

其他人项目运行笔记/运行解决

项目初始化: 1.安装Vue脚手架 2.通过脚手架创建项目 3.配置路由 4.配置Element-UI:在插件中安装,搜索vue-cli-plugin-element 5.配置Axios:在依赖中安装,搜索axios(运行依赖) 6.初始化git仓库 7.将本地项目托管到github或者码云中

后台项目的环境安装配置: 1.安装MySQL数据库:将mydb.sql文件还原到mydb数据库 默认MySQL密码是root 2.安装nodeJS,配置后台项目,从终端打开后台项目vue_api_server 然后在终端中输入命令安装项目依赖包:npm install 并运行node .\app.js将api接口项目跑起来 3.使用Postman测试后台项目接口是否正常(请求登录接口)

vue ui创建项目出现错误Failed to get response from https://...babel helper vue jsx merge props 解决方式: 安装npm install babel-helper-vue-jsx-merge-props --save-dev

安装less依赖:less-loader和less两个

格式化文档和eslint发生冲突 格式规则不一样 可以创建一个文件prettierrc进行配置:如printWidth超过多少字符换行 以符合eslint的规范 也可以关停相应的警告:复制警告的规则 在eslintrc里面进行配置

项目启动时报错Syntax Error: TypeError: this.getOptions is not a function 是因为less-loader 版本过高 需要先卸载再装低版本npm install less-loader@6.0.0 或者不加lang=less也行

Element UI 的标签就是类名 可以直接拿这个设置样式

后台除了登录接口之外,都需要token权限验证,可以通过添加axios请求拦截器来添加token,为请求头加上Authorization属性 值为token,以保证拥有获取数据的权限

layout栅格 总宽度24格

作用域插槽slot-scope,组件如果要根据数据自定义 就要放到作用域插槽里 如权限里的tag

Form表单里的自定义规则

resetFields重置 保存状态

messagebox消息弹框 这个写到方法里面 不是html里面

如果某个函数的返回值是promise 可以用async和await来优化

分类组件里面的下拉表格组件使用插件vue-table-with-tree-grid 先安装 导入 再注册这个组件 (Day4)

按需显示标签 v-if v-else else

级联选择器 父级分类

文本输入框和按钮之间的切换

时间过滤器 将时间以年月日的形式展示 | 管道符

v-model主要是为了让页面上的操作存储到数据里 从而实现双向绑定

安装依赖vue-quill-editor富文本编辑器 然后导入组件并注册

格式转换问题:级联选择器的选中项通过v-model以数组的形式和传递的参数goods_cat绑定了 但是最后传给服务器的时候要字符串形式 但是又不能将其直接改为字符串(正向渲染不出来 会报错)所以要先深拷贝一份总参数对象 安装lodash包 装好依赖后先在本组件里导入(推荐用_接收 类似jquery用$接收)然后调用cloneDeep方法拷贝一份新的对象 在这份新的里面转换好格式再发送给服务器

Timeline时间线组件 element ui 2.6以前的版本是没有的

可视化要安装Echarts依赖 先在report里导入插件 再在mounted里面(不是created)将div初始化为一个echarts实例 合并对象用lodash里的merge方法

生产环境中的项目优化: 1.展示进度条:安装依赖nprogrss 然后在main.js导入两个文件 在request拦截器中显示进度条,在response拦截器中隐藏进度条 2.在serve阶段允许出现console.log 但在build阶段不允许:安装bable-plugin-transform-remove-console(发布时依赖)然后在bable.config.js里面的插件中新增一个transform-remove-console 但是只在发布阶段使用 所以定义一个数组 通过判断process.env.NODE_ENV的值 如果是生产环境则添加这个插件 否则不用这个插件 3.打包报告:记录项目中的错误和其他信息 可以在UI界面中的控制台和分析里面进行查看 饼状图中较大的文件需要减小体积(依赖项)控制台里面打开速度需要优化 资源里面的最大的js文件(1.6M 惊叹号)也需要优化 4.自定义配置(脚手架3)在vue.config.js里面 5.为开发和发布模式指定不同的打包入口:在vue.config.js里面通过chainWebpack修改webpack配置 通过process.env.NODE_ENV的值来设置不同的打包入口 6.设置某些包不合并到js里面 而是在html中以外部CDN的形式导入(如Element UI) 同时将js里面的样式改为html中引入 7.首页定制:开发和发布模式的title显示不一样 先在chainWebpack里面配置isProd 然后title里面根据这个值选择性地渲染标题 那些CDN资源也用这种方式当发布模式才加载上 可以通过build之后生成的dist里面的html里看到最终渲染效果 8.路由懒加载:安装@babel/plugin-syntax-dynamic-import依赖 在babel里面配置好 再将router.js里面的路由改为按需加载

项目上线 1.通过node创建web服务器:在服务包里先初始化npm 再安装express包 将项目里的dist文件夹复制到服务包里 再新建一个app.js 导入express并创建express好服务器 终执行node .\app.js启动服务器 就能在浏览器输入地址查看到项目了 2.开启gzip压缩 减小文件体积 加快传输速度 先安装compression 再导入、注册 打开项目 在network里面可以看到传输的文件大小要小于实际大小 3.配置https服务 让网络传输更加安全 采用https协议对传输的数据进行加密处理 先申请SSL证书FreeSSL.cn 再导入证书 4.pm2管理应用:项目通过在终端运行node .\app.js打开网站 关闭了终端就不能打开了 要想还能打开就要用pm2管理工具 先全局安装pm2 再启动项目pm2 start .\app.js --name zidinyi 此时关闭终端依然能打开网站 要查看运行的项目可打开cmd终端运行pm2 ls 也可停止项目等

练习时出现的问题: 1.serve后出现警告 export 'default' (imported as 'echarts') was not found in 'echarts' 并且项目里出现错误TypeError:Cannot read property 'init' of undefined 解决方法:把import echarts from 'echarts'改为import * as echarts from 'echarts' 2.项目里出现错误'normal' hierarchy in areaStyle has been removed since 4.0. All style properties are configured in areaStyle directly now.echarts版本太老所以从服务器里传来的数据格式不对 areaStyle 里面的normal配置项不用了 直接写在areaStyle 里面就行 3.项目里出现警告(Cate组件中) expand-trigger is removed, use props.expandTrigger instead. 老版本Element-UI(2.6)中的expand-trigger 菜单的触发方式 新版改为了expandTrigger且要加在下面的cascaderProps里 而不是直接写在标签里。change-on-select is removed, use props.checkStrictly instead. 老版本(2.6)中change-on-select属性 新版没有了改为checkStrictly(严格的遵守父子节点不互相关联)

改为

不能导入次数过多

 yfh补充

1. 打开vue项目目录,shift右键打开Powershell窗口
2. 报错#error More than 1 blank line not allowed no-multiple-empty-lines 删除项目中的空行/关闭eslint
3.报错 imported multiple times import/no-duplicates
![](https://img2020.cnblogs.com/blog/2448090/202112/2448090-20211215222301508-596795182.png)
改为,不能import过多
![](https://img2020.cnblogs.com/blog/2448090/202112/2448090-20211215222504666-555204048.png)

Git

打开项目,先不急写代码,打开终端,查看工作区是否干净

在终端中输入

将本地仓库上传到码云中,如何在码云中新建一个仓库并将仓库做关联

git add .    添加到暂存区: 
git status         -当前工作区是否干净    需要开发一个新的功能在新分支里开发,然后合并到master主分支
git commit -m"完成了登录功能"       ——将暂存区的所有代码保存到本地仓库中 -m 后面是描述
git checkout -b login                      创建子分支login
git branch                查看当前项目所有分支
git checkout master    切换分支到master
git merch login            合并login和master代码
git push    本地代码推送到云端

git branch 检查当前所处分支
git checkout -b user 切换到新建分支user上,同时当前所有代码的修改都切换到user子分支上
git status    显示修改文件以及新增文件代码
git add .
git status 发现所有文件都被添加到暂存区
git commit -m "完成用户列表功能的开发"   所有代码的修改都已经提交到user子分支,本地仓库更新完成
git status、
git push -u origin user origin代表云端仓库的别名。将本地的user分支推送到云端origin这个仓库中同时以user分支进行保存
git checkout master
git branch
git merge user     先切换到master主分支,在主分支上合并user分支,代码也更新了
git push -u origin xxx  

推送云端的代码 只能从合并master之后推送到云端master
  1. 初始化git远程仓库

  • 创建码云账号并配置SSH公钥

  • 首次创建,测试密钥是否可用,

     

将本地项目托管到Github或码云中

  • 新建仓库

  • 填写仓库名称,将Readme文件初始化这个仓库去勾

  • 全局设置

    git config --global user.name "fuhua yi"

     

     

新建仓库步骤

1.

 

 

 2.

 

 

 

posted @ 2022-04-28 22:28  衣囧~  阅读(422)  评论(0编辑  收藏  举报