'use strict'; app.controller('cmdbViewCtrl', ["$rootScope","$scope", "$state", "$timeout", "$interval", "$aside", "SweetAlert", "toaster", "Restangular", "api_bpm_domain", "api_configure_data", "api_cmdb", "api_configure_form", function ($rootScope, $scope, $state, $timeout, $interval, $aside, SweetAlert, toaster, Restangular, api_bpm_domain, api_configure_data, api_cmdb, api_configure_form) { var width = $scope.width = 650; var height = $scope.height = 400; var apple_selected, tree, treedata_avm, treedata_geography; $scope.my_tree_handler = function (branch) { //var _ref; var classify=$scope.classify=branch.prefix.toLowerCase()+branch.sign; api_cmdb.query({'sign':classify}).then(function(data){ var myData = Restangular.stripRestangular(data); console.log(myData.data.node); if(myData.data&&myData.status==200){ var ret = myData.data; redrawSvg(myData); } }); }; $scope.my_data = []; function convertListToTree(data, treeMap){ var idToNodeMap = {}; //Keeps track of nodes using id as key, for fast lookup var root = null; //Initially set our loop to null var parentNode = null; //loop over data for(var i = 0; i < data.length; i++) { var datum = data[i]; //each node will have children, so let's give it a "children" poperty datum.children = []; //add an entry for this node to the map so that any future children can //lookup the parent idToNodeMap[datum.id] = datum; //Does this node have a parent? if(typeof datum.parent === "undefined" || datum.parent == null) { //Doesn't look like it, so this node is the root of the tree root = datum; treeMap[datum.id] = root; } else { //This node has a parent, so let's look it up using the id parentNode = idToNodeMap[datum.parent.id]; //We don't need this property, so let's delete it. delete datum.parent; //Let's add the current node as a child of the parent node. parentNode.children.push(datum); } } return root; } function convertParentToChildList(data){ var treeMap = {}; var list=[]; convertListToTree(data, treeMap); angular.forEach(treeMap,function(item){ list.push(item); }); return list; } $scope.my_tree = tree = {}; $scope.try_async_load = function () { $scope.my_data = []; $scope.select_treedata = []; $scope.doing_async = true; api_configure_data.fetchDataList('ciclassify',{'idx':0,'sum':100}).then(function(result){ //console.log(result['list']); $scope.select_treedata = $scope.my_data = convertParentToChildList(result['list']); $scope.doing_async = false; tree.expand_all(); //console.log(treelist); }); }; $scope.select_treedata = []; $scope.propTypeOptions = []; $scope.try_async_load(); $scope.onFilterCallback = function(item){ //console.log(item); if(angular.isDefined(item.children)&&item.children.length>=1){ //not valid }else{ var tempclassify=item.prefix.toLowerCase()+item.sign; $scope.cifilter_classic=tempclassify; api_configure_form.renderTabForm(tempclassify).then(function(data){ var myData = Restangular.stripRestangular(data); $scope.propTypeOptions = myData; }); } } $scope.onPropTypeChange = function(form){ $scope.propOptions = form.fields; } $scope.onPropChange = function(prop){ $scope.cifilter_prop = prop; } $scope.searchCI = function(searchKey, propObj, ciclassify){ //if(searchKey!=null&&searchKey.length>1){ var searchData = {}; if(angular.isUndefined(propObj)){ propObj = $scope.cifilter_prop; } if(angular.isUndefined(ciclassify)){ ciclassify = $scope.cifilter_classic; } searchData['sign']=ciclassify; if(angular.isDefined(propObj)){ searchData[propObj.key] = searchKey; } api_cmdb.query(searchData).then(function(response){ var data=Restangular.stripRestangular(response); //此处不清空nodes var node=data.data.node; var tempNode=[]; //nodes 或者links 要去重 for(var i=0;i'+d.iconname+'

'+d.label+'

'; // }).on('click',function(d){ // //查询节点 // query(d.sign,""); // }); // }else{ // jAlert("服务器请求异常",'提示'); // } // }); function hideLinkForm(hide){ $scope.hideLink=hide; } function hideFeedForm(hide){ $scope.hideFeed=hide; } function redrawSvg(json){ nodes.length=0;//先清空 links.length=0; var data=json.data; for(var i=0;i1){ // jAlert('最大输入值为1','提示'); // this.value=''; // return; // } // }); //添加属性 属性类型 var proTypes=[ {id:1,key:'string',value:'文本类型'}, {id:2,key:'date',value:'日期类型'}, {id:3,key:'int',value:'数字类型'}, {id:4,key:'float',value:'浮点类型'} ]; // init D3 force layout var force = d3.layout.force() .nodes(nodes) .links(links) .size([width, height]) .gravity(.05) .linkDistance(150) .linkStrength(2) .charge(-500) .on('tick', tick); // define arrow markers for graph links svg.append('svg:defs').append('svg:marker') .attr('id', 'end-arrow') .attr('viewBox', '0 -5 10 10') .attr('refX', 6) .attr('markerWidth', 3) .attr('markerHeight', 3) .attr('orient', 'auto') .append('svg:path') .attr('d', 'M0,-5L10,0L0,5') .attr('fill', '#000'); svg.append('svg:defs').append('svg:marker') .attr('id', 'start-arrow') .attr('viewBox', '0 -5 10 10') .attr('refX', 4) .attr('markerWidth', 3) .attr('markerHeight', 3) .attr('orient', 'auto') .append('svg:path') .attr('d', 'M10,-5L0,0L10,5') .attr('fill', '#000'); // line displayed when dragging new nodes var drag_line = svg.append('svg:path') .attr('class', 'link dragline hidden') .attr('d', 'M0,0L0,0'); // handles to link and node element groups //(1)var path = svg.append('svg:g').selectAll('g') var path = svg.append('svg:g').selectAll('g'), circle = svg.append('svg:g').selectAll('g'); // mouse event vars var selected_node = null, selected_link = null, mousedown_link = null, mousedown_node = null, mouseup_node = null; function resetMouseVars() { mousedown_node = null; mouseup_node = null; mousedown_link = null; } // update force layout (called automatically each iteration) function tick() { // draw directed edges with proper padding from node centers path.selectAll('path').attr('d', function(d) { var deltaX = d.target.x - d.source.x, deltaY = d.target.y - d.source.y, dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), normX = deltaX / dist, normY = deltaY / dist, sourcePadding = d.left ? 27 : 22, targetPadding = d.right ? 27 : 22, sourceX = d.source.x + (sourcePadding * normX), sourceY = d.source.y + (sourcePadding * normY), targetX = d.target.x - (targetPadding * normX), targetY = d.target.y - (targetPadding * normY); return 'M' + sourceX + ',' + sourceY + 'L' + targetX + ',' + targetY; }); circle.attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; }); } // update graph (called when needed) function restart() { //绑定link 数据 path.datum(links); // path (link) group path = path.data(links,function(d) { return d.id; }); var p = path.enter().append('svg:g'); //update existing links path.selectAll('path').classed('selected', function(d) { return d === selected_link; }) .style('marker-start', function(d) { return d.left ? 'url(#start-arrow)' : ''; }) .style('marker-end', function(d) { return d.right ? 'url(#end-arrow)' : ''; }); // add new links p.append('svg:path') .attr('class', 'link') .attr('id', function(d) { return "path_" + d.id; }) // .attr('startOffset', '0%') .classed('selected', function(d) { return d === selected_link; }) .style('marker-start', function(d) { return d.left ? 'url(#start-arrow)' : ''; }) .style('marker-end', function(d) { return d.right ? 'url(#end-arrow)' : ''; }) .on('mousedown', function(d) { if(d3.event.ctrlKey) return; //去除没有提交的连线 for(var i=0;i'+labels[i].iconname+''; } } }); // remove old nodes circle.exit().remove(); // set the graph in motion force.start(); } function mousedown() { // prevent I-bar on drag //d3.event.preventDefault(); // because :active only works in WebKit? svg.classed('active', true); if(mousedown_node){ viewNode(mousedown_node); } if(d3.event.ctrlKey || mousedown_node || mousedown_link) return; // insert new node at point 点击添加node // var point = d3.mouse(this), // node = {id: ++lastNodeId, reflexive: false}; // node.x = point[0]; // node.y = point[1]; // nodes.push(node); restart(); } function viewNode(node){ var title = $scope.selected_node.name+"-["+$scope.selected_node.uuid+"]"; if(!$scope.selected_node.props.state){$scope.selected_node.props.state="空"} else if($scope.selected_node.props.state){ if($scope.selected_node.props.state=="1"){$scope.selected_node.props.state="未审核"} else if($scope.selected_node.props.state=="2"){$scope.selected_node.props.state="已审核"} else if($scope.selected_node.props.state=="3"){$scope.selected_node.props.state="不匹配"} else if($scope.selected_node.props.state=="4"){$scope.selected_node.props.state="丢失"} }; if(!$scope.selected_node.name){$scope.selected_node.name="空"} if(!$scope.selected_node.status){$scope.selected_node.statu="空"} if(!$scope.selected_node.props.useradmin){$scope.selected_node.props.useradmin="空"} toaster.pop({ // type: 'info', // title: title, body: '

搜索代码:' + $scope.selected_node.uuid + '

' + '

资产标题:' + $scope.selected_node.name + '

' + '

状态:' + $scope.selected_node.status + '

' + '

审核状态:' + $scope.selected_node.props.state + '

' + '

维护人员:' + $scope.selected_node.props.useradmin + '

', bodyOutputType: 'trustedHtml', timeout: 3000 }) } function mousemove() { if(!mousedown_node) return; // update drag line drag_line.attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'L' + d3.mouse(this)[0] + ',' + d3.mouse(this)[1]); restart(); } function mouseup() { if(mousedown_node) { // hide drag line drag_line .classed('hidden', true) .style('marker-end', ''); } // because :active only works in WebKit? svg.classed('active', false); // clear mouse event vars resetMouseVars(); } function spliceLinksForNode(node) { var toSplice = links.filter(function(l) { return (l.source === node || l.target === node); }); toSplice.map(function(l) { links.splice(links.indexOf(l), 1); }); } // only respond once per keydown var lastKeyDown = -1; function keydown() { //d3.event.preventDefault(); if(lastKeyDown !== -1) return; lastKeyDown = d3.event.keyCode; // ctrl if(d3.event.keyCode === 17) { circle.call(force.drag); svg.classed('ctrl', true); } if(!selected_node && !selected_link) return; switch(d3.event.keyCode) { case 8: // backspace // case 46: // delete // if(selected_node) { // nodes.splice(nodes.indexOf(selected_node), 1); // spliceLinksForNode(selected_node); // } else if(selected_link) { // links.splice(links.indexOf(selected_link), 1); // } // selected_link = null; // selected_node = null; // restart(); // break; case 66: // B if(selected_link) { // set link direction to both left and right selected_link.left = true; selected_link.right = true; } restart(); break; case 76: // L if(selected_link) { // set link direction to left only selected_link.left = true; selected_link.right = false; } restart(); break; case 82: // R if(selected_node) { // toggle node reflexivity selected_node.reflexive = !selected_node.reflexive; } else if(selected_link) { // set link direction to right only selected_link.left = false; selected_link.right = true; } restart(); break; } } function keyup() { lastKeyDown = -1; // ctrl if(d3.event.keyCode === 17) { circle .on('mousedown.drag', null) .on('touchstart.drag', null); svg.classed('ctrl', false); } } // app starts here svg.on('mousedown', mousedown) .on('mousemove', mousemove) .on('mouseup', mouseup); d3.select(window) .on('keydown', keydown) .on('keyup', keyup); //restart(); //GT 颜色与数值对照表 function colors(sign){ //num=num>20?num%20:parseInt(num); for(var i=0;i'; str+='未定义:'+ ''+strS+'' +'' +' '; return str; } for(var i=0;i'; }else{ strS=''; } if(p.fix==1){//固定属性 不允许编辑显示属性名 不允许删除 str+=''+p.descName+':'+ ''+ strS+'' +'' +' '; break; }else{ //类型设置 读取JSON string date int float str+=''+p.descName+':'+ ''+ strS+'' +'' +' '; break; } } } } return str; }); } }else{ jAlert("服务器请求异常!",'提示'); } }); */ } } //显示连线信息 // var openAside = function (model, linkTypes) { var modalInstance = $aside.open({ templateUrl: 'assets/views/system/tpl/asideContent.html', placement: 'right', size: 'sm', backdrop: true, controller: function ($scope, $modalInstance, ModelData, optionLinkTypes) { $scope.modelData = ModelData; $scope.linktypeOptions = optionLinkTypes; if($scope.modelData.name!=""){ angular.forEach($scope.linktypeOptions,function(item){ if(item.type==$scope.modelData.name){ $scope.modelData.linkName=item; } }) } $scope.ok = function (e) { $modalInstance.close($scope.modelData); //e.stopPropagation(); }; $scope.cancel = function (e) { $modalInstance.dismiss(); //e.stopPropagation(); }; }, resolve: { ModelData: function(){ return model; }, optionLinkTypes: function(){ return linkTypes; } } }); modalInstance.result.then(function (selectedItem) { //TODO create Edge console.log(selectedItem); if(selectedItem.id==-1){ api_cmdb.createRef({'id':selectedItem.id,'name':selectedItem.linkName.type,'source':selectedItem.source.id,'target':selectedItem.target.id,'left':selectedItem.left,'right':selectedItem.right}).then(function(response){ if(response&&response.status==200){ //model.name=selectedItem.linkName.type; var link = response.data.edge[0]; for (var j = 0; j < nodes.length; j++) { if (link.source == nodes[j].id) { link.source = nodes[j]; } if (link.target == nodes[j].id) { link.target = nodes[j]; } } links.push(link); // selected_link.name=linkName; // selected_link.cost=linkCost; restart(); }else{ } }) }else{ api_cmdb.putRef({'id':selectedItem.id,'name':selectedItem.linkName.type,'source':selectedItem.source.id,'target':selectedItem.target.id,'left':selectedItem.left,'right':selectedItem.right}, selectedItem.id).then(function(response){ if(response&&response.status==200){ //model=selectedItem; angular.forEach(links,function(link,index){ if(link.name == model.name){ links[index]=response.data.edge[0]; for (var j = 0; j < nodes.length; j++) { if (links[index].source == nodes[j].id) { links[index].source = nodes[j]; } if (links[index].target == nodes[j].id) { links[index].target = nodes[j]; } } } }) restart(); }else{ } }) } }, function () { //console.log('Modal dismissed at: ' + new Date()); }); }; // // function showLink(){ var linkeName = $scope.linkName = selected_link.name==undefined?"":selected_link.name; $scope.linkCost = selected_link.cost==undefined?"":selected_link.cost; // d3.select("#linkName").property('value',selected_link.name==undefined?"":selected_link.name); // d3.select("#linkCost").property('value',selected_link.cost==undefined?"":selected_link.cost); //var linkeName=d3.select("#linkName").property('value'); //先移除div中原来的标签 d3.select('#linkTab').selectAll('tr').remove('tr'); var linkId; //sourceTYpe=2 and sourceId=连线nameId //当前选择的连线name Id for(var i=0;i'; str+='未定义:'+ ''+//111111111111111111111 padding-left: 60px; strS +'' +'' +' '; return str; } for(var j=0;j'; }else{ strS=''; } if(p.fix==1){//固定属性 不允许编辑显示属性名 不允许删除 //类型设置 读取JSON string date int float 22222222222222222padding-left: 21px; str+=''+p.descName+':'+ ''+strS+''+'' +' '; break; }else{ //类型设置 读取JSON string date int float str+=''+p.descName+':'+ ''+//333333333333333 padding-left: 21px; strS +'' +'' +' '; break; } } } return str; }); } hideLinkForm(false); } //删除(修改状态为报废) function delnode_update(){ if(selected_node || selected_link){ jConfirm('确定删除?', '提示', function(r) { if(r){ if(selected_node){//删除配置 //节点ID(节点删除执行成功,数据库节点未删除 ,删除节点关系时执行失败) var id=selected_node.id; var name=selected_node.name; var type=selected_node.type;//资产类型 var label=selected_node.label; //资产类型 var assetNo=selected_node.assetNo;//资产编号 var props =selected_node.props; var status=CMConstants.DISCARDE; //删除后,状态变为废弃 $.ajax({ type: "PUT", contentType:"application/json; charset=UTF-8", url: window.basePath+"/api/cmdb/ci/"+id, data: JSON.stringify({'id':id,'name':name,'status':status,'type':type,'label':label,'assetNo':assetNo,'props':props}), dataType: "json", success:function(data){ if(data.status==200){ jAlert("删除成功!",'提示'); selected_node.type=type;//资产类型 selected_node.status=status; selected_node.label=label; //资产类型 selected_node.assetNo=assetNo; //资产编号 selected_node.props=props; selected_node.name=name; restart(); query(label,""); //shownode(); } }, error: function(data){jAlert("服务器请求异常",'提示');} }); } }else{ jAlert("请求异常",'提示'); } }); }else{ jAlert('请先选择删除项!','提示'); } } //删除 function delnode(){ if(selected_node || selected_link){ jConfirm('确定删除?', '提示', function(r) { if(r){ if(selected_node){//删除配置 //节点ID(节点删除执行成功,数据库节点未删除 ,删除节点关系时执行失败) var id=selected_node.id; //先删除节点关系 d3.xhr(window.basePath+"/api/cmdb/ci/"+id+"/refs").send("DELETE", function(error, json) { if (!error){ if(json.status==200){ var edge=JSON.parse(json.responseText).data.edge; for(var i=0;i0){ jConfirm('更换名称选项,动态属性将会被删除,是否继续?', '提示', function(r) { if(r){ selected_link.name=tType.value; selected_link.props={}; showLink(); selected_link['props']={}; fixPro(tType.value); }else{ tType.value=selected_link.name; return; } }); }else{ selected_link.name=tType.value; selected_link['props']={}; fixPro(tType.value); } }); //加载固定属性(节点/连线) function fixPro(label){ if(selected_node){//操作节点 var labelId=null; //根据选择‘节点’的label 查询label的ID d3.xhr(window.basePath+"/api/cm/findLabel?sign="+label).send("GET", function(error, json) { if (!error){ labelId =JSON.parse(json.responseText).id; $.ajax({ type: "GET", url: window.basePath+"/api/cm/findByPro", data: {sourceType : 1,sourceId: labelId}, dataType: "json", success:function(data){ var keys=[]; for(var i = 0;i < data.length;i++){ var entity=data[i]; if(entity.fix==1){ var key=entity.key; keys.push(key); selected_node['props'][key]=''; } } //先移除div中原来的标签 d3.select('#nodeTab').selectAll('tr').remove('tr'); d3.select('#nodeTab').selectAll('tr') .data(keys).enter() .append('tr') .attr('id',function(d){ return 'tr'+d; }) .html(function(d){ //undefined var str=""; //新增加行 var strS=""; for(var i = 0;i < data.length;i++){ var entity=data[i]; if(entity.fix==1 && entity.key==d){//固态属性 并且key相等 if(entity.valueType=="date"){ strS=''; }else{ strS=''; } //类型设置 读取JSON string date int float str+=''+entity.descName+':'+ ''+strS+''+''+' '; break; } } return str; }); }, error:function(data){jAlert("服务器访问异常!",'提示');} }); } }); }else if(selected_link){//操作连线 var sourceId=null; for(var i=0;i'; }else{ strS=''; } //类型设置 读取JSON string date int float str+=''+entity.descName+':'+ ''+strS+''+'' +' '; break; } } return str; }); }, error:function(data){jAlert("服务器访问异常!",'提示');} }); } } } //节点'添加属性' 点击事件 d3.select('#addBtn').on('click',function(){ var label=d3.select('#nodeLabel').property('value'); if(""!=label){ addRow(); }else{ jAlert('请先选择资产类型!','提示'); } }); //添加属性行 function addRow(){ if(selected_node.props){ selected_node.props['']='未定义'; }else{ selected_node['props']={'':'未定义'}; } //用户写入的记录下来 updJson(); shownode(); } //刷新时记录用户输入 function updJson(){ if(selected_node){ selected_node.assetNo=d3.select("#nodeAssetNo").property('value'); selected_node.name=d3.select("#nodeName").property('value'); selected_node.type=d3.select("#nodeType").property('value'); selected_node.label=d3.select("#nodeLabel").property('value'); selected_node.status=d3.select("#nodeStatus").property('value'); }else if(selected_link){ selected_link.name=d3.select("#linkName").property('value'); selected_link.cost=d3.select("#linkCost").property('value'); } } //=============弹出层添加属性begin======================================= //加载属性类型 d3.select('#proType').selectAll('option') .data(proTypes).enter() .append('option') .attr('value',function(d){return d.key;}) .html(function(d){ return d.value;}); //提交 d3.select('#addSubBtn').on('click',function(){ if(selected_node){ var proType=d3.select("#proType").property('value'); var proNo=d3.select("#proNo").property('value'); var desName=d3.select("#select"+etdBtnId).property('value');//正在编辑select2的值 //插入前先查询节点‘英文编号’的此label 此简称是否存在 var t=d3.select('#nodeLabel').property('value'); var labelId="";//选中的资源label的ID for(var i=0;i