Browse Source

add new agg graph

梅杰 6 years ago
parent
commit
72acb96473

File diff suppressed because it is too large
+ 97 - 84
.idea/workspace.xml


+ 5 - 0
src/main/java/com/mooctest/controller/GraphController.java

@@ -44,6 +44,11 @@ public class GraphController {
 
         return graphService.buildAggReportGraph(masterId);
     }
+    @GetMapping(value = "/tree")
+    public JSONObject getTreeData(@RequestParam("masterId") String masterId) {
+
+        return graphService.buildAggReportTree(masterId);
+    }
 
     @GetMapping(value = "/graphDetail/rawReport")
     public void renderRawReport(@RequestParam("bugId") String bugId,

+ 2 - 2
src/main/java/com/mooctest/controller/ReportController.java

@@ -56,7 +56,7 @@ public class ReportController {
     @GetMapping(value = "/report_test")
     public String report(HttpServletRequest request, @RequestParam(value = "name", required = false, defaultValue = "springboot-thymeleaf") String name) {
         request.setAttribute("name", name);
-        return "aggr_report";
+        return "agg_report";
     }
 
     @GetMapping(value = "/report")
@@ -97,7 +97,7 @@ public class ReportController {
             model.addAttribute("editReport", finalReportDTO.get());
 
         }
-        return "aggr_report";
+        return "agg_report_new";
     }
 
     private String getWordCloudList(List<BugDTO> sourceReports) {

+ 49 - 0
src/main/java/com/mooctest/service/GraphService.java

@@ -20,6 +20,55 @@ public class GraphService {
     @Autowired
     SupplementDao supplementDao;
 
+    public JSONObject buildAggReportTree(String masterId) {
+        List<SupplementItem> supplementItems = supplementDao.findByMasterId(masterId);
+        Map<String, List<SupplementItem>> supplementMap = supplementItems.stream()
+                .collect(groupingBy(SupplementItem::getSupplementId));
+
+        JSONObject root = new JSONObject();
+        root.fluentPut("id", "agg_" + masterId)
+                .fluentPut("group", 1)
+                .fluentPut("name", "聚合报告")
+                .fluentPut("href", "/graphDetail/aggReport?masterId=" + masterId);
+        int idx = 1;
+
+        JSONArray supNodes = new JSONArray();
+        //add sup correspond with raw node
+        for (Map.Entry<String, List<SupplementItem>> entry : supplementMap.entrySet()) {
+            String supId = entry.getKey();
+            List<SupplementItem> items = entry.getValue();
+            JSONObject supNode = new JSONObject();
+
+            //add sup report node
+            supNode.fluentPut("id", supId)
+                    .fluentPut("group", 2)
+                    .fluentPut("name", "补充点" + idx)
+                    .fluentPut("href", "/graphDetail/supReport?supId="+supId+"&masterId="+masterId);
+            supNodes.add(supNode);
+
+            //add raw report node
+            List<String> bugIds = items.stream()
+                    .map(SupplementItem::getBugId)
+                    .distinct()
+                    .collect(Collectors.toList());
+
+            JSONArray rawNodes = new JSONArray();
+            for (int i = 0; i < bugIds.size(); i++) {
+                String bugId = bugIds.get(i);
+                JSONObject rawNode = new JSONObject();
+                rawNode.fluentPut("id", bugId)
+                        .fluentPut("group", 3)
+                        .fluentPut("name", "R" + bugId.substring(12))
+                        .fluentPut("href", "/graphDetail/rawReport?bugId="+bugId);
+                rawNodes.add(rawNode);
+            }
+            supNode.put("children", rawNodes);
+            idx++;
+        }
+        root.put("children", supNodes);
+        return root;
+    }
+
     public JSONObject buildAggReportGraph(String masterId) {
         List<SupplementItem> supplementItems = supplementDao.findByMasterId(masterId);
         Map<String, List<SupplementItem>> supplementMap = supplementItems.stream()

+ 2 - 1
src/main/java/com/mooctest/service/TaskService.java

@@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Random;
 import java.util.stream.Collectors;
@@ -57,7 +58,7 @@ public class TaskService {
                         taskDTO.setNumOfUndeal(0);
                     }
                     return taskDTO;
-                })
+                }).sorted(Comparator.comparing(TaskDTO::getStatus))
                 .collect(Collectors.toList());
 
     }

