在线教育-谷粒学院学习笔记(五)

news2024/11/15 8:41:09

文章目录

    • 1 内容介绍
    • 2 课程分类前端实现
    • 3 课程列表功能实现
    • 4 课程管理概括
    • 5 添加课程信息后端实现
    • 6 添加课程信息前端实现
    • 7 前端完善

1 内容介绍

  • 添加课程分类前端实现
  • 课程分类列表显示功能(树形结构)
  • 课程管理模块需求
  • 添加课程基本信息功能

2 课程分类前端实现

1 添加课程分类的路由

router/index.js

{
  path: '/subject',
  component: Layout,
  redirect: '/subject/list',
  name: '课程分类管理',
  meta: { title: '课程分类管理', icon: 'example' },
  children: [
    {
      path: 'list',
      name: '课程分类列表',
      component: () => import('@/views/edu/subject/list'),
      meta: { title: '课程列表', icon: 'table' }
    },
    {
      path: 'save',
      name: '添加课程分类',
      component: () => import('@/views/edu/subject/save'),
      meta: { title: '添加课程分类', icon: 'tree' }
    },
  ]
},

2 创建课程分类页面,修改路由对应页面路径

views/edu/subject/list.vue save.vue

**3 在添加课程分类页面,实现效果 **

  • 添加上传组件实现
<template>
  <div class="app-container">
    <el-form label-width="120px">
      <el-form-item label="信息描述">
        <el-tag type="info">excel模版说明</el-tag>
        <el-tag>
          <i class="el-icon-download"/>
          <a :href="'/static/write.xlsx'">点击下载模版</a>
        </el-tag>

      </el-form-item>

      <el-form-item label="选择Excel">
        <el-upload
          ref="upload"
          :auto-upload="false"
          :on-success="fileUploadSuccess"
          :on-error="fileUploadError"
          :disabled="importBtnDisabled"
          :limit="1"
          :action="BASE_API+'/eduservice/subject/addSubject'"
          name="file"
          accept="application/vnd.ms-excel">
          <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
          <el-button
            :loading="loading"
            style="margin-left: 10px;"
            size="small"
            type="success"
            @click="submitUpload">上传到服务器</el-button>
        </el-upload>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      BASE_API: process.env.BASE_API, // 接口API地址
      importBtnDisabled: false, // 按钮是否禁用
      loading: false
    }
  },
  methods: {
    // 点击按钮上传文件到接口
    submitUpload() {
      this.importBtnDisabled = true
      this.loading = true
      this.$refs.upload.submit()
    },
    // 上传成功
    fileUploadSuccess() {
      // 提示信息
      this.loading = false
      this.$message({
        type: 'success',
        message: '添加课程分类成功'
      })
      // 跳转课程分类列表
    },
    // 上传失败
    fileUploadError() {
      // 提示信息
      this.loading = false
      this.$message({
        type: 'error',
        message: '添加课程分类失败'
      })
    }
  }
}
</script>

3 课程列表功能实现

用树形结构显示课程列表

1 参考tree模块,整合前端

需要创建接口,按照分类要求的格式返回数据

  • 返回数据格式
