1. 程式人生 > 實用技巧 >我的程式跑了60多小時,就是為了讓你看一眼JDK的BUG導致的記憶體洩漏。

我的程式跑了60多小時,就是為了讓你看一眼JDK的BUG導致的記憶體洩漏。

在前面隨筆介紹了ABP+Vue前後端的整合處理,包括介紹了ABP的後端設計,以及前端對ABP介面API的ES6的封裝,通過JS的繼承類處理,極大減少了重複臃腫的程式碼,可以簡化對後端API介面的封裝,而且前端使用Element元件,很好展示API獲得的資料,通過在介面中展示樹狀列表,以及表格列表資料,可以構建一個很好的列表展示介面,而常規的介面,通過也包括了新增、編輯、檢視等展示場景,一般我們通過對話方塊的方式進行展示處理。本篇隨筆以許可權管理模組中的使用者管理為媒介,進行相關功能的介紹和介面設計的處理。

1、許可權管理模組的設計

我們知道,許可權管理一般都會涉及到使用者、組織機構、角色,以及許可權功能等方面的內容,ABP框架的基礎內容也是涉及到這幾方面的內容,其中它們之間的關係基本上是多對多的關係,它們的關係如下所示。

許可權模組裡面包含的一些主物件表和中間表,中間表主要用來儲存兩個物件之間的多對多關係,如角色包含多個使用者,使用者屬於多個機構,機構包含多個角色等等。

結合ABP後端提供的介面,Vue前端我們要實現基礎的使用者、組織機構、角色、功能許可權等內容的管理,以及維護它們之間的關係。Vue前端對於許可權管理模組的選單列表如下所示。

上圖許可權管理模組中,包括使用者管理、機構管理、角色管理、選單管理、功能管理、審計日誌、登入日誌等內容模組的管理。

其中使用者管理模組,主要用來展示使用者資訊列表,以及檢視對應使用者許可權、維護密碼等處理。

使用者列表介面如下所示,包括對應條件的查詢和列表展示、以及檢視、新增、編輯、刪除、重置密碼等功能入口。

使用者資訊檢視介面如下所示

主要展示使用者基礎資訊,和所屬的關係資訊,其中許可權部分列出對應使用者包含的功能點,用於介面按鈕等方面的控制處理。

使用者新增介面,則主要用來處理錄入使用者基礎資訊部分即可,如下介面所示。

使用者資訊錄入,對使用者基礎表單資料進行校驗,符合格式要求才能錄入。

使用者編輯介面,基本上和上面的類似了,不在贅述。

另外,刪除使用者或者重置密碼,一般需對確認後再行操作,彈出一個對話方塊使用者確認再繼續。

ABP+Vue的框架參考的是已完成的ABP+Winform的功能介面進行開發,具體也可以瞭解下Winform版本框架《ABP開發框架前後端開發系列---(14)基於Winform的ABP快速開發框架

2、使用者管理介面功能

以上我們介紹了許可權管理模組涉及的內容和關係,並著重介紹了使用者管理介面中的內容展示,下面介紹在Element中如何實現對上面介面的處理的。

首先我們需要根據ABP後端的介面進行前端JS端的類的封裝處理,其中前面說過,常規的Get/GetAll/Create/Update/Delete/Count等介面,我們放在BaseApi基類裡面定義,其他子類繼承它即可。

許可權模組我們涉及到的使用者管理、機構管理、角色管理、選單管理、功能管理、審計日誌、登入日誌等業務類,那麼這些類繼承BaseApi,就會具有相關的介面了,如下所示繼承關係。

我們這裡以UserAPI的JS類定義介紹,如下所示。

我們以其中一個介面為例進行介紹實現程式碼,可以看到主要就是簡單封裝的呼叫即可。

  GetGrantedFunctionsByUser(id) { // 獲取使用者許可權列表
    return request({
      url: this.baseurl + 'GetGrantedFunctionsByUser',
      method: 'get',
      params: { id }
    })
  }

有了這些業務類的準備,那麼我們和後端ABP的API介面對接,就很容易了,如下圖所示。

剩下的就是對Vue + Element前端的介面處理事情了。

我們先來看看查詢的處理,常規的查詢涉及日期區間的查詢處理,這裡我們用一個一個查詢日期的處理操作,如下圖所示。

表單的介面程式碼如下所示

    <el-form ref="searchForm" :model="searchForm" label-width="80" :inline="true">
      <el-form-item label="建立時間">
        <el-date-picker
          v-model="searchForm.creationTime"
          type="daterange"
          align="right"
          unlink-panels
          range-separator="至"
          start-placeholder="開始日期"
          end-placeholder="結束日期"
          :picker-options="pickerOptions"
        />
      </el-form-item>
      <el-form-item label="使用者名稱" prop="UserName">
        <el-input v-model="searchForm.UserName" />
      </el-form-item>
      <el-form-item label="手機" prop="PhoneNumber">
        <el-input v-model="searchForm.PhoneNumber" />
      </el-form-item>
    </el-form>

其中定義了一個pickerOptions 屬性,用於快速選擇日期的,在data裡面增加一個這樣的屬性即可。

      pickerOptions: {
        shortcuts: [{
          text: '最近一週',
          onClick(picker) {
            const end = new Date();
            const start = new Date();
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
            picker.$emit('pick', [start, end]);
          }
        }, {
          text: '最近一個月',
          onClick(picker) {
            const end = new Date();
            const start = new Date();
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
            picker.$emit('pick', [start, end]);
          }
        }, {
          text: '最近三個月',
          onClick(picker) {
            const end = new Date();
            const start = new Date();
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
            picker.$emit('pick', [start, end]);
          }
        }]
      },

在頁面裡面,我們定義了一些分頁查詢的處理條件和物件,如下所示。

查詢表單則定義一個單獨的表單物件,如下程式碼所示

      searchForm: { // 查詢表單
        UserName: '',
        PhoneNumber: '',
        creationTime: ''
      },

頁面載入準備好,我們就呼叫獲取列表的資料即可。

  created() { // 頁面載入後,載入列表資料
    this.getlist()
  },

獲取列表的處理操作如下程式碼所示,主要就是準備構建好對應的查詢引數,然後呼叫UserApi類的介面查詢列表即可。

    getlist() { // 列表資料獲取
      var CreationTimeStart = ''
      if (this.searchForm.creationTime && this.searchForm.creationTime.length > 0) {
        CreationTimeStart = this.parseTime(this.searchForm.creationTime[0], '{y}-{m}-{d}')
      }
      var CreationTimeEnd = ''
      if (this.searchForm.creationTime && this.searchForm.creationTime.length > 1) {
        CreationTimeEnd = this.parseTime(this.searchForm.creationTime[1], '{y}-{m}-{d}')
      }

      var param = { // 構造常規的分頁查詢條件
        SkipCount: (this.pageinfo.pageindex - 1) * this.pageinfo.pagesize,
        MaxResultCount: this.pageinfo.pagesize,
        // 過濾條件
        UserName: this.searchForm.UserName,
        PhoneNumber: this.searchForm.PhoneNumber,
        CreationTimeStart: CreationTimeStart,
        CreationTimeEnd: CreationTimeEnd
      };

      // 獲取列表,繫結到模型上,並修改分頁數量
      this.listLoading = true
      user.GetAll(param).then(data => {
        this.list = data.result.items
        this.pageinfo.total = data.result.totalCount
        this.listLoading = false
      })
    },
    search() { // 查詢列表處理
      this.pageinfo.pageindex = 1;// 重置為第一頁=
      this.getlist()
    },

通過列表的查詢操作,我們就可以把資料獲取到,介面就會得到及時的更新顯示了

      // 獲取列表,繫結到模型上,並修改分頁數量
      this.listLoading = true
      user.GetAll(param).then(data => {
        this.list = data.result.items
        this.pageinfo.total = data.result.totalCount
        this.listLoading = false
      })

而列表主要就是在介面使用el-table元件進行展示的了,如下圖所示程式碼。

el-table綁定了對應的資料,並設定好顯示的格式以及選擇操作事件、行雙擊事件等操作。

而el-table裡面的顯示的列,需要根據我們返回資料的屬性名稱進行顯示,如下程式碼所示。

而如果我們需要對屬性進行特殊的展示,我們就需要使用v-if條件或者過濾器進行處理了。如下是根據不同內容,構建標籤顯示內容。

      <el-table-column align="center" label="賬號啟用" width="80">
        <template slot-scope="scope">
          <el-tag v-if="scope.row.isActive === true" type="success" effect="dark">已啟用</el-tag>
          <el-tag v-else type="danger" effect="dark">未啟用</el-tag>
        </template>
      </el-table-column>

而對於時間,我們則可以使用格式化函式或者過濾器規範顯示的格式內容。

<el-table-column align="center" label="建立時間" width="120" prop="creationTime" :formatter="dateFormat" />

