springboot+thymeleaf+mybatis实现甘特图的详细过程

首先我们要明白:这个甘特图需要哪些动态数据。

(1)需要:ID,tName,number,计划开始时间,开始时间,计划结束时间,结束时间,项目负责人,参与人,知情人ID,计划时长(可以计算得出的,不必在数据库中);前置任务;项目进度,该任务属于哪个任务

(2)然后利用easycode插件生成实体类,映射类,服务类,ontCroller等

(3)利用bootstrap框架做出甘特图的样式,写好JS。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleleaf.org">
<head>
    <title>ganttu.html</title>
    <meta name="keywords" content="keyword1,keyword2,keyword3" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <meta name="reason" content="甘特图的实际进度与计划进度可能不符,为了展示实际进度与计划进度的差异和方便统计,自己写了个甘特图框架" />

    <meta name="mast" content="使用代码之前请留言,禁止转载..." />

    <meta name="description" content="liuyuhang    的甘特图,当前版本1.0,2019-02-19" />
    <meta name="description" content="时间日期格式:yyyy-mm-dd" />
    <meta name="description" content="①计划进度与实际进度双重进度体系" />
    <meta name="description" content="②有前置任务连接线" />
    <meta name="description" content="③可修改图颜色" />
    <meta name="description" content="④可隐藏与展示列" />
    <meta name="description" content="⑤可隐藏域展示子项目" />
    <meta name="description" content="⑥可跳转时间到当前时间" />
    <meta name="description" content="⑦可从当前项目开始时间查看" />
    <meta name="description" content="⑦可隐藏某时间之前的内容" />

    <meta name="warning" content="⑧未做图拖拽,并不打算做..." />

    <meta name="author" content="liuyuhang 13501043063" />
    <!-- 只引用了这些,其余的并没有引用 -->
    <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="external nofollow"  rel="stylesheet" />
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>

    <style type="text/css">
        #ganttu-head {
            height: 70px;
            background-color: #dddddd;
            padding: 10px 20px;
        }

        #ganttu-body {
            min-height: 780px;
            background-color: #eeeeee;
            padding: 10px 20px;
            font-size: 20px;
        }

        #ganttu-index-projectName {
            display: inline;
            padding: 5px 15px;
            background-image: linear-gradient(to left, #222222 0%, #222222 75%, #000000 100%);
            color: white;
            border-radius: 18px;
        }

        #ganttu-index-projectDesc {
            display: inline;
            padding: 5px 15px;
            background-image: linear-gradient(to left, #777777 0%, #777777 75%, #333333 100%);
            color: white;
            border-radius: 18px;
        }

        td {
            white-space: nowrap
        }
    </style>
</head>
<body>
<div id='ganttu-head' class='col-lg-12 col-md-12 col-sm-12 col-xs-12' style="height:100px" >
    <div style='display: inline;font-size: 30px;font-weight: normal;padding: 5px 15px;'>甘特图面板</div>
    <div id='ganttu-index-projectName'>此项目 名称...</div>
    <div id='ganttu-index-projectDesc'>此项目描述...</div>
</div>
<div id='ganttu-body' class='col-lg-12 col-md-12 col-sm-12 col-xs-12' style=';overflow-x:scroll;font-size:14px;'>
    <!-- 甘特图放到了这个div中 -->
    <div id="lyh-ganttu" class='col-lg-12 col-md-12 col-sm-12 col-xs-12' style='position:relative;padding:0px;height:700px;'></div>
