第五天课程计划管理

一、课程管理

1.1 需求分析

在线教育平台的课程信息相当于电商平台的商品。课程管理是后台管理功能中最重要的模块。本项目为教学机构提供课程管理功能,教学机构可以添加属于自己的课程,供学生在线学习。

课程管理包括如下功能需求:

1、分类管理

2、新增课程

3、修改课程

4、预览课程

5、发布课程

1.2 环境搭建

1.2.1 前端工程

与系统管理类似,直接复制导入

1.2.2 后端工程

持久层技术介绍:

课程管理服务使用MySQL数据库存储课程信息,持久层技术如下:

1、spring data jpa:用于表的基本CRUD。

2、mybatis:用于复杂的查询操作。

3、druid:使用阿里巴巴提供的spring boot 整合druid包druid-spring-boot-starter管理连接池。

二、课程计划

一个树状列表:

涉及到的功能:添加课程计划、删除课程计划、修改课程计划

2.1 课程计划查询

2.1.1 需求分析

课程计划查询是将某个课程的课程计划内容完整的显示出来,如下图所示:

左侧显示的就是课程计划,课程计划是一个树型结构,方便扩展课程计划的级别。

点击“添加课程计划”即可对课程计划进行添加操作。

点击修改可对某个章节内容进行修改。

点击删除可删除某个章节。

2.1.2 页面原型

本功能使用element-ui 的tree组件来完成

在course_plan.vue文件中添加tree组件的代码,进行测试:

1、组件标签

<el-tree
  :data="teachplanList"
  :props="defaultProps"
  node-key="id"
  default-expand-all
  :expand-on-click-node="false"
  :render-content="renderContent">
</el-tree>

2、数据对象

teachplanList : [{
  id: 1,
  pname: '一级 1',
  children: [{
    id: 4,
    pname: '二级 1-1',
    children: [{
      id: 9,
      pname: '三级 1-1-1'
    }, {
      id: 10,
      pname: '三级 1-1-2'
    }]
  }]
}],

3、renderContent

本组件用到了JSX语法,如下所示:

renderContent(h, { node, data, store }) {
  return (
    <span style="flex: 1; display: flex; align-items: center; justify-content: space-between; font-size: 14px; padding-right: 8px;">
      <span>
        <span>{node.label}</span>
      </span>
      <span>
        <el-button style="font-size: 12px;" type="text" on-click={ () => this.choosevideo(data) }>{data.mediaFileOriginalName}&nbsp;&nbsp;&nbsp;&nbsp; 选择视频</el-button>
        <el-button style="font-size: 12px;" type="text" on-click={ () => this.edit(data) }>修改</el-button>
        <el-button style="font-size: 12px;" type="text" on-click={ () => this.remove(node, data) }>删除</el-button>
      </span>
    </span>);
}

