• PC后台管理系统
  • 功能:用户账号(登录退出,用户管理,权限管理),商品管理(商品分类,分类参数,商品信息,订单),数据统计
  • 系统采用前后端分离的开发模式 前端项目是基于Vue的SPA(单页应用程序)项目
  • 包含所有所需要的素材 phpStudy、mysql数据库数据、后台项目vue_api_server
  • 技术栈:Vue,Vue-Router,Element-UI,Axios,Echarts

项目概述

1. 电商项目基本业务概述

根据不同的应用场景,电商系统一般都提供了 PC 端移动 APP移动 Web微信小程序等多种终端访问方式。这些不同终端都共用同一个数据库和同一个API接口服务器。

本教程主要探讨PC后台管理项目,是给商城的后台管理员使用的。

2. 电商后台管理系统的功能

电商后台管理系统用于管理用户账号、商品分类、商品信息、订单、数据统计等业务功能。

电商后台管理系统.png

3. 采用的开发模式(前后端分离)

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

用户 -> 前端项目(SPA) -> 后端项目 -> 数据库

后端负责写接口,前端负责调接口的开发模式,我们叫做前后端分离的开发模式。这是主流的开发模式,效率高,易维护。

  • 前后端分离:
    • 后端:负责操作数据库,并向前端暴露一些接口
    • 前端:主要负责绘制页面,并通过Ajax技术调用后端提供的API接口,

4. 系统的技术选型

  • 【前端项目技术栈】

    • Vue
    • Vue-router:路由
    • Element-UI:前端UI组件库
    • Axios:发起网络数据请求
    • Echarts:绘制图像报表
  • 【后端项目技术栈】

    • Node.js
    • Express
    • Jwt:一个状态保持的工具,可以模拟Session那样的登录记录功能
    • Mysql:后台数据库
    • Sequelize:操作数据库的框架

【项目初始化】

