谷粒学苑 —— 9、课程管理:课程列表

目录

1、课程列表

1.1、后端

1.1.1、定义列表查询的 VO

1.1.2、条件分页查询课程信息

1.2、前端

1.2.1、定义 API

1.2.2、列表及表单

1.2.3、组件 JS

2、课程删除

2.1、后端

2.1.1、根据课程 ID 删除小节信息

2.1.2、根据课程 ID 删除章节信息

2.1.3、根据课程 ID 删除课程所有信息

2.2、前端

2.2.1、定义 API

2.2.2、删除按钮绑定事件

2.2.3、删除方法

3、完整页面


1、课程列表

1.1、后端

1.1.1、定义列表查询的 VO

@ApiModel(value = "Course查询对象", description = "课程查询对象封装")
@Data
public class CourseQuery {

    @ApiModelProperty(value = "课程名称")
    private String title;

    @ApiModelProperty(value = "讲师id")
    private String teacherId;

    @ApiModelProperty(value = "一级类别id")
    private String subjectParentId;

    @ApiModelProperty(value = "二级类别id")
    private String subjectId;

    @ApiModelProperty(value = "课程状态 Draft未发布  Normal已发布")
    private String status;

}

1.1.2、条件分页查询课程信息

EduCourseController

    /**
     * 条件分页查询课程列表
     * @param page 页码
     * @param limit 每页记录数
     * @param courseQuery 条件查询对象
     * @return
     */
    @ApiOperation("条件分页查询课程列表")
    @GetMapping("/list/{page}/{limit}")
    public R getCourseList(
            @ApiParam(name = "page", value = "当前页码", required = true) @PathVariable Long page,
            @ApiParam(name = "limit", value = "每页记录数", required = true) @PathVariable Long limit,
            @ApiParam(name = "courseQuery", value = "查询对象", required = false) @RequestBody CourseQuery courseQuery
    ) {
        Page<EduCourse> coursePage = new Page<>(page, limit);

        // 封装查询条件
        LambdaQueryWrapper<EduCourse> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(!StringUtils.isEmpty(courseQuery.getTitle()), EduCourse::getTitle, courseQuery.getTitle());
        queryWrapper.eq(!StringUtils.isEmpty(courseQuery.getTeacherId()), EduCourse::getTeacherId, courseQuery.getTeacherId());
        queryWrapper.eq(!StringUtils.isEmpty(courseQuery.getSubjectParentId()), EduCourse::getSubjectParentId, courseQuery.getSubjectParentId());
        queryWrapper.eq(!StringUtils.isEmpty(courseQuery.getSubjectId()), EduCourse::getSubjectId, courseQuery.getSubjectId());
        queryWrapper.eq(!StringUtils.isEmpty(courseQuery.getStatus()), EduCourse::getStatus, courseQuery.getStatus());

        courseService.page(coursePage, queryWrapper);

        long total = coursePage.getTotal();
        List<EduCourse> records = coursePage.getRecords();
        Map<String, Object> map = new HashMap();
        map.put("total", total);
        map.put("records", records);
        return R.ok().data(map);
    }

1.2、前端

1.2.1、定义 API

src\api\edu\course.js

    /**
     * 条件分页查询课程列表
     * @param {*} page 页码
     * @param {*} limit 每页记录数
     * @param {*} courseQuery 条件查询对象
     * @returns 
     */
    getCoursePage(page,limit,courseQuery) {
        return request({
            url: `/eduservice/course/list/${page}/${limit}`,
            method: 'POST',
            data: courseQuery
        })
    }

1.2.2、列表及表单

src\views\edu\course\list.vue

组件:

