D7
2022年1月10日19:44:25
D7-1.添加课程分类前端对接
1.添加路由和页面
//guli-admin/src/router/index.js
{
path: '/subject',
component: Layout,
redirect: '/subject/table',
name: '课程分类管理',
meta: { title: '课程分类管理', icon: 'example' },
children: [
{
path: 'add',
name: '导入课程分类',
component: () => import('@/views/subject/add'),
meta: { title: '导入课程分类', icon: 'tree' }
},
{
path: 'list',
name: '课程分类展示',
component: () => import('@/views/subject/list'),
meta: { title: '课程分类展示', icon: 'table' }
},
]
},
添加页面:在guli-admin/src/views下新建subject文件夹,在此文件夹下新建add.vue和list.vue
2.页面实现
1) 添加页面元素
<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=" '/excel/%E8%AF%BE%E7%A8%8B%E5%88%86%E7%B1%BB%E5%88%97%E8%A1%A8%E6%A8%A1%E6%9D%BF.xls'">点击下载模版</a>
</el-tag>
</el-form-item>
<!--ref类比成HTML中的id,唯一标识。auto-upload是否自动提交。
disabled是否不可操作。-->
<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">{{ fileUploadBtnText }}</el-button>
</el-upload>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
BASE_API: process.env.BASE_API, // 接口API地址
//OSS_PATH: process.env.OSS_PATH, //阿里云OSS地址
fileUploadBtnText: "上传到服务器", // 按钮文字
importBtnDisabled: false, // 按钮是否禁用
loading: false
};
},
created() {},
methods: {
submitUpload() {
this.fileUploadBtnText = "正在上传";
this.importBtnDisabled = true;
this.loading = true;
this.$refs.upload.submit();
},
fileUploadSuccess(response) {
if (response.success === true) {
this.fileUploadBtnText = '导入成功'
this.loading = false
this.$message({
type: 'success',
message: '导入成功'
})
}
},
fileUploadError(response) {
this.fileUploadBtnText = '导入失败'
this.loading = false
this.$message({
type: 'error',
message: '导入失败'
})
}
}
};
</script>
D7-2.课程分类属性结构展示
- 复制已有的类似页面:guli-admin/src/views/tree/index.vue
1.后端实现接口
- 在service_edu/src/main/entity/vo下创建Vo类
@Data
public class OneSubjectVo {
private String id;
private String title;
private List<TwoSubjectVo> children = new ArrayList<>();
}
@Data
public class TwoSubjectVo {
private String id;
private String title;
}
2.实现controller和service
//service_edu/src/main/controller/EduSubjectController.java
@ApiOperation(value = "查询所有课程分类信息") //Day7
@GetMapping("getAllSubject")
public R getAllSubject() {
List<OneSubjectVo> oneSubjectVoList = subjectService.getAllSubject();
return R.ok().data("allSubject", oneSubjectVoList);
}
//service_edu/src/main/service/impl/EduSubjectServiceImpl.java
//查询所有课程分类信息
@Override
public List<OneSubjectVo> getAllSubject() {
//1查询一级信息
QueryWrapper<EduSubject> oneSubjectWrapper = new QueryWrapper<>();
oneSubjectWrapper.eq("parent_id","0");
List<EduSubject> oneSubjectList = baseMapper.selectList(oneSubjectWrapper);
//2查询二级信息
QueryWrapper<EduSubject> twoSubjectWrapper = new QueryWrapper<>();
twoSubjectWrapper.ne("parent_id","0"); //不等于
List<EduSubject> twoSubjectList = baseMapper.selectList(twoSubjectWrapper);
//3封装一级
List<OneSubjectVo> allSubjectList = new ArrayList<>();
for (int i = 0; i <oneSubjectList.size() ; i++) {
//3.1取出每一条一级信息
EduSubject oneSubject = oneSubjectList.get(i);
//3.2把EduSubject转化OneSubjectVo
OneSubjectVo oneSubjectVo = new OneSubjectVo();
//oneSubjectVo.setId(oneSubject.getId());
//oneSubjectVo.setTitle(oneSubject.getTitle());
BeanUtils.copyProperties(oneSubject,oneSubjectVo); //参数一:source,参数二:target
allSubjectList.add(oneSubjectVo);
//4封装二级信息
List<TwoSubjectVo> twoVoList = new ArrayList<>();
for (int m = 0; m < twoSubjectList.size(); m++) {
//4.1取出每一条二级信息
EduSubject twoSubject = twoSubjectList.get(m);
if(oneSubject.getId().equals(twoSubject.getParentId())){
//4.2把EduSubject转化TwoSubjectVo
TwoSubjectVo twoSubjectVo = new TwoSubjectVo();
BeanUtils.copyProperties(twoSubject,twoSubjectVo);
twoVoList.add(twoSubjectVo);
}
}
oneSubjectVo.setChildren(twoVoList);
}
return allSubjectList;
}
3.前端对接
- guli-admin/src/api/subject.js
import request from '@/utils/request'
export default {
//查询所有课程分类信息
getAllSubject(){
return request({
url: `/eduservice/subject/getAllSubject`,
method: 'get'
})
}
}
- guli-admin/src/views/subject/list.vue中的js实现
<template>
<div class="app-container">
<el-input v-model="filterText" placeholder="Filter keyword" style="margin-bottom:30px;" />
<el-tree
ref="tree2"
:data="data2"
:props="defaultProps"
:filter-node-method="filterNode"
class="filter-tree"
default-expand-all
/>
</div>
</template>
<script>
// import subject from "../../api/subject";
import subject from "@/api/subject";
export default {
data() {
return {
filterText: '',
data2: [],
defaultProps: {
children: 'children',
label: 'title'
}
}
},
watch: { //侦听输入框
filterText(val) {
this.$refs.tree2.filter(val)
}
},
created () {
this.getAllSubjectList();
},
methods: {
getAllSubjectList() {
subject.getAllSubject().then(response => {
this.data2 = response.data.allSubject;
});
},
filterNode(value, data) {
if (!value) return true
return data.title.indexOf(value) !== -1
}
}
}
</script>
D7-3.课程发布
1.代码生成器生成代码
public class CodeGenerator {
@Test
public void run() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("testjava");
gc.setOpen(false); //生成后是否打开资源管理器(目录是否展开)
gc.setFileOverride(false); //重新生成时文件是否覆盖
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.ID_WORKER_STR); //主键策略(字符串类型)
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("hrj");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("eduservice"); //模块名
pc.setParent("com.jun");
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
//strategy.setInclude("edu_teacher"); //括号中可以写多张表的名字
//strategy.setInclude("edu_subject");
strategy.setInclude("edu_course","edu_course_description");
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}
- 给EduCourse和EduCourseDescription添加注解
@ApiModelProperty(value = "课程ID")
@TableId(value = "id", type = IdType.INPUT) //修改主键策略
private String id;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间")
private Date gmtCreate;
@TableField(fill = FieldFill.INSERT_UPDATE)
@ApiModelProperty(value = "更新时间")
private Date gmtModified;
2.添加课程信息接口
1)创建Vo类
//service_edu/src/main/java/entity/vo/CourseInfoForm.java
@Data
public class CourseInfoForm {
@ApiModelProperty(value = "课程ID")
private String id;
@ApiModelProperty(value = "课程讲师ID")
private String teacherId;
@ApiModelProperty(value = "二级分类")
private String subjectId;
@ApiModelProperty(value = "一级分类")
private String subjectParentId;
@ApiModelProperty(value = "课程标题")
private String title;
@ApiModelProperty(value = "课程销售价格,设置为0则可免费观看")
private BigDecimal price;
@ApiModelProperty(value = "总课时")
private Integer lessonNum;
@ApiModelProperty(value = "课程封面图片路径")
private String cover;
@ApiModelProperty(value = "课程简介")
private String description;
}
2)实现controller
@Api(description="课程管理")
@RestController
@RequestMapping("/eduservice/course")
@CrossOrigin
public class EduCourseController {
@Autowired
private EduCourseService courseService;
@ApiOperation(value = "添加课程信息")
@PostMapping("addCourseInfo")
public R addCourseInfo(@RequestBody CourseInfoForm courseInfoForm){
courseService.addCourseInfo(courseInfoForm);
return R.ok();
}
}
3)实现service
@Service
public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService {
@Autowired
private EduCourseDescriptionService courseDescriptionService;
//添加课程信息
@Override
public void addCourseInfo(CourseInfoForm courseInfoForm) {
//1.添加课程信息
EduCourse eduCourse = new EduCourse();
BeanUtils.copyProperties(courseInfoForm,eduCourse);
int insert = baseMapper.insert(eduCourse); //插入数据库
if(insert==0){
throw new GuliException(20001,"添加课程信息失败");
}
//2添加课程描述信息
String courseId = eduCourse.getId();
EduCourseDescription courseDescription = new EduCourseDescription();
courseDescription.setId(courseId);
courseDescription.setDescription(courseInfoForm.getDescription());
courseDescriptionService.save(courseDescription);
}
}
3.添加课程信息前端实现
1)添加路由
{
path: '/course',
component: Layout,
redirect: '/course/table',
name: '课程管理',
meta: { title: '课程管理', icon: 'example' },
children: [
{
path: 'add',
name: '课程发布',
component: () => import('@/views/course/add'),
meta: { title: '课程发布', icon: 'tree' }
},
{
path: 'list',
name: '课程列表',
component: () => import('@/views/course/list'),
meta: { title: '课程列表', icon: 'table' }
},
]
},
2)创建api接口方法
//guli-admin/src/api/course.js
import request from '@/utils/request'
export default {
//添加课程信息
addCourseInfo(courseInfo){
return request({
url: `/eduservice/course/addCourseInfo`,
method: 'post',
data:courseInfo
})
}
}
3)创建页面,实现js
- 在views文件夹中新建course文件夹,并创建add.vue和list.vue页面
add.vue
<template>
<div class="app-container">
<h2 style="text-align: center;">发布新课程</h2>
<el-steps :active="1" process-status="wait" align-center style="margin-bottom: 40px;">
<el-step title="填写课程基本信息"/>
<el-step title="创建课程大纲"/>
<el-step title="提交审核"/>
</el-steps>
<el-form label-width="120px">
<el-form-item label="课程标题">
<el-input v-model="courseInfo.title" placeholder=" 示例:机器学习项目课:从基础到搭建项目视频课程。专业名称注意大小写"/>
</el-form-item>
<!-- 所属分类 TODO -->
<!-- 课程讲师 TODO -->
<el-form-item label="总课时">
<el-input-number
:min="0"
v-model="courseInfo.lessonNum"
controls-position="right"
placeholder="请填写课程的总课时数"
/>
</el-form-item>
<!-- 课程简介 TODO -->
<el-form-item label="课程简介">
<el-input v-model="courseInfo.description" />
</el-form-item>
<!-- 课程封面 TODO -->
<el-form-item label="课程价格">
<el-input-number
:min="0"
v-model="courseInfo.price"
controls-position="right"
placeholder="免费课程请设置为0元"
/>元
</el-form-item>
<el-form-item>
<el-button :disabled="saveBtnDisabled" type="primary" @click="next">保存并下一步</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import course from "@/api/course";
export default {
data() {
return {
saveBtnDisabled: false, //保存按钮是否禁用
courseInfo: {} //课程信息
};
},
created() {
console.log("info created");
},
methods: {
next() {
console.log("next");
//1调用接口保存数据
course.addCourseInfo(this.courseInfo).then(response => {
this.$message({
type: "success",
message: "添加成功!"
});
//2跳转到课程大纲页面
//this.$router.push({ path: "/edu/course/chapter/1" });
});
}
}
};
</script>
4.添加讲师信息
1)创建api接口方法
//guli-admin/src/api/teacher.js
//6.查询所有讲师
getAllTeacher() {
return request({
url: `/eduservice/eduteacher`,
method: 'get'
});
}
2)添加页面元素
//guli-admin/src/views/course/add.vue
<!-- 课程讲师 -->
<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>
5.实现课程分类
1)确认接口方法
//src/main/java/controller/EduSubjectController.java
@ApiOperation(value = "查询所有课程分类信息") //Day7
@GetMapping("getAllSubject")
public R getAllSubject() {
List<OneSubjectVo> oneSubjectVoList = subjectService.getAllSubject();
return R.ok().data("allSubject", oneSubjectVoList);
}
2)确认api接口方法
//guli-admin/src/api/subject.js
import request from '@/utils/request'
export default {
//查询所有课程分类信息
getAllSubject(){
return request({
url: `/eduservice/subject/getAllSubject`,
method: 'get'
})
}
}
3)添加页面元素
<!-- 所属分类:级联下拉列表 -->
<el-form-item label="课程类别">
<!-- 一级分类 --> <!--element-ui中,触发的事件中没有加括号,自动将参数塞进去-->
<el-select @change="getTwoByOneSubjectId"
v-model="courseInfo.subjectParentId" placeholder="一级分类">
<el-option
v-for="subject in oneSubjectList"
:key="subject.id"
:label="subject.title"
:value="subject.id"
/>
</el-select>
<!-- 二级分类 -->
<el-select v-model="courseInfo.subjectId" placeholder="二级分类">
<el-option
v-for="subject in twoSubjectList"
:key="subject.id"
:label="subject.title"
:value="subject.id"
/>
</el-select>
</el-form-item>
4)实现一级数据和二级联动
<script>
import course from "@/api/course";
import teacher from "@/api/teacher";
import subject from "@/api/subject";
export default {
data() {
return {
saveBtnDisabled: false, //保存按钮是否禁用
courseInfo: {
subjectId:''
}, //课程信息
teacherList:[], //讲师信息
oneSubjectList:[],//一级分类
twoSubjectList:[]//二级分类
};
},
created() {
console.log("info created");
this.getTeacherList();
this.getOneSubjectList();
},
methods: {
//获取分类信息
getOneSubjectList(){
subject.getAllSubject().then(response=>{
this.oneSubjectList = response.data.allSubject
})
},
//二级联动事件
getTwoByOneSubjectId(oneId){
for(let i=0;i<this.oneSubjectList.length;i++){
let oneSubject = this.oneSubjectList[i]
if(oneId === oneSubject.id){ //恒等,既判断数值又判断类型
this.twoSubjectList = oneSubject.children;
this.courseInfo.subjectId = '';
}
}
},
//获得讲师信息
getTeacherList() { //此初始化方法在页面加载的时候执行
teacher.getAllTeacher().then(response => {
this.teacherList = response.data.items;
});
},
next() {
console.log("next");
//1调用接口保存数据
course.addCourseInfo(this.courseInfo).then(response => {
this.$message({
type: "success",
message: "添加成功!"
});
//2跳转到课程大纲页面
//this.$router.push({ path: "/edu/course/chapter/1" });
});
}
}
};
</script>
6.上传封面
1)添加页面元素
<!-- 课程封面-->
<el-form-item label="课程封面">
<el-upload
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
:action="BASE_API+'/eduoss/ossfile/uploadFile'"
class="avatar-uploader"
>
<img :src="courseInfo.cover">
</el-upload>
</el-form-item>
2)js实现
//guli-admin/src/views/course/add.vue
export default {
data() {
return {
saveBtnDisabled: false, //保存按钮是否禁用
courseInfo: {
subjectId:"",
cover:"/static/vue.png"
}, //课程信息
teacherList:[], //讲师信息
oneSubjectList:[],//一级分类
twoSubjectList:[],//二级分类
BASE_API: process.env.BASE_API // 接口API地址
};
},
created() {
console.log("info created");
this.getTeacherList();
this.getOneSubjectList();
},
methods: {
//获取分类信息
getOneSubjectList(){
subject.getAllSubject().then(response=>{
this.oneSubjectList = response.data.allSubject;
})
},
//二级联动事件
getTwoByOneSubjectId(oneId){
for(let i=0;i<this.oneSubjectList.length;i++){
let oneSubject = this.oneSubjectList[i]
if(oneId === oneSubject.id){ //恒等,既判断数值又判断类型
this.twoSubjectList = oneSubject.children;
this.courseInfo.subjectId = '';
}
}
},
//获得讲师信息
getTeacherList() { //此初始化方法在页面加载的时候执行
teacher.getAllTeacher().then(response => {
this.teacherList = response.data.items;
});
},
handleAvatarSuccess(res, file) {
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("上传头像图片只能是 JPG 格式!");
}
if (!isLt2M) {
this.$message.error("上传头像图片大小不能超过 2MB!");
}
return isJPG && isLt2M;
},
next() {
console.log("next");
//1调用接口保存数据
course.addCourseInfo(this.courseInfo).then(response => {
this.$message({
type: "success",
message: "添加成功!"
});
//2跳转到课程大纲页面
//this.$router.push({ path: "/edu/course/chapter/1" });
});
}
}
};
7.富文本编辑框
1)添加配置
//在 guli-admin/build/webpack.dev.conf.js 中添加配置
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true,
favicon: resolve('favicon.ico'),
title: 'vue-admin-template',
templateParameters: {
BASE_URL: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
}
})
2)引入js脚本
//在guli-admin/index.html 中引入js脚本
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src=<%=BASE_URL %>/tinymce4.7.5/tinymce.min.js ></script>
<script src=<%=BASE_URL %>/tinymce4.7.5/langs / zh_CN.js ></script>
</body>
3)页面引入组件
import Tinymce from '@/components/Tinymce';
export default {
components: {Tinymce},
..........
4)添加页面元素
<!-- 课程简介-->
<el-form-item label="课程简介">
<tinymce :height="300" v-model="courseInfo.description"/>
</el-form-item>
5)添加样式
<style scoped>
.tinymce-container {
line-height: 29px;
}
</style>
8.课程发布页面整合
2)初始化新增页面
//guli-admin/src/views/course/chapter.vue
<template>
<div class="app-container">
<h2 style="text-align: center;">发布新课程</h2>
<el-steps :active="2" process-status="wait" align-center style="margin-bottom: 40px;">
<el-step title="填写课程基本信息"/>
<el-step title="创建课程大纲"/>
<el-step title="提交审核"/>
</el-steps>
<el-form label-width="120px">
<el-form-item>
<el-button @click="previous">上一步</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 // 保存按钮是否禁用
}
},
created() {
console.log('chapter created')
},
methods: {
previous() {
console.log('previous')
this.$router.push({ path: '/edu/course/info/1' })
},
next() {
console.log('next')
this.$router.push({ path: '/edu/course/publish/1' })
}
}
}
</script>
//guli-admin/src/views/course/publish.vue
<template>
<div class="app-container">
<h2 style="text-align: center;">发布新课程</h2>
<el-steps :active="3" process-status="wait" align-center style="margin-bottom: 40px;">
<el-step title="填写课程基本信息"/>
<el-step title="创建课程大纲"/>
<el-step title="提交审核"/>
</el-steps>
<el-form label-width="120px">
<el-form-item>
<el-button @click="previous">返回修改</el-button>
<el-button :disabled="saveBtnDisabled" type="primary" @click="publish">发布课程</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
saveBtnDisabled: false // 保存按钮是否禁用
}
},
created() {
console.log('publish created')
},
methods: {
previous() {
console.log('previous')
this.$router.push({ path: '/edu/course/chapter/1' })
},
publish() {
console.log('publish')
this.$router.push({ path: '/edu/course/list' })
}
}
}
</script>
3)修改课程信息接口
@Api(description="课程管理")
@RestController
@RequestMapping("/eduservice/course")
@CrossOrigin
public class EduCourseController {
@Autowired
private EduCourseService courseService;
@ApiOperation(value = "添加课程信息")
@PostMapping("addCourseInfo")
public R addCourseInfo(@RequestBody CourseInfoForm courseInfoForm){
String courseId = courseService.addCourseInfo(courseInfoForm);
return R.ok().data("courseId",courseId);
}
}