Source: emapDataTable.js

(function() {
  var Plugin;
  var editedBg = 'cell-edited';
  var toDeleteKey = 'isToDelete';
  var toDeleteLine = 'to-delete-line';
  var showToDeleteLine = 'show-to-delete';

  /**
   * @module emapdatatable
   * @alias 表格
   * @description 数据表格 
   */
  Plugin = (function() {
    function Plugin(element, options) {
      //将插件的默认参数及用户定义的参数合并到一个新的obj里
      $.fn.emapdatatable.defaults.fxss = WIS_EMAP_CONFIG['emapdatatable.fxss'];
      this.settings = $.extend({}, $.fn.emapdatatable.defaults, options);
      //将dom jquery对象赋值给插件,方便后续调用
      this.$element = $(element);
      this.$element.attr("emap-role", "datatable").attr("emap-pagePath", this.settings.pagePath).attr("emap-action", this.settings.action);

      //拼接请求地址
      // var url = this.settings.url || WIS_EMAP_SERV.getAbsPath(this.settings.pagePath).replace('.do', '/' + this.settings.action + '.do');
      var url = this.settings.url;
      if (!url) {
        url = WIS_EMAP_SERV.getAbsPath(this.settings.pagePath);
        url = WIS_EMAP_SERV.joinActionIdToDoUrl(url, this.settings.action);
      }

      //前端模拟数据开发时type使用get方式
      var ajaxMethod = this.settings.method || 'POST';
      if (typeof window.MOCK_CONFIG != 'undefined') {
        //qiyu 2016-7-21 将emapdatatable中的获取mock的url提取函数,在mock文件中重新定义
        ajaxMethod = this.settings.method || getMethodMock();
        if (typeof this.settings.url == 'undefined') {
          url = getURLMock(url, this.settings);
        }
      }
      var params = null;
      if (this.settings.params || this.settings.onceParams) {
        params = $.extend({}, this.settings.params, this.settings.onceParams);
      } else {
        params = $.extend({}, this.settings.defaultParams);
        params = _getQuerySetting(params);
      }
      //数据源
      if (this.settings.source) {
        this.source = this.settings.source;
      } else {
        this.source = {
          root: 'datas>' + this.settings.action + '>rows',
          id: this.settings.pk || 'WID', // id: "WID", 主键字段可配置  //qiyu 2016-1-16
          datatype: 'json',
          url: url,
          data: params || {},
          type: WIS_EMAP_CONFIG.tableDataType || ajaxMethod,
          datafields: []
        };
      }

      //qiyu 2016-7-21 将emapdatatable中的获取mock的url提取函数,在mock文件中重新定义
      if (typeof window.MOCK_CONFIG != 'undefined') {
        this.source = getSourceMock(this.source);
      }

      _create(this);
    }

    /**
     * @method reload
     * @description 刷新表格数据
     * @param {Object} params - 附带参数
     * @param {Object} params._gotoFirstPage - 
     * callback 可以是function 或者是 true,true的话意味着强制跳回第一页
     * _gotoFirstPage 如果callback为回调函数,此时需要调回第一页 则可以设置params._gotoFirstPage为true
     * 
     */
    Plugin.prototype.reload = function(params, callback) {
      /**
       * 方法内容
       */
      if (!$.isEmptyObject(this.settings.defaultParams)) {
        this.source.data = _getQuerySetting(this.settings.defaultParams);
      }

      var gotoFirstPage = false;
      if (params) {
        gotoFirstPage = params._gotoFirstPage;
        gotoFirstPage && delete params._gotoFirstPage;
      }
      if (params) {
        if (!$.isEmptyObject(this.settings.defaultParams)) {
          try {
            var query = JSON.parse(params.querySetting);
            query.push.apply(query, JSON.parse(this.source.data.querySetting));
            this.source.data.querySetting = JSON.stringify(query);
          } catch (e) {
            this.source.data = params;
          }
        } else {
          this.source.data = params;
        }
      }
      if (callback === true || gotoFirstPage === true) {
        if (!this.$element.jqxDataTable('goToPage', 0)) {
          this.$element.jqxDataTable('updateBoundData');
        }
      } else {
        this.$element.jqxDataTable('updateBoundData');
      }

      var that = this;
      if (typeof callback == 'function') {
        var intervalId = setInterval(function() {
          if (that.$element.jqxDataTable('isBindingCompleted')) {
            clearInterval(intervalId);
            // 将callback放在 refresh后面, 避免callback中的dom操作被refresh刷新掉 zhuhui 2016-10-21
            that.$element.jqxDataTable('refresh');
            callback();
          }
        }, 10);
      }
    };

    /**
     * @method getCurrentQueryParams
     * @description 获取当钱表格传到后台的查询条件,包含排序
     * @return {Object}
     */
    Plugin.prototype.getCurrentQueryParams = function() {
      return this.$element.data('currentQueryParams');
    };

    /**
     * @method reloadFirstPage
     * @description 默认刷新表格回到首页
     * @param {Object} params - 附带参数
     * @param {Function} callback - 回调函数
     */
    Plugin.prototype.reloadFirstPage = function(params, callback) {
      this.reload($.extend({}, params, {
        _gotoFirstPage: true
      }), callback);
    };

    /**
     * @method checkedRecords
     * @description 获取选中的数据
     */
    Plugin.prototype.checkedRecords = function() {
      var selectedArr = [];
      var rowsData = this.$element.jqxDataTable('getRows');
      var $checkedSelector = this.$element.find('table.jqx-grid-table:not([id^="pinnedtable"])>tbody>tr:not([data-role="row-group"])');
      var $table = this.$element.find('table[id^="pinnedtable"].jqx-grid-table');
      if ($table.length > 0) {
        $checkedSelector = $table.find('tr');
      }
      var self = this;
      $checkedSelector.each(function(index) {
        var row = rowsData[index];
        if (self.settings.editMode && $(this).find('.' + editedBg).length) {
          var value = WIS_EMAP_INPUT.formGetValue($(this), {});
          row = $.extend({}, row, value);
        }
        if ($(this).find('input[type="checkbox"]').length > 0) {
          var ischecked = $(this).find('input[type="checkbox"]').prop('checked');
          if (ischecked) {
            selectedArr.push(row);
          }
        } else if ($(this).find('input[type="radio"]').length > 0) {
          var ischecked = $(this).find('input[type="radio"]').prop('checked');
          if (ischecked) {
            selectedArr.push(row);
          }
        }

      });
      return selectedArr;
    };

    /**
     * @method checkedRowsIndex
     * @description 获取被勾选行的索引
     * @return {Array} 行索引数组
     */
    Plugin.prototype.checkedRowsIndex = function() {
      var selectedArr = [];
      var $checkedSelector = this.$element.find('table:not([id^="pinnedtable"]) tr');
      if (this.$element.find('table[id^="pinnedtable"]').length > 0) {
        $checkedSelector = this.$element.find('table[id^="pinnedtable"] tr');
      }
      $checkedSelector.each(function(index) {
        var ischecked = $(this).find('input[type="checkbox"]').prop('checked');
        if (ischecked) {
          selectedArr.push(index);
        }
      });
      return selectedArr;
    };

    /**
     * @method getTotalRecords
     * @description 获取数据总条数
     */
    Plugin.prototype.getTotalRecords = function() {
      return this.source.totalRecords;
    };

    /**
     * @method getResult 
     * @description 获取当前表格内数据
     */
    Plugin.prototype.getResult = function() {
      return this.$element.data('tableResult');
    };

    /**
     * @method getRowsData 
     * @description 获取接口返回的行数据
     */
    Plugin.prototype.getRowsData = function() {
      return this.$element.data('tableRows');
    };

    /**
     * @method getSort
     * @description 获取表格排序
     */
    Plugin.prototype.getSort = function() {
      var args = this.$element.data("sortfield");

      if (args === undefined)
        return;

      var sortObj = {
        direction: args.sortdirection,
        field: args.sortcolumn,
        exp: ""
      };
      var exp = "";
      if (args.sortdirection.ascending == true) {
        sortObj.exp = "+" + args.sortcolumn;
      } else if (args.sortdirection.descending == true) {
        sortObj.exp = "-" + args.sortcolumn;
      }

      return sortObj;
    };

    /**
     * @method getModel
     * @description 获取表格数据
     */
    Plugin.prototype.getModel = function() {
      return this.$element.data('tableDataModel');
    };

    /**
      * @method selectColumnsExport
      * @description 导出 表格数据, 列为选择列  
      *    
      * @param  {object} params 
      *
      *  【url】:
         /[root]/sys/emapcomponent/imexport/export.do

        【参数 params】:
         root: 
         app:调用导出的应用名称,必填
         module:调用导出的模块名,必填
         page:调用导出的页面,必填
         action:调用导出的动作,必填
         colnames:导出时自定义的字段,多个用逗号分隔,选填  toUpperCase
         analyse:自定义的导出过程分析服务,实现IImportAnalyse,选填
         write:自定义的导出写文件服务,实现IExportWrite,选填
         filename:自定义的导出文件名,选填
      * 
      */
    Plugin.prototype.selectColumnsExport = function(params) {
      this.selectToShowColumns({
        type: 'export',
        params: params
      });
    };

    /**
     * @method selectToShowColumns
     * @description 展开选择列窗口
     * @param  {object} action 动作
     *    {
     *        type: //action type, 内置动作有 toggle(默认),export
     *        handler: //action handler
     *        param:  //action hander 的参数
     *        dialogOpt:{} //同同BH_UTILS.bhWindow
     *        columnsReorder:Boolean 是否需要排序字段
     *    }
     *    'toggle'  显示选择的列,隐藏未选择的列,默认值
     *    'export'  导出表单, 支持选择列                         
     * @param {object} params  action 动作 所需的参数      
     */
    Plugin.prototype.selectToShowColumns = function(action) {
      var self = this;
      action = action || {};
      action.type = action.type || 'toggle';

      // 表格传参时,为了方便高级搜索会将其他参数合并进来,  其中有可能含有type 所以 此处默认走 隐藏显示列
      // zhuhui 6-8
      if (action.type === 'export') {
        action.columnsReorder = false;
        action['name'] = $.i18n('bh-dd-exportChoosedKeys');
        action['handler'] = function(columns) {
          var config, selectedCols;
          selectedCols = [];
          columns.forEach(function(col) {
            if (col.hidden === false && col.hasOwnProperty('datafield')) {
              selectedCols.push(col.datafield);
            }
          });

          config = $.extend({}, action.params, {
            colnames: selectedCols.join(',').replace(/_DISPLAY/g, '').toUpperCase()
          });
          self.export(config);
        };
      } else {
        action['name'] = $.i18n('bh-dd-showOrHideKeys');
        action['handler'] = function(columns) {
          self.$element.data('columns', columns); // 将新的显示列的数据放回data-columns, 保证后续操作数据同步
          if (self.settings.fastRender) {
            columns = columns.filter(function(item) {
              return !item.hidden;
            });
          }
          var conditionDataNew = ""
          if (columns[0].text == "checkbox") {
            conditionDataNew = "field_checkbox,"
          }
          for (var k = 0; k < $("#fooSide").find("li").length; k++) {
            if (k == $("#fooSide").find("li").length - 1) {
              conditionDataNew += $("#fooSide").find("li").eq(k).attr("name")
            } else {
              conditionDataNew += $("#fooSide").find("li").eq(k).attr("name") + ","
            }
          }
          conditionData = conditionDataNew;
          // self.$element.data('schemaList',conditionData.split(","));
          var listColumns = conditionData.split(",");
          var newColumns = [];
          for (var m = 0; m < listColumns.length; m++) {
            for (var n = 0; n < columns.length; n++) {
              var keyData = columns[n].datafield && columns[n].datafield.replace("_DISPLAY", "")
              if (listColumns[m].replace("_DISPLAY", "") == keyData || columns[n].text == "操作") {
                if (JSON.stringify(newColumns).indexOf(JSON.stringify(columns[n])) == -1) {
                  newColumns.push(columns[n]);
                }
              }
            }
          }
          var out_columns = [];
          for (var k = 0; k < columns.length; k++) {
            var keyColums = columns[k].datafield && columns[k].datafield.replace("_DISPLAY", "");
            if (listColumns.indexOf(keyColums) == -1 && columns[k].text != "操作") {
              if (out_columns.indexOf(columns[k]) == -1) {
                out_columns.push(columns[k]);
              }
            }
          }
          newColumns = newColumns.concat(out_columns);
          var eleColumns = self.$element.data("columns");
          var eleColumnsArr = newColumns;
          self.$element.jqxDataTable({
            columns: newColumns
          });
          self.$element.data('columns', eleColumns);
          if ((self.settings.schema || self.settings.columnsReorder) && self.settings.contextPath) { // if rememberCustomColumn , save columns
            _saveSchema(self, newColumns, self.settings.saveSchemaCallback);
          }

        };
      }

      // 导出时,会对列显示数据进行修改, 所以此出将列数据复制,避免导出功能影响自定义列显示 zhuhui 2017-02-09
      var columns = WIS_EMAP_SERV.cloneObj(this.$element.data('columns'));
      var newmodel = this.$element.data('newmodel');
      _initSelectColumnsWindow(this, newmodel, columns, action);
    };

    /**
     * @method export
     * @description 导出表格数据
     * @param {Object} config - 配置参数,导出请求参数
     * @param {String} config.root - 根路径
     */
    Plugin.prototype.export = function(config) {
      config = config || {};
      var root = config.root;
      delete config.root;
      $.ajax({
          url: root + '/sys/emapcomponent/imexport/export.do',
          data: config,
          dataType: 'json',
          type: 'POST'
        })
        .done(function(res) {
          if (res.status == 1) {
            window.location.href = location.protocol + '//' + location.host + root + '/sys/emapcomponent/file/getAttachmentFile/' + res.attachment + '.do';
          } else {
            $.bhTip({
              content: $.i18n('bh-dd-exportRequestFailed'),
              state: 'danger'
            });
          }
        });
    };

    /**
     * @method  getVisibleColumns
     * @description 获取当前表格内所有显示的列
     * @return {Array} 可视的列
     */
    Plugin.prototype.getVisibleColumns = function() {
      var columns = this.$element.data('columns');
      if (columns && columns.length) {
        return columns.filter(function(item) {
          return !item.hidden;
        });
      }
      return [];
    };

    /**
     * @method enterEditMode
     * @description 进入表格编辑模式
     */
    Plugin.prototype.enterEditMode = function() {
      if (this.settings.canEdit) {
        var newmodel = this.$element.data('newmodel');
        var columns = $.extend(true, [], this.$element.data('columns'));
        this.settings.editMode = true;
        _convertEditModeCols(columns, newmodel);
        this.$element.data('changedRowsData', []);
        this.$element.jqxDataTable({
          pageable: !!this.settings.editPageable,
          columns: columns
        });
      }
    };

    /**
     * @method leaveEditMode
     * @description 退出表格编辑模式
     */
    Plugin.prototype.leaveEditMode = function() {
      if (this.settings.canEdit) {
        var $load = this.$element.jqxDataTable('dataloadelement');
        $load.css({
          visibility: 'visible',
          display: 'block',
          width: this.$element.jqxDataTable('host').width()
        });
        $('[xtype]', this.$element).each(function() {
          var _this = $(this);
          var xtype = _this.attr('xtype');
          switch (xtype) {
            case 'select':
              _this.jqxDropDownList('destroy');
              break;
            case 'multi-select':
              _this.jqxComboBox('destroy');
              break;
            case 'date-local':
            case 'date-ym':
            case 'date-full':
              _this.jqxDateTimeInput('destroy');
              break;
            case 'tree':
              _this.jqxDropDownButton('destroy');
              break;
          }
        });
        var columns = this.$element.data('columns');
        var rows = this.$element.jqxDataTable('getRows');
        rows.forEach(function(row) {
          delete row[toDeleteKey];
        });
        this.settings.editMode = false;
        this.$element.data('changedRowsData', []);
        this.$element.jqxDataTable({
          pageable: this.settings.pageable,
          height: this.settings.height,
          columns: columns
        });
        if (!this.settings.pageable) {
          bindingComplete(this);
        }
        $load.css({
          visibility: 'hidden',
          display: 'none',
          width: '100%'
        });
      }
    };

    /**
     * @method getChangedRows
     * @description 获取已改变的数据,不包含待删除的数据
     * @return {Array} 所有已改变的行的数据
     */
    Plugin.prototype.getChangedRows = function() {
      if (this.settings.editMode) {
        var rows = this.$element.jqxDataTable('getRows');
        var $content = this.$element.jqxDataTable('content').find('table:not([id^="pinnedtable"])');
        var changedRow = [];
        $content.find('tbody>tr').each(function(i) {
          if ($(this).find('.' + editedBg).length && rows[i] !== undefined && !rows[i][toDeleteKey]) {
            var value = WIS_EMAP_INPUT.formGetValue($(this), {});
            changedRow.push($.extend({}, rows[i], value));
          }
        });
        return changedRow;
      }
    };

    /**
     * @method getToDeleteRows
     * @description 获取将要被删除的行索引
     * @return {Array} 索引数组
     */
    Plugin.prototype.getToDeleteRows = function() {
      if (this.settings.editMode) {
        var rows = this.$element.jqxDataTable('getRows');
        var $content = this.$element.jqxDataTable('content').find('table:not([id^="pinnedtable"])');
        var $trs = $content.find('tbody>tr');
        var toDeleteData = [];
        rows.forEach(function(row, i) {
          if (row[toDeleteKey]) {
            toDeleteData.push(WIS_EMAP_INPUT.formGetValue($trs.eq(i), {}));
          }
        });
        return toDeleteData;
      }
    };

    /**
     * @method getCurrentTableRows
     * @description 获取当前表格实例包含的数据,不包含待删除的行
     * @return {Array} [description]
     */
    Plugin.prototype.getCurrentTableRows = function() {
      var rows = this.$element.jqxDataTable('getRows');
      if (this.settings.editMode) {
        var $content = this.$element.jqxDataTable('content').find('table:not([id^="pinnedtable"])');
        var currentRows = [];
        $content.find('tbody>tr').each(function(i) {
          if (rows[i] !== undefined && !rows[i][toDeleteKey]) {
            if ($(this).find('.' + editedBg).length) {
              var value = WIS_EMAP_INPUT.formGetValue($(this), {});
              currentRows.push($.extend({}, rows[i], value));
            } else {
              currentRows.push($.extend({}, rows[i]));
            }
          }
        });
        return currentRows;
      } else {
        return rows;
      }
    };

    /**
     * @method deleteRowInEditMode
     * @param  {Object} opt 入参,因组件对字符做特殊处理,用于查询,所以此处规定入参为Object
     * @param {Number} opt.rowIndex 行索引
     */
    Plugin.prototype.deleteRowInEditMode = function(opt) {
      opt = opt || {};
      if ($.isNumeric(opt.rowIndex) && this.settings.editMode) {
        var rows = this.$element.jqxDataTable('getRows');
        var index = opt.rowIndex;
        if (rows[index]) {
          rows[index][toDeleteKey] = true;
          var $content = this.$element.jqxDataTable('content').find('table:not([id^="pinnedtable"])');
          var $tr = $content.find('tbody>tr').eq(index);
          WIS_EMAP_INPUT.formDisable($tr);
          $tr.find('>td').each(function(i) {
            $(this).find('[data-sss] input').prop('disabled', true);
            $(this).addClass(showToDeleteLine);
          });
        }
      }
    };

    /**
     * @method cancelDeleteRowInEditMode
     * @param  {Object} opt 入参,因组件对字符做特殊处理,用于查询,所以此处规定入参为Object
     * @param [Number] opt.rowIndex 行索引
     */
    Plugin.prototype.cancelDeleteRowInEditMode = function(opt) {
      opt = opt || {};
      if ($.isNumeric(opt.rowIndex) && this.settings.editMode) {
        var rows = this.$element.jqxDataTable('getRows');
        var index = opt.rowIndex;
        if (rows[index]) {
          delete rows[index][toDeleteKey];
          var $content = this.$element.jqxDataTable('content').find('table:not([id^="pinnedtable"])');
          var $tr = $content.find('tbody>tr').eq(index);
          WIS_EMAP_INPUT.formEnable($tr);
          $tr.find('>td').each(function(i) {
            $(this).find('[data-sss] input').prop('disabled', false);
            $(this).removeClass(showToDeleteLine);
          });
        }
      }
    };

    /**
     * @method isInEditMode
     * @description 判断表格是否处于编辑模式
     * @return {Boolean}
     */
    Plugin.prototype.isInEditMode = function() {
      return this.settings.editMode;
    };

    /**
     * @method validateTable
     * @description 校验表格输入是否合法
     * @return {Bollean}
     */
    Plugin.prototype.validateTable = function() {
      var $content = this.$element.jqxDataTable('content').find('table:not([id^="pinnedtable"])');
      var isValidate = true;
      $content.find('tbody>tr').filter(function() {
        return $(this).find('.' + showToDeleteLine).length === 0;
      }).each(function() {
        if (!$(this).emapValidate('validate')) {
          isValidate = false;
        }
      });
      return isValidate;
    };

    /**
     * @method addRow
     * @description 添加行,支持编辑模式
     * @param {Object} [obj] 
     * @param {Number} [obj.rowIndex] 第几行(貌似没有作用)
     * @param {Object} [obj.rowData] 添加的数据
     * @param {String | Number} [obj.rowPosition = 'first'] 在添加到第几行后面,添加到第一行传'first',最后一行传'last'
     */
    Plugin.prototype.addRow = function(obj) {
      obj = obj || {};
      var index = obj.rowIndex;
      var rowIndex = obj.rowIndex;
      if (rowIndex === undefined) {
        rowIndex = null;
      }
      var rowData = obj.rowData;
      var rowPosition = '';
      if (obj.hasOwnProperty('rowPosition')) {
        rowPosition = obj.rowPosition;
        if (rowPosition === 'first') {
          index = 0;
        }
      }
      if (rowPosition !== 'last' && this.settings.editMode) {
        var changedData = this.$element.data('changedRowsData');
        changedData.splice(index, 0, rowData || {});
      }
      return this.$element.jqxDataTable('addRow', rowIndex, rowData || {}, rowPosition);
    };

    /**
     * @method deleteRow
     * @description 删除行,支持编辑模式
     * @param  {Object} [obj] 
     * @param {Number | String}  obj.rowIndex 删除第几行
     */
    Plugin.prototype.deleteRow = function(obj) {
      obj = obj || {};
      var index = obj.rowIndex * 1 || 0;
      if (this.settings.editMode) {
        var changedData = this.$element.data('changedRowsData');
        changedData.splice(index, 1);
      }
      return this.$element.jqxDataTable('deleteRow', index);
    };

    return Plugin;

  })();

  //根据JSON拼装query条件
  function _getQuerySetting(params) {
    if (!$.isEmptyObject(params) && !params.querySetting) {
      var query = [];
      for (var key in params) {
        query.push({
          name: key,
          value: params[key],
          linkOpt: 'AND',
          builder: 'equal'
        });
      }
      return {
        querySetting: JSON.stringify(query)
      };
    } else {
      return $.extend({}, params);
    }
  }

  function indexOf(arr, cb) {
    var alength = arr.length;
    for (var i = 0; i < alength; i++) {
      var o = cb(arr[i], i);
      if (o === true) {
        return i;
      }
    }
    return -1;
  }

  function compact(arr) {
    for (var i = 0; i < arr.length; i++) {
      if (!arr[i]) {
        arr.splice(i, 1);
        i--;
      }
    }
    return arr;
  }

  /**
   * 插件的私有方法
   */
  //生成表格
  function _create(instance) {
    if (!instance.settings.contextPath) {
      instance.settings.contextPath = WIS_EMAP_SERV.getContextPath();
    }

    var jqxOptions = $.extend({}, instance.settings);
    try {
      delete jqxOptions.pk; //qiyu 2016-1-16 
      delete jqxOptions.url;
      delete jqxOptions.pagePath;
      delete jqxOptions.params;
      delete jqxOptions.datamodel;
      delete jqxOptions.method;
      delete jqxOptions.action;
      delete jqxOptions.customColumns;
      //qiyu 2018-3-9 增加替换现有column属性功能
      delete jqxOptions.replaceColumns;
      delete jqxOptions.colHasMinWidth;
      delete jqxOptions.beforeSend;
      delete jqxOptions.downloadComplete;
      delete jqxOptions.schema;
      delete jqxOptions.contextPath;
      delete jqxOptions.searchElement;
      delete jqxOptions.minLineNum;
      delete jqxOptions.onceParams;
      delete jqxOptions.alwaysHide;
      delete jqxOptions.customModelName;
      delete jqxOptions.formatData;
      delete jqxOptions.fastRender;
      delete jqxOptions.canEdit;
      delete jqxOptions.schemaList;
      delete jqxOptions.isCellEditable;
      delete jqxOptions.isOnceEmpty;
      delete jqxOptions.isEditMode;
      delete jqxOptions.defaultParams;
      delete jqxOptions.mustSelect;
      delete jqxOptions.editPageable;
      delete jqxOptions.fxss;
      delete jqxOptions.defaultCellsRenderer;
      delete jqxOptions.customOptions;
      delete jqxOptions.saveSchemaCallback;
    } catch (e) {

    }
    if (instance.settings.isEditMode) {
      instance.settings.editMode = true;
    }

    var dataAdapter = new $.jqx.dataAdapter(instance.source, {
      formatData: function(data) {
        if (jqxOptions.pageable) {
          data.pageSize = data.pagesize;
          data.pageNumber = data.pagenum + 1;
        }

        if (instance.settings.isOnceEmpty) {
          data.pageSize = 1;
          data.pageNumber = 1;
          data.querySetting = '[{"name":"' + instance.source.datafields[0].name + '","builder":"include","linkOpt":"AND","value":"NULL"}]';
          delete instance.settings.isOnceEmpty;
        }

        var sortorder = '+';
        if (jqxOptions.sortable && data.sortdatafield && data.sortorder) {
          if (data.sortorder == 'asc') {
            sortorder = '+';
          } else if (data.sortorder == 'desc') {
            sortorder = '-';
          }
          data['*order'] = sortorder + data.sortdatafield.split('_DISPLAY')[0];
        }

        if (instance.settings.formatData && typeof instance.settings.formatData == 'function') {
          data = instance.settings.formatData(data);
        }
        try {
          delete data.pagesize;
          delete data.pagenum;
          delete data.filterslength;
          delete data.sortdatafield;
          delete data.sortorder;
        } catch (e) {}
        instance.$element.data('currentQueryParams', data);
        instance.$element.data('changedRowsData', []);
        return data;
      },
      beforeSend: function(xhr) {
        if (typeof instance.settings.beforeSend === 'function') {
          instance.settings.beforeSend.call(this, arguments);
        }
      },
      downloadComplete: function(data, status, xhr) {
        // 添加downloadComplete 回调  zhuhui 0726
        if (typeof instance.settings.downloadComplete === 'function') {
          if (instance.settings.downloadComplete(data, status, xhr) === false) {
            return;
          }
        }

        // 添加全局ajax的complete回调  liujun 2017-02-28
        if (typeof WIS_EMAP_CONFIG.dataTableAjaxCompleteCallback === 'function') {
          WIS_EMAP_CONFIG.dataTableAjaxCompleteCallback(data, status, xhr);
        }

        //如果未登录则跳转至登录地址
        if (typeof data.loginURL != 'undefined' && data.loginURL != '') {
          window.location.href = data.loginURL;
          return;
        }

        //qiyu 2016-7-21 将emapdatatable中的获取mock的url提取函数,在mock文件中重新定义
        if (typeof window.MOCK_CONFIG != 'undefined') {
          instance.source.totalRecords = getTotalRecordsMock(data, instance.settings.action);
        } else {
          if (data.code === '0' || data.code === 0 || data.code === undefined) {
            if (data.datas[instance.settings.action] === undefined) {
              console.log(data.datas)
              throw new Error("返回的结果中缺少action:" + instance.settings.action);
            }
            //qiyu 2017-10-25 totalSize = 0 的时候,也会走到后面的判断,出现错误
            if (data.datas[instance.settings.action].totalSize !== undefined) {
              instance.source.totalRecords = data.datas[instance.settings.action].totalSize;
            } else {
              instance.source.totalRecords = data.datas[instance.settings.action].total_size;
            }
            // instance.source.totalRecords = data.datas[instance.settings.action].totalSize || data.datas[instance.settings.action].total_size;
            instance.$element.data('tableRows', data.datas[instance.settings.action].rows);
          } else {
            console && console.log(data);
            if (data.code) {
              // 应李忻均要求,若返回的信息里带有logId,则用logId代替code作为展示 zhuhui 2017-4-19
              $.bhTip({
                content: (data.msg ? data.msg + ',' : ($.i18n('bh-edt-systemError') + ',')) + $.i18n('bh-edt-error') + (data.logId || data.code),
                state: 'danger'
              });
            }
          }
        }

        //qiyu 2016-6-8 解决翻页总数刷新问题
        //instance.source.totalrecords = instance.source.totalRecords;

        instance.$element.data('tableResult', data);

        // 联动高级搜索的
        if (instance.settings.searchElement && instance.settings.searchElement.length > 0) {
          instance.settings.searchElement.emapAdvancedQuery('updateTotalNum', (instance.source.totalRecords ? instance.source.totalRecords : 0));
        }
      }
    });

    //保存调用组件时传进来的ready和rendered函数。因为后面checkbox会复写此函数
    var custom_ready = jqxOptions.ready;
    var custom_rendered_tmp = jqxOptions.rendered;

    var custom_rendered = jqxOptions.rendered = function() {
      //处理无排序时表格列背景色及排序按钮背景色问题
      _handleSortStyle(instance);
      if (typeof custom_rendered_tmp === 'function') {
        custom_rendered_tmp();
      }
    };

    jqxOptions.columns = _genColums(instance, jqxOptions, custom_ready, custom_rendered);
    if (jqxOptions.sortable !== true) {
      $(jqxOptions.columns).each(function() {
        if (this.sortable === true) {
          jqxOptions.sortable = true;
        } else {
          this.sortable = false;
        }
      });
    }

    jqxOptions.source = dataAdapter;
    _decorateRendered(jqxOptions, instance);
    //qiyu 2018-9-3 允许初始化时干预jqxOptions,已支持更加特殊的个性化。 @蔡正大
    if (instance.settings.customOptions !== null) {
      jqxOptions = instance.settings.customOptions(jqxOptions);
    }
    instance.$element.jqxDataTable(jqxOptions);

    instance.$element.on('sort', function(event) {
      var args = event.args;
      // column's data field.
      //var sortcolumn = args.sortcolumn;
      instance.$element.data("sortfield", args);
    });

    instance.$element.on('bindingComplete', function(event) {
      bindingComplete(instance, event);
    });

    //qiyu 2016-6-7 增加创建时事件,用于提供给产品线,创建后的行为。需求人:孟斌。如:表格默认增加右侧自定义显示列
    instance.$element.trigger("emapdatatable.created", [instance]);

    if (instance.settings.columnsReorder && instance.settings.contextPath) {
      instance.$element.on('columnReordered', WIS_EMAP_SERV.debounce(function() {
        var columns = $(this).data('columns');
        if (instance.settings.fastRender) {
          var tinners = $(this).jqxDataTable('columns').records;
          var filters = [];
          tinners.forEach(function(item) {
            $(columns).each(function() {
              if (this.datafield === item.datafield) {
                filters.push(this);
                return false;
              }
            });
          });
          var clen = columns.length;
          var col = {};
          var num = 0;
          for (var i = 0; i < clen; i++) {
            col = columns[i];
            var index = indexOf(filters, function(item) {
              return item.datafield === col.datafield;
            });
            if (index > -1) {
              columns[i] = filters[num];
              num++;
            }
          }
        }
        _saveSchema(instance, columns);
      }, 500));
    }
  }

  function bindingComplete(instance, event) {
    var editModeTimer = instance.$element.data('editModeTimer');
    clearTimeout(editModeTimer);
    if (instance.settings.editMode) {
      showLoading(instance);
      editModeTimer = setTimeout(function() {
        _setEditModeData(instance);
      }, 10);
      instance.$element.data('editModeTimer', editModeTimer);
    } else {
      //搜索后当前页没有数据,但是总数不为空,刷新表格,重置到结果的最后一页
      var tableRows = instance.$element.data('tableRows');
      if (tableRows && tableRows.length === 0 && instance.source.totalRecords > 0) {
        instance.$element.jqxDataTable('refresh');
        return;
      }
      _handleSortStyle(instance);
      _handleMinHeight(instance);
      _handleHorizontalScrollBar(instance);
      _handleVerticalScrollBar(instance);
      _resetPageFooter(instance);
    }
  }

  //在纸质弹窗中的页面,改变分页大小,需要重置页脚
  function _resetPageFooter(instance) {
    //当弹框内容的高度出现变化的时候调用以下两个方法
    if (instance.$element.closest(".bh-paper-pile-dialog").length > 0) {
      $.bhPaperPileDialog.resetPageFooter(); //改变页面的页脚位置
      $.bhPaperPileDialog.resetDialogFooter(); //改变弹框的页脚位置
    }
  }

  /**
   * 处理出现横向滚动条后导致的纵向滚动条
   */
  function _handleHorizontalScrollBar(instance) {
    var id = instance.$element.attr('id');
    //qiyu 2016-9-21 希望永远不显示纵向滚动条,判断依此调整,处理出现横向滚动条后导致的纵向滚动条
    // var $selector = $('#horizontalScrollBar' + id);
    var $selector = $('#verticalScrollBar' + id);
    if ($selector.css('visibility') != 'hidden') {
      var height = instance.$element.jqxDataTable('height');
      if (height != null) {
        //qiyu 2016-9-14 解决刷新会不断增高的问题,之前的临时方案是设置表格的height=null
        //instance.$element.jqxDataTable('height', height + 17);
        //qiyu 2016-9-21 调整行高为10px
        instance.$element.jqxDataTable('height', height + 10);
      }
    }
  }

  /**
   * 处理表格行高因自定义内容被撑大后,出现纵向滚动条问题
   */
  function _handleVerticalScrollBar(instance) {
    var id = instance.$element.attr('id');
    var $selector = $('#verticalScrollBar' + id);
    var rowsData = instance.$element.jqxDataTable('getRows');
    var minLineNum = instance.settings.minLineNum;
    if (minLineNum == null || isNaN(minLineNum)) {
      return;
    }
    if ($selector.css('visibility') != 'hidden' && rowsData.length <= minLineNum) {
      instance.$element.jqxDataTable('height', null);
    }
  }
  /**
   * 处理表格最小高度
   */
  function _handleMinHeight(instance) {
    var rowsData = instance.$element.jqxDataTable('getRows');
    var minLineNum = instance.settings.minLineNum;

    if (minLineNum == null || isNaN(minLineNum)) {
      return;
    }

    if (rowsData.length < minLineNum) {
      instance.$element.jqxDataTable('height', BH_UTILS.getTableHeight(parseInt(minLineNum)));
    } else {
      instance.$element.jqxDataTable('height', null);
    }

  }

  /**
   * 初始化 schema, 如果启用schema, 则返回 schema 的数据
   * @param  {object} instance  
   * @param  {string} modelName
   */
  function _initSchema(instance, modelName, contextPath) {
    var $elem = instance.$element;
    var res;
    if (!instance.settings.contextPath) {
      return [];
    }
    if (!instance.settings.schema && !instance.settings.columnsReorder) {
      return [];
    }

    //TODO: enable schema         
    $elem.emapSchema({
      schemaType: 'col',
      contextPath: contextPath,
      data: {
        modelName: modelName
      }
    });

    res = $elem.emapSchema('getSchemaList');
    if (res && res[0] && res[0].CONTENT) {
      return res[0].CONTENT.split(',');
    }
    return [];
  }

  function _handleSortStyle(instance) {
    //处理无排序时表格列背景色问题
    var sortObj = instance.$element.data("sortfield");
    if (typeof sortObj == 'undefined' || (sortObj.sortdirection.ascending == false && sortObj.sortdirection.descending == false)) {
      instance.$element.find('td.jqx-grid-cell-sort').removeClass('jqx-grid-cell-sort');
    }

    //处理表格排序按钮背景色问题
    instance.$element.find('div.sortasc, div.sortdesc').css('background', 'none');
  }

  function _convertEditModeCols(columns, newmodel) {
    columns.forEach(function(col, i) {
      var model = newmodel[i];
      var isCustom = model.custom && model.custom.hasOwnProperty('colIndex');
      if (isCustom) {
        col.hidden = true;
      }
      var edit = col.datafield === 'field_checkbox' || (model.custom && model.custom.type === 'edit_tpl');
      if (edit) {
        col.hidden = false;
      }
    });
  }

  /**
   * 生成表格列
   * @param  {any} instance
   * @param  {any} jqxOptions
   * @param  {any} custom_ready
   * @param  {any} custom_rendered    
   */
  function _genColums(instance, jqxOptions, custom_ready, custom_rendered) {
    var columns = [],
      schemaList;
    //查询顺序
    // 调换了1109与1111行的执行顺序,解决_initSchema里拿不到modelname的参数 from 学工李然 add by jbxu 2018-11-26
    var datamodel = instance.settings.datamodel ||
      WIS_EMAP_SERV.getModel(instance.settings.pagePath, instance.settings.action, "grid", instance.settings.params);
    schemaList = instance.settings.schemaList || _initSchema(instance, WIS_EMAP_SERV.modelName || instance.settings.customModelName, instance.settings.contextPath);
    //对模型进行排序
    if (schemaList.length > 0) {
      var datamodel_result = [];
      var out_result = [];
      for (var i = 0; i < schemaList.length; i++) {
        for (var j = 0; j < datamodel.length; j++) {
          if (datamodel[j].name == schemaList[i]) {
            if (datamodel_result.indexOf(datamodel[j]) == -1) {
              datamodel_result.push(datamodel[j]);
            }
            break;
          }
        }
      }
      for (var k = 0; k < datamodel.length; k++) {
        if (schemaList.indexOf(datamodel[k].name) == -1) {
          if (out_result.indexOf(datamodel[k]) == -1) {
            out_result.push(datamodel[k]);
          }
        }
      }
      datamodel_result = datamodel_result.concat(out_result);
      datamodel = datamodel_result;
    }

    //保存datamodel
    instance.$element.data('tableDataModel', $.extend([], datamodel));

    instance.$element.attr("emap", JSON.stringify({
      "emap-pagePath": instance.settings.pagePath,
      "emap-action": instance.settings.action,
      "emap-url": WIS_EMAP_SERV.url,
      "emap-name": WIS_EMAP_SERV.name,
      "emap-app-name": WIS_EMAP_SERV.appName,
      "emap-model-name": WIS_EMAP_SERV.modelName
    }));

    //保存datamodel
    instance.$element.data('schemaList', schemaList);
    delete WIS_EMAP_SERV.url;
    delete WIS_EMAP_SERV.name;
    delete WIS_EMAP_SERV.appName;
    delete WIS_EMAP_SERV.modelName;

    var cusColLen = 0;
    var customColumns = instance.settings.customColumns;
    if (typeof customColumns != 'undefined' && customColumns != null) {
      cusColLen = customColumns.length;
    }

    //重新组织datamodel
    //type为link时只能为某列快速设置为链接类型,该列必须是模型中已经存在的数据列(此设定为兼容上一版本)
    var newmodel = [];
    var lastcolumns = [];
    var linkCol = [];
    var lastCol = null;
    if (cusColLen > 0) {
      for (var i = 0; i < cusColLen; i++) {
        var colIndex, colField, type;
        if (customColumns && customColumns[i]) {
          colIndex = customColumns[i].colIndex;
          colField = customColumns[i].colField;
          type = customColumns[i].type;
          if (colIndex > 40) {
            colIndex = 'last';
          }
          if (colIndex === 'last') {
            lastCol = customColumns[i];
          }
          if (colIndex < 0) {
            lastcolumns.push({
              index: colIndex * 1,
              col: customColumns[i]
            });
          } else if (typeof colField != 'undefined' && colField != '') {
            for (var j = 0; j < datamodel.length; j++) {
              if (datamodel[j].name == colField) {
                datamodel[j].custom = customColumns[i];
              }
            }
          } else if (colIndex != 'undefined') {
            colIndex = colIndex < 0 ? 0 : colIndex;

            //兼容上一版本设定
            if (type != 'link') {
              newmodel[colIndex] = {
                custom: customColumns[i]
              }
            } else {
              linkCol.push({
                colIndex: colIndex,
                column: customColumns[i]
              });
            }
          }
        }
      }
    }

    //datamodel保存至source的datafields数组中
    for (var m = 0; m < datamodel.length; m++) {
      if (typeof datamodel[m].get == 'function') {
        instance.source.datafields.push({
          name: datamodel[m].name,
          type: 'string'
        });
        if (typeof datamodel[m].url != 'undefined') {
          instance.source.datafields.push({
            name: datamodel[m].name + '_DISPLAY',
            type: 'string'
          });
        }
      }
    }
    for (var k = 0; k < newmodel.length; k++) {
      if (newmodel[k] == undefined) {
        if (datamodel.length > 0) {
          newmodel[k] = datamodel.shift();
        } else {
          newmodel.splice(k, 1);
          k--;
        }
      }
    }

    if (datamodel.length > 0) {
      newmodel = newmodel.concat(datamodel);
    }

    if (lastcolumns.length) {
      lastcolumns.sort(function(a, b) {
        if (a && b) {
          return b.index - a.index;
        }
        return 0;
      });
      lastcolumns.forEach(function(item) {
        var i = item.index + 1;
        if (i === 0) {
          newmodel.push({
            custom: item.col
          });
        } else {
          newmodel.splice(i, 0, {
            custom: item.col
          });
        }
      });
    }

    if (lastCol) {
      newmodel.push({
        custom: lastCol
      });
    }

    var datafield;
    var _col;
    var thiner_columns = [];
    var isFastRender = instance.settings.fastRender;

    //根据schema排序列
    if (instance.settings.columnsReorder && schemaList.length) {
      var orderedModels = [];
      var indexs = [];
      newmodel.forEach(function(item, i) {
        if (item.name) {
          var index = indexOf(schemaList, function(col) {
            if (item.name) {
              return col.replace('_DISPLAY', '') === item.name;
            }
          });
          if (index > -1) {
            orderedModels[index] = item;
            return;
          }
        }
        indexs.push(i);
      });
      indexs.forEach(function(i) {
        orderedModels.splice(i, 0, newmodel[i]);
      });
      newmodel = compact(orderedModels);
    }
    for (var n = 0; n < newmodel.length; n++) {
      //设置自定义列类型为link,且指定了colIndex的项
      for (var t = 0; t < linkCol.length; t++) {
        if (n == linkCol[t].colIndex) {
          newmodel[n].custom = linkCol[t].column;
        }
      }
      //设置数据类型全部是string
      if (typeof newmodel[n].name != 'undefined') {
        instance.source.datafields.push({
          name: newmodel[n].name,
          type: 'string'
        });
      }
      if (typeof newmodel[n].url != 'undefined') {
        datafield = newmodel[n].name + '_DISPLAY';
        instance.source.datafields.push({
          name: datafield,
          type: 'string'
        });
      } else {
        datafield = newmodel[n].name
      }

      var width = null;
      var minWidth = null;
      var widthObj = {};
      var attr = WIS_EMAP_SERV.getAttr(newmodel[n], 'grid');
      var isHidden = attr.hidden;

      //schema: schema 权重高于 hidden属性, 如果不在schemaList中,则隐藏该列
      if (instance.settings.schema && schemaList && schemaList.length && newmodel[n].name && newmodel[n]['grid.fixed'] !== true) {
        _col = newmodel[n].name

        var arrNoDisplay = schemaList.map(function(val) {
          return val.replace('_DISPLAY', '');
        })
        isHidden = $.inArray(_col, arrNoDisplay) === -1
      }

      //固定列属性pinned 默认值
      var pinned = false;
      //从后台模型中读取固定列属性pinned
      pinned = newmodel[n].pinned;
      if (pinned !== true) {
        pinned = false;
      }

      var align = 'left'
      var cellsAlign = 'left';
      //是否采用excel布局,标题居中
      if (WIS_EMAP_CONFIG['emapdatatable.title.center.layout']) {
        align = 'center';
        //如果是数字,单元格内容右对齐
        if (['long', 'int', 'double'].indexOf(newmodel[n].dataType) > -1) {
          cellsAlign = 'right';
        }
      }

      // 默认列宽为100px
      if (newmodel[n].custom == undefined) {
        width = attr.width;
        minWidth = attr.minWidth;
        widthObj = _genWidthObj(width, minWidth, instance.settings.colHasMinWidth);
        var dCol = $.extend({}, {
          text: newmodel[n].caption,
          datafield: datafield,
          hidden: isHidden,
          pinned: pinned,
          align: align,
          cellsAlign: cellsAlign,
          cellsRenderer: _defaultCellsRenderer
        }, widthObj);
        columns.push(dCol);
        dCol = _proxyColOpt(dCol, instance.settings, newmodel[n]);
        if (isFastRender && _canColFastRender(dCol)) {
          thiner_columns.push(dCol);
        }
      } else {
        var type = newmodel[n].custom.type;
        var showCheckAll = newmodel[n].custom.showCheckAll;
        width = newmodel[n].custom.width;
        minWidth = newmodel[n].custom.minWidth;
        if (width == undefined) {
          width = attr.width;
        }
        if (minWidth == undefined) {
          minWidth = newmodel[n]['grid.minWidth'] == undefined ? null : newmodel[n]['grid.minWidth'];
        }
        widthObj = _genWidthObj(width, minWidth, instance.settings.colHasMinWidth);
        var col = _genCustomColumns(type, instance, jqxOptions, showCheckAll, widthObj, newmodel[n], datafield, custom_ready, custom_rendered);
        var cCol = $.extend({
          hidden: isHidden,
          pinned: pinned,
          align: align,
          cellsRenderer: _defaultCellsRenderer
        }, col);
        if (!cCol.cellsAlign && !cCol.cellsalign) {
          cCol.cellsAlign = cellsAlign;
        }
        cCol = _proxyColOpt(cCol, instance.settings, newmodel[n]);
        columns.push(cCol);
        if (isFastRender) {
          thiner_columns.push(cCol);
        }
      }
    }

    //qiyu 2018-3-9 增加替换现有column属性功能
    var replaceColumns = instance.settings.replaceColumns;
    if (replaceColumns !== undefined && replaceColumns !== null) {
      for (var index = 0; index < columns.length; index++) {
        var element = columns[index];
        if (element.datafield !== undefined && replaceColumns[element.datafield] !== undefined) {
          columns[index] = $.extend(element, replaceColumns[element.datafield]);
        }
      }
    }


    if (instance.settings.editMode) {
      _convertEditModeCols(columns, newmodel);
    }

    if (isFastRender) {
      instance.$element.data('newmodel', newmodel);
      instance.$element.data('columns', columns);
      return thiner_columns;
    } else {
      instance.$element.data('newmodel', newmodel);
      instance.$element.data('columns', columns);
      return columns;
    }
  }

  //默认单元格渲染函数
  function _defaultCellsRenderer(row, column, value, rowData, colModel, settings) {
    //qiyu 2018-7-18 RES-312
    function defaultRender(row, column, value, rowData, colModel, settings) {
      //qiyu 2018-3-5 YJS-3066
      var title = "";
      if (value !== undefined && value !== null) {
        title = String(value);
      }
      //end
      if (settings.fxss) {
        var fxssValue = BH_UTILS.fxss(value);
        //qiyu 2018-3-5 YJS-3066
        // return $('<span>' + fxssValue + '</span>').attr('title', value).prop('outerHTML');
        return $('<span>' + fxssValue + '</span>').attr('title', title.replace(/"/g, "'")).prop('outerHTML');
      }
      //qiyu 2018-3-5 YJS-3066
      // return '<span title="' + $("<div>" + value + "</div>").text() + '">' + value + '</span>';
      return '<span title="' + $("<div>" + title + "</div>").text().replace(/"/g, "'") + '">' + value + '</span>';
    }
    //如果有自定义的默认渲染函数,则完全交由外部处理
    if (typeof(settings.defaultCellsRenderer) === "function") {
      var result = settings.defaultCellsRenderer(row, column, value, rowData, colModel, settings);
      if (result === undefined) {
        return defaultRender(row, column, value, rowData, colModel, settings)
      } else {
        return result;
      }
    } else {
      return defaultRender(row, column, value, rowData, colModel, settings)
    }

    // //qiyu 2018-3-5 YJS-3066
    // var title = "";
    // if (value !== undefined && value !== null) {
    //     title = String(value);
    // }
    // //end
    // if (settings.fxss) {
    //     var fxssValue = BH_UTILS.fxss(value);
    //     //qiyu 2018-3-5 YJS-3066
    //     // return $('<span>' + fxssValue + '</span>').attr('title', value).prop('outerHTML');
    //     return $('<span>' + fxssValue + '</span>').attr('title', title.replace(/"/g, "'")).prop('outerHTML');
    // }
    // //qiyu 2018-3-5 YJS-3066
    // // return '<span title="' + $("<div>" + value + "</div>").text() + '">' + value + '</span>';
    // return '<span title="' + $("<div>" + title + "</div>").text().replace(/"/g, "'") + '">' + value + '</span>';
  }

  function _canColFastRender(col) {
    if (col['grid.hidden'] === true) {
      return false;
    } else if (col['grid.hidden'] === undefined && col['hidden'] === true) {
      return false;
    }
    return true;
  }

  function _genWidthObj(width, minWidth, colHasMinWidth) {
    var widthStr = width == null ? '' : width.toString();
    widthStr = widthStr.replace('px', '').replace('PX', '').replace('%', '');
    widthStr = $.trim(widthStr);
    if (!colHasMinWidth) {
      if (width && widthStr != '' && !isNaN(widthStr)) {
        return {
          width: width,
          minWidth: minWidth
        };
      }
      return {};
    } else {
      if (width != null && widthStr != '' && !isNaN(widthStr)) {
        width = width.toString();
        width.replace('px', '').replace('PX', '');
        // qiyu 2017-1-18 解除宽度设定小于100的值仍然按照100来设置的限制。需求人:力磊
        // if (width.indexOf("%") == -1 && parseInt(width) < 100) {
        //     width = 100;
        // }

        // return {
        //     width: width,
        //     minWidth: 100
        // };
        return {
          width: width,
          minWidth: minWidth
        }
      }
      return {
        minWidth: minWidth || 100
      };
    }
  }

  function _saveSchema(instance, columns, saveSchemaCallback) {
    var $elem = instance.$element;
    //1. 获取 含有 name的 显示列
    var data = [];
    columns.forEach(function(column) {
      if (column.hasOwnProperty('datafield') && !column.hidden) {
        data.push(column.datafield)
      }
    });
    //2. 保存 显示列 到 schema
    $elem.emapSchema('saveSchema', [
      'emap.table',
      data.join(',')
    ], saveSchemaCallback);
  }
  /*
   *   列表字段的显示隐藏策略
   *   fixed > 保存方案 > 模型配置
   *   保存方案的优先级高于模型中的显示隐藏配置
   *   模型中配置了固定的字段的显示隐藏以模型中的配置为准,优先级高于保存方案
   * 
   */
  function _initSelectColumnsWindow(instance, newmodel, columns, action) {
    var callback = function(cols) {
      var colMap = {};
      cols.forEach(function(item) {
        colMap[item.name] = {
          hidden: item.hidden
        };
      });

      var clength = columns.length;
      if (action.type === 'export') {
        var exportCols = [];
        for (var i = 0; i < clength; i++) {
          if (columns[i].datafield) {
            var key = columns[i].datafield.replace('_DISPLAY', '');
            if (colMap[key]) {
              exportCols.push({
                datafield: key,
                hidden: !!colMap[key].hidden
              });
            }
          }
        }
        action.handler(exportCols);
      } else {
        if (action.columnsReorder) {
          if (columns.length === 1 && cols.length) {
            columns[0].hidden = cols[0].hidden;
          }
          var orderedCols = [];
          var indexs = [];
          columns.forEach(function(item, i) {
            if (item.datafield) {
              var index = indexOf(cols, function(col) {
                return col.name === item.datafield.replace('_DISPLAY', '');
              });
              if (index > -1) {
                item.hidden = cols[index].hidden;
                orderedCols[index] = item;
                return;
              }
            }
            indexs.push(i);
          });
          indexs.forEach(function(i) {
            orderedCols.splice(i, 0, columns[i]);
          });
          columns = compact(orderedCols);
        } else {
          for (var j = 0; j < clength; j++) {
            if (columns[j].datafield) {
              var key = columns[j].datafield.replace('_DISPLAY', '');
              if (colMap[key]) {
                columns[j].hidden = colMap[key].hidden;
              }
            }
          }
        }

        instance.$element.trigger('custom.grid', [cols]);
        action.handler(columns);
      }
    };
    var opt = {
      model: newmodel,
      alwaysHide: $.extend([], instance.settings.alwaysHide, action.hides || []),
      callback: callback,
      columns: columns,
      title: action.name,
      params: {},
      type: action.type,
      mustSelect: instance.settings.mustSelect,
      columnsReorder: action.columnsReorder,
      useGroup: WIS_EMAP_CONFIG.customFieldsUseGroup
    };
    $.extend(opt.params, action.dialogOpt);
    opt.schemaList = instance.$element.data('schemaList');
    $.bhCustomizeColumn(opt);
  }

  /**
   * 生成自定义列
   * @param  {String} type 自定义列类型
   * @return {Object}       自定义列column
   */
  function _genCustomColumns(type, instance, jqxOptions, showCheckAll, widthObj, model, datafield, custom_ready, custom_rendered) {
    var column = null;
    // checkbox列不可排序
    switch (type) {
      case 'checkbox':
        var pinned = model.custom.pinned;
        if (pinned !== true) {
          pinned = false;
        }
        column = {
          text: 'checkbox',
          datafield: 'field_checkbox',
          // //qiyu 2016-11-30 checkbox列增加标示,解决改变宽度后checkbox状态丢失的问题
          cellClassName: 'datatable-checkbox-column',
          width: 32,
          minWidth: 32,
          maxWidth: 32,
          cellsAlign: 'center',
          align: 'center',
          sortable: false,
          draggable: false,
          pinned: pinned,
          renderer: function(text, align, height) {
            var checkBox = '<div class="selectAllCheckboxFlag bh-checkbox bh-mh-8"><label><input type="checkbox" value=""><i class="bh-choice-helper"></i></label></div>';
            if (showCheckAll === false) {
              return ' ';
            }
            return checkBox;
          },
          rendered: function(element, align, height) {
            //头部的checkbox点击事件的绑定
            element.on("click", "input", function(e) {
              var $table = instance.$element;
              var $tableContent = $table.find('table:not([id^="pinnedtable"])');
              if ($table.find('table[id^="pinnedtable"]').length > 0) {
                $tableContent = $table.find('table[id^="pinnedtable"]');
              }
              var $checkboxList = $tableContent.find("div.bh-checkbox");

              var $input = $(this);
              if ($input.hasClass("selectFlag")) {
                $input.prop("checked", false).removeClass("selectFlag");
                $checkboxList.each(function() {
                  $(this).find("input").not(':disabled').prop("checked", false);
                });
              } else {
                $input.prop("checked", true).addClass("selectFlag");
                $checkboxList.each(function() {
                  $(this).find("input").not(':disabled').prop("checked", true);
                });
              }

              //触发自定义全选按钮事件
              $(this).trigger('checkall', $input.prop("checked"));
              e.stopPropagation();
            });
            return true;
          },
          cellsRenderer: function(row, column, value, rowData) {
            //qiyu 2016-11-30 checkbox列增加标示,解决改变宽度后checkbox状态丢失的问题
            var checked = false;
            if (!rowData.rowguid) {
              rowData.rowguid = BH_UTILS.NewGuid();
            }
            var guid = rowData.rowguid;
            var cbitem = '<input type="checkbox" value="' + rowData.uid + '" data-guid="' + guid + '">';
            var jqcb = $('.datatable-checkbox-column input[type=checkbox][data-guid="' + guid + '"]', this.owner.host);
            //qiyu 2017-1-7 解决render表格时checkbox未正确选中的问题。发生在首次打开页面,点击出现bhWindow时,会改表格变宽度。报告者:梅晓龙
            // if (jqcb.length > 0 && jqcb[row]) {
            // checked = jqcb[row].checked;
            if (jqcb.length > 0) {
              checked = jqcb[0].checked;
              if (checked) {
                cbitem = '<input type="checkbox" value="' + rowData.uid + '" data-guid="' + guid + '" checked>';
              }
            }

            var checkBox = '<div data-sss="" class="bh-checkbox bh-mh-4" style="margin-left:0 !important;"><label>' + cbitem + '<i class="bh-choice-helper"></i></label></div>';
            // var checkBox = '<div data-sss="" class="bh-checkbox bh-mh-4" style="margin-left:0 !important;"><label><input type="checkbox" value=""><i class="bh-choice-helper"></i></label></div>';

            return checkBox;
          }
        };

        //增加处理函数
        jqxOptions.rendered = function() {
          //数据加载完成,读取各列的checkbox,判断头部的checkbox是否要勾选
          var $table = instance.$element;
          var $tableContent = $table.find('table:not([id^="pinnedtable"])');
          if ($table.find('table[id^="pinnedtable"]').length > 0) {
            $tableContent = $table.find('table[id^="pinnedtable"]');
          }
          var $checkboxList = $tableContent.find(".datatable-checkbox-column div.bh-checkbox");
          var isSelectAllFlag = true;
          if ($checkboxList.length == 0) {
            isSelectAllFlag = false;
          }
          $checkboxList.each(function() {
            var $itemCheckbox = $(this);
            if ($itemCheckbox.find("input[checked]").length === 0) {
              isSelectAllFlag = false;
              return false;
            }
          });
          var $selectAllCheckbox = $table.find("div.selectAllCheckboxFlag").find("input");
          if (isSelectAllFlag) {
            $selectAllCheckbox.prop("checked", true).addClass("selectFlag");
          } else {
            $selectAllCheckbox.prop("checked", false).removeClass("selectFlag");
          }

          //调用外部定义的rendered函数
          if (typeof custom_rendered === 'function') {
            custom_rendered();
          }
        };

        jqxOptions.ready = function() {
          //初始化完成后,绑定checkbox的点击事件
          instance.$element.on("click", "div.bh-checkbox", function() {
            _scenesTableContentCheckboxClick($(this).find("input"), instance);
            //触发自定义事件
            $(this).trigger('checkone');
          });

          //调用外部定义的rendered函数
          if (typeof custom_ready === 'function') {
            custom_ready();
          }
        };
        break;

      case 'radio':
        var guid = BH_UTILS.NewGuid();
        var pinned = model.custom.pinned;
        if (pinned !== true) {
          pinned = false;
        }
        column = {
          text: 'radio',
          datafield: 'field_radio',
          width: 40,
          minWidth: 40,
          maxWidth: 40,
          cellsAlign: 'center',
          align: 'center',
          sortable: false,
          draggable: false,
          pinned: pinned,
          renderer: function(text, align, height) {
            var radio = $.i18n('bh-dd-choose');
            return radio;
          },
          cellsRenderer: function(row, column, value, rowData) {
            var radio = '<div data-sss="" class="bh-radio bh-mh-4" style="margin-left:0 !important;"><label style="padding-left: 0;"><input name="' + guid + '" type="radio" value=""><i class="bh-choice-helper"></i></label></div>';
            return radio;
          }
        };

        jqxOptions.ready = function() {
          //初始化完成后,绑定checkbox的点击事件
          instance.$element.on("click", "div.bh-radio", function() {
            //触发自定义事件
            $(this).trigger('checkone');
          });

          //调用外部定义的rendered函数
          if (typeof custom_ready === 'function') {
            custom_ready();
          }
        };
        break;
      case 'link':
        var pinned = model.custom.pinned;
        if (pinned !== true) {
          pinned = false;
        }
        var default_column = {
          text: model.caption,
          datafield: datafield,
          draggable: !!model.custom.colField,
          pinned: pinned
        }
        var cus_column = {
          cellsRenderer: function(row, column, value, rowData) {
            if (!isNaN(value)) {
              value = value.toString();
            }
            //qiyu 2016-8-31 解决ie9,placeholder插件点击后不再显示的问题
            // return '<a href="javascript:void(0);" class="j_link_' + column + '">' + value + '</a>';
            return '<a class="sc-cursor-point j_link_' + column + '">' + value + '</a>';
          }
        }
        column = $.extend(default_column, cus_column, widthObj);
        break;
      case 'tpl':
        var default_column = {
          text: model.caption,
          datafield: datafield,
          draggable: !!model.custom.colField,
          sortable: (model.custom.column && model.custom.column.sortable) || false
        }
        column = $.extend(default_column, model.custom.column, widthObj);
        break;
      case 'edit_tpl':
        var default_column = {
          text: model.caption,
          datafield: datafield,
          hidden: true,
          draggable: !!model.custom.colField,
          sortable: false //自定义显示列默认不能排序
        }
        column = $.extend(default_column, model.custom.column, widthObj);
        break;
    }
    return column;
  }

  /***
   * [_proxyColOpt description]
   * @param  {[type]} col      [description]
   * @param  {[type]} settings [description]
   * @param  {[type]} colModel [description]
   * @return {[type]}          [description]
   */
  function _proxyColOpt(col, settings, colModel) {
    var oldCellsRenderer = col.cellsRenderer;
    var oldCellClassName = col.cellClassName;

    function cellsRenderer(row, column, value, rowData) {
      var args = $(arguments).toArray();
      if (settings.editMode && colModel.name) {
        var model = $.extend(true, {}, colModel);
        var cell = '';
        if (!__isCellEditable.apply(this, args.concat([colModel, settings]))) {
          //判断用户是否自定义了单元格渲染函数
          if (oldCellsRenderer === _defaultCellsRenderer) {
            model.xtype = 'static';
            cell = WIS_EMAP_INPUT.renderPlaceHolder(model).addClass('bh-str-cut bh-form-static');
            cell = $('<div>' + cell.prop('outerHTML') + '</div>');
            WIS_EMAP_INPUT.formSetValue(cell, rowData, {});
            cell = cell.html();
          } else {
            cell = oldCellsRenderer.apply(this, args.concat([colModel, settings]));
          }
        } else {
          var minHeight = 28;
          if (model.xtype === 'textarea') {
            minHeight = 102;
          }
          cell = '<div class="form-validate-block" style="min-height:' + minHeight + 'px">' +
            '<div class="bh-form-group ' + (model.required ? 'bh-required' : '') + '" style="margin-bottom:0;background:none">' +
            '   <label class="bh-form-label" style="display:none">' + col.text + '</label>' +
            '        <div>' +
            '             <div class="bh-form-placeholder bh-form-flow"></div>' +
            WIS_EMAP_INPUT.renderPlaceHolder(model).attr('data-jsonparam', model.JSONParam).prop('outerHTML') +
            '        </div>' +
            '    </div>' +
            '</div>';
          if (model.xtype === 'radiolist') {
            cell = '<form>' + cell + '</form>';
          }
        }
        cell += '<div class="' + toDeleteLine + '"></div>';
        return cell;
      } else {
        if (oldCellsRenderer) {
          if (column === 'field_checkbox') {
            return oldCellsRenderer.apply(this, args.concat([colModel, settings])) + '<div class="' + toDeleteLine + '"></div>';
          }
          return oldCellsRenderer.apply(this, args.concat([colModel, settings]));
        }
      }
      return value === undefined ? '' : (value + '');
    }

    function cellClassName(row, column, value, rowData) {
      var args = $(arguments).toArray().concat([colModel, settings]);
      var className = oldCellClassName;
      if ($.isFunction(oldCellClassName)) {
        className = oldCellClassName.apply(this, args);
      }
      className = className || '';
      if (settings.editMode) {
        var isEditable = __isCellEditable.apply(this, args);
        if (!isEditable) {
          className = className + ' bh-form-static';
        }
        if (rowData[toDeleteKey]) {
          className += ' ' + showToDeleteLine;
        }
        if (isEditable && (column !== 'field_checkbox') && (column !== 'field_radio')) {
          className += ' p-1';
        }
      }
      return className;
    }
    col.cellsRenderer = cellsRenderer;
    col.cellClassName = cellClassName;
    return col;
  }

  function __isCellEditable(row, column, value, rowData, colModel, settings) {
    var args = arguments;
    if (settings.isCellEditable) {
      return settings.isCellEditable.apply(this, args);
    }
    if (colModel.hasOwnProperty('readonly')) {
      return colModel.readonly !== true;
    }
    if (colModel.hasOwnProperty('grid.readonly')) {
      return colModel['grid.readonly'] !== true;
    }
    if (colModel.hasOwnProperty('xtype')) {
      return colModel.xtype !== 'static';
    }
    return true;
  }

  function _decorateRendered(jqxOptions, instance) {
    var oldRendered = jqxOptions.rendered;
    var rendered = function() {
      var editModeTimer = instance.$element.data('editModeTimer');
      clearTimeout(editModeTimer);
      if ($.isFunction(oldRendered)) {
        oldRendered.apply(this, arguments);
      }

      if (instance.settings.editMode) {
        showLoading(instance);
        editModeTimer = setTimeout(function() {
          _setEditModeData(instance);
        }, 10);
        instance.$element.data('editModeTimer', editModeTimer);
      }
    };
    jqxOptions.rendered = rendered;
  }

  function _setEditModeData(instance) {
    var $content = instance.$element.jqxDataTable('content').find('table:not([id^="pinnedtable"])');
    var $trs = $content.find('tbody>tr');
    if ($trs.first().data('formInit')) {
      hideLoading(instance);
      return;
    }

    instance.$element.trigger('editabletatable.renderingcomponent');

    instance.$element.jqxDataTable('content').find('table tbody>tr').addClass('bh-table-form');
    $content.off('change');

    $trs.first().data('formInit', true);

    var rows = instance.$element.jqxDataTable('getRows');
    $trs.find('.form-validate-block').hover(function() {
      var position = {};
      if (this.getBoundingClientRect) {
        var rect = this.getBoundingClientRect();
        position.top = rect.top - 27;
        position.left = rect.left + 8;
      } else {
        var offset = $(this).offset();
        position.top = offset.top - 27 - $('body').scrollTop();
        position.left = offset.left + 8 - $('body').scrollLeft();
      }
      $(this).find('.jqx-validator-error-info').css({
        position: 'fixed',
        top: position.top + 'px',
        left: position.left + 'px',
        width: 'auto',
        right: 'auto'
      });
      $(this).addClass('bh-actived');
    }, function() {
      $(this).removeClass('bh-actived');
    });

    var model = instance.getModel();
    var selectModels = model.filter(function(mod) {
      return mod.xtype === 'radiolist' || mod.xtype === 'checkboxlist';
    });

    var dfds = selectModels.map(function(mod) {
      return $.ajax({
        url: mod.url,
        datatype: "json",
        success: function(resp) {
          if (resp && resp.datas && resp.datas.code) {
            $trs.find('[data-name="' + mod.name + '"][xtype="' + mod.xtype + '"]').data('optiondata', resp.datas.code.rows);
          }
        }
      });
    });

    $.when.apply($, dfds).always(function() {
      $trs.emapFormInputInit({});

      $trs.each(function(i) {
        WIS_EMAP_INPUT.formSetValue($(this), rows[i], {});
        if (rows[i] !== undefined && rows[i][toDeleteKey]) {
          $(this).find('>td [data-sss] input').prop('disabled', true);
        }
        $(this).emapValidate({
          fieldModel: model
        });
      });

      //隐藏下拉框列表项
      $('body').trigger('mousedown');
      $trs.on('mousedown', function() {
        $('body').trigger('mousedown');
      });

      var changedRowsData = instance.$element.data('changedRowsData');
      if (!changedRowsData) {
        changedRowsData = [];
        instance.$element.data('changedRowsData', changedRowsData);
      }
      $trs.on('change checkChange', function(e) {
        var $target = $(e.target);
        var $block = $target.closest('.form-validate-block');
        if ($block.length) {
          var comp = WIS_EMAP_INPUT.core[$block.find('[xtype]').attr('xtype')];
          if (comp) {
            $block.closest('td').addClass(editedBg);
          }
        }
      });

      if (changedRowsData.length) {
        $trs.each(function(i) {
          if (changedRowsData[i]) {
            WIS_EMAP_INPUT.formSetValue($(this), changedRowsData[i], {});
          }
        });
      }

      //不要怀疑,上面的change是为渲染时给改变后的添加标志,下面off后再on一个debounce是解决下拉框打开时触发的change导致误加标志
      $trs.off('change checkChange').on('change checkChange', WIS_EMAP_SERV.debounce(function(e) {
        var $target = $(e.target);
        var $block = $target.closest('.form-validate-block');
        if ($block.length) {
          var index = $block.closest('tr').index();
          var values = WIS_EMAP_INPUT.formGetValue($block, {});
          var key = $block.find('[data-name]').data('name');
          if (changedRowsData[index]) {
            //防止添加行后下拉框初次打开时,导致的change
            if (changedRowsData[index][key] == values[key]) {
              return;
            }
          } else {
            //防止下拉框初次打开时,导致的change
            var value = rows[index][key];
            if (rows[index][key] === null || rows[index][key] === undefined) {
              value = '';
            }
            if (value == values[key]) {
              return;
            }
          }
          $block.closest('td').addClass(editedBg);
          if (!changedRowsData[index]) {
            changedRowsData[index] = {};
          }
          changedRowsData[index][key] = values[key];
          if (values.hasOwnProperty(key + '_DISPLAY')) {
            changedRowsData[index][key + '_DISPLAY'] = values[key + '_DISPLAY'];
          }
          $target.trigger('editabletatable.cell.change', [$block.closest('tr'), values, key, changedRowsData[index]]);
        }
      }, 10));

      //标志已删除的行,需要放在赋值语句后面
      $trs.each(function(i) {
        if (rows[i] !== undefined && rows[i][toDeleteKey]) {
          instance.deleteRowInEditMode({
            rowIndex: i
          });
        }
      });

      hideLoading(instance);

      instance.$element.trigger('editabletatable.complete');
    });
  }

  function showLoading(instance) {
    var $load = instance.$element.jqxDataTable('dataloadelement');
    $load.css({
      visibility: 'visible',
      display: 'block',
      width: instance.$element.jqxDataTable('host').width()
    });
  }

  function hideLoading(instance) {
    instance.$element.jqxDataTable('dataloadelement').css({
      visibility: 'hidden',
      display: 'none',
      width: '100%'
    });
  }

  /**
   * 点击tbody上的checkbox,处理头部的checkbox是否要勾选
   * @param $input
   */
  function _scenesTableContentCheckboxClick($input, instance) {
    if (!$input.hasClass("selectAllCheckboxFlag")) {
      var $table = instance.$element;
      var $selectAllCheckbox = $table.find("div.selectAllCheckboxFlag").find("input");
      var $tableContent = $input.closest('table');
      var $checkboxList = $tableContent.find("div.bh-checkbox");
      if ($input.prop("checked")) {
        var isSelectAllFlag = true;
        $checkboxList.find("input").not(':disabled').each(function() {
          if (!$(this).prop("checked")) {
            isSelectAllFlag = false;
          }
        });

        if (isSelectAllFlag) {
          $selectAllCheckbox.prop("checked", true).addClass("selectFlag");
        } else {
          $selectAllCheckbox.prop("checked", false).removeClass("selectFlag");
        }
      } else {
        $selectAllCheckbox.prop("checked", false).removeClass("selectFlag");
      }
    }
  }

  /**
   * 这里是关键
   * 定义一个插件 plugin
   */
  $.fn.emapdatatable = function(options, params, callback, flag) {
    var instance, initParams;
    instance = this.data('emapdatatable');
    initParams = this.data('initParams');
    if (options === true) return instance;
    /**
     * 判断插件是否已经实例化过,如果已经实例化了则直接返回该实例化对象
     */
    if (!instance) {
      //params为表格渲染的初始化参数,后续表格的reload始终会携带该参数
      $(this).data('initParams', options.params);
      return this.each(function() {
        //将实例化后的插件缓存在dom结构里(内存里)
        return $(this).data('emapdatatable', new Plugin(this, options));
      });
    }
    /**
     * 优雅处: 如果插件的参数是一个字符串,则 调用 插件的 字符串方法。
     * 如 $('#id').plugin('doSomething') 则实际调用的是 $('#id).plugin.doSomething();
     * doSomething是刚才定义的接口。
     * 这种方法 在 juqery ui 的插件里 很常见。
     */
    if ($.type(options) === 'string') {
      var paramsObj = $.extend({}, initParams, params);
      var querySetting = [];
      //默认如果请求参数中有高级搜索的参数 会把其他参数合并进高级搜索参数querySetting
      //如果flag为false则不合并。
      if (typeof paramsObj.querySetting != 'undefined' && flag !== false) {
        // add by liujun 2016-12-8 originQuerySettingType  queryStting处理前后保持相同的类型,如果之前的字符串则处理完后也序列号成字符串
        var originQuerySettingType = ''
        if (typeof paramsObj.querySetting === 'string') {
          querySetting = JSON.parse(paramsObj.querySetting);
          originQuerySettingType = 'string'
        } else {
          querySetting = paramsObj.querySetting
          originQuerySettingType = 'object'
        }
        $.each(paramsObj, function(k, v) {
          if (k != 'querySetting' && ($.type(v) == 'number' || $.type(v) == 'string' || $.type(v) == 'boolean')) {
            if ($.type(v) == 'string' && v.indexOf(',') > -1) {
              // var valueArr = v.split(',');
              // valueArr.forEach(function(item) {
              //     querySetting.push({
              //         name: k,
              //         value: item,
              //         linkOpt: 'or',
              //         builder: 'm_value_equal'
              //     });
              // });
              // add form OA焦祖春 把OR变成AND 因为是emapdatatable的初始条件,跟其他条件应该是AND关系 by jbxu 2019-05-06
              querySetting.push({
                name: k,
                value: v,
                linkOpt: 'AND',
                builder: 'm_value_equal'
              });
            } else {
              querySetting.push({
                name: k,
                value: v,
                linkOpt: 'AND',
                builder: 'equal'
              });
            }
          }
        });

        if (originQuerySettingType === 'string') {
          paramsObj.querySetting = JSON.stringify(querySetting);
        }
        return instance[options](paramsObj, callback);
      }
      //存在初始化参数,携带初始化参数调用方法
      if (initParams) {
        return instance[options](paramsObj, callback);
      }
      //直接使用传参
      return instance[options](params, callback);
    }
    return this;
  };

  /**
   * 插件的默认值
   */
  var height = null;
  if (typeof BH_UTILS != 'undefined') {
    height = BH_UTILS.getTableHeight(10);
  }

  var localization = null;
  if (typeof Globalize != 'undefined') {
    localization = Globalize.culture("zh-CN");
    if (typeof BH_UTILS != 'undefined') {
      if (BH_UTILS.lang() === 'en') {
        localization = {};
      }
    }
  }

  /**
   * @memberOf module:emapdatatable
   * @event 'emapdatatable.created' 
   * @description 表格初次渲染完成后触发的事件
   * @example
   * $el.on('emapdatatable.created',function(e,instance){
   *     console.log(instance.getResult());
   * })
   */

  /**
   * @memberOf module:emapdatatable
   * @event 'editabletatable.renderingcomponent' 
   * @description 可编辑表格开始渲染组件的事件
   * @example
   * $el.on('editabletatable.renderingcomponent',function(e){
   *     console.log(e);
   * })
   */

  /**
   * @memberOf module:emapdatatable
   * @event 'editabletatable.complete' 
   * @description 可编辑表格渲染完成的事件
   * @example
   * $el.on('editabletatable.complete',function(e){
   *     console.log(instance.getResult());
   * })
   */

  /**
   * @memberOf module:emapdatatable
   * @event 'editabletatable.cell.change' 
   * @description 可编辑表格单元格值改变事件
   * @param {DOM} $tr 发生改变的行元素
   * @param {Object} value 改变后整行的值
   * @param {String} key 发生改变的字段
   * @example
   * $el.on('editabletatable.cell.change',function(e,$tr,value,key){
   *     console.log(value);
   * })
   */

  /**
   * @memberof module:emapdatatable
   * @description 其他参数参考jqxDatatable{@link http://www.jqwidgets.com/jquery-widgets-documentation/documentation/jqxdatatable/jquery-datatable-api.htm?search=}
   * @prop {String} [pk=WID] - 数据主键字段
   * @prop {String} [url] - 请求表格数据的后台接口, url和pagePath二选一必填
   * @prop {String} [pagePath] - 请求表格数据页面地址, url和pagePath二选一必填
   * @prop {Object} params - 请求参数
   * @prop {Array} datamodel - 一般为emap返回的数据模型
   * @prop {String} action - emap动作名
   * @prop {Array} customColumns - 自定义表格列,colIndex:该自定义位于表格第几列,从0开始,最后一列可以设置‘last’; colField: 自定义列作用的列模型字段; type: 自定义列类型,支持checkbox,link,tpl。chekcbox不可定义colField参数,如果定义了colIndex,则customColumns数组必须按照colIndex值由小到大排序
   * @prop {Object} replaceColumns - 现有列属性替换,该对象中的key对应模型的name属性,值对应jqwidget datatable column属性,如:{"XH":{sortable:true}},下面有示例代码
   * @prop {Int|Stirng} [height] - 高度
   * @prop {Boolean} [pageable=true] - 是否分页
   * @prop {String} [pagerMode=advanced] - 分页形式 'advanced' 'simple'
   * @prop {Boolean} [serverProcessing=true] - 是否开启服务端分页 
   * @prop {Array} [pageSizeOptions=['10', '20', '50', '100']] - 分页条数选项
   * @prop {String} [localization='zh-CN'] - 语言选择
   * @prop {Boolean} [sortable=false] - 排序
   * @prop {String} [selectionMode='custom'] - Sets or gets the selection mode. Possible values: "multipleRows", "singleRow" and "custom". In the "custom" mode, rows could be selected/unselected only through the API.
   * @prop {Boolean} [enableBrowserSelection=true] - Enables or disables the default text selection of the web browser.
   * @prop {Boolean} [columnsResize=true] - Sets or gets the jqxDataTable's columnsResize.
   * @prop {Boolean} [colHasMinWidth=true] - 列宽是否有默认最小值100px
   * @prop {Boolean} [schema=true] - 启用schema,必须定义 contextPath   &&  未定义contextPath时   schema 不生效
   * @prop {String} [contextPath] - 根路径
   * @prop {Int} [minLineNum] - 最小高度行数 
   * @prop {Boolean} [fastRender=false] - 快速渲染, 用于提高表格渲染速度 
   * @prop {Function} [beforeSend] - 请求发送前的回调函数
   * @prop {Function} [downloadComplete] - 表格数据请求完成的回调 
   * @prop {Boolean} [isOnceEmpty=false] - 表格默认是否为空,不加载数据
   * @prop {Boolean} [mustSelect=true] - 自定义显示列弹窗是否开启必须勾选字段校验 
   * @prop {Boolean} [columnsReorder=false] - 是否开启列拖拽排序 
   * @prop {Function} [customOptions] - 初始化表格的options,允许干预
   * @prop {Boolean} [fxss] - 是否开启开启防跨站脚本攻击,默认与WIS_EMAP_CONFIG['emapdatatable.fxss']相同
   * @prop {Function} [defaultCellsRenderer] - 这是一个同步函数,设置该函数将会忽略默认渲染,必须返回一个字符串。函数的入参:row, column, value, rowData, colModel, settings
   * @example
      $el.emapdatatable({
          pagePath: bs.api.pageModel,
          action: 'T_PXXX_XSJBXX_QUERY',
          customColumns: [{
              colIndex: '0',
              type: 'checkbox'
          }],
          sortable:true,
          replaceColumns:{
              "XH":{
                  sortable:true,
                  cellsRenderer: function(row, column, value, rowData){
                      console.log(111)
                      return value;
                  }
              }
          },
          customOptions: function(jqxOptions) {
              return jqxOptions;
          }
      });
   */
  $.fn.emapdatatable.defaults = {
    width: '100%',
    height: height,
    pageable: true,
    pagerMode: 'advanced',
    serverProcessing: true,
    pageSizeOptions: ['10', '20', '50', '100'],
    localization: localization,
    sortable: false,
    columnsReorder: false,
    selectionMode: "custom",
    enableBrowserSelection: true,
    incrementalSearch: false,
    columnsResize: true,
    defaultParams: false,
    onceParams: false,
    colHasMinWidth: true, // 列宽是否有默认最小值100px
    beforeSend: null,
    contextPath: '', //
    schema: true, // 启用schema,必须定义 contextPath   &&  未定义contextPath时   schema 不生效
    minLineNum: null,
    alwaysHide: ['WID', 'TBRQ', 'TBLX', 'CZRQ', 'CZZ', 'CZZXM'], // 自定义显示列的隐藏字段
    fastRender: false,
    canEdit: true,
    isCellEditable: null,
    isEditMode: false,
    editPageable: false,
    isOnceEmpty: false,
    mustSelect: true,
    defaultCellsRenderer: undefined,
    customOptions: null,
    saveSchemaCallback: null
  };

}).call(this);