如何在ABP框架中使用BootstrapTable組件

本篇文章為大家展示了如何在ABP框架中使用BootstrapTable組件,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

成都創(chuàng)新互聯(lián)主要業(yè)務(wù)有網(wǎng)站營銷策劃、成都網(wǎng)站設(shè)計、做網(wǎng)站、微信公眾號開發(fā)、微信平臺小程序開發(fā)H5頁面制作、程序開發(fā)等業(yè)務(wù)。一次合作終身朋友,是我們奉行的宗旨;我們不僅僅把客戶當(dāng)客戶,還把客戶視為我們的合作伙伴,在開展業(yè)務(wù)的過程中,公司還積累了豐富的行業(yè)經(jīng)驗、成都營銷網(wǎng)站建設(shè)資源和合作伙伴關(guān)系資源,并逐漸建立起規(guī)范的客戶服務(wù)和保障體系。 

一、關(guān)于ABP

ABP是“ASP.NET Boilerplate Project (ASP.NET樣板項目)”的簡稱,它是一個成熟的開源框架,基于DDD+Repository模式,自帶Zero權(quán)限和認(rèn)證模塊,避免了從零開始搭建框架的煩惱。關(guān)于ABP的框架優(yōu)勢就此打住,因為這樣說下去要說三天三夜,脫離文本主題。

如何在ABP框架中使用BootstrapTable組件

點擊CREATE MY DEMO按鈕,系統(tǒng)會自動為你生成演示地址

如何在ABP框架中使用BootstrapTable組件

進(jìn)入對應(yīng)的Demo URL

如何在ABP框架中使用BootstrapTable組件

使用演示的用戶名和密碼登陸進(jìn)去

如何在ABP框架中使用BootstrapTable組件

可以看到Zero模塊的實現(xiàn)效果。

二、jTable在ABP中的運用

如果你下載ABP的源碼,并且選擇的是混合開發(fā)模式(ABP提供了兩種開發(fā)模式,一種是基于MVVM的Angular.js的模式;另一種就是MVC+jQuery的混合開發(fā)模式),如下圖:

如何在ABP框架中使用BootstrapTable組件

當(dāng)你Down下來源碼之后你就會發(fā)現(xiàn),ABP的源碼里面的UI部分的表格都是使用jTable去實現(xiàn)的。為什么會用jTable?原因很簡單,jTable是ABP的作者kalkan寫的一款開源插件,自己寫的肯定用自己的東西嘍。下面jTable的效果來一發(fā)。

如何在ABP框架中使用BootstrapTable組件

如何在ABP框架中使用BootstrapTable組件

來一個jtable的父子表:

如何在ABP框架中使用BootstrapTable組件

如果是不帶父子表的簡單表格,其實jTable的效果其實還行,可是加上一些復(fù)雜的功能之后,那一片片藍(lán)色的區(qū)域不忍直視,并且jTable的api還有待完善,很多需要的功能都需要自己去實現(xiàn),于是就接到了將所有的表格組件換成BootstrapTable的需求,才有了今天的主題:在ABP中封裝BootstrapTable。

三、Bootstrap Table在ABP中的封裝

接到需求,博主各種百度、各種谷歌,都找不到Bootstrap Table組件在ABP中的封裝,有的只是在ABP的項目里面簡單的用傳統(tǒng)的方式去初始化組件,這并不是博主想要的。說到這里不得不說一下,如果你使用ABP開發(fā)的過程中遇到一些難題,你會發(fā)現(xiàn)很難從百度里面搜索到相關(guān)答案,谷歌里面有時能找到,但大部分都是英文社區(qū),所以如果你英文較弱,在查找資料上面會很吃虧,有時一個簡單的配置問題需要折騰很久。

1、jTable在ABP項目里面的初始化

首先來看看jTable在一般的ABP項目里面是如何初始化的。比如我們在Application里面有一個如下的接口和實現(xiàn)