<template>
    <div class="app-container">
        <!--查询表单-->
        <el-form :inline="true" class="demo-form-inline">
            <!-- 所属分类:级联下拉列表 -->
            <!-- 一级分类 -->
            <el-form-item label="课程类别">
                <el-select v-model="courseQuery.subjectParentId" placeholder="请选择" @change="subjectLevelOneChanged">
                    <el-option v-for="subject in subjectOneList" :key="subject.id" :label="subject.title"
                        :value="subject.id" />
                </el-select>
                <!-- 二级分类 -->
                <el-select v-model="courseQuery.subjectId" placeholder="请选择">
                    <el-option v-for="subject in subjectTwoList" :key="subject.id" :label="subject.title" :value="subject.id" />
                </el-select>
            </el-form-item>
        
            <!-- 标题 -->
            <el-form-item>
                <el-input v-model="courseQuery.title" placeholder="课程标题" />
            </el-form-item>

            <!-- 讲师 -->
            <el-form-item>
                <el-select v-model="courseQuery.teacherId" placeholder="请选择讲师">
                    <el-option v-for="teacher in teacherList" :key="teacher.id" :label="teacher.name" :value="teacher.id" />
                </el-select>
            </el-form-item>
            
            <!-- 课程状态 -->
            <el-form-item>
                <el-select v-model="courseQuery.status" clearable placeholder="课程状态">
                    <el-option value="Normal" label="已发布" />
                    <el-option value="Draft" label="未发布" />
                </el-select>
            </el-form-item>
        
            <el-button type="primary" icon="el-icon-search" @click="getList()">查询</el-button>
            <el-button type="default" @click="resetData()">清空</el-button>
        </el-form>

        <!-- 表格 -->
        <el-table v-loading="listLoading" :data="list" element-loading-text="数据加载中" border fit highlight-current-row
            row-class-name="myClassList">
        
            <el-table-column label="序号" width="70" align="center">
                <template slot-scope="scope">
                    {{ (page - 1) * limit + scope.$index + 1 }}
                </template>
            </el-table-column>
        
            <el-table-column label="课程信息" width="470" align="center">
                <template slot-scope="scope">
                    <div class="info">
                        <div class="pic">
                            <img :src="scope.row.cover" alt="scope.row.title" width="150px">
                        </div>
                        <div class="title">
                            <a href="">{{ scope.row.title }}</a>
                            <p>{{ scope.row.lessonNum }}课时</p>
                        </div>
                    </div>
        
                </template>
            </el-table-column>
        
            <el-table-column label="创建时间" align="center">
                <template slot-scope="scope">
                    {{ scope.row.gmtCreate.substr(0, 10) }}
                </template>
            </el-table-column>
            <el-table-column label="发布时间" align="center">
                <template slot-scope="scope">
                    {{ scope.row.gmtModified.substr(0, 10) }}
                </template>
            </el-table-column>
            <el-table-column label="价格" width="100" align="center">
                <template slot-scope="scope">
                    {{ Number(scope.row.price) === 0 ? '免费' :
                    '¥' + scope.row.price.toFixed(2) }}
                </template>
            </el-table-column>
            <el-table-column prop="buyCount" label="付费学员" width="100" align="center">
                <template slot-scope="scope">
                    {{ scope.row.buyCount }}人
                </template>
            </el-table-column>
        
            <el-table-column label="操作" width="150" align="center">
                <template slot-scope="scope">
                    <router-link :to="'/edu/course/info/'+scope.row.id">
                        <el-button type="text" size="mini" icon="el-icon-edit">编辑课程信息</el-button>
                    </router-link>
                    <router-link :to="'/edu/course/chapter/'+scope.row.id">
                        <el-button type="text" size="mini" icon="el-icon-edit">编辑课程大纲</el-button>
                    </router-link>
                    <el-button type="text" size="mini" icon="el-icon-delete">删除</el-button>
                </template>
            </el-table-column>
        </el-table>
        
        <!-- 分页 -->
        <el-pagination 
            :current-page="page" 
            :page-size="limit" 
            :total="total" 
            style="padding: 30px 0; text-align: center;"
            layout="total, prev, pager, next, jumper" 
            @current-change="getList" 
        />
    </div>
