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