111
This commit is contained in:
@@ -219,14 +219,6 @@ export type HomeAssistantLightTransition = {
|
||||
message: string
|
||||
}
|
||||
|
||||
export type HomeAssistantSpeakerDemo = {
|
||||
audioUrl: string
|
||||
speakerOnline: boolean
|
||||
directPlaybackSupported: boolean
|
||||
commandAccepted: boolean
|
||||
message: string
|
||||
}
|
||||
|
||||
export type HomeAssistantStatus = {
|
||||
connected: boolean
|
||||
message: string
|
||||
@@ -299,10 +291,6 @@ export const healthApi = {
|
||||
http.post<never, HomeAssistantLightTransition>('/api/health/home-assistant/lights/wake'),
|
||||
stopLightTransition: () =>
|
||||
http.post<never, HomeAssistantLightTransition>('/api/health/home-assistant/lights/stop'),
|
||||
speakerDemoStatus: () =>
|
||||
http.get<never, HomeAssistantSpeakerDemo>('/api/health/home-assistant/speaker/demo'),
|
||||
playSpeakerDemo: () =>
|
||||
http.post<never, HomeAssistantSpeakerDemo>('/api/health/home-assistant/speaker/play-demo'),
|
||||
executeSleepScene: () =>
|
||||
http.post<never, HomeAssistantSceneResult>('/api/health/home-assistant/scenes/sleep', undefined, { timeout: 90000 }),
|
||||
executeAllOffScene: () =>
|
||||
|
||||
@@ -138,7 +138,7 @@ onMounted(load)
|
||||
</div>
|
||||
<div class="startup-param-badge">
|
||||
<span class="lbl">8H 床垫</span>
|
||||
<strong>左右加热 {{ dashboard?.mattressComfort?.heatingLevel ?? 0 }} 档 · 软硬度{{ dashboard?.mattressComfort?.firmness || '待填写 BMI' }}</strong>
|
||||
<strong>左右加热 {{ dashboard?.mattressComfort?.heatingLevel ?? 0 }} 档 · 软硬度{{ dashboard?.mattressComfort?.firmness || '待填写 BMI' }} · 右侧全身轻柔按摩</strong>
|
||||
</div>
|
||||
<div class="startup-param-badge" v-if="dashboard?.sceneConfig?.enableUv">
|
||||
<span class="lbl">除湿消杀</span>
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
healthApi,
|
||||
type HomeAssistantDiscoveredDevice,
|
||||
type HomeAssistantLightTransition,
|
||||
type HomeAssistantSpeakerDemo,
|
||||
type HomeAssistantStatus,
|
||||
type MattressComfort,
|
||||
type TcmAssessmentResult
|
||||
@@ -31,8 +30,6 @@ const lastUpdatedAt = ref('')
|
||||
const actionFeedback = ref<{ type: 'success' | 'fail'; message: string }>()
|
||||
const lightTransition = ref<HomeAssistantLightTransition>()
|
||||
const lightActionBusy = ref(false)
|
||||
const speakerDemo = ref<HomeAssistantSpeakerDemo>()
|
||||
const speakerDemoBusy = ref(false)
|
||||
let lightProgressTimer: ReturnType<typeof setInterval> | undefined
|
||||
let lightPolling = false
|
||||
|
||||
@@ -73,11 +70,10 @@ function setFeedback(type: 'success' | 'fail', message: string) {
|
||||
}
|
||||
|
||||
const operationBusy = computed(() =>
|
||||
loading.value || lightActionBusy.value || speakerDemoBusy.value || Boolean(sceneRunning.value) || Boolean(settingParam.value) || Boolean(switchingDeviceId.value)
|
||||
loading.value || lightActionBusy.value || Boolean(sceneRunning.value) || Boolean(settingParam.value) || Boolean(switchingDeviceId.value)
|
||||
)
|
||||
|
||||
const currentOperationText = computed(() => {
|
||||
if (speakerDemoBusy.value) return '正在尝试播放示例音频…'
|
||||
if (lightActionBusy.value) return '正在切换灯光渐变模式…'
|
||||
if (sceneRunning.value === 'sleep') return '正在启动全屋舒睡模式…'
|
||||
if (sceneRunning.value === 'all-off') return '正在关闭场景设备…'
|
||||
@@ -188,14 +184,6 @@ async function loadStatus(notify = false) {
|
||||
if (controls.mattress_massage_right_part?.state) localParams.mattressMassageRightPart = controls.mattress_massage_right_part.state
|
||||
if (controls.mattress_massage_level?.state) localParams.mattressMassageLevel = controls.mattress_massage_level.state
|
||||
await syncLightTransitionStatus()
|
||||
try {
|
||||
speakerDemo.value = await healthApi.speakerDemoStatus()
|
||||
} catch (err) {
|
||||
speakerDemo.value = {
|
||||
audioUrl: '', speakerOnline: false, directPlaybackSupported: false, commandAccepted: false,
|
||||
message: err instanceof Error ? err.message : '音箱能力检测失败'
|
||||
}
|
||||
}
|
||||
lastUpdatedAt.value = new Intl.DateTimeFormat('zh-CN', {
|
||||
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false
|
||||
}).format(new Date())
|
||||
@@ -271,26 +259,6 @@ async function controlLightTransition(action: 'sleep' | 'wake' | 'stop') {
|
||||
}
|
||||
}
|
||||
|
||||
async function tryPlaySpeakerDemo() {
|
||||
if (!speakerDemo.value?.directPlaybackSupported || operationBusy.value) return
|
||||
speakerDemoBusy.value = true
|
||||
const loadingToast = showLoadingToast({ message: '正在尝试投放到音箱…', forbidClick: true, duration: 0 })
|
||||
try {
|
||||
const result = await healthApi.playSpeakerDemo()
|
||||
speakerDemo.value = result
|
||||
if (!result.commandAccepted) throw new Error(result.message)
|
||||
setFeedback('success', result.message)
|
||||
showSuccessToast('指令已发送,请确认音箱实际出声')
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : '投放失败'
|
||||
setFeedback('fail', message)
|
||||
showFailToast(message)
|
||||
} finally {
|
||||
loadingToast.close()
|
||||
speakerDemoBusy.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 查找具体设备
|
||||
const dehumidifierDevice = computed(() =>
|
||||
haStatus.value?.devices.find(d => d.category === 'EnvironmentControl')
|
||||
@@ -777,17 +745,6 @@ onUnmounted(() => {
|
||||
</div>
|
||||
|
||||
<div class="params-body">
|
||||
<div class="speaker-demo-panel">
|
||||
<strong>OSS 音频播放 Demo</strong>
|
||||
<small>先在手机试听,再检测能否投放到 Sound Pro。</small>
|
||||
<audio v-if="speakerDemo?.audioUrl" controls preload="none" :src="speakerDemo.audioUrl">
|
||||
当前浏览器不支持播放音频
|
||||
</audio>
|
||||
<p>{{ speakerDemo?.message || '正在检测音箱播放能力…' }}</p>
|
||||
<button type="button" :disabled="operationBusy || !speakerDemo?.directPlaybackSupported" @click="tryPlaySpeakerDemo">
|
||||
{{ speakerDemo?.directPlaybackSupported ? '尝试音箱播放' : '当前音箱集成暂不支持投放' }}
|
||||
</button>
|
||||
</div>
|
||||
<!-- 音量滑块 -->
|
||||
<div class="param-row">
|
||||
<div class="param-header">
|
||||
@@ -1544,29 +1501,6 @@ onUnmounted(() => {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.speaker-demo-panel {
|
||||
padding: 13px;
|
||||
border-radius: 12px;
|
||||
background: #f3f8f7;
|
||||
border: 1px solid #d9e9e5;
|
||||
}
|
||||
|
||||
.speaker-demo-panel strong,
|
||||
.speaker-demo-panel small,
|
||||
.speaker-demo-panel audio {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.speaker-demo-panel strong { font-size: 13px; color: #174d44; }
|
||||
.speaker-demo-panel small { margin-top: 4px; color: #647b75; font-size: 11px; }
|
||||
.speaker-demo-panel audio { width: 100%; margin-top: 10px; height: 38px; }
|
||||
.speaker-demo-panel p { margin: 10px 0; color: #526a64; font-size: 11px; line-height: 1.5; }
|
||||
.speaker-demo-panel button {
|
||||
width: 100%; padding: 9px 10px; border: 0; border-radius: 9px;
|
||||
background: #0c5045; color: #fff; font-size: 12px; font-weight: 600;
|
||||
}
|
||||
.speaker-demo-panel button:disabled { background: #b8c5c1; }
|
||||
|
||||
/* 滑块样式:左右各预留 10px 间距,使滑块在 0% 和 100% 端点时,外凸的圆形按钮完整居中且不被裁剪 */
|
||||
.param-row :deep(.van-slider) {
|
||||
margin: 10px 10px 14px 10px;
|
||||
|
||||
Reference in New Issue
Block a user