diff --git a/banban-mini/src/pages/sleep/index.tsx b/banban-mini/src/pages/sleep/index.tsx index 4de552f..8a85dbe 100644 --- a/banban-mini/src/pages/sleep/index.tsx +++ b/banban-mini/src/pages/sleep/index.tsx @@ -1,6 +1,6 @@ import { View, Text, Image, Input, Button } from '@tarojs/components' -import { useState } from 'react' -import Taro, { useDidShow, useShareAppMessage } from '@tarojs/taro' +import { useEffect, useRef, useState } from 'react' +import Taro, { useDidHide, useDidShow, useShareAppMessage } from '@tarojs/taro' import { authorizeParentPhone, clearToken, getParent, getToken, Parent } from '@/services/auth' import { DEVICE_UNAVAILABLE_MESSAGE } from '@/services/api' import { getCurrentUserId } from '@/services/session' @@ -48,6 +48,22 @@ interface MenuItem { disabled?: boolean } +const FIRMWARE_STATUS_POLL_INTERVAL_MS = 3000 +const FIRMWARE_UPDATE_IN_PROGRESS_STATUSES = new Set(['sent', 'accepted', 'updating']) +const FIRMWARE_UPDATE_SUCCESS_STATUSES = new Set(['success', 'completed']) + +function normalizeFirmwareUpdateStatus(status?: string | null): string { + return String(status || '').trim().toLowerCase() +} + +function isFirmwareUpdateInProgress(status?: string | null): boolean { + return FIRMWARE_UPDATE_IN_PROGRESS_STATUSES.has(normalizeFirmwareUpdateStatus(status)) +} + +function isFirmwareUpdateSuccessful(status?: string | null): boolean { + return FIRMWARE_UPDATE_SUCCESS_STATUSES.has(normalizeFirmwareUpdateStatus(status)) +} + export default function Sleep() { const systemBanner = useSystemBanner() const [loading, setLoading] = useState(true) @@ -89,11 +105,22 @@ export default function Sleep() { const [familyMemberDisplayName, setFamilyMemberDisplayName] = useState('') const [parentInfo, setParentInfo] = useState(null) const [isAuthorizingPhone, setIsAuthorizingPhone] = useState(false) + const firmwareStatusPollTimerRef = useRef | null>(null) + const firmwareStatusPollDeviceIdRef = useRef('') + const isFirmwareStatusPollingRef = useRef(false) useDidShow(() => { void loadData() }) + useDidHide(() => { + stopFirmwareStatusPolling() + }) + + useEffect(() => () => { + stopFirmwareStatusPolling() + }, []) + useShareAppMessage(() => { const targetName = currentChild?.child_name || binding?.device_id || '孩子' return { @@ -145,11 +172,92 @@ export default function Sleep() { const currentChildName = currentChild?.child_name || '未设置' + function clearFirmwareStatusPollTimer() { + if (firmwareStatusPollTimerRef.current) { + clearTimeout(firmwareStatusPollTimerRef.current) + firmwareStatusPollTimerRef.current = null + } + } + + function stopFirmwareStatusPolling() { + clearFirmwareStatusPollTimer() + firmwareStatusPollDeviceIdRef.current = '' + isFirmwareStatusPollingRef.current = false + } + + function scheduleFirmwareStatusPoll(deviceId: string) { + clearFirmwareStatusPollTimer() + firmwareStatusPollTimerRef.current = setTimeout(() => { + void pollFirmwareStatus(deviceId) + }, FIRMWARE_STATUS_POLL_INTERVAL_MS) + } + + function startFirmwareStatusPolling(deviceId: string) { + const normalizedDeviceId = String(deviceId || '').trim() + if (!normalizedDeviceId) return + + firmwareStatusPollDeviceIdRef.current = normalizedDeviceId + scheduleFirmwareStatusPoll(normalizedDeviceId) + } + + function syncFirmwareStatusPolling(deviceId: string, nextFirmwareStatus?: DeviceFirmwareStatus | null) { + const normalizedDeviceId = String(deviceId || '').trim() + if (!normalizedDeviceId) { + stopFirmwareStatusPolling() + return + } + + if (isFirmwareUpdateInProgress(nextFirmwareStatus?.update_status)) { + startFirmwareStatusPolling(normalizedDeviceId) + } else { + stopFirmwareStatusPolling() + } + } + + async function pollFirmwareStatus(deviceId: string) { + const normalizedDeviceId = String(deviceId || '').trim() + if ( + !normalizedDeviceId || + firmwareStatusPollDeviceIdRef.current !== normalizedDeviceId || + isFirmwareStatusPollingRef.current + ) { + return + } + + isFirmwareStatusPollingRef.current = true + try { + const nextFirmwareStatus = await getDeviceFirmwareStatus(normalizedDeviceId) + if (firmwareStatusPollDeviceIdRef.current !== normalizedDeviceId) return + + setFirmwareStatus(nextFirmwareStatus) + if (isFirmwareUpdateInProgress(nextFirmwareStatus?.update_status)) { + scheduleFirmwareStatusPoll(normalizedDeviceId) + return + } + + stopFirmwareStatusPolling() + const nextStatus = normalizeFirmwareUpdateStatus(nextFirmwareStatus?.update_status) + if (isFirmwareUpdateSuccessful(nextStatus)) { + Taro.showToast({ title: '系统更新完成', icon: 'success' }) + } else if (nextStatus === 'failed') { + Taro.showToast({ title: '系统更新失败,可重试', icon: 'none' }) + } + } catch (error) { + console.warn('[manage] firmware poll failed:', error) + if (firmwareStatusPollDeviceIdRef.current === normalizedDeviceId) { + scheduleFirmwareStatusPoll(normalizedDeviceId) + } + } finally { + isFirmwareStatusPollingRef.current = false + } + } + const loadFirmwareStatus = async (deviceId?: string | null) => { const normalizedDeviceId = String(deviceId || '').trim() if (!normalizedDeviceId) { setFirmwareStatus(null) setIsLoadingFirmware(false) + stopFirmwareStatusPolling() return } @@ -157,9 +265,13 @@ export default function Sleep() { try { const nextFirmwareStatus = await getDeviceFirmwareStatus(normalizedDeviceId) setFirmwareStatus(nextFirmwareStatus) + syncFirmwareStatusPolling(normalizedDeviceId, nextFirmwareStatus) } catch (error: any) { console.error('[manage] firmware load failed:', error) setFirmwareStatus(null) + if (firmwareStatusPollDeviceIdRef.current === normalizedDeviceId) { + stopFirmwareStatusPolling() + } Taro.showToast({ title: error?.message || '系统更新状态加载失败', icon: 'none', @@ -551,7 +663,15 @@ export default function Sleep() { } const handleStartFirmwareUpdate = () => { - if (!binding?.device_id || !firmwareStatus?.can_update || isLoadingFirmware || isUpdatingFirmware) return + if ( + !binding?.device_id || + !firmwareStatus?.can_update || + isLoadingFirmware || + isUpdatingFirmware || + isFirmwareUpdateInProgress(firmwareStatus.update_status) + ) { + return + } Taro.showModal({ title: '系统更新', @@ -574,6 +694,7 @@ export default function Sleep() { const nextFirmwareStatus = await startDeviceFirmwareUpdate(binding.device_id) setFirmwareStatus(nextFirmwareStatus) + syncFirmwareStatusPolling(binding.device_id, nextFirmwareStatus) Taro.showToast({ title: '更新指令已发送', icon: 'success', @@ -787,8 +908,25 @@ export default function Sleep() { familyInfo?.device_id === binding.device_id && isFamilyOwner ) - const canUpdateFirmware = Boolean(binding?.device_id && firmwareStatus?.can_update && !isLoadingFirmware && !isUpdatingFirmware) - const firmwareActionText = isLoadingFirmware ? '查询中' : isUpdatingFirmware ? '发送中' : '更新' + const isFirmwareUpdatingByStatus = isFirmwareUpdateInProgress(firmwareStatus?.update_status) + const canUpdateFirmware = Boolean( + binding?.device_id && + firmwareStatus?.can_update && + !isLoadingFirmware && + !isUpdatingFirmware && + !isFirmwareUpdatingByStatus + ) + const firmwareActionText = !binding?.device_id + ? '更新' + : isLoadingFirmware + ? '查询中' + : isUpdatingFirmware + ? '发送中' + : isFirmwareUpdatingByStatus + ? '更新中' + : firmwareStatus?.update_available + ? '更新' + : '已最新' const roleValue = !binding?.device_id ? '未绑定' : isLoadingRoles @@ -803,9 +941,13 @@ export default function Sleep() { ? '绑定设备后可查看系统版本' : isLoadingFirmware ? '正在查询当前设备版本' - : firmwareStatus?.update_available - ? '发现可更新版本' - : '当前设备版本状态' + : isFirmwareUpdatingByStatus + ? '设备正在更新,请稍候' + : normalizeFirmwareUpdateStatus(firmwareStatus?.update_status) === 'failed' + ? '更新失败,可重试' + : firmwareStatus?.update_available + ? '发现可更新版本' + : '当前设备版本状态' const menuItems: MenuItem[] = [ { icon: require('../../assets/tab-icons/orange-robot.png'),