[
    {
      id: 1,
      label: '一级分类名称',
      children: 
      [
          {
            id: 4,
            label: '二级分类名称',
          }
      ]
    }, 
	{
		......
	}
],
  • 针对返回数据,创建对应的实体类

    • 两个实体类:一级和二级 entity/subject/OneSubject TwoSubject

      @Data
      public class OneSubject {
          private String id;
          private String title;
      }
      
      @Data
      public class TwoSubject {
          private String id;
          private String title;
      }
      
  • 在两个实体类之间表示关系(一个一级分类有多个二级分类)

    • OneSubject.java

      private List<TwoSubject> children = new ArrayList<>();
      
  • 具体封装代码编写

    • 封装

      List<EduSubject> oneSubjectList   ===>  List<OneSubject> finalSubject
      
      // 课程分类列表
          @Override
          public List<OneSubject> getAllOneTwoSubject() {
              // 1 查询所有一级分类 parent_id = 0
              QueryWrapper<EduSubject> wrapperOne = new QueryWrapper<>();
              wrapperOne.eq("parent_id", 0);
              List<EduSubject> oneSubjectList = baseMapper.selectList(wrapperOne);
      //        List<EduSubject> oneSubjectList = this.list(wrapperOne);
      
              // 2 查询所有二级分类 parent_id != 0
              QueryWrapper<EduSubject> wrapperTwo = new QueryWrapper<>();
              wrapperTwo.ne("parent_id", 0);
              List<EduSubject> twoSubjectList = baseMapper.selectList(wrapperTwo);
      
              // 创建list集合,用于存储最终封装数据
              List<OneSubject> finalSubjectList = new ArrayList<>();
      
              // 3 封装一级分类
              // oneSubjectList -> finalSubjectList
              for (EduSubject eduSubject : oneSubjectList) {
                  // eduSubject -> oneSubject -> finalSubjectList
                  OneSubject oneSubject = new OneSubject();
                  // 基本写法
      //            oneSubject.setId(eduSubject.getId());
      //            oneSubject.setTitle(eduSubject.getTitle());
                  // 简写
                  BeanUtils.copyProperties(eduSubject, oneSubject); // eduSubject -> oneSubject
                  finalSubjectList.add(oneSubject);
      
      
                  // 4 封装二级分类
                  List<TwoSubject> twoFinalSubjectList = new ArrayList<>();
      
                  // twoSubjectList -> twoFinalSubjectList
                  for (EduSubject eduSubject2 : twoSubjectList) {
                      // eduSubject2 -> twoSubject -> twoFinalSubjectList
                      // 二级分类的parent_id == 一级分类的id
                      if (eduSubject2.getParentId().equals(eduSubject.getId())) {
                          TwoSubject twoSubject = new TwoSubject();
                          BeanUtils.copyProperties(eduSubject2, twoSubject);
                          twoFinalSubjectList.add(twoSubject);
                      }
                  }
                  // 把一级下面的所有二级放到一级分类里
                  // twoFinalSubjectList -> oneSubject
                  oneSubject.setChildren(twoFinalSubjectList);
              }
              return finalSubjectList;
          }
      
  • 完善

    save.vue

    fileUploadSuccess() {
      // 提示信息
      this.loading = false
      this.$message({
        type: 'success',
        message: '添加课程分类成功'
      })
      // 跳转课程分类列表
      this.$router.push({ path: '/subject/list' })
    },
    

    list.vue

    created() {
      this.getAllSubjectList()
    },
    methods: {
      getAllSubjectList() {
        subject.getSubjectList()
          .then(response => {
            this.data2 = response.data.list
          })
      },
      filterNode(value, data) {
        if (!value) return true
        return data.title.toLowerCase().indexOf(value.toLowerCase()) !== -1
      }
    }
    

4 课程管理概括

  • 课程添加流程

在这里插入图片描述

    • edu_course:课程表,存储课程基本信息
    • edu_course_descrpition:课程简介表,存储课程简介信息
    • edu_chapter:课程章节表
    • edu_video:课程小节表,存储章节里边的小节信息
    • edu_teacher:讲师表
    • edu_subject:分类表
  • 表关系

    在这里插入图片描述

5 添加课程信息后端实现

1 使用代码生成器生成课程相关代码

  • 细节问题

    • 创建vo实体类,用于表单数据封装

      • 把表单提交过来的数据添加到数据库
        • 向两张表添加数据:课程表、课程描述表
    • 把讲师和分类使用下拉列表显示

      • 课程表做成二级联动效果

2 创建vo类,封装表单提交的数据

@Data
public class CourseInfoVo {
    @ApiModelProperty(value = "课程ID")
    private String id;

