前端:後臺模板vue-admin-template
尚硅谷Spring筆記-05

後臺模板

非常經典的模板,被用的很廣泛

依賴除錯

課件給的老板本用起來很多錯誤,需要手動排查

// 載都沒載直接報錯停止,可能是npm版本太高,降版本:
npm install npm@6.14.10 -g

/* node-sass問題,報錯為
node-sass@4.14.1 postinstall: `node scripts/build.js`
node-sass跟Node.js版本有很大關係,不相容的時候可以這樣
*/

npm install gulp-sass --save-dev
npm install node-sass@latest

// 清除緩存
npm cache clean --force
  • 都沒問題使用npm run dev就能啟動了
    • 後來我是去它倉庫抓4.4版本的,依賴都沒報錯,也不用修改登入接口那些

開始搭建

新增側邊欄

  • 左邊那些表在vue中對應叫router,修改/src/router/index.js綁定要顯示的項目
  • @/是設定好的別名,表示/src路徑之下
  • 然後在view中添加要顯示的內容,新增檔案後輸入veu+table就能產生模板

image-20220107171039627

串接api

  • 到@/api下編輯接口,複製一個預設的來改,點進去發現第一行import request from '@/utils/request'是已經引用好axios了
    • 但是他這邊request.js裡面成功代號預設是20000,如果與後端用的不同要自己修改
      • 改這個最好用全局取代,因為還有其他比如登入也用到這個代碼,要統一改
  • 修改下面的請求方法,與後端api的URL對接
import request from '@/utils/request'

export default {
  findPageHospitalSet(current, limit, searchObj) {
    return request({
      // ES6特性,反引號包裹強化字串
      url: `http://localhost:8201/admin/hosp/hospitalSet/findPageHospitalSet/${current}/${limit}`,
      // url: `/admin/hosp/hospitalSet/findPageHospitalSet/${current}/${limit}`,
      method: 'post',
      // data表示使用json傳遞給後端的@RequestBody
      data: searchObj
    })
  }
}
  • 暫時先用完整的url跳過需要關閉mock與跨域問題

修改請求端口號

留坑,暫時先用完整的url跳過需要關閉mock與跨域問題

  • main.js先斬斷mock

image-20220107181451993

  • vue.config.js中也有

image-20220107181553061

  • .env.development設定BASE_API

image-20220107190745323

編寫ajax請求

