feat(mini): align companion pages and show OTA progress
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
import FirmwareProgress from '@/components/firmware-progress'
|
||||
import { getRoleArtwork } from '@/utils/artwork'
|
||||
import { getPageStyle } from '@/utils/page-style'
|
||||
import { View, Text, Image, Input, Button } from '@tarojs/components'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import Taro, { useDidHide, useDidShow, useShareAppMessage } from '@tarojs/taro'
|
||||
@@ -82,6 +85,10 @@ export default function Sleep() {
|
||||
const [binding, setBinding] = useState<BindingListItem | null>(null)
|
||||
const [currentChild, setCurrentChild] = useState<Child | null>(null)
|
||||
const [firmwareStatus, setFirmwareStatus] = useState<DeviceFirmwareStatus | null>(null)
|
||||
const [showFirmwareProgress, setShowFirmwareProgress] = useState(false)
|
||||
const [firmwareRefreshError, setFirmwareRefreshError] = useState(false)
|
||||
const firmwareLoadGenerationRef = useRef(0)
|
||||
const firmwareDeviceIdRef = useRef('')
|
||||
const [deviceRole, setDeviceRole] = useState<DeviceCurrentRole | null>(null)
|
||||
const [roles, setRoles] = useState<DeviceRoleSummary[]>([])
|
||||
const [currentCardGroup, setCurrentCardGroup] = useState<BindingCardGroupItem | null>(null)
|
||||
@@ -269,6 +276,7 @@ export default function Sleep() {
|
||||
if (firmwareStatusPollDeviceIdRef.current !== normalizedDeviceId) return
|
||||
|
||||
setFirmwareStatus(nextFirmwareStatus)
|
||||
setFirmwareRefreshError(false)
|
||||
if (isFirmwareUpdateInProgress(nextFirmwareStatus?.update_status)) {
|
||||
scheduleFirmwareStatusPoll(normalizedDeviceId)
|
||||
return
|
||||
@@ -283,6 +291,7 @@ export default function Sleep() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('[manage] firmware poll failed:', error)
|
||||
if (firmwareStatusPollDeviceIdRef.current === normalizedDeviceId) setFirmwareRefreshError(true)
|
||||
if (firmwareStatusPollDeviceIdRef.current === normalizedDeviceId) {
|
||||
scheduleFirmwareStatusPoll(normalizedDeviceId)
|
||||
}
|
||||
@@ -293,6 +302,13 @@ export default function Sleep() {
|
||||
|
||||
const loadFirmwareStatus = async (deviceId?: string | null) => {
|
||||
const normalizedDeviceId = String(deviceId || '').trim()
|
||||
const generation = ++firmwareLoadGenerationRef.current
|
||||
if (firmwareDeviceIdRef.current !== normalizedDeviceId) {
|
||||
setShowFirmwareProgress(false)
|
||||
setFirmwareStatus(null)
|
||||
stopFirmwareStatusPolling()
|
||||
}
|
||||
firmwareDeviceIdRef.current = normalizedDeviceId
|
||||
if (!normalizedDeviceId) {
|
||||
setFirmwareStatus(null)
|
||||
setIsLoadingFirmware(false)
|
||||
@@ -303,9 +319,13 @@ export default function Sleep() {
|
||||
setIsLoadingFirmware(true)
|
||||
try {
|
||||
const nextFirmwareStatus = await getDeviceFirmwareStatus(normalizedDeviceId)
|
||||
if (generation !== firmwareLoadGenerationRef.current) return
|
||||
setFirmwareStatus(nextFirmwareStatus)
|
||||
setFirmwareRefreshError(false)
|
||||
if (isFirmwareUpdateInProgress(nextFirmwareStatus?.update_status)) setShowFirmwareProgress(true)
|
||||
syncFirmwareStatusPolling(normalizedDeviceId, nextFirmwareStatus)
|
||||
} catch (error: any) {
|
||||
if (generation !== firmwareLoadGenerationRef.current) return
|
||||
console.error('[manage] firmware load failed:', error)
|
||||
setFirmwareStatus(null)
|
||||
if (firmwareStatusPollDeviceIdRef.current === normalizedDeviceId) {
|
||||
@@ -316,7 +336,7 @@ export default function Sleep() {
|
||||
icon: 'none',
|
||||
})
|
||||
} finally {
|
||||
setIsLoadingFirmware(false)
|
||||
if (generation === firmwareLoadGenerationRef.current) setIsLoadingFirmware(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,6 +769,9 @@ export default function Sleep() {
|
||||
}
|
||||
|
||||
const nextFirmwareStatus = await startDeviceFirmwareUpdate(binding.device_id)
|
||||
if (firmwareDeviceIdRef.current !== binding.device_id) return
|
||||
setShowFirmwareProgress(true)
|
||||
setFirmwareRefreshError(false)
|
||||
setFirmwareStatus(nextFirmwareStatus)
|
||||
syncFirmwareStatusPolling(binding.device_id, nextFirmwareStatus)
|
||||
Taro.showToast({
|
||||
@@ -961,7 +984,7 @@ export default function Sleep() {
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<View className='manage-page'>
|
||||
<View className='manage-page' style={getPageStyle(true)}>
|
||||
<View className='loading'>
|
||||
<Text>加载中...</Text>
|
||||
</View>
|
||||
@@ -972,7 +995,7 @@ export default function Sleep() {
|
||||
|
||||
if (isGuest) {
|
||||
return (
|
||||
<View className='manage-page'>
|
||||
<View className='manage-page' style={getPageStyle(true)}>
|
||||
<View className='page-header'>
|
||||
<Text className='page-title'>设置与管理</Text>
|
||||
</View>
|
||||
@@ -1054,7 +1077,7 @@ export default function Sleep() {
|
||||
: isUpdatingFirmware
|
||||
? '发送中'
|
||||
: isFirmwareUpdatingByStatus
|
||||
? '更新中'
|
||||
? '查看进度'
|
||||
: firmwareStatus?.update_available
|
||||
? '更新'
|
||||
: '已最新'
|
||||
@@ -1093,7 +1116,7 @@ export default function Sleep() {
|
||||
: `${currentCardGroup?.card_count || 0} 张`
|
||||
const menuItems: MenuItem[] = [
|
||||
{
|
||||
icon: require('../../assets/tab-icons/orange-robot.png'),
|
||||
icon: require('../../assets/ui/menu-role.png'),
|
||||
iconBgClass: 'orange',
|
||||
name: '当前宝贝',
|
||||
value: currentChildName,
|
||||
@@ -1101,7 +1124,7 @@ export default function Sleep() {
|
||||
},
|
||||
...(unassignedBindings.length > 0
|
||||
? [{
|
||||
icon: require('../../assets/tab-icons/rings.png'),
|
||||
icon: require('../../assets/ui/menu-binding.png'),
|
||||
iconBgClass: 'green',
|
||||
name: '关联现有设备',
|
||||
value: `${unassignedBindings.length} 台待关联`,
|
||||
@@ -1109,14 +1132,14 @@ export default function Sleep() {
|
||||
}]
|
||||
: []),
|
||||
{
|
||||
icon: require('../../assets/tab-icons/rings.png'),
|
||||
icon: require('../../assets/ui/menu-binding.png'),
|
||||
iconBgClass: 'green',
|
||||
name: '绑定设备',
|
||||
value: binding?.device_id ? `当前: ${binding.device_id}` : '未绑定',
|
||||
arrow: true,
|
||||
},
|
||||
{
|
||||
icon: require('../../assets/tab-icons/rings.png'),
|
||||
icon: require('../../assets/ui/menu-cards.png'),
|
||||
iconBgClass: 'green',
|
||||
name: '我的卡片',
|
||||
value: cardValue,
|
||||
@@ -1124,7 +1147,7 @@ export default function Sleep() {
|
||||
disabled: !binding,
|
||||
},
|
||||
{
|
||||
icon: require('../../assets/tab-icons/orange-robot.png'),
|
||||
icon: require('../../assets/ui/menu-role.png'),
|
||||
iconBgClass: 'green',
|
||||
name: 'AI 角色',
|
||||
value: roleValue,
|
||||
@@ -1132,7 +1155,7 @@ export default function Sleep() {
|
||||
disabled: !binding,
|
||||
},
|
||||
{
|
||||
icon: require('../../assets/tab-icons/rings.png'),
|
||||
icon: require('../../assets/ui/menu-family.png'),
|
||||
iconBgClass: 'green',
|
||||
name: '家庭成员',
|
||||
value: familyValue,
|
||||
@@ -1140,7 +1163,7 @@ export default function Sleep() {
|
||||
disabled: !binding,
|
||||
},
|
||||
{
|
||||
icon: require('../../assets/tab-icons/rings.png'),
|
||||
icon: require('../../assets/ui/menu-notice.png'),
|
||||
iconBgClass: 'green',
|
||||
name: '服务号通知',
|
||||
value: wechatMpValue,
|
||||
@@ -1148,7 +1171,7 @@ export default function Sleep() {
|
||||
disabled: isStartingWechatMpBind,
|
||||
},
|
||||
{
|
||||
icon: require('../../assets/tab-icons/broken-rings.png'),
|
||||
icon: require('../../assets/ui/menu-unbind.png'),
|
||||
iconBgClass: 'red',
|
||||
name: '解除设备绑定',
|
||||
value: binding?.device_id ? `当前: ${binding.device_id}` : '',
|
||||
@@ -1158,7 +1181,7 @@ export default function Sleep() {
|
||||
]
|
||||
|
||||
return (
|
||||
<View className='manage-page'>
|
||||
<View className='manage-page' style={getPageStyle(true)}>
|
||||
<View className='page-header'>
|
||||
<Text className='page-title'>设置与管理</Text>
|
||||
</View>
|
||||
@@ -1210,12 +1233,15 @@ export default function Sleep() {
|
||||
<View className={`system-update-card ${binding?.device_id ? '' : 'disabled'}`}>
|
||||
<View className='system-update-header'>
|
||||
<View className='system-update-heading'>
|
||||
<Text className='system-update-title'>系统更新</Text>
|
||||
<View className='system-update-title-row'>
|
||||
<Image className='system-update-icon' src={require('../../assets/ui/menu-update.png')} mode='aspectFit' />
|
||||
<Text className='system-update-title'>系统更新</Text>
|
||||
</View>
|
||||
<Text className='system-update-subtitle'>{firmwareSubtitle}</Text>
|
||||
</View>
|
||||
<View
|
||||
className={`system-update-action ${canUpdateFirmware ? '' : 'disabled'}`}
|
||||
onClick={canUpdateFirmware ? handleStartFirmwareUpdate : undefined}
|
||||
className={`system-update-action ${canUpdateFirmware || isFirmwareUpdatingByStatus ? '' : 'disabled'}`}
|
||||
onClick={isFirmwareUpdatingByStatus ? () => setShowFirmwareProgress(true) : canUpdateFirmware ? handleStartFirmwareUpdate : undefined}
|
||||
>
|
||||
<Text className='system-update-action-text'>{firmwareActionText}</Text>
|
||||
</View>
|
||||
@@ -1266,6 +1292,12 @@ export default function Sleep() {
|
||||
<Text className='version-text'>伴伴 Companion V1.1.0</Text>
|
||||
</View>
|
||||
|
||||
{showFirmwareProgress && firmwareStatus?.device_id === binding?.device_id && (
|
||||
<FirmwareProgress status={firmwareStatus} refreshError={firmwareRefreshError}
|
||||
onClose={() => setShowFirmwareProgress(false)}
|
||||
onRetry={canUpdateFirmware ? () => { setShowFirmwareProgress(false); handleStartFirmwareUpdate() } : undefined} />
|
||||
)}
|
||||
|
||||
{showChildModal && (
|
||||
<View className='modal-mask' onClick={() => setShowChildModal(false)}>
|
||||
<View
|
||||
@@ -1443,7 +1475,8 @@ export default function Sleep() {
|
||||
{showModal && (
|
||||
<View className='modal-mask'>
|
||||
<View className='modal-card'>
|
||||
<Text className='modal-title'>修改宝贝姓名</Text>
|
||||
<Text className='modal-title'>编辑宝贝资料</Text>
|
||||
<Text className='modal-field-label'>宝贝名称</Text>
|
||||
<View className='modal-input-wrap'>
|
||||
<Input
|
||||
className='modal-input'
|
||||
@@ -1459,7 +1492,7 @@ export default function Sleep() {
|
||||
取消
|
||||
</Text>
|
||||
<Text className='modal-action confirm' onClick={handleSubmitModal}>
|
||||
确认
|
||||
保存
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -1520,6 +1553,7 @@ export default function Sleep() {
|
||||
className={`role-switch-item ${isActive ? 'active' : ''} ${isUpdatingRole ? 'disabled' : ''}`}
|
||||
onClick={isUpdatingRole ? undefined : () => handleSelectRole(item)}
|
||||
>
|
||||
<Image className='role-switch-art' src={getRoleArtwork(item.role_key)} mode='aspectFit' />
|
||||
<View className='role-switch-head'>
|
||||
<Text className='role-switch-name'>{item.name || item.role_key}</Text>
|
||||
{isActive && <Text className='device-switch-tag'>当前</Text>}
|
||||
|
||||
Reference in New Issue
Block a user