【在线教育】- 前端环境搭建&讲师CURD前端实现

2023-11-01

在线教育


上篇: 【在线教育】- 讲师模块功能实现

一、在线教育前端环境搭建

1.1、vue-element-admin 概述

  • vue element admin 是 基于 Element ui一个半成品项目,已经完成了通用功能。

    • 封装了一些特有的js
    • 封装了一些组件
  • vue-element-admin是基于element-ui 的一套后台管理系统集成方案。

1.2、vue-element-admin-master安装

# 解压压缩包
# 进入目录
cd vue-element-admin-master
# 安装依赖
npm install
# 启动。执行后,浏览器自动弹出并访问http://localhost:9527/
npm run dev

1.3、vue-element-template介绍(了解)

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

  • GitHub地址

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

1.4、vue-element-template安装(了解)

# 解压压缩包
# 进入目录
cd vue-admin-template-master
# 安装依赖
npm install
# 启动。执行后,浏览器自动弹出并访问http://localhost:9527/
npm run dev

二、后台管理系统前端优化

2.1、修改项目信息(可选)

  • package.json
  "name": "zx-study",
  "version": "3.1.0",
  "description": "在线教育后台管理系统",
  "author": "XiaoXin <panfree23@gmail.com>",

package.json

2.2、修改端口号(可选)

  • 在element-ui-admin 最新版本中,使用vue-cli@3构建项目,
  • vue-cli@3构建的项目,核心配置文件 vue.config.js
  • 修改端口号,有3种方式:
  • 方式1:默认端口号

默认端口号

  • 方式2:npm 配置端口号(注意=等左右没有空格)
npm run dev --port=8888

npm 配置端口号

  • 方式3:vue 运行环境中配置端口号
    vue 运行环境中配置端口号
port=7777

在这里插入图片描述

2.3、项目的目录结构

  • 根目录:

.
├── build // 构建脚本

├── mock // 模拟数据服务

├── node_modules // 项目依赖模块 【*】

├── plop-templates // 模块生成工具

├── public // 静态资源目录,build之后,public目录下内容不合并,不压缩,直接拷贝到dist中

├── src //项目源代码 【**】

├── test // 测试程序目录

├── .env.development//开发环境下配置文件,VUE_APP_BASE_API访问路径前缀【*】

├── .env.production //生产环境下配置文件,VUE_APP_BASE_API访问路径前缀

├── package.json // 项目信息和依赖配置 【*】

└── vue.config.js // vue的核心配置文件 【**】

  • src目录

src

├── api // 接口目录 ,发送ajax代码 【**】

├── assets //静态资源目录,在build时,资源进行压缩、合并等操作。

├── components //公共组件目录,非公共组件在各自view下维护

├── directive //指令目录

├── filters // 过滤器目录

├── icons //svg icon

├── router // 路由表 【**】

├── store // 存储 vuex 【**】

├── styles // 各种样式

├── utils // 公共工具,非公共工具,在各自view下维护【*】

├── views // 各种layout 项目中所有的页面都放在此处【**】

├── vendor // 工具(excel、zip)

├── App.vue //项目顶层组件 【**】

├── main.js //项目入口文件 【*】

├── permission.js //认证入口【*】

└── settings.js 项目内容配置文件(项目标题)

2.4、运行项目

npm run dev

2.5、登录页面修改

  • src/views/login/index.vue(登录组件),将Login修改成登录
    在这里插入图片描述

2.6、页面零星修改

2.6.1、标题

在这里插入图片描述

2.6.2、国际化设置

  • 打开 src/main.js,修改element ui 的语言为 zh-CN,使用中文语言环境,例如:日期时间组件
import enLang from 'element-ui/lib/locale/lang/zh-CN' //i18n

在这里插入图片描述

2.6.3、导航栏文字

在这里插入图片描述

  • src/layout/index.vue 布局核心页面

    • src/layout/components/Navbar.vue 导航页面
      在这里插入图片描述
