feat: 新建连接.

This commit is contained in:
lijiahangmax
2023-12-13 23:59:31 +08:00
parent f2ca6abcb0
commit 31d6f20bab
19 changed files with 7072 additions and 4544 deletions

View File

@@ -33,4 +33,7 @@ public class AuthorizedHostWrapperVO {
@Schema(description = "分组树节点映射 'groupId':hostIdList")
private Map<String, Set<Long>> treeNodes;
// TODO 我的收藏
// TODO 最近连接
}

View File

@@ -33,12 +33,6 @@
"@dangojs/a-query-header": "^0.0.31",
"@sanqi377/arco-vue-icon-picker": "^1.0.7",
"@vueuse/core": "^9.3.0",
"@xterm/addon-canvas": "0.6.0-beta.14",
"@xterm/addon-fit": "0.9.0-beta.14",
"@xterm/addon-search": "0.14.0-beta.14",
"@xterm/addon-web-links": "0.10.0-beta.1",
"@xterm/addon-webgl": "0.17.0-beta.14",
"@xterm/xterm": "5.4.0-beta.14",
"axios": "^0.24.0",
"dayjs": "^1.11.5",
"echarts": "^5.4.0",
@@ -53,7 +47,14 @@
"vue": "^3.2.40",
"vue-echarts": "^6.2.3",
"vue-i18n": "^9.2.2",
"vue-router": "^4.0.14"
"vue-router": "^4.0.14",
"xterm": "^5.3.0",
"xterm-addon-canvas": "^0.5.0",
"xterm-addon-fit": "^0.8.0",
"xterm-addon-image": "^0.5.0",
"xterm-addon-search": "^0.13.0",
"xterm-addon-web-links": "^0.9.0",
"xterm-addon-webgl": "^0.16.0"
},
"devDependencies": {
"@arco-plugins/vite-vue": "^1.4.5",

11399
orion-ops-ui/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -76,7 +76,8 @@ body {
.sticky-list {
.arco-list-header {
position: sticky;
background: var(--color-bg-2);
background: var(--color-fill-2);
border-bottom: none;
top: 0;
}
}

View File

@@ -10,6 +10,9 @@ const HOST_OPS: AppRouteRecordRaw = {
name: 'hostTerminal',
path: '/host/terminal',
component: () => import('@/views/host-ops/terminal/index.vue'),
meta: {
noAffix: true
}
},
],
};

View File

