Files
Nexus/frontend/src/components/terminal/TerminalToolbar.vue
T
2026-07-08 22:31:31 +08:00

185 lines
5.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="d-flex align-center justify-space-between px-3 py-1 shrink-0 terminal-toolbar">
<div class="d-flex align-center ga-2 min-w-0 terminal-toolbar__meta">
<div class="min-w-0">
<div class="text-body-2 font-weight-medium text-truncate">
{{ session?.serverName || '...' }}
</div>
<div
v-if="session?.serverDomain"
class="text-caption text-truncate text-medium-emphasis font-mono"
>
{{ session.serverDomain }}
</div>
</div>
<span
v-if="session?.cwd"
class="text-caption font-mono terminal-toolbar__cwd text-medium-emphasis hidden-sm-and-down"
:title="session.cwd"
>
{{ session.cwd }}
</span>
<v-chip v-if="session" :color="statusColor" variant="tonal" size="x-small" label>
<template #prepend>
<v-icon start size="8">mdi-circle</v-icon>
</template>
{{ statusLabel }}
</v-chip>
<span v-if="session?.uptime" class="text-caption text-medium-emphasis hidden-sm-and-down">
{{ session.uptime }}
</span>
<span
v-if="session?.pingMs !== null && session?.pingMs !== undefined"
class="text-caption text-medium-emphasis hidden-sm-and-down"
>
{{ session.pingMs }}ms
</span>
</div>
<div class="d-flex align-center ga-1 terminal-toolbar-actions shrink-0">
<div class="d-none d-md-flex align-center ga-2">
<v-btn
v-if="session"
variant="tonal"
color="deep-orange"
size="x-small"
prepend-icon="mdi-login-variant"
title="一键登录宝塔面板"
class="terminal-toolbar__bt-login"
:loading="btLoginLoading"
:disabled="btLoginLoading"
@click="$emit('bt-login')"
>
宝塔登录
</v-btn>
<span class="text-caption text-medium-emphasis shrink-0">字号</span>
<v-btn variant="tonal" size="x-small" @click="$emit('font-change', -1)"></v-btn>
<span class="text-body-2 font-weight-medium terminal-toolbar__font-size">
{{ fontSize }}
</span>
<v-btn variant="tonal" size="x-small" @click="$emit('font-change', 1)">+</v-btn>
<v-select
:model-value="scrollback"
:items="scrollbackOptions"
item-title="title"
item-value="value"
label="回滚"
density="compact"
hide-details
variant="outlined"
class="terminal-toolbar-scrollback"
@update:model-value="$emit('scrollback-change', $event)"
/>
</div>
<v-menu location="bottom end">
<template #activator="{ props: menuProps }">
<v-btn
v-bind="menuProps"
class="d-md-none"
size="x-small"
variant="tonal"
icon="mdi-cog-outline"
/>
</template>
<v-list density="compact" nav class="py-1">
<v-list-item
v-if="session"
:disabled="btLoginLoading"
@click="$emit('bt-login')"
>
<template #prepend>
<v-icon color="deep-orange">mdi-login-variant</v-icon>
</template>
<v-list-item-title>一键登录宝塔</v-list-item-title>
</v-list-item>
<v-divider v-if="session" class="my-1" />
<v-list-subheader>字号 {{ fontSize }}</v-list-subheader>
<v-list-item @click="$emit('font-change', -1)">
<v-list-item-title>缩小</v-list-item-title>
</v-list-item>
<v-list-item @click="$emit('font-change', 1)">
<v-list-item-title>放大</v-list-item-title>
</v-list-item>
<v-divider class="my-1" />
<v-list-subheader>回滚行数</v-list-subheader>
<v-list-item
v-for="opt in scrollbackOptions"
:key="opt.value"
:active="scrollback === opt.value"
@click="$emit('scrollback-change', opt.value)"
>
<v-list-item-title>{{ opt.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-btn variant="tonal" size="x-small" icon="mdi-fullscreen" title="全屏" @click="$emit('fullscreen')" />
<v-btn
variant="tonal"
size="x-small"
color="error"
icon="mdi-link-off"
title="断开"
@click="$emit('disconnect')"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import {
sessionStatusColor,
sessionStatusLabel,
type TermSessionData,
} from '@/composables/terminal/types'
import { scrollbackOptions } from '@/composables/terminal/useTerminalSettings'
const props = defineProps<{
session: TermSessionData | null
fontSize: number
scrollback: number
btLoginLoading?: boolean
}>()
defineEmits<{
'font-change': [delta: number]
'scrollback-change': [value: number]
fullscreen: []
disconnect: []
'bt-login': []
}>()
const statusLabel = computed(() =>
props.session ? sessionStatusLabel(props.session) : '',
)
const statusColor = computed(() =>
props.session ? sessionStatusColor(props.session) : 'grey',
)
</script>
<style scoped>
.terminal-toolbar {
background: rgb(var(--v-theme-surface));
border-bottom: 1px solid rgb(var(--v-theme-surface-variant));
min-height: 36px;
}
.terminal-toolbar__cwd {
max-width: min(28vw, 240px);
}
.terminal-toolbar__font-size {
min-width: 1.25rem;
text-align: center;
}
.terminal-toolbar-scrollback {
min-width: 6.5rem;
max-width: 7.5rem;
}
.terminal-toolbar__bt-login {
font-weight: 600;
letter-spacing: 0.01em;
text-transform: none;
}
.font-mono {
font-family: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', Menlo, monospace;
}
</style>