mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-08-17 21:25:47 +02:00
1. Add disk IO information to the homepage 2. Add a clear list button in the upload window 3. Optimize the background task overhead of the panel 4. Optimize the disk information caching mechanism 5. Panel Pro edition is online 6. Optimize panel resource usage 7. Optimize SSL certificate renewal 8. Fix the problem of reporting an error when the security entrance is empty 9. Fix the problem of infinite recursion when copying directories in extreme cases
1216 lines
48 KiB
JavaScript
1216 lines
48 KiB
JavaScript
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){
|
|
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('<span class="glyphicon glyphicon-menu-right"></span>').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('<span class="glyphicon glyphicon-menu-left"></span>').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('<span class="glyphicon glyphicon-menu-right"></span>').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('<span class="glyphicon glyphicon-menu-left"></span>').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('<div class="localhost-form-title"><i class="localhost-form_tip"></i><span style="vertical-align: middle;">Login failed, please fill the local server information!</span></div>');
|
|
form.append('<button type="submit" class="btn btn-sm btn-success">Login</button>');
|
|
$('#'+id).append('<div class="localhost-form-shade"><div class="localhost-form-view bt-form-2x">'+ form[0].innerHTML +'</div></div>');
|
|
if(result){
|
|
if(result.indexOf('@127.0.0.1') != -1){
|
|
var user = result.split('@')[0].split(',')[1];
|
|
var port = result.split('1:')[1]
|
|
$("input[name='username']").val(user);
|
|
$("input[name='port']").val(port);
|
|
|
|
}
|
|
|
|
}
|
|
$('.auth_type_checkbox').click(function(){
|
|
var index = $(this).index();
|
|
$(this).addClass('btn-success').removeClass('btn-default').siblings().removeClass('btn-success').addClass('btn-default')
|
|
switch(index){
|
|
case 0:
|
|
$('.c_password_view').addClass('show').removeClass('hidden');
|
|
$('.c_pkey_view').addClass('hidden').removeClass('show').find('input').val('');
|
|
break;
|
|
case 1:
|
|
$('.c_password_view').addClass('hidden').removeClass('show').find('input').val('');
|
|
$('.c_pkey_view').addClass('show').removeClass('hidden');
|
|
break;
|
|
}
|
|
});
|
|
$('.localhost-form-view > button').click(function(){
|
|
var form = {};
|
|
$('.localhost-form-view input,.localhost-form-view textarea').each(function(index,el){
|
|
var name = $(this).attr('name'),value = $(this).val();
|
|
form[name] = value;
|
|
switch(name){
|
|
case 'port':
|
|
if(!bt.check_port(value)){
|
|
bt.msg({status:false,msg:'Server port format error!'});
|
|
return false;
|
|
}
|
|
break;
|
|
case 'username':
|
|
if(value == ''){
|
|
bt.msg({status:false,msg:'Server user name cannot be empty!'});
|
|
return false;
|
|
}
|
|
break;
|
|
case 'password':
|
|
if(value == '' && $('.c_password_view').hasClass('show')){
|
|
bt.msg({status:false,msg:'Server password cannot be empty!'});
|
|
return false;
|
|
}
|
|
break;
|
|
case 'pkey':
|
|
if(value == '' && $('.c_pkey_view').hasClass('show')){
|
|
bt.msg({status:false,msg:'The server key cannot be empty!'});
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
delete form.sort
|
|
form.ps = 'Local server';
|
|
that.create_host(form,function(res){
|
|
bt.msg(res);
|
|
if(res.status){
|
|
bt.msg({status:true,msg:'Login successful!'});
|
|
$('.localhost_item .icon-trem-close').click();
|
|
that.open_term_view();
|
|
}
|
|
});
|
|
});
|
|
$('.localhost-form-view [name="password"]').keyup(function(e){
|
|
if(e.keyCode == 13){
|
|
$('.localhost-form-view > button').click();
|
|
}
|
|
}).focus();
|
|
},
|
|
|
|
reader_right_menu:function(config,callback){
|
|
var menu = $('<ul class="menu_right_list" id="term_title_menu"></ul>').css({'top':config.position[1],'left':config.position[0]}),html = '';
|
|
bt.each(config.list,function(index,item){
|
|
bt.each(item,function(indexs,items){
|
|
(function(items){
|
|
menu.append($('<li></li>').append($('<a href="javascript:;" title="'+ items.title +'">'+ items.title +'</a>').click(function(e){
|
|
if(items.event) items.event(config.el,$(config.el).data())
|
|
menu.remove();
|
|
if(callback) callback();
|
|
})));
|
|
}(items));
|
|
});
|
|
if(index != config.list.length - 1){
|
|
menu.append('<li class="split_line"></li>');
|
|
}
|
|
});
|
|
if(!$('#term_title_menu').length){
|
|
$('body').append(menu);
|
|
}else{
|
|
$('#term_title_menu').replaceWith(menu);
|
|
}
|
|
$(document).click(function(e){
|
|
menu.remove();
|
|
$(this).unbind('click');
|
|
if(callback) callback();
|
|
})
|
|
},
|
|
/**
|
|
* @name 主机信息添加或编辑
|
|
* @author chudong<2020-08-10>
|
|
* @param {Objeact} obj 需要编辑的form数据,可以为空,为空则添加
|
|
* @return void
|
|
*/
|
|
editor_host_view:function(obj){
|
|
var that = this;
|
|
if (!obj) obj = {form: this.host_form, config: {btn: 'Submit', title: 'Add host information'}}
|
|
this.render_template({
|
|
html: host_form_view.innerHTML,
|
|
data: obj
|
|
}, function (html) {
|
|
layer.open({
|
|
type: 1 //Page层类型
|
|
,area: '510px'
|
|
,closeBtn: 2
|
|
,title: obj.config.title
|
|
,btn: [obj.config.btn, 'Cancel']
|
|
,content: html
|
|
,success: function (layers, index){
|
|
$('.auth_type_checkbox').click(function(){
|
|
var index = $(this).index();
|
|
$(this).addClass('btn-success').removeClass('btn-default').siblings().removeClass('btn-success').addClass('btn-default')
|
|
switch(index){
|
|
case 0:
|
|
$('.c_password_view').addClass('show').removeClass('hidden');
|
|
$('.c_pkey_view').addClass('hidden').removeClass('show').find('input').val('');
|
|
break;
|
|
case 1:
|
|
$('.c_password_view').addClass('hidden').removeClass('show').find('input').val('');
|
|
$('.c_pkey_view').addClass('show').removeClass('hidden');
|
|
break;
|
|
}
|
|
});
|
|
|
|
$('[name="host"]').on('change',function(){
|
|
var host_val = $(this).val();
|
|
if(!host_val) return;
|
|
|
|
var s_host,s_port,s_username,s_password;
|
|
s_host = host_val;
|
|
if(host_val.indexOf('@') != -1){
|
|
var tmp = host_val.split('@')
|
|
s_host = tmp[1]
|
|
s_username = tmp[0]
|
|
|
|
if (s_username.indexOf(':') != -1){
|
|
var tmp = s_username.split(':')
|
|
s_username = tmp[0]
|
|
s_password = tmp[1]
|
|
}
|
|
}
|
|
if(s_host.indexOf(':')!=-1){
|
|
var tmp = s_host.split(':')
|
|
s_host = tmp[0]
|
|
s_port = tmp[1]
|
|
}
|
|
|
|
if(s_host) {
|
|
$(this).val(s_host);
|
|
$('[name="ps"]').val(s_host);
|
|
}
|
|
if(s_port) $('[name="port"]').val(s_port);
|
|
if(s_username) $('[name="username"]').val(s_username);
|
|
if(s_password) $('[name="password"]').val(s_password);
|
|
});
|
|
|
|
$('[name="host"]').on('input',function(){
|
|
$('[name="ps"]').val($(this).val());
|
|
});
|
|
$('[name="password"],[name="ps"]').keyup(function(e){
|
|
if(e.keyCode === 13){
|
|
$('#layui-layer'+ index +' .layui-layer-btn0').click();
|
|
}
|
|
});
|
|
},
|
|
yes:function(indexs,layero){
|
|
var form = {};
|
|
$('.bt-form input,.bt-form textarea').each(function(index,el){
|
|
var name = $(this).attr('name'),value = $(this).val();
|
|
form[name] = value;
|
|
switch(name){
|
|
// case 'host':
|
|
// if(!bt.check_ip(value)){
|
|
// bt.msg({status:false,msg:'服务器ip地址格式错误!'});
|
|
// return false;
|
|
// }
|
|
// break;
|
|
case 'port':
|
|
if(!bt.check_port(value)){
|
|
bt.msg({status:false,msg:'Server port format error!'});
|
|
return false;
|
|
}
|
|
break;
|
|
case 'username':
|
|
if(value == ''){
|
|
bt.msg({status:false,msg:'Server user name cannot be empty!'});
|
|
return false;
|
|
}
|
|
break;
|
|
case 'password':
|
|
if(value == '' && $('.c_password_view').hasClass('show')){
|
|
bt.msg({status:false,msg:'Server password cannot be empty!'});
|
|
return false;
|
|
}
|
|
break;
|
|
case 'pkey':
|
|
if(value == '' && $('.c_pkey_view').hasClass('show')){
|
|
bt.msg({status:false,msg:'Server key cannot be empty!'});
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
if(!obj.form.sort){
|
|
delete form.sort;
|
|
that.create_host(form,function(res){
|
|
if(res.status){
|
|
that.open_term_view(form);
|
|
layer.close(indexs)
|
|
that.reader_host_list(function(){
|
|
bt.msg(res);
|
|
})
|
|
}
|
|
});
|
|
}else{
|
|
form.new_host = form.host;
|
|
form.host = obj.form.host;
|
|
that.modify_host(form,function(res){
|
|
if(res.status){
|
|
layer.close(indexs)
|
|
that.reader_host_list(function(){
|
|
bt.msg(res);
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
});
|
|
});
|
|
},
|
|
|
|
/**
|
|
* @name 常用信息添加或编辑
|
|
* @author chudong<2020-08-10>
|
|
* @param {Objeact} obj 需要编辑的form数据,可以为空,为空则添加
|
|
* @return void
|
|
*/
|
|
editor_command_view:function(obj){
|
|
var that = this;
|
|
if (!obj) obj = {form: this.command_form, config: {btn: 'Submit', title: 'Add command information'}};
|
|
this.render_template({
|
|
html: shell_form_view.innerHTML,
|
|
data: obj
|
|
}, function (html) {
|
|
layer.open({
|
|
type: 1 //Page层类型
|
|
,area: '510px'
|
|
,closeBtn: 2
|
|
,title: obj.config.title
|
|
,btn: [obj.config.btn, 'Cancel']
|
|
,content: html
|
|
,yes: function (indexs,layero){
|
|
var shell = $('[name="shell"]').val(),title = $('[name="title"]').val();
|
|
if(title == ''){
|
|
bt.msg({status:false,msg:'Command description cannot be empty!'});
|
|
return false;
|
|
}
|
|
if(shell == ''){
|
|
bt.msg({status:false,msg:'Command cannot be empty!'});
|
|
return false;
|
|
}
|
|
|
|
if(!obj.form.title){
|
|
that.create_command({shell:shell,title:title},function(res){
|
|
if(res.status){
|
|
layer.close(indexs);
|
|
that.reader_command_list(function(){
|
|
bt.msg(res);
|
|
});
|
|
}
|
|
});
|
|
}else{
|
|
that.modify_command({new_title:title,title:obj.form.title,shell:shell},function(res){
|
|
if(res.status){
|
|
layer.close(indexs);
|
|
that.reader_command_list(function(){
|
|
bt.msg(res);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
});
|
|
});
|
|
},
|
|
/**
|
|
* @name 设置终端标题状态
|
|
* @author chudong<2020-08-10>
|
|
* @param {String} id 终端ID
|
|
* @param {number} status 终端状态
|
|
* @return void
|
|
*/
|
|
set_term_icon:function(id,status){
|
|
var icon_list = ['icon-warning','icon-sucess','icon-info'];
|
|
$("[data-id='"+ id +"']").find('.icon').removeAttr('class').addClass(icon_list[status]+' icon');
|
|
},
|
|
/**
|
|
* @name 打开终端显示视图
|
|
* @author chudong<2020-08-10>
|
|
* @param {Objeact} info 终端数据 {
|
|
* ps:已添加的备注,
|
|
* host:已添加的服务器ip
|
|
* }
|
|
* @return void
|
|
*/
|
|
open_term_view:function(info){
|
|
if(typeof info === "undefined") info = {host:'127.0.0.1',ps:'Local server'}
|
|
var random = bt.get_random(9),tab_content = $('.term_content_tab'),item_list = $('.term_item_tab .list');
|
|
tab_content.find('.term_item').removeClass('active').siblings().removeClass('active');
|
|
tab_content.append('<div class="term_item active" id="'+ random +'" data-host="'+ info.host +'"></div>');
|
|
item_list.find('.item').removeClass('active');
|
|
item_list.append('<span class="active item '+ (info.host =='127.0.0.1'?'localhost_item':'') +'" data-host="'+ info.host +'" data-id="'+ random +'"><i class="icon icon-sucess"></i><div class="content"><span>'+ info.ps +'</span></div><span class="icon-trem-close"></span></span>');
|
|
this.host_term[random] = new Terms('#'+random,{ssh_info:{host:info.host,ps:info.ps,id:random}});
|
|
},
|
|
/**
|
|
* @name 关闭终端显示视图
|
|
* @author chudong<2020-08-10>
|
|
* @param {String} id 终端id
|
|
* @return void
|
|
*/
|
|
remove_term_view:function(id){
|
|
var item = $('[data-id="'+ id +'"]'),next = item.next(),prev = item.prev();
|
|
$('#'+id).remove();
|
|
item.remove();
|
|
try {
|
|
this.host_term[id].bws.close();
|
|
} catch (error) {
|
|
}
|
|
delete this.host_term[id];
|
|
if(item.hasClass('active')){
|
|
if(next.length > 0){
|
|
next.click();
|
|
}else{
|
|
prev.click();
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* @name 关闭选中右侧终端显示视图
|
|
* @author chudong<2020-08-10>
|
|
* @param {String} id 终端id
|
|
* @return void
|
|
*/
|
|
remove_term_right_view:function(id){
|
|
var arry = [],item = $('[data-id="'+ id +'"]'),nextAll = item.nextAll(),that = this;
|
|
if(!nextAll.length){
|
|
return false;
|
|
}
|
|
nextAll.each(function(index,el){
|
|
var data = $(this).data();
|
|
try {
|
|
that.host_term[data.id].bws.close();
|
|
} catch (error) {
|
|
}
|
|
delete that.host_term[data.id];
|
|
});
|
|
nextAll.remove();
|
|
item.addClass('active');
|
|
$('#'+id).addClass('active').nextAll().remove();
|
|
},
|
|
/**
|
|
* @name 关闭其他终端显示视图
|
|
* @author chudong<2020-08-10>
|
|
* @param {String} id 终端id
|
|
* @return void
|
|
*/
|
|
remove_term_other_view:function(id){
|
|
var arry = [],item = $('[data-id="'+ id +'"]'),siblings = item.siblings(),that = this;
|
|
if(!siblings.length){
|
|
return false;
|
|
}
|
|
siblings.each(function(index,el){
|
|
var data = $(this).data();
|
|
try {
|
|
that.host_term[data.id].bws.close();
|
|
} catch (error) {
|
|
}
|
|
delete that.host_term[data.id];
|
|
});
|
|
siblings.remove();
|
|
item.addClass('active');
|
|
$('#'+id).addClass('active').siblings().remove();
|
|
},
|
|
/**
|
|
* @name 渲染常用命令列表
|
|
* @author chudong<2020-08-10>
|
|
* @param {Objeact} callback 回调函数,回调参数1:当前请求内容
|
|
* @return void
|
|
*/
|
|
reader_command_list:function(callback){
|
|
var that = this,html = '';
|
|
this.get_command_list(function(rdata){
|
|
bt.each(rdata,function(index,item){
|
|
html += '<li data-title="'+ item.title +'" data-index="'+ index +'" data-clipboard-text="'+ item.shell +'"><i></i><span>'+ item.title +'</span><span class="tootls">'+
|
|
'<span class="glyphicon glyphicon-edit" aria-hidden="true" title="Edit common command information"></span>'+
|
|
'<span class="glyphicon glyphicon-trash" aria-hidden="true" title="Delete common command information"></span>'+
|
|
'</span></li>';
|
|
});
|
|
$('.tootls_commonly_list').html(html);
|
|
var clipboard = new ClipboardJS('.tootls_commonly_list li');
|
|
clipboard.on('success', function(e) {
|
|
layer.msg('Copy succeeded!',{icon:1});
|
|
e.clearSelection();
|
|
});
|
|
|
|
clipboard.on('error', function(e) {
|
|
console.error('Action:', e.action);
|
|
console.error('Trigger:', e.trigger);
|
|
});
|
|
that.command_list = rdata;
|
|
if(callback) callback(rdata)
|
|
});
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
* @name 渲染主机视图列表
|
|
* @author chudong<2020-08-10>
|
|
* @param {Objeact} callback 回调函数,回调参数1:当前请求内容
|
|
* @return void
|
|
*/
|
|
reader_host_list:function(callback){
|
|
var that = this,html = '';
|
|
this.get_host_list(function(rdata){
|
|
bt.each(rdata,function(index,item){
|
|
html += '<li data-host="'+ item.host +'" data-index="'+ index +'"><i></i><span>'+ (item.ps == item.host?item.ps:(item.ps +'【'+ item.host +'】')) +'</span><span class="tootls">'+
|
|
'<span class="glyphicon glyphicon-edit" aria-hidden="true" title="Edit server information"></span>'+
|
|
'<span class="glyphicon glyphicon-trash" aria-hidden="true" title="Delete server information"></span>'+
|
|
'</span></li>';
|
|
});
|
|
$('.tootls_host_list').html(html);
|
|
that.host_list = rdata;
|
|
if(callback) callback()
|
|
});
|
|
},
|
|
/**
|
|
* @name 获取host列表
|
|
* @author chudong<2020-08-010>
|
|
* @param {Objeact} callback 回调函数,回调参数1:当前请求内容
|
|
* @return void
|
|
*/
|
|
get_host_list:function(callback){
|
|
var loadT = bt.load('Getting server list, please wait...');
|
|
this.post('get_host_list',{},function(rdata){
|
|
loadT.close();
|
|
if(callback) callback(rdata);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* @name 获取指定host信息
|
|
* @author hwliang<2020-08-07>
|
|
* @param host string host地址
|
|
* @return void
|
|
*/
|
|
get_host_find:function(host,callback){
|
|
var loadT = bt.load('Getting the specified server information, please wait...');
|
|
this.post('get_host_find',{host:host},function(rdata){
|
|
loadT.close();
|
|
if(callback) callback(rdata);
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* @name 创建新的host信息
|
|
* @author hwliang<2020-08-07>
|
|
* @param ssh_info array ssh信息对象 {
|
|
* host: 主机地址,
|
|
port: 端口
|
|
ps: 备注
|
|
username: 用户名
|
|
password: 密码
|
|
pkey: 密钥(如果不为空,将使用密钥连接)
|
|
* }
|
|
* @return void
|
|
*/
|
|
create_host:function(ssh_info,callback){
|
|
var loadT = bt.load('Adding server information, please wait...');
|
|
this.post('create_host',ssh_info,function(rdata){
|
|
loadT.close();
|
|
if(!rdata.status){
|
|
bt.msg(rdata);
|
|
return false;
|
|
}
|
|
if(callback) callback(rdata);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* @name 修改host信息
|
|
* @author hwliang<2020-08-07>
|
|
* @param ssh_info array ssh信息对象 {
|
|
* host: 主机地址,
|
|
port: 端口
|
|
ps: 备注
|
|
sort: 排序(可选,默认0)
|
|
username: 用户名
|
|
password: 密码
|
|
pkey: 密钥(如果不为空,将使用密钥连接)
|
|
* }
|
|
* @return void
|
|
*/
|
|
modify_host:function(ssh_info,callback){
|
|
var loadT = bt.load('Modifying the specified server information, please wait...');
|
|
this.post('modify_host',ssh_info,function(rdata){
|
|
loadT.close();
|
|
if(callback) callback(rdata);
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* @name 删除host信息
|
|
* @author hwliang<2020-08-07>
|
|
* @param host string host地址
|
|
* @return void
|
|
*/
|
|
remove_host:function(host,callback){
|
|
var loadT = bt.load('Deleting specified server information, please wait...');
|
|
this.post('remove_host',{host:host},function(rdata){
|
|
loadT.close();
|
|
if(callback) callback(rdata);
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* @name 设置host排序(使用降序)
|
|
* @author hwliang<2020-08-07>
|
|
* @param sort_list array 排序对象{
|
|
* "127.0.0.1":3,
|
|
* "192.168.1.254":2
|
|
* }
|
|
* @return void
|
|
*/
|
|
set_sort:function(sort_list,callabck){
|
|
this.post('set_sort',{sort_list:JSON.stringify(sort_list)},function(rdata){
|
|
if(callabck) callabck(rdata);
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* @name 获取常用命令列表
|
|
* @author hwliang<2020-08-08>
|
|
* @return void
|
|
*/
|
|
get_command_list: function(callback){
|
|
var loadT = bt.load('Getting list of frequently used commands, please wait...');
|
|
this.post('get_command_list',{},function(rdata){
|
|
loadT.close();
|
|
if(callback) callback(rdata);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* @name 创建常用命令
|
|
* @author hwliang<2020-08-08>
|
|
* @param {title} string 命令标题
|
|
* @parma {shell} string 命令文本
|
|
* @return void
|
|
*/
|
|
create_command: function(obj,callback){
|
|
var loadT = bt.load('Creating common commands, please wait...');
|
|
this.post('create_command',obj,function(rdata){
|
|
loadT.close();
|
|
if(callback) callback(rdata);
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* @name 获取指定常用命令
|
|
* @author hwliang<2020-08-08>
|
|
* @param {title} string 命令标题
|
|
* @return void
|
|
*/
|
|
get_command_find: function(title,callback){
|
|
var loadT = bt.load('Getting specified common command data, please wait...');
|
|
this.post('get_command_find',{title:title},function(rdata){
|
|
loadT.close();
|
|
if(callback) callback(rdata);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* @name 修改常用命令
|
|
* @author hwliang<2020-08-08>
|
|
* @param {title} string 命令标题
|
|
* @param {new_title} string 新的命令标题
|
|
* @parma {shell} string 命令文本
|
|
* @return void
|
|
*/
|
|
modify_command: function(obj,callback){
|
|
var loadT = bt.load('Modifying specified common commands, please wait...');
|
|
this.post('modify_command',obj,function(rdata){
|
|
loadT.close();
|
|
if(callback) callback(rdata);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* @name 删除指定常用命令
|
|
* @author hwliang<2020-08-08>
|
|
* @param {title} string 命令标题
|
|
* @return void
|
|
*/
|
|
remove_command: function(title,callback){
|
|
var loadT = bt.load('Deleting specified common commands, please wait...');
|
|
this.post('remove_command',{title:title},function(rdata){
|
|
loadT.close();
|
|
// console.log(rdata)
|
|
if(callback) callback(rdata);
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* @name 请求到后端
|
|
* @author hwliang<2020-08-07>
|
|
* @param fun_name string 要访问的方法名称
|
|
* @param pdata array POST数据
|
|
* @param callback function 回调函数
|
|
* @return void
|
|
*/
|
|
post:function(fun_name,pdata,callback){
|
|
bt.send(fun_name,'xterm/'+fun_name,pdata,callback);
|
|
},
|
|
|
|
/**
|
|
* @author chudong<2020-08-08>
|
|
* @param {Object} obj 需要渲染的配置对象
|
|
* @param {*} callback 渲染完成的回调方法
|
|
*/
|
|
render_template:function(obj, callback) {
|
|
if (!obj.html) return '缺少模板HTML';
|
|
var re = /<%([^%>]+)?%>/g, reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g, code = 'var r=[];\n',
|
|
cursor = 0;
|
|
var add = function (line, js) {
|
|
js ? (code += line.match(reExp) ? line + '\n' : 'r.push(' + line + ');\n') :
|
|
(code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
|
|
return add;
|
|
}
|
|
while (match = re.exec(obj.html)) {
|
|
add(obj.html.slice(cursor, match.index))(match[1], true);
|
|
cursor = match.index + match[0].length;
|
|
}
|
|
add(obj.html.substr(cursor, obj.html.length - cursor));
|
|
code += 'return r.join("");';
|
|
if (callback) {
|
|
callback(new Function(code.replace(/[\r\t\n]/g, '')).apply(obj.data));
|
|
} else {
|
|
return new Function(code.replace(/[\r\t\n]/g, '')).apply(obj.data);
|
|
}
|
|
}
|
|
}
|
|
host_trem.init(); |