Online Education_Day07-Project Course Release-Add Course Information

1. Course Publishing Form - Step Navigation

1.1 Demand Analysis

 

 

 

1.2 Course related table relationship

 

2. Add basic course information background

2.1 Generate course-related codes

Use the code generator to generate course-related code.

 

2.2 Define the form form object

When we add basic course information, we need to involve two tables edu_course and edu_course_description. At the same time, we also need to specify the teacher of the course and the classification of the course when adding a class. There are a lot of content added, so we encapsulate the data submitted by the front desk into a CourseInfoFormVo object.

Create the CourseInfoForm class under entity/vo

@ApiModel(value = "Basic course information", description = "Form object for editing course basic information")
@Data
public class CourseInfoFormVo implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value = "Course ID")
    private String id;
    @ApiModelProperty(value = "Course Instructor ID")
    private String teacherId;
    @ApiModelProperty(value = "Course Major ID")
    private String subjectId;
    @ApiModelProperty(value = "course title")
    private String title;
    @ApiModelProperty(value = "Course sales price, if you set it to 0, you can watch it for free")
    private BigDecimal price;
    @ApiModelProperty(value = "Total Class Hours")
    private Integer lessonNum;
    @ApiModelProperty(value = "course cover image path")
    private String cover;
    @ApiModelProperty(value = "Course Introduction")
    private String description;
}                            

2.3 Define the control layer EduCourseController

We have already used the code generation tool to generate the code, we only need to write the code in EduCourseController.java.

@Api(description="Course Management")
@CrossOrigin //cross domain
@RestController
@RequestMapping("/eduservice/course")
public class EduCourseController {
    @Autowired
    private CourseService courseService;
    @ApiOperation(value = "Add new course")
    @PostMapping("/addCourseInfo")
    public R addCourseInfo(@RequestBody CourseInfoFormVo courseInfoFormVo) {
        String courseId = eduCourseService.saveCourseInfo(courseInfoFormVo);
        return R.ok().data("courseId",courseId);
    }
}

2.4 Define the business layer method CourseService

Interface: CourseService.java

/**
     * Save course and course details information
     * @param courseInfoForm
     * @return newly generated course id
     */
void saveCourseInfo(CourseInfoFormVo courseInfoFormVo);

Implementation: CourseServiceImpl.java


/**
 * <p>
 * Course service implementation class
 * </p>
 *
 * @author zjl
 */
@Service
public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService {
    @Autowired
    EduCourseDescriptionService eduCourseDescriptionService;
    // Add course information
    @Override
    public void saveCourseInfo(CourseInfoFormVo courseInfoFormVo) {
        // Add basic course information to the curriculum
        EduCourse eduCourse = new EduCourse();
        BeanUtils.copyProperties(courseInfoFormVo, eduCourse);
        int insert = this.baseMapper.insert(eduCourse);
        // Determine whether adding basic course information is successful
        if (insert==0) {
            throw new EduException(20001, "Failed to add course basic information!");
        }
        // Add a course profile to the course profile table
        EduCourseDescription eduCourseDescription = new EduCourseDescription();
        eduCourseDescription.setDescription(courseInfoFormVo.getDescription());
        eduCourseDescriptionService.save(eduCourseDescription);
    }
}

2.5 Swagger test

 

View database information

 

In database analysis, there is a one-to-one relationship between the course schedule and the course profile table, but when adding data, it is found that it is not a one-to-one relationship.

The id in the edu_course table is 1548334513809661953, the id in the edu_course_description table is1548334513809661954

It is found that the two tables are not related by the two id values. For a one-to-one relationship, the id value in the edu_course_description table should be the id value in the edu_course table.

2.6 Modify CourseServiceImpl

After adding the course information, get the Id of the course, and then set the id of the course to the course description information.

 

At the same time, modify the id primary key strategy in the EduCourseDescription class. The id in this table does not need to be generated vividly. We need to insert it manually.

 

3. Add basic course information front-end

3.1 Add course management route

// course management
  {
    path: '/course',
    component: Layout,
    redirect: '/course/list',
    name: 'Course Management',
    meta: { title: 'Course Management', icon: 'form' },
    children: [
      {
        path: 'list',
        name: 'Course List',
        component: () => import('@/views/edu/course/list'),
        meta: { title: 'Course List' }
      },
      {
        path: 'info',
        name: 'Add Course',
        component: () => import('@/views/edu/course/info'),
        meta: { title: 'Add Course' }
      },
      {
        path: 'info/:id',
        name: 'Edit course basic information',
        component: () => import('@/views/edu/course/info'),
        meta: { title: 'Edit course basic information', noCache: true },
        hidden: true
      },
      {
        path: 'chapter/:id',
        name: 'Edit Course Syllabus',
        component: () => import('@/views/edu/course/chapter'),
        meta: { title: 'Edit Course Syllabus', noCache: true },
        hidden: true
      },
      {
        path: 'publish/:id',
        name: 'Publish Course',
        component: () => import('@/views/edu/course/publish'),
        meta: { title: 'Publish Course', noCache: true },
        hidden: true
      }
    ]
  }

