This commit is contained in:
fuenmao
2026-11-13 14:03:38 +08:00
parent db0c578890
commit 09e8bded7e
22 changed files with 1309 additions and 607 deletions
+39 -12
View File
@@ -1,20 +1,47 @@
<script setup lang="ts">
import { toRefs } from 'vue'
import { reactive, toRefs, watchEffect } from 'vue'
import { Button as VanButton, Slider as VanSlider } from 'vant'
import type { HomeAssistantDiscoveredDevice } from '../../services/health'
import { useDeviceControlContext } from '../../devices/controlContext'
import { useDeviceCardState } from '../../devices/useDeviceCardState'
import { defaults, labels, sync } from '../../devices/fragrance/parameters'
import type { ParameterSnapshot } from '../../devices/parameterState'
const props = defineProps<{ device: HomeAssistantDiscoveredDevice }>()
const { device: fragranceDevice } = toRefs(props)
const { localParams, operationBusy, switchingDeviceId, isDeviceTurnedOn, toggleDevice, applyParam, settingParam } = useDeviceControlContext()
const state = useDeviceCardState(() => props.device)
const { haStatus, operationBusy, switchingDeviceId, isDeviceTurnedOn, toggleDevice,
applyParam: setParameter, settingParam } = useDeviceControlContext()
const localParams = reactive({ ...defaults })
const parameterKey = (key: string) => props.device.moduleKey === 'wake-fragrance' ? `wake_${key}` : key
const card = useDeviceCardState(() => props.device)
const state = {
...card,
available: (key: string) => card.available(parameterKey(key)),
readable: (key: string) => card.readable(parameterKey(key)),
display: (key: string, value: unknown, suffix = '') => card.display(parameterKey(key), value, suffix),
}
function syncReadings() {
const controls: ParameterSnapshot = {}
for (const key of Object.keys(labels)) {
const reading = haStatus.value?.controlParameters?.[parameterKey(key)]
if (reading && state.available(key)) controls[key] = reading
}
Object.assign(localParams, defaults)
sync(localParams, controls)
}
watchEffect(syncReadings)
async function applyParam(key: string, value: unknown) {
await setParameter(props.device.deviceId, parameterKey(key), value)
syncReadings()
}
</script>
<template>
<section class="device-card" v-if="fragranceDevice">
<div class="device-head">
<div class="dev-info">
<span class="category-tag">香氛助眠</span>
<span class="category-tag">香氛控制</span>
<h3>{{ fragranceDevice.name }}</h3>
<span class="status-dot" :class="{ online: fragranceDevice.online }">
{{ fragranceDevice.online ? '设备在线' : '设备离线' }}
@@ -47,7 +74,7 @@ const state = useDeviceCardState(() => props.device)
:max="6"
:step="1"
:disabled="operationBusy || !state.available('fragrance_duration')"
@change="applyParam(fragranceDevice.deviceId, 'fragrance_duration', localParams.fragranceDuration)"
@change="applyParam('fragrance_duration', localParams.fragranceDuration)"
/>
<div class="range-labels"><span>2 秒</span><span>4 秒</span><span>6 秒</span></div>
</div>
@@ -63,7 +90,7 @@ const state = useDeviceCardState(() => props.device)
:max="20"
:step="5"
:disabled="operationBusy || !state.available('fragrance_interval')"
@change="applyParam(fragranceDevice.deviceId, 'fragrance_interval', localParams.fragranceInterval)"
@change="applyParam('fragrance_interval', localParams.fragranceInterval)"
/>
<div class="range-labels"><span>10 分钟</span><span>15 分钟</span><span>20 分钟</span></div>
</div>
@@ -77,7 +104,7 @@ const state = useDeviceCardState(() => props.device)
class="mini-toggle"
:class="{ active: state.readable('fragrance_light') && localParams.fragranceLight }"
:disabled="operationBusy || !state.available('fragrance_light')"
@click="localParams.fragranceLight = !localParams.fragranceLight; applyParam(fragranceDevice.deviceId, 'fragrance_light', localParams.fragranceLight)"
@click="applyParam('fragrance_light', !localParams.fragranceLight)"
>{{ state.display('fragrance_light', localParams.fragranceLight ? '已开启' : '已关闭') }}</button>
</div>
@@ -90,7 +117,7 @@ const state = useDeviceCardState(() => props.device)
class="mini-toggle"
:class="{ active: state.readable('fragrance_auto_release') && localParams.fragranceAutoRelease }"
:disabled="operationBusy || !state.available('fragrance_auto_release')"
@click="localParams.fragranceAutoRelease = !localParams.fragranceAutoRelease; applyParam(fragranceDevice.deviceId, 'fragrance_auto_release', localParams.fragranceAutoRelease)"
@click="applyParam('fragrance_auto_release', !localParams.fragranceAutoRelease)"
>{{ state.display('fragrance_auto_release', localParams.fragranceAutoRelease ? '已开启' : '已关闭') }}</button>
</div>
@@ -103,7 +130,7 @@ const state = useDeviceCardState(() => props.device)
class="mini-toggle"
:class="{ active: state.readable('fragrance_auto_light') && localParams.fragranceAutoLight }"
:disabled="operationBusy || !state.available('fragrance_auto_light')"
@click="localParams.fragranceAutoLight = !localParams.fragranceAutoLight; applyParam(fragranceDevice.deviceId, 'fragrance_auto_light', localParams.fragranceAutoLight)"
@click="applyParam('fragrance_auto_light', !localParams.fragranceAutoLight)"
>{{ state.display('fragrance_auto_light', localParams.fragranceAutoLight ? '已开启' : '已关闭') }}</button>
</div>
@@ -116,7 +143,7 @@ const state = useDeviceCardState(() => props.device)
class="mini-toggle"
:class="{ active: state.readable('fragrance_light_auto_off') && localParams.fragranceLightAutoOff }"
:disabled="operationBusy || !state.available('fragrance_light_auto_off')"
@click="localParams.fragranceLightAutoOff = !localParams.fragranceLightAutoOff; applyParam(fragranceDevice.deviceId, 'fragrance_light_auto_off', localParams.fragranceLightAutoOff)"
@click="applyParam('fragrance_light_auto_off', !localParams.fragranceLightAutoOff)"
>{{ state.display('fragrance_light_auto_off', localParams.fragranceLightAutoOff ? '已开启' : '已关闭') }}</button>
</div>
@@ -130,9 +157,9 @@ const state = useDeviceCardState(() => props.device)
round
plain
color="#0c5045"
:loading="settingParam === `${fragranceDevice.deviceId}_fragrance_quick_release`"
:loading="settingParam === `${fragranceDevice.deviceId}_${parameterKey('fragrance_quick_release')}`"
:disabled="operationBusy || !state.available('fragrance_quick_release')"
@click="applyParam(fragranceDevice.deviceId, 'fragrance_quick_release', true)"
@click="applyParam('fragrance_quick_release', true)"
>{{ state.available('fragrance_quick_release') ? '快速出香' : '暂不可用' }}</VanButton>
</div>
</div>