在线教育_Day05-项目讲师管理模块前端开发

简介: 在线教育_Day05-项目讲师管理模块前端开发

一、vue-element-admin

1.1 简介

vueAdmin-template是基于vue-element-admin的一套后台管理系统基础模板(最少精简版),可作为模板进行二次开发。

功能:介绍 | vue-element-admin功能

GitHub地址:https://github.com/PanJiaChen/vue-element-admin

建议:你可以在 vue-admin-template 的基础上进行二次开发,把 vue-element-admin当做工具箱,想要什么功能或者组件就去 vue-element-admin 那里复制过来。

1.2 安装

# 解压压缩包

# 进入目录

cd vue-element-admin-master

# 安装依赖

npm install

# 启动。执行后,浏览器自动弹出并访问http://localhost:9527/

npm run dev

二、项目的创建和基本配置

2.1 项目信息基本修改

2.1.1 创建项目

将vue-admin-template-master重命名为gl-edu

2.1.2 修改项目信息

修改项目中的package.json文件

{

   "name": "gl-edu",

   ......

   "description": "在线教育后台管理系统",

   "author": "zjl <459380074@qq.com>",

   ......

}

2.1.3 修改端口号

如何需要修改端口号,可以在config/index.js中修改

port: 9528

2.1.4 项目的目录结构

.

├── 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 //认证入口

2.1.5 运行项目

npm run dev

2.2 登录页修改

src/views/login/index.vue(登录组件)中的第4行

<h3 class="title">在线教育后台管理系统</h3>

src/views/login/index.vue(登录组件)中的第28行

<el-button :loading="loading" type="primary" style="width:100%;" @click.native.prevent="handleLogin">

   登录

</el-button>

2.3 页面零星修改

2.3.1 标题

index.html(项目的html入口)

<title>在线教育后台管理系统</title>

修改后热部署功能,浏览器自动刷新

2.3.2 国际化设置

打开 src/main.js(项目的js入口),第7行,修改语言为 zh-CN,使用中文语言环境,例如:日期时间组件

import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n

2.3.3 icon

复制 favicon.ico 到根目录

2.3.4 导航栏文字

src/views/layout/components(当前项目的布局组件)Navbar.vue文件中第13行

<el-dropdown-item>

   首页

</el-dropdown-item>

src/views/layout/components(当前项目的布局组件)Navbar.vue文件中第17行

<span style="display:block;" @click="logout">退出</span>

2.3.5 面包屑文字

src/components(可以在很多项目中复用的通用组件)

src/components/Breadcrumb/index.vue第38行

meta: { title: '首页' }

三、Eslint语法规范型检查

3.1 ESLint简介

JavaScript 是一个动态的弱类型语言,在开发中比较容易出错。因为没有编译程序,为了寻找 JavaScript 代码错误通常需要在执行过程中不断调适。

ESLint 是一个语法规则和代码风格的检查工具,可以用来保证写出语法正确、风格统一的代码。让程序员在编码的过程中发现问题而不是在执行的过程中。

3.2 语法规则

ESLint 内置了一些规则,也可以在使用过程中自定义规则。

本项目的语法规则包括:两个字符缩进,必须使用单引号,不能使用双引号,语句后不可以写分号,代码段之间必须有一个空行等。

3.3 确认开启语法检查

打开 config/index.js,配置是否开启语法检查

useEslint: true,

可以关闭语法检查,建议开启,养成良好的编程习惯。

3.4 ESLint插件安装

vs code的ESLint插件,能帮助我们自动整理代码格式

3.5 插件的扩展设置

选择vs code左下角的“设置”, 打开 VSCode 配置文件,添加如下配置

"files.autoSave": "off",

"eslint.validate": [

 "javascript",

 "javascriptreact",

 "vue-html",

 {

   "language": "vue",

   "autoFix": true

 }

],

"eslint.run": "onSave",

"eslint.autoFixOnSave": true

四、登录改造

前台页面登录按钮访问的地址是:https://easy-mock.com/mock/5950a2419adc231f356a6636/vue-admin/user/login。目前这个地址已经失效,如果我们点击登录,会出现报错的问题,登录不进去。

所以接下来,我们先写一个简单的登录接口,为了我们能登录进去,做一些功能。后期我们再一次完善该功能

把登录地址改造成:https://localhost:8001

4.1 修改配置文件请求地址

config文件夹里面有dev.env.js文件

4.2 编写后台登录功能

在登录时会调用两个方法,login登录方法和info登录之后获取用户信息的方法。所以在后台我们要创建两个方法实现登录。

