caoziwu 2 周之前
父節點
當前提交
2d9385b545
共有 2 個文件被更改,包括 55 次插入 和 36 次删除
  1. 45 36
      src/renderer/src/components/simulator/ParamsPanel.vue
  2. 10 0
      src/renderer/src/lib/speaker/types.ts

+ 45 - 36
src/renderer/src/components/simulator/ParamsPanel.vue

@@ -1,9 +1,9 @@
 <script setup lang="ts">
-import { computed, ref, Ref, watch } from 'vue'
+import { computed, ref, reactive, watch } from 'vue'
 import { useI18n } from 'vue-i18n'
 import { devicesConfig } from '../../config'
 import type { DeviceSpec, DevicePanelState } from '../../lib/speaker/types'
-import type { NumberParamKey } from '../../lib/speaker/types'
+import type { NumberParamKey, DeviceParamKey } from '../../lib/speaker/types'
 
 const { t } = useI18n()
 
@@ -20,6 +20,8 @@ const props = defineProps({
     })
   }
 })
+type FormDataType = Record<DeviceParamKey, number | null>
+
 type NumberField = {
   kind: 'number'
   key: NumberParamKey
@@ -27,7 +29,6 @@ type NumberField = {
   labelKey: string
   unit: string
   step: number
-  value: Ref<number> | number
 }
 
 type FieldConfig = NumberField
@@ -45,20 +46,24 @@ const modelOptions = devicesConfig.map((d) => ({
 }))
 
 const selectedModel = ref<string | null>('custom')
-
 const isExtension = ref(props.state.isExtension || false)
-
 const powerMode = ref<string>('')
 
+const formData = reactive<FormDataType>({
+  splMax: null,
+  hCov: null,
+  vCov: null
+})
+
 const currentSplMaxConfig = computed(() => {
-  return devicesConfig.find((d) => d.model === selectedModel.value).splMax
+  const device = devicesConfig.find((d) => d.model === selectedModel.value)
+  return device ? device.splMax : { standalone: [], extension: [] }
 })
-const splMax = ref<number | null>(null)
-const hCov = ref<number | null>(null)
-const vCov = ref<number | null>(null)
 
 const powerModeOptions = computed(() => {
-  if (currentSplMaxConfig.value.extension.length == 0) return currentSplMaxConfig.value.standalone
+  if (!currentSplMaxConfig.value.extension || currentSplMaxConfig.value.extension.length === 0) {
+    return currentSplMaxConfig.value.standalone || []
+  }
   return isExtension.value
     ? currentSplMaxConfig.value.extension
     : currentSplMaxConfig.value.standalone
@@ -67,44 +72,47 @@ const powerModeOptions = computed(() => {
 const apply = (): void => {
   const device = devicesConfig.find((d) => d.model === selectedModel.value)
   const isCustom = !device || device.model === 'custom'
-  hCov.value = isCustom ? hCov.value : device.horizontalAngle
-  vCov.value = isCustom ? vCov.value : device.verticalAngle
+  formData.hCov = isCustom ? formData.hCov : device.horizontalAngle
+  formData.vCov = isCustom ? formData.vCov : device.verticalAngle
   const deviceState = {
     model: selectedModel.value,
     isExtension: isExtension.value,
     powerMode: powerMode.value,
-    splMax: splMax.value,
-    hCov: hCov.value,
-    vCov: vCov.value
+    splMax: formData.splMax,
+    hCov: formData.hCov,
+    vCov: formData.vCov
   }
   const data = {
-    hCov: hCov.value,
-    vCov: vCov.value,
-    splMax: splMax.value
+    hCov: formData.hCov,
+    vCov: formData.vCov,
+    splMax: formData.splMax
   }
 
   emit('update:state', deviceState)
   emit('apply-spec', data)
 }
 
-const onSelectModel = (model: string): void => {
-  selectedModel.value = model
+const onSelectModel = (model: string | null): void => {
+  const val = model || 'custom'
+  selectedModel.value = val
   isExtension.value = false
-  powerMode.value = powerModeOptions.value[0].label
-  splMax.value = powerModeOptions.value[0].value
+  const firstOption = powerModeOptions.value[0]
+  powerMode.value = firstOption ? firstOption.label : ''
+  formData.splMax = firstOption ? firstOption.value : 0
   apply()
 }
 
 const onToggleExtension = (value: boolean): void => {
   isExtension.value = value
-  powerMode.value = powerModeOptions.value[0].label
-  splMax.value = powerModeOptions.value[0].value
+  const firstOption = powerModeOptions.value[0]
+  powerMode.value = firstOption ? firstOption.label : ''
+  formData.splMax = firstOption ? firstOption.value : 0
   apply()
 }
 
 const onSelectPowerMode = (mode: string): void => {
   powerModeOptions.value.forEach((item) => {
-    if (item.label == mode) splMax.value = item.value
+    if (item.label === mode) formData.splMax = item.value
   })
   apply()
 }
@@ -114,13 +122,13 @@ watch(
     selectedModel.value = newVal.model
     isExtension.value = newVal.isExtension
     powerMode.value = newVal.powerMode
-    splMax.value = newVal.splMax
-    hCov.value = newVal.hCov
-    vCov.value = newVal.vCov
-    console.log(isExtension.value, props.state)
+    formData.splMax = newVal.splMax
+    formData.hCov = newVal.hCov
+    formData.vCov = newVal.vCov
   },
   {
-    immediate: true
+    immediate: true,
+    deep: true
   }
 )
 const fields: FieldConfig[] = [
@@ -130,7 +138,6 @@ const fields: FieldConfig[] = [
     symbol: 'SPLₘₐₓ',
     labelKey: 'params.splMax',
     unit: 'dB SPL',
-    value: splMax,
     step: 0.1
   },
   {
@@ -139,7 +146,6 @@ const fields: FieldConfig[] = [
     symbol: 'H',
     labelKey: 'params.hCov',
     unit: '°',
-    value: hCov,
     step: 1
   },
   {
@@ -148,7 +154,6 @@ const fields: FieldConfig[] = [
     symbol: 'V',
     labelKey: 'params.vCov',
     unit: '°',
-    value: vCov,
     step: 1
   }
 ]
@@ -174,7 +179,10 @@ const fields: FieldConfig[] = [
       <div
         class="field model-field"
         v-if="
-          selectedModel && selectedModel !== 'custom' && currentSplMaxConfig.extension.length > 0
+          selectedModel &&
+          selectedModel !== 'custom' &&
+          currentSplMaxConfig.extension &&
+          currentSplMaxConfig.extension.length > 0
         "
       >
         <div class="field-label">
@@ -201,7 +209,7 @@ const fields: FieldConfig[] = [
       </div>
     </n-flex>
     <NGrid cols="3" responsive="screen" :x-gap="14" :y-gap="14" item-responsive>
-      <template v-for="field in fields" :key="field.kind === 'number' ? field.key : 'dir'">
+      <template v-for="field in fields" :key="field.key">
         <NGi span="3 s:1 m:1">
           <div class="field">
             <div class="field-label">
@@ -209,10 +217,11 @@ const fields: FieldConfig[] = [
               {{ $t(field.labelKey) }}
             </div>
             <NInputNumber
-              :value="field.value"
+              v-model:value="formData[field.key]"
               :step="field.step"
               :show-button="false"
               :disabled="selectedModel !== 'custom'"
+              @update:value="apply"
               class="num-input"
             >
               <template #suffix>{{ field.unit }}</template>

+ 10 - 0
src/renderer/src/lib/speaker/types.ts

@@ -8,6 +8,16 @@ export type Direction = 'H' | 'V'
 
 /** 扬声器参数中的数值字段键(排除方向 dir) */
 export type NumberParamKey = Exclude<keyof SpeakerParams, 'dir'>
+export type DeviceParamKey = Exclude<keyof DeviceParams, 'dir'>
+/** 设备型号参数(与原始 HTML 输入一一对应) */
+export interface DeviceParams {
+  /** 最大声压级 dB SPL */
+  splMax: number
+  /** 水平指向角 (-6 dB) ° */
+  hCov: number
+  /** 垂直指向角 (-6 dB) ° */
+  vCov: number
+}
 
 /** 扬声器参数(与原始 HTML 输入一一对应) */
 export interface SpeakerParams {