</div>
</body>
<script type="text/javascript" th:inline="javascript">
    $(function() {
        lyhGanttuInit('lyh-ganttu'); //甘特图初始化
    })
    var lyhGanttuData=[[${lyhGanttuData}]];

    /**
     * 甘特图设置,变量名固定
     */
    var lyhGanttuConfig = {
        start : '1900/01/01', //初始化开始时间配置    - 别在意
        end : '1900/01/10', //初始化结束时间配置    - 别在意
        planBorder : '#1a8cff', //计划进度的border颜色
        planBackground : '#80bfff', //计划进度的back颜色
        border : '#ffaa00', //实际进度的border染颜色
        background : '#ffcc66', //实际进度的back颜色
        lineColor : 'green', //前置任务线颜色
        //表格中的thead的题头设置,可按照格式任意添加或减少
        labels : {
            'projectName' : {
                'name' : '         任务名         ',
                'show' : true,
            }, //任务名
            'projectCode' : {
                'name' : '编号',
                'show' : true,
            }, //编号
            'planStartAt' : {
                'name' : '计划开始',
                'show' : true,
            }, //计划开始时间
            'planEndAt' : {
                'name' : '计划结束',
                'show' : false,
            }, //计划结束时间
            'startAt' : {
                'name' : '实际开始',
                'show' : false,
            }, //实际开始时间
            'endAt' : {
                'name' : '实际结束',
                'show' : false,
            }, //实际结束时间
            'persent' : {
                'name' : '完成比例',
                'show' : true,
            }, //完工百分比
            'dur' : {
                'name' : '时长',
                'show' : true,
            }, //持续时间
            'resps' : {
                'name' : '负责人',
                'show' : true,
            }, //负责人
            'actors' : {
                'name' : '参与人',
                'show' : true,
            }, //参与人
            'insiders' : {
                'name' : '知情人',
                'show' : false,
            }, //知情人
            'before' : {
                'name' : '前置任务',
                'show' : false,
            }, //前置任务
            'operate' : {
                'name' : "<button title='新建计划' class='btn btn-primary btn-xs'><span class='glyphicon glyphicon-plus' style='margin-right:0px'></span></button>",
                'show' : true,
            }, //修改按钮
        }
    }

    /**
     * 添加修改功能
     */
    function lyhGanttuDataModifyByOperate() {
        var data = lyhGanttuData.data;
        for (var i = 0; i < data.length; i++) {
            data[i]['operate'] = "<button title='修改此计划' class='btn btn-primary btn-xs'><span class='glyphicon glyphicon-edit' style='margin-right:0px'></span></button>";
        }
    }

    //================
    //以下为甘特图本身的绘图代码,调用lyhGanttuInit,参数为要加载甘特图的id
    //请使用谷歌浏览器,缩放倍数为100%

    /**
     * 甘特图初始化函数
     */
    function lyhGanttuInit(target) {
        //重置日期设置缓存
        lyhGanttuConfig.start = '1900/01/01';
        lyhGanttuConfig.end = '1900/01/10';
        lyhGanttuConfigModifyByDate(); //过滤所有时间,获取时间长度
        lyhGanttuDataModifyByOperate(); //添加点修改或新增数据按钮
        var table = lyhGanttuTable(target);
        $('#' + target).html(table);
        drawLink(target); //线条初始化
        //提示工具初始化
        $('#' + target).find('[title]').attr('data-toggle', 'tooltip').attr('data-placement', 'right');
        $("[data-toggle='tooltip']").tooltip();
        //标记today
        var today = lyhGanttuDate(new Date()); //今天的日期字符串
        var todayIn = $('#' + target + ' .table thead tr #date').find('[data-original-title=\'' + today + '\']');
        if (todayIn.length > 0) {
            todayIn.addClass('todayDiv').css('background-color', 'orange').append($('<div>').css({
                'height' : parseInt($('#' + target + ' .table').css('height').split('px')[0]) - 45 + 'px',
                'position' : 'absolute',
                'z-index' : 202,
                'margin-top' : '-40px',
                'margin-left' : '-10px',
                'border-left' : '2px dashed red',
            }).append($('<button>').addClass('btn btn-danger btn-xs todayBtn').css('margin-left', '3px').html(' today ')))
        }
    }

    /**
     * 绘制甘特图基础函数
     */
    function lyhGanttuTable(target) {
        var htr = $('<tr>').addClass('text-center');
        var labels = lyhGanttuConfig.labels; //head的标签json
        var start = lyhGanttuConfig.start; //总开始时间
        var end = lyhGanttuConfig.end; //总结束时间
        var pBorder = lyhGanttuConfig.planBorder;
        var pBackground = lyhGanttuConfig.planBackground;
        var border = lyhGanttuConfig.border;
        var background = lyhGanttuConfig.background;
        var indexBtn = $('<button>').addClass('btn btn-success btn-xs').append("<span class='glyphicon glyphicon-chevron-down' style='margin-right:0px'></span><span class='glyphicon glyphicon-chevron-right' style='display:none;margin-right:0px'></span>");
        indexBtn.click(function() { //展开或隐藏所以有任务卡点击函数
            var me = $(this);
            var indexBtnDown = me.find('.glyphicon-chevron-down'); //转开状态
            var indexBtnRight = me.find('.glyphicon-chevron-right'); //隐藏状态
            var meTrs = $('#' + target + ' .table tr');
            var meTdsHide = meTrs.find('div[hideId]');
            if (indexBtnRight.is(':hidden')) { //若当前为展开状态,则隐藏,同时调整按钮
                meTdsHide.parent().parent().hide(300);
                indexBtnRight.show();
                indexBtnDown.hide();
            } else { //当前为隐藏状态,则展开
                meTdsHide.parent().parent().show(300);
                indexBtnRight.hide();
                indexBtnDown.show();
            }
            setTimeout(function() { //重新绘图
                drawLink('lyh-ganttu');
            }, 400)

        })
        var index = $('<td>').append(indexBtn);
        htr.append(index); //添加index
        //循环添加label
        for (var label in labels) {
            var htd = $('<td>').append($('<div>').attr('id', label).html(labels[label].name));
            if (labels[label].show != true) {
                htd.css('display', 'none');
            }
            htr.append(htd);
        }

        //添加甘特图的日期头
        var dataHtd = $('<td>').attr('id', 'date').css('width', '50%').css('padding', '0px');
        var hDivs = lyhGanttuHeadDivs(target);
        for (var i = 0; i < hDivs.length; i++) {
            dataHtd.append(hDivs[i]);
        }
        htr.append(dataHtd);
        //添加甘特图的数据内容
        var tbody = $('<tbody>')
        var data = lyhGanttuData.data;
        for (var i = 0; i < data.length; i++) {
            //写入展开按钮
            var btr = $('<tr>').addClass('text-center').css('max-height', '40px');
            if (data[i].pid == 0) {
                var plusBtn = $('<button>').append("<span class='glyphicon glyphicon-flag' style='margin-right:0px'></span>").addClass('btn btn-success btn-xs').attr('title', '展开/隐藏-计划').attr('id', data[i]['id']);
                plusBtn.click(function() { //任务展开与隐藏按钮点击函数
                    var me = $(this);
                    var meId = me.attr('id');
                    var meTrs = $('#' + target + ' .table tr');
                    var meTdsHide = meTrs.find('div[hideId=' + meId + ']');
                    if (meTdsHide.is(':hidden')) { //已经隐藏
                        meTdsHide.parent().parent().show(300);
                    } else {
                        meTdsHide.parent().parent().hide(300);
                    }
                    setTimeout(function() { //重新绘图
                        drawLink('lyh-ganttu');
                    }, 400)

                })
                var plus = $('<td>').css('padding', '5px').append(plusBtn)
            } else {
                var plus = $('<td>').css('padding', '5px').append($('<div>').attr('id', data[i]['id']).attr('hideId', data[i]['pid']).attr('title', '工作包').append("<span class='glyphicon glyphicon-tasks' style='margin-right:0px'></span>"));
            }
            btr.append(plus)
            //写入数据
            for (var label in labels) {
                for (var key in data[i]) {
                    if (label == key) {
                        if (label.indexOf('At') > -1) { //若是时间数据,则截取一下
                            var tda = $('<td>').css('padding', '5px').append($('<div>').addClass(key).html(data[i][key].substr(5, 5)).attr('title', data[i][key]))
                        } else if (label == 'resps' || label == 'actors' || label == 'insiders') { //负责人,参与人,知情人加载
                            var tda = $('<td>').css('padding', '5px').append($('<div>').addClass(key).html(data[i][key][0]).attr('title', data[i][key]));
                        } else if (label == 'before') { //前置任务
                            var befores = data[i][key];
                            var beforesNames = [];
                            if (befores.length > 0) {
                                for (var j = 0; j < data.length; j++) {
                                    for (var k = 0; k < befores.length; k++) {
                                        if (data[j].id == befores[k]) {
                                            beforesNames.push(data[j].projectName);
                                        }
                                    }
                                }
                            } else {
                                beforesNames.push('无');
                            }
                            var tda = $('<td>').css('padding', '5px').append($('<div>').addClass(key).html(beforesNames[0]).attr('title', beforesNames));
                        } else { //其他信息加载
                            var tda = $('<td>').css('padding', '5px').append($('<div>').addClass(key).html(data[i][key]));
                        }
                        if (labels[label].show != true) { //该列是否展示
                            tda.hide();
                        }
                        if (label == 'planStartAt') {
                            tda.css('cursor', 'pointer')
                            tda.click(function() { //对planStartAt添加点击函数
                                var me = $(this);
                                var psaTitle = me.find('div').attr('data-original-title');
                                var dateDivs = $('#' + target + ' .table thead #date');
                                var dateBtn = dateDivs.find('div[data-original-title=\'' + psaTitle + '\']').prev();
                                dateBtn.click();
                            })
                        }
                        btr.append(tda);
                        break;
                    }
                }
            }
            //写入图信息

            var ps = data[i]['planStartAt']; //计划开始时间
            var pe = data[i]['planEndAt']; //计划结束时间
            var dpss = lyhGanttuDateDiff(start, ps) - 1; //计划开始时间和总开始时间的时间差
            var dpse = lyhGanttuDateDiff(ps, pe) + 1; //计划开始时间和计划结束时间的时间差
            var dse = lyhGanttuDateDiff(start, end); //总开始和总结束时间差

            var as = data[i]['startAt']; //实际开始时间
            var ae = data[i]['endAt']; //实际结束时间

            var dass = lyhGanttuDateDiff(start, as) - 1; //实际开始时间和总开始时间的时间差
            var dase = lyhGanttuDateDiff(as, ae) + 1; //实际开始时间和实际结束时间的时间差

            var tdu = $('<td>').css('padding', '0px').css('max-height', '38px');
            var d = $('<div>').css({ //计划的div
                'display' : 'inline-block',
                'width' : '55px',
                'height' : '26px',
                'margin-bottom' : '-5px',
                'margin-top' : '3px',
                'padding' : '-1px',
                'z-index' : 200,
            }).addClass('Gout').append($('<div>').css({ //背景色的div,用于标注周末
                'width' : '55px',
                'height' : '30px',
                'position' : 'absolute',
                'margin-top' : '-2px',
                'opacity' : 0.07,
            }).addClass('weekend')).append($('<div>').css({ //实际的div
                'width' : '55px',
                'height' : '14px',
                'position' : 'absolute',
                'margin-top' : '7px',
                'z-index' : 200,
            }).addClass('Gin'));

            var weekDay = new Date(start).getDay(); //获取初始日期是星期几 - - 0-6为星期日 -- 星期六

            //甘特图绘图填色
            for (var k = 0; k < dse; k++) { //在总开始和总结束之间做日期循环
                var dc = d.clone();
                if ((k + weekDay) % 7 == 5 || (k + weekDay) % 7 == 6) { //周末标识填充
                    dc.find('.weekend').css({
                        'background-color' : 'blue',
                        'border-left' : '1px inset #ddd',
                    })
                }
                if (k > dpss - 1 && k < dpss + dpse) { //计划内容填充
                    dc.css({
                        'background-color' : pBackground,
                        'border-top' : '1px inset ' + pBorder,
                        'border-bottom' : '1px inset ' + pBorder,
                    }).attr('title', '计划进度与实际进度');
                    if (k == dpss) { //左边界
                        dc.css('border-left', '1px inset ' + pBorder);
                        dc.find('.Gin').html('<div style="position:absolute;top:-3px;padding-left:10px">' + data[i]['persent'] + '</div>'); //完工百分比
                        dc.attr('sId', data[i]['id']); //标记为开始,查询sid,获取当前的计划的id
                    }
                    if (k == dpss + dpse - 1) { //右边界
                        dc.css('border-right', '1px inset ' + pBorder);
                        dc.attr('eId', data[i]['id']); //标记为结束,查询eid,获取当前的计划的id
                    }
                }
                if (k > dass - 1 && k < dass + dase) { //实际内容填充
                    dc.find('.Gin').css({
                        'background-color' : background,
                        'border-top' : '1px inset ' + border,
                        'border-bottom' : '1px inset ' + border,
                    }).attr('title', '实际进度与实际进度');
                    if (k == dass) { //左边界
                        dc.find('.Gin').css('border-left', '1px inset ' + border);
                    }
                    if (k == dass + dase - 1) { //右边界
                        dc.find('.Gin').css('border-right', '1px inset ' + border);
                    }
                    if (dc.css('border-top-width') != '1px') { //是否是只有实际进度,进行margin-top位置调整
                        dc.find('.Gin').css('margin-top', '8px');
                    }
                }
                tdu.append(dc)
            }
            btr.append(tdu)
            tbody.append(btr);
        }

        //写入table顶部工具栏,包括隐藏展示列功能
        var optr = $('<tr>');
        var hideResetBtn = $('<button>').addClass('btn btn-primary btn-sm').attr('title', '展示所有隐藏项').html('<span class="glyphicon glyphicon-transfer"></span>')
        hideResetBtn.click(function() { //全部展示或隐藏的按钮点击函数
            if (lyhGanttuConfig.labels.planEndAt.show == false) {
                for (var key in lyhGanttuConfig.labels) {
                    if (key != 'projectName' && key != 'planStartAt' && key != 'operate') {
                        lyhGanttuConfig.labels[key].show = true;
                    }
                }
            } else {
                for (var key in lyhGanttuConfig.labels) {
                    if (key != 'projectName' && key != 'planStartAt' && key != 'operate') {
                        lyhGanttuConfig.labels[key].show = false;
                    }
                }
            }
            lyhGanttuInit(target); //重新绘图
        })
        var optdFirst = $('<td>').css('padding', '5px').append(hideResetBtn);
        optr.append(optdFirst); //写入重置隐藏项按钮
        for (var key in labels) {
            if (key != 'projectName' && key != 'planStartAt' && key != 'operate') {
                var checkSpan = $('<span>').addClass('glyphicon glyphicon-check'); //已选择span
                var uncheckSpan = $('<span>').addClass('glyphicon glyphicon-unchecked'); //未选择span
                if (labels[key].show == true) { //该项目要显示,隐藏未选
                    uncheckSpan.hide();
                } else {
                    checkSpan.hide();
                }
                var optBtn = $('<button>').addClass('btn btn-primary btn-sm').html('').append(checkSpan).append(uncheckSpan).append(labels[key].name)
                    .attr('title', '隐藏/展示-' + labels[key].name + '列').attr('id', key);
                optBtn.click(function() { //表格列工具点击函数
                    var me = $(this);
                    var hideColumId = me.attr('id');
                    if (lyhGanttuConfig.labels[hideColumId].show == true) { //隐藏
                        lyhGanttuConfig.labels[hideColumId].show = false;
                    } else {
                        lyhGanttuConfig.labels[hideColumId].show = true; //展示
                    }
                    lyhGanttuInit(target); //重新绘图
                })
                var optd = $('<td>').css('padding', '5px 10px').append(optBtn);
                optr.append(optd);
            }
        }

        //当前进度按钮
        var optBtnToday = $('<button>').addClass('btn btn-danger btn-sm').html('<span class="glyphicon glyphicon-pushpin"></span>今天进度').attr('id', key);
        optBtnToday.click(function() { //跳转到今天的点击函数
            var todayBtn = $('#' + target + ' .table thead tr #date').find('.todayDiv');
            todayBtn.prev().prev().click();
        })
        optr.append($('<td>').css('padding', '5px 10px').append(optBtnToday));

        var opt = $('<caption>').append(optr);

        //组装table
        var thead = $('<thead>').append(htr).css('background-color', '#cccccc');
        var table = $('<table>').append(opt).append(thead).append(tbody).addClass('table table-bordered table-hover');
        return table;
    }

    /**
     * 根据甘特图生成canvas线条连接linked的函数
     */
    function drawLink(target) {
        var temp = $('#' + target);
        var dw = parseInt(temp.find('.table #date').css('width').split('px')[0]);
        var offset = temp.find('.table #date').position().left;
        var dh = parseInt(temp.find('.table').css('height').split('px')[0]) - 80;
        var data = lyhGanttuData.data;
        var canvas = $('<canvas>').css({
            'position' : 'absolute',
            'top' : '0px',
            'left' : '0px',
            'z-index' : 10,
            'margin-top' : '95px', //高偏移量
            'margin-left' : offset + 'px',
        }).attr('width', dw + 'px').attr('height', dh + 'px');

        //删除target下的所有的canvas
        temp.find('canvas').remove()

        for (var i = 0; i < data.length; i++) {
            var before = data[i]['before'];
            var id = data[i]['id'];
            if (before.length > 0) {
                for (var k = 0; k < before.length; k++) {

                    var eDiv = $('#' + target).find('div[sId=' + id + ']')
                    var sDiv = $('#' + target).find('div[eId=' + before[k] + ']')
                    if (eDiv.is(':hidden')) { //若已经被隐藏,则不绘制线条
                        break;
                    }
                    var sy = sDiv.position().top - 88; //设置高度偏移量
                    var sx = sDiv.position().left + 55 - offset; //设置宽度偏移量
                    var ey = eDiv.position().top - 88;
                    var ex = eDiv.position().left - offset;
                    var c = canvas.clone();
                    $('#' + target).append(c); //加载画布
                    var ctx = c[0].getContext("2d"); //创建画布
                    //绘制连接线条
                    ctx.beginPath();
                    ctx.strokeStyle = lyhGanttuConfig.lineColor; //绿色线条
                    ctx.moveTo(sx, sy); //起点
                    ctx.lineTo(sx + 15, sy); //右移15
                    ctx.lineTo(sx + 15, sy + 26); //下移32
                    ctx.lineTo(sx - 15, sy + 26); //左移30
                    ctx.lineTo(sx - 15, ey); //下移到终点行
                    ctx.lineTo(ex, ey); //到终点
                    ctx.stroke(); //描边。stroke不会自动closePath()

                    //绘制起点球球
                    ctx.beginPath();
                    ctx.fillStyle = lyhGanttuConfig.lineColor;
                    ctx.arc(sx, sy, 2, 0, 2 * Math.PI, false); //x,y,半径,*,弧长,时针
                    ctx.fill(); //填充

                    //绘制终点箭头
                    ctx.beginPath();
                    ctx.strokeStyle = lyhGanttuConfig.lineColor;
                    ctx.moveTo(ex - 7, ey - 3);
                    ctx.lineTo(ex, ey);
                    ctx.lineTo(ex - 7, ey + 3);
                    ctx.stroke(); //描边。stroke不会自动closePath()
                }
            }
        }
    }

    var dateLabelClickFlag = null;
    /**
     * 以过滤后的日期制作head中的日期div
     */
    function lyhGanttuHeadDivs(target) {
        var start = lyhGanttuConfig.start;
        var end = lyhGanttuConfig.end;
        var diff = lyhGanttuDateDiff(end, start); //获取时间差
        var arr = [];
        var temp = null;
        for (var i = 0; i < diff; i++) {
            if (null == temp) {
                var next = lyhGanttuDatePlus(start);
            } else {
                var next = lyhGanttuDatePlus(temp);
            }
            temp = next;
            var div = $('<div>').css({
                'border-left' : '1px solid #ddd',
                'display' : 'inline-block',
                'padding' : '9px 9px',
                'title' : next,
                'cursor' : 'pointer',
            }).attr('title', next).html(next.substr(5, 5));
            div.click(function() { //date题头点击的函数,隐藏之前的所有内容
                var me = $(this);
                if (dateLabelClickFlag != me.attr('title')) { //检验第几次点击,第一次点击则隐藏,再次点击则展示之前内容
                    dateClickHide(target, me); //隐藏内容
                    dateLabelClickFlag = me.attr('title'); //更新flag
                } else {
                    dateClickShow(target); //隐藏内容
                    dateLabelClickFlag = null; //更新flag
                }

            })
            arr.push(div);
        }
        return arr; //写回div的jquery的对象的数组
    }

    /**
     * 隐藏点击的日期之前的所有甘特图内容的函数
     */
    function dateClickHide(target, me) {
        var count = 0;
        var temp = me.prev();
        while (temp.length != 0) { //隐藏题头
            var prev = temp;
            temp.hide();
            temp = temp.prev();
            count++;
        }
        var trs = $('#' + target + ' tbody tr');
        for (var i = 0; i < trs.length; i++) {
            var td = $(trs[i]).children("td:last-child");
            var divs = td.find('.Gout');
            for (var k = 0; k < count; k++) {
                $(divs[k]).hide();
            }
        }
        drawLink(target); //重新绘制
    }

    /**
     * 展示点击的日期之前的所有甘特图的内容的函数
     */
    function dateClickShow(target) {
        $('#' + target + ' div').show();
        drawLink(target); //重新绘制
    }

    /**
     * 初始化日期,最早时间-5,最长时间+5
     */
    function lyhGanttuConfigModifyByDate() {
        for (var i = 0; i < lyhGanttuData.data.length; i++) {
            if (lyhGanttuConfig.start == '1900/01/01') {
                lyhGanttuConfig.start = lyhGanttuData.data[i].planStartAt;
            }
            if (lyhGanttuConfig.end == '1900/01/10') {
                lyhGanttuConfig.end = lyhGanttuData.data[i].planEndAt;
            }
            if (str2Date(lyhGanttuConfig.start, '/').getTime() > str2Date(lyhGanttuData.data[i].planStartAt, '/').getTime()) {
                lyhGanttuConfig.start = lyhGanttuData.data[i].planStartAt;
            }
            if (str2Date(lyhGanttuConfig.start, '/').getTime() > str2Date(lyhGanttuData.data[i].startAt, '/').getTime()) {
                lyhGanttuConfig.start = lyhGanttuData.data[i].startAt;
            }
            if (str2Date(lyhGanttuConfig.end, '/').getTime() < str2Date(lyhGanttuData.data[i].planEndAt, '/').getTime()) {
                lyhGanttuConfig.end = lyhGanttuData.data[i].planEndAt;
            }
            if (str2Date(lyhGanttuConfig.end, '/').getTime() < str2Date(lyhGanttuData.data[i].endAt, '/').getTime()) {
                lyhGanttuConfig.end = lyhGanttuData.data[i].endAt;
            }
        }
        lyhGanttuConfig.start = lyhGanttuDate(new Date(str2Date(lyhGanttuConfig.start, '/').getTime() - (3 * 24 * 60 * 60 * 1000)))
        lyhGanttuConfig.end = lyhGanttuDate(new Date(str2Date(lyhGanttuConfig.end, '/').getTime() + (8 * 24 * 60 * 60 * 1000)))
    }

    /**
     * json date转换日期工具
     */
    function lyhGanttuDateStr(dateStr) {
        var date = str2Date(dateStr, '-');
        var year = date.getFullYear().toString();
        var month = (date.getMonth() + 1) <= 9 ? "0"
            + (date.getMonth() + 1) : (date.getMonth() + 1);
        var day = date.getDate() <= 9 ? "0" + date.getDate() : date
            .getDate();
        return year + "/" + month + "/" + day;
    }
    /**
     * json date转换日期工具    date 对象转化为固定格式/日期的函数
     */
    function lyhGanttuDate(date) {
        var year = date.getFullYear().toString();
        var month = (date.getMonth() + 1) <= 9 ? "0"
            + (date.getMonth() + 1) : (date.getMonth() + 1);
        var day = date.getDate() <= 9 ? "0" + date.getDate() : date
            .getDate();
        return year + "/" + month + "/" + day;
    }

    /**
     * 固定格式的字符串转换成date格式函数
     */
    function str2Date(dateStr, separator) {
        if (!separator) {
            separator = "/";
        }
        var dateArr = dateStr.split(separator);
        var year = parseInt(dateArr[0]);
        var month;
        //处理月份为04这样的情况
        if (dateArr[1].indexOf("0") == 0) {
            month = parseInt(dateArr[1].substring(1));
        } else {
            month = parseInt(dateArr[1]);
        }
        var day = parseInt(dateArr[2]);
        var date = new Date(year, month - 1, day);
        return date;
    }

    /**
     * 计算两个日期之间的天数
     */
    function lyhGanttuDateDiff(dateStr1, dateStr2) { //sDate1和sDate2是2006-12-18格式
        var dateSpan,
            tempDate,
            iDays;
        dateStr1 = Date.parse(dateStr1);
        dateStr2 = Date.parse(dateStr2);
        dateSpan = dateStr2 - dateStr1;
        dateSpan = Math.abs(dateSpan);
        iDays = Math.floor(dateSpan / (24 * 3600 * 1000));
        return iDays
    }

    /**
     * 当前日期时间以原格式+1的函数
     */
    function lyhGanttuDatePlus(dateStr, days) {
        var date = str2Date(dateStr);
        if (days == undefined || days == '') {
            days = 1;
        }
        date.setDate(date.getDate() + days); //日期+1
        var year = date.getFullYear().toString();
        var month = (date.getMonth() + 1) <= 9 ? "0"
            + (date.getMonth() + 1) : (date.getMonth() + 1);
        var day = date.getDate() <= 9 ? "0" + date.getDate() : date
            .getDate();
        return year + "/" + month + "/" + day;
    }