1. 前端项目初始化步骤

  1. 安装 Vue 脚手架

  2. 通过 Vue 脚手架创建项目(过程请看之前笔记)

  3. 创建新项目的最后一步配置,不选择历史模式的Vue路由,把那一项开关关上,使用哈希模式的路由

  4. 通过vue ui面板的插件中,安装vue-cli-plugin-element,并配置为按需导入

  5. 通过vue ui面板的依赖中,安装axios运行依赖

  6. 码云账号的申请和SSH密钥的添加(以前弄过的可以跳过)

    • 注册或登录 码云(Gitee),点击右上角头像,进入设置 -> SSH公钥,我们将按照官方教程“怎样生成公钥”来进行如下操作。
    • 复制命令ssh-keygen -t ed25519 -C "xxxxx@xxxxx.com",打开一个本地cmd终端,粘贴执行,注意引号中要替换为自己码云的邮箱。连续按三次回车,即可生成密钥,并被保存到了C:\Users\你的用户名\.ssh目录下了。
    • 按路径找到那个生成的.pub结尾的公钥文件,右键随便用一个编辑器打开,把里面的一坨代码全选复制,粘贴到码云的公钥中,随便起一个标题名字,点击确定。
    • 测试一下密钥能否正常使用,在终端输入命令ssh -T git@gitee.com并执行,选择yes并回车。当你再一次执行命令ssh -T git@gitee.com的时候,就可以正常返回你的账号信息了。(首次使用需要确认并添加主机到本机SSH可信列表。若返回 Hi XXX! You've successfully authenticated, but Gitee.com does not provide shell access. 内容,则证明添加成功。)
  7. 初始化 git 远程仓库

    • 打开码云,点击右上角头像左侧的加号,选择新建仓库。仓库名称随便填比如vue_shop,如果有生成Readme那个选项的话可以取消勾选,然后点击创建。
    • 按照提示,打开终端,分别执行git config --global user.name "码云用户名"git config --global user.email "邮箱"这两句命令。
    • 因为我们刚刚已经创建的本地的vue项目仓库,按照提示,我们复制远程仓库链接git remote add origin https://gitee.com/码云用户名/vue_shop.git。打开本地的vue_shop项目文件夹,右键打开终端(Powershell窗口或者Git Bash Here都可以),右键粘贴执行。可以git remote -v查看是否正常返回仓库地址。
  8. 将本地项目托管到 Github 或 Gitee 中

    • 执行git push -u origin "master"命令,把本地仓库和云端仓库做一下关联。执行后弹出窗口,让你输入码云的账号邮箱和密码。
    • 到你的码云个人主页里,就可以看到本地仓库已经上传成功了。今后我们在本地每做完一个功能,都需要将代码提交到码云中。

      由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

2. 后台项目的环境安装配置

  1. 安装 MySQL 数据库:
    • 双击执行素材包中的phpStudy20161103.exe,一步一步安装到本地就行了。PhPstudy是一个集成环境,叫做小皮面板。
    • Windows电脑这时如果弹出两条分别关于MySQLApache的防火墙警告,点击允许就行了。然后就可以看到Apache和MySQL都处于运行中的状态。
    • 我们在开发过程中只需用到MySQL,那个Apache不需要,得把它停掉。点击其他选项菜单,找到服务管理器,选择Apache,点击停止。光让MySQL正常运行就行啦。
    • 现在导入一个数据库,从而支持API接口服务器的正常运行。找到素材中的vue_api_server.rar压缩包,解压到当前文件夹。点开文件夹中的db目录,里面的mydb.sql脚本就是我们的数据库脚本文件。
    • 点击PhPstudy面板上的MySQL管理器,选择MySQL导入导出。输入密码(默认为root),点击按钮选择要还原的文件,选中mydb.sql脚本文件,然后输入还原到数据库的名称mydb,点击导入,会弹出cmd终端窗口。(如果闪退的话,请把mydb.sql复制到桌面再导入,因为路径中不能有任何中文)耐心等待,运行过程会很长,知道它运行完自动关闭黑窗口。
    • 你可以点击PhPstudy面板的其他选项菜单,点击MySQL工具,选择打开数据库目录,只要能看到一个文件夹叫做mydb,并且里面有很多相关文件,那就证明数据库还原完成了。
  2. 安装 Node.js 环境
  3. 配置项目相关信息
  4. 启动项目
    • 素材中我们上面解压的vue_api_server目录就是我们的后台API项目,只不过这个项目要先安装依赖包才可以正常运行。你可以先把该文件夹挪到合适的地方,在它里面打开终端,执行npm install命令安装所有依赖项。耐心等待,会看到文件夹中多了一个名为node_modules的目录。
    • 终端别关,现在输入 node app.js 命令把API接口项目跑起来。
    • 我们可以打开素材包中的电商管理后台 API 接口文档.md看看整个项目为我们提供了哪些可用的接口,接下来我们就要测试接口了。
  5. 使用 Postman 测试后台项目接口是否正常
    • 找到素材中的Postman-win32-6.7.3-Setup.exe安装包,双击执行即可安装到电脑。首次使用请用邮箱注册,QQ邮箱的话尽量不要使用QQ相同的密码,保护好自己。注册后点击邮箱中刚收到的邮件的激活按钮即可注册成功。返回Postman,选择Sign In(登录),输入账号(邮箱或用户名)和密码,即可进入面板。
    • 比如我们要验证登录验证接口,在Postman中把请求方式改为POST,输入框的请求路径填入接口基准地址http://127.0.0.1:8888/api/private/v1/,然后后面再加个请求路径login,变成完整的请求地址http://127.0.0.1:8888/api/private/v1/login。由于登录带参数,我们点击输入框下面的Body(表单体)选项,数据选择普通的x-www-form-urlencoded这种数据格式就行。然后在下面键值对(KEY 和 VALUE)表单中,根据文档填入需要提供的数据usernamepassword,比如张三123456,点击Send按钮发送请求。稍等片刻,返回结果:
      1
      2
      3
      4
      5
      6
      7
      {
      "data": null,
      "meta": {
      "msg": "无效token",
      "status": 400
      }
      }
      可以看到状态码400表示登录失败。现在我们再请求一次,用户和密码分别是admin123456,发送:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      {
      "data": {
      "id": 500,
      "rid": 0,
      "username": "admin",
      "mobile": "12345678",
      "email": "adsfad@qq.com",
      "token": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjUwMCwicmlkIjowLCJpYXQiOjE2NDk5NjE4MDYsImV4cCI6MTY1MDA0ODIwNn0.pXl8YMiCovNnC_rdyTuYWyX102X7PUn0TpscNNdyC8M"
      },
      "meta": {
      "msg": "登录成功",
      "status": 200
      }
      }
      登陆成功,并返回了用户名、电话、邮箱、以及token。其中token是用来进行客户端与服务器端的登录状态保存的,类似于Node中的session,我们通过token来验证这个人有没有登录。

【登录/退出功能】

登录/退出功能

1. 登录概述

  • 登录业务流程

    1. 在登录页面输入用户名和密码
    2. 调用后台接口进行验证
    3. 通过验证之后,根据后台的响应状态跳转到项目主页
  • 登录业务的相关技术点

    • http 是无状态的
    • 通过 cookie 在客户端记录状态,通过 session 在服务器端记录状态
    • 通过 token 方式维持状态

如果客户端和服务器不存在跨域问题,推荐使用cookie和session结合来记录登录状态;
如果存在跨域问题,推荐使用token方式来维持登录状态。

2. 登录:token原理分析

token原理分析

3. 登录功能实现

(1) 登录页面的绘制

  • 通过 Element-UI 组件实现布局
    • el-form 表单组件
    • el-form-item 子项
    • el-input 输入框
    • el-button 按钮
    • 字体图标

VScode打开vue_shop项目文件夹,在绘制页面前,新建终端查看一下当前工作区是否干净:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 执行命令 git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: babel.config.js
modified: package-lock.json
modified: package.json
modified: src/App.vue
modified: src/main.js

Untracked files:
(use "git add <file>..." to include in what will be committed)
src/plugins/

no changes added to commit (use "git add" and/or "git commit -a")

如上所示就是代表不干净,工作树中还有未提交的git记录,应该是上面项目初始化时安装完依赖和插件之后没有提交,那就执行命令提交一下:

1
2
3
git add .
git commit -m "添加element和axios"
git push origin master

现在gitee上应该有提交记录了,再次查看工作树是否干净:

1
2
3
4
5
6
# 执行命令 git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean
PS C:\Users\10272\vue_shop>

现在就可以进行登陆页面的绘制了。

在撰写代码之前,我们首先创建一个分支。在开发中,只要是开发新功能了,尽量把新功能都放到一个新的分支上进行开发。当功能开发完成后,再把分支合并到master主分支上。

1
2
3
4
5
# 创建login分支,并通过checkout切换到该分支
git checkout -b login

# 查看所有分支
git branch

打开cmd窗口,运行vue ui命令打开可视化面板,运行项目,启动APP弹出页面,可以看到默认的vue项目主页。

想删掉默认内容新建空白页面的话就到App.vue中修改相应内容,然后删除router.js中没用的路由,再删除components文件夹下没用的组件。然后打开项目页面看看效果,没问题就可以书写代码了。

绘制过程略,请看视频。

因为视频教程比较老(3年了),你可能会遇到以下问题:

  • 【vue eslint】报错Component name “xxxxx“ should always be multi-word.eslintvue/解决方案
    那就别叫Login.vue,改成VueLogin.vue
  • Vue中关于Can’t resolve ‘less-loader’
    在可视化面板中安装“开发依赖”:less-loaderless 就行
  • vue遇见的问题:imported multiple times
    原因是element-ui import次数过多,不要学视频中的,我们将要引入的组件写在一起,只写一个import { Button, Form, FormItem, Input } from 'element-ui'
  • 报错: Expected indentation of 2 spaces but found 4
    在Vue单文件的<script>中书写代码时,别用Tab键直接缩进4个空格,而是用空格键手动敲俩就行
  • 报错:Missing space before function parentheses space-before-function-paren
    原因是函数名称或function关键字与开始参数之间缺少空格,通过提示找到缺少的空格应该加在data ()之间
  • 报错:error Extra semicolon semi
    把提示的地方的分号删掉就行了。出现报错的原因是因为使用了eslint,这个是eslint的规范报错,所以能不用分号就不用分号。
  • 页面空白,并且报错[Vue warn]: Property or method "loginForm" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
    检查一下你是不是和我一样把data写成date了……
  • 表单的数据绑定示例步骤:
    1. <el-form>添加:model="loginForm"属性
    2. 在数据data的返回值return里定义数据绑定对象loginForm并书写其属性
    3. 把其属性通过v-model="loginForm.username"形式绑定到对应<el-input>
  • 表单添加验证规则的步骤:
    1. <el-form>通过属性绑定,绑定一个:rules="rules"校验对象
    2. data数据中定义这个数据对象rules:{},其中每个属性都是一个验证规则
    3. 为不同的<el-form-item>通过prop="name"来指定不同的验证规则
  • 为表单重置:
    1. 想要拿到表单实例对象,可以为<el-form>添加ref="loginFormRef"引用,现在这个引用对象的名称loginFormRef就是表单的实例对象
    2. 为重置按钮绑定点击事件@click="resetLoginFrom"
    3. 在方法methods中定义处理函数resetLoginFrom,处理函数中,通过引用对象名称loginFormRef获取实例,直接使用表单resetFields方法重置表单:this.$refs.loginFormRef.resetFields()
  • 和表单重置按钮差不多,若想为登录按钮添加表单登录之前的预验证,可以使用validate方法
  • 如果某方法的返回值是Promise,那我们可以用asyncawait来简化这个Promise操作。注意await只能用在被async修饰的方法中,所以我们要把紧挨着await的那个方法修饰成异步的async方法。

(2) 实现登录

  • 通过 axios 调用登录验证接口
  • 登录成功之后保持用户 token 信息
  • 跳转到项目主页
    1
    2
    3
    4
    5
    6
    7
    8
    const {data: res } = await this.$http.post('login', this.loginForm)
    if (res.meta.status !== 200)return this.$message.error('登录失败!')
    // 提示登录成功
    this.$message.success('登录成功!')
    // 把登录成功的token保存到sessionStorage
    window.sessionStorage.setItem('token', res.data.token)
    // 使用编程式导航,跳转到后台主页
    this.$router.push('/home')

为什么要把token保存在sessionStorage中而不是localStorage中?
因为 localStorage 是持久化的存储机制,而sessionStorage是会话期间的存储机制

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

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

1
2
3
4
5
6
7
8
9
10
// 为路由对象,添加 beforeEach 导航守卫
router.beforeEach((to, from, next) => {
// 如果用户访问的登录页,直接放行
if (to.path === '/login') return next()
// 从 sessionStorage 中获取到 保存的 token 值
const tokenStr = window.sessionStorage.getItem('token')
// 没有token,强制跳转到登录页
if (!tokenStr) return next('/login')
next()
})
  1. 其中 to 代表将要访问的路径
  2. 其中 from 代表从哪个路径跳转而来
  3. 其中 next 是一个函数,表示放行
    • 第一种 next() 放行
    • 第二种 next('/login') 强制跳转

(4) 退出登录实现原理

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

1
2
3
4
// 清空token
window.sessionStorage.clear()
// 跳转到登录页
this.$router.push('/login')

4. 处理项目中语法警告问题

相信在撰写上方代码的时候,每次修改完保存时总是出现各种语法警告。比如“Vue单文件组件名称必须是多单词名称”、“某一行应该是2个缩进空格但是发现了4个”、“Vue单组件文件最后一行必须有换行符”、“if()判断语句的if和括号之间必须有空格”、“Vue单组件文件中空白行不能超过两行”、“某一行的最后不允许有空白占位符”、“某一行末尾发现了多余的分号”、“某处不应写双引号而是应写成单引号”……几乎每次保存重新编译时都有报错提醒,甚是磨人。

这是因为我们有时候写的语法不符合eslint语法规范,被它检查出来了。并且VScode右键格式化(Shift+Alt+F)的代码与eslint语法不一致,导致很烦人。

那如何才能解决这个问题呢?在项目的根目录中创建一个配置文件.prettierrc.js,专门来告诉编辑器在格式化代码的时候如何进行相关的代码格式化:

1
2
3
4
5
6
7
8
9
module.exports = {
semi: false, //代码末尾的分号
singleQuote: true, //使用单引号
bracketSpacing: true, //括号内部不要出现空格
useTabs: false, //使用 tab 缩进
tabWidth: 2, //缩进空格数
trailingComma: 'none', //末尾逗号
printWidth: 1000, //行宽,超过这个数值才换行。否则默认每个标签属性单独占一行
}

其中,还可以到.eslintrc.js中禁用space-before-function-paren的语法规则,这样以后函数名与小括号之间没有空格也不会报错了:

1
2
3
4
5
6
7
// 文件.eslintrc.js中rules里,添加下方代码花括号中的最后一行

rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'space-before-function-paren': 0 //禁用函数的小括号前必须有空格的语法规则
}