JSX 是Javascript和XML结合的一种格式,它是React的核心组成部分,JSX和XML语法类似,可以定义属性以及子元素。唯一特殊的是可以用大括号来加入JavaScript表达式。遇到 HTML 标签(以 < 开头),就遇到代码块(以 { 开头),就用 JavaScript 规则解析。

2.1.3 API接口

2.1.3.1 数据模型

1、表结构

2、pojo类

课程计划为树型结构,由树根(课程)和树枝(章节)组成,为了保证系统的可扩展性,在系统设计时将课程计划设置为树型结构。

package com.xuecheng.framework.domain.course;

import lombok.Data;
import lombok.ToString;
import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;
import java.io.Serializable;


/**
 * @author 98050
 */
@Data
@ToString
@Entity
@Table(name="teachplan")
@GenericGenerator(name = "jpa-uuid", strategy = "uuid")
public class Teachplan implements Serializable {
    private static final long serialVersionUID = -916357110051689485L;
    @Id
    @GeneratedValue(generator = "jpa-uuid")
    @Column(length = 32)
    private String id;
    private String pname;
    private String parentid;
    private String grade;
    private String ptype;
    private String description;
    private String courseid;
    private String status;
    private Integer orderby;
    private Double timelength;
    private String trylearn;

}
2.1.3.2 自定义Tree组件数据

前端页面需要树型结构的数据来展示Tree组件,如下:

{
  id: 1,
  pname: '一级 1',
  children: [{
    id: 4,
    pname: '二级 1-1',
    children: [{
      id: 9,
      pname: '三级 1-1-1'
    }, {
      id: 10,
      pname: '三级 1-1-2'
    }]
  }]
}

所以需要自定义数据类型:

package com.xuecheng.framework.domain.course.ext;

import com.xuecheng.framework.domain.course.Teachplan;
import lombok.Data;
import lombok.ToString;

import java.util.List;


/**
 * @author 98050
 */
@Data
@ToString
public class TeachplanNode extends Teachplan {

    List<TeachplanNode> children;

}
2.1.3.3 接口定义

根据课程id查询课程的计划接口如下,在api工程创建course包,创建CourseControllerApi接口类并定义接口方法如下:

package com.xuecheng.api.course;

import com.xuecheng.framework.domain.course.ext.TeachplanNode;
import io.swagger.annotations.*;

/**
 * @Author: 98050
 * @Time: 2019-04-03 19:59
 * @Feature:
 */
@Api(value = "课程管理接口",description = "课程管理接口")
public interface CourseControllerApi {
    @ApiOperation("课程计划查询")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id",value = "课程Id",required = true,paramType = "path",dataType = "String")
    })
    @ApiResponses({
            @ApiResponse(code = 10000,message = "操作成功"),
            @ApiResponse(code = 11111,message = "操作失败")
    })
    TeachplanNode findTeachplanList(String courseId);
}

2.1.4 课程管理服务

2.1.4.1 sql

课程计划是树型结构,采用表的自连接方式进行查询,sql语句如下:

SELECT  
a.id one_id,
a.pname one_name,
b.id two_id,
b.pname two_name,
c.id three_id,
c.pname three_name
FROM teachplan a LEFT JOIN teachplan b ON a.id = b.parentid LEFT JOIN teachplan c ON b.id = c.parentid
WHERE a.parentid = '0' AND a.courseid = '4028e581617f945f01617f9dabc40000';
ORDER BY a.orderby,b.orderby,c.orderby

结果:

2.1.4.2 Mapper

1、Mapper接口

package com.xuecheng.managecourse.dao;

import com.xuecheng.framework.domain.course.ext.TeachplanNode;
import org.apache.ibatis.annotations.Mapper;


/**
 * @Author: 98050
 * @Time: 2019-04-03 22:58
 * @Feature:
 */
@Mapper
public interface TeachPlanMapper {

    /**
     * 树形查询所有节点
     * @param courseId
     * @return
     */
    TeachplanNode selectList(String courseId);
}

2、Mapper映射文件

TeachPlanMapper.xml

方法一:采用连接查询

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xuecheng.managecourse.dao.TeachPlanMapper">
    
    <resultMap id="teachPlanMap" type="com.xuecheng.framework.domain.course.ext.TeachplanNode">
        <id property="id" column="one_id"></id>
        <result property="pname" column="one_name"></result>
        <collection property="children" ofType="com.xuecheng.framework.domain.course.ext.TeachplanNode">
            <id property="id" column="two_id"></id>
            <result property="pname" column="two_name"></result>
            <collection property="children" ofType="com.xuecheng.framework.domain.course.ext.TeachplanNode">
                <id property="id" column="three_id"></id>
                <result property="pname" column="three_name"></result>
            </collection>
        </collection>
    </resultMap>
    
    <select id="selectList" parameterType="java.lang.String"
            resultMap="teachPlanMap">
        SELECT
        a.id one_id,
        a.pname one_name,
        b.id two_id,
        b.pname two_name,
        c.id three_id,
        c.pname three_name
        FROM teachplan a LEFT JOIN teachplan b ON a.id = b.parentid LEFT JOIN teachplan c ON b.id = c.parentid
        WHERE a.parentid = '0'
        <if test="_parameter != null and _parameter !=''">
            AND a.courseid = #{courseId}
        </if>
        ORDER BY a.orderby,b.orderby,c.orderby
    </select>
</mapper>