如何在ABP框架中使用BootstrapTable組件

 public interface IRequisitionAppService : IApplicationService
 {
  Task<PagedResultDto<RequisitionListDto>> GetRequisitionListAsync(GetRequisitionListInput input);
 }
  [AbpAuthorize(OrderAppPermissions.Pages_Order_Requisition)]
 public class RequisitionAppService : AbpZeroTemplateAppServiceBase, IRequisitionAppService
 {
  private readonly IRepository<Requisition, long> _requisitionRepository;
  public RequisitionAppService(IRepository<Requisition, long> requisitionRepository)
  {
   _requisitionRepository = requisitionRepository;
  }
     public async Task<PagedResultDto<RequisitionListDto>> GetRequisitionListAsync(GetRequisitionListInput input)
  {
   var query = _requisitionRepository.GetAll()
             .WhereIf(input.Status != null, w => (int)w.Status == input.Status.Value)
             .WhereIf(
              !input.Filter.IsNullOrWhiteSpace(),
              u =>
               u.No.Contains(input.Filter) ||
               u.Remark.Contains(input.Filter)
             );
   var count = await query.CountAsync();
   var list = await query
   .OrderBy(input.Sorting)
   .PageBy(input)
   .ToListAsync();
   var dtos = list.MapTo<List<RequisitionListDto>>();
   return new PagedResultDto<RequisitionListDto>(
    count,
    dtos
    );
  }
 }

然后我們前端有一個頁面的列表數(shù)據(jù)從這個接口GetRequisitionListAsync()獲取

<div class="portlet-body">
 <div id="dataListTable"></div>
</div>
(function () {
 $(function () {
  var _$dataListTable = $('#dataListTable');
  var _service = abp.services.app.requisition;
  _$dataListTable.jtable({
   paging: true,
   sorting: true,
   selecting: true,
   actions: {
    listAction: {
     method: _service.getRequisitionListAsync
    }
   },
   fields: {
    id: {
     key: true,
     list: false
    },
    details: {
     width: '1%',
     sorting: false,
     edit: false,
     create: false,
     listClass: 'child-opener-image-column',
     display: function (detailData) {
      var $img = $('<img class="child-opener-image" src="/Common/Images/list_metro.png" title="申購明細(xì)" />');
      $img.click(function () {
       _$dataListTable.jtable('openChildTable',
        $img.closest('tr'),
        {
         title: "申購明細(xì)",
         showCloseButton: true,
         actions: {
          listAction: {
           method: _service.getRequisitionDetailListByIdAsync
          }
         },
         fields: {
          materialClassParentNameAndName: {
           title: app.localize('MaterialClassName'),
           width: '8%'
          },
          materialInfoTypeNo: {
           title: app.localize('TypeNo'),
           width: '5%'
          },
          materialInfoLengthDisplayName: {
           title: app.localize('LengthDisplayName'),
           width: '3%'
          },
          materialInfoWeight: {
           title: app.localize('Weight'),
           width: '5%',
           display: function (data) {
            return data.record.materialInfoMinWeight + '-' + data.record.materialInfoMaxWeight;
           }
          },
          materialInfoMouldTypeDisplayName: {
           title: app.localize('MouldTypeDisplayName'),
           width: '6%'
          },
          materialInfoProductionRemark: {
           title: app.localize('ProductionRemark'),
           width: '8%'
          },
          materialInfoBundleCountDisplayName: {
           title: app.localize('BundleCountDisplayName'),
           width: '3%'
          },
          materialInfoUnitDisplayName: {
           title: app.localize('UnitDisplayName'),
           width: '3%'
          },
          materialInfoProcessCost: {
           title: app.localize('ProcessCost'),
           width: '6%'
          },
          materialInfoProductRemark: {
           title: app.localize('ProductRemark'),
           width: '6%'
          },
          materialInfoRemark: {
           title: app.localize('Remark'),
           width: '6%'
          },
          count: {
           title: app.localize('申購數(shù)量'),
           width: '6%'
          },
          remark: {
           title: app.localize('申購備注'),
           width: '6%'
          }
         }
        }, function (data) {
         data.childTable.jtable('load',
          { requisitionId: detailData.record.id }
         );
        });
      });
      return $img;
     }
    },
    no: {
     title: "申購單號",
     width: '20%'
    },
    creatorUserName: {
     title: "申購人",
     width: '20%'
    },
    creationTime: {
     title: "申購時間",
     width: '10%',
     display: function (data) {
      return moment(data.record.creationTime).format('YYYY-MM-DD HH:mm:ss');
     }
    },
    sumCount: {
     title: "總數(shù)",
     width: '10%'
    },
    status: {
     title: "狀態(tài)",
     width: '20%',
     display: function (data) {
      if (data.record.status === app.order.requisitionAuditStatus.audit)
       return '<span class="label label-info">' + app.localize('Autdit') + '</span>'
      else if (data.record.status === app.order.requisitionAuditStatus.auditPass)
       return '<span class="label label-success">' + app.localize('Pass') + '</span>'
      else if (data.record.status === app.order.requisitionAuditStatus.auditReject)
       return '<span class="label label-danger">' + app.localize('Reject') + '</span>'
      else if (data.record.status === app.order.requisitionAuditStatus.delete)
       return '<span class="label label-danger">' + app.localize('Abandon') + '</span>'
      else
       return '<span class="label label-danger">' + app.localize('Unknown') + '</span>'
     }
    }
   }
  });
 });
})();

