谷粒学院16万字笔记+1600张配图(十)——课程管理

项目源码与所需资料
链接:https://pan.baidu.com/s/1azwRyyFwXz5elhQL0BhkCA?pwd=8z59
提取码:8z59

demo10-课程管理

1.课程信息确认后端

1.1分析

1.课程信息确认页面会显示课程名称、课程价格、课程简介、课程所属分类、课程所属讲师等等…我们要从数据表中查询这些信息,其中从edu_course表查询课程名称、课程价格;从edu_course_description表查询课程简介;从edu_subject表查询课程所属分类;从edu_teacher表查询课程所属讲师。这些数据并没有在一张数据表中,我们应该怎么解决呢?在"demo09-课程管理"的"3.1.3业务层实现类"中我们的做法是:分别查询这两张表,然后将查询到的数据封装到一个VO实体类中。此时我们也可以通过分别查询这几张数据表并封装数据来实现需求,但是在"demo09-课程管理"的"3.1.3业务层实现类"中只涉及到两张数据表,而我们此时涉及到的数据表太多了,所以不建议这样做

2.建议通过手写sql语句来实现

1.2多表连接查询

1.2.1多表查询的三种方式

在这里插入图片描述

假如左边的数据表是课程一级分类表,右边的数据表是课程二级分类表,且右边的表的第三列存放的是课程一级分类的id

  • 内连接
    • 查询的两张表有关联的数据就叫做内连接
    • 那么查询上图中的两张表,就会查询出来四条数据:前端、后端、Java、vue
  • 左外连接
    • 查询时将查询左边表的所有数据,查询右边表时只查询和左边表有关联的数据
    • 那么查询上图中的两张表,就会查询出来五条数据:前端、后端、运维、Java、vue
  • 右外连接
    • 查询时将查询右边表的所有数据,查询左边表时只查询和右边表有关联的数据,实际上就是左外连接反过来呗
    • 那么查询上图中的两张表,就会查询出来五条数据:前端、后端、Java、vue、mysql

1.2.2我们应该用哪种方式

1.实际开发中我们经常用内连接和左外连接,右外连接用的不多。我们此时用内连接可以吗?当然可以,但是我们某一门课可能会没有简介,所以用内连接不太合适,所以我们这里使用左外连接查询

2.在数据库编写如下sql命令

SELECT ec.id,ec.title,ec.price,ec.lesson_num,
       ecd.description,
       et.name,
       es1.title AS oneSubject,
       es2.title AS twoSubject
FROM edu_course ec LEFT OUTER JOIN edu_course_description ecd ON ec.id=ecd.id
                   LEFT OUTER JOIN edu_teacher et ON ec.teacher_id=et.id
                   LEFT OUTER JOIN edu_subject es1 ON ec.subject_parent_id=es1.id
                   LEFT OUTER JOIN edu_subject es2 ON ec.subject_id=es2.id
WHERE ec.id='1562267576652808193'

在这里插入图片描述

  • 我们将课程一级分类和课程二级分类都存到了edu_subject这张表中,此时应该怎么做:如果一张表中有多个字段同时关联一张表,我们就需要查询多次
  • 1562267576652808193是我的edu_course数据表中的id,你们写自己数据表中的

1.3创建vo类

在entity–>vo包下创建vo类CoursePublishVo来封装数据

扫描二维码关注公众号,回复: 15507004 查看本文章
@Data
public class CoursePublishVo {
    
    
    private String id;
    private String title;
    private String cover;
    private Integer lessonNum;
    private String subjectLevelOne;
    private String subjectLevelTwo;
    private String teacherName;
    private String price;//只用于显示
}

在这里插入图片描述

1.4持久层

我们在前面的代码编写中有时只需处理控制层,有时只需处理控制层和业务层,还从来没有处理过持久层。但我们此时手写sql语句,所以需要处理持久层

1.4.1在mapper中定义方法

在EduCourseMapper中定义"根据课程id查询课程具体信息"的抽象方法

public interface EduCourseMapper extends BaseMapper<EduCourse> {
    
    
    //根据课程id查询课程具体信息
    public CoursePublishVo getPublishCourseInfo(String courseId);
}

在这里插入图片描述

1.4.2在idea中连接数据库

1.点击"DataBase"

在这里插入图片描述

