feat: 添加终端交互配置项.
This commit is contained in:
@@ -2,6 +2,7 @@ package com.orion.ops.module.asset.handler.host.terminal.session;
|
|||||||
|
|
||||||
import com.orion.lang.utils.io.Streams;
|
import com.orion.lang.utils.io.Streams;
|
||||||
import com.orion.net.host.SessionStore;
|
import com.orion.net.host.SessionStore;
|
||||||
|
import com.orion.net.host.ssh.TerminalType;
|
||||||
import com.orion.net.host.ssh.shell.ShellExecutor;
|
import com.orion.net.host.ssh.shell.ShellExecutor;
|
||||||
import com.orion.ops.framework.common.constant.Const;
|
import com.orion.ops.framework.common.constant.Const;
|
||||||
import com.orion.ops.framework.websocket.core.utils.WebSockets;
|
import com.orion.ops.framework.websocket.core.utils.WebSockets;
|
||||||
@@ -66,6 +67,8 @@ public class TerminalSession implements ITerminalSession {
|
|||||||
// 打开 shell
|
// 打开 shell
|
||||||
this.executor = sessionStore.getShellExecutor();
|
this.executor = sessionStore.getShellExecutor();
|
||||||
executor.size(cols, rows);
|
executor.size(cols, rows);
|
||||||
|
// FIXME
|
||||||
|
executor.terminalType(TerminalType.XTERM.getType());
|
||||||
executor.streamHandler(this::streamHandler);
|
executor.streamHandler(this::streamHandler);
|
||||||
executor.callback(this::eofCallback);
|
executor.callback(this::eofCallback);
|
||||||
executor.connect();
|
executor.connect();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.orion.ops.module.infra.handler.preference.model;
|
package com.orion.ops.module.infra.handler.preference.model;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.orion.lang.able.IJsonObject;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
@@ -33,14 +33,20 @@ public class TerminalPreferenceModel implements PreferenceModel {
|
|||||||
@Schema(description = "操作栏设置")
|
@Schema(description = "操作栏设置")
|
||||||
private JSONObject actionBarSetting;
|
private JSONObject actionBarSetting;
|
||||||
|
|
||||||
@Schema(description = "背景设置")
|
@Schema(description = "交互设置")
|
||||||
private JSONObject backgroundSetting;
|
private JSONObject interactSetting;
|
||||||
|
|
||||||
|
@Schema(description = "插件设置")
|
||||||
|
private JSONObject pluginsSetting;
|
||||||
|
|
||||||
|
@Schema(description = "会话设置")
|
||||||
|
private JSONObject sessionSetting;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public static class DisplaySettingModel {
|
public static class DisplaySettingModel implements IJsonObject {
|
||||||
|
|
||||||
@Schema(description = "字体样式")
|
@Schema(description = "字体样式")
|
||||||
private String fontFamily;
|
private String fontFamily;
|
||||||
@@ -63,15 +69,75 @@ public class TerminalPreferenceModel implements PreferenceModel {
|
|||||||
@Schema(description = "光标闪烁")
|
@Schema(description = "光标闪烁")
|
||||||
private Boolean cursorBlink;
|
private Boolean cursorBlink;
|
||||||
|
|
||||||
/**
|
|
||||||
* 转为 json
|
|
||||||
*
|
|
||||||
* @return json
|
|
||||||
*/
|
|
||||||
public JSONObject toJson() {
|
|
||||||
return JSON.parseObject(JSON.toJSONString(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class InteractSettingModel implements IJsonObject {
|
||||||
|
|
||||||
|
@Schema(description = "快速滚动")
|
||||||
|
private Boolean fastScrollModifier;
|
||||||
|
|
||||||
|
@Schema(description = "点击移动光标")
|
||||||
|
private Boolean altClickMovesCursor;
|
||||||
|
|
||||||
|
@Schema(description = "右键选中词条")
|
||||||
|
private Boolean rightClickSelectsWord;
|
||||||
|
|
||||||
|
@Schema(description = "选中词条自动复制")
|
||||||
|
private Boolean selectionChangeCopy;
|
||||||
|
|
||||||
|
@Schema(description = "复制去除空格")
|
||||||
|
private Boolean copyAutoTrim;
|
||||||
|
|
||||||
|
@Schema(description = "粘贴去除空格")
|
||||||
|
private Boolean pasteAutoTrim;
|
||||||
|
|
||||||
|
@Schema(description = "右键粘贴")
|
||||||
|
private Boolean rightClickPaste;
|
||||||
|
|
||||||
|
@Schema(description = "启用右键菜单")
|
||||||
|
private Boolean enableRightClickMenu;
|
||||||
|
|
||||||
|
@Schema(description = "启用响铃")
|
||||||
|
private Boolean enableBell;
|
||||||
|
|
||||||
|
@Schema(description = "单词分隔符")
|
||||||
|
private String wordSeparator;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class PluginsSettingModel implements IJsonObject {
|
||||||
|
|
||||||
|
@Schema(description = "超链接插件")
|
||||||
|
private Boolean enableWeblinkPlugin;
|
||||||
|
|
||||||
|
@Schema(description = "WebGL 渲染插件")
|
||||||
|
private Boolean enableWebglPlugin;
|
||||||
|
|
||||||
|
@Schema(description = "图片渲染插件")
|
||||||
|
private Boolean enableImagePlugin;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class SessionSettingModel implements IJsonObject {
|
||||||
|
|
||||||
|
@Schema(description = "伪终端类型")
|
||||||
|
private String terminalEmulationType;
|
||||||
|
|
||||||
|
@Schema(description = "保存在缓冲区的行数")
|
||||||
|
private Integer scrollBackLine;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.orion.ops.module.infra.handler.preference.strategy;
|
package com.orion.ops.module.infra.handler.preference.strategy;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.orion.net.host.ssh.TerminalType;
|
||||||
import com.orion.ops.module.infra.handler.preference.model.TerminalPreferenceModel;
|
import com.orion.ops.module.infra.handler.preference.model.TerminalPreferenceModel;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -16,8 +17,9 @@ public class TerminalPreferenceStrategy implements IPreferenceStrategy<TerminalP
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TerminalPreferenceModel getDefault() {
|
public TerminalPreferenceModel getDefault() {
|
||||||
|
// ...快捷键 ...背景
|
||||||
// 默认显示设置
|
// 默认显示设置
|
||||||
JSONObject defaultDisplaySetting = TerminalPreferenceModel.DisplaySettingModel
|
String defaultDisplaySetting = TerminalPreferenceModel.DisplaySettingModel
|
||||||
.builder()
|
.builder()
|
||||||
.fontFamily("_")
|
.fontFamily("_")
|
||||||
.fontSize(14)
|
.fontSize(14)
|
||||||
@@ -27,13 +29,44 @@ public class TerminalPreferenceStrategy implements IPreferenceStrategy<TerminalP
|
|||||||
.cursorStyle("bar")
|
.cursorStyle("bar")
|
||||||
.cursorBlink(true)
|
.cursorBlink(true)
|
||||||
.build()
|
.build()
|
||||||
.toJson();
|
.toJsonString();
|
||||||
|
|
||||||
|
// 默认交互设置
|
||||||
|
String defaultInteractSetting = TerminalPreferenceModel.InteractSettingModel.builder()
|
||||||
|
.fastScrollModifier(true)
|
||||||
|
.altClickMovesCursor(true)
|
||||||
|
.rightClickSelectsWord(false)
|
||||||
|
.selectionChangeCopy(false)
|
||||||
|
.copyAutoTrim(false)
|
||||||
|
.pasteAutoTrim(false)
|
||||||
|
.rightClickPaste(false)
|
||||||
|
.enableRightClickMenu(true)
|
||||||
|
.enableBell(false)
|
||||||
|
.wordSeparator("/\\()\"'` -.,:;<>~!@#$%^&*|+=[]{}~?│")
|
||||||
|
.build()
|
||||||
|
.toJsonString();
|
||||||
|
// 默认插件设置
|
||||||
|
String defaultPluginsSetting = TerminalPreferenceModel.PluginsSettingModel.builder()
|
||||||
|
.enableWeblinkPlugin(true)
|
||||||
|
.enableWebglPlugin(true)
|
||||||
|
.enableImagePlugin(false)
|
||||||
|
.build()
|
||||||
|
.toJsonString();
|
||||||
|
// 默认会话设置
|
||||||
|
String defaultSessionSetting = TerminalPreferenceModel.SessionSettingModel.builder()
|
||||||
|
.terminalEmulationType(TerminalType.XTERM.getType())
|
||||||
|
.scrollBackLine(1000)
|
||||||
|
.build()
|
||||||
|
.toJsonString();
|
||||||
|
// 默认配置
|
||||||
return TerminalPreferenceModel.builder()
|
return TerminalPreferenceModel.builder()
|
||||||
.newConnectionType("group")
|
.newConnectionType("group")
|
||||||
.theme(new JSONObject())
|
.theme(new JSONObject())
|
||||||
.displaySetting(defaultDisplaySetting)
|
.displaySetting(JSONObject.parseObject(defaultDisplaySetting))
|
||||||
.actionBarSetting(new JSONObject())
|
.actionBarSetting(new JSONObject())
|
||||||
.backgroundSetting(new JSONObject())
|
.interactSetting(JSONObject.parseObject(defaultInteractSetting))
|
||||||
|
.pluginsSetting(JSONObject.parseObject(defaultPluginsSetting))
|
||||||
|
.sessionSetting(JSONObject.parseObject(defaultSessionSetting))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,14 @@ export default defineStore('terminal', {
|
|||||||
// 更新默认主题偏好
|
// 更新默认主题偏好
|
||||||
await this.updateTerminalPreference(PreferenceItem.THEME, data.theme);
|
await this.updateTerminalPreference(PreferenceItem.THEME, data.theme);
|
||||||
}
|
}
|
||||||
this.preference = data;
|
// 选择赋值
|
||||||
|
const keys = Object.keys(this.preference);
|
||||||
|
keys.forEach(key => {
|
||||||
|
const item = data[key as keyof TerminalPreference];
|
||||||
|
if (item) {
|
||||||
|
this.preference[key as keyof TerminalPreference] = item as any;
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Message.error('配置加载失败');
|
Message.error('配置加载失败');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<a-col :span="12">
|
||||||
|
<div class="block-form-item-wrapper">
|
||||||
|
<div class="block-form-item-header">
|
||||||
|
<!-- label -->
|
||||||
|
<div class="block-form-item-label">
|
||||||
|
{{ label }}
|
||||||
|
</div>
|
||||||
|
<!-- item -->
|
||||||
|
<div class="block-form-item-value">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 描述 -->
|
||||||
|
<div class="block-form-item-desc">
|
||||||
|
{{ desc }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'blockSettingItem'
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
label: string,
|
||||||
|
desc: string,
|
||||||
|
}>();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.block-form-item-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
min-height: 64px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: var(--color-fill-2);
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.block-form-item-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-form-item-label {
|
||||||
|
color: var(--color-content-text-3);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-form-item-desc {
|
||||||
|
color: var(--color-text-2);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-input-wrapper) {
|
||||||
|
background-color: var(--color-fill-3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -21,14 +21,14 @@
|
|||||||
position="bottom" />
|
position="bottom" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<!-- 命令输入框 -->
|
<!-- 命令输入框 -->
|
||||||
<a-form-item field="showCommandInput" label="命令输入框">
|
<a-form-item field="commandInput" label="命令输入框">
|
||||||
<a-switch v-model="formModel.commandInput"
|
<a-switch v-model="formModel.commandInput"
|
||||||
class="form-item-command-input"
|
class="form-item-command-input"
|
||||||
:default-checked="true"
|
:default-checked="true"
|
||||||
type="round" />
|
type="round" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<!-- 连接状态 -->
|
<!-- 终端连接状态 -->
|
||||||
<a-form-item field="showStatus" label="连接状态">
|
<a-form-item field="showStatus" label="终端连接状态">
|
||||||
<a-switch v-model="formModel.connectStatus"
|
<a-switch v-model="formModel.connectStatus"
|
||||||
:default-checked="true"
|
:default-checked="true"
|
||||||
type="round" />
|
type="round" />
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
<h2 class="terminal-setting-title">终端设置</h2>
|
<h2 class="terminal-setting-title">终端设置</h2>
|
||||||
<!-- 交互设置 -->
|
<!-- 交互设置 -->
|
||||||
<terminal-interact-block />
|
<terminal-interact-block />
|
||||||
|
<!-- 插件设置 -->
|
||||||
|
<terminal-plugins-block />
|
||||||
<!-- 会话设置 -->
|
<!-- 会话设置 -->
|
||||||
<terminal-session-block />
|
<terminal-session-block />
|
||||||
</div>
|
</div>
|
||||||
@@ -19,6 +21,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import TerminalInteractBlock from './terminal-interact-block.vue';
|
import TerminalInteractBlock from './terminal-interact-block.vue';
|
||||||
|
import TerminalPluginsBlock from './terminal-plugins-block.vue';
|
||||||
import TerminalSessionBlock from './terminal-session-block.vue';
|
import TerminalSessionBlock from './terminal-session-block.vue';
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -9,21 +9,70 @@
|
|||||||
<!-- 提示 -->
|
<!-- 提示 -->
|
||||||
<a-alert class="mb16">修改后会立刻保存, 刷新页面后生效</a-alert>
|
<a-alert class="mb16">修改后会立刻保存, 刷新页面后生效</a-alert>
|
||||||
<!-- 内容区域 -->
|
<!-- 内容区域 -->
|
||||||
<div class="terminal-setting-body">
|
<div class="terminal-setting-body setting-body">
|
||||||
<a-row class="" :gutter="[16, 16]">
|
<a-row class="mb16" align="stretch" :gutter="16">
|
||||||
<a-col :span="12">
|
<!-- 快速滚动 -->
|
||||||
<div class="block-form-item-wrapper">
|
<block-setting-item label="快速滚动" desc="alt + 鼠标滚轮快速滚动">
|
||||||
<div class="block-form-item-label">
|
<a-switch type="round"
|
||||||
label
|
v-model="formModel.fastScrollModifier"
|
||||||
</div>
|
checked-value="alt"
|
||||||
<div class="block-form-item-desc">
|
unchecked-value="none" />
|
||||||
描述一下
|
</block-setting-item>
|
||||||
</div>
|
<!-- 点击移动光标 -->
|
||||||
<div class="block-form-item-value">
|
<block-setting-item label="点击移动光标" desc="alt + 鼠标左键可以切换光标位置">
|
||||||
<a-switch />
|
<a-switch type="round"
|
||||||
</div>
|
v-model="formModel.altClickMovesCursor" />
|
||||||
</div>
|
</block-setting-item>
|
||||||
</a-col>
|
</a-row>
|
||||||
|
<a-row class="mb16" align="stretch" :gutter="16">
|
||||||
|
<!-- 右键选中词条 -->
|
||||||
|
<block-setting-item label="右键选中词条" desc="右键文本">
|
||||||
|
<a-switch type="round"
|
||||||
|
v-model="formModel.rightClickSelectsWord" />
|
||||||
|
</block-setting-item>
|
||||||
|
<!-- 选中词条自动复制 -->
|
||||||
|
<block-setting-item label="选中词条自动复制" desc="自动将选中的词条复制到剪切板">
|
||||||
|
<a-switch type="round"
|
||||||
|
v-model="formModel.selectionChangeCopy" />
|
||||||
|
</block-setting-item>
|
||||||
|
</a-row>
|
||||||
|
<a-row class="mb16" align="stretch" :gutter="16">
|
||||||
|
<!-- 复制去除空格 -->
|
||||||
|
<block-setting-item label="复制去除空格" desc="复制文本后自动删除尾部空格">
|
||||||
|
<a-switch type="round"
|
||||||
|
v-model="formModel.copyAutoTrim" />
|
||||||
|
</block-setting-item>
|
||||||
|
<!-- 粘贴去除空格 -->
|
||||||
|
<block-setting-item label="粘贴去除空格" desc="粘贴文本前自动删除尾部空格">
|
||||||
|
<a-switch type="round"
|
||||||
|
v-model="formModel.pasteAutoTrim" />
|
||||||
|
</block-setting-item>
|
||||||
|
</a-row>
|
||||||
|
<a-row class="mb16" align="stretch" :gutter="16">
|
||||||
|
<!-- 右键粘贴 -->
|
||||||
|
<block-setting-item label="右键粘贴" desc="右键自动粘贴, 启用后需要关闭右键菜单">
|
||||||
|
<a-switch type="round"
|
||||||
|
v-model="formModel.rightClickPaste" />
|
||||||
|
</block-setting-item>
|
||||||
|
<!-- 启用右键菜单 -->
|
||||||
|
<block-setting-item label="启用右键菜单" desc="右键终端将打开自定义菜单, 启用后需要关闭右键粘贴">
|
||||||
|
<a-switch type="round"
|
||||||
|
v-model="formModel.pasteAutoTrim" />
|
||||||
|
</block-setting-item>
|
||||||
|
</a-row>
|
||||||
|
<a-row class="mb16" align="stretch" :gutter="16">
|
||||||
|
<!-- 启用响铃 -->
|
||||||
|
<block-setting-item label="启用响铃" desc="系统接受到 \a 时候会发出响铃 (一般不用开启)">
|
||||||
|
<a-switch type="round"
|
||||||
|
v-model="formModel.enableBell" />
|
||||||
|
</block-setting-item>
|
||||||
|
<!-- 单词分隔符 -->
|
||||||
|
<block-setting-item label="单词分隔符" desc="在终端中双击文本将使用该分隔符进行分割">
|
||||||
|
<a-input size="small"
|
||||||
|
v-model="formModel.wordSeparator"
|
||||||
|
placeholder="单词分隔符"
|
||||||
|
allow-clear />
|
||||||
|
</block-setting-item>
|
||||||
</a-row>
|
</a-row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,46 +86,31 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
||||||
// TODO
|
// 快速滚动 fastScrollModifier
|
||||||
// 交互设置
|
// 点击移动光标 altClickMovesCursor
|
||||||
// alt + 滚轮快速滚动 fastScrollModifier 'none' | 'alt'
|
|
||||||
// alt 点击可以切换光标位置 altClickMovesCursor
|
|
||||||
|
|
||||||
// 右键选中词条 rightClickSelectsWord
|
// 右键选中词条 rightClickSelectsWord
|
||||||
// 自动将选中内容复制到剪切板 onSelectionChange
|
// 自动将选中内容复制到剪切板 selectionChangeCopy onSelectionChange
|
||||||
|
|
||||||
// 粘贴时删除空格
|
// 复制时删除空格 pasteAutoTrim
|
||||||
// 复制时删除空格
|
// 粘贴时删除空格 copyAutoTrim
|
||||||
|
|
||||||
// 右键粘贴
|
// 右键粘贴 rightClickPaste
|
||||||
// 启用右键菜单
|
// 启用右键菜单 enableRightClickMenu
|
||||||
|
|
||||||
// 自动检测 url 并可以点击
|
// 启用响铃 enableBell
|
||||||
// 支持显示图片 使用 sixel 打开图片
|
// 单词分隔符 /\()"'` -.,:;<>~!@#$%^&*|+=[]{}~?│ wordSeparator
|
||||||
|
|
||||||
// bell sound
|
import { ref } from 'vue';
|
||||||
// 分隔符 /\()"'-.,:;<>~!@#$%^&*|+=[]{}~?│ 在终端中双击文本将使用到这些符号 wordSeparator
|
import BlockSettingItem from './block-setting-item.vue';
|
||||||
|
|
||||||
|
const formModel = ref<Record<string, any>>({});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.block-form-item-wrapper {
|
.setting-body {
|
||||||
height: 84px;
|
flex-direction: column;
|
||||||
border-radius: 4px;
|
|
||||||
background: var(--color-fill-2);
|
|
||||||
display: flex;
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
.block-form-item-label {
|
|
||||||
color: var(--color-content-text-3);
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block-form-item-desc {
|
|
||||||
color: var(--color-content-text-2);
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<div class="terminal-setting-block">
|
||||||
|
<!-- 顶部 -->
|
||||||
|
<div class="terminal-setting-subtitle-wrapper">
|
||||||
|
<h3 class="terminal-setting-subtitle">
|
||||||
|
插件设置
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<!-- 内容区域 -->
|
||||||
|
<div class="terminal-setting-body setting-body">
|
||||||
|
<a-row class="mb16" align="stretch" :gutter="16">
|
||||||
|
<!-- 超链接插件 -->
|
||||||
|
<block-setting-item label="超链接插件" desc="自动检测 http url 并可以点击">
|
||||||
|
<a-switch type="round"
|
||||||
|
v-model="formModel.enableWeblinkPlugin"
|
||||||
|
checked-value="alt"
|
||||||
|
unchecked-value="none" />
|
||||||
|
</block-setting-item>
|
||||||
|
<!-- WebGL 渲染插件 -->
|
||||||
|
<block-setting-item label="WebGL 渲染插件" desc="使用 WebGL 加速渲染终端 (建议开启, 若无法开启终端请关闭)">
|
||||||
|
<a-switch type="round"
|
||||||
|
v-model="formModel.enableWebglPlugin" />
|
||||||
|
</block-setting-item>
|
||||||
|
</a-row>
|
||||||
|
<a-row class="mb16" align="stretch" :gutter="16">
|
||||||
|
<!-- 图片渲染插件 -->
|
||||||
|
<block-setting-item label="图片渲染插件" desc="支持使用 sixel 打开图片 (一般不需要开启)">
|
||||||
|
<a-switch type="round"
|
||||||
|
v-model="formModel.enableImagePlugin" />
|
||||||
|
</block-setting-item>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'TerminalPluginsBlock'
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
// fixme
|
||||||
|
// 自动检测 url 并可以点击 enableWeblinkPlugin
|
||||||
|
// 启用 webgl 支持 enableWebglPlugin
|
||||||
|
// 支持显示图片 使用 sixel 打开图片 enableImagePlugin
|
||||||
|
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import BlockSettingItem from './block-setting-item.vue';
|
||||||
|
|
||||||
|
const formModel = ref<Record<string, any>>({});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.setting-body {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -7,9 +7,26 @@
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<!-- 内容区域 -->
|
<!-- 内容区域 -->
|
||||||
<div class="terminal-setting-body">
|
<div class="terminal-setting-body setting-body">
|
||||||
|
<a-row class="mb16" align="stretch" :gutter="16">
|
||||||
|
<!-- 终端类型 -->
|
||||||
|
<block-setting-item label="终端类型" desc="若显示异常请尝试切换此选项 兼容性 vt100 > xterm > 16color > 256color">
|
||||||
|
<a-select style="width: 160px;"
|
||||||
|
v-model="formModel.terminalEmulationType"
|
||||||
|
size="small"
|
||||||
|
:options="toOptions(terminalEmulationTypeKey)" />
|
||||||
|
</block-setting-item>
|
||||||
|
<!-- 缓冲区行数 -->
|
||||||
|
<block-setting-item label="缓冲区行数" desc="保存在缓冲区的行数, 多出的行数会被忽略, 此值越大占用内存的内存会更多">
|
||||||
|
<a-input-number v-model="formModel.scrollBackLine"
|
||||||
|
size="small"
|
||||||
|
:min="1"
|
||||||
|
:max="10000"
|
||||||
|
placeholder="缓冲区行数"
|
||||||
|
allow-clear
|
||||||
|
hide-button />
|
||||||
|
</block-setting-item>
|
||||||
|
</a-row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -21,13 +38,25 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { terminalEmulationTypeKey } from '../../types/terminal.const';
|
||||||
|
|
||||||
|
const { toOptions } = useDictStore();
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// terminal emulation type: xterm 256color
|
// terminalEmulationType: xterm 256color
|
||||||
// 回滚(ScrollBack) scrollback 保存在缓冲区的行数
|
// scrollBackLine 保存在缓冲区的行数 1000
|
||||||
|
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import BlockSettingItem from './block-setting-item.vue';
|
||||||
|
import { useDictStore } from '@/store';
|
||||||
|
|
||||||
|
const formModel = ref<Record<string, any>>({});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
.setting-body {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -227,7 +227,6 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
.address-copy {
|
.address-copy {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { WebglAddon } from 'xterm-addon-webgl';
|
|||||||
import { WebLinksAddon } from 'xterm-addon-web-links';
|
import { WebLinksAddon } from 'xterm-addon-web-links';
|
||||||
import { SearchAddon } from 'xterm-addon-search';
|
import { SearchAddon } from 'xterm-addon-search';
|
||||||
import { ImageAddon } from 'xterm-addon-image';
|
import { ImageAddon } from 'xterm-addon-image';
|
||||||
|
import { CanvasAddon } from 'xterm-addon-canvas';
|
||||||
|
|
||||||
// 终端会话实现
|
// 终端会话实现
|
||||||
export default class TerminalSession implements ITerminalSession {
|
export default class TerminalSession implements ITerminalSession {
|
||||||
@@ -48,12 +49,13 @@ export default class TerminalSession implements ITerminalSession {
|
|||||||
this.inst = new Terminal({
|
this.inst = new Terminal({
|
||||||
...(preference.displaySetting as any),
|
...(preference.displaySetting as any),
|
||||||
theme: preference.theme.schema,
|
theme: preference.theme.schema,
|
||||||
fastScrollModifier: 'ctrl',
|
fastScrollModifier: 'alt',
|
||||||
fontFamily: preference.displaySetting.fontFamily + fontFamilySuffix,
|
fontFamily: preference.displaySetting.fontFamily + fontFamilySuffix,
|
||||||
});
|
});
|
||||||
// 注册插件
|
// 注册插件
|
||||||
this.addons.fit = new FitAddon();
|
this.addons.fit = new FitAddon();
|
||||||
this.addons.webgl = new WebglAddon();
|
// this.addons.webgl = new WebglAddon();
|
||||||
|
this.addons.canvas = new CanvasAddon();
|
||||||
this.addons.link = new WebLinksAddon();
|
this.addons.link = new WebLinksAddon();
|
||||||
this.addons.search = new SearchAddon();
|
this.addons.search = new SearchAddon();
|
||||||
this.addons.image = new ImageAddon();
|
this.addons.image = new ImageAddon();
|
||||||
|
|||||||
@@ -156,10 +156,13 @@ export const extraSshAuthTypeKey = 'hostExtraSshAuthType';
|
|||||||
// 终端状态
|
// 终端状态
|
||||||
export const connectStatusKey = 'terminalConnectStatus';
|
export const connectStatusKey = 'terminalConnectStatus';
|
||||||
|
|
||||||
|
// 终端类型
|
||||||
|
export const terminalEmulationTypeKey = 'terminalEmulationType';
|
||||||
|
|
||||||
// 加载的字典值
|
// 加载的字典值
|
||||||
export const dictKeys = [
|
export const dictKeys = [
|
||||||
fontFamilyKey,
|
fontFamilyKey, fontSizeKey,
|
||||||
fontSizeKey, fontWeightKey,
|
fontWeightKey, cursorStyleKey,
|
||||||
cursorStyleKey, newConnectionTypeKey,
|
newConnectionTypeKey, extraSshAuthTypeKey,
|
||||||
extraSshAuthTypeKey, connectStatusKey
|
connectStatusKey, terminalEmulationTypeKey
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { Terminal } from 'xterm';
|
import type { Terminal } from 'xterm';
|
||||||
import type { FitAddon } from 'xterm-addon-fit';
|
import type { FitAddon } from 'xterm-addon-fit';
|
||||||
|
import type { CanvasAddon } from 'xterm-addon-canvas';
|
||||||
import type { WebglAddon } from 'xterm-addon-webgl';
|
import type { WebglAddon } from 'xterm-addon-webgl';
|
||||||
import type { WebLinksAddon } from 'xterm-addon-web-links';
|
import type { WebLinksAddon } from 'xterm-addon-web-links';
|
||||||
import type { SearchAddon } from 'xterm-addon-search';
|
import type { SearchAddon } from 'xterm-addon-search';
|
||||||
@@ -117,6 +118,7 @@ export interface ITerminalOutputProcessor {
|
|||||||
export interface TerminalAddons {
|
export interface TerminalAddons {
|
||||||
fit: FitAddon;
|
fit: FitAddon;
|
||||||
webgl: WebglAddon;
|
webgl: WebglAddon;
|
||||||
|
canvas: CanvasAddon;
|
||||||
link: WebLinksAddon;
|
link: WebLinksAddon;
|
||||||
search: SearchAddon;
|
search: SearchAddon;
|
||||||
image: ImageAddon;
|
image: ImageAddon;
|
||||||
|
|||||||
Reference in New Issue
Block a user