From e039ac63be367ddf5204a0550c8f787e11c9e4ee Mon Sep 17 00:00:00 2001 From: stu2not Date: Tue, 2 Jun 2026 15:10:52 +0800 Subject: [PATCH] feat: allow binding device without child --- banban-mini/src/pages/bind/index.tsx | 79 ++++++++++++++++++--------- banban-mini/src/pages/sleep/index.tsx | 10 +--- 2 files changed, 55 insertions(+), 34 deletions(-) diff --git a/banban-mini/src/pages/bind/index.tsx b/banban-mini/src/pages/bind/index.tsx index b3f9bc8..4f4361b 100644 --- a/banban-mini/src/pages/bind/index.tsx +++ b/banban-mini/src/pages/bind/index.tsx @@ -1,6 +1,6 @@ import { View, Text, Image, Input, Button } from '@tarojs/components' import { useEffect, useRef, useState } from 'react' -import Taro, { useDidShow, useDidHide } from '@tarojs/taro' +import Taro, { useDidShow, useDidHide, useRouter } from '@tarojs/taro' import { getToken } from '@/services/auth' import { @@ -83,6 +83,8 @@ function parseBindingPayload(rawValue: string): { deviceId: string; serialNumber } export default function Bind() { + const router = useRouter() + const isAssignMode = String(router.params?.mode || '').trim() === 'assign' const systemBanner = useSystemBanner() const [loading, setLoading] = useState(true) const [submitting, setSubmitting] = useState(false) @@ -112,12 +114,17 @@ export default function Bind() { const hasSelectedOrNewChild = selectedChildId !== null || Boolean(newChildName.trim()) const isPendingBinding = Boolean(pendingDeviceId) const isPollingBind = bindStatus === SESSION_STATUS_PENDING && Boolean(bindToken) - const canEditDeviceFields = hasSelectedOrNewChild && !isPollingBind + const canEditDeviceFields = !isPendingBinding && !isPollingBind + const canSubmit = isPendingBinding ? hasSelectedOrNewChild : !isPollingBind const goDevicePage = () => { Taro.reLaunch({ url: '/pages/device/index' }) } + const goManagePage = () => { + Taro.switchTab({ url: '/pages/sleep/index' }) + } + const handleBack = () => { if (getCurrentPages().length > 1) { Taro.navigateBack() @@ -167,10 +174,18 @@ export default function Bind() { if (session.status === SESSION_STATUS_COMPLETED) { setSelectedBindingDeviceId(session.device_id) - setBindHint(session.card_uuid ? `绑定完成,卡号 ${session.card_uuid}` : '绑定完成') + setBindHint( + session.child_id + ? session.card_uuid ? `绑定完成,卡号 ${session.card_uuid}` : '绑定完成' + : session.card_uuid ? `绑定完成,卡号 ${session.card_uuid},稍后可关联孩子` : '绑定完成,稍后可关联孩子' + ) Taro.showToast({ title: '设备绑定成功', icon: 'success' }) setTimeout(() => { - goDevicePage() + if (session.child_id) { + goDevicePage() + } else { + goManagePage() + } }, 500) return } @@ -209,7 +224,7 @@ export default function Bind() { setChildren(currentChildren) setSelectedChildId(currentChild?.child_id || null) - if (activeBinding?.device_id && !activeBinding.child_id) { + if (isAssignMode && activeBinding?.device_id && !activeBinding.child_id) { setPendingDeviceId(activeBinding.device_id) setDeviceId(activeBinding.device_id) } else { @@ -243,7 +258,7 @@ export default function Bind() { const handleScanCode = () => { if (!canEditDeviceFields) { Taro.showToast({ - title: '请先选择或新建儿童资料', + title: isPollingBind ? '绑定确认中,请稍候' : '当前不能扫码', icon: 'none', }) return @@ -283,11 +298,11 @@ export default function Bind() { try { const childId = await ensureChildId() - if (!childId) { - throw new Error('请先选择儿童或填写新的儿童昵称') - } if (isPendingBinding) { + if (!childId) { + throw new Error('请先选择儿童或填写新的儿童昵称') + } await setBindingChild(pendingDeviceId!, { child_id: childId }) setSelectedBindingDeviceId(pendingDeviceId) Taro.showToast({ title: '关联完成', icon: 'success' }) @@ -305,15 +320,15 @@ export default function Bind() { } resetBindSessionState() - const session = await startNFCBind({ + const bindPayload = { device_id: deviceId.trim(), serial_number: serialNumber.trim(), - child_id: childId, - }) + } + const session = await startNFCBind(childId ? { ...bindPayload, child_id: childId } : bindPayload) setBindToken(session.bind_token) setBindStatus(session.status) - setBindHint('已发送绑卡指令,请去设备上贴自己的卡') + setBindHint(childId ? '已发送绑卡指令,请去设备上贴自己的卡' : '已发送绑卡指令,贴卡后设备会先进入待关联状态') schedulePoll(session.bind_token) Taro.showToast({ title: '请去设备上贴卡', icon: 'none' }) } catch (error: any) { @@ -366,11 +381,9 @@ export default function Bind() { - {!canEditDeviceFields ? '请先完成儿童资料' : isScanning ? '正在扫码...' : '点击扫码'} - - - {!canEditDeviceFields ? '先选儿童,再扫设备二维码' : '扫描设备二维码或条码'} + {isScanning ? '正在扫码...' : '点击扫码'} + 扫描设备二维码或条码 @@ -388,6 +401,18 @@ export default function Bind() { {children.length > 0 && ( + {!isPendingBinding && ( + { + setSelectedChildId(null) + setStoredSelectedChildId(null) + setNewChildName('') + }} + > + 暂不关联孩子 + + )} {children.map((child) => ( - 新建儿童昵称 + {isPendingBinding ? '新建儿童昵称' : '新建儿童昵称(可选)'} 0 ? '不选已有儿童时,可填写新昵称' : '请输入儿童昵称'} + placeholder={ + isPendingBinding + ? children.length > 0 ? '不选已有儿童时,可填写新昵称' : '请输入儿童昵称' + : children.length > 0 ? '不选已有儿童时,可填写新昵称' : '可不填,稍后再关联孩子' + } onInput={(event) => { setNewChildName(event.detail.value) if (event.detail.value) { @@ -429,8 +458,8 @@ export default function Bind() { ? '可以选已有儿童,也可以新建一个儿童后关联当前设备' : '当前还没有儿童资料,请先创建一个儿童资料后关联设备' : children.length > 0 - ? '可以选已有儿童,也可以在这里新建一个儿童后再绑定设备' - : '当前还没有儿童资料,请先创建一个儿童资料'} + ? '儿童资料可选;不选择时,设备会先绑定到账号,稍后可关联孩子' + : '也可以先不创建儿童,直接绑定设备,稍后再关联孩子'} @@ -444,7 +473,7 @@ export default function Bind() { className='field-input' value={deviceId} disabled={!canEditDeviceFields || isPendingBinding} - placeholder={canEditDeviceFields ? '请输入设备号' : '请先选择儿童资料'} + placeholder={canEditDeviceFields ? '请输入设备号' : '绑定确认中'} onInput={(event) => setDeviceId(event.detail.value)} /> @@ -455,7 +484,7 @@ export default function Bind() { className='field-input' value={serialNumber} disabled={!canEditDeviceFields || isPendingBinding} - placeholder={canEditDeviceFields ? '请输入设备序列号' : '请先选择儿童资料'} + placeholder={canEditDeviceFields ? '请输入设备序列号' : '绑定确认中'} onInput={(event) => setSerialNumber(event.detail.value)} /> @@ -478,7 +507,7 @@ export default function Bind() {