</template>>

样式:

<style scoped>
.myClassList .info {
    width: 450px;
    overflow: hidden;
}

.myClassList .info .pic {
    width: 150px;
    height: 90px;
    overflow: hidden;
    float: left;
}

.myClassList .info .pic a {
    display: block;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
}

.myClassList .info .pic img {
    display: block;
    width: 100%;
}

.myClassList td .info .title {
    width: 280px;
    float: right;
    height: 90px;
}

.myClassList td .info .title a {
    display: block;
    height: 48px;
    line-height: 24px;
    overflow: hidden;
    color: #00baf2;
    margin-bottom: 12px;
}

.myClassList td .info .title p {
    line-height: 20px;
    margin-top: 5px;
    color: #818181;
}
</style>

1.2.3、组件 JS

src\views\edu\course\list.vue

<script>
    import course from '@/api/edu/course.js'
    import subject from '@/api/edu/subject.js'

    export default {
        data() {
            return {
                listLoading: true,  // 是否显示loading信息
                list: null,         // 数据列表
                total: 0,           // 总记录数
                page: 1,            // 页码
                limit: 3,          // 每页记录数
                courseQuery: {        // 查询条件
                    subjectParentId: '',
                    subjectId: '',
                    title: '',
                    teacherId: '',
                    status: ''
                },
                teacherList: [],    // 讲师列表
                subjectOneList: [],  // 一级分类列表
                subjectTwoList: []  // 二级分类列表
            }
        },
        created() {
            this.getList();
            this.getListTeacher();
            this.getOneSubject();
        },
        methods: {
            /**
             * 获取课程信息
             */
            getList(page = 1) { // 若没有page参数。默认为1
                this.listLoading = true;
                this.page = page;
                course.getCoursePage(this.page,this.limit,this.courseQuery).then(response => {
                    this.list = response.data.records;
                    this.total = response.data.total;
                });
                this.listLoading = false;
            },

            /**
             * 表单清空方法
             */
            resetData() {
                this.courseQuery = {}
                this.getList()
            },

            /**
             * 获取所有讲师信息
             */
            getListTeacher() {
                course.getTeacherList().then(response => {
                    this.teacherList = response.data.items;
                })
            },

            /**
             * 查询所有一级分类(一级分类下含有其包含的二级分类)
             */
            getOneSubject() {
                subject.getSubjectList().then(response => {
                    this.subjectOneList = response.data.list;
                })
            },

            /**
             * 更换选择的一级分类调用的方法,更新二级分类数据
             * @param {*} value 一级分类ID
             */
            subjectLevelOneChanged(value) {
                // 初始化
                this.subjectTwoList = [];
                this.courseQuery.subjectId = '';

                // 遍历所有一级分类,若其ID和value的值相等,将其孩子(二级分类)赋值给subjectTwoList
                for (var i = 0; i < this.subjectOneList.length; i++) {
                    if (value === this.subjectOneList[i].id) {
                        // 二级分类赋值
                        this.subjectTwoList = this.subjectOneList[i].children;
                    }
                }
            },
        }
    }
</script>

2、课程删除

2.1、后端

2.1.1、根据课程 ID 删除小节信息

EduVideoService

    /**
     * 根据课程ID删除小节
     * @param courseId 课程ID
     */
    void removeVideoByCourseId(String courseId);

EduVideoServiceImpl

    /**
     * 根据课程ID删除小节
     * @param courseId 课程ID
     */
    @Override
    public void removeVideoByCourseId(String courseId) {
        LambdaQueryWrapper<EduVideo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EduVideo::getCourseId, courseId);
        this.remove(queryWrapper);
    }

2.1.2、根据课程 ID 删除章节信息

EduChapterService

    /**
     * 根据课程ID删除章节
     * @param courseId 课程ID
     */
    void removeChapterByCourseId(String courseId);

