From 1db572e020f3866a83976f9bf5624253708a277b Mon Sep 17 00:00:00 2001 From: mofeng-git Date: Sun, 6 Sep 2026 11:20:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(web):=20=E5=AE=8C=E5=96=84=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E5=8F=B0=E8=A7=86=E9=A2=91=E4=B8=8E=E7=94=B5=E6=BA=90?= =?UTF-8?q?=E6=8E=A7=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/components/ActionBar.vue | 10 +- web/src/components/AtxPopover.vue | 19 ++- web/src/components/VideoConfigPopover.vue | 25 ++++ web/src/composables/useVideoScaling.ts | 34 +++++- web/src/i18n/en-US.ts | 1 + web/src/i18n/zh-CN.ts | 1 + web/src/views/ConsoleView.vue | 134 +++++++++++++++------- 7 files changed, 177 insertions(+), 47 deletions(-) diff --git a/web/src/components/ActionBar.vue b/web/src/components/ActionBar.vue index d8ccaa08..6bcee857 100644 --- a/web/src/components/ActionBar.vue +++ b/web/src/components/ActionBar.vue @@ -3,7 +3,7 @@ import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue' import { useI18n } from 'vue-i18n' import { useRouter } from 'vue-router' import { useSystemStore } from '@/stores/system' -import type { VideoScaleMode } from '@/composables/useVideoScaling' +import type { VideoRotation, VideoScaleMode } from '@/composables/useVideoScaling' import { Button } from '@/components/ui/button' import { ButtonGroup } from '@/components/ui/button-group' import { @@ -68,8 +68,10 @@ const props = defineProps<{ layout?: ConsoleLayout mouseMode?: 'absolute' | 'relative' videoMode?: VideoMode + videoRotation?: VideoRotation ttydRunning?: boolean showPower?: boolean + atxEnabled?: boolean showTerminal?: boolean showComputerUse?: boolean showPasteText?: boolean @@ -90,6 +92,7 @@ async function setFloatingCollapsed(collapsed: boolean) { target?.$el?.focus() } const showAtx = computed(() => props.showPower !== false) +const atxEnabled = computed(() => props.atxEnabled === true) const showStats = computed(() => (props.videoMode ?? 'mjpeg') !== 'mjpeg') const showPasteText = computed(() => props.showPasteText !== false) const showMic = computed(() => props.showMic === true) @@ -102,6 +105,7 @@ const emit = defineEmits<{ (e: 'toggleVirtualKeyboard'): void (e: 'toggleMouseMode'): void (e: 'update:videoMode', mode: VideoMode): void + (e: 'update:videoRotation', rotation: VideoRotation): void (e: 'powerShort'): void (e: 'powerLong'): void (e: 'reset'): void @@ -381,8 +385,10 @@ const hasRightOverflow = computed(() => { @@ -450,6 +456,7 @@ const hasRightOverflow = computed(() => { :side="isSidebarLayout ? 'right' : 'bottom'" > { {{ t('actionbar.power') }} () +const props = withDefaults(defineProps<{ + /** Whether a hardware ATX controller is configured and available. */ + atxEnabled?: boolean +}>(), { + atxEnabled: false, +}) + const { t } = useI18n() -const activeTab = ref('atx') +const activeTab = ref(props.atxEnabled ? 'atx' : 'wol') +const showAtxControls = computed(() => props.atxEnabled) const tabTriggerClass = 'h-8 rounded-md border-0 bg-transparent text-center text-xs text-muted-foreground shadow-none hover:text-foreground data-[state=active]:border-0 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm' const powerState = ref<'on' | 'off' | 'unknown'>('unknown') @@ -194,12 +202,17 @@ watch( }, { immediate: true }, ) + +watch(showAtxControls, (enabled) => { + // A disabled ATX controller must never leave the hidden ATX tab selected. + if (!enabled) activeTab.value = 'wol' +})