电商后台管理系统

image.png

电商后台管理系统

项目源码:码云
微信号:RanY_Luck

1、前端项目的技术栈

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

2、后端项目技术栈

  • Node.js
  • Express
  • Jwt
  • Mysql
  • sequelize

项目前端初始化

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

1、安装Vue脚手架

npm install -g @vue/cli

2 、通过Vue脚手架创建项目(通过可视化创建)

vue ui

image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png

3、安装Element-UI

image.png
image.png
image.png
image.png

4、配置Axios库

image.png
image.png

5、配置less、less-loader开发依赖

image.png

项目所有依赖

image.png
启动服务并启动app
image.png
你会看到这样的一个画面
image.png

5、将本地项目托管到码云

image.png
image.png
image.png
image.png
测试一下:
image.png

项目后端初始化

1、安装MySql数据库

官网:https://www.mysql.com/

2、安装Node.js环境

官网:https://nodejs.org/zh-cn/

3、配置项目相关信息

image.png

4、启动项目

node app.js

image.png

5、使用Postman测试后台项目接口是否正常

image.png

登录/退出功能

原理

登录功能代码实现

通过Element-UI组件实现布局

  • el-form
  • el-form-item
  • el-input
  • el-button
  • 字体图标

代码解读

main.js

image.png
image.png
image.png
删除views

清空页面

<template>
  <div id="app">

  </div>
</template>

<script>
// 导入helloword
export default {
  name: 'app'
}
</script>

<!-- style样式 -->
<style>
</style>

image.png

创建一个comments目录

创建Login.vue文件

<template>
  <div class="login_container">
    <!-- 登录主体边框 -->
    <div class="login_box">
      <!-- 头像区域 -->
      <div class="avater_box">
        <img src="../assets/logo.png" alt="头像logo">
      </div>
      <!-- 登录表单区域 -->
      <el-form :model="loginForm" :rules="rules" ref="loginFormRef" label-width="0px" class="login_form">
        <!-- 用户名 -->
        <el-form-item prop="username">
          <el-input v-model="loginForm.username" placeholder="请输入账号" prefix-icon="iconfont icon-RectangleCopy"></el-input>
        </el-form-item>
        <!-- 密码 -->
        <el-form-item prop="password">
          <el-input v-model="loginForm.password" placeholder="请输入密码" prefix-icon="iconfont icon-RectangleCopy1" 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('loginForm')">重置</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      // 这是登录表单的数据绑定对象
      loginForm: {
        username: 'admin',
        password: '123456'
      },
      // 这是表单的验证规则对象
      rules: {
        // 验证用户名是否合法
        username: [
          { required: true, message: '请输入登录账号', trigger: 'blur' },
          { min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' }
        ],
        // 验证密码是否合法
        password: [
          { required: true, message: '请输入登录密码', trigger: 'blur' },
          { min: 6, max: 15, message: '长度在 6 到 15 个字符', trigger: 'blur' }
        ]
      }
    }
  },
  methods: {
    // 点击重置按钮,重置登录表单
    resetLoginForm () {
      // 前提是先获取ref节点
      this.$refs.loginFormRef.resetFields()
    },
    login () {
      // 表单之前的预验证
      this.$refs.loginFormRef.validate(async valid => {
        if (!valid) return;
        const { data: res } = await this.$http.post('login', this.loginForm);
        if (res.meta.status !== 200) return this.$message.error('登录失败! ');
        this.$message.success('登录成功');
        // 1. 将登陆成功之后拿到后端返回的token值,保存到客服端也就是临时浏览器sessionStorage中
        //  1.1 项目中出了登录之外的其他api接口,必须在登录之后才能访问
        //  1.2 token只应在当前网站打开期间生效,所以将token保存在sessionStorage中
        const data = res.data.token;
        window.sessionStorage.setItem('token', data);
        // 2. 通过编程式导航跳转到后台主页,路由地址是 /home
        this.$router.push('/home');
      })
    }
  }
}
</script>

<style lang="less" scoped="">
.login_container {
  background: #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%); // 在横轴上进行位移-50%,纵轴上位移-50%
  // 语法嵌套
  .avater_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%); // 在横轴上进行位移-50%,纵轴上位移-50%
    background-color: #fff;
    img {
      width: 100%;
      height: 100%;
      border-radius: 50%; // 添加圆角边框
      background-color: #eee;
    }
  }
}
.btns {
  display: flex; // 弹性布局
  justify-content: flex-end; // 位于容器的结尾
}
.login_form {
  position: absolute; // 绝对定位
  bottom: 0; // 底部对齐
  width: 100%;
  padding: 0 20px;
  box-sizing: border-box; // 将元素限制到宽度里面
}
</style>
  <div id="app">
    <!-- 路由占位符 -->
    <router-view></router-view>
  </div>


<script>
// 导入helloword
export default {
  name: 'app'
}
</script>

<!-- style样式 -->
<style>
</style>

访问页面
image.png
现在需要让用户访问根目录就自动跳转到login页面
image.png

tips:

image.png
post返回值是一个Promise 对象,为了简化Promise操作,我们可以用async await 来优化
await 只能用在async的方法中,所以需要把vaild修饰成异步,这样就能直接拿到服务器返回的数据{ data: res }中的data 才是服务器的真实数据,然后重命名为res对象,然后在根据res的meta属性来判断是否为200,为200就登录成功并打印,不为200就失败并打印。

进行登录跳转

image.png

