按设备回执确认音量调整完成

This commit is contained in:
stu2not
2026-06-05 17:12:48 +08:00
parent a52fa21ecf
commit d33212613b
11 changed files with 405 additions and 62 deletions

View File

@@ -1,11 +1,11 @@
import { View, Text, Slider, Image } from '@tarojs/components'
import { useState } from 'react'
import { useRef, useState } from 'react'
import Taro, { useDidShow } from '@tarojs/taro'
import { getToken } from '@/services/auth'
import { DEVICE_UNAVAILABLE_MESSAGE } from '@/services/api'
import { Binding, loadCurrentChildBindingContext } from '@/services/binding'
import { Child } from '@/services/child'
import { DeviceAlarmItem, DeviceStatus, getDeviceAlarms, getDeviceStatus, setDeviceRemoteSleepWake, setDeviceVolume } from '@/services/device'
import { DeviceAlarmItem, DeviceStatus, getDeviceAlarms, getDeviceStatus, getDeviceVolumeCommandStatus, setDeviceRemoteSleepWake, setDeviceVolume } from '@/services/device'
import { useSystemBanner } from '@/components/system-banner/use-system-banner'
import './index.scss'
@@ -41,6 +41,12 @@ function getSignalLabel(value?: number | null): string {
return '弱'
}
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
function formatBatteryDisplay(value?: number | null): { text: string; showPercent: boolean } {
if (value === null || value === undefined) return { text: '--', showPercent: false }
const normalized = Number(value)
@@ -123,6 +129,7 @@ export default function Device() {
const [isSavingVolume, setIsSavingVolume] = useState(false)
const [sleepWakePending, setSleepWakePending] = useState<'on' | 'off' | null>(null)
const [volumeValue, setVolumeValue] = useState(0)
const volumeCommandInFlightRef = useRef(false)
useDidShow(() => {
void loadDeviceInfo()
@@ -173,21 +180,42 @@ export default function Device() {
}
const handleVolumeChanging = (e: any) => {
if (volumeCommandInFlightRef.current) return
setVolumeValue(Number(e.detail?.value || 0))
}
const handleVolumeCommit = async (e: any) => {
if (!binding?.device_id) return
if (volumeCommandInFlightRef.current) return
const nextLevel = Number(e.detail?.value || 0)
const fallbackLevel = deviceStatus?.volume ?? volumeValue ?? 0
volumeCommandInFlightRef.current = true
setVolumeValue(nextLevel)
setIsSavingVolume(true)
try {
await setDeviceVolume(nextLevel, binding.device_id)
setDeviceStatus((current) => (current ? { ...current, volume: nextLevel } : current))
const command = await setDeviceVolume(nextLevel, binding.device_id)
let completedLevel: number | null = null
let failedMessage = ''
for (let attempt = 0; attempt < 13; attempt += 1) {
await sleep(800)
const status = await getDeviceVolumeCommandStatus(binding.device_id, command.time)
if (status.status === 'completed') {
completedLevel = status.current_level ?? nextLevel
break
}
if (status.status === 'failed' || status.status === 'timeout') {
failedMessage = status.error || (status.status === 'timeout' ? '设备未确认音量调整,请稍后查看设备状态' : '设备音量调整失败')
break
}
}
if (completedLevel === null) {
throw new Error(failedMessage || '设备未确认音量调整,请稍后查看设备状态')
}
setVolumeValue(completedLevel)
setDeviceStatus((current) => (current ? { ...current, volume: completedLevel } : current))
Taro.showToast({
title: '音量指令已发送',
title: '音量已成功调整',
icon: 'success',
})
} catch (error: any) {
@@ -200,6 +228,7 @@ export default function Device() {
icon: 'none',
})
} finally {
volumeCommandInFlightRef.current = false
setIsSavingVolume(false)
}
}
@@ -402,7 +431,7 @@ export default function Device() {
</View>
<View className='control-info'>
<Text className='control-name'></Text>
<Text className='control-detail'>{isSavingVolume ? '发送中...' : `当前 ${volumeLabel}`}</Text>
<Text className='control-detail'>{isSavingVolume ? '调整中...' : `当前 ${volumeLabel}`}</Text>
</View>
</View>
</View>
@@ -417,6 +446,7 @@ export default function Device() {
min={0}
max={100}
value={volumeValue}
disabled={isSavingVolume}
onChanging={handleVolumeChanging}
onChange={handleVolumeCommit}
activeColor='#FF8C42'

View File

@@ -65,6 +65,19 @@ export interface DeviceVolumeUpdateResponse {
device_id: string
level: number
msg_id: string
time: number
status: string
}
export interface DeviceVolumeCommandStatusResponse {
device_id: string
level: number
msg_id: string
time: number
status: 'sent' | 'completed' | 'failed' | string
current_level?: number | null
response_status?: string | null
error?: string | null
}
export interface DeviceSleepScheduleUpdateResponse {
@@ -179,6 +192,13 @@ export async function setDeviceVolume(level: number, deviceId?: string): Promise
})
}
export async function getDeviceVolumeCommandStatus(
deviceId: string,
commandTime: number,
): Promise<DeviceVolumeCommandStatusResponse> {
return request<DeviceVolumeCommandStatusResponse>(`/banban/devices/${deviceId}/volume/${commandTime}`)
}
export async function setDeviceSleepSchedule(
start: string,
end: string,