搭建项目前端环境
# 搭建项目前端环境
# vue-admin-template 模板
vue-admin-template 是基于 vue-element-admin 的一套后台管理系统基础模板(最少精简版),可作为模板进行二次开发。
搭建环境
# 解压压缩包
# 进入目录
cd vue-admin-template-master
# 安装依赖
npm install
# 启动。执行后,浏览器自动弹出并访问http://localhost:9528/
npm run dev
2
3
4
5
6
7
8
9
在启动项目时,出现 npm install --save core-js/modules/es.error.cause.js 的错误,该如何解决

先删除 node_modules 依赖
npm rm -rf node_modules
首先安装 报错的插件
npm install --save core-js
最后再 npm install 或者 yarn install
yarn install
最后 npm run dev 运行启动
yarn run dev
# 修改登录功能
# 创建登录接口
创建 LoginController
此处返回是 vue-admin-template 登陆返回接口的固定值
@RestController
@RequestMapping("/admin/vod/user")
@CrossOrigin
public class LoginController {
/**
* 登录
* @return
*/
@PostMapping("login")
public Result login() {
Map<String, Object> map = new HashMap<>();
map.put("token","admin");
return Result.ok(map);
}
/**
* 获取用户信息
* @return
*/
@GetMapping("info")
public Result info() {
Map<String, Object> map = new HashMap<>();
map.put("roles","[admin]");
map.put("name","admin");
map.put("avatar","https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
return Result.ok(map);
}
/**
* 退出
* @return
*/
@PostMapping("logout")
public Result logout(){
return Result.ok();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 修改状态码
由于 vue-admin-template 返回成功状态为 20000 失败为 20001 我们在 Result 类修改状态码


# 修改登录前端
修改前端环境变量中的接口路径 http://localhost:8301/

修改 src/api/user.js 文件中的 user 请求路径后缀
import request from '@/utils/request'
export function login(data) {
return request({
url: '/admin/vod/user/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/admin/vod/user/info',
method: 'get',
params: { token }
})
}
export function logout() {
return request({
url: '/admin/vod/user/logout',
method: 'post'
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 跨域问题
- 浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域 。前后端分离开发中,需要考虑 ajax 跨域的问题。
- 跨域的本质:浏览器对 Ajax 请求的一种限制
- 这里我们可以从服务端解决这个问题
解决方法:
- 在 Controller 类上添加
@CrossOrigin注解 - 统一网关
# 医院设置路由定义
# 修改路由
修改 src/router/index.js 文件,重新定义 constantRoutes
** 注意:** 每个路由的 name 不能相同
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
// 首页
{
path: '/',
component: Layout,
redirect: '/dashboard',
name: 'Dashboard',
children: [{
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: '硅谷课堂后台管理系统', icon: 'dashboard' }
}]
},
// 讲师管理
{
path: '/vod',
component: Layout,
redirect: '/vod/teacher/list',
name: 'Vod',
meta: {
title: '讲师管理',
icon: 'el-icon-bank-card'
},
alwaysShow: true,
children: [
{
path: 'teacher/list',
name: 'TeacherList',
component: () => import('@/views/vod/teacher/list'),
meta: { title: '讲师列表' }
},
{
path: 'teacher/create',
name: 'TeacherCreate',
component: () => import('@/views/vod/teacher/form'),
meta: { title: '添加讲师' },
//hidden: true
},
{
path: 'teacher/edit/:id',
name: 'TeacherEdit',
component: () => import('@/views/vod/teacher/form'),
meta: { title: '编辑讲师' },
hidden: true
}
]
},
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true }
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 创建 vue 组件
在 src/views 文件夹下创建 teacher 文件夹和 form.vue和list.vue 文件

form.vue
<template>
<div class="app-container">
讲师表单
</div>
</template>
2
3
4
5
list.vue
<template>
<div class="app-container">
讲师列表
</div>
</template>
2
3
4
5
# 讲师分页列表
# 定义 api 文件
创建文件 src/api/vod/ teacher.js
import request from '@/utils/request'
const api_name = '/admin/vod/teacher'
export default {
// 讲师列表
pageList(page, limit, searchObj) {
return request({
url: `${api_name}/findQueryPage/${page}/${limit}`,
method: `post`,
// 使用json格式传递 data:searchObj
// 使用普通格式传递 params:searchObj
data: searchObj
})
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 添加跨域注解
在 TeacherController 类上添加 @CrossOrigin 注解

# 初始化 vue 组件
src/views/vod/teacher/ list.vue
<template>
<div class="app-container">
医院设置列表
</div>
</template>
<script>
import teacherApi from '@/api/vod/teacher'
export default {
// 定义数据模型
data() {
return {
}
},
// 页面渲染成功后获取数据
created() {
this.fetchData()
},
// 定义方法
methods: {
fetchData() {
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 定义 data
// 定义数据模型
data() {
return {
list: [], // 讲师列表
total: 0, // 总记录数
page: 1, // 页码
limit: 10, // 每页记录数
searchObj: {}, // 查询条件
multipleSelection: []// 批量删除选中的记录列表
}
},
2
3
4
5
6
7
8
9
10
11
# 定义 methods
methods: {
fetchData() {
// 调用api
teacherApi.pageList(this.page, this.limit, this.searchObj).then(response => {
debugger
this.list = response.data.records
this.total = response.data.total
})
},
}
2
3
4
5
6
7
8
9
10
# 表格渲染
<!-- 表格 -->
<el-table
:data="list"
border
stripe
@selection-change="handleSelectionChange">
<el-table-column type="selection"/>
<el-table-column
label="#"
width="50">
<template slot-scope="scope">
{{ (page - 1) * limit + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="name" label="名称" width="80" />
<el-table-column label="头衔" width="90">
<template slot-scope="scope">
<el-tag v-if="scope.row.level === 1" type="success" size="mini">高级讲师</el-tag>
<el-tag v-if="scope.row.level === 0" size="mini">首席讲师</el-tag>
</template>
</el-table-column>
<el-table-column prop="intro" label="简介" />
<el-table-column prop="sort" label="排序" width="60" />
<el-table-column prop="joinDate" label="入驻时间" width="160" />
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="removeById(scope.row.id)">删除</el-button>
<router-link :to="'/vod/teacher/edit/'+scope.row.id">
<el-button type="text" size="mini">修改</el-button>
</router-link>
</template>
</el-table-column>
</el-table>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 分页组件
<!-- 分页组件 -->
<el-pagination
:current-page="page"
:total="total"
:page-size="limit"
:page-sizes="[5, 10, 20, 30, 40, 50, 100]"
style="padding: 30px 0; text-align: center;"
layout="total, sizes, prev, pager, next, jumper"
@size-change="changePageSize"
@current-change="changeCurrentPage"
/>
2
3
4
5
6
7
8
9
10
11
# 顶部查询表单
<!--查询表单-->
<el-card class="operate-container" shadow="never">
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="名称">
<el-input v-model="searchObj.name" placeholder="讲师名" />
</el-form-item>
<el-form-item label="头衔">
<el-select v-model="searchObj.level" clearable placeholder="头衔">
<el-option value="1" label="高级讲师"/>
<el-option value="0" label="首席讲师"/>
</el-select>
</el-form-item>
<el-form-item label="入驻时间">
<el-date-picker
v-model="searchObj.joinDateBegin"
placeholder="开始时间"
value-format="yyyy-MM-dd" />
</el-form-item>
<el-form-item label="-">
<el-date-picker
v-model="searchObj.joinDateEnd"
placeholder="结束时间"
value-format="yyyy-MM-dd" />
</el-form-item>
<el-button type="primary" icon="el-icon-search" @click="fetchData()">查询</el-button>
<el-button type="default" @click="resetData()">清空</el-button>
</el-form>
</el-card>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
分页和清空方法
// 每页记录数改变,size:回调参数,表示当前选中的“每页条数”
changePageSize(size) {
this.limit = size
this.fetchData()
},
// 改变页码,page:回调参数,表示当前选中的“页码”
changeCurrentPage(page) {
this.page = page
this.fetchData()
},
// 重置表单
resetData() {
this.searchObj = {}
this.fetchData()
},
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 完整 list.vue 页面代码
<template>
<div class="app-container">
<!--查询表单-->
<el-card class="operate-container" shadow="never">
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="名称">
<el-input v-model="searchObj.name" placeholder="讲师名" />
</el-form-item>
<el-form-item label="头衔">
<el-select v-model="searchObj.level" clearable placeholder="头衔">
<el-option value="1" label="高级讲师" />
<el-option value="0" label="首席讲师" />
</el-select>
</el-form-item>
<el-form-item label="入驻时间">
<el-date-picker
v-model="searchObj.joinDateBegin"
placeholder="开始时间"
value-format="yyyy-MM-dd"
/>
</el-form-item>
<el-form-item label="-">
<el-date-picker
v-model="searchObj.joinDateEnd"
placeholder="结束时间"
value-format="yyyy-MM-dd"
/>
</el-form-item>
<el-button type="primary" icon="el-icon-search" @click="fetchData()">查询</el-button>
<el-button type="default" @click="resetData()">清空</el-button>
</el-form>
</el-card>
<!-- 表格 -->
<el-table
:data="list"
border
stripe
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" />
<el-table-column
label="#"
width="50"
>
<template slot-scope="scope">
{{ (page - 1) * limit + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="name" label="名称" width="80" />
<el-table-column label="头衔" width="90">
<template slot-scope="scope">
<el-tag v-if="scope.row.level === 1" type="success" size="mini">高级讲师</el-tag>
<el-tag v-if="scope.row.level === 0" size="mini">首席讲师</el-tag>
</template>
</el-table-column>
<el-table-column prop="intro" label="简介" />
<el-table-column prop="sort" label="排序" width="60" />
<el-table-column prop="joinDate" label="入驻时间" width="160" />
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="removeById(scope.row.id)">删除</el-button>
<router-link :to="'/vod/teacher/edit/'+scope.row.id">
<el-button type="text" size="mini">修改</el-button>
</router-link>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<el-pagination
:current-page="page"
:total="total"
:page-size="limit"
:page-sizes="[5, 10, 20, 30, 40, 50, 100]"
style="padding: 30px 0; text-align: center;"
layout="total, sizes, prev, pager, next, jumper"
@size-change="changePageSize"
@current-change="changeCurrentPage"
/>
</div>
</template>
<script>
import teacherApi from '@/api/vod/teacher'
export default {
// 定义数据模型
data() {
return {
list: [], // 讲师列表
total: 0, // 总记录数
page: 1, // 页码
limit: 10, // 每页记录数
searchObj: {}, // 查询条件
multipleSelection: []// 批量删除选中的记录列表
}
},
// 页面渲染成功后获取数据
created() {
this.fetchData()
},
// 定义方法
methods: {
fetchData() {
// 调用api
teacherApi.pageList(this.page, this.limit, this.searchObj).then(response => {
debugger
this.list = response.data.records
this.total = response.data.total
})
},
// 每页记录数改变,size:回调参数,表示当前选中的“每页条数”
changePageSize(size) {
this.limit = size
this.fetchData()
},
// 改变页码,page:回调参数,表示当前选中的“页码”
changeCurrentPage(page) {
this.page = page
this.fetchData()
},
// 重置表单
resetData() {
this.searchObj = {}
this.fetchData()
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# 讲师删除
定义 api src/api/vod/teacher.js
removeById(id) {
return request({
url: `${api_name}/remove/${id}`,
method: `delete`
})
},
2
3
4
5
6
在 list.vue 的 methods 添加方法
使用 MessageBox 弹框组件
// 根据id删除数据
removeById(id) {
this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return teacherApi.removeById(id)
}).then((response) => {
this.fetchData()
this.$message.success(response.message)
})
},
2
3
4
5
6
7
8
9
10
11
12
13
# 讲师新增
定义 api
save(teacher) {
return request({
url: `${api_name}/saveTeacher`,
method: `post`,
data: teacher
})
},
2
3
4
5
6
7
初始化组件 src/views/vod/teacher/form.vue
<template>
<div class="app-container">
<!-- 输入表单 -->
<el-form label-width="120px">
<el-form-item label="讲师名称">
<el-input v-model="teacher.name" />
</el-form-item>
<el-form-item label="入驻时间">
<el-date-picker v-model="teacher.joinDate" value-format="yyyy-MM-dd" />
</el-form-item>
<el-form-item label="讲师排序">
<el-input-number v-model="teacher.sort" :min="0"/>
</el-form-item>
<el-form-item label="讲师头衔">
<el-select v-model="teacher.level">
<!--
数据类型一定要和取出的json中的一致,否则没法回填
因此,这里value使用动态绑定的值,保证其数据类型是number
-->
<el-option :value="1" label="高级讲师"/>
<el-option :value="0" label="首席讲师"/>
</el-select>
</el-form-item>
<el-form-item label="讲师简介">
<el-input v-model="teacher.intro"/>
</el-form-item>
<el-form-item label="讲师资历">
<el-input v-model="teacher.career" :rows="10" type="textarea"/>
</el-form-item>
<!-- 讲师头像 -->
<el-form-item label="讲师头像">
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveOrUpdate()">保存</el-button>
</el-form-item>
</el-form>
</div>
</template>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
实现新增功能
<script>
import teacherApi from '@/api/vod/teacher'
export default {
data() {
return {
BASE_API: 'http://localhost:8301',
// 初始化讲师默认数据
teacher: {
sort: 0,
level: 1
},
saveBtnDisabled: false // 保存按钮是否禁用,防止表单重复提交
}
},
// 页面渲染成功
created() {
},
methods: {
saveOrUpdate() {
// 禁用保存按钮
this.saveBtnDisabled = true
if (!this.teacher.id) {
this.saveData()
} else {
this.updateData()
}
},
// 新增讲师
saveData() {
// debugger
teacherApi.save(this.teacher).then(response => {
this.$message({
type: 'success',
message: response.message
})
this.$router.push({ path: '/vod/teacher/list' })
})
},
// 根据id更新记录
updateData() {
}
}
}
</script>
<style scoped>
.avatar-uploader .avatar-uploader-icon {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar-uploader .avatar-uploader-icon:hover {
border-color: #409EFF;
}
.avatar-uploader img {
width: 178px;
height: 178px;
display: block;
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# 讲师修改 - 数据回显
定义 api
src/api/vod/teacher.js
getById(id) {
return request({
url: `${api_name}/getTeacher/${id}`,
method: `get`
})
},
2
3
4
5
6
组件中调用 api
methods 中定义 fetchDataById
// 根据id查询记录
fetchDataById(id) {
teacherApi.getById(id).then(response => {
this.teacher = response.data
})
},
2
3
4
5
6
页面渲染前调用 fetchDataById
// 页面渲染成功
created() {
if (this.$route.params.id) {
this.fetchDataById(this.$route.params.id)
}
},
2
3
4
5
6
# 讲师修改 - 更新
定义 api
updateById(teacher) {
return request({
url: `${api_name}/updateTeacher`,
method: `post`,
data: teacher
})
}
2
3
4
5
6
7
在 from.vue 的 methods 中定义 updateData
// 根据id更新记录
updateData() {
// teacher数据的获取
teacherApi.updateById(this.teacher).then(response => {
this.$message({
type: 'success',
message: response.message
})
this.$router.push({ path: '/vod/teacher/list' })
})
},
2
3
4
5
6
7
8
9
10
11
完善 saveOrUpdate 方法
saveOrUpdate() {
// 禁用保存按钮
this.saveBtnDisabled = true
if (!this.teacher.id) {
this.saveData()
} else {
this.updateData()
}
},
2
3
4
5
6
7
8
9
# 讲师批量删除
定义 api src/api/vod/teacher.js
batchRemove(idList) {
return request({
url: `${api_name}/removeBatch`,
method: `delete`,
data: idList
})
},
2
3
4
5
6
7
初始化组件
src/views/vod/teacher/list.vue
在 table 组件上添加 批量删除 按钮
<!-- 工具按钮 -->
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets" style="margin-top: 5px"></i>
<span style="margin-top: 5px">数据列表</span>
<el-button class="btn-add" @click="add()" style="margin-left: 10px;">添加</el-button>
<el-button class="btn-add" @click="batchRemove()" >批量删除</el-button>
</el-card>
2
3
4
5
6
7
data 定义数据
multipleSelection: []// 批量删除选中的记录列表
完善方法
// 跳转到添加表单页面
add() {
this.$router.push({
path: '/vod/teacher/create'
})
},
// 批量删除
batchRemove() {
if (this.multipleSelection.length === 0) {
this.$message.warning('请选择要删除的记录!')
return
}
this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 点击确定,远程调用ajax
// 遍历selection,将id取出放入id列表
var idList = []
this.multipleSelection.forEach(item => {
idList.push(item.id)
})
// 调用api
return teacherApi.batchRemove(idList)
}).then((response) => {
this.fetchData()
this.$message.success(response.message)
}).catch(error => {
if (error === 'cancel') {
this.$message.info('取消删除')
}
})
},
// 当多选选项发生变化的时候调用
handleSelectionChange(selection) {
console.log(selection)
this.multipleSelection = selection
},
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39