<el-dropdown-menu slot="dropdown">
  <router-link to="/profile/index">
	<el-dropdown-item>Profile</el-dropdown-item>
  </router-link>
  <router-link to="/">
	<el-dropdown-item>控制台</el-dropdown-item>
  </router-link>
  <a target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/">
	<el-dropdown-item>Github</el-dropdown-item>
  </a>
  <a target="_blank" href="https://panjiachen.gitee.io/vue-element-admin/">
	<el-dropdown-item>在线演示</el-dropdown-item>
  </a>
  <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/">
	<el-dropdown-item>Docs帮助文档</el-dropdown-item>
  </a>
  <el-dropdown-item divided @click.native="logout">
	<span style="display:block;">退出</span>
  </el-dropdown-item>
</el-dropdown-menu>

在这里插入图片描述

2.6.4、关机校验(必做)

  • element-ui-admin 默认使用 eslint 代码检查工具
  • 例如:注释后面没有添加空格
    在这里插入图片描述
  • 方式1:忽略所有文件的校验
    在这里插入图片描述
  • 方式2:关闭提示,在vue.config.js文件中,将 lintOnSave 修改成 false
  // 校验默认开发状态开启
  // lintOnSave: process.env.NODE_ENV === 'development',
  lintOnSave: false,

在这里插入图片描述

三、前端路由实现分析

3.1、入口文件中调用路由

  • src/main.js
    在这里插入图片描述

3.2、定义路由模块

  • src/router/index.js
    在这里插入图片描述
  • 步骤1:创建自定义路由文件 @/router/modules/teacher.js
  • 步骤2:导入自定义路由文件
import teacherRouter from './modules/teacher'      //自定义模块--老师模块
  • 步骤3:启用自定义模块路由
 teacherRouter,      //自定义模块--老师模块

3.3、编写路由模块文件

  • 创建 @/router/modules/teacher.js
    在这里插入图片描述

3.3.1、配置一个子路由

  • 修改teacher.js
/** When your routing table is too long, you can split it into small modules **/

import Layout from '@/layout'

const teacherRouter = {
  path: '/teacher',           // 当前模块前缀路径,必须以/开头
  component: Layout,          // 采用布局组件显示当前模块【默认】
  redirect: '/teacher/list',  // “教师管理”默认显示路由
  name: '教师管理',            // 路由名称
  meta: {
    title: '教师管理',         // 一级菜单名称,children.length==0 隐藏
    icon: 'table'             // 一级菜单图标,children.length==0 隐藏
  },
  children: [
    {
      path: 'list',
      component: () => import('@/views/edu/teacher/list'),
      name: '教师列表',
      meta: { title: '教师列表' }   //二级菜单名称
    }
  ]
}
export default teacherRouter

在这里插入图片描述

3.3.2、配置多个子路由

  • 修改teacher.js,添加add子路由
/** When your routing table is too long, you can split it into small modules **/

import Layout from '@/layout'

const teacherRouter = {
  path: '/teacher',           // 当前模块前缀路径,必须以/开头
  component: Layout,          // 采用布局组件显示当前模块【默认】
  redirect: '/teacher/list',  // “教师管理”默认显示路由
  name: '教师管理',            // 路由名称
  meta: {
    title: '教师管理',         // 一级菜单名称,children.length==0 隐藏
    icon: 'table'             // 一级菜单图标,children.length==0 隐藏
  },
  children: [
    {
      path: 'list',
      component: () => import('@/views/edu/teacher/list'),
      name: '教师列表',
      meta: { title: '教师列表', icon: 'list' }   //二级菜单名称
    },
    {
      path: 'add',
      component: () => import('@/views/edu/teacher/add'),
      name: '添加教师',
      meta: { title: '添加教师', icon: 'edit'  }   //二级菜单名称
    }
  ]
}
export default teacherRouter

在这里插入图片描述

3.3.3、编写教师路由对应文件

在这里插入图片描述

  • 创建列表页面 `@/views/edu/teacher/list.vue
<template>
  <div>
    教师管理
  </div>
</template>
  • 创建添加页面 `@/views/edu/teacher/list.vue
<template>
  <div>
    添加
  </div>
</template>

四、后端接口分析

在这里插入图片描述

4.1、访问前缀