4.2.1 编写EduLoginController

在edu-service模块中创建EduLoginController

@RestController

@RequestMapping("/eduservice/user")

public class EduLoginController {



   @RequestMapping("/login")

   public R login() {


       return R.ok().data("token","admin");

   }


   @RequestMapping("/info")

   public R info() {

       HashMap<Object, Object> objectObjectHashMap = new HashMap<>();

       return R.ok().data("roles", "[admin]").data("name", "admin").data("avatar", "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");

   }


}

4.2.2 修改前台页面访问路径

修改api文件夹login.js修改本地接口路径

4.3 解决跨域问题

以上内容我们修改之后,重启前端服务器和启动后台8001商品,进行访问登录,还是会出现无法登录问题。

此时我们打开浏览器控制台,查看报错信息。出现了跨域问题。

4.3.1 什么是跨域

通过一个地址去访问另外一个地址,这个过程如果有三个地方有任何一个地方不一样,就会出现跨域问题。

  • 访问协议
  • ip地址
  • 端口号

4.3.2 跨域解决方式

  • 在Controller方法添加@CrossOrigin注解

  • 使用网关解决(后面讲)

在今天我们使用注解方式解决跨域问题。再次进行访问。

五、前端框架使用步骤

5.1 添加路由

在src/router中的index.js文件添加我们想要的路由。

5.2 点击路由设置相应页面

点击某个路由我们要显示对应的页面。设置路由方式如下图:

在views文件夹下有一个文件table子文件夹,在table文件夹下有一个页面index文件,这个文件就是对应的页面。我们做讲师相应的模块时,就可以按照这个方式进行设置相应的页面。

5.3 创建文件和定义接口和参数

在api文件夹下,创建js文件,定义接口地址和参数。

5.4 在页面文件中引入js文件

在对应的vue页面文件中,引入定义好的接口js文件,调用方法实现功能。

引入语法

import 对象名 from '@/api/...'

5.5 使用Element-ui展示数据

以上工作做完之后,就可以在vue页面中,数据展示等。这里以table.vue为例进行展示。

template是elementui中的写法,用来展示布局

六、后台系统路由实现分析

6.1 入口文件中调用路由

在src/main.js

......

import router from './router' //引入路由模块

......

new Vue({

 el: '#app',

 router, //挂载路由

 store,

 render: h => h(App)

})

6.2 路由模块中定义路由

src/router/index.js

......

export const constantRouterMap = [

 ......

]


export default new Router({

 ......

 routes: constantRouterMap

})    

6.3 在线教育路由定义

6.3.1 复制icon图标

将vue-element-admin/src/icons/svg 中的图标复制到 gl-edu项目中

6.3.2 修改路由

修改 src/router/index.js 文件,重新定义constantRouterMap

注意:每个路由的name不能相同

export const constantRouterMap = [

 { 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: '/edu/teacher',

   component: Layout,

   redirect: '/edu/teacher/list',

   name: 'Teacher',

   meta: { title: '讲师管理', icon: 'peoples' },

   children: [

     {

       path: 'list',

       name: 'EduTeacherList',

       component: () => import('@/views/edu/teacher/list'),

       meta: { title: '讲师列表' }

     },

     {

       path: 'create',

       name: 'EduTeacherCreate',

       component: () => import('@/views/edu/teacher/save'),

       meta: { title: '添加讲师' }

     },

     {

       path: 'edit/:id',

       name: 'EduTeacherEdit',

       component: () => import('@/views/edu/teacher/form'),

       meta: { title: '编辑讲师', noCache: true },

       hidden: true

     }

   ]

 },


 { path: '*', redirect: '/404', hidden: true }

]

6.3.3 创建vue组件

在src/views文件夹下创建以下文件夹和文件

6.3.4 list.vue

<template>

 <div class="app-container">

   讲师列表

 </div>

</template>

6.3.5 save.vue

<template>

 <div class="app-container">

   讲师添加

 </div>

</template>

6.3.5 重启进行测试

七、讲师前台功能实现

7.1 分页列表

7.1.1 定义api

创建文件 src/api/edu/teacher/teacher.js

import request from '@/utils/request'


export default {

   // 此参数的名称 要与后台接口的参数名称一致

   getTeacherListPage(page,limit,teacherQuery) {

       return request({

       //   url: '/eduservice/edu-teacher/pageTeacherCondition/'+page+'/'+limit,

       // 推荐方式

         url: `/eduservice/edu-teacher/pageTeacherCondition/${page}/${limit}`,

         method: 'post',

       //   params 后台使用RequestBody接收数据,是要的json数据,所以不能使用params进行传参

         data: teacherQuery // 把data对象转换成json进行传参

       })

   }

}

