講師模塊前端開發

一、後臺系統路由實現分析

1、入口文件中調用路由

src/main.js

......
import router from './router' //引入路由模塊
......
new Vue({
  el: '#app',
  router, //掛載路由
  store,
  render: h => h(App)
})

2、路由模塊中定義路由

src/router/index.js

......
export const constantRouterMap = [
  ......
]

export default new Router({
  ......
  routes: constantRouterMap
})    

二、穀粒學院路由定義

1、複製icon圖標

將vue-element-admin/src/icons/svg 中的圖標複製到 guli-admin項目中

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/form'),
        meta: { title: '添加講師' }
      },
      {
        path: 'edit/:id',
        name: 'EduTeacherEdit',
        component: () => import('@/views/edu/teacher/form'),
        meta: { title: '編輯講師', noCache: true },
        hidden: true
      }
    ]
  },

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

3、創建vue組件

在src/views文件夾下創建以下文件夾和文件

在這裏插入圖片描述

4、form.vue

<template>
  <div class="app-container">
    講師表單
  </div>
</template>

5、list.vue

<template>
  <div class="app-container">
    講師列表
  </div>
</template>

一、項目中的****Easy Mock

config/dev.env.js 中BASE_API 爲項目的easymock地址,目前具有模擬登錄、登出、獲取用戶信息的功能

BASE_API: '"https://easy-mock.com/mock/5950a2419adc231f356a6636/vue-admin"',

登錄:/user/login

獲取用戶信息:/user/info?token=admin

登出:/user/logout

config/dev.env.js,只有一個api地址的配置位置,而我們實際的後端有很多微服務,所以接口地址有很多,

我們可以使用nginx反向代理讓不同的api路徑分發到不同的api服務器中

二、配置nginx反向代理

1、安裝window版的nginx

將nginx-1.12.0.zip解壓到開發目錄中

如:E:\development\nginx-1.12.0-guli-api

雙擊nginx.exe運行nginx

訪問:localhost

2、配置nginx代理

在Nginx中配置對應的微服務服務器地址即可

注意:最好修改默認的 80端口到81

http {
    server {
        listen       81;
        ......
    },
    
    ......
    server {

        listen 8201;
        server_name localhost;

        location ~ /edu/ {           
             proxy_pass http://localhost:8101;
        }
        
        location ~ /user/ {   
             rewrite /(.+)$ /mock/5950a2419adc231f356a6636/vue-admin/$1  break; 
             proxy_pass https://www.easy-mock.com;
        }
    }
}

3、重啓nginx

nginx -s reload

4、測試

訪問講師列表接口:http://localhost:8201/admin/edu/teacher

訪問獲取用戶信息接口:http://localhost:8201/user/info?token=admin

三、配置開發環境

1、修改config/dev.env.js

BASE_API: '"http://127.0.0.1:8201"'

2、重啓前端程序

修改配置文件後,需要手動重啓前端程序


一、分頁列表

1、定義api

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

import request from '@/utils/request'

const api_name = '/admin/edu/teacher'
export default {

  getPageList(page, limit, searchObj) {
    return request({
      url: `${api_name}/${page}/${limit}`,
      method: 'get',
      data: searchObj
    })
  }
}

2、初始化vue組件

src/views/edu/teacher/list.vue

<template>
  <div class="app-container">
    講師列表
  </div>
</template>

<script>
import teacher from '@/api/edu/teacher'
export default {

  data() {// 定義數據
      return {}
  },
    
  created() { // 當頁面加載時獲取數據
    this.fetchData()
  },
    
  methods: {
    fetchData() { // 調用api層獲取數據庫中的數據
      console.log('加載列表')
    }
  }
}
</script>

3、定義data

  data() {
    return {
      listLoading: true, // 是否顯示loading信息
      list: null, // 數據列表
      total: 0, // 總記錄數
      page: 1, // 頁碼
      limit: 10, // 每頁記錄數
      searchObj: {}// 查詢條件
    }
  },

4、定義methods

  methods: {
    fetchData(page = 1) { // 調用api層獲取數據庫中的數據
      console.log('加載列表')
      this.page = page
      this.listLoading = true
      teacher.getPageList(this.page, this.limit, this.searchObj).then(response => {
        // debugger 設置斷點調試
        if (response.success === true) {
          this.list = response.data.rows
          this.total = response.data.total
        }
        this.listLoading = false
      })
    }
  }

5、表格渲染

    <!-- 表格 -->
    <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>

6、分頁組件

   <!-- 分頁 -->
    <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"
    />

7、頂部查詢表單

注意:

element-ui的 date-picker組件默認綁定的時間值是默認世界標準時間,和中國時間差8小時

設置 value-format=“yyyy-MM-dd HH:mm:ss” 改變綁定的值

    <!--查詢表單-->
    <el-form :inline="true" class="demo-form-inline">
      <el-form-item>
        <el-input v-model="searchObj.name" placeholder="講師名"/>
      </el-form-item>

      <el-form-item>
        <el-select v-model="searchObj.level" clearable placeholder="講師頭銜">
          <el-option :value="1" label="高級講師"/>
          <el-option :value="2" label="首席講師"/>
        </el-select>
      </el-form-item>

      <el-form-item label="添加時間">
        <el-date-picker
          v-model="searchObj.begin"
          type="datetime"
          placeholder="選擇開始時間"
          value-format="yyyy-MM-dd HH:mm:ss"
          default-time="00:00:00"
        />
      </el-form-item>
      <el-form-item>
        <el-date-picker
          v-model="searchObj.end"
          type="datetime"
          placeholder="選擇截止時間"
          value-format="yyyy-MM-dd HH:mm:ss"
          default-time="00:00:00"
        />
      </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>