方法二:递归查询

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xuecheng.managecourse.dao.TeachPlanMapper">
    
    <resultMap id="BaseTreeResultMap" type="com.xuecheng.framework.domain.course.ext.TeachplanNode">
        <id property="id" column="id"></id>
        <result property="pname" column="pname"></result>
        <collection column="id" property="children" select="getNextNodeTree" ofType="com.xuecheng.framework.domain.course.ext.TeachplanNode">

        </collection>
    </resultMap>

    <resultMap id="NextTreeResultMap" type="com.xuecheng.framework.domain.course.ext.TeachplanNode">
        <id property="id" column="id"></id>
        <result property="pname" column="pname"></result>
        <collection column="id" property="children" select="getNextNodeTree" ofType="com.xuecheng.framework.domain.course.ext.TeachplanNode">

        </collection>
    </resultMap>

    <select id="getNextNodeTree" resultMap="NextTreeResultMap">
        SELECT
        <include refid="Base_Column_List"></include>
        FROM teachplan
        WHERE parentid = #{id}
        ORDER BY orderby
    </select>

    <select id="selectList" parameterType="java.lang.String" resultMap="BaseTreeResultMap">
        SELECT
        <include refid="Base_Column_List"></include>
        FROM teachplan
        WHERE parentid = '0'
        <if test="_parameter != null and _parameter !=''">
            AND courseid = #{courseId}
        </if>
        ORDER BY orderby
    </select>

    <sql id="Base_Column_List">
        id,pname
    </sql>
</mapper>

通过 collection 节点继续调用 getNextNodeTree 方法进行循环调用,collection中的column代表会拿父结点id。

注意:

连接查询:连接表的数量有限

递归查询:嵌套 SQL 执行,这里就存在一个性能上的问题。比如 10 万条数据,需要执行 10 万次 SELECT 语句。所以不推荐数据量级大的树形结构。

2.1.4.3 Service

接口:

package com.xuecheng.managecourse.service;

import com.xuecheng.framework.domain.course.ext.TeachplanNode;

/**
 * @Author: 98050
 * @Time: 2019-04-03 22:57
 * @Feature:
 */
public interface CourseService {

    /**
     * 查询课程计划
     * @param courseId
     * @return
     */
    TeachplanNode findTeachplanList(String courseId);
}

实现:

package com.xuecheng.managecourse.service.impl;

import com.xuecheng.framework.domain.course.ext.TeachplanNode;
import com.xuecheng.managecourse.dao.TeachPlanMapper;
import com.xuecheng.managecourse.service.CourseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Author: 98050
 * @Time: 2019-04-03 22:57
 * @Feature:
 */
@Service
public class CourseServiceImpl implements CourseService {

    @Autowired
    public TeachPlanMapper teachPlanMapper;

    @Override
    public TeachplanNode findTeachplanList(String courseId) {
        return teachPlanMapper.selectList(courseId);
    }
}
2.1.4.4 Controller
package com.xuecheng.managecourse.controller;

import com.xuecheng.api.course.CourseControllerApi;
import com.xuecheng.framework.domain.course.ext.TeachplanNode;
import com.xuecheng.managecourse.service.CourseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: 98050
 * @Time: 2019-04-03 22:53
 * @Feature:
 */
@RestController
@RequestMapping("/course")
public class CourseController implements CourseControllerApi {

    @Autowired
    private CourseService courseService;

    @Override
    @GetMapping("/teachplan/list/{courseId}")
    public TeachplanNode findTeachplanList(@PathVariable("courseId") String courseId) {
        return courseService.findTeachplanList(courseId);
    }
}
2.1.4.5 测试

请求:http://localhost:31200/course/teachplan/list/4028e581617f945f01617f9dabc40000

2.1.5 前端页面

2.1.5.1 API方法
// 查询课程计划
export const findTeachplanList = courseid => {
  return http.requestQuickGet(apiUrl + '/course/teachplan/list/' + courseid)
}
2.1.5.2 API调用

1、在mounted钩子方法 中查询 课程计划

定义查询课程计划的方法,赋值给数据对象teachplanList

findTeachplan(){
  this.teachplanList = []
  //查询课程计划
  courseApi.findTeachplanList(this.courseid).then(res=>{
      if(res && res.children) {
        this.teachplanList = res.children;
      }
  })
}

2、在mounted钩子中查询课程计划

