This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
nezha-nezha-fronted/nezha-fronted/src/components/cli/fileListState.vue

297 lines
9.4 KiB
Vue

<template>
<div>
<!-- 显示进度-->
<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">{{$t('terminal.filetransfer')}}</span>
<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">
<div class="item-icon"> <i class="nz-icon" :class="{'nz-icon-upload':item.type === 'upload','nz-icon-download1':item.type === 'download'}"/></div>
<div class="item-progress">
<div class="item-progress-top text-ellipsis" :title="item.name">{{item.name}}</div>
<div class="item-progress-middle">
<el-progress :show-text="false" :percentage="item.done" :color="customColorMethod(item.done, item)"></el-progress>
</div>
<div class="item-progress-bottom">
<span>{{bytes(item.total, 0, 0)}}</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 class="item-state">
<i v-if="item.isFinish" class="nz-icon nz-icon-check" @click="removeRecord(item)"/>
<i v-else class="nz-icon nz-icon-close" @click="removeRecord(item)"/>
</div>
</div>
</div>
<div v-else class="file-nodata">
<svg class="icon" aria-hidden="true">
<use xlink:href="#nz-icon-no-data-list"></use>
</svg>
<div class="table-no-data__title">No results found</div>
</div>
</div>
<!-- 上传文件-->
<div style="display: none">
<el-upload
:ref="'upload'"
:auto-upload="false"
:on-change="importChange"
:multiple="false"
:file-list="importFileList"
action=""
class="upload-demo"
drag>
</el-upload>
</div>
</div>
</template>
<script>
import axios from 'axios'
import chartDataFormat from '@/components/chart/chartDataFormat'
export default {
name: 'fileListState',
computed: {
fileList () {
return this.$store.getters.getFileList
},
uploadItem () {
return this.$store.getters.getUploadItem
}
},
data () {
return {
myFileList: [],
importFileList: [],
position: {
top: 50,
right: 0
},
fileStateBox: false
}
},
watch: {
fileList: {
immediate: true,
handler (n) {
if (!n.length) {
this.fileStateBox = false
}
n.forEach(item => {
if (!item.isStart) {
item.total = 1
item.fileLength = 0
item.startTime = new Date().getTime()
item.speed = '0b/s'
if (item.type === 'download') {
item.isStart = true
this.download(item)
}
if (item.type === 'upload') {
item.isStart = true
this.upload(item)
}
}
})
}
},
uploadItem: {
handler (n) {
if (n && n.myId) {
this.$refs.upload.$children[0].$refs.input.click()
}
}
}
},
methods: {
bytes: chartDataFormat.getUnit(7).compute,
customColorMethod (percentage, item) {
if (item.isError) {
return '#EC7F66'
}
if (percentage < 100) {
return '#3B92F1'
} else {
return '#21BF9A'
}
},
download (item) {
const self = this
const CancelToken = axios.CancelToken
item.cancel = CancelToken.source()
item.startTime = new Date().getTime()
const params = {
uuid: item.uuid,
path: item.path
}
axios.post('/terminal/sftp/download', {
...params
}, {
responseType: 'blob',
cancelToken: item.cancel.token,
onDownloadProgress: function (progressEvent) {
// 处理原生进度事件
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.done = (item.fileLength / item.total) * 100
// this.$set(this.fileList, 0,item)
}
}).then(res => {
item.isFinish = true
if (window.navigator.msSaveOrOpenBlob) {
// 兼容ie11
const blobObject = new Blob([res.data])
window.navigator.msSaveOrOpenBlob(blobObject, item.name)
} else {
const url = URL.createObjectURL(new Blob([res.data]))
const a = document.createElement('a')
document.body.appendChild(a) // 此处增加了将创建的添加到body当中
a.href = url
a.download = item.name
a.target = '_blank'
a.click()
a.remove() // 将a标签移除
}
}, error => {
item.isError = true
const $self = this
const reader = new FileReader()
reader.onload = function (event) {
const responseText = reader.result
const exception = JSON.parse(responseText)
if (exception.message) {
$self.$message.error(exception.message)
} else {
console.error(error)
}
}
reader.readAsText(error.response.data)
})
},
importChange (file, fileList) {
if (fileList.length > 0) {
this.uploadItem.importFileList = [fileList[fileList.length - 1]]
}
if (this.uploadItem.importFileList.length) {
this.$store.dispatch('dispatchAddFileList', this.uploadItem)
}
},
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)
if (item.tid) {
this.$delete('/terminal/sftp/cancel/' + item.tid).then(res => {
if (res.code === 200) {
} else {
this.$message.error(res.msg)
}
})
}
}
}
this.$store.dispatch('dispatchDelFileList', item)
},
upload (item) {
const self = this
const CancelToken = axios.CancelToken
item.cancel = CancelToken.source()
const form = new FormData()
const importFile = item.importFileList[0]
item.name = importFile.name
form.append('file', importFile.raw)
form.append('uuid', item.uuid)
form.append('path', item.path)
axios({
url: '/terminal/sftp/upload',
method: 'PUT',
headers: { 'Content-Type': 'multipart/form-data' },
data: form,
cancelToken: item.cancel.token,
onUploadProgress: function (progressEvent) {
// 处理原生进度事件
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.done = (item.fileLength / (item.total * 2)) * 100
}
}).then(response => {
const res = response.data
// item.isFinish = true
if (res.code == 200) {
self.nextUpload(item, res.data.tid)
} else {
this.$message.error(res.msg)
}
}).catch(err => {
item.isError = true
})
},
nextUpload (item, tid) {
// this.$message.success(response.msg)
item.timer = setInterval(() => { // 上传 50-100
item.tid = tid
this.$get('/terminal/sftp/process/' + tid).then((res) => {
if (res.code == 200) {
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
this.$store.dispatch('upDateConsole', item.uuid)
}
} else {
item.isError = true
clearInterval(item.timer)
this.$store.dispatch('upDateConsole', item.uuid)
}
})
}, 200)
},
fileStateShow (flag, type) {
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 () {
this.fileList.forEach(item => {
this.removeRecord(item)
})
setTimeout(() => {
this.$store.dispatch('dispatchFileList', [])
})
}
}
}
</script>