清空方法

resetData() {
    this.searchObj = {}
    this.fetchData()
}

8、測試

二、刪除

1、定義api

src/api/edu/teacher.js

removeById(teacherId) {
    return request({
        url: `${api_name}/${teacherId}`,
        method: 'delete'
    })
}

2、定義methods

src/views/edu/teacher/list.vue

使用MessageBox 彈框組件

removeDataById(id) {
    // debugger
    // console.log(memberId)
    this.$confirm('此操作將永久刪除該記錄, 是否繼續?', '提示', {
        confirmButtonText: '確定',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(() => {
        return teacher.removeById(id)
    }).then(() => {
        this.fetchData()
        this.$message({
            type: 'success',
            message: '刪除成功!'
        })
    }).catch((response) => { // 失敗
        if (response === 'cancel') {
            this.$message({
                type: 'info',
                message: '已取消刪除'
            })
        } else {
            this.$message({
                type: 'error',
                message: '刪除失敗'
            })
        }
    })
}

一、新增

1、定義api

src/api/edu/teacher.js

save(teacher) {
    return request({
        url: api_name,
        method: 'post',
        data: teacher
    })
}

2、初始化組件

src/views/edu/teacher/form.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.saveData()
    },

    // 保存
    saveData() {

    }

  }
}
</script>

3、實現新增功能

引入teacher api模塊

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

完善save方法

    // 保存
    saveData() {
      teacher.save(this.teacher).then(response => {
        return this.$message({
          type: 'success',
          message: '保存成功!'
        })
      }).then(resposne => {
        this.$router.push({ path: '/edu/teacher' })
      }).catch((response) => {
        // console.log(response)
        this.$message({
          type: 'error',
          message: '保存失敗'
        })
      })
    }

二、回顯

1、定義api

src/api/edu/teacher.js

getById(id) {
    return request({
        url: `${api_name}/${id}`,
        method: 'get'
    })
}

2、組件中調用api

methods中定義fetchDataById

// 根據id查詢記錄
fetchDataById(id) {
    teacher.getById(id).then(response => {
        this.teacher = response.data.item
    }).catch((response) => {
        this.$message({
            type: 'error',
            message: '獲取數據失敗'
        })
    })
}

3、頁面渲染前調用fetchDataById

  created() {
    console.log('created')
    if (this.$route.params && this.$route.params.id) {
      const id = this.$route.params.id
      this.fetchDataById(id)
    }
  }

三、更新

1、定義api

updateById(teacher) {
    return request({
        url: `${api_name}/${teacher.id}`,
        method: 'put',
        data: teacher
    })
}

2、組件中調用api

methods中定義updateData

// 根據id更新記錄
updateData() {
    this.saveBtnDisabled = true
    teacher.updateById(this.teacher).then(response => {
        return this.$message({
            type: 'success',
            message: '修改成功!'
        })
    }).then(resposne => {
        this.$router.push({ path: '/edu/teacher' })
    }).catch((response) => {
        // console.log(response)
        this.$message({
            type: 'error',
            message: '保存失敗'
        })
    })
}

3、完善saveOrUpdate方法

saveOrUpdate() {
    this.saveBtnDisabled = true
    if (!this.teacher.id) {
        this.saveData()
    } else {
        this.updateData()
    }
}

四、存在問題

vue-router導航切換 時,如果兩個路由都渲染同個組件,組件會重(chong)用,

組件的生命週期鉤子(created)不會再被調用, 使得組件的一些數據無法根據 path的改變得到更新

因此:

1、我們可以在watch中監聽路由的變化,當路由變化時,重新調用created中的內容

2、在init方法中我們判斷路由的變化,如果是修改路由,則從api獲取表單數據,

如果是新增路由,則重新初始化表單數據

<script>
import teacher from '@/api/edu/teacher'

const defaultForm = {
  name: '',
  sort: 0,
  level: '',
  career: '',
  intro: '',
  avatar: ''
}

export default {
  data() {
    return {
      teacher: defaultForm,
      saveBtnDisabled: false // 保存按鈕是否禁用,
    }
  },

  watch: {
    $route(to, from) {
      console.log('watch $route')
      this.init()
    }
  },

  created() {
    console.log('created')
    this.init()
  },

  methods: {

    init() {
      if (this.$route.params && this.$route.params.id) {
        const id = this.$route.params.id
        this.fetchDataById(id)
      } else {
        // 使用對象拓展運算符,拷貝對象,而不是引用,
        // 否則新增一條記錄後,defaultForm就變成了之前新增的teacher的值
        this.teacher = { ...defaultForm }
      }
    },

    ......
  }
}
</script>

一、返回操作是否成功

1、刪除業務邏輯

TeacherServiceImpl
@Override
public boolean removeById(Serializable id) {
    Integer result = baseMapper.deleteById(id);
    return null != result && result > 0;
}
TeacherAdminController
@ApiOperation(value = "根據ID刪除講師")
@DeleteMapping("{id}")
public R removeById(
    @ApiParam(name = "id", value = "講師ID", required = true)
    @PathVariable String id){

    boolean result = teacherService.removeById(id);
    if(result){
        return R.ok();
    }else{
        return R.error().message("刪除失敗");
    }
}

2、前端

在catch中處理錯誤信息

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章