</script>
</html>

(4)在Controller层中利用Http请求传参

@RequestMapping(value = "/gantee",method = RequestMethod.GET)
    public String gantee(Model model) throws JSONException {
        Renwu renwu = renwuService.queryById(new Integer("1"));
        Map jsonData = new HashMap();
        List<Map> jsonArray = new ArrayList<>();
        Map jsonObject = new HashMap();
        Integer id = renwu.getProjectid();
        Integer  pid = renwu.getPid();
        String projectName = renwu.getProjectname();
        String projectCode = renwu.getProjectcode();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
        Date planStartDate = renwu.getPlanstartat();
        Date planEndDate = renwu.getPlanendat();
        Date startDate = renwu.getStartat();
        Date endDate = renwu.getEndat();
        String planStartStr = dateFormat.format(planStartDate);
        String planEndStr = dateFormat.format(planEndDate);
        String startStr = dateFormat.format(startDate);
        String endStr = dateFormat.format(endDate);
        String persent = renwu.getPersent();
        String resps = renwu.getResps();
        String actors = renwu.getActors();
        String insiders = renwu.getInsiders();
        Integer dur = renwu.getDur();
        Integer before = renwu.getBefore();
        jsonObject.put("id",id);
        jsonObject.put("pid",pid);
        jsonObject.put("projectName",projectName);
        jsonObject.put("projectCode",projectCode);
        jsonObject.put("planStartAt",planStartStr);
        jsonObject.put("planEndAt",planEndStr);
        jsonObject.put("startAt",startStr);
        jsonObject.put("endAt",endStr);
        jsonObject.put("persent",persent);
        jsonObject.put("resps",resps);
        jsonObject.put("actors",actors);
        jsonObject.put("insiders",insiders);
        jsonObject.put("dur",dur);
        jsonObject.put("before",new Object[]{before});
        jsonArray.add(jsonObject);
        jsonData.put("data",jsonArray);
        model.addAttribute("lyhGanttuData",jsonData);
        return "ganttu";
    }

