feat: 终端截屏.

This commit is contained in:
lijiahangmax
2024-01-17 22:15:25 +08:00
parent 9d8fddd9ae
commit bf3211bf1b
6 changed files with 61 additions and 33 deletions

View File

@@ -19,9 +19,27 @@
<script lang="ts" setup>
import type { SidebarAction } from '../../types/terminal.type';
import { useTerminalStore } from '@/store';
import { TerminalTabType } from '../../types/terminal.const';
import IconActions from './icon-actions.vue';
import { Message } from '@arco-design/web-vue';
const emits = defineEmits(['openSnippet', 'openSftp', 'openTransfer', 'screenshot']);
const emits = defineEmits(['openSnippet', 'openSftp', 'openTransfer']);
const { tabManager, sessionManager } = useTerminalStore();
// 终端截屏
const screenshot = () => {
const tab = tabManager.getCurrentTab();
if (!tab || tab.type !== TerminalTabType.TERMINAL) {
Message.warning('请切换到终端标签页');
return;
}
// 获取处理器并截图
sessionManager.getSession(tab.key)
?.handler
?.screenshot();
};
// 顶部操作
const topActions = [
@@ -50,7 +68,7 @@
{
icon: 'icon-camera',
content: '截图',
click: () => emits('screenshot')
click: screenshot
},
];

View File

@@ -4,6 +4,9 @@ import type { Terminal } from 'xterm';
import useCopy from '@/hooks/copy';
import { useTerminalStore } from '@/store';
import { InnerTabs } from '../types/terminal.const';
import html2canvas from 'html2canvas';
import { saveAs } from 'file-saver';
import { Message } from '@arco-design/web-vue';
const { copy: copyValue, readText } = useCopy();
@@ -178,6 +181,29 @@ export default class TerminalSessionHandler implements ITerminalSessionHandler {
this.session.disconnect();
}
// 截图
async screenshot() {
try {
// 获取截屏
const canvas = await html2canvas(this.inst.element as HTMLElement, {
useCORS: true,
backgroundColor: 'transparent',
});
// 保存图片
const blob = await new Promise((resolve, reject) => {
canvas.toBlob((blob) => {
if (!blob) {
reject();
}
resolve(blob);
}, 'image/png');
});
saveAs(blob as Blob, `screenshot-${Date.now()}.png`);
} catch (e) {
Message.error('保存失败');
}
}
// 关闭 tab
closeTab() {
this.tabManager.deleteTab(this.session.sessionId);

View File

@@ -157,7 +157,7 @@ export default class TerminalSession implements ITerminalSession {
}
if (preference.pluginsSetting.enableWebglPlugin) {
// WebGL 渲染插件
this.addons.webgl = new WebglAddon();
this.addons.webgl = new WebglAddon(true);
} else {
// canvas 渲染插件
this.addons.canvas = new CanvasAddon();

View File

@@ -13,6 +13,14 @@ export default class TerminalTabManager implements ITerminalTabManager {
this.items = [InnerTabs.NEW_CONNECTION];
}
// 获取当前 tab
getCurrentTab() {
if (!this.active) {
return undefined;
}
return this.items.find(s => s.key === this.active);
}
// 点击 tab
clickTab(key: string): void {
this.active = key;

View File

@@ -11,7 +11,7 @@
<terminal-left-sidebar />
</div>
<!-- 内容区域 -->
<div class="host-layout-content" ref="content">
<div class="host-layout-content">
<!-- 主机加载中骨架 -->
<loading-skeleton v-if="contentLoading" />
<!-- 终端内容区域 -->
@@ -19,7 +19,7 @@
</div>
<!-- 右侧操作栏 -->
<div class="host-layout-right">
<terminal-right-sidebar @screenshot="screenshotTerminal" />
<terminal-right-sidebar />
</div>
</main>
</div>
@@ -41,11 +41,8 @@
import TerminalRightSidebar from './components/layout/terminal-right-sidebar.vue';
import TerminalContent from './components/layout/terminal-content.vue';
import LoadingSkeleton from './components/layout/loading-skeleton.vue';
import html2canvas from 'html2canvas';
import { saveAs } from 'file-saver';
import './assets/styles/layout.less';
import 'xterm/css/xterm.css';
import { Message } from '@arco-design/web-vue';
const terminalStore = useTerminalStore();
const dictStore = useDictStore();
@@ -54,7 +51,6 @@
const originTitle = document.title;
const render = ref(false);
const content = ref();
// 关闭视口处理
const handleBeforeUnload = (event: any) => {
@@ -62,30 +58,6 @@
event.returnValue = confirm('系统可能不会保存您所做的更改');
};
// 终端截图
// FIXME test 水印
const screenshotTerminal = async () => {
try {
console.log(content.value);
const canvas = await html2canvas(content.value, {
useCORS: true,
backgroundColor: 'transparent',
});
console.log(canvas);
const blob = await new Promise((resolve, reject) => {
canvas.toBlob((blob) => {
if (!blob) {
reject(new Error('截屏失败'));
}
resolve(blob);
}, 'image/png');
});
saveAs(blob, `screenshot-${Date.now()}.png`);
} catch (e) {
Message.error('保存失败');
}
};
// 加载用户终端偏好
onBeforeMount(async () => {
await terminalStore.fetchPreference();

View File

@@ -98,6 +98,8 @@ export interface ITerminalTabManager {
// 全部 tab
items: Array<TerminalTabItem>;
// 获取当前 tab
getCurrentTab: () => TerminalTabItem | undefined;
// 点击 tab
clickTab: (key: string) => void;
// 删除 tab
@@ -236,6 +238,8 @@ export interface ITerminalSessionHandler {
clear: () => void;
// 断开连接
disconnect: () => void;
// 截图
screenshot: () => void;
// 关闭 tab
closeTab: () => void;
// 切换到前一个 tab