image.png
第一步:你需要进行组件导入
image.png
进行全局导入后,以后用到message就可以直接用this.$message.xxx()
第二步:代码使用
image.png

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

// 为路由对象,添加 beforeEach 导航守卫
router.beforeEach((to, form, next) =>{
  // 如果用户访问的登录页,直接放行
  if(to.path === '/login') return next()
  // 从 sessionStorage 中获取保存的token值
  const tokenStr = window.sessionStorage.getItem('token')
  // 没有token,强制跳转到登录页
  if(!tokenStr) return next('/login')
  next()
})

判断用户在没有token了自动跳转到登录界面
需要进行router.js改写
image.png

退出功能

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

// 清空token
window.sessionStorage.clear();

// 跳转到登录页
this.$router.push('/login')

image.png

主页布局

<el-container>
    // 头部区域
    <el-header></el-header>
    <el-container>
    // 侧边栏区域
    <el-asider></el-asider>
    // 右侧主体区域
    <el-main></el-main>
    </el-container>
</el-container>

image.png

左侧菜单布局

<el-menus>
    <el-submenu>
        // 这个template 是一级菜单的内容模版
            <i class="el-icon-menu"></i>
            <span>一级菜单</span>
        // 在一级菜单中,可以嵌套二级菜单
        <el-menu-item>
            <i class="el-icon-menu"></i>
            <span slot="title">二级菜单</span>
        </el-menu-item>
    </el-submenu>
</el-menus>

image.png

<!-- 侧边栏 -->
      <el-aside width="200px">
        <!-- 侧边栏菜单区 -->
        <el-menu background-color="#333744" text-color="#fff" active-text-color="#ffd04b">
        <!-- 一级菜单 -->
          <el-submenu index="1">
            <!-- 一级菜单的模板区 -->
            <template slot="title">
              <!-- 图标 -->
              <i class="el-icon-location"></i>
              <!-- 文本 -->
              <span>一级菜单</span>
            </template>
            <!-- 二级菜单 -->
            <el-menu-item index="1-4-1">
              <!-- 图标 -->
              <i class="el-icon-location"></i>
              <!-- 文本 -->
              <span>二级菜单</span>
            </el-menu-item>
            </el-submenu>
        </el-menu>
      </el-aside>

需要element.js进行注册
image.png
image.png

通过接口获取菜单数据

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

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

image.png
image.png
对接口请求,获取详细信息:
image.png
就可以看到已经获取到数据,所有的一级菜单都放在了data数据中,二级菜单就嵌到了children中
image.png
拿到了数据 我们就需要渲染到页面中
第一步:需要在一级菜单进行v-for循环
image.png
第二步:需要在一级菜单的基础上对二级菜单再进行v-for循环
image.png
image.png
代码:
image.png
不过可以看到一级菜单的图标都为统一不是很好看,我们需要整改下
第一步:先自定义iconsObj
image.png
第二步:在一级菜单的图标中进行v-bind双向绑定
image.png
效果:
image.png
fix展开后对不齐的问题,先看效果:
image.png
经过分析:
image.png
于是可以在css选择器中添加个border-right: none;就可以了
image.png
fix可以将一级菜单全部展开,先看效果:
image.png
经过分析:element-ui是默认展开的,不过也提供了只保持一个子菜单展开的api
image.png
image.png
水平折叠收起菜单
image.png
经过分析:element-ui是默认不折叠的,不过也提供了只保持一个子菜单展开的api
image.png
第一步:在el-menu新增
image.png
第二步:自定义一个div,并赋予click事件
image.png
image.png
第三步:在data()定义初始值
image.png
第四步:动态赋值侧边栏宽度
image.png

路由重定向

第一步:创建个Welcome.vue文件

image.png
第二步:在router里面导入Welcome.vue
image.png
第三步:在Home.vue中渲染出Welcome.vue的内容
image.png

侧边栏路由跳转

步骤一:
image.png
步骤二:
image.png

image.png
效果:
image.png

用户列表的开发

第一步:在comments里新建一个user的文件夹,创一个Users.vue的文件
image.png
第二步:在router里面引用
image.png
image.png
效果:
image.png

fix点击二级菜单不会高亮,刷新后又重置

步骤一:在侧边栏增加default-active语法
image.png
image.png
image.png
第二步:我们需要动态渲染路径
image.png
image.png
image.png
image.png
组件创建了需要执行created生命周期函数
image.png
在点击不同连接的时候,我们需要给activePath重新赋值
image.png
这样就不会点了其他高亮然后再点回来不高亮啦(可能有点绕)
1.gif

用户列表

增加面包屑

步骤一:element-ui给出了面包屑的方案
image.png
image.png
我们只需要复制过来
步骤二:需要在element.js中进行按需引入
image.png
效果:
image.png

增加Card卡片

步骤一:element-ui给出了卡片的方案
image.png
我们只需要复制过来删除不必要的东西
image.png

增加Layout布局之分栏间隔

步骤一:element-ui给出了卡片的方案
image.png
我们只需要复制过来删除不必要的东西
image.png
效果:
image.png
tips:
需要对card做样式修改。可以在global.css中做全局设定,当然也可以自建class进行修改样式
image.png
image.png

增加获取用户列表数据

第一步:查看接口文档
image.png
第二步:将接口请求参数定义到data中
image.png
第三步:进行axios请求
image.png
第四步:定义空列表
image.png
第五步:赋值数据到空列表中
image.png

增加渲染用户列表数据

