🔨 修改终端逻辑.
This commit is contained in:
@@ -65,7 +65,7 @@ export default defineStore('terminal', {
|
||||
} as TerminalShortcutSetting,
|
||||
},
|
||||
hosts: {} as AuthorizedHostQueryResponse,
|
||||
tabManager: new TerminalTabManager(TerminalTabs.NEW_CONNECTION),
|
||||
tabManager: new TerminalTabManager(),
|
||||
panelManager: new TerminalPanelManager(),
|
||||
sessionManager: new TerminalSessionManager(),
|
||||
transferManager: new SftpTransferManager(),
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -180,6 +180,13 @@
|
||||
@click="emits('openUpdate', record)">
|
||||
修改
|
||||
</a-button>
|
||||
<!-- 配置 -->
|
||||
<a-button type="text"
|
||||
size="mini"
|
||||
v-permission="['asset:host:update-config']"
|
||||
@click="emits('openUpdateConfig', record)">
|
||||
配置
|
||||
</a-button>
|
||||
<!-- 删除 -->
|
||||
<a-popconfirm content="确认删除这条记录吗?"
|
||||
position="left"
|
||||
@@ -198,13 +205,6 @@
|
||||
更多
|
||||
</a-button>
|
||||
<template #content>
|
||||
<!-- 配置 -->
|
||||
<a-doption v-permission="['asset:host:update-config']"
|
||||
@click="emits('openUpdateConfig', record)">
|
||||
<span class="more-doption normal">
|
||||
配置
|
||||
</span>
|
||||
</a-doption>
|
||||
<!-- 修改状态 -->
|
||||
<a-doption v-permission="['asset:host:update-status']"
|
||||
@click="updateStatus(record)">
|
||||
|
||||
@@ -47,7 +47,7 @@ const columns = [
|
||||
}, {
|
||||
title: '操作',
|
||||
slotName: 'handle',
|
||||
width: 162,
|
||||
width: 192,
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
},
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
操作栏设置
|
||||
</h3>
|
||||
</div>
|
||||
<!-- 提示 -->
|
||||
<a-alert class="mb16">修改后会立刻保存, 立即生效 (无需刷新页面)</a-alert>
|
||||
<!-- 非安全环境提示 -->
|
||||
<a-alert v-if="!isSecureEnvironment"
|
||||
type="warning"
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
显示偏好
|
||||
</h3>
|
||||
</div>
|
||||
<!-- 提示 -->
|
||||
<a-alert class="mb16">修改后会立刻保存, 重新打开终端后生效 (无需刷新页面)</a-alert>
|
||||
<!-- 内容区域 -->
|
||||
<div class="terminal-setting-body block-body setting-body">
|
||||
<a-form class="terminal-setting-form"
|
||||
@@ -100,7 +98,7 @@
|
||||
<div class="terminal-example">
|
||||
<span class="vertical-form-label">预览效果</span>
|
||||
<div class="terminal-example-wrapper"
|
||||
:style="{ background: preference.theme.schema.background }">
|
||||
:style="{ background: background }">
|
||||
<terminal-example :schema="preference.theme.schema"
|
||||
ref="previewTerminal" />
|
||||
</div>
|
||||
@@ -117,22 +115,24 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { TerminalDisplaySetting } from '@/store/modules/terminal/types';
|
||||
import type { ISshSession } from '../../../types/define';
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
import { useDictStore, useTerminalStore } from '@/store';
|
||||
import { fontFamilyKey, fontSizeKey, fontWeightKey, cursorStyleKey } from '../../../types/const';
|
||||
import { fontFamilyKey, fontSizeKey, fontWeightKey, cursorStyleKey, PanelSessionType } from '../../../types/const';
|
||||
import { labelFilter } from '@/types/form';
|
||||
import { TerminalPreferenceItem } from '@/store/modules/terminal';
|
||||
import { defaultFontFamily } from '@/types/xterm';
|
||||
import TerminalExample from '../terminal-example.vue';
|
||||
|
||||
const { toOptions, toRadioOptions } = useDictStore();
|
||||
const { preference, updateTerminalPreference } = useTerminalStore();
|
||||
const { preference, updateTerminalPreference, sessionManager } = useTerminalStore();
|
||||
|
||||
const background = preference.theme.schema.background;
|
||||
const previewTerminal = ref();
|
||||
const formModel = ref<TerminalDisplaySetting>({});
|
||||
|
||||
// 监听内容变化
|
||||
watch(formModel, (v) => {
|
||||
watch(formModel, (v, before) => {
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
@@ -149,6 +149,26 @@
|
||||
options[key] = (formModel.value as any)[key];
|
||||
}
|
||||
});
|
||||
// 非初始化则修改终端样式
|
||||
if (before) {
|
||||
Object.values(sessionManager.sessions)
|
||||
.filter(s => s.type === PanelSessionType.SSH.type)
|
||||
.map(s => s as ISshSession)
|
||||
.forEach(s => {
|
||||
const options = s.inst.options;
|
||||
s.inst;
|
||||
// 修改样式
|
||||
Object.keys(v).forEach(k => {
|
||||
let value = v[k as keyof TerminalDisplaySetting];
|
||||
if (k === 'fontFamily') {
|
||||
value = value === '_' ? defaultFontFamily : `${value}, ${defaultFontFamily}`;
|
||||
}
|
||||
options[k as keyof typeof options] = value;
|
||||
});
|
||||
// 自适应
|
||||
s.fit();
|
||||
});
|
||||
}
|
||||
// 同步
|
||||
updateTerminalPreference(TerminalPreferenceItem.DISPLAY_SETTING, formModel.value, true);
|
||||
// 聚焦
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</h3>
|
||||
</div>
|
||||
<!-- 提示 -->
|
||||
<a-alert class="mb16">修改后会立刻保存, 重新打开终端后生效 (无需刷新页面)</a-alert>
|
||||
<a-alert class="mb16">修改后会立刻保存, 重新打开终端后生效</a-alert>
|
||||
<!-- 非安全环境提示 -->
|
||||
<a-alert v-if="!isSecureEnvironment"
|
||||
type="warning"
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
</a-skeleton>
|
||||
<!-- 内容区域 -->
|
||||
<div v-else class="terminal-setting-body terminal-theme-container">
|
||||
<!-- 提示 -->
|
||||
<a-alert class="mb16">选择后会立刻保存, 刷新页面后生效</a-alert>
|
||||
<!-- 终端主题 -->
|
||||
<div class="theme-row"
|
||||
v-for="(themeArr, index) in themes"
|
||||
@@ -57,15 +55,17 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { TerminalTheme } from '@/api/asset/host-terminal';
|
||||
import type { ISshSession } from '../../../types/define';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { TerminalPreferenceItem } from '@/store/modules/terminal';
|
||||
import { PanelSessionType } from '../../../types/const';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { getTerminalThemes } from '@/api/asset/host-terminal';
|
||||
import { getPreference } from '@/api/user/preference';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import TerminalExample from '../terminal-example.vue';
|
||||
|
||||
const { updateTerminalPreference } = useTerminalStore();
|
||||
const { updateTerminalPreference, sessionManager } = useTerminalStore();
|
||||
const { loading, setLoading } = useLoading();
|
||||
|
||||
const currentThemeName = ref();
|
||||
@@ -73,8 +73,20 @@
|
||||
|
||||
// 选择主题
|
||||
const selectTheme = async (theme: TerminalTheme) => {
|
||||
// 修改主题色
|
||||
document.body.setAttribute('terminal-theme', theme.dark ? 'dark' : 'light');
|
||||
// 修改终端主题
|
||||
Object.values(sessionManager.sessions)
|
||||
.filter(s => s.type === PanelSessionType.SSH.type)
|
||||
.map(s => s as ISshSession)
|
||||
.forEach(s => {
|
||||
s.inst.options.theme = theme.schema;
|
||||
// 自适应
|
||||
s.blur();
|
||||
});
|
||||
// 同步
|
||||
currentThemeName.value = theme.name;
|
||||
await updateTerminalPreference(TerminalPreferenceItem.THEME, theme);
|
||||
await updateTerminalPreference(TerminalPreferenceItem.THEME, theme, true);
|
||||
};
|
||||
|
||||
// 加载用户主题
|
||||
|
||||
@@ -128,7 +128,7 @@ export default class SshSession extends BaseSession implements ISshSession {
|
||||
// 启用响铃
|
||||
if (preference.interactSetting.enableBell) {
|
||||
this.inst.onBell(() => {
|
||||
// 播放蜂鸣
|
||||
// 播放响铃
|
||||
playBell();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<!-- 内容区域 -->
|
||||
<main class="host-terminal-layout-content">
|
||||
<!-- 主机加载中骨架 -->
|
||||
<loading-skeleton v-if="contentLoading" />
|
||||
<loading-skeleton v-if="loading" />
|
||||
<!-- 终端内容区域 -->
|
||||
<main-content v-else
|
||||
@open-command-snippet="() => snippetRef.open()"
|
||||
@@ -49,8 +49,10 @@
|
||||
import { ref, onBeforeMount, onUnmounted, onMounted } from 'vue';
|
||||
import { dictKeys, PanelSessionType, TerminalTabs } from './types/const';
|
||||
import { useCacheStore, useDictStore, useTerminalStore } from '@/store';
|
||||
import { useRoute } from 'vue-router';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import debug from '@/utils/env';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import LayoutHeader from './components/layout/layout-header.vue';
|
||||
import LeftSidebar from './components/layout/left-sidebar.vue';
|
||||
import RightSidebar from './components/layout/right-sidebar.vue';
|
||||
@@ -62,10 +64,9 @@
|
||||
import '@/assets/style/host-terminal-layout.less';
|
||||
import '@xterm/xterm/css/xterm.css';
|
||||
|
||||
const terminalStore = useTerminalStore();
|
||||
const dictStore = useDictStore();
|
||||
const cacheStore = useCacheStore();
|
||||
const { loading: contentLoading, setLoading: setContentLoading } = useLoading(true);
|
||||
const { fetchPreference, getCurrentSession, openSession, preference, loadHosts, hosts, tabManager } = useTerminalStore();
|
||||
const { loading, setLoading } = useLoading(true);
|
||||
const route = useRoute();
|
||||
|
||||
const originTitle = document.title;
|
||||
const render = ref(false);
|
||||
@@ -75,7 +76,7 @@
|
||||
|
||||
// 终端截屏
|
||||
const screenshot = () => {
|
||||
const handler = terminalStore.getCurrentSession<ISshSession>(PanelSessionType.SSH.type, true)?.handler;
|
||||
const handler = getCurrentSession<ISshSession>(PanelSessionType.SSH.type, true)?.handler;
|
||||
if (handler && handler.enabledStatus('screenshot')) {
|
||||
handler.screenshot();
|
||||
}
|
||||
@@ -87,27 +88,53 @@
|
||||
event.returnValue = confirm('系统可能不会保存您所做的更改');
|
||||
};
|
||||
|
||||
// 打开默认打开页面
|
||||
onBeforeMount(() => {
|
||||
// 打开默认 tab
|
||||
let openTab;
|
||||
const tab = route.query.tab;
|
||||
if (tab) {
|
||||
openTab = Object.values(TerminalTabs).find(s => s.key === tab);
|
||||
}
|
||||
tabManager.openTab(openTab || TerminalTabs.NEW_CONNECTION);
|
||||
});
|
||||
|
||||
// 加载用户终端偏好
|
||||
onBeforeMount(async () => {
|
||||
await terminalStore.fetchPreference();
|
||||
// 加载偏好
|
||||
await fetchPreference();
|
||||
// 设置系统主题配色
|
||||
const dark = terminalStore.preference.theme.dark;
|
||||
const dark = preference.theme.dark;
|
||||
document.body.setAttribute('terminal-theme', dark ? 'dark' : 'light');
|
||||
render.value = true;
|
||||
});
|
||||
|
||||
// 加载字典值
|
||||
onBeforeMount(async () => {
|
||||
await dictStore.loadKeys(dictKeys);
|
||||
await useDictStore().loadKeys(dictKeys);
|
||||
});
|
||||
|
||||
// 加载主机信息
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await terminalStore.loadHosts();
|
||||
// 加载主机
|
||||
await loadHosts();
|
||||
// 默认连接主机
|
||||
const connect = route.query.connect;
|
||||
if (connect) {
|
||||
const connectHostId = Number.parseInt(connect as string);
|
||||
const connectHost = hosts.hostList.find(s => s.id === connectHostId);
|
||||
// 打开连接
|
||||
if (connectHost) {
|
||||
const type = Object.values(PanelSessionType).find(s => s.type === route.query.type) || PanelSessionType.SSH;
|
||||
openSession(connectHost, type);
|
||||
} else {
|
||||
Message.error(`主机 ${connectHostId} 不存在/无权限`);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setContentLoading(false);
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -124,7 +151,7 @@
|
||||
// 卸载处理
|
||||
onUnmounted(() => {
|
||||
// 卸载时清除 cache
|
||||
cacheStore.reset('authorizedHostKeys', 'authorizedHostIdentities', 'commandSnippetGroups', 'pathBookmarkGroups');
|
||||
useCacheStore().reset('authorizedHostKeys', 'authorizedHostIdentities', 'commandSnippetGroups', 'pathBookmarkGroups');
|
||||
// 移除关闭视口事件
|
||||
window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||
// 去除 body style
|
||||
|
||||
Reference in New Issue
Block a user