此外,可以依次点击VSCode的 【文件file】 => 、首选项preferences】 => 【设置settings】 => 【上方输入tab回车】 => 【找到下方TabSize配置项,将4修改为2】,这样写代码的时候Tab缩进值就是2了。

5. 优化一下Element-UI中按需组件的导入形式

就是把scr => plugins => element.js文件中导入组件的语句合并成一行。

其实这个我之前遇到过了,因为多行导入会报错的,所以从一开始我就是写成了一行:

1
2
3
4
5
6
7
8
9
10
import Vue from 'vue'
import { Button, Form, FormItem, Input, Message } from 'element-ui'

Vue.use(Button)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Input)

// Message组件需要全局挂载,其中$message是自定义的属性,名字可以改,合法就行
Vue.prototype.$message = Message

6. 提交登录功能代码

登录功能写好后就可以提交到Git仓库了(Gitub/Gitee)。

先关掉vue ui可视化面板中的运行状态,然后在VScode中新建终端,先运行git status查看当前项目中源代码的状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
PS C:\Users\10272\vue_shop> git status          
On branch login
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .eslintrc.js
modified: package-lock.json
modified: package.json
modified: src/App.vue
deleted: src/components/HelloWorld.vue
modified: src/main.js
modified: src/plugins/element.js
modified: src/router/index.js