快速入门Table表格(element-ui提供了方法)
第一步:
image.png
第二步:copy代码
image.png
第三步:重置样式
image.png
效果:
image.png
发现序号id,值非常大,不便于查看,我们需要自己创建一个索引,特别简单
image.png
效果:
image.png

增加状态开关

快速入手Switch开关(element-ui提供了方法)
image.png
步骤一:作用域插槽
image.png
image.png
步骤二:将v-model绑定到作用域的mg_state
image.png
效果:
image.png
fix更改后刷新重置,没有更改数据库值
步骤一:element-ui给了一个解决方法api
image.png
image.png
步骤二:修改用户状态接口(put)方法

image.png
步骤三:监听switch开关状态的改变
image.png
接口地址分析:
image.png
效果:
1.gif

增加操作按钮

快速入手Tooltip 文字提示(element-ui提供了方法)
image.png
步骤一:
image.png
步骤二:在element.js按需导入
image.png

效果:
image.png

增加分页模块

快速入手Pagination分页(element-ui提供了方法)
image.png
步骤一:
image.png

事件名称 说明
size-change pageSize 改变时会触发
current-change currentPage 改变时会触发
current-page 当前页数
page-sizes 每页显示个数选择器的下拉
page-size 每页显示条目个数
layout 组件布局,子组件名需要用逗号隔开
total 总条目数

步骤二:传参
image.png
第三步:在element.js按需导入
image.png
第四步:重置样式(global.css)
image.png
效果:
12.gif

增加搜索/清空功能image.png

效果:
1.gif

增加添加用户对话框

快速入手Dialog对话框(element-ui提供了方法)
image.png
image.png
第二步:进入element.js按需引入
image.png
第三步:初始化对话框为隐藏
image.png
第四步:在添加用户这个按钮上给一个click事件,并赋值为true
image.png
效果:
1.gif

完善添加用户表单

步骤一:
code.png
model数据绑定对象 rules验证规则对象 ref引用对象 label-width确定了文本所占宽度
步骤二:添加表单用户的表单数据
image.png
步骤三:添加表单的验证规则对象
code.png
效果:
image.png
新增邮箱、手机校验规则
快速入手Form表单自定义校验规则(element-ui提供了方法)
步骤一:查看官方文档示例
image.png
因为邮箱/手机这种校验规则比较复杂,这里推荐大家下个插件
image.png
image.png
步骤二:增加校验规则
image.png
效果:
1.gif
fix填写完表单后重新打开未重置效果
第一步:element-ui给出了Form表单重置方案
image.png
第二步:写一个close的关闭事件
image.png
第三步:
image.png
效果:
1.gif

添加用户

请求预校验

步骤一:当点击确定时,我们需要预加载数据看是否符合规则
image.png
image.png
效果:
image.png
image.png

请求添加一个新用户

第一步:查看接口文档
image.png
image.png
第二步:发起axios请求
image.png
效果:
1.gif

操作之编辑

增加修改用户对话框

第一步:使用Dialog对话框(element-ui给出了例子)
image.png
第二步:在编辑按钮上增加click事件
image.png
第三步:增加编辑对话框
image.png
第四步:methods增加显示为true
image.png
第五步:控制修改用户对话框显示与隐藏
image.png
效果:
1.gif

增加根据用户id查询用户信息

第一步:使用scope.row.id获取到用户id
image.png
第二步:查看接口文档
image.png
第三步:进行接口文档的调用
image.png
第四步:在data中创建editForm
image.png
第五步:res的数据保存到第四步中
image.png
效果:点击编辑按钮后将id传入到api接口中
image.png

增加编辑表单

第一步:制作表单
image.png
第二步:定义验证规则
image.png
效果:
1.gif

fix验证不通过存留状态

第一步:添加一个click事件
image.png
第二步:监听修改用户关闭对话框
image.png

增加提交修改预校验表单

第一步:在提交按钮上增加一个click事件
image.png
第二步:进行预校验
image.png
效果:
image.png

增加修改用户信息操作

步骤一:看后端接口
image.png
步骤二:在确定按钮上添加click事件
image.png
效果:
1.gif

增加删除用户信息操作

第一步:导入MessageBox 弹框(element-ui给出了方案)
image.png
image.png
第二步:在删除按钮上增加一个click(id)事件
image.png
第三步:根据id删除对应用户信息(参考elementui给出的方案)
image.png
image.png
效果:
1.gif
第四步:使用接口文档进行删除用户信息
image.png
第五步:调用接口
image.png
效果:
1.gif

增加分配角色操作

第一步:导入Dialog对话框 弹框(element-ui给出了方案)
image.png
image.png
第二步:在分配角色按钮新增click事件
image.png
第三步:在data中定义对话框初始化为隐藏
image.png
第四步:点击角色分配按钮就进行展示为true
image.png
效果:
1.gif

增加分配角色操作之下拉选择职位

第一步:在data创建接收对象
image.png
第二步:查看接口文档
image.png
第三步:接口请求
image.png
第四步:导入Select选择器(element-ui给出了方案)
image.png
image.png
第五步:赋予一个接收选中对象的值
image.png
第六步:进行组件注册
image.png
效果:
1.gif

新增选择职位后点击确定应用

第一步:在确定按钮增加click事件
image.png
第二步:查看接口文档
image.png
第三步:接口调用
image.png
效果:
1.gif

fix第二次选择进行重置

第一步:给分配角色一个close事件
image.png
第二步:重置列表
image.png
效果:
1.gif

权限列表

增加权限列表路由

