ds.js做tree,可拖拽,缩放,右键菜单等

1.首先展示html代码,注意相关的引用









    

2.smartMenu.d3.可以自行下载,dndtree.js

/*Copyright (c) 2013-2016, Rob Schmuecker
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* The name Rob Schmuecker may not be used to endorse or promote products
  derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/

// Get JSON data
d3.json("flare.json", function(error, treeData) {

    // Calculate total nodes, max label length
    var totalNodes = 0;
    var maxLabelLength = 0;
    // variables for drag/drop
    var selectedNode = null;
    var draggingNode = null;
    // panning variables
    var panSpeed = 200;
    var panBoundary = 20; // Within 20px from edges will pan when dragging.
    // Misc. variables
    var i = 0;
    var duration = 750;
    var root;

    // size of the diagram
    var viewerWidth = $(document).width();
    var viewerHeight = $(document).height();

    var tree = d3.layout.tree()
        .size([viewerHeight, viewerWidth]);

    // 定义一个d3对角线投影,供以后的节点路径使用.
    var diagonal = d3.svg.diagonal()
        .projection(function(d) {
            return [d.y, d.x];
        });

    // 递归辅助函数,通过遍历所有节点来执行某些设置

    function visit(parent, visitFn, childrenFn) {
        if (!parent) return;

        visitFn(parent);

        var children = childrenFn(parent);
        if (children) {
            var count = children.length;
            for (var i = 0; i < count; i++) {
                visit(children[i], visitFn, childrenFn);
            }
        }
    }

    //  调用visit 函数来实现 establish maxLabelLength
    visit(treeData, function(d) {
        totalNodes++;
        maxLabelLength = Math.max(d.label.length, maxLabelLength);

    }, function(d) {
        return d.children && d.children.length > 0 ? d.children : null;
    });


    // 根据节点名对树进行排序

    function sortTree() {
        tree.sort(function(a, b) {
            return b.label.toLowerCase() < a.label.toLowerCase() ? 1 : -1;
        });
    }
    // 首先对树进行排序,以防JSON不是按排序顺序排列的.
    sortTree();

    // TODO: Pan function, can be better 应用.

    function pan(domNode, direction) {
        var speed = panSpeed;
        if (panTimer) {
            clearTimeout(panTimer);
            translateCoords = d3.transform(svgGroup.attr("transform"));
            if (direction == 'left' || direction == 'right') {
                translateX = direction == 'left' ? translateCoords.translate[0] + speed : translateCoords.translate[0] - speed;
                translateY = translateCoords.translate[1];
            } else if (direction == 'up' || direction == 'down') {
                translateX = translateCoords.translate[0];
                translateY = direction == 'up' ? translateCoords.translate[1] + speed : translateCoords.translate[1] - speed;
            }
            scaleX = translateCoords.scale[0];
            scaleY = translateCoords.scale[1];
            scale = zoomListener.scale();
            svgGroup.transition().attr("transform", "translate(" + translateX + "," + translateY + ")scale(" + scale + ")");
            d3.select(domNode).select('g.node').attr("transform", "translate(" + translateX + "," + translateY + ")");
            zoomListener.scale(zoomListener.scale());
            zoomListener.translate([translateX, translateY]);
            panTimer = setTimeout(function() {
                pan(domNode, speed, direction);
            }, 50);
        }
    }

    // 为可缩放树定义缩放函数

    function zoom() {
        svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
    }


    // 定义zoomListener,它在缩放范围内约束的“缩放”事件上调用缩放函数
    var zoomListener = d3.behavior.zoom().scaleExtent([0.1, 3]).on("zoom", zoom);

    function initiateDrag(d, domNode) {
        draggingNode = d;
        d3.select(domNode).select('.ghostCircle').attr('pointer-events', 'none');
        d3.selectAll('.ghostCircle').attr('class', 'ghostCircle show');
        d3.select(domNode).attr('class', 'node activeDrag');

        svgGroup.selectAll("g.node").sort(function(a, b) { // select the parent and sort the path's
            if (a.id != draggingNode.id) return 1; // a is not the hovered element, send "a" to the back
            else return -1; // a is the hovered element, bring "a" to the front
        });
        // if nodes has children, remove the links and nodes
        if (nodes.length > 1) {
            // remove link paths
            links = tree.links(nodes);
            nodePaths = svgGroup.selectAll("path.link")
                .data(links, function(d) {
                    return d.target.id;
                }).remove();
            // remove child nodes
            nodesExit = svgGroup.selectAll("g.node")
                .data(nodes, function(d) {
                    return d.id;
                }).filter(function(d, i) {
                    if (d.id == draggingNode.id) {
                        return false;
                    }
                    return true;
                }).remove();
        }

        // remove parent link
        parentLink = tree.links(tree.nodes(draggingNode.parent));
        svgGroup.selectAll('path.link').filter(function(d, i) {
            if (d.target.id == draggingNode.id) {
                return true;
            }
            return false;
        }).remove();

        dragStarted = null;
    }

    // 定义菜单选项
    var userMenuData = [
      [{
          text: "新建",
          func: function () {
            console.log(this)
            alert("新建"+ this.id)
          }
        },
        {
          text: "编辑",
          func: function () {
            alert("编辑"+ this.id)
          }
        },
        {
          text: "删除",
          func: function () {
            alert("删除"+ this.id)
          }
        }
      ]
    ];
    // 事件监听方式添加事件绑定
    $("body").smartMenu(userMenuData, {
      name: "chatRightControl",
      container: "g.node"
    });

    // 定义baseSvg,附加一个用于样式化的类和zoomListener
    var baseSvg = d3.select("#tree-container").append("svg")
        .attr("width", viewerWidth)
        .attr("height", viewerHeight)
        .attr("class", "overlay")
        .call(zoomListener);


    // 为节点的拖放行为定义拖放侦听器.
    dragListener = d3.behavior.drag()
        .on("dragstart", function(d) {
            if (d == root) {
                return;
            }
            dragStarted = true;
            nodes = tree.nodes(d);
            d3.event.sourceEvent.stopPropagation();
            // it's important that we suppress the mouseover event on the node being dragged. Otherwise it will absorb the mouseover event and the underlying node will not detect it d3.select(this).attr('pointer-events', 'none');
        })
        .on("drag", function(d) {
            if (d == root) {
                return;
            }
            if (dragStarted) {
                domNode = this;
                initiateDrag(d, domNode);
            }

            // get coords of mouseEvent relative to svg container to allow for panning
            relCoords = d3.mouse($('svg').get(0));
            if (relCoords[0] < panBoundary) {
                panTimer = true;
                pan(this, 'left');
            } else if (relCoords[0] > ($('svg').width() - panBoundary)) {

                panTimer = true;
                pan(this, 'right');
            } else if (relCoords[1] < panBoundary) {
                panTimer = true;
                pan(this, 'up');
            } else if (relCoords[1] > ($('svg').height() - panBoundary)) {
                panTimer = true;
                pan(this, 'down');
            } else {
                try {
                    clearTimeout(panTimer);
                } catch (e) {

                }
            }

            d.x0 += d3.event.dy;
            d.y0 += d3.event.dx;
            var node = d3.select(this);
            node.attr("transform", "translate(" + d.y0 + "," + d.x0 + ")");
            updateTempConnector();
        }).on("dragend", function(d) {
            if (d == root) {
                return;
            }
            domNode = this;
            if (selectedNode) {
                // now remove the element from the parent, and insert it into the new elements children
                var index = draggingNode.parent.children.indexOf(draggingNode);
                if (index > -1) {
                    draggingNode.parent.children.splice(index, 1);
                }
                if (typeof selectedNode.children !== 'undefined' || typeof selectedNode._children !== 'undefined') {
                    if (typeof selectedNode.children !== 'undefined') {
                        selectedNode.children.push(draggingNode);
                    } else {
                        selectedNode._children.push(draggingNode);
                    }
                } else {
                    selectedNode.children = [];
                    selectedNode.children.push(draggingNode);
                }
                // Make sure that the node being added to is expanded so user can see added node is correctly moved
                expand(selectedNode);
                sortTree();
                endDrag();
            } else {
                endDrag();
            }
        });

    function endDrag() {
        selectedNode = null;
        d3.selectAll('.ghostCircle').attr('class', 'ghostCircle');
        d3.select(domNode).attr('class', 'node');
        // now restore the mouseover event or we won't be able to drag a 2nd time
        d3.select(domNode).select('.ghostCircle').attr('pointer-events', '');
        updateTempConnector();
        if (draggingNode !== null) {
            update(root);
            centerNode(draggingNode);
            draggingNode = null;
        }
    }

    // 用于折叠和展开节点的辅助函数.

    function collapse(d) {
        if (d.children) {
            d._children = d.children;
            d._children.forEach(collapse);
            d.children = null;
        }
    }

    function expand(d) {
        if (d._children) {
            d.children = d._children;
            d.children.forEach(expand);
            d._children = null;
        }
    }

    var overCircle = function(d) {
        selectedNode = d;
        updateTempConnector();
    };
    var outCircle = function(d) {
        selectedNode = null;
        updateTempConnector();
    };

    // 函数更新指示拖动关联的临时连接器
    var updateTempConnector = function() {
        var data = [];
        if (draggingNode !== null && selectedNode !== null) {
            // have to flip the source coordinates since we did this for the existing connectors on the original tree
            data = [{
                source: {
                    x: selectedNode.y0,
                    y: selectedNode.x0
                },
                target: {
                    x: draggingNode.y0,
                    y: draggingNode.x0
                }
            }];
        }
        var link = svgGroup.selectAll(".templink").data(data);

        link.enter().append("path")
            .attr("class", "templink")
            .attr("d", d3.svg.diagonal())
            .attr('pointer-events', 'none');

        link.attr("d", d3.svg.diagonal());

        link.exit().remove();
    };

    // 函数在单击/删除时指向中心节点,这样在折叠/移动大量子节点时节点不会丢失.

    function centerNode(source) {
        scale = zoomListener.scale();
        x = -source.y0;
        y = -source.x0;
        x = x * scale + viewerWidth / 2;
        y = y * scale + viewerHeight / 2;
        d3.select('g').transition()
            .duration(duration)
            .attr("transform", "translate(" + x + "," + y + ")scale(" + scale + ")");
        zoomListener.scale(scale);
        zoomListener.translate([x, y]);
    }

    // 切换孩子函数

    function toggleChildren(d) {
        if (d.children) {
            d._children = d.children;
            d.children = null;
        } else if (d._children) {
            d.children = d._children;
            d._children = null;
        }
        return d;
    }

    // 切换子节点点击.

    function click(d) {
        if (d3.event.defaultPrevented) return; // click suppressed
        d = toggleChildren(d);
        update(d);
        centerNode(d);
    }

    function update(source) {
        // 计算新的高度,函数计算根节点的所有子节点并相应地设置树的高度.
        // 这可以防止在新节点可见时布局看起来被压扁,或者在删除节点时布局看起来稀疏
        // This makes the layout more consistent.
        var levelWidth = [1];
        var childCount = function(level, n) {

            if (n.children && n.children.length > 0) {
                if (levelWidth.length <= level + 1) levelWidth.push(0);

                levelWidth[level + 1] += n.children.length;
                n.children.forEach(function(d) {
                    childCount(level + 1, d);
                });
            }
        };
        childCount(0, root);
        var newHeight = d3.max(levelWidth) * 25; // 25 pixels per line  
        tree = tree.size([newHeight, viewerWidth]);

        // 计算新的树布局.
        var nodes = tree.nodes(root).reverse(),
            links = tree.links(nodes);

        // Set widths between levels based on maxLabelLength.
        nodes.forEach(function(d) {
            d.y = (d.depth * (maxLabelLength * 10)); //maxLabelLength * 10px
            // alternatively to keep a fixed scale one can set a fixed depth per level
            // Normalize for fixed-depth by commenting out below line
            // d.y = (d.depth * 500); //500px per level.
        });

        // Update the nodes…
        node = svgGroup.selectAll("g.node")
            .data(nodes, function(d) {
                return d.id || (d.id = ++i);
            });

        // 在父节点之前的位置输入任何新节点.
        var nodeEnter = node.enter().append("g")
            .call(dragListener)
            .attr("class", "node")
            .attr("id", function(d) {
                console.log(d)
                 return d.id
            })
            .attr("transform", function(d) {
                return "translate(" + source.y0 + "," + source.x0 + ")";
            })
            .on('click', click);

        nodeEnter.append("rect")
            .attr('class', 'nodeCircle')
            .attr("width", 6)
            .attr("height", 6)
            .attr("y", -3)
            .attr("x", 0)
            .style("fill", function(d) {
                if ( d._children || d.children ){
                    if (d.nodeInfo.status === "未执行") {
                        return "#909399"
                    } else if(d.nodeInfo.status === "正常") {
                        return "#67C23A"
                    } else if(d.nodeInfo.status === "异常") {
                        return "#F56C6C"
                    }
                } else {
                    return "#fff"
                }
                
            })
            .style("stroke", function(d) {
                if (d.nodeInfo.status === "未执行") {
                    return "#d3d4d6"
                } else if(d.nodeInfo.status === "正常") {
                    return "#c2e7b0"
                } else if(d.nodeInfo.status === "异常") {
                    return "#fbc4c4"
                }
            })
            .style("stroke-width", 1)

        nodeEnter.append("text")
            .attr("x", function(d) {
                return d.children || d._children ? -10 : 10;
            })
            .attr("dy", ".35em")
            .attr('class', 'nodeText')
            .attr("text-anchor", function(d) {
                return d.children || d._children ? "end" : "start";
            })
            .text(function(d) {
                return d.label;
            })
            .style("fill-opacity", 0);

        // 幻影节点,让我们鼠标在它周围的半径内移动
        nodeEnter.append("rect")
            .attr('class', 'ghostCircle')
            .attr("width", 16)
            .attr("height", 16)
            .attr("y", -8)
            .attr("x", -5)
            .attr("opacity", 0.2) // change this to zero to hide the target area
        .style("fill", "red")
            .attr('pointer-events', 'mouseover')
            .on("mouseover", function(node) {
                overCircle(node);
            })
            .on("mouseout", function(node) {
                outCircle(node);
            });

        // 更新文本以反映节点是否有子节点  .
        node.select('text')
            .attr("x", function(d) {
                return d.children || d._children ? -10 : 10;
            })
            .attr("text-anchor", function(d) {
                return d.children || d._children ? "end" : "start";
            })
            .text(function(d) {
                return d.label;
            });

        // 根据是否有子元素和是否折叠来更改圆的填充
        node.select("circle.nodeCircle")
            .attr("r", 4.5)
            .style("fill", function(d) {
                return d._children ? "#00569e" : "#fff";
            });

        // Transition nodes to their new position.
        var nodeUpdate = node.transition()
            .duration(duration)
            .attr("transform", function(d) {
                return "translate(" + d.y + "," + d.x + ")";
            });

        // Fade the text in
        nodeUpdate.select("text")
            .style("fill-opacity", 1);

        // Transition exiting nodes to the parent's new position.
        var nodeExit = node.exit().transition()
            .duration(duration)
            .attr("transform", function(d) {
                return "translate(" + source.y + "," + source.x + ")";
            })
            .remove();

        nodeExit.select("circle")
            .attr("r", 0);

        nodeExit.select("text")
            .style("fill-opacity", 0);

        // Update the links…
        var link = svgGroup.selectAll("path.link")
            .data(links, function(d) {
                return d.target.id;
            });

        // Enter any new links at the parent's previous position.
        link.enter().insert("path", "g")
            .attr("class", "link")
            .style("stroke", function(d) {
                if (d.source.nodeInfo.status === "未执行") {
                    return "#d3d4d6"
                } else if(d.source.nodeInfo.status === "正常") {
                    return "#c2e7b0"
                } else if(d.source.nodeInfo.status === "异常") {
                    return "#fbc4c4"
                }
            })
            .attr("d", function(d) {
                var o = {
                    x: source.x0,
                    y: source.y0
                };
                return diagonal({
                    source: o,
                    target: o
                });
            });

        // Transition links to their new position.
        link.transition()
            .duration(duration)
            .attr("d", diagonal);

        // Transition exiting nodes to the parent's new position.
        link.exit().transition()
            .duration(duration)
            .attr("d", function(d) {
                var o = {
                    x: source.x,
                    y: source.y
                };
                return diagonal({
                    source: o,
                    target: o
                });
            })
            .remove();

        // Stash the old positions for transition.
        nodes.forEach(function(d) {
            d.x0 = d.x;
            d.y0 = d.y;
        });
    }

    // Append a group which holds all nodes and which the zoom Listener can act upon.
    var svgGroup = baseSvg.append("g");

    // Define the root
    root = treeData;
    root.x0 = viewerHeight / 2;
    root.y0 = 0;

    // Layout the tree initially and center on the root node.
    update(root);
    centerNode(root);
});

3.flare.json

{
  "nodeInfo" : {
    "id" : 0,
    "roomId" : 0,
    "stepIndex" : 0,
    "title" : "root节点",
    "remark" : "ROOT节点",
    "taskPhase" : "事前",
    "triggerMode" : "自动",
    "information" : null,
    "levels" : 0,
    "keywords" : null,
    "isNode" : null,
    "sequence" : 0,
    "parentId" : -1,
    "broadcast" : 0,
    "broadcastInfo" : null,
    "im" : 0,
    "imInfo" : null,
    "send" : 0,
    "sendInfo" : null,
    "status" : "正常",
    "createTime" : "2019-06-25 11:25:24",
    "updateTime" : null,
    "hibernateLazyInitializer" : { }
  },
  "label" : "root节点",
  "id" : 0,
  "parentId" : -1,
  "children" : [ {
    "nodeInfo" : {
      "id" : 4,
      "roomId" : 1,
      "stepIndex" : 5,
      "title" : "场景二",
      "remark" : null,
      "taskPhase" : "事前",
      "triggerMode" : "自动",
      "information" : null,
      "levels" : 1,
      "keywords" : null,
      "isNode" : null,
      "sequence" : 1,
      "parentId" : 0,
      "broadcast" : 0,
      "broadcastInfo" : null,
      "im" : 0,
      "imInfo" : null,
      "send" : 0,
      "sendInfo" : null,
      "status" : "正常",
      "createTime" : "2019-06-25 11:27:58",
      "updateTime" : null
    },
    "label" : "场景二",
    "id" : 4,
    "parentId" : 0,
    "children" : [ {
      "nodeInfo" : {
        "id" : 16,
        "roomId" : 1,
        "stepIndex" : null,
        "title" : "任务协调",
        "remark" : "新增平级任务",
        "taskPhase" : "事中",
        "triggerMode" : "手动",
        "information" : null,
        "levels" : 2,
        "keywords" : null,
        "isNode" : null,
        "sequence" : 4,
        "parentId" : 4,
        "broadcast" : 0,
        "broadcastInfo" : null,
        "im" : 0,
        "imInfo" : null,
        "send" : 0,
        "sendInfo" : null,
        "status" : "未执行",
        "createTime" : "2019-06-25 17:19:53",
        "updateTime" : null
      },
      "label" : "任务协调",
      "id" : 16,
      "parentId" : 4,
      "children" : [ ]
    }, {
      "nodeInfo" : {
        "id" : 25,
        "roomId" : 1,
        "stepIndex" : null,
        "title" : "哦总结阶级",
        "remark" : "新增平级任务",
        "taskPhase" : "事后",
        "triggerMode" : "规则",
        "information" : null,
        "levels" : 2,
        "keywords" : null,
        "isNode" : null,
        "sequence" : 9,
        "parentId" : 4,
        "broadcast" : 0,
        "broadcastInfo" : null,
        "im" : 0,
        "imInfo" : null,
        "send" : 0,
        "sendInfo" : null,
        "status" : "异常",
        "createTime" : "2019-06-25 19:17:46",
        "updateTime" : null
      },
      "label" : "哦总结阶级",
      "id" : 25,
      "parentId" : 4,
      "children" : [ {
        "nodeInfo" : {
          "id" : 26,
          "roomId" : 1,
          "stepIndex" : null,
          "title" : "下发一",
          "remark" : "下发子任务",
          "taskPhase" : "事中",
          "triggerMode" : "规则",
          "information" : null,
          "levels" : 3,
          "keywords" : null,
          "isNode" : null,
          "sequence" : 1,
          "parentId" : 25,
          "broadcast" : 0,
          "broadcastInfo" : null,
          "im" : 0,
          "imInfo" : null,
          "send" : 0,
          "sendInfo" : null,
          "status" : "正常",
          "createTime" : "2019-06-25 19:19:51",
          "updateTime" : null
        },
        "label" : "下发一",
        "id" : 26,
        "parentId" : 25,
        "children" : [ ]
      } ]
    }, {
      "nodeInfo" : {
        "id" : 5,
        "roomId" : 1,
        "stepIndex" : 6,
        "title" : "启动节点",
        "remark" : "测试场景任务",
        "taskPhase" : "事前",
        "triggerMode" : "自动",
        "information" : null,
        "levels" : 2,
        "keywords" : null,
        "isNode" : null,
        "sequence" : 1,
        "parentId" : 4,
        "broadcast" : 0,
        "broadcastInfo" : null,
        "im" : 0,
        "imInfo" : null,
        "send" : 0,
        "sendInfo" : null,
        "status" : "正常",
        "createTime" : "2019-06-25 10:42:49",
        "updateTime" : null
      },
      "label" : "启动节点",
      "id" : 5,
      "parentId" : 4,
      "children" : [ {
        "nodeInfo" : {
          "id" : 17,
          "roomId" : 1,
          "stepIndex" : null,
          "title" : "任务启动二",
          "remark" : "下发子任务",
          "taskPhase" : "事前",
          "triggerMode" : "自动",
          "information" : null,
          "levels" : 3,
          "keywords" : null,
          "isNode" : null,
          "sequence" : 2,
          "parentId" : 5,
          "broadcast" : 0,
          "broadcastInfo" : null,
          "im" : 0,
          "imInfo" : null,
          "send" : 0,
          "sendInfo" : null,
          "status" : "正常",
          "createTime" : "2019-06-25 17:20:35",
          "updateTime" : null
        },
        "label" : "任务启动二",
        "id" : 17,
        "parentId" : 5,
        "children" : [ ]
      } ]
    }, {
      "nodeInfo" : {
        "id" : 6,
        "roomId" : 1,
        "stepIndex" : 7,
        "title" : "网络巡检及隐患整治",
        "remark" : "测试场景任务",
        "taskPhase" : "事中",
        "triggerMode" : "手动",
        "information" : null,
        "levels" : 2,
        "keywords" : null,
        "isNode" : null,
        "sequence" : 2,
        "parentId" : 4,
        "broadcast" : 0,
        "broadcastInfo" : null,
        "im" : 0,
        "imInfo" : null,
        "send" : 0,
        "sendInfo" : null,
        "status" : "正常",
        "createTime" : "2019-06-25 10:43:00",
        "updateTime" : null
      },
      "label" : "网络巡检及隐患整治",
      "id" : 6,
      "parentId" : 4,
      "children" : [ {
        "nodeInfo" : {
          "id" : 22,
          "roomId" : 1,
          "stepIndex" : null,
          "title" : "隐患整治一",
          "remark" : "下发子任务",
          "taskPhase" : "事前",
          "triggerMode" : "自动",
          "information" : null,
          "levels" : 3,
          "keywords" : null,
          "isNode" : null,
          "sequence" : 2,
          "parentId" : 6,
          "broadcast" : 0,
          "broadcastInfo" : null,
          "im" : 0,
          "imInfo" : null,
          "send" : 0,
          "sendInfo" : null,
          "status" : "正常",
          "createTime" : "2019-06-25 18:07:26",
          "updateTime" : null
        },
        "label" : "隐患整治一",
        "id" : 22,
        "parentId" : 6,
        "children" : [ ]
      }, {
        "nodeInfo" : {
          "id" : 21,
          "roomId" : 1,
          "stepIndex" : null,
          "title" : "网络巡检一",
          "remark" : "下发子任务",
          "taskPhase" : "事前",
          "triggerMode" : "手动",
          "information" : null,
          "levels" : 3,
          "keywords" : null,
          "isNode" : null,
          "sequence" : 1,
          "parentId" : 6,
          "broadcast" : 0,
          "broadcastInfo" : null,
          "im" : 0,
          "imInfo" : null,
          "send" : 0,
          "sendInfo" : null,
          "status" : "正常",
          "createTime" : "2019-06-25 18:06:35",
          "updateTime" : null
        },
        "label" : "网络巡检一",
        "id" : 21,
        "parentId" : 6,
        "children" : [ ]
      }, {
        "nodeInfo" : {
          "id" : 24,
          "roomId" : 11,
          "stepIndex" : null,
          "title" : "11",
          "remark" : "下发子任务",
          "taskPhase" : null,
          "triggerMode" : null,
          "information" : null,
          "levels" : 3,
          "keywords" : null,
          "isNode" : null,
          "sequence" : null,
          "parentId" : 6,
          "broadcast" : 0,
          "broadcastInfo" : null,
          "im" : 0,
          "imInfo" : null,
          "send" : 0,
          "sendInfo" : null,
          "status" : "正常",
          "createTime" : "2019-06-25 18:50:59",
          "updateTime" : null
        },
        "label" : "11",
        "id" : 24,
        "parentId" : 6,
        "children" : [ ]
      } ]
    }, {
      "nodeInfo" : {
        "id" : 7,
        "roomId" : 1,
        "stepIndex" : 8,
        "title" : "应急资源检查",
        "remark" : "测试场景任务",
        "taskPhase" : "事前",
        "triggerMode" : "自动",
        "information" : null,
        "levels" : 2,
        "keywords" : null,
        "isNode" : null,
        "sequence" : 3,
        "parentId" : 4,
        "broadcast" : 0,
        "broadcastInfo" : null,
        "im" : 0,
        "imInfo" : null,
        "send" : 0,
        "sendInfo" : null,
        "status" : "正常",
        "createTime" : "2019-06-25 10:43:11",
        "updateTime" : null
      },
      "label" : "应急资源检查",
      "id" : 7,
      "parentId" : 4,
      "children" : [ ]
    }, {
      "nodeInfo" : {
        "id" : 8,
        "roomId" : 1,
        "stepIndex" : 9,
        "title" : "保障开始",
        "remark" : "测试场景任务",
        "taskPhase" : "事中",
        "triggerMode" : "手动",
        "information" : null,
        "levels" : 2,
        "keywords" : null,
        "isNode" : null,
        "sequence" : 4,
        "parentId" : 4,
        "broadcast" : 0,
        "broadcastInfo" : null,
        "im" : 0,
        "imInfo" : null,
        "send" : 0,
        "sendInfo" : null,
        "status" : "正常",
        "createTime" : "2019-06-25 10:43:21",
        "updateTime" : null
      },
      "label" : "保障开始",
      "id" : 8,
      "parentId" : 4,
      "children" : [ ]
    }, {
      "nodeInfo" : {
        "id" : 9,
        "roomId" : 1,
        "stepIndex" : 10,
        "title" : "突发状态应急预案",
        "remark" : "测试场景任务",
        "taskPhase" : "事中",
        "triggerMode" : "自动",
        "information" : null,
        "levels" : 2,
        "keywords" : null,
        "isNode" : null,
        "sequence" : 5,
        "parentId" : 4,
        "broadcast" : 0,
        "broadcastInfo" : null,
        "im" : 0,
        "imInfo" : null,
        "send" : 0,
        "sendInfo" : null,
        "status" : "正常",
        "createTime" : "2019-06-25 10:43:33",
        "updateTime" : null
      },
      "label" : "突发状态应急预案",
      "id" : 9,
      "parentId" : 4,
      "children" : [ ]
    }, {
      "nodeInfo" : {
        "id" : 10,
        "roomId" : 1,
        "stepIndex" : 11,
        "title" : "保障总结",
        "remark" : "测试场景任务",
        "taskPhase" : "事后",
        "triggerMode" : "手动",
        "information" : null,
        "levels" : 2,
        "keywords" : null,
        "isNode" : null,
        "sequence" : 6,
        "parentId" : 4,
        "broadcast" : 0,
        "broadcastInfo" : null,
        "im" : 0,
        "imInfo" : null,
        "send" : 0,
        "sendInfo" : null,
        "status" : "正常",
        "createTime" : "2019-06-25 10:43:47",
        "updateTime" : null
      },
      "label" : "保障总结",
      "id" : 10,
      "parentId" : 4,
      "children" : [ ]
    } ]
  } ]
}

 

你可能感兴趣的:(UI)