mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-06-14 19:51:58 +08:00
feat: 引入统一配置 store 并迁移 Console/Settings 配置读写;自动显示当前使用的配置
This commit is contained in:
@@ -20,6 +20,7 @@ import {
|
||||
} from '@/components/ui/select'
|
||||
import { Volume2, RefreshCw, Loader2 } from 'lucide-vue-next'
|
||||
import { audioApi, configApi } from '@/api'
|
||||
import { useConfigStore } from '@/stores/config'
|
||||
import { useSystemStore } from '@/stores/system'
|
||||
import { getUnifiedAudio } from '@/composables/useUnifiedAudio'
|
||||
|
||||
@@ -37,6 +38,7 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const configStore = useConfigStore()
|
||||
const systemStore = useSystemStore()
|
||||
const unifiedAudio = getUnifiedAudio()
|
||||
|
||||
@@ -87,9 +89,9 @@ async function loadDevices() {
|
||||
|
||||
// Initialize from current config
|
||||
function initializeFromCurrent() {
|
||||
const audio = systemStore.audio
|
||||
const audio = configStore.audio
|
||||
if (audio) {
|
||||
audioEnabled.value = audio.available && audio.streaming
|
||||
audioEnabled.value = audio.enabled
|
||||
selectedDevice.value = audio.device || ''
|
||||
selectedQuality.value = (audio.quality as 'voice' | 'balanced' | 'high') || 'balanced'
|
||||
}
|
||||
@@ -104,12 +106,10 @@ async function applyConfig() {
|
||||
|
||||
try {
|
||||
// Update config
|
||||
await configApi.update({
|
||||
audio: {
|
||||
enabled: audioEnabled.value,
|
||||
device: selectedDevice.value,
|
||||
quality: selectedQuality.value,
|
||||
},
|
||||
await configStore.updateAudio({
|
||||
enabled: audioEnabled.value,
|
||||
device: selectedDevice.value,
|
||||
quality: selectedQuality.value,
|
||||
})
|
||||
|
||||
// If enabled and device is selected, try to start audio stream
|
||||
@@ -151,12 +151,19 @@ async function applyConfig() {
|
||||
|
||||
// Watch popover open state
|
||||
watch(() => props.open, (isOpen) => {
|
||||
if (isOpen) {
|
||||
if (devices.value.length === 0) {
|
||||
loadDevices()
|
||||
}
|
||||
initializeFromCurrent()
|
||||
if (!isOpen) return
|
||||
|
||||
if (devices.value.length === 0) {
|
||||
loadDevices()
|
||||
}
|
||||
|
||||
configStore.refreshAudio()
|
||||
.then(() => {
|
||||
initializeFromCurrent()
|
||||
})
|
||||
.catch(() => {
|
||||
initializeFromCurrent()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -22,7 +22,9 @@ import {
|
||||
import { MousePointer, Move, Loader2, RefreshCw } from 'lucide-vue-next'
|
||||
import HelpTooltip from '@/components/HelpTooltip.vue'
|
||||
import { configApi } from '@/api'
|
||||
import { useSystemStore } from '@/stores/system'
|
||||
import { useConfigStore } from '@/stores/config'
|
||||
import { HidBackend } from '@/types/generated'
|
||||
import type { HidConfigUpdate } from '@/types/generated'
|
||||
|
||||
const props = defineProps<{
|
||||
open: boolean
|
||||
@@ -35,7 +37,7 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const systemStore = useSystemStore()
|
||||
const configStore = useConfigStore()
|
||||
|
||||
const DEFAULT_MOUSE_MOVE_SEND_INTERVAL_MS = 16
|
||||
|
||||
@@ -72,7 +74,7 @@ watch(showCursor, (newValue, oldValue) => {
|
||||
})
|
||||
|
||||
// HID Device Settings (requires apply)
|
||||
const hidBackend = ref<'otg' | 'ch9329' | 'none'>('none')
|
||||
const hidBackend = ref<HidBackend>(HidBackend.None)
|
||||
const devicePath = ref<string>('')
|
||||
const baudrate = ref<number>(9600)
|
||||
|
||||
@@ -89,9 +91,9 @@ const buttonText = computed(() => t('actionbar.hidConfig'))
|
||||
|
||||
// Available device paths based on backend type
|
||||
const availableDevicePaths = computed(() => {
|
||||
if (hidBackend.value === 'ch9329') {
|
||||
if (hidBackend.value === HidBackend.Ch9329) {
|
||||
return serialDevices.value
|
||||
} else if (hidBackend.value === 'otg') {
|
||||
} else if (hidBackend.value === HidBackend.Otg) {
|
||||
// For OTG, we show UDC devices
|
||||
return udcDevices.value.map(udc => ({
|
||||
path: udc.name,
|
||||
@@ -124,9 +126,17 @@ function initializeFromCurrent() {
|
||||
showCursor.value = storedCursor
|
||||
|
||||
// Initialize HID device settings from system state
|
||||
const hid = systemStore.hid
|
||||
const hid = configStore.hid
|
||||
if (hid) {
|
||||
hidBackend.value = (hid.backend as 'otg' | 'ch9329' | 'none') || 'none'
|
||||
hidBackend.value = hid.backend || HidBackend.None
|
||||
if (hidBackend.value === HidBackend.Ch9329) {
|
||||
devicePath.value = hid.ch9329_port || ''
|
||||
baudrate.value = hid.ch9329_baudrate || 9600
|
||||
} else if (hidBackend.value === HidBackend.Otg) {
|
||||
devicePath.value = hid.otg_udc || ''
|
||||
} else {
|
||||
devicePath.value = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,10 +146,8 @@ function toggleMouseMode() {
|
||||
emit('update:mouseMode', newMode)
|
||||
|
||||
// Update backend config
|
||||
configApi.update({
|
||||
hid: {
|
||||
mouse_absolute: newMode === 'absolute',
|
||||
},
|
||||
configStore.updateHid({
|
||||
mouse_absolute: newMode === 'absolute',
|
||||
}).catch(_e => {
|
||||
console.info('[HidConfig] Failed to update mouse mode')
|
||||
toast.error(t('config.updateFailed'))
|
||||
@@ -162,7 +170,11 @@ function handleThrottleChange(value: number[] | undefined) {
|
||||
// Handle backend change
|
||||
function handleBackendChange(backend: unknown) {
|
||||
if (typeof backend !== 'string') return
|
||||
hidBackend.value = backend as 'otg' | 'ch9329' | 'none'
|
||||
if (backend === HidBackend.Otg || backend === HidBackend.Ch9329 || backend === HidBackend.None) {
|
||||
hidBackend.value = backend
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
// Clear device path when changing backend
|
||||
devicePath.value = ''
|
||||
@@ -189,18 +201,18 @@ function handleBaudrateChange(rate: unknown) {
|
||||
async function applyHidConfig() {
|
||||
applying.value = true
|
||||
try {
|
||||
const config: Record<string, unknown> = {
|
||||
const config: HidConfigUpdate = {
|
||||
backend: hidBackend.value,
|
||||
}
|
||||
|
||||
if (hidBackend.value === 'ch9329') {
|
||||
if (hidBackend.value === HidBackend.Ch9329) {
|
||||
config.ch9329_port = devicePath.value
|
||||
config.ch9329_baudrate = baudrate.value
|
||||
} else if (hidBackend.value === 'otg') {
|
||||
} else if (hidBackend.value === HidBackend.Otg) {
|
||||
config.otg_udc = devicePath.value
|
||||
}
|
||||
|
||||
await configApi.update({ hid: config })
|
||||
await configStore.updateHid(config)
|
||||
|
||||
toast.success(t('config.applied'))
|
||||
|
||||
@@ -215,14 +227,20 @@ async function applyHidConfig() {
|
||||
|
||||
// Watch open state
|
||||
watch(() => props.open, (isOpen) => {
|
||||
if (isOpen) {
|
||||
// Load devices on first open
|
||||
if (serialDevices.value.length === 0) {
|
||||
loadDevices()
|
||||
}
|
||||
// Initialize from current config
|
||||
initializeFromCurrent()
|
||||
if (!isOpen) return
|
||||
|
||||
// Load devices on first open
|
||||
if (serialDevices.value.length === 0) {
|
||||
loadDevices()
|
||||
}
|
||||
|
||||
configStore.refreshHid()
|
||||
.then(() => {
|
||||
initializeFromCurrent()
|
||||
})
|
||||
.catch(() => {
|
||||
initializeFromCurrent()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -331,15 +349,15 @@ watch(() => props.open, (isOpen) => {
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="otg" class="text-xs">USB OTG</SelectItem>
|
||||
<SelectItem value="ch9329" class="text-xs">CH9329 (Serial)</SelectItem>
|
||||
<SelectItem value="none" class="text-xs">{{ t('common.disabled') }}</SelectItem>
|
||||
<SelectItem :value="HidBackend.Otg" class="text-xs">USB OTG</SelectItem>
|
||||
<SelectItem :value="HidBackend.Ch9329" class="text-xs">CH9329 (Serial)</SelectItem>
|
||||
<SelectItem :value="HidBackend.None" class="text-xs">{{ t('common.disabled') }}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<!-- Device Path (OTG or CH9329) -->
|
||||
<div v-if="hidBackend !== 'none'" class="space-y-2">
|
||||
<div v-if="hidBackend !== HidBackend.None" class="space-y-2">
|
||||
<Label class="text-xs text-muted-foreground">{{ t('actionbar.devicePath') }}</Label>
|
||||
<Select
|
||||
:model-value="devicePath"
|
||||
@@ -363,7 +381,7 @@ watch(() => props.open, (isOpen) => {
|
||||
</div>
|
||||
|
||||
<!-- Baudrate (CH9329 only) -->
|
||||
<div v-if="hidBackend === 'ch9329'" class="space-y-2">
|
||||
<div v-if="hidBackend === HidBackend.Ch9329" class="space-y-2">
|
||||
<Label class="text-xs text-muted-foreground">{{ t('actionbar.baudrate') }}</Label>
|
||||
<Select
|
||||
:model-value="String(baudrate)"
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
import { Monitor, RefreshCw, Loader2, Settings, Zap, Scale, Image } from 'lucide-vue-next'
|
||||
import HelpTooltip from '@/components/HelpTooltip.vue'
|
||||
import { configApi, streamApi, type VideoCodecInfo, type EncoderBackendInfo, type BitratePreset } from '@/api'
|
||||
import { useSystemStore } from '@/stores/system'
|
||||
import { useConfigStore } from '@/stores/config'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
export type VideoMode = 'mjpeg' | 'h264' | 'h265' | 'vp8' | 'vp9'
|
||||
@@ -51,7 +51,7 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const systemStore = useSystemStore()
|
||||
const configStore = useConfigStore()
|
||||
const router = useRouter()
|
||||
|
||||
// Device list
|
||||
@@ -64,7 +64,7 @@ const loadingCodecs = ref(false)
|
||||
|
||||
// Backend list
|
||||
const backends = ref<EncoderBackendInfo[]>([])
|
||||
const currentEncoderBackend = ref<string>('auto')
|
||||
const currentEncoderBackend = computed(() => configStore.stream?.encoder || 'auto')
|
||||
|
||||
// Browser supported codecs (WebRTC receive capabilities)
|
||||
const browserSupportedCodecs = ref<Set<string>>(new Set())
|
||||
@@ -197,11 +197,11 @@ const applyingBitrate = ref(false)
|
||||
|
||||
// Current config from store
|
||||
const currentConfig = computed(() => ({
|
||||
device: systemStore.stream?.device || '',
|
||||
format: systemStore.stream?.format || '',
|
||||
width: systemStore.stream?.resolution?.[0] || 1920,
|
||||
height: systemStore.stream?.resolution?.[1] || 1080,
|
||||
fps: systemStore.stream?.targetFps || 30,
|
||||
device: configStore.video?.device || '',
|
||||
format: configStore.video?.format || '',
|
||||
width: configStore.video?.width || 1920,
|
||||
height: configStore.video?.height || 1080,
|
||||
fps: configStore.video?.fps || 30,
|
||||
}))
|
||||
|
||||
// Button display text - simplified to just show label
|
||||
@@ -303,19 +303,6 @@ async function loadCodecs() {
|
||||
}
|
||||
}
|
||||
|
||||
// Load current encoder backend from config
|
||||
async function loadEncoderBackend() {
|
||||
try {
|
||||
const config = await configApi.get()
|
||||
// Access nested stream.encoder
|
||||
const streamConfig = config.stream as { encoder?: string } | undefined
|
||||
currentEncoderBackend.value = streamConfig?.encoder || 'auto'
|
||||
} catch (e) {
|
||||
console.info('[VideoConfig] Failed to load encoder backend config')
|
||||
currentEncoderBackend.value = 'auto'
|
||||
}
|
||||
}
|
||||
|
||||
// Navigate to settings page (video tab)
|
||||
function goToSettings() {
|
||||
router.push('/settings?tab=video')
|
||||
@@ -440,14 +427,12 @@ async function applyVideoConfig() {
|
||||
|
||||
applying.value = true
|
||||
try {
|
||||
await configApi.update({
|
||||
video: {
|
||||
device: selectedDevice.value,
|
||||
format: selectedFormat.value,
|
||||
width,
|
||||
height,
|
||||
fps: selectedFps.value,
|
||||
},
|
||||
await configStore.updateVideo({
|
||||
device: selectedDevice.value,
|
||||
format: selectedFormat.value,
|
||||
width,
|
||||
height,
|
||||
fps: selectedFps.value,
|
||||
})
|
||||
|
||||
toast.success(t('config.applied'))
|
||||
@@ -463,26 +448,32 @@ async function applyVideoConfig() {
|
||||
|
||||
// Watch open state
|
||||
watch(() => props.open, (isOpen) => {
|
||||
if (isOpen) {
|
||||
// Detect browser codec support on first open
|
||||
if (browserSupportedCodecs.value.size === 0) {
|
||||
detectBrowserCodecSupport()
|
||||
}
|
||||
// Load devices on first open
|
||||
if (devices.value.length === 0) {
|
||||
loadDevices()
|
||||
}
|
||||
// Load codecs and backends on first open
|
||||
if (codecs.value.length === 0) {
|
||||
loadCodecs()
|
||||
}
|
||||
// Load encoder backend config
|
||||
loadEncoderBackend()
|
||||
// Initialize from current config
|
||||
initializeFromCurrent()
|
||||
} else {
|
||||
if (!isOpen) {
|
||||
isDirty.value = false
|
||||
return
|
||||
}
|
||||
|
||||
// Detect browser codec support on first open
|
||||
if (browserSupportedCodecs.value.size === 0) {
|
||||
detectBrowserCodecSupport()
|
||||
}
|
||||
// Load devices on first open
|
||||
if (devices.value.length === 0) {
|
||||
loadDevices()
|
||||
}
|
||||
// Load codecs and backends on first open
|
||||
if (codecs.value.length === 0) {
|
||||
loadCodecs()
|
||||
}
|
||||
|
||||
Promise.all([
|
||||
configStore.refreshVideo(),
|
||||
configStore.refreshStream(),
|
||||
]).then(() => {
|
||||
initializeFromCurrent()
|
||||
}).catch(() => {
|
||||
initializeFromCurrent()
|
||||
})
|
||||
})
|
||||
|
||||
// Sync selected values when backend config changes (e.g., auto format switch on mode change)
|
||||
|
||||
Reference in New Issue
Block a user