第一步:写Rights.vue
code.png
第二步:在路由引入步骤一
注意:因为在home里面继续跳转,所以权限列表为home的子路由
image.png
image.png
效果:
image.png

权限列表的基本布局

第一步:使用面包屑
image.png
第二步:使用card卡片
image.png
效果:
image.png

权限列表的数据获取

第一步:创建一个权限列表的接收对象
image.png
第二步:创建生命周期
image.png
第三步:查看接口文档
image.png
第四步:创建方法并声明
image.png
效果:
image.png

表格渲染

第一步:使用el-card
image.png
第二步:使用el-table表格image.png
第三步:使用el-table-column 填入数据 label 定义列名 width定义列宽
image.png
第四步:使用el-tag标签
image.png
效果:
image.png

角色列表

增加角色列表路由

第一步:写Rights.vue
code.png
第二步:在路由引入步骤一
注意:因为在home里面继续跳转,所以权限列表为home的子路由
image.png
image.png
效果:
image.png

角色列表基本布局

第一步:使用面包屑
image.png
第二步:使用card卡片
image.png
image.png

角色列表的数据获取

第一步:创建一个权限列表的接收对象
image.png
第二步:创建生命周期
image.png
第三步:查看接口文档
image.png
第四步:创建方法并声明
image.png
效果:
image.png

表格渲染

第一步:使用el-card
image.png
第二步:使用el-row Layout布局
image.png
第三步:使用el-table/el-table-column 表格
image.png
效果:
1.gif

新增下拉列表数据展示

第一步:使用插槽进行数据展示/v-for进行循环取出值
image.png
image.png
效果:image.png

美化一级权限表格

第一步:增加样式
image.png
第二步:
image.png
效果:
image.png

美化二级权限表格

第一步:
image.png
效果:
image.png

美化三级权限表格

第一步:
image.png
效果:
image.png
总体效果:
image.png

美化权限表格

第一步:创建一个样式
image.png
第二步:将样式放到需要的位置
image.png
效果:
image.png

新增删除权限

第一步:使用可移除标签(element ui给出了方案)
image.png
image.png
第二步:点击移除标签是触发的事件
image.png
image.png
第三步:写二次弹框(element ui 给出了方案)
image.png
image.png
效果:1.gif

fix删除权限完整功能

第一步:查看接口文档
image.png
第二步:接口请求
image.png
image.png
效果:
1.gif

新增分配权限获取所有权限数据

第一步:新增一个click事件
image.png
第二步:点击分配权限弹框(element ui 给出了方案)
image.png
image.png
第三步:默认分配权限对话框为隐藏
image.png
第四步:点击对话框就显示
image.png
效果:
1.gif
第五步:查看接口文档
image.png
第六步:接口调用
image.png
效果:1.gif

新增分配权限树形组件

快速入门Tree树形控件(element-ui提供了方法)
第一步:
image.png
image.png
第二步:将控件树形树形控件属性绑定对象
image.png
第三步:进行组件注册
image.png
效果:1.gif

fix分配权限复选框/默认展开

第一步:在el-tree增加属性(element-ui给了方案)
image.png
效果:
1.gif

获取角色原有权限

第一步:默认勾选节点key的数组(element ui给出了方案)
image.png
image.png
第二步:在data中定义一个接收对象
image.png
第三步:进行递归函数遍历权限接口
image.png
第四步:在分配权限增加click事件并拿到所有数据
image.png
第五步:将role进行传参,将获取到的id传入第三步defkeys中
image.png
效果:1.gif

fix点击不同角色分配权限造成权限id累积

第一步:新增close事件
image.png
第二步:监听分配权限对话框关闭事件,没关闭一次,就像defkeys赋值一个空数组
image.png

新增角色权限增加

第一步:新增一个click事件在确定按钮上
image.png
第二步:定义一个dom元素
image.png
第三步:选中权限点击确定
el-tree给了2个函数,getCheckedKeys 节点选择后返回节点的key所组成的数组
getHalfCheckedKeys 节点被选择,返回目前半选节点的key所组成的数组
image.png
image.png
tips:...为JS中展开运算符

let a={x:1,y:2};
let b={z:3};
let ab={...a,...b};
ab //{x:1,y:2,z:3}

效果:
1.gif

fix勾选权限点击确定并应用

第一步:查看接口文档
image.png
第二步:进行接口请求
image.png
效果:
1.gif

商品分类

增加商品分类骨架

第一步:需要重新创建一个分支取名为:goods_cate
image.png
第二步:在comments创建一个goods目录,创建Cate.vue
image.png
第三步:写基础骨架

// Cate.vue
<template>
    <div>
        商品分类组件
    </div>
</template>

<script>
export default {
    data() {
        return {}
    },
    // 生命周期函数
    created() {
    },
    // 所有的事件处理函数
    methods: {
    }
}
</script>

<style lang="less">

</style>

第四步:在路由引入
image.png
image.png
效果:image.png

增加面包屑/按钮/卡片基础页面

第一步:引入面包屑
image.png
第二步:引入卡片视图
image.png
第三步:引入button按钮
image.png
效果:image.png

获取商品分类后端数据

第一步:查看接口文档
image.png
第二步:创建data数据
image.png
第三步:创建生命周期
image.png
第四步:接口请求
image.png
效果:
image.png

首次使用Vue-table-with-tree插件