EduChapterServiceImpl

    /**
     * 根据课程ID删除章节
     * @param courseId 课程ID
     */
    @Override
    public void removeChapterByCourseId(String courseId) {
        LambdaQueryWrapper<EduChapter> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EduChapter::getCourseId, courseId);
        this.remove(queryWrapper);
    }

2.1.3、根据课程 ID 删除课程所有信息

EduCourseService

    /**
     * 删除课程
     * @param courseId 课程ID
     */
    void removeCourse(String courseId);

EduCourseServiceImpl

    /**
     * 删除课程
     * @param courseId 课程ID
     */
    @Override
    public void removeCourse(String courseId) {
        // 删除小节
        videoService.removeVideoByCourseId(courseId);

        // 删除章节
        chapterService.removeChapterByCourseId(courseId);

        // 删除描述
        descriptionService.removeById(courseId);

        // 删除课程信息
        this.removeById(courseId);
    }

EduCourseController

    /**
     * 删除课程
     * @param courseId 课程ID
     * @return
     */
    @DeleteMapping("/{courseId}")
    public R deleteCourse(
            @ApiParam(name = "courseId", value = "课程ID", required = true) @PathVariable String courseId
    ) {
        courseService.removeCourse(courseId);
        return R.ok();
    }

2.2、前端

2.2.1、定义 API

src\api\edu\course.js

    /**
     * 删除课程
     * @param {*} courseId 课程ID
     * @returns 
     */
    removeCourseById(courseId) {
        return request({
            url: `/eduservice/course/${courseId}`,
            method: 'DELETE'
        })
    }

2.2.2、删除按钮绑定事件

<el-button type="text" size="mini" icon="el-icon-delete" @click="removeCourse(scope.row.id)">删除</el-button>

2.2.3、删除方法

