import { useState, useCallback } from 'react' import { useDidShow } from '@tarojs/taro' import { View, Text } from '@tarojs/components' import { useAppSelector, useAppDispatch } from '@/store/hooks' import { setDeviceList, type Device } from '@/store/deviceSlice' import { Navbar } from '@/components/navbar' import { Loading } from '@/components/loading' import { StateView } from '@/components/state-view' import { BottomSheet } from '@/components/bottom-sheet' import { getDeviceList } from '@/api/device' import { DEVICE_ICON_MAP, type DeviceModel } from '@/constants/enums' import { ROUTES } from '@/constants/routes' import { navigateTo } from '@/utils/navigation' import { getFamilies, type Family } from '@/api/family' import styles from './index.module.scss' const FALLBACK_ICON = '⌂' export default function DeviceList() { const dispatch = useAppDispatch() const scene = useAppSelector((s) => s.scene.current) const deviceList = useAppSelector((s) => s.device.list) const [loading, setLoading] = useState(true) const [loadError, setLoadError] = useState(false) const [families, setFamilies] = useState([]) const [currentFamily, setCurrentFamily] = useState(null) const [familySheetOpen, setFamilySheetOpen] = useState(false) const [pendingFamily, setPendingFamily] = useState(null) // 在线状态需每次进入页面都新鲜:useDidShow 覆盖 // 首次进入、从详情页 navigateBack 返回、tab 切换回三种场景 const loadDevices = useCallback(async () => { setLoading(true) setLoadError(false) try { const data = await getDeviceList(scene?.id ?? null) dispatch(setDeviceList(data)) } catch { setLoadError(true) } finally { setLoading(false) } }, [dispatch, scene?.id]) const loadFamilies = useCallback(async () => { try { const list = await getFamilies() setFamilies(list) // 若当前未选中,默认选第一条 setCurrentFamily((prev) => prev ?? list[0] ?? null) } catch { // 静默:家庭圈加载失败不阻断设备列表 } }, []) useDidShow(() => { loadDevices() loadFamilies() }) const goDetail = (device: Device) => { const name = encodeURIComponent(device.name) navigateTo(`${ROUTES.DEVICE_DETAIL}?id=${device.id}&name=${name}&model=${device.model}&online=${device.online ? 1 : 0}`) } const goAdd = () => navigateTo(ROUTES.DEVICE_ADD) const goRoom = () => navigateTo(ROUTES.SCENE_SELECT) const iconOf = (model: DeviceModel) => DEVICE_ICON_MAP[model] ?? FALLBACK_ICON const openFamilySheet = () => { setPendingFamily(currentFamily) setFamilySheetOpen(true) } const closeFamilySheet = () => { setFamilySheetOpen(false) setPendingFamily(null) } const confirmFamilySheet = () => { if (pendingFamily) setCurrentFamily(pendingFamily) closeFamilySheet() } return ( {/* 绿色衬底:承接浮卡的上浮区,避免 -40px 压到导航标题 */} {/* 设备应用家庭信息卡 */} 设备应用家庭 {currentFamily?.name ?? scene?.name ?? '未选择'} 关爱对象 {currentFamily?.caredLabel ?? '--'} 关爱地址 {currentFamily?.address ?? '--'} 切换家庭圈 {/* 房间管理 + 添加设备 两张并排 */} ⌂ 房间管理 + 添加设备 {/* 设备网格 */} {loading ? ( ) : loadError ? ( ) : deviceList.length === 0 ? ( ) : ( {deviceList.map((device) => ( goDetail(device)}> {iconOf(device.model)} {device.name} {device.online ? '在线' : '离线'} ))} )} {/* 切换家庭圈弹层 */} {families.map((family) => { const active = pendingFamily?.id === family.id return ( setPendingFamily(family)} > {family.name} {family.role && ( {family.role} )} 关爱对象 {family.caredLabel} 设备数量 {family.deviceCount}台 ) })} 确定 ) }