111
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import type { HomeAssistantDiscoveredDevice } from '../../services/health'
|
||||
import { useDeviceControlContext } from '../../devices/controlContext'
|
||||
import { entityStateLabel } from '../../devices/entityState'
|
||||
const props = defineProps<{ device: HomeAssistantDiscoveredDevice }>()
|
||||
const { operationBusy, toggleDevice, isDeviceTurnedOn, isDeviceControlAvailable, switchingDeviceId } = useDeviceControlContext()
|
||||
const expanded = ref(false)
|
||||
@@ -25,7 +26,7 @@ const entities = computed(() => expanded.value ? props.device.entities : props.d
|
||||
<div class="params-body">
|
||||
<div v-for="entity in entities" :key="entity.entityId" class="param-row">
|
||||
<span class="p-title">{{ entity.name }}</span>
|
||||
<span class="p-val">{{ entity.available && !['unknown', 'unavailable'].includes(entity.state) ? entity.state : '不可用' }} {{ entity.unit || '' }}</span>
|
||||
<span class="p-val">{{ entityStateLabel(entity) }} {{ entity.unit || '' }}</span>
|
||||
</div>
|
||||
<button v-if="device.entities.length > 6" class="text-refresh" @click="expanded = !expanded">
|
||||
{{ expanded ? '收起能力' : '查看全部能力' }}
|
||||
|
||||
@@ -1,94 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import { toRefs } from 'vue'
|
||||
import { Button as VanButton, Slider as VanSlider } from 'vant'
|
||||
import { computed } from 'vue'
|
||||
import type { HomeAssistantDiscoveredDevice } from '../../services/health'
|
||||
import { useDeviceControlContext } from '../../devices/controlContext'
|
||||
import { useDeviceCardState } from '../../devices/useDeviceCardState'
|
||||
import { lightCapabilities } from '../../devices/lighting/capabilities'
|
||||
import StandardLightCard from './StandardLightCard.vue'
|
||||
import { lightTransitionForDevice } from '../../devices/lighting/transitions'
|
||||
const props = defineProps<{ device: HomeAssistantDiscoveredDevice }>()
|
||||
const { device: lightDevice } = toRefs(props)
|
||||
const { localParams, operationBusy, switchingDeviceId, isDeviceTurnedOn, toggleDevice, applyParam, controlLightTransition, lightTransition, loading } = useDeviceControlContext()
|
||||
const state = useDeviceCardState(() => props.device)
|
||||
const { operationBusy, lightTransition, controlLightTransition } = useDeviceControlContext()
|
||||
const transition = computed(() => lightTransitionForDevice(props.device, lightTransition.value))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="device-card" v-if="lightDevice">
|
||||
<div class="device-head">
|
||||
<div class="dev-info">
|
||||
<span class="category-tag">卧室灯光</span>
|
||||
<h3>{{ lightDevice.name }}</h3>
|
||||
<span class="status-dot" :class="{ online: lightDevice.online }">
|
||||
{{ lightDevice.online ? '设备在线' : '设备离线' }}
|
||||
</span>
|
||||
</div>
|
||||
<VanButton
|
||||
size="small"
|
||||
round
|
||||
:type="isDeviceTurnedOn(lightDevice) ? 'primary' : 'default'"
|
||||
:color="isDeviceTurnedOn(lightDevice) ? '#0c5045' : ''"
|
||||
:loading="switchingDeviceId === lightDevice.deviceId"
|
||||
:disabled="operationBusy || !state.powerAvailable()"
|
||||
@click="toggleDevice(lightDevice)"
|
||||
>
|
||||
{{ state.powerLabel('已点亮', '已熄灭') }}
|
||||
</VanButton>
|
||||
<StandardLightCard :device="device" category-label="卧室灯光"
|
||||
:reported-brightness="transition?.running ? transition.brightnessPercent : undefined"
|
||||
note="手动调节会停止当前渐变;本灯保留助眠、唤醒及灯灭停止按摩的专属联动。">
|
||||
<template #before-controls>
|
||||
<div class="light-mode-panel">
|
||||
<div>
|
||||
<strong v-if="transition?.running">{{ transition.mode === 'wake' ? '晨起唤醒中' : '助眠渐暗中' }} · {{ transition.brightnessPercent }}%</strong>
|
||||
<strong v-else>渐变灯光</strong>
|
||||
<small>{{ transition?.message || '开灯从50%逐渐变暗;晨起从当前亮度逐渐变亮至70%' }}</small>
|
||||
</div>
|
||||
|
||||
<div class="params-body">
|
||||
<div class="light-mode-panel">
|
||||
<div>
|
||||
<strong v-if="lightTransition?.running">
|
||||
{{ lightTransition.mode === 'wake' ? '晨起唤醒中' : '助眠渐暗中' }} · {{ lightTransition.brightnessPercent }}%
|
||||
</strong>
|
||||
<strong v-else>渐变灯光</strong>
|
||||
<small>{{ lightTransition?.message || '开灯从50%逐渐变暗;晨起从当前亮度逐渐变亮至70%' }}</small>
|
||||
</div>
|
||||
<div class="light-mode-actions">
|
||||
<button type="button" :disabled="operationBusy || !state.available('brightness')" @click="controlLightTransition('sleep')">🌙 开始助眠渐暗</button>
|
||||
<button type="button" :disabled="operationBusy || !state.available('brightness')" @click="controlLightTransition('wake')">🌅 晨起唤醒</button>
|
||||
<button v-if="lightTransition?.running" type="button" :disabled="operationBusy" @click="controlLightTransition('stop')">停止渐变</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 亮度滑块 -->
|
||||
<div class="param-row">
|
||||
<div class="param-header">
|
||||
<span class="p-title">灯光亮度</span>
|
||||
<strong class="p-val">{{ lightTransition?.running ? `${localParams.lightBrightness}%` : state.display('brightness', localParams.lightBrightness, '%') }}</strong>
|
||||
</div>
|
||||
<VanSlider
|
||||
v-model="localParams.lightBrightness"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:disabled="operationBusy || !state.available('brightness')"
|
||||
active-color="#d6a657"
|
||||
@change="applyParam(lightDevice.deviceId, 'brightness', localParams.lightBrightness)"
|
||||
/>
|
||||
<div class="slider-scale">
|
||||
<span>0% 关闭灯光</span>
|
||||
<span>50% 舒缓</span>
|
||||
<span>100% 满亮</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 色温滑块 -->
|
||||
<div class="param-row">
|
||||
<div class="param-header">
|
||||
<span class="p-title">灯光色温调节</span>
|
||||
<strong class="p-val">{{ state.display('color_temp', localParams.lightColorTemp, 'K') }}</strong>
|
||||
</div>
|
||||
<VanSlider
|
||||
v-model="localParams.lightColorTemp"
|
||||
:min="2200"
|
||||
:max="5000"
|
||||
:step="50"
|
||||
:disabled="operationBusy || !state.available('color_temp')"
|
||||
active-color="#c87f2b"
|
||||
@change="applyParam(lightDevice.deviceId, 'color_temp', localParams.lightColorTemp)"
|
||||
/>
|
||||
<div class="slider-scale">
|
||||
<span>2200K 超暖橙光 (利于褪黑素)</span>
|
||||
<span>5000K 清爽白光</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="light-mode-actions">
|
||||
<button type="button" :disabled="operationBusy || !lightCapabilities(device).available || !lightCapabilities(device).canDim" @click="controlLightTransition('sleep')">🌙 开始助眠渐暗</button>
|
||||
<button type="button" :disabled="operationBusy || !lightCapabilities(device).available || !lightCapabilities(device).canDim" @click="controlLightTransition('wake')">🌅 晨起唤醒</button>
|
||||
<button v-if="transition?.running" type="button" :disabled="operationBusy" @click="controlLightTransition('stop')">停止渐变</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
</StandardLightCard>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { Button as VanButton } from 'vant'
|
||||
import type { HomeAssistantDiscoveredDevice } from '../../services/health'
|
||||
import { useDeviceControlContext } from '../../devices/controlContext'
|
||||
import { lightCapabilities } from '../../devices/lighting/capabilities'
|
||||
import StandardLightControls from './StandardLightControls.vue'
|
||||
import { lightTransitionForDevice } from '../../devices/lighting/transitions'
|
||||
const props = withDefaults(defineProps<{ device: HomeAssistantDiscoveredDevice; categoryLabel?: string; note?: string; reportedBrightness?: number }>(),
|
||||
{ categoryLabel: '灯光控制' })
|
||||
const { operationBusy, switchingDeviceId, toggleDevice, lightTransition } = useDeviceControlContext()
|
||||
const capability = computed(() => lightCapabilities(props.device))
|
||||
const transition = computed(() => lightTransitionForDevice(props.device, lightTransition.value))
|
||||
const brightness = computed(() => props.reportedBrightness ?? (transition.value?.running ? transition.value.brightnessPercent : undefined))
|
||||
const note = computed(() => props.note ?? (props.device.defaultLightEffect
|
||||
? '已加入一键舒睡和关闭;从50%开始,每5秒降低1%,最终关灯。手动调节仅停止本灯渐变。'
|
||||
: '按本灯实际上报的能力显示参数;单独控制,不自动加入舒睡或唤醒场景。'))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="device-card">
|
||||
<div class="device-head">
|
||||
<div class="dev-info"><span class="category-tag">{{ categoryLabel }}</span><h3>{{ device.name }}</h3>
|
||||
<span class="status-dot" :class="{ online: capability.available }">{{ capability.available ? capability.entity?.state === 'on' ? '已点亮' : '已熄灭' : '灯光主控当前不可用' }}</span>
|
||||
</div>
|
||||
<VanButton size="small" round :type="capability.entity?.state === 'on' ? 'primary' : 'default'"
|
||||
:loading="switchingDeviceId === device.deviceId" :disabled="operationBusy || !capability.available" @click="toggleDevice(device)">
|
||||
{{ capability.available ? capability.entity?.state === 'on' ? '关闭' : '开启' : '暂不可用' }}
|
||||
</VanButton>
|
||||
</div>
|
||||
<div class="params-body">
|
||||
<slot name="before-controls" />
|
||||
<p v-if="device.defaultLightEffect && (transition?.running || transition?.message)" class="scale-note"
|
||||
:class="{ unavailable: transition?.success === false }">{{ transition?.running ? `助眠渐暗中 · ${transition.brightnessPercent}%` : transition?.message }}</p>
|
||||
<StandardLightControls :device="device" :reported-brightness="brightness" />
|
||||
<slot name="after-controls" />
|
||||
<p class="scale-note">{{ note }}</p>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import { Slider as VanSlider } from 'vant'
|
||||
import type { HomeAssistantDiscoveredDevice } from '../../services/health'
|
||||
import { useDeviceControlContext } from '../../devices/controlContext'
|
||||
import { useLightControls } from '../../devices/lighting/useLightControls'
|
||||
const props = defineProps<{ device: HomeAssistantDiscoveredDevice; reportedBrightness?: number }>()
|
||||
const { operationBusy, applyParam } = useDeviceControlContext()
|
||||
const { capability, brightnessReading, brightnessTarget, temperatureTarget, effectTarget, defaultEffect, setBrightness, setTemperature, setEffect } =
|
||||
useLightControls(() => props.device, () => operationBusy.value, applyParam, () => props.reportedBrightness)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="capability.canDim" class="param-row">
|
||||
<div class="param-header"><span class="p-title">灯光亮度</span><strong class="p-val">{{ brightnessReading === undefined ? '--' : `${brightnessReading}%` }}</strong></div>
|
||||
<VanSlider v-model="brightnessTarget" :min="0" :max="100" :step="1" :disabled="operationBusy || !capability.available"
|
||||
active-color="#d6a657" aria-label="待设置的灯光亮度" @change="setBrightness" />
|
||||
<div class="slider-scale"><span>0% 关闭</span><span>100% 满亮</span></div>
|
||||
<p v-if="capability.available" class="scale-note">目标亮度 {{ brightnessTarget }}%;滑动后设置,非当前回读值。</p>
|
||||
</div>
|
||||
<div v-if="capability.temperatureRange" class="param-row">
|
||||
<div class="param-header"><span class="p-title">灯光色温调节</span><strong class="p-val">{{ capability.colorTemperature === undefined ? '--' : `${capability.colorTemperature}K` }}</strong></div>
|
||||
<VanSlider v-model="temperatureTarget" :min="capability.temperatureRange.min" :max="capability.temperatureRange.max" :step="1"
|
||||
:disabled="operationBusy || !capability.available" active-color="#c87f2b" aria-label="待设置的灯光色温" @change="setTemperature" />
|
||||
<div class="slider-scale"><span>{{ capability.temperatureRange.min }}K 暖光</span><span>{{ capability.temperatureRange.max }}K 冷光</span></div>
|
||||
<p v-if="capability.available" class="scale-note">目标色温 {{ temperatureTarget }}K;滑动后设置,关灯时调节会点亮灯。</p>
|
||||
</div>
|
||||
<div v-if="capability.effects.length" class="param-row">
|
||||
<div class="param-header"><span class="p-title">灯光模式</span><strong class="p-val">{{ capability.effect || '--' }}</strong></div>
|
||||
<select v-model="effectTarget" class="standard-light-select" aria-label="选择灯光模式" :disabled="operationBusy || !capability.available" @change="setEffect">
|
||||
<option value="" disabled>选择要设置的模式</option>
|
||||
<option v-for="effect in capability.effects" :key="effect" :value="effect">{{ effect }}</option>
|
||||
</select>
|
||||
<p class="scale-note">使用这盏灯实际提供的模式;选择后可能点亮灯。</p>
|
||||
<p v-if="defaultEffect" class="scale-note">舒睡默认 {{ defaultEffect }};实际模式以顶部回读为准。</p>
|
||||
</div>
|
||||
<p v-if="!capability.canDim && !capability.temperatureRange && !capability.effects.length" class="scale-note">这盏灯未上报可用的调光能力,目前仅提供开关。</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.standard-light-select { width: 100%; min-height: 40px; padding: 8px 12px; border: 1px solid #d9e6de; border-radius: 10px; background: #fff; color: #174d40; font: inherit; font-size: 13px; }
|
||||
.standard-light-select:disabled { opacity: .5; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user