Untracked files:
(use "git add <file>..." to include in what will be committed)
.prettierrc
src/assets/css/
src/assets/fonts/
src/components/VueHome.vue
src/components/VueLogin.vue

no changes added to commit (use "git add" and/or "git commit -a")

上半部分的红色文件代表发生了修改,下半部分的红色文件代表是我们新增的。把所有文件全部添加到暂存区:

1
git add .

可以再次运行命令 git status查看仓库代码状态。可以发现,所有的文件全部变成了绿色,说明被添加到了暂存区。

现在运行如下命令把这些代码提交一下,双引号里是提交的信息,你想写啥写啥:

1
git commit -m "完成了登录功能"

现在就把暂存区中的代码提交到了本地仓库中了。可以执行git branch命令查看一下分支:

1
2
3
PS C:\Users\10272\vue_shop> git branch
* login
master

可以看到当前我们处于login分支,刚才我们git commit提交的文件都被放到了login分支中进行了保存了。我们现在可以把login分支中的所有代码更新/合并到master分支。

首先第一步,要先切换到master分支,因为你要合并到哪个分支,必须先切换到哪个分支,然后再从这个分支主动合并login分支就行了:

1
2
3
4
5
# 切换到主分支
git checkout master

# 查看当前分支
git branch

切换到master分支后,执行合并命令:

1
git merge login

此时master中的代码也变成了最新的,下面进行远程的推送,把本地的master分支推送到码云(Gitee)中:

1
git push

此时就已经把本地master中的代码推送到了码云中,可以打开码云看一下提交情况。

可以发现,云端仓库只有一个master分支,我们如何把本地的login分支推送到云端进行保存呢?先切换分支:

1
2
3
4
5
# 切换分支
git checkout login

# 查看分支状态
git branch

由于我们是第一次将login分支推送到云端,因此需要加上-u参数:

1
git push -u origin login

由于我们第一次推送login分支时,加上了-u参数,Git不但会把本地的login分支内容推送的远程新的login分支,还会把本地的login分支和远程的login分支关联起来,在以后的推送或者拉取时就可以简化命令(git push/git pull)。不带任何参数的git push,默认只推送当前分支,这叫做simple方式。