第一步:安装插件
进入到vue ui中依赖--安装依赖---vue-table-with-tree-grid
image.png
第二步:在main.js引入插件
image.png
image.png
第三步:运用插件
image.png
data:指定绑定数据;columns:表格各列的配置;selection-type:关闭复选框
expand-type:关闭展开项;show-index:增加索引;index-text:索引名称;border:显示纵向边框;show-row-hover:鼠标悬停是否高亮
第四步:录入数据
image.png
效果:
image.png

美化表格

第一步:增加自定义模版列渲染,表格数据,定义插槽
image.png
第二步:添加对应样式
image.png
效果:
image.png

新增排序/操作

第一步:增加自定义模版列渲染,表格数据,定义插槽
image.png
第二步:添加对应样式
image.png
效果:
image.png

新增分页区域

第一步:引入Pagination分页(element ui给出了方案)
image.png
image.png
size-change:监听pagesize事件;current-change:监听pagenum事件;current-page:当前页;page-sizes:显示下拉条数;page-size:默认显示条数;
total:总条数
第二步:在methods创建对应事件
image.png
效果:
image.png

新增添加分类弹出框

第一步:引入Dialog对话框(element ui给出了方案)
image.png
image.png
第二步:在data中初始化该对话框为隐藏
image.png
第三步:在添加分类button上增加一个click事件
image.png
第四步:在methods中处理事件
image.png
效果;
1.gif

新增添加分类数据

第一步:引入Form表单(element ui给出了方案)
image.png
image.png
第二步:查看接口文档
image.png
第三步:添加分类相关数据
image.png
效果:
image.png

获取商品分类数据列表

第一步:查看接口文档
image.png
第二步:接口请求
image.png
第三步:在data中定义一个接收对象
image.png
第四步:在点击添加分类按钮时进行触发
image.png
效果:
1.gif

新增父级分类下拉列表

第一步:引入Cascader级联选择器(element ui给出了方案)
image.png
image.png
步骤二:进行数据绑定
image.png
第三步:在勾选选项的时候触发日志打印
image.png
效果:
image.png
第四步:进行组注册
image.png
fix下拉数据过多导致显示不全
image.png
效果:
1.gif

将分类名称数据绑定到父级分类中

第一步:进行数组length判断
image.png
第二步:给确定按钮增加一个click事件
image.png
第三步:日志打印
image.png
效果:
image.png
image.png
image.png

添加分类关闭清空已选数据

第一步:新增一个close事件
image.png
第二步:进行数据重置
image.png
效果:
1.gif

新增点击确定添加新的分类

第一步:查看接口文档
image.png
第二步:调用接口
image.png
效果:
1.gif

后续补写编辑/删除功能

image.png
image.png
image.png

分类参数

增加分类参数骨架

第一步:需要重新创建一个分支取名为:goods_params
image.png
第二步:在goods目录创建Params.vue
image.png
第三步:写基础骨架

<template>
    <div>
        分类参数
    </div>
</template>

<script>
export default {
    data() {
    },
    created() {
    },
    methods: {
    }
}
</script>

<style lang="less" scoped="">
</style>

第四步:在路由引入
image.png
image.png
效果:
image.png

增加面包屑/警告框/卡片基础页面

第一步:引入面包屑
image.png
第二步:引入卡片视图
image.png
第三步:引入alert组件(element ui给出了方案)
image.png
image.png
第四步:进行组件注册
image.png
第五步:增加商品分类
image.png
效果:
image.png

商品分类数据获取

第一步:查看接口文档
image.png
第二步:调用接口
image.png
效果:
image.png

商品分类的级联选择框

第一步:引入Cascader级联选择器(element ui给出了方案)
image.png
image.png
第二步:在data中定义数据
image.png
image.png
第三步:
image.png
效果:
1.gif

fix不在同一水平面上展示

在样式上添加属性:
image.png
效果:
image.png

控制级联选择器的选择范围

第一步:获取selectedCateKeys的长度后进行判断
image.png
效果:
1.gif

新增动态参数/静态属性 Tabs 标签页

第一步:引入Tabs标签页(element ui给出了方案)
image.png
image.png
第二步:在data中加入activeName参数
image.png
第三步:进行tabs页签点击事件处理函数
image.png
第五步:注册组件
image.png
效果:
1.gif

新增添加按钮和属性/并控制禁用

第一步:新增button按钮
image.png
第二步:新增一个计算属性(computed)
image.png
效果:
1.gif

获取参数列表

第一步:查看接口文档
image.png
第二步:在computed创建一个函数获取到三级分类的id
image.png
第三步:接口调用
image.png
第四步:更改tabs标签页中的name
image.png
第五步:更改被激活的页签名称
image.png
效果:
1.gif

fix切换标签没有重新进行请求

第一步:将handleChange中的数据抽离出来,创建一个getParamsData函数
image.png
第二步:单独添加该函数
image.png
效果:
1.gif

动态参数表格和静态参数表格渲染

第一步:在data中定义空数组
image.png
第二步:进行判断数据属于哪个标签
image.png
第三步:进行表格渲染
image.png
image.png
效果:
1.gif

新增添加参数/属性对话框/form表单校验

在添加参数按钮新增一个click事件
image.png
第一步:引入Dialog对话框(element ui给出了方案)
image.png
image.png
第二步:在data中定义对话框默认隐藏
image.png
第三步:在computed中新增titleText达到对话框titile赋值
image.png
第四步:引入Form表单(element ui给出了方案)
image.png
image.png
第五步:在data中新增属性
image.png
第六:监听添加对话框的关闭事件
image.png
效果:
1.gif

新增点击确定添加动态参数或静态属性

第一步:查看接口文档
image.png
第二步:在确定按钮上新增click事件
image.png
第三步:接口请求
image.png
效果:
1.gif