7.1.2 初始化vue组件

src/views/edu/teacher/list.vue

<template>

 <div class="app-container">

   讲师列表

 </div>

</template>


<script>

import teacher from '@/api/edu/teacher/teacher.js'

export default {


 data() {// 定义数据

     return {}

 },

   

 created() { // 当页面加载时获取数据

   

 },

   

 methods: {

   

 }

}

</script>

7.1.3 定义data

 data() {

   return {

     listLoading: true, // 是否显示loading信息

     list: null, // 数据列表

     total: 0, // 总记录数

     page: 1, // 页码

     limit: 10, // 每页记录数

     teacherQuery: {}// 查询条件

   }

 },

7.1.4 定义methods

methods: {

   getList(){

       teacher.getTeacherListPage(this.page,this.limit,this.teacherQuery)

           .then(response =>{ // 请求成功所调用的函数

           console.log(response)

       })

           .catch(error =>{ // 请求成功所调用的函数

           console.log(error)

       })

   },

}

进行测试,接口是否正常,最好都要重启前后台的服务器进行测试

7.1.5 填充后台传过来的数据

在method方法中,接收后台真实传递过来的数据,最后在页面列表中显示

getList() {

   teacher

       .getTeacherListPage(this.page, this.limit, this.teacherQuery)

       .then((response) => {

       this.listLoading = false

       // 请求成功所调用的函数

       // console.log(response)

       this.list = response.data.rows;

       this.total = response.data.total;

       console.log("总记录数:" + this.list);

       console.log("total:" + this.total);

   })

       .catch((error) => {

       // 请求成功所调用的函数

       console.log(error);

   });

},

7.1.6 表格渲染

将接收到的列表数据,渲染到页面上

<!-- 表格 -->

<el-table

         v-loading="listLoading"

         :data="list"

         element-loading-text="数据加载中"

         border

         fit

         highlight-current-row>


   <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 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>

7.1.7 分页组件

  • 添加分页组件

<!-- 分页 -->

<el-pagination

     :current-page="page"

     :page-size="limit"

     :page-sizes="[5, 10, 20, 30]"

     :total="total"

     style="padding: 30px 0; text-align: center"

     layout="total, sizes, prev, pager, next, jumper"

     @size-change="handleSizeChange"

     @current-change="handleCurrentChange"

   />

  • 修改分页展示为中文提示

在main.js中引入中文element-ui包

  • import locale from 'element-ui/lib/locale/lang/zh-CN'

7.1.8 顶部查询表单

<!--查询表单-->

   <el-form :inline="true" class="demo-form-inline">

     <el-form-item size="medium">

       <el-input v-model="teacherQuery.name" placeholder="讲师名" />

     </el-form-item>


     <el-form-item>

       <el-select v-model="teacherQuery.level" clearable placeholder="讲师头衔" size="medium">

         <el-option :value="1" label="高级讲师" />

         <el-option :value="2" label="首席讲师" />

       </el-select>

     </el-form-item>


     <el-form-item label="添加时间">

       <el-date-picker

         v-model="teacherQuery.begin"

         type="datetime"

         placeholder="选择开始时间"

         value-format="yyyy-MM-dd HH:mm:ss"

         default-time="00:00:00"

         size="medium"

       />

     </el-form-item>

     <el-form-item>

       <el-date-picker

         v-model="teacherQuery.end"

         type="datetime"

         placeholder="选择截止时间"

         value-format="yyyy-MM-dd HH:mm:ss"

         default-time="00:00:00"

         size="medium"

       />

     </el-form-item>


     <el-button type="primary" size="medium" icon="el-icon-search" @click="fetchData()"

       >查询</el-button

     >

     <el-button type="default" size="medium" @click="resetData()">清空</el-button>

   </el-form>

注意:

element-ui的 date-picker组件默认绑定的时间值是默认世界标准时间,和中国时间差8小时

设置 value-format="yyyy-MM-dd HH:mm:ss" 改变绑定的值

点击按键清空输入内容的方法

// 表单清空

resetData() {

   this.teacherQuery = {}

}

7.1.9 测试

7.2 删除功能

7.2.1 定义api

在src/api/edu/teacher/teacher.js下添加以下方法

