项目源码与所需资料
链接:https://pan.baidu.com/s/1azwRyyFwXz5elhQL0BhkCA?pwd=8z59
提取码:8z59
我们这里用vue-admin-template框架来进行环境搭建
1.去资料中找到模板压缩文件,有两个,我们使用171KB的那个模板压缩文件
vue-admin-template和vue-element-admin的区别:前者是精简版,只有最基础的功能,后者功能更多。我们在前者的基础上进行二次开发,把后者当做工具箱,想要什么功能或者组件就去后者那里复制过来

2.解压这个171KB的压缩文件到工作区里面(我的工作区是vs1010)

3.在vscode中以终端方式打开上一步解压得到的文件夹,使用命令npm install进行依赖安装,安装完毕后会自动生成node_modules文件夹,这个文件夹存放的就是安装好的依赖


如果下载时爆红,那么此时自动生成的node_modules文件夹里面只会安装部分依赖,并没有将package.json中记录的依赖全都按装,所以我们要删掉这个自动生成的node_modules文件夹,重新执行npm install命令安装依赖,通常多试几次就能下载成功了
4.上面只是为了让我们熟悉一下流程,其实老师给的有已下载好依赖的后台系统页面,我放在了资料中(苹果电脑不用看4、5步了,因为苹果电脑只能使用npm install命令自己下载依赖,没办法使用已经下载好的依赖)

5.将这个压缩文件解压到工作区中(我的工作区是vs1010)

6.在终端中使用如下命令启动项目,启动后的项目的默认端口号是9528
npm run dev

7.在地址栏输入http://localhost:9528就可以访问了

我们编写的后端程序的入口是main方法,同样的这个前端框架也有入口(有两个入口)
入口一:vue-admin-1010–>index.html
不过这个页面只做了一件事:写一个div标签,并给该div标签添加一个id属性。做这件事的意义在讲解入口二时会说到

入口二:vue-admin-1010–>src–>main.js
该js中先是用import...from...引入了其它组件或者文件,最后new Vue({el: 'app',...}),其中app就是入口一的index.html中div标签的id=“app”
所以呢,入口一(index.html)写一个div标签用于显示,入口二(main.js)引入了其它组件然后创建vue对象进行操作

我们前端页面环境使用的vue-admin-template框架(模板)主要基于两种技术实现出来。
vue-admin-template模板 = vue + element-ui
1.build目录:放项目构建的脚本文件(一般不用管这个目录)
2.config目录:基本配置信息
我们可以在index.js中修改ip、端口号(可以修改但没必要修改),但注意一定要把index.js中useEslint: true改为useEslint: false(这是ESLint插件,这个插件用来检查代码,但是它的检查太严格了,我多敲几个空格多敲几个换行就会被视为错误代码,所以我们改为false,不使用这个插件)

我们在"1.搭建项目前端页面环境"的第6步使用命令npm run dev启动项目时会执行文件dev.env.js(同理如果使用命令npm run prod启动项目时会执行文件prod.env.js)
dev.env.js和prod.env.js都有BASE_API: '"https://easy-mock.com/mock/5950a2419adc231f356a6636/vue-admin"',这表示要访问的后端接口的地址,这里是默认地址,我们日后(3.1修改前端项目访问路径的第4步)要改成我们本地的后端接口地址localhost:8001

3.node_modules目录:存放下载的依赖
4.static目录:存放静态资源(一般不用管这个目录)
5.src目录:
①api目录:定义方法
②assets目录:存放静态资源(如:css文件、js文件、项目的相关图片…)
③components目录:存放一些组件/插件。比如说,我觉得当前这个框架缺少某个功能,那么我就可以引入额外的框架,引入的框架就放到这个目录(components)
④icons目录:存放项目用到的图标
⑤router目录:路由,就是我们说的菜单
⑥store目录:存放脚本文件(一般不用管这个目录)
⑦styles目录:存放样式文件(一般不用管这个目录)
⑧utils目录:存放框架中用到的工具类(一般不用管这个目录)
⑨views目录:存放项目具体的页面
我们用框架的目的是少写代码,更快的完成功能开发,那么理所当然的我们使用的这个前端页面框架也给我们封装了很多功能以便让我们减少代码编写(比如①封装了ajax请求、②以前必须使用babel将es6模块化转为es5模块化才可以在node中执行,现在框架会替我们完成es6转为es5)
那么我们开发功能时就需要做什么,具体流程是什么呢(这里先混眼熟就行,在后面的"4.4总结"中会细说)
1.在终端执行npm run dev命令来启动前端项目,启动成功后在地址栏输入http://localhost:9528进行访问