新增编辑功能

在编辑按钮增加一个click事件
image.png
image.png
image.png
第二步:在data中定义对话框默认隐藏
image.png
第三步:引入Form表单(element ui给出了方案)
image.png
image.png
第四步:在data中新增属性
image.png
第五步:关闭对话框进行重置
image.png
效果:
1.gif

获取动态参数值

采用作用域插槽进行attr_id获取
image.png
第一步:查看接口文档
image.png
第二步:调用接口
image.png
效果:1.gif

新增修改属性值

第一步:查看接口文档
image.png
第二步:调用接口image.png
效果:
1.gif

新增删除功能

在删除按钮新增一个click事件
image.png
第一步:查看接口文档
image.png
第二步:接口调用
引入MessageBox弹框(element ui给出了方案)
image.png
image.png
效果:
1.gif

新增展开页标签

第一步:将数据进行分割重组
image.png
第二步:在展开行新增tag标签页,for循环
image.png
效果:
1.gif

新增New Tags

第一步:引入New Tags(element ui给出了方案)
image.png
image.png
第二步:在data中定义相关初始值
image.png
第三步:在methods中定义方法
image.png
第四步:修改下宽度
image.png
效果:
1.gif

fix修改New Tags 数据 关联到其他New Tags

第一步:找到获取参数列表的方法
image.png
每一行数据都有自己的bool和value
第二步:使用作用域插槽指定数据
image.png
第三步:删除data中定义相关初始值
image.png
第四步:在click事件中传入scope.row
image.png
第五步:在函数的形参中传入row
image.png
效果:
1.gif

fix点击New Tags 自动获取焦点

第一步:引入New Tags获取焦点(element ui给出了方案)
image.png
效果:
1.gif

fix失去焦点文本框与按钮切换

第一步:在属性框增加scope.row
image.png
第二步:失去焦点后,从input过度到tags
image.png
效果:
1.gif

fix判断用户是否输入无效字符(空格)进行重置

第一步:进行输入值长度判断
image.png
效果:
1.gif

新增添加tags到数据库操作

第一步:查看接口文档
image.png
第二步:调用接口
image.png
效果:
1.gif

新增删除tag标签

第一步:在tags中增加close事件
image.png
第二步:将添加tags到数据库的方法单独封装一下
image.png
image.png
第三步:删除对应参数可选项
image.png
效果:
1.gif

fix选择三级分类后再选择二级分类数据依旧存在

第一步:image.png
效果:
1.gif

商品列表

增加商品列表参数骨架

第一步:需要重新创建一个分支取名为:goods_list
image.png
第二步:在goods目录创建List.vue
image.png
第三步:写基础骨架

<template>
    <div>
        商品列表
    </div>
</template>

<script>
export default {
    data() {
        return {}
    },
    created() {
    },
    methods: {}
}
</script>

<style lang="less" scoped="">
</style>

第四步:在路由引入
image.png
image.png
效果:
image.png

增加面包屑/输入框/按钮

第一步:引入面包屑
image.png
第二步:引入卡片视图
image.png
第三步:引入输入框/按钮
image.png
效果:
image.png

商品列表数据获取

第一步:查看接口文档
image.png
第二步:定义参数
image.png
第三步:接口调用
image.png
效果:
image.png

新增表格区域数据渲染

第一步:
image.png
效果:
image.png

fix创建时间未格式化

第一步:全局定义格式化时间的过滤器
image.png
第二步:进行调用
image.png
image.png

新增分页标签功能

第一步:引入Pagination分页(element-ui提供了方法)
image.png
image.png
第二步:创建方法
image.png
效果:
1.gif

新增搜索/清空功能

第一步:在input输入框增加数据绑定,清空,清空触发功能
image.png
效果:
1.gif

新增删除功能

第一步:在删除按钮上新增click事件
image.png
第二步:查看接口文档
image.png
第三步:调用接口文档
引入MessageBox弹框(element-ui提供了方法)
image.png
image.png
效果:
1.gif

新增添加商品单独页面

第一步:在添加商品新增一个click事件
image.png
第二步:在methods写一个路由跳转的方法
image.png
第三步:新增一个Add.vue
image.png
第四步:编写Add.vue骨架
code.png
第五步:在index.js注册该路由
image.png
效果:
1.gif

新增添加商品

第一步:引入面包屑
image.png
第二步:引入卡片
image.png
第三步:引入Alert警告(element ui给出了方案)
image.png
image.png
第三步:引入Steps步骤条(elementui给出了方案)
image.png
image.png
image.png
image.png
image.png
效果:
image.png

新增tabs栏渲染

第一步:引入Tabs标签页(element ui给了方案)
image.png
image.png
效果:
image.png

新增步骤条与tab栏数据联动效果

第一步:新增name索引值、v-model数据绑定
image.png
第二步:长得像数字的字符串
image.png
第三步:
image.png
效果:
1.gif

新增商品基本信息绘制

第一步:引入Form表单、表格校验
image.png
image.png
第二步:加入校验规则
image.png
效果:
1.gif

商品分类的数据获取

第一步:查看接口文档
image.png
第二步:创建声明周期函数
image.png
第三步:调用接口函数
image.png
效果:
image.png

新增商品列表级联选择器

第一步:引入级联选择器
image.png
第二步:在addForm新增一个goods_cat接收数据和校验image.png
image.png
第三步:级联选择器数据
image.png
image.png
效果:
1.gif

控制Tabs标签切换

