功能:对业态,门店分类,门店,专柜分类,专柜等各个不同的模块的编辑和添加整合到一个树状结构中,同时优化不同门店下专柜名称不能重复的问题
目前的名称规则,门店名称不能重复,门店名称允许和专柜名称重复,同一门店下的专柜的名称不允许重复。
第一级,业态:业态的编辑和添加页面是一个编辑记录和添加记录,提交无法自动关闭,需手动关闭并刷新页面才可展示最新数据。
第二级至第五级:分别对应门店分类,门店,专柜分类,专柜,当节点未展开时提供编辑功能,当节点展开后提供为当前节点添加子节点的功能
对某一个节点编辑或添加后会自动刷新数据并按照编辑的路径展开树状结构
逻辑实现:
将每个模块的实体封装为节点数据
因各模块不是真正的树状数据,并未存在上下级关系,会出现第二级的节点数据可能属于多个第一级数据的节点数据,所以必须以idPath作为节点标识符,格式为:type:level1Id,level2Id,level3Id,level4Id,level5Id
数据改动后展开树状结构的逻辑:
当前操作为编辑时,则以idPath为展开路径,当前操作为删除时则以idPath+新增的数据的id为展开路径,由于树状数据是分层级获取,需在获取当前层级数据时根据idPath的长度及内容判断当前层级需要展开的数据
基于aceADmin的tree实现
前端代码:
<script src="${base}/assets/js/fuelux/fuelux.spinner.js"></script>
<script src="${base}/assets/js/bootstrap.min.js" type="text/javascript"></script>
<script src="${base}/assets/js/jquery-validation/jquery.validate.min.js" type="text/javascript"></script>
<script src="${base}/assets/js/jquery-validation/additional-methods.min.js" type="text/javascript"></script>
<script src="${base}/assets/js/jquery-validation/messages_zh.js" type="text/javascript"></script>
<script src="${base}/static/js/jquery.form.js" type="text/javascript"></script>
<script src="${base}/static/js/layer/layer.min.js" type="text/javascript"></script>
<script src="${base}/static/js/jquery.ajaxfileupload-20140125.js" type="text/javascript"></script>
<script src="${base}/static/js/uploadPreview.js" type="text/javascript"></script>
<script src="${base}/static/js/common.js" type="text/javascript"></script>
<script src="${base}/static/js/select2.min.js"></script>
<script src="${base}/static/js/LodopFuncs.js"></script>
<script type="text/javascript">
var remoteDateSource = function(options, callback) {
var parent_id = null;
if (!('text' in options || 'type' in options)) {
parent_id = 0;// load first level data
} else if ('type' in options && options['type'] == 'folder') {// it has children
if ('additionalParameters' in options && 'children' in options.additionalParameters)
parent_id = options.additionalParameters['id'];
}
if (parent_id !== null) {
$.ajax({
url : '${base}/admin//deliveryStore/tree/ajaxData?rand=' + Math.random(1000),
data : {
param : parent_id,
openPath: '${openPath}'
},
type : 'POST',
dataType : 'json',
complete : function(response) {
var returninfo = eval("(" + response.responseText + ")");
if (returninfo.status == "OK") {
callback({
data : returninfo.data
});
}
}
});
}
};
$('#tree').ace_tree({
dataSource : remoteDateSource,
//dataSource : DataSourceTree('${base}/admin/resources/tree/ajaxData?rand=' + Math.random(1000)),
loadingHTML : '<div class="tree-loading"><i class="ace-icon fa fa-refresh fa-spin blue"></i></div>',
multiSelect: false,
'open-icon': 'ace-icon tree-minus',
'close-icon': 'ace-icon tree-plus',
'selectable': true,
'selected-icon': 'ace-icon fa fa-check',
'unselected-icon': 'ace-icon fa fa-check'
}).on('selected.fu.tree', function(e,data) {
var ids = "";
var items = data.selected;
for(var i = 0; i < items.length; i++) {
var item = items[i];
ids += item.additionalParameters['id']+";";
}
$("#typeId").val(ids.substring(0,ids.length - 1));
$("#treeType").val("item");
$dataTable.fnDraw();
}).on('opened.fu.tree', function(e,data) {
var id=data.additionalParameters['id'];
if(id=="root"){
$('button[id="'+id+'"]').prop("hidden",false);
}
$('button[id="'+id+'"]').html("添加");
$('button[id="'+id+'"]').attr("type","add");
$('button[id="'+id+'"]').prop("class","btn-primary");
}).on('closed.fu.tree', function(e,data) {
var id=data.additionalParameters['id'];
if(id=="root"){
$('button[id="'+id+'"]').prop("hidden",true);
}
$('button[id="'+id+'"]').html("编辑");
$('button[id="'+id+'"]').attr("type","edit");
$('button[id="'+id+'"]').prop("class","btn-link");
}).on('loaded.fu.tree', function(e,data) {
$(data).find("li[name='leftclick']").each(function (index,ele){
var idPath=$(ele).attr("text");
var buttonEle=$("<button name='optButton' id='"+idPath+"' class='btn-link' style='margin-left: 10px;height: 20px;float: right;margin-right: 15px;border-radius: 5px' type='edit'>编辑</button>");
$(ele).find('span[class="tree-label"]').append(buttonEle);
$("button[name='optButton']").unbind("click").on("click",function(event){
event.stopPropagation();
var html=$(this).attr("type");
idPath=$(this).prop("id");
var text=$(this).html();
if(idPath=="root"){
optYt(idPath);
return;
}
var array=(idPath.split(":")[1]).split(",");
var len=array.length;
var name="";
var url="";
if(html=="add"){
len=len+1;
}
if(html=="edit"){
if(len==4){
html+="/"+array[3];
}else if(len==6){
html+="/"+array[5];
}
}
if(len==1){
optYt(idPath);
return;
}else if(len==2){
name=text+"aa类信息";
if(html=="edit"){
url="/aa/"+html+"InTree";
}else{
url="/aa/"+html;
}
}else if(len==3){
name=text+"bb信息";
url="/bb/"+html+"InTree";
}else if(len==4){
name=text+"cc类信息";
url="/cc/"+html;
}else if(len==5){
name=text+"bb信息";
url="/bb/"+html+"InTree";
}
//如果是dd则弹出提示框
if(len==6){
if(text=="添加"){//String code, String shopNo,String parentId
idPath+=",&codeId="+array[0]+"&shopNo="+array[4];
}
name=text+"dd分类";
url="/goods/dd/"+html;
}
//如果添加门店则弹出提示框
doAdd(name,url,idPath);
});
});
});
function doAdd(name,val,idPath){
var type='a';
if(idPath.split(':')[1].split(",").length==6){
type='b';
}
layer.open({
type: 2,
title: name,
maxmin: true,
shadeClose: false, //点击遮罩关闭层
area : ['1200px' , '460px'],//控制层宽高
content: '${base}/'+type+val+'?idPath='+idPath+'&t='+ Math.random()
});
}
</script>
后台处理代码
/**
*升级版树形数据源
*
* @param param
*/
@RequestMapping(value = "tree/ajaxData")
@ResponseBody
public Object treeAjaxData(Model model, String param,String openPath) {
String path="";
if(StringUtils.isNotEmpty(openPath)){
path=openPath.split(":")[1];
}
....
if (StringUtils.equals(param, "0")) {
// 根节点
map = new HashMap<String, Object>();
map.put("name", "xxxx");
map.put("type", "folder");
additionalParameters = new HashMap<String, Object>();
additionalParameters.put("id", "root");
additionalParameters.put("children", true);
additionalParameters.put("item-selected", true);
map.put("additionalParameters", additionalParameters);
Map<String,String> attr=new HashMap<>();
attr.put("name","leftclick");
attr.put("text","root");
map.put("attr",attr);
list.add(map);
} else if (StringUtils.equals(param, "root")) {
// 获取其子节点 类型:aa,bb,cc,dd,ee,ff
for (int i = 0; i < xxxx.size(); i++) {
map = new HashMap<String, Object>();
map.put("name", busiType.get(i).get("name"));
map.put("type", "folder");
additionalParameters = new HashMap<String, Object>();
Map<String,String> attr=new HashMap<>();
attr.put("text","aa:"+busiType.get(i).get("id"));
attr.put("name","leftclick");
map.put("attr",attr);
additionalParameters.put("id", "aa:"+busiType.get(i).get("id"));
additionalParameters.put("children", true);
if(split.length>=1){
if(split[0].equals(busiType.get(i).get("id").toString())){
additionalParameters.put("item-selected", true);
}
}
map.put("additionalParameters", additionalParameters);
list.add(map);
}
} else {
// 获取其子节点 类型:aa,bb,cc,dd,ee,ff
try {
List<Map<String, Object>> nodeData=new ArrayList<>();
String type=param.split(":")[0];
String id=param.split(":")[1];
Criteria cri=new Criteria();
cri.add(Restrictions.eq("tenantId",getCurrentTenantId()));
switch (type){
case "aa":
type="bb";
// 获取其子节点 类型:aa,bb,cc,dd,ee,ff
List<Yt> ytList =...
if(ytList!=null && ytList.size()>0){
for (Yt item : ytList) {
Map<String,Object> mapItem=new HashMap<>();
mapItem.put("name",item.getDytname());
mapItem.put("id",id+","+item.getDytno());
nodeData.add(mapItem);
}
}
break;
case "bb":
type="cc";
。。。
nodeData = xxxService.selectList(a,b);
if(nodeData!=null&&nodeData.size()>0){
for (Map item : nodeData) {
item.put("id",id+","+item.get("xxxx"));
}
}
break;
case cc":
type="dd";
List<ZgCate> all = ...;
if(all!=null && all.size()>0){
for (ZgCate item : all) {
Map<String,Object> mapItem=new HashMap<>();
mapItem.put("name",item.getZgCate());
mapItem.put("id",id+","+item.getId());
nodeData.add(mapItem);
}
}
break;
case "dd":
type="ee";
List<DeliveryStore> deliveryStoreList = ...
if(deliveryStoreList!=null && deliveryStoreList.size()>0){
for (DeliveryStore item : deliveryStoreList) {
Map<String,Object> mapItem=new HashMap<>();
mapItem.put("name",item.getName());
mapItem.put("id",id+","+item.xxx());
nodeData.add(mapItem);
}
}
break;
case "ee":
type="ff";
cri.add(Restrictions.eq("shopNo",id.split(",")[4]));
List<GoodsCategory> goodsCategoryList = ...
if(goodsCategoryList!=null && goodsCategoryList.size()>0){
for (GoodsCategory item : goodsCategoryList) {
Map<String,Object> mapItem=new HashMap<>();
mapItem.put("name",item.getName());
mapItem.put("id",id+","+item.getId());
nodeData.add(mapItem);
}
}
break;
}
if (nodeData != null && nodeData.size() > 0) {
for (int i = 0; i < nodeData.size(); i++) {
map = new HashMap<String, Object>();
map.put("name", nodeData.get(i).get("name"));
additionalParameters = new HashMap<String, Object>();
additionalParameters.put("id", type+":"+nodeData.get(i).get("id"));
if(type.equals("bb")&&split.length>=2){
if(split[1].equals(nodeData.get(i).get("id").toString().split(",")[1])){
additionalParameters.put("item-selected", true);
}
}
if(type.equals("cc")&&split.length>=3){
if(split[2].equals(nodeData.get(i).get("id").toString().split(",")[2])){
additionalParameters.put("item-selected", true);
}
}
if(type.equals("dd")&&split.length>=4){
if(split[3].equals(nodeData.get(i).get("id").toString().split(",")[3])){
additionalParameters.put("item-selected", true);
}
}
if(type.equals("ee")&&split.length>=5){
if(split[4].equals(nodeData.get(i).get("id").toString().split(",")[4])){
additionalParameters.put("item-selected", true);
}
}
if(type.equals("ff")&&split.length>=6){
if(split[5].equals(nodeData.get(i).get("id").toString().split(",")[5])){
additionalParameters.put("item-selected", true);
}
}
if(type.equals("ff")){
map.put("type", "item");
additionalParameters.put("children",true);
}else if(type.equals("bb")){
String dshop=nodeData.get(i).get("id").toString().split(",")[1];
if(dshop.equals("xxxx")){ // || dshop.equals("xxxx")
map.put("type", "folder");
additionalParameters.put("children", false);
}else{
map.put("type", "item");
additionalParameters.put("children",true);
}
}else{
map.put("type", "folder");
additionalParameters.put("children", false);
}
map.put("additionalParameters", additionalParameters);
Map<String,String> attr=new HashMap<>();
attr.put("text",type+":"+nodeData.get(i).get("id"));
attr.put("name","leftclick");
map.put("attr",attr);
list.add(map);
}
}
} catch (Exception ex) {
logger.error("获取其子节点时,发生异常", ex);
result.putAll(ajaxJsonErrorMessage("后台出错了,删除失败!"));
}
}
result.put("data", list);
result.put("status", "OK");
return result;
}
核心:对idPAth在同一个操作链条中的互相传递。