基於layui的查詢條件樹

1、想要實現一個自由組合查詢條件的功能,給不會寫SQL語句的人使用。比如生成的查詢條件樹如下圖:

它表達的查詢條件是:( 1=1    AND ATTACK_TIMES > 8   OR ( ATTACK_SOURCE = 外網   AND ATTACK_TYPE = SHELL腳本  ) )

2、分析這個需求,核心是父節點和其子節點要作爲一個整體條件:

(1)根節點的默認條件是1=1,如果沒有子節點,查詢條件就是1=1;

(2)在根節點下添加一個節點:AND 攻擊次數 大於8,查詢條件變爲:1=1 and attack_times>8;(節點的數據包括哪些屬性,後邊再說)

(3)在根節點下再增加一個節點:OR 攻擊來源 等於外網,查詢條件變爲:1=1 and attck_times>8 or attack_src='外網';

(4)在OR 攻擊來源 等於外網這個節點下添加一個節點:AND攻擊類型 等於SHELL腳本,則OR這節點的整體條件爲:or( attack_src='外網' and attack_type='SHELL腳本'),整棵樹表示的條件是:( 1=1    AND ATTACK_TIMES > 8   OR ( ATTACK_SOURCE = 外網   AND ATTACK_TYPE = SHELL腳本  ) )

3、因爲節點可以無限添加,則可以據此構造任何查詢條件。下面說一下節點數據的結構,

(1)id:'0101' id的主要功能,是記住當前選擇的節點,後續的添加、修改或刪除操作,都要用到這個值;

(2)name:'AND 攻擊次數 大於8' name主要用於顯示節點,就是我要看到的節點名字;

(3)cron:' and attack_times >8' cron表示的是當前節點的查詢條件,如果name屬性的值和cron相同,則可以不要這個屬性;

(4)children:[{}] children用來表示當前節點的子節點。

4、整棵樹的數據結構是一個無限嵌套的json數組。初始的數據結構爲:

var nodeData = [
      {
       name: '根節點'
       ,id: '01'
       ,cron: ' 1=1 '
       ,children: []
      }
    ];

初始化樹的方法是:

layui.use(['form','tree', 'layer'], function(){
  var layer = layui.layer
  ,$ = layui.jquery; 
  var form = layui.form;
  var tree = layui.tree;
  
  layui.tree({
    elem: '#demo1' //指定元素
    ,click: function(obj){
      nodeSelect(obj);
    }
    ,showLine: true
    ,target: '_blank' 
    ,nodes: nodeData
  });
});

nodeSelect函數的功能是記住當前節點的id值,並設置節點的選中效果,具體代碼如下:

function nodeSelect(obj){
  selectedNodeId = obj.id;
  var citeArr = $("cite");
  $(".tree-txt-active").removeClass("tree-txt-active");
      for(var i=0;i<citeArr.length;i++){
      	if($(citeArr[i]).html() == obj.name){
      		$(citeArr[i]).attr('class','tree-txt-active');
      		return false;
      	}
      }
}

selectedNodeId是全局變量,tree-txt-active是選中節點的樣式,自己隨意定義,我這裏只定義了一個顏色,用於和沒有選中的節點進行區分。

這裏有一個問題,就是layui的樹節點點擊事件,拿到的是該節點的數據,不是節點對象本身。上邊的函數是根據選中節點的name值和樹節點中cite元素的文本值進行對比,相同就認爲是選中的節點。如果有兩個節點的名稱一樣,則不能保證設爲選中樣式的節點,就是真實選中的節點(選中節點的數據,是真實選中的數據)。嚴謹的做法是,根據選中節點的數據在nodeData的層次位置,來找到樹對應的層次位置的名稱相同的節點。

5、樹的增刪改操作

操作按鈕如下圖:

(1)新增:

var isNew = false;
function add(){
 if(selectedNodeId == ''){
 	layer.msg('請選擇一個節點');
 	return false;
 }
 isNew = true;
 $('#cond1').show();
 
 $('#logicOp').val("AND");
 $('#field').val("");
 $('#opType').val("");
 $('#val').val("");	 
}

cond1是一個用於編輯節點屬性的div,大概張這樣:

第一個下拉框是選中and或or邏輯關係,第二個是實體屬性的顯示名稱和數據庫列名,第三個是邏輯符號,如大於、小於、等於、介於、包含(於)等,最後一個是條件的值。點擊“確定”按鈕,則把新節點的數據更新到全局變量nodeData中,然後重新渲染樹。新增函數代碼如下:

function saveNode(){
//取值
	var logicOp = $('#logicOp').val();
	var fieldName = $("#field").find("option:selected").text();
	var fieldVal = $('#field').val();
	var opName = $("#opType").find("option:selected").text();
	var opVal = $('#opType').val();
	var val = $('#val').val();
//處理包含於、包含和介於運算符
	if(opVal == 'in' || opVal == 'like' || opVal == 'between'){
     	val = getSeveralVal(opVal,val);
    }
//	layer.msg(fieldName+',' +fieldVal+',' +opName+',' +opVal+',' +val + ',selectedNodeId:' + selectedNodeId);
//根據節點id找到父節點數據
	parentNode = getNode(selectedNodeId,nodeData);
//找到父節點下最大的子節點id值
	maxChildId = getMaxChildId(selectedNodeId,parentNode);
//設置新節點的id(每層兩位,值遞增)
	childNodeId = '';
	if(maxChildId == ''){
		childNodeId = selectedNodeId + '01';	
	}else{
		var tmpId = Number(maxChildId) +1;
		childNodeId = selectedNodeId +(tmpId>9?tmpId:('0'+ tmpId));
	}
//將新節點數據添加到全局變量nodeData中
	addNode(selectedNodeId,nodeData,{id:childNodeId,name:logicOp + fieldName + " " + opName + val,children:[],cron: '' + logicOp + ' ' + fieldVal + ' ' + opVal + ' ' + val});
//根據nodeData生成查詢表達式
	geneCron();
//隱藏編輯div
	$('#cond1').hide();
//清空樹
	$("#demo1").find("li").remove();
//重新渲染樹
	layui.tree({
    elem: '#demo1' //指定元素
    ,click: function(obj){
      nodeSelect(obj);
    }
    ,showLine: true
    ,target: '_blank' 
    ,nodes: nodeData
 	 });
}

(2)修改

點擊修改按鈕,先獲取選中節點的數據,然後將數據填充到條件編輯頁面,修改保存後,將新的查詢條件數據更新到nodeData,再重新渲染樹。

(3)刪除

點擊刪除按鈕,根據選中節點,遍歷nodeData,找到對應的節點後,通過splice函數刪除該節點,然後重新渲染樹。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章