Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

php打造可视化源码发布系统 #23

Open
fredshare opened this issue Jan 4, 2016 · 0 comments
Open

php打造可视化源码发布系统 #23

fredshare opened this issue Jan 4, 2016 · 0 comments
Labels

Comments

@fredshare
Copy link
Owner

php打造可视化源码发布系统

  • 前言

    之前在大公司里有现成文件发布系统。今年在创业公司,很多工具都得自己从头搭建,比如日志、itil监控、用户信息监控。这次是源码发布系统。在最开始我们直接使用ftp上传到idc机器,因为idc机器只有一台,用ftp很简单;随着业务不断扩大,idc机器越来越多,ftp发布就变得很麻烦了,你得一个文件一个文件上传不说,还得切换机器上传。我们研究了常见的文件同步软件后,采用了rsync软件同步。 rsync很方便的就是可以一次同步到多个机器,可以备份,方便回退;唯一的缺点就是命令行操作,不能查看以往的发布记录。所以当团队越来越大的时候很有必要基于sync做一个可视化的发布系统。

  • 需要解决的问题点

    • 文件目录可视化操作勾选以及搜索
    • 以发布任务的形式操作文件发布、回退
    • 源代码查看以及和线上代码对比功能
  • 一个一个解决

    • 目录文件可视化操作

    随便百度了下,发现有很多这样的开源项目,采用了jstree项目,这个项目对服务器上的路径的目录文件能很好的解析,同时配备js代码绘制树形结构,很方便就画好文档树了。如下图

image

* 任务发布