【主页布局】

1. 整体布局

整体布局:先上下划分,再左右划分。

1
2
3
4
5
6
7
8
9
10
<el-container>
<!-- 头部区域 -->
<el-header></el-header>
<el-container>
<!-- 侧边栏区域 -->
<el-aside></el-aside>
<!-- 右侧主体区域 -->
<el-main></el-main>
</el-container>
</el-container>

2. 左侧菜单布局

左侧菜单布局:菜单分为二级,并且可以折叠。

1
2
3
4
5
6
7
8
9
10
11
12
<el-menu>
<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-menu>

3. 通过接口获取菜单数据

除了登录接口,其他所有API接口在请求时都需要token令牌

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

1
2
3
4
5
6
7
// axios请求拦截,相当于对请求头进行一次预处理
axios.interceptors.request.use(config => {
// 为请求头对象,添加 Token 验证的 Authorization 字段
config.headers.Authorization = window.sessionStorage.getItem('token')
// 在最后必须return config
return config
})

4. 动态渲染菜单数据并进行路由控制

  • 通过 v-for 双层循环分别进行一级菜单和二级菜单的渲染
  • 通过路由相关属性启用菜单的路由功能
1
2
3
4
5
6
7
8
9
10
11
<el-menu router>
<el-submenu :index="item.id + ''" v-for=“item in menus" :key="item.id">
<template slot="title">
<span>{{item.authName}}</span>
</template>
<el-menu-item :index="'/' + subItem.path" v-for="subItem in item.children"
:key="subItem.id" >
<span slot="title">{{subItem.authName}}</span>
</el-menu-item>
</el-submenu>
</el-menu>

【用户管理】

用户管理

1. 用户管理概述

通过后台管理用户的账号信息,具体包括用户信息的展示、添加、修改、删除、角色分配、账号启用/注销等功能。

  • 用户信息列表展示
  • 添加用户
  • 修改用户
  • 删除用户
  • 启用或禁用用户
  • 用户角色分配

2. 用户信息列表展示

(1) 用户列表布局

(2) 用户状态列和操作列处理

(3) 表格数据填充

(4) 表格数据分页

(5) 搜索功能

3. 用户状态控制

4. 添加用户

(1) 添加用户表单弹窗布局

(2) 表单验证

  • https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=53
  • 自定义校验规则https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=54
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // 验证邮箱的规则
    var checkEmail = (rule, value, callback) => {
    // 验证邮箱的正则表达式
    const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/

    if (regEmail.test(value)) {
    // 合法的邮箱
    return callback()
    }
    // 返回一个错误提示
    callback(new Error('请输入合法的邮箱'))
    }

    // 验证手机号码的规则
    var checkMobile = (rule, value, callback) => {
    // 验证手机号码的正则表达式
    const regMobile = /^(0|86|17951)?(13[0-9]|15[0123456789]|17[678]|18|[0-9]|14[57])[0-9]{8}$/

    if (regMobile.test(value)) {
    return callback()
    }
    // 返回一个错误提示
    callback(new Error('请输入合法的手机号码'))
    }

(3) 表单提交

  • 表单重置:https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=55

    1
    2
    3
    4
    // 监听添加用户对话框的关闭事件
    addDialogClosed () {
    this.$refs.addFormRef.resetFields()
    },
  • 表单提交预验证:https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=56

    1
    2
    3
    4
    5
    6
    7
    8
    // 点击按钮,添加新用户
    addUser () {
    this.$refs.addFormRef.validate(valid => {
    // console.log(valid)
    if (!valid) return
    // 可以发起添加用户的网络请求
    })
    }
  • 添加用户表单提交:https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=57

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // 点击按钮,添加新用户
    addUser () {
    this.$refs.addFormRef.validate(async valid => {
    // console.log(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()
    })
    }

5. 修改用户

6. 删除用户

7. user分支的创建和代码的推送

用户管理功能写完了,现在提交代码到git仓库。

1
2
3
4
# 查看当前分支
PS E:\vue_shop> git branch
* login
master
1
2
3
4
5
6
7
8
9
# 新建并切换到user分支(checkout切换;-b新建)
PS E:\vue_shop> git checkout -b user
Switched to a new branch 'user'

# 查看当前分支
PS E:\vue_shop> git branch
login
master
* user
1
2
3
4
5
# 检查当前分支文件修改状态
PS E:\vue_shop> git status

# 添加到缓存区
PS E:\vue_shop> git add .
1
2
3
4
5
# 检查当前分支文件修改状态
PS E:\vue_shop> git status

# 提交
PS E:\vue_shop> git commit -m "用户管理功能"
1
2
3
4
5
# 检查当前分支文件修改状态
PS E:\vue_shop> git status

# 推送到云端仓库(此分支首次推送,需要加-u参数)
PS E:\vue_shop> git push -u origin user
1
2
3
4
5
6
7
8
# 查看当前分支
PS E:\vue_shop> git branch
login
master
* user

# 切换到主分支
PS E:\vue_shop> git checkout master
1
2
3
4
5
6
7
8
# 查看当前分支
PS E:\vue_shop> git branch
login
* master
user

