`
uule
  • 浏览: 6352265 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

自定义树Tree

 
阅读更多

本例是jQueryEasyUi中datagrid的树形展示,包含上下移动,编辑等。

可以主要看树形的部分。

 

Bean:

package com.zte.soa.demo.model;

import java.util.List;

public class Tree {
	
	private Long id;
	private Long pid;
	private List<Tree> children;

	private String attribute1;
	private String attribute2;
	private String attribute3;
	private String attribute4;
	private String attribute5;
	private String attribute6;
	private String attribute7;
	private String attribute8;
	private String attribute9;  //serviceId
	
	private Long treeIndex;  //treeIndex
	
	//临时Id、Pid,操作时取该字段
	private String idStr;
	private String pidStr;
	
	...
	
}

 

package com.zte.soa.demo.model;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import com.zte.soa.util.JsonDateSerializer;

/**
 * 类 编 号:
 * 类 名 称: EipServiceParameter
 * 内容摘要: 
 * 完成日期: 
 * 编码作者:
*/
@Entity
@Table(name = "eip_service_parameter")
public class EipServiceParameter  implements Serializable
{

	/**
	 * 
	 */
	private static final long serialVersionUID = -3159405932590138034L;

	@Id
	@SequenceGenerator(name = "EIP_SERVICE_PARAMETER_S", sequenceName = "EIP_SERVICE_PARAMETER_S", initialValue = 1, allocationSize = 1)
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="EIP_SERVICE_PARAMETER_S")
	@Column(name = "ID", nullable = false)
	protected java.lang.Long  id;
	
	@Column(name = "SERVICE_VERSION_ID")
	protected Long serviceId;
	
	@Column(name = "PARAMETER_NAME_CH", nullable = false)
	protected java.lang.String  parameterNameCh;
	
	@Column(name = "PARAMETER_NAME_EN", nullable = false)
	protected java.lang.String  parameterNameEn;
	
	@Column(name = "REMARK", nullable = true)
	protected java.lang.String  remark;
	
	@Column(name = "PARAMETER_TYPE", nullable = true)
	protected java.lang.String  parameterType;
	
	@Column(name = "DATA_TYPE", nullable = false)
	protected java.lang.String  dataType;
	@Column(name = "DATA_TYPE_LENGTH")
	protected java.lang.Long  dataTypeLength;
	@Column(name = "BELONG_FLAG", nullable = false)
	protected java.lang.String  belongFlag;
	@Column(name = "PARAM_CONSTRAINT", nullable = true)
	protected java.lang.String  constraint;
	
	@Column(name = "PARENT_PARAMETER_ID")
	protected java.lang.Long  parentParameterId;
   
	@Column(name = "CREATED_BY")
	protected java.lang.Long  createdBy;
	
	@Column(name = "CREATION_DATE")
	@Temporal(TemporalType.DATE)
	@JsonSerialize(using=JsonDateSerializer.class)
	protected java.util.Date  creationDate;

    @Column(name = "LAST_UPDATED_BY", nullable = false)
    protected java.lang.Long lastUpdateBy;

    @Column(name = "LAST_UPDATE_LOGIN", nullable = false)
    protected java.lang.Long lastUpdateLogin;

    @Column(name = "LAST_UPDATE_DATE", nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    @JsonSerialize(using = JsonDateSerializer.class, include = JsonSerialize.Inclusion.NON_NULL)
    protected java.util.Date lastUpdateDate;

    @Column(name = "ENABLED_FLAG", length = 1)
    protected java.lang.String enabledFlag;
    
    @Column(name = "TREE_INDEX")
	protected java.lang.Long  treeIndex;
    ...	
}

 

Java:

package com.zte.soa.demo.controller.json;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.zte.soa.demo.model.EipServiceParameter;
import com.zte.soa.demo.model.EipUser;
import com.zte.soa.demo.model.Tree;
import com.zte.soa.demo.model.User;
import com.zte.soa.demo.service.EipServiceParmService;
import com.zte.soa.demo.service.EipServiceService;
import com.zte.soa.demo.service.EipUserService;
import com.zte.soa.demo.service.UserService;

@Controller
public class UserController {

	@Autowired
	protected EipServiceParmService eipServiceParmService;
	
	
	public static <T> T fromJson(String json, Class<T> valueType){
		ObjectMapper mapper = new ObjectMapper();
		try {
			return mapper.readValue(json, valueType);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	public static String toJson(Object obj){
		String json = "";
		ObjectMapper mapper = new ObjectMapper();
		try {
			StringWriter writer = new StringWriter();
			JsonGenerator generator = mapper.getJsonFactory().createJsonGenerator(writer);
			mapper.writeValue(generator, obj);
			json = writer.toString();
			generator.close();
			writer.close();			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return json;
	}
	
	
	public EipServiceParameter getOriginalData(Tree t1){
		EipServiceParameter p = new EipServiceParameter();
		p.setParentParameterId(Long.parseLong(t1.getPidStr()));
		p.setParameterNameCh(t1.getAttribute1());
		p.setParameterNameEn(t1.getAttribute2());
		p.setDataType(t1.getAttribute3());
		Long dataTypeLen = StringUtils.isBlank(t1.getAttribute4()) || t1.getAttribute4().equals("null") ? 0 : Long.parseLong(t1.getAttribute4());
		p.setDataTypeLength(dataTypeLen);
		p.setBelongFlag(t1.getAttribute5());
		p.setConstraint(t1.getAttribute6());
		p.setParameterType(t1.getAttribute7());
		p.setRemark(t1.getAttribute8());
		p.setServiceId(Long.parseLong(t1.getAttribute9()));
		p.setTreeIndex(t1.getTreeIndex());
		
		p.setCreatedBy(1l);
		p.setCreationDate(new Date());
		p.setLastUpdateBy(1l);
		p.setLastUpdateDate(new Date());
		p.setLastUpdateLogin(1L);
		p.setEnabledFlag("Y");
		p = eipServiceParmService.save(p);
		return p;
	}
	
	public Boolean checkIsBlankAppend(Map map ){
		if(StringUtils.isBlank(String.valueOf(map.get("attribute1"))) &&
				StringUtils.isBlank(String.valueOf(map.get("attribute2"))) &&	
				StringUtils.isBlank(String.valueOf(map.get("attribute3"))) &&	
				StringUtils.isBlank(String.valueOf(map.get("attribute4"))) &&	
				StringUtils.isBlank(String.valueOf(map.get("attribute5")))		
			)
			return true;
		
		return false;
	}
	
	public List<Tree> changeDataType(List<HashMap> list){
		List<Tree> treeList = new ArrayList<Tree>();
		for(Map map : list){
			if(checkIsBlankAppend(map)) continue; //忽略空白添加
			Tree t = new Tree();
			String idStr = String.valueOf(map.get("id"));
			String pidStr = String.valueOf(map.get("pid"));
			//t.setId(idStr.startsWith("copy") ? 0l : Long.parseLong(idStr));
			//t.setPid(pidStr.startsWith("copy") ? 0l : Long.parseLong(pidStr));
			t.setAttribute1(String.valueOf(map.get("attribute1")));
			t.setAttribute2(String.valueOf(map.get("attribute2")));
			t.setAttribute3(String.valueOf(map.get("attribute3")));
			t.setAttribute4(String.valueOf(map.get("attribute4")));
			t.setAttribute5(String.valueOf(map.get("attribute5")));
			t.setAttribute6(String.valueOf(map.get("attribute6")));
			t.setAttribute7(String.valueOf(map.get("attribute7")));
			t.setAttribute8(String.valueOf(map.get("attribute8")));
			t.setAttribute9(String.valueOf(map.get("attribute9")));
			t.setIdStr(idStr);
			t.setPidStr(pidStr);
			t.setTreeIndex(Long.parseLong(String.valueOf(map.get("treeIndex"))));
			treeList.add(t);
		}
		return treeList;
	}
	
	/*
	 * 需要添加的都为新增节点,id都是如copy1000这种临时Id
	 * 添加需要一个一个保存到数据库,因为可能新增的节点他的父节点也是新增的,需要得到真实的父节点Id
	 */
	public void insertData(List<Tree> insertedList , Map<String,Long> copyIdsMap){
		System.out.println();
		//先保存父节点是真实节点的数据,保存后从List中删除
		for(int i = insertedList.size() - 1 ; i >= 0 ;i--){
			Tree t1 = insertedList.get(i);
			String copyId = t1.getIdStr();
			String pid = t1.getPidStr();
			//父节点也是新增的
			if(pid.startsWith("copy")) continue; 
			EipServiceParameter p = getOriginalData(t1);
			insertedList.remove(t1);
			copyIdsMap.put(copyId, p.getId());  //收集新增节点的真实Id,以备其他父节点是临时Id的节点使用
		}
		//再递归保存父节点是临时节点的数据
		for(int i = insertedList.size() - 1 ; i >= 0 ;i--){
			Tree t = insertedList.get(i);
			String copyId = t.getIdStr();
			String pid = t.getPidStr();
			if(copyIdsMap.containsKey(pid)){
				Long id = copyIdsMap.get(pid); //获取真实Id
				t.setPidStr(String.valueOf(id));
				EipServiceParameter p = getOriginalData(t);
				insertedList.remove(t);
				copyIdsMap.put(copyId, p.getId()); 
			}else{
				insertData(insertedList,copyIdsMap); //递归获取id
			}
		}
		
	}
	
	
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/json/saveTreeGridData.json")
	@ResponseBody
	public Map<String, Object> saveTreeGridData(@RequestParam String treeGridData) {
		Map map = fromJson(treeGridData,Map.class);
		List<HashMap> insertedList = (List<HashMap>) map.get("inserted"); 
		List<HashMap> updatedList = (List<HashMap>) map.get("updated"); 
		List<HashMap> deletedList = (List<HashMap>) map.get("deleted"); 
		
		List<EipServiceParameter> updList = new ArrayList<EipServiceParameter>();
		List<EipServiceParameter> delList = new ArrayList<EipServiceParameter>();
		
		//添加
		Map<String,Long> copyIdsMap = new HashMap<String,Long>();
		insertData(changeDataType(insertedList),copyIdsMap);
		
		System.out.println();
		//更新
		for(Tree t : changeDataType(updatedList)){
			Long id = Long.parseLong(t.getIdStr());
			EipServiceParameter p = eipServiceParmService.getById(id);
			p.setParentParameterId(Long.parseLong(t.getPidStr()));
			p.setParameterNameCh(t.getAttribute1());
			p.setParameterNameEn(t.getAttribute2());
			p.setDataType(t.getAttribute3());
			Long dataTypeLen = StringUtils.isBlank(t.getAttribute4()) || t.getAttribute4().equals("null") ? 0 : Long.parseLong(t.getAttribute4());
			p.setDataTypeLength(dataTypeLen);
			p.setBelongFlag(t.getAttribute5());
			p.setConstraint(t.getAttribute6());
			p.setParameterType(t.getAttribute7());
			p.setRemark(t.getAttribute8());
			p.setServiceId(Long.parseLong(t.getAttribute9()));
			p.setTreeIndex(t.getTreeIndex());
			updList.add(p);
		}	
		eipServiceParmService.batchUpdate(updList);
		//删除
		for(Tree t : changeDataType(deletedList)){
			Long id = Long.parseLong(t.getIdStr());
			EipServiceParameter p = eipServiceParmService.getById(id);
			delList.add(p);
		}
		eipServiceParmService.batchDelete(delList);
		
		return null;
	}
	

	//入口方法
	@RequestMapping(value = "/json/getTreeGridData.json")
	@ResponseBody
	public Map<String, Object> getTreeGridData() {
	
		List<Tree> lt = new ArrayList<Tree>();
		String paramHql = " from EipServiceParameter pt where 1 = 1 and pt.serviceId = 492 order by pt.treeIndex desc";
		List<EipServiceParameter> paramList = eipServiceParmService.findByHql(paramHql);
		buildTreeData(paramList,lt);
		//展示树
		List<Tree> topTree = buildTree(lt);
		Map<String,Object> map = new HashMap<String,Object>();
		map.put("total", topTree.size());
		map.put("rows", topTree);
		
		return map;
	}
	
	
	//转换树数据
	private void buildTreeData(List<EipServiceParameter> paramList, List<Tree> lt) {
		long i = 0;
		if(paramList.get(0).getTreeIndex() == null){ //首次进入初始化更新全部TreeIndex
			for(EipServiceParameter p : paramList){
				p.setTreeIndex(i);
				i++;
			}
			eipServiceParmService.batchUpdate(paramList); 
		}
		
		
		for(EipServiceParameter p : paramList){
			Tree t = new Tree();
			t.setId(p.getId());
			t.setPid(p.getParentParameterId());
			t.setAttribute1(p.getParameterNameCh());
			t.setAttribute2(p.getParameterNameEn());
			t.setAttribute3(p.getDataType());
			t.setAttribute4(String.valueOf(p.getDataTypeLength()));
			t.setAttribute5(p.getBelongFlag());
			t.setAttribute6(p.getConstraint());
			t.setAttribute7(p.getParameterType());
			t.setAttribute8(p.getRemark());
			t.setAttribute9(String.valueOf(p.getServiceId()));
			t.setTreeIndex(p.getTreeIndex());
			lt.add(t);
		}
	}

	//构建树根
	public List<Tree> buildTree(List<Tree> data){
		List<Tree> topTree = new ArrayList<Tree>();
		for(int i = data.size() - 1 ; i >= 0 ;i--){
			Tree t = data.get(i);
			
			Long pid = t.getPid();
			if(pid == -1){
				topTree.add(t);
				data.remove(t);
			}
		}
		
		for(Tree top : topTree){
			buildBranchTree(top, data);
		}
		
		return topTree;
	}
	
	//构建树的子节点
	public void buildBranchTree(Tree parent , List<Tree> data){
		for(int i = data.size() - 1 ; i >= 0 ;i--){  //倒叙,否则remove后List会有问题
			Tree t = data.get(i);
			if(parent.getId() - 544  == 0 && t.getId() - 545 == 0){
				System.out.println();
			}
			if(parent.getId() - t.getPid() == 0){
				if(null == parent.getChildren())
					parent.setChildren(new ArrayList<Tree>());
				
				parent.getChildren().add(t);
				data.remove(t);
			}
		}
		
		if(data.size() == 0) return;
		if(null != parent.getChildren()){
			for(Tree branch : parent.getChildren()){
				buildBranchTree(branch, data);
			}
		}
		
	}	
	
	
	
}

 JSP:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>表格查询</title>
		<%@include file="/taglibs.jsp"%>
		<script type="text/javascript" src="treegrid_data.json"></script>
		<style>
			.tree-collapsed {
			    margin-left: 12px;
			}
			
			.tree-collapsed-hover {
			    background: url("js/jquery-easyui/themes/default/images/tree_arrows.gif") no-repeat scroll 0 0 transparent;
			}
			
			.tree-expanded {
			    margin-left: 12px;
			}
			.tree-expanded-hover {
			    background: url("js/jquery-easyui/themes/default/images/tree_arrows.gif") no-repeat scroll -18px 0 transparent;
			}
			
			.tree-folder-open {
			    background: none;
			}
			.tree-folder {
			    background: none;
			    width: 4px;
			}
		</style>
		
		<script type="text/javascript">
		
		var lastIndex;  //结束编辑的上一行用到
		var codeIndex = 1000;  //临时Id起始值
		
		var insertRows = [];
		var updateRows = [];
		var deleteRows = [];
		
		//编辑时选项下拉框数据
		var belongFlag = [
		      {type:'Y',typeName:'是'},
		      {type:'N',typeName:'否'}
		  ];
		  
		var dataType = [
			{type:'VARCHAR2'},
			{type:'TIMESTAMP'},
			{type:'NVARCHAR2'},
			{type:'NUMBER'},
			{type:'LONG'},
			{type:'BLOB'},
			{type:'CLOB'},
			{type:'DATE'}
		]; 
		
	(function($) {  
        $.extend($, {  
            //获取下标,删除时使用
            getArrayIndex :  function (array,value) {
				var index = -1;
				var length = array.length;
				for (var i = 0; i < length; i++) {
					if (array[i].id == value.id) {
						index = i;
						break;
					}
				}
				return index;
			} ,
			removeValue : function (array,value){
				var index = $.getArrayIndex(array,value);
				if(index < 0) return array;
				array.splice(index,1);
				return array;
			}
        });  
    })(jQuery); 
		
	$(function() {	
		$('#test').treegrid({   
		    url:"json/getTreeGridData.json", 
		    idField:'id',
            treeField:'id',
            animate: true,  
            checkbox:true,
            singleSelect:true,		
            checkOnSelect:true,  
            selectOnCheck:true,  
            toolbar: '#toolbar',
           /* frozenColumns: [[{
	            title: '参数中文名',
	            field: 'attribute1',
	            width: 200,
	            align:'left',
	            editor:'text'
	        }]],*/
		    columns:[[    
		        {field:'id',title:'id',width:300},   
		        {field:'pid',title:'pid',width:100,align:'right'},  
		        {field:'treeIndex',title:'行位置标记',hidden:false},  
		        {field:'attribute1',title:'参数中文名',width:200,align:'left',editor:'text'},   
		        {field:'attribute2',title:'参数英文名',width:200,align:'right',editor:'text'},   
		        {field:'attribute3',title:'数据类型',width:200,align:'right',
		        	formatter:function(value){  
	                    for(var i=0; i<dataType.length; i++){  
	                        if (dataType[i].type == value) return dataType[i].type;  
	                    }  
	                    return value;  
	                },  
	                editor:{  
	                    type:'combobox',  
	                    options:{  
	                        valueField:'type',  
	                        textField:'type',  
	                        data:dataType,  
	                        required:true
	                    }  
	                } 
		        },   
		        {field:'attribute4',title:'数据长度',width:200,align:'right',editor:'text'},   
		        {field:'attribute5',title:'是否必填',width:200,align:'right',
		        	formatter:function(value){  
	                    for(var i=0; i<belongFlag.length; i++){  
	                        if (belongFlag[i].type == value) return belongFlag[i].typeName;  
	                    }  
	                    return value;  
	                },  
	                editor:{  
	                    type:'combobox',  
	                    options:{  
	                        valueField:'type',  
	                        textField:'typeName',  
	                        data:belongFlag,  
	                        required:true 
	                    }  
	                }  
		        
		        },   
		        {field:'attribute6',title:'约束',width:200,align:'right',editor:'text'},  
		        {field:'attribute7',title:'参数类型',width:200,align:'right',editor:'text',hidden:true},  
		        {field:'attribute8',title:'备注',width:200,align:'right',editor:'text'},  
		        {field:'attribute9',title:'服务Id',width:200,align:'right',editor:'text',hidden:true}
		    ]],
		    onLoadSuccess:function(data){
            	//alert(data);
            	//drag();
        	},
		    onLoadError:function(data){
            	alert("1:"+data);
        	},
        	onClickRow: function(row) { //运用单击事件实现一行的编辑结束,在该事件触发前会先执行onAfterEdit事件
	            var rowIndex = row.id;
	            if (lastIndex != rowIndex) {
	                $('#test').treegrid('endEdit', lastIndex);
	            }
	        },
	        onDblClickRow: function(row) { //运用双击事件实现对一行的编辑
	            var rowIndex = row.id;
	            if (lastIndex != rowIndex) {
	                $('#test').treegrid('endEdit', lastIndex);
	                $('#test').treegrid('beginEdit', rowIndex);
	                lastIndex = rowIndex;
	            }else{
	            	$('#test').treegrid('beginEdit', lastIndex);
	            }
	        },
	        onBeforeEdit: function(row) {
	           // beforEditRow(row); //这里是功能实现的主要步骤和代码
	        },
	        onAfterEdit: function(row, changes) {
	        	if(!checkExist(updateRows,row)){
		        	updateRows[updateRows.length] = row;
	        	}
	            var rowId = row.id;
	            $.ajax({
	                url: "",
	                data: row,
	                success: function(text) {
	                    //$.messager.alert('提示信息', text, 'info');
	                }
	            });
	        }
		});  
		setTimeout(collapseAll,1000);
		setTimeout(toolbar,1000);
	});
	
	//将工具条从默认位置移到下方
	function toolbar(){
		var bar = $("#toolbar").html();
		var toolbarTitle = "<div id='toolbar' class='datagrid-toolbar'>";
		var toolbar = toolbarTitle + bar + "</div>";
		$(".datagrid-view").prev().remove();
		$(".datagrid-view").parent().append(toolbar);
	}
	
	//拖动drag和drop都是datagrid的头的datagrid-cell
    function drag() {
        $('.datagrid-row').draggable({
            revert: true,
            proxy: 'clone'
        }).droppable({
            accept: '.datagrid-row',
            onDrop: function (e, source) {
                //取得拖动源的html值
                var src = $(e.currentTarget.innerHTML).html();
                //取得拖动目标的html值
                var sou = $(source.innerHTML).html();
                var tempcolsrc;//拖动后源和目标列交换
                var tempcolsou;
                var tempcols=[];
                for (var i = 0; i < cols.length; i++) {
                    if (cols[i].title == sou) {
                        tempcolsrc = cols[i];//循环读一遍列把源和目标列都记下来
                    }
                    else if (cols[i].title == src) {
                        tempcolsou = cols[i];
                    }
                }
                for (var i = 0; i < cols.length; i++) {
                    //再循环一遍,把源和目标的列对换
                    var col = {
                        field: cols[i].field,
                        title: cols[i].title,
                        align: cols[i].align,
                        width: cols[i].width
                    };
                    if (cols[i].title == sou) {
                        col = tempcolsou;
                    }
                    else if (cols[i].title == src) {
                        col = tempcolsrc;
                    }
                     tempcols.push(col);  
                }
                 cols = tempcols;
                 //1秒后执行重绑定datagrid操作。可能是revert需要时间,这边如果没有做延时就直接重绑 就会出错。
                 //我目前的水平就想到这个笨办法,各位如果有好的想法建议可以提出来讨论下。
                timeid = setTimeout("init()", 1000);
            }
        });
    }
		
	
	function beforEditRow(row){
	     
    }
	
	
	
	function checkExist(array,node){
		var id = node.id;
		var flag = false;
		for(var i = 0;i<array.length; i++){
			var row = array[i];
			if(row.id == id){
				flag = true;
				break; //中断循环
			}
		}
		return flag;
	}
	/*
	function checkInsertExist(array,node){
		return checkExist(insertRows,node);
	}
	function checkUpdateExist(node){
		return checkExist(updateRows,node);
	}*/
	
	function saveChanges(){
		if (lastIndex != undefined) {
			$('#test').treegrid('endEdit', lastIndex);
		}
	
		var s = $('#test').treegrid('getChanges');
       	/*var insertRows = $('#test').datagrid('getChanges','inserted');
		var updateRows = $('#test').datagrid('getChanges','updated');
		var deleteRows = $('#test').datagrid('getChanges','deleted');
		*/
		//updateRows = $('#test').treegrid('getChanges','updated');
		for(var i = updateRows.length - 1 ;i>=0 ;i--){
			var nod = updateRows[i];
			if(checkExist(insertRows,nod)){ //该项是新增的,删除更新组数据和新增组中老数据,将新数据添加到新增组中
				//$.removeValue(insertRows,nod); //删除添加组中老数据,替换新数据
				$.removeValue(updateRows,nod);  //新增组中会自动获取到最新数据,因此不用删除老数据即可。
				//insertRows[insertRows.length] = nod;
			}
		}

		
		var changesRows = {
  				inserted : [],
  				updated : [],
  				deleted : [],
   		};
		if (insertRows.length>0) {
			for (var i=0;i<insertRows.length;i++) {
				changesRows.inserted.push(insertRows[i]);
			}
		}

		if (updateRows.length>0) {
			for (var k=0;k<updateRows.length;k++) {
				changesRows.updated.push(updateRows[k]);
			}
		}
		
		if (deleteRows.length>0) {
			for (var j=0;j<deleteRows.length;j++) {
				changesRows.deleted.push(deleteRows[j]);
			}
		}

		//alert(JSON.stringify(changesRows));

				// 保存成功后,可以刷新页面,也可以:
		//$('#test').treegrid('acceptChanges');
		var json = JSON.stringify(changesRows);
		$.post('json/saveTreeGridData.json', {"treeGridData": json}, function(data){
			/*if(data == 'success'){
				alert(1);
			}else{
				alert(2);
			}*/
			reload();
		});
	}
	
	
	function reload(){
		//var node = $('#test').treegrid('getSelected');
		//if (node){
		//	$('#test').treegrid('reload', node.id);
		//} else {
			$('#test').treegrid('reload');
		//}
		insertRows = [];
		updateRows = [];
		deleteRows = [];
		setTimeout(collapseAll,1000);
	}
	function getChildren(){
		var node = $('#test').treegrid('getSelected');
		if (node){
			var nodes = $('#test').treegrid('getChildren', node.id);
		} else {
			var nodes = $('#test').treegrid('getChildren');
		}
		var s = '';
		for(var i=0; i<nodes.length; i++){
			s += nodes[i].id + ',';
		}
		alert(s);
	}
	function getSelected(){
		var node = $('#test').treegrid('getSelected');
		if (node){
			alert(node.id);
		}
		return false;
	}
	function collapse(){
		var node = $('#test').treegrid('getSelected');
		if (node){
			$('#test').treegrid('collapse', node.id);
		}
	}
	function expand(){
		var node = $('#test').treegrid('getSelected');
		if (node){
			$('#test').treegrid('expand', node.id);
		}
	}
	function collapseAll(){
		$('#test').treegrid('collapseAll');
	}
	function expandAll(){
		$('#test').treegrid('expandAll');
	}
	
	
	function commonDataCopy(pid){
		codeIndex++;   
		var copyId = 'copy'+codeIndex;
		var node = $('#test').treegrid('getSelected');
		var data = [{
			id: copyId,
			pid: pid,
			treeIndex:new Date().getTime(),
			attribute1: node.attribute1,
			attribute2: node.attribute2,
			attribute3: node.attribute3,
			attribute4: node.attribute4,
			attribute5: node.attribute5,
			attribute6: node.attribute6,
			attribute7: node.attribute7,
			attribute8: node.attribute8,
			attribute9: node.attribute9
		}];
		$('#test').treegrid('append', {
			parent: (node?pid:null),
			data: data
		});
		
		var node = $('#test').treegrid('find', copyId);
		insertRows[insertRows.length] = node;
	}
	
	function commonBlankCopy(pid){
		codeIndex++;   
		var node = $('#test').treegrid('getSelected');
		var copyId = 'copy'+codeIndex;
		var data = [{
			id: copyId,
			pid: pid,
			treeIndex:new Date().getTime(),
			attribute1: '',
			attribute2: '',
			attribute3: '',
			attribute4: '',
			attribute5: '',
			attribute6: '',
			attribute7: '',
			attribute8: '',
			attribute9: ''
		}];
		$('#test').treegrid('append', {
			parent: pid,
			data: data
		});
		
		var node = $('#test').treegrid('find', copyId);
		insertRows[insertRows.length] = node;
	}
		
	//添加平行节点		        
	function copy(){	   
		var node = $('#test').treegrid('getSelected');
		if(!node) alert("Please one row !");
		commonDataCopy(node.pid);
		return false;
	}
	
	//添加子节点
	function appendCopy(){		
		var node = $('#test').treegrid('getSelected');
		if(!node) alert("Please one row !");
		commonDataCopy(node.id);
		return false;
	}
	
	function appendBlank(){
		var node = $('#test').treegrid('getSelected');
		commonBlankCopy(node ? node.id : -1);
		return false;
	}
	function blank(){
		var node = $('#test').treegrid('getSelected');
		commonBlankCopy(node ? node.pid : -1);
		return false;
	}
	function remove(){
		$.messager.confirm('确认','是否真的删除?',function(r){
               if (r){
                   var node = $('#test').treegrid('getSelected');
					if (node){
						deleteNode(node);						
						$('#test').treegrid('remove', node.id);
					}
               }
           });
	}
	
	function removeMulSelected(){
		$.messager.confirm('确认','是否真的删除?',function(r){
               if (r){
                   var nodes = $('#test').treegrid('getSelections');
                   for(var i = 0;i<nodes.length;i++){
                   	  var node = nodes[i];
                   	  if (node){
						  deleteNode(node);						
						  $('#test').treegrid('remove', node.id);
					  }
                   }
					
               }
           });
	}
	
	
	function commonDelete(node){
		if(checkExist(insertRows,node)){
			$.removeValue(insertRows,node);
		}else{//添加组中没有,说明不是新增的,需要加入删除组
			deleteRows[deleteRows.length] = node;
		}
		if(checkExist(updateRows,node)){
			$.removeValue(updateRows,node);
		}
	}
	
	function deleteNode(node){
		var children = $('#test').treegrid('getChildren', node.id);
		//删除添加组和更新组中的子数据
		if(children != null && children.length > 0){
			for(var i = 0 ; i < children.length ; i++){
				var child = children[i];
				commonDelete(child);
			}
		}
		//删除添加组和更新组中的当前节点数据
		commonDelete(node);
	}
	
	
	function toggle(){
		var node = $('#test').treegrid('getSelected');
		if (node){
			$('#test').treegrid('toggle', node.id);
		}
	}
	
	function moveUp(){
		var node = $('#test').treegrid('getSelected');
		var selectRow = $('#datagrid-row-r2-2-'+node.id);
		var pre = selectRow.prev();
		var next = selectRow.next();
		
		//处理新增行的移动
		//var i = node.id.indexOf("copy");
		var preLen = selectRow.parent().parent().prev().length; 
		var flag = typeof node.id == 'string'; 
		//只有新增的未移动的行才需要重新设置pre
		//pre.length == 0 判断是否是新增的未移动的行(新增的移动过的行和数字行一样)
		//preLen > 0 判断是否已移动到同级第一行
		if(flag && pre.length == 0 && preLen > 0){
			var tmpTable = selectRow.parent().parent().prev();
			var ran = new Date().getTime();
			tmpTable.attr("id","id"+ran);
			
			var _tr = $("#id"+ran+">tbody>tr");
			var tmpLast = _tr[_tr.length-1];
			var last = $(tmpLast);
			if(last.hasClass('treegrid-tr-tree')){
				pre = last.prev();
			}else{
				pre = last;
			}
			selectRow.parent().parent().remove();//删除新增行所在的table
			//pre = tmp.find("tr[class!='treegrid-tr-tree'] :last");
			//selectRow.parent().parent().remove(); //删掉新增行的Table
		}
		
		var preId;
		var preTreeIndex;
		if(pre.hasClass('treegrid-tr-tree')){  //前面节点含有子节点
			var child = pre;
			var treeprev = child.prev();
			preHtml = treeprev;
		}else{
			preHtml = pre;
		}
		
		//获取pre的Id
		preId = preHtml.find("td:eq(0)").text();
		selectRow.insertBefore(preHtml);
			
		if(next.hasClass('treegrid-tr-tree')){ //自己含有子节点
			var child = next;
			selectRow.after(child);
		}
		
		
		//交换treeIndex
		var selectTreeIndex = node.treeIndex;
		var prenode = $('#test').treegrid('find',preId);
		node.treeIndex = prenode.treeIndex;
		prenode.treeIndex = selectTreeIndex;
		$('#test').treegrid('refresh',node.id);
		$('#test').treegrid('refresh',preId);
						
		updateTreeIndex(node);
		updateTreeIndex(prenode);
		var i ;
	}
	
	
	function updateTreeIndex(node){
		if(checkExist(insertRows,node)){ 
			$.removeValue(insertRows,node); 
			$.removeValue(updateRows,node);  
			insertRows[insertRows.length] = node;
		}else{
			//将换了treeIndex的行加入更新组
			updateRows[updateRows.length] = node;
		}
	}
	
</script>
	</head>
	<body>
		<table id="test" class="easyui-treegrid" style="width: 1200px; height: 400px" data-options="rownumbers:true,pagination:false,fitColumns:true,autoRowHeight:false"></table>

		<div id="toolbar">     
		    <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-tree-save" plain="true" onclick="saveChanges()">保存</a>     
		    <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-tree-reload" plain="true" onclick="reload()">重置</a>     
		    <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-tree-expand" plain="true" onclick="expandAll()">全部展开</a>     
		    <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-tree-collapse" plain="true" onclick="collapseAll()">全部收缩</a>     
		    <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-tree-appendBlank" plain="true" onclick="appendBlank()">添加子节点</a>     
		    <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-tree-appendCopy" plain="true" onclick="appendCopy()">复制子节点</a>     
		    <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-tree-blank" plain="true" onclick="blank()">添加节点</a>     
		    <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-tree-copy" plain="true" onclick="copy()">复制节点</a>     
		    <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-tree-remove" plain="true" onclick="remove()">删除节点</a>     
		    <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-tree-moveUp" plain="true" onclick="moveUp()">同级上移</a>     
		    <a href="javascript:void(0);" class="easyui-linkbutton" iconCls="icon-tree-moveDown" plain="true" onclick="javascript:alert('Save')">同级下移</a>     
		</div>  
	</body>
</html>

 

。。

 

 java 递归读取数据库生成tree的结构

 http://bbs.csdn.net/topics/320094100

 根据递归高效的生成树:

http://jsf.iteye.com/blog/124799

分享到:
评论

相关推荐

    可自定义树节点的Tree组件

    `可自定义树节点的Tree组件`是一个专为满足这种需求而设计的功能强大的工具。它允许开发者根据具体项目的需求来定制树形结构的节点展示,提升用户体验并优化数据管理。在本文中,我们将深入探讨这个组件的工作原理、...

    VUE自定义树形结构组件.zip

    "VUE自定义树形结构组件.zip"这个压缩包包含了一个实现这一功能的示例项目。让我们深入探讨其中涉及的关键知识点。 1. **Vue.js**: Vue.js是一个轻量级的前端JavaScript框架,它允许开发者通过声明式的方式构建用户...

    小程序 树结构相关内容 自定义 树结构组件

    在小程序开发中,自定义树结构组件是一项重要的技术任务,它能够帮助用户以直观的方式浏览和操作层级化信息。以下将详细阐述小程序中自定义树结构组件的相关知识点。 一、树结构基础 树结构由节点(Node)和边...

    c# winfrom 自定义简单的tree控件(入门)

    在C# WinForm开发中,有时我们可能需要创建自定义的控件来满足特定的界面需求,例如构建一个简单的Tree控件。这个教程将引导初学者如何从零开始实现一个基本的Tree控件,主要涉及的技术点包括自定义控件、事件处理...

    flex自定义树形结构

    结合`Flex`与`Tree`,我们可以构建一个自定义的树形结构。以下是一些关键步骤和知识点: 1. **容器设置**:首先,我们需要一个容器来承载整个树形结构。这个容器应该应用`display: flex`样式,使其成为Flex容器,并...

    vued3treeVUE实现自定义节点的树结构

    本项目"vued3treeVUE实现自定义节点的树结构"是基于Vue.js和D3.js的一个示例,旨在展示如何在Vue中利用D3库创建可自定义的树形数据结构。D3.js是一个强大的数据可视化库,它允许开发者通过数据操作DOM(文档对象模型...

    element-ui tree结构实现增删改自定义功能代码

    在这个模板中,`el-tree`组件用于显示树结构,`data`属性接收树的数据,`node-key`定义了唯一标识每个节点的字段,`render-content`用于自定义节点的内容,`expand-on-click-node`设置为`false`表示点击节点时不自动...

    Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作

    需求: vue-cli项目树形控件:一级节点为本地节点,默认展开一级节点,增删改后局部刷新数据。 增加节点,点击确定后局部刷新,渲染新数据。 源码 element组件样式 &lt;el-tree class="treeitems" :data="data...

    Extjs 自定义树结构实现以及动态表头实现

    在本文中,我们将深入探讨如何使用ExtJS框架来实现自定义树结构以及动态表头的功能。ExtJS是一款强大的JavaScript库,常用于构建富客户端应用程序,它提供了丰富的UI组件和强大的数据绑定机制。VS2015是Visual ...

    vue + element ui工程,Tree 树形控件展示指定值,比如name

    // 引入自定义树形组件 Vue.use(ElementUI); new Vue({ render: (h) =&gt; h(App), components: { CustomTree, }, }).$mount('#app'); ``` 这样,在应用中就可以使用`CustomTree`组件来展示以`name`字段为标签...

    ext自定义树组件

    创建自定义树组件,我们需要继承Ext.tree.Panel类,并覆盖或扩展其默认配置和方法。 2. **模型(Model)与存储(Store)**:树数据通常存储在EXT的数据存储组件(如Ext.data.TreeStore)中,它负责管理数据的加载、...

    TreeDemo13 自定义model示例.rar

    【标题】"TreeDemo13 自定义model示例"是一个关于使用Qt库创建自定义图形树视图的应用程序。这个示例着重展示了如何利用Qt的模型视图框架(Model/View Framework)来构建一个可拖动节点的树形结构。 在Qt中,模型...

    Qt实现自定义树状导航栏

    在QT编程中,自定义控件是提升应用界面独特性和用户体验的重要手段。"QT实现自定义树状导航栏"这个项目就是针对这一需求,通过QT的模型视图委托机制来创建一个可定制的、功能丰富的导航结构。让我们深入探讨一下其中...

    layui-tree树形模板

    layui-tree是layui框架中的一个重要组件,它主要用于构建树形结构的界面元素,尤其适用于后台管理系统中的权限列表展示。layui是一款轻量级、模块化的前端UI框架,提供了丰富的组件和样式,便于快速构建美观且功能...

    Android自定义任意层级树形

    本教程将详细讲解如何在Android中自定义这种任意层级的树形结构。 首先,理解树形结构的基本概念至关重要。树形结构是一种数据结构,它由节点(或称为顶点)和边组成,每个节点可以有零个或多个子节点,没有父节点...

    .net ,递归写自定义树

    在.NET开发中,构建自定义树形结构是一种常见的需求,特别是在网页UI设计中,用于展现层级关系的数据。这里我们关注的是使用jQuery控件配合后台.NET代码来递归构造树形结构。递归是一种强大的编程技术,它允许函数或...

    使用jsTree实现js树形结构

    **jsTree:构建前端树形结构的利器** jsTree 是一个强大的 JavaScript 库,专用于在 Web 页面上创建交互式的树形结构。它基于纯 JavaScript 编写,无需依赖其他库,因此对于初学者和有经验的开发者来说,都是一个...

    Unity UGUI自定义树形菜单(TreeView)GitHub配套.UnityPackage

    5.5.0版本Open_csdn文章名为_Unity UGUI自定义树形菜单(TreeView) 解决“当把所有的二级菜单折叠后,再展开,本来属于第一个二级菜单的三级菜单的内容就会显示全部显示在最后一个二级菜单的尾部。”

    JAVA制作树TREE

    在Java编程中,"制作树TREE"通常是指创建和操作数据结构中的树。树是一种非线性数据结构,由节点(或称为顶点)和边组成,每个节点可以有零个或多个子节点。在Java中,我们可以用类来表示树的节点,通过节点之间的...

Global site tag (gtag.js) - Google Analytics