得到如下效果:

如何在ABP框架中使用BootstrapTable組件

代碼釋疑:

(1) var _service = abp.services.app.requisition; 這一句聲明當(dāng)前頁面需要使用哪個服務(wù)。

(2)  _service.getRequisitionListAsync 這一句對應(yīng)的是服務(wù)調(diào)用的方法,你會發(fā)現(xiàn)在后臺方法名是GetRequisitionListAsync(),而在js里面卻變成了getRequisitionListAsync(),我們暫且稱之為“潛規(guī)則”。

2、bootstrapTable在ABP項目里面的封裝

通過上述代碼你會發(fā)現(xiàn),ABP在application層里面定義的方法,最終會生成某一些js對應(yīng)的function,這里難點來了。我們找遍了bootstrapTable組件的api,都沒有通過某一個function去獲取數(shù)據(jù)的啊。這可如何是好?為這個問題,博主折騰了兩天。最開始博主想,function最終還不是要換成http請求的,我們只要拿到http請求的url,然后將function轉(zhuǎn)換為url不就行了么:

如何在ABP框架中使用BootstrapTable組件

我們使用bootstrapTable組件初始化的時候聲明  {url:'/api/services/app/requisition/GetRequisitionListAsync'}  這樣不就行了么?呵呵,經(jīng)過測試,這樣確實能正確取到數(shù)據(jù)。但是不夠理想,因為這前面的前綴是ABP給我們生成的,是否會變化我們尚且不說,給每一個url加上這么一長串著實看著很不爽,于是進(jìn)一步想,是否我們的bootstrapTable也可以使用function去初始化呢,組件沒有,難道我們就不能給他擴(kuò)展一個嗎?我們不用url獲取數(shù)據(jù),通過調(diào)用這個function取到數(shù)據(jù),然后將數(shù)據(jù)渲染到組件不就行了。思路有了,那么這里有兩個難題:一是如何將原來url的方式變成這里的調(diào)用function的方式呢?二是參數(shù)的封裝。經(jīng)過查看組件的源碼發(fā)現(xiàn),如果是服務(wù)端分頁,組件最終是進(jìn)入到initServer()這個方法去獲取數(shù)據(jù),然后渲染到頁面上面的,組件原始的initServer()方法如下:

BootstrapTable.prototype.initServer = function (silent, query) {
  var that = this,
   data = {},
   params = {
    pageSize: this.options.pageSize === this.options.formatAllRows() ?
     this.options.totalRows : this.options.pageSize,
    pageNumber: this.options.pageNumber,
    searchText: this.searchText,
    sortName: this.options.sortName,
    sortOrder: this.options.sortOrder
   },
   request;
  if (!this.options.url && !this.options.ajax) {
   return;
  }
  if (this.options.queryParamsType === 'limit') {
   params = {
    search: params.searchText,
    sort: params.sortName,
    order: params.sortOrder
   };
   if (this.options.pagination) {
    params.limit = this.options.pageSize === this.options.formatAllRows() ?
     this.options.totalRows : this.options.pageSize;
    params.offset = this.options.pageSize === this.options.formatAllRows() ?
: this.options.pageSize * (this.options.pageNumber - 1);
   }
  }
  if (!($.isEmptyObject(this.filterColumnsPartial))) {
   params['filter'] = JSON.stringify(this.filterColumnsPartial, null);
  }
  data = calculateObjectValue(this.options, this.options.queryParams, [params], data);
  $.extend(data, query || {});
  // false to stop request
  if (data === false) {
   return;
  }
  if (!silent) {
   this.$tableLoading.show();
  }
  request = $.extend({}, calculateObjectValue(null, this.options.ajaxOptions), {
   type: this.options.method,
   url: this.options.url,
   data: this.options.contentType === 'application/json' && this.options.method === 'post' ?
    JSON.stringify(data) : data,
   cache: this.options.cache,
   contentType: this.options.contentType,
   dataType: this.options.dataType,
   success: function (res) {
    res = calculateObjectValue(that.options, that.options.responseHandler, [res], res);
    that.load(res);
    that.trigger('load-success', res);
   },
   error: function (res) {
    that.trigger('load-error', res.status, res);
   },
   complete: function () {
    if (!silent) {
     that.$tableLoading.hide();
    }
   }
  });
  if (this.options.ajax) {
   calculateObjectValue(this, this.options.ajax, [request], null);
  } else {
   $.ajax(request);
  }
 };

