NEZ-2359 feat: web terminal 支持文件上传下载界面开发
This commit is contained in:
4072
nezha-fronted/src/assets/css/animate.css
vendored
Normal file
4072
nezha-fronted/src/assets/css/animate.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,77 @@
|
||||
.fileDirectory {
|
||||
height: 80%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
background: #1E1E1E;
|
||||
box-shadow: 5px 0 3px 0 #5E5E5E;
|
||||
width: 100% !important;
|
||||
z-index: 10;
|
||||
.file-directory-header{
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
background: #1E1E1E;
|
||||
box-sizing: border-box;
|
||||
color: #ffffff;
|
||||
i {
|
||||
margin-right: 22px;
|
||||
}
|
||||
}
|
||||
.file-directory-content{
|
||||
height: calc(100% - 26px);
|
||||
width: calc(100% - 15px);
|
||||
overflow: auto;
|
||||
}
|
||||
.file-state-panel-content::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
.file-directory-content::-webkit-scrollbar-thumb {
|
||||
background: rgba(244,244,244,0.16);
|
||||
border-radius: 4px;
|
||||
border:none
|
||||
}
|
||||
.file-directory-content::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(244,244,244,0.16);
|
||||
border-radius: 4px;
|
||||
border:none
|
||||
}
|
||||
.file-item{
|
||||
font-family: Roboto-Regular;
|
||||
font-size: 14px;
|
||||
color: #B7B7B7;
|
||||
line-height: 21px;
|
||||
font-weight: 400;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.file-item{
|
||||
display: flex;
|
||||
padding: 0 10px;
|
||||
.file-name{
|
||||
width: calc(100% - 300px);
|
||||
flex: 1;
|
||||
}
|
||||
.file-feature{
|
||||
width: 100px;
|
||||
flex-shrink: 1;
|
||||
>.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{
|
||||
background: rgba(255,134,0,0.50);
|
||||
font-family: Roboto-Regular;
|
||||
font-size: 14px;
|
||||
color: #FF9230;
|
||||
line-height: 21px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
113
nezha-fronted/src/assets/css/components/cli/fileListState.scss
Normal file
113
nezha-fronted/src/assets/css/components/cli/fileListState.scss
Normal file
@@ -0,0 +1,113 @@
|
||||
.file-state-panel{
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
right:0;
|
||||
top:-100px;
|
||||
max-height: 194px;
|
||||
min-width: 96px;
|
||||
width: 308px;
|
||||
background: #222329;
|
||||
box-shadow: 1px 1px 4px -1px #1E1E1E;
|
||||
border-radius: 2px;
|
||||
.file-state-panel-content::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
.file-state-panel-content::-webkit-scrollbar-thumb {
|
||||
background: rgba(244,244,244,0.16);
|
||||
border-radius: 4px;
|
||||
border:none
|
||||
}
|
||||
.file-state-panel-content::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(244,244,244,0.16);
|
||||
border-radius: 4px;
|
||||
border:none
|
||||
}
|
||||
.file-state-panel-header{
|
||||
height: 48px;
|
||||
background: #222329;
|
||||
box-shadow: 0 1px 0 0 #19191C;
|
||||
padding: 0 20px;
|
||||
line-height: 48px;
|
||||
}
|
||||
.file-state-panel-title{
|
||||
font-size: 14px;
|
||||
color: #E7EAED;
|
||||
letter-spacing: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
.file-state-panel-content {
|
||||
min-height: 50px;
|
||||
max-height: 146px;
|
||||
line-height: 48px;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
.file-state-panel-item{
|
||||
height: 48px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 12px 14px 0px 20px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
.item-icon{
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
background: #19191C;
|
||||
border-radius: 2px;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-items: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-shrink:0;
|
||||
}
|
||||
.item-progress{
|
||||
width: calc(100% - 86px);
|
||||
flex: 1;
|
||||
margin: 0 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.item-progress-top{
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
height: 15px;
|
||||
line-height: 15px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.item-progress-middle{
|
||||
}
|
||||
.item-progress-bottom{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 10px;
|
||||
color: #B7B7B7;
|
||||
line-height: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
.item-state{
|
||||
flex-shrink:0;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
color: #fff;
|
||||
line-height: 28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.file-nodata{
|
||||
text-align: center;
|
||||
color: #b7b7b7;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 15px;
|
||||
.table-no-data__title{
|
||||
text-align: center;
|
||||
color: #b7b7b7;
|
||||
}
|
||||
}
|
||||
.translationOriginUp{
|
||||
transform-origin: 70% 100%
|
||||
}
|
||||
.translationOriginDown{
|
||||
transform-origin: 70% 0%
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
@import './charts/chart.scss';
|
||||
@import './charts/chart-list.scss';
|
||||
@import './cli/webSSH.scss';
|
||||
@import './cli/fileDirectory.scss';
|
||||
@import './cli/fileListState.scss';
|
||||
@import './common/alert/alertLabel.scss';
|
||||
@import './common/alert/alertStateInfo.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,20 @@
|
||||
"css_prefix_text": "nz-icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "32964483",
|
||||
"name": "File",
|
||||
"font_class": "File",
|
||||
"unicode": "e7ae",
|
||||
"unicode_decimal": 59310
|
||||
},
|
||||
{
|
||||
"icon_id": "32961611",
|
||||
"name": "Clear",
|
||||
"font_class": "Clear",
|
||||
"unicode": "e7b0",
|
||||
"unicode_decimal": 59312
|
||||
},
|
||||
{
|
||||
"icon_id": "32660007",
|
||||
"name": "Folder ",
|
||||
@@ -12,13 +26,6 @@
|
||||
"unicode": "e7ad",
|
||||
"unicode_decimal": 59309
|
||||
},
|
||||
{
|
||||
"icon_id": "32660008",
|
||||
"name": "File",
|
||||
"font_class": "File",
|
||||
"unicode": "e7ae",
|
||||
"unicode_decimal": 59310
|
||||
},
|
||||
{
|
||||
"icon_id": "32659266",
|
||||
"name": "file transfer",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -11,7 +11,7 @@
|
||||
}
|
||||
/*---滚动条大小--*/
|
||||
::-webkit-scrollbar {
|
||||
width: 14px;
|
||||
width: 6px;
|
||||
height: 14px;
|
||||
}
|
||||
/*---滚动框背景样式--*/
|
||||
@@ -1617,4 +1617,4 @@ li {
|
||||
}
|
||||
.hover .user-username{
|
||||
color: $--color-primary;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
<div class="active-icon green-bg"></div>
|
||||
{{userName}}
|
||||
</span>
|
||||
<span style="color: #fff">
|
||||
<i class="nz-icon nz-icon-reconnect" style="margin-right: 22px"></i>
|
||||
<i class="nz-icon nz-icon-SFTP" style="margin-right: 22px" @click="fileDirectoryShow = !fileDirectoryShow"></i>
|
||||
<span style="color: #fff" v-show="isLogin">
|
||||
<i class="nz-icon nz-icon-reconnect" style="margin-right: 22px" @click="reconnect"></i>
|
||||
<i class="nz-icon nz-icon-SFTP" v-if="userName && terminalType == '1'" style="margin-right: 22px" @click="showFileDir(true)"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div :id="'terminal'+idIndex" ></div>
|
||||
<fileDirectory :uuid="terminal.uuid" v-if="fileDirectoryShow" @close="fileDirectoryShow=false" style=""/>
|
||||
<fileDirectory :uuid="terminal.uuid" v-show="fileDirectoryShow" @close="showFileDir(false)" :fileDirectoryShow="fileDirectoryShow" ref="fileDirectory"/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -28,10 +28,11 @@ import fileDirectory from './fileDirectory'
|
||||
export default {
|
||||
name: 'console',
|
||||
components: {
|
||||
fileDirectory,
|
||||
fileDirectory
|
||||
},
|
||||
props: {
|
||||
terminal: { },
|
||||
terminalType: { default: '1' },
|
||||
idIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
@@ -55,6 +56,7 @@ export default {
|
||||
obj: {
|
||||
id: 2
|
||||
},
|
||||
isLogin: false,
|
||||
successBackContent: 'Connecting to',
|
||||
failBackContent: 'Sorry',
|
||||
connectFailContent: 'Connection failed',
|
||||
@@ -63,7 +65,7 @@ export default {
|
||||
conFinish: false,
|
||||
conSuccessNum: 0,
|
||||
inputSecret: false,
|
||||
userName: 'root@192.168.44.36',
|
||||
userName: '',
|
||||
fileDirectoryShow: false
|
||||
}
|
||||
},
|
||||
@@ -192,10 +194,18 @@ export default {
|
||||
authPinTip: this.$loadsh.get(this.terminal, 'custom.authPinTip', '')
|
||||
}
|
||||
this.$post('/terminal/login', params).then(res => {
|
||||
this.terminal.uuid = res.data.uuid
|
||||
this.userName = res.data.authUsername + '@' + res.data.host
|
||||
this.host = res.data.host
|
||||
this.create()
|
||||
this.isLogin = true
|
||||
if (res.code == 200) {
|
||||
this.terminal.uuid = res.data.uuid
|
||||
this.userName = res.data.authUsername + '@' + res.data.host
|
||||
this.host = res.data.host
|
||||
this.create()
|
||||
} else {
|
||||
this.terminal.uuid = res.data.uuid
|
||||
this.userName = res.data.authUsername + '@' + res.data.host
|
||||
this.host = res.data.host
|
||||
this.$message.error(res.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
create () {
|
||||
@@ -335,6 +345,26 @@ export default {
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
reconnect () {
|
||||
this.isLogin = false
|
||||
this.closeSocket()
|
||||
this.term.off('selection')
|
||||
this.term.off('data')
|
||||
this.beforeCreate()
|
||||
},
|
||||
showFileDir (show) {
|
||||
if (JSON.stringify(show) == JSON.stringify(this.fileDirectoryShow)) {
|
||||
return
|
||||
}
|
||||
if (show) {
|
||||
this.fileDirectoryShow = show
|
||||
}
|
||||
let animationClass = ''
|
||||
animationClass = show ? 'backInUp' : 'backOutDown'
|
||||
this.animateCSS(this.$refs.fileDirectory.$el, animationClass).then((message) => {
|
||||
this.fileDirectoryShow = show
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="fileDirectory">
|
||||
<div class="fileDirectory" style="width: 100% !important;transform: scale(1) !important;">
|
||||
<div class="file-directory-header">
|
||||
<span style="color: #fff">SFTP <span style="color: #B7B7B7">{{fileDirectory}}</span></span>
|
||||
<span style="color: #fff">
|
||||
@@ -8,17 +8,21 @@
|
||||
<i class="nz-icon nz-icon-close" @click="$emit('close')"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="file-directory-content">
|
||||
<div class="file-directory-content" v-my-loading="fileDirectoryLoading">
|
||||
<div v-if="fileDirectory !== '/'" @click="backFileDirectory" class="file-item"><i class="nz-icon nz-icon-a-upperlevel"/>上一级</div>
|
||||
<div v-for="(item,index) in fileList" :key="index" class="file-item" @click="selectFile(item)">
|
||||
<span>
|
||||
<div class="text-ellipsis file-name">
|
||||
<i class="nz-icon" :class="selIcon(item)"/>
|
||||
{{item.name}}
|
||||
</span>
|
||||
<span>
|
||||
</div>
|
||||
<div class="file-feature" v-if="!item.isDir">
|
||||
<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>
|
||||
</span>
|
||||
</div>
|
||||
<div class="file-date">
|
||||
<span>{{momentTz(item.cts * 1000)}}</span>
|
||||
<span v-if="!item.isDir">{{bytes(item.size, 0, 0)}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog
|
||||
@@ -40,23 +44,34 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import chartDataFormat from '@/components/chart/chartDataFormat'
|
||||
export default {
|
||||
name: 'fileDirectory',
|
||||
props: {
|
||||
uuid: {}
|
||||
uuid: {},
|
||||
fileDirectoryShow: {}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
fileDirectory: '/',
|
||||
fileList: [],
|
||||
newFolderBoxShow: false,
|
||||
folder: ''
|
||||
folder: '',
|
||||
fileDirectoryLoading: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.init()
|
||||
// this.init()
|
||||
},
|
||||
watch: {
|
||||
fileDirectoryShow (n) {
|
||||
if (n) {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
bytes: chartDataFormat.getUnit(7).compute,
|
||||
init () {
|
||||
this.getSftpPath(this.fileDirectory)
|
||||
},
|
||||
@@ -78,7 +93,6 @@ export default {
|
||||
path: path + '/' + this.folder
|
||||
}
|
||||
this.$post('/terminal/sftp/mkdir', params).then(res => {
|
||||
console.log(res)
|
||||
this.newFolderBoxShow = false
|
||||
this.getSftpPath(this.fileDirectory)
|
||||
})
|
||||
@@ -86,9 +100,7 @@ export default {
|
||||
backFileDirectory () {
|
||||
const arr = this.fileDirectory.split('/')
|
||||
arr.pop()
|
||||
console.log(arr, this.fileDirectory.split('/').pop())
|
||||
const path = arr.join('/')
|
||||
console.log(path)
|
||||
this.getSftpPath(path || '/')
|
||||
},
|
||||
getSftpPath (path) {
|
||||
@@ -96,10 +108,11 @@ export default {
|
||||
uuid: this.uuid,
|
||||
path: path
|
||||
}
|
||||
this.fileDirectoryLoading = true
|
||||
this.$post('/terminal/sftp/ls', params).then(res => {
|
||||
this.fileDirectoryLoading = false
|
||||
this.fileDirectory = res.data.path
|
||||
this.fileList = res.data.list
|
||||
console.log(res)
|
||||
})
|
||||
},
|
||||
uploadFile () {
|
||||
@@ -116,28 +129,35 @@ export default {
|
||||
fileLength: '',
|
||||
startTime: '',
|
||||
cancel: '',
|
||||
axios: ''
|
||||
axios: '',
|
||||
timer: '',
|
||||
done: 0
|
||||
}
|
||||
this.$store.dispatch('uploadFile', params)
|
||||
},
|
||||
downloadFile (item) {
|
||||
const path = this.fileDirectory == '/' ? '' : this.fileDirectory
|
||||
const params = {
|
||||
...item,
|
||||
uuid: this.uuid,
|
||||
path: path + '/' + item.name,
|
||||
myId: 'download' + this.uuid + new Date().getTime(),
|
||||
type: 'download',
|
||||
isStart: false,
|
||||
isFinish: false,
|
||||
total: '',
|
||||
speed: '',
|
||||
fileLength: '',
|
||||
startTime: '',
|
||||
cancel: '',
|
||||
axios: ''
|
||||
if (item.timer) {
|
||||
clearTimeout(item.timer)
|
||||
}
|
||||
this.$store.dispatch('dispatchAddFileList', params)
|
||||
item.timer = setTimeout(() => {
|
||||
const path = this.fileDirectory == '/' ? '' : this.fileDirectory
|
||||
const params = {
|
||||
...item,
|
||||
uuid: this.uuid,
|
||||
path: path + '/' + item.name,
|
||||
myId: 'download' + this.uuid + new Date().getTime(),
|
||||
type: 'download',
|
||||
isStart: false,
|
||||
isFinish: false,
|
||||
total: '',
|
||||
speed: '',
|
||||
fileLength: '',
|
||||
startTime: '',
|
||||
cancel: '',
|
||||
axios: ''
|
||||
}
|
||||
this.$store.dispatch('dispatchAddFileList', params)
|
||||
}, 300)
|
||||
},
|
||||
delFile (item) {
|
||||
const params = {
|
||||
@@ -168,53 +188,5 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.fileDirectory {
|
||||
height: 80%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
background: #1E1E1E;
|
||||
box-shadow: 5px 0 3px 0 #5E5E5E;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
/deep/ .el-menu::-webkit-scrollbar-thumb {
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
}
|
||||
/deep/ .el-menu::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.file-directory-header{
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
background: #1E1E1E;
|
||||
box-sizing: border-box;
|
||||
color: #ffffff;
|
||||
i {
|
||||
margin-right: 22px;
|
||||
}
|
||||
}
|
||||
.file-directory-content{
|
||||
height: calc(100% - 26px);
|
||||
overflow: auto;
|
||||
}
|
||||
.file-item{
|
||||
font-family: Roboto-Regular;
|
||||
font-size: 14px;
|
||||
color: #B7B7B7;
|
||||
line-height: 21px;
|
||||
font-weight: 400;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.file-item:hover{
|
||||
background: rgba(255,134,0,0.50);
|
||||
font-family: Roboto-Regular;
|
||||
font-size: 14px;
|
||||
color: #FF9230;
|
||||
line-height: 21px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 显示进度-->
|
||||
<div class="file-state-panel" v-show="fileStateBox" :style="{'top': position.top + 'px', right: '10px'}">
|
||||
<div class="file-state-panel" v-show="fileStateBox && fileList.length" :style="{'top': position.top + 'px', right: '10px'}" ref="fileStatePanel" :class="position.top>0? 'translationOriginDown': 'translationOriginUp'">
|
||||
<div class="file-state-panel-header">
|
||||
<span class="file-state-panel-title">File transfers</span>
|
||||
<i class="nz-icon nz-icon-delete"></i>
|
||||
<i class="nz-icon nz-icon-Clear" @click="clearFileList"></i>
|
||||
</div>
|
||||
<div class="file-state-panel-content" v-if="fileList.length">
|
||||
<div v-for="item in fileList" :key="item.myId" class="file-state-panel-item">
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="item-progress">
|
||||
<div class="item-progress-top text-ellipsis">{{item.name}}</div>
|
||||
<div class="item-progress-middle">
|
||||
<el-progress :show-text="false" :percentage="(item.fileLength/item.total) * 100" :color="customColorMethod"></el-progress>
|
||||
<el-progress :show-text="false" :percentage="item.done" :color="customColorMethod"></el-progress>
|
||||
</div>
|
||||
<div class="item-progress-bottom">
|
||||
<span>{{bytes(item.total, 0, 0)}}</span>
|
||||
@@ -66,7 +66,7 @@ export default {
|
||||
myFileList: [],
|
||||
importFileList: [],
|
||||
position: {
|
||||
top: 10,
|
||||
top: 50,
|
||||
right: 0
|
||||
},
|
||||
fileStateBox: false
|
||||
@@ -77,7 +77,6 @@ export default {
|
||||
immediate: true,
|
||||
handler (n) {
|
||||
n.forEach(item => {
|
||||
console.log(item.isStart)
|
||||
if (!item.isStart) {
|
||||
item.total = 1
|
||||
item.fileLength = 0
|
||||
@@ -98,7 +97,6 @@ export default {
|
||||
uploadItem: {
|
||||
handler (n) {
|
||||
if (n && n.myId) {
|
||||
console.log(this.$refs.upload)
|
||||
this.$refs.upload.$children[0].$refs.input.click()
|
||||
}
|
||||
}
|
||||
@@ -132,7 +130,7 @@ export default {
|
||||
item.total = progressEvent.total
|
||||
item.fileLength = progressEvent.loaded
|
||||
item.speed = item.fileLength / ((new Date().getTime() - item.startTime) / 1000)
|
||||
item.speed = self.bytes(item.speed, 0 , 0) + '/s'
|
||||
item.speed = self.bytes(item.speed, 0, 0) + '/s'
|
||||
// this.$set(this.fileList, 0,item)
|
||||
}
|
||||
}).then(res => {
|
||||
@@ -177,6 +175,15 @@ export default {
|
||||
removeRecord (item) {
|
||||
if (!item.isFinish) {
|
||||
item.cancel.cancel('operation canceled by the user.')
|
||||
if (item.done || (item.fileLength === item.total)) { // 取消 上传 50-100
|
||||
clearInterval(item.timer)
|
||||
this.$delete('/terminal/sftp/cancel/' + item.tid).then(res => {
|
||||
if (res.code === 200) {
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
this.$store.dispatch('dispatchDelFileList', item)
|
||||
},
|
||||
@@ -202,140 +209,67 @@ export default {
|
||||
item.fileLength = progressEvent.loaded
|
||||
item.speed = item.fileLength / ((new Date().getTime() - item.startTime) / 1000)
|
||||
item.speed = self.bytes(item.speed, 0, 0) + '/s'
|
||||
item.done = (item.fileLength / (item.total * 2)) * 100
|
||||
}
|
||||
|
||||
}).then(response => {
|
||||
console.log(response)
|
||||
item.isFinish = true
|
||||
if (response.code == 200) {
|
||||
this.$message.success(response.msg)
|
||||
// todo 上传成功后 刷新对应terminal
|
||||
const res = response.data
|
||||
// item.isFinish = true
|
||||
if (res.code == 200) {
|
||||
self.nextUpload(item, res.data.tid)
|
||||
} else {
|
||||
this.$message.error(response.msg)
|
||||
this.$message.error(res.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
nextUpload (item, tid){
|
||||
// this.$message.success(response.msg)
|
||||
item.timer = setInterval(() => { // 上传 50-100
|
||||
item.tid = tid
|
||||
this.$get('/terminal/sftp/process/' + tid).then((res) => {
|
||||
item.done = 50 + parseInt(res.data.done) / 2
|
||||
item.speed = (item.fileLength + (item.done * 0.01 * item.total)) / ((new Date().getTime() - item.startTime) / 1000)
|
||||
item.speed = this.bytes(item.speed, 0, 0) + '/s'
|
||||
if (item.done === 100) {
|
||||
item.isFinish = true
|
||||
clearInterval(item.timer)
|
||||
// todo 上传成功后 刷新对应terminal
|
||||
}
|
||||
})
|
||||
}, 200)
|
||||
},
|
||||
fileStateShow (flag, type) {
|
||||
this.fileStateBox = flag
|
||||
if (flag) {
|
||||
// if (type === 'top') {
|
||||
// this.position = {
|
||||
// top: '',
|
||||
// right: ''
|
||||
// }
|
||||
// } else {
|
||||
// this.position = {
|
||||
// top: '',
|
||||
// right: ''
|
||||
// }
|
||||
// }
|
||||
if (JSON.stringify(flag) == JSON.stringify(this.fileStateBox)) {
|
||||
return
|
||||
}
|
||||
if (flag) {
|
||||
this.fileStateBox = flag
|
||||
if (type === 'down') {
|
||||
this.position = {
|
||||
top: 45,
|
||||
right: 0
|
||||
}
|
||||
} else {
|
||||
this.position = {
|
||||
top: -195,
|
||||
right: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
let animationClass = ''
|
||||
animationClass = flag ? 'zoomIn' : 'zoomOut'
|
||||
this.animateCSS(this.$refs.fileStatePanel, animationClass).then((message) => {
|
||||
this.fileStateBox = flag
|
||||
})
|
||||
},
|
||||
clearFileList () {
|
||||
const arr = this.fileList.filter(item => !item.isFinish)
|
||||
this.$store.dispatch('dispatchFileList', arr)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.file-state-panel{
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
right:0;
|
||||
top:-100px;
|
||||
max-height: 194px;
|
||||
min-width: 96px;
|
||||
width: 308px;
|
||||
background: #222329;
|
||||
box-shadow: 1px 1px 4px -1px #1E1E1E;
|
||||
border-radius: 2px;
|
||||
/deep/ .file-state-panel-content::-webkit-scrollbar-thumb {
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
}
|
||||
/deep/ .file-state-panel-content::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.file-state-panel-header{
|
||||
height: 48px;
|
||||
background: #222329;
|
||||
box-shadow: 0 1px 0 0 #19191C;
|
||||
padding: 0 20px;
|
||||
line-height: 48px;
|
||||
}
|
||||
.file-state-panel-title{
|
||||
font-size: 14px;
|
||||
color: #E7EAED;
|
||||
letter-spacing: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
.file-state-panel-content {
|
||||
min-height: 50px;
|
||||
max-height: 146px;
|
||||
line-height: 48px;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
.file-state-panel-item{
|
||||
height: 48px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 12px 14px 0px 20px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
.item-icon{
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
background: #19191C;
|
||||
border-radius: 2px;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-items: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-shrink:0;
|
||||
}
|
||||
.item-progress{
|
||||
width: calc(100% - 86px);
|
||||
flex: 1;
|
||||
margin: 0 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.item-progress-top{
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
height: 15px;
|
||||
line-height: 15px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.item-progress-middle{
|
||||
}
|
||||
.item-progress-bottom{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 10px;
|
||||
color: #B7B7B7;
|
||||
line-height: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
.item-state{
|
||||
flex-shrink:0;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
color: #fff;
|
||||
line-height: 28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.file-nodata{
|
||||
text-align: center;
|
||||
color: #b7b7b7;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 15px;
|
||||
.table-no-data__title{
|
||||
text-align: center;
|
||||
color: #b7b7b7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -39,7 +39,16 @@
|
||||
style="margin-top: 0px;"></div>{{item.title}}
|
||||
</span>
|
||||
|
||||
<my-console :fontSize="fontSize" :idIndex="index" :isFullScreen="isFullScreen" :ref="'console'+index" :terminal="item.terminal" @closeConsole="removeTab" @refreshConsoleTitle="refreshTabTitle"></my-console>
|
||||
<my-console
|
||||
:fontSize="fontSize"
|
||||
:terminalType="item.terminal.terminalType"
|
||||
:idIndex="index"
|
||||
:isFullScreen="isFullScreen"
|
||||
:ref="'console'+index"
|
||||
:terminal="item.terminal"
|
||||
@closeConsole="removeTab"
|
||||
@refreshConsoleTitle="refreshTabTitle"
|
||||
></my-console>
|
||||
|
||||
</el-tab-pane>
|
||||
<el-tab-pane key="add" name="addConsole" style="width: 20px">
|
||||
@@ -59,7 +68,7 @@
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="console-icon">
|
||||
<div class="console-title-icon" style='right: 106px;display: inline;' @click="showFileState">
|
||||
<div class="console-title-icon" style='right: 106px;display: inline;' @click="showFileState" v-show="fileList.length">
|
||||
<i class="nz-icon nz-icon-a-filetransfer" :title="$t('guide.webTerminal')"></i>
|
||||
<span v-show="fileList.length>0" class="right-tip">{{fileList.length<=99?fileList.length:'99+'}}</span>
|
||||
</div>
|
||||
@@ -273,12 +282,13 @@ export default {
|
||||
language () { return this.$store.getters.getLanguage },
|
||||
fileList () {
|
||||
return this.$store.getters.getFileList
|
||||
},
|
||||
}
|
||||
},
|
||||
data () {
|
||||
const termFontSize = parseInt(localStorage.getItem('termFontSize'))
|
||||
return {
|
||||
selectValue: 'SSH',
|
||||
fileListStateType: 'down',
|
||||
searchMetrics: [
|
||||
{
|
||||
value: 'SSH',
|
||||
@@ -519,6 +529,7 @@ export default {
|
||||
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),
|
||||
@@ -528,9 +539,16 @@ export default {
|
||||
authProtocol: encodeURIComponent(this.customConnect.authProtocol)
|
||||
}
|
||||
}
|
||||
if (id) {
|
||||
this.$get('/asset/asset/' + id).then(res => {
|
||||
console.terminal.terminalType = res.data.type.authProtocol
|
||||
this.editableTabsValue = newTabName
|
||||
this.editableTabs.push(console)
|
||||
})
|
||||
return
|
||||
}
|
||||
this.editableTabsValue = newTabName
|
||||
this.editableTabs.push(console)
|
||||
|
||||
setTimeout(function () {
|
||||
const tabScroll = document.getElementsByClassName('el-tabs__nav is-top')
|
||||
const tabViewWidth = document.getElementsByClassName('el-tabs__nav-scroll')
|
||||
@@ -980,12 +998,23 @@ export default {
|
||||
}
|
||||
},
|
||||
showFileState () {
|
||||
let type = 'top'
|
||||
console.log( this.$refs.fileListState)
|
||||
this.$refs.fileListState.fileStateShow(true, type)
|
||||
let type = 'down'
|
||||
const targetDiv = document.getElementById('shell-service')
|
||||
let height = targetDiv.style.height
|
||||
if (height) {
|
||||
height = height.slice(0, -2)
|
||||
if (height < 265) {
|
||||
this.fileListStateType = type = 'up'
|
||||
} else {
|
||||
this.fileListStateType = type = 'down'
|
||||
}
|
||||
} else {
|
||||
this.fileListStateType = type = 'down'
|
||||
}
|
||||
this.$refs.fileListState.fileStateShow(!this.$refs.fileListState.fileStateBox, type)
|
||||
},
|
||||
hideFileState () {
|
||||
this.$refs.fileListState.fileStateShow(false)
|
||||
this.$refs.fileListState.fileStateShow(false, this.fileListStateType)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
@@ -151,7 +151,6 @@ export default {
|
||||
}
|
||||
},
|
||||
clearInput () {
|
||||
console.log(666)
|
||||
this.$refs.elementQuery.focus()
|
||||
},
|
||||
changeTime (size, unit) {
|
||||
|
||||
@@ -126,7 +126,6 @@ export default {
|
||||
}
|
||||
},
|
||||
clearInput () {
|
||||
console.log(666)
|
||||
this.$refs.elementQuery.focus()
|
||||
},
|
||||
changeTime (size, unit) {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
:targetTab="targetTab"
|
||||
@changeTab="changeTab"
|
||||
:title="'Session ID'"
|
||||
id="terminalLogCMDTab"
|
||||
>
|
||||
<template v-slot:title><span :title="obj.uuid.substring(0, 8).toUpperCase()">{{obj.uuid.substring(0, 8).toUpperCase()}}</span></template>
|
||||
<template v-slot>
|
||||
@@ -52,7 +51,6 @@ export default {
|
||||
calcTime () {
|
||||
return function (time) {
|
||||
if (this.obj.startTime) {
|
||||
console.log(this.utcTimeToTimezoneStr(this.obj.startTime))
|
||||
const startTime = this.momentStrToTimestamp(this.utcTimeToTimezoneStr(this.obj.startTime))
|
||||
if (startTime) {
|
||||
const thisTime = startTime + time
|
||||
|
||||
@@ -95,6 +95,22 @@ export default {
|
||||
this.$copyText(txt).then(() => {
|
||||
this.$message.success({ message: this.$t('overall.copySuccess') })
|
||||
})
|
||||
},
|
||||
animateCSS (node, animation, prefix = 'animate__') {
|
||||
// We create a Promise and return it
|
||||
return new Promise((resolve, reject) => {
|
||||
const animationName = `${prefix}${animation}`
|
||||
node.classList.add(`${prefix}animated`, animationName)
|
||||
|
||||
// When the animation ends, we clean the classes and resolve the Promise
|
||||
function handleAnimationEnd (event) {
|
||||
event.stopPropagation()
|
||||
node.classList.remove(`${prefix}animated`, animationName)
|
||||
resolve('Animation ended')
|
||||
}
|
||||
|
||||
node.addEventListener('animationend', handleAnimationEnd, { once: true })
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,9 +198,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
dateChange (val) {
|
||||
console.log(val)
|
||||
const startTime = this.momentTz(this.momentStrToTimestamp(val))
|
||||
console.log(this.stepSearchTime[1], this.stepSearchTime[0])
|
||||
const end = this.momentStrToTimestamp(val) + this.momentStrToTimestamp(this.stepSearchTime[1]) - this.momentStrToTimestamp(this.stepSearchTime[0])
|
||||
const endTime = this.momentTz(end, this.multipleTime)
|
||||
this.$set(this.searchTime, 0, startTime)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// import 'element-ui/lib/theme-chalk/index.css'
|
||||
import 'xterm/dist/xterm.css'
|
||||
import '@/assets/css/main.scss'
|
||||
import '@/assets/css/animate.css'
|
||||
import '@/assets/css/font/iconfont.js'
|
||||
import 'intro.js/introjs.css'
|
||||
import ElementUI from 'element-ui'
|
||||
|
||||
@@ -75,10 +75,9 @@ axios.interceptors.request.use(
|
||||
}
|
||||
} else if (config.method === 'post' || config.method === 'put') {
|
||||
try {
|
||||
console.log(config.data.name)
|
||||
let params = config.data
|
||||
if ((typeof params == 'string') && params.constructor == String) {
|
||||
params = JSON.parse( config.data)
|
||||
params = JSON.parse(config.data)
|
||||
}
|
||||
Object.keys(params).forEach(key => {
|
||||
if ((typeof params[key] == 'string') && params[key].constructor == String) {
|
||||
|
||||
@@ -8,7 +8,6 @@ const terminalFile = {
|
||||
state.fileList = arr
|
||||
},
|
||||
addFileList (state, item) {
|
||||
console.log(item)
|
||||
state.fileList.push(item)
|
||||
},
|
||||
delFileList (state, item) {
|
||||
|
||||
Reference in New Issue
Block a user