mounted(){
  //课程id(通过路由获取)
  this.courseid = this.$route.params.courseid;
  //查询课程计划
  this.findTeachplan()
}

3、修改树节点的标签属性

课程计划信息中pname为节点的名称,需要修改树节点的标签属性方可正常显示课程计划名称,如下:

defaultProps:{
  children: 'children',
  label: 'pname'
}
2.1.5.3 测试

修改course_list.vue中课程静态数据:

courses: [
  {
    id:'4028e581617f945f01617f9dabc40000',
    name:'test01',
    pic:''
  },
  {
    id:'test02',
    name:'test02',
    pic:''
  }
]

测试结果:

2.2 添加课程计划

2.2.1 需求分析

用户操作流程:

1、进入课程计划页面,点击“添加课程计划”

2、打开添加课程计划页面,输入课程计划信息

上级节点说明:

不选择上级节点表示当前课程计划为该课程的一级节点

当添加该课程在课程计划中还没有节点时要自动添加课程的根节点

3、点击提交

2.2.2 页面原型

添加课程计划采用弹出窗口组件Dialog。

1、视图部分

course_plan.vue页面添加课程计划的弹出窗口代码:

<el-dialog title="添加课程计划" :visible.sync="teachplayFormVisible" >
  <el-form ref="teachplanForm" label-position="left"  :model="teachplanActive" label-width="140px" style="width:600px;" :rules="teachplanRules" >
    <el-form-item label="上级结点" >
      <el-select v-model="teachplanActive.parentid" placeholder="不填表示根结点">
        <el-option
          v-for="item in teachplanList"
          :key="item.id"
          :label="item.pname"
          :value="item.id">
        </el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="章节/课时名称" prop="pname">
      <el-input v-model="teachplanActive.pname" auto-complete="off"></el-input>
    </el-form-item>
    <el-form-item label="课程类型" >
      <el-radio-group v-model="teachplanActive.ptype">
        <el-radio class="radio" label='1'>视频</el-radio>
        <el-radio class="radio" label='2'>文档</el-radio>
      </el-radio-group>
    </el-form-item>
    <el-form-item label="学习时长(分钟)  请输入数字" >
      <el-input type="number" v-model="teachplanActive.timelength" auto-complete="off" ></el-input>
    </el-form-item>
    <el-form-item label="排序字段" >
      <el-input v-model="teachplanActive.orderby" auto-complete="off" ></el-input>
    </el-form-item>
    <el-form-item label="章节/课时介绍" prop="description">
      <el-input type="textarea" v-model="teachplanActive.description" ></el-input>
    </el-form-item>

    <el-form-item label="状态" prop="status">
      <el-radio-group v-model="teachplanActive.status" >
        <el-radio class="radio" label="0" >未发布</el-radio>
        <el-radio class="radio" label='1'>已发布</el-radio>
      </el-radio-group>
    </el-form-item>
    <el-form-item  >
      <el-button type="primary" v-on:click="addTeachplan">提交</el-button>
      <el-button type="primary" v-on:click="resetForm">重置</el-button>
    </el-form-item>

  </el-form>
</el-dialog>

2、数据原型

在数据模型中添加如下变量:

//控制添加窗口是否显示
teachplayFormVisible:false,
// 校验规则
teachplanRules: {
  pname: [
    {required: true, message: '请输入课程计划名称', trigger: 'blur'}
  ],
  status: [
    {required: true, message: '请选择状态', trigger: 'blur'}
  ]
},
// 数据
teachplanActive:{},

3、添加按钮

通过变量teachplayFormVisible控制弹出窗口是否显示。

<el-button type="primary" @click="teachplayFormVisible = true">添加课程计划</el-button>

4、定义表单提交方法和重置方法

//重置表单
resetForm(){
  this.teachplanActive = {}
}
//提交课程计划
addTeachplan(){
  
}

2.2.3 API接口

添加课程计划

/**
 * 课程计划添加
 * @param teachplan
 * @return
 */
@ApiOperation("课程计划添加")
@ApiResponses({
        @ApiResponse(code = 10000,message = "操作成功"),
        @ApiResponse(code = 11111,message = "操作失败")
})
TeachPlanResult add(Teachplan teachplan);

xc-framework-modelcom.xuecheng.framework.domain.course.response包下定义TeachPlanResult