(5)直接启动SpringBoot项目即可。

这个是Springboot项目,自然也是可以转到SpringCloud的子项目中。

  注意:HTML并不是我原创没我只是在其基础上改了一下JS。在这个开放的时代,我觉得大家应该把学到的东西开放出来,不管多好或是很差。

到此这篇关于springboot+thymeleaf+mybatis实现甘特图的详细过程的文章就介绍到这了,更多相关springboot+thymeleaf+mybatis实现甘特图内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot+mybatis+thymeleaf实现登录功能示例

    1.项目文件目录一栏 2.开始工作 先按照上图建立好相应的controller,mapper等文件. 接着进行一个配置 首先是application.properties server.port=8080#启动端口 #加载Mybatis配置文件 mybatis.mapper-locations = classpath:mapper/*.xml #数据源必填项 spring.datasource.driver-class-name= com.mysql.cj.jdbc.Driver spring.

  • springboot+thymeleaf+druid+mybatis 多模块实现用户登录功能

    项目代码:https://github.com/bruceq/supermarket 项目结构: 依赖关系: common:公共层,无依赖 dao:数据层,依赖common service:服务层,依赖dao.common web:应用层,依赖dao.common.service 注:启动类在web层中 父依赖pom <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http:/

  • springboot+thymeleaf+mybatis实现甘特图的详细过程

    首先我们要明白:这个甘特图需要哪些动态数据. (1)需要:ID,tName,number,计划开始时间,开始时间,计划结束时间,结束时间,项目负责人,参与人,知情人ID,计划时长(可以计算得出的,不必在数据库中):前置任务:项目进度,该任务属于哪个任务 (2)然后利用easycode插件生成实体类,映射类,服务类,ontCroller等 (3)利用bootstrap框架做出甘特图的样式,写好JS. <!DOCTYPE html> <html xmlns:th="http://w

  • SpringBoot中Mybatis + Druid 数据访问的详细过程

    目录 1.简介 2.JDBC 3.CRUD操作 4.自定义数据源 DruidDataSource 1.配置 Druid 数据源监控 2.配置 Druid web 监控 filter 5.SpringBoot 整合mybatis 1. 导入mybatis所需要的依赖 2.配置数据库连接信息 3,创建实体类 4.配置Mapper接口类 6.SpringBoot 整合 1.简介 ​ 对于数据访问层,无论是SQL(关系型数据库) 还是NOSQL(非关系型数据库),SpringBoot 底层都是采用 Sp

  • SpringBoot thymeleaf实现饼状图与柱形图流程介绍

    今天给大家带来的是一个用SpringBoot + thymeleaf显示出饼状图和柱形图 首先我们先创建项目 注意:创建SpringBoot项目时一定要联网不然会报错 项目创建好后我们首先对 application.yml 进行编译 #指定端口号server: port: 8888#配置mysql数据源spring:  datasource:    driver-class-name: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://localhost

  • Vue echarts画甘特图流程详细讲解

    vue项目中添加echarts,只需要增加echarts依赖,然后在main.js中引入echarts就可以使用了. 1.npm install echarts --save 2.修改main.js import * as echarts from 'echarts' Vue.prototype.$echarts = echarts 3.具体页面使用: <template> <div class="about"> <h1>This is echart

  • Springboot入门案例及部署项目的详细过程

    今天闲来无事就来学习一下SpringBoot框架,顺手搭了一个入门小案例. Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者. 这篇入门案例使用的是Springboot1.5.9,可能最新的已经更简单了,创建的

  • SpringBoot整合Redis实现常用功能超详细过程

    目录 1 登陆功能 1.1 基于Session实现登录流程 1.1.1 session共享问题 1.2 Redis替代Session 1.2.1.设计key的结构 1.2.2.设计key的具体细节 1.2.3.整体访问流程 2 缓存功能 2.1 什么是缓存? 2.1.1 为什么要使用缓存 2.1.2 如何使用缓存 2.2.使用缓存 2.2.1 .缓存模型和思路 2.3 缓存更新策略 2.3.1 .数据库缓存不一致解决方案: 2.3.2 .数据库和缓存不一致采用什么方案 2.4 缓存穿透问题的解决

  • 使用python matplotlib contour画等高线图的详细过程讲解

    目录 函数画图 颜色取反 数据画图 选择性画图 总结 函数画图 以 z = x 2 + y 2 为例 #导入模块 import numpy as np import matplotlib.pyplot as plt #建立步长为0.01,即每隔0.01取一个点 step = 0.01 x = np.arange(-10,10,step) y = np.arange(-10,10,step) #也可以用x = np.linspace(-10,10,100)表示从-10到10,分100份 #将原始数

  • 从零开始搭建springboot+springcloud+mybatis本地项目全过程(图解)

    记录一下从零开始搭建一个springboot+springcloud+mybatis本地项目的demo的过程.纯代码小白一枚,若有不足或错误之处,欢迎广大朋友指出! 开发环境准备: IDE:IntelliJ Idea 2019.3 数据库:mysql 8.0.2.2 SpringBoot版本:2.2.0.RELEASE SpringCloud版本:Hoxton.RELEASE 一.创建一个新的Idea项目 打开Idea,单击New->File->Project,选择Maven,直接下一步 输入

  • 一篇文章教你学会使用Python绘制甘特图

    目录 优点 局限 一日一书 用来制作甘特图的专业工具也不少,常见的有:Microsoft Office Project.GanttProject.WARCHART XGantt.jQuery.Gantt.Excel等,网络上也有一些优质工具支持在线绘制甘特图. 可是这种现成的工具,往往也存在一些弊端,让编程人员不知所措.比如说,花里胡哨的UI,让人目不暇接,不知点哪个才好: 比如说,有些基于浏览器的图表需要掌握HTML.JS等编程语言,只会点Python的我直接被劝退: 再比如,进来就是注册.登

随机推荐