    @ApiModelProperty(value = "课程讲师ID")
    private String teacherId;

    @ApiModelProperty(value = "课程专业ID")
    private String subjectId;

    @ApiModelProperty(value = "课程标题")
    private String title;

    @ApiModelProperty(value = "课程销售价格,设置为0则可免费观看")
    private BigDecimal price; // BigDecimal:精度更准确

    @ApiModelProperty(value = "总课时")
    private Integer lessonNum;

    @ApiModelProperty(value = "课程封面图片路径")
    private String cover;

    @ApiModelProperty(value = "课程简介")
    private String description;
}

3 编写controller和service

注意:课程和课程简介是一对一关系,需要对应联系起来

controller

@RestController
@RequestMapping("/eduservice/edu-course")
@CrossOrigin
public class EduCourseController {
    @Autowired
    private EduCourseService courseService;

    // 添加课程基本信息方法
    @PostMapping("addCourseInfo")
    public R addCourseInfo(@RequestBody CourseInfoVo courseInfoVo) {
        courseService.saveCourseInfo(courseInfoVo);
        return R.ok();
    }
}

service

@Service
public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService {
    @Autowired
    private EduCourseDescriptionService courseDescriptionService;
    // 添加课程基本信息方法
    @Override
    public void saveCourseInfo(CourseInfoVo courseInfoVo) {
        // 1 向课程表添加课程信息
        // courseInfoVo -> eduCourse
        EduCourse eduCourse = new EduCourse();
        BeanUtils.copyProperties(courseInfoVo, eduCourse);
        int insert = baseMapper.insert(eduCourse);
        if (insert <= 0) {
            // 添加失败
            throw new GuliException(20001, "添加课程信息失败");
        }
        // 获取添加之后课程id
        String cid = eduCourse.getId();
        // 2 向课程简介表添加课程简介信息
        EduCourseDescription courseDescription = new EduCourseDescription();
        courseDescription.setDescription(courseInfoVo.getDescription());
        // 设置课程简介id就是课程id
        courseDescription.setId(cid);
        courseDescriptionService.save(courseDescription);
    }
}

其他需要修改的地方:

1、实体类的时间上加注解

@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;

@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;

2、EduCourseDescription中的id注解修改

@ApiModelProperty(value = "课程ID")
@TableId(value = "id", type = IdType.INPUT)
private String id;

6 添加课程信息前端实现

1 添加课程管理的路由,并添加隐藏路由,做步骤条的页面跳转

router/index.js

{
  path: '/course',
  component: Layout,
  redirect: '/course/list',
  name: '课程管理',
  meta: { title: '课程管理', icon: 'example' },
  children: [
    {
      path: 'list',
      name: '课程列表',
      component: () => import('@/views/edu/course/list'),
      meta: { title: '课程列表', icon: 'table' }
    },
    {
      path: 'info',
      name: '添加课程',
      component: () => import('@/views/edu/course/info'),
      meta: { title: '编辑课程基本信息', icon: 'tree' },
    },
    {
      path: 'info/:id',
      name: '添加课程',
      component: () => import('@/views/edu/course/info'),
      meta: { title: '编辑课程基本信息', icon: 'tree' },
      hidden: true
    },
    {
      path: 'chapter/:id',
      name: '添加课程',
      component: () => import('@/views/edu/course/chapter'),
      meta: { title: '编辑课程大纲', icon: 'tree' },
      hidden: true
    },
    {
      path: 'publish/:id',
      name: '添加课程',
      component: () => import('@/views/edu/course/publish'),
      meta: { title: '发布课程', icon: 'tree' },
      hidden: true
    }
  ]
},

2 实现课程添加的步骤条

info.vue -> chapter.vue -> publish.vue

3 调用接口

api/edu/course.js

4 添加之后,返回课程id

EduCourseController修改:

@PostMapping("addCourseInfo")
public R addCourseInfo(@RequestBody CourseInfoVo courseInfoVo) {
    String id = courseService.saveCourseInfo(courseInfoVo);
    return R.ok().data("courseId", id);
}