package com.xuecheng.framework.domain.course.response;

import com.xuecheng.framework.domain.course.Teachplan;
import com.xuecheng.framework.model.response.ResponseResult;
import com.xuecheng.framework.model.response.ResultCode;

/**
 * @Author: 98050
 * @Time: 2019-04-04 21:38
 * @Feature:
 */
public class TeachPlanResult extends ResponseResult {

    Teachplan teachplan;
    public TeachPlanResult(ResultCode resultCode,Teachplan teachplan){
        super(resultCode);
        this.teachplan = teachplan;
    }
}

2.2.4 Service

课程计划添加流程分析:

1、判断传入后台的Teachplan对象的parentid字段是否为空,如果为空的话,那么就需要根据课程id获取课程计划的根节点,如果无法获取,说明是第一次为该课程添加课程计划,那么就创建课程计划的一级节点,并且返回id。

2、设置parentid字段

3、设置当前课程计划的级别

4、插入数据库

注意:

在新增课程计划的过程中,涉及到多个对象的持久化,所以要进行事务管理,使用@Transactional注解。

接口:

/**
 * 课程计划添加
 * @param teachplan
 * @return
 */
TeachPlanResult add(Teachplan teachplan);

实现:

package com.xuecheng.managecourse.service.impl;

import com.xuecheng.framework.domain.course.CourseBase;
import com.xuecheng.framework.domain.course.Teachplan;
import com.xuecheng.framework.domain.course.ext.TeachplanNode;
import com.xuecheng.framework.domain.course.response.CourseCode;
import com.xuecheng.framework.domain.course.response.TeachPlanResult;
import com.xuecheng.framework.exception.ExceptionCast;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.managecourse.dao.CourseBaseRepository;
import com.xuecheng.managecourse.dao.TeachPlanMapper;
import com.xuecheng.managecourse.dao.TeachPlanRepository;
import com.xuecheng.managecourse.service.CourseService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.List;
import java.util.Optional;

/**
 * @Author: 98050
 * @Time: 2019-04-03 22:57
 * @Feature:
 */
@Service
public class CourseServiceImpl implements CourseService {

    private final TeachPlanMapper teachPlanMapper;

    private final CourseBaseRepository courseBaseRepository;

    private final TeachPlanRepository teachPlanRepository;
    
    @Autowired
    public CourseServiceImpl(TeachPlanMapper teachPlanMapper, CourseBaseRepository courseBaseRepository, TeachPlanRepository teachPlanRepository) {
        this.teachPlanMapper = teachPlanMapper;
        this.courseBaseRepository = courseBaseRepository;
        this.teachPlanRepository = teachPlanRepository;
    }

    /**
     * 课程计划查询
     * @param courseId
     * @return
     */
    @Override
    public TeachplanNode findTeachplanList(String courseId) {
        return teachPlanMapper.selectList(courseId);
    }

