feat: 设置功能新增ssh终端样式自定义

This commit is contained in:
meilin.huang
2022-01-21 16:39:38 +08:00
parent db923eace7
commit 8f912ead2e
6 changed files with 167 additions and 78 deletions

View File

@@ -48,6 +48,10 @@ export interface ThemeConfigState {
globalViceTitle: string;
globalI18n: string;
globalComponentSize: string;
terminalForeground: string;
terminalBackground: string;
terminalCursor: string;
terminalFontSize: number;
};
}

View File

@@ -106,6 +106,15 @@ const themeConfigModule: Module<ThemeConfigState, RootStateTypes> = {
// 默认布局,可选 1、默认 defaults 2、经典 classic 3、横向 transverse 4、分栏 columns
layout: 'classic',
// ssh终端字体颜色
terminalForeground: '#7e9192',
// ssh终端背景色
terminalBackground: '#002833',
// ssh终端cursor色
terminalCursor: '#268F81',
terminalFontSize: 15,
/* 后端控制路由
------------------------------- */
// 是否开启后端控制路由

View File

@@ -2,6 +2,42 @@
<div class="layout-breadcrumb-seting">
<el-drawer title="布局设置" v-model="getThemeConfig.isDrawer" direction="rtl" destroy-on-close size="240px" @close="onDrawerClose">
<el-scrollbar class="layout-breadcrumb-seting-bar">
<!-- ssh终端主题 -->
<el-divider content-position="left">终端主题</el-divider>
<div class="layout-breadcrumb-seting-bar-flex">
<div class="layout-breadcrumb-seting-bar-flex-label">字体颜色</div>
<div class="layout-breadcrumb-seting-bar-flex-value">
<el-color-picker v-model="getThemeConfig.terminalForeground" size="small" @change="onColorPickerChange('terminalForeground')"> </el-color-picker>
</div>
</div>
<div class="layout-breadcrumb-seting-bar-flex">
<div class="layout-breadcrumb-seting-bar-flex-label">背景颜色</div>
<div class="layout-breadcrumb-seting-bar-flex-value">
<el-color-picker v-model="getThemeConfig.terminalBackground" size="small" @change="onColorPickerChange('terminalBackground')"> </el-color-picker>
</div>
</div>
<div class="layout-breadcrumb-seting-bar-flex">
<div class="layout-breadcrumb-seting-bar-flex-label">cursor颜色</div>
<div class="layout-breadcrumb-seting-bar-flex-value">
<el-color-picker v-model="getThemeConfig.terminalCursor" size="small" @change="onColorPickerChange('terminalCursor')"> </el-color-picker>
</div>
</div>
<div class="layout-breadcrumb-seting-bar-flex">
<div class="layout-breadcrumb-seting-bar-flex-label">字体大小</div>
<div class="layout-breadcrumb-seting-bar-flex-value">
<el-input-number
v-model="getThemeConfig.terminalFontSize"
controls-position="right"
:min="12"
:max="24"
@change="setLocalThemeConfig"
size="small"
style="width: 90px"
>
</el-input-number>
</div>
</div>
<!-- 全局主题 -->
<el-divider content-position="left">全局主题</el-divider>
<div class="layout-breadcrumb-seting-bar-flex">

View File

@@ -12,16 +12,16 @@
<Account v-show="isTabPaneShow" />
</transition>
</el-tab-pane>
<el-tab-pane label="手机号登录" name="mobile" :disabled="tabsActiveName === 'mobile'">
<!-- <el-tab-pane label="手机号登录" name="mobile" :disabled="tabsActiveName === 'mobile'">
<transition name="el-zoom-in-center">
<Mobile v-show="!isTabPaneShow" />
</transition>
</el-tab-pane>
</el-tab-pane> -->
</el-tabs>
<div class="mt10">
<!-- <div class="mt10">
<el-button type="text" size="small">第三方登录</el-button>
<el-button type="text" size="small">友情链接</el-button>
</div>
</div> -->
</div>
</div>
<div class="login-copyright">

View File

@@ -2,57 +2,83 @@
<div :style="{ height: height }" id="xterm" class="xterm" />
</template>
<script>
<script lang="ts">
import 'xterm/css/xterm.css';
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
import { getSession } from '@/common/utils/storage.ts';
import config from '@/common/config'
import config from '@/common/config';
import { useStore } from '@/store/index.ts';
import { toRefs, watch, computed, reactive, defineComponent, onMounted, onBeforeUnmount } from 'vue';
export default {
name: 'Xterm',
export default defineComponent({
name: 'SshTerminal',
props: {
machineId: Number,
cmd: String,
height: String,
machineId: { type: Number },
cmd: { type: String },
height: { type: String },
},
watch: {
machineId(val) {
if (val !== '') {
this.initSocket();
setup(props: any) {
const state = reactive({
machineId: 0,
cmd: '',
height: '',
term: null as any,
socket: null as any,
});
watch(props, (newValue) => {
console.log(newValue);
state.machineId = newValue.machineId;
state.cmd = newValue.cmd;
state.height = newValue.height;
if (state.machineId) {
initSocket();
}
},
},
mounted() {
this.initSocket();
// this.initTerm()
},
beforeUnmount() {
this.socket.close();
if (this.term) {
this.term.dispose();
});
onMounted(() => {
state.machineId = props.machineId;
state.height = props.height;
state.cmd = props.cmd;
if (state.machineId) {
initSocket();
}
},
methods: {
initXterm() {
const term = new Terminal({
fontSize: 15,
});
onBeforeUnmount(() => {
closeAll();
});
const store = useStore();
// 获取布局配置信息
const getThemeConfig: any = computed(() => {
return store.state.themeConfig.themeConfig;
});
function initXterm() {
const term: any = new Terminal({
fontSize: getThemeConfig.value.terminalFontSize,
cursorBlink: true,
// cursorStyle: 'underline', //光标样式
disableStdin: false,
theme: {
foreground: '#7e9192', //字体
background: '#002833', //背景色
cursor: '#268F81', //设置光标
// foreground: '#7e9192', //字体
// background: '#002833', //背景色
// cursor: '#268F81', //设置光标
lineHeight: 16,
},
foreground: getThemeConfig.value.terminalForeground, //字体
background: getThemeConfig.value.terminalBackground, //背景色
cursor: getThemeConfig.value.terminalCursor, //设置光标
} as any,
});
const fitAddon = new FitAddon();
term.loadAddon(fitAddon);
term.open(document.getElementById('xterm'));
fitAddon.fit();
term.focus();
this.term = term;
state.term = term;
// / **
// *添加事件监听器,用于按下键时的事件。事件值包含
@@ -68,51 +94,59 @@ export default {
// * @返回一个IDisposable停止监听。
// * /
// 支持输入与粘贴方法
term.onData((key) => {
this.sendCmd(key);
term.onData((key: any) => {
sendCmd(key);
});
// 为解决窗体resize方法才会向后端发送列数和行数所以页面加载时也要触发此方法
this.send({
send({
type: 'resize',
Cols: parseInt(term.cols),
Rows: parseInt(term.rows),
});
// 如果有初始要执行的命令,则发送执行命令
if (this.cmd) {
this.sendCmd(this.cmd + ' \r');
if (state.cmd) {
sendCmd(state.cmd + ' \r');
}
},
initSocket() {
this.socket = new WebSocket(`${config.baseWsUrl}/machines/${this.machineId}/terminal?token=${getSession('token')}`);
}
function initSocket() {
state.socket = new WebSocket(`${config.baseWsUrl}/machines/${state.machineId}/terminal?token=${getSession('token')}`);
// 监听socket连接
this.socket.onopen = this.open;
state.socket.onopen = open;
// 监听socket错误信息
this.socket.onerror = this.error;
state.socket.onerror = error;
// 监听socket消息
this.socket.onmessage = this.getMessage;
state.socket.onmessage = getMessage;
// 发送socket消息
this.socket.onsend = this.send;
},
open: function () {
state.socket.onsend = send;
}
function open() {
console.log('socket连接成功');
this.initXterm();
initXterm();
//开启心跳
// this.start();
},
error: function () {
}
function error() {
console.log('连接错误');
//重连
this.reconnect();
},
close: function () {
this.socket.close();
// reconnect();
}
function close() {
if (state.socket) {
state.socket.close();
console.log('socket关闭');
}
//重连
// this.reconnect()
},
getMessage: function (msg) {
}
function getMessage(msg: string) {
// console.log(msg)
this.term.write(msg['data']);
state.term.write(msg['data']);
//msg是返回的数据
// msg = JSON.parse(msg.data);
// this.socket.send("ping");//有事没事ping一下看看ws还活着没
@@ -126,24 +160,30 @@ export default {
// }
//收到服务器信息,心跳重置
// this.reset();
},
send: function (msg) {
this.socket.send(JSON.stringify(msg));
},
}
sendCmd(key) {
this.send({
function send(msg: any) {
state.socket.send(JSON.stringify(msg));
}
function sendCmd(key: any) {
send({
type: 'cmd',
msg: key,
});
},
closeAll() {
this.close();
if (this.term) {
this.term.dispose();
this.term = null;
}
function closeAll() {
close();
if (state.term) {
state.term.dispose();
state.term = null;
}
}
return {
...toRefs(state),
};
},
},
};
});
</script>

View File

@@ -1,12 +1,12 @@
<template>
<div class="file-manage">
<div>
<ssh-terminal ref="terminal" :machineId="machineId" :height="height + 'px'" />
</div>
</template>
<script lang="ts">
import SshTerminal from './SshTerminal.vue';
import { reactive, toRefs, onBeforeMount, defineComponent } from 'vue';
import { reactive, toRefs, onBeforeMount, defineComponent, onMounted } from 'vue';
import { useRoute } from 'vue-router';
export default defineComponent({
@@ -24,7 +24,7 @@ export default defineComponent({
height: 700,
});
onBeforeMount(() => {
onMounted(() => {
state.height = window.innerHeight;
state.machineId = Number.parseInt(route.query.id as string);
});