removeById(teacherId) {

     return request({

         url: `/eduservice/edu-teacher/${teacherId}`,

         method: 'delete'

     })

 }

7.2.2 定义methods

src/views/edu/teacher/list.vue

使用MessageBox 弹框组件

// 根据id删除讲师

   removeDataById(id) {

     this.$confirm("此操作将永久删除该数据, 是否继续?", "提示", {

       confirmButtonText: "确定",

       cancelButtonText: "取消",

       type: "warning",

     }).then(()=>{

       teacher.removeById(id).then(response =>{

           this.$message({

               type: 'success',

               message: '删除成功!'

           })

           this.getList()

       })

     

     })

   },

7.3 新增功能

7.3.1 定义api

在src/api/edu/teacher/teacher.js下添加以下方法

addTeacher(teacher) {

   return request({

     url: `/eduservice/edu-teacher/addTeacher`,

       method: 'post',

       data: teacher

   })

 }

7.3.2 初始化组件

src/views/edu/teacher/save.vue

html页面代码

<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="请选择">

         <!--

           数据类型一定要和取出的json中的一致,否则没法回填

           因此,这里value使用动态绑定的值,保证其数据类型是number

         -->

         <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"/>

     </el-form-item>

     <el-form-item label="讲师简介">

       <el-input v-model="teacher.intro" :rows="10" type="textarea"/>

     </el-form-item>


     <!-- 讲师头像:TODO -->


     <el-form-item>

       <el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate">保存</el-button>

     </el-form-item>

   </el-form>

 </div>

</template>

js代码

<script>

   export default {

data() {

   return {

       teacher: {

           name: '',

           sort: 0,

           level: 1,

           career: '',

           intro: '',

           avatar: ''

       },

       saveBtnDisabled: false // 保存按钮是否禁用,

   }

},


   methods: {

// 该方法要实现添加和修改两个功能

       saveOrUpdate() {

           this.saveBtnDisabled = true

           this.saveTeacher()

       },


           // 保存

           saveTeacher() {


           }


   }

}

</script>

7.3.3 实现新增功能

引入teacher api模块

import teacher from "@/api/edu/teacher/teacher.js";

完善saveTeacher方法

// 保存
saveTeacher() {
    teacher.addTeacher(this.teacher).then(response => {
        this.$message({
            type: 'success',
            message: '添加成功!'
        })
        // 重新查询数据,路由跳转
        this.$router.push({path:"/teacher/table"})
    })
},

7.4 回显功能

7.4.0 添加路由

在src/router下index.js文件,添加编辑功能路由

{
        path: 'edit/:id',
        name: '编辑讲师',
        component: () => import('@/views/edu/teacher/save'),
        meta: { title: '编辑讲师', icon: 'tree' },
        hidden:true // 不显示
}

修改list.vue,设置修改按钮路由跳转路径

<router-link :to="'/teacher/edit/' + scope.row.id">

   <el-button type="primary" size="mini" icon="el-icon-edit">修改</el-button>

</router-link>

7.4.1 定义api

在src/api/edu/teacher/teacher.js下添加以下方法

// 根据id查询讲师
  getTeacherById(teacherId) {
    return request({
        url: `/eduservice/edu-teacher/getTeacherById/${teacherId}`,
        method: 'get'
    })
  }

7.4.2 组件中调用api

在save.vue文件的methods中定义根据讲师id查询的方法

// 根据讲师id查询讲师

getTeacherInfo(id){

   teacher.getTeacherById(id).then(response =>{

       this.teacher= response.data.item

   })

},

7.4.3 页面渲染前调用getTeacherInfo

该页面是添加和修改共用一个页面,所以还是要判断什么时候是修改操作,什么时候是添加操作。

我们可以判断路径中是否有讲师id,如果有讲师id就是修改操作,反之则是添加操作。

 created() {

   console.log('created')

   if (this.$route.params && this.$route.params.id) {

     const id = this.$route.params.id

     this.getTeacherInfo(id)

   }

 }

7.5 更新操作

7.5.1 定义api

在src/api/edu/teacher/teacher.js下添加以下方法

updateTeacherById(teacher) {
    return request({
        url: `/eduservice/edu-teacher/updateTeacherById`,
        method: 'post',
        data: teacher
    })
}

7.5.2 组件中调用api

在save.vue中的methods中定义updateTeacher方法

// 根据id更新记录 
updateTeacher() {
        this.saveBtnDisabled = true
        teacher.updateTeacherById(this.teacher).then(response => {
             this.$message({
                type: 'success',
                message: '修改成功!'
            })
            // 重新查询数据,路由跳转
             this.$router.push({path:"/teacher/table"})
        })
    }
