在src/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' }
},
]
},
在scr/view
中创建subject文件夹,并加入list.vue
和save.vue
两个vue文件
save.vue
<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/template.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
}
},
created(){
},
methods:{
//点击按钮上传文件到接口
submitUpload(){
this.importBtnDisabled = true
this.loading = true
//提交表单
//js写法:document.getElementById("upload").submit();
this.$refs.upload.submit()
},
//上传成功的事件
fileUploadSuccess(){
this.loading = false
this.$message({
type: 'success',
message: '添加课程分类成功'
})
//跳转到课程分类的列表界面
this.$router.push({path : "/subject/list"})
},
//上传失败的事件
fileUploadError(){
this.loading = false
this.$message({
type: 'error',
message: '添加课程分类失败'
})
}
}
}
</script>
进入课程分类添加路由
点击 选取文件 按钮,选择含有课程分类的信息的excel文件
点击 上传到服务器按钮 等待上传成功。上传成功之后,会有成功提示,而且会跳转到课程分类页面。
数据库中也添加了相应的信息
在src/view/subject/list.vue
中添加下面的模版本内容:
<template>
<div class="app-container">
<el-input v-model="filterText" placeholder="关键字" 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>
export default {
data() {
return {
filterText: '',
data2: [{
id: 1,
label: 'Level one 1',
children: [{
id: 4,
label: 'Level two 1-1',
children: [{
id: 9,
label: 'Level three 1-1-1'
}, {
id: 10,
label: 'Level three 1-1-2'
}]
}]
}, {
id: 2,
label: 'Level one 2',
children: [{
id: 5,
label: 'Level two 2-1'
}, {
id: 6,
label: 'Level two 2-2'
}]
}, {
id: 3,
label: 'Level one 3',
children: [{
id: 7,
label: 'Level two 3-1'
}, {
id: 8,
label: 'Level two 3-2'
}]
}],
defaultProps: {
children: 'children',
label: 'label'
}
}
},
watch: {
filterText(val) {
this.$refs.tree2.filter(val)
}
},
methods: {
filterNode(value, data) {
if (!value) return true
return data.label.indexOf(value) !== -1
}
}
}
script>
显示效果:
其中树状图中的数据都定义在data的data2中,这个就是后台需要返回的数据。而且数据格式要和data2定义的一致,组件才能识别。
package cn.hanzhuang42.eduservice.entity.subject;
import lombok.Data;
import java.util.List;
/**
* 用于封装返回的树状数据
*/
@Data
public class SubjectResult {
//id
private String id;
//名称
private String title;
//如果是一级分类用于存放其子分类
//如果是二级分类则为空
private List<SubjectResult> children = null;
}
/**
* 获取课程分类信息,并一树状结构返回
* @return
*/
@GetMapping("getAll")
public R getAllSubject(){
List<SubjectResult> res = subjectService.getAllSubject();
return R.ok().data("data", res);
}
在接口EduSubjectService中添加方法
public interface EduSubjectService extends IService<EduSubject> {
...//其他方法定义
List<SubjectResult> getAllSubject();
}
在service实现类EduSubjectServiceImpl中添加对应的实现方法。
主要功能就是将数据库中的课程分类信息封装成上边前端中data2那样的格式,详细过程参见代码
@Service
public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements EduSubjectService {
...//其他方法实现
@Override
public List<SubjectResult> getAllSubject() {
List<EduSubject> rowData = this.list();
List<SubjectResult> res = new ArrayList<>();
//用于存储 SubjectResult 的 id 和在 List 中索引的对应关系,便于之后存取
Map<String, Integer> map = new HashMap<>();
int i = 0;
//先将一级分类存储到 res 中
for (EduSubject subject : rowData) {
if ("0".equals(subject.getParentId())){
//通过 EduSubject 创建一个 一级分类SubjectResult
SubjectResult subjectResult = new SubjectResult();
String topId = subject.getId();
subjectResult.setId(topId);
subjectResult.setTitle(subject.getTitle());
subjectResult.setChildren(new ArrayList<>());
//将一级分类 SubjectResult 放入list中
res.add(subjectResult);
map.put(topId, i++);
}
}
//将二级分类存储到对应的一级分类中
for (EduSubject subject : rowData) {
String parentId = subject.getParentId();
if (!"0".equals(parentId)) {
//通过 EduSubject 创建一个 二级分类SubjectResult
SubjectResult subjectResult = new SubjectResult();
subjectResult.setId(subject.getId());
subjectResult.setTitle(subject.getTitle());
//通过 parentId 先获取 list 中的索引,再通过索引获得 parent
SubjectResult parent = res.get(map.get(parentId));
//将二级分类加入到对应的一级分类中
parent.getChildren().add(subjectResult);
}
}
return res;
}
}
在前端中的src/api/edu
中添加subject.js
接口定义
import request from '@/utils/request'
export default {
/**
* 获得课程分类信息(树状)
*/
getAllSubject(){
return request({
url: `/eduservice/subject/getAll`,
method: 'get'
})
},
}
在前端页面中通过js调用后端接口获取数据
<script>
import subjectApi from '@/api/edu/subject.js'
export default {
data() {
return {
filterText: '',
data2: [], //返回所有分类的数据(树状)
defaultProps: {
children: 'children',
label: 'title'
}
}
},
watch: {
filterText(val) {
this.$refs.tree2.filter(val)
}
},
created(){
this.getAllSubject()
},
methods: {
getAllSubject(){
subjectApi.getAllSubject()
.then(response =>{
this.data2 = response.data.list
})
},
filterNode(value, data) {
if (!value) return true
//比较时都用小写
return data.title.toLowerCase().indexOf(value.toLowerCase()) !== -1
}
}
}
</script>
重启服务,进入页面点击导航上的课程分类,内容显示没有问题