代碼不難讀懂,解析參數(shù),整合參數(shù),得到參數(shù),發(fā)送ajax請求,在success事件里面將得到的數(shù)據(jù)渲染到界面。讀懂了這段代碼,我們再來封裝function就容易多了。

最終我們封裝的代碼如下:

(function ($) {
 'use strict';
 //debugger;
 //通過構(gòu)造函數(shù)獲取到bootstrapTable里面的初始化方法
 var BootstrapTable = $.fn.bootstrapTable.Constructor,
  _initData = BootstrapTable.prototype.initData,
  _initPagination = BootstrapTable.prototype.initPagination,
  _initBody = BootstrapTable.prototype.initBody,
  _initServer = BootstrapTable.prototype.initServer,
  _initContainer = BootstrapTable.prototype.initContainer;
 //重寫
 BootstrapTable.prototype.initData = function () {
  _initData.apply(this, Array.prototype.slice.apply(arguments));
 };
 BootstrapTable.prototype.initPagination = function () {
  _initPagination.apply(this, Array.prototype.slice.apply(arguments));
 };
 BootstrapTable.prototype.initBody = function (fixedScroll) {
  _initBody.apply(this, Array.prototype.slice.apply(arguments));
 };
 BootstrapTable.prototype.initServer = function (silent, query) {
  //構(gòu)造自定義參數(shù)
  for (var key in this.options.methodParams) {
   $.fn.bootstrapTable.defaults.methodParams[key] = this.options.methodParams[key];
  }
  //如果傳了url,則走原來的邏輯
  if (this.options.url) {
   _initServer.apply(this, Array.prototype.slice.apply(arguments));
   return;
  }
  //如果定義了abpMethod,則走abpMethod的邏輯
  if (!this.options.abpMethod) {
   return;
  }
  var that = this,
   data = {},
   params = {
    pageSize: this.options.pageSize === this.options.formatAllRows() ?
     this.options.totalRows : this.options.pageSize,
    pageNumber: this.options.pageNumber,
    searchText: this.searchText,
    sortName: this.options.sortName,
    sortOrder: this.options.sortOrder
   },
   request;
  //debugger;
  if (this.options.queryParamsType === 'limit') {
   params = {
    search: params.searchText,
    sort: params.sortName,
    order: params.sortOrder
   };
   if (this.options.pagination) {
    params.limit = this.options.pageSize === this.options.formatAllRows() ?
     this.options.totalRows : this.options.pageSize;
    params.offset = this.options.pageSize === this.options.formatAllRows() ?
     0 : this.options.pageSize * (this.options.pageNumber - 1);
   }
  }
  if (!($.isEmptyObject(this.filterColumnsPartial))) {
   params['filter'] = JSON.stringify(this.filterColumnsPartial, null);
  }
  data = $.fn.bootstrapTable.utils.calculateObjectValue(this.options, this.options.queryParams, [params], data);
  $.extend(data, query || {});
  // false to stop request
  if (data === false) {
   return;
  }
  if (!silent) {
   this.$tableLoading.show();
  }
  this.options.abpMethod(data).done(function (result) {
   result = $.fn.bootstrapTable.utils.calculateObjectValue(that.options, that.options.responseHandler, [result], result);
   that.load(result);
   that.trigger('load-success', result);
  });
  request = $.extend({}, $.fn.bootstrapTable.utils.calculateObjectValue(null, this.options.ajaxOptions), {
   type: this.options.method,
   url: this.options.url,
   data: this.options.contentType === 'application/json' && this.options.method === 'post' ?
    JSON.stringify(data) : data,
   cache: this.options.cache,
   contentType: this.options.contentType,
   dataType: this.options.dataType,
   success: function (res) {
    debugger;
    res = $.fn.bootstrapTable.utils.calculateObjectValue(that.options, that.options.responseHandler, [res], res);
    that.load(res);
    that.trigger('load-success', res);
   },
   error: function (res) {
    that.trigger('load-error', res.status, res);
   },
   complete: function () {
    if (!silent) {
     that.$tableLoading.hide();
    }
   }
  });
  if (this.options.ajax) {
   $.fn.bootstrapTable.utils.calculateObjectValue(this, this.options.ajax, [request], null);
  } else {
   $.ajax(request);
  }
 }
 BootstrapTable.prototype.initContainer = function () {
  _initContainer.apply(this, Array.prototype.slice.apply(arguments));
 };
 abp.bootstrapTableDefaults = {
  striped: false,
  classes: 'table table-striped table-bordered table-advance table-hover',
  pagination: true,
  cache: false,
  sidePagination: 'server',
  uniqueId: 'id',
  showRefresh: false,
  search: false,
  method: 'post',
  //toolbar: '#toolbar',
  pageSize: 10,
  paginationPreText: '上一頁',
  paginationNextText: '下一頁',
  queryParams: function (param) {
   //$.fn.bootstrapTable.defaults.methodParams.propertyIsEnumerable()
   var abpParam = {
    Sorting: param.sort,
    filter: param.search,
    skipCount: param.offset,
    maxResultCount: param.limit
   };
   for (var key in $.fn.bootstrapTable.defaults.methodParams) {
    abpParam[key] = $.fn.bootstrapTable.defaults.methodParams[key];
   }
   return abpParam;
  },
  responseHandler: function (res) {
   if (res.totalCount)
    return { total: res.totalCount, rows: res.items };
   else
    return { total: res.result.totalCount, rows: res.result.items };
  },
  methodParams: {},
  abpMethod: function () { }
 };
 $.extend($.fn.bootstrapTable.defaults, abp.bootstrapTableDefaults);
})(jQuery);