第一步:使用element ui 提供函数
image.png
image.png
第二步:判断是不是选中第一个tabs标签或是否选择了3级选择
image.png
效果:
1.gif

商品参数面板对应数据获取

第一步:新增tab被选中时触发(element ui给出了方案)
image.png
image.png
第二步:查看接口文档
image.png
第三步:判断激活面板是否等于1、接口调用
image.png
第四步:请求成功后保存到manyTableData
image.png
效果:
1.gif

新增商品参数面板绘制

第一步:在tab被选中时触发image.png
第二步:引入复选框(element ui给出了方案)
image.png
image.png
第三步:进行组件注册
image.png
效果:
1.gif

fix复选框样式优化

第一步:
image.png
效果:
image.png

商品属性面板对应数据获取

第一步:
image.png
第二步:将获取到的数据保存到onlyTableData
image.png
image.png
效果:
1.gif

新增商品属性面板绘制

第一步:进行表单循环(和商品参数一致)
image.png
效果:
1.gif

新增图片上传功能

第一步:引入Upload上传组件(element ui 给出了方案)
image.png
image.png
第二步:将Url写在data中,注意这个url是baseURL的根路径
image.png
第三步:写方法
image.png
第四步:组件注册
image.png
效果:
1.gif

fix上传图片不成功

第一步:点击上传图片后在网络请求中可以看到是无效token,就证明发起这个请求并没有携带
image.png
第二步:Upload上传给了一个设置上传请求头部的事件
image.png
第三步:在el-upload中添加这个事件
image.png
第四步:在data中写入请求头
image.png
效果:
image.png

新增图片上传成功之后操作

第一步:Upload图片上传给出了文件上传成功时的钩子(element ui给出了方案)
image.png
image.png
第二步:将图片信息对象push到pisc中,先创建一个接收对象
image.png
第三步:写方法
image.png
效果:
image.png

新增图片移除操作

第一步:Upload图片上传给出了文件移除时的钩子(element ui给出了方案)
image.png
image.png
第二步:处理移动图片的操作
image.png
效果:
1.gif

新增图片预览功能

第一步:Upload图片上传给出了文件上传时的钩子(element ui给出了方案)
image.png
image.png
第二步:引入Dialog对话框
image.png
第三步:获取图片预览地址
image.png
image.png
第四步:控制dialog对话框的显示与隐藏
image.png
当点击图片名称就触发
image.png
第五步:修改样式
image.png
image.png
效果:
1.gif

新增富文本框

第一步:安装vue-quil-editor
image.png
第二步:man.js进行全局引用富文本编辑器
image.png
image.png
第三步:在Add.vue引入富文本
image.png
第四步:在addForm创建一个goods_introduce接收富文本内容
image.png
第五步:修饰样式
image.png
效果:
image.png

新增添加商品预验证

第一步:新增添加商品按钮、click事件
image.png
第二步:写click事件方法
知识点:validate是校验表单项prop值,校验是否通过
image.png
效果:
1.gif

添加商品前数据转换

第一步:
image.png
第二步:引入深拷贝依赖库
image.png
第三步:在代码中导入深拷贝库官方地址
image.png
image.png
为什么需要进行深拷贝呢?因为在此之前级联选择器希望是数组,而另外个希望是字符串产生了分歧,所以同时满足就采用深拷贝。
效果:
1.gif
image.png

添加商品时数据转换

第一步:
image.png
image.png
第二步:新增attrs数组
image.png
第三步:
image.png
效果:
image.png

完善添加商品

第一步:查看接文档
image.png
第二步:接口请求
image.png
效果:
1.gif

新增订单管理分支

新增订单管理骨架

第一步:需要重新创建一个分支取名为:order
image.png
image.png
第二步:在order目录创建Order.vue
image.png
第三步:写基础骨架

<template>
    <div>
        订单管理
    </div>
</template>


<script>
export default {
    // 初始化基础数据节点
    data(){
        return {}
    },
    // 声明周期函数
    created() {},
    // 事件处理函数
    methods: {}
}
</script>

<style lang="less" scoped="">

</style>

第四步:在路由引入
image.png
image.png
效果:
image.png

增加面包屑/卡片/输入框基础页面

第一步:引入面包屑
image.png
第二步:引入卡片
image.png
第三步:引入input搜索框
image.png
效果:
image.png

商品订单数据获取

第一步:查看接口文档
image.png
第二步:增加查询信息
image.png
第三步:接口请求
image.png
效果:
image.png

商品订单数据渲染

第一步:引入el-tab表格
image.png
第二步:
image.png
效果:
image.png

新增分页功能

第一步:引入Pagination分页
image.png
第二步:写对应方法
image.png
效果:
1.gif

新增省市区/县联动效果

第一步:给编辑按钮新增clikc事件
image.png
第二步:引入Dialog对话框
image.png
第三步:控制默认对话框为隐藏
image.png
第四步:点击编辑按钮控制对话框显示
image.png
第五步:引入表单校验
image.png
第六步:表单校验规则
image.png
第七步:引入城市列表(citydata.js)
image.png
image.png
image.png
第八步:引入级联选择器,并将城市数据绑定到opthions
image.png
第九步:新增dialog对话框close事件
image.png
第十步:关闭对话框后触发清空表单事件
image.png
效果:
1.gif

新增物流进度的对话框/物流进度数据获取

第一步:在定位图标新增click 事件
image.png
第二步:引入Dialog对话框
image.png
第三步:设置对话框为隐藏状态
image.png
第四步:查看接口文档
image.png
第五步:接口请求
image.png
效果:
1.gif