当点击文件的时候,将文件展示出来,并添加查看源码和文件对比的功能。
$('#tree')
    .jstree({
        'core' : {
            'data' : {
                'url' : '/release/getNodeInfo?path='+path+'&operation=get_node',
                'data' : function (node) {
                    return { 'id' : node.id };
                }
            },
            'check_callback' : function(o, n, p, i, m) {
                if(m && m.dnd && m.pos !== 'i') { return false; }
                if(o === "move_node" || o === "copy_node") {
                    if(this.get_node(n).parent === this.get_node(p).id) { return false; }
                }
                return true;
            },
            'themes' : {
                'responsive' : false,
                'variant' : 'small',
                'stripes' : true
            }
        },
        'sort' : function(a, b) {
            return this.get_type(a) === this.get_type(b) ? (this.get_text(a) > this.get_text(b) ? 1 : -1) : (this.get_type(a) >= this.get_type(b) ? 1 : -1);
        },
        'contextmenu' : {
            'items' : function(node) {
                var tmp = $.jstree.defaults.contextmenu.items();
                delete tmp.create.action;
                tmp.create.label = "New";
                tmp.create.submenu = {
                    "create_folder" : {
                        "separator_after"   : true,
                        "label"             : "Folder",
                        "action"            : function (data) {
                            var inst = $.jstree.reference(data.reference),
                                obj = inst.get_node(data.reference);
                            inst.create_node(obj, { type : "default" }, "last", function (new_node) {
                                setTimeout(function () { inst.edit(new_node); },0);
                            });
                        }
                    },
                    "create_file" : {
                        "label"             : "File",
                        "action"            : function (data) {
                            var inst = $.jstree.reference(data.reference),
                                obj = inst.get_node(data.reference);
                            inst.create_node(obj, { type : "file" }, "last", function (new_node) {
                                setTimeout(function () { inst.edit(new_node); },0);
                            });
                        }
                    }
                };
                if(this.get_type(node) === "file") {
                    delete tmp.create;
                }
                return tmp;
            }
        },
        'types' : {
            'default' : { 'icon' : 'folder' },
            'file' : { 'valid_children' : [], 'icon' : 'file' }
        },
        'unique' : {
            'duplicate' : function (name, counter) {
                return name + ' ' + counter;
            }
        },
        'plugins' : ['state','dnd','sort','types','contextmenu','unique']
    })
    .on('delete_node.jstree', function (e, data) {
        $.get('/release/getNodeInfo?path='+path+'&operation=delete_node', { 'id' : data.node.id })
            .fail(function () {
                data.instance.refresh();
            });
    })
    .on('create_node.jstree', function (e, data) {
        $.get('/release/getNodeInfo?path='+path+'&operation=create_node', { 'type' : data.node.type, 'id' : data.node.parent, 'text' : data.node.text })
            .done(function (d) {
                data.instance.set_id(data.node, d.id);
            })
            .fail(function () {
                data.instance.refresh();
            });
    })
    .on('rename_node.jstree', function (e, data) {
        $.get('/release/getNodeInfo?path='+path+'&operation=rename_node', { 'id' : data.node.id, 'text' : data.text })
            .done(function (d) {
                data.instance.set_id(data.node, d.id);
            })
            .fail(function () {
                data.instance.refresh();
            });
    })
    .on('move_node.jstree', function (e, data) {
        $.get('/release/getNodeInfo?path='+path+'&operation=move_node', { 'id' : data.node.id, 'parent' : data.parent })
            .done(function (d) {
                //data.instance.load_node(data.parent);
                data.instance.refresh();
            })
            .fail(function () {
                data.instance.refresh();
            });
    })
    .on('copy_node.jstree', function (e, data) {
        $.get('/release/getNodeInfo?path='+path+'&operation=copy_node', { 'id' : data.original.id, 'parent' : data.parent })
            .done(function (d) {
                //data.instance.load_node(data.parent);
                data.instance.refresh();
            })
            .fail(function () {
                data.instance.refresh();
            });
    })
    .on('changed.jstree', function (e, data) {
        if(data && data.selected && data.selected.length) {
            var id = data.selected.join(':');
            if(id.split('.').length>1){
                //保存id信息
                if(!isIdExist(id)){
                    saveId(id);
                    $('#js_file_list').append('<li class="jstree-node  jstree-no"><span class="js_path">'+ id +'</span>&nbsp;&nbsp;<a href="#del" class="js_del">删除</a>&nbsp;&nbsp;<a href="#query" class="js_query">查看文件</a>&nbsp;&nbsp;<a href="#query" class="js_diff">对比文件</a></li>');
                }
            }



        }
        else {
            //$('#data .content').hide();
            $('#data .default').html('Select a file from the tree.').show();
        }
    });
    function isIdExist(id){
        for (var i = 0; i < fileList.length; i++) {
            if(fileList[i] == id){
                return true;
            }
        };
        return false;
    }
    function saveId(id){
        fileList.push(id);
    }
    function delId(id){
        for (var i = 0; i < fileList.length; i++) {
            if(fileList[i] == id){
                fileList.splice(i,1)
            }
        };
    }
    $('body').delegate('.js_del','click',function(e){
        var target = $(e.target).closest('li'),
            id = target.find('.js_path').text();
        console.log(target);
        target.remove();
        delId(id);
    })
    $('body').delegate('.js_query','click',function(e){
        var target = $(e.target).closest('li'),
            id = target.find('.js_path').text();
        var loading_id = layer.load(2);
        $.get('/release/getNodeInfo?path='+path+'&operation=get_content&id=' + id, function (d) {
            if(d && typeof d.type !== 'undefined') {
                switch(d.type) {
                    case 'text':
                    case 'txt':
                    case 'md':
                    case 'htaccess':
                    case 'log':
                    case 'sql':
                    case 'php':
                    case 'js':
                    case 'json':
                    case 'css':
                    case 'html':
                        //$('#data .code').show();
                        //$('#code').val(d.content);
                        //break;
                    case 'png':
                    case 'jpg':
                    case 'jpeg':
                    case 'bmp':
                    case 'gif':
                        /*$('#data .image img').one('load', function () { $(this).css({'marginTop':'-' + $(this).height()/2 + 'px','marginLeft':'-' + $(this).width()/2 + 'px'}); }).attr('src',d.content);
                        $('#data .image').show();*/
                        layer.close(loading_id);
                        layer.open({
                            type: 2,
                            title: false,
                            closeBtn: 0, //不显示关闭按钮
                            shade: [0],
                            area: ['340px', '215px'],
                            offset: 'rb', //右下角弹出
                            time: 1000, //1秒后自动关闭
                            shift: 2,
                            content: ['/release/fileInfo?path='+path+'&operation=get_content&id='+id, 'no'], //iframe的url,no代表不显示滚动条
                            end: function(){ //此处用于演示
                                layer.open({
                                    type: 2,
                                    title: '源码查看-'+id,
                                    shadeClose: true,
                                    shade: false,
                                    maxmin: true, //开启最大化最小化按钮
                                    area: ['893px', '600px'],
                                    content: '/release/fileInfo?path='+path+'&operation=get_content&id='+id
                                });
                            }
                        }); 
                        break;
                    default:
                        //$('#data .default').html(d.content).show();
                        //$('#js_file_list').append('<li class="jstree-node  jstree-no">'+data.selected.join(':')+'&nbsp;&nbsp;<a href="#del">删除</a>&nbsp;&nbsp;<a href="#query">查看文件</a></li>');
                        break;
                }
            }
        });
    })
    $('body').delegate('#js_release','click',function(e){
        console.log(fileList);
    })
    $('body').delegate('.js_diff','click',function(e){
        var target = $(e.target).closest('li'),
            id = target.find('.js_path').text();
        var loading_id = layer.load(2);
        layer.close(loading_id);
        layer.open({
            type: 2,
            title: false,
            closeBtn: 0, //不显示关闭按钮
            shade: [0],
            area: ['340px', '215px'],
            offset: 'rb', //右下角弹出
            time: 1000, //1秒后自动关闭
            shift: 2,
            content: ['/release/diffFile?path='+path+'&id='+id, 'no'], //iframe的url,no代表不显示滚动条
            end: function(){ //此处用于演示
                layer.open({
                    type: 2,
                    title: '源码对比-'+id,
                    shadeClose: true,
                    shade: false,
                    maxmin: true, //开启最大化最小化按钮
                    area: ['893px', '600px'],
                    content: '/release/diffFile?path='+path+'&id='+id
                });
            }
        }); 
    })
});

效果如下图:

image

  • 文件源码查看和问价对比

    文件源码查看比较简单,路径发到后台,后台读出文档内容返回给前端,前端用codemirror渲染下就行了,如下:

image

文件对比就比较麻烦了,你得分别读开发环境下的文件的线上的文件,再一行一行的对比,还得渲染出来,不过网上还蛮多这样的开源项目,拿来主义,哈哈。我采用了[php-diff](https://github.com/chrisboulton/php-diff)项目。效果如下:

image

  • 任务系统这块未完待续
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant