function Terms(el,config){ if(typeof config == "undefined") config = {}; this.el = el; this.id = config.ssh_info.id || ''; this.bws = null; //websocket对象 this.route ='/webssh'; // 访问的方法 this.term =null; //term对象 this.info =null; // 请求数据 this.last_body =null; this.fontSize =15; //终端字体大小 this.ssh_info = config.ssh_info; this.run(); } Terms.prototype = { // websocket持久化连接 connect:function(callback){ var that = this; // 判断当前websocket连接是否存在 if(!this.bws || this.bws.readyState == 3 || this.bws.readyState == 2){ this.bws = new WebSocket((window.location.protocol === 'http:' ? 'ws://' : 'wss://') + window.location.host + this.route); this.bws.addEventListener('message',function(ev){that.on_message(ev)}); this.bws.addEventListener('close',function(ev){that.on_close(ev)}); this.bws.addEventListener('error',function(ev){that.on_error(ev)}); this.bws.addEventListener('open',function(ev){that.on_open(ev)}); if(callback) callback(this.bws) } }, //连接服务器成功 on_open:function(ws_event){ var http_token = $("#request_token_head").attr('token'); this.send(JSON.stringify({'x-http-token':http_token})) this.send(JSON.stringify(this.ssh_info || {})) this.term.FitAddon.fit(); this.resize({cols:this.term.cols, rows:this.term.rows}); }, //服务器消息事件 on_message: function (ws_event){ result= ws_event.data; if(!result) return; that = this; if ((result.indexOf("@127.0.0.1:") != -1 || result.indexOf("@localhost:") != -1) && result.indexOf('Authentication failed') != -1) { that.term.write(result); host_trem.localhost_login_form(result); that.close(); return; } if(result.length > 1 && that.last_body === false){ that.last_body = true; } that.term.write(result); that.set_term_icon(1); if (result == '\r\n登出\r\n' || result == '登出\r\n' || result == '\r\nlogout\r\n' || result == 'logout\r\n') { that.close(); that.bws = null; } }, //websocket关闭事件 on_close: function (ws_event) { this.set_term_icon(0); this.bws = null; }, /** * @name 设置终端标题状态 * @author chudong<2020-08-10> * @param {number} status 终端状态 * @return void */ set_term_icon:function(status){ var icon_list = ['icon-warning','icon-sucess','icon-info']; if(status == 1){ if($("[data-id='"+ this.id +"']").attr("class").indexOf('active') == -1){ status = 2; } } $("[data-id='"+ this.id +"']").find('.icon').removeAttr('class').addClass(icon_list[status]+' icon'); if(status == 2){ that = this; setTimeout(function(){ $("[data-id='"+ that.id +"']").find('.icon').removeAttr('class').addClass(icon_list[1]+' icon'); },200); } }, //websocket错误事件 on_error: function (ws_event) { if(ws_event.target.readyState === 3){ // var msg = '错误: 无法创建WebSocket连接,请在面板设置页面关闭【开发者模式】'; // layer.msg(msg,{time:5000}) // if(Term.state === 3) return // Term.term.write(msg) // Term.state = 3; }else{ console.log(ws_event) } }, //发送数据 //@param event 唯一事件名称 //@param data 发送的数据 //@param callback 服务器返回结果时回调的函数,运行完后将被回收 send: function (data, num) { var that = this; //如果没有连接,则尝试连接服务器 if (!this.bws || this.bws.readyState == 3 || this.bws.readyState == 2) { this.connect(); } //判断当前连接状态,如果!=1,则100ms后尝试重新发送 if (this.bws.readyState === 1) { this.bws.send(data); } else { if(this.state === 3) return; if (!num) num = 0; if (num < 5) { num++; setTimeout(function () { that.send(data, num++); }, 100) } } }, //关闭连接 close: function () { this.bws.close(); this.set_term_icon(0); }, resize: function (size){ if(this.bws){ size['resize'] = 1; this.send(JSON.stringify(size)); } }, run: function (ssh_info) { var that = this; this.term = new Terminal({fontSize:this.fontSize, screenKeys: true, useStyle: true }); this.term.setOption('cursorBlink', true); this.last_body = false; this.term.open($(this.el)[0]); this.term.FitAddon = new FitAddon.FitAddon(); this.term.loadAddon(this.term.FitAddon); this.term.WebLinksAddon = new WebLinksAddon.WebLinksAddon() this.term.loadAddon(this.term.WebLinksAddon) if (ssh_info) this.ssh_info = ssh_info this.connect(); that.term.onData(function (data) { try { that.bws.send(data) } catch (e) { that.term.write('\r\nConnection lost, trying to connect again!\r\n') that.connect() } }); this.term.focus(); } } var host_trem = { host_term:{}, host_list:[], command_list:[], sort_time:null, is_full:false, command_form:{ title:'', shell:'', }, host_form:{ host:'', port:'22', //默认端口22 username:'root', password:'', pkey: '', ps: '' }, init:function(){ var that = this; Object.defineProperty(host_trem,'is_full',{ get:function(val){ return val; }, set:function(newValue) { if(newValue){ $('body').addClass('full_term_view'); var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight; $('.main-content .safe').height(win_height); $('#term_box_view,.term_tootls').height(win_height); $('.tootls_host_list').height((win_height - 80) * .75); $('.tootls_commonly_list').height((win_height - 80) * .25); $('.tab_tootls .glyphicon').removeClass('glyphicon-resize-full').addClass('glyphicon-resize-small').attr('title','Exit full screen'); }else{ $('body').removeClass('full_term_view'); $('.tab_tootls .glyphicon').removeClass('glyphicon-resize-small').addClass('glyphicon-resize-full').attr('title','Full Screen'); } } }); document.onkeydown = function(e){ e = e || window.event; if ((e.metaKey && e.keyCode == 82) || e.keyCode == 116){ return false; } if(that.is_full && e.keyCode == 27){ return false; } } //本地存储 var _tool_status = localStorage.getItem("tool_status"); _tool_host_height = localStorage.getItem("hostHeight"), _tool_commonly_height = localStorage.getItem("commonlyHeight"); if(_tool_commonly_height <= 100 )_tool_commonly_height=100; $(window).resize(function(ev){ that.on_resize(that); }); $('.tab_tootls').on('click','.glyphicon-resize-full',function(){ $(this).removeClass('glyphicon-resize-full').addClass('glyphicon-resize-small').attr('title','Exit full Screen'); $('body').addClass('full_term_view'); that.requestFullScreen(); }); $('.tab_tootls').on('click','.glyphicon-resize-small',function(){ $(this).removeClass('glyphicon-resize-small').addClass('glyphicon-resize-full').attr('title','Full Screen'); $('body').removeClass('full_term_view'); that.exitFullscreen(); }); $(document).ready(function (e) { var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight,host_commonly = win_height - 185; $('.main-content .safe').height(win_height - 105); $('#term_box_view,.term_tootls').height(win_height - 105); if(_tool_host_height !=0&&_tool_commonly_height !=0){ $(".tootls_host_list").css("height",_tool_host_height+"px"), $(".tootls_commonly_list").css("height", _tool_commonly_height+"px"); }else{ $('.tootls_host_list').height(host_commonly * .75); $('.tootls_commonly_list').height(host_commonly * .25); } that.open_term_view(); }); // 添加服务器信息 $('.addServer').on('click',function(){ that.editor_host_view(); }); // 切换服务器终端视图 $('.term_item_tab .list').on('click','span.item',function(ev){ var index = $(this).index(),data = $(this).data(); if($(this).hasClass('addServer')){ }else if($(this).hasClass('tab_tootls')){ }else{ $(this).addClass('active').siblings().removeClass('active'); $('.term_content_tab .term_item:eq('+ index +')').addClass('active').siblings().removeClass('active'); that.host_term[data.id]; var item = that.host_term[data.id]; item.term.focus(); item.term.FitAddon.fit(); item.resize({cols:item.term.cols, rows:item.term.rows}); } }); //通过本地存储获取显示设置 if(_tool_status==0){ $(".term-tool-button").empty(); $(".term-tool-button").append('').addClass("tool-hide").removeClass("tool-show"); $(".term_box").css("margin-right","260px"); $(".term_tootls").css("display","block"); if(_tool_host_height !=0&&_tool_commonly_height !=0){ $(".tootls_host_list").css("height",_tool_host_height+"px"), $(".tootls_commonly_list").css("height", _tool_commonly_height+"px"); } }else{ $(".term-tool-button").empty(); $(".term-tool-button").append('').addClass("tool-show").removeClass("tool-hide"); $(".term_box").css("margin-right","0px"); $(".term_tootls").css("display","none"); } //终端工具栏显示 $('.term_content_tab').on('click','.tool-show',function(){ $(this).empty(); $(this).append('').addClass("tool-hide").removeClass("tool-show"); $(".term_box").css("margin-right","260px"); $(".term_tootls").css("display","block"); localStorage.setItem("tool_status",0); that.on_resize(that); }); //终端工具栏隐藏 $('.term_content_tab').on('click','.tool-hide',function(){ $(this).empty(); $(this).append('').addClass("tool-show").removeClass("tool-hide"); $(".term_box").css("margin-right","0px"); $(".term_tootls").css("display","none"); localStorage.setItem("tool_status",1); that.on_resize(that); }); $(".term-move-border").on('mousedown', function (e) { var hostbox_height = parseInt($(".tootls_host_list").css("height")), commonlybox_height = parseInt($(".tootls_commonly_list").css("height")), max_height = hostbox_height + commonlybox_height+38, move_y = e.clientY; $(document).on('mousemove', function (ev) { var offsetY = ev.clientY - move_y, _host = hostbox_height+offsetY; _commonly = commonlybox_height-offsetY; if(_host <= 300){ _host = 300;_commonly = max_height-_host-38; }else if(_commonly <= 100){ _commonly = 100;_host = max_height-_commonly-38; } $(".tootls_host_list").css("height",_host+"px"),$(".tootls_commonly_list").css("height",_commonly+"px"); }); $(document).on('mouseup', function (ev) { var _host_height = parseInt($(".tootls_host_list").css("height")), _commonly_height = parseInt($(".tootls_commonly_list").css("height")); localStorage.setItem("hostHeight",_host_height); localStorage.setItem("commonlyHeight",_commonly_height); $(this).unbind('mousemove mouseup'); }); e.stopPropagation(); }); $('.term_item_tab').on('click','.icon-trem-close',function(){ var id = $(this).parent().data('id'); that.remove_term_view(id); }) // 服务器列表工具箱 $('.tootls_host_list').on('click','li .tootls span',function(ev){ var item = $(this).parent().parent(),host = item.data('host'),index = item.data('index'); if(!$(this).index()){ that.get_host_find(host,function(rdata){ if(rdata.status === false){ bt.msg(rdata); return false; } that.editor_host_view({ form:rdata, config: {btn: 'Save', title: 'Edit server information [ '+ host +' ]'} }); }); }else{ bt.confirm({title:'Delete information',msg:'Delete service information [ '+ host +' ], continue?',icon:0},function(index){ that.remove_host(host,function(rdata){ layer.close(index); that.reader_host_list(function(){ bt.msg(rdata); }); }); }); } ev.stopPropagation(); }); // 服务器列表工具箱 $('.tootls_commonly_list').on('click','li .tootls span',function(ev){ var item = $(this).parent().parent(),title = item.data('title'),index = item.data('index'); if(!$(this).index()){ that.get_command_find(title,function(rdata){ if(rdata.status === false){ bt.msg(rdata); return false; } that.editor_command_view({ form:rdata, config: {btn: 'Save', title: 'Edit command information【'+ title +'】'} }); }); }else{ bt.confirm({title:'Delete command',msg:'Delete service command 【'+ title +'】, continue?',icon:0},function(index){ that.remove_command(title,function(rdata){ layer.close(index); that.reader_command_list(function(){ bt.msg(rdata); }); }); }); } ev.stopPropagation(); }); // 右键菜单 $('.term_item_tab .list').on('mousedown','.item',function(ev){ if(ev.which == 3){ that.reader_right_menu({ el:$(this), position:[ev.clientX,ev.clientY], list:[ [{title:'Copy session',event:function(el,data){ that.open_term_view(that.host_term[data.id].ssh_info); }}], [{title:'Close session',event:function(el,data){ that.remove_term_view(data.id); }}, {title:'Close to right',event:function(el,data){ bt.confirm({msg:'After closing the terminal session, the command in progress in the current command line session may be aborted. Continue?',title: "Close the terminal session?"},function(index){ that.remove_term_right_view(data.id); layer.close(index); }); }}, {title:'Close other',event:function(el,data){ bt.confirm({msg:'After closing the terminal session, the command in progress in the current command line session may be aborted. Continue?',title: "Close the terminal session?"},function(index){ that.remove_term_other_view(data.id); layer.close(index); }); }}] ] },function(){ $(document).unbind('contextmenu'); }); ev.preventDefault(); $(document).contextmenu(function(e){ e.preventDefault(); }); } }); // 添加服务器和常用秘钥 $('.term_tootls .tootls_tab a').click(function(){ var type = $(this).data('type'); if(type == 'host'){ that.editor_host_view(); }else{ that.editor_command_view(); } }); // var clientX = null,clientY = null; // $('.tootls_host_list').on('mousedown','li',function(e){ // clientX = e.clientX,clientY = e.clientY; // }) // 模拟触发服务器列表点击事件 // $('.tootls_host_list').on('mouseup','li',function(e){ // if(e.button == 0){ // if(clientX == e.clientX && clientY == e.clientY){ // } // } // }); $('.tootls_host_list').on('click','li',function(e){ var index = $(this).index(),host = $(this).data('host'); $(this).find('i').addClass('active'); if($('.item[data-host="'+ host +'"]').length > 0){ layer.msg('For multi session window, right click the terminal title to copy the session!',{icon:0,time:3000}) }else{ that.open_term_view(that.host_list[index]); } }); // 服务器列表拖动 $('.tootls_host_list').dragsort({ dragSelector:'li i', dragEnd:function(){ clearTimeout(that.sort_time); that.sort_time = setTimeout(function(){ var sort_list = {}; $('.tootls_host_list li').each(function(index,el){ sort_list[$(this).data('host')] = index; }); that.set_sort(sort_list,function(rdata){ if(!rdata.status){ bt.msg(rdata); } }); },500); }, dragBetween:false, }); this.reader_host_list(); this.reader_command_list(); }, // 判断全屏状态 isFullScreen:function() { var is_full = document.isFullScreen || document.mozIsFullScreen || document.webkitIsFullScreen; this.is_full = is_full return is_full; }, // 进入全屏 requestFullScreen:function(element){ if(element == undefined) element = document.documentElement; // 判断各种浏览器,找到正确的方法 var requestMethod = element.requestFullScreen || //W3C element.webkitRequestFullScreen || //FireFox element.mozRequestFullScreen || //Chrome等 element.msRequestFullScreen; //IE11 if (requestMethod) { requestMethod.call(element); } else if (typeof window.ActiveXObject !== "undefined") { //for Internet Explorer var wscript = new ActiveXObject("WScript.Shell"); if (wscript !== null) { wscript.SendKeys("{F11}"); } } this.is_full = true; }, // 退出全屏 exitFullscreen:function(element) { if(element == undefined) element = document.documentElement; // 判断各种浏览器,找到正确的方法 var exitMethod = document.exitFullscreen || //W3C document.mozCancelFullScreen || //FireFox document.webkitExitFullscreen || //Chrome等 document.webkitExitFullscreen; //IE11 if (exitMethod) { exitMethod.call(document); } else if (typeof window.ActiveXObject !== "undefined") { //for Internet Explorer var wscript = new ActiveXObject("WScript.Shell"); if (wscript !== null) { wscript.SendKeys("{F11}"); } } this.is_full = false; }, on_resize:function(that){ var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight,host_commonly = win_height - 185; if(that.isFullScreen()){ $('.main-content .safe').height(win_height); $('#term_box_view,.term_tootls').height(win_height); $('.tootls_host_list').height((win_height - 80) * .75); $('.tootls_commonly_list').height((win_height - 80) * .25); }else{ $('.main-content .safe').height(win_height - 105); $('#term_box_view,.term_tootls').height(win_height - 105); $('.tootls_host_list').height(host_commonly * .75); $('.tootls_commonly_list').height(host_commonly * .25); } var id = $('.term_item_tab .active').data('id'); var item_term = that.host_term[id].term; item_term.FitAddon.fit(); that.host_term[id].resize({cols:item_term.cols, rows:item_term.rows}); }, /** * @name 本地服务器登录表单 * @author chudong<2020-08-10> * @return void */ localhost_login_form:function(result){ var that = this,form = $(this.render_template({html:host_form_view.innerHTML,data:{form:$.extend(that.host_form,{host:'127.0.0.1'})}})),id = $('.localhost_item').data('id') form.find('.ssh_ps_tips').remove(); form.prepend('