其中:formatter="dateFormat" 指定了對應的格式化處理函式。

    dateFormat(row, column, cellValue) {
      // this.parseTime是在main.js中的全域性掛載函式
      return cellValue ? this.parseTime(cellValue, '{y}-{m}-{d}') : '' // 完整格式:{y}-{m}-{d} {h}-{i}-{s}
    },
    timeFormat(row, column, cellValue) {
      // this.parseTime是在main.js中的全域性掛載函式
      return cellValue ? this.parseTime(cellValue, '{y}-{m}-{d} {h}:{i}:{s}') : '' // 完整格式:{y}-{m}-{d} {h}-{i}-{s}
    }

另外,操作列的程式碼,主要就是構建一些方法操作的入口,並傳遞對應的變數,如ID值即可。

      <el-table-column align="center" label="操作" width="190">
        <template scope="scope">
          <el-row>
            <el-tooltip effect="light" content="檢視" placement="top-start">
              <el-button icon="el-icon-search" type="success" circle size="mini" @click="showView(scope.row.id)" />
            </el-tooltip>
            <el-tooltip effect="light" content="編輯" placement="top-start">
              <el-button icon="el-icon-edit" type="primary" circle size="mini" @click="showEdit(scope.row.id)" />
            </el-tooltip>
            <el-tooltip effect="light" content="刪除" placement="top-start">
              <el-button icon="el-icon-delete" type="danger" circle size="mini" @click="showDelete(scope.row.id)" />
            </el-tooltip>
            <el-tooltip effect="light" content="重置密碼" placement="top-start">
              <el-button icon="el-icon-setting" type="warning" circle size="mini" @click="showSetPass(scope.row.id)" />
            </el-tooltip>
          </el-row>
        </template>
      </el-table-column>

列表的底部分頁處理,也是利用對應的屬性進行顯示即可,並處理分頁變化的事件。

    <div class="block" style="height:70px;">
      <el-pagination
        :current-page="pageinfo.pageindex"
        :page-size="pageinfo.pagesize"
        :total="pageinfo.total"
        :page-sizes="[10,20,30,40]"
        layout="total, sizes, prev, pager, next"
        @size-change="sizeChange"
        @current-change="currentChange"
      />
    </div>

最後完成列表介面程式碼,顯示列表介面如下所示。

而對於檢視、編輯、新增等對話方塊,一般我們需要建立對應的表單屬性,用來承載對應的資訊的,如我們為了檢視資訊的需要,建立一個viewForm的物件,如下所示。

      viewForm: { // 查看錶單
        id: '',
        userName: '',
        surname: '',
        name: '',
        emailAddress: '',
        phoneNumber: '',
        ouNames: ''
      },

在檢視資訊對話方塊裡面,我們展示對應的使用者資訊,包括基礎資訊和相關的關係,如下介面程式碼所示。

介面元件通過v-modal進行繫結對應的ViewForm屬性物件即可。

最後,我們在觸發showView函式裡面,獲取對應的使用者資訊,然後展示在介面上即可,showView函式程式碼如下所示。

    showView(id) { // 顯示檢視對話方塊處理
      var param = { id: id }
      user.Get(param).then(data => {
        // console.log(data.result)
        Object.assign(this.viewForm, data.result);

        this.getOuName(id).then(result => {
          this.viewForm.ouNames = result
        })
      })
      this.getFunctionsByUser(id)

      this.isView = true
    },

在新增或者編輯處理介面中,我們修改了資料,都會提交到ABP後端進行錄入或者更新,因此就涉及到資料的回寫處理,然後提示客戶端狀態即可。

下面是儲存編輯介面的內容操作。

    saveEdit() { // 儲存資料處理
      this.$refs['editForm'].validate(valid => {
        if (valid) {
          // 儲存資料
          const form = this.editForm
          user.Update(form).then(data => {
            // console.log(data)
            if (data.success) {
              // 提示資訊
              this.msgSuccess('更新成功!')
              // 重新整理資料
              this.getlist()
            } else {
              this.msgError('更新失敗:' + data.error)
            }

            this.$refs['editForm'].resetFields()
            // 重置視窗狀態
            this.closeDialog()
          })
        }
      })
    },

其中msgSuccess、msgError是全域性掛載的提示資訊函式,在入口main.js裡面統一處理,封裝的函式方便在各個介面中統一處理。

以上就是關於使用者管理介面的內容介紹,其中涉及到前端API類的封裝處理,介面元件的使用,以及一些常規操作,希望能夠帶給大家一些vue+element開發介面的參考。