import { useState, useCallback } from 'react' import { useDidShow } from '@tarojs/taro' import Taro from '@tarojs/taro' import { View, Text, Image } from '@tarojs/components' import { Navbar } from '@/components/navbar' import { Loading } from '@/components/loading' import { StateView } from '@/components/state-view' import { BottomSheet } from '@/components/bottom-sheet' import { store } from '@/store' import { storage } from '@/utils/storage' import { getHomeDeviceList, type HomeDevice } from '@/api/homeDevice' import { getRoomList, type HomeRoom } from '@/api/homeRoom' import { getHomeList, type HomeInfo } from '@/api/home' import { resolveCurrentHome, setCurrentHomeId } from '@/store/currentHome' import { ROUTES } from '@/constants/routes' import { navigateTo } from '@/utils/navigation' import ed713Icon from '@/assets/device/ed713.png' import ed719Icon from '@/assets/device/ed719.png' import eb15Icon from '@/assets/device/eb15.jpg' import styles from './index.module.scss' const FALLBACK_ICON = '⌂' // 设备型号 → 产品图:sub-device 优先(EB15 是 EP832 网关下的子设备, // 在 deviceModel 中没有对应值,需要走 subDeviceType 分支)。后端有时把型号 // 放在 deviceModel、有时放 subDeviceType,所以两个字段都查一遍 const pickDeviceIcon = (device: HomeDevice): string | null => { const model = device.subDeviceType ?? device.deviceModel if (model === 'EB15') return eb15Icon if (model === 'ED713') return ed713Icon if (model === 'ED719') return ed719Icon return null } // 设备显示名:优先 name,未命名回落序列号 const deviceLabel = (device: HomeDevice): string => device.name || device.deviceName export default function DeviceList() { const [loading, setLoading] = useState(true) const [loadError, setLoadError] = useState(false) const [deviceList, setDeviceList] = useState([]) const [families, setFamilies] = useState([]) const [currentFamily, setCurrentFamily] = useState(null) const [familySheetOpen, setFamilySheetOpen] = useState(false) const [pendingFamily, setPendingFamily] = useState(null) // 房间筛选:'' 为全部房间 const [rooms, setRooms] = useState([]) const [filterRoomId, setFilterRoomId] = useState('') // 游客浏览:未登录不拉数据,展示引导登录(微信审核要求不强制授权) const isGuest = () => !store.getState().auth.token && !storage.get('auth_token') const isGuestEmpty = isGuest() // 设备列表随家庭 + 房间筛选联动 const loadDevices = useCallback(async (homeId?: string, roomId?: string) => { const targetHomeId = homeId ?? currentFamily?.homeId if (!targetHomeId) { setDeviceList([]) setLoading(false) return } setLoading(true) setLoadError(false) try { const data = await getHomeDeviceList({ homeId: targetHomeId, roomId: roomId || undefined }) setDeviceList(data ?? []) } catch { setLoadError(true) } finally { setLoading(false) } }, [currentFamily?.homeId]) const loadFamilies = useCallback(async () => { try { const list = await getHomeList() setFamilies(list) // 未选中时按持久化的 homeId 恢复,失效则回落第一条 setCurrentFamily((prev) => { const next = prev ?? resolveCurrentHome(list) if (next && next.homeId !== prev?.homeId) { setCurrentHomeId(next.homeId) setFilterRoomId('') loadDevices(next.homeId) loadRooms(next.homeId) } return next }) } catch { // 静默:家庭圈加载失败不阻断设备列表 } }, [loadDevices]) // 房间列表随家庭加载,供筛选条使用;失败静默(仅少了筛选能力) const loadRooms = useCallback(async (homeId?: string) => { const targetHomeId = homeId ?? currentFamily?.homeId if (!targetHomeId) return try { const list = await getRoomList(targetHomeId) setRooms(list ?? []) } catch { setRooms([]) } }, [currentFamily?.homeId]) const selectRoom = (roomId: string) => { if (roomId === filterRoomId) return setFilterRoomId(roomId) loadDevices(undefined, roomId) } useDidShow(() => { if (isGuest()) { setDeviceList([]) setLoading(false) setLoadError(false) return } loadDevices(undefined, filterRoomId) loadFamilies() loadRooms() }) // EventChannel 把整个设备对象传给详情页:首屏零延迟渲染体征快照 const goDetail = (device: HomeDevice) => { const name = encodeURIComponent(deviceLabel(device)) Taro.navigateTo({ url: `${ROUTES.DEVICE_DETAIL}?id=${device.installId}&name=${name}&model=${device.subDeviceType ?? ''}&online=${device.onlineStatus ? 1 : 0}`, success: (res) => res.eventChannel.emit('device', device) }) } const goAdd = () => navigateTo(ROUTES.DEVICE_ADD) const goRoom = () => navigateTo(ROUTES.SCENE_SELECT) const goLogin = () => navigateTo(ROUTES.LOGIN) const openFamilySheet = () => { setPendingFamily(currentFamily) setFamilySheetOpen(true) } const closeFamilySheet = () => { setFamilySheetOpen(false) setPendingFamily(null) } const confirmFamilySheet = () => { if (pendingFamily && pendingFamily.homeId !== currentFamily?.homeId) { setCurrentFamily(pendingFamily) setCurrentHomeId(pendingFamily.homeId) setFilterRoomId('') loadDevices(pendingFamily.homeId) loadRooms(pendingFamily.homeId) } closeFamilySheet() } return ( {/* 绿色衬底:承接浮卡的上浮区,避免 -40px 压到导航标题 */} {/* 设备应用家庭信息卡 */} 设备应用家庭 {currentFamily?.name ?? '未选择'} 关爱对象 {currentFamily ? (currentFamily.careMemberCount > 0 ? `${currentFamily.careMemberCount} 人` : '--') : '--'} 关爱地址 {currentFamily?.address ?? '--'} 切换家庭圈 {/* 房间管理 + 添加设备 两张并排 */} ⌂ 房间管理 + 添加设备 {/* 房间筛选条:横向滚动 chip,随当前家庭房间列表渲染 */} {rooms.length > 0 && ( selectRoom('')} > 全部 {rooms.map((room) => { const active = filterRoomId === room.roomId return ( selectRoom(room.roomId)} > {room.name} ) })} )} {/* 「我的设备」分区标题:数量随筛选联动 */} {!loading && !loadError && !isGuestEmpty && ( 我的设备 {deviceList.length} )} {/* 设备网格 */} {loading ? ( ) : isGuestEmpty ? ( ) : loadError ? ( loadDevices()} /> ) : deviceList.length === 0 ? ( ) : ( {deviceList.map((device) => ( goDetail(device)}> {(() => { const src = pickDeviceIcon(device) return src ? ( ) : ( {FALLBACK_ICON} ) })()} {deviceLabel(device)} {device.onlineStatus ? '在线' : '离线'} ))} )} {/* 切换家庭圈弹层 */} {families.map((family) => { const active = pendingFamily?.homeId === family.homeId return ( setPendingFamily(family)} > {family.name} 关爱对象 {family.careMemberCount > 0 ? `${family.careMemberCount} 人` : '--'} 设备数量 {family.deviceCount}台 ) })} 确定 ) }