363 lines
11 KiB
Vue
363 lines
11 KiB
Vue
<template>
|
||
<div class="replay-tab" ref="replayTab">
|
||
<div class="sub-top-tools">
|
||
<div class="sub-list-tabs">
|
||
<div class="sub-list-tab-title">ID:{{obj.id}}</div>
|
||
<div class="sub-list-tab sub-list-tab-active">{{$t("config.terminallog.monitor.monitor")}}</div>
|
||
</div>
|
||
</div>
|
||
<div class="replay-container">
|
||
<div class="record-console" ref="recordConsole">
|
||
<div :id="obj.uuid" class="record-terminal"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import Terminal from '../../js/Xterm';
|
||
import bus from "../../../../libs/bus";
|
||
|
||
export default {
|
||
name:"terminalLogReplayTab",
|
||
components:{
|
||
Terminal
|
||
},
|
||
props:{
|
||
obj:Object, //关联的实体对象
|
||
},
|
||
data(){
|
||
return {
|
||
filter:{
|
||
size:1,
|
||
uuid:""
|
||
},
|
||
terminal:null,
|
||
term:null,
|
||
terminalSocket:null,
|
||
recordData:[],
|
||
isNeedStop:false, // 是否需要停止
|
||
playedCount:0, // 当前已经播放完的数量
|
||
isPlaying:true, // 是否正在播放
|
||
isFinish:false, //是否已结束
|
||
isDragging:false, //是否正在拖动进度条
|
||
draggingOriginalX:0, //开始拖拽时鼠标的x
|
||
draggingOriginalProgress:0, //开始拖拽时的进度
|
||
recordTick:50, // 输出间隔时间ms,默认50
|
||
playerTimer:null, // 定时器
|
||
playerCurrentTime:0, // 当前时间进度
|
||
speedTable:[ // 快进倍速选项
|
||
{speed:1,name:'×1'},
|
||
{speed:2,name:'×2'},
|
||
{speed:4,name:'×4'},
|
||
{speed:8,name:'×8'},
|
||
{speed:16,name:'×16'}
|
||
],
|
||
speedOffset:0, // 快进倍数index
|
||
progress:0, // 进度条进度
|
||
needSkip:true, // 是否跳过无操作时间,为true时表示需要,即不跳过无操作时间
|
||
timeUsed:0,
|
||
successBackContent:'Connecting to',
|
||
failBackContent:'Sorry',
|
||
connectFailContent:'Connection failed',
|
||
welcomeBackContent:'Welcome',
|
||
psdCont:'password: ',
|
||
}
|
||
},
|
||
methods:{
|
||
//创建连接
|
||
create(){
|
||
let that=this;
|
||
if(this.terminalSocket){
|
||
this.terminalSocket.close();
|
||
}
|
||
if(this.terminal){
|
||
this.terminal.off("selection");
|
||
this.terminal.off("data")
|
||
this.terminal.destroy();
|
||
}
|
||
this.terminal=new Terminal({
|
||
rows:parseInt(this.$refs.recordConsole.offsetHeight/18),
|
||
cols:parseInt(this.$refs.recordConsole.offsetWidth/11),
|
||
cursorStyle:'block', // 光标样式 null | 'block' | 'underline' | 'bar'
|
||
//bellStyle:'sound',
|
||
disableStdin:true,//是否应禁用输入
|
||
});
|
||
this.terminal.open(document.getElementById(this.obj.uuid));
|
||
|
||
let token=sessionStorage.getItem('nz-token');
|
||
let baseUrl=this.$axios.defaults.baseURL;
|
||
if(baseUrl.startsWith("/")){
|
||
baseUrl="ws://"+window.location.host+baseUrl;
|
||
}else{
|
||
baseUrl=baseUrl.replace("http://","ws://").replace("https://","ws://");
|
||
}
|
||
///monitor
|
||
let url=baseUrl+"/terminal/monitor.ws?"+"&token="+token+"&uuid="+this.obj.uuid;
|
||
console.info(url);
|
||
if(this.terminalSocket){//如果存在之前的链接 先断开 再链接新的
|
||
this.terminalSocket.close();
|
||
}
|
||
this.terminalSocket=new WebSocket(url);
|
||
//连接成功
|
||
this.terminalSocket.onopen=()=>{
|
||
};
|
||
//登录后,你输入的内容从后台服务返回
|
||
this.terminal.on("data",function(data){
|
||
console.log(data,'data')
|
||
/*
|
||
let code = data.charCodeAt(0);
|
||
if(code==13){
|
||
}else {
|
||
//that.term.write(data);
|
||
}*/
|
||
});
|
||
//返回
|
||
this.terminalSocket.onmessage=function(evt){
|
||
let backContent=evt.data;
|
||
/*
|
||
if(that.inputSecret){//当前为密码输入状态
|
||
}
|
||
if(backContent.length>1){
|
||
let pwdInput = backContent.endsWith(that.psdCont);
|
||
if(pwdInput){//输入密码
|
||
that.inputSecret = true;
|
||
}
|
||
}*/
|
||
|
||
let 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{
|
||
let successContentIndex=backContent.indexOf(that.successBackContent);
|
||
if(successContentIndex> -1){
|
||
//that.conFinish = true;
|
||
let startIndex=successContentIndex+that.successBackContent.length+1;
|
||
backContent=backContent.substring(startIndex);
|
||
let endIndex=backContent.indexOf('\r\n');
|
||
let title=backContent.substring(0,endIndex);
|
||
const connectResult={
|
||
title:title,
|
||
color:2,
|
||
};
|
||
that.$emit("refreshConsoleTitle",connectResult);//1:grey 2 green 3 red
|
||
}else{//失败
|
||
let failContentIndex=backContent.indexOf(that.failBackContent);
|
||
let 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){
|
||
let startIndex=successContentIndex+that.successBackContent.length+1;
|
||
backContent=backContent.substring(startIndex);
|
||
let endIndex=backContent.indexOf('\r\n');
|
||
let title=backContent.substring(0,endIndex);
|
||
const connectResult={
|
||
title:'',
|
||
color:3,
|
||
};
|
||
that.$emit("refreshConsoleTitle",connectResult);//1:grey 2 green 3 red
|
||
}
|
||
}
|
||
}
|
||
};
|
||
//关闭
|
||
this.terminalSocket.onclose=()=>{
|
||
//报错sorry的,还没来得及看信息就关闭
|
||
// this.$emit("closeConsole",this.terminal.name);//应该调用父窗口
|
||
};
|
||
|
||
|
||
//错误
|
||
this.terminalSocket.onerror=(e)=>{
|
||
};
|
||
//选中 复制
|
||
this.terminal.on("selection",function(){
|
||
});
|
||
this.terminal.attachCustomKeyEventHandler(function(ev){
|
||
});
|
||
|
||
this.terminal.attach(this.terminalSocket);
|
||
this.terminal._initialized=true;
|
||
this.terminal.fit();//自适应大小(使终端的尺寸和几何尺寸适合于终端容器的尺寸) 只是width
|
||
// this.$nextTick(()=>{// 解决进入全屏和退出全屏是底部隐藏
|
||
// this.setFontSize(this.fontSize);
|
||
// })
|
||
},
|
||
|
||
//关闭连接
|
||
closeSocket(){
|
||
if(this.terminalSocket){
|
||
this.terminalSocket.close();
|
||
}
|
||
if(this.terminal){
|
||
this.terminal.destroy();
|
||
}
|
||
},
|
||
// 切换tab
|
||
changeTab(tab){
|
||
this.$emit('changeTab',tab);
|
||
},
|
||
|
||
getRecordData(){
|
||
return new Promise(resolve=>{
|
||
this.$get("/terminal/record",this.filter).then(res=>{
|
||
if(res.code===200){
|
||
this.recordData=res.data.list;
|
||
this.timeUsed=res.data.endTime;
|
||
}
|
||
resolve();
|
||
});
|
||
});
|
||
},
|
||
|
||
consoleResize(){
|
||
this.terminal&&this.terminal.resize(parseInt(this.$refs.recordConsole.offsetWidth/11),parseInt(this.$refs.recordConsole.offsetHeight/18));
|
||
this.$nextTick(()=>{
|
||
this.terminal&&this.terminal.fit();
|
||
});
|
||
},
|
||
shutdown(){
|
||
this.$confirm(this.$t("tip.killTerm"),{
|
||
confirmButtonText:this.$t("tip.yes"),
|
||
cancelButtonText:this.$t("tip.no"),
|
||
type:'warning'
|
||
}).then(()=>{
|
||
this.$put("/terminal/kill",{uuid:this.obj.uuid}).then(res=>{
|
||
if(res.code===200){
|
||
this.$message.success(this.$t("config.terminallog.success"));
|
||
this.$emit('exit')
|
||
}else{
|
||
this.$message.error(this.$t("config.terminallog.killErrorTip"));
|
||
}
|
||
});
|
||
});
|
||
},
|
||
},
|
||
watch:{
|
||
// 入口,监听terminal session的变化,开始功能
|
||
obj:{
|
||
immediate:true,
|
||
deep:true,
|
||
handler(n){
|
||
if(n.uuid){
|
||
this.recordData=[];
|
||
this.filter.uuid=n.uuid;
|
||
this.playerCurrentTime=0;
|
||
if(this.playerTimer){
|
||
clearTimeout(this.playerTimer);
|
||
}
|
||
setTimeout(()=>{
|
||
this.create();
|
||
},200);
|
||
}
|
||
}
|
||
},
|
||
progress(n){
|
||
let progressController=document.getElementById("progressController");
|
||
progressController.style.left=`${n}%`;
|
||
}
|
||
},
|
||
computed:{
|
||
parseCurrentTime(){
|
||
let currentTime=parseInt(this.playerCurrentTime/1000);
|
||
let totalTime=parseInt(this.timeUsed/1000);
|
||
if(currentTime>totalTime){
|
||
currentTime=totalTime;
|
||
}
|
||
return `${currentTime} / ${totalTime}`;
|
||
}
|
||
},
|
||
created(){
|
||
window.addEventListener('resize',bus.debounce(this.consoleResize,1000));
|
||
},
|
||
mounted(){
|
||
|
||
},
|
||
beforeDestroy(){
|
||
window.removeEventListener('resize',bus.debounce);
|
||
this.closeSocket();
|
||
this.terminal.off("selection");
|
||
this.terminal.off("data")
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.replay-tab {
|
||
height: 100%;
|
||
}
|
||
|
||
.replay-container {
|
||
height: calc(100% - 40px);
|
||
}
|
||
|
||
.record-console {
|
||
padding: 10px 4px 10px 10px;
|
||
background-color: black;
|
||
height: calc(100% - 80px);
|
||
}
|
||
|
||
.terminal-replay-progress {
|
||
height: 20px;
|
||
padding: 3px 0;
|
||
position: relative;
|
||
width: 500px;
|
||
}
|
||
|
||
#terminal-kill {
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.terminal-replay-progress-bar {
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
|
||
.el-progress-bar__inner {
|
||
transition: unset;
|
||
user-select: none;
|
||
}
|
||
}
|
||
|
||
.replay-operate {
|
||
.nz-btn {
|
||
margin-right: 8px;
|
||
|
||
.nz-icon {
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.operate-skip {
|
||
margin: 0 12px !important;
|
||
}
|
||
|
||
.time-box {
|
||
border: none;
|
||
border-radius: 16px;
|
||
}
|
||
|
||
.progress-controller {
|
||
position: absolute;
|
||
height: 14px;
|
||
width: 14px;
|
||
border-radius: 50%;
|
||
background-color: #409eef;
|
||
top: 50%;
|
||
transform: translate(-7px, -50%);
|
||
}
|
||
|
||
.progress-controller:hover {
|
||
background-color: #207ecf;
|
||
}
|
||
</style>
|