SEC_Warehouse/src/pages/device/feature/add.tsx

186 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect } from 'react'
import Taro from '@tarojs/taro'
import { useDidShow } from '@tarojs/taro'
import { View, Text, Input } from '@tarojs/components'
import { Navbar } from '@/components/navbar'
import { Loading } from '@/components/loading'
import { StateView } from '@/components/state-view'
import { addHomeDevice } from '@/api/homeDevice'
import { getHomeList, type HomeInfo } from '@/api/home'
import { getRoomList, type HomeRoom } from '@/api/homeRoom'
import { resolveCurrentHome, setCurrentHomeId } from '@/store/currentHome'
import { showToast } from '@/utils/toast'
import { navigateBack } from '@/utils/navigation'
import styles from './add.module.scss'
export default function DeviceAdd() {
const [deviceId, setDeviceId] = useState('')
const [submitting, setSubmitting] = useState(false)
const [loading, setLoading] = useState(true)
const [loadError, setLoadError] = useState(false)
const [home, setHome] = useState<HomeInfo | null>(null)
const [rooms, setRooms] = useState<HomeRoom[]>([])
const [roomId, setRoomId] = useState('')
// 数据加载体:useDidShow 首次与错误重试共用(state 变化触发 useDidShow 不可行,用计数器驱动 effect)
const [reload, setReload] = useState(0)
const [loaded, setLoaded] = useState(false)
// 默认家庭 + 房间列表:addHomeDevice 需 homeId + roomId
useEffect(() => {
let cancelled = false
setLoading(true)
setLoadError(false)
getHomeList()
.then(async (list) => {
const first = resolveCurrentHome(list)
if (cancelled) return
setHome(first)
if (first) setCurrentHomeId(first.homeId)
if (!first) return
const roomList = await getRoomList(first.homeId)
if (cancelled) return
setRooms(roomList ?? [])
setRoomId((prev) => prev || roomList[0]?.roomId || '')
})
.catch(() => !cancelled && setLoadError(true))
.finally(() => {
if (cancelled) return
setLoading(false)
setLoaded(true)
})
return () => {
cancelled = true
}
}, [reload])
// 从房间管理等页面返回时刷新(房间可能已变更)
useDidShow(() => {
if (loaded) setReload((n) => n + 1)
})
const submitManual = async () => {
if (submitting) return
const code = deviceId.trim()
if (!code) {
showToast('请输入设备编号')
return
}
if (!home || !roomId) {
showToast('请选择安装房间')
return
}
setSubmitting(true)
try {
await addHomeDevice({ deviceName: code, homeId: home.homeId, roomId })
showToast('添加成功')
navigateBack()
} catch (e) {
showToast(e instanceof Error ? e.message : '添加失败')
} finally {
setSubmitting(false)
}
}
// 点击扫码区拉起相机扫码,识别结果回填到输入框,确认后提交
const scanQRCode = async () => {
try {
const res = await Taro.scanCode({ scanType: ['qrCode', 'barCode'] })
const code = String(res.result ?? '').trim()
if (!code) {
showToast('未识别到有效编号')
return
}
setDeviceId(code)
showToast('已填入扫码结果')
} catch {
showToast('扫码取消')
}
}
if (loading) {
return (
<View className={styles.page}>
<Navbar title="添加设备" autoBack variant="hero" />
<View className={styles.stateWrap}><Loading /></View>
</View>
)
}
if (loadError || !home) {
return (
<View className={styles.page}>
<Navbar title="添加设备" autoBack variant="hero" />
<StateView
status="error"
mode="list"
text={loadError ? '加载失败' : '暂无家庭圈'}
retryText={loadError ? '重试' : '返回'}
onRetry={() => (loadError ? setReload((n) => n + 1) : navigateBack())}
/>
</View>
)
}
return (
<View className={styles.page}>
<Navbar title="添加设备" autoBack={true} variant="hero" />
<View className={styles.section}>
<Text className={styles.sectionTitle}>手动输入</Text>
<Text className={styles.sectionDesc}>
将智能设备添加至「{home.name}」,可实时查看设备状态和告警信息。
</Text>
<Input
className={styles.input}
placeholder="请输入设备编号"
maxlength={32}
confirmType="done"
value={deviceId}
onInput={(e) => setDeviceId(e.detail.value)}
/>
{rooms.length > 0 && (
<View className={styles.roomPicker}>
<Text className={styles.roomLabel}>安装房间</Text>
<View className={styles.roomOptions}>
{rooms.map((room) => (
<View
key={room.roomId}
className={`${styles.roomChip} ${roomId === room.roomId ? styles.roomChipActive : ''}`}
onClick={() => setRoomId(room.roomId)}
>
<Text>{room.name}</Text>
</View>
))}
</View>
</View>
)}
<View
className={`${styles.submitBtn} ${submitting ? styles.submitBtnDisabled : ''}`}
hoverClass={styles.submitBtnPressed}
onClick={submitManual}
>
<Text className={styles.submitBtnText}>{submitting ? '提交中...' : '提交'}</Text>
</View>
</View>
<View className={styles.section}>
<Text className={styles.sectionTitle}>扫码添加</Text>
<Text className={styles.sectionDesc}>扫描设备机身或包装盒上的二维码,自动填入编号。</Text>
<View className={styles.scanArea} hoverClass={styles.scanAreaPressed} onClick={scanQRCode}>
<View className={styles.scanFrame}>
<View className={`${styles.scanCorner} ${styles.scanCornerTopLeft}`} />
<View className={`${styles.scanCorner} ${styles.scanCornerTopRight}`} />
<View className={`${styles.scanCorner} ${styles.scanCornerBottomLeft}`} />
<View className={`${styles.scanCorner} ${styles.scanCornerBottomRight}`} />
<View className={styles.scanLine} />
</View>
<Text className={styles.scanText}>点击开始扫码</Text>
<Text className={styles.scanHint}>支持二维码 / 条形码</Text>
</View>
</View>
</View>
)
}