+ 1 - 1
src/main/java/com/mooctest/util/MongoAPIUtil.java

@@ -14,7 +14,7 @@ public class MongoAPIUtil {
     public static final String CO_REPORT_DB = "co-report";
     public static final String REPORT_COLLECTION = "report";
     public static final String BUG_HISTORY_COLLECTION = "bugHistory";
-    public static final String BASE64_AUTH = "Basic YWRtaW46Y2hhbmdlaXQ=";
+    public static final String BASE64_AUTH = "Basic YWRtaW46MTIzdHNldGNvb20=";
 
     public static final String WITH_MAX_PAGE_SIZE = "&count&page=1&pagesize=1000";
 

+ 123 - 0
src/main/resources/static/css/agg_report_new.css

@@ -0,0 +1,123 @@
+/*#nav-header {
+  padding: 0px 78px;
+}*/
+
+.table {
+    font-size: 12px;
+}
+
+.agg-title.panel-heading {
+    border-bottom: 0px;
+}
+
+.agg-title.panel-heading span{
+    margin-left: -8px;
+}
+
+.detail-table .box-header, .source-table .box-header, .attr-title {
+    /*background-color: #f5f5f5;*/
+    font-weight: bold;
+}
+
+.dup-supplementary .list-group .list-group-item {
+    border: 0px;
+}
+
+.dup-supplementary .list-group .list-group-item .list-group .list-group-item {
+    /*border-bottom: 1px dashed #ddd;*/
+}
+
+.source-table .list-group-item {
+    #border-bottom: 0px;
+    border-top: 1px dashed #ddd;
+    border-left: 0px;
+    border-right: 0px;
+}
+
+/* force svg */
+.svg-div {
+    /*background-color: #f5f5f5;*/
+    /*border: 3px solid #f5f5f5;*/
+}
+
+.detail-div {
+    /*background-color: #f5f5f5;*/
+    /*border: 3px solid #f5f5f5;*/
+}
+
+.links line {
+    /*stroke: #999;*/
+    stroke: #509AE5;
+    stroke-opacity: 0.8;
+    stroke-width: 1.5px;
+}
+
+.node circle {
+    stroke: #fff;
+    stroke-width: 1.5px;
+}
+
+.node text {
+    /*display: none;*/
+    font: 14px sans-serif;
+    /*font-weight: bold;*/
+    fill: black;
+}
+/*.nodeCircle.raw {*/
+/*stroke: rgb(130, 57, 53);*/
+/*}*/
+/*.nodeCircle.sup {*/
+/*stroke: rgb(137, 190, 178);*/
+/*}*/
+/*.nodeCircle.agg {*/
+/*stroke: rgb(222, 211, 140);*/
+/*}*/
+.node:hover {
+    cursor: pointer;
+}
+
+.node:hover text {
+    display: inline;
+}
+
+/* detail side */
+.detail-div .list-group {
+    margin-bottom: 0px;
+}
+
+.detail-div .list-group-item {
+    border-top: 0px;
+    border-left: 0px;
+    border-right: 0px;
+    border-bottom: 1px solid #ddd;
+}
+
+.detail-div .list-group-item:last-child {
+    border-bottom: none;
+}
+
+.detail-div .list-group-item:first-child {
+    border-top-left-radius: 0px;
+    border-top-right-radius: 0px;
+}
+
+.detail-div .sup-list .list-group-item {
+    border-top: 0px;
+    border-left: 0px;
+    border-right: 0px;
+    border-bottom: 1px dashed #ddd;
+}
+
+.detail-div .sup-list .list-group-item:last-child {
+    border-bottom: none;
+}
+
+svg .link {
+    fill: none;
+    stroke-width: 1.5px;
+    stroke: #509AE5;
+    stroke-opacity: 0.8;
+}
+/*#summary .table .td {
+	padding: 4px;
+}*/

+ 144 - 0
src/main/resources/static/js/agg_report_new.js

@@ -0,0 +1,144 @@
+$(function () {
+
+    function createImg(src) {
+        var $img = $('<img />')
+        $img.attr("src", src);
+        $img.attr("class", "my-img-thumbnail pointer to-delete");
+        $img.on("click", function (){
+            showimage(src);
+        });
+        return $img;
+    }
+    $(".to-add").on("dragend", function (e) {
+
+        var src = $(e.target).attr("src");
+        if (images.indexOf(src) < 0) {
+
+            images.push(src);
+
+            var $img = createImg(src);
+            $img.on("dragend", function (e) {
+                var src = $(e.target).attr("src");
+                var idx = images.indexOf(src);
+                if (idx >= 0) {
+                    images.splice(idx, 1);
+                }
+
+                $(e.target).remove();
+            });
+
+
+            $("#new-report-img").append($img)
+        }
+    });
+
+
+
+    $('.sup-collapse').click(function () {
+        var dupTitle = $(this).parents('li').find('.sup-title');
+        dupTitle.toggle();
+    });
+
+    var color = {
+        1: '#E36402',
+        2: '#1995CF',
+        3 : '#FFC000',
+        2.1: '#FFC000'
+    };
+
+    var urlParams = new URLSearchParams(window.location.search);
+    d3.json("/tree?masterId=" + urlParams.get("masterId"), function(error, data) {
+        var root = d3.hierarchy(data);
+
+        var normal_r = 14;
+        var mouseon_r = 18;
+
+        var handleEvents = function (selection) {
+            selection.on('click', function (d) {
+                $.get(
+                    d.data.href,
+                    function (data) {
+                        $('.detail-div').css('background-color', 'white');
+                        $('.detail-div').html(data);
+                    });
+            })
+                .on('mouseover', function (d) {
+
+                var g = d3.select(this); // The node
+                var n = g.select('.the-node');
+                var info = n.transition().duration(400).attr('r', 47 / d.data.group)
+            })
+                .on('mouseout', function (d) {
+                    var g = d3.select(this); // The node
+                    var n = g.select('.the-node');
+                    var info = n.transition().duration(400).attr('r', 40 / d.data.group)
+                });
+        }
+
+        /* TREE LAYOUT */
+
+
+        var treeLayout = d3.tree()
+        treeLayout.size([660, 250]);
+        treeLayout(root);
+
+
+        var tree = d3.select('#tree g.nodes')
+
+        var treeNodes = tree.selectAll('g.node')
+            .data(root.descendants())
+            .enter()
+            .append('g')
+            .classed('node', true)
+            .call(handleEvents)
+
+
+        treeNodes.append('circle')
+            .classed('the-node solid', true)
+            .attr('cx', d => d.x)
+            .attr('cy', d => d.y + 20)
+            .attr('r', d => 40 / d.data.group)
+            .style("fill", function (d) {
+                return color[d.data.group]
+            });
+
+        treeNodes.append('text')
+            .attr('class', 'label')
+            .attr('dx', function (d) {
+                return (d.data.group == 3) ? d.x - 40 / d.data.group : d.x + 40 / d.data.group + 5
+            })
+            .attr('dy', function (d) {
+                return (d.data.group == 3) ? d.y + 54 : d.y + 24
+            })
+            .text(d => d.data.name)
+
+        // var treeLinks = d3.select('#tree g.links')
+        //     .selectAll('line.link')
+        //     .data(root.links())
+        //     .enter()
+        //     .append('line')
+        //     .classed('link', true)
+        //     .attr("x1", d => d.source.x)
+        //     .attr("y1", d => d.source.y)
+        //     .attr("x2", d => d.target.x)
+        //     .attr("y2", d => d.target.y)
+        //     .style("stroke", "#5f5f5f");
+
+        var treeLinks = d3.select('#tree g.links')
+            .selectAll('path.link')
+            .data(root.descendants().slice(1))
+            .enter()
+            .append('path')
+            .classed('link', true)
+            .attr("d", (d) => {
+                return `
+      M ${d.x} ${d.y}
+      C 
+      ${d.x} ${(d.y + d.parent.y) / 2}
+      ${d.parent.x} ${(d.y + d.parent.y) / 2}
+      ${d.parent.x} ${d.parent.y}
+      `;
+            })
+            .style("stroke", "#5f5f5f");
+    });
+});

+ 519 - 0
src/main/resources/templates/agg_report_new.html

@@ -0,0 +1,519 @@
+<!DOCTYPE html>
+<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org"
+      xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
+      layout:decorator="main">
+<head>
+    <link rel="stylesheet" type="text/css" href="/static/css/main.css"/>
+    <link rel="stylesheet" type="text/css" href="/static/css/agg_report_new.css"/>
+    <link rel="stylesheet" type="text/css" href="/static/css/word_cloud.css"/>
+</head>
+<body>
+<th:block layout:fragment="sidebar">
+
+    <li>
+        <a th:href="'/final_reports?examId=' + ${examId} + '&amp;caseId=' + ${caseId}">
+            <i class="fa fa-calendar-check-o"></i>
+            <span>预交付报告</span>
+        </a>
+    </li>
+    <li class="treeview">
+        <a href="#">
+            <i class="fa fa-list"></i>
+            <span>Reports</span>
+            <span class="pull-right-container">
+			<i class="fa fa-angle-left pull-right"></i>
+		</span>
+        </a>
+        <ul class="treeview-menu" style="display: block;">
+            <li>
+                <a th:href="'/task_detail?examId='+${examId}+'&amp;caseId='+${caseId}">
+                    <i class="fa fa-sticky-note text-success"></i>
+                    <span>默认视图</span>
+                </a>
+            </li>
+            <li>
+                <a th:href="'/agg_report_list?examId='+${examId}+'&amp;caseId='+${caseId}">
+                    <i class="fa fa-sitemap text-warning"></i>
+                    <span>聚合视图</span>
+                </a>
+            </li>
+
+
+        </ul>
+    </li>
+</th:block>
+<th:block layout:fragment="maincontent">
+
+    <section class="content-header">
+        <h1>融合报告详情
+            <small th:text="${aggReportId}"></small>
+        </h1>
+        <!-- <h1>Summary for report 0-5</h1> -->
+        <!-- <small style="font-style: italic;">at 50% report-level and 25% supplementary level</small> -->
+
+        <ol class="breadcrumb">
+            <!-- style="margin-right: 173px;" -->
+            <li>
+                <a href="/home">
+                    <i class="fa fa-dashboard"></i>
+                    全部任务
+                </a>
+            </li>
+            <li>
+                <a th:href="'/agg_report_list?examId='+${examId}+'&amp;caseId='+${caseId}">
+                    审核列表
+                </a>
+            </li>
+            <li class="active" th:text="${aggReportId}">
+
+            </li>
+        </ol>
+    </section>
+    <section class="content container-fluid">
+        <div style="overflow: auto;" class="row">
+            <div class="col-md-8" id="summary">
+                <div class="box box-info detail-table">
+                    <div class="box-header with-border" style="padding: 4px;">
+                        <i class="fa fa-object-group" style="color: #00c0ef;"></i>
+                        <h3 class="box-title" th:text="${aggReportId}">
+
+                        </h3>
+                        <button class="btn-xs btn-primary pull-right" id="create_bug" style="margin-left: 5px;" onclick="showCreateBlock()" th:if="${finalReportId == null}">创建缺陷报告
+                        </button>
+                        <button class="btn-xs btn-primary pull-right" id="review_confirm" th:unless="${reviewed}" onclick="reviewConfirm()">确认审核</button>
+
+                        <span th:if="${reviewed}" class="pull-right label label-success">
+                            <span class="glyphicon glyphicon-ok"></span>
+                            已审核
+                        </span>
+                    </div>
+                    <table class="table table-reponsive">
+                        <tbody>
+                        <tr>
+                            <td class="attr-title">创建时间&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
+                            <td class="dup-create-time">2017-12-01 ~ 2017-12-05</td>
+                            <td class="attr-title">Bug 严重性</td>
+                            <td class="dup-severity">一般 ~ 严重
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="attr-title">Bug分类&nbsp;&nbsp;&nbsp;&nbsp;</td>
+                            <td class="dup-category" colspan="3">
+
+                                <!--<i class="fa fa-square" style="color: {{ category.category_color  }};"></i>-->
+                                <span style="margin-right: 10px;" th:if="${categories == null}">暂无</span>
+                                <span style="margin-right: 10px;" th:if="${categories != null}" th:each="ca : ${categories}" th:text="${ca}"></span>
+
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="attr-title">审核人</td>
+                            <td class="dup-assignee" colspan="3">
+
+                                <a href="#" style="margin-right: 5px;">
+                                    <i class="fa fa-vcard"></i>
+                                    admin
+                                </a>
+
+
+                            </td>
+                        </tr><!-- Attribute -->
+
+                        <!-- Start Content -->
+                        <tr>
+                            <td class="attr-title">主要点<span class="glyphicon glyphicon-star"
+                                                            style="margin-left: 5px;"></span></td>
+                            <td class="dup-master" colspan="3">
+                                <span th:text="${masterReport.getDescription()}"></span><br/>
+                                <img class="my-img-thumbnail pointer to-add" th:src="${imgUrl}"
+                                     th:each="imgUrl,iterStat : ${masterReport.getImgUrls()}"
+                                     th:onclick="'javascript:showimage(\''+${imgUrl}+'\');'"/>
+
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="attr-title">补充点</td>
+                            <td class="dup-supplementary" colspan="3">
+                                <ul id="sup-list" class="list-group"
+                                    style="max-height: 450px; margin-bottom: 0px; overflow: scroll;">
+
+                                    <li class="list-group-item" style="padding: 3px 3px;"
+                                        th:each="supplement, iterStat : ${supplements}">
+
+                                        <p style="border-bottom: 1px solid #ddd; margin: 0 0 1px;">
+                                            <b><a href="#" th:text="'Supplementary ' + ${iterStat.count}"> </a></b>
+                                            <a th:href="'#sup-' + ${iterStat.count}"
+                                               class="glyphicon glyphicon-menu-hamburger pull-right sup-collapse"
+                                               data-toggle="collapse" style="color: #000;"></a>
+                                        </p>
+                                        <div class="sup-title">
+                                            <!-- 如果有文字,则仅显示top 1的diff_sentence,并且不展示图片 -->
+
+                                            <span th:if="${supplement.hasTxt}"
+                                                  th:text="'...' + ${supplement.topTxt} + '...'"></span>
+
+                                            <img th:if="${!supplement.hasTxt}" class="my-img-thumbnail pointer to-add"
+                                                 th:src="${imgUrl}" th:each="imgUrl,iterStat : ${supplement.top3Img}"
+                                                 th:onclick="'javascript:showimage(\''+${imgUrl}+'\');'"/>
+
+
+                                        </div>
+                                        <div th:id="'sup-' + ${iterStat.count}" class="collapse">
+                                            <ul class="list-group" style="margin-bottom: 0px;">
+                                                <li class="list-group-item" style="padding: 3px 3px;"
+                                                    th:each="report : ${supplement.bugs}">
+                                                <span class="glyphicon glyphicon-file"
+                                                      style="color: #3c8dbc; margin-right: 5px;"></span>
+                                                    <a href="#" style="margin-right: 5px;" th:text="${report.id}"></a>
+
+                                                    <!-- description -->
+
+                                                    <th:block th:each="sent, iterStat : ${report.taggedSentences}">
+
+
+                                                        <span th:if="${sent.isDiff()}" th:text="${sent.sentence}"
+                                                              style="color: red; font-weight: bold;"></span>
+                                                        <span th:unless="${sent.isDiff()}"
+                                                              th:text="${sent.sentence}"></span>
+                                                    </th:block>
+
+                                                    <br/>
+
+                                                    <!-- imgs -->
+                                                    <th:block th:each="img, iterStat : ${report.taggedImgs}">
+
+                                                        <img class="my-img-thumbnail pointer to-add"
+                                                             th:style="${img.isDiff()? 'border: 2px solid red;' : ''}"
+                                                             th:src="${img.imgUrl}"
+                                                             th:onclick="'javascript:showimage(\''+${img.imgUrl}+'\');'"/>
+
+                                                    </th:block>
+                                                </li>
+                                            </ul>
+                                        </div>
+                                    </li>
+
+
+                                </ul>
+                            </td>
+                        </tr>
+                        </tbody>
+                    </table>
+                </div>
+
+            </div>
+
+            <div class="col-md-4 pull-right">
+                <div id="my_favorite_latin_words" class="box box-info" style="margin-bottom: 5px; min-height: 182px;"></div>
+
+                <div class="box box-danger source-table" id="new-report-create-block" style="display: none">
+                    <div class="box-header" style="border-bottom: 1px #f4f4f4 solid;">
+                        <h3 class="box-title">
+                            编辑报告
+                        </h3>
+                        <button class="btn-xs btn-primary pull-right" style="margin-left: 5px"
+                                onclick="createOrUpdateFinalReport()">保存
+                        </button>
+                        <button class="btn-xs btn-primary pull-right" onclick="hideCreateBlock()">取消</button>
+                    </div>
+                    <div id="new-report" class="box-body"
+                         style="font-size: 12px; max-height: 340px; overflow: scroll;">
+                        <form role="form">
+
+                            <!-- select -->
+                            <div class="form-group">
+                                <label>Bug 复现程度</label>
+                                <select id="recurrent" name="recurrent" class="form-control">
+                                    <option th:each="mapItem : ${recurrent2String}"
+                                            th:value="${mapItem.key}" th:text="${mapItem.value}">必现</option>
+
+                                </select>
+                            </div>
+                            <!-- select -->
+                            <div class="form-group">
+                                <label>Bug 严重性</label>
+                                <select id="severity" name="severity" class="form-control">
+                                    <option th:each="mapItem : ${severity2String}"
+                                            th:value="${mapItem.key}" th:text="${mapItem.value}">必现</option>
+                                </select>
+                            </div>
+
+                            <!-- select -->
+                            <div class="form-group">
+                                <label>Bug 分类</label>
+                                <select id="category" class="form-control">
+                                    <option th:each="mapItem : ${category2String}"
+                                            th:value="${mapItem.key}" th:text="${mapItem.value}">必现</option>
+                                </select>
+                            </div>
+
+                            <!-- textarea -->
+                            <div class="form-group">
+                                <label>Bug 描述</label>
+                                <textarea id="bug-description" name="description" class="form-control" rows="3"
+                                          placeholder="Enter ..."></textarea>
+                            </div>
+                            <div class="form-group">
+                                <label>Bug 截图</label>
+                                <div id="new-report-img"></div>
+                            </div>
+
+                        </form>
+
+                    </div>
+                </div>
+
+
+                <div class="box box-info source-table" id="new-report-list-block">
+                    <div class="box-header">
+                        <h3 class="box-title">
+                            已创建报告
+
+                        </h3>
+                    </div>
+                    <div id="new-created-reports" class="box-body"
+                         style="font-size: 12px; max-height: 340px; overflow: scroll;">
+                        <div th:if="${finalReports.size() == 0}" style="font-size: 20px">
+                            暂无 <a onclick="showCreateBlock()" style="cursor: pointer">立即创建报告</a>
+                        </div>
+                        <ul class="list-group">
+
+                            <!-- other reports -->
+                            <th:block th:each="finalReport : ${finalReports}">
+                                <li class="list-group-item">
+                                    <div style="overflow: auto;">
+                                        <a href="#" th:text="${finalReport.id}"></a>
+                                        <span class="pull-right">
+
+                                            <a th:href="'report?masterId='+${finalReport.sourceId}+'&amp;examId='+${examId}+'&amp;caseId='+${caseId}+'&amp;finalReportId='+${finalReport.id}">编辑</a>
+                                            <a href="#" th:onclick="'deleteReport('+ ${finalReport.id} +')'">删除</a>
+                                        </span>
+                                    </div>
+
+                                    <div>
+                                        <span>
+                                            复现程度:<span th:text="${recurrent2String.get(finalReport.recurrent)}"></span>
+                                        </span>
+                                        <span class="pull-right">
+                                            分类:<span th:text="${category2String.get(finalReport.category)}"></span>
+                                        </span>
+                                    </div>
+                                    <div>
+                                        严重程度:<span th:text="${severity2String.get(finalReport.severity)}"></span>
+                                    </div>
+                                    <br/>
+                                    <span th:text="${finalReport.description}"></span>
+                                    <br/>
+                                    <img class="my-img-thumbnail pointer to-add" th:src="${imgUrl}"
+                                         th:each="imgUrl,iterStat : ${finalReport.getImgUrls()}"
+                                         th:onclick="'javascript:showimage(\''+${imgUrl}+'\');'"/>
+                                </li>
+
+                            </th:block>
+
+                        </ul>
+                    </div>
+                </div>
+
+            </div>
+        </div>
+
+        <div style="overflow: auto;" class="row tree-container">
+            <div class="col-md-8 tree-wrapper">
+
+                <div class="box box-info pull-left svg-div" style="background-color: rgb(247, 247, 247); ">
+                    <h4 style="padding-left: 10px;" class="pull-left">聚合图</h4>
+                    <svg class="graph" id="tree" width="100%" height="420" viewBox="0 0 700 350">
+                        <g transform="translate(10,20)" id="tree-g">
+                            <g class="links"></g>
+                            <g class="nodes"></g>
+                        </g>
+                    </svg>
+
+                </div>
+            </div>
+            <div class="col-md-4">
+
+                <div class="detail-div"
+                     style="height: 459px; max-height: 459px; font-size: 10px; overflow: scroll;">
+
+                </div>
+            </div>
+        </div>
+
+
+    </section>
+</th:block>
+
+
+</body>
+</html>
+
+
+<div class="modal fade bs-example-modal-lg text-center" id="imgModal" tabindex="-1" role="dialog"
+     aria-labelledby="myLargeModalLabel">
+
+    <div class="modal-dialog modal-lg" style="display: inline-block; width: 300px;">
+        <div class="modal-content">
+            <img id="imgInModalID"
+                 class="carousel-inner img-responsive img-rounded"
+                 onclick="closeImageViewer()"
+                 onmouseover="this.style.cursor='pointer';this.style.cursor='hand'"
+                 onmouseout="this.style.cursor='default'"
+
+            />
+        </div>
+    </div>
+
+</div>
+<script type="text/javascript">
+    //显示大图
+    function showimage(source) {
+        $("#imgModal").find("#imgInModalID").attr("src", source);
+        $("#imgModal").modal();
+    }
+
+    //关闭
+    function closeImageViewer() {
+        $("#imgModal").modal('hide');
+    }
+</script>
+<script src="https://d3js.org/d3.v4.min.js"></script>
+<script type="text/javascript" src="/static/js/agg_report_new.js"></script>
+<script type="text/javascript" src="/static/js/jqcloud-1.0.4.min.js"></script>
+<script type="text/javascript" xmlns:th="http://www.thymeleaf.org" th:inline="javascript">
+    /*<![CDATA[*/
+
+    var word_list = /*[[${wordList}]]*/;
+    var urlParams = new URLSearchParams(window.location.search);
+    var masterId = urlParams.get('masterId');
+    var examId = urlParams.get('examId');
+    var caseId = urlParams.get('caseId');
+    var finalReportId = urlParams.get('finalReportId');
+    /*]]>*/
+    word_list = JSON.parse(word_list)
+
+    var images = [];
+    $(function () {
+        $("#my_favorite_latin_words").jQCloud(word_list,
+            {
+                shape: "rectangular",
+                autoResize: true
+            });
+        var urlParams = new URLSearchParams(window.location.search);
+        if (urlParams.get("finalReportId")) {
+            showCreateBlock()
+            /*<![CDATA[*/
+            var editReport = /*[[${editReport}]]*/;
+            /*]]>*/
+            fillNewReportBlock(editReport);
+        }
+    });
+
+    function createOrUpdateFinalReport() {
+
+        var report = {
+            'description': $("#bug-description").val(),
+            'severity': $("#severity").val(),
+            'recurrent': $("#recurrent").val(),
+            'category': $("#category").val(),
+            'sourceId': masterId,
+            'reviewerId': 1,
+            'examId': examId,
+            'caseId': caseId,
+            'imgUrls': images
+        }
+        if (finalReportId) {
+            report.id = finalReportId
+            $.ajax({
+                type: "PUT",
+                url: '/final_report/'+finalReportId,
+                data: JSON.stringify(report),
+                contentType: "application/json",
+                success: function (data) {
+                    /*<![CDATA[*/
+                    window.location.href='report?masterId='+masterId+'&examId='+examId+'&caseId='+caseId
+                    /*]]>*/                }
+            });
+        } else {
+
+            $.ajax({
+                type: "POST",
+                url: '/final_report',
+                data: JSON.stringify(report),
+                contentType: "application/json",
+                success: function (data) {
+                    location.reload()
+                }
+            });
+        }
+    }
+
+    function showCreateBlock() {
+        $("#new-report-create-block").show()
+        $("#new-report-list-block").hide()
+    }
+    function hideCreateBlock() {
+        if (finalReportId){
+            /*<![CDATA[*/
+            window.location.href='report?masterId='+masterId+'&examId='+examId+'&caseId='+caseId
+            /*]]>*/
+        }
+        $("#new-report-create-block").hide()
+        $("#new-report-list-block").show()
+
+    }
+
+    function fillNewReportBlock(editReport) {
+        console.log(editReport)
+        $("#recurrent").val(editReport.recurrent);
+        $("#severity").val(editReport.severity);
+        $("#category").val(editReport.category);
+        $("#bug-description").val(editReport.description);
+        var $new_report_img = $("#new-report-img");
+        /*<![CDATA[*/
+        for (var i=0;i<editReport.imgUrls.length;i++) {
+            var src = editReport.imgUrls[i]
+            var $img = $('<img />')
+            $img.attr("src", src);
+            $img.attr("class", "my-img-thumbnail pointer to-delete");
+            $img.on("click", function (){
+                showimage(src);
+            });
+            $img.on("dragend", function (e) {
+                var src = $(e.target).attr("src");
+                var idx = images.indexOf(src);
+                if (idx >= 0) {
+                    images.splice(idx, 1);
+                }
+
+                $(e.target).remove();
+            });
+            $new_report_img.append($img)
+        }
+        /*]]>*/
+        $("#new-report-img").val(editReport.description);
+    }
+    function deleteReport(finalReportId) {
+        $.ajax({
+            url: '/final_report/' + finalReportId,
+            type: 'DELETE',
+            success: function (result) {
+                // Do something with the result
+                alert("删除成功");
+                location.reload();
+            }
+        });
+    }
+
+    function reviewConfirm() {
+        $.ajax({
+            url: '/bug_review?masterId='+masterId,
+            type: 'PUT',
+            success: function (result) {
+                alert("确认审核成功,修改报告状态为已审核");
+                location.reload();
+            }
+        });
+    }
+</script>

BIN
target/classes/com/mooctest/controller/GraphController.class


BIN
target/classes/com/mooctest/controller/ReportController.class


BIN
target/classes/com/mooctest/service/GraphService.class


BIN
target/classes/com/mooctest/service/TaskService.class


BIN
target/classes/com/mooctest/util/MongoAPIUtil.class


Some files were not shown because too many files changed in this diff