feat:外部打开Terminal (80%)
This commit is contained in:
56
nezha-fronted/src/assets/css/animate.css
vendored
56
nezha-fronted/src/assets/css/animate.css
vendored
@@ -950,15 +950,15 @@
|
|||||||
}
|
}
|
||||||
@-webkit-keyframes backInRight {
|
@-webkit-keyframes backInRight {
|
||||||
0% {
|
0% {
|
||||||
-webkit-transform: translateX(2000px) scale(0.7);
|
-webkit-transform: translateX(2000px);
|
||||||
transform: translateX(2000px) scale(0.7);
|
transform: translateX(2000px);
|
||||||
opacity: 0.7;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
80% {
|
80% {
|
||||||
-webkit-transform: translateX(0px) scale(0.7);
|
-webkit-transform: translateX(0px);
|
||||||
transform: translateX(0px) scale(0.7);
|
transform: translateX(0px);
|
||||||
opacity: 0.7;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
@@ -969,15 +969,15 @@
|
|||||||
}
|
}
|
||||||
@keyframes backInRight {
|
@keyframes backInRight {
|
||||||
0% {
|
0% {
|
||||||
-webkit-transform: translateX(2000px) scale(0.7);
|
-webkit-transform: translateX(2000px);
|
||||||
transform: translateX(2000px) scale(0.7);
|
transform: translateX(2000px);
|
||||||
opacity: 0.7;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
80% {
|
80% {
|
||||||
-webkit-transform: translateX(0px) scale(0.7);
|
-webkit-transform: translateX(0px);
|
||||||
transform: translateX(0px) scale(0.7);
|
transform: translateX(0px);
|
||||||
opacity: 0.7;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
@@ -1081,8 +1081,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
20% {
|
20% {
|
||||||
-webkit-transform: translateX(0px) scale(0.7);
|
-webkit-transform: translateX(0px);
|
||||||
transform: translateX(0px) scale(0.7);
|
transform: translateX(0px);
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1100,14 +1100,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
20% {
|
20% {
|
||||||
-webkit-transform: translateX(0px) scale(0.7);
|
-webkit-transform: translateX(0px);
|
||||||
transform: translateX(0px) scale(0.7);
|
transform: translateX(0px);
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
-webkit-transform: translateX(-2000px) scale(0.7);
|
-webkit-transform: translateX(-2000px);
|
||||||
transform: translateX(-2000px) scale(0.7);
|
transform: translateX(-2000px);
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1123,15 +1123,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
20% {
|
20% {
|
||||||
-webkit-transform: translateX(0px) scale(0.7);
|
-webkit-transform: translateX(0px);
|
||||||
transform: translateX(0px) scale(0.7);
|
transform: translateX(0px);
|
||||||
opacity: 0.7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
-webkit-transform: translateX(2000px) scale(0.7);
|
-webkit-transform: translateX(2000px);
|
||||||
transform: translateX(2000px) scale(0.7);
|
transform: translateX(2000px);
|
||||||
opacity: 0.7;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@keyframes backOutRight {
|
@keyframes backOutRight {
|
||||||
@@ -1142,15 +1140,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
20% {
|
20% {
|
||||||
-webkit-transform: translateX(0px) scale(0.7);
|
-webkit-transform: translateX(0px);
|
||||||
transform: translateX(0px) scale(0.7);
|
transform: translateX(0px);
|
||||||
opacity: 0.7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
-webkit-transform: translateX(2000px) scale(0.7);
|
-webkit-transform: translateX(2000px);
|
||||||
transform: translateX(2000px) scale(0.7);
|
transform: translateX(2000px);
|
||||||
opacity: 0.7;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.animate__backOutRight {
|
.animate__backOutRight {
|
||||||
|
|||||||
@@ -1,26 +1,62 @@
|
|||||||
.fileDirectory {
|
.fileDirectory {
|
||||||
height: 80%;
|
width: 45%;
|
||||||
|
min-width: 700px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
top: -5px;
|
||||||
background: #1E1E1E;
|
height: calc(100% + 30px);
|
||||||
box-shadow: 5px 0 3px 0 #5E5E5E;
|
right: -15px;
|
||||||
width: 100% !important;
|
background: $--background-color-empty;
|
||||||
|
box-shadow: 5px 0 3px 0 $--explore-border-color-bottom;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
font-size: 14px;
|
||||||
.file-directory-header{
|
.file-directory-header{
|
||||||
display: flex;
|
display: flex;
|
||||||
|
font-size: 14px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 0 10px;
|
padding: 0 20px;
|
||||||
background: #1E1E1E;
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
background: $--background-color-empty;
|
||||||
|
border-bottom: 1px solid rgba(51,51,51,0.10);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: #ffffff;
|
color:$--color-text-regular;
|
||||||
.header-option{
|
.header-option{
|
||||||
>i {
|
>i {
|
||||||
margin-right: 22px;
|
margin-right: 22px;
|
||||||
}
|
}
|
||||||
|
.nz-icon-close {
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.file-directory-path{
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 20px;
|
||||||
|
background: $--background-color-empty;
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color:$--color-text-regular;
|
||||||
|
.breadcrumb-box{
|
||||||
|
.nz-icon-edit{
|
||||||
|
margin-left: 15px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.breadcrumb-box:hover {
|
||||||
|
.nz-icon-edit{
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nz-icon-edit:hover{
|
||||||
|
color: $--color-primary;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.breadcrumb-item{
|
.breadcrumb-item{
|
||||||
color: #ffffff
|
color:$--color-text-regular
|
||||||
}
|
}
|
||||||
.breadcrumb-action{
|
.breadcrumb-action{
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -28,9 +64,17 @@
|
|||||||
.breadcrumb-action:hover{
|
.breadcrumb-action:hover{
|
||||||
color: $--color-primary;
|
color: $--color-primary;
|
||||||
}
|
}
|
||||||
|
.path-option{
|
||||||
|
display: inline-block;
|
||||||
|
align-items: center;
|
||||||
|
.nz-icon-a-newfolder{
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.file-directory-content{
|
.file-directory-content{
|
||||||
height: calc(100% - 26px);
|
height: calc(100% - 60px);
|
||||||
width: calc(100% - 15px);
|
width: calc(100% - 15px);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
@@ -38,61 +82,74 @@
|
|||||||
width: 6px;
|
width: 6px;
|
||||||
}
|
}
|
||||||
.file-directory-content::-webkit-scrollbar-thumb {
|
.file-directory-content::-webkit-scrollbar-thumb {
|
||||||
background: rgba(244,244,244,0.16);
|
width: 6px;
|
||||||
border-radius: 4px;
|
|
||||||
border:none
|
|
||||||
}
|
}
|
||||||
.file-directory-content::-webkit-scrollbar-thumb:hover {
|
.file-directory-content::-webkit-scrollbar-thumb:hover {
|
||||||
background: rgba(244,244,244,0.16);
|
width: 6px;
|
||||||
border-radius: 4px;
|
}
|
||||||
border:none;
|
.directory-content-header{
|
||||||
.file-feature{
|
height: 32px;
|
||||||
display: none;
|
line-height: 32px;
|
||||||
|
background: $--background-color-2;
|
||||||
|
width: calc(100% - 22px);
|
||||||
|
color: $--color-text-regular;
|
||||||
|
> div{text-transform:capitalize};
|
||||||
|
}
|
||||||
|
.file-name{
|
||||||
|
width: 44%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-left: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.file-size{
|
||||||
|
width: 15%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.file-date{
|
||||||
|
width: 25%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.file-opt{
|
||||||
|
width: 14%;
|
||||||
|
display: inline-block;
|
||||||
|
.nz-icon-shuxing{
|
||||||
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.file-item{
|
.file-item{
|
||||||
font-family: Roboto-Regular;
|
font-family: Roboto-Regular;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #B7B7B7;
|
color: $--color-text-regular;
|
||||||
line-height: 21px;
|
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
line-height: 24px;
|
||||||
.file-item{
|
height: 24px;
|
||||||
display: flex;
|
|
||||||
padding: 0 10px;
|
|
||||||
.file-name{
|
|
||||||
width: calc(100% - 300px);
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
.file-feature{
|
|
||||||
width: 100px;
|
|
||||||
flex-shrink: 1;
|
|
||||||
opacity: 0;
|
|
||||||
>.nz-icon-download1 {
|
|
||||||
margin-right: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.file-date {
|
|
||||||
width: 260px;
|
|
||||||
flex-shrink: 1;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.file-item:hover{
|
.file-item:hover{
|
||||||
background: rgba(255,134,0,0.50);
|
background: rgba(255,134,0,0.50);
|
||||||
font-family: Roboto-Regular;
|
font-family: Roboto-Regular;
|
||||||
font-size: 14px;
|
|
||||||
color: #FF9230;
|
|
||||||
line-height: 21px;
|
|
||||||
font-weight: 400;
|
|
||||||
.file-feature{
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.my-loading-box{
|
.my-loading-box{
|
||||||
background: #1a1a1a;
|
background: #1a1a1a;
|
||||||
}
|
}
|
||||||
|
.nz-icon:hover{
|
||||||
|
color: $--color-primary;
|
||||||
|
}
|
||||||
|
.file-info-item-header{
|
||||||
|
padding-bottom: 20px; border-bottom: 1px solid $--border-color-light;
|
||||||
|
}
|
||||||
|
.file-info-item{
|
||||||
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.file-info-item-left{
|
||||||
|
width: 180px;
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
.file-info-item-right{
|
||||||
|
width: 200px;
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,46 +3,48 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
right:0;
|
right:0;
|
||||||
top:-100px;
|
top:-100px;
|
||||||
max-height: 194px;
|
max-height: 246px;
|
||||||
min-width: 96px;
|
min-width: 96px;
|
||||||
width: 308px;
|
width: 308px;
|
||||||
background: #222329;
|
background: $--background-color-empty;
|
||||||
box-shadow: 1px 1px 4px -1px #1E1E1E;
|
box-shadow: -2px 1px 4px 0 rgba(0,0,0,0.06), 1px 1px 4px -1px rgba(0,0,0,0.16);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
.file-state-panel-content::-webkit-scrollbar {
|
.file-state-panel-content::-webkit-scrollbar {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
}
|
}
|
||||||
.file-state-panel-content::-webkit-scrollbar-thumb {
|
.file-state-panel-content::-webkit-scrollbar-thumb {
|
||||||
background: rgba(244,244,244,0.16);
|
background: rgba(0,0,0,0.16);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border:none
|
border:none
|
||||||
}
|
}
|
||||||
.file-state-panel-content::-webkit-scrollbar-thumb:hover {
|
.file-state-panel-content::-webkit-scrollbar-thumb:hover {
|
||||||
background: rgba(244,244,244,0.16);
|
background: rgba(0,0,0,0.16);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border:none
|
border:none
|
||||||
}
|
}
|
||||||
.file-state-panel-header{
|
.file-state-panel-header{
|
||||||
height: 48px;
|
height: 48px;
|
||||||
background: #222329;
|
background: $--background-color-empty;
|
||||||
box-shadow: 0 1px 0 0 #19191C;
|
box-shadow: 0 1px 0 0 $--background-color-disabled;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
line-height: 48px;
|
line-height: 48px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
text-transform: capitalize;
|
||||||
> i {
|
> i {
|
||||||
color: #ffffff;
|
color: $--color-text-primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.file-state-panel-title{
|
.file-state-panel-title{
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #E7EAED;
|
|
||||||
letter-spacing: 0;
|
letter-spacing: 0;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
text-transform: capitalize;
|
||||||
|
color: $--color-text-primary;
|
||||||
}
|
}
|
||||||
.file-state-panel-content {
|
.file-state-panel-content {
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
max-height: 146px;
|
max-height: 180px;
|
||||||
line-height: 48px;
|
line-height: 48px;
|
||||||
padding-bottom: 15px;
|
padding-bottom: 15px;
|
||||||
border-radius: 0 0 2px 2px;
|
border-radius: 0 0 2px 2px;
|
||||||
@@ -59,9 +61,9 @@
|
|||||||
.item-icon{
|
.item-icon{
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
background: #19191C;
|
background: $--background-color-base;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
color: #fff;
|
color: $--color-text-regular;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -76,21 +78,21 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
.item-progress-top{
|
.item-progress-top{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: #fff;
|
color: $--color-text-regular;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
line-height: 15px;
|
line-height: 15px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
margin-bottom: 3px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
.item-progress-middle{
|
.item-progress-middle{
|
||||||
}
|
}
|
||||||
.item-progress-bottom{
|
.item-progress-bottom{
|
||||||
margin-top: 3px;
|
margin-top: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
color: #B7B7B7;
|
color: $--color-text-secondary;
|
||||||
line-height: 12px;
|
line-height: 12px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
@@ -99,7 +101,7 @@
|
|||||||
flex-shrink:0;
|
flex-shrink:0;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
color: #fff;
|
color: $--color-text-regular;
|
||||||
line-height: 28px;
|
line-height: 28px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@@ -122,6 +124,6 @@
|
|||||||
transform-origin: 70% 0%
|
transform-origin: 70% 0%
|
||||||
}
|
}
|
||||||
.el-progress-bar__outer{
|
.el-progress-bar__outer{
|
||||||
background-color: #19191C;
|
background-color: $--el-progress-bar__outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,6 +253,38 @@
|
|||||||
.popper__arrow{
|
.popper__arrow{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.webshell-box-top{
|
||||||
|
border-bottom: 1px solid rgba(25,25,28,0.10);
|
||||||
|
}
|
||||||
|
.webshell-box-bottom{
|
||||||
|
border-top: 1px solid rgba(25,25,28,0.10);
|
||||||
|
}
|
||||||
|
.webshell-box-item{
|
||||||
|
height: 32px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $--color-text-primary;
|
||||||
|
letter-spacing: 0;
|
||||||
|
line-height: 32px;
|
||||||
|
.nz-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.webshell-box-item:hover{
|
||||||
|
background: $--background-color-base;
|
||||||
|
color: $--color-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.popover-webshell-new{
|
||||||
|
padding: 0 !important;
|
||||||
|
.webshell-box-top, .webshell-box-bottom{
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.webshell-box-top, .webshell-box-bottom,.webshell-box-item{
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
div.sp-header{
|
div.sp-header{
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
147
nezha-fronted/src/assets/css/components/cli/webSSHNew.scss
Normal file
147
nezha-fronted/src/assets/css/components/cli/webSSHNew.scss
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
.web-terminal-new{
|
||||||
|
height: calc(100vh - 68px);
|
||||||
|
background: $--background-color-base;
|
||||||
|
/*border-top: 1px solid #BEBEBE;*/
|
||||||
|
box-shadow: 0 1px 0 0 $--border-color-light;
|
||||||
|
/deep/ .el-tabs{
|
||||||
|
border: none;
|
||||||
|
height: 100%;
|
||||||
|
width:100%;
|
||||||
|
margin-left:0px;
|
||||||
|
.el-tabs__nav-prev, .el-tabs__nav-next{
|
||||||
|
display: inline-block;
|
||||||
|
background: $--background-color-2 !important;
|
||||||
|
width: 20px;
|
||||||
|
height: 36px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 40px;
|
||||||
|
color: $--color-text-primary;
|
||||||
|
}
|
||||||
|
.el-tabs__nav-prev.is-disabled, .el-tabs__nav-next.is-disabled{
|
||||||
|
cursor: pointer !important;
|
||||||
|
display: inline-block;
|
||||||
|
background: $--background-color-2 !important;
|
||||||
|
width: 20px;
|
||||||
|
height: 36px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 40px;
|
||||||
|
color: $--color-text-primary;
|
||||||
|
}
|
||||||
|
.el-tabs__header{
|
||||||
|
height: 36px;
|
||||||
|
width: 100%;
|
||||||
|
.el-tabs__item{
|
||||||
|
height: 36px;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
padding: 0 10px 0 10px;
|
||||||
|
margin-top: 0;
|
||||||
|
border-top: 2px solid transparent;
|
||||||
|
width: 126px;
|
||||||
|
background: $--background-color-empty;
|
||||||
|
line-height: 34px;
|
||||||
|
display: inline-block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
.el-tabs__item-label{
|
||||||
|
display: inline-flex;
|
||||||
|
width: calc(100% - 20px);
|
||||||
|
align-items: center;
|
||||||
|
.active-icon{
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
.el-tabs__item-label-name{
|
||||||
|
flex: 1;
|
||||||
|
width: calc(100% - 30px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-icon-close{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-tabs__item.is-active {
|
||||||
|
width: 200px;
|
||||||
|
border-top: 2px solid $--color-primary;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $--color-text-primary;
|
||||||
|
}
|
||||||
|
.icon-reference{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.el-tabs__item:hover{
|
||||||
|
width: 200px;
|
||||||
|
.icon-reference{
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.el-icon-close{
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-tabs__item:last-of-type {
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 5px;
|
||||||
|
border: none;
|
||||||
|
border-top: 2px solid transparent;
|
||||||
|
background: transparent;
|
||||||
|
width: 40px;
|
||||||
|
line-height: 34px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-tabs__content{
|
||||||
|
height: calc(100% - 36px);
|
||||||
|
background: #000;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: unset;
|
||||||
|
padding: 5px 5px;
|
||||||
|
.el-tab-pane{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webTerminal{
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
.web-terminal-header{
|
||||||
|
height: 36px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 15px;
|
||||||
|
background: $--background-color-base;
|
||||||
|
box-shadow: inset 0 -1px 0 0 $--dropdown-menu-box-shadow-color;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 36px;
|
||||||
|
color: $--color-text-primary;
|
||||||
|
img {
|
||||||
|
vertical-align: sub;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.right-tip {
|
||||||
|
position: absolute;
|
||||||
|
left: 8px;
|
||||||
|
top: 4px;
|
||||||
|
padding: 0 6px;
|
||||||
|
line-height: 15px;
|
||||||
|
height: 15px;
|
||||||
|
background-color: #ba3939;
|
||||||
|
opacity: .9;
|
||||||
|
border-radius: 7px;
|
||||||
|
color: white;
|
||||||
|
font-size: 6px;
|
||||||
|
}
|
||||||
|
.shell-input{
|
||||||
|
input {
|
||||||
|
background: #1E1E1E !important;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
input::input-placeholder{
|
||||||
|
color: #7C7C7C;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
@import './cli/webSSH.scss';
|
@import './cli/webSSH.scss';
|
||||||
@import './cli/fileDirectory.scss';
|
@import './cli/fileDirectory.scss';
|
||||||
@import './cli/fileListState.scss';
|
@import './cli/fileListState.scss';
|
||||||
|
@import './cli/webSSHNew.scss';
|
||||||
@import './common/alert/alertLabel.scss';
|
@import './common/alert/alertLabel.scss';
|
||||||
@import './common/alert/alertStateInfo.scss';
|
@import './common/alert/alertStateInfo.scss';
|
||||||
@import './common/alert/alertRuleInfo.scss';
|
@import './common/alert/alertRuleInfo.scss';
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,6 +5,97 @@
|
|||||||
"css_prefix_text": "nz-icon-",
|
"css_prefix_text": "nz-icon-",
|
||||||
"description": "",
|
"description": "",
|
||||||
"glyphs": [
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "680988",
|
||||||
|
"name": "属性",
|
||||||
|
"font_class": "shuxing",
|
||||||
|
"unicode": "e785",
|
||||||
|
"unicode_decimal": 59269
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33167519",
|
||||||
|
"name": "套接字文件",
|
||||||
|
"font_class": "taojieziwenjian",
|
||||||
|
"unicode": "e7bb",
|
||||||
|
"unicode_decimal": 59323
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33166559",
|
||||||
|
"name": "目录链接",
|
||||||
|
"font_class": "mululianjie",
|
||||||
|
"unicode": "e7b9",
|
||||||
|
"unicode_decimal": 59321
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33165863",
|
||||||
|
"name": "套接字文件链接",
|
||||||
|
"font_class": "taojieziwenjianlianjie",
|
||||||
|
"unicode": "e7ba",
|
||||||
|
"unicode_decimal": 59322
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33158668",
|
||||||
|
"name": "文件链接",
|
||||||
|
"font_class": "wenjianlianjie",
|
||||||
|
"unicode": "e7b5",
|
||||||
|
"unicode_decimal": 59317
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33158669",
|
||||||
|
"name": "管道文件链接",
|
||||||
|
"font_class": "guandaowenjianlianjie",
|
||||||
|
"unicode": "e7b6",
|
||||||
|
"unicode_decimal": 59318
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33158670",
|
||||||
|
"name": "块设备文件链接",
|
||||||
|
"font_class": "kuaishebeiwenjianlianjie",
|
||||||
|
"unicode": "e7b7",
|
||||||
|
"unicode_decimal": 59319
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33158671",
|
||||||
|
"name": "字符串设备文件链接",
|
||||||
|
"font_class": "zifuchuanshebeiwenjianlianjie",
|
||||||
|
"unicode": "e7b8",
|
||||||
|
"unicode_decimal": 59320
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33158636",
|
||||||
|
"name": "管道文件",
|
||||||
|
"font_class": "guandaowenjian",
|
||||||
|
"unicode": "e7b1",
|
||||||
|
"unicode_decimal": 59313
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33158637",
|
||||||
|
"name": "链接文件",
|
||||||
|
"font_class": "lianjiewenjian",
|
||||||
|
"unicode": "e7b2",
|
||||||
|
"unicode_decimal": 59314
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33158639",
|
||||||
|
"name": "块设备文件",
|
||||||
|
"font_class": "kuaishebeiwenjian",
|
||||||
|
"unicode": "e7b3",
|
||||||
|
"unicode_decimal": 59315
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33158641",
|
||||||
|
"name": "字符设备文件",
|
||||||
|
"font_class": "zifushebeiwenjian",
|
||||||
|
"unicode": "e7b4",
|
||||||
|
"unicode_decimal": 59316
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33112141",
|
||||||
|
"name": "home",
|
||||||
|
"font_class": "home",
|
||||||
|
"unicode": "e7af",
|
||||||
|
"unicode_decimal": 59311
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"icon_id": "32964483",
|
"icon_id": "32964483",
|
||||||
"name": "File",
|
"name": "File",
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -259,7 +259,8 @@ $--tooltip-background-color: #222329;
|
|||||||
$--tooltip-border-color: rgba(112,116,122,0.6);
|
$--tooltip-border-color: rgba(112,116,122,0.6);
|
||||||
/* 17.label*/
|
/* 17.label*/
|
||||||
$--label-background-color: $--background-color-empty;
|
$--label-background-color: $--background-color-empty;
|
||||||
|
/* 18 进度条颜色 */
|
||||||
|
$--el-progress-bar__outer: #19191C;
|
||||||
/*** themes/common.scss是与主题切换无关的变量 ***/
|
/*** themes/common.scss是与主题切换无关的变量 ***/
|
||||||
@import './src/common/var.scss';
|
@import './src/common/var.scss';
|
||||||
@import './common.scss';
|
@import './common.scss';
|
||||||
|
|||||||
@@ -254,7 +254,8 @@ $--tooltip-background-color: #ffffff;
|
|||||||
$--tooltip-border-color: rgba(119,131,145,0.6);
|
$--tooltip-border-color: rgba(119,131,145,0.6);
|
||||||
/* 17.label*/
|
/* 17.label*/
|
||||||
$--label-background-color: #D8d8d8;
|
$--label-background-color: #D8d8d8;
|
||||||
|
/* 18 进度条颜色 */
|
||||||
|
$--el-progress-bar__outer: #ebeef5;
|
||||||
/*** themes/common.scss是与主题切换无关的变量 ***/
|
/*** themes/common.scss是与主题切换无关的变量 ***/
|
||||||
@import './src/common/var.scss';
|
@import './src/common/var.scss';
|
||||||
@import './common.scss';
|
@import './common.scss';
|
||||||
|
|||||||
@@ -699,7 +699,8 @@ const unitOptions = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
const units = []
|
const units = []
|
||||||
window.onload = function () {
|
window.addEventListener('load', function () {
|
||||||
|
console.log(13213)
|
||||||
if (units.length < 1) {
|
if (units.length < 1) {
|
||||||
unitOptions.forEach((item, index) => {
|
unitOptions.forEach((item, index) => {
|
||||||
item.children.forEach((n, i) => {
|
item.children.forEach((n, i) => {
|
||||||
@@ -707,8 +708,7 @@ window.onload = function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
unitOptions: function () {
|
unitOptions: function () {
|
||||||
return unitOptions
|
return unitOptions
|
||||||
|
|||||||
323
nezha-fronted/src/components/cli/consoleNew.vue
Normal file
323
nezha-fronted/src/components/cli/consoleNew.vue
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
<style scoped>
|
||||||
|
.console{
|
||||||
|
height: 100%;
|
||||||
|
padding:5px 5px;
|
||||||
|
background-color: black;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<template>
|
||||||
|
<div :id="'ternimalContainer'+idIndex" class="console">
|
||||||
|
<div :id="'terminal'+idIndex" style="height: 100%"></div>
|
||||||
|
<fileDirectory :host="host" v-clickoutside="closeFileDir" :uuid="terminal.uuid" v-show="fileDirectoryShow" @close="showFileDir(false)" :fileDirectoryShow="fileDirectoryShow" ref="fileDirectory"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import Terminal from '../common/js/Xterm'
|
||||||
|
import fileDirectory from './fileDirectory'
|
||||||
|
export default {
|
||||||
|
name: 'console',
|
||||||
|
components: {
|
||||||
|
fileDirectory
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
terminal: { },
|
||||||
|
terminalType: { default: '1' },
|
||||||
|
idIndex: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
isFullScreen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
fontSize: {}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
term: null,
|
||||||
|
terminalSocket: null,
|
||||||
|
termimalRows: 15,
|
||||||
|
termimalHeight: 270,
|
||||||
|
topMenuHeight: 30,
|
||||||
|
dragHeigh: 8,
|
||||||
|
minRow: 1,
|
||||||
|
fontSpaceHeight: 2, // 一行高度=fontSize+fontSpaceHeight
|
||||||
|
obj: {
|
||||||
|
id: 2
|
||||||
|
},
|
||||||
|
isInit: false,
|
||||||
|
successBackContent: 'Connecting to',
|
||||||
|
failBackContent: 'Sorry',
|
||||||
|
connectFailContent: 'Connection failed',
|
||||||
|
welcomeBackContent: 'Welcome',
|
||||||
|
psdCont: 'password: ',
|
||||||
|
conFinish: false,
|
||||||
|
conSuccessNum: 0,
|
||||||
|
inputSecret: false,
|
||||||
|
userName: '',
|
||||||
|
fileDirectoryShow: false,
|
||||||
|
host: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
prompt (term) {
|
||||||
|
term.write('\r\n ')// term.write('\r\n~$ ');
|
||||||
|
},
|
||||||
|
resize (consoleHeigt, consoleWidth) {
|
||||||
|
this.term.fit()
|
||||||
|
this.resizeServiceConsole()
|
||||||
|
},
|
||||||
|
resizeServiceConsole () {
|
||||||
|
const consoleBox = document.getElementById('ternimalContainer' + this.idIndex)
|
||||||
|
const width = document.body.clientWidth// 可视宽度
|
||||||
|
const height = parseInt(consoleBox.offsetHeight)
|
||||||
|
const winStyle = {
|
||||||
|
width: width,
|
||||||
|
height: height - 100,
|
||||||
|
cols: this.term.cols, // cols和rows在resizeConsole方法已经设置
|
||||||
|
rows: this.term.rows
|
||||||
|
}
|
||||||
|
this.$post('terminal/resize', winStyle).then(response => {
|
||||||
|
if (response.code === 200) {
|
||||||
|
this.term.fit()
|
||||||
|
} else {
|
||||||
|
this.$message.error(response.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
focusConsole () {
|
||||||
|
this.term.focus()
|
||||||
|
},
|
||||||
|
beforeCreate () {
|
||||||
|
let rows = this.termimalRows
|
||||||
|
// const consoleBox = document.getElementById('ternimalContainer' + this.idIndex)
|
||||||
|
const height = document.body.clientHeight// 高度
|
||||||
|
// consoleBox.style.height = `${height - 120}px`
|
||||||
|
rows = (height - this.topMenuHeight) / (this.fontSize + this.fontSpaceHeight)
|
||||||
|
rows = parseInt(rows)
|
||||||
|
const terminalContainer = document.getElementById('terminal' + this.idIndex)
|
||||||
|
this.term = new Terminal({
|
||||||
|
rows: rows, // 15行大概300px高,无法设置heigh,只能设置rows
|
||||||
|
cursorStyle: 'block', // 光标样式 null | 'block' | 'underline' | 'bar'
|
||||||
|
disableStdin: false, // 是否应禁用输入
|
||||||
|
fontSize: this.fontSize
|
||||||
|
})
|
||||||
|
this.term.open(terminalContainer)
|
||||||
|
this.term.focus()
|
||||||
|
const params = {
|
||||||
|
width: this.terminal.width,
|
||||||
|
height: this.terminal.height,
|
||||||
|
cols: this.terminal.cols,
|
||||||
|
rows: this.terminal.rows,
|
||||||
|
host: this.$loadsh.get(this.terminal, 'custom.host', ''),
|
||||||
|
port: this.$loadsh.get(this.terminal, 'custom.port', ''),
|
||||||
|
assetId: this.$loadsh.get(this.terminal, 'assetId', ''),
|
||||||
|
accountId: this.$loadsh.get(this.terminal, 'accountId', ''),
|
||||||
|
authProtocol: this.$loadsh.get(this.terminal, 'custom.authProtocol', ''),
|
||||||
|
authProtocolPort: this.$loadsh.get(this.terminal, 'custom.authProtocolPort', ''),
|
||||||
|
authType: this.$loadsh.get(this.terminal, 'custom.authType', ''),
|
||||||
|
authUsername: this.$loadsh.get(this.terminal, 'custom.authUsername', ''),
|
||||||
|
authPin: this.$loadsh.get(this.terminal, 'custom.authPin', ''),
|
||||||
|
authPriKey: this.$loadsh.get(this.terminal, 'custom.authPriKey', ''),
|
||||||
|
authUserTip: this.$loadsh.get(this.terminal, 'custom.authUserTip', ''),
|
||||||
|
authPinTip: this.$loadsh.get(this.terminal, 'custom.authPinTip', '')
|
||||||
|
}
|
||||||
|
this.$post('/terminal/login', params).then(res => {
|
||||||
|
console.log(res)
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.terminal.uuid = res.data.uuid
|
||||||
|
this.$forceUpdate()
|
||||||
|
this.terminal.userName = res.data.authUsername + '@' + res.data.host
|
||||||
|
this.host = res.data.host
|
||||||
|
this.create()
|
||||||
|
} else {
|
||||||
|
this.terminal.uuid = res.data.uuid
|
||||||
|
this.terminal.userName = res.data.authUsername + '@' + res.data.host
|
||||||
|
this.host = res.data.host
|
||||||
|
params.name = this.terminal.name
|
||||||
|
this.$emit('loginFail', params)
|
||||||
|
this.$message.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
create () {
|
||||||
|
const that = this
|
||||||
|
const token = localStorage.getItem('nz-token')
|
||||||
|
let baseUrl = JSON.parse(JSON.stringify(this.$axios.defaults.baseURL))
|
||||||
|
const protocol = window.location.protocol.indexOf('https') > -1 ? 'wss' : 'ws'
|
||||||
|
if (baseUrl.startsWith('/')) {
|
||||||
|
baseUrl = `${protocol}://` + window.location.host + baseUrl
|
||||||
|
} else {
|
||||||
|
baseUrl = baseUrl.replace('http://', 'ws://').replace('https://', 'wss://')
|
||||||
|
}
|
||||||
|
let url = ''
|
||||||
|
this.terminal.height = document.body.clientHeight - 100
|
||||||
|
if (this.terminal.type === 'asset') {
|
||||||
|
url = baseUrl + '/terminal.ws?width=' + this.terminal.width + '&height=' + this.terminal.height + '&cols=' + this.terminal.cols + '&rows=' + this.terminal.rows + '&token=' + token + '&assetId=' + this.terminal.assetId + '&accountId=' + this.terminal.accountId + '&uuid=' + this.terminal.uuid
|
||||||
|
} else if (this.terminal.type === 'custom') {
|
||||||
|
url = baseUrl + '/terminal.ws?width=' + this.terminal.width + '&height=' + this.terminal.height + '&cols=' + this.terminal.cols + '&rows=' + this.terminal.rows + '&token=' + token + '&accountId=' + this.terminal.accountId + '&uuid=' + this.terminal.uuid
|
||||||
|
Object.keys(this.terminal.custom).forEach(key => {
|
||||||
|
if (this.terminal.custom[key]) {
|
||||||
|
url += '&' + key + '=' + this.terminal.custom[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.terminalSocket = new WebSocket(url)
|
||||||
|
// 连接成功onclose
|
||||||
|
this.terminalSocket.onopen = () => {
|
||||||
|
this.terminal.isLogin = true
|
||||||
|
this.isInit = true
|
||||||
|
}
|
||||||
|
// 登录后,你输入的内容从后台服务返回
|
||||||
|
this.term.on('data', function (data) {
|
||||||
|
/*
|
||||||
|
let code = data.charCodeAt(0);
|
||||||
|
if(code==13){
|
||||||
|
}else {
|
||||||
|
//that.term.write(data);
|
||||||
|
} */
|
||||||
|
})
|
||||||
|
// 返回
|
||||||
|
this.terminalSocket.onmessage = function (evt) {
|
||||||
|
let backContent = evt.data
|
||||||
|
const welComIndex = backContent.indexOf(that.welcomeBackContent)
|
||||||
|
if (welComIndex > -1) { // 无服务器信息(只与nezha进行了连接)
|
||||||
|
const connectResult = {
|
||||||
|
title: '',
|
||||||
|
color: 1
|
||||||
|
}
|
||||||
|
that.$emit('refreshConsoleTitle', connectResult)// 1:grey 2 green 3 red
|
||||||
|
} else {
|
||||||
|
const successContentIndex = backContent.indexOf(that.successBackContent)
|
||||||
|
if (successContentIndex > -1) {
|
||||||
|
// that.conFinish = true;
|
||||||
|
const startIndex = successContentIndex + that.successBackContent.length + 1
|
||||||
|
backContent = backContent.substring(startIndex)
|
||||||
|
const endIndex = backContent.indexOf('\r\n')
|
||||||
|
const title = backContent.substring(0, endIndex)
|
||||||
|
const connectResult = {
|
||||||
|
title: title,
|
||||||
|
color: 2
|
||||||
|
}
|
||||||
|
that.$emit('refreshConsoleTitle', connectResult)// 1:grey 2 green 3 red
|
||||||
|
} else { // 失败
|
||||||
|
const failContentIndex = backContent.indexOf(that.failBackContent)
|
||||||
|
const connectFailIndex = backContent.indexOf(that.connectFailContent)
|
||||||
|
if (failContentIndex > -1) {
|
||||||
|
// that.conFinish = true;
|
||||||
|
const connectResult = {
|
||||||
|
title: '',
|
||||||
|
color: 3
|
||||||
|
}
|
||||||
|
that.$emit('refreshConsoleTitle', connectResult)// 1:grey 2 green 3 red
|
||||||
|
} else if (connectFailIndex > -1) {
|
||||||
|
const connectResult = {
|
||||||
|
title: '',
|
||||||
|
color: 3
|
||||||
|
}
|
||||||
|
that.$emit('refreshConsoleTitle', connectResult)// 1:grey 2 green 3 red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 关闭
|
||||||
|
this.terminalSocket.onclose = () => {
|
||||||
|
this.terminal.isLogin = false
|
||||||
|
// 报错sorry的,还没来得及看信息就关闭
|
||||||
|
// this.$emit("closeConsole",this.terminal.name);//
|
||||||
|
this.term && this.term.setOption('disableStdin', true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误
|
||||||
|
this.terminalSocket.onerror = (e) => {
|
||||||
|
this.terminal.isLogin = false
|
||||||
|
console.log(this.terminal.isLogin, 'close')
|
||||||
|
}
|
||||||
|
// 选中 复制
|
||||||
|
this.term.on('selection', function () {})
|
||||||
|
this.term.attachCustomKeyEventHandler(function (ev) { })
|
||||||
|
|
||||||
|
this.term.attach(this.terminalSocket)
|
||||||
|
this.term._initialized = true
|
||||||
|
this.term.fit()// 自适应大小(使终端的尺寸和几何尺寸适合于终端容器的尺寸) 只是width
|
||||||
|
this.$nextTick(() => { // 解决进入全屏和退出全屏是底部隐藏
|
||||||
|
this.setFontSize(this.fontSize)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
closeSocket () {
|
||||||
|
if (this.terminalSocket) {
|
||||||
|
this.terminalSocket.close()
|
||||||
|
}
|
||||||
|
if (this.term) {
|
||||||
|
this.term.destroy()
|
||||||
|
}
|
||||||
|
// 初始化console的高度
|
||||||
|
this.conFinish = false
|
||||||
|
},
|
||||||
|
setFontSize (fontSize) {
|
||||||
|
this.term && this.term.setOption('fontSize', fontSize)
|
||||||
|
const consoleBox = document.getElementById('ternimalContainer' + this.idIndex)
|
||||||
|
const width = document.body.clientWidth// 可视宽度
|
||||||
|
console.log(consoleBox.offsetHeight)
|
||||||
|
let height = parseInt(consoleBox.offsetHeight)
|
||||||
|
if (height == null || !height) { height = this.termimalHeight }
|
||||||
|
const winStyle = {
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
cols: this.term.cols, // cols和rows在resizeConsole方法已经设置
|
||||||
|
rows: this.term.rows
|
||||||
|
}
|
||||||
|
// 调整终端可视区域高度
|
||||||
|
// document.getElementsByClassName('xterm-screen')[this.idIndex].style.height = height - 30 + 'px'
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.term.resize(this.term.cols, this.term.rows)
|
||||||
|
this.$post('terminal/resize', winStyle).then(response => {
|
||||||
|
if (response.code === 200) {
|
||||||
|
this.term.fit()
|
||||||
|
} else {
|
||||||
|
this.$message.error(response.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
reconnect () {
|
||||||
|
this.terminal.isLogin = false
|
||||||
|
this.closeSocket()
|
||||||
|
this.term.off('selection')
|
||||||
|
this.term.off('data')
|
||||||
|
this.beforeCreate()
|
||||||
|
},
|
||||||
|
closeFileDir () {
|
||||||
|
this.showFileDir(false)
|
||||||
|
},
|
||||||
|
showFileDir (show) {
|
||||||
|
if (JSON.stringify(show) == JSON.stringify(this.fileDirectoryShow)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (show) {
|
||||||
|
this.fileDirectoryShow = show
|
||||||
|
}
|
||||||
|
let animationClass = ''
|
||||||
|
animationClass = show ? 'backInRight' : 'backOutRight'
|
||||||
|
this.animateCSS(this.$refs.fileDirectory.$el, animationClass).then((message) => {
|
||||||
|
this.fileDirectoryShow = show
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.beforeCreate()
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
this.closeSocket()
|
||||||
|
this.term.off('selection')
|
||||||
|
this.term.off('data')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,35 +1,99 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="fileDirectory" style="width: 100% !important;">
|
<div class="fileDirectory">
|
||||||
<div class="file-directory-header">
|
<div class="file-directory-header">
|
||||||
<span style="color: #fff">
|
|
||||||
{{$t('terminal.sftp')}}
|
{{$t('terminal.sftp')}}
|
||||||
<span style="color: #B7B7B7;margin-left: 10px">
|
<span class="header-option">
|
||||||
<span @click="getSftpPath('/')" class="breadcrumb-item breadcrumb-action"><i class="nz-icon nz-icon-Computer"/></span>
|
|
||||||
<span v-for="(item,index) in breadcrumb" :key="index" class="breadcrumb-item">
|
|
||||||
/<span class="breadcrumb-action" @click="gotoPath(item,index)">{{item}}</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<span style="color: #fff" class="header-option">
|
|
||||||
<i class="nz-icon nz-icon-a-newfolder" @click="newFolderBoxShow = true"></i>
|
|
||||||
<i class="nz-icon nz-icon-upload" @click="uploadFile"></i>
|
<i class="nz-icon nz-icon-upload" @click="uploadFile"></i>
|
||||||
<i class="nz-icon nz-icon-close" @click="$emit('close')"></i>
|
<i class="nz-icon nz-icon-close" @click="$emit('close')"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="file-directory-content" v-my-loading="fileDirectoryLoading">
|
<div class="file-directory-path" v-clickoutside="hideEditPath">
|
||||||
<div v-if="fileDirectory !== '/'" @click="backFileDirectory" class="file-item"><i class="nz-icon nz-icon-a-upperlevel" style="margin-right: 10px"/>{{$t('terminal.back')}}</div>
|
<span v-show="!editPathShow" class="breadcrumb-box">
|
||||||
<div v-for="(item,index) in fileList" :key="index" class="file-item" @click="selectFile(item)">
|
<span @click="getSftpPath('/')" class="breadcrumb-item breadcrumb-action"><i class="nz-icon nz-icon-home"/></span>
|
||||||
|
<span v-for="(item,index) in breadcrumb" :key="index" class="breadcrumb-item">
|
||||||
|
/<span class="breadcrumb-action" @click="gotoPath(item,index)">{{item}}</span>
|
||||||
|
</span>
|
||||||
|
<i class="nz-icon nz-icon-edit" @click="showEditPath"/>
|
||||||
|
</span>
|
||||||
|
<span v-show="editPathShow">
|
||||||
|
<el-input v-model="editPath" size="small" @keyup.enter.native="goEditPath"/>
|
||||||
|
</span>
|
||||||
|
<div class="path-option">
|
||||||
|
<span style="margin-right: 5px">Show hide File: </span>
|
||||||
|
<el-switch v-model="showHideFile"/>
|
||||||
|
<i class="nz-icon nz-icon-a-newfolder" @click="newFolderBoxShow = true"></i>
|
||||||
|
<i class="nz-icon nz-icon-upload" @click="uploadFile"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div style="padding: 0 20px;height: calc(100% - 50px)" v-my-loading="fileDirectoryLoading">
|
||||||
|
<div class="directory-content-header">
|
||||||
<div class="text-ellipsis file-name">
|
<div class="text-ellipsis file-name">
|
||||||
<i class="nz-icon" :class="selIcon(item)"/>
|
{{$t('overall.name')}}
|
||||||
{{item.name}}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="file-feature" v-if="!item.isDir">
|
<div class="text-ellipsis file-size">
|
||||||
<i class="nz-icon nz-icon-download1" v-if="!item.isDir" @click="downloadFile(item)"></i>
|
{{$t('backup.size')}}
|
||||||
<i class="nz-icon nz-icon-delete" v-if="!item.isDir" @click="delFile(item)"></i>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="file-date">
|
<div class="text-ellipsis file-date">
|
||||||
<span>{{momentTz(item.cts * 1000)}}</span>
|
{{$t('issue.createTime')}}
|
||||||
<span v-if="!item.isDir">{{bytes(item.size, 0, 0)}}</span>
|
</div>
|
||||||
|
<div class="text-ellipsis file-opt">
|
||||||
|
{{$t('overall.option')}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="file-directory-content">
|
||||||
|
<div v-if="fileDirectory !== '/'" @click="backFileDirectory" class="file-item">
|
||||||
|
<div class="text-ellipsis file-name">
|
||||||
|
<i class="nz-icon nz-icon-a-upperlevel" style="margin-right: 10px"/>
|
||||||
|
{{$t('terminal.back')}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-for="(item,index) in fileList" :key="index" class="file-item" @click="selectFile(item)">
|
||||||
|
<div class="text-ellipsis file-name">
|
||||||
|
<i class="nz-icon" :class="selIcon(item)"/>
|
||||||
|
{{item.name}}
|
||||||
|
</div>
|
||||||
|
<div class="text-ellipsis file-size">
|
||||||
|
<span v-if="!item.isDir">{{bytes(item.size, 0, 0)}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-ellipsis file-date">
|
||||||
|
<span>{{momentTz(item.cts * 1000)}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-ellipsis file-opt">
|
||||||
|
<i class="nz-icon nz-icon-shuxing" @click.stop="showFileInfo(item)"/>
|
||||||
|
<el-dropdown size="medium" trigger="click" @command="tableOperation">
|
||||||
|
<div class="table-operation-item table-operation-item--more" @click.stop="" :title="$t('overall.moreOperations')">
|
||||||
|
<i class="nz-icon nz-icon-more3"></i>
|
||||||
|
</div>
|
||||||
|
<el-dropdown-menu slot="dropdown" class="right-box-select-top right-public-box-dropdown-top">
|
||||||
|
<el-dropdown-item
|
||||||
|
:command="['rename', item]">
|
||||||
|
<i class="nz-icon nz-icon-edit"></i>
|
||||||
|
<span class="operation-dropdown-text">
|
||||||
|
{{$t('terminal.rename')}}
|
||||||
|
</span>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
:disabled="item.isDir"
|
||||||
|
:command="['download', item]">
|
||||||
|
<i class="nz-icon nz-icon-download1"></i>
|
||||||
|
<span class="operation-dropdown-text">
|
||||||
|
{{$t('overall.download')}}
|
||||||
|
</span>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
:disabled="item.isDir"
|
||||||
|
:command="['del', item]">
|
||||||
|
<i class="nz-icon nz-icon-delete"></i>
|
||||||
|
<span class="operation-dropdown-text">
|
||||||
|
{{$t('overall.delete')}}
|
||||||
|
</span>
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
<!-- <i class="nz-icon nz-icon-download1" v-if="!item.isDir" @click="downloadFile(item)"></i>-->
|
||||||
|
<!-- <i class="nz-icon nz-icon-delete" v-if="!item.isDir" @click="delFile(item)"></i>-->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -43,7 +107,7 @@
|
|||||||
@close="newFolder(false)"
|
@close="newFolder(false)"
|
||||||
>
|
>
|
||||||
<div style="display: flex; align-items: center">
|
<div style="display: flex; align-items: center">
|
||||||
<div style="width: 100px;flex-shrink: 1">{{$t('overall.folderName')}}</div>
|
<div style="width: 100px;flex-shrink: 1;text-transform: capitalize">{{$t('overall.folderName')}}</div>
|
||||||
<el-input v-model="folder" size="small" style="flex: 1"/>
|
<el-input v-model="folder" size="small" style="flex: 1"/>
|
||||||
</div>
|
</div>
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
@@ -57,6 +121,87 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
class="nz-dialog snapshot-dialog"
|
||||||
|
width="472px"
|
||||||
|
:title='$t("terminal.rename")'
|
||||||
|
destroy-on-close
|
||||||
|
:modal-append-to-body="false"
|
||||||
|
:visible.sync="renameBox"
|
||||||
|
@close="renameBox = false"
|
||||||
|
>
|
||||||
|
<div style="display: flex; align-items: center">
|
||||||
|
<div style="width: 100px;flex-shrink: 1;text-transform: capitalize">{{$t('overall.name')}}</div>
|
||||||
|
<el-input v-model="renameStr" size="small" style="flex: 1"/>
|
||||||
|
</div>
|
||||||
|
<div slot="footer">
|
||||||
|
<div class="el-message-box__btns">
|
||||||
|
<button class="nz-btn el-button el-button--small el-button--default" @click="renameBox = false">
|
||||||
|
<span>{{$t('overall.cancel')}}</span>
|
||||||
|
</button>
|
||||||
|
<button class="nz-btn el-button--small nz-btn-style-normal" @click="setRename">
|
||||||
|
<span style="text-transform:Capitalize">{{$t('overall.save')}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
class="nz-dialog snapshot-dialog"
|
||||||
|
width="472px"
|
||||||
|
:title='$t("overall.delete")'
|
||||||
|
destroy-on-close
|
||||||
|
:modal-append-to-body="false"
|
||||||
|
:visible.sync="delDialog"
|
||||||
|
@close="delDialog = false"
|
||||||
|
>
|
||||||
|
<div style="display: flex; align-items: center" v-if="delObj">
|
||||||
|
{{$t('terminal.delinfo',{fileName: delObj.name})}}
|
||||||
|
</div>
|
||||||
|
<div slot="footer">
|
||||||
|
<div class="el-message-box__btns">
|
||||||
|
<button class="nz-btn el-button el-button--small el-button--default" @click="delDialog = false" >
|
||||||
|
<span>{{$t('tip.no')}}</span>
|
||||||
|
</button>
|
||||||
|
<button class="nz-btn el-button--small nz-btn-style-normal" @click="delFile">
|
||||||
|
<span style="text-transform:Capitalize">{{$t('tip.yes')}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- fileInfo-->
|
||||||
|
<el-dialog
|
||||||
|
class="nz-dialog snapshot-dialog"
|
||||||
|
width="472px"
|
||||||
|
:title='$t("overall.labels")'
|
||||||
|
destroy-on-close
|
||||||
|
:modal-append-to-body="false"
|
||||||
|
:visible.sync="fileInfoShow"
|
||||||
|
@close="fileInfoShow = false"
|
||||||
|
>
|
||||||
|
<div v-if="fileInfo">
|
||||||
|
<div class="file-info-item-header">
|
||||||
|
<i class="nz-icon" :class="selIcon(fileInfo)"/>
|
||||||
|
{{fileInfo.name}}
|
||||||
|
</div>
|
||||||
|
<div v-for="item in fileAttr" :key="item.name" class="file-info-item">
|
||||||
|
<div class="file-info-item-left" :class="{'is-disabled': fileInfo.isDir && item.key =='size'}">
|
||||||
|
{{$t(item.name)}} :
|
||||||
|
</div>
|
||||||
|
<div class="file-info-item-right">
|
||||||
|
{{selInfo(fileInfo, item.key)}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div slot="footer">
|
||||||
|
<div class="el-message-box__btns">
|
||||||
|
<button class="nz-btn el-button--small nz-btn-style-normal" @click="fileInfoShow = false">
|
||||||
|
<span style="text-transform:Capitalize">{{$t('overall.close')}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -66,7 +211,8 @@ export default {
|
|||||||
name: 'fileDirectory',
|
name: 'fileDirectory',
|
||||||
props: {
|
props: {
|
||||||
uuid: {},
|
uuid: {},
|
||||||
fileDirectoryShow: {}
|
fileDirectoryShow: {},
|
||||||
|
host: {}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
@@ -76,7 +222,27 @@ export default {
|
|||||||
newFolderBoxShow: false,
|
newFolderBoxShow: false,
|
||||||
folder: '',
|
folder: '',
|
||||||
fileDirectoryLoading: false,
|
fileDirectoryLoading: false,
|
||||||
timer: ''
|
timer: '',
|
||||||
|
editPathShow: false,
|
||||||
|
editPath: '',
|
||||||
|
showHideFile: false,
|
||||||
|
delObj: '',
|
||||||
|
delDialog: false,
|
||||||
|
renameBox: false,
|
||||||
|
renameStr: '',
|
||||||
|
fileInfo: '',
|
||||||
|
fileInfoShow: false,
|
||||||
|
fileAttr: [
|
||||||
|
{ name: 'overall.type', key: 'isDir' },
|
||||||
|
{ name: 'config.operationlog.ip', key: 'ip' },
|
||||||
|
{ name: 'asset.location', key: 'location' },
|
||||||
|
{ name: 'backup.size', key: 'size' },
|
||||||
|
{ name: 'terminal.modifyTime', key: 'uts' },
|
||||||
|
{ name: 'Owner', key: 'Owner' },
|
||||||
|
{ name: 'dashboard.panel.chartForm.group', key: 'group' },
|
||||||
|
{ name: 'config.menus.perms', key: 'permissionsString' }
|
||||||
|
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -113,12 +279,33 @@ export default {
|
|||||||
init () {
|
init () {
|
||||||
this.getSftpPath(this.fileDirectory)
|
this.getSftpPath(this.fileDirectory)
|
||||||
},
|
},
|
||||||
|
showEditPath () {
|
||||||
|
this.editPath = this.fileDirectory
|
||||||
|
this.editPathShow = true
|
||||||
|
},
|
||||||
|
hideEditPath () {
|
||||||
|
this.editPath = ''
|
||||||
|
this.editPathShow = false
|
||||||
|
},
|
||||||
|
goEditPath () {
|
||||||
|
console.log('123123123')
|
||||||
|
this.getSftpPath(this.editPath)
|
||||||
|
setTimeout(() => {
|
||||||
|
this.editPath = ''
|
||||||
|
this.editPathShow = false
|
||||||
|
})
|
||||||
|
},
|
||||||
selectFile (item) {
|
selectFile (item) {
|
||||||
if (item.isDir) {
|
if (item.isDir) {
|
||||||
const path = this.fileDirectory == '/' ? '' : this.fileDirectory
|
const path = this.fileDirectory == '/' ? '' : this.fileDirectory
|
||||||
this.getSftpPath(path + '/' + item.name)
|
this.getSftpPath(path + '/' + item.name)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
showFileInfo (item) {
|
||||||
|
console.log(item)
|
||||||
|
this.fileInfo = item
|
||||||
|
this.fileInfoShow = true
|
||||||
|
},
|
||||||
newFolder (flag) {
|
newFolder (flag) {
|
||||||
if (!flag) {
|
if (!flag) {
|
||||||
this.newFolderBoxShow = false
|
this.newFolderBoxShow = false
|
||||||
@@ -146,16 +333,23 @@ export default {
|
|||||||
this.getSftpPath(path || '/')
|
this.getSftpPath(path || '/')
|
||||||
},
|
},
|
||||||
getSftpPath (path) {
|
getSftpPath (path) {
|
||||||
this.breadcrumb = path.split('/').filter(item => item)
|
|
||||||
const params = {
|
const params = {
|
||||||
uuid: this.uuid,
|
uuid: this.uuid,
|
||||||
path: path
|
path: path,
|
||||||
|
showHideFile: this.showHideFile
|
||||||
}
|
}
|
||||||
this.fileDirectoryLoading = true
|
this.fileDirectoryLoading = true
|
||||||
this.$post('/terminal/sftp/ls', params).then(res => {
|
this.$post('/terminal/sftp/ls', params).then(res => {
|
||||||
this.fileDirectoryLoading = false
|
if (res.code === 200) {
|
||||||
this.fileDirectory = res.data.path
|
this.fileDirectoryLoading = false
|
||||||
this.fileList = res.data.list
|
this.fileDirectory = res.data.path
|
||||||
|
this.fileList = res.data.list
|
||||||
|
this.editPath = ''
|
||||||
|
this.breadcrumb = res.data.path.split('/').filter(item => item)
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg)
|
||||||
|
this.editPath = ''
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
uploadFile () {
|
uploadFile () {
|
||||||
@@ -166,6 +360,7 @@ export default {
|
|||||||
type: 'upload',
|
type: 'upload',
|
||||||
isStart: false,
|
isStart: false,
|
||||||
isFinish: false,
|
isFinish: false,
|
||||||
|
isError: false,
|
||||||
importFileList: [],
|
importFileList: [],
|
||||||
total: '',
|
total: '',
|
||||||
speed: '',
|
speed: '',
|
||||||
@@ -174,7 +369,8 @@ export default {
|
|||||||
cancel: '',
|
cancel: '',
|
||||||
axios: '',
|
axios: '',
|
||||||
timer: '',
|
timer: '',
|
||||||
done: 0
|
done: 0,
|
||||||
|
delObj: ''
|
||||||
}
|
}
|
||||||
this.$store.dispatch('uploadFile', params)
|
this.$store.dispatch('uploadFile', params)
|
||||||
},
|
},
|
||||||
@@ -192,6 +388,7 @@ export default {
|
|||||||
type: 'download',
|
type: 'download',
|
||||||
isStart: false,
|
isStart: false,
|
||||||
isFinish: false,
|
isFinish: false,
|
||||||
|
isError: false,
|
||||||
total: '',
|
total: '',
|
||||||
speed: '',
|
speed: '',
|
||||||
fileLength: '',
|
fileLength: '',
|
||||||
@@ -202,7 +399,11 @@ export default {
|
|||||||
this.$store.dispatch('dispatchAddFileList', params)
|
this.$store.dispatch('dispatchAddFileList', params)
|
||||||
}, 300)
|
}, 300)
|
||||||
},
|
},
|
||||||
delFile (item) {
|
setRename () {
|
||||||
|
this.renameBox = false
|
||||||
|
},
|
||||||
|
delFile () {
|
||||||
|
const item = this.delObj
|
||||||
const path = this.fileDirectory == '/' ? '' : this.fileDirectory
|
const path = this.fileDirectory == '/' ? '' : this.fileDirectory
|
||||||
const params = {
|
const params = {
|
||||||
uuid: this.uuid,
|
uuid: this.uuid,
|
||||||
@@ -210,8 +411,10 @@ export default {
|
|||||||
}
|
}
|
||||||
this.$post('/terminal/sftp/rm', params).then(res => {
|
this.$post('/terminal/sftp/rm', params).then(res => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
|
this.delDialog = false
|
||||||
this.getSftpPath(this.fileDirectory)
|
this.getSftpPath(this.fileDirectory)
|
||||||
} else {
|
} else {
|
||||||
|
this.delDialog = false
|
||||||
this.getSftpPath(this.fileDirectory)
|
this.getSftpPath(this.fileDirectory)
|
||||||
this.$message.error(res.msg)
|
this.$message.error(res.msg)
|
||||||
}
|
}
|
||||||
@@ -227,6 +430,66 @@ export default {
|
|||||||
return 'nz-icon-File'
|
return 'nz-icon-File'
|
||||||
}
|
}
|
||||||
return 'nz-icon-File'
|
return 'nz-icon-File'
|
||||||
|
},
|
||||||
|
selInfo (item, key) {
|
||||||
|
if (key === 'isDir') {
|
||||||
|
if (item.isDir) {
|
||||||
|
return this.$t('terminal.catalogueFile')
|
||||||
|
} else {
|
||||||
|
return this.$t('backup.File')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key === 'ip') {
|
||||||
|
return this.host
|
||||||
|
}
|
||||||
|
// fileAttr: [
|
||||||
|
// { name: 'overall.type', key: 'isDir' },
|
||||||
|
// { name: 'config.operationlog.ip', key: 'ip' },
|
||||||
|
// { name: 'asset.location', key: 'location' },
|
||||||
|
// { name: 'backup.size', key: 'size' },
|
||||||
|
// { name: 'terminal.modifyTime', key: 'uts' },
|
||||||
|
// { name: 'Owner', key: 'Owner' },
|
||||||
|
// { name: 'dashboard.panel.chartForm.group', key: 'group' },
|
||||||
|
// { name: 'config.menus.perms', key: 'permissionsString' }
|
||||||
|
//
|
||||||
|
// ]
|
||||||
|
if (key === 'location') {
|
||||||
|
return this.fileDirectory
|
||||||
|
}
|
||||||
|
if (key === 'size' && !item.isDir) {
|
||||||
|
return this.bytes(item.size, 0, 0)
|
||||||
|
} else if (key === 'size' && item.isDir) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
if (key === 'uts') {
|
||||||
|
return this.momentTz(item.uts * 1000)
|
||||||
|
}
|
||||||
|
if (key === 'Owner') {
|
||||||
|
return 'Owner'
|
||||||
|
}
|
||||||
|
if (key === 'group') {
|
||||||
|
return 'group'
|
||||||
|
}
|
||||||
|
if (key === 'permissionsString') {
|
||||||
|
return item.permissionsString
|
||||||
|
}
|
||||||
|
return '-'
|
||||||
|
},
|
||||||
|
tableOperation ([command, row, param]) {
|
||||||
|
switch (command) {
|
||||||
|
case 'rename':
|
||||||
|
this.renameStr = row.name
|
||||||
|
this.renameBox = true
|
||||||
|
break
|
||||||
|
case 'download':
|
||||||
|
this.downloadFile(row)
|
||||||
|
break
|
||||||
|
case 'del':
|
||||||
|
this.delObj = row
|
||||||
|
this.delDialog = true
|
||||||
|
// this.delFile(row)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,13 @@
|
|||||||
<div class="item-progress">
|
<div class="item-progress">
|
||||||
<div class="item-progress-top text-ellipsis">{{item.name}}</div>
|
<div class="item-progress-top text-ellipsis">{{item.name}}</div>
|
||||||
<div class="item-progress-middle">
|
<div class="item-progress-middle">
|
||||||
<el-progress :show-text="false" :percentage="item.done" :color="customColorMethod"></el-progress>
|
<el-progress :show-text="false" :percentage="item.done" :color="customColorMethod.bind(item)"></el-progress>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-progress-bottom">
|
<div class="item-progress-bottom">
|
||||||
<span>{{bytes(item.total, 0, 0)}}</span>
|
<span>{{bytes(item.total, 0, 0)}}</span>
|
||||||
<span>{{item.speed}}</span>
|
<span v-if="!item.isFinish && !item.isError">{{item.speed}}</span>
|
||||||
|
<span v-if="item.isFinish">Completed</span>
|
||||||
|
<span v-if="item.isError">Error</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-state">
|
<div class="item-state">
|
||||||
@@ -107,7 +109,8 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
bytes: chartDataFormat.getUnit(7).compute,
|
bytes: chartDataFormat.getUnit(7).compute,
|
||||||
customColorMethod (percentage) {
|
customColorMethod (percentage, item) {
|
||||||
|
console.log(item)
|
||||||
if (percentage < 100) {
|
if (percentage < 100) {
|
||||||
return '#3B92F1'
|
return '#3B92F1'
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
94
nezha-fronted/src/components/cli/terminal.vue
Normal file
94
nezha-fronted/src/components/cli/terminal.vue
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<div class="webTerminal">
|
||||||
|
<div class="web-terminal-header">
|
||||||
|
<div> <img alt="loading..." height="26" :src="logo?logo:require('../../assets/img/logo1-2.png')"/>Web terminal</div>
|
||||||
|
<div>
|
||||||
|
<div class="console-title-icon" style='right: 106px;display: inline;position: absolute' @click="showFileState" v-show="fileList.length">
|
||||||
|
<i class="nz-icon nz-icon-a-filetransfer" :title="$t('terminal.filetransfer')"></i>
|
||||||
|
<span v-show="fileList.length>0" class="right-tip">{{fileList.length<=99?fileList.length:'99+'}}</span>
|
||||||
|
</div>
|
||||||
|
{{name}}</div>
|
||||||
|
</div>
|
||||||
|
<fileListState v-clickoutside="hideFileState" ref="fileListState"/>
|
||||||
|
<webSSHNew ref="websshNew" />
|
||||||
|
<el-input :placeholder="'发送文本到所有SSH终端'" size="small" class="shell-input" v-model="message"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import webSSHNew from '@/components/cli/webSSHNew'
|
||||||
|
import fileListState from './fileListState'
|
||||||
|
export default {
|
||||||
|
name: 'terminal',
|
||||||
|
components: {
|
||||||
|
webSSHNew,
|
||||||
|
fileListState
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
logo: '',
|
||||||
|
fileListStateType: '',
|
||||||
|
message: '',
|
||||||
|
name: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
language () { return this.$store.getters.getLanguage },
|
||||||
|
fileList () {
|
||||||
|
return this.$store.getters.getFileList
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
const self = this
|
||||||
|
window.addEventListener('setItemEvent', function (e) {
|
||||||
|
if (e.key == 'nz-sys-logo' && e.value) {
|
||||||
|
self.logo = e.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.logo = localStorage.getItem('nz-sys-logo')
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
const self = this
|
||||||
|
this.name = localStorage.getItem('nz-username')
|
||||||
|
window.onbeforeunload = () => {
|
||||||
|
const opener = window.opener
|
||||||
|
opener.postMessage(
|
||||||
|
JSON.stringify({
|
||||||
|
close: true
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
window.addEventListener('message', function (e) {
|
||||||
|
console.log(e)
|
||||||
|
if (e.data) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(e.data)
|
||||||
|
self.$get('asset/asset/' + data.id).then(res => {
|
||||||
|
const asset = res.data
|
||||||
|
self.$refs.websshNew.addConsole(asset.id, asset.manageIp, '', '', 'asset')
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showFileState () {
|
||||||
|
let type = 'down'
|
||||||
|
this.fileListStateType = type = 'down'
|
||||||
|
this.$refs.fileListState.fileStateShow(!this.$refs.fileListState.fileStateBox, type)
|
||||||
|
},
|
||||||
|
hideFileState () {
|
||||||
|
this.$refs.fileListState.fileStateShow(false, this.fileListStateType)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -31,12 +31,10 @@
|
|||||||
:popper-class="'popover-webshell'"
|
:popper-class="'popover-webshell'"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
Session ID : {{item.uuid.slice(0,7).toLocaleUpperCase()}}
|
Session ID : {{item.terminal.uuid.slice(0,7).toLocaleUpperCase()}}
|
||||||
</div>
|
</div>
|
||||||
<span slot="reference"> <i class="nz-icon nz-icon-about" /></span>
|
<span slot="reference"> <i class="nz-icon nz-icon-about" /></span>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<div :class="{'active-icon grey':item.circleColor == 1,'active-icon green':item.circleColor == 2,'active-icon red':item.circleColor == 3}"
|
|
||||||
style="margin-top: 0px;"></div>{{item.title}}
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<my-console
|
<my-console
|
||||||
|
|||||||
680
nezha-fronted/src/components/cli/webSSHNew.vue
Normal file
680
nezha-fronted/src/components/cli/webSSHNew.vue
Normal file
@@ -0,0 +1,680 @@
|
|||||||
|
<template>
|
||||||
|
<div class="ani-webSHH-height web-terminal-new" id="web-terminal-new">
|
||||||
|
<el-tabs :before-leave="beforeLeave"
|
||||||
|
@tab-click="handleClick"
|
||||||
|
@tab-remove="removeTab"
|
||||||
|
type="border-card"
|
||||||
|
v-model="editableTabsValue" >
|
||||||
|
<el-tab-pane :key="item.name"
|
||||||
|
:label="item.title"
|
||||||
|
:name="item.name"
|
||||||
|
closable
|
||||||
|
v-for="(item, index) in editableTabs"
|
||||||
|
>
|
||||||
|
<!-- tab显示的内容 1 grey,2 green, 3 red-->
|
||||||
|
<span slot="label" class="el-tabs__item-label">
|
||||||
|
<div class="active-icon" :class="item.terminal.isLogin ? 'green-bg': 'red-bg'"></div>
|
||||||
|
<div class="el-tabs__item-label-name text-ellipsis">
|
||||||
|
{{item.terminal.userName}}
|
||||||
|
</div>
|
||||||
|
<el-popover
|
||||||
|
slot="label"
|
||||||
|
placement="bottom"
|
||||||
|
width="180"
|
||||||
|
trigger="click"
|
||||||
|
:popper-class="'popover-webshell popover-webshell-new'"
|
||||||
|
>
|
||||||
|
<div class="popover-webshell-box">
|
||||||
|
<div class="webshell-box-top">
|
||||||
|
Session ID : {{item.terminal.uuid.slice(0,7).toLocaleUpperCase()}}
|
||||||
|
</div>
|
||||||
|
<div class="webshell-box-middle" v-show="item.terminal.userName">
|
||||||
|
<div @click="duplicate(item, index)" class="webshell-box-item">
|
||||||
|
<i class="nz-icon nz-icon-override"/>
|
||||||
|
{{$t('overall.duplicate')}}
|
||||||
|
</div>
|
||||||
|
<div @click="reconnect(item, index)" v-show="item.terminal.userName" class="webshell-box-item">
|
||||||
|
<i class="nz-icon nz-icon-reconnect"></i>
|
||||||
|
{{$t('terminal.reconnect')}}
|
||||||
|
</div>
|
||||||
|
<div @click="showFileDir(item, index)" class="webshell-box-item" v-if="item.terminal.isLogin && item.terminal.terminalType == '1'">
|
||||||
|
<i class="nz-icon nz-icon-SFTP"></i>
|
||||||
|
{{$t('terminal.sftp')}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="webshell-box-item webshell-box-bottom" @click="closeShell(item,index)">
|
||||||
|
<div >
|
||||||
|
<i class="nz-icon nz-icon-close"/>
|
||||||
|
{{$t('overall.close')}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<span slot="reference" class="icon-reference"> <i class="nz-icon nz-icon-more1" /></span>
|
||||||
|
</el-popover>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<terminal
|
||||||
|
:fontSize="fontSize"
|
||||||
|
:terminalType="item.terminal.terminalType"
|
||||||
|
:idIndex="index"
|
||||||
|
:ref="'console'+index"
|
||||||
|
:terminal="item.terminal"
|
||||||
|
@loginFail="loginFail"
|
||||||
|
@closeConsole="removeTab"
|
||||||
|
@refreshConsoleTitle="refreshTabTitle"
|
||||||
|
></terminal>
|
||||||
|
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane key="add" name="addConsole" class="add-console" style="width: 20px">
|
||||||
|
<el-popover
|
||||||
|
slot="label"
|
||||||
|
placement="bottom-start"
|
||||||
|
width="150"
|
||||||
|
trigger="hover"
|
||||||
|
:popper-class="'popover-webshell'"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div class="popover-webshell-item" @click="assetShowChange"><i class="nz-icon nz-icon-menu-assets" />{{$t('webshell.selAsset')}}</div>
|
||||||
|
<div class="popover-webshell-item" @click="customShow=true"><i class="nz-icon nz-icon-edit" />{{$t('webshell.custom')}}</div>
|
||||||
|
</div>
|
||||||
|
<span slot="reference" style="padding:8px;font-size:20px;font-weight:bold;">+</span>
|
||||||
|
</el-popover>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<!--弹窗-->
|
||||||
|
<el-dialog :modal-append-to-body='false' :show-close="true" :visible.sync="assetShow" @close="closeAssetCustom" class="nz-dialog" width="620px">
|
||||||
|
<div slot="title">{{$t('webshell.connect')}}</div>
|
||||||
|
<div >
|
||||||
|
<el-form label-width="120px" size="small" :model="assetContent" label-position = "top" :rules="rules" ref="assetConnect" v-my-loading="assetLoading" >
|
||||||
|
<el-form-item :label='$t("overall.asset")' prop="assetId" class="flex">
|
||||||
|
<el-dropdown trigger="click" class="header-el-dropdown">
|
||||||
|
<span class="el-dropdown-link">
|
||||||
|
<span>{{selectValue}}</span>
|
||||||
|
<span><i class="el-icon-arrow-down el-icon--right"></i></span>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu style="width: 118px" class="el-dropdown__width right-box-select-top right-public-box-dropdown-top" placement="bottom-end" slot="dropdown">
|
||||||
|
<el-dropdown-item
|
||||||
|
@click.native="selectAssetAuth(item.label, item.value)"
|
||||||
|
v-for="item in searchMetrics"
|
||||||
|
:key="item.value"><i class="nz-icon" :class="item.icon" style="margin-right: 5px"/>{{item.label}}</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
<v-selectpage
|
||||||
|
ref="selectPage"
|
||||||
|
style="flex: 1"
|
||||||
|
data="asset/asset"
|
||||||
|
:params="selectPageParams"
|
||||||
|
:tb-columns="columns"
|
||||||
|
key-field="id"
|
||||||
|
show-field="manageIp"
|
||||||
|
search-field="manageIp"
|
||||||
|
v-model="assetContent.assetId"
|
||||||
|
size="small"
|
||||||
|
:language="language"
|
||||||
|
:placeholder="$t('dashboard.panel.chartForm.selectAsset')"
|
||||||
|
id="box-input-asset-id"
|
||||||
|
:result-format="resultFormat"></v-selectpage>
|
||||||
|
<button :disabled="prevent_opt.save" class="nz-btn nz-btn-size-normal nz-btn-style-normal" type="button" @click.prevent="connect">Connect</button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog :modal-append-to-body='false' :show-close="true" :visible.sync="customShow" @close="closeAssetCustom" class="nz-dialog" width="620px"destroy-on-close >
|
||||||
|
<div slot="title">{{$t('webshell.connect')}}</div>
|
||||||
|
<div >
|
||||||
|
<el-form label-width="120px" size="small" :model="customConnect" label-position = "top" :rules=" customConnect.authProtocol ===2 ? rulesCustom2: rulesCustom" ref="customConnect" v-my-loading="assetLoading" class="custom">
|
||||||
|
<el-form-item :label='$t("webshell.protocol")' prop="authProtocol">
|
||||||
|
<el-select @change="protocolChange" value-key="id" popper-class="config-dropdown w260 right-box-select-top right-public-box-dropdown-top" v-model="customConnect.authProtocol" placeholder="" size="small" id="webshell-box-input-protocol">
|
||||||
|
<el-option v-for="item in authProtocol" :id="'dc-principal-op-'+item.value" :key="item.value" :label="item.name" :value="item.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label='$t("asset.authType")' prop="authType" @change="authTypeChange" >
|
||||||
|
<el-select value-key="id" popper-class="config-dropdown w260 right-box-select-top right-public-box-dropdown-top" v-model="customConnect.authType" :disabled="customConnect.authProtocol === 2" placeholder="" size="small" id="webshell-box-input-protocol">
|
||||||
|
<el-option v-for="item in authType" :id="'dc-principal-op-'+item.value" :key="item.value" :label="item.name" :value="item.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label='$t("asset.host")' prop="host">
|
||||||
|
<el-input v-model="customConnect.host" size="small"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label='$t("asset.port")' prop="port">
|
||||||
|
<el-input v-model="customConnect.port" size="small"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label='$t("profile.username")' prop="authUsername">
|
||||||
|
<el-input v-model="customConnect.authUsername" size="small" autocomplete="new-password"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="customConnect.authType === 2"
|
||||||
|
:label='$t("asset.talon.token")'
|
||||||
|
prop="authPriKey"
|
||||||
|
>
|
||||||
|
<el-input v-model="customConnect.authPriKey" size="small" autocomplete="new-password"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label='$t("login.pin")' prop="authPin"
|
||||||
|
:rules="[
|
||||||
|
{ required: customConnect.authType ===1, message:$t('validate.required'), trigger: 'change'},
|
||||||
|
]">
|
||||||
|
<el-input v-model="customConnect.authPin" size="small" type="password" autocomplete="new-password"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="customConnect.authProtocol === 2"
|
||||||
|
:label='$t("asset.usernamePrompt")'
|
||||||
|
prop="authUserTip">
|
||||||
|
<el-input v-model="customConnect.authUserTip" size="small"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="customConnect.authProtocol === 2"
|
||||||
|
:label='$t("asset.pinPrompt")'
|
||||||
|
prop="authPinTip"
|
||||||
|
>
|
||||||
|
<el-input v-model="customConnect.authPinTip" size="small"/>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="right-box__footer custom-footer">
|
||||||
|
<button id="asset-edit-cancel" @click="customShow=false" class="footer__btn footer__btn--light" type="button">
|
||||||
|
<span>{{$t('overall.cancel')}}</span>
|
||||||
|
</button>
|
||||||
|
<button id="asset-edit-save" :disabled="prevent_opt.save" class="footer__btn" @click.prevent="connect" type="button">
|
||||||
|
<span>{{$t('webshell.connect')}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import terminal from './consoleNew'
|
||||||
|
import { host, port } from '@/components/common/js/validate'
|
||||||
|
export default {
|
||||||
|
name: 'webSSH',
|
||||||
|
components: {
|
||||||
|
terminal
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
language () { return this.$store.getters.getLanguage },
|
||||||
|
fileList () {
|
||||||
|
return this.$store.getters.getFileList
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
tabIndex: 0,
|
||||||
|
editableTabs: [],
|
||||||
|
editableTabsValue: '',
|
||||||
|
fontSize: 16,
|
||||||
|
assetShow: false,
|
||||||
|
selectValue: 'SSH',
|
||||||
|
fileListStateType: 'down',
|
||||||
|
searchMetrics: [
|
||||||
|
{
|
||||||
|
value: 'SSH',
|
||||||
|
label: 'SSH'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Telnet',
|
||||||
|
label: 'Telnet'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
selectPageParams: {
|
||||||
|
authProtocol: 1
|
||||||
|
},
|
||||||
|
authProtocol: [
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
name: 'SSH'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 2,
|
||||||
|
name: 'TELNET'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
authType: [
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
name: 'Password'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 2,
|
||||||
|
name: 'Key'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
consoleShow: false,
|
||||||
|
closeConfirmShow: false,
|
||||||
|
customConnect: {
|
||||||
|
host: '',
|
||||||
|
port: 22,
|
||||||
|
authType: 1,
|
||||||
|
authUsername: '',
|
||||||
|
authPin: '',
|
||||||
|
authPriKey: '',
|
||||||
|
authUserTip: '',
|
||||||
|
authPinTip: '',
|
||||||
|
authProtocolPort: '',
|
||||||
|
authProtocol: 1
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{ title: 'ID', data: 'id' },
|
||||||
|
{
|
||||||
|
title: 'Name',
|
||||||
|
data: function (row) {
|
||||||
|
if (row.name.length > 15) {
|
||||||
|
return row.name.substring(0, 12) + '...'
|
||||||
|
}
|
||||||
|
return row.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ title: 'Manage Ip', data: 'manageIp' },
|
||||||
|
{
|
||||||
|
title: 'Type',
|
||||||
|
data: (row) => {
|
||||||
|
return row.type ? row.type.name : ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Model',
|
||||||
|
data: (row) => {
|
||||||
|
return row.model ? row.model.name : ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Datacenter',
|
||||||
|
data: (row) => {
|
||||||
|
return row.dc ? row.dc.name : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
assetId: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
rulesCustom: {
|
||||||
|
authProtocol: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
],
|
||||||
|
authType: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
],
|
||||||
|
host: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' },
|
||||||
|
{ validator: host, trigger: 'change' }
|
||||||
|
],
|
||||||
|
port: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' },
|
||||||
|
{ validator: port, trigger: 'change' }
|
||||||
|
],
|
||||||
|
authUsername: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
],
|
||||||
|
authPin: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
]
|
||||||
|
// authUserTip: [
|
||||||
|
// { validator: this.authUserTipValid, trigger: 'change' }
|
||||||
|
// ],
|
||||||
|
// authPinTip: [
|
||||||
|
// { validator: this.authPinTipValid, trigger: 'change' }
|
||||||
|
// ],
|
||||||
|
// authPriKey: [
|
||||||
|
// { validator: this.authPriKeyValid, trigger: 'change' }
|
||||||
|
// ]
|
||||||
|
},
|
||||||
|
rulesCustom2: {
|
||||||
|
authProtocol: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
],
|
||||||
|
authType: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
],
|
||||||
|
host: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' },
|
||||||
|
{ validator: host, trigger: 'change' }
|
||||||
|
],
|
||||||
|
port: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' },
|
||||||
|
{ validator: port, trigger: 'change' }
|
||||||
|
],
|
||||||
|
authUsername: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
],
|
||||||
|
authPin: [
|
||||||
|
{ required: false, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
],
|
||||||
|
authUserTip: [
|
||||||
|
{ required: false, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
],
|
||||||
|
authPinTip: [
|
||||||
|
{ required: false, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
],
|
||||||
|
authPriKey: [
|
||||||
|
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
assetData: [],
|
||||||
|
assetLoading: false,
|
||||||
|
assetContent: {
|
||||||
|
assetId: ''
|
||||||
|
},
|
||||||
|
customShow: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
selectAssetAuth (val, label) {
|
||||||
|
this.$refs.selectPage.remove()
|
||||||
|
if (val) {
|
||||||
|
this.selectValue = val
|
||||||
|
if (val === 'SSH') {
|
||||||
|
this.selectPageParams = { authProtocol: 1, pageNumber: 1 }
|
||||||
|
} else {
|
||||||
|
this.selectPageParams = { authProtocol: 2, pageNumber: 1 }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
label = 'SSH'
|
||||||
|
this.selectPageParams = { authProtocol: 1, pageNumber: 1 }
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.selectPage.pageChange()
|
||||||
|
}, 100)
|
||||||
|
},
|
||||||
|
assetShowChange () {
|
||||||
|
this.assetShow = true
|
||||||
|
this.selectValue = 'SSH'
|
||||||
|
this.selectPageParams = { authProtocol: 1, pageNumber: 1 }
|
||||||
|
if (this.$refs.selectPage) {
|
||||||
|
this.$refs.selectPage.remove()
|
||||||
|
this.$refs.selectPage.pageChange()
|
||||||
|
}
|
||||||
|
// this.getAssetData()
|
||||||
|
},
|
||||||
|
/* 活动标签切换时触发 */
|
||||||
|
beforeLeave (currentName, oldName) {
|
||||||
|
// 重点,如果name是add,则什么都不触发
|
||||||
|
if (currentName === 'add') {
|
||||||
|
this.addTab()
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
// 切换tab
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.editableTabs && this.editableTabs.length > 0) {
|
||||||
|
this.editableTabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === currentName) {
|
||||||
|
this.$refs['console' + index][0].focusConsole()
|
||||||
|
this.currentUuid = tab.terminal.uuid
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.currentIndex = currentName
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleClick () {
|
||||||
|
|
||||||
|
},
|
||||||
|
windowChange () { // 窗口大小改变
|
||||||
|
// alert('winChange');
|
||||||
|
if (this.editableTabs && this.editableTabs.length > 0) {
|
||||||
|
this.editableTabs.forEach((tab, index) => {
|
||||||
|
this.$refs['console' + index][0].resize()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeTab (targetName) {
|
||||||
|
const tabs = this.editableTabs
|
||||||
|
let activeName = this.editableTabsValue
|
||||||
|
if (activeName === targetName) {
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === targetName) {
|
||||||
|
const nextTab = tabs[index + 1] || tabs[index - 1]
|
||||||
|
if (nextTab) {
|
||||||
|
activeName = nextTab.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.editableTabsValue = activeName
|
||||||
|
this.editableTabs = tabs.filter(tab => tab.name !== targetName)
|
||||||
|
|
||||||
|
if (this.editableTabs.length <= 0) {
|
||||||
|
// this.closeConsole()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loginFail (params) {
|
||||||
|
this.removeTab(params.name)
|
||||||
|
setTimeout(() => {
|
||||||
|
if (params.assetId) {
|
||||||
|
this.assetShowChange()
|
||||||
|
} else {
|
||||||
|
this.customConnect = {
|
||||||
|
...params,
|
||||||
|
authType: Number(params.authType),
|
||||||
|
authPin: atob(decodeURIComponent(params.authPin))
|
||||||
|
}
|
||||||
|
this.customShow = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
refreshTabTitle (connectResult) {
|
||||||
|
if (this.editableTabs && this.editableTabs.length > 0) {
|
||||||
|
this.editableTabs.forEach((tab, index) => {
|
||||||
|
if (tab.name === this.editableTabsValue) {
|
||||||
|
if (connectResult.title && connectResult.title != '') {
|
||||||
|
tab.title = connectResult.title
|
||||||
|
}
|
||||||
|
tab.circleColor = connectResult.color
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cancleConfirm () {
|
||||||
|
this.closeConfirmShow = false
|
||||||
|
},
|
||||||
|
resultFormat (resp) {
|
||||||
|
if (resp && resp.data) {
|
||||||
|
const assetData = {}
|
||||||
|
assetData.list = resp.data.list
|
||||||
|
assetData.totalRow = resp.data.total
|
||||||
|
return assetData
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getAssetData () {
|
||||||
|
this.assetLoading = true
|
||||||
|
this.$get('asset/asset', { pageSize: -1, typeIds: '1,2' }).then(res => {
|
||||||
|
this.assetLoading = false
|
||||||
|
this.assetData = res.data.list
|
||||||
|
})
|
||||||
|
},
|
||||||
|
connect () {
|
||||||
|
this.prevent_opt.save = true
|
||||||
|
if (this.assetShow) {
|
||||||
|
this.$refs.assetConnect.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
this.$get('asset/asset/' + this.assetContent.assetId).then(res => {
|
||||||
|
const asset = res.data
|
||||||
|
this.addConsole(asset.id, asset.manageIp, '', '', 'asset')
|
||||||
|
this.assetShow = false
|
||||||
|
this.prevent_opt.save = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.prevent_opt.save = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.$refs.customConnect.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
this.addConsole('', this.customConnect.host, '', this.customConnect.port, 'custom')
|
||||||
|
this.customShow = false
|
||||||
|
this.prevent_opt.save = false
|
||||||
|
} else {
|
||||||
|
this.prevent_opt.save = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
protocolChange () {
|
||||||
|
if (this.customConnect.authProtocol === 1) {
|
||||||
|
this.customConnect.authUserTip = ''
|
||||||
|
this.customConnect.authPinTip = ''
|
||||||
|
this.customConnect.port = 22
|
||||||
|
} else {
|
||||||
|
this.customConnect.authPriKey = ''
|
||||||
|
this.customConnect.port = 23
|
||||||
|
this.customConnect.authType = 1
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.customConnect.clearValidate()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
authTypeChange () {
|
||||||
|
if (this.customConnect.authType === 1) {
|
||||||
|
this.customConnect.authPriKey = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
encode (str) {
|
||||||
|
// 对编码的字符串转化base64
|
||||||
|
const base64 = encodeURIComponent(btoa(str))
|
||||||
|
return base64
|
||||||
|
},
|
||||||
|
closeAssetCustom () {
|
||||||
|
this.assetShow = false
|
||||||
|
this.customShow = false
|
||||||
|
this.assetContent.assetId = ''
|
||||||
|
this.customConnect = {
|
||||||
|
host: '',
|
||||||
|
port: 22,
|
||||||
|
authType: 1,
|
||||||
|
authUsername: '',
|
||||||
|
authPin: '',
|
||||||
|
authPriKey: '',
|
||||||
|
authUserTip: '',
|
||||||
|
authPinTip: '',
|
||||||
|
authProtocolPort: '',
|
||||||
|
authProtocol: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addConsole (id, host, accountId, port, type) {
|
||||||
|
if (!id) { id = '' }
|
||||||
|
if (!host) { host = '' }
|
||||||
|
if (!accountId) { accountId = '' }
|
||||||
|
if (!port) { port = '' }
|
||||||
|
const uuid = ''
|
||||||
|
const newTabName = ++this.tabIndex + ''
|
||||||
|
let title = host
|
||||||
|
if (port) {
|
||||||
|
title = title + ':' + port
|
||||||
|
}
|
||||||
|
if (!title) {
|
||||||
|
title = this.$t('webshell.shellTitle')
|
||||||
|
}
|
||||||
|
const width = document.body.clientWidth// 可视宽度
|
||||||
|
const console = {
|
||||||
|
title: title,
|
||||||
|
name: newTabName,
|
||||||
|
circleColor: 1, // 1 grey,2 green, 3 red
|
||||||
|
uuid: uuid,
|
||||||
|
terminal: {
|
||||||
|
name: newTabName,
|
||||||
|
cols: 225,
|
||||||
|
rows: 200,
|
||||||
|
width: width,
|
||||||
|
height: this.consoleHeight,
|
||||||
|
assetId: id,
|
||||||
|
accountId: accountId,
|
||||||
|
uuid: uuid,
|
||||||
|
type: type,
|
||||||
|
username: '',
|
||||||
|
isLogin: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type === 'custom') {
|
||||||
|
console.terminal.custom = {
|
||||||
|
host: this.customConnect.host,
|
||||||
|
port: this.customConnect.port,
|
||||||
|
authType: this.customConnect.authType,
|
||||||
|
terminalType: this.customConnect.authProtocol,
|
||||||
|
authUsername: encodeURIComponent(this.customConnect.authUsername),
|
||||||
|
authPin: this.encode(this.customConnect.authPin),
|
||||||
|
authPriKey: encodeURIComponent(this.customConnect.authPriKey),
|
||||||
|
authUserTip: encodeURIComponent(this.customConnect.authUserTip),
|
||||||
|
authPinTip: encodeURIComponent(this.customConnect.authPinTip),
|
||||||
|
authProtocolPort: encodeURIComponent(this.customConnect.authProtocolPort),
|
||||||
|
authProtocol: encodeURIComponent(this.customConnect.authProtocol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (id) {
|
||||||
|
this.$get('/asset/asset/' + id).then(res => {
|
||||||
|
console.terminal.terminalType = res.data.type.authProtocol
|
||||||
|
console.terminal.username = ''
|
||||||
|
this.editableTabsValue = newTabName
|
||||||
|
this.editableTabs.push(console)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.terminal.username = ''
|
||||||
|
this.editableTabsValue = newTabName
|
||||||
|
this.editableTabs.push(console)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
duplicate (item, index) {
|
||||||
|
console.log(item, index)
|
||||||
|
if (item.terminal.assetId) {
|
||||||
|
const newTabName = ++this.tabIndex + ''
|
||||||
|
this.editableTabsValue = newTabName
|
||||||
|
this.editableTabs.push(console)
|
||||||
|
} else {
|
||||||
|
this.customConnect = {
|
||||||
|
...item.terminal.custom,
|
||||||
|
authType: Number(item.terminal.custom.authType),
|
||||||
|
authPin: atob(decodeURIComponent(item.terminal.custom.authPin))
|
||||||
|
}
|
||||||
|
this.customShow = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
debounce (operate, delay) {
|
||||||
|
let time = null
|
||||||
|
let timer = null
|
||||||
|
let newTime = null
|
||||||
|
function task () {
|
||||||
|
newTime = +new Date()
|
||||||
|
if (newTime - time < delay) {
|
||||||
|
timer = setTimeout(task, delay)
|
||||||
|
} else {
|
||||||
|
operate()
|
||||||
|
timer = null
|
||||||
|
}
|
||||||
|
time = newTime
|
||||||
|
}
|
||||||
|
return function () {
|
||||||
|
// 更新时间戳
|
||||||
|
time = +new Date()
|
||||||
|
if (!timer) {
|
||||||
|
timer = setTimeout(task, delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reconnect (item, index) {
|
||||||
|
console.log(item, index)
|
||||||
|
this.$refs['console' + index][0].reconnect()
|
||||||
|
},
|
||||||
|
showFileDir (item, index) {
|
||||||
|
this.$refs['console' + index][0].showFileDir(true)
|
||||||
|
},
|
||||||
|
closeShell (item, index) {
|
||||||
|
this.removeTab(item.name)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
window.addEventListener('resize', this.debounce(this.windowChange, 1000), false)
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
window.removeEventListener('resize', this.debounce(this.windowChange, 1000), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -142,7 +142,12 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
...mapActions(['logoutSuccess']),
|
...mapActions(['logoutSuccess']),
|
||||||
cli () {
|
cli () {
|
||||||
this.$store.commit('openConsole')
|
// this.$store.commit('openConsole')
|
||||||
|
if (!this.externalTerminal) {
|
||||||
|
this.$store.dispatch('dispatchExternalTerminal')
|
||||||
|
} else {
|
||||||
|
this.$store.dispatch('dispatchOpenExternalTerminalWindow')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// 打开全局搜索
|
// 打开全局搜索
|
||||||
openGlobalSearch () {
|
openGlobalSearch () {
|
||||||
@@ -283,6 +288,9 @@ export default {
|
|||||||
},
|
},
|
||||||
isShrink () {
|
isShrink () {
|
||||||
return this.$store.getters.getIsShrink
|
return this.$store.getters.getIsShrink
|
||||||
|
},
|
||||||
|
externalTerminal () {
|
||||||
|
return this.$store.getters.getExternalTerminal
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="home" :class="mode" v-my-loading.dark="loading">
|
<div class="home" :class="mode" v-my-loading.dark="loading" >
|
||||||
<left-menu @refresh="refresh"></left-menu>
|
<left-menu @refresh="refresh" v-show="showMenu"></left-menu>
|
||||||
<div ref="body" class="body">
|
<div ref="body" class="body">
|
||||||
<Header></Header>
|
<Header v-show="showHeader"></Header>
|
||||||
<container v-if="containerShow" ref="container"></container>
|
<container v-if="containerShow" ref="container"></container>
|
||||||
</div>
|
</div>
|
||||||
<!--web-ssh-->
|
<!--web-ssh-->
|
||||||
@@ -46,6 +46,12 @@ export default {
|
|||||||
},
|
},
|
||||||
loading () {
|
loading () {
|
||||||
return this.$store.getters.getHomeLoading
|
return this.$store.getters.getHomeLoading
|
||||||
|
},
|
||||||
|
showMenu () {
|
||||||
|
return !this.$route.meta.hideMenu
|
||||||
|
},
|
||||||
|
showHeader () {
|
||||||
|
return !this.$route.meta.hideHeader
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -54,6 +60,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
console.log(this.$router, this.$route)
|
||||||
},
|
},
|
||||||
destroyed () {
|
destroyed () {
|
||||||
localStorage.removeItem('moduleProjectId')
|
localStorage.removeItem('moduleProjectId')
|
||||||
|
|||||||
@@ -225,6 +225,11 @@ export default {
|
|||||||
detailViewTopSearch
|
detailViewTopSearch
|
||||||
},
|
},
|
||||||
mixins: [dataListMixin, detailViewMixin, routerPathParams],
|
mixins: [dataListMixin, detailViewMixin, routerPathParams],
|
||||||
|
computed: {
|
||||||
|
externalTerminal () {
|
||||||
|
return this.$store.getters.getExternalTerminal
|
||||||
|
}
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
url: 'asset/asset',
|
url: 'asset/asset',
|
||||||
@@ -467,7 +472,12 @@ export default {
|
|||||||
host: row.manageIp,
|
host: row.manageIp,
|
||||||
port: row.authProtocolPort
|
port: row.authProtocolPort
|
||||||
}
|
}
|
||||||
this.$store.commit('addConsole', consoleParam)
|
if (!this.externalTerminal) {
|
||||||
|
this.$store.dispatch('dispatchExternalTerminal', consoleParam)
|
||||||
|
} else {
|
||||||
|
this.$store.dispatch('dispatchOpenExternalTerminalWindow', consoleParam)
|
||||||
|
}
|
||||||
|
// this.$store.commit('addConsole', consoleParam)
|
||||||
},
|
},
|
||||||
duplicate (row) {
|
duplicate (row) {
|
||||||
this.$get(`${this.url}/${row.id}`).then(response => {
|
this.$get(`${this.url}/${row.id}`).then(response => {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import bus from '../../../../libs/bus'
|
|||||||
import vm from '../../../../entrance/app/main'
|
import vm from '../../../../entrance/app/main'
|
||||||
import exportHtml from '../../../../entrance/exportHtml/exportHtml'
|
import exportHtml from '../../../../entrance/exportHtml/exportHtml'
|
||||||
// const vm = window.dataJson ? exportHtml : app
|
// const vm = window.dataJson ? exportHtml : app
|
||||||
window.onload = function () {
|
window.addEventListener('load', function () {
|
||||||
|
console.log(123213)
|
||||||
if (!window.dataJson) {
|
if (!window.dataJson) {
|
||||||
commonOption.toolbox.feature.dataZoom.title.zoom = vm.$i18n.t('overall.toolBox.zoom')
|
commonOption.toolbox.feature.dataZoom.title.zoom = vm.$i18n.t('overall.toolBox.zoom')
|
||||||
commonOption.toolbox.feature.dataZoom.title.back = vm.$i18n.t('overall.toolBox.back')
|
commonOption.toolbox.feature.dataZoom.title.back = vm.$i18n.t('overall.toolBox.back')
|
||||||
@@ -13,7 +14,7 @@ window.onload = function () {
|
|||||||
commonOption.toolbox.feature.dataZoom.title.back = exportHtml.$i18n.t('overall.toolBox.back')
|
commonOption.toolbox.feature.dataZoom.title.back = exportHtml.$i18n.t('overall.toolBox.back')
|
||||||
commonOption.toolbox.feature.magicType.title.stack = exportHtml.$i18n.t('overall.toolBox.stack')
|
commonOption.toolbox.feature.magicType.title.stack = exportHtml.$i18n.t('overall.toolBox.stack')
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
const bgColorList = ['#b3424a', '#7bbfea', '#f05b72', '#596032', '#bd6758',
|
const bgColorList = ['#b3424a', '#7bbfea', '#f05b72', '#596032', '#bd6758',
|
||||||
'#cd9a5b', '#918597', '#70a19f', '#005344', '#FF00FF',
|
'#cd9a5b', '#918597', '#70a19f', '#005344', '#FF00FF',
|
||||||
'#f7acbc', '#5f5d46', '#66ffff', '#ccFF66', '#f47920',
|
'#f7acbc', '#5f5d46', '#66ffff', '#ccFF66', '#f47920',
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import VueResource from 'vue-resource'
|
|||||||
import bus from '@/libs/bus'
|
import bus from '@/libs/bus'
|
||||||
Vue.use(VueResource)
|
Vue.use(VueResource)
|
||||||
|
|
||||||
const loginWhiteList = ['/setup', '/sys/license/upload', '/sys/license/state', '/sys/appearance', '/i18n'] // 免登陆白名单
|
const loginWhiteList = ['/setup', '/sys/license/upload', '/sys/license/state', '/sys/appearance', '/i18n', '/externalTerminal'] // 免登陆白名单
|
||||||
const permissionWhiteList = ['/profile', '/menu', ...loginWhiteList] // 权限白名单
|
const permissionWhiteList = ['/profile', '/menu', ...loginWhiteList] // 权限白名单
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
if (window.entrance) {
|
if (window.entrance) {
|
||||||
|
|||||||
@@ -221,6 +221,14 @@ export default new Router({
|
|||||||
component: resolve => require(['@/components/page/tool/trace'], resolve)
|
component: resolve => require(['@/components/page/tool/trace'], resolve)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/externalTerminal',
|
||||||
|
component: resolve => require(['@/components/cli/terminal'], resolve),
|
||||||
|
meta: {
|
||||||
|
hideHeader: true,
|
||||||
|
hideMenu: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ const terminalFile = {
|
|||||||
fileList: [],
|
fileList: [],
|
||||||
uploadItem: {},
|
uploadItem: {},
|
||||||
updateUuid: '', // 根据uuid的变化 判断页面是否需要刷新
|
updateUuid: '', // 根据uuid的变化 判断页面是否需要刷新
|
||||||
updateIndex: 1
|
updateIndex: 1,
|
||||||
|
externalTerminal: false,
|
||||||
|
messageFunction: false,
|
||||||
|
externalTerminalWindow: ''
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
setFileList (state, arr) {
|
setFileList (state, arr) {
|
||||||
@@ -18,6 +21,48 @@ const terminalFile = {
|
|||||||
setUploadItem (state, item) {
|
setUploadItem (state, item) {
|
||||||
state.uploadItem = item
|
state.uploadItem = item
|
||||||
},
|
},
|
||||||
|
setExternalTerminal (state, item) { // 第一次 关闭或者打开 termail
|
||||||
|
state.externalTerminal = !state.externalTerminal
|
||||||
|
if (!state.messageFunction) {
|
||||||
|
state.messageFunction = true
|
||||||
|
window.addEventListener('message', function (e) {
|
||||||
|
console.log(e)
|
||||||
|
const data = JSON.parse(e.data) // e.data 里面有自己所传的所有参数 可以根据参数做自己的判断
|
||||||
|
if (data.close) {
|
||||||
|
state.externalTerminal = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (state.externalTerminal) {
|
||||||
|
state.externalTerminalWindow = window.open('/ui/externalTerminal', 'terminal')
|
||||||
|
} else {
|
||||||
|
state.externalTerminalWindow = ''
|
||||||
|
}
|
||||||
|
if (item && state.externalTerminal) {
|
||||||
|
console.log('onloda', state.externalTerminalWindow)
|
||||||
|
state.externalTerminalWindow.addEventListener('load', () => {
|
||||||
|
console.log(123123123123123)
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log('time')
|
||||||
|
state.externalTerminalWindow.postMessage(
|
||||||
|
JSON.stringify(item)
|
||||||
|
)
|
||||||
|
}, 3000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openExternalTerminalWindow (state, item) { // 后续打开 termail
|
||||||
|
if (state.externalTerminalWindow) {
|
||||||
|
window.open('', 'terminal')
|
||||||
|
} else {
|
||||||
|
state.externalTerminalWindow = window.open('/ui/externalTerminal', 'terminal')
|
||||||
|
}
|
||||||
|
if (item) {
|
||||||
|
state.externalTerminalWindow.postMessage(
|
||||||
|
JSON.stringify(item)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
setUpdateUuid (state, uuid) {
|
setUpdateUuid (state, uuid) {
|
||||||
state.updateUuid = uuid
|
state.updateUuid = uuid
|
||||||
state.updateIndex++
|
state.updateIndex++
|
||||||
@@ -38,6 +83,9 @@ const terminalFile = {
|
|||||||
},
|
},
|
||||||
getUpdateIndex (state) {
|
getUpdateIndex (state) {
|
||||||
return state.updateIndex
|
return state.updateIndex
|
||||||
|
},
|
||||||
|
getExternalTerminal (state) {
|
||||||
|
return state.externalTerminal
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@@ -55,6 +103,13 @@ const terminalFile = {
|
|||||||
},
|
},
|
||||||
upDateConsole (store, uuid) {
|
upDateConsole (store, uuid) {
|
||||||
store.commit('setUpdateUuid', uuid)
|
store.commit('setUpdateUuid', uuid)
|
||||||
|
},
|
||||||
|
// 打开外部termail
|
||||||
|
dispatchExternalTerminal (store, item) { // 第一次打开termail
|
||||||
|
store.commit('setExternalTerminal', item)
|
||||||
|
},
|
||||||
|
dispatchOpenExternalTerminalWindow (store, item) { // 后续操作termail
|
||||||
|
store.commit('openExternalTerminalWindow', item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user