<script>
// 引入接口的js
import hospitalSet from "@/api/hospital-set";
export default {
  // 定義接收用的變量與初始值
  data() {
    return {
      current: 1, // 當前頁
      limit: 5, // 每頁幾筆
      searchObj: {}, // 搜索條件
      list: [], // 每頁中的數據集合
      total: 0, // 總頁數
      multipleSelection: [], // 批量選擇中的記錄列表
    };
  },
  created() {
    // 在頁面渲染之前,通常用來調用methods裡的方法取得數據
    this.getList();
  },
  methods: {
    getList(page = 1) {
      // 當前頁數預設是1
      // 發送axaj請求
      this.current = page;
      // 對應後端條件查詢帶分頁
      hospitalSet
        .findPageHospitalSet(this.current, this.limit, this.searchObj)
        .then((response) => {
          // 請求成功,取出回應資料
          this.list = response.data.records;
          this.total = response.data.total;
        })
        // 請求失敗
        .catch((error) => {
          console.log(error);
        });
    },

顯示資料

<el-table
      :data="list"
      stripe
      style="width: 100%"
      @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" width="55" />
      <el-table-column type="index" width="50" label="序號" />
      <el-table-column prop="hosname" label="醫院名稱" />
      <el-table-column prop="hoscode" label="醫院編號" />
      <el-table-column prop="apiUrl" label="api基礎路徑" width="200" />
      <el-table-column prop="contactsName" label="聯繫人姓名" />
      <el-table-column prop="contactsPhone" label="聯繫人手機" />
      <el-table-column label="狀態" width="80">
        <template slot-scope="scope">
          {{ scope.row.status === 1 ? "可用" : "不可用" }}
        </template>
      </el-table-column>

跨域問題

  • 以下三種情況都會引起:

    • 協議不同:http與https

    • 端口不同:9528與8201

    • ip不同

  • 解法:

    • 後端Controller註解@CrossOrigin
    • 使用nginx反向代理

完成其他功能

  • list.vue
<template>
  <div class="app-container">
    醫院設置列表
    <el-form :inline="true" class="demo-form-inline">
      <el-form-item>
        <el-input v-model="searchObj.hosname" placeholder="醫院名稱" />
      </el-form-item>
      <el-form-item>
        <el-input v-model="searchObj.hoscode" placeholder="醫院編號" />
      </el-form-item>
      <el-button type="primary" icon="el-icon-search" @click="getList()"
        >查詢</el-button
      >
    </el-form>

    <!-- 工具條 -->
    <div>
      <el-button type="danger" size="mini" @click="removeRows()"
        >批量刪除</el-button
      >
    </div>

    <el-table
      :data="list"
      stripe
      style="width: 100%"
      @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" width="55" />
      <el-table-column type="index" width="50" label="序列" />
      <el-table-column prop="hosname" label="醫院名稱" />
      <el-table-column prop="hoscode" label="醫院編號" />
      <el-table-column prop="apiUrl" label="api基礎路徑" width="200" />
      <el-table-column prop="contactsName" label="聯繫人姓名" />
      <el-table-column prop="contactsPhone" label="聯繫人手機" />
      <el-table-column label="狀態" width="80">
        <template slot-scope="scope">
          {{ scope.row.status === 1 ? "可用" : "禁用" }}
        </template>
      </el-table-column>

      <el-table-column label="操作" width="280" align="center">
        <template slot-scope="scope">
          <el-button
            type="danger"
            size="mini"
            icon="el-icon-delete"
            @click="removeDataById(scope.row.id)"
            >刪除</el-button
          >
          <el-button
            v-if="scope.row.status == 1"
            type="primary"
            size="mini"
            icon="el-icon-delete"
            @click="lockHospitalSet(scope.row.id, 0)"
            >鎖定</el-button
          >
          <el-button
            v-if="scope.row.status == 0"
            type="danger"
            size="mini"
            icon="el-icon-delete"
            @click="lockHospitalSet(scope.row.id, 1)"
            >解鎖</el-button
          >
          <router-link :to="'/hospitalSet/edit/' + scope.row.id">
            <el-button
              type="primary"
              size="mini"
              icon="el-icon-edit"
            ></el-button>
          </router-link>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分頁 -->
    <el-pagination
      :current-page="current"
      :page-size="limit"
      :total="total"
      style="padding: 30px 0; text-align: center"
      layout="total, prev, pager, next, jumper"
      @current-change="getList"
    />
  </div>
</template>

<script>
// 引入接口的js
import hospitalSet from "@/api/hospital-set";
export default {
  // 定義接收用的變量與初始值
  data() {
    return {
      current: 1, // 當前頁
      limit: 5, // 每頁幾筆
      searchObj: {}, // 搜索條件
      list: [], // 每頁中的數據集合
      total: 0, // 總頁數
      multipleSelection: [], // 批量選擇中的記錄列表
    };
  },
  created() {
    // 在頁面渲染之前,通常用來調用methods裡的方法取得數據
    this.getList();
  },
  methods: {
    getList(page = 1) {
      // 當前頁數預設是1
      // 發送axaj請求
      this.current = page;
      // 對應後端條件查詢帶分頁
      hospitalSet
        .findPageHospitalSet(this.current, this.limit, this.searchObj)
        .then((response) => {
          // 請求成功,取出回應資料
          this.list = response.data.records;
          this.total = response.data.total;
        })
        // 請求失敗
        .catch((error) => {
          console.log(error);
        });
    },
    // 鎖定和取消鎖定
    lockHospitalSet(id, status) {
      hospitalSet.lockHospitalSet(id, status).then((response) => {
        // 刷新
        this.getList(this.current);
      });
    },
    // 獲取選擇複選框的id值
    handleSelectionChange(selection) {
      this.multipleSelection = selection;
    },
    // 批量刪除
    removeRows() {
      this.$confirm("此操作將永久刪除醫院的設置信息, 是否繼續?", "提示", {
        confirmButtonText: "確定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          // 確定執行then方法
          var idList = [];
          // 遍歷數組得到每個id值,塞到idList裏面
          for (var i = 0; i < this.multipleSelection.length; i++) {
            var obj = this.multipleSelection[i];
            var id = obj.id;
            idList.push(id);
          }
          // 調用接口
          hospitalSet.batchRemove(idList).then((response) => {
            //提示
            this.$message({
              type: "success",
              message: "刪除成功!",
            });
            // 刷新頁面
            this.getList(this.current);
          });
        })
        .catch(() => {
          this.$message({
            type: "warning",
            message: "取消操作",
          });
        });
    }, // 刪除醫院設置的方法
    removeDataById(id) {
      this.$confirm("此操作將永久刪除醫院的設置信息, 是否繼續?", "提示", {
        confirmButtonText: "確定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          // 確定執行then方法
          // 調用接口
          hospitalSet.removeHospitalSet(id).then((response) => {
            // 提示
            this.$message({
              type: "success",
              message: "刪除成功!",
            });
            // 刷新頁面
            this.getList(this.current);
          });
        })
        .catch(() => {
          this.$message({
            type: "warning",
            message: "取消操作",
          });
        });
    },
  },
};
</script>

<style>
</style>
  • hospital-set.js綁定接口
import request from '@/utils/request'

export default {
  findPageHospitalSet(current, limit, searchObj) {
    return request({
      // ES6特性,反引號包裹強化字串
      url: `http://localhost:8201/admin/hosp/hospitalSet/findPageHospitalSet/${current}/${limit}`,
      // url: `/admin/hosp/hospitalSet/findPageHospitalSet/${current}/${limit}`,
      method: 'post',
      // data表示使用json傳遞給後端的@RequestBody
      data: searchObj
    })
  },
  // 刪除醫院設置
  removeHospitalSet(id) {
    return request({
      url: `http://localhost:8201/admin/hosp/hospitalSet/removeHospitalSet/${id}`,
      method: 'delete'
    })
  },
  // 批量刪除
  batchRemove(idList) {
    return request({
      url: `http://localhost:8201/admin/hosp/hospitalSet/batchRemove`,
      method: 'delete',
      data: idList
    })
  },
  // 鎖定和取消鎖定
  lockHospitalSet(id, status) {
    return request({
      url: `http://localhost:8201/admin/hosp/hospitalSet/lockHospitalSet/${id}/${status}`,
      method: 'put'
    })
  },
  // 添加醫院設置
  saveHospitalSet(hospitalSet) {
    return request({
      url: `http://localhost:8201/admin/hosp/hospitalSet/saveHospitalSet`,
      method: 'post',
      data: hospitalSet
    })
  },
  // 院設置id查詢
  getHospitalSet(id) {
    return request({
      url: `http://localhost:8201/admin/hosp/hospitalSet/getHospitalSet/${id}`,
      method: 'get'
    })
  },
  // 修改醫院設置
  updateHospitalset(hospitalSet) {
    return request({
      url: `http://localhost:8201/admin/hosp/hospitalSet/updateHospitalSet`,
      method: 'post',
      data: hospitalSet
    })
  }
}

知識點

獲取多選框

批量XX功能

// 先定義一個批量選擇中的記錄列表
multipleSelection: [],

// 上面選框綁定@selection-change動作
<el-table-column type="selection" width="55" />
@selection-change="handleSelectionChange"

// 獲取選擇複選框的id值
handleSelectionChange(selection) {
this.multipleSelection = selection;

// 遍歷數組得到每個id值,塞到idList裏面
for (var i = 0; i < this.multipleSelection.length; i++) {
var obj = this.multipleSelection[i];
var id = obj.id;
idList.push(id);
}

// 調用接口,拿idList當參數發請求

確認彈窗

// 上面綁一個按鈕
<el-button
type="danger"
size="mini"
icon="el-icon-delete"
@click="removeDataById(scope.row.id)"
>刪除</el-button>

// 下面寫方法
    removeDataById(id) {
      this.$confirm("此操作將永久刪除醫院的設置信息, 是否繼續?", "提示", {
        confirmButtonText: "確定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          // 確定執行then方法
          // 調用接口
          hospitalset.removeHospitalSet(id).then((response) => {
            // 提示
            this.$message({
              type: "success",
              message: "刪除成功!",
            });
            // 刷新頁面
            this.getList(this.current);
          });
        })
        .catch(() => {
          this.$message({
            type: "warning",
            message: "取消操作",
          });
        });
    },
  • 注意刷新可以回到當前頁this.getList(this.current),教學中它統一回到第1頁,感覺會很不爽
  • .catch(() => {是應對選取消的,如果不寫會拋出一個錯誤沒人接,怪怪的

大小寫風格

為了防坑看了好多風格說明,但也沒個結論,先暫時定一下,插個眼

  • 前端的節點、頁面名,參考預設的項目全小寫且用-相連,文件名全小寫可以防止linux系統的麻煩,例如hospital-set.js

image-20220107224249021

  • 這樣記住原則,前端的頁面@/開頭或/轉址都是全小寫-
  • 其他方法、變量都用小駝峰,這樣最符合直覺,不然一個lockHospitalset後面的Set忘記駝峰害我找半天
  • 前後端調用的函數名最好一樣
  • 可以善用VS code的搜尋功能,這裡可以切換大小寫是否要完全相符,如果發現搜到的結果有變動,那就是有坑

image-20220107213726009

  • 自訂的事件名、HTML標籤名用-相連,例如<blog-post>selection-change

新增&修改頁面

  • 先去/router/index.js綁定網址
    • :id表示動態,類似SQL中?佔位符
    • hidden: true,不會顯示在側邊欄
      {
        path: 'edit/:id',
        name: '醫院設定編輯',
        component: () => import('@/views/hospital-set/add'),
        meta: { title: '醫院設定編輯', icon: 'table' },
        hidden: true
      }
  • 接著回到list.vue,綁定修改按鈕,
    • <router-link :to="跳轉至
          <router-link :to="'/hospital-set/edit/' + scope.row.id">
            <el-button
              type="primary"
              size="mini"
              icon="el-icon-edit"
            ></el-button>
          </router-link>
  • 回到add.vue
<template>
  <div class="app-container">
    添加醫院設置
    <el-form label-width="120px">
      <el-form-item label="醫院名稱">
        <el-input v-model="hospitalSet.hosname" />
      </el-form-item>
      <el-form-item label="醫院編號">
        <el-input v-model="hospitalSet.hoscode" />
      </el-form-item>
      <el-form-item label="api基礎路徑">
        <el-input v-model="hospitalSet.apiUrl" />
      </el-form-item>
      <el-form-item label="聯繫人姓名">
        <el-input v-model="hospitalSet.contactsName" />
      </el-form-item>
      <el-form-item label="聯繫人手機">
        <el-input v-model="hospitalSet.contactsPhone" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="saveOrUpdate">保存</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
import hospitalSet from "@/api/hospital-set";

export default {
  data() {
    return {
      hospitalSet: {},
    };
  },
  created() {
    // 頁面渲染之前執行
    // 獲取路由id值,如果有表示修改來的,需要先查詢回顯
    // 調用接口得到醫院設置信息
    if (this.$route.params && this.$route.params.id) {
      const id = this.$route.params.id;
      this.getHospitalSet(id);
    } else {
      // 表單清空,為了防有人點進修改又去按新增
      this.hospitalSet = {};
    }
  },
  methods: {
    // 根據id查詢
    getHospitalSet(id) {
      hospitalSet.getHospitalSet(id).then((response) => {
        this.hospitalSet = response.data;
      });
    },
    // 添加
    save() {
      hospitalSet.saveHospitalSet(this.hospitalSet).then((response) => {
        // 提示
        this.$message({
          type: "success",
          message: "添加成功!",
        });
        // 跳轉列表頁面,使用路由跳轉方式實現
        this.$router.push({ path: "/hospital-set/list" });
      });
    },
    // 修改
    update() {
      hospitalSet.updateHospitalSet(this.hospitalSet).then((response) => {
        // 提示
        this.$message({
          type: "success",
          message: "修改成功!",
        });
        // 跳轉列表頁面,使用路由跳轉方式實現
        this.$router.push({ path: "/hospital-set/list" });
      });
    },
    saveOrUpdate() {
      // 先防空
      if (!this.hospitalSet.hoscode || !this.hospitalSet.hosname) {
        // 提示
        this.$message({
          type: "error",
          message: "醫院名與編號為必填!",
        });
        return;
      }
      // 判斷添加還是修改
      if (!this.hospitalSet.id) {
        // 沒有id,做添加
        this.save();
      } else {
        // 修改
        this.update();
      }
    },
  },
};
</script>
  • this.$route.params && this.$route.params.id從網址參數判斷是要新增還是修改
  • this.$router.push({ path: "/hospital-set/list" });跳轉頁面
    • 注意請求是route,跳轉是router


上次修改於 2022-01-15