    /**
     * 课程计划添加
     * 说明:如果当前teachplan对象中parentId为空,说明这是一个二级节点,那么parentId应该为根节点,也就是一级节点
     * @param teachplan
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public TeachPlanResult add(Teachplan teachplan) {
        //1.校验参数对象
        if (teachplan == null) {
            ExceptionCast.cast(CourseCode.COURSE_PLAN_ADD_PARAMETERISNULL);
        }
        //2.取出课程id
        String courseId = teachplan.getCourseid();
        if (StringUtils.isEmpty(courseId)) {
            ExceptionCast.cast(CourseCode.COURSE_PLAN_ADD_COURSEIDISNULL);
        }
        //3.根据课程id和课程计划名称进行校验
        List<Teachplan> list = this.teachPlanRepository.findByCourseidAndPname(courseId, teachplan.getPname());
        if (list.size() != 0){
            ExceptionCast.cast(CourseCode.COURSE_PLAN_ADD_PLANNAMEISEXISTS);
        }
        //4.取出父节点id
        String parentId = teachplan.getParentid();
        if (StringUtils.isEmpty(parentId)) {
            parentId = getTeachPlanRoot(courseId);
        }
        //5.获取父节点信息
        Optional<Teachplan> optional = this.teachPlanRepository.findById(parentId);
        if (!optional.isPresent()) {
            ExceptionCast.cast(CourseCode.COURSE_PLAN_ADD_PARENTNODEISNULL);
        }
        Teachplan parentNode = optional.get();
        //6.设置父节点
        teachplan.setParentid(parentId);
        //7.未发布
        teachplan.setStatus("0");
        //8.设置子节点的级别,根据父节点来判断
        String level1 = "1";
        String level2 = "2";
        String level3 = "3";
        if (level1.equals(parentNode.getGrade())) {
            teachplan.setGrade(level2);
        } else if (level2.equals(parentNode.getGrade())) {
            teachplan.setGrade(level3);
        }
        //9.设置课程id
        teachplan.setCourseid(parentNode.getCourseid());
        //10.保存
        Teachplan save = this.teachPlanRepository.save(teachplan);
        return new TeachPlanResult(CommonCode.SUCCESS, save);
    }

    /**
     * 根据课程id获取一级节点
     * 如果没有找到,说明是第一次添加课程计划,需要构造根节点
     * @param courseId
     * @return
     */
    private String getTeachPlanRoot(String courseId) {
        //1.校验课程
        Optional<CourseBase> optional = this.courseBaseRepository.findById(courseId);
        if (!optional.isPresent()){
            ExceptionCast.cast(CourseCode.COURSE_PLAN_ADD_COURSEISNULL);
        }
        CourseBase courseBase = optional.get();
        //2.获取课程计划根节点
        List<Teachplan> teachplanList = this.teachPlanRepository.findByCourseidAndParentid(courseId, "0");
        if (teachplanList == null || teachplanList.size() == 0){
            //3.新增根节点
            Teachplan teachplanRoot = new Teachplan();
            teachplanRoot.setCourseid(courseId);
            teachplanRoot.setPname(courseBase.getName());
            teachplanRoot.setParentid("0");
            //层级:一级
            teachplanRoot.setGrade("1");
            //未发布
            teachplanRoot.setStatus("0");
            Teachplan save = teachPlanRepository.save(teachplanRoot);
            return save.getId();
        }
        Teachplan teachplan = teachplanList.get(0);
        return teachplan.getId();
    }
}

2.2.5 DAO

根据课程id和父节点id查询根节点

根据课程id和pname查询

package com.xuecheng.managecourse.dao;

import com.xuecheng.framework.domain.course.Teachplan;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/**
 * @Author: 98050
 * @Time: 2019-04-04 22:31
 * @Feature:
 */
public interface TeachPlanRepository extends JpaRepository<Teachplan,String> {
    /**
     * 根据课程id查询课程计划的根节点
     * @param courseId
     * @param parentId
     * @return
     */
    List<Teachplan> findByCourseidAndParentid(String courseId, String parentId);

    /**
     * 根据课程id和pname进行查询
     * @param courseId
     * @param panme
     * @return
     */
    List<Teachplan> findByCourseidAndPname(String courseId,String panme);
}

2.2.6 Controller

@Override
@PostMapping("/teachplan/add")
public TeachPlanResult add(@RequestBody Teachplan teachplan) {
    return this.courseService.add(teachplan);
}

2.2.7 测试

使用接口文档进行测试

2.2.8 前端

2.2.8.1 API调用

1、定义api方法

// 添加课程计划
export const addTeachplan = teachplah => {
  return http.requestPost(apiUrl + '/course/teachplan/add', teachplah)
}

2、调用api

	addTeachplan(){
        //校验表单
        this.$refs.teachplanForm.validate((valid) => {
            if (valid) {
                //调用api方法
              //将课程id设置到teachplanActive
              this.teachplanActive.courseid = this.courseid
              courseApi.addTeachplan(this.teachplanActive).then(res=>{
                if(res.success){
                    this.$message.success("添加成功")
                    //刷新树
                    this.findTeachplan()
                    // 重置表单
                    this.resetForm()
                    // 关闭表单
                    this.teachplayFormVisible = false;
                }else if (res.message) {
                  this.$message.error(res.message)
                }else {
                  this.$message.error("添加失败")
                }

              })
              console.log(this.teachplanActive)
            }
        })
      },
2.2.8.2 测试

结果:

2.3 课程计划修改

2.4 课程计划删除

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值