185 lines
5.7 KiB
Vue
185 lines
5.7 KiB
Vue
<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>
|