2.点击加号(“+”),然后点击Data Source下的MySQL

在这里插入图片描述

3.输入我们的mysql密码和数据库名字,然后点击"Ok"

在这里插入图片描述

4.填写mysql的账号密码,然后点击"Ok"

在这里插入图片描述

5.此时我们就可以看到数据库guli中的数据表了,说明此时连接成功

在这里插入图片描述

1.4.3编写映射

在EduCourseMapper.xml中编写刚刚定义的抽象方法的映射

<!--sql语句:根据课程id查询课程具体信息-->
<select id="getPublishCourseInfo" resultType="com.atguigu.eduservice.entity.vo.CoursePublishVo">
    SELECT ec.id,ec.title,ec.cover,ec.lesson_num AS lessonNum,ec.price,
           es1.title AS subjectLevelOne,
           es2.title AS subjectLevelTwo,
           et.name AS teacherName
    FROM edu_course ec LEFT OUTER JOIN edu_subject es1 ON ec.subject_parent_id=es1.id
                       LEFT OUTER JOIN edu_subject es2 ON ec.subject_id=es2.id
                       LEFT OUTER JOIN edu_teacher et ON ec.teacher_id=et.id
    WHERE ec.id=#{courseId}
</select>

在这里插入图片描述

  • 为什么截图中的第6行、第7行、第8行、第9行要分别用AS lessonNumAS subjectLevelOnesubjectLevelTwoteacherName来起别名?

    • 因为我们vo类CoursePublishVo中定义的属性名是lessonNum、subjectLevelOne、subjectLevelTwo、teacher Name。所以我们需要起别名,并且起的别名一定要和CoursePublishVo中的属性名对应上
  • 我们在"1.4.1在mapper中定义方法"定义的抽象方法只有一个参数,所以截图中第13行的WHERE ec.id=#{courseId}中的courseId可以随便写(不过别写成中文啊!!!)

  • <select>标签中的id属性值就填写我们在"1.4.1在mapper中定义方法"定义的抽象方法的名字

  • <select>标签中的resultType属性是方法返回值的类型,这里我们需要填写CoursePublishVo类的全路径:com.atguigu.eduservice.entity.vo,末尾再加上.CoursePublishVo

    在这里插入图片描述

1.5控制层

在控制器EduCourseController中定义方法

//根据课程id查询课程具体信息
@GetMapping("getPublishCourseInfo/{id}")
public R getPublishCourseInfo(@PathVariable String id) {
    
    
    CoursePublishVo coursePublishVo= courseService.publishCourseInfo(id);
    return R.ok().data("publishCourse", coursePublishVo);
}

在这里插入图片描述

1.6业务层接口

在业务层接口EduCourseService定义抽象方法

//根据课程id查询课程具体信息
CoursePublishVo publishCourseInfo(String id);

1.7业务层实现类

在业务层实现类EduCourseServiceImpl中实现上一步定义的抽象方法

//根据课程id查询课程具体信息
@Override
public CoursePublishVo publishCourseInfo(String id) {
    
    
    //调用mapper中的方法
    CoursePublishVo publishCourseInfo = baseMapper.getPublishCourseInfo(id);
    return publishCourseInfo;
}

在这里插入图片描述

我们在"demo07-课程分类管理"的"7.4.2业务层实现类"的第1步说过,在业务层调用mapper中的方法我们有两种方式:使用baseMapper.xxx或使用this.xxx。但是因为我们此时是调用mapper中我们自己定义的方法,所以我们只能用BaseMapper.xxx

1.8测试

1.重启EduApplication服务,使用swagger进行测试

2.在输入框输入课程id后点击"Try it out!"

在这里插入图片描述

3.执行了异常,说明我们接口是有问题的,解决方法在后面的"1.9加载问题"

在这里插入图片描述

1.9加载问题

1.9.1分析问题

1.接口报错如下

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.atguigu.eduservice.mapper.EduCourseMapper.getPublishCourseInfo

在这里插入图片描述

2.出现这种报错我们首先查看EduCourseMapper.xml的<select>标签中id属性值和我们在EduCourseMapper中定义的方法名字是否对应上,检查过后发现我们这里是对应上的

3.其实这个错误是maven默认加载机制造成的

①我们先看下面这张图,此时是有xml文件的

