330 lines
12 KiB
Vue
330 lines
12 KiB
Vue
<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 => {
|
||
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
|
||
}
|
||
// 选中 复制
|
||
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()
|
||
this.terminalSocket = ''
|
||
}
|
||
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// 可视宽度
|
||
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
|
||
})
|
||
},
|
||
enterStr (message) {
|
||
if (this.terminalSocket && this.terminal.isLogin) {
|
||
this.terminalSocket.send(message)
|
||
setTimeout(()=>{
|
||
this.terminalSocket.send('\n')
|
||
}, 100)
|
||
}
|
||
}
|
||
},
|
||
mounted () {
|
||
this.beforeCreate()
|
||
},
|
||
beforeDestroy () {
|
||
this.closeSocket()
|
||
this.term.off('selection')
|
||
this.term.off('data')
|
||
}
|
||
}
|
||
</script>
|
||
<style scoped lang="scss">
|
||
|
||
</style>
|