基于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函数删除该节点,然后重新渲染树。

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