# 从master分支上把user分支的代码合并过来
PS E:\vue_shop> git merge user

【权限管理】

2022-60 (5)
2022-60 (6)

1. 权限管理业务分析

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

1
2
3
4
5
6
7
8
9
# 查看当前分支
PS E:\vue_shop> git branch
login
* master
user

# 创建并切换到rights分支(权限)
PS E:\vue_shop> git checkout -b rights
Switched to a new branch 'rights'
1
2
3
4
5
6
7
8
9
# 查看当前分支
PS E:\vue_shop> git branch
login
master
* rights
user

# 推送到云端(此分支首次推送,需要加-u参数)
PS E:\vue_shop> git push -u origin rights

2. 权限列表展示

3. 角色列表展示

4. 用户角色分配

(1) 展示角色对话框

  1. 实现用户角色对话框布局
  2. 控制角色对话框显示和隐藏
  3. 角色对话框显示时,加载角色列表数据

(2) 完成角色分配功能

5. 角色权限分配

(1) 表格行展开效果

(2) 渲染一级权限菜单

(3) 渲染二、三级权限菜单

(4) 删除角色下的权限

(5) 给角色分配权限流程

  1. 实现角色分配权限对话框布局
  2. 控制对话框的显示和隐藏
  3. 对话框显示时调用后台接口加载权限列表数据
  4. 完成树形权限菜单的展示
  5. 选中默认的权限
  6. 保存选中的权限,调用后台接口完成角色权限的分配

(6) 实现权限分配对话框布局

  • 实现对话框布局效果
  • 控制对话框显示和隐藏

(7) 渲染权限的树形结构

(8) 设置默认权限菜单选中

  • 获取所有叶子节点的 id
  • 设置权限节点选中

(9) 完成角色授权

6. rights分支的创建和代码的推送

1
2
3
4
5
6
# 查看当前分支
PS E:\vue_shop> git branch
login
master
* rights
user
1
2
3
git add .
git commit -m "权限管理"
git push
1
2
3
4
5
# 切换到主分支
PS E:\vue_shop> git checkout master

# 从master分支上把user分支的代码合并过来
PS E:\vue_shop> git merge user
1
2
3
4
5
6
7
8
9
# 查看当前分支
PS E:\vue_shop> git branch
login
* master
rights
user

# 推送到云端(此分支首次推送,需要加-u参数)
PS E:\vue_shop> git push

【分类管理】

2022-60 (7)

界面演示:https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=96

1. 商品分类概述

商品分类用于在购物时,快速找到所要购买的商品,可以通过电商平台主页直观的看到。

1
2
3
4
5
6
7
8
9
10
11
# 创建商品管理分支
PS E:\vue_shop> git checkout -b goods_cate
Switched to a new branch 'goods_cate'

# 查看当前分支
PS C:\vue_shop> git branch
* goods_cate
login
master
rights
user
1
2
# 首次推送到云端(参数-u)
git push -u origin goods_cate

2. 商品分类列表

基本布局与数据获取

  • 实现基本布局
  • 实现分类列表数据加载

3. 树形表格

(1) 第三方树形表格的基本使用

安装第三方插件实现Element-UI没有的树形table表格:https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=101

打开 Vue 面板,选择【依赖】这一项,点击【安装依赖】,选择【运行依赖】,搜索 vue-table-with-tree-grid

也可以手动安装依赖包npm i vue-table-with-tree-grid -S

基本使用:

1
2
3
4
5
# 在 main.js 中导入
import TreeTable from 'vue-table-with-tree-grid'

# 在下方找位置进行注册,变成全局可用的组件
Vue.component('tree-table', TreeTable)

组件的配置与使用:https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=101

(2) 实现分类树形列表

4. 分页功能

5. 添加分类

(1) 实现分类树形列表

(2) 实现分类级联菜单效果

Element新版本(比如2.15.7)的级联选择器有几处与视频教程中(版本1.6.0)有些不一样:

  1. 一个是原来单独的属性expandTrigger归到了Props中,成为了配置对象的一项;
  2. 另一个是菜单会过高超出页面区域,只需在global.css中添加全局样式即可:
    1
    2
    3
    4
    /* 级联选择器 */
    .el-cascader-panel {
    height: 300px;
    }
  3. 视频教程中可选择任意一级菜单change-on-select属性,在新版本中归到了Props中的checkStrictly: true属性上,表示是否严格的遵守父子节点不互相关联

(3) 控制父级分类的选择

父级分类选择时,获取对应的分类 id。

(4) 完成分类添加

将分类名称、分类等级和父分类 id 提交到后台,完成分类添加。

1
2
3
4
5
6
7
8
9
10
# 查看分支
PS C:\vue_shop> git branch
* goods_cate
login
master
rights
user

# 查看分支文件状态
PS C:\vue_shop> git status
1
2
3
4
# Git三连
git add .
git commit -m "分类功能"
git push
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 查看分支
PS C:\vue_shop> git branch
* goods_cate
login
master
rights
user

# 切换到主分支
git checkout master

# 合并分支到master
git merge goods_cate

# 同步到远程仓库
git push

