✨ 完善终端UI与逻辑
This commit is contained in:
parent
6a13c961c3
commit
851d063773
@ -5,14 +5,12 @@ import CryptoJS from 'crypto-js'
|
||||
|
||||
export const EventBus = reactive({})
|
||||
|
||||
// 在组件中触发事件
|
||||
EventBus.$emit = (event, data) => {
|
||||
if (EventBus[event]) {
|
||||
EventBus[event].forEach(callback => callback(data))
|
||||
}
|
||||
}
|
||||
|
||||
// 在组件中监听事件
|
||||
EventBus.$on = (event, callback) => {
|
||||
if (!EventBus[event]) {
|
||||
EventBus[event] = []
|
||||
|
@ -1,17 +1,6 @@
|
||||
<template>
|
||||
<div class="info_container" :style="{ width: visible ? `250px` : 0 }">
|
||||
<header>
|
||||
<a href="/">
|
||||
<img src="@/assets/logo-easynode.png" alt="logo">
|
||||
</a>
|
||||
<!-- <div class="visible" @click="visibleSidebar">
|
||||
<svg-icon
|
||||
name="icon-xianshi"
|
||||
class="svg-icon"
|
||||
/>
|
||||
</div> -->
|
||||
</header>
|
||||
<el-divider class="first-divider" content-position="center">地理位置</el-divider>
|
||||
<!-- <el-divider class="first-divider" content-position="center">地理位置</el-divider> -->
|
||||
<el-descriptions
|
||||
class="margin-top"
|
||||
:column="1"
|
||||
@ -47,7 +36,9 @@
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider content-position="center">实时监控</el-divider>
|
||||
<!-- <el-divider content-position="center">实时监控</el-divider> -->
|
||||
<br>
|
||||
|
||||
<el-descriptions
|
||||
class="margin-top"
|
||||
:column="1"
|
||||
@ -118,7 +109,9 @@
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider content-position="center">系统信息</el-divider>
|
||||
<!-- <el-divider content-position="center">系统信息</el-divider> -->
|
||||
<br>
|
||||
|
||||
<el-descriptions
|
||||
class="margin-top"
|
||||
:column="1"
|
||||
@ -188,13 +181,13 @@
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider content-position="center">FEATURE</el-divider>
|
||||
<el-button
|
||||
<!-- <el-button
|
||||
:type="sftpStatus ? 'primary' : 'success'"
|
||||
style="display: block;width: 80%;margin: 30px auto;"
|
||||
@click="handleSftp"
|
||||
>
|
||||
{{ sftpStatus ? '关闭SFTP' : '连接SFTP' }}
|
||||
</el-button>
|
||||
</el-button> -->
|
||||
<el-button
|
||||
:type="inputCommandStyle ? 'primary' : 'success'"
|
||||
style="display: block;width: 80%;margin: 30px auto;"
|
||||
@ -267,10 +260,10 @@ const inputCommandStyle = computed({
|
||||
}
|
||||
})
|
||||
|
||||
const handleSftp = () => {
|
||||
sftpStatus.value = !sftpStatus.value
|
||||
emit('connect-sftp', sftpStatus.value)
|
||||
}
|
||||
// const handleSftp = () => {
|
||||
// sftpStatus.value = !sftpStatus.value
|
||||
// emit('connect-sftp', sftpStatus.value)
|
||||
// }
|
||||
|
||||
const clickInputCommand = () => {
|
||||
inputCommandStyle.value = true
|
||||
@ -353,24 +346,25 @@ onBeforeUnmount(() => {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.info_container {
|
||||
// border-top: 1px solid var(--el-border-color);
|
||||
flex-shrink: 0;
|
||||
overflow: scroll;
|
||||
background-color: #fff; //#E0E2EF;
|
||||
transition: all 0.15s;
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 30px;
|
||||
margin: 10px;
|
||||
position: relative;
|
||||
// header {
|
||||
// display: flex;
|
||||
// justify-content: space-between;
|
||||
// align-items: center;
|
||||
// height: 30px;
|
||||
// margin: 10px;
|
||||
// position: relative;
|
||||
|
||||
img {
|
||||
cursor: pointer;
|
||||
height: 80%;
|
||||
}
|
||||
}
|
||||
// img {
|
||||
// cursor: pointer;
|
||||
// height: 80%;
|
||||
// }
|
||||
// }
|
||||
|
||||
// 表格中系统标识的title
|
||||
.item-title {
|
||||
|
@ -533,6 +533,7 @@ const getPath = (name = '') => {
|
||||
.sftp_tab_container {
|
||||
position: relative;
|
||||
background: #ffffff;
|
||||
border: 1px solid var(--el-border-color);
|
||||
.adjust {
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
|
@ -1,12 +1,28 @@
|
||||
<template>
|
||||
<div class="terminal_wrap">
|
||||
<InfoSide
|
||||
ref="infoSideRef"
|
||||
v-model:show-input-command="showInputCommand"
|
||||
:host-info="curHost"
|
||||
:visible="visible"
|
||||
@click-input-command="clickInputCommand"
|
||||
/>
|
||||
<div class="info_box">
|
||||
<div class="top">
|
||||
<el-dropdown trigger="click">
|
||||
<div class="action_wrap">
|
||||
<span class="link_host">连接<el-icon class="el-icon--right"><arrow-down /></el-icon></span>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="(item, index) in hostList" :key="index" @click="handleCommandHost(item)">
|
||||
{{ item.name }} {{ item.host }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<InfoSide
|
||||
ref="infoSideRef"
|
||||
v-model:show-input-command="showInputCommand"
|
||||
:host-info="curHost"
|
||||
:visible="visible"
|
||||
@click-input-command="clickInputCommand"
|
||||
/>
|
||||
</div>
|
||||
<div class="terminals_sftp_wrap">
|
||||
<!-- <el-button class="full-screen-button" type="success" @click="handleFullScreen">
|
||||
{{ isFullScreen ? '退出全屏' : '全屏' }}
|
||||
@ -40,13 +56,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineEmits, computed, defineProps, getCurrentInstance, watch, onMounted } from 'vue'
|
||||
import { ref, defineEmits, computed, defineProps, getCurrentInstance, watch, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { ArrowDown } from '@element-plus/icons-vue'
|
||||
import TerminalTab from './terminal-tab.vue'
|
||||
import InfoSide from './info-side.vue'
|
||||
import Sftp from './sftp.vue'
|
||||
import InputCommand from '@/components/input-command/index.vue'
|
||||
|
||||
const { proxy: { $nextTick } } = getCurrentInstance()
|
||||
const { proxy: { $nextTick, $store } } = getCurrentInstance()
|
||||
|
||||
const props = defineProps({
|
||||
terminalTabs: {
|
||||
@ -55,13 +72,12 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['closed', 'removeTab',])
|
||||
const emit = defineEmits(['closed', 'removeTab', 'add-host',])
|
||||
|
||||
const activeTabIndex = ref(0)
|
||||
// const terminalTabs = reactive([])
|
||||
const isFullScreen = ref(false)
|
||||
const timer = ref(null)
|
||||
const showSftp = ref(false)
|
||||
const showInputCommand = ref(false)
|
||||
const visible = ref(true)
|
||||
const infoSideRef = ref(null)
|
||||
@ -71,15 +87,29 @@ let mainHeight = ref('')
|
||||
const terminalTabs = computed(() => props.terminalTabs)
|
||||
const terminalTabsLen = computed(() => props.terminalTabs.length)
|
||||
const curHost = computed(() => terminalTabs.value[activeTabIndex.value])
|
||||
let hostList = computed(() => $store.hostList)
|
||||
|
||||
// const closable = computed(() => terminalTabs.length > 1)
|
||||
|
||||
onMounted(() => {
|
||||
$nextTick(() => {
|
||||
mainHeight.value = document.querySelector('.terminals_sftp_wrap').offsetHeight - 45 // 45 is tab-header height+10
|
||||
})
|
||||
handleResizeTerminalSftp()
|
||||
window.addEventListener('resize', handleResizeTerminalSftp)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', handleResizeTerminalSftp)
|
||||
})
|
||||
|
||||
function handleResizeTerminalSftp() {
|
||||
$nextTick(() => {
|
||||
mainHeight.value = document.querySelector('.terminals_sftp_wrap').offsetHeight - 45 // 45 is tab-header height+15
|
||||
})
|
||||
}
|
||||
|
||||
const handleCommandHost = (host) => {
|
||||
emit('add-host', host)
|
||||
}
|
||||
|
||||
const tabChange = async (index) => {
|
||||
await $nextTick()
|
||||
const curTabTerminal = terminalTabRefs.value[index]
|
||||
@ -178,10 +208,40 @@ const handleInputCommand = async (command) => {
|
||||
:deep(.el-tabs__content) {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
padding-top: 0px;
|
||||
padding: 0 5px 5px 0;
|
||||
}
|
||||
|
||||
:deep(.el-tabs--border-card) {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.info_box {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.top {
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
z-index: 1;
|
||||
background-color: rgb(255, 255, 255);
|
||||
padding-right: 15px;
|
||||
display: flex;
|
||||
:deep(.el-dropdown) {
|
||||
margin-left: auto;
|
||||
}
|
||||
.action_wrap {
|
||||
height: 39px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.link_host {
|
||||
font-size: var(--el-font-size-base);
|
||||
color: var(--el-color-primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.terminals_sftp_wrap {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
@ -228,13 +288,6 @@ const handleInputCommand = async (command) => {
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
// .el-tabs {
|
||||
// border: none;
|
||||
// }
|
||||
|
||||
// .el-tabs--border-card>.el-tabs__content {
|
||||
// padding: 0;
|
||||
// }
|
||||
|
||||
// .el-tabs__header {
|
||||
// position: sticky;
|
||||
@ -243,12 +296,6 @@ const handleInputCommand = async (command) => {
|
||||
// user-select: none;
|
||||
// }
|
||||
|
||||
// .el-tabs__nav-scroll {
|
||||
// .el-tabs__nav {
|
||||
// // padding-left: 60px;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .el-tabs__new-tab {
|
||||
// position: absolute;
|
||||
// left: 18px;
|
||||
|
@ -35,7 +35,12 @@
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else>
|
||||
<Terminal ref="terminalRef" :terminal-tabs="terminalTabs" @remove-tab="handleRemoveTab" />
|
||||
<Terminal
|
||||
ref="terminalRef"
|
||||
:terminal-tabs="terminalTabs"
|
||||
@remove-tab="handleRemoveTab"
|
||||
@add-host="linkTerminal"
|
||||
/>
|
||||
</div>
|
||||
<HostForm
|
||||
v-model:show="hostFormVisible"
|
||||
@ -47,12 +52,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onActivated, getCurrentInstance, reactive, nextTick, watch } from 'vue'
|
||||
import { ref, computed, onActivated, getCurrentInstance, reactive, nextTick } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import Terminal from './components/terminal.vue'
|
||||
import HostForm from '../server/components/host-form.vue'
|
||||
|
||||
const { proxy: { $store, $route, $message } } = getCurrentInstance()
|
||||
const { proxy: { $store, $message } } = getCurrentInstance()
|
||||
|
||||
let terminalTabs = reactive([])
|
||||
const hostFormVisible = ref(false)
|
||||
|
Loading…
x
Reference in New Issue
Block a user