3.2 Add vue components

 

3.3 Integrate the step bar component

Reference http://element-cn.eleme.io/#/zh-CN/component/steps

3.3.1 Course Information Page

Add the following to info.vue:

<template>
  <div class="app-container">
    <h2 style="text-align: center;">Publish a new course</h2>
    <el-steps :active="1" process-status="wait" align-center style="margin-bottom: 40px;">
      <el-step title="Fill in basic course information"/>
      <el-step title="Create Course Outline"/>
      <el-step title="Final Release"/>
    </el-steps>
    <el-form label-width="120px">
      <el-form-item>
        <el-button :disabled="saveBtnDisabled" type="primary" @click="next">Save and next</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      saveBtnDisabled: false // Whether the save button is disabled
    }
  },
  created() {
    console.log('info created')
  },
  methods: {
    next() {
      console.log('next')
      this.$router.push({ path: '/course/chapter/1' })
    }
  }
}
</script>

3.3.2 Course Outline Page

Add the following to chapter.vue

<template>
  <div class="app-container">
    <h2 style="text-align: center;">Publish a new course</h2>
    <el-steps :active="2" process-status="wait" align-center style="margin-bottom: 40px;">
      <el-step title="Fill in basic course information"/>
      <el-step title="Create Course Outline"/>
      <el-step title="Final Release"/>
    </el-steps>
    <el-form label-width="120px">
      <el-form-item>
        <el-button @click="previous">Back</el-button>
        <el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      saveBtnDisabled: false // Whether the save button is disabled
    }
  },
  created() {
    console.log('chapter created')
  },
  methods: {
    previous() {
      console.log('previous')
      this.$router.push({ path: '/course/info/1' })
    },
    next() {
      console.log('next')
      this.$router.push({ path: '/course/publish/1' })
    }
  }
}
</script>

3.3.3 Course release page

Add the following to the publish.vue file

<template>
  <div class="app-container">
    <h2 style="text-align: center;">Publish a new course</h2>
    <el-steps :active="3" process-status="wait" align-center style="margin-bottom: 40px;">
      <el-step title="Fill in basic course information"/>
      <el-step title="Create Course Outline"/>
      <el-step title="Final Release"/>
    </el-steps>
    <el-form label-width="120px">
      <el-form-item>
        <el-button @click="previous">Back to modify</el-button>
        <el-button :disabled="saveBtnDisabled" type="primary" @click="publish">Publish course</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      saveBtnDisabled: false // Whether the save button is disabled
    }
  },
  created() {
    console.log('publish created')
  },
  methods: {
    previous() {
      console.log('previous')
      this.$router.push({ path: '/course/chapter/1' })
    },
    publish() {
      console.log('publish')
      this.$router.push({ path: '/course/list' })
    }
  }
}
</script>

3.4 Add course page implementation

3.4.1 Define APIs

Create a course.js file under src/api/edu and add the following content

import request from '@/utils/request'