新增时间线

第一步:引入时间线(element ui)给出了方案
image.png
image.png
第二步:注册组建
image.png
效果:
1.gif

合并分支到master

image.png

Report报告

新增报表骨架

第一步:需要重新创建一个分支取名为:report
image.png
image.png
第二步:在report目录创建Report.vue
image.png
第三步:写基础骨架

<template>
    <div>
        报表组件
    </div>
</template>

<script>
export default {
    data() {},
    created() {},
    methods: {}
}
</script>

<style lang="less" scoped="">

</style>

第四步:在路由引入
image.png
image.png
效果:
image.png

添加面包屑/卡片

第一步:引入面包屑
image.png
第二步:引入卡片
image.png
效果:
image.png

引入Echars图表

第一步:安装Echars插件
image.png
第二步:在项目中引入Echarts
1.导入Echarts
image.png
2.创建一个Dom节点
image.png
3.创建一个mounted钩子 该钩子的作用是Dom创建完成之后才会执行,此时,页面上的元素已经渲染完毕了
image.png
4.准备Echarts展示数据和配置项
image.png
5.在页面上展示Echarts
image.png
效果:
image.png

数据报表渲染

第一步:查看接口文档
image.png
第二步:请求接口
image.png
第三步:进行数据合并
image.png
image.png
效果:
image.png

优化项目

新增顶部加载进度条

第一步:下载nprogress插件
image.png
第二步:在main.js导入nprogress
image.png
第三步:在发起axios请求前调用Nprogress.start()
image.png
第四步:在发起axios请求后调用Nprogress.done()
image.png
效果:
1.gif

安装生产环境禁止console.*打印

第一步:在开发依赖下载对应插件image.png
第二步:在build过程中,新增该插件
image.png

关于插件在生产环境禁止console.log()输出

第一步:下载插件【babel-plugin-transform-remove-console】
image.png
第二步:在根目录可以看到babel.config.js这个文件
image.png
第三步:进行判断为什么环境,如果为生产环境,则使用这个插件,非正式环境则不使用这个插件
image.png
效果:现在在开发环境,所以可以正常打印console.log
1.gif

项目生产打包报告

  • 生成打包报告
// 通过 vue-cli 的命令选项可以生成打包报告
// --report 选项可以生成 report.html 以帮助分析包内容
vue-cli-service build --report
  • 通过可视化的UI面板直接查看报告

在可视化UI面板中,通过控制台和分析面板,可以方便看到项目中所存在的问题
image.png

修改webpack默认配置

第一步:在根目录创建vue.config.js这个配置文件
image.png
第二步:固定写法

// vue.config.js
// 这个文件中,应该导出一个包含了自定义配置选项的对象
module.exports = {
  // 选项...
}

chainWebpack 自定义打包入口

  • 新增一个自己的打包入口文件

第一步:将原来main.js修改成dev和prod模式
image.png
第二步:定义打包入口image.png

通过 externals 加载外部CDN资源

默认情况下,通过import语法导入第三方依赖包,最终会被打包合并到同一个文件中,从而导致打包成功后,单个文件体积过大的问题。

第一步:配置externals
image.png
第二步:删除在main.js引入的资源,进行
image.png
第三步:在public文件夹下找到index.html
image.png
效果:编译后体积明显变小
image.png

通过CDN优化ElementUI的打包

  • 在main-prod.js中,注释掉element-ui按需加载的代码

image.png

  • 在index.html的头部区域中,通过CDN加载element-ui的js和css样式

image.png
效果:编译后体积明显变小
image.png

首页内容定制

在public/index.html首页中,可以根据isProd的值,来决定如何渲染页面结构

第一步:在vue.config.js中增加一个自定义属性

chainWebpack: config => {
    // 发布模式默认打包入口
    config.when(process.env.NODE_ENV === 'production', config => {
      // html插件新增一个自定义属性
    	config.plugin('html').tap(args =>{
        args[0].isProd = true
        return args
      })
    })
		// 开发模式默认打包入口
    config.when(process.env.NODE_ENV === 'production', config => {
      config.plugin('html').tap(args =>{
        args[0].isProd = false
        return args
      })
    })
}

第二步:在index.html中进行判断
image.png
效果:编译后体积明显变小
image.png

路由的懒加载

不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件

  1. 安装@babel/plugin-syntax-dynamic-import包

image.png

  1. 在babel.config.js配置文件中声明该插件

image.png

  1. 将路由改为按需加载的形式

image.png
效果:
image.png

项目上线


导入阿里icon到自己项目

第一步:首先去网站进行注册并选好需要的图标下载到本地
image.png
第二步:将这个目录放在src/assets里
image.png
第三步:去main.js进行引入
image.png
第四步:使用图标
image.png

git使用大全

创建子分支

git checkout -b 分支名字

查看当前所有分支

git branch

将代码添加到暂存区

git add .

查看上次提交之后是否有进行再次修改

git status

提交代码

git commit -m "备注"

切换主分支

git checkout master

合并代码

git merge 分支

推送到代码管理仓库(码云/github)

git push -u origin 仓库名(-u 是没有将分支推送到仓库的操作)
git push

目录结构

├─README
├─babel.config.js
├─package-lock.json
├─package.json
├─src
├─vue.config.js
└─电商管理后台 API 接口文档

posted @ 2021-10-21 18:54  Daydayup,ran  阅读(797)  评论(0编辑  收藏  举报