在这里插入图片描述

  • 修改 `.env.development
# just a flag
ENV = 'development'

# base api
# VUE_APP_BASE_API = '/dev-api'
VUE_APP_BASE_API = 'http://localhost:10010/'

4.2、axios工具类配置

4.2.1、查看工具类

  • element ui admin 提供了对原生axios进行了增强的工具类

  • 位置:@/utils/request.js

  • 内容:

// 导入axios
import axios from 'axios'

// 创建axios实例,并使用 VUE_APP_BASE_API 确定的访问前缀
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})

// 请求处理(略)
service.interceptors.request.use(...)
                                 
// 响应处理(略)
service.interceptors.response.use(...)  

// 返回处理后的axios
export default service

4.2.2、修改工具类

  • 完善工具类,打印错误提示信息
// 请求异常时,打印提示(路径等,数据等)
console.info(response.config, res)

在这里插入图片描述

4.2.3、禁用模拟数据

在这里插入图片描述

4.3、自定义后端接口

  • 为了方面后期程序的维护,统一将所有axios访问路径,抽取到 @/api下,且一个模块创建一个js文件。

4.3.1、修改用户登录文件

  • 修改 `@/api/user.js
    在这里插入图片描述
import axios from '@/utils/request'

export function login(user) {
  //return axios.post('/user-service/user/login',user);
  // 临时模拟
  return axios.post('/teacher-service/user/login',user);
}

export function getInfo(token) {
  //return axios.get('/user-service/user/info',{
  return axios.get('/teacher-service/user/info',{
    params: {token}
  });
}

export function logout() {
  return axios({
    url: '/vue-element-admin/user/logout',
    method: 'post'
  })
}

  • 在 teacher服务中,创建临时登录处理类
    在这里插入图片描述
  • JavaBean:User
@Data
public class User {
    private String username;
    private String password;
}
  • 处理类:UserController,Element UI Admin
@RestController
@RequestMapping("/user")
public class UserController {
    /**
     * 用户登录
     * @param user
     * @return
     */
    @PostMapping("/login")
    public BaseResult login(@RequestBody User user) {
        Map<String,Object> map = new HashMap<>();
        if("admin".equals(user.getUsername())) {
            map.put("token", "admin-token");
        } else {
            map.put("token", "editor-token");
        }
        return BaseResult.ok("登录成功",map);
    }