【参数管理】

1. 参数管理概述

商品参数用于显示商品的固定的特征信息,可以通过电商平台商品详情页面直观的看到。

2022-60 (8)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看分支
PS C:\vue_shop> git branch
goods_cate
login
* master
rights
user

# 创建并切换到参数分支
git checkout -b goods_params

# 推送并创建到云端
git push -u origin goods_params

2. 商品分类选择

(1) 选择商品分类

(2) 控制级联菜单分类选择

其中,Vue中这次添加的 computed 节点,与datacreatedmethods平级,用于计算属性,用法和data中类似,直接this.isBtnDisabledthis.cateId即可获取值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
export default {
data() {
},
created() {
},
methods: {
},
// 计算属性
computed: {
// 如果按钮需要被禁用,则返回true
isBtnDisabled() {
if (this.selectedCateKeys.length !== 3) {
return true
}
return false
},
// 当前选中的三级分类的Id
cateId() {
if (this.selectedCateKeys.length === 3) {
return this.selectedCateKeys[2]
}
return null
}
}
}

3. 实现参数列表

(1) 根据选择的商品分类加载对应的参数数据

(2) 处理标签数据格式

将字符串形式的数据分隔为数组:https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=130

1
2
3
4
5
6
res.data.forEach(item => {
// 将循环并用空格分隔得到的数组重新赋值为字符串
item.attr_vals = item.attr_vals.split(' ')
// 判断是否为空,空则赋值为空数组
// item.attr_vals = item.attr_vals ? item.attr_vals.split(',') : []
})

(3) 控制添加标签文本框的显示

(4) 实现标签动态添加的文本框控制逻辑

  • 控制标签输入域的显示和隐藏
  • 对输入的内容进行数据绑定

(5) 实现标签的添加和删除操作

添加标签和删除标签使用的是同一个接口,参数是一样的。

https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=137

4. 实现动态参数与静态属性添加

  • 动态参数与静态属性表单重用
  • 添加动态参数与静态属性使用的是同一个接口,参数是一样的

https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=139

5. 代码的推送

1
2
3
4
5
6
7
8
9
10
11
# 查看分支
PS C:\vue_shop> git branch
goods_cate
* goods_params
login
master
rights
user

# 查看文件状态
PS C:\vue_shop> git status
1
2
3
git add .
git commit -m "完成了商品分类参数的开发"
git push
1
2
3
git checkout master
git merge goods_params
git push

【商品管理】

2022-60 (9)
2022-60 (10)
2022-60 (11)
2022-60 (12)
2022-60 (13)
2022-60 (14)

1. 商品管理概述

商品管理模块用于维护电商平台的商品信息,包括商品的类型、参数、图片、详情等信息。通过商品管理模块可以实现商品的添加、修改、展示和删除等功能。

1
2
git checkout -b goods_list
git push -u origin goods_list

1. 商品列表

https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=142

2. 添加商品

(1) 基本布局与分布条效果

(2) 商品信息选项卡Tab布局效果

  • Tab 组件的基本使用

(3) 商品基本信息

(4) 商品分类信息

(5) 商品动态参数

(6) 商品静态属性

(7) 商品图片上传

(8) 商品详情

(8) 完成商品添加

(9) 代码的合并与提交

1
2
3
4
5
git status
git branch
git add .
git commit -m "商品列表"
git push
1
2
3
4
git checkout master
git branch
git merge goods_list
git push

【订单管理】

2022-60 (15)
2022-60 (16)
2022-60 (17)

1. 订单管理概述

订单管理模块用于维护商品的订单信息,可以查看订单的商品信息、物流信息,并且可以根据实际的运营情况对订
单做适当的调整。

1
2
git checkout -b order
git push -u origin order

2. 订单列表

(1) 订单列表展示

(2) 查看订单地址信息