代碼釋疑:增加兩個參數(shù) methodParams: {},abpMethod: function () { } 來獲取abp的function和參數(shù),然后獲取數(shù)據(jù)的時候如果定義了abpMethod,則通過function獲取數(shù)據(jù),否則還是走原來的邏輯。

然后我們調(diào)用就簡單了

//選取界面上要先數(shù)據(jù)的表格
  var _$SendOrdersTable = $('#SendOrdersTable');
  //獲取服務(wù)層方法
  var _SendOrderService = abp.services.app.sendOrder;
  _$SendOrdersTable.bootstrapTable({
   abpMethod: _SendOrderService.getSendOrderListAsync,
   detailView: true,
   onExpandRow: function (index, row, $detail) {
    var cur_table = $detail.html('<table></table>').find('table');
    $(cur_table).bootstrapTable({
     showRefresh: false,
     search: false,
     pagination: false,
     abpMethod: _SendOrderService.getSendOrderDetailListAsync,
     methodParams: { SendOrderId: row.id },
     columns: [
      {
       field: 'materialClassName',
       title: app.localize('MaterialClassName'),
       width: '8%'
      },
      {
       field: 'typeNo',
       title: app.localize('TypeNo'),
       width: '8%'
      }
     ]
    });
   },
   columns: [{
    field: 'no',
    title: app.localize('SendOrderNO'),
    align: 'center'
   },
   {
    field: 'supplierName',
    title: app.localize('SupplierName'),
    align: 'center'
   },
   {
    title: app.localize('SendOrderTime'),
    align: 'center',
    field: 'createdDate',
    formatter: function (data) {
     return moment(data).format('YYYY-MM-DD HH:mm:ss');
    }
   },
   {
    field: 'status',
    align: 'center',
    title: app.localize('SendOrderStatus'),
    formatter: function (data) {
     var value = "";
     if (data == 1) {
      value = '<span class="label label-info">' + app.localize('Autdit') + '</span>';
     }
     else if (data == 2) {
      value = '<span class="label label-success">' + app.localize('Pass') + '</span>';
     }
     else if (data == 3) {
      value = '<span class="label label-default">' + app.localize('Reject') + '</span>';
     }
     else
      value = '<span class="label label-default">' + app.localize('Abandon') + '</span>';
     return value;
    }
   },
   {
    field: 'createName',
    align: 'center',
    title: app.localize('SendOrderCreator'),
   },
   {
    field: 'sumCount',
    align: 'center',
    title: app.localize('SendOrderTotalCount'),
   },
   ]
  });

得到如下效果

如何在ABP框架中使用BootstrapTable組件

上述內(nèi)容就是如何在ABP框架中使用BootstrapTable組件,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

本文題目:如何在ABP框架中使用BootstrapTable組件
URL標(biāo)題:http://muchs.cn/article22/jsoijc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、動態(tài)網(wǎng)站網(wǎng)站維護(hù)、App設(shè)計Google、網(wǎng)站設(shè)計

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)