2.在打开的页面按F12打开开发者工具,在开发者工具中点击"Network"菜单,然后点击页面的"Sign in"按钮(点击按钮可能登录不进去,这是因为要访问的这个网站经常崩掉,不用管,第4步我们会把访问路径改为我们自己开发的后端接口的路径localhost:8001)

3.我们点击发送的第一个请求,可以看到请求路径是:
https://easy-mock.com/mock/5950a2419adc231f356a6636/vue-admin/user/login
这时我们回过头看"2.3 项目的目录结构"的第2条说的config目录下的dev.env.js和prod.env.js页面共有的BASE_API:
https://easy-mock.com/mock/5950a2419adc231f356a6636/vue-admin
发现第一个路径前半部分和第二个路径一样,后半部分多了个"/user/login",此时我们也就明白了:原来前端项目要访问的后端接口的地址就是在config目录下的dev.env.js和prod.env.js页面中的BASE_API设置的呀

4.分析完了现在开始修改后台访问路径:
将config目录下的dev.env.js中的BASE_API: '"https://easy-mock.com/mock/5950a2419adc231f356a6636/vue-admin"',注释掉,并添加如下这行代码
BASE_API: '"http://localhost:8001"',

1.看src–>utils–>request.js:

因为人家框架定义了非20000的状态码都是抛错,所以我们在"demo03-后台讲师管理模块"的"5.1统一返回数据格式"的第2步定义成功的状态码是20000
2.看src–>api–>login.js:

我们看login.js定义的方法中的这两个:login方法和getInfo方法:
url: '/user/login'和url: '/user/info'就是axios要访问的路径,所以我们等下需要在后端的控制层中编写两个方法,使访问/user/login或/user/info时可以执行对应的方法3.看src–>store–>modules–>user.js:

登录账号时底层会做两件事:登录&获取用户信息。
看"登录"方法中,成功调用login方法(在刚刚的第2条说过这个方法,这是在api目录下定义的方法)后要做的事在then(response => {…})里面编写了,省略号中有部分代码是:const data = response.data、commit('SET_TOKEN', data.token),从这里我们可以看出来后端对应方法返回的数据中一定要有token。同理,看"获取用户信息"方法,我们也知道了后端对应方法返回的数据中一定要有roles、name、avatar
在service_edu模块的控制层创建一个EduLoginController类,并在类中编写代码
@RestController
@RequestMapping("/eduservice/user")
public class EduLoginController {
//登录
@PostMapping("login")
public R login() {
return R.ok()
.data("token", "admin");
}
//获取用户信息
@GetMapping("info")
public R info() {
return R.ok()
.data("roles", "[admin]")
.data("name", "admin")
.data("avatar", "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
}
}

return R.ok().data("token", "admin");:我们在"3.2稍微看一点点底层"的第3条已经详细解释过了为什么返回的数据需要有token。info方法中的 return R.ok().data("roles", "[admin]").da......也是同理1.因为我们在"3.3在后端开发接口"编写代码时设置路径是/eduservice/user/login和/eduservice/userinfo,所以我们要去src–>api–>login.js中将login方法中的url: '/user/login'改为url: '/eduservice/user/login';将getInfo方法中的url: '/user/info'改为url: '/eduservice/user/info'
2.我们在"3.3在后端开发接口"编写的login方法上有一个注解是@PostMapping; info方法上有一个注解是@GetMapping,那么就需要让login.js页面的login方法中的method是post;让getInfo方法中的method是get。恰好这两个方法的method本来就是这样的,所以不需要修改
3.我们在"3.3在后端开发接口"编写的login方法和info方法都没有参数,所以login.js页面的login方法中的data: {...}和getInfo方法中的params: {...}暂时都无实际意义,暂时用不上,但也不用管它们,就在这儿放着就可以了
所以说呢,login.js页面中只需要修改login和getInfo方法的url,别的地方不需要修改。修改后的login.js如下:

1.启动后端项目

2.在终端使用命令npm run dev启动前端项目

3.在地址栏输入http://localhost:9528进入登录页面,然后按F12打开开发者工具,接着点击"Sign in"按钮发现还是不能登录,我们点击"Console"菜单去控制台看一下输出了什么错误信息

No 'Access-Control-Allow-Origin’这在术语上是叫跨域问题
什么叫跨域:通过一个地址去访问另外一个地址,这个过程中如果①访问协议(http、https)、②ip地址、③端口号这三处只要有任何一处不一样,就叫做跨域
我们现在是通过http://localhost:9528去访问http://localhost:8001,这两个地址的端口号不一样,所以会出现跨域问题
4.跨域问题的解决方式有很多种,简单列举两种:
我这里就是使用添加注解来解决跨域问题的:


5.重启后端项目,在地址栏输入http://localhost:9528进入登录页面,然后按F12打开开发者工具,接着点击"Sign in"按钮,此时就可以正常登录进去了。
并且注意看,它既向.../user/login发送了请求,又向.../user/info发送了请求,这就证实了我们在"3.2稍微看一点点底层"中第3点说的话:登录账号时底层会做两件事:登录&获取用户信息。


可能有朋友会有疑问:为啥每个请求都是请求了两次呢?
这是浏览器的机制,就拿第一个请求login举例:
该路径的第一次请求的请求方式是options;第二次请求的请求方式是post。
第一次的请求可以理解为是一个预请求,只是为了测是否能和后台服务器接口连通,如果能连通才会进行第二次的真正请求,不过第一次请求不会返回任何数据。




怎么编写添加路由的代码呢?我们可以看一下Example菜单的示例代码,以后路由就根据这个示例代码修改就可以了


component: () => import(...) 就是路由对应的页面,这样的话,点击某个路由,就可以显示路由对应的页面内容
既然点击路由可以显示路由对应的页面内容,那么相应的我们就需要创建页面
1在哪创建vue页面:
看上面那张图中的component: () => import('@/views/table/index'),我们根据路径可以找到view–>table–>index

所以我们就知道了,我们创建的页面是在views目录下(准确来说,是views目录的子目录下)
我们上面说的页面存放位置是框架默认的,当然了,你说我不想按照框架默认的存放位置(先在views目录下创建子目录,然后在子目录下创建页面),我想在views目录下创建一个子目录,然后在子目录下再创建一个子目录,最后才在最里层的目录中创建vue页面,这当然是可以的,但是别忘了需要配套地填写router–>index.js页面的component: () => import(...)中的路径。反正页面创建在哪都可以(大前提是在src目录下),只要配套填写路径就可以了
2.为什么创建的是vue页面而不是html页面或其他页面?
看上面那张图,人家创建的就是vue页面
老规矩,先看人家怎么在页面中编写代码的:
1.看src–>views–>table–>index.vue页面中的import { getList } from '@/api/table',这我们在"demo04-前端技术"的"9.3.1第一种写法"说过,是引入js文件中定义的方法

2.我们根据import { getList } from '@/api/table'可以去api目录下找到table.js文件,发现这个js文件是用来定义方法的。这样我们也就清楚了下一步应该干嘛:在api目录下创建js文件,定义方法

3.回到最初的问题:我们需要在vue页面中编写什么代码?
先再看一下vue页面:

现在我们知道vue页面就需要编写什么代码了吧:先使用import...from...引入方法,然后编写data():{...},created(){...},methods:{...},最后用element-ui显示数据内容(就在该页面的1-43行,太多了,所以我就没有放到截图里面)
data():{...},created(){...},methods:{...}1.随便找一段例子的代码,将代码复制粘贴

下面是复制粘贴好的indes.js页面:

2.将我们刚刚复制粘贴过来的代码根据需要进行修改,修改后务必保存修改

3.如果后端、前端项目都已启动,那么在地址栏输入http://localhost:9528进行访问,在登录页面点击"Sign in"登录进去后效果如下:

我们在"4.2在src–>views中创建vue页面"中说过,我们可以在任何地方(大前提是在src目录下)创建vue页面,只要配套的修改router–>index.js页面的component: () => import(...)中的路径即可
1.那么我们就可以在src–>views目录下创建一个目录edu,在edu下再创建一个目录teacher,最后在teacher目录下创建页面list.vue和save.vue

2.配套的修改index.js中component: () => import(...)的路径,修改后记得保存修改

3.在list.vue中编写代码
讲师列表

在我们以后创建的所有vue页面中都是必不可少的,这是人家封装的,省略号的内容我们根据具体需求写
4.在save.vue中编写代码
讲师添加

1.在api目录下创建teacher文件夹,然后在该文件夹下创建teacher.js文件

2.老办法,参考框架怎么定义方法的:将api–>tables.js中的代码复制粘贴到teacher.js中

有人可能要问:return request({...})中的request方法是干嘛用的?
这是框架给我们做的封装,只要我们调用了getList方法,就会使用axios发送ajax请求
3.es6模块化操作有两种写法,框架给的是第一种写法,我们开发中用第二种写法("demo04-前端技术"的9.3.2第二种写法)比较多,所以我们对teacher.js的代码进行修改
import request from '@/utils/request'
export default {
getList(params) {
return request({
url: '/table/list',
method: 'get',
params
})
}
}

4.好,我们现在根据需要来修改定义方法
先看我们后端控制层的EduTeacherController类和类中的方法:条件查询讲师带分页(pageTeacherCondition)


我们需要知道这几个东西:
/eduservice/edu-teacherpageTeacherCondition/{current}/{limit}知道了上面这些,我们就可以修改teacher.js中定义的方法了:
url的参数需要修改,有两种方式(建议用第一种)
方法参数改为current, limit, teacherQuery。分别表示当前页、每页记录数、条件对象
请求方式改为post
删去"params",添加一行代码data:teacherQuery,这表示把teacherQuery对象转换为json数据传递到接口中
方法名改为getTeacherListPage
5.修改后的teacher.js完整代码如下:
import request from '@/utils/request'
export default {
//1.讲师列表(条件查询带分页)
//current:当前页 limit:每页记录数 teacherQuery:条件对象
getTeacherListPage(current, limit, teacherQuery) {
return request({
url: `/eduservice/edu-teacher/pageTeacherCondition/${current}/${limit}`,
method: 'post',
//data: teacherQuery表示把teacherQuery对象转换为json数据传递到接口中
data: teacherQuery
})
}
}

1.既然用人家的框架,就要用人家规定的格式编写代码,参考人家给的src–>views–>dashboard–>index.vue页面我们可以知道,需要先写一个,然后才能在省略号的位置编写我们的核心代码

2.在src–>views–>edu–>teacher–>list.vue页面先敲一个

有人可能要问了,使用axios发送ajax请求不应该是getList() {axios.post("...").then(...).catch(...)}吗,为什么这里是teacher.getTeacherListPage(this.page, this.limit, this.teacherQuery).then(...).catch(...)
这是因为人家框架给我们做了封装,我们执行teacher.js中定义的getTeacherListPage方法的过程实际上就是使用axios发送ajax请求的过程(我们在"5.3在api目录下创建js文件,定义方法"的第2步就已经说过了)
1.启动后端项目和前端项目,访问http://localhost:9528,在首页打开开发者工具,点击"讲师列表",查看控制台输出

2.上图中使用大方框圈起来的就是请求成功之后返回的信息,所以我们想要获取讲师列表就需要用这个代码:response.data.rows,知道了这些,那么list.vue中的console.log(response)就没什么用了,我们把它注释掉就可以了,然后我们给list.vue页面中添加如下代码:
this.list = response.data.rows
this.total = response.data.total
console.log(this.list)
console.log(this.total)

3.刷新页面,看控制台的输出:

4.现在我们已经可以拿到数据,接下来我们在list.vue页面的template标签的div标签下编写代码使数据以列表的形式在页面显示,这里我们使用element-ui组件实现
①进入element-ui的官网https://element.eleme.cn/#/zh-CN,点击组件的"查看详情"

②点击"Table 表格"就会有很多示例供我们选择,我们这里就使用第一个吧。点击"显示代码"

③为了便于观看,我们将示例的代码复制到文件中

:data="tableData"是v-bing:data="tableData"的简写形式(忘了的可以去回顾"demo04-前端技术"的"3.3基本数据渲染和指令"),用来和tableData单向绑定以获取数据prop="date"和tableData中的date对应label="..."就是表头④老师给的有代码,我们直接复制粘贴到list.vue页面的template标签的div标签下
{{ (page - 1) * limit + scope.$index + 1 }}
{{ scope.row.level===1?'高级讲师':'首席讲师' }}
修改
删除

this.list = response.data.rows将讲师数据存放到了list变量中,所以截图的第6行是:data="list",以获取讲师数据element-loading-text="数据加载中" 作用是:点击前端页面的"讲师列表"后,如果网速比较慢,还没有获取到数据并展现,此时就会显示"数据加载中"。可有可无,如果不需要这个功能,就把截图中第5行的v-loading="listLoading"和第7行的element-loading-text="数据加载中"删掉,听弹幕说如果使用这个功能日后可能会报错,吓得我赶紧把这两行代码删了{{ (page - 1) * limit + scope.$index + 1 }}是显示序号,不用太深究,固定用就可以了和第25行的{{ scope.row.level===1?'高级讲师':'首席讲师' }}
slot-scope="scope"是获取当前对象,scop.row用来获取行,scop.row.level用来获取行的level值。既然我们知道了这些,那么举一反三我们就可以写出和作用一样的如下代码(但下面这段代码太冗余了,不建议这样写):
{{scope.row.name}}
⑤完整的list.vue代码如下
{{ (page - 1) * limit + scope.$index + 1 }}
{{ scope.row.level===1?'高级讲师':'首席讲师' }}
修改
删除
5.再次刷新页面进行测试,效果图如下

点击分页组件"Paginaion 分页",有很多示例供我们选择

我们本来应该将某个示例的代码复制过来根据需求修改,但是老师已经给了我们修改之后的代码,如下。分页肯定是显示在列表的下面,所以我们将这段代码复制到

:current-page="page"、:page-size="limit"、:total="total"分别表示得到当前页、每页记录数、总记录数,获取到这些值后element-ui底层给我们做了封装,会自己把分页的结构和功能展现出来(比如说:现在是在第几页,一共有几页,点击下一页会显示下一页的数据…)@current-change="getList"是v-on:current-change="getList"的简写(在"demo04-前端技术"的"3.5绑定事件"说过)这行代码表示每次做分页切换都会调用getList方法(该方法是我们在methods: {...}中定义的,该方法用来从后端获取分页数据和总记录数,并将其分别赋值给list变量和total变量)
@current-change="getList()",这个()想写就写,不想写就不写那么就出现了一个问题:我们定义的getList方法是没有参数的,并且分页代码中的:current-page="page":current-page和page做了单向数据绑定而不是双向数据绑定。那么getList方法内部每次执行teacher.getTeacherListPage(this.page, this.limit,......时的参数this.page永远都是我们在data() {...}中定义的page: 1。解决方法:
page = 1
this.page = page有人可能会问了:既然我给getList方法添加了形参,那么在"6.2使用老师给的代码"的截图中的第50行的@current-change="getList"是不是要修改成@current-change="getList(page + 1)"?老师说不需要修改,说人家框架已经封装了,会自己传参数给getList方法

1.我们数据库中数据太少了,先直接去SQLyog中执行下面这些sql语句向我们的edu_teacher表中添加数据
INSERT INTO `edu_teacher` VALUES ('2', 'lucy', '高级讲师简介', '高级讲师资历', '2', 'http://edu-longyang.oss-cn-beijing.aliyuncs.com/2020/08/05/25f411209c8b44b9b003482b6265c3c9file.png', '2', '0', '2019-10-30 11:55:19', '2019-11-12 13:37:52');
INSERT INTO `edu_teacher` VALUES ('1189390295668469763', '李刚upupup2', '高级讲师简介111', '高级讲师111', '2', 'http://edu-longyang.oss-cn-beijing.aliyuncs.com/2020/08/05/25f411209c8b44b9b003482b6265c3c9file.png', '2', '0', '2019-10-30 11:55:19', '2019-11-12 13:37:52');
INSERT INTO `edu_teacher` VALUES ('1189426437876985858', '王二2', '高级讲师简介', '高级讲师', '1', 'http://edu-longyang.oss-cn-beijing.aliyuncs.com/2020/08/05/25f411209c8b44b9b003482b6265c3c9file.png', '0', '0', '2019-10-30 14:18:56', '2019-11-12 13:37:35');
INSERT INTO `edu_teacher` VALUES ('1189426464967995394', '王五2', '高级讲师简介', '高级讲师', '2', 'http://edu-longyang.oss-cn-beijing.aliyuncs.com/2020/08/05/25f411209c8b44b9b003482b6265c3c9file.png', '0', '0', '2019-10-30 14:19:02', '2019-11-12 13:37:18');
INSERT INTO `edu_teacher` VALUES ('1192249914833055747', '李四2', '高级讲师简介', '高级讲师', '1', 'http://edu-longyang.oss-cn-beijing.aliyuncs.com/2020/08/05/25f411209c8b44b9b003482b6265c3c9file.png', '0', '0', '2019-11-07 09:18:25', '2019-11-12 13:37:01');
INSERT INTO `edu_teacher` VALUES ('3', 'lucy2', '高级讲师简介', '高级讲师资历', '2', 'http://edu-longyang.oss-cn-beijing.aliyuncs.com/2020/08/05/25f411209c8b44b9b003482b6265c3c9file.png', '2', '0', '2019-10-30 11:55:19', '2019-11-12 13:37:52');
INSERT INTO `edu_teacher` VALUES ('1189390295668469764', '李刚upupup3', '高级讲师简介111', '高级讲师111', '2', 'http://edu-longyang.oss-cn-beijing.aliyuncs.com/2020/08/05/25f411209c8b44b9b003482b6265c3c9file.png', '2', '0', '2019-10-30 11:55:19', '2019-11-12 13:37:52');
INSERT INTO `edu_teacher` VALUES ('1189426437876985859', '王二3', '高级讲师简介', '高级讲师', '1', 'http://edu-longyang.oss-cn-beijing.aliyuncs.com/2020/08/05/25f411209c8b44b9b003482b6265c3c9file.png', '0', '0', '2019-10-30 14:18:56', '2019-11-12 13:37:35');
INSERT INTO `edu_teacher` VALUES ('1189426464967995395', '王五3', '高级讲师简介', '高级讲师', '2', 'http://edu-longyang.oss-cn-beijing.aliyuncs.com/2020/08/05/25f411209c8b44b9b003482b6265c3c9file.png', '0', '0', '2019-10-30 14:19:02', '2019-11-12 13:37:18');
INSERT INTO `edu_teacher` VALUES ('1192249914833055748', '李四3', '高级讲师简介', '高级讲师', '1', 'http://edu-longyang.oss-cn-beijing.aliyuncs.com/2020/08/05/25f411209c8b44b9b003482b6265c3c9file.png', '0', '0', '2019-11-07 09:18:25', '2019-11-12 13:37:01');
2.去页面中看效果


1.点击表单组件"Form 表单",有很多示例供我们选择,我们想要的效果是行内表单这个示例的效果,所以就点击行内表单示例的"显示代码"

2.为了便于观看,我们将示例的代码复制到文件中

:inline="true"表示让表单在一行显示:model="formInline"是v-bind:model="formInline"的简写,用来和formInline单向绑定以获取数据placeholder="审批人"和第6行的placeholder="活动区域"分别是示例中输入框和下拉框的提示词v-model="formInline.user"和第6行的v-model="formInline.region"是双向数据绑定(在"demo04-前端技术"的"3.4单向、双向数据绑定"说过),这样的话我们在输入框和下拉框中填写的数据就会分别赋值给data() {...}中定义的变量user和region1.我们本来应该将这些代码复制到list.vue中根据需求修改,但是老师已经给了我们修改之后的代码,如下。因为条件查询表单应该显示在讲师列表的上面,所以我们将下面这些代码复制粘贴到list.vue页面的template标签的div标签下的最前面
查询
清空

data() {...}中定义了条件对象变量teacherQuery,所以我们需要让输入框、下拉框与teacherQuery对象中对应属性进行双向绑定(比如说:v-model="teacherQuery.name"就是和teacherQuery对象的name属性进行双向绑定)。所以我们需要将上面这些代码中的searchObj.改为teacherQuery.@click="fetchData()"改为@click="getList()"

2.刷新页面,在"讲师名"输入框输入"李",查看效果

1.我们想要点击"清空"按钮后可以做两件事:清空表单中输入的条件和查询所有数据
我们看"7.2使用老师给的代码"的第一个截图的第36行@click="resetData()",所以我们在methods: {...}中编写方法resetData
//"清空"的方法
resetData() {
//1.表单输入项数据清空
this.teacherQuery = {}
//2.查询所有讲师数据
this.getList()
}

this.teacherQuery = {}是让teacherQuery对象为空,这样的话该对象没有属性了,那么表单中的数据自然也就清空了
2.刷新页面,自行进行测试
我们在"5.讲师列表"的"5.5显示讲师列表"的第4步的④这一步中复制了老师给的代码到list.vue中,老师给的代码中本来就有删除按钮的代码,并已经给按钮绑定事件了,下面是list.vue页面的部分截图

在src–>api–>edu–>teacher.js文件中定义方法,方法内部调用后端的逻辑删除接口
//2.删除讲师
deleteTeacherId(id) {
return request({
url: `/eduservice/edu-teacher/${id}`,
method: 'delete'
})
}

因为后端的逻辑删除方法上的注解是@DeleteMapping,所以这里提交方式要用delete
在list.vue的methods: {...}中定义removeDataById方法,方法内部调用"8.2在api中定义删除方法"中定义的deleteTeacherId方法
1.为了用户体验,当用户点击"删除"按钮时需要弹出一个提示框,和以前一样,我们去element-ui中找代码。代码是从组件中的"MessageBox 弹框"的"确认消息"找到的,我们将红方框圈起来的部分复制到vue.js中然后根据需求修改

2.removeDataById方法如下
//删除讲师
removeDataById(id) {
this.$confirm('此操作将永久删除讲师记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => { //点击确定会执行then方法
//调用teacher.js中定义的删除方法
teacher.deleteTeacherId(id)
.then(response => { //删除成功
//1.提示删除成功
this.$message({
type: 'success',
message: '删除成功!'
});
//2.回到列表页面
this.getList()
})
.catch(error => {}) //删除失败
})
}

绿框圈起来的部分就是第1步中红框圈起来的代码,我们根据需求进行了修改
刷新页面,自行测试
1.先去src–>router–>index.js中看,从component: () => import('@/views/edu/teacher/save')我们知道了点击"添加讲师"后会去views–>edu–>teacher–>save.vue,所以我们在save.vue中编写代码

2.具体怎么编写代码呢,我们知道当点击首页的"添加讲师"路由时进入表单页面供我们填写信息,所以说我们需要给save.vue页面添加表单组件,老办法,去element-ui中复制过来再根据需求修改,老师已经给了我们修改后的代码,如下。save.vue中是有代码的,是在"5.2创建路由对应的页面"的第4步编写的,我们将save.vue中的代码都删掉,然后将下面的代码复制到save.vue中
保存

截图中的40-47行:我们在"7.1去element-ui找示例代码"的第2步的截图中说过:因为进行了双向数据绑定,所以这里定义或不定义对象的属性都是可以的,我们在"7.1去element-ui找示例代码"没有给对象定义属性,这里换一种写法:给对象定义属性
截图中第30行的:disabled="saveBtnDisabled"和第48行的saveBtnDisabled: false共同作用,目的是:当点击"保存"按钮成功添加讲师后,不能再点击该按钮,防止重复多次提交造成添加多条数据
3.刷新页面,点击路由"添加讲师"看效果

在src–>api–>edu–>teacher.js文件中定义方法,方法内部调用后端的添加讲师接口
//3.添加讲师
addTeacher(teacher) {
return request({
url: `/eduservice/edu-teacher/addTeacher`,
method: 'post',
data: teacher
})
}

data: teacher在"5.3在api目录下创建js文件,定义方法"的第4步说过,是为了将teacher对象转换为json数据传递到接口中
1.先在