@@ -20,9 +20,9 @@ export interface TerminalThemeSchema {
foreground: string;
cursor: string;
cursorAccent?: string;
selectionInactiveBackground?: string;
selectionBackground?: string;
selectionForeground?: string;
selectionInactiveBackground?: string;
black: string;
red: string;
green: string;

View File

@@ -205,21 +205,26 @@ body[terminal-theme='dark'] .host-layout {
// 终端设置容器
.terminal-setting-container {
padding: 32px 16px;
width: max-content;
padding: 32px 16px 16px 16px;
width: fit-content;
margin: auto;
display: flex;
flex-direction: column;
.terminal-setting-wrapper {
min-width: 932px;
}
.terminal-setting-title {
margin: 0 0 24px 0;
user-select: none;
font-size: 1.65em;
color: var(--color-content-text-3);
}
.terminal-setting-block {
color: var(--color-content-text-2);
margin-bottom: 18px;
margin-bottom: 24px;
}
.terminal-setting-subtitle-wrapper {
@@ -229,13 +234,13 @@ body[terminal-theme='dark'] .host-layout {
}
.terminal-setting-subtitle {
margin: 0;
margin: 0 0 16px 0;
user-select: none;
color: var(--color-content-text-3);
}
.terminal-setting-body {
margin: 16px 0 24px 0;
display: flex;
}
}

View File

@@ -8,12 +8,11 @@
arrow-class="terminal-tooltip-arrow"
:content="action.content">
<div class="terminal-sidebar-icon-wrapper"
v-if="action.visible !== false"
:style="action?.style">
v-if="action.visible !== false">
<div class="terminal-sidebar-icon"
:class="iconClass"
@click="action.click">
<component :is="action.icon" />
<component :is="action.icon" :style="action?.iconStyle" />
</div>
</div>
</a-tooltip>

View File

@@ -7,9 +7,12 @@
:title="tab.title">
<!-- 设置 -->
<template v-if="tab.type === TabType.SETTING">
<!-- 新建连接 -->
<new-connection-view v-if="tab.key === InnerTabs.NEW_CONNECTION.key" />
<!-- 显示设置 -->
<terminal-view-setting v-if="tab.key === InnerTabs.THEME_SETTING.key" />
<terminal-view-setting v-else-if="tab.key === InnerTabs.THEME_SETTING.key" />
<span v-else>
{{ tab.key }}
{{ tab.title }}
</span>
</template>
@@ -37,6 +40,7 @@
import { computed } from 'vue';
import { TabType, InnerTabs } from '../../types/terminal.const';
import TerminalViewSetting from '../view-setting/terminal-view-setting.vue';
import NewConnectionView from '@/views/host-ops/terminal/components/new-connection/new-connection-view.vue';
const props = defineProps({
modelValue: {

View File

@@ -2,6 +2,10 @@
<div class="terminal-header">
<!-- 左侧 logo -->
<div class="terminal-header-left">
<img alt="logo"
class="terminal-header-logo-img"
draggable="false"
src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/dfdba5317c0c20ce20e64fac803d52bc.svg~tplv-49unhts6dw-image.image" />
<h5 class="terminal-header-logo-text">Orion Ops Pro</h5>
</div>
<!-- 左侧 tabs -->
@@ -105,7 +109,7 @@
<style lang="less" scoped>
.terminal-header {
--logo-width: 150px;
--logo-width: 168px;
--right-avatar-width: calc(28px * 5 - 7px * 4);
--right-action-width: calc(var(--header-height) * 3);
}
@@ -118,6 +122,15 @@
&-left {
width: var(--logo-width);
display: flex;
align-items: center;
justify-content: flex-start;
}
&-logo-img {
padding-left: 6px;
width: 36px;
height: 36px;
}
&-logo-text {
@@ -125,7 +138,7 @@
margin: 0;
display: flex;
align-items: center;
padding-left: 16px;
padding: 0 8px;
font-size: 16px;
}

View File

@@ -29,7 +29,7 @@
{
icon: 'icon-plus',
content: '新建连接',
click: () => emits('switchTab', InnerTabs.HOST_LIST)
click: () => emits('switchTab', InnerTabs.NEW_CONNECTION)
},
{
icon: 'icon-copy',

View File

@@ -28,19 +28,17 @@
{
icon: 'icon-code-block',
content: '打开命令片段',
style: {},
click: () => emits('openSnippet')
},
{
icon: 'icon-folder',
content: '打开 SFTP',
style: {},
click: () => emits('openSftp')
},
{
icon: 'icon-swap',
content: '文件传输列表',
style: {
iconStyle: {
transform: 'rotate(90deg)'
},
click: () => emits('openTransfer')
@@ -58,7 +56,6 @@
{
icon: 'icon-camera',
content: '截图',
style: {},
click: () => emits('screenshot')
},
];

View File

@@ -0,0 +1,86 @@
<template>
<div class="terminal-setting-container">
<div class="terminal-setting-wrapper">
<!-- 主标题 -->
<h2 class="terminal-setting-title">新建连接</h2>
<!-- 操作栏 -->
<div class="terminal-setting-block header-actions">
<a-radio-group type="button">
<a-radio value="1">分组</a-radio>
<a-radio value="2">列表</a-radio>
<a-radio value="3">最近连接</a-radio>
</a-radio-group>
<a-input-search class="host-filter"
placeholder="输入名称/编码/IP 进行过滤" />
</div>
<!-- 授权主机 -->
<div class="terminal-setting-block">
<!-- 顶部 -->
<div class="terminal-setting-subtitle-wrapper">
<h3 class="terminal-setting-subtitle">
授权主机
</h3>
</div>
<!-- 内容区域 -->
<div class="terminal-setting-body hosts-container">
<div class="host-tree">
<a-tree :data="hosts.groupTree"
:blockNode="true"
>
</a-tree>
{{ }}
</div>
<div class="host-list">
{{ hosts.treeNodes }}
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
export default {
name: 'newConnectionView'
};
</script>
<script lang="ts" setup>
import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
import { getCurrentAuthorizedHost } from '@/api/asset/asset-authorized-data';
import { onMounted, ref } from 'vue';
const hosts = ref<AuthorizedHostQueryResponse>({} as AuthorizedHostQueryResponse);
onMounted(async () => {
const { data } = await getCurrentAuthorizedHost();
hosts.value = data;
});
</script>
<style lang="less" scoped>
.header-actions {
display: flex;
align-items: center;
justify-content: space-between;
.host-filter {
width: 40%;
}
}
.hosts-container {
justify-content: space-between;
.host-tree {
margin-right: 16px;
width: 350px;
}
.host-list {
width: 490px;
}
}
</style>

View File

@@ -10,7 +10,7 @@
<script lang="ts" setup>
import type { TerminalThemeSchema } from '@/store/modules/terminal/types';
import { Terminal } from '@xterm/xterm';
import { Terminal } from 'xterm';
import { onMounted, onUnmounted, ref } from 'vue';
const props = defineProps<{
@@ -23,7 +23,7 @@
onMounted(() => {
term.value = new Terminal({
theme: props.theme,
cols: 47,
cols: 42,
rows: 6,
fontSize: 15,
cursorInactiveStyle: 'none',
@@ -35,7 +35,7 @@
'dr-xr-xr-x. 2 root root sbin\r\n' +
'dr-xr-xr-x. 43 root root lib\r\n' +
'dr-xr-xr-x. 62 root root lib64\r\n' +
'lrwxrwxrwx. 1 root root tmp'
'lrwxrwxrwx. 1 root root tmp'
);
});

View File

@@ -15,7 +15,7 @@
</a-radio-group>
</div>
<!-- 内容区域 -->
<div class="terminal-setting-body">
<div class="terminal-setting-body terminal-theme-container">
<div class="theme-row"
v-for="index in ThemeSchema.length / 2"
:key="index">
@@ -101,9 +101,13 @@
@terminal-width: 458px;
@terminal-height: 138px;
.theme-row {
display: flex;
margin-bottom: 16px;
.terminal-theme-container {
flex-direction: column;
.theme-row {
display: flex;
margin-bottom: 16px;
}
}
.terminal-theme-card {

View File

@@ -1,6 +1,6 @@
<template>
<div class="terminal-setting-container view-setting-container">
<div class="view-setting-wrapper">
<div class="terminal-setting-container">
<div class="terminal-setting-wrapper">
<!-- 主标题 -->
<h2 class="terminal-setting-title">外观设置</h2>
<!-- 显示设置 -->
@@ -24,8 +24,5 @@
</script>
<style lang="less" scoped>
.view-setting-wrapper {
width: 932px;
}
</style>

View File

@@ -42,14 +42,14 @@
import TerminalRightSidebar from './components/layout/terminal-right-sidebar.vue';
import TerminalContent from './components/layout/terminal-content.vue';
import './assets/styles/layout.less';
import '@xterm/xterm/css/xterm.css';
import 'xterm/css/xterm.css';
const terminalStore = useTerminalStore();
const dictStore = useDictStore();
const render = ref(false);
const activeKey = ref(InnerTabs.THEME_SETTING.key);
const tabs = ref<Array<TabItem>>([InnerTabs.THEME_SETTING]);
const activeKey = ref(InnerTabs.NEW_CONNECTION.key);
const tabs = ref<Array<TabItem>>([InnerTabs.NEW_CONNECTION]);
for (let i = 0; i < 3; i++) {
tabs.value.push({
key: `host${i}`,
@@ -125,7 +125,7 @@
}
&-content {
width: 100%;
width: calc(100% - var(--sidebar-width) * 2);
height: 100%;
background: var(--color-bg-content);
overflow: auto;

View File

@@ -4,7 +4,7 @@ import type { CSSProperties } from 'vue';
export interface SidebarAction {
icon: string;
content: string;
style?: CSSProperties;
iconStyle?: CSSProperties;
visible?: boolean;
click: () => void;
}
@@ -17,8 +17,8 @@ export const TabType = {
// 内置 tab
export const InnerTabs = {
HOST_LIST: {
key: 'hostList',
NEW_CONNECTION: {
key: 'newConnection',
title: '新建连接',
type: TabType.SETTING
},

View File

@@ -8,9 +8,9 @@ export const DEFAULT_SCHEMA = {
foreground: '#C6D0F5',
cursor: '#F2D5CF',
cursorAccent: '#232634',
// selectionInactiveBackground: 'rgba(98, 104, 128, 0.30078125)',
selectionBackground: '#C9DDF0',
selectionForeground: '#303446',
// selectionInactiveBackground: 'rgba(98, 104, 128, 0.30078125)',
black: '#51576D',
red: '#E78284',
green: '#A6D189',
@@ -38,9 +38,9 @@ export default [
foreground: '#4C4F69',
cursor: '#DC8A78',
cursorAccent: '#EFF1F5',
// selectionInactiveBackground: 'rgba(172, 176, 190, 0.30078125)',
selectionForeground: '#EFF1F5',
selectionBackground: '#6C6F85',
selectionForeground: '#EFF1F5',
// selectionInactiveBackground: 'rgba(172, 176, 190, 0.30078125)',
black: '#5C5F77',
red: '#D20F39',
green: '#40A02B',
@@ -65,9 +65,9 @@ export default [
foreground: '#CAD3F5',
cursor: '#F4DBD6',
cursorAccent: '#181926',
// selectionInactiveBackground: 'rgba(91, 96, 120, 0.30078125)',
selectionForeground: '#24273A',
selectionBackground: '#A5ADCB',
selectionForeground: '#24273A',
// selectionInactiveBackground: 'rgba(91, 96, 120, 0.30078125)',
black: '#494D64',
red: '#ED8796',
green: '#A6DA95',
@@ -92,9 +92,9 @@ export default [
foreground: '#CDD6F4',
cursor: '#F5E0DC',
cursorAccent: '#11111B',
// selectionInactiveBackground: 'rgba(88, 91, 112, 0.30078125)',
selectionForeground: '#1E1E2E',
selectionBackground: '#A6ADC8',
selectionForeground: '#1E1E2E',
// selectionInactiveBackground: 'rgba(88, 91, 112, 0.30078125)',
black: '#45475A',
red: '#F38BA8',
green: '#A6E3A1',
@@ -163,8 +163,8 @@ export default [
foreground: '#F8F8F2',
cursor: '#F8F8F2',
cursorAccent: '#282A36',
selectionForeground: '#44475A',
selectionBackground: '#50FA7B',
selectionForeground: '#44475A',
black: '#21222C',
red: '#FF5555',
green: '#50FA7B',