目录 一、搭建前端工程1.1、测试启动1.2、目录结构1.3、配置环境 二、后台系统登录功能2.1、分析登录流程代码2.2、编写接口 三、讲师模块的前端实现3.1、路由视图及测试讲师列表接口3.2、渲染讲师列表3.3、分页功能实现3.4、多条件查询功能3.5、讲师删除3.6、讲师添加3.7、讲师修改-回显数据3.8、讲师修改3.9、bug解决
一、搭建前端工程 1.1、测试启动
1、从资料中解压 vue-element-admin
修改为 gulicollege_ui
2、安装依赖 (安装太慢了直接放弃)npm install
2、从资料中拷贝 node_modules
文件夹到项目中 并执行如下安装依赖
npm install node-sass
npm i node-sass -D
npm install --save element-ui
3、启动 npm run dev
1.2、目录结构
.
├── build // 构建脚本
├── config // 全局配置
├── node_modules // 项目依赖模块
├── src //项目源代码
├── static // 静态资源
└── package.jspon // 项目信息和依赖配置
src
├── api // 各种接口
├── assets // 图片等资源
├── components // 各种公共组件,非公共组件在各自view下维护
├── icons //svg icon
├── router // 路由表
├── store // 存储
├── styles // 各种样式
├── utils // 公共工具,非公共工具,在各自view下维护
├── views // 各种layout
├── App.vue //***项目顶层组件***
├── main.js //***项目入口文件***
└── permission.js //认证入口
1.3、配置环境
1、package.json
{
"name": "gulicollege_ui",
"version": "3.8.0",
"license": "MIT",
"description": "谷粒学院后台管理系统",
"author": "Laptoy",
}
2、config/index.js 配置端口号
port: 9528
3、config/index.js 关闭语法检查
useEslint: false
4、config/dev.env.js
修改为访问后台端口
BASE_API: '"http://localhost:8001"',
二、后台系统登录功能 2.1、分析登录流程代码
1、src/views/login/index.vue
methods: {
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
// 触发 store 的 Login事件
this.$store.dispatch('Login', this.loginForm).then(() => {
this.loading = false
this.$router.push({ path: this.redirect || '/' })
}).catch(() => {
this.loading = false
})
} else {
console.log('error submit!!')
return false
}
})
}
}
2、src/store/modules/user.js
(这里没有使用 namespaces: true
) 所以不需要通过命名空间调用
import { login, logout, getInfo } from '@/api/login'
actions: {
// 登录
Login({ commit }, userInfo) {
const username = userInfo.username.trim()
return new Promise((resolve, reject) => {
login(username, userInfo.password).then(response => {
const data = response.data
setToken(data.token)
commit('SET_TOKEN', data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
}
3、src/api/login.js
(通过 axios 发送请求)
import request from '@/utils/request'
export function login(username, password) {
return request({
url: '/user/login',
method: 'post',
data: {
username,
password
}
})
}
4、src/utils/request.js
(封装 axios 调用)
import axios from 'axios'
import { Message, MessageBox } from 'element-ui'
import store from '../store'
import { getToken } from '@/utils/auth'
// 创建axios实例
const service = axios.create({
baseURL: process.env.BASE_API, // api 的 base_url
timeout: 5000 // 请求超时时间
})
// request拦截器
service.interceptors.request.use(
config => {
if (store.getters.token) {
config.headers['X-Token'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
return config
},
error => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
}
)
// response 拦截器
service.interceptors.response.use(
response => {
/**
* code为非20000是抛错 可结合自己业务进行修改
*/
const res = response.data
if (res.code !== 20000) {
Message({
message: res.message,
type: 'error',
duration: 5 * 1000
})
// 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
MessageBox.confirm(
'你已被登出,可以取消继续留在该页面,或者重新登录',
'确定登出',
{
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
store.dispatch('FedLogOut').then(() => {
location.reload() // 为了重新实例化vue-router对象 避免bug
})
})
}
return Promise.reject('error')
} else {
return response.data
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service
2.2、编写接口
根据前端代码分析
1、登录请求需要返回 token
2、获取用户信息请求需要返回 roles、name、avatar
1、EduLoginController (使用 @CrossOrigin 解决跨域问题)
@Api(tags = "登录模块")
@RestController
@CrossOrigin //解决跨域问题
@RequestMapping("/eduservice/user")
public class EduLoginController {
// 登录
@PostMapping("/login")
public R login() {
return R.ok().data("token", "admin");
}
// 获取信息
@GetMapping("/info")
public R info() {
return R.ok()
.data("roles", "admin")
.data("name", "Laptoy")
.data("avatar", "http://www.kaotop.com/file/tupian/20220516/480b7a82bddb4f6a9b6942c88db18d85.png");
}
// 登出
@PostMapping("/logout")
public R logOut() {
return R.ok();
}
}
2、修改 src/api/login.js
匹配后端接口
三、讲师模块的前端实现 3.1、路由视图及测试讲师列表接口
1、添加路由 - src/router/index.js
// 讲师模块路由
{
path: '/teacher',
component: Layout,
redirect: '/teacher/table',
name: '讲师管理',
meta: { title: '讲师管理', icon: 'example' },
children: [
{
path: 'table',
name: '讲师列表',
component: () => import('@/views/edu/teacher/list.vue'),
meta: { title: '讲师列表', icon: 'table' }
},
{
path: 'save',
name: '添加讲师',
component: () => import('@/views/edu/teacher/save.vue'),
meta: { title: '添加讲师', icon: 'tree' }
}
]
},
2、创建路由对应组件
创建文件夹src/views/edu/teacher
创建 list.vue
和 save.vue
组件
3、定义访问的接口地址
在src/api文件创建 teacher/teacher.js
定义访问的接口地址
import request from '@/utils/request'
export default {
// 1、获取讲师列表(多条件分页查询)
getTeacherListPage(page, limit, teacherQuery) {
return request({
url: `/eduservice/teacher/pageTeacherCondition/${page}/${limit}`,
method: 'post',
data: teacherQuery
})
}
}
4、组件页面调用定义接口方法 - list.vue
<template>
<div class="app-container">讲师列表div>
template>
<script>
import teacher from '@/api/teacher/teacher.js'
export default {
data() {
return {
list: null, // 查询之后给接口返回的数据装的集合
page: 1, // 当前页
limit: 5, // 每页显示记录数
teacherQuery: {}, // 条件封装对象
total: 0 // 总记录数
}
},
created() {
this.getList()
},
methods: {
// 获取讲师列表
getList() {
teacher.getTeacherListPage(this.page, this.limit, this.teacherQuery)
.then((resp) => {
this.list = resp.data.data
console.log(this.list)
this.total = resp.data.total
console.log(this.total)
})
.catch((err) => {
console.log(err)
})
}
}
}
script>
5、测试
3.2、渲染讲师列表
1、ui
<template>
<div>
<el-table :data="list" style="width: 100%" border fit highlight-current-row element-loading-text="数据加载中">
<el-table-column prop="date" label="序号" width="70" align="center">
<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="80">
<template slot-scope="scope">
{{ scope.row.level === 1 ? "高级讲师" : "首席讲师" }}
template>
el-table-column>
<el-table-column prop="intro" label="资历" />
<el-table-column prop="gmtCreate" label="添加时间" width="160" />
<el-table-column prop="sort" label="排序" width="60" />
<el-table-column label=" *** 作" width="200" align="center">
<template slot-scope="scope">
<router-link :to="'/edu/teacher/edit/' + scope.row.id">
<el-button type="primary" size="mini" icon="el-icon-edit">修改el-button>
router-link>
<el-button type="danger" size="mini" icon="el-icon-delete" @click="removeDataById(scope.row.id)">删除el-button>
template>
el-table-column>
el-table>
div>
template>
2、展示
3.3、分页功能实现
1、ui
<div>
<el-table>
el-table>
<el-pagination :total="total" :page-size="limit" :current-page="page"
background layout="prev, pager, next,total,jumper"
style="padding: 30px 0; text-align: center"
@current-change="getList" />
div>
2、方法
3、展示
3.4、多条件查询功能
1、ui
<el-form :inline="true" class="demo-form-inline" style="margin-left: 20px; margin-top: 12px;">
<el-form-item label="名称">
<el-input v-model="teacherQuery.name" placeholder="请输入名称">el-input>
el-form-item>
<el-form-item label="级别">
<el-select v-model="teacherQuery.level" placeholder="讲师头衔">
<el-option label="高级讲师" :value="1">el-option>
<el-option label="特级讲师" :value="2">el-option>
el-select>
el-form-item>
<el-form-item label="添加时间">
<el-time-picker placeholder="选择开始时间" v-model="teacherQuery.begin" value-format="yyyy-MM-dd HH:mm:ss" default-time="00:00:00" type="datetime">el-form-item>
<el-form-item>
<el-time-picker placeholder="选择截止时间" v-model="teacherQuery.end" value-format="yyyy-MM-dd HH:mm:ss" default-time="00:00:00" type="datetime">el-time-picker>
el-form-item>
<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-item>
el-form>
2、方法
export default {
methods: {
// 清空查询栏
resetData() {
// 表单输入项数据清空
this.teacherQuery = {};
// 查询所有讲师数据
this.getList();
},
}
}
3、展示
3.5、讲师删除
1、定义API - src/api/teacher/teacher.js
export default {
...
// 2、根据id删除讲师
removeById(id) {
return request({
url: `/eduservice/teacher/deleteTeacherById/${id}`,
method: 'delete',
})
}
}
2、定义 methods
// 根据id删除讲师
removeDataById(id) {
this.$confirm("此 *** 作将永久删除该讲师记录, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
teacher.removeById(id)
.then((resp) => {
this.$message({
type: "success",
message: "删除成功!",
});
//刷新页面
this.getList();
});
});
}
3.6、讲师添加
1、定义API
// 添加讲师
saveTeacher(teacher) {
return request({
url: `/eduservice/teacher/save`,
method: `post`,
data: teacher
})
}
2、初始化 save.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-input-number v-model="teacher.sort" controls-position="right" :min="0" />
el-form-item>
<el-form-item label="讲师头衔">
<el-select v-model="teacher.level" clearable placeholder="选择讲师头衔">
<el-option :value="1" label="高级讲师" />
<el-option :value="2" label="首席讲师" />
el-select>
el-form-item>
<el-form-item label="讲师资历">
<el-input v-model="teacher.career" placeholder="职业生涯、获得的证书、其他含金量的经历" />
el-form-item>
<el-form-item label="讲师简介">
<el-input v-model="teacher.intro" :rows="3" type="textarea" />
el-form-item>
<el-form-item>
<el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate">保存el-button>
el-form-item>
el-form>
div>
template>
<script>
//引入对应的新增api方法
import teacherApi from "@/api/teacher/teacher.js";
export default {
data() {
return {
teacher: {
name: "",
sort: 0,
level: 1,
career: "",
intro: "",
avatar: "",
},
saveBtnDisabled: false, // 保存按钮是否禁用,
};
},
methods: {
saveOrUpdate() {
this.saveBtnDisabled = true; // 防止表单多次提交,保存后就禁用按钮
this.saveData();
},
// 保存
saveData() {
teacherApi.saveTeacher(this.teacher).then((resp) => {//添加成功
//提示信息
this.$message({
message: "添加讲师记录成功",
type: "success",
});
//回到讲师列表 路由跳转
this.$router.push({ path: '/teacher/table' })
});
},
},
};
script>
3、展示
3.7、讲师修改-回显数据
1、添加路由 - 实际上以保存组件作为模板跳转
// 讲师模块路由
{
path: '/teacher',
...
children: [
...
{
path: 'edit/:id',
name: '修改讲师',
component: () => import('@/views/edu/teacher/save.vue'),
meta: { title: '修改讲师', noCache: true },
hidden: true
}
]
},
2、list.vue - 通过路由携带id进行修改
3、定义API 根据id查询信息
//根据id查询讲师
updateById(id) {
return request({
url: `/eduservice/teacher/getById/${id}`,
method: `get`,
})
}
4、根据id回显信息 - save.vue
// 修改请求--根据id回显信息
getInfoById(id) {
teacherApi.updateById(id)
.then(resp => {
this.teacher = resp.data.data
})
}
5、钩子函数添加判断
created() {
// 判断路由跳转时是否携带参数
if (this.$route.params && this.$route.params.id) {
this.getInfoById(this.$route.params.id)
}
}
6、展示 - 点击修改后数据回显
3.8、讲师修改
1、定义API
// 修改讲师信息
updateTeacherInfo(teacher) {
return request({
url: `/eduservice/teacher/updateById`,
method: `post`,
data: teacher
})
}
2、修改方法 - save.vue
// 修改请求--修改讲师信息
updateTeacher() {
teacherApi.updateTeacherInfo(this.teacher).then((resp) => {
this.$message({
message: "修改讲师记录成功",
type: "success",
});
this.$router.push({ path: "/teacher/table" });
});
}
3、区分新增或修改请求(通过路由跳转是否携带id进行判断)
saveOrUpdate() {
if (!this.teacher.id) {
//没有id值,做【新增 *** 作】
this.saveBtnDisabled = true; // 只能点击一次保存 *** 作,防止表单多次保存
this.saveData();
} else {
//有id值,做【修改 *** 作】
this.updateTeacher()
}
},
3.9、bug解决
场景
用户点击修改按钮后不想修改了反而想添加讲师点击添加讲师按钮,此时表单数据未清空将 回显数据流程 封装为
init()
方法(当路由中有id时回显数据,没有就清空表单)通过 watch属性 观察路由是否发生变化,变化那就重新执行 init()
进行页面加载
旧代码
created() {
// 判断路由跳转时是否携带参数
if (this.$route.params && this.$route.params.id) {
this.getInfoById(this.$route.params.id)
}
}
优化后
methods: {
...
// 初始化页面
init() {
if (this.$route.params && this.$route.params.id) {
this.getInfoById(this.$route.params.id)
} else {
this.teacher = {};
}
},
},
created() {
this.init();
},
watch: {
// 当路由发生变化时初始化页面
$route(to, from) {
this.init();
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)