在这里插入图片描述

②然后再看下图,发现编译后没有xml文件了,也就是说编译时并没有编译xml文件

在这里插入图片描述

③这是maven默认加载机制造成的:加载时只会加载java文件夹下的.java类型文件,而不会加载java文件夹下的xml类型的文件

在这里插入图片描述

1.9.2解决问题

解决方法有很多种:

1.方法一:

将这些xml文件复制粘贴到编译后的mapper文件夹下(我没有用这种方法,所以我把具体操作截图后又将编译后的mapper文件夹下的这些xml文件删掉了)

在这里插入图片描述

这种方法不建议用,因为每次修改xml文件后都需要手动再将修改后的xml文件复制到编译后的mapper文件夹下,很麻烦

2.方法二:

将这些xml文件剪切粘贴到resources目录下(我没有用这种方法,所以我把具体操作截图后又将resources目录下的这些xml文件剪切粘贴到了mapper文件夹下,即归位)

在这里插入图片描述

这种方法不建议用,因为我们的代码都是用代码生成器生成的,人家给的结构就是xml在mapper文件夹下。这种方法可行,但以后每次再新生成xml文件就又需要我们将该xml文件剪切粘贴到resources文件夹下,挺麻烦的

3.方法三(推荐使用):

①在pom.xml中进行配置(我们可以在service_edu的pom.xml中进行配置,但我们后期别的项目中可能也需要这样的配置,所以我们选择在service的pom.xml中进行配置)

<!-- 项目打包时会将java目录中的*.xml文件也进行打包 -->
<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

在这里插入图片描述

