text: /**
   @Name：treeGrid树状表格
   @Author：beijiyi
   @version: 0.1
   码云地址：https://gitee.com/beijiyi/tree_table_treegrid_based_on_layui
   在线demo：http://beijiyi.com/
   */
  layui.config({
  }).extend({
  }).define(['laytpl', 'laypage', 'layer', 'form'], function(exports){
      "use strict";
      var $ = layui.$
          ,laytpl = layui.laytpl
          ,laypage = layui.laypage
          ,layer = layui.layer
          ,form = layui.form
          ,hint = layui.hint()
          ,device = layui.device()
          //外部接口
          ,table = {
              config: {//全局配置项,表格级别
                  indexName: 'lay_table_index' //下标索引名
                  ,cols:{//节点级别的附加字段
                      isCheckName: 'lay_is_checked' //选中状态（true，false）
                      ,isRadio:'lay_is_radio'//单选状态（true，false）
                      ,isOpen:'lay_is_open'//是否展开节点
                      ,isShow:'lay_is_show'//是否显示节点
                      ,level:'lay_level'//节点的层级关系（不需要设置）
                      ,children:'children'//存放下级的变量
  
                      ,cheDisabled:'lay_che_disabled'//禁止多选（true，false）
                      ,radDisabled:'lay_rad_disabled'//禁止单选（true，false）
  
                      ,iconOpen:'lay_icon_open'//打开的图标
                      ,iconClose:'lay_icon_close'//关闭的图标
                      ,icon:'lay_icon'//叶子节点图标
                  }
                  ,initWidth:{//默认列宽度定义
                      checkbox: 48
                      ,space: 15
                      ,numbers: 40
                      ,radio:48
                  }
              }
              /**
               * 缓存数据
               *
               * 结构图示
               * cache{}                  缓存（对象）
               *      key['data']{}       全部数据缓存（对象）
               *          key[list][]     列表数据对象（数组）
               *          key[map]{}      列表数据Map对象（Map）
               *          key[treeList][] 树状结构的对象（数组）
               *      key['cla']{}        全部已初始化过的Calss对象类（注意渲染是异步执行）
               *          key['claIds'][] 全部已经吊用过初始化方法的表格类
               *          key[claObjs]{key[tableId]}  全部已经初始化好的cla对象
               *
               */
              ,cache: {
                  tableId:{
                      data:{
                          list:[]//列表数据
                          ,map:{}//列表数据以idField或唯一值作为key的Map数据
                          ,treeList:[]//树状数据
                          ,upIds:[]//父节点集合  在一次外部请求前严格按照第一次的顺序
                      }
                  }
                  ,cla:{
                      claIds:{
                          tableId:true
                      }
                      ,claObjs:{
                          tableId:{}
                      }
                  }
                  ,selectcode:{//数据字典缓存
                      demokey:[
                          {
                              key:{value:''}
                          }
                      ]
                  }
              }
              ,index: layui.table ? (layui.table.index + 10000) : 0
              /**
               * 设置全局项
               * @param options
               * @return {table}
               */
              ,set: function(options){
                  var that = this;
                  that.config = $.extend({}, that.config, options);
                  return that;
              }
              /**
               * 事件监听
               * @param events
               * @param callback
               * @return {*}
               */
              ,on: function(events, callback){
                  return layui.onevent.call(this, MOD_NAME, events, callback);
              }
              ,getClass:function (tableId) {
                  return table.cache.cla.claObjs[tableId];;
              }
              ,pushClass:function (tableId,that) {
                  table.cache.cla.claObjs[tableId]=that;
              }
              ,isCalss:function (tableId) {
                  var ids=this.cache.cla.claIds||{};
                  return  ids.hasOwnProperty(tableId)||false;
              }
              ,isClassYes:function (tableId) {
                  var ids=this.cache.cla.claIds||{};
                  return ids[tableId]||false;
              }
              ,pushClassIds:function (tableId,is) {
                  this.cache.cla.claIds[tableId]=is;
              }
              ,setObj:function (tableId,key,o) {
                  if(!this.obj[tableId])this.obj[tableId]={};
                  this.obj[tableId][key]=o;
              }
              ,getObj:function (tableId, key) {
                  return this.obj[tableId]?this.obj[tableId][key]:null;
              }
              /**
               * 获取列表数据
               */
              ,getDataList:function (tableId) {
                  if(table.cache[tableId]){
                      return table.cache[tableId].data.list;
                  }
                  return [];
              }
              /**
               * 设置列表数据
               */
              ,setDataList:function (tableId, list) {
                  if(!table.cache[tableId])table.cache[tableId]={};
                  if(!table.cache[tableId].data)table.cache[tableId].data={};
                  if(!table.cache[tableId].data.list)table.cache[tableId].data.list=[];
                  table.cache[tableId].data.list=list;
              }
              /**
               * 获取列表数据
               */
              ,getDataMap:function (tableId) {
                  if(table.cache[tableId]){
                      return table.cache[tableId].data.map;
                  }
                  return {};
              }
              /**
               * 设置列表数据
               */
              ,setDataMap:function (tableId, map) {
                  if(!table.cache[tableId])table.cache[tableId]={};
                  if(!table.cache[tableId].data)table.cache[tableId].data={};
                  if(!table.cache[tableId].data.map)table.cache[tableId].data.map={};
                  table.cache[tableId].data.map=map;
              }
              /**
               * 获取树状数据
               */
              ,getDataTreeList:function (tableId) {
                  if(table.cache[tableId]){
                      return table.cache[tableId].data.treeList;
                  }
                  return [];
              }
              /**
               * 设置树状数据
               */
              ,setDataTreeList:function (tableId, treeList) {
                  if(!table.cache[tableId])table.cache[tableId]={};
                  if(!table.cache[tableId].data)table.cache[tableId].data={};
                  if(!table.cache[tableId].data.treeList)table.cache[tableId].data.treeList={};
                  table.cache[tableId].data.treeList=treeList;
              }
              /**
               * 获取根节点数据
               */
              ,getDataRootList:function (tableId) {
                  if(table.cache[tableId]){
                      return table.cache[tableId].data.upIds||[];
                  }
                  return [];
              }
              /**
               * 设置根节点数据
               */
              ,setDataRootList:function (tableId, rootList) {
                  if(!table.cache[tableId])table.cache[tableId]={};
                  if(!table.cache[tableId].data)table.cache[tableId].data={};
                  if(!table.cache[tableId].data.upIds)table.cache[tableId].data.upIds=[];
                  table.cache[tableId].data.upIds=rootList;
              }
              /**
               * 初始化
               * @param filter
               * @param settings
               * @return {table}
               */
              ,init:function (filter, settings) {
                  settings = settings || {};
                  var that = this
                      ,elemTable = filter ? $('table[lay-filter="'+ filter +'"]') : $(ELEM + '[lay-data]')
                      ,errorTips = 'Table element property lay-data configuration item has a syntax error: ';
                  //遍历数据表格
                  elemTable.each(function(){
                      var othis = $(this), tableData = othis.attr('lay-data');
                      try{
                          tableData = new Function('return '+ tableData)();
                      } catch(e){
                          hint.error(errorTips + tableData)
                      }
                      var cols = [], options = $.extend({
                          elem: this
                          ,cols: []
                          ,data: []
                          ,skin: othis.attr('lay-skin') //风格
                          ,size: othis.attr('lay-size') //尺寸
                          ,even: typeof othis.attr('lay-even') === 'string' //偶数行背景
                      }, table.config, settings, tableData);
  
                      filter && othis.hide();
  
                      //获取表头数据
                      othis.find('thead>tr').each(function(i){
                          options.cols[i] = [];
                          $(this).children().each(function(ii){
                              var th = $(this), itemData = th.attr('lay-data');
  
                              try{
                                  itemData = new Function('return '+ itemData)();
                              } catch(e){
                                  return hint.error(errorTips + itemData)
                              }
  
                              var row = $.extend({
                                  title: th.text()
                                  ,colspan: th.attr('colspan') || 0 //列单元格
                                  ,rowspan: th.attr('rowspan') || 0 //行单元格
                              }, itemData);
  
                              if(row.colspan < 2) cols.push(row);
                              options.cols[i].push(row);
                          });
                      });
  
                      //获取表体数据
                      othis.find('tbody>tr').each(function(i1){
                          var tr = $(this), row = {};
                          //如果定义了字段名
                          tr.children('td').each(function(i2, item2){
                              var td = $(this)
                                  ,field = td.data('field');
                              if(field){
                                  return row[field] = td.html();
                              }
                          });
                          //如果未定义字段名
                          layui.each(cols, function(i3, item3){
                              var td = tr.children('td').eq(i3);
                              row[item3.field] = td.html();
                          });
                          options.data[i1] = row;
                      });
                      table.render(options);
                  });
  
                  return that;
              }
              /**
               * 渲染入口方法（核心入口）
               */
              ,render:function (options) {
                  table.pushClassIds(options.id);
                  var inst = new Class(options);
                  return thisTable.call(inst);
              }
              /**
               * 对应的表格加载完成后执行
               * @param tableId
               * @param fn
               */
              ,ready:function (tableId,fn) {
                  var is=false;
                  var myDate=new Date();
                  function isReady() {
                      if(tableId){
                          var that=table.getClass(tableId);
                          if(that&&that.hasOwnProperty('layBody')){
                              fn(that);
                              is=true;
                          }else{
                              var myDate2=new Date();
                              var i=myDate2.getTime()-myDate.getTime();
                              if(i<=(1000*10)&&!is){//大于10秒退出
                                  setTimeout(isReady,50);
                              }
                          }
                      }
                  }
                  if(tableId&&fn){
                      setTimeout(isReady,50);
                  }
              }
              /**
               * 获取表格选中记录
               * @param tableId
               * @return {{data: Array, isAll: boolean}}
               */
              ,checkStatus:function (tableId) {
                  var nums = 0
                      ,invalidNum = 0
                      ,arr = []
                      ,data = table.getDataList(tableId) || [];
                  //计算全选个数
                  layui.each(data, function(i, item){
                      if(item.constructor === Array){
                          invalidNum++; //无效数据，或已删除的
                          return;
                      }
                      if(item[table.config.cols.isCheckName]){
                          nums++;
                          arr.push(table.clearCacheKey(item));
                      }
                  });
                  return {
                      data: arr //选中的数据
                      ,isAll: data.length ? (nums === (data.length - invalidNum)) : false //是否全选
                  };
              }
              /**
               * 设置表格复选状态
               * @param tableId
               * @param value     此值存在时为设置操作
               * @returns {*}
               */
              ,setCheckStatus:function(tableId, fildName, ids){
                  var retObj=null;
                  var that=table.getClass(tableId)
                      ,invalidNum = 0
                      ,arr = []
                      ,data = table.getDataList(tableId) || []
                      ,childs = that.layBody.find('input[name="layTableCheckbox"]')//复选框
                  ;
                  if(fildName&&ids){//设置选中
                      var idsarr=ids.split(',');
                      idsarr.forEach(function (o) {
                          var temo=null;
                          data.forEach(function (e) {
                              var b1=e[fildName]+"";
                              var b2=o+"";
                              if(b1==b2){
                                  temo=e;
                                  return;
                              };
                          });
                          if(temo){
                              var v=temo[table.config.indexName];
                              that.layBody.find('input[name="layTableCheckbox"][value="'+v+'"]').prop("checked",true);
                              that.setCheckData(v, true);
                          }
                      });
                      that.syncCheckAll();
                      that.renderForm('checkbox');
                  }
                  return retObj;
              }
              /**
               * 表格单选状态
               * @param tableId
               * @param value     此值存在时为设置操作
               * @returns {*}
               */
              ,radioStatus:function (tableId) {
                  var retObj=null;
                  var nums = 0
                      ,invalidNum = 0
                      ,arr = []
                      ,data = table.getDataList(tableId) || [];
                  var v=$("input[name='"+TABLE_RADIO_ID+tableId+"']:checked").val();
                  v=parseInt(v);
                  data.forEach(function (e) {
                      if(e[table.config.indexName]==v){
                          retObj=e;
                      };
                  });
                  return table.clearCacheKey(retObj);
              }
              /**
               * 设置表格单选状态
               * @param tableId
               * @param value     此值存在时为设置操作
               * @returns {*}
               */
              ,setRadioStatus:function (tableId,fildName,value) {
                  var retObj=null;
                  var nums = 0
                      ,invalidNum = 0
                      ,arr = []
                      ,data = table.getDataList(tableId) || [];
  
                  if(fildName&&value){//设置选中
                      data.forEach(function (e) {
                          var b1=e[fildName]+"";
                          var b2=value+"";
                          if(b1==b2){
                              retObj=e;
                              return;
                          };
                      });
  
                      if(retObj){
                          var v=retObj[table.config.indexName];
                          $("input:radio[name='"+TABLE_RADIO_ID+tableId+"'][value='"+v+"']").prop("checked",true);
                          form.render('radio');
                      }
                  }
                  return retObj;
              }
              /**
               * 清除临时Key
               * @param data
               * @return {*}
               */
              ,clearCacheKey:function (data) {
                  data = $.extend({}, data);
                  delete data[table.config.cols.isCheckName];
                  delete data[table.config.indexName];
                  return data;
              }
              /**
               * 刷新数据
               * @param id
               * @param options
               * @return {*}
               */
              ,query:function (tableId, options) {
                  var that= table.getClass(tableId);
                  that.renderTdCss();
                  if(that.config.data && that.config.data.constructor === Array) delete that.config.data;
                  that.config = $.extend({}, that.config, options);
                  that.pullData(that.page, that.loading());
              }
              /**
               * 此方法为整体重新渲染（重量级刷新方法）
               * @param id
               * @param options
               */
              ,reload:function (tableId, options) {
                  var config = thisTable.config[tableId];
                  options = options || {};
                  if(!config) return hint.error('The ID option was not found in the table instance');
                  if(options.data && options.data.constructor === Array) delete config.data;
                  return table.render($.extend(true, {}, config, options));
              }
              /**
               * 添加一行或多行数据
               * @param tableId   表格id
               * @param index     在第几个位置插入（从0开始）
               * @param data      数据
               * @returns {*}
               */
              ,addRow:function (tableId, index, data) {
                  var that=table.getClass(tableId)
                      ,options=that.config
                      ,uo = []//父级节点
                      ,treeList=table.getDataTreeList(tableId)
                      ,list = table.getDataList(tableId) || [];
                  that.resetData(data);
                  //插入到父节点后面
                  list.splice(index,0,data);//更新缓存
                  table.kit.restNumbers(list);//重置下标
                  table.setDataMap(tableId,that.resetDataMap(list));//处理map
                  if(options.isTree){//处理层级
                      //1、处理父级  2、处理treeObj 3、层级
                      var uo=that.treeFindUpData(data);
                      if(uo) {
                          var clist=uo.children;
                          uo.children.push(data);
                          data[table.config.cols.level]=uo[table.config.cols.level]+1;
                      }else{
                          data[table.config.cols.level]=1;
                          treeList.push(data);
                      }
                  }
                  //生成html
                  var tds=that.renderTr(data,data[table.config.indexName]);
                  var trs='<tr data-index="'+ data[table.config.indexName] +'"'+that.renderTrUpids(data)+'>'+ tds.join('') + '</tr>';
                  if(index==0){//在第一个位置插入
                      var  tbody=that.layBody.find('table tbody');
                      $(tbody).prepend(trs);
                      that.layBody.find(".layui-none").remove();
                  }else{
                      var o=that.layBody.find('[data-index='+(index-1)+']');//父节点dom树
                      $(o).after(trs);
                  }
                  that.renderForm();
                  if(options.isPage)that.renderPage(that.config.page.count+1);//分页渲染
                  that.restNumbers();
                  that.events();
                  if(options.isTree) {//展开节点
                      that.treeNodeOpen(uo, true);
                      that.renderTreeConvertShowName(uo);
                  }
              }
              /**
               * 删除一行或多行数据
               * （如果是树状则删除自己和子节点）
               * @param tableId
               * @param data（1、数组；2、对象）
               */
              ,delRow:function (tableId, data) {
                  //1、页面清除 2、缓存清除
                  var that=table.getClass(tableId)
                      ,options=that.config
                      ,list=table.getDataList(tableId);
                  var sonList=[];//需要删除的数据
                  var delIds={};//需要删除的数据map
                  var delDatas=[];
                  var upDelDatas=[];//全部待删除节点的父节点（处理折叠）
                  if(!that||!data)return;
                  if(table.kit.isArray(data)){//是数组，删除多个
                      delDatas=data;
                  }else{
                      delDatas[0]=data;
                  }
                  delDatas.forEach(function(temo) {//记录全部父节点
                      var uo=that.treeFindUpData(temo);
                      if(uo){
                          upDelDatas.push(uo);
                      }
                  });
                  sonList=options.isTree?table.treeFindSonList(that.config.id,delDatas):delDatas;
                  //页面元素处理
                  sonList.forEach(function (temo) {
                      var index=temo[table.config.indexName];
                      delIds[index]=index;//设置代删除的id集合
                      var tr = that.layBody.find('tr[data-index="'+ index +'"]');
                      tr.remove();
                  });
                  //数据处理
                  that.restNumbers();
                  var newList=[];//重构一个新的数组
                  for (var i=0,len=list.length;i<len;i++) {
                      var isP=true;
                      var temo1=null;
                      sonList.forEach(function (temo) {
                          if (temo[table.config.indexName] === list[i][table.config.indexName]) {
                              isP = false;
                          }
                      });
                      if(isP){
                          newList.push(list[i]);
                      }
                  }
                  table.kit.restNumbers(newList);
                  //that.resetDatas(newList);//更新缓存数据
                  //处理父级节点
                  upDelDatas.forEach(function(temo) {
                      that.renderTreeConvertShowName(temo);
                  });
                  if(options.isPage)that.renderPage(that.config.page.count-Object.keys(delIds).length);//分页渲染
                  //处理list
                  table.setDataList(tableId,newList);
                  //处理map
                  table.setDataMap(tableId,that.resetDataMap(newList));
                  //处理树结构
                  table.setDataTreeList(tableId,that.resetDataTreeList(newList,table.getDataRootList(tableId)));
                  that.events();
              }
              /**
               * 更新指定的记录
               * @param obj
               * @param index
               */
              ,updateRow:function (tableId,obj) {
                  var that=table.getClass(tableId);
                  if(!that||!obj)return;
                  var id=obj[that.config.idField];
                  //更新缓存数据
                  var maps=table.getDataMap(tableId);
                  var thisobj=maps[id];
                  if(thisobj){
                      $.extend(thisobj, obj);
                  }else{
                      return;
                  }
                  //更新页面
                  var oi=thisobj[table.config.indexName];
                  var  tds=that.renderTr(thisobj,oi);
                  var tr=that.layBody.find('tr[data-index='+oi+']');
                  $(tr).html(tds);
              }
              ,treeNodeOpen:function (tableId,o, isOpen) {
                  var that=table.getClass(tableId);
                  if(!that||!o)return;
                  that.treeNodeOpen(o,isOpen);
              }
              /**
               * 折叠或展开全部(默认为展开全部节点)
               * @param tableId
               * @param isOpen    展开还是折叠（默认值为true 展开）
               */
              ,treeOpenAll:function (tableId,isOpen) {
                  var that=table.getClass(tableId);
                  if(!that)return;
                  if(isOpen===undefined){isOpen=true;}
                  var list=table.getDataList(tableId);
                  if(!list)return;
                  list.forEach(function (temo) {
                      that.treeNodeOpen(temo,isOpen);
                  });
              }
              /**
               * 获取全部需要子节点对象集合
               * @param data（数组或对象）
               */
              ,treeFindSonList:function (tableId,data) {
                  var that=table.getClass(tableId);
                  if(!that||!data)return [];
                  var delDatas=[];
                  var sonList=[];//需要删除的数据
                  var delIds={};//需要删除的数据map
                  if(table.kit.isArray(data)){//是数组，删除多个
                      delDatas=data;
                  }else{
                      delDatas[0]=data;
                  }
                  delDatas.forEach(function (temo) {
                      if(temo.children.length>0){
                          var temSonList=that.treeFindSonData(temo);
                          temSonList.forEach(function (temii) {
                              if(!delIds[temii[table.config.indexName]]){
                                  sonList.push(temii);
                                  delIds[temii[table.config.indexName]]=temii[table.config.indexName];
                              }
                          });
                      }
                      sonList.push(temo);
                      delIds[temo[table.config.indexName]]=temo[table.config.indexName];
                  });
                  return sonList;
              }
              ,treeFindUpDatas:function (tableId, o) {
                  var that=table.getClass(tableId);
                  if(!that||!o)return [];
                  return that.treeFindUpDatas(o);
              }
              ,treeFindUpData:function (tableId, o) {
                  var that=table.getClass(tableId);
                  if(!that||!o)return [];
                  return that.treeFindUpData(o);
              }
              /**
               * 获取全部需要子节点id集合
               * @param data（数组或对象）
               */
              ,treeFindSonIds:function (tableId,data) {
                  var delIds=[];
                  var sonList=table.treeFindSonList(tableId,data);
                  sonList.forEach(function (temo) {
                      delIds.push([table.config.indexName]);
                  });
                  return delIds;
              }
              /**
               * 获取全部的id字段集合
               * @param tableId
               * @param data
               * @returns {Array}
               */
              ,treeFindSonIdFields:function (tableId,data) {
                  var idField=[];
                  var that=table.getClass(tableId);
                  var sonList=table.treeFindSonList(tableId,data);
                  sonList.forEach(function (temo) {
                      idField.push(temo[that.config.idField]);
                  });
                  return idField;
              }
              ,treeIconRender:function (tableId, o) {
                  var that=table.getClass(tableId);
                  if(!that||!o)return [];
                  return that.treeIconRender(o,false);
              }
              /**
               * 工具方法对象
               */
              ,kit:{
                  isArray:function (o) {
                      return Object.prototype.toString.call(o) === '[object Array]';
                  }
                  ,isNumber:function (val){
                      var regPos = /^\d+(\.\d+)?$/; //非负浮点数
                      var regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; //负浮点数
                      if(regPos.test(val) || regNeg.test(val)){
                          return true;
                      }else{
                          return false;
                      }
  
                  }
                  ,restNumbers:function (list) {
                      if(!list)return;
                      var i=0;
                      list.forEach(function (o) {
                          o[table.config.indexName]=i;
                          i++;
                      });
                  }
              }
          }
          //操作当前实例
          ,thisTable = function(){
              var that = this
                  ,options = that.config
                  ,id = options.id;
              id && (thisTable.config[id] = options);
              return {
                  reload: function(options){
                      that.reload.call(that, options);
                  }
                  ,config: options
              }
          }
          //字符常量
          ,MOD_NAME = 'treeGrid', ELEM = '.layui-table', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide', DISABLED = 'layui-disabled', NONE = 'layui-none'
          ,ELEM_VIEW = 'layui-table-view', ELEM_HEADER = '.layui-table-header', ELEM_BODY = '.layui-table-body', ELEM_MAIN = '.layui-table-main', ELEM_FIXED = '.layui-table-fixed', ELEM_FIXL = '.layui-table-fixed-l', ELEM_FIXR = '.layui-table-fixed-r', ELEM_TOOL = '.layui-table-tool', ELEM_PAGE = '.layui-table-page', ELEM_SORT = '.layui-table-sort', ELEM_EDIT = 'layui-table-edit', ELEM_HOVER = 'layui-table-hover'
          ,TABLE_RADIO_ID='table_radio_'
          ,ELEM_FILTER='.layui-table-filter'
          ,TREE_ID='treeId',TREE_UPID='treeUpId',TREE_SHOW_NAME='treeShowName',TREE_KEY_MAP='tree_key_map'
          //thead区域模板
          ,TPL_HEADER = function(options){
              var rowCols = '{{#if(item2.colspan){}} colspan="{{item2.colspan}}"{{#} if(item2.rowspan){}} rowspan="{{item2.rowspan}}"{{#}}}';
              options = options || {};
              return ['<table cellspacing="0" cellpadding="0" border="0" class="layui-table" '
                  ,'{{# if(d.data.skin){ }}lay-skin="{{d.data.skin}}"{{# } }} {{# if(d.data.size){ }}lay-size="{{d.data.size}}"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>'
                  ,'<thead>'
                  ,'{{# layui.each(d.data.cols, function(i1, item1){ }}'
                  ,'<tr>'
                  ,'{{# layui.each(item1, function(i2, item2){ }}'
                  ,'{{# if(item2.fixed && item2.fixed !== "right"){ left = true; } }}'
                  ,'{{# if(item2.fixed === "right"){ right = true; } }}'
                  ,function(){
                      if(options.fixed && options.fixed !== 'right'){
                          return '{{# if(item2.fixed && item2.fixed !== "right"){ }}';
                      }
                      if(options.fixed === 'right'){
                          return '{{# if(item2.fixed === "right"){ }}';
                      }
                      return '';
                  }()
                  ,'<th data-field="{{ item2.field||i2 }}" {{# if(item2.minWidth){ }}data-minwidth="{{item2.minWidth}}"{{# } }} '+ rowCols +' {{# if(item2.unresize){ }}data-unresize="true"{{# } }}>'
                  ,'<div class="layui-table-cell laytable-cell-'
                  ,'{{# if(item2.colspan > 1){ }}'
                  ,'group'
                  ,'{{# } else { }}'
                  ,'{{d.index}}-{{item2.field || i2}}'
                  ,'{{# if(item2.type !== "normal"){ }}'
                  ,' laytable-cell-{{ item2.type }}'
                  ,'{{# } }}'
                  ,'{{# } }}'
                  ,'" {{#if(item2.align){}}align="{{item2.align}}"{{#}}}>'
                  ,'{{# if(item2.type === "checkbox"){ }}' //复选框
                  ,'<input type="checkbox" name="layTableCheckbox" lay-skin="primary" lay-filter="layTableAllChoose">'
                  ,'{{# } else { }}'
                  ,'<span>{{item2.title||""}}</span>'
                  ,'{{# if(!(item2.colspan > 1) && item2.sort){ }}'
                  ,'<span class="layui-table-sort layui-inline"><i class="layui-edge layui-table-sort-asc"></i><i class="layui-edge layui-table-sort-desc"></i></span>'
                  ,'{{# } }}'
                  ,'{{# } }}'
                  ,'</div>'
                  ,'</th>'
                  ,(options.fixed ? '{{# }; }}' : '')
                  ,'{{# }); }}'
                  ,'</tr>'
                  ,'{{# }); }}'
                  ,'</thead>'
                  ,'</table>'].join('');
          }
          /**
           * 行内过滤区域
           */
          ,TPL_FILTER = function(options){
          }
          //tbody区域模板
          ,TPL_BODY = ['<table cellspacing="0" cellpadding="0" border="0" class="layui-table" '
              ,'{{# if(d.data.skin){ }}lay-skin="{{d.data.skin}}"{{# } }} {{# if(d.data.size){ }}lay-size="{{d.data.size}}"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>'
              ,'<tbody></tbody>'
              ,'</table>'].join('')
          //主模板
          ,TPL_MAIN = ['<div class="layui-form layui-border-box {{d.VIEW_CLASS}}" lay-filter="LAY-table-{{d.index}}" style="{{# if(d.data.width){ }}width:{{d.data.width}}px;{{# } }} {{# if(d.data.height){ }}height:{{d.data.height}}px;{{# } }}">'
  
              ,'{{# if(d.data.toolbar){ }}'
              ,'<div class="layui-table-tool"></div>'
              ,'{{# } }}'
  
              ,'<div class="layui-table-box">'
              ,'{{# var left, right; }}'
              ,'<div class="layui-table-header">'
              ,TPL_HEADER()
              ,'</div>'
              ,'<div class="layui-table-filter">'
              ,TPL_FILTER()
              ,'</div>'
              ,'<div class="layui-table-body layui-table-main">'
              ,TPL_BODY
              ,'</div>'
  
              ,'{{# if(left){ }}'
              ,'<div class="layui-table-fixed layui-table-fixed-l">'
              ,'<div class="layui-table-header">'
              ,TPL_HEADER({fixed: true})
              ,'</div>'
              ,'<div class="layui-table-body">'
              ,TPL_BODY
              ,'</div>'
              ,'</div>'
              ,'{{# }; }}'
  
              ,'{{# if(right){ }}'
              ,'<div class="layui-table-fixed layui-table-fixed-r">'
              ,'<div class="layui-table-header">'
              ,TPL_HEADER({fixed: 'right'})
              ,'<div class="layui-table-mend"></div>'
              ,'</div>'
              ,'<div class="layui-table-body">'
              ,TPL_BODY
              ,'</div>'
              ,'</div>'
              ,'{{# }; }}'
              ,'</div>'
  
              ,'{{# if(d.data.isPage){ }}'
              ,'<div class="layui-table-page">'
              ,'<div id="layui-table-page{{d.index}}"></div>'
              ,'</div>'
              ,'{{# } }}'
  
              /*,'<style>'
              ,'{{# layui.each(d.data.cols, function(i1, item1){'
              ,'layui.each(item1, function(i2, item2){ }}'
              ,'.laytable-cell-{{d.index}}-{{item2.field||i2}}{ '
              ,'{{# if(item2.width){ }}'
              ,'width: {{item2.width}}px;'
              ,'{{# } }}'
              ,' }'
              ,'{{# });'
              ,'}); }}'
              ,'</style>'*/
              ,'</div>'].join('')
          ,_WIN = $(window)
          ,_DOC = $(document)
  
          //构造器
          ,Class = function(options){
              var that = this;
              that.index = ++table.index;
              that.config = $.extend({}, that.config, table.config, options);
              that.configFirst = $.extend({}, that.config, table.config, options);
              that.render();
              table.pushClass(options.id,that);
          };
      /**
       * 表格行为属性（默认配置）
       */
      Class.prototype.config = {
          limit: 10 //每页显示的数量
          ,loading: true //请求数据时，是否显示loading
          ,cellMinWidth: 60 //所有单元格默认最小宽度
          ,heightRemove:[]//非固定高度情况下，不参与计算的高度
          ,text: {
              none: '无数据'
          }
          ,isFilter:false//是否开启行内过滤
          ,method:'post'//默认以post方式请求后台
          ,radDisabledNum:0//禁止单选的记录数
          ,cheDisabledNum:0//禁止多选的记录数
          //树相关图表
          ,branch: ['&#xe622;', '&#xe624;'] //父节点
          ,leaf: '&#xe621;' //叶节点
          ,iconOpen:true//默认开启树节点图标
          ,isOpenDefault:true//默认展开还是折叠节点
          ,parseData:null//加载数据后的回调方法
          ,onClickRow:null//行单击事件
          ,onDblClickRow:null//行双击事件
          ,onBeforeCheck:null//复选前事件
          ,isTree:true//默认为树表格
          ,isPage:false//不分页
          ,height:'100%'//默认高度100%
      };
      Class.prototype.configFirst={};//页面定义时原始参数
      //表格渲染
      Class.prototype.render = function(){
          var that = this
              ,options = that.config;
          options.elem = $(options.elem);
          options.where = options.where || {};
          options.id = options.id || options.elem.attr('id');
          that.test();
          //请求参数的自定义格式
          options.request = $.extend({
              pageName: 'page'
              ,limitName: 'limit'
          }, options.request)
          //响应数据的自定义格式
          options.response = $.extend({
              statusName: 'code'
              ,statusCode: 0
              ,msgName: 'msg'
              ,dataName: 'data'
              ,countName: 'count'
          }, options.response);
          //如果 page 传入 laypage 对象
          if(typeof options.page === 'object'){
              options.limit = options.page.limit || options.limit;
              options.limits = options.page.limits || options.limits;
              that.page = options.page.curr = options.page.curr || 1;
              delete options.page.elem;
              delete options.page.jump;
          }
          if(!options.elem[0]) return that;
          that.columnWidthInit();//列宽度计算
          //开始插入替代元素
          var othis = options.elem
              ,hasRender = othis.next('.' + ELEM_VIEW)
              //主容器
              ,reElem = that.elem = $(laytpl(TPL_MAIN).render({
                  VIEW_CLASS: ELEM_VIEW
                  ,data: options
                  ,index: that.index //索引
              }));
          options.index = that.index;
          //生成替代元素
          hasRender[0] && hasRender.remove(); //如果已经渲染，则Rerender
          othis.after(reElem);
          that.renderTdCss();
          //各级容器
          that.layHeader = reElem.find(ELEM_HEADER);  //表头
          that.layMain = reElem.find(ELEM_MAIN);//内容区域
          that.layBody = reElem.find(ELEM_BODY);//内容区域
          that.layFixed = reElem.find(ELEM_FIXED);//浮动区域
          that.layFixLeft = reElem.find(ELEM_FIXL);//左浮动
          that.layFixRight = reElem.find(ELEM_FIXR);//有浮动
          that.layTool = reElem.find(ELEM_TOOL);//工具栏区域
          that.layPage = reElem.find(ELEM_PAGE);//分页区域
          that.layFilter=reElem.find(ELEM_FILTER);//行内过滤条件区域
          that.layTool.html(
              laytpl($(options.toolbar).html()||'').render(options)
          );
          if(options.height){
              that.tableHeight();//表格高度计算
              that.resizeHeight();//高度控制
              that.renderCss();
          }
          //如果多级表头，则填补表头高度
          if(options.cols.length > 1){
              var th = that.layFixed.find(ELEM_HEADER).find('th');
              th.height(that.layHeader.height() - 1 - parseFloat(th.css('padding-top')) - parseFloat(th.css('padding-bottom')));
          }
          //渲染过滤区域
          if(options.isFilter){
              that.layFilter.html(
                  that.renderFilter()
              );
          }
          //请求数据
          that.pullData(that.page,that.loading());
          that.test();
      };
      //根据列类型，定制化参数
      Class.prototype.initOpts = function(item){
          var that = this,
              options = that.config;
          //让 type 参数兼容旧版本
          if(item.checkbox) item.type = "checkbox";
          if(item.space) item.type = "space";
          if(!item.type) item.type = "normal";
  
          if(item.type !== "normal"){
              item.unresize = true;
              item.width = item.width || table.config.initWidth[item.type];
          }
  
          if(options.isFilter){//开启行内过滤
              if(item.isFilter!=false){
                  item.isFilter=true;
              }
          }
      };
  
      /**
       * 表格获取父容器高度
       * @param tableId
       */
      Class.prototype.getParentDivHeight = function(tableId){
          var th=$("#"+tableId).parent().height();
          return th;
      };
  
      /**
       * 获取列定义
       * @param tableId
       */
      Class.prototype.getCols = function(field){
          var that = this;
          var o={};
          var cols=that.config.cols[0];
          var isInt=false;
          var reg = /^[0-9]+.?[0-9]*$/;
          if (reg.test(field)) {//数字
              isInt=true;
          }
          for(var ii in cols){
              if(isInt){
                  if(ii==parseInt(field)) return cols[ii];
              }else{
                  if(field==cols[ii].field)return cols[ii];
              }
          }
          return o;
      };
  
      //表格重载
      Class.prototype.reload = function(options){
          var that = this;
          if(that.config.data && that.config.data.constructor === Array) delete that.config.data;
          that.config = $.extend({}, that.config, options);
          that.configFirst = $.extend({}, that.config, options);
          //获取行内过滤的值
          that.render();
      };
      //页码
      Class.prototype.page = 1;
      /**
       * 重置下标（插入删除等操作）
       * 1、data-index中的下标
       * 2、tr中data的值
       * 3、下标字段的值
       * @param list
       */
      Class.prototype.restNumbers=function(){
          var that = this
              ,options = that.config;
          var  trs=that.layBody.find('table tbody tr');
          var i=0;
          trs.each(function (o) {
              $(this).attr("data-index",i);
              $(this).find(".laytable-cell-numbers p").text(i+1);
              $(this).data('index',i);
              i++;
          });
      }
  
      /**
       * 初始化节点
       * 在每一次数据加载时只执行一次
       * query、reload时会执行
       * @param o
       */
      Class.prototype.resetData=function(n) {
          var that = this
              ,options = that.config;
          if(options.isTree){
              if(!n.hasOwnProperty(table.config.cols.isOpen)){//如果不存在该属性则默认为true
                  n[table.config.cols.isOpen]=options.isOpenDefault;
              }
              if(!n.hasOwnProperty(table.config.cols.isShow)){//如果不存在该属性则默认为true
                  n[table.config.cols.isShow]=options.isOpenDefault?true:false;
              }
          }
          //禁止设置
          if(!n.hasOwnProperty(table.config.cols.cheDisabled)){//不存在则默认为false
              n[table.config.cols.cheDisabled]=false;
          }
          //记录禁止多选、单选的记录数
          if(n[table.config.cols.cheDisabled])options.cheDisabledNum++;
          if(n[table.config.cols.radDisabled])options.radDisabledNum++;
          n.children=[];
      }
      /**
       * 构建map数据
       * @param list
       * @return {{}}
       */
      Class.prototype.resetDataMap=function(list) {
          var that = this
              ,options = that.config;
          var field_Id=options.idField;
          var map={};
          list.forEach(function (o) {
              map[o[field_Id]]=o;
          });
          return map;
      }
      Class.prototype.resetDataresetRoot=true;//是否重新确定根节点
      /**
       * 确定根节点id(重新登录根节点)
       */
      Class.prototype.resetDataRoot=function (list) {
          var that = this
              ,options = that.config;
          var field_Id=options[TREE_ID];
          var field_upId=options[TREE_UPID];
          var map=table.getDataMap(that.config.id);//列表map，fieldId为key  //设置map数据集合
          var rootList=table.cache[options.id].data.upIds||[];//根节点list集合
          var rootMap={};//根节点map集合
          table.cache[options.id].data.upIds=[];
          rootList=table.cache[options.id].data.upIds;
          for(var i=0;i<list.length;i++){
              var temo=list[i];
              if(!map[temo[field_upId]]){//没有找到父节点
                  if(!rootMap[temo[field_upId]]){//还不存在
                      var temis=true;
                      rootList.forEach(function (temoo) {
                          if(temoo===temo[field_upId])temis=false;
                      });
                      if(temis)rootList.push(temo[field_upId]);
                  }
                  rootMap[temo[field_upId]]=temo[field_upId];
              }
          }
          return rootList;
      }
      /**
       * 处理树结构
       * 1、原始列表数据
       * 2、根节点集合
       */
      Class.prototype.resetDataTreeList=function (list, rootList) {
          var that = this
              ,options = that.config;
          var field_Id=options[TREE_ID];
          var field_upId=options[TREE_UPID];
          var treeList=[];
          //处理树结构
          var fa = function(upId) {
              var _array = [];
              for (var i = 0; i < list.length; i++) {
                  var n = list[i];
                  if (n[field_upId] === upId) {
                      n.children = fa(n[field_Id]);
                      _array.push(n);
                  }
              }
              return _array;
          }
          rootList.forEach(function (temo) {
              var temTreeObj=fa(temo);//递归
              if(temTreeObj){
                  temTreeObj.forEach(function (o) {
                      treeList.push(o);
                  });
              }
          });
          return treeList;
      }
  
      /**
       * 处理数据列表结构
       * 1、树结构
       */
      Class.prototype.resetDataTableList=function (treeList) {
          var that = this
              ,options = that.config;
          var field_Id=options[TREE_ID];
          var field_upId=options[TREE_UPID];
          var tableList=[];
          //处理表格结构
          var fa2=function (l,level) {
              for (var i = 0; i < l.length; i++) {
                  var n = l[i];
                  n[table.config.cols.level]=level;//设置当前层级
                  tableList.push(n);
                  if (n.children&&n.children.length>0) {
                      fa2(n.children,1+level);
                  }
              }
              return;
          }
          fa2(treeList,1);
  
          //设置isOpen 和is_show状态
          tableList.forEach(function (o) {
              var uo=that.treeFindUpData(o);
              if(!uo||(uo[table.config.cols.isOpen]&&uo[table.config.cols.isShow])){//没有父亲：显示；父亲打开状态（显示状态：显示；隐藏状态：隐藏）
                  o[table.config.cols.isShow]=true;
              }else{
                  o[table.config.cols.isShow]=false;
              }
          });
          return tableList;
      }
  
      /**
       * 重置当前表格的数据（1、普通列表；2树状表格）
       * 将列表数据转成树形结构和符合table展示的列表
       * @param list          列表数据
       * @param field_Id      树形结构主键字段
       * @param field_upId    树形结构上级字段
       * @returns {Array}     [0]表格列表  [1]树形结构
       */
      Class.prototype.resetDatas=function(list) {
          //console.time("resetDatas");
          var that = this
              ,options = that.config;
          var field_Id=options[TREE_ID];
          var field_upId=options[TREE_UPID];
          var datas=[];
          var treeList=[];
          var tableList=list;
          var map=that.resetDataMap(list);//列表map，fieldId为key  //设置map数据集合
          datas.push(tableList);//table结构
          datas.push(treeList)//tree树结构
          datas.push(map)//data数据 map结构
          //设置到内存中去
          table.setDataList(that.config.id,tableList);
          table.setDataTreeList(that.config.id,treeList);
          table.setDataMap(that.config.id,map);
          if(list==null||list.length<=0)return datas;
          //设置默认参数
          for (var i = 0; i < list.length; i++) {
              that.resetData(list[i]);
          }
          if(options.isTree){//树状
              tableList=[];
              table.setDataList(that.config.id,tableList);
              var rootList=table.cache[options.id].data.upIds||[];//根节点list集合
              if(rootList.length<=0||that.resetDataresetRoot){//确定根节点
                  table.cache[options.id].data.upIds=[];
                  rootList=that.resetDataRoot(list);
                  that.resetDataresetRoot=false;
              }
              treeList=that.resetDataTreeList(list,rootList);
              table.setDataTreeList(that.config.id,treeList);//设置树结构到缓存
              tableList=that.resetDataTableList(treeList);
              table.setDataList(that.config.id,tableList);//设置数据列表结构到缓存
          }
          //console.timeEnd("resetDatas");
          return datas;
      }
      /**
       * 根据id从表格数据中获取对象
       * @param data
       * @param field_Id
       * @param field_upId
       * @returns {Array}
       */
      Class.prototype.treeFindDataById=function(u_Id) {
          var that = this
              ,options = that.config;
          var e=null;
          var list=table.getDataList(that.key);
          var key=options[TREE_ID];
          list.forEach(function (o) {
              if(o[key]==u_Id){
                  e=o;
                  return;
              }
          });
          return e;
      }
      /**
       * 获取父节点
       * @param u_Id
       */
      Class.prototype.treeFindUpData=function(o){
          var uOjb=null;
          var that = this
              ,options = that.config;
          //处理父级
          var key=options[TREE_UPID];//父节点key名称
          var mapData=table.getDataMap(that.config.id);//获取map形式对象集合
          uOjb=mapData[o[key]];
          return uOjb;
      }
      /**
       * 获取全部父节点集合，返回list(不包含自己)
       * @param u_Id
       */
      Class.prototype.treeFindUpDatas=function(o){
          var uOjb=null;
          var that = this
              ,options = that.config;
          var list=[];
          var temf=function (temo) {
              var uo=that.treeFindUpData(temo);
              if(uo){
                  list.push(uo);
                  temf(uo);
              }
          };
          temf(o);
          return list;
      }
      /**
       * 根据父id获取全部的叶子节点(递归)
       * @param o 数据对象
       * @return {string}
       */
      Class.prototype.treeFindSonData=function (data) {
          var objs=[];
          function f(o) {
              if(o.children.length>0){
                  o.children.forEach(function (i) {
                      objs.push(i);
                      if(i.children.length>0){
                          f(i);
                      }
                  });
              }
          }f(data);
          return objs;
      };
      /**
       * 叶子节点显示转换
       * @param o             数据
       * @param fieldName     树显示列名
       * @returns {string}
       */
      Class.prototype.treeConvertShowName=function (o) {
          var that = this
              ,options = that.config;
          var isTreeNode=(o.children&&o.children.length>0);
          var temhtml='<div style="float: left;height: 28px;line-height: 28px;padding-left: '+
              function () {
                  if(isTreeNode){
                      return '5px'
                  }else{
                      return '21px'
                  }
              }()
              +'">'
              +function () {//位移量
                  var nbspHtml="<i>"//一次位移
                  for(var i=1;i<o[table.config.cols.level];i++) {
                      nbspHtml = nbspHtml + "&nbsp;&nbsp;&nbsp;&nbsp;";
                  }
                  nbspHtml=nbspHtml+"</i>";
                  return nbspHtml;
              }()
              +function () {//图标或占位符
                  var temTreeHtml='';
                  var temTreeIsOpen=o[table.config.cols.isOpen]?"&#xe625;":"&#xe623;";
                  if(isTreeNode){//父节点
                      temTreeHtml='<i class="layui-icon layui-tree-head">'+temTreeIsOpen+'</i>'
                          +that.treeIconRender(o,true);
                  }else{//叶子节点
                      temTreeHtml+=that.treeIconRender(o,true);
                  }
                  return temTreeHtml;
              }()
              +'</div>';
          return temhtml;
      };
      /**
       * 节点的展开或折叠
       * @param o         节点数据（树状表格）
       * @param isOpen    展开（true）或折叠（false）
       *
       * 每个节点有两种状态，
       * 1、打开状态（isOpen）   打开状态只需在点击瞬间控制，其他时候不需要变动
       * 2、显示状态（显示或隐藏） 显示状态根据父级节点控制，父级节点是显示并且打开状态的则显示，否则不显示，但不影响其打开状态
       */
      Class.prototype.treeNodeOpen=function (o,isOpen) {
          var that = this
              ,tr = that.layBody.find('tr[data-index="'+ o[table.config.indexName] +'"]');
          if(!o){
              return
          }
          o[table.config.cols.isOpen]=isOpen;
          //处理树结构
          var fa = function(e) {
              if(e.children&&e.children.length>0){
                  var temList=e.children;
                  for (var i = 0; i < temList.length; i++) {
                      var n = temList[i];
                      if(o[table.config.cols.isOpen]){//打开状态的，关闭
                          if(e[table.config.cols.isOpen]&&e[table.config.cols.isShow]){//该节点显示
                              var temo=that.layBody.find('tr[data-index="'+ n[table.config.indexName] +'"]');
                              temo.css('display', '');
                              n[table.config.cols.isShow]=true;
                          }
                      }else{
                          var temo=that.layBody.find('tr[data-index="'+ n[table.config.indexName] +'"]');
                          temo.css('display', 'none');
                          n[table.config.cols.isShow]=false;
                      }
                      fa(n);
                  }
              }
          }
          fa(o);
          //处理图标
          that.treeIconRender(o,false);
          var dbClickI=tr.find('.layui-tree-head');
          if(o[table.config.cols.isOpen]){//打开状态
              dbClickI.html('&#xe625;');
          }else{
              dbClickI.html('&#xe623;');
          }
      };
  
      /**
       * icon渲染
       * @param o
       * @param isHtml  true（返回html）  false（立即渲染）
       */
      Class.prototype.treeIconRender=function (o,isHtml) {
          var that = this
              ,options = that.config
              ,iconOpen=options.iconOpen
              ,isTreeNode=(o.children&&o.children.length>0);
          var temTreeHtml='';
          if(iconOpen){
              var temf=function () {//自定义图标
                  var temhtml='<i class="layui-tree-'+o[options.idField]+'" style="display:inline-block;width: 16px;height: 16px;background:url(';
                  if(isTreeNode){//父节点
                      if(o[table.config.cols.isOpen]){
                          temhtml+=o[table.config.cols.iconOpen];
                      }else{
                          temhtml+=o[table.config.cols.iconClose];
                      }
                  }else{
                      temhtml+=o[table.config.cols.icon];
                  }
                  temhtml+=') 0 0 no-repeat;"></i>';
                  return temhtml;
              }
              if(isTreeNode){//父节点
                  if((o[table.config.cols.iconOpen]||o[table.config.cols.iconClose])){
                      temTreeHtml=temf();
                  }else{
                      temTreeHtml='<i class="layui-icon layui-tree-'+o[options.idField]+' layui-tree-'+ (o[table.config.cols.isOpen] ? "branch" : "leaf") +'" '+iconOpen+'>'+(o[table.config.cols.isOpen]?that.config.branch[1]:that.config.branch[0])+'</i>';
                  }
              }else{//叶子节点
                  if(o[table.config.cols.icon]){
                      temTreeHtml=temf();
                  }else{
                      temTreeHtml+='<i class="layui-icon layui-tree-'+o[options.idField]+' layui-tree-leaf"  '+iconOpen+'>'+that.config.leaf+'</i>';
                  }
              }
              if(isHtml){
                  return temTreeHtml;
              }else{
                  var temdiv=that.layBody.find('tr[data-index="'+ o[table.config.indexName] +'"]').find('td[data-field='+options[TREE_SHOW_NAME]+']').find('.layui-table-cell');
                  $(temdiv).find('div .layui-tree-'+o[options.idField]).remove();//节点附加div
                  $(temdiv).find('div').append(temTreeHtml);
              }
          }else{
              return temTreeHtml;
          }
      }
      //获得数据
      Class.prototype.pullData = function(curr, loadIndex){
          var that = this
              ,options = that.config
              ,request = options.request
              ,response = options.response
              ,sort = function(){
                  if(typeof options.initSort === 'object'){
                      that.sort(options.initSort.field, options.initSort.type);
                  }
              };
          that.startTime = new Date().getTime(); //渲染开始时间
          if(options.url){ //Ajax请求
              var params = {};
              params[request.pageName] = curr;
              params[request.limitName] = options.limit;
              that.filterRulesSet(params);//行内过滤条件
              that.sortSet(params);//排序条件
              $.ajax({
                  type: options.method || 'get'
                  ,url: options.url
                  ,data: $.extend(params, options.where)
                  ,dataType: 'json'
                  ,success: function(res){
                      that.resetDataresetRoot=true;
                      //如果有数据解析的回调，则获得其返回的数据
                      if(typeof options.parseData === 'function'){
                          res = options.parseData(res) || res;
                      }
                      that.resetDatas(res[response.dataName]);
                      res[response.dataName]=table.getDataList(options.id);
                      if(res[response.statusName] != response.statusCode){
                          that.renderForm();
                          that.layMain.html('<div class="'+ NONE +'">'+ (res[response.msgName] || '返回的数据状态异常') +'</div>');
                      } else {
                          that.renderData(res, curr, res[response.countName]);
                          options.time = (new Date().getTime() - that.startTime) + ' ms'; //耗时（接口请求+视图渲染）
                      }
                      loadIndex && layer.close(loadIndex);
                      that.events();
                      typeof options.done === 'function' && options.done(res, curr, res[response.countName]);
  
  
                  }
                  ,error: function(e, m){
                      that.layMain.html('<div class="'+ NONE +'">数据接口请求异常</div>');
                      that.renderForm();
                      loadIndex && layer.close(loadIndex);
                  }
              });
          } else if(options.data && options.data.constructor === Array){ //已知数据
              var res = {},startLimit = curr*options.limit - options.limit
              res[response.dataName] = options.data.concat().splice(startLimit, options.limit);
              res[response.countName] = options.data.length;
              that.renderData(res, curr, options.data.length);
              that.events();
              typeof options.done === 'function' && options.done(res, curr, res[response.countName]);
          }
      };
      /**
       * 设置过滤条件
       */
      Class.prototype.filterRulesSet=function (p) {
          var that = this;
          p["filterRules"]=JSON.stringify(that.filterRules());
      }
      /**
       * 获取过滤条件
       * filterRules:
       * [
       * {"field":"XXXX","op":"equals","value":["1"],"datatype":"array"}
       * ,{"field":"XXXX","op":"contains","value":"3","datatype":"string"}
       * ]
       */
      Class.prototype.filterRules=function () {
          var that = this;
          var filterRules=[];
          //行内过滤条件
          var list=that.layFilter.find("[name^='filter_']");
          layui.each(list,function (i, o) {
              if($(o).val()){
                  var tem={
                      "field":o.name
                      ,"op":"like"
                      ,"value":$(o).val()
                      ,"datatype":"string"
                  }
                  filterRules.push(tem);
              }
          });
          // console.log(filterRules,filterRules.toString(),JSON.stringify(filterRules));
          return filterRules;
      }
  
      //遍历表头
      Class.prototype.eachCols = function(callback){
          var cols = $.extend(true, [], this.config.cols)
              ,arrs = [], index = 0;
  
          //重新整理表头结构
          layui.each(cols, function(i1, item1){
              layui.each(item1, function(i2, item2){
                  //如果是组合列，则捕获对应的子列
                  if(item2.colspan > 1){
                      var childIndex = 0;
                      index++
                      item2.CHILD_COLS = [];
                      layui.each(cols[i1 + 1], function(i22, item22){
                          if(item22.PARENT_COL || childIndex == item2.colspan) return;
                          item22.PARENT_COL = index;
                          item2.CHILD_COLS.push(item22);
                          childIndex = childIndex + (item22.colspan > 1 ? item22.colspan : 1);
                      });
                  }
                  if(item2.PARENT_COL) return; //如果是子列，则不进行追加，因为已经存储在父列中
                  arrs.push(item2)
              });
          });
  
          //重新遍历列，如果有子列，则进入递归
          var eachArrs = function(obj){
              layui.each(obj || arrs, function(i, item){
                  if(item.CHILD_COLS) return eachArrs(item.CHILD_COLS);
                  callback(i, item);
              });
          };
  
          eachArrs();
      };
      /**
       * 渲染节点显示
       * @param callback
       */
      Class.prototype.renderTreeConvertShowName = function(o){
          var that = this
              ,options = that.config
              ,m=options.elem
              ,hasRender = m.next('.' + ELEM_VIEW);
          var temhtml=that.treeConvertShowName(o);
          var temdiv=that.layBody.find('tr[data-index="'+ o[table.config.indexName] +'"]').find('td[data-field='+options[TREE_SHOW_NAME]+']').find('.layui-table-cell');
          $(temdiv).find('div').remove();
          $(temdiv).prepend(temhtml);
      }
      /**
       * 渲染表格单元格样式(宽度样式设置)
       * @param callback
       */
      Class.prototype.renderTdCss = function(){
          var that = this
              ,options = that.config
              ,m=options.elem
              ,hasRender = m.next('.' + ELEM_VIEW);
          var id= that.index+"_"+MOD_NAME+'_td_style';
          hasRender.find("#"+id).remove();
          var styel='<style id="'+id+'">'
              +function () {
                  var ret="";
                  layui.each(that.config.cols,function (i1, item1) {
                      layui.each(item1, function(i2, item2){
                          ret+='.laytable-cell-'+that.index+'-'+(item2.field||i2)+'{' +
                              'width:'+(item2.width?item2.width+"px":"0px")
                              +'}';
                      });
                  });
                  return ret;
              }()+'</style>';
          hasRender.append(styel);
      }
  
      /**
       * 插件内css
       */
      Class.prototype.renderCss = function(){
          var that = this
              ,options = that.config
              ,m=options.elem
              ,hasRender = m.next('.' + ELEM_VIEW);
          var id=that.index+"_"+MOD_NAME+'_style';
          hasRender.find("#"+id).remove();
          var styel='<style id="'+id+'">'
              +function () {
                  var ret=".layui-tree-head{cursor: pointer;}";//树图标点击样式
                  ret+=".layui-table-view {margin:0;}";
                  return ret;
              }()+'</style>';
          hasRender.append(styel);
      }
  
      /**
       * 生成单元格
       * @param obj       行数据
       * @param numbers   下标
       * @param cols      列定义数据
       * @param i3        第几列
       */
      Class.prototype.renderTrUpids=function (obj) {
          var that = this
              ,options = that.config;
          var tree_upid_key=options[TREE_UPID];
          var upids=' upids="'+obj["upIds"]+'" ';
          var u_id=' u_id="'+obj[tree_upid_key]+'" '
          var ret=options.isTree?u_id:'';
          return ret;
      }
      /**
       * 生成单元格
       * @param obj       行数据
       * @param numbers   下标
       * @param cols      列定义数据
       * @param i3        第几列
       */
      Class.prototype.renderTd=function (obj,cols,numbers,i3) {
          var that = this
              ,options = that.config;
          var v=obj[cols.field]==null?'':String(obj[cols.field]);
  
          var field = cols.field || i3, content = v
              ,cell = that.getColElem(that.layHeader, field);
  
          var treeImgHtml='';
          if(options.isTree){
              if(options.treeShowName==cols.field){
                  treeImgHtml=that.treeConvertShowName(obj);
              }
          }
          //td内容
          var td = ['<td data-field="'+ field +'" '+ function(){
              var attr = [];
              if(cols.edit) attr.push('data-edit="'+ cols.edit +'"'); //是否允许单元格编辑
              if(cols.align) attr.push('align="'+ cols.align +'"'); //对齐方式
              if(cols.templet) attr.push('data-content="'+ content +'"'); //自定义模板
              if(cols.toolbar) attr.push('data-off="true"'); //自定义模板
              if(cols.event) attr.push('lay-event="'+ cols.event +'"'); //自定义事件
              if(cols.style) attr.push('style="'+ cols.style +'"'); //自定义样式
              if(cols.minWidth) attr.push('data-minwidth="'+ cols.minWidth +'"'); //单元格最小宽度
              return attr.join(' ');
          }() +'>'
              ,'<div class="layui-table-cell laytable-cell-'+ function(){ //返回对应的CSS类标识
                  var str = (options.index + '-' + field);
                  return cols.type === 'normal' ? str
                      : (str + ' laytable-cell-' + cols.type);
              }() +'">'+treeImgHtml+'<p style="width: auto;height: 100%;">'+ function(){
                  var tplData = $.extend(true, {LAY_INDEX: numbers}, obj);
                  //渲染复选框列视图
                  if(cols.type === 'checkbox'){
                      return tplData[table.config.cols.cheDisabled]?''
                          :'<input type="checkbox" name="layTableCheckbox" value="'+tplData[table.config.indexName]+'" lay-skin="primary" '+ function(){
                          var isCheckName = table.config.cols.isCheckName;
                          //如果是全选
                          if(cols[isCheckName]){
                              obj[isCheckName] = cols[isCheckName];
                              return cols[isCheckName] ? 'checked' : '';
                          }
                          return tplData[isCheckName] ? 'checked' : '';
                      }() +'>';
                  } else if(cols.type === 'numbers'){ //渲染序号
                      return numbers;
                  }else if(cols.type === 'drop'){//下拉框
                      var rowsField=dl.ui.table.drop.findFieldObj(options.cols[0],field);
                      if(rowsField&&rowsField['drop']){
                          var o=dl.cache.code.get(rowsField.drop);
                          return dl.ui.table.drop.findDropLable(rowsField.drop,content);
                      }
                  }else if(cols.type === 'radio'){//单选
                      return tplData[table.config.cols.radDisabled]?''
                          :'<input type="radio" name="'+TABLE_RADIO_ID+options.id+'" '+function () {
                          var isRadio = table.config.cols.isRadio;
                          if(cols[isRadio]){
                              obj[isRadio] = cols[isRadio];
                              return cols[isRadio] ? 'checked' : '';
                          }
                          return tplData[isRadio] ? 'checked' : '';
                      }()+' value="'+tplData[table.config.indexName]+'" title=" ">';
                  }
  
                  //解析工具列模板
                  if(cols.toolbar){
                      return laytpl($(cols.toolbar).html()||'').render(tplData);
                  }
  
                  return cols.templet ? function(){
                      return typeof cols.templet === 'function'
                          ? cols.templet(tplData)
                          : laytpl($(cols.templet).html() || String(content)).render(tplData)
                  }() : content;
              }()
              ,'</p></div></td>'].join('');
          return td;
      }
      /**
       * 生成tr中的一行
       * @param obj            行数据
       * @param numbers          行号
       */
      Class.prototype.renderTr=function (obj,numbers) {
          var that = this
              ,options = that.config;
          var tds= [];
          that.eachCols(function(i3, cols){//cols列定义
              var field = cols.field || i3, content = obj[field];
              if(cols.colspan > 1) return;
              var td = that.renderTd(obj,cols,numbers,i3);//td内容
              tds.push(td);
              // if(item3.fixed && item3.fixed !== 'right') tds_fixed.push(td);
              // if(item3.fixed === 'right') tds_fixed_r.push(td);
          });
          return tds;
      };
      /**
       * 表格数据部分渲染入口
       * @param res
       * @param curr
       * @param count
       * @param sort
       */
      Class.prototype.renderData = function(res, curr, count, sort){
          var that = this
              ,options = that.config
              ,data = res[options.response.dataName] || []
              ,trs = []
              ,trs_fixed = []
              ,trs_fixed_r = []
              //渲染视图
              ,render = function(){ //后续性能提升的重点
                  if(!sort && that.sortKey){
                      return that.sort(that.sortKey.field, that.sortKey.sort, true);
                  }
  
                  layui.each(data, function(i1, obj){
                      var uo=that.treeFindUpData(obj);
                      var display="";
                      if(!obj[table.config.cols.isShow]&&options.isTree){
                          display="display: none;";
                      }
                      var tds = [], tds_fixed = [], tds_fixed_r = []
                          ,numbers = i1 + options.limit*(curr - 1) + 1; //序号
                      if(obj.length === 0) return;
                      if(!sort){
                          obj[table.config.indexName] = i1;
                      }
                      tds=that.renderTr(obj,numbers);
                      trs.push('<tr style="'+display+'" data-index="'+ i1 +'" '+that.renderTrUpids(obj)+'>'+ tds.join('') + '</tr>');
                      trs_fixed.push('<tr data-index="'+ i1 +'">'+ tds_fixed.join('') + '</tr>');
                      trs_fixed_r.push('<tr data-index="'+ i1 +'">'+ tds_fixed_r.join('') + '</tr>');
                  });
                  //if(data.length === 0) return;
                  that.layBody.scrollTop(0);
                  that.layMain.find('.'+ NONE).remove();
                  that.layMain.find('tbody').html(trs.join(''));
                  that.layFixLeft.find('tbody').html(trs_fixed.join(''));
                  that.layFixRight.find('tbody').html(trs_fixed_r.join(''));
                  that.renderForm();
                  that.haveInit ? that.scrollPatch() : setTimeout(function(){
                      that.scrollPatch();
                  }, 50);
                  that.haveInit = true;
                  layer.close(that.tipsIndex);
              };
          that.key = options.id || options.index;
          // table.cache[that.key] = data; //记录数据
          table.setDataList(that.key,data);
          //显示隐藏分页栏
          that.layPage[data.length === 0 && curr == 1 ? 'addClass' : 'removeClass'](HIDE);
          //排序
          if(sort){
              return render();
          }
          if(data.length === 0){
              that.renderForm();
              that.layFixed.remove();
              that.layMain.find('tbody').html('');
              that.layMain.find('.'+ NONE).remove();
              return that.layMain.append('<div class="'+ NONE +'">'+ options.text.none +'</div>');
          }
          render();
          that.renderPage(count);//分页渲染
          //calss加载完成
          table.pushClassIds(options.id,true);
      };
      /**
       * 渲染分页
       */
      Class.prototype.renderPage=function (count) {
          var that = this
              ,options = that.config;
          //同步分页状态
          if(options.isPage){
              options.page = $.extend({
                  elem: 'layui-table-page' + options.index
                  ,count: count
                  ,limit: options.limit
                  ,limits: options.limits || [10,15,20,30,40,50,60,70,80,90]
                  ,groups: 3
                  ,layout: ['prev', 'page', 'next', 'skip', 'count', 'limit']
                  ,prev: '<i class="layui-icon">&#xe603;</i>'
                  ,next: '<i class="layui-icon">&#xe602;</i>'
                  ,jump: function(obj, first){
                      if(!first){
                          //分页本身并非需要做以下更新，下面参数的同步，主要是因为其它处理统一用到了它们
                          //而并非用的是 options.page 中的参数（以确保分页未开启的情况仍能正常使用）
                          that.page = obj.curr; //更新页码
                          options.limit = obj.limit; //更新每页条数
                          that.pullData(obj.curr, that.loading());
                      }
                  }
              }, options.page);
              options.page.count = count; //更新总条数
              laypage.render(options.page);
          }
      };
      /**
       * 过滤区域的渲染
       */
      Class.prototype.renderFilter = function(){
          var that = this
              ,options = that.config
              ,VIEW_CLASS=ELEM_VIEW
              ,index=that.index; //索引
          var v = [];
          v.push('<form method="post"  id="'+options.id+'_filter_form">');
          v.push('<table cellspacing="0" cellpadding="0" border="0" class="layui-table"><thead><tr>');
          layui.each(options.cols,function (i, o) {
              layui.each(o, function(i2, item2){
                  var field=item2.field||i2;
                  var minW=item2.minWidth?"data-minwidth='"+item2.minWidth+"'":"";
                  var rowCols=item2.colspan?'colspan="'+item2.colspan+'"':'';
                  var rowspan=item2.rowspan?'rowspan="'+item2.rowspan+'"':'';
                  var unresize=item2.unresize?'data-unresize="true"':'';
                  v.push('<th data-field="'+field+'"'+minW+rowCols+rowspan +unresize+'>');
                  v.push('<div class="layui-table-cell laytable-cell-'+function () {
                      var tem="";
                      if (item2.colspan > 1) {
                          tem='group';
                      }else{
                          tem=index+"-"+field;
                          if(item2.type !== "normal"){
                              tem+=" laytable-cell-"+item2.type;
                          }
                      }
                      return tem;
                  }()+'">');
                  if(!item2.isFilter||!item2.field){//不开启行内过滤或没有列名
                      v.push('');
                  }else{
                      v.push('<input class="layui-input '+ ELEM_EDIT +'" id="filter_'+item2.field+'" name="filter_'+item2.field+'">');
                  }
                  v.push('</div></th>');
  
              });
          });
          v.push('</tr></thead></table>');
          v.push('</form>');
          return v.join('');
      };
      //找到对应的列元素
      Class.prototype.getColElem = function(parent, field){
          var that = this
              ,options = that.config;
          return parent.eq(0).find('.laytable-cell-'+ (options.index + '-' + field) + ':eq(0)');
      };
      //渲染表单
      Class.prototype.renderForm = function(type){
          form.render(type, 'LAY-table-'+ this.index);
      }
      /**
       * 设置排序参数
       * @param p
       */
      Class.prototype.sortSet=function (p) {
          var that = this;
          var sort=[];
          var cols=that.config.cols[0];
          cols.forEach(function (t) {
              if(t.sortType){
                  var tem={
                     "field":t.field
                      ,"sort":t.sortType
                  }
                  sort.push(tem);
              }
          });
          p.sort=JSON.stringify(sort);
      }
      /**
       * 设置排序字段
       * @param th
       * @param type
       * @param pull
       * @param formEvent
       */
      Class.prototype.sort = function(th, type, pull, formEvent){
          var that = this
              ,field
              ,res = {}
              ,options = that.config
              ,filter = options.elem.attr('lay-filter')
              ,data = table.getDataList(that.key), thisData;
          //字段匹配
          if(typeof th === 'string'){
              that.layHeader.find('th').each(function(i, item){
                  var othis = $(this)
                      ,_field = othis.data('field');
                  if(_field === th){
                      th = othis;
                      field = _field;
                      return false;
                  }
              });
          }
          try {
              var field = field || th.data('field');
              //如果欲执行的排序已在状态中，则不执行渲染
              if(that.sortKey && !pull){
                  if(field === that.sortKey.field && type === that.sortKey.sort){
                      return;
                  }
              }
              var elemSort = that.layHeader.find('th .laytable-cell-'+ options.index +'-'+ field).find(ELEM_SORT);
              //that.layHeader.find('th').find(ELEM_SORT).removeAttr('lay-sort'); //清除其它标题排序状态
              elemSort.attr('lay-sort', type || null);
              that.layFixed.find('th')
          } catch(e){
              return hint.error('Table modules: Did not match to field');
          }
         /* //记录排序索引和类型
          that.sortKey = {
              field: field
              ,sort: type
          };
          if(type === 'asc'){ //升序
          } else if(type === 'desc'){ //降序
              thisData = layui.sort(data, field, true);
          } else { //清除排序
              thisData = layui.sort(data, table.config.indexName);
          }
          */
          var cols=that.getCols(field);
          if(cols){
              cols.sortType=type
          }
      };
      //请求loading
      Class.prototype.loading = function(){
          var that = this
              ,options = that.config;
          if(options.loading && options.url){
              return layer.msg('数据请求中', {
                  icon: 16
                  ,offset: [
                      that.elem.offset().top + that.elem.height()/2 - 35 - _WIN.scrollTop() + 'px'
                      ,that.elem.offset().left + that.elem.width()/2 - 90 - _WIN.scrollLeft() + 'px'
                  ]
                  ,time: -1
                  ,anim: -1
                  ,fixed: false
              });
          }
      };
      //同步选中值状态
      Class.prototype.setCheckData = function(index, checked){
          var that = this
              ,options = that.config
              ,thisData = table.getDataList(that.key);
          if(!thisData[index]) return;
          if(thisData[index].constructor === Array) return;
          thisData[index][table.config.cols.isCheckName] = checked;
      };
      //同步全选按钮状态
      Class.prototype.syncCheckAll = function(){
              var that = this
                  ,options = that.config;
              var list=table.getDataList(that.config.id);
              if(!list)return;
              var temis=true;//全选
              var checkNum=0;//选中的个数
              list.forEach(function (t) {
                  if(!t[table.config.cols.cheDisabled]){
                      if(t[table.config.cols.isCheckName]){
                          var  checkAllElem = that.layBody.find('tr[data-index='+t[table.config.indexName]+']').find('input[name="layTableCheckbox"]');
                          checkAllElem.prop('checked', true);
                          checkNum++;
                      }else{
                          temis=false;
                          var  checkAllElem = that.layBody.find('tr[data-index='+t[table.config.indexName]+']').find('input[name="layTableCheckbox"]');
                          checkAllElem.prop('checked', false);
                      }
                  }
              });
              if(temis){//设置全选
                  var  checkAllElem = that.layHeader.find('input[name="layTableCheckbox"]');
                  checkAllElem.prop('checked', true);
              }
              if(checkNum<(list.length-options.cheDisabledNum)){
                  var  checkAllElem = that.layHeader.find('input[name="layTableCheckbox"]');
                  checkAllElem.prop('checked', false);
              }
          console.time("pullData");
          console.timeEnd("pullData");
  
          that.renderForm('checkbox');
      };
      //获取cssRule
      Class.prototype.getCssRule = function(field, callback){
          var that = this
              ,style = that.elem.find('style')[0]
              ,sheet = style.sheet || style.styleSheet || {}
              ,rules = sheet.cssRules || sheet.rules;
          layui.each(rules, function(i, item){
              if(item.selectorText === ('.laytable-cell-'+ that.index +'-'+ field)){
                  return callback(item), true;
              }
          });
      };
  
      Class.prototype.test = function(){
      }
      /**
       * 窗体变化自适应
       */
      Class.prototype.resize = function(){
          var that = this;
          //根据父窗体高度设置table的高度
          // 1、table自身顶级容器高度（layui-table-view）
          // 2、内容区域高度（layui-table-main）
          that.columnWidthInit();//列宽度计算
          that.tableHeight();//表格高度计算
          that.resizeHeight();//高度控制
          that.resizeWidth();//宽度控制
      };
  
      //动态分配列宽高
      Class.prototype.setArea = function(){
          var that = this;
          that.columnWidthInit();//列宽度计算
          that.tableHeight();//表格高度计算
      };
      /**
       * 列宽度计算
       */
      Class.prototype.columnWidthInit = function(){
          var that = this,
              options = that.config
              ,colNums = 0 //列个数
              ,autoColNums = 0 //自动列宽的列个数
              ,autoWidth = 0 //自动列分配的宽度
              ,countWidth = 0 //所有列总宽度和
              ,cntrWidth = options.width ||function(){ //获取容器宽度
                  //如果父元素宽度为0（一般为隐藏元素），则继续查找上层元素，直到找到真实宽度为止
                  var getWidth = function(parent){
                      var width, isNone;
                      parent = parent || options.elem.parent()
                      width = parent.width();
                      try {
                          isNone = parent.css('display') === 'none';
                      } catch(e){}
                      if(parent[0] && (!width || isNone)) return getWidth(parent.parent());
                      return width;
                  };
                  return getWidth();
              }()-17;
          //统计列个数
          that.eachCols(function(){
              colNums++;
          });
          //减去边框差
          cntrWidth = cntrWidth - function(){
              return (options.skin === 'line' || options.skin === 'nob') ? 2 : colNums + 1;
          }();
  
          //遍历所有列
          layui.each(options.cols, function(i1, item1){
              layui.each(item1, function(i2, item2){
                  var width;
                  if(!item2){
                      item1.splice(i2, 1);
                      return;
                  }
                  that.initOpts(item2);
                  width = item2.width || 0;
                  if(item2.colspan > 1) return;
                  if(/\d+%$/.test(width)){
                      item2.width = width = Math.floor((parseFloat(width) / 100) * cntrWidth);
                  } else if(item2._is_width_dev||!width){ //列宽未填写
                      item2._is_width_dev=true;//采用默认宽度的列
                      item2.width = width = 0;
                      autoColNums++;
                  }
                  countWidth = countWidth + width;
              });
          });
          that.autoColNums = autoColNums; //记录自动列数
          //如果未填充满，则将剩余宽度平分。否则，给未设定宽度的列赋值一个默认宽
          (cntrWidth > countWidth && autoColNums) && (
              autoWidth = (cntrWidth - countWidth) / autoColNums
          );
          layui.each(options.cols, function(i1, item1){
              layui.each(item1, function(i2, item2){
                  var minWidth = item2.minWidth || options.cellMinWidth;
                  if(item2.colspan > 1) return;
                  if(item2.width === 0){
                      item2.width = Math.floor(autoWidth >= minWidth ? autoWidth : minWidth); //不能低于设定的最小宽度
                  }
              });
          });
      };
      /**
       * 重新渲染宽度
       */
      Class.prototype.resizeWidth = function(){
          var that = this;
          that.renderTdCss();
      };
      /**
       * 表格高度计算
       */
      Class.prototype.tableHeight = function(){
          var that = this,
              options = that.config,
              optionsFirst = that.configFirst;
          //确定高度
          if(!table.kit.isNumber(optionsFirst.height)){//如果非固定高度，则计算高度
              var htremove=0;//减去的高度
              if(options.heightRemove&&table.kit.isArray(options.heightRemove)){
                  var htatt=options.heightRemove;
                  htatt.forEach(function (t) {
                      var temh=table.kit.isNumber(t)?t:$(t).outerHeight(true);
                      if(table.kit.isNumber(temh)){
                          htremove+=temh;
                      }
                  });
              }
              //高度铺满：full-差距值
              var th=_WIN.height()-htremove-1;//that.getParentDivHeight(options.id);
              that.fullHeightGap=0;
              if(options.height){
                  if(/^full-\d+$/.test(options.height)){
                      that.fullHeightGap = options.height.split('-')[1];
                  }
              }
              options.height = th - that.fullHeightGap;
          }
      };
      /**
       * 重新渲染高度
       */
      Class.prototype.resizeHeight = function(){
          var that = this
              ,options = that.config
              ,height = options.height, bodyHeight;
          if(height < 135) height = 135;
          that.elem.css('height', height);
          //tbody区域高度
          // bodyHeight = parseFloat(height) - parseFloat(that.layHeader.height()) - 1;//原本代码
          var theader=options.isFilter?76:38;//没有行内过滤区域
          bodyHeight = parseFloat(height) - theader - 1;//###注意：现在写死表头固定高度为38px，即不支持多表头方式（在tab方式下无法获取正确的高度，待处理）
          if(options.toolbar){
              bodyHeight = bodyHeight - that.layTool.outerHeight();
          }
          if(options.isPage){
              bodyHeight = bodyHeight - that.layPage.outerHeight() - 1;
          }
          that.layMain.css('height', bodyHeight);
      };
      //获取滚动条宽度
      Class.prototype.getScrollWidth = function(elem){
          var width = 0;
          if(elem){
              width = elem.offsetWidth - elem.clientWidth;
          } else {
              elem = document.createElement('div');
              elem.style.width = '100px';
              elem.style.height = '100px';
              elem.style.overflowY = 'scroll';
  
              document.body.appendChild(elem);
              width = elem.offsetWidth - elem.clientWidth;
              document.body.removeChild(elem);
          }
          return width;
      };
      //滚动条补丁
      Class.prototype.scrollPatch = function(){
          var that = this
              ,layMainTable = that.layMain.children('table')
              ,scollWidth = that.layMain.width() - that.layMain.prop('clientWidth') //纵向滚动条宽度
              ,scollHeight = that.layMain.height() - that.layMain.prop('clientHeight') //横向滚动条高度
              ,getScrollWidth = that.getScrollWidth(that.layMain[0]) //获取主容器滚动条宽度，如果有的话
              ,outWidth = layMainTable.outerWidth() - that.layMain.width(); //表格内容器的超出宽度
  
          //如果存在自动列宽，则要保证绝对填充满，并且不能出现横向滚动条
          if(that.autoColNums && outWidth < 5 && !that.scrollPatchWStatus){
              var th = that.layHeader.eq(0).find('thead th:last-child')
                  ,field = th.data('field');
              that.getCssRule(field, function(item){
                  var width = item.style.width || th.outerWidth();
                  item.style.width = (parseFloat(width) - getScrollWidth - outWidth) + 'px';
                  //二次校验，如果仍然出现横向滚动条
                  if(that.layMain.height() - that.layMain.prop('clientHeight') > 0){
                      item.style.width = parseFloat(item.style.width) - 1 + 'px';
                  }
                  that.scrollPatchWStatus = true;
              });
          }
          if(scollWidth && scollHeight){
              if(that.elem.find('.layui-table-patch').length<=0){
                  var patchElem = $('<th class="layui-table-patch"><div class="layui-table-cell"></div></th>'); //补丁元素
                  patchElem.find('div').css({
                      width: scollWidth
                  });
                  that.layHeader.eq(0).find('thead tr').append(patchElem);
                  //that.layFilter.find('table thead tr').append(patchElem);
              }
          } else {
              that.layFilter.eq(0).find('.layui-table-patch').remove();
              that.layHeader.eq(0).find('.layui-table-patch').remove();
          }
          //固定列区域高度
          var mainHeight = that.layMain.height()
              ,fixHeight = mainHeight - scollHeight;
          that.layFixed.find(ELEM_BODY).css('height', layMainTable.height() > fixHeight ? fixHeight : 'auto');
          //表格宽度小于容器宽度时，隐藏固定列
          that.layFixRight[outWidth > 0 ? 'removeClass' : 'addClass'](HIDE);
          //操作栏
          that.layFixRight.css('right', scollWidth - 1);
      };
      //事件处理
      Class.prototype.events = function(){
          var that = this
              ,options = that.config
              ,_BODY = $('body')
              ,dict = {}
              ,th = that.layHeader.find('th')
              ,bodytr=that.layBody.find('tr')
              ,resizing;
          //行点击事件
          bodytr.unbind('click').on('click',function (e) {
              var index=$(this).attr("data-index");
              var list=table.getDataList(that.config.id);
              var o=list[index];
              typeof options.onClickRow === 'function' && options.onClickRow(index,o);
          });
          //行双击事件
          bodytr.unbind('dblclick').on('dblclick',function (e) {
              var index=$(this).attr("data-index");
              var list=table.getDataList(that.config.id);
              var o=list[index];
              that.config.onDblClickRow(index,o);
          });
          //拖拽调整宽度
          th.unbind('mousemove').on('mousemove', function(e){
              var othis = $(this)
                  ,oLeft = othis.offset().left
                  ,pLeft = e.clientX - oLeft;
              if(othis.attr('colspan') > 1 || othis.data('unresize') || dict.resizeStart){
                  return;
              }
              dict.allowResize = othis.width() - pLeft <= 10; //是否处于拖拽允许区域
              _BODY.css('cursor', (dict.allowResize ? 'col-resize' : ''));
          })
          th.unbind('mouseleave').on('mouseleave', function(){
              var othis = $(this);
              if(dict.resizeStart) return;
              _BODY.css('cursor', '');
          })
          th.unbind('mousedown').on('mousedown', function(e){
              var othis = $(this);
              if(dict.allowResize){
                  var field = othis.data('field');
                  e.preventDefault();
                  dict.resizeStart = true; //开始拖拽
                  dict.offset = [e.clientX, e.clientY]; //记录初始坐标
  
                  that.getCssRule(field, function(item){
                      var width = item.style.width || othis.outerWidth();
                      dict.rule = item;
                      dict.ruleWidth = parseFloat(width);
                      dict.minWidth = othis.data('minwidth') || options.cellMinWidth;
                  });
              }
          });
          //拖拽中
          _DOC.unbind('mousemove').on('mousemove', function(e){
              if(dict.resizeStart){
                  e.preventDefault();
                  if(dict.rule){
                      var setWidth = dict.ruleWidth + e.clientX - dict.offset[0];
                      if(setWidth < dict.minWidth) setWidth = dict.minWidth;
                      dict.rule.style.width = setWidth + 'px';
                      layer.close(that.tipsIndex);
                  }
                  resizing = 1
              }
          })
          _DOC.unbind('mouseup').on('mouseup', function(e){
              if(dict.resizeStart){
                  dict = {};
                  _BODY.css('cursor', '');
                  that.scrollPatch();
              }
              if(resizing === 2){
                  resizing = null;
              }
          });
          //排序
          th.unbind('click').on('click', function(){//点击标题列
              var othis = $(this)
                  ,elemSort = othis.find(ELEM_SORT)
                  ,nowType = elemSort.attr('lay-sort')
                  ,type;
  
              if(!elemSort[0] || resizing === 1) return resizing = 2;
  
              if(nowType === 'asc'){
                  type = 'desc';
              } else if(nowType === 'desc'){
                  type = null;
              } else {
                  type = 'asc';
              }
              that.sort(othis, type, null, true);
              table.query(that.key);//从新查询
          })
          th.find(ELEM_SORT+' .layui-edge ').unbind('click').on('click', function(e){//点击小三角形
              var othis = $(this)
                  ,index = othis.index()
                  ,field = othis.parents('th').eq(0).data('field')
              layui.stope(e);
              if(index === 0){
                  that.sort(field, 'asc', null, true);
              } else {
                  that.sort(field, 'desc', null, true);
              }
              table.query(that.key);//从新查询
          });
          if(!that.eventsinitIsRun){
              that.eventsinit();
              that.eventsinitIsRun=true;
          }
          //同步滚动条
          that.layMain.unbind('scroll').on('scroll', function(){
              var othis = $(this)
                  ,scrollLeft = othis.scrollLeft()
                  ,scrollTop = othis.scrollTop();
  
              that.layHeader.scrollLeft(scrollLeft);
              that.layFilter.scrollLeft(scrollLeft);
              that.layFixed.find(ELEM_BODY).scrollTop(scrollTop);
  
              layer.close(that.tipsIndex);
          });
          _WIN.unbind('resize').on('resize', function(){ //自适应
              that.resize();
          });
      };
      //事件处理单元格编辑(只执行一次)
      Class.prototype.eventsinitIsRun=false;
      //只执行一次的事件
      Class.prototype.eventsinit = function(){
          var that = this
              ,options = that.config
              ,ELEM_CELL = '.layui-table-cell'
              ,filter = options.elem.attr('lay-filter');
          //行内过滤
          that.layFilter.on('keyup',"[name^='filter_']",function () {
              that.page=1;
              that.pullData(that.page, that.loading());
          });
          //行事件
          that.layBody.on('mouseenter','tr',function(){
              var othis = $(this)
                  ,index = othis.index();
              that.layBody.find('tr:eq('+ index +')').addClass(ELEM_HOVER)
          })
          that.layBody.on('mouseleave','tr', function(){
              var othis = $(this)
                  ,index = othis.index();
              that.layBody.find('tr:eq('+ index +')').removeClass(ELEM_HOVER)
          });
          //单元格事件
          that.layBody.on('click','td div.layui-table-cell p',function(){
              var othis = $(this).parent().parent()
                  ,field = othis.data('field')
                  ,editType = othis.data('edit')
                  ,index = othis.parents('tr').eq(0).data('index')
                  ,data = table.getDataList(that.key)[index]
                  ,elemCell = othis.children(ELEM_CELL);
              var  options = that.config;
              layer.close(that.tipsIndex);
              if(othis.data('off')) return;
  
              //显示编辑表单
              if(editType){
                  if(editType === 'select') { //选择框
                      var dropName=othis.data('drop');
                      var rowsField=dl.ui.table.drop.findFieldObj(options.cols[0],field);
                      var o=dl.cache.code.get(rowsField.drop);
                      var html='';
                      var scv=o.syscodevaluecache;
                      for(var i in scv){
                          var isSelected="";
                          if(scv[i].scv_value==data[field]){
                              isSelected="selected='selected'";
                          }
                          //选中
                          html+='<option '+isSelected+'  value="'+scv[i].scv_value+'">'+scv[i].scv_show_name+'</option>'
                      }
                      var select = $('<select class="'+ ELEM_EDIT +'" lay-ignore>' +
                          html+
                          '</select>');
                      othis.find('.'+ELEM_EDIT)[0] || othis.append(select);
                  } else { //输入框
                      var input = $('<input class="layui-input '+ ELEM_EDIT +'">');
                      input[0].value = $.trim($(this).text());//  othis.data('content') || elemCell.text();
                      othis.find('.'+ELEM_EDIT)[0] || othis.append(input);
                      input.focus();
                  }
                  return;
              }
  
              //如果出现省略，则可查看更多
              var c=that.getCols(field);
  
              if(!table.config.initWidth[c["type"]]){
                  if(elemCell.find('.layui-form-switch,.layui-form-checkbox')[0]) return; //限制不出现更多（暂时）
                  if(Math.round(elemCell.prop('scrollWidth')) > Math.round(elemCell.outerWidth())){
                      that.tipsIndex = layer.tips([
                          '<div class="layui-table-tips-main" style="margin-top: -'+ (elemCell.height() + 16) +'px;'+ function(){
                              if(options.size === 'sm'){
                                  return 'padding: 4px 15px; font-size: 12px;';
                              }
                              if(options.size === 'lg'){
                                  return 'padding: 14px 15px;';
                              }
                              return '';
                          }() +'">'
                          ,elemCell.html()
                          ,'</div>'
                          ,'<i class="layui-icon layui-table-tips-c">&#x1006;</i>'
                      ].join(''), elemCell[0], {
                          tips: [3, '']
                          ,time: -1
                          ,anim: -1
                          ,maxWidth: (device.ios || device.android) ? 300 : 600
                          ,isOutAnim: false
                          ,skin: 'layui-table-tips'
                          ,success: function(layero, index){
                              layero.find('.layui-table-tips-c').on('click', function(){
                                  layer.close(index);
                              });
                          }
                      });
                  }
              }
          });
          that.layBody.on('change','.'+ELEM_EDIT, function(){
              var othis = $(this)
                  ,value = this.value
                  ,field = othis.parent().data('field')
                  ,index = othis.parents('tr').eq(0).data('index')
                  ,data = table.getDataList(that.key)[index];
              data[field] = value; //更新缓存中的值
              layui.event.call(this, MOD_NAME, 'edit('+ filter +')', {
                  value: value
                  ,data: data
                  ,field: field
              });
          });
          that.layBody.on('blur','.'+ELEM_EDIT, function(){//单元格失去焦点
              var templet
                  ,othis = $(this)
                  ,field = othis.parent().data('field')
                  ,index = othis.parents('tr').eq(0).data('index')
                  ,editType = othis.parent().data('edit')
                  ,data = table.getDataList(that.key)[index];
              var  options = that.config;
              that.eachCols(function(i, item){
                  if(item.field == field && item.templet){
                      templet = item.templet;
                  }
              });
              var value="";
              if(editType === 'select') { //选择框
                  var rowsField=dl.ui.table.drop.findFieldObj(options.cols[0],field);
                  if(rowsField&&rowsField['drop']){
                      var o=dl.cache.code.get(rowsField.drop);
                      value=dl.ui.table.drop.findDropLable(rowsField.drop,this.value);
                  }
                  othis.parent().find(ELEM_CELL+' p').html(
                      templet ? laytpl($(templet).html() || value).render(data) : value
                  );
              } else {//输入框
                  othis.parent().find(ELEM_CELL+' p').html(
                      templet ? laytpl($(templet).html() || this.value).render(data) : this.value
                  );
              }
              othis.parent().data('content', this.value);
              othis.remove();
          });
          //树形节点点击事件（隐藏展开下级节点）
          that.elem.on('click','i.layui-tree-head', function(){
              var othis = $(this)
                  ,index = othis.parents('tr').eq(0).data('index')
                  ,options=that.config
                  ,datas=table.getDataList(that.key);//数据
              var o=datas[index];
              that.treeNodeOpen(o,!o[table.config.cols.isOpen]);
              that.resize();
          });
          //复选框选择
          that.elem.on('click','input[name="layTableCheckbox"]+', function(){
              var checkbox = $(this).prev()
                  ,childs = that.layBody.find('input[name="layTableCheckbox"]')
                  ,index = checkbox.parents('tr').eq(0).data('index')
                  ,checked = checkbox[0].checked
                  ,obj=table.getDataList(that.config.id)[index]
                  ,isAll = checkbox.attr('lay-filter') === 'layTableAllChoose';
              //全选
              if(isAll){
                  var list=table.getDataList(that.key);
                  list.forEach(function (temo) {
                      if(!temo[table.config.cols.cheDisabled]){//可以选择的才设置
                          that.setCheckData(temo[table.config.indexName], checked);
                      }
                  });
              } else {
                  that.setCheckData(index, checked);
                  if(options.isTree){
                      //处理下级
                      var sonList=that.treeFindSonData(obj);
                      sonList.forEach(function (temo) {
                          if(!temo[table.config.cols.cheDisabled]){//可以选择的才设置
                              that.setCheckData(temo[table.config.indexName], checked);
                          }
                      });
  
                      //处理上级
                      var temf=function (o) {
                          if(o==null)return;
                          if(o&&o.children.length>0){
                              var temis=true;
                              o.children.forEach(function (temo) {
                                  if(!temo[table.config.cols.isCheckName]){
                                      temis=false;
                                  }
                              });
                              if(temis){
                                  that.setCheckData(o[table.config.indexName], checked);
                              }
  
                              var temuo=that.treeFindUpData(o);
                              if(temuo){
                                  temf(temuo);
                              }
                          }
                      }
                      var uo=that.treeFindUpData(obj);
                      temf(uo);
                  }
              }
              that.syncCheckAll();
              layui.event.call(this, MOD_NAME, 'checkbox('+ filter +')', {
                  checked: checked
                  ,data: table.getDataList(that.key) ? (obj || {}) : {}
                  ,type: isAll ? 'all' : 'one'
              });
          });
          //工具条操作事件
          that.layBody.on('click', '*[lay-event]',function(){
              var othis = $(this)
                  ,index = othis.parents('tr').eq(0).data('index')
                  ,tr = that.layBody.find('tr[data-index="'+ index +'"]')
                  ,ELEM_CLICK = 'layui-table-click'
                  ,list = table.getDataList(that.key)
                  ,data = table.getDataList(that.key)[index];
              layui.event.call(this, MOD_NAME, 'tool('+ filter +')', {
                  data: data//table.clearCacheKey(data)
                  ,event: othis.attr('lay-event')
                  ,tr: tr
                  ,del: function(){
                      table.delRow(options.id,data);
                  }
                  ,update: function(fields){
                      fields = fields || {};
                      layui.each(fields, function(key, value){
                          if(key in data){
                              var templet, td = tr.children('td[data-field="'+ key +'"]');
                              data[key] = value;
                              that.eachCols(function(i, item2){
                                  if(item2.field == key && item2.templet){
                                      templet = item2.templet;
                                  }
                              });
                              td.children(ELEM_CELL).html(
                                  templet ? laytpl($(templet).html() || value).render(data) : value
                              );
                              td.data('content', value);
                          }
                      });
                  }
              });
              tr.addClass(ELEM_CLICK).siblings('tr').removeClass(ELEM_CLICK);
          });
      }
      //表格重载
      thisTable.config = {};
      //自动完成渲染
      table.init();
      // layui.link('treeGrid.css');
      exports(MOD_NAME, table);
  });