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.ssh_info['x-http-token'] = http_token;

      this.send(JSON.stringify(this.ssh_info || { 'x-http-token': http_token }))
      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\n连接丢失,正在尝试重新连接!\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', '退出全屏');
              } else {
                  $('body').removeClass('full_term_view');
                  $('.tab_tootls .glyphicon').removeClass('glyphicon-resize-small').addClass('glyphicon-resize-full').attr('title', '全屏显示');
              }
          }
      });
      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', '退出全屏');
          $('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', '全屏显示');
          $('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", "300px");
          $(".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", "300px");
          $(".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: '保存', title: '编辑服务器信息【' + host + '】' }
                  });
              });
          } else {
              bt.confirm({ title: '删除信息', msg: '是否删除服务信息【' + host + '】，是否继续?', 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: '保存', title: '编辑常用命令信息【' + title + '】' }
                  });
              });
          } else {
              bt.confirm({ title: '删除常用命令', msg: '是否删除常用命令信息【' + title + '】，是否继续?', 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: '复制会话', event: function (el, data) {
                              that.open_term_view(that.host_term[data.id].ssh_info);
                          }
                      }],
                      [{
                          title: '关闭会话', event: function (el, data) {
                              that.remove_term_view(data.id);
                          }
                      },
                      {
                          title: '关闭到右侧', event: function (el, data) {
                              bt.confirm({ msg: '关闭SSH会话后，当前命令行会话正在执行的命令可能被中止，确定关闭吗？', title: "确定要关闭SSH会话吗？" }, function (index) {
                                  that.remove_term_right_view(data.id);
                                  layer.close(index);
                              });
                          }
                      },
                      {
                          title: '关闭其他', event: function (el, data) {
                              bt.confirm({ msg: '关闭SSH会话后，当前命令行会话正在执行的命令可能被中止，确定关闭吗？', title: "确定要关闭SSH会话吗？" }, 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 ul a').click(function () {
      //     var type = $(this).data('type');
      //     switch (type) {
      //         case 'host':
      //             that.editor_host_view();
      //             break;
      //         case 'shell':
      //             that.editor_command_view();
      //             break;
      //     }
      // });
      // 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('如需多会话窗口，请右键终端标题复制会话!', { 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,
      });

      // tab切换
      $('.term_tootls .tab-nav span').click(function () {
          if ($(this).hasClass('on')) return;

          var index = $(this).index();
          $(this).siblings('.on').removeClass('on');
          $(this).addClass('on');
          $('.term_tootls .tab-con .tab-block').removeClass('on');
          $('.term_tootls .tab-con .tab-block').eq(index).addClass('on');
          var type = $(this).attr('data-type');
          switch (type) {
              case 'host':
                  that.reader_host_list();
                  break;
              case 'shell':
                  that.reader_command_list();
                  break;
          }
      });

      // 右侧tab点击添加
      $('.term_tootls .btn').click(function () {
          var type = $(this).data('type');
          switch (type) {
              case 'host':
                  that.editor_host_view();
                  break;
              case 'shell':
                  that.editor_command_view();
                  break;
          }
      });

      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;">无法自动认证，请填写本地服务器的登录信息!</span></div>');
      form.append('<button type="submit" class="btn btn-sm btn-success">登录</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: '服务器端口格式错误！' });
                          return false;
                      }
                      break;
                  case 'username':
                      if (value == '') {
                          bt.msg({ status: false, msg: '服务器用户名不能为空!' });
                          return false;
                      }
                      break;
                  case 'password':
                      if (value == '' && $('.c_password_view').hasClass('show')) {
                          bt.msg({ status: false, msg: '服务器密码不能为空!' });
                          return false;
                      }
                      break;
                  case 'pkey':
                      if (value == '' && $('.c_pkey_view').hasClass('show')) {
                          bt.msg({ status: false, msg: '服务器秘钥不能为空!' });
                          return false;
                      }
                      break;
              }
          });
          delete form.sort
          form.ps = '本地服务器';
          that.create_host(form, function (res) {
              bt.msg(res);
              if (res.status) {
                  bt.msg({ status: true, msg: '登录成功！' });
                  $('.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: '提交', title: '添加主机信息' } }
      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, '取消']
              , 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 'port':
                              if (!bt.check_port(value)) {
                                  bt.msg({ status: false, msg: '服务器端口格式错误！' });
                                  return false;
                              }
                              break;
                          case 'username':
                              if (value == '') {
                                  bt.msg({ status: false, msg: '服务器用户名不能为空!' });
                                  return false;
                              }
                              break;
                          case 'password':
                              if (value == '' && $('.c_password_view').hasClass('show')) {
                                  bt.msg({ status: false, msg: '服务器密码不能为空!' });
                                  return false;
                              }
                              break;
                          case 'pkey':
                              if (value == '' && $('.c_pkey_view').hasClass('show')) {
                                  bt.msg({ status: false, msg: '服务器秘钥不能为空!' });
                                  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: '提交', title: '添加常用命令信息' } };
      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, '取消']
              , content: html
              , yes: function (indexs, layero) {
                  var shell = $('[name="shell"]').val(), title = $('[name="title"]').val();
                  if (title == '') {
                      bt.msg({ status: false, msg: '常用命令描述不能为空！' });
                      return false;
                  }
                  if (shell == '') {
                      bt.msg({ status: false, msg: '常用命令不能为空！' });
                      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: '本地服务器' }
      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="编辑常用命令信息"></span>' +
                  '<span class="glyphicon glyphicon-trash" aria-hidden="true" title="删除常用命令信息"></span>' +
                  '</span></li>';
          });
          $('.tootls_commonly_list').html(html);
          var clipboard = new ClipboardJS('.tootls_commonly_list li');
          clipboard.on('success', function (e) {
              layer.msg('复制成功！', { 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="编辑服务器信息"></span>\
                          <span class="glyphicon glyphicon-trash" aria-hidden="true" title="删除服务器信息"></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('正在获取服务器列表，请稍候...');
      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('正在获取指定服务器信息，请稍候...');
      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('正在添加服务器信息，请稍候...');
      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('正在修改指定服务器信息，请稍候...');
      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('正在删除指定服务器信息，请稍候...');
      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('正在获取常用命令列表，请稍候...');
      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('正在创建常用命令，请稍候...');
      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('正在获取指定常用命令数据，请稍候...');
      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('正在修改指定常用命令，请稍候...');
      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('正在删除指定常用命令，请稍候...');
      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();