第123行的<include>**/*.xml</include>中的**(两个星号)表示多层目录,如果是*(一个星号)则表示java目录下的一层目录,一样加载不到我们的xml文件(因为我们的xml文件是在java目录下的很多层目录下的)

②点击"Load Maven Changes"刷新pom文件

在这里插入图片描述

③在application.properties中进行配置

#配置mapper xml文件的路径
mybatis-plus.mapper-locations=classpath:com/atguigu/eduservice/mapper/xml/*.xml

在这里插入图片描述

1.9.3再次测试

1.重启EduApplication服务,可以看到编译后mapper文件夹下就有xml文件了

在这里插入图片描述

2.在输入框输入课程id后点击"Try it out!"

在这里插入图片描述

3.可以看到成功返回了数据,测试成功

在这里插入图片描述

2.课程信息确认前端

2.1在api中定义方法

在src–>api–>edu–>course.js页面中编写方法调用后端接口

//5.根据课程id查询课程具体信息
getPublishCourseInfo(courseId) {
    
    
  return request({
    
    
    url: `/eduservice/course/getPublishCourseInfo/${
      
      courseId}`,
    method: 'get'
  })
}

在这里插入图片描述

2.2获取路径中的课程id

在publish.vue页面得到路由中的课程id

//获取路由中的课程id
if(this.$route.params && this.$route.params.id) {
    
    
    this.courseId = this.$route.params.id
}

在这里插入图片描述

截图中第32行用到了数据模型courseId,现在我们去定义这个数据模型

在这里插入图片描述

2.3调用api中的方法

1.我们接下来需要调用在"2.1在api中定义方法"定义的方法getPublishCourseInfo,所以需要在publish.vue页面中引入course.js文件

import course from '@/api/edu/course'

在这里插入图片描述

2.在publish.vue页面中定义方法来调用api中的方法

//根据课程id查询课程具体信息
getCoursePublishId() {
    
    
    //调用api中的方法
    course.getPublishCourseInfo(this.courseId)
        .then(response => {
    
    
            this.publishCourse = response.data.publishCourse
        })
},

在这里插入图片描述

截图的第43行用到了数据模型coursePublish。现在我们去定义这个数据模型

在这里插入图片描述

2.4初始化页面

我们在created方法中调用在"2.3调用api中的方法"的第2步定义的getCoursePublishId方法以初始化页面得到该门课程的信息

//调用方法:根据课程id查询课程具体信息
this.getCoursePublishId()

在这里插入图片描述

2.5将内容显示到页面上

1.将方框圈起来的部分删掉

在这里插入图片描述

2.将老师给的代码复制过来

<div class="ccInfo">
  <img :src="coursePublish.cover">
  <div class="main">
    <h2>{
   
   { coursePublish.title }}</h2>
    <p class="gray"><span>共{
   
   { coursePublish.lessonNum }}课时</span></p>
    <p><span>所属分类:{
   
   { coursePublish.subjectLevelOne }} — {
   
   { coursePublish.subjectLevelTwo }}</span></p>
    <p>课程讲师:{
   
   { coursePublish.teacherName }}</p>
    <h3 class="red">¥{
   
   { coursePublish.price }}</h3>
  </div>
</div>
<div>
  <el-button @click="previous">返回修改</el-button>
  <el-button :disabled="saveBtnDisabled" type="primary" @click="publish">发布课程</el-button>
</div>

在这里插入图片描述

3.将老师给的css样式复制过来

<style scoped>
.ccInfo {
    
    
    background: #f5f5f5;
    padding: 20px;
    overflow: hidden;
    border: 1px dashed #DDD;
    margin-bottom: 40px;
    position: relative;
}
.ccInfo img {
    
    
    background: #d6d6d6;
    width: 500px;
    height: 278px;
    display: block;
    float: left;
    border: none;
}
.ccInfo .main {
    
    
    margin-left: 520px;
}

.ccInfo .main h2 {
    
    
    font-size: 28px;
    margin-bottom: 30px;
    line-height: 1;
    font-weight: normal;
}
.ccInfo .main p {
    
    
    margin-bottom: 10px;
    word-wrap: break-word;
    line-height: 24px;
    max-height: 48px;
    overflow: hidden;
}

.ccInfo .main p {
    
    
    margin-bottom: 10px;
    word-wrap: break-word;
    line-height: 24px;
    max-height: 48px;
    overflow: hidden;
}
.ccInfo .main h3 {
    
    
    left: 540px;
    bottom: 20px;
    line-height: 1;
    font-size: 28px;
    color: #d32f24;
    font-weight: normal;
    position: absolute;
}
</style>

在这里插入图片描述

2.6测试

在地址栏输入http://localhost:9528/#/course/publish/1562267576652808193进行测试,可以看到成功显示数据

在这里插入图片描述

3.课程最终发布后端

3.1分析

1.虽然此时数据库中有课程信息,但是我们还没有最终发布课程,只有当我们最终发布课程了,前台用户才可以看到这个课程

2.先看一下我们创建的edu_course表中status字段的含义

在这里插入图片描述

可以知道我们是通过status字段的值来判断该门课程是否发布:值为Draft时课程未发布;值为Normal时课程已发布

3.由下图可知当我们新的课程数据插入数据库中时,status字段默认是Draft,也就是说默认是未发布状态

在这里插入图片描述

3.2控制层

在控制器EduCourseController中编写方法用于将课程的发布状态改为"已发布"

//课程最终发布(修改edu_course表中status字段的值)
@PostMapping("publishCourse/{id}")
public R publishCourse(@PathVariable String id) {
    
    
    EduCourse eduCourse = new EduCourse();
    eduCourse.setId(id);
    eduCourse.setStatus("Normal"); //设置课程发布状态为"已发布"
    courseService.updateById(eduCourse);
    return R.ok();
}

在这里插入图片描述

4.课程最终发布前端

4.1在api中定义方法

在course.js中定义方法来调用上一步编写的后端接口

//6.课程最终发布(将课程的发布状态改为"已发布")
publishCourse(courseId) {
    
    
  return request({
    
    
    url: `/eduservice/course/publishCourse/${
      
      courseId}`,
    method: 'post'
  })
}

在这里插入图片描述

4.2调用api中的方法

1.可以看到,"发布课程"按钮我们给它绑定的方法是publish方法

在这里插入图片描述

2.publish方法我们曾经编写过

在这里插入图片描述

3.完整的publish方法如下

//课程最终发布
publish() {
    
    
    course.publishCourse(this.courseId)
        .then(response => {
    
    
            //提示发布成功
            this.$message({
    
    
                type: 'success',
                message: '发布成功!'
            });
            //跳转到list.vue页面
            this.$router.push({
    
    path: '/course/list'})
        })
}

在这里插入图片描述

4.3测试

1.在地址栏输入http://localhost:9528/#/course/publish/1562267576652808193,然后点击"发布课程"

在这里插入图片描述

2.提示发布成功

在这里插入图片描述

3.去数据库查看,可以看到这条数据的status字段的值确实被修改为了Normal

在这里插入图片描述

5.课程列表后端

5.1分析

其实和讲师列表是一样的,老师这里只做了最基本的实现,后期的条件查询带分页由我们自己完善,那我暂时也只做最基本的实现吧

5.2控制层

在控制器EduCourseController中编写方法

//课程列表最基本实现(条件查询带分页后期再完善)
@GetMapping
public R getCourseList() {
    
    
    List<EduCourse> list = courseService.list(null);
    return R.ok().data("list", list);
}

在这里插入图片描述

6.课程列表前端

6.1在api中定义方法

在course.js中编写方法用于调用上一步编写的后端接口

//7.课程列表
getListCourse() {
    
    
  return request({
    
    
    url: `/eduservice/course`,
    method: 'get'
  })
}

在这里插入图片描述

6.2编写list.vue页面

此时list.vue(是course目录下的list.vue)中没有任何代码,我们说过了课程列表页面和讲师列表页面很相似,所以我们直接将讲师列表页面的代码全部复制粘贴到课程列表页面,并根据需求进行修改,修改后的课程列表页面如下

<template>
  <div class="app-container">

    <!-- 表格 -->
    <el-table
      :data="list"
      border
      fit
      highlight-current-row>

      <el-table-column
        label="序号"
        width="70"
        align="center">
        <template slot-scope="scope">
          {
   
   { scope.$index + 1 }}
        </template>
      </el-table-column>

      <el-table-column prop="title" label="课程名称" width="80" />

      <el-table-column label="课程状态" width="80">
        <template slot-scope="scope">
          {
   
   { scope.row.status==='Normal'?'已发布':'未发布' }}
        </template>
      </el-table-column>

      <el-table-column prop="lessonNum" label="课时数"/>

      <el-table-column prop="gmtCreate" label="添加时间" width="160"/>

      <el-table-column prop="viewCount" label="浏览数量" width="80" />

      <el-table-column label="操作" width="450" align="center">

        <template slot-scope="scope">
          <router-link :to="'/course/info/'+scope.row.id">
            <el-button type="primary" size="mini" icon="el-icon-edit">编辑课程基本信息</el-button>
          </router-link>

          <router-link :to="'/course/chapter/'+scope.row.id">
            <el-button type="primary" size="mini" icon="el-icon-edit">编辑课程大纲</el-button>
          </router-link>

          <el-button type="danger" size="mini" icon="el-icon-delete">删除课程信息</el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
//引入course.js文件
import course from '@/api/edu/course'

export default {
  data() { //定义变量和初始值
    return {
      list: null //查询之后接口返回的数据赋值给list
    }
  },
  created() { //页面渲染之前执行,一般用来调用methods中定义的方法
    //调用
    this.getList()
  },
  methods: { //创建具体的方法,调用course.js中定义的方法
    //课程列表的方法
    getList() {
      //调用方法,使用axios发送ajax请求
      course.getListCourse()
        .then(response => {
          this.list = response.data.list
        })
    }
  }
}
</script>

在这里插入图片描述

  • 截图中第41行的:to="'/course/chapter/'+scope.row.id"是为了实现:点击"编辑课程大纲 "按钮时走/course/chapter/+课程id路由从而在浏览器展现chapter.vue页面。截图中第37行的:to="'/course/info/'+scope.row.id"同理
  • 删除按钮的后端和前端代码我们接下来就会说

6.3测试

自行测试

7.课程删除后端

7.1分析

1.课程里面有课程描述、章节,章节里面又有小节,小节里面又有视频,所以我们删除课程时需要将视频、小节、章节、课程描述还有课程本身都给删除掉

2.外键约束

两张表一对多关联时,在多的那一方创建字段,指向一的那一方的主键,这个字段就叫做外键

拿课程表和章节表举例:

在这里插入图片描述

3.去章节表看一下:

在这里插入图片描述

这里的course_id字段就是外键。但是我们发现我们并没有给这个字段添加foreign key将这个外键声明出来,我们只是自己心里知道它是一个外键,这种方式我们称之为物理外键

为什么不给外键字段添加foreign key呢?有一个原因是:如果添加了foreign key那么删除数据时就必须先删除视频,然后删除小节,然后删除章节,再删除课程描述,最后才能删除课程本身,否则就会报错(其中删除课程描述不一定非要在删除章节之后,因为课程描述只和课程本身有关联,所以只要是在删除课程本身之前删除课程描述就可以了)

如果不添加foreign key那么我们删除数据时就没有先后之别了,不过还是建议使用刚刚说的顺序进行删除

7.2控制层

在控制器EduCourseController中编写代码

//删除课程
@DeleteMapping("{courseId}")
public R deleteCourse(@PathVariable String courseId) {
    
    
    courseService.removeCourse(courseId);
    return R.ok();
}

在这里插入图片描述

7.3业务层接口

在业务层接口EduCourseService中定义抽象方法

//删除课程
void removeCourse(String courseId);

在这里插入图片描述

7.4业务层实现类

在业务层实现类EduCourseServiceImpl中实现上一步定义的抽象方法:

1.我们会在抽象方法中删除小节表、章节表、课程描述表中的数据,其中课程描述表我们曾经已经注入过了,现在我们来注入小节表和章节表

//注入小节和章节service
@Autowired
private EduVideoServiceImpl eduVideoService;
@Autowired
private EduChapterService chapterService;

在这里插入图片描述

2.在EduCourseServiceImpl中编写代码

//删除课程
@Override
public void removeCourse(String courseId) {
    
    
    //1.根据课程id删除小节
    eduVideoService.removeVideoByCourseId(courseId);

    //2.根据课程id删除章节
    chapterService.removeChapterByCourseId(courseId);

    //3.根据课程id删除课程描述
    courseDescriptionService.removeDescriptionByCourseId(courseId);

    //4.根据课程id删除课程本身
    int result = baseMapper.deleteById(courseId);
    if (result == 0) {
    
     //删除失败
        throw new GuliException(20001, "删除失败");
    }
}

在这里插入图片描述

7.5编写removeVideoByCourseId方法

1.在业务层接口EduVideoService中定义抽象方法

//根据课程id删除小节
void removeVideoByCourseId(String courseId);

在这里插入图片描述

2.在业务层实现类EduVideoServiceImpl中实现上一步定义的抽象方法

//根据课程id删除小节
@Override
public void removeVideoByCourseId(String courseId) {
    
    

    //TODO 删除小节前需要先删除小节下的视频文件
    QueryWrapper<EduVideo> wrapper = new QueryWrapper<>();
    wrapper.eq("course_id", courseId);
    baseMapper.delete(wrapper);
}

在这里插入图片描述

删除小节时需要先删除小节中的视频,这个业务我们后面实现

7.6编写removeChapterByCourseId方法

1.在业务层接口EduChapterService中定义抽象方法

//根据课程id删除章节
void removeChapterByCourseId(String courseId);

在这里插入图片描述

2.在业务层实现类EduChapterServiceImpl中实现上一步定义的抽象方法

在这里插入图片描述

7.7疑问

有没有朋友疑惑为什么不将removeVideoByCourseId方法和removeChapterByCourseId方法的逻辑编写在业务层实现类EduCourseServiceImpl的removeCourse方法中呢?我们这样做是为了解耦

7.8测试

重启后端项目后使用swagger自行测试吧

8.课程删除前端

8.1在api中定义方法

//8.根据课程id删除课程
deleteCourseById(courseId) {
    
    
  return request({
    
    
    url: `/eduservice/course/${
      
      courseId}`,
    method: 'delete'
  })
}

在这里插入图片描述

8.2绑定事件

给list.vue页面的"删除课程信息"按钮绑定事件

在这里插入图片描述

8.3调用api中的方法

//根据课程id删除课程
deleteCourse(courseId) {
    
    
  this.$confirm('此操作将永久删除课程记录, 是否继续?', '提示', {
    
    
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    
    
    course.deleteCourseById(courseId)
      .then(response => {
    
    
        //1.提示删除成功
        this.$message({
    
    
          type: 'success',
          message: '删除成功!'
        });
        //2.回到列表页面
        this.getList()
      })
      .catch(error => {
    
    }) //删除失败
  })
},

在这里插入图片描述

8.4测试

自行测试

猜你喜欢

转载自blog.csdn.net/maxiangyu_/article/details/127027935