对应修改service的代码,返回课程id

info.vue修改:

// 跳转到下一步
// 获取课程id:response.data.courseId
this.$router.push({ path: '/course/chapter/' + response.data.courseId })

7 前端完善

1 讲师下拉列表显示

<el-form-item label="课程讲师">
  <el-select
    v-model="courseInfo.teacherId"
    placeholder="请选择">
    <el-option
      v-for="teacher in teacherList"
      :key="teacher.id"
      :label="teacher.name"
      :value="teacher.id"/>
  </el-select>
</el-form-item>
created() {
  // 初始化所有讲师
  this.getListTeacher()
},
methods: {
  // 查询所有讲师
  getListTeacher() {
    course.getListTeacher()
      .then(response => {
        this.teacherList = response.data.items()
      })
  },

**2 显示分类:二级联动 **

<el-form-item label="课程分类">
  <el-select
    v-model="courseInfo.teacherId"
    placeholder="一级分类"
    @change="subjectLeaveOneChanged">
    <el-option
      v-for="subject in subjectOneList"
      :key="subject.id"
      :label="subject.title"
      :value="subject.id"/>
  </el-select>
  <el-select
    v-model="courseInfo.subjectId"
    placeholder="二级分类">
    <el-option
      v-for="subject in subjectTwoList"
      :key="subject.id"
      :label="subject.title"
      :value="subject.id"/>
  </el-select>
</el-form-item>
// 查询课程列表:一级分类
getOneSubject() {
  subject.getSubjectList()
    .then(response => {
      this.subjectOneList = response.data.list
    })
},
// 点击某个一级分类,触发change,显示对应二级分类
// value是一级分类的id值
subjectLeaveOneChanged(value) {
  // 遍历所有分类,包含一级、二级
  for (let i = 0; i < this.subjectOneList.length; i++) {
    const onsSubject = this.subjectOneList[i]
    if (onsSubject.id === value) {
      this.subjectTwoList = onsSubject.children
      // 清空二级分类的id值
      this.courseInfo.subjectId = ''
    }
  }
},

3 封面上传

<el-form-item label="课程封面">
  <el-upload
    :show-file-list="false"
    :on-success="handleAvatarSuccess"
    :before-upload="beforeAvatarUpload"
    :action="BASE_API+'/eduoss/fileoss'"
    class="avatar-uploader">
    <img :src="courseInfo.cover">
  </el-upload>
</el-form-item>
// 上传封面之前
beforeAvatarUpload(file) {
  const isJPG = file.type === 'image/jpeg'
  const isLt2M = file.size / 1024 / 1024 < 2
  if (!isJPG) {
    this.$message.error('上传头像图片只能是 JPG 格式!')
  }
  if (!isLt2M) {
    this.$message.error('上传头像图片大小不能超过 2MB!')
  }
  return isJPG && isLt2M
},
// 上传封面成功
handleAvatarSuccess(res, file) {
  this.courseInfo.cover = res.data.url
},

4 整合文本编辑器

  • 复制文本编辑器相关组件

    • components/Tinymce
    • static/tinymce4.7.5
  • 添加配置build/webpack.dev.conf.js

    new HtmlWebpackPlugin({
    ......,
    templateParameters: {
    BASE_URL: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
     }
    })
    
  • index.html中引入js脚本

    <script src=<%= BASE_URL %>/tinymce4.7.5/tinymce.min.js></script>
    <script src=<%= BASE_URL %>/tinymce4.7.5/langs/zh_CN.js></script>
    
  • 页面使用文本编辑器

    • 引入组件 import Tinymce from '@/components/Tinymce'

    • 声明组件 components: { Tinymce },

    • 页面中使用标签实现文本编辑器组件

      <el-form-item label="课程简介">
        <tinymce :height="300" v-model="courseInfo.description" />
      </el-form-item>
      
  • 样式

    <style scoped>
    .tinymce-container {
      line-height: 29px;
    }
    </style>
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/171406.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何设置OpenFeign请求超时

Feign和OpenFeign介绍 Feign集成了Ribbon、RestTemplate实现了负载均衡的执行Http调用&#xff0c;只不过对原有的方式&#xff08;RibbonRestTemplate&#xff09;进行了封装&#xff0c;开发者不必手动使用RestTemplate调服务&#xff0c;而是定义一个接口&#xff0c;在这个…

byzer笔记本使用

byzer笔记本使用 数据源的定义 对于etl&#xff0c;起始的第一步往往是定义一个数据来源。 设置数据源 通过设置 -> 外部数据源 -> 新增可以新增jdbc类型的数据源。 命令指定数据源 notebook中可以使用connect命令进行jdbc数据源的指定: > SET user"root&q…

Elasticsearch(四)--一文弄懂ES的映射操作

一、前言 上一章学习了ES的索引相关操作&#xff0c;那么这一章就轮到映射&#xff0c;了解映射操作最重要的点就是去学习ES的数据类型。那么本章我们会了解到映射的创建、查看和修改操作&#xff0c;然后详细介绍ES中的基本数据类型和复杂的数据类型&#xff0c;并且会对常用…

解决ElementUI导航栏重复点菜单报错问题

在使用ElementUI中的导航时&#xff0c;默认情况下如果重复点击某选项&#xff0c;会报错。 element-ui.common.js?b705:3354 Error: Avoided redundant navigation to current location: “/home/home1”. at createRouterError (vue-router.esm.js?8c4f:2060) at createNa…

Java IO流 - 打印流详细使用介绍

文章目录打印流打印流基本使用输出语句重定向打印流 打印流基本使用 打印流: 作用&#xff1a;打印流可以实现更方便、更高效的打印数据到文件中去。打印流一般是指&#xff1a;PrintStream&#xff0c;PrintWriter两个类。 可以实现打印什么数据就是什么数据&#xff0c;例如…

【GD32F427开发板试用】06-硬件I2C软件I2C驱动0.91OLED

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;Stark_GS I2C 简介及特点 并行总线至 I2C 总线协议的转换及接口&#xff1b;同一接口既可实现主机功能又可实现从机功能&#xff1b;主从机之…

在线教育-谷粒学院学习笔记(四)

文章目录1 内容介绍2 阿里云存储OSS3 Java代码操作阿里云oss4 搭建阿里云oss项目环境5 上传头像后端实现6 Nginx使用7 上传头像前端实现8 课程分类管理介绍9 EasyExcel工具10 课程分类添加功能1 内容介绍 添加讲师实现头像上传功能 阿里云oss存储服务 添加课程分类功能 使用Ea…

欧拉的“她力量”,如何为品牌注入新能量?

文|智能相对论作者| Kinki近日&#xff0c;百度营销联合CBNData推出的《2022新能源汽车趋势洞察》正式发布&#xff0c;报告显示&#xff0c;随着新能源汽车的普及&#xff0c;新中产女性已成为了“消费新势力”。女性更偏爱新能源汽车已不是新鲜观点&#xff0c;调研显示&…

物理主机telenet登录ensp虚拟网络设备并显示配置python脚本

一、物理主机telnet登录ensp虚拟网络设备 1、物理主机配置 1.1、物理主机环回口虚拟网卡配置 见本人博客:Ensp用windows回环口连接cloud配置_ensp环回口配置_林锋Space的博客-CSDN博客https://liulinfeng.blog.csdn.net/article/details/128098737 1.2、物理主机telnet开启 …

大数据的整体见解

如何建设高效的数据模型体系&#xff0c;使数据易用&#xff0c;避免重复建设和数据不一致性&#xff0c;保证数据的规范性&#xff1b;如何提供高效易用的数据开发工具&#xff1b;如何做好数据质量保障&#xff1b;如何有效管理和控制日益增长的存储和计算消耗&#xff1b;如…

文件下载 response响应ContentType与a标签download属性

参考资料 MediaType介绍了解HTML/HTML5中的download属性header中Content-Disposition的作用 目录一. ContentType二. a标签download属性2.1 下载同源静态资源文件2.2 后台可省略Content-Disposition一. ContentType 我们在进行文件下载的时候&#xff0c;后端往往需要通过如下…

CSRF(跨站请求伪造)

一、csrf是什么CSRF&#xff08;Cross Site Request Forgery&#xff0c;跨站请求伪造&#xff09;。是一种对网站的恶意利用&#xff0c;通过伪装来自受信任用户的请求来利用受信任的网站。原理是攻击者构造网站后台某个功能接口的请求地址&#xff0c;诱导用户去点击或者用特…

uni-app 中实现文件和图片的上传-H5

之前写过一篇上传的文章&#x1f4d5;&#xff0c;但是那篇文章仅仅只能实现上传图片的功能&#xff0c;而且代码写的比较乱&#xff0c;看起来很繁杂&#xff0c;最近有幸又遇到了上传图片和文件的需求&#xff0c;在完成这个功能后&#xff0c;整理一下&#xff0c;希望能给需…

第十四届蓝桥杯单片机组学习笔记(2):按键

第十四届蓝桥杯单片机组学习笔记&#xff08;2&#xff09;&#xff1a;按键前言区分高低电平驱动按键消抖软件消抖触发处理的方式矩阵键盘最简单常用的人机交互手段——按键 前言 实现按键检测需要解决的问题&#xff1a; 按键是低电平按下还是高电平按下&#xff1b;按键消…

(1分钟速览)KBM-SLAM 论文阅读笔记

编辑切换为居中添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09;这篇博客记录了上面这篇论文的学习笔记。编辑切换为居中添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09;这个是本文的摘要&#xff0c;一眼开过去就是单目slam当今所遇到…

机器学习(一):人工智能概述

文章目录 人工智能概述 一、人工智能应用场景 二、人工智能小案例 三、人工智能发展必备三要素 四、人工智能、机器学习和深度学习 人工智能概述 一、人工智能应用场景 二、人工智能小案例 案例一 学习链接&#xff1a;https://quickdraw.withgoogle.com 案例二 学习链…

老杨说运维 | 2023,浅谈智能运维趋势(三)

文末附有视频回顾 前言&#xff1a; 在回顾&#xff08;一&#xff09;中&#xff0c;老杨提到的智能运维发展趋势中&#xff0c;面对国际化形势不确定的情况&#xff0c;信创部分的比例要求正在递增。作为国家经济发展的新动能&#xff0c;信创发展已步入深水区&#xff0c;智…

cv2.imread()、cv2.putText、cv2.imwrite()、cv2.waitKey()

cv2cv2.imread()cv2.putText&#xff08;&#xff09;cv2.imwrite&#xff08;&#xff09;cv2.waitKey()cv2.imread() 用于读取图像数据案例演示&#xff1a; import cv2# ouput img properties img_pathC:/Users/WHY/Pictures/Saved Pictures/OIP-C (1).jfif def funOutput…

安卓手机使用Linux Deploy安装CentOS

目录 前言 准备工作 实践 busybox安装 安装并配置Linux Deploy 局域网使用ssh连接服务器 公网使用ssh连接服务器 环境安装 写在最后 前言 最近沉迷于服务器搭建&#xff0c;书接上文&#xff0c;在安卓高版本中成功安装了服务器&#xff0c;但是安卓低版本的却一言难尽…

2023CUPT第七题 法拉第波 思路和解法

本文未完原题A droplet of less viscous liquid floating in a bath of a more viscous liquid develops surprising wave- like patterns when the entire system is set into vertical oscillation. Investigate this phenomenon and the parameters relevant to the product…