    @GetMapping("/info")
    public BaseResult login(String token) {
        Map<String,Object> map = new HashMap<>();
        if("admin-token".equals(token)) {
            map.put("roles", Arrays.asList("admin"));
            map.put("avatar", "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
            map.put("name", "Super Admin");
        } else {
            map.put("roles", Arrays.asList("editor"));
            map.put("avatar", "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
            map.put("name", "Normal Editor");
        }
        return BaseResult.ok("登录成功",map);
    }
}
  • 修改用户登录处理函数,打印错误信息,方便出错提示
    在这里插入图片描述

4.3.2、教师接口文件

在这里插入图片描述

  • 创建 @/api/edu/teacher.js 文件
// 导入axios工具类
import axios from '@/utils/request'

//编写具体功能,一个功能一个函数,并使用export导出

// 查询所有教师
export function findAll() {
  return axios.get('/teacher-service/teacher')
}

// 添加教师
export function save(teacher) {
  return axios.post('/teacher-service/teacher', teacher)
}

4.3.3、使用接口

在这里插入图片描述

<template>
  <div>
    教师管理
  </div>
</template>

<script>
// 导入接口文件,并解构指定的方法
import { findAll } from '@/api/edu/teacher'

export default {
  methods: {
    async findAllTeacher() {
      // 调用接口文件中接口到的方法
      let { data } = await findAll()
    }
  },
  mounted() {
    // 页面加载成功,查询所有老师
    this.findAllTeacher()
  },
}
</script>

<style>

</style>

五、后台管理-讲师模块-前端实现

5.1、查询所有

5.1.1、需求

在这里插入图片描述

5.1.2、表格渲染

<template>
  <div>
    <el-table
      v-loading="listLoading"
      :data="teacherList"
      border
      fit
      highlight-current-row
      style="width: 100%;"
    >
      <el-table-column label="ID" prop="id" align="center" width="80">
        <template slot-scope="{row}">
          <span>{{ row.id }}</span>
        </template>
      </el-table-column>
      <el-table-column label="姓名" prop="name" align="center" width="80">
      </el-table-column>
      <el-table-column label="头衔" prop="id" align="center" width="120">
        <template slot-scope="{row}">
          <span>{{ row.level == 1 ? '高级讲师' : '首席讲师' }}</span>
        </template>
      </el-table-column>
      <el-table-column label="资历" prop="intro" align="center" width="350">
      </el-table-column>
      <el-table-column label="添加时间" width="150px" align="center">
        <template slot-scope="{row}">
          {{row.gmtCreate}}
          <span>{{ row.gmtCreate | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
        </template>
      </el-table-column>
      <el-table-column label="排序" prop="sort" width="80px" min-width="50px">
      </el-table-column>
      <el-table-column label="状态" width="100px" align="center">
        <template slot-scope="{row}">
          <span>{{ row.isDeleted == 1 ? '已删除' : '未删除' }}</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" width="230" class-name="small-padding fixed-width">
        <template slot-scope="{row,$index}">
          <el-button type="primary" size="mini" @click="updateTeacher(row)">
            修改
          </el-button>
          <el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="deleteTeacher(row,$index)">
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    {{teacherList}}
  </div>
</template>

<script>
// 导入接口文件,并解构指定的方法
import { findAll } from '@/api/teacher'
import { parseTime } from '@/utils'

export default {
  data() {
    return {
      listLoading: true,
      teacherList: []
    }
  },
  methods: {
    async findAllTeacher() {
      this.listLoading = true
      // 调用接口文件中接口到的方法
      let { data } = await findAll()
      this.teacherList = data
      // 恢复状态
      this.listLoading = false
    },
    updateTeacher() {

    },
    deleteTeacher() {

    }

  },
  mounted() {
    // 页面加载成功,查询所有老师
    this.findAllTeacher()
  },
}
</script>

<style>

</style>

5.2、分页列表

在这里插入图片描述

5.2.1、定义api

  • src/api/teacher.js 中添加
/*  条件查询
  @param teacherPage 分页对象
  @param teacherVo 条件对象
*/
export function condition(teacherPage,teacherVo) {
  return axios.post(`/teacher-service/teacher/condition/${teacherPage.size}/${teacherPage.current}`, teacherVo)
}

5.2.2、分页实现

<template>
  <div>
    <el-table
      v-loading="listLoading"
      :data="teacherPage.records"
      border
      fit
      highlight-current-row
      style="width: 100%;"
    >
      <el-table-column label="ID" prop="id" align="center" width="80">
        <template slot-scope="{row}">
          <span>{{ row.id }}</span>
        </template>
      </el-table-column>
      <el-table-column label="姓名" prop="name" align="center" width="80">
      </el-table-column>
      <el-table-column label="头衔" prop="id" align="center" width="120">
        <template slot-scope="{row}">
          <span>{{ row.level == 1 ? '高级讲师' : '首席讲师' }}</span>
        </template>
      </el-table-column>
      <el-table-column label="资历" prop="intro" align="center" width="350">
      </el-table-column>
      <el-table-column label="添加时间" width="150px" align="center">
        <template slot-scope="{row}">
          {{row.gmtCreate}}
          <span>{{ row.gmtCreate | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
        </template>
      </el-table-column>
      <el-table-column label="排序" prop="sort" width="80px" min-width="50px">
      </el-table-column>
      <el-table-column label="状态" width="100px" align="center">
        <template slot-scope="{row}">
          <span>{{ row.isDeleted == 1 ? '已删除' : '未删除' }}</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" width="230" class-name="small-padding fixed-width">
        <template slot-scope="{row,$index}">
          <el-button type="primary" size="mini" @click="updateTeacherPre(row)">
            修改
          </el-button>
          <el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="deleteTeacher(row,$index)">
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 分页条 -->
    <pagination v-show="teacherPage.total>0" :total="teacherPage.total" :pageSizes="[1,2,3,5]" :page.sync="teacherPage.current" :limit.sync="teacherPage.size" @pagination="conditionTeacher" />

    <!--  -->
  </div>
</template>

<script>
// 导入接口文件,并解构指定的方法
import { findAll,condition } from '@/api/teacher'
import { parseTime } from '@/utils'
import Pagination from '@/components/Pagination' // secondary package based on el-pagination

export default {
  components: { Pagination },
  data() {
    return {
      listLoading: true,
      teacherPage: {    // 分页数据
        current: 1,
        size: 3,
        total: 0
      },
      teacherVo: {      // 查询条件

      }
    }
  },
  methods: {
    /*
    async findAllTeacher() {
      this.listLoading = true
      // 调用接口文件中接口到的方法
      let { data } = await findAll()
      this.teacherList = data
      // 恢复状态
      this.listLoading = false
    },
    */
    async conditionTeacher() {
      this.listLoading = true
      // 调用接口文件中接口到的方法
      let { data } = await condition(this.teacherPage,this.teacherVo)
      this.teacherPage = data
      // 恢复状态
      this.listLoading = false
    },
    updateTeacherPre() {

    },
    deleteTeacher() {

    }

  },
  mounted() {
    // 页面加载成功,查询所有老师
    // this.findAllTeacher()
    this.conditionTeacher()
  },
}
</script>

<style>

</style>

5.2.3、条件

<!-- 分页 -->
    <el-pagination
      :current-page="page"
      :page-size="limit"
      :total="total"
      style="padding: 30px 0; text-align: center;"
      layout="total, prev, pager, next, jumper"
      @current-change="fetchData"
    />

5.2.4、条件表单

  • 通过 value-format=“yyyy-MM-dd” 设置日期组件数据格式
<!-- 查询条件 -->
    <div class="filter-container">
      <el-form ref="conditionForm" :inline="true" :model="teacherVo" class="demo-form-inline">
        <el-form-item >
          <el-input v-model="teacherVo.name" placeholder="讲师名" style="width: 150px;" class="filter-item" @keyup.enter.native="handleFilter" />
          <el-select v-model="teacherVo.level" placeholder="讲师头衔" clearable style="width: 150px" class="filter-item">
            <el-option label="高级讲师" :value="1" />
            <el-option label="首席讲师" :value="2" />
          </el-select>
        </el-form-item>
        <el-form-item label="活动时间">
          <el-col :span="12">
            <el-date-picker type="date" placeholder="查询开始时间" v-model="teacherVo.beginDate" value-format="yyyy-MM-dd" style="width: 100%;"></el-date-picker>
          </el-col>
          <el-col :span="12">
            <el-date-picker placeholder="查询结束时间" v-model="teacherVo.endDate" value-format="yyyy-MM-dd" style="width: 100%;"></el-date-picker>
          </el-col>
        </el-form-item>
        <el-form-item >
          <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="conditionTeacher">
            搜索
          </el-button>
          <el-button class="filter-item" style="margin-left: 10px;"  @click="clearCondition">
            清空
          </el-button>
        </el-form-item>
      </el-form>
    </div>
  • 清空函数
    clearCondition() {
      this.teacherVo = {}
    }

5.2.5、BUG修复:element ui admin v-waves失效

在这里插入图片描述

    // 修复波浪与@click冲突
    // 参考:https://blog.csdn.net/hd243608836/article/details/110954416
    const removeHandler = el[context].removeHandle
    setTimeout(_ => {
      el.removeEventListener('click', removeHandler, false)
    })
    el.addEventListener('click', handleClick(el, binding), false)

5.3、添加

5.3.1、定义Api

  • src/api/edu/teacher.js (已有)
// 添加教师
export function save(teacher) {
  return axios.post('/teacher-service/teacher', teacher)
}

5.3.2、显示添加页面

  • 编写路由 (已有)
    在这里插入图片描述
    {
      path: 'add',
      component: () => import('@/views/edu/teacher/add'),
      name: '添加教师',
      meta: { title: '添加教师', icon: 'edit'  }   //二级菜单名称
    }
  • src/views/edu/teacher/add.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="请选择">
          <!--
            数据类型一定要和取出的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 type="primary" @click="saveTeacher">保存</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      teacher: {

      }
    }
  },
  methods: {
    saveTeacher() {

    }
  },
}
</script>

<style>

</style>

5.3.3、实现添加功能

  • 导入 api,并修改 saveTeacher 发送ajax
<script>
// 导入ajax方法
import { save } from '@/api/teacher'

export default {
  data() {
    return {
      teacher: {

      }
    }
  },
  methods: {
    async saveTeacher() {
      // ajax 查询,返回结果为BaseResult
      let { message , data } = await save( this.teacher )
      // 成功提示
      this.$message.success( message )
      // 关闭当前选项卡,【注意:必须放在跳转之前】
      this.$store.dispatch('tagsView/delView', this.$route)
      // 跳转到列表页面
      this.$router.push('/teacher/list')
    }
  },
  mounted() {
    console.info(this.$refs)
  },
}
</script>

5.3.4、扩展:关闭选项卡分析

// 关闭当前选项卡,【注意:必须放在跳转之前】
this.$store.dispatch('tagsView/delView', this.$route)
  • 分析
//操作vuex的标准写法
this.$store

//执行vuex的action的标准写法
this.$store.dispatch

// 执行模块“tagsView”中,名称为“delView”的action
tagsView/delView

// 参数为当前路由
this.$route
  • vuex的位置
  • 模块文件的位置
    在这里插入图片描述
  • action的位置
    在这里插入图片描述
  • 代码出处
    在这里插入图片描述

5.4、修改&回显

5.4.1、定义回显Api

  • src/api/teacher.js
    在这里插入图片描述
// 查询详情
export function findById(id) {
  return axios.get(`/teacher-service/teacher/${id}`)
}

5.4.2、显示修改弹出框

  • 添加弹出框
    <!-- 修改弹出框 -->
    <el-dialog title="修改讲师" :visible.sync="editDialogVisible">
      <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>
      <div slot="footer" class="dialog-footer">
        <el-button @click="editDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="updateTeacher">修改</el-button>
      </div>
    </el-dialog>
  • 定义两个变量
      editDialogVisible: false, // 修改弹出框
      teacher: {                // 表单对象

      }

5.4.3、调用回显Api

  • 修改 src/views/edu/teacher/list.vue
  • 从api解构 findById
    在这里插入图片描述
// 导入接口文件,并解构指定的方法
import { findAll,condition, findById } from '@/api/teacher'
  • 编写 findTeacherById方法,调用ajax方法
    在这里插入图片描述
    async findTeacherById(tid) {
      // 查询结果 BaseResult
      let { message, data } = await findById(tid)
      // 保存查询结果
      this.teacher = data
    }
  • 修改 updateTeacherPre 方法,显示弹出框,并回显表单
    updateTeacherPre( teacher ) {
      // 显示弹出框
      this.editDialogVisible = true
      // 查询详情
      this.findTeacherById(teacher.id)
    },

5.4.4、测试回显

在这里插入图片描述

5.4.5、定义修改Api

在这里插入图片描述

// 修改讲师
export function update( teacher ) {
  return axios.put(`/teacher-service/teacher`, teacher)
}

5.4.6、调用修改Api

在这里插入图片描述

    async updateTeacher() {
      // 发送ajax
      let { message } = await update( this.teacher )
      // 提示
      this.$message.success(message)
      // 刷新列表
      this.conditionTeacher()
      // 关闭弹出框
      this.editDialogVisible = false

    }

5.5、删除

5.5.1、定义删除Api

在这里插入图片描述

// 通过id删除
export function deleteById(id) {
  return axios.delete(`/teacher-service/teacher/${id}`)
}

5.5.2、调用删除Api

  • 解构删除方法

在这里插入图片描述

// 导入接口文件,并解构指定的方法
import { findAll,condition, findById, update, deleteById } from '@/api/teacher'
  • 定义方法deleteTeacherById
    deleteTeacher( teacher ) {
      this.$confirm('您确定要删除么?', '删除提示', {type: 'warning'})
      .then(async () => {
        // 确定
        // 发送ajax
        let { message } = await deleteById( teacher.id )
        // 提示
        this.$message.success(message)
        // 刷新列表
        this.conditionTeacher()
      }).catch(() => {
        // 取消
      });
    },

5.6、批量删除

5.6.1、后端实现

在这里插入图片描述

    /**
     * 批量删除
     * @param ids
     * @return
     */
    @PostMapping("/deleteBatch")
    public BaseResult deleteBatch(@RequestBody List<String> ids) {
        boolean result = eduTeacherService.removeByIds(ids);
        if(result) {
            return BaseResult.ok("批量删除成功");
        }
        return BaseResult.error("批量删除失败");
    }

5.6.2、定义批量删除Api

在这里插入图片描述

// 批量删除
export function deleteBatch( ids ) {
  return axios.post(`/teacher-service/teacher/deleteBatch`, ids )
}

5.6.3、前端多选

  • 添加多选框
    在这里插入图片描述
      <el-table-column
        type="selection"
        width="55">
      </el-table-column>
  • 添加多选事件
    在这里插入图片描述
    handleSelectionChange(val) {
      this.multipleSelection = val;
    }
  • 添加多选变量
multipleSelection: [] ,   //多选内容

5.6.4、调用批量删除Api

  • 解构 deleteBatch
    在这里插入图片描述
  • 批量删除方法
    deleteTeacherBatch() {
      // 校验
      if(this.multipleSelection.length <=0) {
        this.$message.warning('请选择删除项')
        return
      }
      // 确认
      this.$confirm('您确定要删除所选讲师么?', '批量删除提示', {type: 'error'})
      .then(async () => {
        // 从选择内容中过滤所有的id
        this.ids = this.multipleSelection.map(teacher=>teacher.id)
        // 发送ajax
        let { message } = await deleteBatch( this.ids )
        // 提示
        this.$message.success(message)
        // 刷新列表
        this.conditionTeacher()
      }).catch(() => {
        // 取消
      });
    }

5.6.5、批量按钮

在这里插入图片描述

<!-- 批量删除 -->
<el-button size="mini" type="danger" @click="deleteTeacherBatch">批量删除</el-button>

5.6.6、测试批量删除

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【在线教育】- 前端环境搭建&讲师CURD前端实现 的相关文章

随机推荐

  • 最小熵原理系列:词向量的维度应该怎么选择?

    PaperWeekly 原创 作者 苏剑林 单位 追一科技 研究方向 NLP 神经网络 随着 NLP 的发展 像 Word2Vec Glove 这样的词向量模型 正逐渐地被基于 Transformer 的 BERT 等模型代替 不过经典始终
  • Linux系统下word转pdf,xls转pdf,ppt转pdf

    word转换pdf的技术方案 供参考 doc docx ppt pptx xls xlsx均支持转换 本方案是Java结合shell命令完成 不同于以往的仅依赖java组件转换或打印pdf的方案 需要目标服务器安装office套件 可选方案
  • LayUI登录页面

    使用LayUI对你所做系统进行前端的美化和交互完善设计 使得系统的操作和交互更加符合人机交互理念 下面文章仅是登录页面的美化
  • 国际期货是什么?正大期货的定义怎么来的?

    国际期货市场是国际上进行期货交易的市场 期货交易是预先签订商品买卖合同 而贷款的支付和货物的交割要在约定的时间内进行的一种交易 但一般不需要真正交割 绝大多数合约在到期前对冲 期货交易只需支付少量保证金 通过期货交易所买进卖出期货合约 即一
  • Anaconda配置OpenCV环境

    1 移除旧的环境 如果原来有一个opencv的环境 那么要先进行这个环境的删除 conda env remove opencv 2 虚拟环境创建 首先进行虚拟环境的创建 使用Anaconda进行虚拟环境的创建 我这里的虚拟环境的名称是 op
  • Java如何让自定义类型具有可比较大小的能力

    自定义类型大小比较 一 背景 二 两种方法 方式一 自然排序 方式二 定制排序 一 背景 Java中基本数据类型之间可以使用比较运算符 gt lt gt lt 等进行比较 引用数据类型之间进行比较时 使用继承于Object类的equals方
  • atheros面试

    6道题目 1 是swap的宏的定义 2 用一个语句判断一个数是不是2的n次幂 3 判断sizeof作为参数传入的 char 的长度 4 用两个栈实现一个队列 5 将字符串bcde转换为edcb 6 循环计数1 n 如果计到m 则打印出来 第
  • Impala 三大组件:Impala Daemon, Impala Statestore, Impala Catelog

    Impala 三大组件 Impala Daemon 功能 负责读写数据文件 接受来自 Impala shell ODBC Hue 和 JDBC 的查询请求 然后与集群中的其他节点分布式并行工作 将本节点的查询结果返回给中心协调者节点 查询流
  • 创建项目Vue 3 + Vite,引入 Element Plus UI 组件库。

    首先要下载vite 在终端输入npm init vitejs app my vue app template vue 快速生成一个使用 Vite 构建的 Vue 3 项目模版 这时候如果是第一次创建 电脑就会提示 只用输入y 电脑即可自动下
  • 高通9008刷机

    1 进入9008模式 第一种方法 adb reboot edl 第二种方法 手机按钮进入 第三种方法 小米安全通线 第四种方法 短路接点 2 需要安装安卓驱动 高通驱动 QFIL软件 3 需要下载ROM包 4 解压ROM包 5 打开QFIL
  • 毕业季

    进入六月 毕业的氛围越来越浓 虽然忙 但更多的是不舍 四年 转眼之间 大一在高密校区的岁月仍历历在目 6 10 从公司请假 早上八点半去图书馆布置创新比赛的展板 6 11 休整一天 PPT准备6 12号早上的答辩 6 12 早八点半 在中德
  • 欧科云链让科技赋能乡村教育,获公益时报等主流媒体报道...

    中国经济网 公益时报前线报道 近日 欧科云链CSR团队到访饶河县饶河农场中心小学 为该校的人工智能创客实验室注入了新的活力 这一举措旨在助力学校推进人工智能教育 为农村学生提供更广阔的发展机会 饶河农场中心小学一直以来致力于创新教育 自20
  • nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 的解决办法

    问题概述 在基于微服务架构风格的项目开发过程中 为了提高快速开发的目的 提高开发效率 集成了 MyBatisPlus 对于 MyBatisPlus 封装的 CRUD API 接口已经非常强大了 但是有时还是需要使用其动态 SQL 的拼接 在
  • 性能测试之性能优化篇

    目录 为什么进行性能测试 性能测试的目的 服务性能优化的思考 衡量系统性能常用的指标 系统性能计数器 性能测试分类 如何合理的规划我们的架构性能 最后拿数据说话 性能优化原则 性能优化的方法 性能优化的分层思想 所有的优化都会对系统性能产生
  • flask 文件 服务器,flask服务器文件上传云

    flask服务器文件上传云 内容精选 换一换 弹性云服务器支持通过内网访问OBS OBS可供用户存储任意类型的数据 将图片 视频等数据存储至OBS后 在ECS上可以访问OBS 下载桶中的图片或视频等数据 通过内网访问OBS 可以避免因网络不
  • ASP.NET中JSON的序列化和反序列化

    在项目开发过程中 发现需要用到JSON序列化 反序列化的问题 所有 在网上找到了一下这篇文章 摘录了下来 摘自 http www cnblogs com zhaozhan archive 2011 01 09 1931340 html JS
  • 使用ijkplayer播放4k视频卡顿的解决方法

    使用ijkplayer播放4k视频卡顿的解决方法 使用硬解码 ijkMediaPlayer setOption IjkMediaPlayer OPT CATEGORY PLAYER mediacodec 1
  • PAT甲级1135

    红黑树的特点 1 根节点是黑色 2 如果一个节点是红色那么他的两个子节点都是红色 3 任意从根节点到叶子结点的路径上 所有的路径经过的黑色节点数相同 4 红黑树是二叉搜索树 算法 1 根节点是否为黑色 2 红色节点的两个子节点是不是都是黑色
  • JS 数组或对象的遍历(for、for...in、for...of、foreach)

    转载自 JavaScript 比较for for in for of forEach的区别 非早起选手的博客 CSDN博客 目录 一 for 二 for in 三 for of 四 forEach 五 小结 一 for 最原始的方法 用来遍
  • 【在线教育】- 前端环境搭建&讲师CURD前端实现

    在线教育 一 在线教育前端环境搭建 1 1 vue element admin 概述 1 2 vue element admin master安装 1 3 vue element template介绍 了解 1 4 vue element