src\views\edu\course\list.vue

            /**
             * 删除课程
             * @param {} courseId 
             */
            removeCourse(courseId) {
                this.$confirm('此操作将永久删除该课程信息, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                })
                // 确认删除
                .then(() => {
                    course.removeCourseById(courseId).then(response => {
                            // 提示信息
                            this.$message({
                                type: 'success',
                                message: '删除成功!'
                            });
                            // 重新加载列表
                            if (this.list.length == 1) {
                                this.page = this.page - 1;
                            }
                            this.getList(this.page);
                    })
                })
                // 取消删除
                .catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
            }

3、完整页面

<template>
    <div class="app-container">
        <!--查询表单-->
        <el-form :inline="true" class="demo-form-inline">
            <!-- 所属分类:级联下拉列表 -->
            <!-- 一级分类 -->
            <el-form-item label="课程类别">
                <el-select v-model="courseQuery.subjectParentId" placeholder="请选择" @change="subjectLevelOneChanged">
                    <el-option v-for="subject in subjectOneList" :key="subject.id" :label="subject.title"
                        :value="subject.id" />
                </el-select>
                <!-- 二级分类 -->
                <el-select v-model="courseQuery.subjectId" placeholder="请选择">
                    <el-option v-for="subject in subjectTwoList" :key="subject.id" :label="subject.title" :value="subject.id" />
                </el-select>
            </el-form-item>
        
            <!-- 标题 -->
            <el-form-item>
                <el-input v-model="courseQuery.title" placeholder="课程标题" />
            </el-form-item>

            <!-- 讲师 -->
            <el-form-item>
                <el-select v-model="courseQuery.teacherId" placeholder="请选择讲师">
                    <el-option v-for="teacher in teacherList" :key="teacher.id" :label="teacher.name" :value="teacher.id" />
                </el-select>
            </el-form-item>
            
            <!-- 课程状态 -->
            <el-form-item>
                <el-select v-model="courseQuery.status" clearable placeholder="课程状态">
                    <el-option value="Normal" label="已发布" />
                    <el-option value="Draft" label="未发布" />
                </el-select>
            </el-form-item>
        
            <el-button type="primary" icon="el-icon-search" @click="getList()">查询</el-button>
            <el-button type="default" @click="resetData()">清空</el-button>
        </el-form>

        <!-- 表格 -->
        <el-table v-loading="listLoading" :data="list" element-loading-text="数据加载中" border fit highlight-current-row
            row-class-name="myClassList">
        
            <el-table-column label="序号" width="70" align="center">
                <template slot-scope="scope">
                    {{ (page - 1) * limit + scope.$index + 1 }}
                </template>
            </el-table-column>
        
            <el-table-column label="课程信息" width="470" align="center">
                <template slot-scope="scope">
                    <div class="info">
                        <div class="pic">
                            <img :src="scope.row.cover" alt="scope.row.title" width="150px">
                        </div>
                        <div class="title">
                            <a href="">{{ scope.row.title }}</a>
                            <p>{{ scope.row.lessonNum }}课时</p>
                        </div>
                    </div>
        
                </template>
            </el-table-column>
        
            <el-table-column label="创建时间" align="center">
                <template slot-scope="scope">
                    {{ scope.row.gmtCreate.substr(0, 10) }}
                </template>
            </el-table-column>
            <el-table-column label="发布时间" align="center">
                <template slot-scope="scope">
                    {{ scope.row.gmtModified.substr(0, 10) }}
                </template>
            </el-table-column>
            <el-table-column label="价格" width="100" align="center">
                <template slot-scope="scope">
                    {{ Number(scope.row.price) === 0 ? '免费' :
                    '¥' + scope.row.price.toFixed(2) }}
                </template>
            </el-table-column>
            <el-table-column prop="buyCount" label="付费学员" width="100" align="center">
                <template slot-scope="scope">
                    {{ scope.row.buyCount }}人
                </template>
            </el-table-column>
        
            <el-table-column label="操作" width="150" align="center">
                <template slot-scope="scope">
                    <router-link :to="'/edu/course/info/'+scope.row.id">
                        <el-button type="text" size="mini" icon="el-icon-edit">编辑课程信息</el-button>
                    </router-link>
                    <router-link :to="'/edu/course/chapter/'+scope.row.id">
                        <el-button type="text" size="mini" icon="el-icon-edit">编辑课程大纲</el-button>
                    </router-link>
                    <el-button type="text" size="mini" icon="el-icon-delete" @click="removeCourse(scope.row.id)">删除</el-button>
                </template>
            </el-table-column>
        </el-table>
        
        <!-- 分页 -->
        <el-pagination 
            :current-page="page" 
            :page-size="limit" 
            :total="total" 
            style="padding: 30px 0; text-align: center;"
            layout="total, prev, pager, next, jumper" 
            @current-change="getList" 
        />
    </div>
</template>>
<script>
    import course from '@/api/edu/course.js'
    import subject from '@/api/edu/subject.js'

    export default {
        data() {
            return {
                listLoading: true,  // 是否显示loading信息
                list: null,         // 数据列表
                total: 0,           // 总记录数
                page: 1,            // 页码
                limit: 3,          // 每页记录数
                courseQuery: {        // 查询条件
                    subjectParentId: '',
                    subjectId: '',
                    title: '',
                    teacherId: '',
                    status: ''
                },
                teacherList: [],    // 讲师列表
                subjectOneList: [],  // 一级分类列表
                subjectTwoList: []  // 二级分类列表
            }
        },
        created() {
            this.getList();
            this.getListTeacher();
            this.getOneSubject();
        },
        methods: {
            /**
             * 获取课程信息
             */
            getList(page = 1) { // 若没有page参数。默认为1
                this.listLoading = true;
                this.page = page;
                course.getCoursePage(this.page,this.limit,this.courseQuery).then(response => {
                    this.list = response.data.records;
                    this.total = response.data.total;
                });
                this.listLoading = false;
            },

            /**
             * 表单清空方法
             */
            resetData() {
                this.courseQuery = {}
                this.getList()
            },

            /**
             * 获取所有讲师信息
             */
            getListTeacher() {
                course.getTeacherList().then(response => {
                    this.teacherList = response.data.items;
                })
            },

            /**
             * 查询所有一级分类(一级分类下含有其包含的二级分类)
             */
            getOneSubject() {
                subject.getSubjectList().then(response => {
                    this.subjectOneList = response.data.list;
                })
            },

            /**
             * 更换选择的一级分类调用的方法,更新二级分类数据
             * @param {*} value 一级分类ID
             */
            subjectLevelOneChanged(value) {
                // 初始化
                this.subjectTwoList = [];
                this.courseQuery.subjectId = '';

                // 遍历所有一级分类,若其ID和value的值相等,将其孩子(二级分类)赋值给subjectTwoList
                for (var i = 0; i < this.subjectOneList.length; i++) {
                    if (value === this.subjectOneList[i].id) {
                        // 二级分类赋值
                        this.subjectTwoList = this.subjectOneList[i].children;
                    }
                }
            },

            /**
             * 删除课程
             * @param {} courseId 
             */
            removeCourse(courseId) {
                this.$confirm('此操作将永久删除该课程信息, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                })
                // 确认删除
                .then(() => {
                    course.removeCourseById(courseId).then(response => {
                            // 提示信息
                            this.$message({
                                type: 'success',
                                message: '删除成功!'
                            });
                            // 重新加载列表
                            if (this.list.length == 1) {
                                this.page = this.page - 1;
                            }
                            this.getList(this.page);
                    })
                })
                // 取消删除
                .catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
            }
        }
    }
</script>
<style scoped>
.myClassList .info {
    width: 450px;
    overflow: hidden;
}

.myClassList .info .pic {
    width: 150px;
    height: 90px;
    overflow: hidden;
    float: left;
}

.myClassList .info .pic a {
    display: block;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
}

.myClassList .info .pic img {
    display: block;
    width: 100%;
}

.myClassList td .info .title {
    width: 280px;
    float: right;
    height: 90px;
}

.myClassList td .info .title a {
    display: block;
    height: 48px;
    line-height: 24px;
    overflow: hidden;
    color: #00baf2;
    margin-bottom: 12px;
}

.myClassList td .info .title p {
    line-height: 20px;
    margin-top: 5px;
    color: #818181;
}
</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
谷粒是一个教育机构,提供课程培训和习资源,其中有一个叫做Jenkins.war的项目。 Jenkins是一个流行的开源持续集成和交付工具,它提供了一个可视化的界面,帮助自动化构建、测试和发布软件项目。 Jenkins.war则是Jenkins的可执行文件,以.war(Web Application Archive)格式打包。通过将Jenkins.war部署到Java应用服务器中,可以快速搭建起Jenkins服务器环境。 Jenkins.war具有以下特点和功能: 1. 可扩展性:Jenkins.war支持安装插件以扩展其功能。用户可以根据自己的需求选择并安装各种插件,如Git、Maven、SonarQube等。 2. 自动化构建:Jenkins.war能够监控软件代码库的变化,并在检测到新的提交或推送时自动触发构建任务。这样可以确保代码在每次变更后都能正确构建,减少手动操作和人为错误。 3. 高度可配置:Jenkins.war提供了丰富的配置选项,可以根据项目的需求进行精细调整。用户可以设置构建触发条件、构建步骤、构建环境等,以满足不同项目的特定要求。 4. 可视化界面:Jenkins.war提供了直观友好的web界面,方便用户管理和监控构建任务的执行情况。用户可以通过界面查看构建历史、日志输出、构建报告等信息,以便随时了解项目的状态。 总之,Jenkins.war是谷粒所提供的一个工具,能够帮助开发团队提高软件开发流程的效率和质量。通过使用Jenkins.war,可以实现自动化构建、持续集成和交付,从而加快软件开发周期,减少人力成本,并提升软件质量和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值