export default {
  addCourseInfo(courseInfo) {
    return request({
      url: `/eduservice/course/addCourseInfo`,
      method: 'post',
      data: courseInfo
    })
  }

3.4.2 Component Templates

Add the following page information in edu/course/info.vue:

<el-form label-width="120px">

  <el-form-item label="Course Title">
    <el-input v-model="courseInfo.title" placeholder="Example: Machine Learning Project Course: From Basics to Project Construction Video Course. Pay attention to capitalization of professional names"/>
  </el-form-item>

  <!-- Category TODO -->

  <!-- Course Instructor TODO -->

  <el-form-item label="Total Class Hours">
    <el-input-number :min="0" v-model="courseInfo.lessonNum" controls-position="right" placeholder="Please fill in the total class hours of the course"/>
  </el-form-item>

  <!-- Course Introduction TODO -->
 <el-form-item label="Course Introduction">
    <el-input v-model="courseInfo.description" placeholder="fill in course description information"/>
  </el-form-item>

  <!-- course cover TODO -->

  <el-form-item label="Course Price">
    <el-input-number :min="0" v-model="courseInfo.price" controls-position="right" placeholder="Please set it to 0 yuan for free courses"/>
  </el-form-item>

  <el-form-item>
    <el-button :disabled="saveBtnDisabled" type="primary" @click="next">Save and next</el-button>
  </el-form-item>
</el-form>

3.4.3 Add js

<script>
import course from '@/api/edu/course.js'
export default {
  data() {
    return {
      saveBtnDisabled: false , // Whether the save button is disabled
      courseInfo:{
            title: '',
            subjectId: '',
            teacherId: '',
            lessonNum: 0,
            description: '',
            cover: '',
            price: 0
      }
    }
  },

  created() {
    console.log('info created')
  },

  methods: {

    saveOrUpdate() {
      console.log('next')
      course.addCourseInfo(this.courseInfo).then(response =>{
         this.$message({
          type: 'success',
          message: 'Save successfully!'
        })
          this.$router.push({ path: '/course/chapter/1' })
      })
      
    }
  }
}
</script>

3.4.4 After adding, return the course id

After adding course information, the id of the course is still needed when adding sections later, so we need to modify it as follows:

Modify EduCourseController

In the addCourseInfo method in EduCourseController, add the return value

@PostMapping("/addCourseInfo")
public R addCourseInfo(@RequestBody CourseInfoFormVo courseInfoFormVo) {

    String courseId = eduCourseService.saveCourseInfo(courseInfoFormVo);

    return R.ok().data("courseId",courseId);
}

Modify EduCourseService

Add return value String

public interface EduCourseService extends IService<EduCourse> {

    String saveCourseInfo(CourseInfoFormVo courseInfoFormVo);
}

// Add course information
@Override
public String saveCourseInfo(CourseInfoFormVo courseInfoFormVo) {

    // Add basic course information to the curriculum
    EduCourse eduCourse = new EduCourse();
    BeanUtils.copyProperties(courseInfoFormVo, eduCourse);
    int insert = this.baseMapper.insert(eduCourse);

    // Determine whether adding basic course information is successful
    if (insert==0) {
        throw new EduException(20001, "Failed to add course basic information!");

    }

    // Get the id after adding the course
    String cid = eduCourse.getId();

    // Add a course profile to the course profile table
    EduCourseDescription eduCourseDescription = new EduCourseDescription();
    eduCourseDescription.setId(cid);
    eduCourseDescription.setDescription(courseInfoFormVo.getDescription());
    eduCourseDescriptionService.save(eduCourseDescription);

    return cid;
}

modified info.vue

Modify the saveOrUpdate method in edu/course/info.vue

saveOrUpdate() {
      console.log('next')
      course.addCourseInfo(this.courseInfo).then(response =>{
         this.$message({
          type: 'success',
          message: 'Save successfully!'
        })
          this.$router.push({ path: '/course/chapter/'+response.data.courseId })
      })
      
    }

 

3.5 Lecturer drop-down list

3.5.1 Component Templates

Add the following code to views/edu/course/info.vue

<!-- Course Instructor -->
<el-form-item label="Course Instructor">
  <el-select
    v-model="courseInfo.teacherId"
    placeholder="Please select">
    <el-option
      v-for="teacher in teacherList"
      :key="teacher.id"
      :label="teacher.name"
      :value="teacher.id"/>
  </el-select>
</el-form-item>

3.5.2 Define the interface for obtaining the lecturer list

Just call the findAll interface in EduTeacherController directly. We've all written about it before.

 

3.5.3 Define APIs

Define query for all lecturers in api/edu/course.js

getListTeacher() {
    return request({
        url: `/eduservice/edu-teacher/findAll`,
        method: 'get'
    })
},

3.5.4 Component scripts

Define data, do not define it in courseInfo

teacherList: [] // list of teachers

Get the list of lecturers when the form is initialized

created() {
    console.log('info created')
    // Initialize the lecturer list
    this.getListTeacher()
},
    methods: {
        // query all lecturers
        getListTeacher(){
            course.getListTeacher().then(response =>{
                this.teacherList = response.data.items
            })
        },

    }

3.5.5 Effect display

3.6 Realization of multi-level linkage of course classification

need

 

 

3.6.1 Obtain the primary classification

Component Data Definition

Define the first-level classification and second-level classification collection in the data of views/edu/course/info.vue. Finally, add subjectParentId in courseInfo

subjectOneList: [],//List of first class categories
subjectTwoList: []//Secondary classification list

 

component template

Define the first-level classification drop-down box in course/info.vue

<!-- Level 1 classification-->
<el-form-item label="Course Category">
    <el-select
               v-model="courseInfo.subjectParentId"
               placeholder="Please select">
        <el-option
                   v-for="subject in subjectOneList"
                   :key="subject.id"
                   :label="subject.title"
                   :value="subject.id"/>
    </el-select>
</el-form-item>

component script

Introduce subject.js in course/info.vue

import subject from '@/api/edu/subject.js'

 

Define the method to query all first-level classifications

created() {
    console.log('info created')
    // Initialize the lecturer list
    this.getListTeacher()
    // Initialize the first-level classification list
    this.getOneSubjectList()
},

    methods: {
        // Query all first-level categories
        getOneSubjectList(){
            subject.getSubjectList().then(response =>{
                this.subjectOneList = response.data.list
            })
        },
    }

3.6.2 Cascade display of secondary categories

component template

<!-- Secondary classification -->
<el-select v-model="courseInfo.subjectId" placeholder="secondary classification">
  <el-option
    v-for="subject in subjectTwoList"
    :key="subject.id"
    :label="subject.title"
    :value="subject.id"/>
</el-select>

Register change event

Register the change event in the <el-select> component of the first-level classification

 <el-select @change="subjectLevelOneChanged" ......

Define the change event method

subjectLevelOneChanged(value) {
    console.log(value);
    // Traverse all categories, including primary and secondary categories
    for (let i = 0; i < this.subjectOneList.length; i++) {
        if (this.subjectOneList[i].id === value) {
            this.subjectTwoList = this.subjectOneList[i].children;
            // Clear the secondary category
            this.courseInfo.subjectId = "";
        }
    }
},

3.7 Course Cover

3.7.1 Integrated upload component

Refer to http://element-cn.eleme.io/#/zh-CN/component/upload User Avatar Upload

3.7.2 Upload default cover

Create a folder cover and upload the default course cover

 

3.7.3 Define data data

BASE_API: process.env.BASE_API // interface API address

3.7.4 Component Templates

Add upload component template in info.vue

<!-- Course cover -->
<el-form-item label="Course Cover">

  <el-upload
    :show-file-list="false"
    :on-success="handleAvatarSuccess"
    :before-upload="beforeAvatarUpload"
    :action="BASE_API+'/eduoss/file/upload'"
    class="avatar-uploader">
     <img :src="courseInfo.cover" width="250px" height="150px" />
  </el-upload>

</el-form-item>

3.7.5 Define default cover page

cover: "https://zjledu.oss-cn-beijing.aliyuncs.com/cover/%E9%BB%98%E8%AE%A4%E8%AF%BE%E7%A8%8B%E5%B0%81%E9%9D%A2.jpg",

3.7.6 Result callback

handleAvatarSuccess(res, file) {
  console.log(res)// upload response
  console.log(URL.createObjectURL(file.raw))// base64编码
  this.courseInfo.cover = res.data.url
},

beforeAvatarUpload(file) {
  const isJPG = file.type === 'image/jpeg'
  const isLt2M = file.size / 1024 / 1024 < 2

  if (!isJPG) {
    this.$message.error('The uploaded avatar picture can only be in JPG format!')
  }
  if (!isLt2M) {
    this.$message.error('The size of the uploaded avatar picture cannot exceed 2MB!')
  }
  return isJPG && isLt2M
}

3.7.8 Comprehensive test

 

4. Rich text editor Tinymce

On the course basic information adding page, integrate a rich text editor

4.1 Component initialization

Tinymce is a traditional javascript plugin, it cannot be used for Vue.js by default, so some special integration steps are required

4.1.1 Copy script library

Copy the components/Tinymce in the data to the components directory in the front-end project

 

Get the \static\tinymce4.7.5 in the data to the static directory

 

4.1.2 Configure html variables

Add configuration in /build/webpack.dev.conf.js to use the BASE_URL variable defined here in the html page

 

new HtmlWebpackPlugin({
    ......
    templateParameters: {
        BASE_URL: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
    }
})

Note: After the configuration is complete, it is best to restart the front-end server

4.1.3 Import js script

Introduce js script in /index.html

<script src=<%= BASE_URL %>/tinymce4.7.5/tinymce.min.js></script>
<script src=<%= BASE_URL %>/tinymce4.7.5/langs/zh_CN.js></script>

 

4.2 Using a text editor

In order to allow Tinymce to be used in Vue.js projects, vue-element-admin-master encapsulates Tinymce, and we will introduce it to our course information page below

4.2.1 Importing components

Introduce Tinymce in course information info.vue

import Tinymce from '@/components/Tinymce'

export default {
  components: { Tinymce },
  ......
}

 

4.2.2 Reference component template

<!-- Course Introduction-->
<el-form-item label="Course Introduction">
    <tinymce :height="300" v-model="courseInfo.description"/>
</el-form-item>

4.2.3 Component styles

Add the following code at the end of the info.vue file to adjust the height of the upload image button

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

4.2.5 base64 encoding of pictures

The image upload function in Tinymce directly stores the base64 encoding of the image, so there is no need for an image server

4.2.6 Testing

There will be no data when the test will add the secondary classification of the course. It is because, in CourseInfoFormVo, there is no subjectParentId field. Just add this field in the CourseInfoFormVo class.

@ApiModelProperty(value = "Level 1 classification ID")
private String subjectParentId;

Guess you like

Origin blog.csdn.net/whirlwind526/article/details/129375742