Handle unassigned device after child deletion

This commit is contained in:
stu2not
2026-07-01 18:25:21 +08:00
parent da95a3cfb1
commit 429d96a9b3
2 changed files with 46 additions and 13 deletions

View File

@@ -126,6 +126,7 @@ function getAlarmLocationHint(alarm: DeviceAlarmItem | null): string {
export default function Device() { export default function Device() {
const systemBanner = useSystemBanner() const systemBanner = useSystemBanner()
const [binding, setBinding] = useState<Binding | null>(null) const [binding, setBinding] = useState<Binding | null>(null)
const [pendingBinding, setPendingBinding] = useState<Binding | null>(null)
const [child, setChild] = useState<Child | null>(null) const [child, setChild] = useState<Child | null>(null)
const [deviceStatus, setDeviceStatus] = useState<DeviceStatus | null>(null) const [deviceStatus, setDeviceStatus] = useState<DeviceStatus | null>(null)
const [deviceAlarms, setDeviceAlarms] = useState<DeviceAlarmItem[]>([]) const [deviceAlarms, setDeviceAlarms] = useState<DeviceAlarmItem[]>([])
@@ -144,6 +145,7 @@ export default function Device() {
const loadDeviceInfo = async () => { const loadDeviceInfo = async () => {
if (!getToken()) { if (!getToken()) {
setBinding(null) setBinding(null)
setPendingBinding(null)
setChild(null) setChild(null)
setDeviceStatus(null) setDeviceStatus(null)
setDeviceAlarms([]) setDeviceAlarms([])
@@ -159,6 +161,7 @@ export default function Device() {
const context = await loadCurrentChildBindingContext() const context = await loadCurrentChildBindingContext()
setChild(context.currentChild) setChild(context.currentChild)
setBinding(context.currentBinding) setBinding(context.currentBinding)
setPendingBinding(context.pendingBinding)
if (context.currentBinding?.device_id) { if (context.currentBinding?.device_id) {
const [nextStatus, nextAlarms] = await Promise.all([ const [nextStatus, nextAlarms] = await Promise.all([
@@ -324,6 +327,7 @@ export default function Device() {
} }
if (!child) { if (!child) {
const hasPendingDevice = Boolean(pendingBinding?.device_id)
return ( return (
<View className='device-page'> <View className='device-page'>
<View className='page-header'> <View className='page-header'>
@@ -334,10 +338,14 @@ export default function Device() {
<View className='empty-robot'> <View className='empty-robot'>
<Image className='robot-img' src={require('../../assets/tab-icons/robot.png')} mode='aspectFit' /> <Image className='robot-img' src={require('../../assets/tab-icons/robot.png')} mode='aspectFit' />
</View> </View>
<Text className='empty-title'></Text> <Text className='empty-title'>{hasPendingDevice ? '设备已绑定,待关联孩子' : '先绑定一台伴伴设备'}</Text>
<Text className='empty-subtitle'></Text> <Text className='empty-subtitle'>
<View className='empty-btn' onClick={() => Taro.navigateTo({ url: '/pages/bind/index' })}> {hasPendingDevice
<Text className='empty-btn-text'></Text> ? '这台设备还没有关联孩子,关联后即可查看定位、聊天和设备状态'
: '绑定时可以选择已有孩子,或直接新建孩子昵称'}
</Text>
<View className='empty-btn' onClick={() => Taro.navigateTo({ url: hasPendingDevice ? '/pages/bind/index?mode=assign' : '/pages/bind/index' })}>
<Text className='empty-btn-text'>{hasPendingDevice ? '关联孩子' : '添加设备'}</Text>
</View> </View>
</View> </View>
{systemBanner} {systemBanner}
@@ -346,6 +354,7 @@ export default function Device() {
} }
if (!binding) { if (!binding) {
const hasPendingDevice = Boolean(pendingBinding?.device_id)
return ( return (
<View className='device-page'> <View className='device-page'>
<View className='page-header'> <View className='page-header'>
@@ -366,10 +375,14 @@ export default function Device() {
<View className='empty-robot'> <View className='empty-robot'>
<Image className='robot-img' src={require('../../assets/tab-icons/robot.png')} mode='aspectFit' /> <Image className='robot-img' src={require('../../assets/tab-icons/robot.png')} mode='aspectFit' />
</View> </View>
<Text className='empty-title'></Text> <Text className='empty-title'>{hasPendingDevice ? '有设备待关联' : '给当前孩子绑定一台设备'}</Text>
<Text className='empty-subtitle'></Text> <Text className='empty-subtitle'>
<View className='empty-btn' onClick={() => Taro.navigateTo({ url: '/pages/bind/index' })}> {hasPendingDevice
<Text className='empty-btn-text'></Text> ? `设备 ${pendingBinding?.device_id} 还没有关联孩子,可以关联到当前孩子`
: '绑定后,这个孩子的聊天记录、定位和设备状态都会显示在首页'}
</Text>
<View className='empty-btn' onClick={() => Taro.navigateTo({ url: hasPendingDevice ? '/pages/bind/index?mode=assign' : '/pages/bind/index' })}>
<Text className='empty-btn-text'>{hasPendingDevice ? '关联到当前孩子' : '去绑定设备'}</Text>
</View> </View>
</View> </View>
{systemBanner} {systemBanner}

View File

@@ -54,6 +54,7 @@ export interface BindingCardGroupListResponse {
export interface BindingChildContext { export interface BindingChildContext {
currentChild: Child | null currentChild: Child | null
currentBinding: Binding | null currentBinding: Binding | null
pendingBinding: Binding | null
} }
export interface DirectBindPayload { export interface DirectBindPayload {
@@ -253,9 +254,23 @@ export function resolveBindingForChild<T extends { child_id: number | null }>(
return childBindings[0] || null return childBindings[0] || null
} }
export function resolveUnassignedBinding<T extends { child_id: number | null; device_id: string }>(items: T[]): T | null {
const unassignedBindings = items.filter((item) => item.device_id && item.child_id === null)
if (unassignedBindings.length === 0) return null
const selectedDeviceId = getSelectedBindingDeviceId()
if (selectedDeviceId) {
const selectedBinding = unassignedBindings.find((item) => item.device_id === selectedDeviceId) || null
if (selectedBinding) return selectedBinding
}
return unassignedBindings[0] || null
}
export function syncChildAndBindingSelection(children: Child[], bindings: Binding[]): BindingChildContext { export function syncChildAndBindingSelection(children: Child[], bindings: Binding[]): BindingChildContext {
const currentChild = resolveChildSelection(children) const currentChild = resolveChildSelection(children)
const currentBinding = currentChild ? resolveBindingForChild(bindings, currentChild.child_id) : null const childBinding = currentChild ? resolveBindingForChild(bindings, currentChild.child_id) : null
const unassignedBinding = resolveUnassignedBinding(bindings)
if (currentChild) { if (currentChild) {
setSelectedChildId(currentChild.child_id) setSelectedChildId(currentChild.child_id)
@@ -263,15 +278,18 @@ export function syncChildAndBindingSelection(children: Child[], bindings: Bindin
clearSelectedChildId() clearSelectedChildId()
} }
if (currentBinding?.device_id) { if (childBinding?.device_id) {
setSelectedBindingDeviceId(currentBinding.device_id) setSelectedBindingDeviceId(childBinding.device_id)
} else if (unassignedBinding?.device_id) {
setSelectedBindingDeviceId(unassignedBinding.device_id)
} else { } else {
clearSelectedBindingDeviceId() clearSelectedBindingDeviceId()
} }
return { return {
currentChild, currentChild,
currentBinding, currentBinding: childBinding,
pendingBinding: unassignedBinding,
} }
} }
@@ -280,16 +298,18 @@ export async function loadCurrentChildBindingContext(): Promise<{
bindings: Binding[] bindings: Binding[]
currentChild: Child | null currentChild: Child | null
currentBinding: Binding | null currentBinding: Binding | null
pendingBinding: Binding | null
}> { }> {
const [childResponse, bindingResponse] = await Promise.all([getChildren(undefined, 100), getBindings(undefined, 100)]) const [childResponse, bindingResponse] = await Promise.all([getChildren(undefined, 100), getBindings(undefined, 100)])
const children = childResponse.items || [] const children = childResponse.items || []
const bindings = bindingResponse.items || [] const bindings = bindingResponse.items || []
const { currentChild, currentBinding } = syncChildAndBindingSelection(children, bindings) const { currentChild, currentBinding, pendingBinding } = syncChildAndBindingSelection(children, bindings)
return { return {
children, children,
bindings, bindings,
currentChild, currentChild,
currentBinding, currentBinding,
pendingBinding,
} }
} }