(3) 查看订单物流信息

  • 调用接口获取物流数据
    由于源代码中所使用的第三方API接口响应数据失效,此功能无法正常使用。
    源代码有关部分:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 自动匹配运单号所属的物流公司
    function autoComNumber(orderno) {
    const url = `https://www.kuaidi100.com/autonumber/autoComNum?resultv2=1&text=${orderno}`
    return new Promise(function(resolve, reject) {
    request(url, (err, response, body) => {
    if (err) return reject({ status: 500, msg: err.message })
    // resolve(body)
    // console.log(body.num)
    body = JSON.parse(body)
    if (body.auto.length <= 0) return reject({ status: 501, msg: '无对应的物流公司' })
    resolve({ status: 200, msg: body.auto[0], comCode: body.auto[0].comCode })
    })
    })
    }

    终端窗口报错代码:

    1
    2
    E:\vue_api_server\modules\Logistics.js:13
    if (body.auto.length <= 0) return reject({ status: 501, msg: '无对应的物流公司' })

    考虑到黑马的这个Vue课程录制时间已久,文档中用于测试的真实物流单号804909574412544580相关数据早已被物流公司清除。所以此次请求只能根据文档自定义返回数据:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    // 展示物流进度对话框
    showProgressBox() {
    // 此接口已失效
    // const { data: res } = await this.$http.get('/kuaidi/804909574412544580')

    // 此次请求自定义接口返回数据
    const res = {
    data: [
    {
    time: '2018-05-10 09:39:00',
    ftime: '2018-05-10 09:39:00',
    context: '已签收,感谢使用顺丰,期待再次为您服务',
    location: ''
    },
    {
    time: '2018-05-10 08:23:00',
    ftime: '2018-05-10 08:23:00',
    context: '[北京市]北京海淀育新小区营业点派件员 顺丰速运 95338正在为您派件',
    location: ''
    },
    {
    time: '2018-05-10 07:32:00',
    ftime: '2018-05-10 07:32:00',
    context: '快件到达 [北京海淀育新小区营业点]',
    location: ''
    },
    {
    time: '2018-05-10 02:03:00',
    ftime: '2018-05-10 02:03:00',
    context: '快件在[北京顺义集散中心]已装车,准备发往 [北京海淀育新小区营业点]',
    location: ''
    },
    {
    time: '2018-05-09 23:05:00',
    ftime: '2018-05-09 23:05:00',
    context: '快件到达 [北京顺义集散中心]',
    location: ''
    },
    {
    time: '2018-05-09 21:21:00',
    ftime: '2018-05-09 21:21:00',
    context: '快件在[北京宝胜营业点]已装车,准备发往 [北京顺义集散中心]',
    location: ''
    },
    {
    time: '2018-05-09 13:07:00',
    ftime: '2018-05-09 13:07:00',
    context: '顺丰速运 已收取快件',
    location: ''
    },
    {
    time: '2018-05-09 12:25:03',
    ftime: '2018-05-09 12:25:03',
    context: '卖家发货',
    location: ''
    },
    {
    time: '2018-05-09 12:22:24',
    ftime: '2018-05-09 12:22:24',
    context: '您的订单将由HLA(北京海淀区清河中街店)门店安排发货。',
    location: ''
    },
    {
    time: '2018-05-08 21:36:04',
    ftime: '2018-05-08 21:36:04',
    context: '商品已经下单',
    location: ''
    }
    ],
    meta: { status: 200, message: '获取物流信息成功!' }
    }

    if (res.meta.status !== 200) {
    return this.$message.error('获取物流进度失败')
    }

    this.progressInfo = res.data

    this.progressVisible = true
    console.log(this.progressInfo)
    }
  • 实现物流信息列表时间线效果:https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=183

3. 代码提交与推送

1
2
3
4
5
git branch
git status
git add .
git commit -m "订单功能"
git push
1
2
3
git checkout master
git merge order
git push

【数据统计】

2022-60 (18)

1
2
3
git checkout -b report
git branch
git push -u origin report

1. 数据统计概述

数据统计模块主要用于统计电商平台运营过程的中的各种统计数据,并通过直观的可视化方式展示出来,方便相关
运营和管理人员查看。

2. 用户来源数据统计报表

(1) Echarts 第三方可视化库的基本使用

1
2
3
// 1. 引入Echarts
// import echarts from 'echarts'
import * as echarts from 'echarts'
1
2
<!-- 2. 为Echarts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 600px;height:400px;"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 生命周期mounted在Dom创建渲染完成之后执行
mounted() {
// 3. 基于准备好的Dom,初始化Echarts实例
var myChart = echarts.init(document.getElementById('main'))


// 4. 准备数据和配置项
var option = {
title: {
text: 'Echarts 入门实例'
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
}

// 5. 使用刚指定的配置项和数据显示图表
myChart.setOption(option)
},

(2) 实现用户来源数据统计报表

  1. 调用接口获取后台接口数据
  2. 通过echarts的api实现报表效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
data() {
return {
// 需要合并的数据
options: {
title: {
text: '用户来源'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#575a64'
}
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
boundaryGap: false
}
],
yAxis: [
{
type: 'value'
}
]
}
}
},

3. 代码提交与推送

1
2
3
4
5
6
7
git add .
git commit -m "报表功能"
git push

git checkout master
git merge report
git push

完成于2022年8月23日 22:06


问题解答

  • Vue当属性是布尔值的时候为什么要加冒号进行数据绑定?
    比如下方enterable这个属性

    1
    2
    3
    <el-tooltip effect="dark" content="分配角色" placement="top" :enterable="false">
    <el-button type="warning" icon="el-icon-setting" size="mini"></el-button>
    </el-tooltip>

    或者下方line-width属性。是由于数据类型的关系吗?比如 Boolean+Number 类型因为是 properties 就需要加:,而 String 因为是 attribute 所以不需要?

    1
    2
    3
    4
    5
    <tab :line-width="2" active-color="#fc378c">
    <tab-item :selected="demo2 === item"
    v-for="item in list2"
    @click="demo2 = item"></tab-item>
    </tab>

    【参考回答】:差不多就是这个意思,加上冒号会首先将这个属性当作变量解析,没加冒号就直接是字符串。冒号vue的v-bind简写语法。

  • 在反引号中可以用 ${} 来包裹变量,实现字符串拼接

    1
    2
    // this.$http.put(`users/:uId/state/:type`)
    this.$http.put(`users/${userinfo.id}/state/${userinfo.mg_state}`)

参考内容