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/common/bottomBox/tabs/terminalLogMonitorTab.vue

363 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>