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/consoleNew.vue

324 lines
11 KiB
Vue
Raw Normal View History

2022-12-09 09:22:38 +08:00
<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>