7.5.3 完善saveOrUpdate方法
saveOrUpdate() {
    // 判断是修改还是添加
    // 根据teacher是否有id
    this.saveBtnDisabled = true;
    if(!this.teacher.id){
        this.saveTeacher()
    }else{
        this.updateTeacher()
    }
}

7.6 存在问题

vue-router导航切换 时,如果两个路由都渲染同个组件,组件会重(chong)用,

组件的生命周期钩子(created)不会再被调用, 使得组件的一些数据无法根据 path的改变得到更新

因此:

1、我们可以在watch中监听路由的变化,当路由变化时,重新调用created中的内容

2、在init方法中我们判断路由的变化,如果是修改路由,则从api获取表单数据,

如果是新增路由,则重新初始化表单数据

export default {

   // 监听路由变化

watch: {
        $route(to, from) {
            console.log("watch $route");
            this.init();
        },
    },
    created() {
        console.log("created");
        // if (this.$route.params && this.$route.params.id) {
        //   const id = this.$route.params.id;
        //   this.getTeacherInfo(id);
        // } else {
        //   this.teacher = {};
        // }
        this.init()
    },
    methods: {
        // 抽取判断路径中是否有参数方法
        init() {
            if (this.$route.params && this.$route.params.id) {
                const id = this.$route.params.id;
                this.getTeacherInfo(id);
            } else {
                this.teacher = {};
            }
        },
    }
}
</script>
相关文章
|
2天前
|
前端开发 Shell 容器
前端练习小项目——视觉冲击卡片
前端练习小项目——视觉冲击卡片
|
12天前
|
前端开发 JavaScript 架构师
Webpack模块联邦:微前端架构的新选择
Webpack的模块联邦是Webpack 5引入的革命性特性,革新了微前端架构。它允许独立的Web应用在运行时动态共享代码,无需传统打包过程。基本概念包括容器应用(负责加载协调)和远程应用(独立应用,可暴露模块)。实现步骤涉及容器和远程应用的`ModuleFederationPlugin`配置,以及在应用间导入和使用远程模块。模块联邦的优势在于独立开发、按需加载、版本管理和易于维护。通过实战案例展示了如何构建微前端应用,包括创建容器和远程应用,以及消费远程组件。高级用法涉及动态加载、路由集成、状态管理和错误处理。
16 3
|
12天前
|
缓存 前端开发 JavaScript
Webpack作为模块打包器,为前端项目提供了高度灵活和可配置的构建流程
【6月更文挑战第12天】本文探讨了优化TypeScript与Webpack构建性能的策略。理解Webpack的解析、构建和生成阶段是关键。优化包括:调整tsconfig.json(如关闭不必要的类型检查)和webpack.config.js选项,启用Webpack缓存,实现增量构建,代码拆分和懒加载。这些方法能提升构建速度,提高开发效率。
30 3
|
12天前
|
Web App开发 运维 前端开发
从0开始搭建一个前端项目的架子
从0开始搭建一个前端项目的架子
14 1
|
13天前
|
缓存 JavaScript 前端开发
前端小白也能懂:ES模块和CommonJS的那些事
【6月更文挑战第1天】在JavaScript的世界中,模块化是构建大型应用的关键。ES模块(ESM)和CommonJS是两种主流的模块系统,它们各自有着不同的特性和使用场景。你了解它们的区别吗?
37 2
|
19天前
|
存储 前端开发 Windows
对于莫名其妙使用smarttomcat上传前端项目失败,上传css等静态资源失败等原因,及解决方法
对于莫名其妙使用smarttomcat上传前端项目失败,上传css等静态资源失败等原因,及解决方法
|
27天前
|
前端开发 JavaScript
前端综合练手小项目
前端综合练手小项目
|
11天前
|
JavaScript 前端开发 Java
【Vue实战项目】学完前端基础后,可能你还需要掌握这些才能接手开发项目
【Vue实战项目】学完前端基础后,可能你还需要掌握这些才能接手开发项目
24 0
|
20天前
|
JSON 前端开发 JavaScript
前端Ajax、Axios和Fetch的用法和区别笔记
前端Ajax、Axios和Fetch的用法和区别笔记
27 2
|
1月前
|
存储 前端开发 JavaScript
前端笔记_OAuth规则机制下实现个人站点接入qq三方登录
前端笔记_OAuth规则机制下实现个人站点接入qq三方登录
50 1